1e80cfcfcSbellard /* 2e80cfcfcSbellard * QEMU Sparc SLAVIO interrupt controller emulation 3e80cfcfcSbellard * 466321a11Sbellard * Copyright (c) 2003-2005 Fabrice Bellard 5e80cfcfcSbellard * 6e80cfcfcSbellard * Permission is hereby granted, free of charge, to any person obtaining a copy 7e80cfcfcSbellard * of this software and associated documentation files (the "Software"), to deal 8e80cfcfcSbellard * in the Software without restriction, including without limitation the rights 9e80cfcfcSbellard * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10e80cfcfcSbellard * copies of the Software, and to permit persons to whom the Software is 11e80cfcfcSbellard * furnished to do so, subject to the following conditions: 12e80cfcfcSbellard * 13e80cfcfcSbellard * The above copyright notice and this permission notice shall be included in 14e80cfcfcSbellard * all copies or substantial portions of the Software. 15e80cfcfcSbellard * 16e80cfcfcSbellard * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17e80cfcfcSbellard * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18e80cfcfcSbellard * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19e80cfcfcSbellard * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20e80cfcfcSbellard * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21e80cfcfcSbellard * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22e80cfcfcSbellard * THE SOFTWARE. 23e80cfcfcSbellard */ 24a1961a4bSBlue Swirl 2590191d07SPeter Maydell #include "qemu/osdep.h" 260d09e41aSPaolo Bonzini #include "hw/sparc/sun4m.h" 2783c9089eSPaolo Bonzini #include "monitor/monitor.h" 2883c9f4caSPaolo Bonzini #include "hw/sysbus.h" 29*148fbe95SHervé Poussineau #include "hw/intc/intc.h" 3097bf4851SBlue Swirl #include "trace.h" 3187ecb68bSpbrook 32e80cfcfcSbellard //#define DEBUG_IRQ_COUNT 33e80cfcfcSbellard 34e80cfcfcSbellard /* 35e80cfcfcSbellard * Registers of interrupt controller in sun4m. 36e80cfcfcSbellard * 37e80cfcfcSbellard * This is the interrupt controller part of chip STP2001 (Slave I/O), also 38e80cfcfcSbellard * produced as NCR89C105. See 39e80cfcfcSbellard * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt 40e80cfcfcSbellard * 41e80cfcfcSbellard * There is a system master controller and one for each cpu. 42e80cfcfcSbellard * 43e80cfcfcSbellard */ 44e80cfcfcSbellard 45e80cfcfcSbellard #define MAX_CPUS 16 46b3a23197Sblueswir1 #define MAX_PILS 16 47e80cfcfcSbellard 48a1961a4bSBlue Swirl struct SLAVIO_INTCTLState; 49a1961a4bSBlue Swirl 50a1961a4bSBlue Swirl typedef struct SLAVIO_CPUINTCTLState { 518bb5ef33SBenoît Canet MemoryRegion iomem; 52a1961a4bSBlue Swirl struct SLAVIO_INTCTLState *master; 5307dd0035SBlue Swirl uint32_t intreg_pending; 54a1961a4bSBlue Swirl uint32_t cpu; 55462eda24SBlue Swirl uint32_t irl_out; 56a1961a4bSBlue Swirl } SLAVIO_CPUINTCTLState; 57a8f48dccSblueswir1 587abad863SAndreas Färber #define TYPE_SLAVIO_INTCTL "slavio_intctl" 597abad863SAndreas Färber #define SLAVIO_INTCTL(obj) \ 607abad863SAndreas Färber OBJECT_CHECK(SLAVIO_INTCTLState, (obj), TYPE_SLAVIO_INTCTL) 617abad863SAndreas Färber 62e80cfcfcSbellard typedef struct SLAVIO_INTCTLState { 637abad863SAndreas Färber SysBusDevice parent_obj; 647abad863SAndreas Färber 6513c89a11SBenoît Canet MemoryRegion iomem; 66e80cfcfcSbellard #ifdef DEBUG_IRQ_COUNT 67e80cfcfcSbellard uint64_t irq_count[32]; 68e80cfcfcSbellard #endif 69a1961a4bSBlue Swirl qemu_irq cpu_irqs[MAX_CPUS][MAX_PILS]; 70a1961a4bSBlue Swirl SLAVIO_CPUINTCTLState slaves[MAX_CPUS]; 7107dd0035SBlue Swirl uint32_t intregm_pending; 7207dd0035SBlue Swirl uint32_t intregm_disabled; 7307dd0035SBlue Swirl uint32_t target_cpu; 74e80cfcfcSbellard } SLAVIO_INTCTLState; 75e80cfcfcSbellard 76e80cfcfcSbellard #define INTCTL_MAXADDR 0xf 775aca8c3bSblueswir1 #define INTCTL_SIZE (INTCTL_MAXADDR + 1) 78a8f48dccSblueswir1 #define INTCTLM_SIZE 0x14 7980be36b8Sblueswir1 #define MASTER_IRQ_MASK ~0x0fa2007f 809a87ce9bSblueswir1 #define MASTER_DISABLE 0x80000000 816341fdcbSblueswir1 #define CPU_SOFTIRQ_MASK 0xfffe0000 82462eda24SBlue Swirl #define CPU_IRQ_INT15_IN (1 << 15) 83462eda24SBlue Swirl #define CPU_IRQ_TIMER_IN (1 << 14) 849a87ce9bSblueswir1 850d0a7e69SBlue Swirl static void slavio_check_interrupts(SLAVIO_INTCTLState *s, int set_irqs); 86e80cfcfcSbellard 87e80cfcfcSbellard // per-cpu interrupt controller 88a8170e5eSAvi Kivity static uint64_t slavio_intctl_mem_readl(void *opaque, hwaddr addr, 898bb5ef33SBenoît Canet unsigned size) 90e80cfcfcSbellard { 91a8f48dccSblueswir1 SLAVIO_CPUINTCTLState *s = opaque; 92dd4131b3Sblueswir1 uint32_t saddr, ret; 93e80cfcfcSbellard 94a8f48dccSblueswir1 saddr = addr >> 2; 95e80cfcfcSbellard switch (saddr) { 96e80cfcfcSbellard case 0: 97a8f48dccSblueswir1 ret = s->intreg_pending; 98dd4131b3Sblueswir1 break; 99e80cfcfcSbellard default: 100dd4131b3Sblueswir1 ret = 0; 101e80cfcfcSbellard break; 102e80cfcfcSbellard } 10397bf4851SBlue Swirl trace_slavio_intctl_mem_readl(s->cpu, addr, ret); 104dd4131b3Sblueswir1 105dd4131b3Sblueswir1 return ret; 106e80cfcfcSbellard } 107e80cfcfcSbellard 108a8170e5eSAvi Kivity static void slavio_intctl_mem_writel(void *opaque, hwaddr addr, 1098bb5ef33SBenoît Canet uint64_t val, unsigned size) 110e80cfcfcSbellard { 111a8f48dccSblueswir1 SLAVIO_CPUINTCTLState *s = opaque; 112e80cfcfcSbellard uint32_t saddr; 113e80cfcfcSbellard 114a8f48dccSblueswir1 saddr = addr >> 2; 11597bf4851SBlue Swirl trace_slavio_intctl_mem_writel(s->cpu, addr, val); 116e80cfcfcSbellard switch (saddr) { 117e80cfcfcSbellard case 1: // clear pending softints 118462eda24SBlue Swirl val &= CPU_SOFTIRQ_MASK | CPU_IRQ_INT15_IN; 119a8f48dccSblueswir1 s->intreg_pending &= ~val; 1200d0a7e69SBlue Swirl slavio_check_interrupts(s->master, 1); 12197bf4851SBlue Swirl trace_slavio_intctl_mem_writel_clear(s->cpu, val, s->intreg_pending); 122e80cfcfcSbellard break; 123e80cfcfcSbellard case 2: // set softint 1246341fdcbSblueswir1 val &= CPU_SOFTIRQ_MASK; 125a8f48dccSblueswir1 s->intreg_pending |= val; 1260d0a7e69SBlue Swirl slavio_check_interrupts(s->master, 1); 12797bf4851SBlue Swirl trace_slavio_intctl_mem_writel_set(s->cpu, val, s->intreg_pending); 128e80cfcfcSbellard break; 129e80cfcfcSbellard default: 130e80cfcfcSbellard break; 131e80cfcfcSbellard } 132e80cfcfcSbellard } 133e80cfcfcSbellard 1348bb5ef33SBenoît Canet static const MemoryRegionOps slavio_intctl_mem_ops = { 1358bb5ef33SBenoît Canet .read = slavio_intctl_mem_readl, 1368bb5ef33SBenoît Canet .write = slavio_intctl_mem_writel, 1378bb5ef33SBenoît Canet .endianness = DEVICE_NATIVE_ENDIAN, 1388bb5ef33SBenoît Canet .valid = { 1398bb5ef33SBenoît Canet .min_access_size = 4, 1408bb5ef33SBenoît Canet .max_access_size = 4, 1418bb5ef33SBenoît Canet }, 142e80cfcfcSbellard }; 143e80cfcfcSbellard 144e80cfcfcSbellard // master system interrupt controller 145a8170e5eSAvi Kivity static uint64_t slavio_intctlm_mem_readl(void *opaque, hwaddr addr, 14613c89a11SBenoît Canet unsigned size) 147e80cfcfcSbellard { 148e80cfcfcSbellard SLAVIO_INTCTLState *s = opaque; 149dd4131b3Sblueswir1 uint32_t saddr, ret; 150e80cfcfcSbellard 151a8f48dccSblueswir1 saddr = addr >> 2; 152e80cfcfcSbellard switch (saddr) { 153e80cfcfcSbellard case 0: 1549a87ce9bSblueswir1 ret = s->intregm_pending & ~MASTER_DISABLE; 155dd4131b3Sblueswir1 break; 156e80cfcfcSbellard case 1: 15780be36b8Sblueswir1 ret = s->intregm_disabled & MASTER_IRQ_MASK; 158dd4131b3Sblueswir1 break; 159e80cfcfcSbellard case 4: 160dd4131b3Sblueswir1 ret = s->target_cpu; 161dd4131b3Sblueswir1 break; 162e80cfcfcSbellard default: 163dd4131b3Sblueswir1 ret = 0; 164e80cfcfcSbellard break; 165e80cfcfcSbellard } 16697bf4851SBlue Swirl trace_slavio_intctlm_mem_readl(addr, ret); 167dd4131b3Sblueswir1 168dd4131b3Sblueswir1 return ret; 169e80cfcfcSbellard } 170e80cfcfcSbellard 171a8170e5eSAvi Kivity static void slavio_intctlm_mem_writel(void *opaque, hwaddr addr, 17213c89a11SBenoît Canet uint64_t val, unsigned size) 173e80cfcfcSbellard { 174e80cfcfcSbellard SLAVIO_INTCTLState *s = opaque; 175e80cfcfcSbellard uint32_t saddr; 176e80cfcfcSbellard 177a8f48dccSblueswir1 saddr = addr >> 2; 17897bf4851SBlue Swirl trace_slavio_intctlm_mem_writel(addr, val); 179e80cfcfcSbellard switch (saddr) { 180e80cfcfcSbellard case 2: // clear (enable) 1816bae7071Sbellard // Force clear unused bits 1829a87ce9bSblueswir1 val &= MASTER_IRQ_MASK; 183e80cfcfcSbellard s->intregm_disabled &= ~val; 18497bf4851SBlue Swirl trace_slavio_intctlm_mem_writel_enable(val, s->intregm_disabled); 1850d0a7e69SBlue Swirl slavio_check_interrupts(s, 1); 186e80cfcfcSbellard break; 18710760f0fSArtyom Tarasenko case 3: // set (disable; doesn't affect pending) 1886bae7071Sbellard // Force clear unused bits 1899a87ce9bSblueswir1 val &= MASTER_IRQ_MASK; 190e80cfcfcSbellard s->intregm_disabled |= val; 1910d0a7e69SBlue Swirl slavio_check_interrupts(s, 1); 19297bf4851SBlue Swirl trace_slavio_intctlm_mem_writel_disable(val, s->intregm_disabled); 193e80cfcfcSbellard break; 194e80cfcfcSbellard case 4: 195e80cfcfcSbellard s->target_cpu = val & (MAX_CPUS - 1); 1960d0a7e69SBlue Swirl slavio_check_interrupts(s, 1); 19797bf4851SBlue Swirl trace_slavio_intctlm_mem_writel_target(s->target_cpu); 198e80cfcfcSbellard break; 199e80cfcfcSbellard default: 200e80cfcfcSbellard break; 201e80cfcfcSbellard } 202e80cfcfcSbellard } 203e80cfcfcSbellard 20413c89a11SBenoît Canet static const MemoryRegionOps slavio_intctlm_mem_ops = { 20513c89a11SBenoît Canet .read = slavio_intctlm_mem_readl, 20613c89a11SBenoît Canet .write = slavio_intctlm_mem_writel, 20713c89a11SBenoît Canet .endianness = DEVICE_NATIVE_ENDIAN, 20813c89a11SBenoît Canet .valid = { 20913c89a11SBenoît Canet .min_access_size = 4, 21013c89a11SBenoît Canet .max_access_size = 4, 21113c89a11SBenoît Canet }, 212e80cfcfcSbellard }; 213e80cfcfcSbellard 214d453c2c3SBlue Swirl void slavio_pic_info(Monitor *mon, DeviceState *dev) 215e80cfcfcSbellard { 2167abad863SAndreas Färber SLAVIO_INTCTLState *s = SLAVIO_INTCTL(dev); 217e80cfcfcSbellard int i; 218e80cfcfcSbellard 219e80cfcfcSbellard for (i = 0; i < MAX_CPUS; i++) { 220376253ecSaliguori monitor_printf(mon, "per-cpu %d: pending 0x%08x\n", i, 221a1961a4bSBlue Swirl s->slaves[i].intreg_pending); 222e80cfcfcSbellard } 223376253ecSaliguori monitor_printf(mon, "master: pending 0x%08x, disabled 0x%08x\n", 22477f193daSblueswir1 s->intregm_pending, s->intregm_disabled); 225e80cfcfcSbellard } 226e80cfcfcSbellard 227d453c2c3SBlue Swirl void slavio_irq_info(Monitor *mon, DeviceState *dev) 228e80cfcfcSbellard { 229e80cfcfcSbellard #ifndef DEBUG_IRQ_COUNT 230376253ecSaliguori monitor_printf(mon, "irq statistic code not compiled.\n"); 231e80cfcfcSbellard #else 2327abad863SAndreas Färber SLAVIO_INTCTLState *s = SLAVIO_INTCTL(dev); 233e80cfcfcSbellard int i; 234e80cfcfcSbellard int64_t count; 235e80cfcfcSbellard 2367abad863SAndreas Färber s = SLAVIO_INTCTL(dev); 237376253ecSaliguori monitor_printf(mon, "IRQ statistics:\n"); 238e80cfcfcSbellard for (i = 0; i < 32; i++) { 239e80cfcfcSbellard count = s->irq_count[i]; 240e80cfcfcSbellard if (count > 0) 241376253ecSaliguori monitor_printf(mon, "%2d: %" PRId64 "\n", i, count); 242e80cfcfcSbellard } 243e80cfcfcSbellard #endif 244e80cfcfcSbellard } 245e80cfcfcSbellard 24668556e2eSBlue Swirl static const uint32_t intbit_to_level[] = { 247462eda24SBlue Swirl 2, 3, 5, 7, 9, 11, 13, 2, 3, 5, 7, 9, 11, 13, 12, 12, 248462eda24SBlue Swirl 6, 13, 4, 10, 8, 9, 11, 0, 0, 0, 0, 15, 15, 15, 15, 0, 24968556e2eSBlue Swirl }; 25068556e2eSBlue Swirl 2510d0a7e69SBlue Swirl static void slavio_check_interrupts(SLAVIO_INTCTLState *s, int set_irqs) 25266321a11Sbellard { 253327ac2e7Sblueswir1 uint32_t pending = s->intregm_pending, pil_pending; 254327ac2e7Sblueswir1 unsigned int i, j; 25566321a11Sbellard 25666321a11Sbellard pending &= ~s->intregm_disabled; 25766321a11Sbellard 25897bf4851SBlue Swirl trace_slavio_check_interrupts(pending, s->intregm_disabled); 259ba3c64fbSbellard for (i = 0; i < MAX_CPUS; i++) { 260327ac2e7Sblueswir1 pil_pending = 0; 261462eda24SBlue Swirl 262462eda24SBlue Swirl /* If we are the current interrupt target, get hard interrupts */ 2639a87ce9bSblueswir1 if (pending && !(s->intregm_disabled & MASTER_DISABLE) && 264b3a23197Sblueswir1 (i == s->target_cpu)) { 265b3a23197Sblueswir1 for (j = 0; j < 32; j++) { 266462eda24SBlue Swirl if ((pending & (1 << j)) && intbit_to_level[j]) { 26768556e2eSBlue Swirl pil_pending |= 1 << intbit_to_level[j]; 268b3a23197Sblueswir1 } 269b3a23197Sblueswir1 } 270462eda24SBlue Swirl } 271462eda24SBlue Swirl 272462eda24SBlue Swirl /* Calculate current pending hard interrupts for display */ 273462eda24SBlue Swirl s->slaves[i].intreg_pending &= CPU_SOFTIRQ_MASK | CPU_IRQ_INT15_IN | 274462eda24SBlue Swirl CPU_IRQ_TIMER_IN; 275462eda24SBlue Swirl if (i == s->target_cpu) { 276462eda24SBlue Swirl for (j = 0; j < 32; j++) { 2777d45e784SPeter Maydell if ((s->intregm_pending & (1U << j)) && intbit_to_level[j]) { 278462eda24SBlue Swirl s->slaves[i].intreg_pending |= 1 << intbit_to_level[j]; 279462eda24SBlue Swirl } 280462eda24SBlue Swirl } 281462eda24SBlue Swirl } 282462eda24SBlue Swirl 28394c5f455SArtyom Tarasenko /* Level 15 and CPU timer interrupts are only masked when 28494c5f455SArtyom Tarasenko the MASTER_DISABLE bit is set */ 28594c5f455SArtyom Tarasenko if (!(s->intregm_disabled & MASTER_DISABLE)) { 286462eda24SBlue Swirl pil_pending |= s->slaves[i].intreg_pending & 287462eda24SBlue Swirl (CPU_IRQ_INT15_IN | CPU_IRQ_TIMER_IN); 28894c5f455SArtyom Tarasenko } 289462eda24SBlue Swirl 290462eda24SBlue Swirl /* Add soft interrupts */ 291a1961a4bSBlue Swirl pil_pending |= (s->slaves[i].intreg_pending & CPU_SOFTIRQ_MASK) >> 16; 292327ac2e7Sblueswir1 2930d0a7e69SBlue Swirl if (set_irqs) { 294c84a88d8SPeter Maydell /* Since there is not really an interrupt 0 (and pil_pending 295c84a88d8SPeter Maydell * and irl_out bit zero are thus always zero) there is no need 296c84a88d8SPeter Maydell * to do anything with cpu_irqs[i][0] and it is OK not to do 297c84a88d8SPeter Maydell * the j=0 iteration of this loop. 298c84a88d8SPeter Maydell */ 299c84a88d8SPeter Maydell for (j = MAX_PILS-1; j > 0; j--) { 300327ac2e7Sblueswir1 if (pil_pending & (1 << j)) { 301462eda24SBlue Swirl if (!(s->slaves[i].irl_out & (1 << j))) { 302327ac2e7Sblueswir1 qemu_irq_raise(s->cpu_irqs[i][j]); 3030d0a7e69SBlue Swirl } 304327ac2e7Sblueswir1 } else { 305462eda24SBlue Swirl if (s->slaves[i].irl_out & (1 << j)) { 306327ac2e7Sblueswir1 qemu_irq_lower(s->cpu_irqs[i][j]); 307ba3c64fbSbellard } 308ba3c64fbSbellard } 3090d0a7e69SBlue Swirl } 3100d0a7e69SBlue Swirl } 311462eda24SBlue Swirl s->slaves[i].irl_out = pil_pending; 312ba3c64fbSbellard } 31366321a11Sbellard } 31466321a11Sbellard 315e80cfcfcSbellard /* 316e80cfcfcSbellard * "irq" here is the bit number in the system interrupt register to 317e80cfcfcSbellard * separate serial and keyboard interrupts sharing a level. 318e80cfcfcSbellard */ 319d7edfd27Sblueswir1 static void slavio_set_irq(void *opaque, int irq, int level) 320e80cfcfcSbellard { 321e80cfcfcSbellard SLAVIO_INTCTLState *s = opaque; 322e80cfcfcSbellard uint32_t mask = 1 << irq; 32368556e2eSBlue Swirl uint32_t pil = intbit_to_level[irq]; 324462eda24SBlue Swirl unsigned int i; 325b3a23197Sblueswir1 32697bf4851SBlue Swirl trace_slavio_set_irq(s->target_cpu, irq, pil, level); 327e80cfcfcSbellard if (pil > 0) { 328e80cfcfcSbellard if (level) { 329327ac2e7Sblueswir1 #ifdef DEBUG_IRQ_COUNT 330327ac2e7Sblueswir1 s->irq_count[pil]++; 331327ac2e7Sblueswir1 #endif 332e80cfcfcSbellard s->intregm_pending |= mask; 333462eda24SBlue Swirl if (pil == 15) { 334462eda24SBlue Swirl for (i = 0; i < MAX_CPUS; i++) { 335462eda24SBlue Swirl s->slaves[i].intreg_pending |= 1 << pil; 336462eda24SBlue Swirl } 337462eda24SBlue Swirl } 338b3a23197Sblueswir1 } else { 339e80cfcfcSbellard s->intregm_pending &= ~mask; 340462eda24SBlue Swirl if (pil == 15) { 341462eda24SBlue Swirl for (i = 0; i < MAX_CPUS; i++) { 342462eda24SBlue Swirl s->slaves[i].intreg_pending &= ~(1 << pil); 343462eda24SBlue Swirl } 344462eda24SBlue Swirl } 345e80cfcfcSbellard } 3460d0a7e69SBlue Swirl slavio_check_interrupts(s, 1); 347e80cfcfcSbellard } 348e80cfcfcSbellard } 349e80cfcfcSbellard 350d7edfd27Sblueswir1 static void slavio_set_timer_irq_cpu(void *opaque, int cpu, int level) 351ba3c64fbSbellard { 352ba3c64fbSbellard SLAVIO_INTCTLState *s = opaque; 353ba3c64fbSbellard 35497bf4851SBlue Swirl trace_slavio_set_timer_irq_cpu(cpu, level); 355d7edfd27Sblueswir1 356e3a79bcaSblueswir1 if (level) { 357462eda24SBlue Swirl s->slaves[cpu].intreg_pending |= CPU_IRQ_TIMER_IN; 358e3a79bcaSblueswir1 } else { 359462eda24SBlue Swirl s->slaves[cpu].intreg_pending &= ~CPU_IRQ_TIMER_IN; 360e3a79bcaSblueswir1 } 361d7edfd27Sblueswir1 3620d0a7e69SBlue Swirl slavio_check_interrupts(s, 1); 363ba3c64fbSbellard } 364ba3c64fbSbellard 365a1961a4bSBlue Swirl static void slavio_set_irq_all(void *opaque, int irq, int level) 366a1961a4bSBlue Swirl { 367a1961a4bSBlue Swirl if (irq < 32) { 368a1961a4bSBlue Swirl slavio_set_irq(opaque, irq, level); 369a1961a4bSBlue Swirl } else { 370a1961a4bSBlue Swirl slavio_set_timer_irq_cpu(opaque, irq - 32, level); 371a1961a4bSBlue Swirl } 372a1961a4bSBlue Swirl } 373a1961a4bSBlue Swirl 374e59fb374SJuan Quintela static int vmstate_intctl_post_load(void *opaque, int version_id) 375e80cfcfcSbellard { 376e80cfcfcSbellard SLAVIO_INTCTLState *s = opaque; 377e80cfcfcSbellard 3780d0a7e69SBlue Swirl slavio_check_interrupts(s, 0); 379e80cfcfcSbellard return 0; 380e80cfcfcSbellard } 381e80cfcfcSbellard 382c9e95029SBlue Swirl static const VMStateDescription vmstate_intctl_cpu = { 383c9e95029SBlue Swirl .name ="slavio_intctl_cpu", 384c9e95029SBlue Swirl .version_id = 1, 385c9e95029SBlue Swirl .minimum_version_id = 1, 386c9e95029SBlue Swirl .fields = (VMStateField[]) { 387c9e95029SBlue Swirl VMSTATE_UINT32(intreg_pending, SLAVIO_CPUINTCTLState), 388c9e95029SBlue Swirl VMSTATE_END_OF_LIST() 389c9e95029SBlue Swirl } 390c9e95029SBlue Swirl }; 391c9e95029SBlue Swirl 392c9e95029SBlue Swirl static const VMStateDescription vmstate_intctl = { 393c9e95029SBlue Swirl .name ="slavio_intctl", 394c9e95029SBlue Swirl .version_id = 1, 395c9e95029SBlue Swirl .minimum_version_id = 1, 396752ff2faSJuan Quintela .post_load = vmstate_intctl_post_load, 397c9e95029SBlue Swirl .fields = (VMStateField[]) { 398c9e95029SBlue Swirl VMSTATE_STRUCT_ARRAY(slaves, SLAVIO_INTCTLState, MAX_CPUS, 1, 399c9e95029SBlue Swirl vmstate_intctl_cpu, SLAVIO_CPUINTCTLState), 400c9e95029SBlue Swirl VMSTATE_UINT32(intregm_pending, SLAVIO_INTCTLState), 401c9e95029SBlue Swirl VMSTATE_UINT32(intregm_disabled, SLAVIO_INTCTLState), 402c9e95029SBlue Swirl VMSTATE_UINT32(target_cpu, SLAVIO_INTCTLState), 403c9e95029SBlue Swirl VMSTATE_END_OF_LIST() 404c9e95029SBlue Swirl } 405c9e95029SBlue Swirl }; 406c9e95029SBlue Swirl 40778971d57SBlue Swirl static void slavio_intctl_reset(DeviceState *d) 408e80cfcfcSbellard { 4097abad863SAndreas Färber SLAVIO_INTCTLState *s = SLAVIO_INTCTL(d); 410e80cfcfcSbellard int i; 411e80cfcfcSbellard 412e80cfcfcSbellard for (i = 0; i < MAX_CPUS; i++) { 413a1961a4bSBlue Swirl s->slaves[i].intreg_pending = 0; 414462eda24SBlue Swirl s->slaves[i].irl_out = 0; 415e80cfcfcSbellard } 4169a87ce9bSblueswir1 s->intregm_disabled = ~MASTER_IRQ_MASK; 417e80cfcfcSbellard s->intregm_pending = 0; 418e80cfcfcSbellard s->target_cpu = 0; 4190d0a7e69SBlue Swirl slavio_check_interrupts(s, 0); 420e80cfcfcSbellard } 421e80cfcfcSbellard 422*148fbe95SHervé Poussineau #ifdef DEBUG_IRQ_COUNT 423*148fbe95SHervé Poussineau static bool slavio_intctl_get_statistics(InterruptStatsProvider *obj, 424*148fbe95SHervé Poussineau uint64_t **irq_counts, 425*148fbe95SHervé Poussineau unsigned int *nb_irqs) 426*148fbe95SHervé Poussineau { 427*148fbe95SHervé Poussineau SLAVIO_INTCTLState *s = SLAVIO_INTCTL(obj); 428*148fbe95SHervé Poussineau *irq_counts = s->irq_count; 429*148fbe95SHervé Poussineau *nb_irqs = ARRAY_SIZE(s->irq_count); 430*148fbe95SHervé Poussineau return true; 431*148fbe95SHervé Poussineau } 432*148fbe95SHervé Poussineau #endif 433*148fbe95SHervé Poussineau 434*148fbe95SHervé Poussineau static void slavio_intctl_print_info(InterruptStatsProvider *obj, Monitor *mon) 435*148fbe95SHervé Poussineau { 436*148fbe95SHervé Poussineau SLAVIO_INTCTLState *s = SLAVIO_INTCTL(obj); 437*148fbe95SHervé Poussineau int i; 438*148fbe95SHervé Poussineau 439*148fbe95SHervé Poussineau for (i = 0; i < MAX_CPUS; i++) { 440*148fbe95SHervé Poussineau monitor_printf(mon, "per-cpu %d: pending 0x%08x\n", i, 441*148fbe95SHervé Poussineau s->slaves[i].intreg_pending); 442*148fbe95SHervé Poussineau } 443*148fbe95SHervé Poussineau monitor_printf(mon, "master: pending 0x%08x, disabled 0x%08x\n", 444*148fbe95SHervé Poussineau s->intregm_pending, s->intregm_disabled); 445*148fbe95SHervé Poussineau } 446*148fbe95SHervé Poussineau 447c09008d2Sxiaoqiang.zhao static void slavio_intctl_init(Object *obj) 448e80cfcfcSbellard { 449c09008d2Sxiaoqiang.zhao DeviceState *dev = DEVICE(obj); 450c09008d2Sxiaoqiang.zhao SLAVIO_INTCTLState *s = SLAVIO_INTCTL(obj); 451c09008d2Sxiaoqiang.zhao SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 452a1961a4bSBlue Swirl unsigned int i, j; 4538bb5ef33SBenoît Canet char slave_name[45]; 454e80cfcfcSbellard 4557abad863SAndreas Färber qdev_init_gpio_in(dev, slavio_set_irq_all, 32 + MAX_CPUS); 456c09008d2Sxiaoqiang.zhao memory_region_init_io(&s->iomem, obj, &slavio_intctlm_mem_ops, s, 45713c89a11SBenoît Canet "master-interrupt-controller", INTCTLM_SIZE); 4587abad863SAndreas Färber sysbus_init_mmio(sbd, &s->iomem); 459e80cfcfcSbellard 460e80cfcfcSbellard for (i = 0; i < MAX_CPUS; i++) { 4618bb5ef33SBenoît Canet snprintf(slave_name, sizeof(slave_name), 4628bb5ef33SBenoît Canet "slave-interrupt-controller-%i", i); 463a1961a4bSBlue Swirl for (j = 0; j < MAX_PILS; j++) { 4647abad863SAndreas Färber sysbus_init_irq(sbd, &s->cpu_irqs[i][j]); 465e80cfcfcSbellard } 4661437c94bSPaolo Bonzini memory_region_init_io(&s->slaves[i].iomem, OBJECT(s), 4671437c94bSPaolo Bonzini &slavio_intctl_mem_ops, 4688bb5ef33SBenoît Canet &s->slaves[i], slave_name, INTCTL_SIZE); 4697abad863SAndreas Färber sysbus_init_mmio(sbd, &s->slaves[i].iomem); 470a1961a4bSBlue Swirl s->slaves[i].cpu = i; 471a1961a4bSBlue Swirl s->slaves[i].master = s; 472a1961a4bSBlue Swirl } 473e80cfcfcSbellard } 474a1961a4bSBlue Swirl 475999e12bbSAnthony Liguori static void slavio_intctl_class_init(ObjectClass *klass, void *data) 476999e12bbSAnthony Liguori { 47739bffca2SAnthony Liguori DeviceClass *dc = DEVICE_CLASS(klass); 478*148fbe95SHervé Poussineau InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(klass); 479999e12bbSAnthony Liguori 48039bffca2SAnthony Liguori dc->reset = slavio_intctl_reset; 48139bffca2SAnthony Liguori dc->vmsd = &vmstate_intctl; 482*148fbe95SHervé Poussineau #ifdef DEBUG_IRQ_COUNT 483*148fbe95SHervé Poussineau ic->get_statistics = slavio_intctl_get_statistics; 484*148fbe95SHervé Poussineau #endif 485*148fbe95SHervé Poussineau ic->print_info = slavio_intctl_print_info; 486999e12bbSAnthony Liguori } 487999e12bbSAnthony Liguori 4888c43a6f0SAndreas Färber static const TypeInfo slavio_intctl_info = { 4897abad863SAndreas Färber .name = TYPE_SLAVIO_INTCTL, 49039bffca2SAnthony Liguori .parent = TYPE_SYS_BUS_DEVICE, 49139bffca2SAnthony Liguori .instance_size = sizeof(SLAVIO_INTCTLState), 492c09008d2Sxiaoqiang.zhao .instance_init = slavio_intctl_init, 493999e12bbSAnthony Liguori .class_init = slavio_intctl_class_init, 494*148fbe95SHervé Poussineau .interfaces = (InterfaceInfo[]) { 495*148fbe95SHervé Poussineau { TYPE_INTERRUPT_STATS_PROVIDER }, 496*148fbe95SHervé Poussineau { } 497*148fbe95SHervé Poussineau }, 498a1961a4bSBlue Swirl }; 499a1961a4bSBlue Swirl 50083f7d43aSAndreas Färber static void slavio_intctl_register_types(void) 501a1961a4bSBlue Swirl { 50239bffca2SAnthony Liguori type_register_static(&slavio_intctl_info); 503a1961a4bSBlue Swirl } 504a1961a4bSBlue Swirl 50583f7d43aSAndreas Färber type_init(slavio_intctl_register_types) 506