xref: /qemu/hw/intc/loongarch_extioi.c (revision 9b4b4e510bcb8b1c3c4789615dce3b520aa1f1d3)
1cbff2db1SXiaojuan Yang /* SPDX-License-Identifier: GPL-2.0-or-later */
2cbff2db1SXiaojuan Yang /*
3cbff2db1SXiaojuan Yang  * Loongson 3A5000 ext interrupt controller emulation
4cbff2db1SXiaojuan Yang  *
5cbff2db1SXiaojuan Yang  * Copyright (C) 2021 Loongson Technology Corporation Limited
6cbff2db1SXiaojuan Yang  */
7cbff2db1SXiaojuan Yang 
8cbff2db1SXiaojuan Yang #include "qemu/osdep.h"
9cbff2db1SXiaojuan Yang #include "qemu/module.h"
10cbff2db1SXiaojuan Yang #include "qemu/log.h"
11cbff2db1SXiaojuan Yang #include "hw/irq.h"
12cbff2db1SXiaojuan Yang #include "hw/sysbus.h"
13cbff2db1SXiaojuan Yang #include "hw/loongarch/virt.h"
14cbff2db1SXiaojuan Yang #include "hw/qdev-properties.h"
15cbff2db1SXiaojuan Yang #include "exec/address-spaces.h"
16cbff2db1SXiaojuan Yang #include "hw/intc/loongarch_extioi.h"
17cbff2db1SXiaojuan Yang #include "migration/vmstate.h"
18cbff2db1SXiaojuan Yang #include "trace.h"
19cbff2db1SXiaojuan Yang 
20cbff2db1SXiaojuan Yang 
21cbff2db1SXiaojuan Yang static void extioi_update_irq(LoongArchExtIOI *s, int irq, int level)
22cbff2db1SXiaojuan Yang {
23cbff2db1SXiaojuan Yang     int ipnum, cpu, found, irq_index, irq_mask;
24cbff2db1SXiaojuan Yang 
25cbff2db1SXiaojuan Yang     ipnum = s->sw_ipmap[irq / 32];
26cbff2db1SXiaojuan Yang     cpu = s->sw_coremap[irq];
27cbff2db1SXiaojuan Yang     irq_index = irq / 32;
28cbff2db1SXiaojuan Yang     irq_mask = 1 << (irq & 0x1f);
29cbff2db1SXiaojuan Yang 
30cbff2db1SXiaojuan Yang     if (level) {
31cbff2db1SXiaojuan Yang         /* if not enable return false */
32cbff2db1SXiaojuan Yang         if (((s->enable[irq_index]) & irq_mask) == 0) {
33cbff2db1SXiaojuan Yang             return;
34cbff2db1SXiaojuan Yang         }
35cbff2db1SXiaojuan Yang         s->coreisr[cpu][irq_index] |= irq_mask;
36cbff2db1SXiaojuan Yang         found = find_first_bit(s->sw_isr[cpu][ipnum], EXTIOI_IRQS);
37cbff2db1SXiaojuan Yang         set_bit(irq, s->sw_isr[cpu][ipnum]);
38cbff2db1SXiaojuan Yang         if (found < EXTIOI_IRQS) {
39cbff2db1SXiaojuan Yang             /* other irq is handling, need not update parent irq level */
40cbff2db1SXiaojuan Yang             return;
41cbff2db1SXiaojuan Yang         }
42cbff2db1SXiaojuan Yang     } else {
43cbff2db1SXiaojuan Yang         s->coreisr[cpu][irq_index] &= ~irq_mask;
44cbff2db1SXiaojuan Yang         clear_bit(irq, s->sw_isr[cpu][ipnum]);
45cbff2db1SXiaojuan Yang         found = find_first_bit(s->sw_isr[cpu][ipnum], EXTIOI_IRQS);
46cbff2db1SXiaojuan Yang         if (found < EXTIOI_IRQS) {
47cbff2db1SXiaojuan Yang             /* other irq is handling, need not update parent irq level */
48cbff2db1SXiaojuan Yang             return;
49cbff2db1SXiaojuan Yang         }
50cbff2db1SXiaojuan Yang     }
51cbff2db1SXiaojuan Yang     qemu_set_irq(s->parent_irq[cpu][ipnum], level);
52cbff2db1SXiaojuan Yang }
53cbff2db1SXiaojuan Yang 
54cbff2db1SXiaojuan Yang static void extioi_setirq(void *opaque, int irq, int level)
55cbff2db1SXiaojuan Yang {
56cbff2db1SXiaojuan Yang     LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque);
57cbff2db1SXiaojuan Yang     trace_loongarch_extioi_setirq(irq, level);
58cbff2db1SXiaojuan Yang     if (level) {
59cbff2db1SXiaojuan Yang         /*
60cbff2db1SXiaojuan Yang          * s->isr should be used in vmstate structure,
61cbff2db1SXiaojuan Yang          * but it not support 'unsigned long',
62cbff2db1SXiaojuan Yang          * so we have to switch it.
63cbff2db1SXiaojuan Yang          */
64cbff2db1SXiaojuan Yang         set_bit(irq, (unsigned long *)s->isr);
65cbff2db1SXiaojuan Yang     } else {
66cbff2db1SXiaojuan Yang         clear_bit(irq, (unsigned long *)s->isr);
67cbff2db1SXiaojuan Yang     }
68cbff2db1SXiaojuan Yang     extioi_update_irq(s, irq, level);
69cbff2db1SXiaojuan Yang }
70cbff2db1SXiaojuan Yang 
713fc8f74bSXiaojuan Yang static MemTxResult extioi_readw(void *opaque, hwaddr addr, uint64_t *data,
723fc8f74bSXiaojuan Yang                                 unsigned size, MemTxAttrs attrs)
73cbff2db1SXiaojuan Yang {
74cbff2db1SXiaojuan Yang     LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque);
75cbff2db1SXiaojuan Yang     unsigned long offset = addr & 0xffff;
763fc8f74bSXiaojuan Yang     uint32_t index, cpu;
77cbff2db1SXiaojuan Yang 
78cbff2db1SXiaojuan Yang     switch (offset) {
79cbff2db1SXiaojuan Yang     case EXTIOI_NODETYPE_START ... EXTIOI_NODETYPE_END - 1:
80cbff2db1SXiaojuan Yang         index = (offset - EXTIOI_NODETYPE_START) >> 2;
813fc8f74bSXiaojuan Yang         *data = s->nodetype[index];
82cbff2db1SXiaojuan Yang         break;
83cbff2db1SXiaojuan Yang     case EXTIOI_IPMAP_START ... EXTIOI_IPMAP_END - 1:
84cbff2db1SXiaojuan Yang         index = (offset - EXTIOI_IPMAP_START) >> 2;
853fc8f74bSXiaojuan Yang         *data = s->ipmap[index];
86cbff2db1SXiaojuan Yang         break;
87cbff2db1SXiaojuan Yang     case EXTIOI_ENABLE_START ... EXTIOI_ENABLE_END - 1:
88cbff2db1SXiaojuan Yang         index = (offset - EXTIOI_ENABLE_START) >> 2;
893fc8f74bSXiaojuan Yang         *data = s->enable[index];
90cbff2db1SXiaojuan Yang         break;
91cbff2db1SXiaojuan Yang     case EXTIOI_BOUNCE_START ... EXTIOI_BOUNCE_END - 1:
92cbff2db1SXiaojuan Yang         index = (offset - EXTIOI_BOUNCE_START) >> 2;
933fc8f74bSXiaojuan Yang         *data = s->bounce[index];
94cbff2db1SXiaojuan Yang         break;
95cbff2db1SXiaojuan Yang     case EXTIOI_COREISR_START ... EXTIOI_COREISR_END - 1:
96a649fffcSXiaojuan Yang         index = (offset - EXTIOI_COREISR_START) >> 2;
97a649fffcSXiaojuan Yang         /* using attrs to get current cpu index */
98a649fffcSXiaojuan Yang         cpu = attrs.requester_id;
993fc8f74bSXiaojuan Yang         *data = s->coreisr[cpu][index];
100cbff2db1SXiaojuan Yang         break;
101cbff2db1SXiaojuan Yang     case EXTIOI_COREMAP_START ... EXTIOI_COREMAP_END - 1:
102cbff2db1SXiaojuan Yang         index = (offset - EXTIOI_COREMAP_START) >> 2;
1033fc8f74bSXiaojuan Yang         *data = s->coremap[index];
104cbff2db1SXiaojuan Yang         break;
105cbff2db1SXiaojuan Yang     default:
106cbff2db1SXiaojuan Yang         break;
107cbff2db1SXiaojuan Yang     }
108cbff2db1SXiaojuan Yang 
1093fc8f74bSXiaojuan Yang     trace_loongarch_extioi_readw(addr, *data);
1103fc8f74bSXiaojuan Yang     return MEMTX_OK;
111cbff2db1SXiaojuan Yang }
112cbff2db1SXiaojuan Yang 
113cbff2db1SXiaojuan Yang static inline void extioi_enable_irq(LoongArchExtIOI *s, int index,\
114cbff2db1SXiaojuan Yang                                      uint32_t mask, int level)
115cbff2db1SXiaojuan Yang {
116cbff2db1SXiaojuan Yang     uint32_t val;
117cbff2db1SXiaojuan Yang     int irq;
118cbff2db1SXiaojuan Yang 
119cbff2db1SXiaojuan Yang     val = mask & s->isr[index];
120cbff2db1SXiaojuan Yang     irq = ctz32(val);
121cbff2db1SXiaojuan Yang     while (irq != 32) {
122cbff2db1SXiaojuan Yang         /*
123cbff2db1SXiaojuan Yang          * enable bit change from 0 to 1,
124cbff2db1SXiaojuan Yang          * need to update irq by pending bits
125cbff2db1SXiaojuan Yang          */
126cbff2db1SXiaojuan Yang         extioi_update_irq(s, irq + index * 32, level);
127cbff2db1SXiaojuan Yang         val &= ~(1 << irq);
128cbff2db1SXiaojuan Yang         irq = ctz32(val);
129cbff2db1SXiaojuan Yang     }
130cbff2db1SXiaojuan Yang }
131cbff2db1SXiaojuan Yang 
1323fc8f74bSXiaojuan Yang static MemTxResult extioi_writew(void *opaque, hwaddr addr,
1333fc8f74bSXiaojuan Yang                           uint64_t val, unsigned size,
1343fc8f74bSXiaojuan Yang                           MemTxAttrs attrs)
135cbff2db1SXiaojuan Yang {
136cbff2db1SXiaojuan Yang     LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque);
137cbff2db1SXiaojuan Yang     int i, cpu, index, old_data, irq;
138cbff2db1SXiaojuan Yang     uint32_t offset;
139cbff2db1SXiaojuan Yang 
140cbff2db1SXiaojuan Yang     trace_loongarch_extioi_writew(addr, val);
141cbff2db1SXiaojuan Yang     offset = addr & 0xffff;
142cbff2db1SXiaojuan Yang 
143cbff2db1SXiaojuan Yang     switch (offset) {
144cbff2db1SXiaojuan Yang     case EXTIOI_NODETYPE_START ... EXTIOI_NODETYPE_END - 1:
145cbff2db1SXiaojuan Yang         index = (offset - EXTIOI_NODETYPE_START) >> 2;
146cbff2db1SXiaojuan Yang         s->nodetype[index] = val;
147cbff2db1SXiaojuan Yang         break;
148cbff2db1SXiaojuan Yang     case EXTIOI_IPMAP_START ... EXTIOI_IPMAP_END - 1:
149cbff2db1SXiaojuan Yang         /*
150cbff2db1SXiaojuan Yang          * ipmap cannot be set at runtime, can be set only at the beginning
151cbff2db1SXiaojuan Yang          * of intr driver, need not update upper irq level
152cbff2db1SXiaojuan Yang          */
153cbff2db1SXiaojuan Yang         index = (offset - EXTIOI_IPMAP_START) >> 2;
154cbff2db1SXiaojuan Yang         s->ipmap[index] = val;
155cbff2db1SXiaojuan Yang         /*
156cbff2db1SXiaojuan Yang          * loongarch only support little endian,
157cbff2db1SXiaojuan Yang          * so we paresd the value with little endian.
158cbff2db1SXiaojuan Yang          */
159cbff2db1SXiaojuan Yang         val = cpu_to_le64(val);
160cbff2db1SXiaojuan Yang         for (i = 0; i < 4; i++) {
161cbff2db1SXiaojuan Yang             uint8_t ipnum;
162cbff2db1SXiaojuan Yang             ipnum = val & 0xff;
163cbff2db1SXiaojuan Yang             ipnum = ctz32(ipnum);
164cbff2db1SXiaojuan Yang             ipnum = (ipnum >= 4) ? 0 : ipnum;
165cbff2db1SXiaojuan Yang             s->sw_ipmap[index * 4 + i] = ipnum;
166cbff2db1SXiaojuan Yang             val = val >> 8;
167cbff2db1SXiaojuan Yang         }
168cbff2db1SXiaojuan Yang 
169cbff2db1SXiaojuan Yang         break;
170cbff2db1SXiaojuan Yang     case EXTIOI_ENABLE_START ... EXTIOI_ENABLE_END - 1:
171cbff2db1SXiaojuan Yang         index = (offset - EXTIOI_ENABLE_START) >> 2;
172cbff2db1SXiaojuan Yang         old_data = s->enable[index];
173cbff2db1SXiaojuan Yang         s->enable[index] = val;
174cbff2db1SXiaojuan Yang 
175cbff2db1SXiaojuan Yang         /* unmask irq */
176cbff2db1SXiaojuan Yang         val = s->enable[index] & ~old_data;
177cbff2db1SXiaojuan Yang         extioi_enable_irq(s, index, val, 1);
178cbff2db1SXiaojuan Yang 
179cbff2db1SXiaojuan Yang         /* mask irq */
180cbff2db1SXiaojuan Yang         val = ~s->enable[index] & old_data;
181cbff2db1SXiaojuan Yang         extioi_enable_irq(s, index, val, 0);
182cbff2db1SXiaojuan Yang         break;
183cbff2db1SXiaojuan Yang     case EXTIOI_BOUNCE_START ... EXTIOI_BOUNCE_END - 1:
184cbff2db1SXiaojuan Yang         /* do not emulate hw bounced irq routing */
185cbff2db1SXiaojuan Yang         index = (offset - EXTIOI_BOUNCE_START) >> 2;
186cbff2db1SXiaojuan Yang         s->bounce[index] = val;
187cbff2db1SXiaojuan Yang         break;
188cbff2db1SXiaojuan Yang     case EXTIOI_COREISR_START ... EXTIOI_COREISR_END - 1:
189a649fffcSXiaojuan Yang         index = (offset - EXTIOI_COREISR_START) >> 2;
190a649fffcSXiaojuan Yang         /* using attrs to get current cpu index */
191a649fffcSXiaojuan Yang         cpu = attrs.requester_id;
192cbff2db1SXiaojuan Yang         old_data = s->coreisr[cpu][index];
193cbff2db1SXiaojuan Yang         s->coreisr[cpu][index] = old_data & ~val;
194*9b4b4e51SMichael Tokarev         /* write 1 to clear interrupt */
195cbff2db1SXiaojuan Yang         old_data &= val;
196cbff2db1SXiaojuan Yang         irq = ctz32(old_data);
197cbff2db1SXiaojuan Yang         while (irq != 32) {
198cbff2db1SXiaojuan Yang             extioi_update_irq(s, irq + index * 32, 0);
199cbff2db1SXiaojuan Yang             old_data &= ~(1 << irq);
200cbff2db1SXiaojuan Yang             irq = ctz32(old_data);
201cbff2db1SXiaojuan Yang         }
202cbff2db1SXiaojuan Yang         break;
203cbff2db1SXiaojuan Yang     case EXTIOI_COREMAP_START ... EXTIOI_COREMAP_END - 1:
204cbff2db1SXiaojuan Yang         irq = offset - EXTIOI_COREMAP_START;
205cbff2db1SXiaojuan Yang         index = irq / 4;
206cbff2db1SXiaojuan Yang         s->coremap[index] = val;
207cbff2db1SXiaojuan Yang         /*
208cbff2db1SXiaojuan Yang          * loongarch only support little endian,
209cbff2db1SXiaojuan Yang          * so we paresd the value with little endian.
210cbff2db1SXiaojuan Yang          */
211cbff2db1SXiaojuan Yang         val = cpu_to_le64(val);
212cbff2db1SXiaojuan Yang 
213cbff2db1SXiaojuan Yang         for (i = 0; i < 4; i++) {
214cbff2db1SXiaojuan Yang             cpu = val & 0xff;
215cbff2db1SXiaojuan Yang             cpu = ctz32(cpu);
216cbff2db1SXiaojuan Yang             cpu = (cpu >= 4) ? 0 : cpu;
217cbff2db1SXiaojuan Yang             val = val >> 8;
218cbff2db1SXiaojuan Yang 
219cbff2db1SXiaojuan Yang             if (s->sw_coremap[irq + i] == cpu) {
220cbff2db1SXiaojuan Yang                 continue;
221cbff2db1SXiaojuan Yang             }
222cbff2db1SXiaojuan Yang 
223cbff2db1SXiaojuan Yang             if (test_bit(irq, (unsigned long *)s->isr)) {
224cbff2db1SXiaojuan Yang                 /*
225cbff2db1SXiaojuan Yang                  * lower irq at old cpu and raise irq at new cpu
226cbff2db1SXiaojuan Yang                  */
227cbff2db1SXiaojuan Yang                 extioi_update_irq(s, irq + i, 0);
228cbff2db1SXiaojuan Yang                 s->sw_coremap[irq + i] = cpu;
229cbff2db1SXiaojuan Yang                 extioi_update_irq(s, irq + i, 1);
230cbff2db1SXiaojuan Yang             } else {
231cbff2db1SXiaojuan Yang                 s->sw_coremap[irq + i] = cpu;
232cbff2db1SXiaojuan Yang             }
233cbff2db1SXiaojuan Yang         }
234cbff2db1SXiaojuan Yang         break;
235cbff2db1SXiaojuan Yang     default:
236cbff2db1SXiaojuan Yang         break;
237cbff2db1SXiaojuan Yang     }
2383fc8f74bSXiaojuan Yang     return MEMTX_OK;
239cbff2db1SXiaojuan Yang }
240cbff2db1SXiaojuan Yang 
241cbff2db1SXiaojuan Yang static const MemoryRegionOps extioi_ops = {
2423fc8f74bSXiaojuan Yang     .read_with_attrs = extioi_readw,
2433fc8f74bSXiaojuan Yang     .write_with_attrs = extioi_writew,
244cbff2db1SXiaojuan Yang     .impl.min_access_size = 4,
245cbff2db1SXiaojuan Yang     .impl.max_access_size = 4,
246cbff2db1SXiaojuan Yang     .valid.min_access_size = 4,
247cbff2db1SXiaojuan Yang     .valid.max_access_size = 8,
248cbff2db1SXiaojuan Yang     .endianness = DEVICE_LITTLE_ENDIAN,
249cbff2db1SXiaojuan Yang };
250cbff2db1SXiaojuan Yang 
251cbff2db1SXiaojuan Yang static const VMStateDescription vmstate_loongarch_extioi = {
252cbff2db1SXiaojuan Yang     .name = TYPE_LOONGARCH_EXTIOI,
253cbff2db1SXiaojuan Yang     .version_id = 1,
254cbff2db1SXiaojuan Yang     .minimum_version_id = 1,
255cbff2db1SXiaojuan Yang     .fields = (VMStateField[]) {
256cbff2db1SXiaojuan Yang         VMSTATE_UINT32_ARRAY(bounce, LoongArchExtIOI, EXTIOI_IRQS_GROUP_COUNT),
257646c39b2SSong Gao         VMSTATE_UINT32_2DARRAY(coreisr, LoongArchExtIOI, EXTIOI_CPUS,
258cbff2db1SXiaojuan Yang                                EXTIOI_IRQS_GROUP_COUNT),
259cbff2db1SXiaojuan Yang         VMSTATE_UINT32_ARRAY(nodetype, LoongArchExtIOI,
260cbff2db1SXiaojuan Yang                              EXTIOI_IRQS_NODETYPE_COUNT / 2),
261cbff2db1SXiaojuan Yang         VMSTATE_UINT32_ARRAY(enable, LoongArchExtIOI, EXTIOI_IRQS / 32),
262cbff2db1SXiaojuan Yang         VMSTATE_UINT32_ARRAY(isr, LoongArchExtIOI, EXTIOI_IRQS / 32),
263cbff2db1SXiaojuan Yang         VMSTATE_UINT32_ARRAY(ipmap, LoongArchExtIOI, EXTIOI_IRQS_IPMAP_SIZE / 4),
264cbff2db1SXiaojuan Yang         VMSTATE_UINT32_ARRAY(coremap, LoongArchExtIOI, EXTIOI_IRQS / 4),
265cbff2db1SXiaojuan Yang         VMSTATE_UINT8_ARRAY(sw_ipmap, LoongArchExtIOI, EXTIOI_IRQS_IPMAP_SIZE),
266cbff2db1SXiaojuan Yang         VMSTATE_UINT8_ARRAY(sw_coremap, LoongArchExtIOI, EXTIOI_IRQS),
267cbff2db1SXiaojuan Yang 
268cbff2db1SXiaojuan Yang         VMSTATE_END_OF_LIST()
269cbff2db1SXiaojuan Yang     }
270cbff2db1SXiaojuan Yang };
271cbff2db1SXiaojuan Yang 
272cbff2db1SXiaojuan Yang static void loongarch_extioi_instance_init(Object *obj)
273cbff2db1SXiaojuan Yang {
274cbff2db1SXiaojuan Yang     SysBusDevice *dev = SYS_BUS_DEVICE(obj);
275cbff2db1SXiaojuan Yang     LoongArchExtIOI *s = LOONGARCH_EXTIOI(obj);
276cbff2db1SXiaojuan Yang     int i, cpu, pin;
277cbff2db1SXiaojuan Yang 
278cbff2db1SXiaojuan Yang     for (i = 0; i < EXTIOI_IRQS; i++) {
2797d5b0d68SPhilippe Mathieu-Daudé         sysbus_init_irq(dev, &s->irq[i]);
280cbff2db1SXiaojuan Yang     }
281cbff2db1SXiaojuan Yang 
282cbff2db1SXiaojuan Yang     qdev_init_gpio_in(DEVICE(obj), extioi_setirq, EXTIOI_IRQS);
283cbff2db1SXiaojuan Yang 
284646c39b2SSong Gao     for (cpu = 0; cpu < EXTIOI_CPUS; cpu++) {
285cbff2db1SXiaojuan Yang         memory_region_init_io(&s->extioi_iocsr_mem[cpu], OBJECT(s), &extioi_ops,
286cbff2db1SXiaojuan Yang                               s, "extioi_iocsr", 0x900);
2877d5b0d68SPhilippe Mathieu-Daudé         sysbus_init_mmio(dev, &s->extioi_iocsr_mem[cpu]);
288cbff2db1SXiaojuan Yang         for (pin = 0; pin < LS3A_INTC_IP; pin++) {
289cbff2db1SXiaojuan Yang             qdev_init_gpio_out(DEVICE(obj), &s->parent_irq[cpu][pin], 1);
290cbff2db1SXiaojuan Yang         }
291cbff2db1SXiaojuan Yang     }
292cbff2db1SXiaojuan Yang     memory_region_init_io(&s->extioi_system_mem, OBJECT(s), &extioi_ops,
293cbff2db1SXiaojuan Yang                           s, "extioi_system_mem", 0x900);
2947d5b0d68SPhilippe Mathieu-Daudé     sysbus_init_mmio(dev, &s->extioi_system_mem);
295cbff2db1SXiaojuan Yang }
296cbff2db1SXiaojuan Yang 
297cbff2db1SXiaojuan Yang static void loongarch_extioi_class_init(ObjectClass *klass, void *data)
298cbff2db1SXiaojuan Yang {
299cbff2db1SXiaojuan Yang     DeviceClass *dc = DEVICE_CLASS(klass);
300cbff2db1SXiaojuan Yang 
301cbff2db1SXiaojuan Yang     dc->vmsd = &vmstate_loongarch_extioi;
302cbff2db1SXiaojuan Yang }
303cbff2db1SXiaojuan Yang 
304cbff2db1SXiaojuan Yang static const TypeInfo loongarch_extioi_info = {
305cbff2db1SXiaojuan Yang     .name          = TYPE_LOONGARCH_EXTIOI,
306cbff2db1SXiaojuan Yang     .parent        = TYPE_SYS_BUS_DEVICE,
307cbff2db1SXiaojuan Yang     .instance_init = loongarch_extioi_instance_init,
308cbff2db1SXiaojuan Yang     .instance_size = sizeof(struct LoongArchExtIOI),
309cbff2db1SXiaojuan Yang     .class_init    = loongarch_extioi_class_init,
310cbff2db1SXiaojuan Yang };
311cbff2db1SXiaojuan Yang 
312cbff2db1SXiaojuan Yang static void loongarch_extioi_register_types(void)
313cbff2db1SXiaojuan Yang {
314cbff2db1SXiaojuan Yang     type_register_static(&loongarch_extioi_info);
315cbff2db1SXiaojuan Yang }
316cbff2db1SXiaojuan Yang 
317cbff2db1SXiaojuan Yang type_init(loongarch_extioi_register_types)
318