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" 26d6454270SMarkus Armbruster #include "migration/vmstate.h" 2783c9089eSPaolo Bonzini #include "monitor/monitor.h" 280b8fa32fSMarkus Armbruster #include "qemu/module.h" 2983c9f4caSPaolo Bonzini #include "hw/sysbus.h" 30148fbe95SHervé Poussineau #include "hw/intc/intc.h" 3164552b6bSMarkus Armbruster #include "hw/irq.h" 3297bf4851SBlue Swirl #include "trace.h" 33*db1015e9SEduardo Habkost #include "qom/object.h" 3487ecb68bSpbrook 35e80cfcfcSbellard //#define DEBUG_IRQ_COUNT 36e80cfcfcSbellard 37e80cfcfcSbellard /* 38e80cfcfcSbellard * Registers of interrupt controller in sun4m. 39e80cfcfcSbellard * 40e80cfcfcSbellard * This is the interrupt controller part of chip STP2001 (Slave I/O), also 41e80cfcfcSbellard * produced as NCR89C105. See 42e80cfcfcSbellard * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt 43e80cfcfcSbellard * 44e80cfcfcSbellard * There is a system master controller and one for each cpu. 45e80cfcfcSbellard * 46e80cfcfcSbellard */ 47e80cfcfcSbellard 48e80cfcfcSbellard #define MAX_CPUS 16 49b3a23197Sblueswir1 #define MAX_PILS 16 50e80cfcfcSbellard 51a1961a4bSBlue Swirl struct SLAVIO_INTCTLState; 52a1961a4bSBlue Swirl 53a1961a4bSBlue Swirl typedef struct SLAVIO_CPUINTCTLState { 548bb5ef33SBenoît Canet MemoryRegion iomem; 55a1961a4bSBlue Swirl struct SLAVIO_INTCTLState *master; 5607dd0035SBlue Swirl uint32_t intreg_pending; 57a1961a4bSBlue Swirl uint32_t cpu; 58462eda24SBlue Swirl uint32_t irl_out; 59a1961a4bSBlue Swirl } SLAVIO_CPUINTCTLState; 60a8f48dccSblueswir1 617abad863SAndreas Färber #define TYPE_SLAVIO_INTCTL "slavio_intctl" 62*db1015e9SEduardo Habkost typedef struct SLAVIO_INTCTLState SLAVIO_INTCTLState; 637abad863SAndreas Färber #define SLAVIO_INTCTL(obj) \ 647abad863SAndreas Färber OBJECT_CHECK(SLAVIO_INTCTLState, (obj), TYPE_SLAVIO_INTCTL) 657abad863SAndreas Färber 66*db1015e9SEduardo Habkost struct SLAVIO_INTCTLState { 677abad863SAndreas Färber SysBusDevice parent_obj; 687abad863SAndreas Färber 6913c89a11SBenoît Canet MemoryRegion iomem; 70e80cfcfcSbellard #ifdef DEBUG_IRQ_COUNT 71e80cfcfcSbellard uint64_t irq_count[32]; 72e80cfcfcSbellard #endif 73a1961a4bSBlue Swirl qemu_irq cpu_irqs[MAX_CPUS][MAX_PILS]; 74a1961a4bSBlue Swirl SLAVIO_CPUINTCTLState slaves[MAX_CPUS]; 7507dd0035SBlue Swirl uint32_t intregm_pending; 7607dd0035SBlue Swirl uint32_t intregm_disabled; 7707dd0035SBlue Swirl uint32_t target_cpu; 78*db1015e9SEduardo Habkost }; 79e80cfcfcSbellard 80e80cfcfcSbellard #define INTCTL_MAXADDR 0xf 815aca8c3bSblueswir1 #define INTCTL_SIZE (INTCTL_MAXADDR + 1) 82a8f48dccSblueswir1 #define INTCTLM_SIZE 0x14 8380be36b8Sblueswir1 #define MASTER_IRQ_MASK ~0x0fa2007f 849a87ce9bSblueswir1 #define MASTER_DISABLE 0x80000000 856341fdcbSblueswir1 #define CPU_SOFTIRQ_MASK 0xfffe0000 86462eda24SBlue Swirl #define CPU_IRQ_INT15_IN (1 << 15) 87462eda24SBlue Swirl #define CPU_IRQ_TIMER_IN (1 << 14) 889a87ce9bSblueswir1 890d0a7e69SBlue Swirl static void slavio_check_interrupts(SLAVIO_INTCTLState *s, int set_irqs); 90e80cfcfcSbellard 91e80cfcfcSbellard // per-cpu interrupt controller 92a8170e5eSAvi Kivity static uint64_t slavio_intctl_mem_readl(void *opaque, hwaddr addr, 938bb5ef33SBenoît Canet unsigned size) 94e80cfcfcSbellard { 95a8f48dccSblueswir1 SLAVIO_CPUINTCTLState *s = opaque; 96dd4131b3Sblueswir1 uint32_t saddr, ret; 97e80cfcfcSbellard 98a8f48dccSblueswir1 saddr = addr >> 2; 99e80cfcfcSbellard switch (saddr) { 100e80cfcfcSbellard case 0: 101a8f48dccSblueswir1 ret = s->intreg_pending; 102dd4131b3Sblueswir1 break; 103e80cfcfcSbellard default: 104dd4131b3Sblueswir1 ret = 0; 105e80cfcfcSbellard break; 106e80cfcfcSbellard } 10797bf4851SBlue Swirl trace_slavio_intctl_mem_readl(s->cpu, addr, ret); 108dd4131b3Sblueswir1 109dd4131b3Sblueswir1 return ret; 110e80cfcfcSbellard } 111e80cfcfcSbellard 112a8170e5eSAvi Kivity static void slavio_intctl_mem_writel(void *opaque, hwaddr addr, 1138bb5ef33SBenoît Canet uint64_t val, unsigned size) 114e80cfcfcSbellard { 115a8f48dccSblueswir1 SLAVIO_CPUINTCTLState *s = opaque; 116e80cfcfcSbellard uint32_t saddr; 117e80cfcfcSbellard 118a8f48dccSblueswir1 saddr = addr >> 2; 11997bf4851SBlue Swirl trace_slavio_intctl_mem_writel(s->cpu, addr, val); 120e80cfcfcSbellard switch (saddr) { 121e80cfcfcSbellard case 1: // clear pending softints 122462eda24SBlue Swirl val &= CPU_SOFTIRQ_MASK | CPU_IRQ_INT15_IN; 123a8f48dccSblueswir1 s->intreg_pending &= ~val; 1240d0a7e69SBlue Swirl slavio_check_interrupts(s->master, 1); 12597bf4851SBlue Swirl trace_slavio_intctl_mem_writel_clear(s->cpu, val, s->intreg_pending); 126e80cfcfcSbellard break; 127e80cfcfcSbellard case 2: // set softint 1286341fdcbSblueswir1 val &= CPU_SOFTIRQ_MASK; 129a8f48dccSblueswir1 s->intreg_pending |= val; 1300d0a7e69SBlue Swirl slavio_check_interrupts(s->master, 1); 13197bf4851SBlue Swirl trace_slavio_intctl_mem_writel_set(s->cpu, val, s->intreg_pending); 132e80cfcfcSbellard break; 133e80cfcfcSbellard default: 134e80cfcfcSbellard break; 135e80cfcfcSbellard } 136e80cfcfcSbellard } 137e80cfcfcSbellard 1388bb5ef33SBenoît Canet static const MemoryRegionOps slavio_intctl_mem_ops = { 1398bb5ef33SBenoît Canet .read = slavio_intctl_mem_readl, 1408bb5ef33SBenoît Canet .write = slavio_intctl_mem_writel, 1418bb5ef33SBenoît Canet .endianness = DEVICE_NATIVE_ENDIAN, 1428bb5ef33SBenoît Canet .valid = { 1438bb5ef33SBenoît Canet .min_access_size = 4, 1448bb5ef33SBenoît Canet .max_access_size = 4, 1458bb5ef33SBenoît Canet }, 146e80cfcfcSbellard }; 147e80cfcfcSbellard 148e80cfcfcSbellard // master system interrupt controller 149a8170e5eSAvi Kivity static uint64_t slavio_intctlm_mem_readl(void *opaque, hwaddr addr, 15013c89a11SBenoît Canet unsigned size) 151e80cfcfcSbellard { 152e80cfcfcSbellard SLAVIO_INTCTLState *s = opaque; 153dd4131b3Sblueswir1 uint32_t saddr, ret; 154e80cfcfcSbellard 155a8f48dccSblueswir1 saddr = addr >> 2; 156e80cfcfcSbellard switch (saddr) { 157e80cfcfcSbellard case 0: 1589a87ce9bSblueswir1 ret = s->intregm_pending & ~MASTER_DISABLE; 159dd4131b3Sblueswir1 break; 160e80cfcfcSbellard case 1: 16180be36b8Sblueswir1 ret = s->intregm_disabled & MASTER_IRQ_MASK; 162dd4131b3Sblueswir1 break; 163e80cfcfcSbellard case 4: 164dd4131b3Sblueswir1 ret = s->target_cpu; 165dd4131b3Sblueswir1 break; 166e80cfcfcSbellard default: 167dd4131b3Sblueswir1 ret = 0; 168e80cfcfcSbellard break; 169e80cfcfcSbellard } 17097bf4851SBlue Swirl trace_slavio_intctlm_mem_readl(addr, ret); 171dd4131b3Sblueswir1 172dd4131b3Sblueswir1 return ret; 173e80cfcfcSbellard } 174e80cfcfcSbellard 175a8170e5eSAvi Kivity static void slavio_intctlm_mem_writel(void *opaque, hwaddr addr, 17613c89a11SBenoît Canet uint64_t val, unsigned size) 177e80cfcfcSbellard { 178e80cfcfcSbellard SLAVIO_INTCTLState *s = opaque; 179e80cfcfcSbellard uint32_t saddr; 180e80cfcfcSbellard 181a8f48dccSblueswir1 saddr = addr >> 2; 18297bf4851SBlue Swirl trace_slavio_intctlm_mem_writel(addr, val); 183e80cfcfcSbellard switch (saddr) { 184e80cfcfcSbellard case 2: // clear (enable) 1856bae7071Sbellard // Force clear unused bits 1869a87ce9bSblueswir1 val &= MASTER_IRQ_MASK; 187e80cfcfcSbellard s->intregm_disabled &= ~val; 18897bf4851SBlue Swirl trace_slavio_intctlm_mem_writel_enable(val, s->intregm_disabled); 1890d0a7e69SBlue Swirl slavio_check_interrupts(s, 1); 190e80cfcfcSbellard break; 19110760f0fSArtyom Tarasenko case 3: // set (disable; doesn't affect pending) 1926bae7071Sbellard // Force clear unused bits 1939a87ce9bSblueswir1 val &= MASTER_IRQ_MASK; 194e80cfcfcSbellard s->intregm_disabled |= val; 1950d0a7e69SBlue Swirl slavio_check_interrupts(s, 1); 19697bf4851SBlue Swirl trace_slavio_intctlm_mem_writel_disable(val, s->intregm_disabled); 197e80cfcfcSbellard break; 198e80cfcfcSbellard case 4: 199e80cfcfcSbellard s->target_cpu = val & (MAX_CPUS - 1); 2000d0a7e69SBlue Swirl slavio_check_interrupts(s, 1); 20197bf4851SBlue Swirl trace_slavio_intctlm_mem_writel_target(s->target_cpu); 202e80cfcfcSbellard break; 203e80cfcfcSbellard default: 204e80cfcfcSbellard break; 205e80cfcfcSbellard } 206e80cfcfcSbellard } 207e80cfcfcSbellard 20813c89a11SBenoît Canet static const MemoryRegionOps slavio_intctlm_mem_ops = { 20913c89a11SBenoît Canet .read = slavio_intctlm_mem_readl, 21013c89a11SBenoît Canet .write = slavio_intctlm_mem_writel, 21113c89a11SBenoît Canet .endianness = DEVICE_NATIVE_ENDIAN, 21213c89a11SBenoît Canet .valid = { 21313c89a11SBenoît Canet .min_access_size = 4, 21413c89a11SBenoît Canet .max_access_size = 4, 21513c89a11SBenoît Canet }, 216e80cfcfcSbellard }; 217e80cfcfcSbellard 21868556e2eSBlue Swirl static const uint32_t intbit_to_level[] = { 219462eda24SBlue Swirl 2, 3, 5, 7, 9, 11, 13, 2, 3, 5, 7, 9, 11, 13, 12, 12, 220462eda24SBlue Swirl 6, 13, 4, 10, 8, 9, 11, 0, 0, 0, 0, 15, 15, 15, 15, 0, 22168556e2eSBlue Swirl }; 22268556e2eSBlue Swirl 2230d0a7e69SBlue Swirl static void slavio_check_interrupts(SLAVIO_INTCTLState *s, int set_irqs) 22466321a11Sbellard { 225327ac2e7Sblueswir1 uint32_t pending = s->intregm_pending, pil_pending; 226327ac2e7Sblueswir1 unsigned int i, j; 22766321a11Sbellard 22866321a11Sbellard pending &= ~s->intregm_disabled; 22966321a11Sbellard 23097bf4851SBlue Swirl trace_slavio_check_interrupts(pending, s->intregm_disabled); 231ba3c64fbSbellard for (i = 0; i < MAX_CPUS; i++) { 232327ac2e7Sblueswir1 pil_pending = 0; 233462eda24SBlue Swirl 234462eda24SBlue Swirl /* If we are the current interrupt target, get hard interrupts */ 2359a87ce9bSblueswir1 if (pending && !(s->intregm_disabled & MASTER_DISABLE) && 236b3a23197Sblueswir1 (i == s->target_cpu)) { 237b3a23197Sblueswir1 for (j = 0; j < 32; j++) { 238462eda24SBlue Swirl if ((pending & (1 << j)) && intbit_to_level[j]) { 23968556e2eSBlue Swirl pil_pending |= 1 << intbit_to_level[j]; 240b3a23197Sblueswir1 } 241b3a23197Sblueswir1 } 242462eda24SBlue Swirl } 243462eda24SBlue Swirl 244462eda24SBlue Swirl /* Calculate current pending hard interrupts for display */ 245462eda24SBlue Swirl s->slaves[i].intreg_pending &= CPU_SOFTIRQ_MASK | CPU_IRQ_INT15_IN | 246462eda24SBlue Swirl CPU_IRQ_TIMER_IN; 247462eda24SBlue Swirl if (i == s->target_cpu) { 248462eda24SBlue Swirl for (j = 0; j < 32; j++) { 2497d45e784SPeter Maydell if ((s->intregm_pending & (1U << j)) && intbit_to_level[j]) { 250462eda24SBlue Swirl s->slaves[i].intreg_pending |= 1 << intbit_to_level[j]; 251462eda24SBlue Swirl } 252462eda24SBlue Swirl } 253462eda24SBlue Swirl } 254462eda24SBlue Swirl 25594c5f455SArtyom Tarasenko /* Level 15 and CPU timer interrupts are only masked when 25694c5f455SArtyom Tarasenko the MASTER_DISABLE bit is set */ 25794c5f455SArtyom Tarasenko if (!(s->intregm_disabled & MASTER_DISABLE)) { 258462eda24SBlue Swirl pil_pending |= s->slaves[i].intreg_pending & 259462eda24SBlue Swirl (CPU_IRQ_INT15_IN | CPU_IRQ_TIMER_IN); 26094c5f455SArtyom Tarasenko } 261462eda24SBlue Swirl 262462eda24SBlue Swirl /* Add soft interrupts */ 263a1961a4bSBlue Swirl pil_pending |= (s->slaves[i].intreg_pending & CPU_SOFTIRQ_MASK) >> 16; 264327ac2e7Sblueswir1 2650d0a7e69SBlue Swirl if (set_irqs) { 266c84a88d8SPeter Maydell /* Since there is not really an interrupt 0 (and pil_pending 267c84a88d8SPeter Maydell * and irl_out bit zero are thus always zero) there is no need 268c84a88d8SPeter Maydell * to do anything with cpu_irqs[i][0] and it is OK not to do 269c84a88d8SPeter Maydell * the j=0 iteration of this loop. 270c84a88d8SPeter Maydell */ 271c84a88d8SPeter Maydell for (j = MAX_PILS-1; j > 0; j--) { 272327ac2e7Sblueswir1 if (pil_pending & (1 << j)) { 273462eda24SBlue Swirl if (!(s->slaves[i].irl_out & (1 << j))) { 274327ac2e7Sblueswir1 qemu_irq_raise(s->cpu_irqs[i][j]); 2750d0a7e69SBlue Swirl } 276327ac2e7Sblueswir1 } else { 277462eda24SBlue Swirl if (s->slaves[i].irl_out & (1 << j)) { 278327ac2e7Sblueswir1 qemu_irq_lower(s->cpu_irqs[i][j]); 279ba3c64fbSbellard } 280ba3c64fbSbellard } 2810d0a7e69SBlue Swirl } 2820d0a7e69SBlue Swirl } 283462eda24SBlue Swirl s->slaves[i].irl_out = pil_pending; 284ba3c64fbSbellard } 28566321a11Sbellard } 28666321a11Sbellard 287e80cfcfcSbellard /* 288e80cfcfcSbellard * "irq" here is the bit number in the system interrupt register to 289e80cfcfcSbellard * separate serial and keyboard interrupts sharing a level. 290e80cfcfcSbellard */ 291d7edfd27Sblueswir1 static void slavio_set_irq(void *opaque, int irq, int level) 292e80cfcfcSbellard { 293e80cfcfcSbellard SLAVIO_INTCTLState *s = opaque; 294e80cfcfcSbellard uint32_t mask = 1 << irq; 29568556e2eSBlue Swirl uint32_t pil = intbit_to_level[irq]; 296462eda24SBlue Swirl unsigned int i; 297b3a23197Sblueswir1 29897bf4851SBlue Swirl trace_slavio_set_irq(s->target_cpu, irq, pil, level); 299e80cfcfcSbellard if (pil > 0) { 300e80cfcfcSbellard if (level) { 301327ac2e7Sblueswir1 #ifdef DEBUG_IRQ_COUNT 302327ac2e7Sblueswir1 s->irq_count[pil]++; 303327ac2e7Sblueswir1 #endif 304e80cfcfcSbellard s->intregm_pending |= mask; 305462eda24SBlue Swirl if (pil == 15) { 306462eda24SBlue Swirl for (i = 0; i < MAX_CPUS; i++) { 307462eda24SBlue Swirl s->slaves[i].intreg_pending |= 1 << pil; 308462eda24SBlue Swirl } 309462eda24SBlue Swirl } 310b3a23197Sblueswir1 } else { 311e80cfcfcSbellard s->intregm_pending &= ~mask; 312462eda24SBlue Swirl if (pil == 15) { 313462eda24SBlue Swirl for (i = 0; i < MAX_CPUS; i++) { 314462eda24SBlue Swirl s->slaves[i].intreg_pending &= ~(1 << pil); 315462eda24SBlue Swirl } 316462eda24SBlue Swirl } 317e80cfcfcSbellard } 3180d0a7e69SBlue Swirl slavio_check_interrupts(s, 1); 319e80cfcfcSbellard } 320e80cfcfcSbellard } 321e80cfcfcSbellard 322d7edfd27Sblueswir1 static void slavio_set_timer_irq_cpu(void *opaque, int cpu, int level) 323ba3c64fbSbellard { 324ba3c64fbSbellard SLAVIO_INTCTLState *s = opaque; 325ba3c64fbSbellard 32697bf4851SBlue Swirl trace_slavio_set_timer_irq_cpu(cpu, level); 327d7edfd27Sblueswir1 328e3a79bcaSblueswir1 if (level) { 329462eda24SBlue Swirl s->slaves[cpu].intreg_pending |= CPU_IRQ_TIMER_IN; 330e3a79bcaSblueswir1 } else { 331462eda24SBlue Swirl s->slaves[cpu].intreg_pending &= ~CPU_IRQ_TIMER_IN; 332e3a79bcaSblueswir1 } 333d7edfd27Sblueswir1 3340d0a7e69SBlue Swirl slavio_check_interrupts(s, 1); 335ba3c64fbSbellard } 336ba3c64fbSbellard 337a1961a4bSBlue Swirl static void slavio_set_irq_all(void *opaque, int irq, int level) 338a1961a4bSBlue Swirl { 339a1961a4bSBlue Swirl if (irq < 32) { 340a1961a4bSBlue Swirl slavio_set_irq(opaque, irq, level); 341a1961a4bSBlue Swirl } else { 342a1961a4bSBlue Swirl slavio_set_timer_irq_cpu(opaque, irq - 32, level); 343a1961a4bSBlue Swirl } 344a1961a4bSBlue Swirl } 345a1961a4bSBlue Swirl 346e59fb374SJuan Quintela static int vmstate_intctl_post_load(void *opaque, int version_id) 347e80cfcfcSbellard { 348e80cfcfcSbellard SLAVIO_INTCTLState *s = opaque; 349e80cfcfcSbellard 3500d0a7e69SBlue Swirl slavio_check_interrupts(s, 0); 351e80cfcfcSbellard return 0; 352e80cfcfcSbellard } 353e80cfcfcSbellard 354c9e95029SBlue Swirl static const VMStateDescription vmstate_intctl_cpu = { 355c9e95029SBlue Swirl .name ="slavio_intctl_cpu", 356c9e95029SBlue Swirl .version_id = 1, 357c9e95029SBlue Swirl .minimum_version_id = 1, 358c9e95029SBlue Swirl .fields = (VMStateField[]) { 359c9e95029SBlue Swirl VMSTATE_UINT32(intreg_pending, SLAVIO_CPUINTCTLState), 360c9e95029SBlue Swirl VMSTATE_END_OF_LIST() 361c9e95029SBlue Swirl } 362c9e95029SBlue Swirl }; 363c9e95029SBlue Swirl 364c9e95029SBlue Swirl static const VMStateDescription vmstate_intctl = { 365c9e95029SBlue Swirl .name ="slavio_intctl", 366c9e95029SBlue Swirl .version_id = 1, 367c9e95029SBlue Swirl .minimum_version_id = 1, 368752ff2faSJuan Quintela .post_load = vmstate_intctl_post_load, 369c9e95029SBlue Swirl .fields = (VMStateField[]) { 370c9e95029SBlue Swirl VMSTATE_STRUCT_ARRAY(slaves, SLAVIO_INTCTLState, MAX_CPUS, 1, 371c9e95029SBlue Swirl vmstate_intctl_cpu, SLAVIO_CPUINTCTLState), 372c9e95029SBlue Swirl VMSTATE_UINT32(intregm_pending, SLAVIO_INTCTLState), 373c9e95029SBlue Swirl VMSTATE_UINT32(intregm_disabled, SLAVIO_INTCTLState), 374c9e95029SBlue Swirl VMSTATE_UINT32(target_cpu, SLAVIO_INTCTLState), 375c9e95029SBlue Swirl VMSTATE_END_OF_LIST() 376c9e95029SBlue Swirl } 377c9e95029SBlue Swirl }; 378c9e95029SBlue Swirl 37978971d57SBlue Swirl static void slavio_intctl_reset(DeviceState *d) 380e80cfcfcSbellard { 3817abad863SAndreas Färber SLAVIO_INTCTLState *s = SLAVIO_INTCTL(d); 382e80cfcfcSbellard int i; 383e80cfcfcSbellard 384e80cfcfcSbellard for (i = 0; i < MAX_CPUS; i++) { 385a1961a4bSBlue Swirl s->slaves[i].intreg_pending = 0; 386462eda24SBlue Swirl s->slaves[i].irl_out = 0; 387e80cfcfcSbellard } 3889a87ce9bSblueswir1 s->intregm_disabled = ~MASTER_IRQ_MASK; 389e80cfcfcSbellard s->intregm_pending = 0; 390e80cfcfcSbellard s->target_cpu = 0; 3910d0a7e69SBlue Swirl slavio_check_interrupts(s, 0); 392e80cfcfcSbellard } 393e80cfcfcSbellard 394148fbe95SHervé Poussineau #ifdef DEBUG_IRQ_COUNT 395148fbe95SHervé Poussineau static bool slavio_intctl_get_statistics(InterruptStatsProvider *obj, 396148fbe95SHervé Poussineau uint64_t **irq_counts, 397148fbe95SHervé Poussineau unsigned int *nb_irqs) 398148fbe95SHervé Poussineau { 399148fbe95SHervé Poussineau SLAVIO_INTCTLState *s = SLAVIO_INTCTL(obj); 400148fbe95SHervé Poussineau *irq_counts = s->irq_count; 401148fbe95SHervé Poussineau *nb_irqs = ARRAY_SIZE(s->irq_count); 402148fbe95SHervé Poussineau return true; 403148fbe95SHervé Poussineau } 404148fbe95SHervé Poussineau #endif 405148fbe95SHervé Poussineau 406148fbe95SHervé Poussineau static void slavio_intctl_print_info(InterruptStatsProvider *obj, Monitor *mon) 407148fbe95SHervé Poussineau { 408148fbe95SHervé Poussineau SLAVIO_INTCTLState *s = SLAVIO_INTCTL(obj); 409148fbe95SHervé Poussineau int i; 410148fbe95SHervé Poussineau 411148fbe95SHervé Poussineau for (i = 0; i < MAX_CPUS; i++) { 412148fbe95SHervé Poussineau monitor_printf(mon, "per-cpu %d: pending 0x%08x\n", i, 413148fbe95SHervé Poussineau s->slaves[i].intreg_pending); 414148fbe95SHervé Poussineau } 415148fbe95SHervé Poussineau monitor_printf(mon, "master: pending 0x%08x, disabled 0x%08x\n", 416148fbe95SHervé Poussineau s->intregm_pending, s->intregm_disabled); 417148fbe95SHervé Poussineau } 418148fbe95SHervé Poussineau 419c09008d2Sxiaoqiang.zhao static void slavio_intctl_init(Object *obj) 420e80cfcfcSbellard { 421c09008d2Sxiaoqiang.zhao DeviceState *dev = DEVICE(obj); 422c09008d2Sxiaoqiang.zhao SLAVIO_INTCTLState *s = SLAVIO_INTCTL(obj); 423c09008d2Sxiaoqiang.zhao SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 424a1961a4bSBlue Swirl unsigned int i, j; 4258bb5ef33SBenoît Canet char slave_name[45]; 426e80cfcfcSbellard 4277abad863SAndreas Färber qdev_init_gpio_in(dev, slavio_set_irq_all, 32 + MAX_CPUS); 428c09008d2Sxiaoqiang.zhao memory_region_init_io(&s->iomem, obj, &slavio_intctlm_mem_ops, s, 42913c89a11SBenoît Canet "master-interrupt-controller", INTCTLM_SIZE); 4307abad863SAndreas Färber sysbus_init_mmio(sbd, &s->iomem); 431e80cfcfcSbellard 432e80cfcfcSbellard for (i = 0; i < MAX_CPUS; i++) { 4338bb5ef33SBenoît Canet snprintf(slave_name, sizeof(slave_name), 4348bb5ef33SBenoît Canet "slave-interrupt-controller-%i", i); 435a1961a4bSBlue Swirl for (j = 0; j < MAX_PILS; j++) { 4367abad863SAndreas Färber sysbus_init_irq(sbd, &s->cpu_irqs[i][j]); 437e80cfcfcSbellard } 4381437c94bSPaolo Bonzini memory_region_init_io(&s->slaves[i].iomem, OBJECT(s), 4391437c94bSPaolo Bonzini &slavio_intctl_mem_ops, 4408bb5ef33SBenoît Canet &s->slaves[i], slave_name, INTCTL_SIZE); 4417abad863SAndreas Färber sysbus_init_mmio(sbd, &s->slaves[i].iomem); 442a1961a4bSBlue Swirl s->slaves[i].cpu = i; 443a1961a4bSBlue Swirl s->slaves[i].master = s; 444a1961a4bSBlue Swirl } 445e80cfcfcSbellard } 446a1961a4bSBlue Swirl 447999e12bbSAnthony Liguori static void slavio_intctl_class_init(ObjectClass *klass, void *data) 448999e12bbSAnthony Liguori { 44939bffca2SAnthony Liguori DeviceClass *dc = DEVICE_CLASS(klass); 450148fbe95SHervé Poussineau InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(klass); 451999e12bbSAnthony Liguori 45239bffca2SAnthony Liguori dc->reset = slavio_intctl_reset; 45339bffca2SAnthony Liguori dc->vmsd = &vmstate_intctl; 454148fbe95SHervé Poussineau #ifdef DEBUG_IRQ_COUNT 455148fbe95SHervé Poussineau ic->get_statistics = slavio_intctl_get_statistics; 456148fbe95SHervé Poussineau #endif 457148fbe95SHervé Poussineau ic->print_info = slavio_intctl_print_info; 458999e12bbSAnthony Liguori } 459999e12bbSAnthony Liguori 4608c43a6f0SAndreas Färber static const TypeInfo slavio_intctl_info = { 4617abad863SAndreas Färber .name = TYPE_SLAVIO_INTCTL, 46239bffca2SAnthony Liguori .parent = TYPE_SYS_BUS_DEVICE, 46339bffca2SAnthony Liguori .instance_size = sizeof(SLAVIO_INTCTLState), 464c09008d2Sxiaoqiang.zhao .instance_init = slavio_intctl_init, 465999e12bbSAnthony Liguori .class_init = slavio_intctl_class_init, 466148fbe95SHervé Poussineau .interfaces = (InterfaceInfo[]) { 467148fbe95SHervé Poussineau { TYPE_INTERRUPT_STATS_PROVIDER }, 468148fbe95SHervé Poussineau { } 469148fbe95SHervé Poussineau }, 470a1961a4bSBlue Swirl }; 471a1961a4bSBlue Swirl 47283f7d43aSAndreas Färber static void slavio_intctl_register_types(void) 473a1961a4bSBlue Swirl { 47439bffca2SAnthony Liguori type_register_static(&slavio_intctl_info); 475a1961a4bSBlue Swirl } 476a1961a4bSBlue Swirl 47783f7d43aSAndreas Färber type_init(slavio_intctl_register_types) 478