Skip to content

Commit daee2f9

Browse files
lixianglaichenhuacai
authored andcommitted
LoongArch: KVM: Add IPI read and write function
Add implementation of IPI interrupt controller's address space read and write function simulation. Signed-off-by: Min Zhou <[email protected]> Signed-off-by: Tianrui Zhao <[email protected]> Signed-off-by: Xianglai Li <[email protected]> Signed-off-by: Huacai Chen <[email protected]>
1 parent c532de5 commit daee2f9

File tree

3 files changed

+291
-2
lines changed

3 files changed

+291
-2
lines changed

arch/loongarch/include/asm/kvm_host.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ struct kvm_vm_stat {
4545
struct kvm_vm_stat_generic generic;
4646
u64 pages;
4747
u64 hugepages;
48+
u64 ipi_read_exits;
49+
u64 ipi_write_exits;
4850
};
4951

5052
struct kvm_vcpu_stat {

arch/loongarch/include/asm/kvm_ipi.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,18 @@ struct ipi_state {
2828
#define IOCSR_IPI_BASE 0x1000
2929
#define IOCSR_IPI_SIZE 0x160
3030

31+
#define IOCSR_IPI_STATUS 0x000
32+
#define IOCSR_IPI_EN 0x004
33+
#define IOCSR_IPI_SET 0x008
34+
#define IOCSR_IPI_CLEAR 0x00c
35+
#define IOCSR_IPI_BUF_20 0x020
36+
#define IOCSR_IPI_BUF_28 0x028
37+
#define IOCSR_IPI_BUF_30 0x030
38+
#define IOCSR_IPI_BUF_38 0x038
39+
#define IOCSR_IPI_SEND 0x040
40+
#define IOCSR_MAIL_SEND 0x048
41+
#define IOCSR_ANY_SEND 0x158
42+
3143
int kvm_loongarch_register_ipi_device(void);
3244

3345
#endif

arch/loongarch/kvm/intc/ipi.c

Lines changed: 277 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,293 @@
77
#include <asm/kvm_ipi.h>
88
#include <asm/kvm_vcpu.h>
99

10+
static void ipi_send(struct kvm *kvm, uint64_t data)
11+
{
12+
int cpu, action;
13+
uint32_t status;
14+
struct kvm_vcpu *vcpu;
15+
struct kvm_interrupt irq;
16+
17+
cpu = ((data & 0xffffffff) >> 16) & 0x3ff;
18+
vcpu = kvm_get_vcpu_by_cpuid(kvm, cpu);
19+
if (unlikely(vcpu == NULL)) {
20+
kvm_err("%s: invalid target cpu: %d\n", __func__, cpu);
21+
return;
22+
}
23+
24+
action = BIT(data & 0x1f);
25+
spin_lock(&vcpu->arch.ipi_state.lock);
26+
status = vcpu->arch.ipi_state.status;
27+
vcpu->arch.ipi_state.status |= action;
28+
spin_unlock(&vcpu->arch.ipi_state.lock);
29+
if (status == 0) {
30+
irq.irq = LARCH_INT_IPI;
31+
kvm_vcpu_ioctl_interrupt(vcpu, &irq);
32+
}
33+
}
34+
35+
static void ipi_clear(struct kvm_vcpu *vcpu, uint64_t data)
36+
{
37+
uint32_t status;
38+
struct kvm_interrupt irq;
39+
40+
spin_lock(&vcpu->arch.ipi_state.lock);
41+
vcpu->arch.ipi_state.status &= ~data;
42+
status = vcpu->arch.ipi_state.status;
43+
spin_unlock(&vcpu->arch.ipi_state.lock);
44+
if (status == 0) {
45+
irq.irq = -LARCH_INT_IPI;
46+
kvm_vcpu_ioctl_interrupt(vcpu, &irq);
47+
}
48+
}
49+
50+
static uint64_t read_mailbox(struct kvm_vcpu *vcpu, int offset, int len)
51+
{
52+
uint64_t data = 0;
53+
54+
spin_lock(&vcpu->arch.ipi_state.lock);
55+
data = *(ulong *)((void *)vcpu->arch.ipi_state.buf + (offset - 0x20));
56+
spin_unlock(&vcpu->arch.ipi_state.lock);
57+
58+
switch (len) {
59+
case 1:
60+
return data & 0xff;
61+
case 2:
62+
return data & 0xffff;
63+
case 4:
64+
return data & 0xffffffff;
65+
case 8:
66+
return data;
67+
default:
68+
kvm_err("%s: unknown data len: %d\n", __func__, len);
69+
return 0;
70+
}
71+
}
72+
73+
static void write_mailbox(struct kvm_vcpu *vcpu, int offset, uint64_t data, int len)
74+
{
75+
void *pbuf;
76+
77+
spin_lock(&vcpu->arch.ipi_state.lock);
78+
pbuf = (void *)vcpu->arch.ipi_state.buf + (offset - 0x20);
79+
80+
switch (len) {
81+
case 1:
82+
*(unsigned char *)pbuf = (unsigned char)data;
83+
break;
84+
case 2:
85+
*(unsigned short *)pbuf = (unsigned short)data;
86+
break;
87+
case 4:
88+
*(unsigned int *)pbuf = (unsigned int)data;
89+
break;
90+
case 8:
91+
*(unsigned long *)pbuf = (unsigned long)data;
92+
break;
93+
default:
94+
kvm_err("%s: unknown data len: %d\n", __func__, len);
95+
}
96+
spin_unlock(&vcpu->arch.ipi_state.lock);
97+
}
98+
99+
static int send_ipi_data(struct kvm_vcpu *vcpu, gpa_t addr, uint64_t data)
100+
{
101+
int i, ret;
102+
uint32_t val = 0, mask = 0;
103+
104+
/*
105+
* Bit 27-30 is mask for byte writing.
106+
* If the mask is 0, we need not to do anything.
107+
*/
108+
if ((data >> 27) & 0xf) {
109+
/* Read the old val */
110+
ret = kvm_io_bus_read(vcpu, KVM_IOCSR_BUS, addr, sizeof(val), &val);
111+
if (unlikely(ret)) {
112+
kvm_err("%s: : read date from addr %llx failed\n", __func__, addr);
113+
return ret;
114+
}
115+
/* Construct the mask by scanning the bit 27-30 */
116+
for (i = 0; i < 4; i++) {
117+
if (data & (BIT(27 + i)))
118+
mask |= (0xff << (i * 8));
119+
}
120+
/* Save the old part of val */
121+
val &= mask;
122+
}
123+
val |= ((uint32_t)(data >> 32) & ~mask);
124+
ret = kvm_io_bus_write(vcpu, KVM_IOCSR_BUS, addr, sizeof(val), &val);
125+
if (unlikely(ret))
126+
kvm_err("%s: : write date to addr %llx failed\n", __func__, addr);
127+
128+
return ret;
129+
}
130+
131+
static int mail_send(struct kvm *kvm, uint64_t data)
132+
{
133+
int cpu, mailbox, offset;
134+
struct kvm_vcpu *vcpu;
135+
136+
cpu = ((data & 0xffffffff) >> 16) & 0x3ff;
137+
vcpu = kvm_get_vcpu_by_cpuid(kvm, cpu);
138+
if (unlikely(vcpu == NULL)) {
139+
kvm_err("%s: invalid target cpu: %d\n", __func__, cpu);
140+
return -EINVAL;
141+
}
142+
mailbox = ((data & 0xffffffff) >> 2) & 0x7;
143+
offset = IOCSR_IPI_BASE + IOCSR_IPI_BUF_20 + mailbox * 4;
144+
145+
return send_ipi_data(vcpu, offset, data);
146+
}
147+
148+
static int any_send(struct kvm *kvm, uint64_t data)
149+
{
150+
int cpu, offset;
151+
struct kvm_vcpu *vcpu;
152+
153+
cpu = ((data & 0xffffffff) >> 16) & 0x3ff;
154+
vcpu = kvm_get_vcpu_by_cpuid(kvm, cpu);
155+
if (unlikely(vcpu == NULL)) {
156+
kvm_err("%s: invalid target cpu: %d\n", __func__, cpu);
157+
return -EINVAL;
158+
}
159+
offset = data & 0xffff;
160+
161+
return send_ipi_data(vcpu, offset, data);
162+
}
163+
164+
static int loongarch_ipi_readl(struct kvm_vcpu *vcpu, gpa_t addr, int len, void *val)
165+
{
166+
int ret = 0;
167+
uint32_t offset;
168+
uint64_t res = 0;
169+
170+
offset = (uint32_t)(addr & 0x1ff);
171+
WARN_ON_ONCE(offset & (len - 1));
172+
173+
switch (offset) {
174+
case IOCSR_IPI_STATUS:
175+
spin_lock(&vcpu->arch.ipi_state.lock);
176+
res = vcpu->arch.ipi_state.status;
177+
spin_unlock(&vcpu->arch.ipi_state.lock);
178+
break;
179+
case IOCSR_IPI_EN:
180+
spin_lock(&vcpu->arch.ipi_state.lock);
181+
res = vcpu->arch.ipi_state.en;
182+
spin_unlock(&vcpu->arch.ipi_state.lock);
183+
break;
184+
case IOCSR_IPI_SET:
185+
res = 0;
186+
break;
187+
case IOCSR_IPI_CLEAR:
188+
res = 0;
189+
break;
190+
case IOCSR_IPI_BUF_20 ... IOCSR_IPI_BUF_38 + 7:
191+
if (offset + len > IOCSR_IPI_BUF_38 + 8) {
192+
kvm_err("%s: invalid offset or len: offset = %d, len = %d\n",
193+
__func__, offset, len);
194+
ret = -EINVAL;
195+
break;
196+
}
197+
res = read_mailbox(vcpu, offset, len);
198+
break;
199+
default:
200+
kvm_err("%s: unknown addr: %llx\n", __func__, addr);
201+
ret = -EINVAL;
202+
break;
203+
}
204+
*(uint64_t *)val = res;
205+
206+
return ret;
207+
}
208+
209+
static int loongarch_ipi_writel(struct kvm_vcpu *vcpu, gpa_t addr, int len, const void *val)
210+
{
211+
int ret = 0;
212+
uint64_t data;
213+
uint32_t offset;
214+
215+
data = *(uint64_t *)val;
216+
217+
offset = (uint32_t)(addr & 0x1ff);
218+
WARN_ON_ONCE(offset & (len - 1));
219+
220+
switch (offset) {
221+
case IOCSR_IPI_STATUS:
222+
ret = -EINVAL;
223+
break;
224+
case IOCSR_IPI_EN:
225+
spin_lock(&vcpu->arch.ipi_state.lock);
226+
vcpu->arch.ipi_state.en = data;
227+
spin_unlock(&vcpu->arch.ipi_state.lock);
228+
break;
229+
case IOCSR_IPI_SET:
230+
ret = -EINVAL;
231+
break;
232+
case IOCSR_IPI_CLEAR:
233+
/* Just clear the status of the current vcpu */
234+
ipi_clear(vcpu, data);
235+
break;
236+
case IOCSR_IPI_BUF_20 ... IOCSR_IPI_BUF_38 + 7:
237+
if (offset + len > IOCSR_IPI_BUF_38 + 8) {
238+
kvm_err("%s: invalid offset or len: offset = %d, len = %d\n",
239+
__func__, offset, len);
240+
ret = -EINVAL;
241+
break;
242+
}
243+
write_mailbox(vcpu, offset, data, len);
244+
break;
245+
case IOCSR_IPI_SEND:
246+
ipi_send(vcpu->kvm, data);
247+
break;
248+
case IOCSR_MAIL_SEND:
249+
ret = mail_send(vcpu->kvm, *(uint64_t *)val);
250+
break;
251+
case IOCSR_ANY_SEND:
252+
ret = any_send(vcpu->kvm, *(uint64_t *)val);
253+
break;
254+
default:
255+
kvm_err("%s: unknown addr: %llx\n", __func__, addr);
256+
ret = -EINVAL;
257+
break;
258+
}
259+
260+
return ret;
261+
}
262+
10263
static int kvm_ipi_read(struct kvm_vcpu *vcpu,
11264
struct kvm_io_device *dev,
12265
gpa_t addr, int len, void *val)
13266
{
14-
return 0;
267+
int ret;
268+
struct loongarch_ipi *ipi;
269+
270+
ipi = vcpu->kvm->arch.ipi;
271+
if (!ipi) {
272+
kvm_err("%s: ipi irqchip not valid!\n", __func__);
273+
return -EINVAL;
274+
}
275+
ipi->kvm->stat.ipi_read_exits++;
276+
ret = loongarch_ipi_readl(vcpu, addr, len, val);
277+
278+
return ret;
15279
}
16280

17281
static int kvm_ipi_write(struct kvm_vcpu *vcpu,
18282
struct kvm_io_device *dev,
19283
gpa_t addr, int len, const void *val)
20284
{
21-
return 0;
285+
int ret;
286+
struct loongarch_ipi *ipi;
287+
288+
ipi = vcpu->kvm->arch.ipi;
289+
if (!ipi) {
290+
kvm_err("%s: ipi irqchip not valid!\n", __func__);
291+
return -EINVAL;
292+
}
293+
ipi->kvm->stat.ipi_write_exits++;
294+
ret = loongarch_ipi_writel(vcpu, addr, len, val);
295+
296+
return ret;
22297
}
23298

24299
static const struct kvm_io_device_ops kvm_ipi_ops = {

0 commit comments

Comments
 (0)