17702e47cSPaolo Bonzini /*
27702e47cSPaolo Bonzini * QEMU Sparc SLAVIO interrupt controller emulation
37702e47cSPaolo Bonzini *
47702e47cSPaolo Bonzini * Copyright (c) 2003-2005 Fabrice Bellard
57702e47cSPaolo Bonzini *
67702e47cSPaolo Bonzini * Permission is hereby granted, free of charge, to any person obtaining a copy
77702e47cSPaolo Bonzini * of this software and associated documentation files (the "Software"), to deal
87702e47cSPaolo Bonzini * in the Software without restriction, including without limitation the rights
97702e47cSPaolo Bonzini * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
107702e47cSPaolo Bonzini * copies of the Software, and to permit persons to whom the Software is
117702e47cSPaolo Bonzini * furnished to do so, subject to the following conditions:
127702e47cSPaolo Bonzini *
137702e47cSPaolo Bonzini * The above copyright notice and this permission notice shall be included in
147702e47cSPaolo Bonzini * all copies or substantial portions of the Software.
157702e47cSPaolo Bonzini *
167702e47cSPaolo Bonzini * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
177702e47cSPaolo Bonzini * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
187702e47cSPaolo Bonzini * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
197702e47cSPaolo Bonzini * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
207702e47cSPaolo Bonzini * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
217702e47cSPaolo Bonzini * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
227702e47cSPaolo Bonzini * THE SOFTWARE.
237702e47cSPaolo Bonzini */
247702e47cSPaolo Bonzini
2590191d07SPeter Maydell #include "qemu/osdep.h"
26d6454270SMarkus Armbruster #include "migration/vmstate.h"
270b8fa32fSMarkus Armbruster #include "qemu/module.h"
287702e47cSPaolo Bonzini #include "hw/sysbus.h"
29148fbe95SHervé Poussineau #include "hw/intc/intc.h"
3064552b6bSMarkus Armbruster #include "hw/irq.h"
317702e47cSPaolo Bonzini #include "trace.h"
32db1015e9SEduardo Habkost #include "qom/object.h"
337702e47cSPaolo Bonzini
347702e47cSPaolo Bonzini //#define DEBUG_IRQ_COUNT
357702e47cSPaolo Bonzini
367702e47cSPaolo Bonzini /*
377702e47cSPaolo Bonzini * Registers of interrupt controller in sun4m.
387702e47cSPaolo Bonzini *
397702e47cSPaolo Bonzini * This is the interrupt controller part of chip STP2001 (Slave I/O), also
407702e47cSPaolo Bonzini * produced as NCR89C105. See
417702e47cSPaolo Bonzini * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
427702e47cSPaolo Bonzini *
437702e47cSPaolo Bonzini * There is a system master controller and one for each cpu.
447702e47cSPaolo Bonzini *
457702e47cSPaolo Bonzini */
467702e47cSPaolo Bonzini
477702e47cSPaolo Bonzini #define MAX_CPUS 16
487702e47cSPaolo Bonzini #define MAX_PILS 16
497702e47cSPaolo Bonzini
507702e47cSPaolo Bonzini struct SLAVIO_INTCTLState;
517702e47cSPaolo Bonzini
527702e47cSPaolo Bonzini typedef struct SLAVIO_CPUINTCTLState {
537702e47cSPaolo Bonzini MemoryRegion iomem;
547702e47cSPaolo Bonzini struct SLAVIO_INTCTLState *master;
557702e47cSPaolo Bonzini uint32_t intreg_pending;
567702e47cSPaolo Bonzini uint32_t cpu;
577702e47cSPaolo Bonzini uint32_t irl_out;
587702e47cSPaolo Bonzini } SLAVIO_CPUINTCTLState;
597702e47cSPaolo Bonzini
607abad863SAndreas Färber #define TYPE_SLAVIO_INTCTL "slavio_intctl"
618063396bSEduardo Habkost OBJECT_DECLARE_SIMPLE_TYPE(SLAVIO_INTCTLState, SLAVIO_INTCTL)
627abad863SAndreas Färber
63db1015e9SEduardo Habkost struct SLAVIO_INTCTLState {
647abad863SAndreas Färber SysBusDevice parent_obj;
657abad863SAndreas Färber
667702e47cSPaolo Bonzini MemoryRegion iomem;
677702e47cSPaolo Bonzini #ifdef DEBUG_IRQ_COUNT
687702e47cSPaolo Bonzini uint64_t irq_count[32];
697702e47cSPaolo Bonzini #endif
707702e47cSPaolo Bonzini qemu_irq cpu_irqs[MAX_CPUS][MAX_PILS];
717702e47cSPaolo Bonzini SLAVIO_CPUINTCTLState slaves[MAX_CPUS];
727702e47cSPaolo Bonzini uint32_t intregm_pending;
737702e47cSPaolo Bonzini uint32_t intregm_disabled;
747702e47cSPaolo Bonzini uint32_t target_cpu;
75db1015e9SEduardo Habkost };
767702e47cSPaolo Bonzini
777702e47cSPaolo Bonzini #define INTCTL_MAXADDR 0xf
787702e47cSPaolo Bonzini #define INTCTL_SIZE (INTCTL_MAXADDR + 1)
797702e47cSPaolo Bonzini #define INTCTLM_SIZE 0x14
807702e47cSPaolo Bonzini #define MASTER_IRQ_MASK ~0x0fa2007f
817702e47cSPaolo Bonzini #define MASTER_DISABLE 0x80000000
827702e47cSPaolo Bonzini #define CPU_SOFTIRQ_MASK 0xfffe0000
837702e47cSPaolo Bonzini #define CPU_IRQ_INT15_IN (1 << 15)
847702e47cSPaolo Bonzini #define CPU_IRQ_TIMER_IN (1 << 14)
857702e47cSPaolo Bonzini
867702e47cSPaolo Bonzini static void slavio_check_interrupts(SLAVIO_INTCTLState *s, int set_irqs);
877702e47cSPaolo Bonzini
887702e47cSPaolo Bonzini // per-cpu interrupt controller
slavio_intctl_mem_readl(void * opaque,hwaddr addr,unsigned size)897702e47cSPaolo Bonzini static uint64_t slavio_intctl_mem_readl(void *opaque, hwaddr addr,
907702e47cSPaolo Bonzini unsigned size)
917702e47cSPaolo Bonzini {
927702e47cSPaolo Bonzini SLAVIO_CPUINTCTLState *s = opaque;
937702e47cSPaolo Bonzini uint32_t saddr, ret;
947702e47cSPaolo Bonzini
957702e47cSPaolo Bonzini saddr = addr >> 2;
967702e47cSPaolo Bonzini switch (saddr) {
977702e47cSPaolo Bonzini case 0:
987702e47cSPaolo Bonzini ret = s->intreg_pending;
997702e47cSPaolo Bonzini break;
1007702e47cSPaolo Bonzini default:
1017702e47cSPaolo Bonzini ret = 0;
1027702e47cSPaolo Bonzini break;
1037702e47cSPaolo Bonzini }
1047702e47cSPaolo Bonzini trace_slavio_intctl_mem_readl(s->cpu, addr, ret);
1057702e47cSPaolo Bonzini
1067702e47cSPaolo Bonzini return ret;
1077702e47cSPaolo Bonzini }
1087702e47cSPaolo Bonzini
slavio_intctl_mem_writel(void * opaque,hwaddr addr,uint64_t val,unsigned size)1097702e47cSPaolo Bonzini static void slavio_intctl_mem_writel(void *opaque, hwaddr addr,
1107702e47cSPaolo Bonzini uint64_t val, unsigned size)
1117702e47cSPaolo Bonzini {
1127702e47cSPaolo Bonzini SLAVIO_CPUINTCTLState *s = opaque;
1137702e47cSPaolo Bonzini uint32_t saddr;
1147702e47cSPaolo Bonzini
1157702e47cSPaolo Bonzini saddr = addr >> 2;
1167702e47cSPaolo Bonzini trace_slavio_intctl_mem_writel(s->cpu, addr, val);
1177702e47cSPaolo Bonzini switch (saddr) {
1187702e47cSPaolo Bonzini case 1: // clear pending softints
1197702e47cSPaolo Bonzini val &= CPU_SOFTIRQ_MASK | CPU_IRQ_INT15_IN;
1207702e47cSPaolo Bonzini s->intreg_pending &= ~val;
1217702e47cSPaolo Bonzini slavio_check_interrupts(s->master, 1);
1227702e47cSPaolo Bonzini trace_slavio_intctl_mem_writel_clear(s->cpu, val, s->intreg_pending);
1237702e47cSPaolo Bonzini break;
1247702e47cSPaolo Bonzini case 2: // set softint
1257702e47cSPaolo Bonzini val &= CPU_SOFTIRQ_MASK;
1267702e47cSPaolo Bonzini s->intreg_pending |= val;
1277702e47cSPaolo Bonzini slavio_check_interrupts(s->master, 1);
1287702e47cSPaolo Bonzini trace_slavio_intctl_mem_writel_set(s->cpu, val, s->intreg_pending);
1297702e47cSPaolo Bonzini break;
1307702e47cSPaolo Bonzini default:
1317702e47cSPaolo Bonzini break;
1327702e47cSPaolo Bonzini }
1337702e47cSPaolo Bonzini }
1347702e47cSPaolo Bonzini
1357702e47cSPaolo Bonzini static const MemoryRegionOps slavio_intctl_mem_ops = {
1367702e47cSPaolo Bonzini .read = slavio_intctl_mem_readl,
1377702e47cSPaolo Bonzini .write = slavio_intctl_mem_writel,
1387702e47cSPaolo Bonzini .endianness = DEVICE_NATIVE_ENDIAN,
1397702e47cSPaolo Bonzini .valid = {
1407702e47cSPaolo Bonzini .min_access_size = 4,
1417702e47cSPaolo Bonzini .max_access_size = 4,
1427702e47cSPaolo Bonzini },
1437702e47cSPaolo Bonzini };
1447702e47cSPaolo Bonzini
1457702e47cSPaolo Bonzini // master system interrupt controller
slavio_intctlm_mem_readl(void * opaque,hwaddr addr,unsigned size)1467702e47cSPaolo Bonzini static uint64_t slavio_intctlm_mem_readl(void *opaque, hwaddr addr,
1477702e47cSPaolo Bonzini unsigned size)
1487702e47cSPaolo Bonzini {
1497702e47cSPaolo Bonzini SLAVIO_INTCTLState *s = opaque;
1507702e47cSPaolo Bonzini uint32_t saddr, ret;
1517702e47cSPaolo Bonzini
1527702e47cSPaolo Bonzini saddr = addr >> 2;
1537702e47cSPaolo Bonzini switch (saddr) {
1547702e47cSPaolo Bonzini case 0:
1557702e47cSPaolo Bonzini ret = s->intregm_pending & ~MASTER_DISABLE;
1567702e47cSPaolo Bonzini break;
1577702e47cSPaolo Bonzini case 1:
1587702e47cSPaolo Bonzini ret = s->intregm_disabled & MASTER_IRQ_MASK;
1597702e47cSPaolo Bonzini break;
1607702e47cSPaolo Bonzini case 4:
1617702e47cSPaolo Bonzini ret = s->target_cpu;
1627702e47cSPaolo Bonzini break;
1637702e47cSPaolo Bonzini default:
1647702e47cSPaolo Bonzini ret = 0;
1657702e47cSPaolo Bonzini break;
1667702e47cSPaolo Bonzini }
1677702e47cSPaolo Bonzini trace_slavio_intctlm_mem_readl(addr, ret);
1687702e47cSPaolo Bonzini
1697702e47cSPaolo Bonzini return ret;
1707702e47cSPaolo Bonzini }
1717702e47cSPaolo Bonzini
slavio_intctlm_mem_writel(void * opaque,hwaddr addr,uint64_t val,unsigned size)1727702e47cSPaolo Bonzini static void slavio_intctlm_mem_writel(void *opaque, hwaddr addr,
1737702e47cSPaolo Bonzini uint64_t val, unsigned size)
1747702e47cSPaolo Bonzini {
1757702e47cSPaolo Bonzini SLAVIO_INTCTLState *s = opaque;
1767702e47cSPaolo Bonzini uint32_t saddr;
1777702e47cSPaolo Bonzini
1787702e47cSPaolo Bonzini saddr = addr >> 2;
1797702e47cSPaolo Bonzini trace_slavio_intctlm_mem_writel(addr, val);
1807702e47cSPaolo Bonzini switch (saddr) {
1817702e47cSPaolo Bonzini case 2: // clear (enable)
1827702e47cSPaolo Bonzini // Force clear unused bits
1837702e47cSPaolo Bonzini val &= MASTER_IRQ_MASK;
1847702e47cSPaolo Bonzini s->intregm_disabled &= ~val;
1857702e47cSPaolo Bonzini trace_slavio_intctlm_mem_writel_enable(val, s->intregm_disabled);
1867702e47cSPaolo Bonzini slavio_check_interrupts(s, 1);
1877702e47cSPaolo Bonzini break;
1887702e47cSPaolo Bonzini case 3: // set (disable; doesn't affect pending)
1897702e47cSPaolo Bonzini // Force clear unused bits
1907702e47cSPaolo Bonzini val &= MASTER_IRQ_MASK;
1917702e47cSPaolo Bonzini s->intregm_disabled |= val;
1927702e47cSPaolo Bonzini slavio_check_interrupts(s, 1);
1937702e47cSPaolo Bonzini trace_slavio_intctlm_mem_writel_disable(val, s->intregm_disabled);
1947702e47cSPaolo Bonzini break;
1957702e47cSPaolo Bonzini case 4:
1967702e47cSPaolo Bonzini s->target_cpu = val & (MAX_CPUS - 1);
1977702e47cSPaolo Bonzini slavio_check_interrupts(s, 1);
1987702e47cSPaolo Bonzini trace_slavio_intctlm_mem_writel_target(s->target_cpu);
1997702e47cSPaolo Bonzini break;
2007702e47cSPaolo Bonzini default:
2017702e47cSPaolo Bonzini break;
2027702e47cSPaolo Bonzini }
2037702e47cSPaolo Bonzini }
2047702e47cSPaolo Bonzini
2057702e47cSPaolo Bonzini static const MemoryRegionOps slavio_intctlm_mem_ops = {
2067702e47cSPaolo Bonzini .read = slavio_intctlm_mem_readl,
2077702e47cSPaolo Bonzini .write = slavio_intctlm_mem_writel,
2087702e47cSPaolo Bonzini .endianness = DEVICE_NATIVE_ENDIAN,
2097702e47cSPaolo Bonzini .valid = {
2107702e47cSPaolo Bonzini .min_access_size = 4,
2117702e47cSPaolo Bonzini .max_access_size = 4,
2127702e47cSPaolo Bonzini },
2137702e47cSPaolo Bonzini };
2147702e47cSPaolo Bonzini
2157702e47cSPaolo Bonzini static const uint32_t intbit_to_level[] = {
2167702e47cSPaolo Bonzini 2, 3, 5, 7, 9, 11, 13, 2, 3, 5, 7, 9, 11, 13, 12, 12,
2177702e47cSPaolo Bonzini 6, 13, 4, 10, 8, 9, 11, 0, 0, 0, 0, 15, 15, 15, 15, 0,
2187702e47cSPaolo Bonzini };
2197702e47cSPaolo Bonzini
slavio_check_interrupts(SLAVIO_INTCTLState * s,int set_irqs)2207702e47cSPaolo Bonzini static void slavio_check_interrupts(SLAVIO_INTCTLState *s, int set_irqs)
2217702e47cSPaolo Bonzini {
2227702e47cSPaolo Bonzini uint32_t pending = s->intregm_pending, pil_pending;
2237702e47cSPaolo Bonzini unsigned int i, j;
2247702e47cSPaolo Bonzini
2257702e47cSPaolo Bonzini pending &= ~s->intregm_disabled;
2267702e47cSPaolo Bonzini
2277702e47cSPaolo Bonzini trace_slavio_check_interrupts(pending, s->intregm_disabled);
2287702e47cSPaolo Bonzini for (i = 0; i < MAX_CPUS; i++) {
2297702e47cSPaolo Bonzini pil_pending = 0;
2307702e47cSPaolo Bonzini
2317702e47cSPaolo Bonzini /* If we are the current interrupt target, get hard interrupts */
2327702e47cSPaolo Bonzini if (pending && !(s->intregm_disabled & MASTER_DISABLE) &&
2337702e47cSPaolo Bonzini (i == s->target_cpu)) {
2347702e47cSPaolo Bonzini for (j = 0; j < 32; j++) {
2357702e47cSPaolo Bonzini if ((pending & (1 << j)) && intbit_to_level[j]) {
2367702e47cSPaolo Bonzini pil_pending |= 1 << intbit_to_level[j];
2377702e47cSPaolo Bonzini }
2387702e47cSPaolo Bonzini }
2397702e47cSPaolo Bonzini }
2407702e47cSPaolo Bonzini
2417702e47cSPaolo Bonzini /* Calculate current pending hard interrupts for display */
2427702e47cSPaolo Bonzini s->slaves[i].intreg_pending &= CPU_SOFTIRQ_MASK | CPU_IRQ_INT15_IN |
2437702e47cSPaolo Bonzini CPU_IRQ_TIMER_IN;
2447702e47cSPaolo Bonzini if (i == s->target_cpu) {
2457702e47cSPaolo Bonzini for (j = 0; j < 32; j++) {
2467d45e784SPeter Maydell if ((s->intregm_pending & (1U << j)) && intbit_to_level[j]) {
2477702e47cSPaolo Bonzini s->slaves[i].intreg_pending |= 1 << intbit_to_level[j];
2487702e47cSPaolo Bonzini }
2497702e47cSPaolo Bonzini }
2507702e47cSPaolo Bonzini }
2517702e47cSPaolo Bonzini
2527702e47cSPaolo Bonzini /* Level 15 and CPU timer interrupts are only masked when
2537702e47cSPaolo Bonzini the MASTER_DISABLE bit is set */
2547702e47cSPaolo Bonzini if (!(s->intregm_disabled & MASTER_DISABLE)) {
2557702e47cSPaolo Bonzini pil_pending |= s->slaves[i].intreg_pending &
2567702e47cSPaolo Bonzini (CPU_IRQ_INT15_IN | CPU_IRQ_TIMER_IN);
2577702e47cSPaolo Bonzini }
2587702e47cSPaolo Bonzini
2597702e47cSPaolo Bonzini /* Add soft interrupts */
2607702e47cSPaolo Bonzini pil_pending |= (s->slaves[i].intreg_pending & CPU_SOFTIRQ_MASK) >> 16;
2617702e47cSPaolo Bonzini
2627702e47cSPaolo Bonzini if (set_irqs) {
2637702e47cSPaolo Bonzini /* Since there is not really an interrupt 0 (and pil_pending
2647702e47cSPaolo Bonzini * and irl_out bit zero are thus always zero) there is no need
2657702e47cSPaolo Bonzini * to do anything with cpu_irqs[i][0] and it is OK not to do
2667702e47cSPaolo Bonzini * the j=0 iteration of this loop.
2677702e47cSPaolo Bonzini */
2687702e47cSPaolo Bonzini for (j = MAX_PILS-1; j > 0; j--) {
2697702e47cSPaolo Bonzini if (pil_pending & (1 << j)) {
2707702e47cSPaolo Bonzini if (!(s->slaves[i].irl_out & (1 << j))) {
2717702e47cSPaolo Bonzini qemu_irq_raise(s->cpu_irqs[i][j]);
2727702e47cSPaolo Bonzini }
2737702e47cSPaolo Bonzini } else {
2747702e47cSPaolo Bonzini if (s->slaves[i].irl_out & (1 << j)) {
2757702e47cSPaolo Bonzini qemu_irq_lower(s->cpu_irqs[i][j]);
2767702e47cSPaolo Bonzini }
2777702e47cSPaolo Bonzini }
2787702e47cSPaolo Bonzini }
2797702e47cSPaolo Bonzini }
2807702e47cSPaolo Bonzini s->slaves[i].irl_out = pil_pending;
2817702e47cSPaolo Bonzini }
2827702e47cSPaolo Bonzini }
2837702e47cSPaolo Bonzini
2847702e47cSPaolo Bonzini /*
2857702e47cSPaolo Bonzini * "irq" here is the bit number in the system interrupt register to
2867702e47cSPaolo Bonzini * separate serial and keyboard interrupts sharing a level.
2877702e47cSPaolo Bonzini */
slavio_set_irq(void * opaque,int irq,int level)2887702e47cSPaolo Bonzini static void slavio_set_irq(void *opaque, int irq, int level)
2897702e47cSPaolo Bonzini {
2907702e47cSPaolo Bonzini SLAVIO_INTCTLState *s = opaque;
2917702e47cSPaolo Bonzini uint32_t mask = 1 << irq;
2927702e47cSPaolo Bonzini uint32_t pil = intbit_to_level[irq];
2937702e47cSPaolo Bonzini unsigned int i;
2947702e47cSPaolo Bonzini
2957702e47cSPaolo Bonzini trace_slavio_set_irq(s->target_cpu, irq, pil, level);
2967702e47cSPaolo Bonzini if (pil > 0) {
2977702e47cSPaolo Bonzini if (level) {
2987702e47cSPaolo Bonzini #ifdef DEBUG_IRQ_COUNT
2997702e47cSPaolo Bonzini s->irq_count[pil]++;
3007702e47cSPaolo Bonzini #endif
3017702e47cSPaolo Bonzini s->intregm_pending |= mask;
3027702e47cSPaolo Bonzini if (pil == 15) {
3037702e47cSPaolo Bonzini for (i = 0; i < MAX_CPUS; i++) {
3047702e47cSPaolo Bonzini s->slaves[i].intreg_pending |= 1 << pil;
3057702e47cSPaolo Bonzini }
3067702e47cSPaolo Bonzini }
3077702e47cSPaolo Bonzini } else {
3087702e47cSPaolo Bonzini s->intregm_pending &= ~mask;
3097702e47cSPaolo Bonzini if (pil == 15) {
3107702e47cSPaolo Bonzini for (i = 0; i < MAX_CPUS; i++) {
3117702e47cSPaolo Bonzini s->slaves[i].intreg_pending &= ~(1 << pil);
3127702e47cSPaolo Bonzini }
3137702e47cSPaolo Bonzini }
3147702e47cSPaolo Bonzini }
3157702e47cSPaolo Bonzini slavio_check_interrupts(s, 1);
3167702e47cSPaolo Bonzini }
3177702e47cSPaolo Bonzini }
3187702e47cSPaolo Bonzini
slavio_set_timer_irq_cpu(void * opaque,int cpu,int level)3197702e47cSPaolo Bonzini static void slavio_set_timer_irq_cpu(void *opaque, int cpu, int level)
3207702e47cSPaolo Bonzini {
3217702e47cSPaolo Bonzini SLAVIO_INTCTLState *s = opaque;
3227702e47cSPaolo Bonzini
3237702e47cSPaolo Bonzini trace_slavio_set_timer_irq_cpu(cpu, level);
3247702e47cSPaolo Bonzini
3257702e47cSPaolo Bonzini if (level) {
3267702e47cSPaolo Bonzini s->slaves[cpu].intreg_pending |= CPU_IRQ_TIMER_IN;
3277702e47cSPaolo Bonzini } else {
3287702e47cSPaolo Bonzini s->slaves[cpu].intreg_pending &= ~CPU_IRQ_TIMER_IN;
3297702e47cSPaolo Bonzini }
3307702e47cSPaolo Bonzini
3317702e47cSPaolo Bonzini slavio_check_interrupts(s, 1);
3327702e47cSPaolo Bonzini }
3337702e47cSPaolo Bonzini
slavio_set_irq_all(void * opaque,int irq,int level)3347702e47cSPaolo Bonzini static void slavio_set_irq_all(void *opaque, int irq, int level)
3357702e47cSPaolo Bonzini {
3367702e47cSPaolo Bonzini if (irq < 32) {
3377702e47cSPaolo Bonzini slavio_set_irq(opaque, irq, level);
3387702e47cSPaolo Bonzini } else {
3397702e47cSPaolo Bonzini slavio_set_timer_irq_cpu(opaque, irq - 32, level);
3407702e47cSPaolo Bonzini }
3417702e47cSPaolo Bonzini }
3427702e47cSPaolo Bonzini
vmstate_intctl_post_load(void * opaque,int version_id)3437702e47cSPaolo Bonzini static int vmstate_intctl_post_load(void *opaque, int version_id)
3447702e47cSPaolo Bonzini {
3457702e47cSPaolo Bonzini SLAVIO_INTCTLState *s = opaque;
3467702e47cSPaolo Bonzini
3477702e47cSPaolo Bonzini slavio_check_interrupts(s, 0);
3487702e47cSPaolo Bonzini return 0;
3497702e47cSPaolo Bonzini }
3507702e47cSPaolo Bonzini
3517702e47cSPaolo Bonzini static const VMStateDescription vmstate_intctl_cpu = {
3527702e47cSPaolo Bonzini .name ="slavio_intctl_cpu",
3537702e47cSPaolo Bonzini .version_id = 1,
3547702e47cSPaolo Bonzini .minimum_version_id = 1,
35545b1f81dSRichard Henderson .fields = (const VMStateField[]) {
3567702e47cSPaolo Bonzini VMSTATE_UINT32(intreg_pending, SLAVIO_CPUINTCTLState),
3577702e47cSPaolo Bonzini VMSTATE_END_OF_LIST()
3587702e47cSPaolo Bonzini }
3597702e47cSPaolo Bonzini };
3607702e47cSPaolo Bonzini
3617702e47cSPaolo Bonzini static const VMStateDescription vmstate_intctl = {
3627702e47cSPaolo Bonzini .name ="slavio_intctl",
3637702e47cSPaolo Bonzini .version_id = 1,
3647702e47cSPaolo Bonzini .minimum_version_id = 1,
3657702e47cSPaolo Bonzini .post_load = vmstate_intctl_post_load,
36645b1f81dSRichard Henderson .fields = (const VMStateField[]) {
3677702e47cSPaolo Bonzini VMSTATE_STRUCT_ARRAY(slaves, SLAVIO_INTCTLState, MAX_CPUS, 1,
3687702e47cSPaolo Bonzini vmstate_intctl_cpu, SLAVIO_CPUINTCTLState),
3697702e47cSPaolo Bonzini VMSTATE_UINT32(intregm_pending, SLAVIO_INTCTLState),
3707702e47cSPaolo Bonzini VMSTATE_UINT32(intregm_disabled, SLAVIO_INTCTLState),
3717702e47cSPaolo Bonzini VMSTATE_UINT32(target_cpu, SLAVIO_INTCTLState),
3727702e47cSPaolo Bonzini VMSTATE_END_OF_LIST()
3737702e47cSPaolo Bonzini }
3747702e47cSPaolo Bonzini };
3757702e47cSPaolo Bonzini
slavio_intctl_reset(DeviceState * d)3767702e47cSPaolo Bonzini static void slavio_intctl_reset(DeviceState *d)
3777702e47cSPaolo Bonzini {
3787abad863SAndreas Färber SLAVIO_INTCTLState *s = SLAVIO_INTCTL(d);
3797702e47cSPaolo Bonzini int i;
3807702e47cSPaolo Bonzini
3817702e47cSPaolo Bonzini for (i = 0; i < MAX_CPUS; i++) {
3827702e47cSPaolo Bonzini s->slaves[i].intreg_pending = 0;
3837702e47cSPaolo Bonzini s->slaves[i].irl_out = 0;
3847702e47cSPaolo Bonzini }
3857702e47cSPaolo Bonzini s->intregm_disabled = ~MASTER_IRQ_MASK;
3867702e47cSPaolo Bonzini s->intregm_pending = 0;
3877702e47cSPaolo Bonzini s->target_cpu = 0;
3887702e47cSPaolo Bonzini slavio_check_interrupts(s, 0);
3897702e47cSPaolo Bonzini }
3907702e47cSPaolo Bonzini
391148fbe95SHervé Poussineau #ifdef DEBUG_IRQ_COUNT
slavio_intctl_get_statistics(InterruptStatsProvider * obj,uint64_t ** irq_counts,unsigned int * nb_irqs)392148fbe95SHervé Poussineau static bool slavio_intctl_get_statistics(InterruptStatsProvider *obj,
393148fbe95SHervé Poussineau uint64_t **irq_counts,
394148fbe95SHervé Poussineau unsigned int *nb_irqs)
395148fbe95SHervé Poussineau {
396148fbe95SHervé Poussineau SLAVIO_INTCTLState *s = SLAVIO_INTCTL(obj);
397148fbe95SHervé Poussineau *irq_counts = s->irq_count;
398148fbe95SHervé Poussineau *nb_irqs = ARRAY_SIZE(s->irq_count);
399148fbe95SHervé Poussineau return true;
400148fbe95SHervé Poussineau }
401148fbe95SHervé Poussineau #endif
402148fbe95SHervé Poussineau
slavio_intctl_print_info(InterruptStatsProvider * obj,GString * buf)403b2580720SPhilippe Mathieu-Daudé static void slavio_intctl_print_info(InterruptStatsProvider *obj, GString *buf)
404148fbe95SHervé Poussineau {
405148fbe95SHervé Poussineau SLAVIO_INTCTLState *s = SLAVIO_INTCTL(obj);
406148fbe95SHervé Poussineau int i;
407148fbe95SHervé Poussineau
408148fbe95SHervé Poussineau for (i = 0; i < MAX_CPUS; i++) {
409b2580720SPhilippe Mathieu-Daudé g_string_append_printf(buf, "per-cpu %d: pending 0x%08x\n", i,
410148fbe95SHervé Poussineau s->slaves[i].intreg_pending);
411148fbe95SHervé Poussineau }
412b2580720SPhilippe Mathieu-Daudé g_string_append_printf(buf, "master: pending 0x%08x, disabled 0x%08x\n",
413148fbe95SHervé Poussineau s->intregm_pending, s->intregm_disabled);
414148fbe95SHervé Poussineau }
415148fbe95SHervé Poussineau
slavio_intctl_init(Object * obj)416c09008d2Sxiaoqiang.zhao static void slavio_intctl_init(Object *obj)
4177702e47cSPaolo Bonzini {
418c09008d2Sxiaoqiang.zhao DeviceState *dev = DEVICE(obj);
419c09008d2Sxiaoqiang.zhao SLAVIO_INTCTLState *s = SLAVIO_INTCTL(obj);
420c09008d2Sxiaoqiang.zhao SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
4217702e47cSPaolo Bonzini unsigned int i, j;
4227702e47cSPaolo Bonzini char slave_name[45];
4237702e47cSPaolo Bonzini
4247abad863SAndreas Färber qdev_init_gpio_in(dev, slavio_set_irq_all, 32 + MAX_CPUS);
425c09008d2Sxiaoqiang.zhao memory_region_init_io(&s->iomem, obj, &slavio_intctlm_mem_ops, s,
4267702e47cSPaolo Bonzini "master-interrupt-controller", INTCTLM_SIZE);
4277abad863SAndreas Färber sysbus_init_mmio(sbd, &s->iomem);
4287702e47cSPaolo Bonzini
4297702e47cSPaolo Bonzini for (i = 0; i < MAX_CPUS; i++) {
4307702e47cSPaolo Bonzini snprintf(slave_name, sizeof(slave_name),
4317702e47cSPaolo Bonzini "slave-interrupt-controller-%i", i);
4327702e47cSPaolo Bonzini for (j = 0; j < MAX_PILS; j++) {
4337abad863SAndreas Färber sysbus_init_irq(sbd, &s->cpu_irqs[i][j]);
4347702e47cSPaolo Bonzini }
4351437c94bSPaolo Bonzini memory_region_init_io(&s->slaves[i].iomem, OBJECT(s),
4361437c94bSPaolo Bonzini &slavio_intctl_mem_ops,
4377702e47cSPaolo Bonzini &s->slaves[i], slave_name, INTCTL_SIZE);
4387abad863SAndreas Färber sysbus_init_mmio(sbd, &s->slaves[i].iomem);
4397702e47cSPaolo Bonzini s->slaves[i].cpu = i;
4407702e47cSPaolo Bonzini s->slaves[i].master = s;
4417702e47cSPaolo Bonzini }
4427702e47cSPaolo Bonzini }
4437702e47cSPaolo Bonzini
slavio_intctl_class_init(ObjectClass * klass,void * data)4447702e47cSPaolo Bonzini static void slavio_intctl_class_init(ObjectClass *klass, void *data)
4457702e47cSPaolo Bonzini {
4467702e47cSPaolo Bonzini DeviceClass *dc = DEVICE_CLASS(klass);
447148fbe95SHervé Poussineau InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(klass);
4487702e47cSPaolo Bonzini
449*e3d08143SPeter Maydell device_class_set_legacy_reset(dc, slavio_intctl_reset);
4507702e47cSPaolo Bonzini dc->vmsd = &vmstate_intctl;
451148fbe95SHervé Poussineau #ifdef DEBUG_IRQ_COUNT
452148fbe95SHervé Poussineau ic->get_statistics = slavio_intctl_get_statistics;
453148fbe95SHervé Poussineau #endif
454148fbe95SHervé Poussineau ic->print_info = slavio_intctl_print_info;
4557702e47cSPaolo Bonzini }
4567702e47cSPaolo Bonzini
4577702e47cSPaolo Bonzini static const TypeInfo slavio_intctl_info = {
4587abad863SAndreas Färber .name = TYPE_SLAVIO_INTCTL,
4597702e47cSPaolo Bonzini .parent = TYPE_SYS_BUS_DEVICE,
4607702e47cSPaolo Bonzini .instance_size = sizeof(SLAVIO_INTCTLState),
461c09008d2Sxiaoqiang.zhao .instance_init = slavio_intctl_init,
4627702e47cSPaolo Bonzini .class_init = slavio_intctl_class_init,
463148fbe95SHervé Poussineau .interfaces = (InterfaceInfo[]) {
464148fbe95SHervé Poussineau { TYPE_INTERRUPT_STATS_PROVIDER },
465148fbe95SHervé Poussineau { }
466148fbe95SHervé Poussineau },
4677702e47cSPaolo Bonzini };
4687702e47cSPaolo Bonzini
slavio_intctl_register_types(void)4697702e47cSPaolo Bonzini static void slavio_intctl_register_types(void)
4707702e47cSPaolo Bonzini {
4717702e47cSPaolo Bonzini type_register_static(&slavio_intctl_info);
4727702e47cSPaolo Bonzini }
4737702e47cSPaolo Bonzini
4747702e47cSPaolo Bonzini type_init(slavio_intctl_register_types)
475