Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/loongarch/kvm/intc/ipi.c
29537 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* Copyright (C) 2024 Loongson Technology Corporation Limited
4
*/
5
6
#include <linux/kvm_host.h>
7
#include <asm/kvm_ipi.h>
8
#include <asm/kvm_vcpu.h>
9
10
static void ipi_set(struct kvm_vcpu *vcpu, uint32_t data)
11
{
12
uint32_t status;
13
struct kvm_interrupt irq;
14
15
spin_lock(&vcpu->arch.ipi_state.lock);
16
status = vcpu->arch.ipi_state.status;
17
vcpu->arch.ipi_state.status |= data;
18
spin_unlock(&vcpu->arch.ipi_state.lock);
19
if ((status == 0) && data) {
20
irq.irq = LARCH_INT_IPI;
21
kvm_vcpu_ioctl_interrupt(vcpu, &irq);
22
}
23
}
24
25
static void ipi_send(struct kvm *kvm, uint64_t data)
26
{
27
int cpu;
28
struct kvm_vcpu *vcpu;
29
30
cpu = ((data & 0xffffffff) >> 16) & 0x3ff;
31
vcpu = kvm_get_vcpu_by_cpuid(kvm, cpu);
32
if (unlikely(vcpu == NULL)) {
33
kvm_err("%s: invalid target cpu: %d\n", __func__, cpu);
34
return;
35
}
36
37
ipi_set(vcpu, BIT(data & 0x1f));
38
}
39
40
static void ipi_clear(struct kvm_vcpu *vcpu, uint64_t data)
41
{
42
uint32_t status;
43
struct kvm_interrupt irq;
44
45
spin_lock(&vcpu->arch.ipi_state.lock);
46
vcpu->arch.ipi_state.status &= ~data;
47
status = vcpu->arch.ipi_state.status;
48
spin_unlock(&vcpu->arch.ipi_state.lock);
49
if (status == 0) {
50
irq.irq = -LARCH_INT_IPI;
51
kvm_vcpu_ioctl_interrupt(vcpu, &irq);
52
}
53
}
54
55
static uint64_t read_mailbox(struct kvm_vcpu *vcpu, int offset, int len)
56
{
57
uint64_t data = 0;
58
59
spin_lock(&vcpu->arch.ipi_state.lock);
60
data = *(ulong *)((void *)vcpu->arch.ipi_state.buf + (offset - 0x20));
61
spin_unlock(&vcpu->arch.ipi_state.lock);
62
63
switch (len) {
64
case 1:
65
return data & 0xff;
66
case 2:
67
return data & 0xffff;
68
case 4:
69
return data & 0xffffffff;
70
case 8:
71
return data;
72
default:
73
kvm_err("%s: unknown data len: %d\n", __func__, len);
74
return 0;
75
}
76
}
77
78
static void write_mailbox(struct kvm_vcpu *vcpu, int offset, uint64_t data, int len)
79
{
80
void *pbuf;
81
82
spin_lock(&vcpu->arch.ipi_state.lock);
83
pbuf = (void *)vcpu->arch.ipi_state.buf + (offset - 0x20);
84
85
switch (len) {
86
case 1:
87
*(unsigned char *)pbuf = (unsigned char)data;
88
break;
89
case 2:
90
*(unsigned short *)pbuf = (unsigned short)data;
91
break;
92
case 4:
93
*(unsigned int *)pbuf = (unsigned int)data;
94
break;
95
case 8:
96
*(unsigned long *)pbuf = (unsigned long)data;
97
break;
98
default:
99
kvm_err("%s: unknown data len: %d\n", __func__, len);
100
}
101
spin_unlock(&vcpu->arch.ipi_state.lock);
102
}
103
104
static int mail_send(struct kvm *kvm, uint64_t data)
105
{
106
int i, cpu, mailbox, offset;
107
uint32_t val = 0, mask = 0;
108
struct kvm_vcpu *vcpu;
109
110
cpu = ((data & 0xffffffff) >> 16) & 0x3ff;
111
vcpu = kvm_get_vcpu_by_cpuid(kvm, cpu);
112
if (unlikely(vcpu == NULL)) {
113
kvm_err("%s: invalid target cpu: %d\n", __func__, cpu);
114
return -EINVAL;
115
}
116
mailbox = ((data & 0xffffffff) >> 2) & 0x7;
117
offset = IOCSR_IPI_BUF_20 + mailbox * 4;
118
if ((data >> 27) & 0xf) {
119
val = read_mailbox(vcpu, offset, 4);
120
for (i = 0; i < 4; i++)
121
if (data & (BIT(27 + i)))
122
mask |= (0xff << (i * 8));
123
val &= mask;
124
}
125
126
val |= ((uint32_t)(data >> 32) & ~mask);
127
write_mailbox(vcpu, offset, val, 4);
128
129
return 0;
130
}
131
132
static int send_ipi_data(struct kvm_vcpu *vcpu, gpa_t addr, uint64_t data)
133
{
134
int i, idx, ret;
135
uint64_t val = 0, mask = 0;
136
137
/*
138
* Bit 27-30 is mask for byte writing.
139
* If the mask is 0, we need not to do anything.
140
*/
141
if ((data >> 27) & 0xf) {
142
/* Read the old val */
143
idx = srcu_read_lock(&vcpu->kvm->srcu);
144
ret = kvm_io_bus_read(vcpu, KVM_IOCSR_BUS, addr, 4, &val);
145
srcu_read_unlock(&vcpu->kvm->srcu, idx);
146
if (unlikely(ret)) {
147
kvm_err("%s: : read data from addr %llx failed\n", __func__, addr);
148
return ret;
149
}
150
/* Construct the mask by scanning the bit 27-30 */
151
for (i = 0; i < 4; i++) {
152
if (data & (BIT(27 + i)))
153
mask |= (0xff << (i * 8));
154
}
155
/* Save the old part of val */
156
val &= mask;
157
}
158
val |= ((uint32_t)(data >> 32) & ~mask);
159
idx = srcu_read_lock(&vcpu->kvm->srcu);
160
ret = kvm_io_bus_write(vcpu, KVM_IOCSR_BUS, addr, 4, &val);
161
srcu_read_unlock(&vcpu->kvm->srcu, idx);
162
if (unlikely(ret))
163
kvm_err("%s: : write data to addr %llx failed\n", __func__, addr);
164
165
return ret;
166
}
167
168
static int any_send(struct kvm *kvm, uint64_t data)
169
{
170
int cpu, offset;
171
struct kvm_vcpu *vcpu;
172
173
cpu = ((data & 0xffffffff) >> 16) & 0x3ff;
174
vcpu = kvm_get_vcpu_by_cpuid(kvm, cpu);
175
if (unlikely(vcpu == NULL)) {
176
kvm_err("%s: invalid target cpu: %d\n", __func__, cpu);
177
return -EINVAL;
178
}
179
offset = data & 0xffff;
180
181
return send_ipi_data(vcpu, offset, data);
182
}
183
184
static int loongarch_ipi_readl(struct kvm_vcpu *vcpu, gpa_t addr, int len, void *val)
185
{
186
int ret = 0;
187
uint32_t offset;
188
uint64_t res = 0;
189
190
offset = (uint32_t)(addr & 0x1ff);
191
WARN_ON_ONCE(offset & (len - 1));
192
193
switch (offset) {
194
case IOCSR_IPI_STATUS:
195
spin_lock(&vcpu->arch.ipi_state.lock);
196
res = vcpu->arch.ipi_state.status;
197
spin_unlock(&vcpu->arch.ipi_state.lock);
198
break;
199
case IOCSR_IPI_EN:
200
spin_lock(&vcpu->arch.ipi_state.lock);
201
res = vcpu->arch.ipi_state.en;
202
spin_unlock(&vcpu->arch.ipi_state.lock);
203
break;
204
case IOCSR_IPI_SET:
205
res = 0;
206
break;
207
case IOCSR_IPI_CLEAR:
208
res = 0;
209
break;
210
case IOCSR_IPI_BUF_20 ... IOCSR_IPI_BUF_38 + 7:
211
if (offset + len > IOCSR_IPI_BUF_38 + 8) {
212
kvm_err("%s: invalid offset or len: offset = %d, len = %d\n",
213
__func__, offset, len);
214
ret = -EINVAL;
215
break;
216
}
217
res = read_mailbox(vcpu, offset, len);
218
break;
219
default:
220
kvm_err("%s: unknown addr: %llx\n", __func__, addr);
221
ret = -EINVAL;
222
break;
223
}
224
*(uint64_t *)val = res;
225
226
return ret;
227
}
228
229
static int loongarch_ipi_writel(struct kvm_vcpu *vcpu, gpa_t addr, int len, const void *val)
230
{
231
int ret = 0;
232
uint64_t data;
233
uint32_t offset;
234
235
data = *(uint64_t *)val;
236
237
offset = (uint32_t)(addr & 0x1ff);
238
WARN_ON_ONCE(offset & (len - 1));
239
240
switch (offset) {
241
case IOCSR_IPI_STATUS:
242
ret = -EINVAL;
243
break;
244
case IOCSR_IPI_EN:
245
spin_lock(&vcpu->arch.ipi_state.lock);
246
vcpu->arch.ipi_state.en = data;
247
spin_unlock(&vcpu->arch.ipi_state.lock);
248
break;
249
case IOCSR_IPI_SET:
250
ipi_set(vcpu, data);
251
break;
252
case IOCSR_IPI_CLEAR:
253
/* Just clear the status of the current vcpu */
254
ipi_clear(vcpu, data);
255
break;
256
case IOCSR_IPI_BUF_20 ... IOCSR_IPI_BUF_38 + 7:
257
if (offset + len > IOCSR_IPI_BUF_38 + 8) {
258
kvm_err("%s: invalid offset or len: offset = %d, len = %d\n",
259
__func__, offset, len);
260
ret = -EINVAL;
261
break;
262
}
263
write_mailbox(vcpu, offset, data, len);
264
break;
265
case IOCSR_IPI_SEND:
266
ipi_send(vcpu->kvm, data);
267
break;
268
case IOCSR_MAIL_SEND:
269
ret = mail_send(vcpu->kvm, data);
270
break;
271
case IOCSR_ANY_SEND:
272
ret = any_send(vcpu->kvm, data);
273
break;
274
default:
275
kvm_err("%s: unknown addr: %llx\n", __func__, addr);
276
ret = -EINVAL;
277
break;
278
}
279
280
return ret;
281
}
282
283
static int kvm_ipi_read(struct kvm_vcpu *vcpu,
284
struct kvm_io_device *dev,
285
gpa_t addr, int len, void *val)
286
{
287
vcpu->stat.ipi_read_exits++;
288
return loongarch_ipi_readl(vcpu, addr, len, val);
289
}
290
291
static int kvm_ipi_write(struct kvm_vcpu *vcpu,
292
struct kvm_io_device *dev,
293
gpa_t addr, int len, const void *val)
294
{
295
vcpu->stat.ipi_write_exits++;
296
return loongarch_ipi_writel(vcpu, addr, len, val);
297
}
298
299
static const struct kvm_io_device_ops kvm_ipi_ops = {
300
.read = kvm_ipi_read,
301
.write = kvm_ipi_write,
302
};
303
304
static int kvm_ipi_regs_access(struct kvm_device *dev,
305
struct kvm_device_attr *attr,
306
bool is_write)
307
{
308
int len = 4;
309
int cpu, addr;
310
uint64_t val;
311
void *p = NULL;
312
struct kvm_vcpu *vcpu;
313
314
cpu = (attr->attr >> 16) & 0x3ff;
315
addr = attr->attr & 0xff;
316
317
vcpu = kvm_get_vcpu_by_id(dev->kvm, cpu);
318
if (unlikely(vcpu == NULL)) {
319
kvm_err("%s: invalid target cpu: %d\n", __func__, cpu);
320
return -EINVAL;
321
}
322
323
switch (addr) {
324
case IOCSR_IPI_STATUS:
325
p = &vcpu->arch.ipi_state.status;
326
break;
327
case IOCSR_IPI_EN:
328
p = &vcpu->arch.ipi_state.en;
329
break;
330
case IOCSR_IPI_SET:
331
p = &vcpu->arch.ipi_state.set;
332
break;
333
case IOCSR_IPI_CLEAR:
334
p = &vcpu->arch.ipi_state.clear;
335
break;
336
case IOCSR_IPI_BUF_20:
337
p = &vcpu->arch.ipi_state.buf[0];
338
len = 8;
339
break;
340
case IOCSR_IPI_BUF_28:
341
p = &vcpu->arch.ipi_state.buf[1];
342
len = 8;
343
break;
344
case IOCSR_IPI_BUF_30:
345
p = &vcpu->arch.ipi_state.buf[2];
346
len = 8;
347
break;
348
case IOCSR_IPI_BUF_38:
349
p = &vcpu->arch.ipi_state.buf[3];
350
len = 8;
351
break;
352
default:
353
kvm_err("%s: unknown ipi register, addr = %d\n", __func__, addr);
354
return -EINVAL;
355
}
356
357
if (is_write) {
358
if (len == 4) {
359
if (get_user(val, (uint32_t __user *)attr->addr))
360
return -EFAULT;
361
*(uint32_t *)p = (uint32_t)val;
362
} else if (len == 8) {
363
if (get_user(val, (uint64_t __user *)attr->addr))
364
return -EFAULT;
365
*(uint64_t *)p = val;
366
}
367
} else {
368
if (len == 4) {
369
val = *(uint32_t *)p;
370
return put_user(val, (uint32_t __user *)attr->addr);
371
} else if (len == 8) {
372
val = *(uint64_t *)p;
373
return put_user(val, (uint64_t __user *)attr->addr);
374
}
375
}
376
377
return 0;
378
}
379
380
static int kvm_ipi_get_attr(struct kvm_device *dev,
381
struct kvm_device_attr *attr)
382
{
383
switch (attr->group) {
384
case KVM_DEV_LOONGARCH_IPI_GRP_REGS:
385
return kvm_ipi_regs_access(dev, attr, false);
386
default:
387
kvm_err("%s: unknown group (%d)\n", __func__, attr->group);
388
return -EINVAL;
389
}
390
}
391
392
static int kvm_ipi_set_attr(struct kvm_device *dev,
393
struct kvm_device_attr *attr)
394
{
395
switch (attr->group) {
396
case KVM_DEV_LOONGARCH_IPI_GRP_REGS:
397
return kvm_ipi_regs_access(dev, attr, true);
398
default:
399
kvm_err("%s: unknown group (%d)\n", __func__, attr->group);
400
return -EINVAL;
401
}
402
}
403
404
static int kvm_ipi_create(struct kvm_device *dev, u32 type)
405
{
406
int ret;
407
struct kvm *kvm;
408
struct kvm_io_device *device;
409
struct loongarch_ipi *s;
410
411
if (!dev) {
412
kvm_err("%s: kvm_device ptr is invalid!\n", __func__);
413
return -EINVAL;
414
}
415
416
kvm = dev->kvm;
417
if (kvm->arch.ipi) {
418
kvm_err("%s: LoongArch IPI has already been created!\n", __func__);
419
return -EINVAL;
420
}
421
422
s = kzalloc(sizeof(struct loongarch_ipi), GFP_KERNEL);
423
if (!s)
424
return -ENOMEM;
425
426
spin_lock_init(&s->lock);
427
s->kvm = kvm;
428
429
/*
430
* Initialize IOCSR device
431
*/
432
device = &s->device;
433
kvm_iodevice_init(device, &kvm_ipi_ops);
434
mutex_lock(&kvm->slots_lock);
435
ret = kvm_io_bus_register_dev(kvm, KVM_IOCSR_BUS, IOCSR_IPI_BASE, IOCSR_IPI_SIZE, device);
436
mutex_unlock(&kvm->slots_lock);
437
if (ret < 0) {
438
kvm_err("%s: Initialize IOCSR dev failed, ret = %d\n", __func__, ret);
439
goto err;
440
}
441
442
kvm->arch.ipi = s;
443
return 0;
444
445
err:
446
kfree(s);
447
return -EFAULT;
448
}
449
450
static void kvm_ipi_destroy(struct kvm_device *dev)
451
{
452
struct kvm *kvm;
453
struct loongarch_ipi *ipi;
454
455
if (!dev || !dev->kvm || !dev->kvm->arch.ipi)
456
return;
457
458
kvm = dev->kvm;
459
ipi = kvm->arch.ipi;
460
kvm_io_bus_unregister_dev(kvm, KVM_IOCSR_BUS, &ipi->device);
461
kfree(ipi);
462
}
463
464
static struct kvm_device_ops kvm_ipi_dev_ops = {
465
.name = "kvm-loongarch-ipi",
466
.create = kvm_ipi_create,
467
.destroy = kvm_ipi_destroy,
468
.set_attr = kvm_ipi_set_attr,
469
.get_attr = kvm_ipi_get_attr,
470
};
471
472
int kvm_loongarch_register_ipi_device(void)
473
{
474
return kvm_register_device_ops(&kvm_ipi_dev_ops, KVM_DEV_TYPE_LOONGARCH_IPI);
475
}
476
477