Skip to content

Commit 2e8b9df

Browse files
lixianglaichenhuacai
authored andcommitted
LoongArch: KVM: Add EIOINTC device support
Add device model for EIOINTC interrupt controller, implement basic create & destroy interfaces, and register device model to kvm device table. Signed-off-by: Tianrui Zhao <[email protected]> Signed-off-by: Xianglai Li <[email protected]> Signed-off-by: Huacai Chen <[email protected]>
1 parent 8e30542 commit 2e8b9df

File tree

6 files changed

+237
-1
lines changed

6 files changed

+237
-1
lines changed
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
/*
3+
* Copyright (C) 2024 Loongson Technology Corporation Limited
4+
*/
5+
6+
#ifndef __ASM_KVM_EIOINTC_H
7+
#define __ASM_KVM_EIOINTC_H
8+
9+
#include <kvm/iodev.h>
10+
11+
#define EIOINTC_IRQS 256
12+
#define EIOINTC_ROUTE_MAX_VCPUS 256
13+
#define EIOINTC_IRQS_U8_NUMS (EIOINTC_IRQS / 8)
14+
#define EIOINTC_IRQS_U16_NUMS (EIOINTC_IRQS_U8_NUMS / 2)
15+
#define EIOINTC_IRQS_U32_NUMS (EIOINTC_IRQS_U8_NUMS / 4)
16+
#define EIOINTC_IRQS_U64_NUMS (EIOINTC_IRQS_U8_NUMS / 8)
17+
/* map to ipnum per 32 irqs */
18+
#define EIOINTC_IRQS_NODETYPE_COUNT 16
19+
20+
#define EIOINTC_BASE 0x1400
21+
#define EIOINTC_SIZE 0x900
22+
23+
#define EIOINTC_VIRT_BASE (0x40000000)
24+
#define EIOINTC_VIRT_SIZE (0x1000)
25+
26+
#define LOONGSON_IP_NUM 8
27+
28+
struct loongarch_eiointc {
29+
spinlock_t lock;
30+
struct kvm *kvm;
31+
struct kvm_io_device device;
32+
struct kvm_io_device device_vext;
33+
uint32_t num_cpu;
34+
uint32_t features;
35+
uint32_t status;
36+
37+
/* hardware state */
38+
union nodetype {
39+
u64 reg_u64[EIOINTC_IRQS_NODETYPE_COUNT / 4];
40+
u32 reg_u32[EIOINTC_IRQS_NODETYPE_COUNT / 2];
41+
u16 reg_u16[EIOINTC_IRQS_NODETYPE_COUNT];
42+
u8 reg_u8[EIOINTC_IRQS_NODETYPE_COUNT * 2];
43+
} nodetype;
44+
45+
/* one bit shows the state of one irq */
46+
union bounce {
47+
u64 reg_u64[EIOINTC_IRQS_U64_NUMS];
48+
u32 reg_u32[EIOINTC_IRQS_U32_NUMS];
49+
u16 reg_u16[EIOINTC_IRQS_U16_NUMS];
50+
u8 reg_u8[EIOINTC_IRQS_U8_NUMS];
51+
} bounce;
52+
53+
union isr {
54+
u64 reg_u64[EIOINTC_IRQS_U64_NUMS];
55+
u32 reg_u32[EIOINTC_IRQS_U32_NUMS];
56+
u16 reg_u16[EIOINTC_IRQS_U16_NUMS];
57+
u8 reg_u8[EIOINTC_IRQS_U8_NUMS];
58+
} isr;
59+
union coreisr {
60+
u64 reg_u64[EIOINTC_ROUTE_MAX_VCPUS][EIOINTC_IRQS_U64_NUMS];
61+
u32 reg_u32[EIOINTC_ROUTE_MAX_VCPUS][EIOINTC_IRQS_U32_NUMS];
62+
u16 reg_u16[EIOINTC_ROUTE_MAX_VCPUS][EIOINTC_IRQS_U16_NUMS];
63+
u8 reg_u8[EIOINTC_ROUTE_MAX_VCPUS][EIOINTC_IRQS_U8_NUMS];
64+
} coreisr;
65+
union enable {
66+
u64 reg_u64[EIOINTC_IRQS_U64_NUMS];
67+
u32 reg_u32[EIOINTC_IRQS_U32_NUMS];
68+
u16 reg_u16[EIOINTC_IRQS_U16_NUMS];
69+
u8 reg_u8[EIOINTC_IRQS_U8_NUMS];
70+
} enable;
71+
72+
/* use one byte to config ipmap for 32 irqs at once */
73+
union ipmap {
74+
u64 reg_u64;
75+
u32 reg_u32[EIOINTC_IRQS_U32_NUMS / 4];
76+
u16 reg_u16[EIOINTC_IRQS_U16_NUMS / 4];
77+
u8 reg_u8[EIOINTC_IRQS_U8_NUMS / 4];
78+
} ipmap;
79+
/* use one byte to config coremap for one irq */
80+
union coremap {
81+
u64 reg_u64[EIOINTC_IRQS / 8];
82+
u32 reg_u32[EIOINTC_IRQS / 4];
83+
u16 reg_u16[EIOINTC_IRQS / 2];
84+
u8 reg_u8[EIOINTC_IRQS];
85+
} coremap;
86+
87+
DECLARE_BITMAP(sw_coreisr[EIOINTC_ROUTE_MAX_VCPUS][LOONGSON_IP_NUM], EIOINTC_IRQS);
88+
uint8_t sw_coremap[EIOINTC_IRQS];
89+
};
90+
91+
int kvm_loongarch_register_eiointc_device(void);
92+
93+
#endif /* __ASM_KVM_EIOINTC_H */

