1e69954b9Spbrook /* 29ee6e8bbSpbrook * ARM Generic/Distributed Interrupt Controller 3e69954b9Spbrook * 49ee6e8bbSpbrook * Copyright (c) 2006-2007 CodeSourcery. 5e69954b9Spbrook * Written by Paul Brook 6e69954b9Spbrook * 78e31bf38SMatthew Fernandez * This code is licensed under the GPL. 8e69954b9Spbrook */ 9e69954b9Spbrook 109ee6e8bbSpbrook /* This file contains implementation code for the RealView EB interrupt 110d256bdcSPeter Maydell * controller, MPCore distributed interrupt controller and ARMv7-M 120d256bdcSPeter Maydell * Nested Vectored Interrupt Controller. 130d256bdcSPeter Maydell * It is compiled in two ways: 140d256bdcSPeter Maydell * (1) as a standalone file to produce a sysbus device which is a GIC 150d256bdcSPeter Maydell * that can be used on the realview board and as one of the builtin 160d256bdcSPeter Maydell * private peripherals for the ARM MP CPUs (11MPCore, A9, etc) 170d256bdcSPeter Maydell * (2) by being directly #included into armv7m_nvic.c to produce the 180d256bdcSPeter Maydell * armv7m_nvic device. 190d256bdcSPeter Maydell */ 20e69954b9Spbrook 2183c9f4caSPaolo Bonzini #include "hw/sysbus.h" 2247b43a1fSPaolo Bonzini #include "gic_internal.h" 23dfc08079SAndreas Färber #include "qom/cpu.h" 24386e2955SPeter Maydell 25e69954b9Spbrook //#define DEBUG_GIC 26e69954b9Spbrook 27e69954b9Spbrook #ifdef DEBUG_GIC 28001faf32SBlue Swirl #define DPRINTF(fmt, ...) \ 295eb98401SPeter A. G. Crosthwaite do { fprintf(stderr, "arm_gic: " fmt , ## __VA_ARGS__); } while (0) 30e69954b9Spbrook #else 31001faf32SBlue Swirl #define DPRINTF(fmt, ...) do {} while(0) 32e69954b9Spbrook #endif 33e69954b9Spbrook 342a29ddeeSPeter Maydell static const uint8_t gic_id[] = { 352a29ddeeSPeter Maydell 0x90, 0x13, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 362a29ddeeSPeter Maydell }; 372a29ddeeSPeter Maydell 38c988bfadSPaul Brook #define NUM_CPU(s) ((s)->num_cpu) 399ee6e8bbSpbrook 40fae15286SPeter Maydell static inline int gic_get_current_cpu(GICState *s) 41926c4affSPeter Maydell { 42926c4affSPeter Maydell if (s->num_cpu > 1) { 434917cf44SAndreas Färber return current_cpu->cpu_index; 44926c4affSPeter Maydell } 45926c4affSPeter Maydell return 0; 46926c4affSPeter Maydell } 47926c4affSPeter Maydell 48e69954b9Spbrook /* TODO: Many places that call this routine could be optimized. */ 49e69954b9Spbrook /* Update interrupt status after enabled or pending bits have been changed. */ 50fae15286SPeter Maydell void gic_update(GICState *s) 51e69954b9Spbrook { 52e69954b9Spbrook int best_irq; 53e69954b9Spbrook int best_prio; 54e69954b9Spbrook int irq; 559ee6e8bbSpbrook int level; 569ee6e8bbSpbrook int cpu; 579ee6e8bbSpbrook int cm; 58e69954b9Spbrook 59c988bfadSPaul Brook for (cpu = 0; cpu < NUM_CPU(s); cpu++) { 609ee6e8bbSpbrook cm = 1 << cpu; 619ee6e8bbSpbrook s->current_pending[cpu] = 1023; 629ee6e8bbSpbrook if (!s->enabled || !s->cpu_enabled[cpu]) { 639ee6e8bbSpbrook qemu_irq_lower(s->parent_irq[cpu]); 64e69954b9Spbrook return; 65e69954b9Spbrook } 66e69954b9Spbrook best_prio = 0x100; 67e69954b9Spbrook best_irq = 1023; 68a32134aaSMark Langsdorf for (irq = 0; irq < s->num_irq; irq++) { 6941bf234dSRabin Vincent if (GIC_TEST_ENABLED(irq, cm) && GIC_TEST_PENDING(irq, cm)) { 709ee6e8bbSpbrook if (GIC_GET_PRIORITY(irq, cpu) < best_prio) { 719ee6e8bbSpbrook best_prio = GIC_GET_PRIORITY(irq, cpu); 72e69954b9Spbrook best_irq = irq; 73e69954b9Spbrook } 74e69954b9Spbrook } 75e69954b9Spbrook } 769ee6e8bbSpbrook level = 0; 77cad065f1SPeter Maydell if (best_prio < s->priority_mask[cpu]) { 789ee6e8bbSpbrook s->current_pending[cpu] = best_irq; 799ee6e8bbSpbrook if (best_prio < s->running_priority[cpu]) { 808c815fb3SPeter Crosthwaite DPRINTF("Raised pending IRQ %d (cpu %d)\n", best_irq, cpu); 819ee6e8bbSpbrook level = 1; 82e69954b9Spbrook } 83e69954b9Spbrook } 849ee6e8bbSpbrook qemu_set_irq(s->parent_irq[cpu], level); 859ee6e8bbSpbrook } 86e69954b9Spbrook } 87e69954b9Spbrook 88fae15286SPeter Maydell void gic_set_pending_private(GICState *s, int cpu, int irq) 899ee6e8bbSpbrook { 909ee6e8bbSpbrook int cm = 1 << cpu; 919ee6e8bbSpbrook 929ee6e8bbSpbrook if (GIC_TEST_PENDING(irq, cm)) 939ee6e8bbSpbrook return; 949ee6e8bbSpbrook 959ee6e8bbSpbrook DPRINTF("Set %d pending cpu %d\n", irq, cpu); 969ee6e8bbSpbrook GIC_SET_PENDING(irq, cm); 979ee6e8bbSpbrook gic_update(s); 989ee6e8bbSpbrook } 999ee6e8bbSpbrook 1009ee6e8bbSpbrook /* Process a change in an external IRQ input. */ 101e69954b9Spbrook static void gic_set_irq(void *opaque, int irq, int level) 102e69954b9Spbrook { 103544d1afaSPeter Maydell /* Meaning of the 'irq' parameter: 104544d1afaSPeter Maydell * [0..N-1] : external interrupts 105544d1afaSPeter Maydell * [N..N+31] : PPI (internal) interrupts for CPU 0 106544d1afaSPeter Maydell * [N+32..N+63] : PPI (internal interrupts for CPU 1 107544d1afaSPeter Maydell * ... 108544d1afaSPeter Maydell */ 109fae15286SPeter Maydell GICState *s = (GICState *)opaque; 110544d1afaSPeter Maydell int cm, target; 111544d1afaSPeter Maydell if (irq < (s->num_irq - GIC_INTERNAL)) { 112e69954b9Spbrook /* The first external input line is internal interrupt 32. */ 113544d1afaSPeter Maydell cm = ALL_CPU_MASK; 11469253800SRusty Russell irq += GIC_INTERNAL; 115544d1afaSPeter Maydell target = GIC_TARGET(irq); 116544d1afaSPeter Maydell } else { 117544d1afaSPeter Maydell int cpu; 118544d1afaSPeter Maydell irq -= (s->num_irq - GIC_INTERNAL); 119544d1afaSPeter Maydell cpu = irq / GIC_INTERNAL; 120544d1afaSPeter Maydell irq %= GIC_INTERNAL; 121544d1afaSPeter Maydell cm = 1 << cpu; 122544d1afaSPeter Maydell target = cm; 123544d1afaSPeter Maydell } 124544d1afaSPeter Maydell 125544d1afaSPeter Maydell if (level == GIC_TEST_LEVEL(irq, cm)) { 126e69954b9Spbrook return; 127544d1afaSPeter Maydell } 128e69954b9Spbrook 129e69954b9Spbrook if (level) { 130544d1afaSPeter Maydell GIC_SET_LEVEL(irq, cm); 13104050c5cSChristoffer Dall if (GIC_TEST_EDGE_TRIGGER(irq) || GIC_TEST_ENABLED(irq, cm)) { 132544d1afaSPeter Maydell DPRINTF("Set %d pending mask %x\n", irq, target); 133544d1afaSPeter Maydell GIC_SET_PENDING(irq, target); 134e69954b9Spbrook } 135e69954b9Spbrook } else { 136544d1afaSPeter Maydell GIC_CLEAR_LEVEL(irq, cm); 137e69954b9Spbrook } 138e69954b9Spbrook gic_update(s); 139e69954b9Spbrook } 140e69954b9Spbrook 141fae15286SPeter Maydell static void gic_set_running_irq(GICState *s, int cpu, int irq) 142e69954b9Spbrook { 1439ee6e8bbSpbrook s->running_irq[cpu] = irq; 1449ee6e8bbSpbrook if (irq == 1023) { 1459ee6e8bbSpbrook s->running_priority[cpu] = 0x100; 1469ee6e8bbSpbrook } else { 1479ee6e8bbSpbrook s->running_priority[cpu] = GIC_GET_PRIORITY(irq, cpu); 1489ee6e8bbSpbrook } 149e69954b9Spbrook gic_update(s); 150e69954b9Spbrook } 151e69954b9Spbrook 152fae15286SPeter Maydell uint32_t gic_acknowledge_irq(GICState *s, int cpu) 153e69954b9Spbrook { 154e69954b9Spbrook int new_irq; 1559ee6e8bbSpbrook int cm = 1 << cpu; 1569ee6e8bbSpbrook new_irq = s->current_pending[cpu]; 1579ee6e8bbSpbrook if (new_irq == 1023 1589ee6e8bbSpbrook || GIC_GET_PRIORITY(new_irq, cpu) >= s->running_priority[cpu]) { 159e69954b9Spbrook DPRINTF("ACK no pending IRQ\n"); 160e69954b9Spbrook return 1023; 161e69954b9Spbrook } 1629ee6e8bbSpbrook s->last_active[new_irq][cpu] = s->running_irq[cpu]; 1639ee6e8bbSpbrook /* Clear pending flags for both level and edge triggered interrupts. 1649ee6e8bbSpbrook Level triggered IRQs will be reasserted once they become inactive. */ 1659ee6e8bbSpbrook GIC_CLEAR_PENDING(new_irq, GIC_TEST_MODEL(new_irq) ? ALL_CPU_MASK : cm); 1669ee6e8bbSpbrook gic_set_running_irq(s, cpu, new_irq); 167e69954b9Spbrook DPRINTF("ACK %d\n", new_irq); 168e69954b9Spbrook return new_irq; 169e69954b9Spbrook } 170e69954b9Spbrook 171*9df90ad0SChristoffer Dall void gic_set_priority(GICState *s, int cpu, int irq, uint8_t val) 172*9df90ad0SChristoffer Dall { 173*9df90ad0SChristoffer Dall if (irq < GIC_INTERNAL) { 174*9df90ad0SChristoffer Dall s->priority1[irq][cpu] = val; 175*9df90ad0SChristoffer Dall } else { 176*9df90ad0SChristoffer Dall s->priority2[(irq) - GIC_INTERNAL] = val; 177*9df90ad0SChristoffer Dall } 178*9df90ad0SChristoffer Dall } 179*9df90ad0SChristoffer Dall 180fae15286SPeter Maydell void gic_complete_irq(GICState *s, int cpu, int irq) 181e69954b9Spbrook { 182e69954b9Spbrook int update = 0; 1839ee6e8bbSpbrook int cm = 1 << cpu; 184df628ff1Spbrook DPRINTF("EOI %d\n", irq); 185a32134aaSMark Langsdorf if (irq >= s->num_irq) { 186217bfb44SPeter Maydell /* This handles two cases: 187217bfb44SPeter Maydell * 1. If software writes the ID of a spurious interrupt [ie 1023] 188217bfb44SPeter Maydell * to the GICC_EOIR, the GIC ignores that write. 189217bfb44SPeter Maydell * 2. If software writes the number of a non-existent interrupt 190217bfb44SPeter Maydell * this must be a subcase of "value written does not match the last 191217bfb44SPeter Maydell * valid interrupt value read from the Interrupt Acknowledge 192217bfb44SPeter Maydell * register" and so this is UNPREDICTABLE. We choose to ignore it. 193217bfb44SPeter Maydell */ 194217bfb44SPeter Maydell return; 195217bfb44SPeter Maydell } 1969ee6e8bbSpbrook if (s->running_irq[cpu] == 1023) 197e69954b9Spbrook return; /* No active IRQ. */ 198e69954b9Spbrook /* Mark level triggered interrupts as pending if they are still 199e69954b9Spbrook raised. */ 20004050c5cSChristoffer Dall if (!GIC_TEST_EDGE_TRIGGER(irq) && GIC_TEST_ENABLED(irq, cm) 2019ee6e8bbSpbrook && GIC_TEST_LEVEL(irq, cm) && (GIC_TARGET(irq) & cm) != 0) { 2029ee6e8bbSpbrook DPRINTF("Set %d pending mask %x\n", irq, cm); 2039ee6e8bbSpbrook GIC_SET_PENDING(irq, cm); 204e69954b9Spbrook update = 1; 205e69954b9Spbrook } 2069ee6e8bbSpbrook if (irq != s->running_irq[cpu]) { 207e69954b9Spbrook /* Complete an IRQ that is not currently running. */ 2089ee6e8bbSpbrook int tmp = s->running_irq[cpu]; 2099ee6e8bbSpbrook while (s->last_active[tmp][cpu] != 1023) { 2109ee6e8bbSpbrook if (s->last_active[tmp][cpu] == irq) { 2119ee6e8bbSpbrook s->last_active[tmp][cpu] = s->last_active[irq][cpu]; 212e69954b9Spbrook break; 213e69954b9Spbrook } 2149ee6e8bbSpbrook tmp = s->last_active[tmp][cpu]; 215e69954b9Spbrook } 216e69954b9Spbrook if (update) { 217e69954b9Spbrook gic_update(s); 218e69954b9Spbrook } 219e69954b9Spbrook } else { 220e69954b9Spbrook /* Complete the current running IRQ. */ 2219ee6e8bbSpbrook gic_set_running_irq(s, cpu, s->last_active[s->running_irq[cpu]][cpu]); 222e69954b9Spbrook } 223e69954b9Spbrook } 224e69954b9Spbrook 225a8170e5eSAvi Kivity static uint32_t gic_dist_readb(void *opaque, hwaddr offset) 226e69954b9Spbrook { 227fae15286SPeter Maydell GICState *s = (GICState *)opaque; 228e69954b9Spbrook uint32_t res; 229e69954b9Spbrook int irq; 230e69954b9Spbrook int i; 2319ee6e8bbSpbrook int cpu; 2329ee6e8bbSpbrook int cm; 2339ee6e8bbSpbrook int mask; 234e69954b9Spbrook 235926c4affSPeter Maydell cpu = gic_get_current_cpu(s); 2369ee6e8bbSpbrook cm = 1 << cpu; 237e69954b9Spbrook if (offset < 0x100) { 238e69954b9Spbrook if (offset == 0) 239e69954b9Spbrook return s->enabled; 240e69954b9Spbrook if (offset == 4) 241a32134aaSMark Langsdorf return ((s->num_irq / 32) - 1) | ((NUM_CPU(s) - 1) << 5); 242e69954b9Spbrook if (offset < 0x08) 243e69954b9Spbrook return 0; 244b79f2265SRob Herring if (offset >= 0x80) { 245b79f2265SRob Herring /* Interrupt Security , RAZ/WI */ 246b79f2265SRob Herring return 0; 247b79f2265SRob Herring } 248e69954b9Spbrook goto bad_reg; 249e69954b9Spbrook } else if (offset < 0x200) { 250e69954b9Spbrook /* Interrupt Set/Clear Enable. */ 251e69954b9Spbrook if (offset < 0x180) 252e69954b9Spbrook irq = (offset - 0x100) * 8; 253e69954b9Spbrook else 254e69954b9Spbrook irq = (offset - 0x180) * 8; 2559ee6e8bbSpbrook irq += GIC_BASE_IRQ; 256a32134aaSMark Langsdorf if (irq >= s->num_irq) 257e69954b9Spbrook goto bad_reg; 258e69954b9Spbrook res = 0; 259e69954b9Spbrook for (i = 0; i < 8; i++) { 26041bf234dSRabin Vincent if (GIC_TEST_ENABLED(irq + i, cm)) { 261e69954b9Spbrook res |= (1 << i); 262e69954b9Spbrook } 263e69954b9Spbrook } 264e69954b9Spbrook } else if (offset < 0x300) { 265e69954b9Spbrook /* Interrupt Set/Clear Pending. */ 266e69954b9Spbrook if (offset < 0x280) 267e69954b9Spbrook irq = (offset - 0x200) * 8; 268e69954b9Spbrook else 269e69954b9Spbrook irq = (offset - 0x280) * 8; 2709ee6e8bbSpbrook irq += GIC_BASE_IRQ; 271a32134aaSMark Langsdorf if (irq >= s->num_irq) 272e69954b9Spbrook goto bad_reg; 273e69954b9Spbrook res = 0; 27469253800SRusty Russell mask = (irq < GIC_INTERNAL) ? cm : ALL_CPU_MASK; 275e69954b9Spbrook for (i = 0; i < 8; i++) { 2769ee6e8bbSpbrook if (GIC_TEST_PENDING(irq + i, mask)) { 277e69954b9Spbrook res |= (1 << i); 278e69954b9Spbrook } 279e69954b9Spbrook } 280e69954b9Spbrook } else if (offset < 0x400) { 281e69954b9Spbrook /* Interrupt Active. */ 2829ee6e8bbSpbrook irq = (offset - 0x300) * 8 + GIC_BASE_IRQ; 283a32134aaSMark Langsdorf if (irq >= s->num_irq) 284e69954b9Spbrook goto bad_reg; 285e69954b9Spbrook res = 0; 28669253800SRusty Russell mask = (irq < GIC_INTERNAL) ? cm : ALL_CPU_MASK; 287e69954b9Spbrook for (i = 0; i < 8; i++) { 2889ee6e8bbSpbrook if (GIC_TEST_ACTIVE(irq + i, mask)) { 289e69954b9Spbrook res |= (1 << i); 290e69954b9Spbrook } 291e69954b9Spbrook } 292e69954b9Spbrook } else if (offset < 0x800) { 293e69954b9Spbrook /* Interrupt Priority. */ 2949ee6e8bbSpbrook irq = (offset - 0x400) + GIC_BASE_IRQ; 295a32134aaSMark Langsdorf if (irq >= s->num_irq) 296e69954b9Spbrook goto bad_reg; 2979ee6e8bbSpbrook res = GIC_GET_PRIORITY(irq, cpu); 298e69954b9Spbrook } else if (offset < 0xc00) { 299e69954b9Spbrook /* Interrupt CPU Target. */ 3006b9680bbSPeter Maydell if (s->num_cpu == 1 && s->revision != REV_11MPCORE) { 3016b9680bbSPeter Maydell /* For uniprocessor GICs these RAZ/WI */ 3026b9680bbSPeter Maydell res = 0; 3036b9680bbSPeter Maydell } else { 3049ee6e8bbSpbrook irq = (offset - 0x800) + GIC_BASE_IRQ; 3056b9680bbSPeter Maydell if (irq >= s->num_irq) { 306e69954b9Spbrook goto bad_reg; 3076b9680bbSPeter Maydell } 3089ee6e8bbSpbrook if (irq >= 29 && irq <= 31) { 3099ee6e8bbSpbrook res = cm; 3109ee6e8bbSpbrook } else { 3119ee6e8bbSpbrook res = GIC_TARGET(irq); 3129ee6e8bbSpbrook } 3136b9680bbSPeter Maydell } 314e69954b9Spbrook } else if (offset < 0xf00) { 315e69954b9Spbrook /* Interrupt Configuration. */ 3169ee6e8bbSpbrook irq = (offset - 0xc00) * 2 + GIC_BASE_IRQ; 317a32134aaSMark Langsdorf if (irq >= s->num_irq) 318e69954b9Spbrook goto bad_reg; 319e69954b9Spbrook res = 0; 320e69954b9Spbrook for (i = 0; i < 4; i++) { 321e69954b9Spbrook if (GIC_TEST_MODEL(irq + i)) 322e69954b9Spbrook res |= (1 << (i * 2)); 32304050c5cSChristoffer Dall if (GIC_TEST_EDGE_TRIGGER(irq + i)) 324e69954b9Spbrook res |= (2 << (i * 2)); 325e69954b9Spbrook } 326e69954b9Spbrook } else if (offset < 0xfe0) { 327e69954b9Spbrook goto bad_reg; 328e69954b9Spbrook } else /* offset >= 0xfe0 */ { 329e69954b9Spbrook if (offset & 3) { 330e69954b9Spbrook res = 0; 331e69954b9Spbrook } else { 332e69954b9Spbrook res = gic_id[(offset - 0xfe0) >> 2]; 333e69954b9Spbrook } 334e69954b9Spbrook } 335e69954b9Spbrook return res; 336e69954b9Spbrook bad_reg: 3378c8dc39fSPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 3388c8dc39fSPeter Maydell "gic_dist_readb: Bad offset %x\n", (int)offset); 339e69954b9Spbrook return 0; 340e69954b9Spbrook } 341e69954b9Spbrook 342a8170e5eSAvi Kivity static uint32_t gic_dist_readw(void *opaque, hwaddr offset) 343e69954b9Spbrook { 344e69954b9Spbrook uint32_t val; 345e69954b9Spbrook val = gic_dist_readb(opaque, offset); 346e69954b9Spbrook val |= gic_dist_readb(opaque, offset + 1) << 8; 347e69954b9Spbrook return val; 348e69954b9Spbrook } 349e69954b9Spbrook 350a8170e5eSAvi Kivity static uint32_t gic_dist_readl(void *opaque, hwaddr offset) 351e69954b9Spbrook { 352e69954b9Spbrook uint32_t val; 353e69954b9Spbrook val = gic_dist_readw(opaque, offset); 354e69954b9Spbrook val |= gic_dist_readw(opaque, offset + 2) << 16; 355e69954b9Spbrook return val; 356e69954b9Spbrook } 357e69954b9Spbrook 358a8170e5eSAvi Kivity static void gic_dist_writeb(void *opaque, hwaddr offset, 359e69954b9Spbrook uint32_t value) 360e69954b9Spbrook { 361fae15286SPeter Maydell GICState *s = (GICState *)opaque; 362e69954b9Spbrook int irq; 363e69954b9Spbrook int i; 3649ee6e8bbSpbrook int cpu; 365e69954b9Spbrook 366926c4affSPeter Maydell cpu = gic_get_current_cpu(s); 367e69954b9Spbrook if (offset < 0x100) { 368e69954b9Spbrook if (offset == 0) { 369e69954b9Spbrook s->enabled = (value & 1); 370e69954b9Spbrook DPRINTF("Distribution %sabled\n", s->enabled ? "En" : "Dis"); 371e69954b9Spbrook } else if (offset < 4) { 372e69954b9Spbrook /* ignored. */ 373b79f2265SRob Herring } else if (offset >= 0x80) { 374b79f2265SRob Herring /* Interrupt Security Registers, RAZ/WI */ 375e69954b9Spbrook } else { 376e69954b9Spbrook goto bad_reg; 377e69954b9Spbrook } 378e69954b9Spbrook } else if (offset < 0x180) { 379e69954b9Spbrook /* Interrupt Set Enable. */ 3809ee6e8bbSpbrook irq = (offset - 0x100) * 8 + GIC_BASE_IRQ; 381a32134aaSMark Langsdorf if (irq >= s->num_irq) 382e69954b9Spbrook goto bad_reg; 3839ee6e8bbSpbrook if (irq < 16) 3849ee6e8bbSpbrook value = 0xff; 385e69954b9Spbrook for (i = 0; i < 8; i++) { 386e69954b9Spbrook if (value & (1 << i)) { 387f47b48fbSDaniel Sangorrin int mask = 388f47b48fbSDaniel Sangorrin (irq < GIC_INTERNAL) ? (1 << cpu) : GIC_TARGET(irq + i); 38969253800SRusty Russell int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK; 39041bf234dSRabin Vincent 39141bf234dSRabin Vincent if (!GIC_TEST_ENABLED(irq + i, cm)) { 392e69954b9Spbrook DPRINTF("Enabled IRQ %d\n", irq + i); 39341bf234dSRabin Vincent } 39441bf234dSRabin Vincent GIC_SET_ENABLED(irq + i, cm); 395e69954b9Spbrook /* If a raised level triggered IRQ enabled then mark 396e69954b9Spbrook is as pending. */ 3979ee6e8bbSpbrook if (GIC_TEST_LEVEL(irq + i, mask) 39804050c5cSChristoffer Dall && !GIC_TEST_EDGE_TRIGGER(irq + i)) { 3999ee6e8bbSpbrook DPRINTF("Set %d pending mask %x\n", irq + i, mask); 4009ee6e8bbSpbrook GIC_SET_PENDING(irq + i, mask); 4019ee6e8bbSpbrook } 402e69954b9Spbrook } 403e69954b9Spbrook } 404e69954b9Spbrook } else if (offset < 0x200) { 405e69954b9Spbrook /* Interrupt Clear Enable. */ 4069ee6e8bbSpbrook irq = (offset - 0x180) * 8 + GIC_BASE_IRQ; 407a32134aaSMark Langsdorf if (irq >= s->num_irq) 408e69954b9Spbrook goto bad_reg; 4099ee6e8bbSpbrook if (irq < 16) 4109ee6e8bbSpbrook value = 0; 411e69954b9Spbrook for (i = 0; i < 8; i++) { 412e69954b9Spbrook if (value & (1 << i)) { 41369253800SRusty Russell int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK; 41441bf234dSRabin Vincent 41541bf234dSRabin Vincent if (GIC_TEST_ENABLED(irq + i, cm)) { 416e69954b9Spbrook DPRINTF("Disabled IRQ %d\n", irq + i); 41741bf234dSRabin Vincent } 41841bf234dSRabin Vincent GIC_CLEAR_ENABLED(irq + i, cm); 419e69954b9Spbrook } 420e69954b9Spbrook } 421e69954b9Spbrook } else if (offset < 0x280) { 422e69954b9Spbrook /* Interrupt Set Pending. */ 4239ee6e8bbSpbrook irq = (offset - 0x200) * 8 + GIC_BASE_IRQ; 424a32134aaSMark Langsdorf if (irq >= s->num_irq) 425e69954b9Spbrook goto bad_reg; 4269ee6e8bbSpbrook if (irq < 16) 4279ee6e8bbSpbrook irq = 0; 4289ee6e8bbSpbrook 429e69954b9Spbrook for (i = 0; i < 8; i++) { 430e69954b9Spbrook if (value & (1 << i)) { 431f47b48fbSDaniel Sangorrin GIC_SET_PENDING(irq + i, GIC_TARGET(irq + i)); 432e69954b9Spbrook } 433e69954b9Spbrook } 434e69954b9Spbrook } else if (offset < 0x300) { 435e69954b9Spbrook /* Interrupt Clear Pending. */ 4369ee6e8bbSpbrook irq = (offset - 0x280) * 8 + GIC_BASE_IRQ; 437a32134aaSMark Langsdorf if (irq >= s->num_irq) 438e69954b9Spbrook goto bad_reg; 439e69954b9Spbrook for (i = 0; i < 8; i++) { 4409ee6e8bbSpbrook /* ??? This currently clears the pending bit for all CPUs, even 4419ee6e8bbSpbrook for per-CPU interrupts. It's unclear whether this is the 4429ee6e8bbSpbrook corect behavior. */ 443e69954b9Spbrook if (value & (1 << i)) { 4449ee6e8bbSpbrook GIC_CLEAR_PENDING(irq + i, ALL_CPU_MASK); 445e69954b9Spbrook } 446e69954b9Spbrook } 447e69954b9Spbrook } else if (offset < 0x400) { 448e69954b9Spbrook /* Interrupt Active. */ 449e69954b9Spbrook goto bad_reg; 450e69954b9Spbrook } else if (offset < 0x800) { 451e69954b9Spbrook /* Interrupt Priority. */ 4529ee6e8bbSpbrook irq = (offset - 0x400) + GIC_BASE_IRQ; 453a32134aaSMark Langsdorf if (irq >= s->num_irq) 454e69954b9Spbrook goto bad_reg; 455*9df90ad0SChristoffer Dall gic_set_priority(s, cpu, irq, value); 456e69954b9Spbrook } else if (offset < 0xc00) { 4576b9680bbSPeter Maydell /* Interrupt CPU Target. RAZ/WI on uniprocessor GICs, with the 4586b9680bbSPeter Maydell * annoying exception of the 11MPCore's GIC. 4596b9680bbSPeter Maydell */ 4606b9680bbSPeter Maydell if (s->num_cpu != 1 || s->revision == REV_11MPCORE) { 4619ee6e8bbSpbrook irq = (offset - 0x800) + GIC_BASE_IRQ; 4626b9680bbSPeter Maydell if (irq >= s->num_irq) { 463e69954b9Spbrook goto bad_reg; 4646b9680bbSPeter Maydell } 4656b9680bbSPeter Maydell if (irq < 29) { 4669ee6e8bbSpbrook value = 0; 4676b9680bbSPeter Maydell } else if (irq < GIC_INTERNAL) { 4689ee6e8bbSpbrook value = ALL_CPU_MASK; 4696b9680bbSPeter Maydell } 4709ee6e8bbSpbrook s->irq_target[irq] = value & ALL_CPU_MASK; 4716b9680bbSPeter Maydell } 472e69954b9Spbrook } else if (offset < 0xf00) { 473e69954b9Spbrook /* Interrupt Configuration. */ 4749ee6e8bbSpbrook irq = (offset - 0xc00) * 4 + GIC_BASE_IRQ; 475a32134aaSMark Langsdorf if (irq >= s->num_irq) 476e69954b9Spbrook goto bad_reg; 47769253800SRusty Russell if (irq < GIC_INTERNAL) 4789ee6e8bbSpbrook value |= 0xaa; 479e69954b9Spbrook for (i = 0; i < 4; i++) { 480e69954b9Spbrook if (value & (1 << (i * 2))) { 481e69954b9Spbrook GIC_SET_MODEL(irq + i); 482e69954b9Spbrook } else { 483e69954b9Spbrook GIC_CLEAR_MODEL(irq + i); 484e69954b9Spbrook } 485e69954b9Spbrook if (value & (2 << (i * 2))) { 48604050c5cSChristoffer Dall GIC_SET_EDGE_TRIGGER(irq + i); 487e69954b9Spbrook } else { 48804050c5cSChristoffer Dall GIC_CLEAR_EDGE_TRIGGER(irq + i); 489e69954b9Spbrook } 490e69954b9Spbrook } 491e69954b9Spbrook } else { 4929ee6e8bbSpbrook /* 0xf00 is only handled for 32-bit writes. */ 493e69954b9Spbrook goto bad_reg; 494e69954b9Spbrook } 495e69954b9Spbrook gic_update(s); 496e69954b9Spbrook return; 497e69954b9Spbrook bad_reg: 4988c8dc39fSPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 4998c8dc39fSPeter Maydell "gic_dist_writeb: Bad offset %x\n", (int)offset); 500e69954b9Spbrook } 501e69954b9Spbrook 502a8170e5eSAvi Kivity static void gic_dist_writew(void *opaque, hwaddr offset, 503e69954b9Spbrook uint32_t value) 504e69954b9Spbrook { 505e69954b9Spbrook gic_dist_writeb(opaque, offset, value & 0xff); 506e69954b9Spbrook gic_dist_writeb(opaque, offset + 1, value >> 8); 507e69954b9Spbrook } 508e69954b9Spbrook 509a8170e5eSAvi Kivity static void gic_dist_writel(void *opaque, hwaddr offset, 510e69954b9Spbrook uint32_t value) 511e69954b9Spbrook { 512fae15286SPeter Maydell GICState *s = (GICState *)opaque; 5138da3ff18Spbrook if (offset == 0xf00) { 5149ee6e8bbSpbrook int cpu; 5159ee6e8bbSpbrook int irq; 5169ee6e8bbSpbrook int mask; 5179ee6e8bbSpbrook 518926c4affSPeter Maydell cpu = gic_get_current_cpu(s); 5199ee6e8bbSpbrook irq = value & 0x3ff; 5209ee6e8bbSpbrook switch ((value >> 24) & 3) { 5219ee6e8bbSpbrook case 0: 5229ee6e8bbSpbrook mask = (value >> 16) & ALL_CPU_MASK; 5239ee6e8bbSpbrook break; 5249ee6e8bbSpbrook case 1: 525fa250144SAdam Lackorzynski mask = ALL_CPU_MASK ^ (1 << cpu); 5269ee6e8bbSpbrook break; 5279ee6e8bbSpbrook case 2: 528fa250144SAdam Lackorzynski mask = 1 << cpu; 5299ee6e8bbSpbrook break; 5309ee6e8bbSpbrook default: 5319ee6e8bbSpbrook DPRINTF("Bad Soft Int target filter\n"); 5329ee6e8bbSpbrook mask = ALL_CPU_MASK; 5339ee6e8bbSpbrook break; 5349ee6e8bbSpbrook } 5359ee6e8bbSpbrook GIC_SET_PENDING(irq, mask); 5369ee6e8bbSpbrook gic_update(s); 5379ee6e8bbSpbrook return; 5389ee6e8bbSpbrook } 539e69954b9Spbrook gic_dist_writew(opaque, offset, value & 0xffff); 540e69954b9Spbrook gic_dist_writew(opaque, offset + 2, value >> 16); 541e69954b9Spbrook } 542e69954b9Spbrook 543755c0802SAvi Kivity static const MemoryRegionOps gic_dist_ops = { 544755c0802SAvi Kivity .old_mmio = { 545755c0802SAvi Kivity .read = { gic_dist_readb, gic_dist_readw, gic_dist_readl, }, 546755c0802SAvi Kivity .write = { gic_dist_writeb, gic_dist_writew, gic_dist_writel, }, 547755c0802SAvi Kivity }, 548755c0802SAvi Kivity .endianness = DEVICE_NATIVE_ENDIAN, 549e69954b9Spbrook }; 550e69954b9Spbrook 551fae15286SPeter Maydell static uint32_t gic_cpu_read(GICState *s, int cpu, int offset) 552e69954b9Spbrook { 553e69954b9Spbrook switch (offset) { 554e69954b9Spbrook case 0x00: /* Control */ 5559ee6e8bbSpbrook return s->cpu_enabled[cpu]; 556e69954b9Spbrook case 0x04: /* Priority mask */ 5579ee6e8bbSpbrook return s->priority_mask[cpu]; 558e69954b9Spbrook case 0x08: /* Binary Point */ 559e69954b9Spbrook /* ??? Not implemented. */ 560e69954b9Spbrook return 0; 561e69954b9Spbrook case 0x0c: /* Acknowledge */ 5629ee6e8bbSpbrook return gic_acknowledge_irq(s, cpu); 56366a0a2cbSDong Xu Wang case 0x14: /* Running Priority */ 5649ee6e8bbSpbrook return s->running_priority[cpu]; 565e69954b9Spbrook case 0x18: /* Highest Pending Interrupt */ 5669ee6e8bbSpbrook return s->current_pending[cpu]; 567e69954b9Spbrook default: 5688c8dc39fSPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 5698c8dc39fSPeter Maydell "gic_cpu_read: Bad offset %x\n", (int)offset); 570e69954b9Spbrook return 0; 571e69954b9Spbrook } 572e69954b9Spbrook } 573e69954b9Spbrook 574fae15286SPeter Maydell static void gic_cpu_write(GICState *s, int cpu, int offset, uint32_t value) 575e69954b9Spbrook { 576e69954b9Spbrook switch (offset) { 577e69954b9Spbrook case 0x00: /* Control */ 5789ee6e8bbSpbrook s->cpu_enabled[cpu] = (value & 1); 5799ab1b605SEvgeny Voevodin DPRINTF("CPU %d %sabled\n", cpu, s->cpu_enabled[cpu] ? "En" : "Dis"); 580e69954b9Spbrook break; 581e69954b9Spbrook case 0x04: /* Priority mask */ 5829ee6e8bbSpbrook s->priority_mask[cpu] = (value & 0xff); 583e69954b9Spbrook break; 584e69954b9Spbrook case 0x08: /* Binary Point */ 585e69954b9Spbrook /* ??? Not implemented. */ 586e69954b9Spbrook break; 587e69954b9Spbrook case 0x10: /* End Of Interrupt */ 5889ee6e8bbSpbrook return gic_complete_irq(s, cpu, value & 0x3ff); 589e69954b9Spbrook default: 5908c8dc39fSPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 5918c8dc39fSPeter Maydell "gic_cpu_write: Bad offset %x\n", (int)offset); 592e69954b9Spbrook return; 593e69954b9Spbrook } 594e69954b9Spbrook gic_update(s); 595e69954b9Spbrook } 596e2c56465SPeter Maydell 597e2c56465SPeter Maydell /* Wrappers to read/write the GIC CPU interface for the current CPU */ 598a8170e5eSAvi Kivity static uint64_t gic_thiscpu_read(void *opaque, hwaddr addr, 599e2c56465SPeter Maydell unsigned size) 600e2c56465SPeter Maydell { 601fae15286SPeter Maydell GICState *s = (GICState *)opaque; 602926c4affSPeter Maydell return gic_cpu_read(s, gic_get_current_cpu(s), addr); 603e2c56465SPeter Maydell } 604e2c56465SPeter Maydell 605a8170e5eSAvi Kivity static void gic_thiscpu_write(void *opaque, hwaddr addr, 606e2c56465SPeter Maydell uint64_t value, unsigned size) 607e2c56465SPeter Maydell { 608fae15286SPeter Maydell GICState *s = (GICState *)opaque; 609926c4affSPeter Maydell gic_cpu_write(s, gic_get_current_cpu(s), addr, value); 610e2c56465SPeter Maydell } 611e2c56465SPeter Maydell 612e2c56465SPeter Maydell /* Wrappers to read/write the GIC CPU interface for a specific CPU. 613fae15286SPeter Maydell * These just decode the opaque pointer into GICState* + cpu id. 614e2c56465SPeter Maydell */ 615a8170e5eSAvi Kivity static uint64_t gic_do_cpu_read(void *opaque, hwaddr addr, 616e2c56465SPeter Maydell unsigned size) 617e2c56465SPeter Maydell { 618fae15286SPeter Maydell GICState **backref = (GICState **)opaque; 619fae15286SPeter Maydell GICState *s = *backref; 620e2c56465SPeter Maydell int id = (backref - s->backref); 6210e4a398aSPeter Maydell return gic_cpu_read(s, id, addr); 622e2c56465SPeter Maydell } 623e2c56465SPeter Maydell 624a8170e5eSAvi Kivity static void gic_do_cpu_write(void *opaque, hwaddr addr, 625e2c56465SPeter Maydell uint64_t value, unsigned size) 626e2c56465SPeter Maydell { 627fae15286SPeter Maydell GICState **backref = (GICState **)opaque; 628fae15286SPeter Maydell GICState *s = *backref; 629e2c56465SPeter Maydell int id = (backref - s->backref); 6300e4a398aSPeter Maydell gic_cpu_write(s, id, addr, value); 631e2c56465SPeter Maydell } 632e2c56465SPeter Maydell 633e2c56465SPeter Maydell static const MemoryRegionOps gic_thiscpu_ops = { 634e2c56465SPeter Maydell .read = gic_thiscpu_read, 635e2c56465SPeter Maydell .write = gic_thiscpu_write, 636e2c56465SPeter Maydell .endianness = DEVICE_NATIVE_ENDIAN, 637e2c56465SPeter Maydell }; 638e2c56465SPeter Maydell 639e2c56465SPeter Maydell static const MemoryRegionOps gic_cpu_ops = { 640e2c56465SPeter Maydell .read = gic_do_cpu_read, 641e2c56465SPeter Maydell .write = gic_do_cpu_write, 642e2c56465SPeter Maydell .endianness = DEVICE_NATIVE_ENDIAN, 643e2c56465SPeter Maydell }; 644e69954b9Spbrook 645fae15286SPeter Maydell void gic_init_irqs_and_distributor(GICState *s, int num_irq) 646e69954b9Spbrook { 647285b4432SAndreas Färber SysBusDevice *sbd = SYS_BUS_DEVICE(s); 6489ee6e8bbSpbrook int i; 649e69954b9Spbrook 650544d1afaSPeter Maydell i = s->num_irq - GIC_INTERNAL; 651544d1afaSPeter Maydell /* For the GIC, also expose incoming GPIO lines for PPIs for each CPU. 652544d1afaSPeter Maydell * GPIO array layout is thus: 653544d1afaSPeter Maydell * [0..N-1] SPIs 654544d1afaSPeter Maydell * [N..N+31] PPIs for CPU 0 655544d1afaSPeter Maydell * [N+32..N+63] PPIs for CPU 1 656544d1afaSPeter Maydell * ... 657544d1afaSPeter Maydell */ 65884e4fccbSPeter Maydell if (s->revision != REV_NVIC) { 659c48c6522SPeter Maydell i += (GIC_INTERNAL * s->num_cpu); 66084e4fccbSPeter Maydell } 661285b4432SAndreas Färber qdev_init_gpio_in(DEVICE(s), gic_set_irq, i); 662c988bfadSPaul Brook for (i = 0; i < NUM_CPU(s); i++) { 663285b4432SAndreas Färber sysbus_init_irq(sbd, &s->parent_irq[i]); 6649ee6e8bbSpbrook } 6651437c94bSPaolo Bonzini memory_region_init_io(&s->iomem, OBJECT(s), &gic_dist_ops, s, 6661437c94bSPaolo Bonzini "gic_dist", 0x1000); 6672b518c56SPeter Maydell } 6682b518c56SPeter Maydell 66953111180SPeter Maydell static void arm_gic_realize(DeviceState *dev, Error **errp) 6702b518c56SPeter Maydell { 67153111180SPeter Maydell /* Device instance realize function for the GIC sysbus device */ 6722b518c56SPeter Maydell int i; 67353111180SPeter Maydell GICState *s = ARM_GIC(dev); 67453111180SPeter Maydell SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 6751e8cae4dSPeter Maydell ARMGICClass *agc = ARM_GIC_GET_CLASS(s); 6761e8cae4dSPeter Maydell 67753111180SPeter Maydell agc->parent_realize(dev, errp); 67853111180SPeter Maydell if (error_is_set(errp)) { 67953111180SPeter Maydell return; 68053111180SPeter Maydell } 6811e8cae4dSPeter Maydell 6822b518c56SPeter Maydell gic_init_irqs_and_distributor(s, s->num_irq); 6832b518c56SPeter Maydell 684e2c56465SPeter Maydell /* Memory regions for the CPU interfaces (NVIC doesn't have these): 685e2c56465SPeter Maydell * a region for "CPU interface for this core", then a region for 686e2c56465SPeter Maydell * "CPU interface for core 0", "for core 1", ... 687e2c56465SPeter Maydell * NB that the memory region size of 0x100 applies for the 11MPCore 688e2c56465SPeter Maydell * and also cores following the GIC v1 spec (ie A9). 689e2c56465SPeter Maydell * GIC v2 defines a larger memory region (0x1000) so this will need 690e2c56465SPeter Maydell * to be extended when we implement A15. 691e2c56465SPeter Maydell */ 6921437c94bSPaolo Bonzini memory_region_init_io(&s->cpuiomem[0], OBJECT(s), &gic_thiscpu_ops, s, 693e2c56465SPeter Maydell "gic_cpu", 0x100); 694e2c56465SPeter Maydell for (i = 0; i < NUM_CPU(s); i++) { 695e2c56465SPeter Maydell s->backref[i] = s; 6961437c94bSPaolo Bonzini memory_region_init_io(&s->cpuiomem[i+1], OBJECT(s), &gic_cpu_ops, 6971437c94bSPaolo Bonzini &s->backref[i], "gic_cpu", 0x100); 698e2c56465SPeter Maydell } 699496dbcd1SPeter Maydell /* Distributor */ 70053111180SPeter Maydell sysbus_init_mmio(sbd, &s->iomem); 701496dbcd1SPeter Maydell /* cpu interfaces (one for "current cpu" plus one per cpu) */ 702496dbcd1SPeter Maydell for (i = 0; i <= NUM_CPU(s); i++) { 70353111180SPeter Maydell sysbus_init_mmio(sbd, &s->cpuiomem[i]); 704496dbcd1SPeter Maydell } 705496dbcd1SPeter Maydell } 706496dbcd1SPeter Maydell 707496dbcd1SPeter Maydell static void arm_gic_class_init(ObjectClass *klass, void *data) 708496dbcd1SPeter Maydell { 709496dbcd1SPeter Maydell DeviceClass *dc = DEVICE_CLASS(klass); 7101e8cae4dSPeter Maydell ARMGICClass *agc = ARM_GIC_CLASS(klass); 71153111180SPeter Maydell 712496dbcd1SPeter Maydell dc->no_user = 1; 71353111180SPeter Maydell agc->parent_realize = dc->realize; 71453111180SPeter Maydell dc->realize = arm_gic_realize; 715496dbcd1SPeter Maydell } 716496dbcd1SPeter Maydell 7178c43a6f0SAndreas Färber static const TypeInfo arm_gic_info = { 7181e8cae4dSPeter Maydell .name = TYPE_ARM_GIC, 7191e8cae4dSPeter Maydell .parent = TYPE_ARM_GIC_COMMON, 720fae15286SPeter Maydell .instance_size = sizeof(GICState), 721496dbcd1SPeter Maydell .class_init = arm_gic_class_init, 722998a74bcSPeter Maydell .class_size = sizeof(ARMGICClass), 723496dbcd1SPeter Maydell }; 724496dbcd1SPeter Maydell 725496dbcd1SPeter Maydell static void arm_gic_register_types(void) 726496dbcd1SPeter Maydell { 727496dbcd1SPeter Maydell type_register_static(&arm_gic_info); 728496dbcd1SPeter Maydell } 729496dbcd1SPeter Maydell 730496dbcd1SPeter Maydell type_init(arm_gic_register_types) 731