Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/loongarch/kvm/intc/pch_pic.c
53158 views
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_pch_pic.h>
8
#include <asm/kvm_vcpu.h>
9
#include <linux/count_zeros.h>
10
11
/* update the isr according to irq level and route irq to eiointc */
12
static void pch_pic_update_irq(struct loongarch_pch_pic *s, int irq, int level)
13
{
14
u64 mask = BIT(irq);
15
16
/*
17
* set isr and route irq to eiointc and
18
* the route table is in htmsi_vector[]
19
*/
20
if (level) {
21
if (mask & s->irr & ~s->mask) {
22
s->isr |= mask;
23
irq = s->htmsi_vector[irq];
24
eiointc_set_irq(s->kvm->arch.eiointc, irq, level);
25
}
26
} else {
27
if (mask & s->isr & ~s->irr) {
28
s->isr &= ~mask;
29
irq = s->htmsi_vector[irq];
30
eiointc_set_irq(s->kvm->arch.eiointc, irq, level);
31
}
32
}
33
}
34
35
/* update batch irqs, the irq_mask is a bitmap of irqs */
36
static void pch_pic_update_batch_irqs(struct loongarch_pch_pic *s, u64 irq_mask, int level)
37
{
38
unsigned int irq;
39
DECLARE_BITMAP(irqs, 64) = { BITMAP_FROM_U64(irq_mask) };
40
41
for_each_set_bit(irq, irqs, 64)
42
pch_pic_update_irq(s, irq, level);
43
}
44
45
/* called when a irq is triggered in pch pic */
46
void pch_pic_set_irq(struct loongarch_pch_pic *s, int irq, int level)
47
{
48
u64 mask = BIT(irq);
49
50
spin_lock(&s->lock);
51
if (level)
52
s->irr |= mask; /* set irr */
53
else {
54
/*
55
* In edge triggered mode, 0 does not mean to clear irq
56
* The irr register variable is cleared when cpu writes to the
57
* PCH_PIC_CLEAR_START address area
58
*/
59
if (s->edge & mask) {
60
spin_unlock(&s->lock);
61
return;
62
}
63
s->irr &= ~mask;
64
}
65
pch_pic_update_irq(s, irq, level);
66
spin_unlock(&s->lock);
67
}
68
69
/* msi irq handler */
70
void pch_msi_set_irq(struct kvm *kvm, int irq, int level)
71
{
72
eiointc_set_irq(kvm->arch.eiointc, irq, level);
73
}
74
75
static int loongarch_pch_pic_read(struct loongarch_pch_pic *s, gpa_t addr, int len, void *val)
76
{
77
int offset;
78
u64 data = 0;
79
void *ptemp;
80
81
offset = addr - s->pch_pic_base;
82
offset -= offset & 7;
83
84
spin_lock(&s->lock);
85
switch (offset) {
86
case PCH_PIC_INT_ID_START ... PCH_PIC_INT_ID_END:
87
data = s->id.data;
88
break;
89
case PCH_PIC_MASK_START ... PCH_PIC_MASK_END:
90
data = s->mask;
91
break;
92
case PCH_PIC_HTMSI_EN_START ... PCH_PIC_HTMSI_EN_END:
93
/* read htmsi enable reg */
94
data = s->htmsi_en;
95
break;
96
case PCH_PIC_EDGE_START ... PCH_PIC_EDGE_END:
97
/* read edge enable reg */
98
data = s->edge;
99
break;
100
case PCH_PIC_AUTO_CTRL0_START ... PCH_PIC_AUTO_CTRL0_END:
101
case PCH_PIC_AUTO_CTRL1_START ... PCH_PIC_AUTO_CTRL1_END:
102
/* we only use default mode: fixed interrupt distribution mode */
103
break;
104
case PCH_PIC_ROUTE_ENTRY_START ... PCH_PIC_ROUTE_ENTRY_END:
105
/* only route to int0: eiointc */
106
ptemp = s->route_entry + (offset - PCH_PIC_ROUTE_ENTRY_START);
107
data = *(u64 *)ptemp;
108
break;
109
case PCH_PIC_HTMSI_VEC_START ... PCH_PIC_HTMSI_VEC_END:
110
/* read htmsi vector */
111
ptemp = s->htmsi_vector + (offset - PCH_PIC_HTMSI_VEC_START);
112
data = *(u64 *)ptemp;
113
break;
114
case PCH_PIC_POLARITY_START ... PCH_PIC_POLARITY_END:
115
data = s->polarity;
116
break;
117
case PCH_PIC_INT_IRR_START:
118
data = s->irr;
119
break;
120
case PCH_PIC_INT_ISR_START:
121
data = s->isr;
122
break;
123
default:
124
break;
125
}
126
spin_unlock(&s->lock);
127
128
offset = (addr - s->pch_pic_base) & 7;
129
data = data >> (offset * 8);
130
memcpy(val, &data, len);
131
132
return 0;
133
}
134
135
static int kvm_pch_pic_read(struct kvm_vcpu *vcpu,
136
struct kvm_io_device *dev,
137
gpa_t addr, int len, void *val)
138
{
139
int ret = 0;
140
struct loongarch_pch_pic *s = vcpu->kvm->arch.pch_pic;
141
142
if (!s) {
143
kvm_err("%s: pch pic irqchip not valid!\n", __func__);
144
return ret;
145
}
146
147
if (addr & (len - 1)) {
148
kvm_err("%s: pch pic not aligned addr %llx len %d\n", __func__, addr, len);
149
return ret;
150
}
151
152
/* statistics of pch pic reading */
153
vcpu->stat.pch_pic_read_exits++;
154
ret = loongarch_pch_pic_read(s, addr, len, val);
155
156
return ret;
157
}
158
159
static int loongarch_pch_pic_write(struct loongarch_pch_pic *s, gpa_t addr,
160
int len, const void *val)
161
{
162
int offset;
163
u64 old, data, mask;
164
void *ptemp;
165
166
switch (len) {
167
case 1:
168
data = *(u8 *)val;
169
mask = 0xFF;
170
break;
171
case 2:
172
data = *(u16 *)val;
173
mask = USHRT_MAX;
174
break;
175
case 4:
176
data = *(u32 *)val;
177
mask = UINT_MAX;
178
break;
179
case 8:
180
default:
181
data = *(u64 *)val;
182
mask = ULONG_MAX;
183
break;
184
}
185
186
offset = (addr - s->pch_pic_base) & 7;
187
mask = mask << (offset * 8);
188
data = data << (offset * 8);
189
offset = (addr - s->pch_pic_base) - offset;
190
191
spin_lock(&s->lock);
192
switch (offset) {
193
case PCH_PIC_MASK_START:
194
old = s->mask;
195
s->mask = (old & ~mask) | data;
196
if (old & ~data)
197
pch_pic_update_batch_irqs(s, old & ~data, 1);
198
if (~old & data)
199
pch_pic_update_batch_irqs(s, ~old & data, 0);
200
break;
201
case PCH_PIC_HTMSI_EN_START:
202
s->htmsi_en = (s->htmsi_en & ~mask) | data;
203
break;
204
case PCH_PIC_EDGE_START:
205
s->edge = (s->edge & ~mask) | data;
206
break;
207
case PCH_PIC_POLARITY_START:
208
s->polarity = (s->polarity & ~mask) | data;
209
break;
210
case PCH_PIC_CLEAR_START:
211
old = s->irr & s->edge & data;
212
if (old) {
213
s->irr &= ~old;
214
pch_pic_update_batch_irqs(s, old, 0);
215
}
216
break;
217
case PCH_PIC_HTMSI_VEC_START ... PCH_PIC_HTMSI_VEC_END:
218
ptemp = s->htmsi_vector + (offset - PCH_PIC_HTMSI_VEC_START);
219
*(u64 *)ptemp = (*(u64 *)ptemp & ~mask) | data;
220
break;
221
/* Not implemented */
222
case PCH_PIC_AUTO_CTRL0_START:
223
case PCH_PIC_AUTO_CTRL1_START:
224
case PCH_PIC_ROUTE_ENTRY_START ... PCH_PIC_ROUTE_ENTRY_END:
225
break;
226
default:
227
break;
228
}
229
spin_unlock(&s->lock);
230
231
return 0;
232
}
233
234
static int kvm_pch_pic_write(struct kvm_vcpu *vcpu,
235
struct kvm_io_device *dev,
236
gpa_t addr, int len, const void *val)
237
{
238
int ret = 0;
239
struct loongarch_pch_pic *s = vcpu->kvm->arch.pch_pic;
240
241
if (!s) {
242
kvm_err("%s: pch pic irqchip not valid!\n", __func__);
243
return ret;
244
}
245
246
if (addr & (len - 1)) {
247
kvm_err("%s: pch pic not aligned addr %llx len %d\n", __func__, addr, len);
248
return ret;
249
}
250
251
/* statistics of pch pic writing */
252
vcpu->stat.pch_pic_write_exits++;
253
ret = loongarch_pch_pic_write(s, addr, len, val);
254
255
return ret;
256
}
257
258
static const struct kvm_io_device_ops kvm_pch_pic_ops = {
259
.read = kvm_pch_pic_read,
260
.write = kvm_pch_pic_write,
261
};
262
263
static int kvm_pch_pic_init(struct kvm_device *dev, u64 addr)
264
{
265
int ret;
266
struct kvm *kvm = dev->kvm;
267
struct kvm_io_device *device;
268
struct loongarch_pch_pic *s = dev->kvm->arch.pch_pic;
269
270
s->pch_pic_base = addr;
271
device = &s->device;
272
/* init device by pch pic writing and reading ops */
273
kvm_iodevice_init(device, &kvm_pch_pic_ops);
274
mutex_lock(&kvm->slots_lock);
275
/* register pch pic device */
276
ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS, addr, PCH_PIC_SIZE, device);
277
mutex_unlock(&kvm->slots_lock);
278
279
return (ret < 0) ? -EFAULT : 0;
280
}
281
282
/* used by user space to get or set pch pic registers */
283
static int kvm_pch_pic_regs_access(struct kvm_device *dev,
284
struct kvm_device_attr *attr,
285
bool is_write)
286
{
287
char buf[8];
288
int addr, offset, len = 8, ret = 0;
289
void __user *data;
290
void *p = NULL;
291
struct loongarch_pch_pic *s;
292
293
s = dev->kvm->arch.pch_pic;
294
addr = attr->attr;
295
data = (void __user *)attr->addr;
296
297
/* get pointer to pch pic register by addr */
298
switch (addr) {
299
case PCH_PIC_MASK_START:
300
p = &s->mask;
301
break;
302
case PCH_PIC_HTMSI_EN_START:
303
p = &s->htmsi_en;
304
break;
305
case PCH_PIC_EDGE_START:
306
p = &s->edge;
307
break;
308
case PCH_PIC_AUTO_CTRL0_START:
309
p = &s->auto_ctrl0;
310
break;
311
case PCH_PIC_AUTO_CTRL1_START:
312
p = &s->auto_ctrl1;
313
break;
314
case PCH_PIC_ROUTE_ENTRY_START ... PCH_PIC_ROUTE_ENTRY_END:
315
offset = addr - PCH_PIC_ROUTE_ENTRY_START;
316
p = &s->route_entry[offset];
317
len = 1;
318
break;
319
case PCH_PIC_HTMSI_VEC_START ... PCH_PIC_HTMSI_VEC_END:
320
offset = addr - PCH_PIC_HTMSI_VEC_START;
321
p = &s->htmsi_vector[offset];
322
len = 1;
323
break;
324
case PCH_PIC_INT_IRR_START:
325
p = &s->irr;
326
break;
327
case PCH_PIC_INT_ISR_START:
328
p = &s->isr;
329
break;
330
case PCH_PIC_POLARITY_START:
331
p = &s->polarity;
332
break;
333
default:
334
return -EINVAL;
335
}
336
337
if (is_write) {
338
if (copy_from_user(buf, data, len))
339
return -EFAULT;
340
}
341
342
spin_lock(&s->lock);
343
if (is_write)
344
memcpy(p, buf, len);
345
else
346
memcpy(buf, p, len);
347
spin_unlock(&s->lock);
348
349
if (!is_write) {
350
if (copy_to_user(data, buf, len))
351
return -EFAULT;
352
}
353
354
return ret;
355
}
356
357
static int kvm_pch_pic_get_attr(struct kvm_device *dev,
358
struct kvm_device_attr *attr)
359
{
360
switch (attr->group) {
361
case KVM_DEV_LOONGARCH_PCH_PIC_GRP_REGS:
362
return kvm_pch_pic_regs_access(dev, attr, false);
363
default:
364
return -EINVAL;
365
}
366
}
367
368
static int kvm_pch_pic_set_attr(struct kvm_device *dev,
369
struct kvm_device_attr *attr)
370
{
371
u64 addr;
372
void __user *uaddr = (void __user *)(long)attr->addr;
373
374
switch (attr->group) {
375
case KVM_DEV_LOONGARCH_PCH_PIC_GRP_CTRL:
376
switch (attr->attr) {
377
case KVM_DEV_LOONGARCH_PCH_PIC_CTRL_INIT:
378
if (copy_from_user(&addr, uaddr, sizeof(addr)))
379
return -EFAULT;
380
381
if (!dev->kvm->arch.pch_pic) {
382
kvm_err("%s: please create pch_pic irqchip first!\n", __func__);
383
return -ENODEV;
384
}
385
386
return kvm_pch_pic_init(dev, addr);
387
default:
388
kvm_err("%s: unknown group (%d) attr (%lld)\n", __func__, attr->group,
389
attr->attr);
390
return -EINVAL;
391
}
392
case KVM_DEV_LOONGARCH_PCH_PIC_GRP_REGS:
393
return kvm_pch_pic_regs_access(dev, attr, true);
394
default:
395
return -EINVAL;
396
}
397
}
398
399
static int kvm_setup_default_irq_routing(struct kvm *kvm)
400
{
401
int i, ret;
402
u32 nr = KVM_IRQCHIP_NUM_PINS;
403
struct kvm_irq_routing_entry *entries;
404
405
entries = kcalloc(nr, sizeof(*entries), GFP_KERNEL);
406
if (!entries)
407
return -ENOMEM;
408
409
for (i = 0; i < nr; i++) {
410
entries[i].gsi = i;
411
entries[i].type = KVM_IRQ_ROUTING_IRQCHIP;
412
entries[i].u.irqchip.irqchip = 0;
413
entries[i].u.irqchip.pin = i;
414
}
415
ret = kvm_set_irq_routing(kvm, entries, nr, 0);
416
kfree(entries);
417
418
return ret;
419
}
420
421
static int kvm_pch_pic_create(struct kvm_device *dev, u32 type)
422
{
423
int i, ret, irq_num;
424
struct kvm *kvm = dev->kvm;
425
struct loongarch_pch_pic *s;
426
427
/* pch pic should not has been created */
428
if (kvm->arch.pch_pic)
429
return -EINVAL;
430
431
ret = kvm_setup_default_irq_routing(kvm);
432
if (ret)
433
return -ENOMEM;
434
435
s = kzalloc(sizeof(struct loongarch_pch_pic), GFP_KERNEL);
436
if (!s)
437
return -ENOMEM;
438
439
/*
440
* Interrupt controller identification register 1
441
* Bit 24-31 Interrupt Controller ID
442
* Interrupt controller identification register 2
443
* Bit 0-7 Interrupt Controller version number
444
* Bit 16-23 The number of interrupt sources supported
445
*/
446
irq_num = 32;
447
s->mask = -1UL;
448
s->id.desc.id = PCH_PIC_INT_ID_VAL;
449
s->id.desc.version = PCH_PIC_INT_ID_VER;
450
s->id.desc.irq_num = irq_num - 1;
451
for (i = 0; i < irq_num; i++) {
452
s->route_entry[i] = 1;
453
s->htmsi_vector[i] = i;
454
}
455
spin_lock_init(&s->lock);
456
s->kvm = kvm;
457
kvm->arch.pch_pic = s;
458
459
return 0;
460
}
461
462
static void kvm_pch_pic_destroy(struct kvm_device *dev)
463
{
464
struct kvm *kvm;
465
struct loongarch_pch_pic *s;
466
467
if (!dev || !dev->kvm || !dev->kvm->arch.pch_pic)
468
return;
469
470
kvm = dev->kvm;
471
s = kvm->arch.pch_pic;
472
/* unregister pch pic device and free it's memory */
473
kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS, &s->device);
474
kfree(s);
475
kfree(dev);
476
}
477
478
static struct kvm_device_ops kvm_pch_pic_dev_ops = {
479
.name = "kvm-loongarch-pch-pic",
480
.create = kvm_pch_pic_create,
481
.destroy = kvm_pch_pic_destroy,
482
.set_attr = kvm_pch_pic_set_attr,
483
.get_attr = kvm_pch_pic_get_attr,
484
};
485
486
int kvm_loongarch_register_pch_pic_device(void)
487
{
488
return kvm_register_device_ops(&kvm_pch_pic_dev_ops, KVM_DEV_TYPE_LOONGARCH_PCHPIC);
489
}
490
491