arch/loongarch/include/asm/kvm_host.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <asm/inst.h>
2020
#include <asm/kvm_mmu.h>
2121
#include <asm/kvm_ipi.h>
22+
#include <asm/kvm_eiointc.h>
2223
#include <asm/loongarch.h>
2324

2425
/* Loongarch KVM register ids */
@@ -87,7 +88,7 @@ struct kvm_world_switch {
8788
*
8889
* For LOONGARCH_CSR_CPUID register, max CPUID size if 512
8990
* For IPI hardware, max destination CPUID size 1024
90-
* For extioi interrupt controller, max destination CPUID size is 256
91+
* For eiointc interrupt controller, max destination CPUID size is 256
9192
* For msgint interrupt controller, max supported CPUID size is 65536
9293
*
9394
* Currently max CPUID is defined as 256 for KVM hypervisor, in future
@@ -121,6 +122,7 @@ struct kvm_arch {
121122
s64 time_offset;
122123
struct kvm_context __percpu *vmcs;
123124
struct loongarch_ipi *ipi;
125+
struct loongarch_eiointc *eiointc;
124126
};
125127

126128
#define CSR_MAX_NUMS 0x800

arch/loongarch/kvm/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,6 @@ kvm-y += tlb.o
1919
kvm-y += vcpu.o
2020
kvm-y += vm.o
2121
kvm-y += intc/ipi.o
22+
kvm-y += intc/eiointc.o
2223

2324
CFLAGS_exit.o += $(call cc-option,-Wno-override-init,)

arch/loongarch/kvm/intc/eiointc.c

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* Copyright (C) 2024 Loongson Technology Corporation Limited
4+
*/
5+
6+
#include <asm/kvm_eiointc.h>
7+
#include <asm/kvm_vcpu.h>
8+
#include <linux/count_zeros.h>
9+
10+
static int kvm_eiointc_read(struct kvm_vcpu *vcpu,
11+
struct kvm_io_device *dev,
12+
gpa_t addr, int len, void *val)
13+
{
14+
return 0;
15+
}
16+
17+
static int kvm_eiointc_write(struct kvm_vcpu *vcpu,
18+
struct kvm_io_device *dev,
19+
gpa_t addr, int len, const void *val)
20+
{
21+
return 0;
22+
}
23+
24+
static const struct kvm_io_device_ops kvm_eiointc_ops = {
25+
.read = kvm_eiointc_read,
26+
.write = kvm_eiointc_write,
27+
};
28+
29+
static int kvm_eiointc_virt_read(struct kvm_vcpu *vcpu,
30+
struct kvm_io_device *dev,
31+
gpa_t addr, int len, void *val)
32+
{
33+
return 0;
34+
}
35+
36+
static int kvm_eiointc_virt_write(struct kvm_vcpu *vcpu,
37+
struct kvm_io_device *dev,
38+
gpa_t addr, int len, const void *val)
39+
{
40+
return 0;
41+
}
42+
43+
static const struct kvm_io_device_ops kvm_eiointc_virt_ops = {
44+
.read = kvm_eiointc_virt_read,
45+
.write = kvm_eiointc_virt_write,
46+
};
47+
48+
static int kvm_eiointc_get_attr(struct kvm_device *dev,
49+
struct kvm_device_attr *attr)
50+
{
51+
return 0;
52+
}
53+
54+
static int kvm_eiointc_set_attr(struct kvm_device *dev,
55+
struct kvm_device_attr *attr)
56+
{
57+
return 0;
58+
}
59+
60+
static int kvm_eiointc_create(struct kvm_device *dev, u32 type)
61+
{
62+
int ret;
63+
struct loongarch_eiointc *s;
64+
struct kvm_io_device *device, *device1;
65+
struct kvm *kvm = dev->kvm;
66+
67+
/* eiointc has been created */
68+
if (kvm->arch.eiointc)
69+
return -EINVAL;
70+
71+
s = kzalloc(sizeof(struct loongarch_eiointc), GFP_KERNEL);
72+
if (!s)
73+
return -ENOMEM;
74+
75+
spin_lock_init(&s->lock);
76+
s->kvm = kvm;
77+
78+
/*
79+
* Initialize IOCSR device
80+
*/
81+
device = &s->device;
82+
kvm_iodevice_init(device, &kvm_eiointc_ops);
83+
mutex_lock(&kvm->slots_lock);
84+
ret = kvm_io_bus_register_dev(kvm, KVM_IOCSR_BUS,
85+
EIOINTC_BASE, EIOINTC_SIZE, device);
86+
mutex_unlock(&kvm->slots_lock);
87+
if (ret < 0) {
88+
kfree(s);
89+
return ret;
90+
}
91+
92+
device1 = &s->device_vext;
93+
kvm_iodevice_init(device1, &kvm_eiointc_virt_ops);
94+
ret = kvm_io_bus_register_dev(kvm, KVM_IOCSR_BUS,
95+
EIOINTC_VIRT_BASE, EIOINTC_VIRT_SIZE, device1);
96+
if (ret < 0) {
97+
kvm_io_bus_unregister_dev(kvm, KVM_IOCSR_BUS, &s->device);
98+
kfree(s);
99+
return ret;
100+
}
101+
kvm->arch.eiointc = s;
102+
103+
return 0;
104+
}
105+
106+
static void kvm_eiointc_destroy(struct kvm_device *dev)
107+
{
108+
struct kvm *kvm;
109+
struct loongarch_eiointc *eiointc;
110+
111+
if (!dev || !dev->kvm || !dev->kvm->arch.eiointc)
112+
return;
113+
114+
kvm = dev->kvm;
115+
eiointc = kvm->arch.eiointc;
116+
kvm_io_bus_unregister_dev(kvm, KVM_IOCSR_BUS, &eiointc->device);
117+
kvm_io_bus_unregister_dev(kvm, KVM_IOCSR_BUS, &eiointc->device_vext);
118+
kfree(eiointc);
119+
}
120+
121+
static struct kvm_device_ops kvm_eiointc_dev_ops = {
122+
.name = "kvm-loongarch-eiointc",
123+
.create = kvm_eiointc_create,
124+
.destroy = kvm_eiointc_destroy,
125+
.set_attr = kvm_eiointc_set_attr,
126+
.get_attr = kvm_eiointc_get_attr,
127+
};
128+
129+
int kvm_loongarch_register_eiointc_device(void)
130+
{
131+
return kvm_register_device_ops(&kvm_eiointc_dev_ops, KVM_DEV_TYPE_LOONGARCH_EIOINTC);
132+
}

arch/loongarch/kvm/main.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <asm/cacheflush.h>
1010
#include <asm/cpufeature.h>
1111
#include <asm/kvm_csr.h>
12+
#include <asm/kvm_eiointc.h>
1213
#include "trace.h"
1314

1415
unsigned long vpid_mask;
@@ -370,6 +371,11 @@ static int kvm_loongarch_env_init(void)
370371

371372
/* Register LoongArch IPI interrupt controller interface. */
372373
ret = kvm_loongarch_register_ipi_device();
374+
if (ret)
375+
return ret;
376+
377+
/* Register LoongArch EIOINTC interrupt controller interface. */
378+
ret = kvm_loongarch_register_eiointc_device();
373379

374380
return ret;
375381
}

include/uapi/linux/kvm.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1160,6 +1160,8 @@ enum kvm_device_type {
11601160
#define KVM_DEV_TYPE_RISCV_AIA KVM_DEV_TYPE_RISCV_AIA
11611161
KVM_DEV_TYPE_LOONGARCH_IPI,
11621162
#define KVM_DEV_TYPE_LOONGARCH_IPI KVM_DEV_TYPE_LOONGARCH_IPI
1163+
KVM_DEV_TYPE_LOONGARCH_EIOINTC,
1164+
#define KVM_DEV_TYPE_LOONGARCH_EIOINTC KVM_DEV_TYPE_LOONGARCH_EIOINTC
11631165

11641166
KVM_DEV_TYPE_MAX,
11651167

0 commit comments

Comments
 (0)