hw/arm/gic: Kill code duplication

Extracted duplicated initialization code from SW-emulated and KVM GIC
implementations and put into gic_init_irqs_and_mmio()

Signed-off-by: Pavel Fedin <p.fedin@samsung.com>
Message-id: 8ea5b2781ef39cb5989420987fc73c70e377687d.1438758065.git.p.fedin@samsung.com
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Pavel Fedin 2015-08-13 11:26:21 +01:00 committed by Peter Maydell
parent 6d6d2abf2c
commit 7926c210ab
4 changed files with 64 additions and 72 deletions

View File

@ -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, static MemTxResult gic_cpu_read(GICState *s, int cpu, int offset,
uint64_t *data, MemTxAttrs attrs) 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); return gic_cpu_write(s, id, addr, value, attrs);
} }
static const MemoryRegionOps gic_thiscpu_ops = { static const MemoryRegionOps gic_ops[2] = {
.read_with_attrs = gic_thiscpu_read, {
.write_with_attrs = gic_thiscpu_write, .read_with_attrs = gic_dist_read,
.endianness = DEVICE_NATIVE_ENDIAN, .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 = { static const MemoryRegionOps gic_cpu_ops = {
@ -1068,31 +1069,10 @@ static const MemoryRegionOps gic_cpu_ops = {
.endianness = DEVICE_NATIVE_ENDIAN, .endianness = DEVICE_NATIVE_ENDIAN,
}; };
/* This function is used by nvic model */
void gic_init_irqs_and_distributor(GICState *s) void gic_init_irqs_and_distributor(GICState *s)
{ {
SysBusDevice *sbd = SYS_BUS_DEVICE(s); gic_init_irqs_and_mmio(s, gic_set_irq, gic_ops);
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);
} }
static void arm_gic_realize(DeviceState *dev, Error **errp) static void arm_gic_realize(DeviceState *dev, Error **errp)
@ -1110,28 +1090,22 @@ static void arm_gic_realize(DeviceState *dev, Error **errp)
return; 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): /* Extra core-specific regions for the CPU interfaces. This is
* a region for "CPU interface for this core", then a region for * necessary for "franken-GIC" implementations, for example on
* "CPU interface for core 0", "for core 1", ... * Exynos 4.
* NB that the memory region size of 0x100 applies for the 11MPCore * NB that the memory region size of 0x100 applies for the 11MPCore
* and also cores following the GIC v1 spec (ie A9). * and also cores following the GIC v1 spec (ie A9).
* GIC v2 defines a larger memory region (0x1000) so this will need * GIC v2 defines a larger memory region (0x1000) so this will need
* to be extended when we implement A15. * 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++) { for (i = 0; i < NUM_CPU(s); i++) {
s->backref[i] = s; s->backref[i] = s;
memory_region_init_io(&s->cpuiomem[i+1], OBJECT(s), &gic_cpu_ops, memory_region_init_io(&s->cpuiomem[i+1], OBJECT(s), &gic_cpu_ops,
&s->backref[i], "gic_cpu", 0x100); &s->backref[i], "gic_cpu", 0x100);
} sysbus_init_mmio(sbd, &s->cpuiomem[i+1]);
/* 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]);
} }
} }

View File

@ -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) static void arm_gic_common_realize(DeviceState *dev, Error **errp)
{ {
GICState *s = ARM_GIC_COMMON(dev); GICState *s = ARM_GIC_COMMON(dev);

View File

@ -543,7 +543,6 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp)
{ {
int i; int i;
GICState *s = KVM_ARM_GIC(dev); GICState *s = KVM_ARM_GIC(dev);
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
KVMARMGICClass *kgc = KVM_ARM_GIC_GET_CLASS(s); KVMARMGICClass *kgc = KVM_ARM_GIC_GET_CLASS(s);
Error *local_err = NULL; Error *local_err = NULL;
int ret; int ret;
@ -560,32 +559,13 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp)
return; return;
} }
i = s->num_irq - GIC_INTERNAL; gic_init_irqs_and_mmio(s, kvm_arm_gic_set_irq, NULL);
/* 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);
for (i = 0; i < s->num_irq - GIC_INTERNAL; i++) { for (i = 0; i < s->num_irq - GIC_INTERNAL; i++) {
qemu_irq irq = qdev_get_gpio_in(dev, i); qemu_irq irq = qdev_get_gpio_in(dev, i);
kvm_irqchip_set_qemuirq_gsi(kvm_state, irq, 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 */ /* Try to create the device via the device control API */
s->dev_fd = -1; s->dev_fd = -1;
ret = kvm_create_device(kvm_state, KVM_DEV_TYPE_ARM_VGIC_V2, false); 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 */ /* 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_register_device(&s->iomem,
(KVM_ARM_DEVICE_VGIC_V2 << KVM_ARM_DEVICE_ID_SHIFT) (KVM_ARM_DEVICE_VGIC_V2 << KVM_ARM_DEVICE_ID_SHIFT)
| KVM_VGIC_V2_ADDR_TYPE_DIST, | 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 * provide the "interface for core #N" memory regions, because
* cores with a VGIC don't have those. * 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_register_device(&s->cpuiomem[0],
(KVM_ARM_DEVICE_VGIC_V2 << KVM_ARM_DEVICE_ID_SHIFT) (KVM_ARM_DEVICE_VGIC_V2 << KVM_ARM_DEVICE_ID_SHIFT)
| KVM_VGIC_V2_ADDR_TYPE_CPU, | KVM_VGIC_V2_ADDR_TYPE_CPU,

View File

@ -138,4 +138,7 @@ typedef struct ARMGICCommonClass {
void (*post_load)(GICState *s); void (*post_load)(GICState *s);
} ARMGICCommonClass; } ARMGICCommonClass;
void gic_init_irqs_and_mmio(GICState *s, qemu_irq_handler handler,
const MemoryRegionOps *ops);
#endif #endif