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
eiointc_set_sw_coreisr(struct loongarch_eiointc * s)10 static void eiointc_set_sw_coreisr(struct loongarch_eiointc *s)
11 {
12 int ipnum, cpu, cpuid, irq;
13 struct kvm_vcpu *vcpu;
14
15 for (irq = 0; irq < EIOINTC_IRQS; irq++) {
16 ipnum = (s->ipmap >> (irq / 32 * 8)) & 0xff;
17 if (!(s->status & BIT(EIOINTC_ENABLE_INT_ENCODE))) {
18 ipnum = count_trailing_zeros(ipnum);
19 ipnum = ipnum < 4 ? ipnum : 0;
20 } else
21 ipnum = ipnum < LOONGSON_IP_NUM ? ipnum : 0;
22
23 cpuid = ((u8 *)s->coremap)[irq];
24 vcpu = kvm_get_vcpu_by_cpuid(s->kvm, cpuid);
25 if (!vcpu)
26 continue;
27
28 cpu = vcpu->vcpu_id;
29 if (test_bit(irq, (unsigned long *)s->coreisr[cpu]))
30 __set_bit(irq, s->sw_coreisr[cpu][ipnum]);
31 else
32 __clear_bit(irq, s->sw_coreisr[cpu][ipnum]);
33 }
34 }
35
eiointc_update_irq(struct loongarch_eiointc * s,int irq,int level)36 static void eiointc_update_irq(struct loongarch_eiointc *s, int irq, int level)
37 {
38 int ipnum, cpu, found;
39 struct kvm_vcpu *vcpu;
40
41 ipnum = (s->ipmap >> (irq / 32 * 8)) & 0xff;
42 if (!(s->status & BIT(EIOINTC_ENABLE_INT_ENCODE))) {
43 ipnum = count_trailing_zeros(ipnum);
44 ipnum = ipnum < 4 ? ipnum : 0;
45 } else
46 ipnum = ipnum < LOONGSON_IP_NUM ? ipnum : 0;
47
48 cpu = s->sw_coremap[irq];
49 vcpu = kvm_get_vcpu_by_id(s->kvm, cpu);
50 if (unlikely(vcpu == NULL)) {
51 kvm_pr_unimpl("%s: invalid target cpu: %d\n", __func__, cpu);
52 return;
53 }
54
55 if (level) {
56 /* if not enable return false */
57 if (!test_bit(irq, (unsigned long *)s->enable))
58 return;
59 __set_bit(irq, (unsigned long *)s->coreisr[cpu]);
60 found = find_first_bit(s->sw_coreisr[cpu][ipnum], EIOINTC_IRQS);
61 __set_bit(irq, s->sw_coreisr[cpu][ipnum]);
62 } else {
63 __clear_bit(irq, (unsigned long *)s->coreisr[cpu]);
64 __clear_bit(irq, s->sw_coreisr[cpu][ipnum]);
65 found = find_first_bit(s->sw_coreisr[cpu][ipnum], EIOINTC_IRQS);
66 }
67
68 if (found < EIOINTC_IRQS)
69 return; /* other irq is handling, needn't update parent irq */
70
71 if (level)
72 kvm_queue_irq(vcpu, INT_HWI0 + ipnum);
73 else
74 kvm_dequeue_irq(vcpu, INT_HWI0 + ipnum);
75 kvm_vcpu_kick(vcpu);
76 }
77
eiointc_update_sw_coremap(struct loongarch_eiointc * s,int irq,u64 val,u32 len,bool notify)78 static inline void eiointc_update_sw_coremap(struct loongarch_eiointc *s,
79 int irq, u64 val, u32 len, bool notify)
80 {
81 int i, cpu, cpuid;
82 struct kvm_vcpu *vcpu;
83
84 for (i = 0; i < len; i++) {
85 cpuid = val & 0xff;
86 val = val >> 8;
87
88 if (!(s->status & BIT(EIOINTC_ENABLE_CPU_ENCODE))) {
89 cpuid = ffs(cpuid) - 1;
90 cpuid = ((cpuid < 0) || (cpuid >= 4)) ? 0 : cpuid;
91 }
92
93 vcpu = kvm_get_vcpu_by_cpuid(s->kvm, cpuid);
94 if (!vcpu)
95 continue;
96
97 cpu = vcpu->vcpu_id;
98 if (s->sw_coremap[irq + i] == cpu)
99 continue;
100
101 if (notify && test_bit(irq + i, (unsigned long *)s->isr)) {
102 /* lower irq at old cpu and raise irq at new cpu */
103 eiointc_update_irq(s, irq + i, 0);
104 s->sw_coremap[irq + i] = cpu;
105 eiointc_update_irq(s, irq + i, 1);
106 } else {
107 s->sw_coremap[irq + i] = cpu;
108 }
109 }
110 }
111
eiointc_set_irq(struct loongarch_eiointc * s,int irq,int level)112 void eiointc_set_irq(struct loongarch_eiointc *s, int irq, int level)
113 {
114 unsigned long flags;
115 unsigned long *isr = (unsigned long *)s->isr;
116
117 spin_lock_irqsave(&s->lock, flags);
118 level ? __set_bit(irq, isr) : __clear_bit(irq, isr);
119 eiointc_update_irq(s, irq, level);
120 spin_unlock_irqrestore(&s->lock, flags);
121 }
122
loongarch_eiointc_read(struct kvm_vcpu * vcpu,struct loongarch_eiointc * s,gpa_t addr,unsigned long * val)123 static int loongarch_eiointc_read(struct kvm_vcpu *vcpu, struct loongarch_eiointc *s,
124 gpa_t addr, unsigned long *val)
125 {
126 int index;
127 u64 data = 0;
128 gpa_t offset;
129
130 offset = addr - EIOINTC_BASE;
131 switch (offset) {
132 case EIOINTC_NODETYPE_START ... EIOINTC_NODETYPE_END:
133 index = (offset - EIOINTC_NODETYPE_START) >> 3;
134 data = s->nodetype[index];
135 break;
136 case EIOINTC_IPMAP_START ... EIOINTC_IPMAP_END:
137 index = (offset - EIOINTC_IPMAP_START) >> 3;
138 data = s->ipmap;
139 break;
140 case EIOINTC_ENABLE_START ... EIOINTC_ENABLE_END:
141 index = (offset - EIOINTC_ENABLE_START) >> 3;
142 data = s->enable[index];
143 break;
144 case EIOINTC_BOUNCE_START ... EIOINTC_BOUNCE_END:
145 index = (offset - EIOINTC_BOUNCE_START) >> 3;
146 data = s->bounce[index];
147 break;
148 case EIOINTC_COREISR_START ... EIOINTC_COREISR_END:
149 index = (offset - EIOINTC_COREISR_START) >> 3;
150 data = s->coreisr[vcpu->vcpu_id][index];
151 break;
152 case EIOINTC_COREMAP_START ... EIOINTC_COREMAP_END:
153 index = (offset - EIOINTC_COREMAP_START) >> 3;
154 data = s->coremap[index];
155 break;
156 default:
157 break;
158 }
159 *val = data;
160
161 return 0;
162 }
163
kvm_eiointc_read(struct kvm_vcpu * vcpu,struct kvm_io_device * dev,gpa_t addr,int len,void * val)164 static int kvm_eiointc_read(struct kvm_vcpu *vcpu,
165 struct kvm_io_device *dev,
166 gpa_t addr, int len, void *val)
167 {
168 unsigned long flags, data, offset;
169 struct loongarch_eiointc *eiointc = vcpu->kvm->arch.eiointc;
170
171 if (!eiointc) {
172 kvm_pr_unimpl("%s: eiointc irqchip not valid!\n", __func__);
173 return 0;
174 }
175
176 if (addr & (len - 1)) {
177 kvm_pr_unimpl("%s: eiointc not aligned addr %llx len %d\n", __func__, addr, len);
178 return 0;
179 }
180
181 offset = addr & 0x7;
182 addr -= offset;
183 vcpu->stat.eiointc_read_exits++;
184 spin_lock_irqsave(&eiointc->lock, flags);
185 loongarch_eiointc_read(vcpu, eiointc, addr, &data);
186 spin_unlock_irqrestore(&eiointc->lock, flags);
187
188 data = data >> (offset * 8);
189 switch (len) {
190 case 1:
191 *(long *)val = (s8)data;
192 break;
193 case 2:
194 *(long *)val = (s16)data;
195 break;
196 case 4:
197 *(long *)val = (s32)data;
198 break;
199 default:
200 *(long *)val = (long)data;
201 break;
202 }
203
204 return 0;
205 }
206
loongarch_eiointc_write(struct kvm_vcpu * vcpu,struct loongarch_eiointc * s,gpa_t addr,u64 value,u64 field_mask)207 static int loongarch_eiointc_write(struct kvm_vcpu *vcpu,
208 struct loongarch_eiointc *s,
209 gpa_t addr, u64 value, u64 field_mask)
210 {
211 int index, irq;
212 u8 cpu;
213 u64 data, old, mask;
214 gpa_t offset;
215
216 offset = addr & 7;
217 mask = field_mask << (offset * 8);
218 data = (value & field_mask) << (offset * 8);
219
220 addr -= offset;
221 offset = addr - EIOINTC_BASE;
222
223 switch (offset) {
224 case EIOINTC_NODETYPE_START ... EIOINTC_NODETYPE_END:
225 index = (offset - EIOINTC_NODETYPE_START) >> 3;
226 old = s->nodetype[index];
227 s->nodetype[index] = (old & ~mask) | data;
228 break;
229 case EIOINTC_IPMAP_START ... EIOINTC_IPMAP_END:
230 /*
231 * ipmap cannot be set at runtime, can be set only at the beginning
232 * of irqchip driver, need not update upper irq level
233 */
234 old = s->ipmap;
235 s->ipmap = (old & ~mask) | data;
236 break;
237 case EIOINTC_ENABLE_START ... EIOINTC_ENABLE_END:
238 index = (offset - EIOINTC_ENABLE_START) >> 3;
239 old = s->enable[index];
240 s->enable[index] = (old & ~mask) | data;
241 /*
242 * 1: enable irq.
243 * update irq when isr is set.
244 */
245 data = s->enable[index] & ~old & s->isr[index];
246 while (data) {
247 irq = __ffs(data);
248 eiointc_update_irq(s, irq + index * 64, 1);
249 data &= ~BIT_ULL(irq);
250 }
251 /*
252 * 0: disable irq.
253 * update irq when isr is set.
254 */
255 data = ~s->enable[index] & old & s->isr[index];
256 while (data) {
257 irq = __ffs(data);
258 eiointc_update_irq(s, irq + index * 64, 0);
259 data &= ~BIT_ULL(irq);
260 }
261 break;
262 case EIOINTC_BOUNCE_START ... EIOINTC_BOUNCE_END:
263 /* do not emulate hw bounced irq routing */
264 index = (offset - EIOINTC_BOUNCE_START) >> 3;
265 old = s->bounce[index];
266 s->bounce[index] = (old & ~mask) | data;
267 break;
268 case EIOINTC_COREISR_START ... EIOINTC_COREISR_END:
269 index = (offset - EIOINTC_COREISR_START) >> 3;
270 /* use attrs to get current cpu index */
271 cpu = vcpu->vcpu_id;
272 old = s->coreisr[cpu][index];
273 /* write 1 to clear interrupt */
274 s->coreisr[cpu][index] = old & ~data;
275 data &= old;
276 while (data) {
277 irq = __ffs(data);
278 eiointc_update_irq(s, irq + index * 64, 0);
279 data &= ~BIT_ULL(irq);
280 }
281 break;
282 case EIOINTC_COREMAP_START ... EIOINTC_COREMAP_END:
283 index = (offset - EIOINTC_COREMAP_START) >> 3;
284 old = s->coremap[index];
285 s->coremap[index] = (old & ~mask) | data;
286 data = s->coremap[index];
287 eiointc_update_sw_coremap(s, index * 8, data, sizeof(data), true);
288 break;
289 default:
290 break;
291 }
292
293 return 0;
294 }
295
kvm_eiointc_write(struct kvm_vcpu * vcpu,struct kvm_io_device * dev,gpa_t addr,int len,const void * val)296 static int kvm_eiointc_write(struct kvm_vcpu *vcpu,
297 struct kvm_io_device *dev,
298 gpa_t addr, int len, const void *val)
299 {
300 unsigned long flags, value;
301 struct loongarch_eiointc *eiointc = vcpu->kvm->arch.eiointc;
302
303 if (!eiointc) {
304 kvm_pr_unimpl("%s: eiointc irqchip not valid!\n", __func__);
305 return 0;
306 }
307
308 if (addr & (len - 1)) {
309 kvm_pr_unimpl("%s: eiointc not aligned addr %llx len %d\n", __func__, addr, len);
310 return 0;
311 }
312
313 vcpu->stat.eiointc_write_exits++;
314 spin_lock_irqsave(&eiointc->lock, flags);
315 switch (len) {
316 case 1:
317 value = *(unsigned char *)val;
318 loongarch_eiointc_write(vcpu, eiointc, addr, value, 0xFF);
319 break;
320 case 2:
321 value = *(unsigned short *)val;
322 loongarch_eiointc_write(vcpu, eiointc, addr, value, USHRT_MAX);
323 break;
324 case 4:
325 value = *(unsigned int *)val;
326 loongarch_eiointc_write(vcpu, eiointc, addr, value, UINT_MAX);
327 break;
328 default:
329 value = *(unsigned long *)val;
330 loongarch_eiointc_write(vcpu, eiointc, addr, value, ULONG_MAX);
331 break;
332 }
333 spin_unlock_irqrestore(&eiointc->lock, flags);
334
335 return 0;
336 }
337
338 static const struct kvm_io_device_ops kvm_eiointc_ops = {
339 .read = kvm_eiointc_read,
340 .write = kvm_eiointc_write,
341 };
342
kvm_eiointc_virt_read(struct kvm_vcpu * vcpu,struct kvm_io_device * dev,gpa_t addr,int len,void * val)343 static int kvm_eiointc_virt_read(struct kvm_vcpu *vcpu,
344 struct kvm_io_device *dev,
345 gpa_t addr, int len, void *val)
346 {
347 unsigned long flags;
348 u32 *data = val;
349 struct loongarch_eiointc *eiointc = vcpu->kvm->arch.eiointc;
350
351 if (!eiointc) {
352 kvm_pr_unimpl("%s: eiointc irqchip not valid!\n", __func__);
353 return 0;
354 }
355
356 addr -= EIOINTC_VIRT_BASE;
357 spin_lock_irqsave(&eiointc->lock, flags);
358 switch (addr) {
359 case EIOINTC_VIRT_FEATURES:
360 *data = eiointc->features;
361 break;
362 case EIOINTC_VIRT_CONFIG:
363 *data = eiointc->status;
364 break;
365 default:
366 break;
367 }
368 spin_unlock_irqrestore(&eiointc->lock, flags);
369
370 return 0;
371 }
372
kvm_eiointc_virt_write(struct kvm_vcpu * vcpu,struct kvm_io_device * dev,gpa_t addr,int len,const void * val)373 static int kvm_eiointc_virt_write(struct kvm_vcpu *vcpu,
374 struct kvm_io_device *dev,
375 gpa_t addr, int len, const void *val)
376 {
377 unsigned long flags;
378 u32 value = *(u32 *)val;
379 struct loongarch_eiointc *eiointc = vcpu->kvm->arch.eiointc;
380
381 if (!eiointc) {
382 kvm_pr_unimpl("%s: eiointc irqchip not valid!\n", __func__);
383 return 0;
384 }
385
386 addr -= EIOINTC_VIRT_BASE;
387 spin_lock_irqsave(&eiointc->lock, flags);
388 switch (addr) {
389 case EIOINTC_VIRT_FEATURES:
390 break;
391 case EIOINTC_VIRT_CONFIG:
392 /*
393 * eiointc features can only be set at disabled status
394 */
395 if ((eiointc->status & BIT(EIOINTC_ENABLE)) && value) {
396 break;
397 }
398 eiointc->status = value & eiointc->features;
399 break;
400 default:
401 break;
402 }
403 spin_unlock_irqrestore(&eiointc->lock, flags);
404
405 return 0;
406 }
407
408 static const struct kvm_io_device_ops kvm_eiointc_virt_ops = {
409 .read = kvm_eiointc_virt_read,
410 .write = kvm_eiointc_virt_write,
411 };
412
kvm_eiointc_ctrl_access(struct kvm_device * dev,struct kvm_device_attr * attr)413 static int kvm_eiointc_ctrl_access(struct kvm_device *dev,
414 struct kvm_device_attr *attr)
415 {
416 int ret = 0;
417 unsigned long flags;
418 unsigned long type = (unsigned long)attr->attr;
419 u32 i, start_irq, val;
420 void __user *data;
421 struct loongarch_eiointc *s = dev->kvm->arch.eiointc;
422
423 data = (void __user *)attr->addr;
424 switch (type) {
425 case KVM_DEV_LOONGARCH_EXTIOI_CTRL_INIT_NUM_CPU:
426 case KVM_DEV_LOONGARCH_EXTIOI_CTRL_INIT_FEATURE:
427 if (copy_from_user(&val, data, 4))
428 return -EFAULT;
429 break;
430 default:
431 break;
432 }
433
434 spin_lock_irqsave(&s->lock, flags);
435 switch (type) {
436 case KVM_DEV_LOONGARCH_EXTIOI_CTRL_INIT_NUM_CPU:
437 if (val > EIOINTC_ROUTE_MAX_VCPUS)
438 ret = -EINVAL;
439 else
440 s->num_cpu = val;
441 break;
442 case KVM_DEV_LOONGARCH_EXTIOI_CTRL_INIT_FEATURE:
443 s->features = val;
444 if (!(s->features & BIT(EIOINTC_HAS_VIRT_EXTENSION)))
445 s->status |= BIT(EIOINTC_ENABLE);
446 break;
447 case KVM_DEV_LOONGARCH_EXTIOI_CTRL_LOAD_FINISHED:
448 eiointc_set_sw_coreisr(s);
449 for (i = 0; i < (EIOINTC_IRQS / 8); i++) {
450 start_irq = i * 8;
451 eiointc_update_sw_coremap(s, start_irq,
452 s->coremap[i], sizeof(u64), false);
453 }
454 break;
455 default:
456 break;
457 }
458 spin_unlock_irqrestore(&s->lock, flags);
459
460 return ret;
461 }
462
kvm_eiointc_regs_access(struct kvm_device * dev,struct kvm_device_attr * attr,bool is_write,int * data)463 static int kvm_eiointc_regs_access(struct kvm_device *dev,
464 struct kvm_device_attr *attr,
465 bool is_write, int *data)
466 {
467 int addr, cpu, offset, ret = 0;
468 unsigned long flags;
469 void *p = NULL;
470 struct loongarch_eiointc *s;
471
472 s = dev->kvm->arch.eiointc;
473 addr = attr->attr;
474 cpu = addr >> 16;
475 addr &= 0xffff;
476 switch (addr) {
477 case EIOINTC_NODETYPE_START ... EIOINTC_NODETYPE_END:
478 offset = (addr - EIOINTC_NODETYPE_START) / 4;
479 p = (void *)s->nodetype + offset * 4;
480 break;
481 case EIOINTC_IPMAP_START ... EIOINTC_IPMAP_END:
482 offset = (addr - EIOINTC_IPMAP_START) / 4;
483 p = (void *)&s->ipmap + offset * 4;
484 break;
485 case EIOINTC_ENABLE_START ... EIOINTC_ENABLE_END:
486 offset = (addr - EIOINTC_ENABLE_START) / 4;
487 p = (void *)s->enable + offset * 4;
488 break;
489 case EIOINTC_BOUNCE_START ... EIOINTC_BOUNCE_END:
490 offset = (addr - EIOINTC_BOUNCE_START) / 4;
491 p = (void *)s->bounce + offset * 4;
492 break;
493 case EIOINTC_ISR_START ... EIOINTC_ISR_END:
494 offset = (addr - EIOINTC_ISR_START) / 4;
495 p = (void *)s->isr + offset * 4;
496 break;
497 case EIOINTC_COREISR_START ... EIOINTC_COREISR_END:
498 if (cpu >= s->num_cpu)
499 return -EINVAL;
500
501 offset = (addr - EIOINTC_COREISR_START) / 4;
502 p = (void *)s->coreisr[cpu] + offset * 4;
503 break;
504 case EIOINTC_COREMAP_START ... EIOINTC_COREMAP_END:
505 offset = (addr - EIOINTC_COREMAP_START) / 4;
506 p = (void *)s->coremap + offset * 4;
507 break;
508 default:
509 kvm_pr_unimpl("%s: unknown eiointc register, addr = %d\n", __func__, addr);
510 return -EINVAL;
511 }
512
513 spin_lock_irqsave(&s->lock, flags);
514 if (is_write)
515 memcpy(p, data, 4);
516 else
517 memcpy(data, p, 4);
518 spin_unlock_irqrestore(&s->lock, flags);
519
520 return ret;
521 }
522
kvm_eiointc_sw_status_access(struct kvm_device * dev,struct kvm_device_attr * attr,bool is_write,int * data)523 static int kvm_eiointc_sw_status_access(struct kvm_device *dev,
524 struct kvm_device_attr *attr,
525 bool is_write, int *data)
526 {
527 int addr, ret = 0;
528 unsigned long flags;
529 void *p = NULL;
530 struct loongarch_eiointc *s;
531
532 s = dev->kvm->arch.eiointc;
533 addr = attr->attr;
534 addr &= 0xffff;
535
536 switch (addr) {
537 case KVM_DEV_LOONGARCH_EXTIOI_SW_STATUS_NUM_CPU:
538 if (is_write)
539 return ret;
540
541 p = &s->num_cpu;
542 break;
543 case KVM_DEV_LOONGARCH_EXTIOI_SW_STATUS_FEATURE:
544 if (is_write)
545 return ret;
546
547 p = &s->features;
548 break;
549 case KVM_DEV_LOONGARCH_EXTIOI_SW_STATUS_STATE:
550 p = &s->status;
551 break;
552 default:
553 kvm_pr_unimpl("%s: unknown eiointc register, addr = %d\n", __func__, addr);
554 return -EINVAL;
555 }
556 spin_lock_irqsave(&s->lock, flags);
557 if (is_write)
558 memcpy(p, data, 4);
559 else
560 memcpy(data, p, 4);
561 spin_unlock_irqrestore(&s->lock, flags);
562
563 return ret;
564 }
565
kvm_eiointc_get_attr(struct kvm_device * dev,struct kvm_device_attr * attr)566 static int kvm_eiointc_get_attr(struct kvm_device *dev,
567 struct kvm_device_attr *attr)
568 {
569 int ret, data;
570
571 switch (attr->group) {
572 case KVM_DEV_LOONGARCH_EXTIOI_GRP_REGS:
573 ret = kvm_eiointc_regs_access(dev, attr, false, &data);
574 if (ret)
575 return ret;
576
577 if (copy_to_user((void __user *)attr->addr, &data, 4))
578 ret = -EFAULT;
579
580 return ret;
581 case KVM_DEV_LOONGARCH_EXTIOI_GRP_SW_STATUS:
582 ret = kvm_eiointc_sw_status_access(dev, attr, false, &data);
583 if (ret)
584 return ret;
585
586 if (copy_to_user((void __user *)attr->addr, &data, 4))
587 ret = -EFAULT;
588
589 return ret;
590 default:
591 return -EINVAL;
592 }
593 }
594
kvm_eiointc_set_attr(struct kvm_device * dev,struct kvm_device_attr * attr)595 static int kvm_eiointc_set_attr(struct kvm_device *dev,
596 struct kvm_device_attr *attr)
597 {
598 int data;
599
600 switch (attr->group) {
601 case KVM_DEV_LOONGARCH_EXTIOI_GRP_CTRL:
602 return kvm_eiointc_ctrl_access(dev, attr);
603 case KVM_DEV_LOONGARCH_EXTIOI_GRP_REGS:
604 if (copy_from_user(&data, (void __user *)attr->addr, 4))
605 return -EFAULT;
606
607 return kvm_eiointc_regs_access(dev, attr, true, &data);
608 case KVM_DEV_LOONGARCH_EXTIOI_GRP_SW_STATUS:
609 if (copy_from_user(&data, (void __user *)attr->addr, 4))
610 return -EFAULT;
611
612 return kvm_eiointc_sw_status_access(dev, attr, true, &data);
613 default:
614 return -EINVAL;
615 }
616 }
617
kvm_eiointc_create(struct kvm_device * dev,u32 type)618 static int kvm_eiointc_create(struct kvm_device *dev, u32 type)
619 {
620 int ret;
621 struct loongarch_eiointc *s;
622 struct kvm_io_device *device;
623 struct kvm *kvm = dev->kvm;
624
625 /* eiointc has been created */
626 if (kvm->arch.eiointc)
627 return -EINVAL;
628
629 s = kzalloc_obj(struct loongarch_eiointc);
630 if (!s)
631 return -ENOMEM;
632
633 spin_lock_init(&s->lock);
634 s->kvm = kvm;
635
636 /*
637 * Initialize IOCSR device
638 */
639 device = &s->device;
640 kvm_iodevice_init(device, &kvm_eiointc_ops);
641 mutex_lock(&kvm->slots_lock);
642 ret = kvm_io_bus_register_dev(kvm, KVM_IOCSR_BUS,
643 EIOINTC_BASE, EIOINTC_SIZE, device);
644 mutex_unlock(&kvm->slots_lock);
645 if (ret < 0) {
646 kfree(s);
647 return ret;
648 }
649
650 device = &s->device_vext;
651 kvm_iodevice_init(device, &kvm_eiointc_virt_ops);
652 mutex_lock(&kvm->slots_lock);
653 ret = kvm_io_bus_register_dev(kvm, KVM_IOCSR_BUS,
654 EIOINTC_VIRT_BASE, EIOINTC_VIRT_SIZE, device);
655 mutex_unlock(&kvm->slots_lock);
656 if (ret < 0) {
657 mutex_lock(&kvm->slots_lock);
658 kvm_io_bus_unregister_dev(kvm, KVM_IOCSR_BUS, &s->device);
659 mutex_unlock(&kvm->slots_lock);
660 kfree(s);
661 return ret;
662 }
663 kvm->arch.eiointc = s;
664
665 return 0;
666 }
667
kvm_eiointc_destroy(struct kvm_device * dev)668 static void kvm_eiointc_destroy(struct kvm_device *dev)
669 {
670 struct kvm *kvm;
671 struct loongarch_eiointc *eiointc;
672
673 if (!dev || !dev->kvm || !dev->kvm->arch.eiointc)
674 return;
675
676 kvm = dev->kvm;
677 eiointc = kvm->arch.eiointc;
678 mutex_lock(&kvm->slots_lock);
679 kvm_io_bus_unregister_dev(kvm, KVM_IOCSR_BUS, &eiointc->device);
680 kvm_io_bus_unregister_dev(kvm, KVM_IOCSR_BUS, &eiointc->device_vext);
681 mutex_unlock(&kvm->slots_lock);
682 kfree(eiointc);
683 kfree(dev);
684 }
685
686 static struct kvm_device_ops kvm_eiointc_dev_ops = {
687 .name = "kvm-loongarch-eiointc",
688 .create = kvm_eiointc_create,
689 .destroy = kvm_eiointc_destroy,
690 .set_attr = kvm_eiointc_set_attr,
691 .get_attr = kvm_eiointc_get_attr,
692 };
693
kvm_loongarch_register_eiointc_device(void)694 int kvm_loongarch_register_eiointc_device(void)
695 {
696 return kvm_register_device_ops(&kvm_eiointc_dev_ops, KVM_DEV_TYPE_LOONGARCH_EIOINTC);
697 }
698
kvm_loongarch_unregister_eiointc_device(void)699 void kvm_loongarch_unregister_eiointc_device(void)
700 {
701 kvm_unregister_device_ops(KVM_DEV_TYPE_LOONGARCH_EIOINTC);
702 }
703