]> git.proxmox.com Git - mirror_qemu.git/blame - hw/intc/slavio_intctl.c
intc/slavio_intctl: implement InterruptStatsProvider interface
[mirror_qemu.git] / hw / intc / slavio_intctl.c
CommitLineData
e80cfcfc
FB
1/*
2 * QEMU Sparc SLAVIO interrupt controller emulation
5fafdf24 3 *
66321a11 4 * Copyright (c) 2003-2005 Fabrice Bellard
5fafdf24 5 *
e80cfcfc
FB
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
a1961a4b 24
90191d07 25#include "qemu/osdep.h"
0d09e41a 26#include "hw/sparc/sun4m.h"
83c9089e 27#include "monitor/monitor.h"
83c9f4ca 28#include "hw/sysbus.h"
148fbe95 29#include "hw/intc/intc.h"
97bf4851 30#include "trace.h"
87ecb68b 31
e80cfcfc
FB
32//#define DEBUG_IRQ_COUNT
33
34/*
35 * Registers of interrupt controller in sun4m.
36 *
37 * This is the interrupt controller part of chip STP2001 (Slave I/O), also
38 * produced as NCR89C105. See
39 * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
40 *
41 * There is a system master controller and one for each cpu.
5fafdf24 42 *
e80cfcfc
FB
43 */
44
45#define MAX_CPUS 16
b3a23197 46#define MAX_PILS 16
e80cfcfc 47
a1961a4b
BS
48struct SLAVIO_INTCTLState;
49
50typedef struct SLAVIO_CPUINTCTLState {
8bb5ef33 51 MemoryRegion iomem;
a1961a4b 52 struct SLAVIO_INTCTLState *master;
07dd0035 53 uint32_t intreg_pending;
a1961a4b 54 uint32_t cpu;
462eda24 55 uint32_t irl_out;
a1961a4b 56} SLAVIO_CPUINTCTLState;
a8f48dcc 57
7abad863
AF
58#define TYPE_SLAVIO_INTCTL "slavio_intctl"
59#define SLAVIO_INTCTL(obj) \
60 OBJECT_CHECK(SLAVIO_INTCTLState, (obj), TYPE_SLAVIO_INTCTL)
61
e80cfcfc 62typedef struct SLAVIO_INTCTLState {
7abad863
AF
63 SysBusDevice parent_obj;
64
13c89a11 65 MemoryRegion iomem;
e80cfcfc
FB
66#ifdef DEBUG_IRQ_COUNT
67 uint64_t irq_count[32];
68#endif
a1961a4b 69 qemu_irq cpu_irqs[MAX_CPUS][MAX_PILS];
a1961a4b 70 SLAVIO_CPUINTCTLState slaves[MAX_CPUS];
07dd0035
BS
71 uint32_t intregm_pending;
72 uint32_t intregm_disabled;
73 uint32_t target_cpu;
e80cfcfc
FB
74} SLAVIO_INTCTLState;
75
76#define INTCTL_MAXADDR 0xf
5aca8c3b 77#define INTCTL_SIZE (INTCTL_MAXADDR + 1)
a8f48dcc 78#define INTCTLM_SIZE 0x14
80be36b8 79#define MASTER_IRQ_MASK ~0x0fa2007f
9a87ce9b 80#define MASTER_DISABLE 0x80000000
6341fdcb 81#define CPU_SOFTIRQ_MASK 0xfffe0000
462eda24
BS
82#define CPU_IRQ_INT15_IN (1 << 15)
83#define CPU_IRQ_TIMER_IN (1 << 14)
9a87ce9b 84
0d0a7e69 85static void slavio_check_interrupts(SLAVIO_INTCTLState *s, int set_irqs);
e80cfcfc
FB
86
87// per-cpu interrupt controller
a8170e5e 88static uint64_t slavio_intctl_mem_readl(void *opaque, hwaddr addr,
8bb5ef33 89 unsigned size)
e80cfcfc 90{
a8f48dcc 91 SLAVIO_CPUINTCTLState *s = opaque;
dd4131b3 92 uint32_t saddr, ret;
e80cfcfc 93
a8f48dcc 94 saddr = addr >> 2;
e80cfcfc
FB
95 switch (saddr) {
96 case 0:
a8f48dcc 97 ret = s->intreg_pending;
dd4131b3 98 break;
e80cfcfc 99 default:
dd4131b3
BS
100 ret = 0;
101 break;
e80cfcfc 102 }
97bf4851 103 trace_slavio_intctl_mem_readl(s->cpu, addr, ret);
dd4131b3
BS
104
105 return ret;
e80cfcfc
FB
106}
107
a8170e5e 108static void slavio_intctl_mem_writel(void *opaque, hwaddr addr,
8bb5ef33 109 uint64_t val, unsigned size)
e80cfcfc 110{
a8f48dcc 111 SLAVIO_CPUINTCTLState *s = opaque;
e80cfcfc 112 uint32_t saddr;
e80cfcfc 113
a8f48dcc 114 saddr = addr >> 2;
97bf4851 115 trace_slavio_intctl_mem_writel(s->cpu, addr, val);
e80cfcfc
FB
116 switch (saddr) {
117 case 1: // clear pending softints
462eda24 118 val &= CPU_SOFTIRQ_MASK | CPU_IRQ_INT15_IN;
a8f48dcc 119 s->intreg_pending &= ~val;
0d0a7e69 120 slavio_check_interrupts(s->master, 1);
97bf4851 121 trace_slavio_intctl_mem_writel_clear(s->cpu, val, s->intreg_pending);
f930d07e 122 break;
e80cfcfc 123 case 2: // set softint
6341fdcb 124 val &= CPU_SOFTIRQ_MASK;
a8f48dcc 125 s->intreg_pending |= val;
0d0a7e69 126 slavio_check_interrupts(s->master, 1);
97bf4851 127 trace_slavio_intctl_mem_writel_set(s->cpu, val, s->intreg_pending);
f930d07e 128 break;
e80cfcfc 129 default:
f930d07e 130 break;
e80cfcfc
FB
131 }
132}
133
8bb5ef33
BC
134static const MemoryRegionOps slavio_intctl_mem_ops = {
135 .read = slavio_intctl_mem_readl,
136 .write = slavio_intctl_mem_writel,
137 .endianness = DEVICE_NATIVE_ENDIAN,
138 .valid = {
139 .min_access_size = 4,
140 .max_access_size = 4,
141 },
e80cfcfc
FB
142};
143
144// master system interrupt controller
a8170e5e 145static uint64_t slavio_intctlm_mem_readl(void *opaque, hwaddr addr,
13c89a11 146 unsigned size)
e80cfcfc
FB
147{
148 SLAVIO_INTCTLState *s = opaque;
dd4131b3 149 uint32_t saddr, ret;
e80cfcfc 150
a8f48dcc 151 saddr = addr >> 2;
e80cfcfc
FB
152 switch (saddr) {
153 case 0:
9a87ce9b 154 ret = s->intregm_pending & ~MASTER_DISABLE;
dd4131b3 155 break;
e80cfcfc 156 case 1:
80be36b8 157 ret = s->intregm_disabled & MASTER_IRQ_MASK;
dd4131b3 158 break;
e80cfcfc 159 case 4:
dd4131b3
BS
160 ret = s->target_cpu;
161 break;
e80cfcfc 162 default:
dd4131b3
BS
163 ret = 0;
164 break;
e80cfcfc 165 }
97bf4851 166 trace_slavio_intctlm_mem_readl(addr, ret);
dd4131b3
BS
167
168 return ret;
e80cfcfc
FB
169}
170
a8170e5e 171static void slavio_intctlm_mem_writel(void *opaque, hwaddr addr,
13c89a11 172 uint64_t val, unsigned size)
e80cfcfc
FB
173{
174 SLAVIO_INTCTLState *s = opaque;
175 uint32_t saddr;
176
a8f48dcc 177 saddr = addr >> 2;
97bf4851 178 trace_slavio_intctlm_mem_writel(addr, val);
e80cfcfc
FB
179 switch (saddr) {
180 case 2: // clear (enable)
f930d07e 181 // Force clear unused bits
9a87ce9b 182 val &= MASTER_IRQ_MASK;
f930d07e 183 s->intregm_disabled &= ~val;
97bf4851 184 trace_slavio_intctlm_mem_writel_enable(val, s->intregm_disabled);
0d0a7e69 185 slavio_check_interrupts(s, 1);
f930d07e 186 break;
10760f0f 187 case 3: // set (disable; doesn't affect pending)
f930d07e 188 // Force clear unused bits
9a87ce9b 189 val &= MASTER_IRQ_MASK;
f930d07e 190 s->intregm_disabled |= val;
0d0a7e69 191 slavio_check_interrupts(s, 1);
97bf4851 192 trace_slavio_intctlm_mem_writel_disable(val, s->intregm_disabled);
f930d07e 193 break;
e80cfcfc 194 case 4:
f930d07e 195 s->target_cpu = val & (MAX_CPUS - 1);
0d0a7e69 196 slavio_check_interrupts(s, 1);
97bf4851 197 trace_slavio_intctlm_mem_writel_target(s->target_cpu);
f930d07e 198 break;
e80cfcfc 199 default:
f930d07e 200 break;
e80cfcfc
FB
201 }
202}
203
13c89a11
BC
204static const MemoryRegionOps slavio_intctlm_mem_ops = {
205 .read = slavio_intctlm_mem_readl,
206 .write = slavio_intctlm_mem_writel,
207 .endianness = DEVICE_NATIVE_ENDIAN,
208 .valid = {
209 .min_access_size = 4,
210 .max_access_size = 4,
211 },
e80cfcfc
FB
212};
213
d453c2c3 214void slavio_pic_info(Monitor *mon, DeviceState *dev)
e80cfcfc 215{
7abad863 216 SLAVIO_INTCTLState *s = SLAVIO_INTCTL(dev);
e80cfcfc
FB
217 int i;
218
219 for (i = 0; i < MAX_CPUS; i++) {
376253ec 220 monitor_printf(mon, "per-cpu %d: pending 0x%08x\n", i,
a1961a4b 221 s->slaves[i].intreg_pending);
e80cfcfc 222 }
376253ec
AL
223 monitor_printf(mon, "master: pending 0x%08x, disabled 0x%08x\n",
224 s->intregm_pending, s->intregm_disabled);
e80cfcfc
FB
225}
226
d453c2c3 227void slavio_irq_info(Monitor *mon, DeviceState *dev)
e80cfcfc
FB
228{
229#ifndef DEBUG_IRQ_COUNT
376253ec 230 monitor_printf(mon, "irq statistic code not compiled.\n");
e80cfcfc 231#else
7abad863 232 SLAVIO_INTCTLState *s = SLAVIO_INTCTL(dev);
e80cfcfc
FB
233 int i;
234 int64_t count;
235
7abad863 236 s = SLAVIO_INTCTL(dev);
376253ec 237 monitor_printf(mon, "IRQ statistics:\n");
e80cfcfc
FB
238 for (i = 0; i < 32; i++) {
239 count = s->irq_count[i];
240 if (count > 0)
376253ec 241 monitor_printf(mon, "%2d: %" PRId64 "\n", i, count);
e80cfcfc
FB
242 }
243#endif
244}
245
68556e2e 246static const uint32_t intbit_to_level[] = {
462eda24
BS
247 2, 3, 5, 7, 9, 11, 13, 2, 3, 5, 7, 9, 11, 13, 12, 12,
248 6, 13, 4, 10, 8, 9, 11, 0, 0, 0, 0, 15, 15, 15, 15, 0,
68556e2e
BS
249};
250
0d0a7e69 251static void slavio_check_interrupts(SLAVIO_INTCTLState *s, int set_irqs)
66321a11 252{
327ac2e7
BS
253 uint32_t pending = s->intregm_pending, pil_pending;
254 unsigned int i, j;
66321a11
FB
255
256 pending &= ~s->intregm_disabled;
257
97bf4851 258 trace_slavio_check_interrupts(pending, s->intregm_disabled);
ba3c64fb 259 for (i = 0; i < MAX_CPUS; i++) {
327ac2e7 260 pil_pending = 0;
462eda24
BS
261
262 /* If we are the current interrupt target, get hard interrupts */
9a87ce9b 263 if (pending && !(s->intregm_disabled & MASTER_DISABLE) &&
b3a23197
BS
264 (i == s->target_cpu)) {
265 for (j = 0; j < 32; j++) {
462eda24 266 if ((pending & (1 << j)) && intbit_to_level[j]) {
68556e2e 267 pil_pending |= 1 << intbit_to_level[j];
462eda24
BS
268 }
269 }
270 }
271
272 /* Calculate current pending hard interrupts for display */
273 s->slaves[i].intreg_pending &= CPU_SOFTIRQ_MASK | CPU_IRQ_INT15_IN |
274 CPU_IRQ_TIMER_IN;
275 if (i == s->target_cpu) {
276 for (j = 0; j < 32; j++) {
7d45e784 277 if ((s->intregm_pending & (1U << j)) && intbit_to_level[j]) {
462eda24
BS
278 s->slaves[i].intreg_pending |= 1 << intbit_to_level[j];
279 }
b3a23197
BS
280 }
281 }
462eda24 282
94c5f455
AT
283 /* Level 15 and CPU timer interrupts are only masked when
284 the MASTER_DISABLE bit is set */
285 if (!(s->intregm_disabled & MASTER_DISABLE)) {
286 pil_pending |= s->slaves[i].intreg_pending &
287 (CPU_IRQ_INT15_IN | CPU_IRQ_TIMER_IN);
288 }
462eda24
BS
289
290 /* Add soft interrupts */
a1961a4b 291 pil_pending |= (s->slaves[i].intreg_pending & CPU_SOFTIRQ_MASK) >> 16;
327ac2e7 292
0d0a7e69 293 if (set_irqs) {
c84a88d8
PM
294 /* Since there is not really an interrupt 0 (and pil_pending
295 * and irl_out bit zero are thus always zero) there is no need
296 * to do anything with cpu_irqs[i][0] and it is OK not to do
297 * the j=0 iteration of this loop.
298 */
299 for (j = MAX_PILS-1; j > 0; j--) {
0d0a7e69 300 if (pil_pending & (1 << j)) {
462eda24 301 if (!(s->slaves[i].irl_out & (1 << j))) {
0d0a7e69
BS
302 qemu_irq_raise(s->cpu_irqs[i][j]);
303 }
304 } else {
462eda24 305 if (s->slaves[i].irl_out & (1 << j)) {
0d0a7e69
BS
306 qemu_irq_lower(s->cpu_irqs[i][j]);
307 }
308 }
ba3c64fb
FB
309 }
310 }
462eda24 311 s->slaves[i].irl_out = pil_pending;
ba3c64fb 312 }
66321a11
FB
313}
314
e80cfcfc
FB
315/*
316 * "irq" here is the bit number in the system interrupt register to
317 * separate serial and keyboard interrupts sharing a level.
318 */
d7edfd27 319static void slavio_set_irq(void *opaque, int irq, int level)
e80cfcfc
FB
320{
321 SLAVIO_INTCTLState *s = opaque;
b3a23197 322 uint32_t mask = 1 << irq;
68556e2e 323 uint32_t pil = intbit_to_level[irq];
462eda24 324 unsigned int i;
b3a23197 325
97bf4851 326 trace_slavio_set_irq(s->target_cpu, irq, pil, level);
b3a23197
BS
327 if (pil > 0) {
328 if (level) {
327ac2e7
BS
329#ifdef DEBUG_IRQ_COUNT
330 s->irq_count[pil]++;
331#endif
b3a23197 332 s->intregm_pending |= mask;
462eda24
BS
333 if (pil == 15) {
334 for (i = 0; i < MAX_CPUS; i++) {
335 s->slaves[i].intreg_pending |= 1 << pil;
336 }
337 }
b3a23197
BS
338 } else {
339 s->intregm_pending &= ~mask;
462eda24
BS
340 if (pil == 15) {
341 for (i = 0; i < MAX_CPUS; i++) {
342 s->slaves[i].intreg_pending &= ~(1 << pil);
343 }
344 }
b3a23197 345 }
0d0a7e69 346 slavio_check_interrupts(s, 1);
e80cfcfc
FB
347 }
348}
349
d7edfd27 350static void slavio_set_timer_irq_cpu(void *opaque, int cpu, int level)
ba3c64fb
FB
351{
352 SLAVIO_INTCTLState *s = opaque;
353
97bf4851 354 trace_slavio_set_timer_irq_cpu(cpu, level);
d7edfd27 355
e3a79bca 356 if (level) {
462eda24 357 s->slaves[cpu].intreg_pending |= CPU_IRQ_TIMER_IN;
e3a79bca 358 } else {
462eda24 359 s->slaves[cpu].intreg_pending &= ~CPU_IRQ_TIMER_IN;
e3a79bca 360 }
d7edfd27 361
0d0a7e69 362 slavio_check_interrupts(s, 1);
ba3c64fb
FB
363}
364
a1961a4b
BS
365static void slavio_set_irq_all(void *opaque, int irq, int level)
366{
367 if (irq < 32) {
368 slavio_set_irq(opaque, irq, level);
369 } else {
370 slavio_set_timer_irq_cpu(opaque, irq - 32, level);
371 }
372}
373
e59fb374 374static int vmstate_intctl_post_load(void *opaque, int version_id)
e80cfcfc
FB
375{
376 SLAVIO_INTCTLState *s = opaque;
3b46e624 377
c9e95029
BS
378 slavio_check_interrupts(s, 0);
379 return 0;
e80cfcfc
FB
380}
381
c9e95029
BS
382static const VMStateDescription vmstate_intctl_cpu = {
383 .name ="slavio_intctl_cpu",
384 .version_id = 1,
385 .minimum_version_id = 1,
35d08458 386 .fields = (VMStateField[]) {
c9e95029
BS
387 VMSTATE_UINT32(intreg_pending, SLAVIO_CPUINTCTLState),
388 VMSTATE_END_OF_LIST()
389 }
390};
e80cfcfc 391
c9e95029
BS
392static const VMStateDescription vmstate_intctl = {
393 .name ="slavio_intctl",
394 .version_id = 1,
395 .minimum_version_id = 1,
752ff2fa 396 .post_load = vmstate_intctl_post_load,
35d08458 397 .fields = (VMStateField[]) {
c9e95029
BS
398 VMSTATE_STRUCT_ARRAY(slaves, SLAVIO_INTCTLState, MAX_CPUS, 1,
399 vmstate_intctl_cpu, SLAVIO_CPUINTCTLState),
400 VMSTATE_UINT32(intregm_pending, SLAVIO_INTCTLState),
401 VMSTATE_UINT32(intregm_disabled, SLAVIO_INTCTLState),
402 VMSTATE_UINT32(target_cpu, SLAVIO_INTCTLState),
403 VMSTATE_END_OF_LIST()
e80cfcfc 404 }
c9e95029 405};
e80cfcfc 406
78971d57 407static void slavio_intctl_reset(DeviceState *d)
e80cfcfc 408{
7abad863 409 SLAVIO_INTCTLState *s = SLAVIO_INTCTL(d);
e80cfcfc
FB
410 int i;
411
412 for (i = 0; i < MAX_CPUS; i++) {
a1961a4b 413 s->slaves[i].intreg_pending = 0;
462eda24 414 s->slaves[i].irl_out = 0;
e80cfcfc 415 }
9a87ce9b 416 s->intregm_disabled = ~MASTER_IRQ_MASK;
e80cfcfc
FB
417 s->intregm_pending = 0;
418 s->target_cpu = 0;
0d0a7e69 419 slavio_check_interrupts(s, 0);
e80cfcfc
FB
420}
421
148fbe95
HP
422#ifdef DEBUG_IRQ_COUNT
423static bool slavio_intctl_get_statistics(InterruptStatsProvider *obj,
424 uint64_t **irq_counts,
425 unsigned int *nb_irqs)
426{
427 SLAVIO_INTCTLState *s = SLAVIO_INTCTL(obj);
428 *irq_counts = s->irq_count;
429 *nb_irqs = ARRAY_SIZE(s->irq_count);
430 return true;
431}
432#endif
433
434static void slavio_intctl_print_info(InterruptStatsProvider *obj, Monitor *mon)
435{
436 SLAVIO_INTCTLState *s = SLAVIO_INTCTL(obj);
437 int i;
438
439 for (i = 0; i < MAX_CPUS; i++) {
440 monitor_printf(mon, "per-cpu %d: pending 0x%08x\n", i,
441 s->slaves[i].intreg_pending);
442 }
443 monitor_printf(mon, "master: pending 0x%08x, disabled 0x%08x\n",
444 s->intregm_pending, s->intregm_disabled);
445}
446
c09008d2 447static void slavio_intctl_init(Object *obj)
e80cfcfc 448{
c09008d2
XZ
449 DeviceState *dev = DEVICE(obj);
450 SLAVIO_INTCTLState *s = SLAVIO_INTCTL(obj);
451 SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
a1961a4b 452 unsigned int i, j;
8bb5ef33 453 char slave_name[45];
e80cfcfc 454
7abad863 455 qdev_init_gpio_in(dev, slavio_set_irq_all, 32 + MAX_CPUS);
c09008d2 456 memory_region_init_io(&s->iomem, obj, &slavio_intctlm_mem_ops, s,
13c89a11 457 "master-interrupt-controller", INTCTLM_SIZE);
7abad863 458 sysbus_init_mmio(sbd, &s->iomem);
e80cfcfc
FB
459
460 for (i = 0; i < MAX_CPUS; i++) {
8bb5ef33
BC
461 snprintf(slave_name, sizeof(slave_name),
462 "slave-interrupt-controller-%i", i);
a1961a4b 463 for (j = 0; j < MAX_PILS; j++) {
7abad863 464 sysbus_init_irq(sbd, &s->cpu_irqs[i][j]);
a1961a4b 465 }
1437c94b
PB
466 memory_region_init_io(&s->slaves[i].iomem, OBJECT(s),
467 &slavio_intctl_mem_ops,
8bb5ef33 468 &s->slaves[i], slave_name, INTCTL_SIZE);
7abad863 469 sysbus_init_mmio(sbd, &s->slaves[i].iomem);
a1961a4b
BS
470 s->slaves[i].cpu = i;
471 s->slaves[i].master = s;
472 }
a1961a4b
BS
473}
474
999e12bb
AL
475static void slavio_intctl_class_init(ObjectClass *klass, void *data)
476{
39bffca2 477 DeviceClass *dc = DEVICE_CLASS(klass);
148fbe95 478 InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(klass);
999e12bb 479
39bffca2
AL
480 dc->reset = slavio_intctl_reset;
481 dc->vmsd = &vmstate_intctl;
148fbe95
HP
482#ifdef DEBUG_IRQ_COUNT
483 ic->get_statistics = slavio_intctl_get_statistics;
484#endif
485 ic->print_info = slavio_intctl_print_info;
999e12bb
AL
486}
487
8c43a6f0 488static const TypeInfo slavio_intctl_info = {
7abad863 489 .name = TYPE_SLAVIO_INTCTL,
39bffca2
AL
490 .parent = TYPE_SYS_BUS_DEVICE,
491 .instance_size = sizeof(SLAVIO_INTCTLState),
c09008d2 492 .instance_init = slavio_intctl_init,
39bffca2 493 .class_init = slavio_intctl_class_init,
148fbe95
HP
494 .interfaces = (InterfaceInfo[]) {
495 { TYPE_INTERRUPT_STATS_PROVIDER },
496 { }
497 },
a1961a4b 498};
d7edfd27 499
83f7d43a 500static void slavio_intctl_register_types(void)
a1961a4b 501{
39bffca2 502 type_register_static(&slavio_intctl_info);
e80cfcfc 503}
a1961a4b 504
83f7d43a 505type_init(slavio_intctl_register_types)