1 /* 2 * SPDX-License-Identifier: GPL-2.0-or-later 3 * 4 * QEMU Motorola 680x0 IRQ Controller 5 * 6 * (c) 2020 Laurent Vivier <laurent@vivier.eu> 7 * 8 */ 9 10 #include "qemu/osdep.h" 11 #include "cpu.h" 12 #include "migration/vmstate.h" 13 #include "hw/qdev-properties.h" 14 #include "hw/nmi.h" 15 #include "hw/intc/intc.h" 16 #include "hw/intc/m68k_irqc.h" 17 18 19 static bool m68k_irqc_get_statistics(InterruptStatsProvider *obj, 20 uint64_t **irq_counts, unsigned int *nb_irqs) 21 { 22 M68KIRQCState *s = M68K_IRQC(obj); 23 24 *irq_counts = s->stats_irq_count; 25 *nb_irqs = ARRAY_SIZE(s->stats_irq_count); 26 return true; 27 } 28 29 static void m68k_irqc_print_info(InterruptStatsProvider *obj, GString *buf) 30 { 31 M68KIRQCState *s = M68K_IRQC(obj); 32 g_string_append_printf(buf, "m68k-irqc: ipr=0x%x\n", s->ipr); 33 } 34 35 static void m68k_set_irq(void *opaque, int irq, int level) 36 { 37 M68KIRQCState *s = opaque; 38 M68kCPU *cpu = M68K_CPU(s->cpu); 39 int i; 40 41 if (level) { 42 s->ipr |= 1 << irq; 43 s->stats_irq_count[irq]++; 44 } else { 45 s->ipr &= ~(1 << irq); 46 } 47 48 for (i = M68K_IRQC_LEVEL_7; i >= M68K_IRQC_LEVEL_1; i--) { 49 if ((s->ipr >> i) & 1) { 50 m68k_set_irq_level(cpu, i + 1, i + M68K_IRQC_AUTOVECTOR_BASE); 51 return; 52 } 53 } 54 m68k_set_irq_level(cpu, 0, 0); 55 } 56 57 static void m68k_irqc_reset(DeviceState *d) 58 { 59 M68KIRQCState *s = M68K_IRQC(d); 60 int i; 61 62 s->ipr = 0; 63 for (i = 0; i < ARRAY_SIZE(s->stats_irq_count); i++) { 64 s->stats_irq_count[i] = 0; 65 } 66 } 67 68 static void m68k_irqc_instance_init(Object *obj) 69 { 70 qdev_init_gpio_in(DEVICE(obj), m68k_set_irq, M68K_IRQC_LEVEL_NUM); 71 } 72 73 static void m68k_nmi(NMIState *n, int cpu_index, Error **errp) 74 { 75 m68k_set_irq(n, M68K_IRQC_LEVEL_7, 1); 76 } 77 78 static const VMStateDescription vmstate_m68k_irqc = { 79 .name = "m68k-irqc", 80 .version_id = 1, 81 .minimum_version_id = 1, 82 .fields = (const VMStateField[]) { 83 VMSTATE_UINT8(ipr, M68KIRQCState), 84 VMSTATE_END_OF_LIST() 85 } 86 }; 87 88 static Property m68k_irqc_properties[] = { 89 DEFINE_PROP_LINK("m68k-cpu", M68KIRQCState, cpu, 90 TYPE_M68K_CPU, ArchCPU *), 91 DEFINE_PROP_END_OF_LIST(), 92 }; 93 94 static void m68k_irqc_class_init(ObjectClass *oc, void *data) 95 { 96 DeviceClass *dc = DEVICE_CLASS(oc); 97 NMIClass *nc = NMI_CLASS(oc); 98 InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(oc); 99 100 device_class_set_props(dc, m68k_irqc_properties); 101 nc->nmi_monitor_handler = m68k_nmi; 102 device_class_set_legacy_reset(dc, m68k_irqc_reset); 103 dc->vmsd = &vmstate_m68k_irqc; 104 ic->get_statistics = m68k_irqc_get_statistics; 105 ic->print_info = m68k_irqc_print_info; 106 } 107 108 static const TypeInfo m68k_irqc_type_info = { 109 .name = TYPE_M68K_IRQC, 110 .parent = TYPE_SYS_BUS_DEVICE, 111 .instance_size = sizeof(M68KIRQCState), 112 .instance_init = m68k_irqc_instance_init, 113 .class_init = m68k_irqc_class_init, 114 .interfaces = (InterfaceInfo[]) { 115 { TYPE_NMI }, 116 { TYPE_INTERRUPT_STATS_PROVIDER }, 117 { } 118 }, 119 }; 120 121 static void q800_irq_register_types(void) 122 { 123 type_register_static(&m68k_irqc_type_info); 124 } 125 126 type_init(q800_irq_register_types); 127