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 250d09e41aSPaolo Bonzini #include "hw/sparc/sun4m.h" 2683c9089eSPaolo Bonzini #include "monitor/monitor.h" 2783c9f4caSPaolo Bonzini #include "hw/sysbus.h" 2897bf4851SBlue Swirl #include "trace.h" 2987ecb68bSpbrook 30e80cfcfcSbellard //#define DEBUG_IRQ_COUNT 31e80cfcfcSbellard 32e80cfcfcSbellard /* 33e80cfcfcSbellard * Registers of interrupt controller in sun4m. 34e80cfcfcSbellard * 35e80cfcfcSbellard * This is the interrupt controller part of chip STP2001 (Slave I/O), also 36e80cfcfcSbellard * produced as NCR89C105. See 37e80cfcfcSbellard * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt 38e80cfcfcSbellard * 39e80cfcfcSbellard * There is a system master controller and one for each cpu. 40e80cfcfcSbellard * 41e80cfcfcSbellard */ 42e80cfcfcSbellard 43e80cfcfcSbellard #define MAX_CPUS 16 44b3a23197Sblueswir1 #define MAX_PILS 16 45e80cfcfcSbellard 46a1961a4bSBlue Swirl struct SLAVIO_INTCTLState; 47a1961a4bSBlue Swirl 48a1961a4bSBlue Swirl typedef struct SLAVIO_CPUINTCTLState { 498bb5ef33SBenoît Canet MemoryRegion iomem; 50a1961a4bSBlue Swirl struct SLAVIO_INTCTLState *master; 5107dd0035SBlue Swirl uint32_t intreg_pending; 52a1961a4bSBlue Swirl uint32_t cpu; 53462eda24SBlue Swirl uint32_t irl_out; 54a1961a4bSBlue Swirl } SLAVIO_CPUINTCTLState; 55a8f48dccSblueswir1 567abad863SAndreas Färber #define TYPE_SLAVIO_INTCTL "slavio_intctl" 577abad863SAndreas Färber #define SLAVIO_INTCTL(obj) \ 587abad863SAndreas Färber OBJECT_CHECK(SLAVIO_INTCTLState, (obj), TYPE_SLAVIO_INTCTL) 597abad863SAndreas Färber 60e80cfcfcSbellard typedef struct SLAVIO_INTCTLState { 617abad863SAndreas Färber SysBusDevice parent_obj; 627abad863SAndreas Färber 6313c89a11SBenoît Canet MemoryRegion iomem; 64e80cfcfcSbellard #ifdef DEBUG_IRQ_COUNT 65e80cfcfcSbellard uint64_t irq_count[32]; 66e80cfcfcSbellard #endif 67a1961a4bSBlue Swirl qemu_irq cpu_irqs[MAX_CPUS][MAX_PILS]; 68a1961a4bSBlue Swirl SLAVIO_CPUINTCTLState slaves[MAX_CPUS]; 6907dd0035SBlue Swirl uint32_t intregm_pending; 7007dd0035SBlue Swirl uint32_t intregm_disabled; 7107dd0035SBlue Swirl uint32_t target_cpu; 72e80cfcfcSbellard } SLAVIO_INTCTLState; 73e80cfcfcSbellard 74e80cfcfcSbellard #define INTCTL_MAXADDR 0xf 755aca8c3bSblueswir1 #define INTCTL_SIZE (INTCTL_MAXADDR + 1) 76a8f48dccSblueswir1 #define INTCTLM_SIZE 0x14 7780be36b8Sblueswir1 #define MASTER_IRQ_MASK ~0x0fa2007f 789a87ce9bSblueswir1 #define MASTER_DISABLE 0x80000000 796341fdcbSblueswir1 #define CPU_SOFTIRQ_MASK 0xfffe0000 80462eda24SBlue Swirl #define CPU_IRQ_INT15_IN (1 << 15) 81462eda24SBlue Swirl #define CPU_IRQ_TIMER_IN (1 << 14) 829a87ce9bSblueswir1 830d0a7e69SBlue Swirl static void slavio_check_interrupts(SLAVIO_INTCTLState *s, int set_irqs); 84e80cfcfcSbellard 85e80cfcfcSbellard // per-cpu interrupt controller 86a8170e5eSAvi Kivity static uint64_t slavio_intctl_mem_readl(void *opaque, hwaddr addr, 878bb5ef33SBenoît Canet unsigned size) 88e80cfcfcSbellard { 89a8f48dccSblueswir1 SLAVIO_CPUINTCTLState *s = opaque; 90dd4131b3Sblueswir1 uint32_t saddr, ret; 91e80cfcfcSbellard 92a8f48dccSblueswir1 saddr = addr >> 2; 93e80cfcfcSbellard switch (saddr) { 94e80cfcfcSbellard case 0: 95a8f48dccSblueswir1 ret = s->intreg_pending; 96dd4131b3Sblueswir1 break; 97e80cfcfcSbellard default: 98dd4131b3Sblueswir1 ret = 0; 99e80cfcfcSbellard break; 100e80cfcfcSbellard } 10197bf4851SBlue Swirl trace_slavio_intctl_mem_readl(s->cpu, addr, ret); 102dd4131b3Sblueswir1 103dd4131b3Sblueswir1 return ret; 104e80cfcfcSbellard } 105e80cfcfcSbellard 106a8170e5eSAvi Kivity static void slavio_intctl_mem_writel(void *opaque, hwaddr addr, 1078bb5ef33SBenoît Canet uint64_t val, unsigned size) 108e80cfcfcSbellard { 109a8f48dccSblueswir1 SLAVIO_CPUINTCTLState *s = opaque; 110e80cfcfcSbellard uint32_t saddr; 111e80cfcfcSbellard 112a8f48dccSblueswir1 saddr = addr >> 2; 11397bf4851SBlue Swirl trace_slavio_intctl_mem_writel(s->cpu, addr, val); 114e80cfcfcSbellard switch (saddr) { 115e80cfcfcSbellard case 1: // clear pending softints 116462eda24SBlue Swirl val &= CPU_SOFTIRQ_MASK | CPU_IRQ_INT15_IN; 117a8f48dccSblueswir1 s->intreg_pending &= ~val; 1180d0a7e69SBlue Swirl slavio_check_interrupts(s->master, 1); 11997bf4851SBlue Swirl trace_slavio_intctl_mem_writel_clear(s->cpu, val, s->intreg_pending); 120e80cfcfcSbellard break; 121e80cfcfcSbellard case 2: // set softint 1226341fdcbSblueswir1 val &= CPU_SOFTIRQ_MASK; 123a8f48dccSblueswir1 s->intreg_pending |= val; 1240d0a7e69SBlue Swirl slavio_check_interrupts(s->master, 1); 12597bf4851SBlue Swirl trace_slavio_intctl_mem_writel_set(s->cpu, val, s->intreg_pending); 126e80cfcfcSbellard break; 127e80cfcfcSbellard default: 128e80cfcfcSbellard break; 129e80cfcfcSbellard } 130e80cfcfcSbellard } 131e80cfcfcSbellard 1328bb5ef33SBenoît Canet static const MemoryRegionOps slavio_intctl_mem_ops = { 1338bb5ef33SBenoît Canet .read = slavio_intctl_mem_readl, 1348bb5ef33SBenoît Canet .write = slavio_intctl_mem_writel, 1358bb5ef33SBenoît Canet .endianness = DEVICE_NATIVE_ENDIAN, 1368bb5ef33SBenoît Canet .valid = { 1378bb5ef33SBenoît Canet .min_access_size = 4, 1388bb5ef33SBenoît Canet .max_access_size = 4, 1398bb5ef33SBenoît Canet }, 140e80cfcfcSbellard }; 141e80cfcfcSbellard 142e80cfcfcSbellard // master system interrupt controller 143a8170e5eSAvi Kivity static uint64_t slavio_intctlm_mem_readl(void *opaque, hwaddr addr, 14413c89a11SBenoît Canet unsigned size) 145e80cfcfcSbellard { 146e80cfcfcSbellard SLAVIO_INTCTLState *s = opaque; 147dd4131b3Sblueswir1 uint32_t saddr, ret; 148e80cfcfcSbellard 149a8f48dccSblueswir1 saddr = addr >> 2; 150e80cfcfcSbellard switch (saddr) { 151e80cfcfcSbellard case 0: 1529a87ce9bSblueswir1 ret = s->intregm_pending & ~MASTER_DISABLE; 153dd4131b3Sblueswir1 break; 154e80cfcfcSbellard case 1: 15580be36b8Sblueswir1 ret = s->intregm_disabled & MASTER_IRQ_MASK; 156dd4131b3Sblueswir1 break; 157e80cfcfcSbellard case 4: 158dd4131b3Sblueswir1 ret = s->target_cpu; 159dd4131b3Sblueswir1 break; 160e80cfcfcSbellard default: 161dd4131b3Sblueswir1 ret = 0; 162e80cfcfcSbellard break; 163e80cfcfcSbellard } 16497bf4851SBlue Swirl trace_slavio_intctlm_mem_readl(addr, ret); 165dd4131b3Sblueswir1 166dd4131b3Sblueswir1 return ret; 167e80cfcfcSbellard } 168e80cfcfcSbellard 169a8170e5eSAvi Kivity static void slavio_intctlm_mem_writel(void *opaque, hwaddr addr, 17013c89a11SBenoît Canet uint64_t val, unsigned size) 171e80cfcfcSbellard { 172e80cfcfcSbellard SLAVIO_INTCTLState *s = opaque; 173e80cfcfcSbellard uint32_t saddr; 174e80cfcfcSbellard 175a8f48dccSblueswir1 saddr = addr >> 2; 17697bf4851SBlue Swirl trace_slavio_intctlm_mem_writel(addr, val); 177e80cfcfcSbellard switch (saddr) { 178e80cfcfcSbellard case 2: // clear (enable) 1796bae7071Sbellard // Force clear unused bits 1809a87ce9bSblueswir1 val &= MASTER_IRQ_MASK; 181e80cfcfcSbellard s->intregm_disabled &= ~val; 18297bf4851SBlue Swirl trace_slavio_intctlm_mem_writel_enable(val, s->intregm_disabled); 1830d0a7e69SBlue Swirl slavio_check_interrupts(s, 1); 184e80cfcfcSbellard break; 18510760f0fSArtyom Tarasenko case 3: // set (disable; doesn't affect pending) 1866bae7071Sbellard // Force clear unused bits 1879a87ce9bSblueswir1 val &= MASTER_IRQ_MASK; 188e80cfcfcSbellard s->intregm_disabled |= val; 1890d0a7e69SBlue Swirl slavio_check_interrupts(s, 1); 19097bf4851SBlue Swirl trace_slavio_intctlm_mem_writel_disable(val, s->intregm_disabled); 191e80cfcfcSbellard break; 192e80cfcfcSbellard case 4: 193e80cfcfcSbellard s->target_cpu = val & (MAX_CPUS - 1); 1940d0a7e69SBlue Swirl slavio_check_interrupts(s, 1); 19597bf4851SBlue Swirl trace_slavio_intctlm_mem_writel_target(s->target_cpu); 196e80cfcfcSbellard break; 197e80cfcfcSbellard default: 198e80cfcfcSbellard break; 199e80cfcfcSbellard } 200e80cfcfcSbellard } 201e80cfcfcSbellard 20213c89a11SBenoît Canet static const MemoryRegionOps slavio_intctlm_mem_ops = { 20313c89a11SBenoît Canet .read = slavio_intctlm_mem_readl, 20413c89a11SBenoît Canet .write = slavio_intctlm_mem_writel, 20513c89a11SBenoît Canet .endianness = DEVICE_NATIVE_ENDIAN, 20613c89a11SBenoît Canet .valid = { 20713c89a11SBenoît Canet .min_access_size = 4, 20813c89a11SBenoît Canet .max_access_size = 4, 20913c89a11SBenoît Canet }, 210e80cfcfcSbellard }; 211e80cfcfcSbellard 212d453c2c3SBlue Swirl void slavio_pic_info(Monitor *mon, DeviceState *dev) 213e80cfcfcSbellard { 2147abad863SAndreas Färber SLAVIO_INTCTLState *s = SLAVIO_INTCTL(dev); 215e80cfcfcSbellard int i; 216e80cfcfcSbellard 217e80cfcfcSbellard for (i = 0; i < MAX_CPUS; i++) { 218376253ecSaliguori monitor_printf(mon, "per-cpu %d: pending 0x%08x\n", i, 219a1961a4bSBlue Swirl s->slaves[i].intreg_pending); 220e80cfcfcSbellard } 221376253ecSaliguori monitor_printf(mon, "master: pending 0x%08x, disabled 0x%08x\n", 22277f193daSblueswir1 s->intregm_pending, s->intregm_disabled); 223e80cfcfcSbellard } 224e80cfcfcSbellard 225d453c2c3SBlue Swirl void slavio_irq_info(Monitor *mon, DeviceState *dev) 226e80cfcfcSbellard { 227e80cfcfcSbellard #ifndef DEBUG_IRQ_COUNT 228376253ecSaliguori monitor_printf(mon, "irq statistic code not compiled.\n"); 229e80cfcfcSbellard #else 2307abad863SAndreas Färber SLAVIO_INTCTLState *s = SLAVIO_INTCTL(dev); 231e80cfcfcSbellard int i; 232e80cfcfcSbellard int64_t count; 233e80cfcfcSbellard 2347abad863SAndreas Färber s = SLAVIO_INTCTL(dev); 235376253ecSaliguori monitor_printf(mon, "IRQ statistics:\n"); 236e80cfcfcSbellard for (i = 0; i < 32; i++) { 237e80cfcfcSbellard count = s->irq_count[i]; 238e80cfcfcSbellard if (count > 0) 239376253ecSaliguori monitor_printf(mon, "%2d: %" PRId64 "\n", i, count); 240e80cfcfcSbellard } 241e80cfcfcSbellard #endif 242e80cfcfcSbellard } 243e80cfcfcSbellard 24468556e2eSBlue Swirl static const uint32_t intbit_to_level[] = { 245462eda24SBlue Swirl 2, 3, 5, 7, 9, 11, 13, 2, 3, 5, 7, 9, 11, 13, 12, 12, 246462eda24SBlue Swirl 6, 13, 4, 10, 8, 9, 11, 0, 0, 0, 0, 15, 15, 15, 15, 0, 24768556e2eSBlue Swirl }; 24868556e2eSBlue Swirl 2490d0a7e69SBlue Swirl static void slavio_check_interrupts(SLAVIO_INTCTLState *s, int set_irqs) 25066321a11Sbellard { 251327ac2e7Sblueswir1 uint32_t pending = s->intregm_pending, pil_pending; 252327ac2e7Sblueswir1 unsigned int i, j; 25366321a11Sbellard 25466321a11Sbellard pending &= ~s->intregm_disabled; 25566321a11Sbellard 25697bf4851SBlue Swirl trace_slavio_check_interrupts(pending, s->intregm_disabled); 257ba3c64fbSbellard for (i = 0; i < MAX_CPUS; i++) { 258327ac2e7Sblueswir1 pil_pending = 0; 259462eda24SBlue Swirl 260462eda24SBlue Swirl /* If we are the current interrupt target, get hard interrupts */ 2619a87ce9bSblueswir1 if (pending && !(s->intregm_disabled & MASTER_DISABLE) && 262b3a23197Sblueswir1 (i == s->target_cpu)) { 263b3a23197Sblueswir1 for (j = 0; j < 32; j++) { 264462eda24SBlue Swirl if ((pending & (1 << j)) && intbit_to_level[j]) { 26568556e2eSBlue Swirl pil_pending |= 1 << intbit_to_level[j]; 266b3a23197Sblueswir1 } 267b3a23197Sblueswir1 } 268462eda24SBlue Swirl } 269462eda24SBlue Swirl 270462eda24SBlue Swirl /* Calculate current pending hard interrupts for display */ 271462eda24SBlue Swirl s->slaves[i].intreg_pending &= CPU_SOFTIRQ_MASK | CPU_IRQ_INT15_IN | 272462eda24SBlue Swirl CPU_IRQ_TIMER_IN; 273462eda24SBlue Swirl if (i == s->target_cpu) { 274462eda24SBlue Swirl for (j = 0; j < 32; j++) { 275*7d45e784SPeter Maydell if ((s->intregm_pending & (1U << j)) && intbit_to_level[j]) { 276462eda24SBlue Swirl s->slaves[i].intreg_pending |= 1 << intbit_to_level[j]; 277462eda24SBlue Swirl } 278462eda24SBlue Swirl } 279462eda24SBlue Swirl } 280462eda24SBlue Swirl 28194c5f455SArtyom Tarasenko /* Level 15 and CPU timer interrupts are only masked when 28294c5f455SArtyom Tarasenko the MASTER_DISABLE bit is set */ 28394c5f455SArtyom Tarasenko if (!(s->intregm_disabled & MASTER_DISABLE)) { 284462eda24SBlue Swirl pil_pending |= s->slaves[i].intreg_pending & 285462eda24SBlue Swirl (CPU_IRQ_INT15_IN | CPU_IRQ_TIMER_IN); 28694c5f455SArtyom Tarasenko } 287462eda24SBlue Swirl 288462eda24SBlue Swirl /* Add soft interrupts */ 289a1961a4bSBlue Swirl pil_pending |= (s->slaves[i].intreg_pending & CPU_SOFTIRQ_MASK) >> 16; 290327ac2e7Sblueswir1 2910d0a7e69SBlue Swirl if (set_irqs) { 292c84a88d8SPeter Maydell /* Since there is not really an interrupt 0 (and pil_pending 293c84a88d8SPeter Maydell * and irl_out bit zero are thus always zero) there is no need 294c84a88d8SPeter Maydell * to do anything with cpu_irqs[i][0] and it is OK not to do 295c84a88d8SPeter Maydell * the j=0 iteration of this loop. 296c84a88d8SPeter Maydell */ 297c84a88d8SPeter Maydell for (j = MAX_PILS-1; j > 0; j--) { 298327ac2e7Sblueswir1 if (pil_pending & (1 << j)) { 299462eda24SBlue Swirl if (!(s->slaves[i].irl_out & (1 << j))) { 300327ac2e7Sblueswir1 qemu_irq_raise(s->cpu_irqs[i][j]); 3010d0a7e69SBlue Swirl } 302327ac2e7Sblueswir1 } else { 303462eda24SBlue Swirl if (s->slaves[i].irl_out & (1 << j)) { 304327ac2e7Sblueswir1 qemu_irq_lower(s->cpu_irqs[i][j]); 305ba3c64fbSbellard } 306ba3c64fbSbellard } 3070d0a7e69SBlue Swirl } 3080d0a7e69SBlue Swirl } 309462eda24SBlue Swirl s->slaves[i].irl_out = pil_pending; 310ba3c64fbSbellard } 31166321a11Sbellard } 31266321a11Sbellard 313e80cfcfcSbellard /* 314e80cfcfcSbellard * "irq" here is the bit number in the system interrupt register to 315e80cfcfcSbellard * separate serial and keyboard interrupts sharing a level. 316e80cfcfcSbellard */ 317d7edfd27Sblueswir1 static void slavio_set_irq(void *opaque, int irq, int level) 318e80cfcfcSbellard { 319e80cfcfcSbellard SLAVIO_INTCTLState *s = opaque; 320e80cfcfcSbellard uint32_t mask = 1 << irq; 32168556e2eSBlue Swirl uint32_t pil = intbit_to_level[irq]; 322462eda24SBlue Swirl unsigned int i; 323b3a23197Sblueswir1 32497bf4851SBlue Swirl trace_slavio_set_irq(s->target_cpu, irq, pil, level); 325e80cfcfcSbellard if (pil > 0) { 326e80cfcfcSbellard if (level) { 327327ac2e7Sblueswir1 #ifdef DEBUG_IRQ_COUNT 328327ac2e7Sblueswir1 s->irq_count[pil]++; 329327ac2e7Sblueswir1 #endif 330e80cfcfcSbellard s->intregm_pending |= mask; 331462eda24SBlue Swirl if (pil == 15) { 332462eda24SBlue Swirl for (i = 0; i < MAX_CPUS; i++) { 333462eda24SBlue Swirl s->slaves[i].intreg_pending |= 1 << pil; 334462eda24SBlue Swirl } 335462eda24SBlue Swirl } 336b3a23197Sblueswir1 } else { 337e80cfcfcSbellard s->intregm_pending &= ~mask; 338462eda24SBlue Swirl if (pil == 15) { 339462eda24SBlue Swirl for (i = 0; i < MAX_CPUS; i++) { 340462eda24SBlue Swirl s->slaves[i].intreg_pending &= ~(1 << pil); 341462eda24SBlue Swirl } 342462eda24SBlue Swirl } 343e80cfcfcSbellard } 3440d0a7e69SBlue Swirl slavio_check_interrupts(s, 1); 345e80cfcfcSbellard } 346e80cfcfcSbellard } 347e80cfcfcSbellard 348d7edfd27Sblueswir1 static void slavio_set_timer_irq_cpu(void *opaque, int cpu, int level) 349ba3c64fbSbellard { 350ba3c64fbSbellard SLAVIO_INTCTLState *s = opaque; 351ba3c64fbSbellard 35297bf4851SBlue Swirl trace_slavio_set_timer_irq_cpu(cpu, level); 353d7edfd27Sblueswir1 354e3a79bcaSblueswir1 if (level) { 355462eda24SBlue Swirl s->slaves[cpu].intreg_pending |= CPU_IRQ_TIMER_IN; 356e3a79bcaSblueswir1 } else { 357462eda24SBlue Swirl s->slaves[cpu].intreg_pending &= ~CPU_IRQ_TIMER_IN; 358e3a79bcaSblueswir1 } 359d7edfd27Sblueswir1 3600d0a7e69SBlue Swirl slavio_check_interrupts(s, 1); 361ba3c64fbSbellard } 362ba3c64fbSbellard 363a1961a4bSBlue Swirl static void slavio_set_irq_all(void *opaque, int irq, int level) 364a1961a4bSBlue Swirl { 365a1961a4bSBlue Swirl if (irq < 32) { 366a1961a4bSBlue Swirl slavio_set_irq(opaque, irq, level); 367a1961a4bSBlue Swirl } else { 368a1961a4bSBlue Swirl slavio_set_timer_irq_cpu(opaque, irq - 32, level); 369a1961a4bSBlue Swirl } 370a1961a4bSBlue Swirl } 371a1961a4bSBlue Swirl 372e59fb374SJuan Quintela static int vmstate_intctl_post_load(void *opaque, int version_id) 373e80cfcfcSbellard { 374e80cfcfcSbellard SLAVIO_INTCTLState *s = opaque; 375e80cfcfcSbellard 3760d0a7e69SBlue Swirl slavio_check_interrupts(s, 0); 377e80cfcfcSbellard return 0; 378e80cfcfcSbellard } 379e80cfcfcSbellard 380c9e95029SBlue Swirl static const VMStateDescription vmstate_intctl_cpu = { 381c9e95029SBlue Swirl .name ="slavio_intctl_cpu", 382c9e95029SBlue Swirl .version_id = 1, 383c9e95029SBlue Swirl .minimum_version_id = 1, 384c9e95029SBlue Swirl .minimum_version_id_old = 1, 385c9e95029SBlue Swirl .fields = (VMStateField []) { 386c9e95029SBlue Swirl VMSTATE_UINT32(intreg_pending, SLAVIO_CPUINTCTLState), 387c9e95029SBlue Swirl VMSTATE_END_OF_LIST() 388c9e95029SBlue Swirl } 389c9e95029SBlue Swirl }; 390c9e95029SBlue Swirl 391c9e95029SBlue Swirl static const VMStateDescription vmstate_intctl = { 392c9e95029SBlue Swirl .name ="slavio_intctl", 393c9e95029SBlue Swirl .version_id = 1, 394c9e95029SBlue Swirl .minimum_version_id = 1, 395c9e95029SBlue Swirl .minimum_version_id_old = 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 4227abad863SAndreas Färber static int slavio_intctl_init1(SysBusDevice *sbd) 423e80cfcfcSbellard { 4247abad863SAndreas Färber DeviceState *dev = DEVICE(sbd); 4257abad863SAndreas Färber SLAVIO_INTCTLState *s = SLAVIO_INTCTL(dev); 426a1961a4bSBlue Swirl unsigned int i, j; 4278bb5ef33SBenoît Canet char slave_name[45]; 428e80cfcfcSbellard 4297abad863SAndreas Färber qdev_init_gpio_in(dev, slavio_set_irq_all, 32 + MAX_CPUS); 4301437c94bSPaolo Bonzini memory_region_init_io(&s->iomem, OBJECT(s), &slavio_intctlm_mem_ops, s, 43113c89a11SBenoît Canet "master-interrupt-controller", INTCTLM_SIZE); 4327abad863SAndreas Färber sysbus_init_mmio(sbd, &s->iomem); 433e80cfcfcSbellard 434e80cfcfcSbellard for (i = 0; i < MAX_CPUS; i++) { 4358bb5ef33SBenoît Canet snprintf(slave_name, sizeof(slave_name), 4368bb5ef33SBenoît Canet "slave-interrupt-controller-%i", i); 437a1961a4bSBlue Swirl for (j = 0; j < MAX_PILS; j++) { 4387abad863SAndreas Färber sysbus_init_irq(sbd, &s->cpu_irqs[i][j]); 439e80cfcfcSbellard } 4401437c94bSPaolo Bonzini memory_region_init_io(&s->slaves[i].iomem, OBJECT(s), 4411437c94bSPaolo Bonzini &slavio_intctl_mem_ops, 4428bb5ef33SBenoît Canet &s->slaves[i], slave_name, INTCTL_SIZE); 4437abad863SAndreas Färber sysbus_init_mmio(sbd, &s->slaves[i].iomem); 444a1961a4bSBlue Swirl s->slaves[i].cpu = i; 445a1961a4bSBlue Swirl s->slaves[i].master = s; 446a1961a4bSBlue Swirl } 44778971d57SBlue Swirl 44881a322d4SGerd Hoffmann return 0; 449e80cfcfcSbellard } 450a1961a4bSBlue Swirl 451999e12bbSAnthony Liguori static void slavio_intctl_class_init(ObjectClass *klass, void *data) 452999e12bbSAnthony Liguori { 45339bffca2SAnthony Liguori DeviceClass *dc = DEVICE_CLASS(klass); 454999e12bbSAnthony Liguori SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); 455999e12bbSAnthony Liguori 456999e12bbSAnthony Liguori k->init = slavio_intctl_init1; 45739bffca2SAnthony Liguori dc->reset = slavio_intctl_reset; 45839bffca2SAnthony Liguori dc->vmsd = &vmstate_intctl; 459999e12bbSAnthony Liguori } 460999e12bbSAnthony Liguori 4618c43a6f0SAndreas Färber static const TypeInfo slavio_intctl_info = { 4627abad863SAndreas Färber .name = TYPE_SLAVIO_INTCTL, 46339bffca2SAnthony Liguori .parent = TYPE_SYS_BUS_DEVICE, 46439bffca2SAnthony Liguori .instance_size = sizeof(SLAVIO_INTCTLState), 465999e12bbSAnthony Liguori .class_init = slavio_intctl_class_init, 466a1961a4bSBlue Swirl }; 467a1961a4bSBlue Swirl 46883f7d43aSAndreas Färber static void slavio_intctl_register_types(void) 469a1961a4bSBlue Swirl { 47039bffca2SAnthony Liguori type_register_static(&slavio_intctl_info); 471a1961a4bSBlue Swirl } 472a1961a4bSBlue Swirl 47383f7d43aSAndreas Färber type_init(slavio_intctl_register_types) 474