xref: /qemu/hw/intc/loongarch_extioi.c (revision 3fc8f74b51858353356968b3d04a5cccdc547caa)
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 
71*3fc8f74bSXiaojuan Yang static MemTxResult extioi_readw(void *opaque, hwaddr addr, uint64_t *data,
72*3fc8f74bSXiaojuan Yang                                 unsigned size, MemTxAttrs attrs)
73cbff2db1SXiaojuan Yang {
74cbff2db1SXiaojuan Yang     LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque);
75cbff2db1SXiaojuan Yang     unsigned long offset = addr & 0xffff;
76*3fc8f74bSXiaojuan 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;
81*3fc8f74bSXiaojuan 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;
85*3fc8f74bSXiaojuan 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;
89*3fc8f74bSXiaojuan 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;
93*3fc8f74bSXiaojuan Yang         *data = s->bounce[index];
94cbff2db1SXiaojuan Yang         break;
95cbff2db1SXiaojuan Yang     case EXTIOI_COREISR_START ... EXTIOI_COREISR_END - 1:
96cbff2db1SXiaojuan Yang         index = ((offset - EXTIOI_COREISR_START) & 0x1f) >> 2;
97cbff2db1SXiaojuan Yang         cpu = ((offset - EXTIOI_COREISR_START) >> 8) & 0x3;
98*3fc8f74bSXiaojuan Yang         *data = s->coreisr[cpu][index];
99cbff2db1SXiaojuan Yang         break;
100cbff2db1SXiaojuan Yang     case EXTIOI_COREMAP_START ... EXTIOI_COREMAP_END - 1:
101cbff2db1SXiaojuan Yang         index = (offset - EXTIOI_COREMAP_START) >> 2;
102*3fc8f74bSXiaojuan Yang         *data = s->coremap[index];
103cbff2db1SXiaojuan Yang         break;
104cbff2db1SXiaojuan Yang     default:
105cbff2db1SXiaojuan Yang         break;
106cbff2db1SXiaojuan Yang     }
107cbff2db1SXiaojuan Yang 
108*3fc8f74bSXiaojuan Yang     trace_loongarch_extioi_readw(addr, *data);
109*3fc8f74bSXiaojuan Yang     return MEMTX_OK;
110cbff2db1SXiaojuan Yang }
111cbff2db1SXiaojuan Yang 
112cbff2db1SXiaojuan Yang static inline void extioi_enable_irq(LoongArchExtIOI *s, int index,\
113cbff2db1SXiaojuan Yang                                      uint32_t mask, int level)
114cbff2db1SXiaojuan Yang {
115cbff2db1SXiaojuan Yang     uint32_t val;
116cbff2db1SXiaojuan Yang     int irq;
117cbff2db1SXiaojuan Yang 
118cbff2db1SXiaojuan Yang     val = mask & s->isr[index];
119cbff2db1SXiaojuan Yang     irq = ctz32(val);
120cbff2db1SXiaojuan Yang     while (irq != 32) {
121cbff2db1SXiaojuan Yang         /*
122cbff2db1SXiaojuan Yang          * enable bit change from 0 to 1,
123cbff2db1SXiaojuan Yang          * need to update irq by pending bits
124cbff2db1SXiaojuan Yang          */
125cbff2db1SXiaojuan Yang         extioi_update_irq(s, irq + index * 32, level);
126cbff2db1SXiaojuan Yang         val &= ~(1 << irq);
127cbff2db1SXiaojuan Yang         irq = ctz32(val);
128cbff2db1SXiaojuan Yang     }
129cbff2db1SXiaojuan Yang }
130cbff2db1SXiaojuan Yang 
131*3fc8f74bSXiaojuan Yang static MemTxResult extioi_writew(void *opaque, hwaddr addr,
132*3fc8f74bSXiaojuan Yang                           uint64_t val, unsigned size,
133*3fc8f74bSXiaojuan Yang                           MemTxAttrs attrs)
134cbff2db1SXiaojuan Yang {
135cbff2db1SXiaojuan Yang     LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque);
136cbff2db1SXiaojuan Yang     int i, cpu, index, old_data, irq;
137cbff2db1SXiaojuan Yang     uint32_t offset;
138cbff2db1SXiaojuan Yang 
139cbff2db1SXiaojuan Yang     trace_loongarch_extioi_writew(addr, val);
140cbff2db1SXiaojuan Yang     offset = addr & 0xffff;
141cbff2db1SXiaojuan Yang 
142cbff2db1SXiaojuan Yang     switch (offset) {
143cbff2db1SXiaojuan Yang     case EXTIOI_NODETYPE_START ... EXTIOI_NODETYPE_END - 1:
144cbff2db1SXiaojuan Yang         index = (offset - EXTIOI_NODETYPE_START) >> 2;
145cbff2db1SXiaojuan Yang         s->nodetype[index] = val;
146cbff2db1SXiaojuan Yang         break;
147cbff2db1SXiaojuan Yang     case EXTIOI_IPMAP_START ... EXTIOI_IPMAP_END - 1:
148cbff2db1SXiaojuan Yang         /*
149cbff2db1SXiaojuan Yang          * ipmap cannot be set at runtime, can be set only at the beginning
150cbff2db1SXiaojuan Yang          * of intr driver, need not update upper irq level
151cbff2db1SXiaojuan Yang          */
152cbff2db1SXiaojuan Yang         index = (offset - EXTIOI_IPMAP_START) >> 2;
153cbff2db1SXiaojuan Yang         s->ipmap[index] = val;
154cbff2db1SXiaojuan Yang         /*
155cbff2db1SXiaojuan Yang          * loongarch only support little endian,
156cbff2db1SXiaojuan Yang          * so we paresd the value with little endian.
157cbff2db1SXiaojuan Yang          */
158cbff2db1SXiaojuan Yang         val = cpu_to_le64(val);
159cbff2db1SXiaojuan Yang         for (i = 0; i < 4; i++) {
160cbff2db1SXiaojuan Yang             uint8_t ipnum;
161cbff2db1SXiaojuan Yang             ipnum = val & 0xff;
162cbff2db1SXiaojuan Yang             ipnum = ctz32(ipnum);
163cbff2db1SXiaojuan Yang             ipnum = (ipnum >= 4) ? 0 : ipnum;
164cbff2db1SXiaojuan Yang             s->sw_ipmap[index * 4 + i] = ipnum;
165cbff2db1SXiaojuan Yang             val = val >> 8;
166cbff2db1SXiaojuan Yang         }
167cbff2db1SXiaojuan Yang 
168cbff2db1SXiaojuan Yang         break;
169cbff2db1SXiaojuan Yang     case EXTIOI_ENABLE_START ... EXTIOI_ENABLE_END - 1:
170cbff2db1SXiaojuan Yang         index = (offset - EXTIOI_ENABLE_START) >> 2;
171cbff2db1SXiaojuan Yang         old_data = s->enable[index];
172cbff2db1SXiaojuan Yang         s->enable[index] = val;
173cbff2db1SXiaojuan Yang 
174cbff2db1SXiaojuan Yang         /* unmask irq */
175cbff2db1SXiaojuan Yang         val = s->enable[index] & ~old_data;
176cbff2db1SXiaojuan Yang         extioi_enable_irq(s, index, val, 1);
177cbff2db1SXiaojuan Yang 
178cbff2db1SXiaojuan Yang         /* mask irq */
179cbff2db1SXiaojuan Yang         val = ~s->enable[index] & old_data;
180cbff2db1SXiaojuan Yang         extioi_enable_irq(s, index, val, 0);
181cbff2db1SXiaojuan Yang         break;
182cbff2db1SXiaojuan Yang     case EXTIOI_BOUNCE_START ... EXTIOI_BOUNCE_END - 1:
183cbff2db1SXiaojuan Yang         /* do not emulate hw bounced irq routing */
184cbff2db1SXiaojuan Yang         index = (offset - EXTIOI_BOUNCE_START) >> 2;
185cbff2db1SXiaojuan Yang         s->bounce[index] = val;
186cbff2db1SXiaojuan Yang         break;
187cbff2db1SXiaojuan Yang     case EXTIOI_COREISR_START ... EXTIOI_COREISR_END - 1:
188cbff2db1SXiaojuan Yang         index = ((offset - EXTIOI_COREISR_START) & 0x1f) >> 2;
189cbff2db1SXiaojuan Yang         cpu = ((offset - EXTIOI_COREISR_START) >> 8) & 0x3;
190cbff2db1SXiaojuan Yang         old_data = s->coreisr[cpu][index];
191cbff2db1SXiaojuan Yang         s->coreisr[cpu][index] = old_data & ~val;
192cbff2db1SXiaojuan Yang         /* write 1 to clear interrrupt */
193cbff2db1SXiaojuan Yang         old_data &= val;
194cbff2db1SXiaojuan Yang         irq = ctz32(old_data);
195cbff2db1SXiaojuan Yang         while (irq != 32) {
196cbff2db1SXiaojuan Yang             extioi_update_irq(s, irq + index * 32, 0);
197cbff2db1SXiaojuan Yang             old_data &= ~(1 << irq);
198cbff2db1SXiaojuan Yang             irq = ctz32(old_data);
199cbff2db1SXiaojuan Yang         }
200cbff2db1SXiaojuan Yang         break;
201cbff2db1SXiaojuan Yang     case EXTIOI_COREMAP_START ... EXTIOI_COREMAP_END - 1:
202cbff2db1SXiaojuan Yang         irq = offset - EXTIOI_COREMAP_START;
203cbff2db1SXiaojuan Yang         index = irq / 4;
204cbff2db1SXiaojuan Yang         s->coremap[index] = val;
205cbff2db1SXiaojuan Yang         /*
206cbff2db1SXiaojuan Yang          * loongarch only support little endian,
207cbff2db1SXiaojuan Yang          * so we paresd the value with little endian.
208cbff2db1SXiaojuan Yang          */
209cbff2db1SXiaojuan Yang         val = cpu_to_le64(val);
210cbff2db1SXiaojuan Yang 
211cbff2db1SXiaojuan Yang         for (i = 0; i < 4; i++) {
212cbff2db1SXiaojuan Yang             cpu = val & 0xff;
213cbff2db1SXiaojuan Yang             cpu = ctz32(cpu);
214cbff2db1SXiaojuan Yang             cpu = (cpu >= 4) ? 0 : cpu;
215cbff2db1SXiaojuan Yang             val = val >> 8;
216cbff2db1SXiaojuan Yang 
217cbff2db1SXiaojuan Yang             if (s->sw_coremap[irq + i] == cpu) {
218cbff2db1SXiaojuan Yang                 continue;
219cbff2db1SXiaojuan Yang             }
220cbff2db1SXiaojuan Yang 
221cbff2db1SXiaojuan Yang             if (test_bit(irq, (unsigned long *)s->isr)) {
222cbff2db1SXiaojuan Yang                 /*
223cbff2db1SXiaojuan Yang                  * lower irq at old cpu and raise irq at new cpu
224cbff2db1SXiaojuan Yang                  */
225cbff2db1SXiaojuan Yang                 extioi_update_irq(s, irq + i, 0);
226cbff2db1SXiaojuan Yang                 s->sw_coremap[irq + i] = cpu;
227cbff2db1SXiaojuan Yang                 extioi_update_irq(s, irq + i, 1);
228cbff2db1SXiaojuan Yang             } else {
229cbff2db1SXiaojuan Yang                 s->sw_coremap[irq + i] = cpu;
230cbff2db1SXiaojuan Yang             }
231cbff2db1SXiaojuan Yang         }
232cbff2db1SXiaojuan Yang         break;
233cbff2db1SXiaojuan Yang     default:
234cbff2db1SXiaojuan Yang         break;
235cbff2db1SXiaojuan Yang     }
236*3fc8f74bSXiaojuan Yang     return MEMTX_OK;
237cbff2db1SXiaojuan Yang }
238cbff2db1SXiaojuan Yang 
239cbff2db1SXiaojuan Yang static const MemoryRegionOps extioi_ops = {
240*3fc8f74bSXiaojuan Yang     .read_with_attrs = extioi_readw,
241*3fc8f74bSXiaojuan Yang     .write_with_attrs = extioi_writew,
242cbff2db1SXiaojuan Yang     .impl.min_access_size = 4,
243cbff2db1SXiaojuan Yang     .impl.max_access_size = 4,
244cbff2db1SXiaojuan Yang     .valid.min_access_size = 4,
245cbff2db1SXiaojuan Yang     .valid.max_access_size = 8,
246cbff2db1SXiaojuan Yang     .endianness = DEVICE_LITTLE_ENDIAN,
247cbff2db1SXiaojuan Yang };
248cbff2db1SXiaojuan Yang 
249cbff2db1SXiaojuan Yang static const VMStateDescription vmstate_loongarch_extioi = {
250cbff2db1SXiaojuan Yang     .name = TYPE_LOONGARCH_EXTIOI,
251cbff2db1SXiaojuan Yang     .version_id = 1,
252cbff2db1SXiaojuan Yang     .minimum_version_id = 1,
253cbff2db1SXiaojuan Yang     .fields = (VMStateField[]) {
254cbff2db1SXiaojuan Yang         VMSTATE_UINT32_ARRAY(bounce, LoongArchExtIOI, EXTIOI_IRQS_GROUP_COUNT),
255cbff2db1SXiaojuan Yang         VMSTATE_UINT32_2DARRAY(coreisr, LoongArchExtIOI, LOONGARCH_MAX_VCPUS,
256cbff2db1SXiaojuan Yang                                EXTIOI_IRQS_GROUP_COUNT),
257cbff2db1SXiaojuan Yang         VMSTATE_UINT32_ARRAY(nodetype, LoongArchExtIOI,
258cbff2db1SXiaojuan Yang                              EXTIOI_IRQS_NODETYPE_COUNT / 2),
259cbff2db1SXiaojuan Yang         VMSTATE_UINT32_ARRAY(enable, LoongArchExtIOI, EXTIOI_IRQS / 32),
260cbff2db1SXiaojuan Yang         VMSTATE_UINT32_ARRAY(isr, LoongArchExtIOI, EXTIOI_IRQS / 32),
261cbff2db1SXiaojuan Yang         VMSTATE_UINT32_ARRAY(ipmap, LoongArchExtIOI, EXTIOI_IRQS_IPMAP_SIZE / 4),
262cbff2db1SXiaojuan Yang         VMSTATE_UINT32_ARRAY(coremap, LoongArchExtIOI, EXTIOI_IRQS / 4),
263cbff2db1SXiaojuan Yang         VMSTATE_UINT8_ARRAY(sw_ipmap, LoongArchExtIOI, EXTIOI_IRQS_IPMAP_SIZE),
264cbff2db1SXiaojuan Yang         VMSTATE_UINT8_ARRAY(sw_coremap, LoongArchExtIOI, EXTIOI_IRQS),
265cbff2db1SXiaojuan Yang 
266cbff2db1SXiaojuan Yang         VMSTATE_END_OF_LIST()
267cbff2db1SXiaojuan Yang     }
268cbff2db1SXiaojuan Yang };
269cbff2db1SXiaojuan Yang 
270cbff2db1SXiaojuan Yang static void loongarch_extioi_instance_init(Object *obj)
271cbff2db1SXiaojuan Yang {
272cbff2db1SXiaojuan Yang     SysBusDevice *dev = SYS_BUS_DEVICE(obj);
273cbff2db1SXiaojuan Yang     LoongArchExtIOI *s = LOONGARCH_EXTIOI(obj);
274cbff2db1SXiaojuan Yang     int i, cpu, pin;
275cbff2db1SXiaojuan Yang 
276cbff2db1SXiaojuan Yang     for (i = 0; i < EXTIOI_IRQS; i++) {
277cbff2db1SXiaojuan Yang         sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[i]);
278cbff2db1SXiaojuan Yang     }
279cbff2db1SXiaojuan Yang 
280cbff2db1SXiaojuan Yang     qdev_init_gpio_in(DEVICE(obj), extioi_setirq, EXTIOI_IRQS);
281cbff2db1SXiaojuan Yang 
282cbff2db1SXiaojuan Yang     for (cpu = 0; cpu < LOONGARCH_MAX_VCPUS; cpu++) {
283cbff2db1SXiaojuan Yang         memory_region_init_io(&s->extioi_iocsr_mem[cpu], OBJECT(s), &extioi_ops,
284cbff2db1SXiaojuan Yang                               s, "extioi_iocsr", 0x900);
285cbff2db1SXiaojuan Yang         sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->extioi_iocsr_mem[cpu]);
286cbff2db1SXiaojuan Yang         for (pin = 0; pin < LS3A_INTC_IP; pin++) {
287cbff2db1SXiaojuan Yang             qdev_init_gpio_out(DEVICE(obj), &s->parent_irq[cpu][pin], 1);
288cbff2db1SXiaojuan Yang         }
289cbff2db1SXiaojuan Yang     }
290cbff2db1SXiaojuan Yang     memory_region_init_io(&s->extioi_system_mem, OBJECT(s), &extioi_ops,
291cbff2db1SXiaojuan Yang                           s, "extioi_system_mem", 0x900);
292cbff2db1SXiaojuan Yang     sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->extioi_system_mem);
293cbff2db1SXiaojuan Yang }
294cbff2db1SXiaojuan Yang 
295cbff2db1SXiaojuan Yang static void loongarch_extioi_class_init(ObjectClass *klass, void *data)
296cbff2db1SXiaojuan Yang {
297cbff2db1SXiaojuan Yang     DeviceClass *dc = DEVICE_CLASS(klass);
298cbff2db1SXiaojuan Yang 
299cbff2db1SXiaojuan Yang     dc->vmsd = &vmstate_loongarch_extioi;
300cbff2db1SXiaojuan Yang }
301cbff2db1SXiaojuan Yang 
302cbff2db1SXiaojuan Yang static const TypeInfo loongarch_extioi_info = {
303cbff2db1SXiaojuan Yang     .name          = TYPE_LOONGARCH_EXTIOI,
304cbff2db1SXiaojuan Yang     .parent        = TYPE_SYS_BUS_DEVICE,
305cbff2db1SXiaojuan Yang     .instance_init = loongarch_extioi_instance_init,
306cbff2db1SXiaojuan Yang     .instance_size = sizeof(struct LoongArchExtIOI),
307cbff2db1SXiaojuan Yang     .class_init    = loongarch_extioi_class_init,
308cbff2db1SXiaojuan Yang };
309cbff2db1SXiaojuan Yang 
310cbff2db1SXiaojuan Yang static void loongarch_extioi_register_types(void)
311cbff2db1SXiaojuan Yang {
312cbff2db1SXiaojuan Yang     type_register_static(&loongarch_extioi_info);
313cbff2db1SXiaojuan Yang }
314cbff2db1SXiaojuan Yang 
315cbff2db1SXiaojuan Yang type_init(loongarch_extioi_register_types)
316