mirror of https://github.com/xemu-project/xemu.git
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:
parent
6d6d2abf2c
commit
7926c210ab
|
@ -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]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue