diff options
Diffstat (limited to 'hw/intc')
| -rw-r--r-- | hw/intc/arm_gic.c | 64 | ||||
| -rw-r--r-- | hw/intc/arm_gic_common.c | 41 | ||||
| -rw-r--r-- | hw/intc/arm_gic_kvm.c | 28 | ||||
| -rw-r--r-- | hw/intc/imx_avic.c | 56 |
4 files changed, 71 insertions, 118 deletions
diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c index 454bfd7df5..a8c5d19448 100644 --- a/hw/intc/arm_gic.c +++ b/hw/intc/arm_gic.c @@ -922,12 +922,6 @@ static MemTxResult gic_dist_write(void *opaque, hwaddr offset, uint64_t data, } } -static const MemoryRegionOps gic_dist_ops = { - .read_with_attrs = gic_dist_read, - .write_with_attrs = gic_dist_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - static MemTxResult gic_cpu_read(GICState *s, int cpu, int offset, uint64_t *data, MemTxAttrs attrs) { @@ -1056,10 +1050,17 @@ static MemTxResult gic_do_cpu_write(void *opaque, hwaddr addr, return gic_cpu_write(s, id, addr, value, attrs); } -static const MemoryRegionOps gic_thiscpu_ops = { - .read_with_attrs = gic_thiscpu_read, - .write_with_attrs = gic_thiscpu_write, - .endianness = DEVICE_NATIVE_ENDIAN, +static const MemoryRegionOps gic_ops[2] = { + { + .read_with_attrs = gic_dist_read, + .write_with_attrs = gic_dist_write, + .endianness = DEVICE_NATIVE_ENDIAN, + }, + { + .read_with_attrs = gic_thiscpu_read, + .write_with_attrs = gic_thiscpu_write, + .endianness = DEVICE_NATIVE_ENDIAN, + } }; static const MemoryRegionOps gic_cpu_ops = { @@ -1068,31 +1069,10 @@ static const MemoryRegionOps gic_cpu_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; +/* This function is used by nvic model */ void gic_init_irqs_and_distributor(GICState *s) { - SysBusDevice *sbd = SYS_BUS_DEVICE(s); - int i; - - i = s->num_irq - GIC_INTERNAL; - /* For the GIC, also expose incoming GPIO lines for PPIs for each CPU. - * GPIO array layout is thus: - * [0..N-1] SPIs - * [N..N+31] PPIs for CPU 0 - * [N+32..N+63] PPIs for CPU 1 - * ... - */ - if (s->revision != REV_NVIC) { - i += (GIC_INTERNAL * s->num_cpu); - } - qdev_init_gpio_in(DEVICE(s), gic_set_irq, i); - for (i = 0; i < NUM_CPU(s); i++) { - sysbus_init_irq(sbd, &s->parent_irq[i]); - } - for (i = 0; i < NUM_CPU(s); i++) { - sysbus_init_irq(sbd, &s->parent_fiq[i]); - } - memory_region_init_io(&s->iomem, OBJECT(s), &gic_dist_ops, s, - "gic_dist", 0x1000); + gic_init_irqs_and_mmio(s, gic_set_irq, gic_ops); } static void arm_gic_realize(DeviceState *dev, Error **errp) @@ -1110,28 +1090,22 @@ static void arm_gic_realize(DeviceState *dev, Error **errp) return; } - gic_init_irqs_and_distributor(s); + /* This creates distributor and main CPU interface (s->cpuiomem[0]) */ + gic_init_irqs_and_mmio(s, gic_set_irq, gic_ops); - /* Memory regions for the CPU interfaces (NVIC doesn't have these): - * a region for "CPU interface for this core", then a region for - * "CPU interface for core 0", "for core 1", ... + /* Extra core-specific regions for the CPU interfaces. This is + * necessary for "franken-GIC" implementations, for example on + * Exynos 4. * NB that the memory region size of 0x100 applies for the 11MPCore * and also cores following the GIC v1 spec (ie A9). * GIC v2 defines a larger memory region (0x1000) so this will need * to be extended when we implement A15. */ - memory_region_init_io(&s->cpuiomem[0], OBJECT(s), &gic_thiscpu_ops, s, - "gic_cpu", 0x100); for (i = 0; i < NUM_CPU(s); i++) { s->backref[i] = s; memory_region_init_io(&s->cpuiomem[i+1], OBJECT(s), &gic_cpu_ops, &s->backref[i], "gic_cpu", 0x100); - } - /* Distributor */ - sysbus_init_mmio(sbd, &s->iomem); - /* cpu interfaces (one for "current cpu" plus one per cpu) */ - for (i = 0; i <= NUM_CPU(s); i++) { - sysbus_init_mmio(sbd, &s->cpuiomem[i]); + sysbus_init_mmio(sbd, &s->cpuiomem[i+1]); } } diff --git a/hw/intc/arm_gic_common.c b/hw/intc/arm_gic_common.c index a64d0714ea..fe64b51cff 100644 --- a/hw/intc/arm_gic_common.c +++ b/hw/intc/arm_gic_common.c @@ -84,6 +84,47 @@ static const VMStateDescription vmstate_gic = { } }; +void gic_init_irqs_and_mmio(GICState *s, qemu_irq_handler handler, + const MemoryRegionOps *ops) +{ + SysBusDevice *sbd = SYS_BUS_DEVICE(s); + int i = s->num_irq - GIC_INTERNAL; + + /* For the GIC, also expose incoming GPIO lines for PPIs for each CPU. + * GPIO array layout is thus: + * [0..N-1] SPIs + * [N..N+31] PPIs for CPU 0 + * [N+32..N+63] PPIs for CPU 1 + * ... + */ + if (s->revision != REV_NVIC) { + i += (GIC_INTERNAL * s->num_cpu); + } + qdev_init_gpio_in(DEVICE(s), handler, i); + + for (i = 0; i < s->num_cpu; i++) { + sysbus_init_irq(sbd, &s->parent_irq[i]); + } + for (i = 0; i < s->num_cpu; i++) { + sysbus_init_irq(sbd, &s->parent_fiq[i]); + } + + /* Distributor */ + memory_region_init_io(&s->iomem, OBJECT(s), ops, s, "gic_dist", 0x1000); + sysbus_init_mmio(sbd, &s->iomem); + + if (s->revision != REV_NVIC) { + /* This is the main CPU interface "for this core". It is always + * present because it is required by both software emulation and KVM. + * NVIC is not handled here because its CPU interface is different, + * neither it can use KVM. + */ + memory_region_init_io(&s->cpuiomem[0], OBJECT(s), ops ? &ops[1] : NULL, + s, "gic_cpu", s->revision == 2 ? 0x1000 : 0x100); + sysbus_init_mmio(sbd, &s->cpuiomem[0]); + } +} + static void arm_gic_common_realize(DeviceState *dev, Error **errp) { GICState *s = ARM_GIC_COMMON(dev); diff --git a/hw/intc/arm_gic_kvm.c b/hw/intc/arm_gic_kvm.c index f56bff1afb..e5d0f67186 100644 --- a/hw/intc/arm_gic_kvm.c +++ b/hw/intc/arm_gic_kvm.c @@ -543,7 +543,6 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp) { int i; GICState *s = KVM_ARM_GIC(dev); - SysBusDevice *sbd = SYS_BUS_DEVICE(dev); KVMARMGICClass *kgc = KVM_ARM_GIC_GET_CLASS(s); Error *local_err = NULL; int ret; @@ -560,32 +559,13 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp) return; } - i = s->num_irq - GIC_INTERNAL; - /* For the GIC, also expose incoming GPIO lines for PPIs for each CPU. - * GPIO array layout is thus: - * [0..N-1] SPIs - * [N..N+31] PPIs for CPU 0 - * [N+32..N+63] PPIs for CPU 1 - * ... - */ - i += (GIC_INTERNAL * s->num_cpu); - qdev_init_gpio_in(dev, kvm_arm_gic_set_irq, i); + gic_init_irqs_and_mmio(s, kvm_arm_gic_set_irq, NULL); for (i = 0; i < s->num_irq - GIC_INTERNAL; i++) { qemu_irq irq = qdev_get_gpio_in(dev, i); kvm_irqchip_set_qemuirq_gsi(kvm_state, irq, i); } - /* We never use our outbound IRQ/FIQ lines but provide them so that - * we maintain the same interface as the non-KVM GIC. - */ - for (i = 0; i < s->num_cpu; i++) { - sysbus_init_irq(sbd, &s->parent_irq[i]); - } - for (i = 0; i < s->num_cpu; i++) { - sysbus_init_irq(sbd, &s->parent_fiq[i]); - } - /* Try to create the device via the device control API */ s->dev_fd = -1; ret = kvm_create_device(kvm_state, KVM_DEV_TYPE_ARM_VGIC_V2, false); @@ -609,9 +589,6 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp) } /* Distributor */ - memory_region_init_reservation(&s->iomem, OBJECT(s), - "kvm-gic_dist", 0x1000); - sysbus_init_mmio(sbd, &s->iomem); kvm_arm_register_device(&s->iomem, (KVM_ARM_DEVICE_VGIC_V2 << KVM_ARM_DEVICE_ID_SHIFT) | KVM_VGIC_V2_ADDR_TYPE_DIST, @@ -622,9 +599,6 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp) * provide the "interface for core #N" memory regions, because * cores with a VGIC don't have those. */ - memory_region_init_reservation(&s->cpuiomem[0], OBJECT(s), - "kvm-gic_cpu", 0x1000); - sysbus_init_mmio(sbd, &s->cpuiomem[0]); kvm_arm_register_device(&s->cpuiomem[0], (KVM_ARM_DEVICE_VGIC_V2 << KVM_ARM_DEVICE_ID_SHIFT) | KVM_VGIC_V2_ADDR_TYPE_CPU, diff --git a/hw/intc/imx_avic.c b/hw/intc/imx_avic.c index e48f66c8fa..96c376b6af 100644 --- a/hw/intc/imx_avic.c +++ b/hw/intc/imx_avic.c @@ -7,6 +7,7 @@ * Copyright (c) 2008 OKL * Copyright (c) 2011 NICTA Pty Ltd * Originally written by Hans Jiang + * Updated by Jean-Christophe Dubois <jcd@tribudubois.net> * * This code is licensed under the GPL version 2 or later. See * the COPYING file in the top-level directory. @@ -14,16 +15,14 @@ * TODO: implement vectors. */ -#include "hw/hw.h" -#include "hw/sysbus.h" -#include "qemu/host-utils.h" +#include "hw/intc/imx_avic.h" #define DEBUG_INT 1 #undef DEBUG_INT /* comment out for debugging */ #ifdef DEBUG_INT #define DPRINTF(fmt, args...) \ -do { printf("imx_avic: " fmt , ##args); } while (0) +do { printf("%s: " fmt , TYPE_IMX_AVIC, ##args); } while (0) #else #define DPRINTF(fmt, args...) do {} while (0) #endif @@ -35,46 +34,13 @@ do { printf("imx_avic: " fmt , ##args); } while (0) #define DEBUG_IMPLEMENTATION 1 #if DEBUG_IMPLEMENTATION # define IPRINTF(fmt, args...) \ - do { fprintf(stderr, "imx_avic: " fmt, ##args); } while (0) + do { fprintf(stderr, "%s: " fmt, TYPE_IMX_AVIC, ##args); } while (0) #else # define IPRINTF(fmt, args...) do {} while (0) #endif -#define IMX_AVIC_NUM_IRQS 64 - -/* Interrupt Control Bits */ -#define ABFLAG (1<<25) -#define ABFEN (1<<24) -#define NIDIS (1<<22) /* Normal Interrupt disable */ -#define FIDIS (1<<21) /* Fast interrupt disable */ -#define NIAD (1<<20) /* Normal Interrupt Arbiter Rise ARM level */ -#define FIAD (1<<19) /* Fast Interrupt Arbiter Rise ARM level */ -#define NM (1<<18) /* Normal interrupt mode */ - - -#define PRIO_PER_WORD (sizeof(uint32_t) * 8 / 4) -#define PRIO_WORDS (IMX_AVIC_NUM_IRQS/PRIO_PER_WORD) - -#define TYPE_IMX_AVIC "imx_avic" -#define IMX_AVIC(obj) \ - OBJECT_CHECK(IMXAVICState, (obj), TYPE_IMX_AVIC) - -typedef struct IMXAVICState { - SysBusDevice parent_obj; - - MemoryRegion iomem; - uint64_t pending; - uint64_t enabled; - uint64_t is_fiq; - uint32_t intcntl; - uint32_t intmask; - qemu_irq irq; - qemu_irq fiq; - uint32_t prio[PRIO_WORDS]; /* Priorities are 4-bits each */ -} IMXAVICState; - static const VMStateDescription vmstate_imx_avic = { - .name = "imx-avic", + .name = TYPE_IMX_AVIC, .version_id = 1, .minimum_version_id = 1, .fields = (VMStateField[]) { @@ -88,8 +54,6 @@ static const VMStateDescription vmstate_imx_avic = { }, }; - - static inline int imx_avic_prio(IMXAVICState *s, int irq) { uint32_t word = irq / PRIO_PER_WORD; @@ -249,7 +213,7 @@ static uint64_t imx_avic_read(void *opaque, return 0x4; default: - IPRINTF("imx_avic_read: Bad offset 0x%x\n", (int)offset); + IPRINTF("%s: Bad offset 0x%x\n", __func__, (int)offset); return 0; } } @@ -261,12 +225,12 @@ static void imx_avic_write(void *opaque, hwaddr offset, /* Vector Registers not yet supported */ if (offset >= 0x100 && offset <= 0x2fc) { - IPRINTF("imx_avic_write to vector register %d ignored\n", + IPRINTF("%s to vector register %d ignored\n", __func__, (unsigned int)((offset - 0x100) >> 2)); return; } - DPRINTF("imx_avic_write(0x%x) = %x\n", + DPRINTF("%s(0x%x) = %x\n", __func__, (unsigned int)offset>>2, (unsigned int)val); switch (offset >> 2) { case 0: /* Interrupt Control Register, INTCNTL */ @@ -341,7 +305,7 @@ static void imx_avic_write(void *opaque, hwaddr offset, return; default: - IPRINTF("imx_avic_write: Bad offset %x\n", (int)offset); + IPRINTF("%s: Bad offset %x\n", __func__, (int)offset); } imx_avic_update(s); } @@ -370,7 +334,7 @@ static int imx_avic_init(SysBusDevice *sbd) IMXAVICState *s = IMX_AVIC(dev); memory_region_init_io(&s->iomem, OBJECT(s), &imx_avic_ops, s, - "imx_avic", 0x1000); + TYPE_IMX_AVIC, 0x1000); sysbus_init_mmio(sbd, &s->iomem); qdev_init_gpio_in(dev, imx_avic_set_irq, IMX_AVIC_NUM_IRQS); |