diff options
Diffstat (limited to 'hw/arm_gic.c')
-rw-r--r-- | hw/arm_gic.c | 241 |
1 files changed, 14 insertions, 227 deletions
diff --git a/hw/arm_gic.c b/hw/arm_gic.c index ad5ab3c1ba..ec22322930 100644 --- a/hw/arm_gic.c +++ b/hw/arm_gic.c @@ -19,13 +19,7 @@ */ #include "sysbus.h" - -/* Maximum number of possible interrupts, determined by the GIC architecture */ -#define GIC_MAXIRQ 1020 -/* First 32 are private to each CPU (SGIs and PPIs). */ -#define GIC_INTERNAL 32 -/* Maximum number of possible CPU interfaces, determined by GIC architecture */ -#define NCPU 8 +#include "arm_gic_internal.h" //#define DEBUG_GIC @@ -36,88 +30,12 @@ do { printf("arm_gic: " fmt , ## __VA_ARGS__); } while (0) #define DPRINTF(fmt, ...) do {} while(0) #endif -/* The NVIC has 16 internal vectors. However these are not exposed - through the normal GIC interface. */ -#define GIC_BASE_IRQ ((s->revision == REV_NVIC) ? 32 : 0) - static const uint8_t gic_id[] = { 0x90, 0x13, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 }; -#define FROM_SYSBUSGIC(type, dev) \ - DO_UPCAST(type, gic, FROM_SYSBUS(gic_state, dev)) - -typedef struct gic_irq_state -{ - /* The enable bits are only banked for per-cpu interrupts. */ - unsigned enabled:NCPU; - unsigned pending:NCPU; - unsigned active:NCPU; - unsigned level:NCPU; - unsigned model:1; /* 0 = N:N, 1 = 1:N */ - unsigned trigger:1; /* nonzero = edge triggered. */ -} gic_irq_state; - -#define ALL_CPU_MASK ((unsigned)(((1 << NCPU) - 1))) #define NUM_CPU(s) ((s)->num_cpu) -#define GIC_SET_ENABLED(irq, cm) s->irq_state[irq].enabled |= (cm) -#define GIC_CLEAR_ENABLED(irq, cm) s->irq_state[irq].enabled &= ~(cm) -#define GIC_TEST_ENABLED(irq, cm) ((s->irq_state[irq].enabled & (cm)) != 0) -#define GIC_SET_PENDING(irq, cm) s->irq_state[irq].pending |= (cm) -#define GIC_CLEAR_PENDING(irq, cm) s->irq_state[irq].pending &= ~(cm) -#define GIC_TEST_PENDING(irq, cm) ((s->irq_state[irq].pending & (cm)) != 0) -#define GIC_SET_ACTIVE(irq, cm) s->irq_state[irq].active |= (cm) -#define GIC_CLEAR_ACTIVE(irq, cm) s->irq_state[irq].active &= ~(cm) -#define GIC_TEST_ACTIVE(irq, cm) ((s->irq_state[irq].active & (cm)) != 0) -#define GIC_SET_MODEL(irq) s->irq_state[irq].model = 1 -#define GIC_CLEAR_MODEL(irq) s->irq_state[irq].model = 0 -#define GIC_TEST_MODEL(irq) s->irq_state[irq].model -#define GIC_SET_LEVEL(irq, cm) s->irq_state[irq].level = (cm) -#define GIC_CLEAR_LEVEL(irq, cm) s->irq_state[irq].level &= ~(cm) -#define GIC_TEST_LEVEL(irq, cm) ((s->irq_state[irq].level & (cm)) != 0) -#define GIC_SET_TRIGGER(irq) s->irq_state[irq].trigger = 1 -#define GIC_CLEAR_TRIGGER(irq) s->irq_state[irq].trigger = 0 -#define GIC_TEST_TRIGGER(irq) s->irq_state[irq].trigger -#define GIC_GET_PRIORITY(irq, cpu) (((irq) < GIC_INTERNAL) ? \ - s->priority1[irq][cpu] : \ - s->priority2[(irq) - GIC_INTERNAL]) -#define GIC_TARGET(irq) s->irq_target[irq] - -typedef struct gic_state -{ - SysBusDevice busdev; - qemu_irq parent_irq[NCPU]; - int enabled; - int cpu_enabled[NCPU]; - - gic_irq_state irq_state[GIC_MAXIRQ]; - int irq_target[GIC_MAXIRQ]; - int priority1[GIC_INTERNAL][NCPU]; - int priority2[GIC_MAXIRQ - GIC_INTERNAL]; - int last_active[GIC_MAXIRQ][NCPU]; - - int priority_mask[NCPU]; - int running_irq[NCPU]; - int running_priority[NCPU]; - int current_pending[NCPU]; - - uint32_t num_cpu; - - MemoryRegion iomem; /* Distributor */ - /* This is just so we can have an opaque pointer which identifies - * both this GIC and which CPU interface we should be accessing. - */ - struct gic_state *backref[NCPU]; - MemoryRegion cpuiomem[NCPU+1]; /* CPU interfaces */ - uint32_t num_irq; - uint32_t revision; -} gic_state; - -/* The special cases for the revision property: */ -#define REV_11MPCORE 0 -#define REV_NVIC 0xffffffff - static inline int gic_get_current_cpu(gic_state *s) { if (s->num_cpu > 1) { @@ -128,7 +46,7 @@ static inline int gic_get_current_cpu(gic_state *s) /* TODO: Many places that call this routine could be optimized. */ /* Update interrupt status after enabled or pending bits have been changed. */ -static void gic_update(gic_state *s) +void gic_update(gic_state *s) { int best_irq; int best_prio; @@ -166,8 +84,7 @@ static void gic_update(gic_state *s) } } -#ifdef NVIC -static void gic_set_pending_private(gic_state *s, int cpu, int irq) +void gic_set_pending_private(gic_state *s, int cpu, int irq) { int cm = 1 << cpu; @@ -178,7 +95,6 @@ static void gic_set_pending_private(gic_state *s, int cpu, int irq) GIC_SET_PENDING(irq, cm); gic_update(s); } -#endif /* Process a change in an external IRQ input. */ static void gic_set_irq(void *opaque, int irq, int level) @@ -232,7 +148,7 @@ static void gic_set_running_irq(gic_state *s, int cpu, int irq) gic_update(s); } -static uint32_t gic_acknowledge_irq(gic_state *s, int cpu) +uint32_t gic_acknowledge_irq(gic_state *s, int cpu) { int new_irq; int cm = 1 << cpu; @@ -251,7 +167,7 @@ static uint32_t gic_acknowledge_irq(gic_state *s, int cpu) return new_irq; } -static void gic_complete_irq(gic_state * s, int cpu, int irq) +void gic_complete_irq(gic_state *s, int cpu, int irq) { int update = 0; int cm = 1 << cpu; @@ -623,7 +539,6 @@ static const MemoryRegionOps gic_dist_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -#ifndef NVIC static uint32_t gic_cpu_read(gic_state *s, int cpu, int offset) { switch (offset) { @@ -715,124 +630,10 @@ static const MemoryRegionOps gic_cpu_ops = { .write = gic_do_cpu_write, .endianness = DEVICE_NATIVE_ENDIAN, }; -#endif -static void gic_reset(DeviceState *dev) +void gic_init_irqs_and_distributor(gic_state *s, int num_irq) { - gic_state *s = FROM_SYSBUS(gic_state, sysbus_from_qdev(dev)); - int i; - memset(s->irq_state, 0, GIC_MAXIRQ * sizeof(gic_irq_state)); - for (i = 0 ; i < NUM_CPU(s); i++) { - s->priority_mask[i] = 0xf0; - s->current_pending[i] = 1023; - s->running_irq[i] = 1023; - s->running_priority[i] = 0x100; - s->cpu_enabled[i] = 0; - } - for (i = 0; i < 16; i++) { - GIC_SET_ENABLED(i, ALL_CPU_MASK); - GIC_SET_TRIGGER(i); - } - if (s->num_cpu == 1) { - /* For uniprocessor GICs all interrupts always target the sole CPU */ - for (i = 0; i < GIC_MAXIRQ; i++) { - s->irq_target[i] = 1; - } - } - s->enabled = 0; -} - -static void gic_save(QEMUFile *f, void *opaque) -{ - gic_state *s = (gic_state *)opaque; - int i; - int j; - - qemu_put_be32(f, s->enabled); - for (i = 0; i < NUM_CPU(s); i++) { - qemu_put_be32(f, s->cpu_enabled[i]); - for (j = 0; j < GIC_INTERNAL; j++) - qemu_put_be32(f, s->priority1[j][i]); - for (j = 0; j < s->num_irq; j++) - qemu_put_be32(f, s->last_active[j][i]); - qemu_put_be32(f, s->priority_mask[i]); - qemu_put_be32(f, s->running_irq[i]); - qemu_put_be32(f, s->running_priority[i]); - qemu_put_be32(f, s->current_pending[i]); - } - for (i = 0; i < s->num_irq - GIC_INTERNAL; i++) { - qemu_put_be32(f, s->priority2[i]); - } - for (i = 0; i < s->num_irq; i++) { - qemu_put_be32(f, s->irq_target[i]); - qemu_put_byte(f, s->irq_state[i].enabled); - qemu_put_byte(f, s->irq_state[i].pending); - qemu_put_byte(f, s->irq_state[i].active); - qemu_put_byte(f, s->irq_state[i].level); - qemu_put_byte(f, s->irq_state[i].model); - qemu_put_byte(f, s->irq_state[i].trigger); - } -} - -static int gic_load(QEMUFile *f, void *opaque, int version_id) -{ - gic_state *s = (gic_state *)opaque; int i; - int j; - - if (version_id != 3) { - return -EINVAL; - } - - s->enabled = qemu_get_be32(f); - for (i = 0; i < NUM_CPU(s); i++) { - s->cpu_enabled[i] = qemu_get_be32(f); - for (j = 0; j < GIC_INTERNAL; j++) - s->priority1[j][i] = qemu_get_be32(f); - for (j = 0; j < s->num_irq; j++) - s->last_active[j][i] = qemu_get_be32(f); - s->priority_mask[i] = qemu_get_be32(f); - s->running_irq[i] = qemu_get_be32(f); - s->running_priority[i] = qemu_get_be32(f); - s->current_pending[i] = qemu_get_be32(f); - } - for (i = 0; i < s->num_irq - GIC_INTERNAL; i++) { - s->priority2[i] = qemu_get_be32(f); - } - for (i = 0; i < s->num_irq; i++) { - s->irq_target[i] = qemu_get_be32(f); - s->irq_state[i].enabled = qemu_get_byte(f); - s->irq_state[i].pending = qemu_get_byte(f); - s->irq_state[i].active = qemu_get_byte(f); - s->irq_state[i].level = qemu_get_byte(f); - s->irq_state[i].model = qemu_get_byte(f); - s->irq_state[i].trigger = qemu_get_byte(f); - } - - return 0; -} - -static void gic_init_irqs_and_distributor(gic_state *s, int num_irq) -{ - int i; - - if (s->num_cpu > NCPU) { - hw_error("requested %u CPUs exceeds GIC maximum %d\n", - s->num_cpu, NCPU); - } - s->num_irq = num_irq + GIC_BASE_IRQ; - if (s->num_irq > GIC_MAXIRQ) { - hw_error("requested %u interrupt lines exceeds GIC maximum %d\n", - num_irq, GIC_MAXIRQ); - } - /* ITLinesNumber is represented as (N / 32) - 1 (see - * gic_dist_readb) so this is an implementation imposed - * restriction, not an architectural one: - */ - if (s->num_irq < 32 || (s->num_irq % 32)) { - hw_error("%d interrupt lines unsupported: not divisible by 32\n", - num_irq); - } i = s->num_irq - GIC_INTERNAL; /* For the GIC, also expose incoming GPIO lines for PPIs for each CPU. @@ -850,17 +651,17 @@ static void gic_init_irqs_and_distributor(gic_state *s, int num_irq) sysbus_init_irq(&s->busdev, &s->parent_irq[i]); } memory_region_init_io(&s->iomem, &gic_dist_ops, s, "gic_dist", 0x1000); - - register_savevm(NULL, "arm_gic", -1, 3, gic_save, gic_load, s); } -#ifndef NVIC - static int arm_gic_init(SysBusDevice *dev) { /* Device instance init function for the GIC sysbus device */ int i; gic_state *s = FROM_SYSBUS(gic_state, dev); + ARMGICClass *agc = ARM_GIC_GET_CLASS(s); + + agc->parent_init(dev); + gic_init_irqs_and_distributor(s, s->num_irq); /* Memory regions for the CPU interfaces (NVIC doesn't have these): @@ -878,7 +679,6 @@ static int arm_gic_init(SysBusDevice *dev) memory_region_init_io(&s->cpuiomem[i+1], &gic_cpu_ops, &s->backref[i], "gic_cpu", 0x100); } - /* Distributor */ sysbus_init_mmio(dev, &s->iomem); /* cpu interfaces (one for "current cpu" plus one per cpu) */ @@ -888,30 +688,19 @@ static int arm_gic_init(SysBusDevice *dev) return 0; } -static Property arm_gic_properties[] = { - DEFINE_PROP_UINT32("num-cpu", gic_state, num_cpu, 1), - DEFINE_PROP_UINT32("num-irq", gic_state, num_irq, 32), - /* Revision can be 1 or 2 for GIC architecture specification - * versions 1 or 2, or 0 to indicate the legacy 11MPCore GIC. - * (Internally, 0xffffffff also indicates "not a GIC but an NVIC".) - */ - DEFINE_PROP_UINT32("revision", gic_state, revision, 1), - DEFINE_PROP_END_OF_LIST(), -}; - static void arm_gic_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass); + ARMGICClass *agc = ARM_GIC_CLASS(klass); + agc->parent_init = sbc->init; sbc->init = arm_gic_init; - dc->props = arm_gic_properties; - dc->reset = gic_reset; dc->no_user = 1; } static TypeInfo arm_gic_info = { - .name = "arm_gic", - .parent = TYPE_SYS_BUS_DEVICE, + .name = TYPE_ARM_GIC, + .parent = TYPE_ARM_GIC_COMMON, .instance_size = sizeof(gic_state), .class_init = arm_gic_class_init, }; @@ -922,5 +711,3 @@ static void arm_gic_register_types(void) } type_init(arm_gic_register_types) - -#endif |