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