qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [RFC PATCH v1 8/8] arm: axxmpcore: Add CPUs to MPCore


From: Peter Crosthwaite
Subject: [Qemu-devel] [RFC PATCH v1 8/8] arm: axxmpcore: Add CPUs to MPCore
Date: Sun, 14 Jun 2015 15:37:29 -0700

Add the ARM a9/a15 Cortex CPUs to their respective MPCore containers.
Update all users or MPCore to not instantiate CPUs on the machine
level.

A9 MPCore needs to be extended with the external interrupt controller
capability (which ors a set of pins with the GIC CPU IRQs). This is
needed by Exynos, which uses the current MPCore/CPU split to manually
implement an extra interrupt controller.

Change both a15 and a9 at once to the interface consistent for the
Vexpress and Highbank boards.

This defeatures cpu_model override of some of the existing ARM boards.
This is ok, as this is invalid for all of these platforms. A board
including an A9 or A15 MPCore cannot validly have its CPU type
overridden.

Promote property setters of some of the CPU properties to &error abort.
With no CPU model flexibility, these shouldn't fail anymore for the way
they are used by the fixed machine models.

As part of the change, A9MPCore now supports the oring in of external
interrupt controller natively. This obsoletes the Exynos specific IRQ
gate logic.

Signed-off-by: Peter Crosthwaite <address@hidden>
---
Sorry about the big patch. I can't see a way to split this without
having to rewrite/delete added code.

 hw/arm/exynos4210.c         |  72 +++++++-----------------------
 hw/arm/highbank.c           |  65 +++++----------------------
 hw/arm/realview.c           |  54 +++++++++++++----------
 hw/arm/vexpress.c           |  71 +++++++-----------------------
 hw/arm/xilinx_zynq.c        |  65 ++++++++++-----------------
 hw/cpu/a15mpcore.c          |  66 ++++++++++++++++++++++++----
 hw/cpu/a9mpcore.c           |  97 +++++++++++++++++++++++++++++++++++++---
 hw/intc/exynos4210_gic.c    | 105 --------------------------------------------
 include/hw/arm/exynos4210.h |   2 -
 include/hw/cpu/a15mpcore.h  |   2 +
 include/hw/cpu/a9mpcore.h   |   6 +++
 11 files changed, 253 insertions(+), 352 deletions(-)

diff --git a/hw/arm/exynos4210.c b/hw/arm/exynos4210.c
index c55fab8..1c6e061 100644
--- a/hw/arm/exynos4210.c
+++ b/hw/arm/exynos4210.c
@@ -137,73 +137,34 @@ void exynos4210_write_secondary(ARMCPU *cpu,
 Exynos4210State *exynos4210_init(MemoryRegion *system_mem,
         unsigned long ram_size)
 {
-    int i, n;
+    int n;
     Exynos4210State *s = g_new(Exynos4210State, 1);
-    qemu_irq gate_irq[EXYNOS4210_NCPUS][EXYNOS4210_IRQ_GATE_NINPUTS];
     unsigned long mem_size;
-    DeviceState *dev;
+    DeviceState *dev, *mpcore;
     SysBusDevice *busdev;
     ObjectClass *cpu_oc;
 
     cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, "cortex-a9");
     assert(cpu_oc);
 
-    for (n = 0; n < EXYNOS4210_NCPUS; n++) {
-        Object *cpuobj = object_new(object_class_get_name(cpu_oc));
-        Error *err = NULL;
-
-        /* By default A9 CPUs have EL3 enabled.  This board does not currently
-         * support EL3 so the CPU EL3 property is disabled before realization.
-         */
-        if (object_property_find(cpuobj, "has_el3", NULL)) {
-            object_property_set_bool(cpuobj, false, "has_el3", &err);
-            if (err) {
-                error_report_err(err);
-                exit(1);
-            }
-        }
-
-        s->cpu[n] = ARM_CPU(cpuobj);
-        object_property_set_int(cpuobj, EXYNOS4210_SMP_PRIVATE_BASE_ADDR,
-                                "reset-cbar", &error_abort);
-        object_property_set_bool(cpuobj, true, "realized", &err);
-        if (err) {
-            error_report_err(err);
-            exit(1);
-        }
-    }
-
     /*** IRQs ***/
 
     s->irq_table = exynos4210_init_irq(&s->irqs);
 
-    /* IRQ Gate */
-    for (i = 0; i < EXYNOS4210_NCPUS; i++) {
-        dev = qdev_create(NULL, "exynos4210.irq_gate");
-        qdev_prop_set_uint32(dev, "n_in", EXYNOS4210_IRQ_GATE_NINPUTS);
-        qdev_init_nofail(dev);
-        /* Get IRQ Gate input in gate_irq */
-        for (n = 0; n < EXYNOS4210_IRQ_GATE_NINPUTS; n++) {
-            gate_irq[i][n] = qdev_get_gpio_in(dev, n);
-        }
-        busdev = SYS_BUS_DEVICE(dev);
-
-        /* Connect IRQ Gate output to CPU's IRQ line */
-        sysbus_connect_irq(busdev, 0,
-                           qdev_get_gpio_in(DEVICE(s->cpu[i]), ARM_CPU_IRQ));
-    }
-
-    /* Private memory region and Internal GIC */
-    dev = qdev_create(NULL, "a9mpcore_priv");
-    qdev_prop_set_uint32(dev, "num-cpu", EXYNOS4210_NCPUS);
-    qdev_init_nofail(dev);
-    busdev = SYS_BUS_DEVICE(dev);
+    /* MPCore (Contains internal GIC) */
+    mpcore = qdev_create(NULL, "a9mpcore_priv");
+    qdev_prop_set_uint32(mpcore, "num-cpu", EXYNOS4210_NCPUS);
+    /* By default A9 CPUs have EL3 enabled.  This board does not currently
+     * support EL3 so the CPU EL3 property is disabled before realization.
+     */
+    object_property_set_bool(OBJECT(mpcore), false, "has_el3", &error_abort);
+    object_property_set_int(OBJECT(mpcore), EXYNOS4210_SMP_PRIVATE_BASE_ADDR,
+                            "reset-cbar", &error_abort);
+    qdev_init_nofail(mpcore);
+    busdev = SYS_BUS_DEVICE(mpcore);
     sysbus_mmio_map(busdev, 0, EXYNOS4210_SMP_PRIVATE_BASE_ADDR);
-    for (n = 0; n < EXYNOS4210_NCPUS; n++) {
-        sysbus_connect_irq(busdev, n, gate_irq[n][0]);
-    }
     for (n = 0; n < EXYNOS4210_INT_GIC_NIRQ; n++) {
-        s->irqs.int_gic_irq[n] = qdev_get_gpio_in(dev, n);
+        s->irqs.int_gic_irq[n] = qdev_get_gpio_in(mpcore, n);
     }
 
     /* Cache controller */
@@ -216,10 +177,11 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem,
     busdev = SYS_BUS_DEVICE(dev);
     /* Map CPU interface */
     sysbus_mmio_map(busdev, 0, EXYNOS4210_EXT_GIC_CPU_BASE_ADDR);
-    /* Map Distributer interface */
+    /* Map Distributor interface */
     sysbus_mmio_map(busdev, 1, EXYNOS4210_EXT_GIC_DIST_BASE_ADDR);
     for (n = 0; n < EXYNOS4210_NCPUS; n++) {
-        sysbus_connect_irq(busdev, n, gate_irq[n][1]);
+        sysbus_connect_irq(busdev, n,
+                           qdev_get_gpio_in_named(mpcore, "ext-interrupt", n));
     }
     for (n = 0; n < EXYNOS4210_EXT_GIC_NIRQ; n++) {
         s->irqs.ext_gic_irq[n] = qdev_get_gpio_in(dev, n);
diff --git a/hw/arm/highbank.c b/hw/arm/highbank.c
index f8353a7..32deadb 100644
--- a/hw/arm/highbank.c
+++ b/hw/arm/highbank.c
@@ -208,7 +208,6 @@ enum cxmachines {
 static void calxeda_init(MachineState *machine, enum cxmachines machine_id)
 {
     ram_addr_t ram_size = machine->ram_size;
-    const char *cpu_model = machine->cpu_model;
     const char *kernel_filename = machine->kernel_filename;
     const char *kernel_cmdline = machine->kernel_cmdline;
     const char *initrd_filename = machine->initrd_filename;
@@ -216,61 +215,14 @@ static void calxeda_init(MachineState *machine, enum 
cxmachines machine_id)
     SysBusDevice *busdev;
     qemu_irq pic[128];
     int n;
-    qemu_irq cpu_irq[4];
-    qemu_irq cpu_fiq[4];
     MemoryRegion *sysram;
     MemoryRegion *dram;
     MemoryRegion *sysmem;
     char *sysboot_filename;
 
-    if (!cpu_model) {
-        switch (machine_id) {
-        case CALXEDA_HIGHBANK:
-            cpu_model = "cortex-a9";
-            break;
-        case CALXEDA_MIDWAY:
-            cpu_model = "cortex-a15";
-            break;
-        }
-    }
-
-    for (n = 0; n < smp_cpus; n++) {
-        ObjectClass *oc = cpu_class_by_name(TYPE_ARM_CPU, cpu_model);
-        Object *cpuobj;
-        ARMCPU *cpu;
-        Error *err = NULL;
-
-        if (!oc) {
-            error_report("Unable to find CPU definition");
-            exit(1);
-        }
-
-        cpuobj = object_new(object_class_get_name(oc));
-        cpu = ARM_CPU(cpuobj);
-
-        /* By default A9 and A15 CPUs have EL3 enabled.  This board does not
-         * currently support EL3 so the CPU EL3 property is disabled before
-         * realization.
-         */
-        if (object_property_find(cpuobj, "has_el3", NULL)) {
-            object_property_set_bool(cpuobj, false, "has_el3", &err);
-            if (err) {
-                error_report_err(err);
-                exit(1);
-            }
-        }
-
-        if (object_property_find(cpuobj, "reset-cbar", NULL)) {
-            object_property_set_int(cpuobj, MPCORE_PERIPHBASE,
-                                    "reset-cbar", &error_abort);
-        }
-        object_property_set_bool(cpuobj, true, "realized", &err);
-        if (err) {
-            error_report_err(err);
-            exit(1);
-        }
-        cpu_irq[n] = qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ);
-        cpu_fiq[n] = qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_FIQ);
+    if (machine->cpu_model) {
+        error_report("Highbank/Midway does not support CPU model override!\n");
+        exit(1);
     }
 
     sysmem = get_system_memory();
@@ -310,13 +262,16 @@ static void calxeda_init(MachineState *machine, enum 
cxmachines machine_id)
     }
     qdev_prop_set_uint32(dev, "num-cpu", smp_cpus);
     qdev_prop_set_uint32(dev, "num-irq", NIRQ_GIC);
+     /* By default A9 and A15 CPUs have EL3 enabled.  This board does not
+     * currently support EL3 so the CPU EL3 property is disabled before
+     * realization.
+     */
+    object_property_set_bool(OBJECT(dev), false, "has_el3", &error_abort);
+    object_property_set_int(OBJECT(dev), MPCORE_PERIPHBASE, "reset-cbar",
+                            &error_abort);
     qdev_init_nofail(dev);
     busdev = SYS_BUS_DEVICE(dev);
     sysbus_mmio_map(busdev, 0, MPCORE_PERIPHBASE);
-    for (n = 0; n < smp_cpus; n++) {
-        sysbus_connect_irq(busdev, n, cpu_irq[n]);
-        sysbus_connect_irq(busdev, n + smp_cpus, cpu_fiq[n]);
-    }
 
     for (n = 0; n < 128; n++) {
         pic[n] = qdev_get_gpio_in(dev, n);
diff --git a/hw/arm/realview.c b/hw/arm/realview.c
index 251b328..9684b58 100644
--- a/hw/arm/realview.c
+++ b/hw/arm/realview.c
@@ -93,6 +93,7 @@ static void realview_init(MachineState *machine,
     int done_nic = 0;
     qemu_irq cpu_irq[4];
     int is_mpcore = 0;
+    bool mpcore_cpus = false;
     int is_pb = 0;
     uint32_t proc_id = 0;
     uint32_t sys_id;
@@ -112,6 +113,7 @@ static void realview_init(MachineState *machine,
         break;
     case BOARD_PBX_A9:
         is_mpcore = 1;
+        mpcore_cpus = true;
         is_pb = 1;
         periphbase = 0x1f000000;
         break;
@@ -123,7 +125,7 @@ static void realview_init(MachineState *machine,
         exit(1);
     }
 
-    for (n = 0; n < smp_cpus; n++) {
+    for (n = 0; !mpcore_cpus && n < smp_cpus; n++) {
         Object *cpuobj = object_new(object_class_get_name(cpu_oc));
         Error *err = NULL;
 
@@ -137,21 +139,6 @@ static void realview_init(MachineState *machine,
 
         cpu_irq[n] = qdev_get_gpio_in(DEVICE(cpuobj), ARM_CPU_IRQ);
     }
-    cpu = ARM_CPU(first_cpu);
-    env = &cpu->env;
-    if (arm_feature(env, ARM_FEATURE_V7)) {
-        if (is_mpcore) {
-            proc_id = 0x0c000000;
-        } else {
-            proc_id = 0x0e000000;
-        }
-    } else if (arm_feature(env, ARM_FEATURE_V6K)) {
-        proc_id = 0x06000000;
-    } else if (arm_feature(env, ARM_FEATURE_V6)) {
-        proc_id = 0x04000000;
-    } else {
-        proc_id = 0x02000000;
-    }
 
     if (is_pb && ram_size > 0x20000000) {
         /* Core tile RAM.  */
@@ -181,20 +168,16 @@ static void realview_init(MachineState *machine,
         ram_size = low_ram_size;
     }
 
-    sys_id = is_pb ? 0x01780500 : 0xc1400400;
-    sysctl = qdev_create(NULL, "realview_sysctl");
-    qdev_prop_set_uint32(sysctl, "sys_id", sys_id);
-    qdev_prop_set_uint32(sysctl, "proc_id", proc_id);
-    qdev_init_nofail(sysctl);
-    sysbus_mmio_map(SYS_BUS_DEVICE(sysctl), 0, 0x10000000);
-
     if (is_mpcore) {
         dev = qdev_create(NULL, is_pb ? "a9mpcore_priv": "realview_mpcore");
         qdev_prop_set_uint32(dev, "num-cpu", smp_cpus);
+        if (mpcore_cpus) {
+            realview_init_cpu_props(OBJECT(dev), periphbase, is_pb);
+        }
         qdev_init_nofail(dev);
         busdev = SYS_BUS_DEVICE(dev);
         sysbus_mmio_map(busdev, 0, periphbase);
-        for (n = 0; n < smp_cpus; n++) {
+        for (n = 0; !mpcore_cpus && n < smp_cpus; n++) {
             sysbus_connect_irq(busdev, n, cpu_irq[n]);
         }
         sysbus_create_varargs("l2x0", periphbase + 0x2000, NULL);
@@ -209,6 +192,29 @@ static void realview_init(MachineState *machine,
         pic[n] = qdev_get_gpio_in(dev, n);
     }
 
+    cpu = ARM_CPU(first_cpu);
+    env = &cpu->env;
+    if (arm_feature(env, ARM_FEATURE_V7)) {
+        if (is_mpcore) {
+            proc_id = 0x0c000000;
+        } else {
+            proc_id = 0x0e000000;
+        }
+    } else if (arm_feature(env, ARM_FEATURE_V6K)) {
+        proc_id = 0x06000000;
+    } else if (arm_feature(env, ARM_FEATURE_V6)) {
+        proc_id = 0x04000000;
+    } else {
+        proc_id = 0x02000000;
+    }
+
+    sys_id = is_pb ? 0x01780500 : 0xc1400400;
+    sysctl = qdev_create(NULL, "realview_sysctl");
+    qdev_prop_set_uint32(sysctl, "sys_id", sys_id);
+    qdev_prop_set_uint32(sysctl, "proc_id", proc_id);
+    qdev_init_nofail(sysctl);
+    sysbus_mmio_map(SYS_BUS_DEVICE(sysctl), 0, 0x10000000);
+
     pl041 = qdev_create(NULL, "pl041");
     qdev_prop_set_uint32(pl041, "nc_fifo_depth", 512);
     qdev_init_nofail(pl041);
diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c
index da21788..784203f 100644
--- a/hw/arm/vexpress.c
+++ b/hw/arm/vexpress.c
@@ -179,7 +179,6 @@ typedef struct {
 
 typedef void DBoardInitFn(const VexpressMachineState *machine,
                           ram_addr_t ram_size,
-                          const char *cpu_model,
                           qemu_irq *pic);
 
 struct VEDBoardInfo {
@@ -195,45 +194,23 @@ struct VEDBoardInfo {
     DBoardInitFn *init;
 };
 
-static void init_cpus(const char *cpu_model, const char *privdev,
+static void init_cpus(const char *privdev,
                       hwaddr periphbase, qemu_irq *pic, bool secure)
 {
-    ObjectClass *cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, cpu_model);
     DeviceState *dev;
     SysBusDevice *busdev;
     int n;
 
-    if (!cpu_oc) {
-        fprintf(stderr, "Unable to find CPU definition\n");
-        exit(1);
-    }
-
-    /* Create the actual CPUs */
-    for (n = 0; n < smp_cpus; n++) {
-        Object *cpuobj = object_new(object_class_get_name(cpu_oc));
-        Error *err = NULL;
-
-        if (!secure) {
-            object_property_set_bool(cpuobj, false, "has_el3", NULL);
-        }
-
-        if (object_property_find(cpuobj, "reset-cbar", NULL)) {
-            object_property_set_int(cpuobj, periphbase,
-                                    "reset-cbar", &error_abort);
-        }
-        object_property_set_bool(cpuobj, true, "realized", &err);
-        if (err) {
-            error_report_err(err);
-            exit(1);
-        }
-    }
-
-    /* Create the private peripheral devices (including the GIC);
-     * this must happen after the CPUs are created because a15mpcore_priv
-     * wires itself up to the CPU's generic_timer gpio out lines.
-     */
+    /* Create the relevant CPU MPCore */
     dev = qdev_create(NULL, privdev);
     qdev_prop_set_uint32(dev, "num-cpu", smp_cpus);
+    if (!secure) {
+        object_property_set_bool(OBJECT(dev), false, "has_el3", NULL);
+    }
+    if (object_property_find(OBJECT(dev), "reset-cbar", NULL)) {
+        object_property_set_int(OBJECT(dev), periphbase, "reset-cbar",
+                                &error_abort);
+    }
     qdev_init_nofail(dev);
     busdev = SYS_BUS_DEVICE(dev);
     sysbus_mmio_map(busdev, 0, periphbase);
@@ -247,20 +224,10 @@ static void init_cpus(const char *cpu_model, const char 
*privdev,
     for (n = 0; n < 64; n++) {
         pic[n] = qdev_get_gpio_in(dev, n);
     }
-
-    /* Connect the CPUs to the GIC */
-    for (n = 0; n < smp_cpus; n++) {
-        DeviceState *cpudev = DEVICE(qemu_get_cpu(n));
-
-        sysbus_connect_irq(busdev, n, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ));
-        sysbus_connect_irq(busdev, n + smp_cpus,
-                           qdev_get_gpio_in(cpudev, ARM_CPU_FIQ));
-    }
 }
 
 static void a9_daughterboard_init(const VexpressMachineState *vms,
                                   ram_addr_t ram_size,
-                                  const char *cpu_model,
                                   qemu_irq *pic)
 {
     MemoryRegion *sysmem = get_system_memory();
@@ -268,10 +235,6 @@ static void a9_daughterboard_init(const 
VexpressMachineState *vms,
     MemoryRegion *lowram = g_new(MemoryRegion, 1);
     ram_addr_t low_ram_size;
 
-    if (!cpu_model) {
-        cpu_model = "cortex-a9";
-    }
-
     if (ram_size > 0x40000000) {
         /* 1GB is the maximum the address space permits */
         fprintf(stderr, "vexpress-a9: cannot model more than 1GB RAM\n");
@@ -293,7 +256,7 @@ static void a9_daughterboard_init(const 
VexpressMachineState *vms,
     memory_region_add_subregion(sysmem, 0x60000000, ram);
 
     /* 0x1e000000 A9MPCore (SCU) private memory region */
-    init_cpus(cpu_model, "a9mpcore_priv", 0x1e000000, pic, vms->secure);
+    init_cpus("a9mpcore_priv", 0x1e000000, pic, vms->secure);
 
     /* Daughterboard peripherals : 0x10020000 .. 0x20000000 */
 
@@ -349,17 +312,12 @@ static VEDBoardInfo a9_daughterboard = {
 
 static void a15_daughterboard_init(const VexpressMachineState *vms,
                                    ram_addr_t ram_size,
-                                   const char *cpu_model,
                                    qemu_irq *pic)
 {
     MemoryRegion *sysmem = get_system_memory();
     MemoryRegion *ram = g_new(MemoryRegion, 1);
     MemoryRegion *sram = g_new(MemoryRegion, 1);
 
-    if (!cpu_model) {
-        cpu_model = "cortex-a15";
-    }
-
     {
         /* We have to use a separate 64 bit variable here to avoid the gcc
          * "comparison is always false due to limited range of data type"
@@ -378,7 +336,7 @@ static void a15_daughterboard_init(const 
VexpressMachineState *vms,
     memory_region_add_subregion(sysmem, 0x80000000, ram);
 
     /* 0x2c000000 A15MPCore private memory region (GIC) */
-    init_cpus(cpu_model, "a15mpcore_priv", 0x2c000000, pic, vms->secure);
+    init_cpus("a15mpcore_priv", 0x2c000000, pic, vms->secure);
 
     /* A15 daughterboard peripherals: */
 
@@ -556,7 +514,12 @@ static void vexpress_common_init(MachineState *machine)
     const hwaddr *map = daughterboard->motherboard_map;
     int i;
 
-    daughterboard->init(vms, machine->ram_size, machine->cpu_model, pic);
+    if (machine->cpu_model) {
+        error_report("Vexpress does not support CPU model override!\n");
+        exit(1);
+    }
+
+    daughterboard->init(vms, machine->ram_size, pic);
 
     /*
      * If a bios file was provided, attempt to map it into memory
diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c
index a4e7b5c..037cd21 100644
--- a/hw/arm/xilinx_zynq.c
+++ b/hw/arm/xilinx_zynq.c
@@ -26,6 +26,7 @@
 #include "hw/loader.h"
 #include "hw/ssi.h"
 #include "qemu/error-report.h"
+#include "hw/cpu/a9mpcore.h"
 
 #define NUM_SPI_FLASHES 4
 #define NUM_QSPI_FLASHES 2
@@ -104,12 +105,10 @@ static inline void zynq_init_spi_flashes(uint32_t 
base_addr, qemu_irq irq,
 static void zynq_init(MachineState *machine)
 {
     ram_addr_t ram_size = machine->ram_size;
-    const char *cpu_model = machine->cpu_model;
     const char *kernel_filename = machine->kernel_filename;
     const char *kernel_cmdline = machine->kernel_cmdline;
     const char *initrd_filename = machine->initrd_filename;
-    ObjectClass *cpu_oc;
-    ARMCPU *cpu;
+    A9MPPrivState *mpcore;
     MemoryRegion *address_space_mem = get_system_memory();
     MemoryRegion *ext_ram = g_new(MemoryRegion, 1);
     MemoryRegion *ocm_ram = g_new(MemoryRegion, 1);
@@ -119,39 +118,8 @@ static void zynq_init(MachineState *machine)
     Error *err = NULL;
     int n;
 
-    if (!cpu_model) {
-        cpu_model = "cortex-a9";
-    }
-    cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, cpu_model);
-
-    cpu = ARM_CPU(object_new(object_class_get_name(cpu_oc)));
-
-    /* By default A9 CPUs have EL3 enabled.  This board does not
-     * currently support EL3 so the CPU EL3 property is disabled before
-     * realization.
-     */
-    if (object_property_find(OBJECT(cpu), "has_el3", NULL)) {
-        object_property_set_bool(OBJECT(cpu), false, "has_el3", &err);
-        if (err) {
-            error_report_err(err);
-            exit(1);
-        }
-    }
-
-    object_property_set_int(OBJECT(cpu), ZYNQ_BOARD_MIDR, "midr", &err);
-    if (err) {
-        error_report_err(err);
-        exit(1);
-    }
-
-    object_property_set_int(OBJECT(cpu), MPCORE_PERIPHBASE, "reset-cbar", 
&err);
-    if (err) {
-        error_report_err(err);
-        exit(1);
-    }
-    object_property_set_bool(OBJECT(cpu), true, "realized", &err);
-    if (err) {
-        error_report_err(err);
+    if (machine->cpu_model) {
+        error_report("Zynq does not support CPU model override!\n");
         exit(1);
     }
 
@@ -185,16 +153,27 @@ static void zynq_init(MachineState *machine)
     qdev_init_nofail(dev);
     sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xF8000000);
 
-    dev = qdev_create(NULL, "a9mpcore_priv");
-    qdev_prop_set_uint32(dev, "num-cpu", 1);
-    qdev_init_nofail(dev);
-    busdev = SYS_BUS_DEVICE(dev);
+    mpcore = A9MPCORE_PRIV(object_new("a9mpcore_priv"));
+    qdev_prop_set_uint32(DEVICE(mpcore), "num-cpu", 1);
+    qdev_prop_set_uint32(DEVICE(mpcore), "midr", ZYNQ_BOARD_MIDR);
+    qdev_prop_set_uint64(DEVICE(mpcore), "reset-cbar", MPCORE_PERIPHBASE);
+
+    /* By default A9 CPUs have EL3 enabled.  This board does not
+     * currently support EL3 so the CPU EL3 property is disabled before
+     * realization.
+     */
+    object_property_set_bool(OBJECT(mpcore), false, "has_el3", &error_abort);
+    object_property_set_bool(OBJECT(mpcore), true, "realized", &err);
+    if (err != NULL) {
+        error_report("Couldn't realize the Zynq A9MPCore: %s",
+                     error_get_pretty(err));
+        exit(1);
+    }
+    busdev = SYS_BUS_DEVICE(DEVICE(mpcore));
     sysbus_mmio_map(busdev, 0, MPCORE_PERIPHBASE);
-    sysbus_connect_irq(busdev, 0,
-                       qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ));
 
     for (n = 0; n < 64; n++) {
-        pic[n] = qdev_get_gpio_in(dev, n);
+        pic[n] = qdev_get_gpio_in(DEVICE(mpcore), n);
     }
 
     zynq_init_spi_flashes(0xE0006000, pic[58-IRQ_OFFSET], false);
diff --git a/hw/cpu/a15mpcore.c b/hw/cpu/a15mpcore.c
index acc419e..c5c8869 100644
--- a/hw/cpu/a15mpcore.c
+++ b/hw/cpu/a15mpcore.c
@@ -20,6 +20,7 @@
 
 #include "hw/cpu/a15mpcore.h"
 #include "sysemu/kvm.h"
+#include "qapi/visitor.h"
 
 static void a15mp_priv_set_irq(void *opaque, int irq, int level)
 {
@@ -28,6 +29,39 @@ static void a15mp_priv_set_irq(void *opaque, int irq, int 
level)
     qemu_set_irq(qdev_get_gpio_in(DEVICE(&s->gic), irq), level);
 }
 
+static void a15mpcore_set_num_cpus(Object *obj, Visitor *v,
+                                   void *opaque, const char *name,
+                                   Error **errp)
+{
+    A15MPPrivState *s = A15MPCORE_PRIV(obj);
+    ObjectClass *cpu_oc;
+    Error *err = NULL;
+    int i;
+    int64_t value;
+
+    visit_type_int(v, &value, name, &err);
+    if (err) {
+        error_propagate(errp, err);
+        return;
+    }
+    s->num_cpu = value;
+
+    s->cpu = g_new0(ARMCPU, s->num_cpu);
+    cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, "cortex-a15");
+
+    for (i = 0; i < s->num_cpu; i++) {
+        object_initialize(&s->cpu[i], sizeof(*s->cpu),
+                          object_class_get_name(cpu_oc));
+
+        object_property_add_alias(obj, "midr", OBJECT(&s->cpu[i]),
+                                  "midr", &error_abort);
+        object_property_add_alias(obj, "reset-cbar", OBJECT(&s->cpu[i]),
+                                  "reset-cbar", &error_abort);
+        object_property_add_alias(obj, "has_el3", OBJECT(&s->cpu[i]),
+                                  "has_el3", &error_abort);
+    }
+}
+
 static void a15mp_priv_initfn(Object *obj)
 {
     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
@@ -39,6 +73,10 @@ static void a15mp_priv_initfn(Object *obj)
         gictype = "kvm-arm-gic";
     }
 
+    object_property_add(obj, "num-cpu", "int",
+                        NULL, a15mpcore_set_num_cpus,
+                        NULL, NULL, NULL);
+
     memory_region_init(&s->container, obj, "a15mp-priv-container", 0x8000);
     sysbus_init_mmio(sbd, &s->container);
 
@@ -50,13 +88,16 @@ static void a15mp_priv_initfn(Object *obj)
 
 static void a15mp_priv_realize(DeviceState *dev, Error **errp)
 {
-    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
     A15MPPrivState *s = A15MPCORE_PRIV(dev);
     DeviceState *gicdev;
     SysBusDevice *busdev;
     int i;
     Error *err = NULL;
 
+    if (!s->cpu) {
+        qdev_prop_set_uint32(dev, "num-cpu", 1);
+    }
+
     gicdev = DEVICE(&s->gic);
     qdev_prop_set_uint32(gicdev, "num-cpu", s->num_cpu);
     qdev_prop_set_uint32(gicdev, "num-irq", s->num_irq);
@@ -67,18 +108,26 @@ static void a15mp_priv_realize(DeviceState *dev, Error 
**errp)
     }
     busdev = SYS_BUS_DEVICE(&s->gic);
 
-    /* Pass through outbound IRQ lines from the GIC */
-    sysbus_pass_irq(sbd, busdev);
-
     /* Pass through inbound GPIO lines to the GIC */
     qdev_init_gpio_in(dev, a15mp_priv_set_irq, s->num_irq - 32);
 
-    /* Wire the outputs from each CPU's generic timer to the
-     * appropriate GIC PPI inputs
-     */
     for (i = 0; i < s->num_cpu; i++) {
-        DeviceState *cpudev = DEVICE(qemu_get_cpu(i));
+        DeviceState *cpudev = DEVICE(&s->cpu[i]);
         int ppibase = s->num_irq - 32 + i * 32;
+
+        object_property_set_bool(OBJECT(&s->cpu[i]), true,
+                                 "realized", &err);
+        if (err) {
+            error_propagate(errp, err);
+            return;
+        }
+        sysbus_connect_irq(busdev, i, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ));
+        sysbus_connect_irq(busdev, i + s->num_cpu,
+                           qdev_get_gpio_in(cpudev, ARM_CPU_FIQ));
+        /* Wire the outputs from each CPU's generic timer to the
+         * appropriate GIC PPI inputs
+         */
+
         /* physical timer; we wire it up to the non-secure timer's ID,
          * since a real A15 always has TrustZone but QEMU doesn't.
          */
@@ -104,7 +153,6 @@ static void a15mp_priv_realize(DeviceState *dev, Error 
**errp)
 }
 
 static Property a15mp_priv_properties[] = {
-    DEFINE_PROP_UINT32("num-cpu", A15MPPrivState, num_cpu, 1),
     /* The Cortex-A15MP may have anything from 0 to 224 external interrupt
      * IRQ lines (with another 32 internal). We default to 128+32, which
      * is the number provided by the Cortex-A15MP test chip in the
diff --git a/hw/cpu/a9mpcore.c b/hw/cpu/a9mpcore.c
index c09358c..4a7c561 100644
--- a/hw/cpu/a9mpcore.c
+++ b/hw/cpu/a9mpcore.c
@@ -9,6 +9,7 @@
  */
 
 #include "hw/cpu/a9mpcore.h"
+#include "qapi/visitor.h"
 
 static void a9mp_priv_set_irq(void *opaque, int irq, int level)
 {
@@ -17,10 +18,77 @@ static void a9mp_priv_set_irq(void *opaque, int irq, int 
level)
     qemu_set_irq(qdev_get_gpio_in(DEVICE(&s->gic), irq), level);
 }
 
+static inline void a9mp_priv_set_cpu_irq(A9MPPrivState *s, int irq,
+                                         bool old_pin_state)
+{
+    bool pin_state = s->gic_pin_states[irq] || s->ext_intc_states[irq];
+
+    if (pin_state != old_pin_state) {
+        qemu_set_irq(s->cpu_irq[irq], pin_state);
+    }
+}
+
+static void a9mp_priv_set_ext_irq(void *opaque, int irq, int level)
+{
+    A9MPPrivState *s = (A9MPPrivState *)opaque;
+    bool old_pin_state = s->gic_pin_states[irq] || s->ext_intc_states[irq];
+
+    assert(irq < s->num_cpu);
+    s->ext_intc_states[irq] = level;
+    a9mp_priv_set_cpu_irq(s, irq, old_pin_state);
+}
+
+static void a9mp_priv_set_gic_irq(void *opaque, int irq, int level)
+{
+    A9MPPrivState *s = (A9MPPrivState *)opaque;
+    bool old_pin_state = s->gic_pin_states[irq] || s->ext_intc_states[irq];
+
+    assert(irq < s->num_cpu);
+    s->gic_pin_states[irq] = level;
+    a9mp_priv_set_cpu_irq(s, irq, old_pin_state);
+}
+
+static void a9mpcore_set_num_cpus(Object *obj, Visitor *v,
+                                  void *opaque, const char *name,
+                                  Error **errp)
+{
+    A9MPPrivState *s = A9MPCORE_PRIV(obj);
+    ObjectClass *cpu_oc;
+    Error *err = NULL;
+    int i;
+    int64_t value;
+
+    visit_type_int(v, &value, name, &err);
+    if (err) {
+        error_propagate(errp, err);
+        return;
+    }
+    s->num_cpu = value;
+
+    s->cpu = g_new0(ARMCPU, s->num_cpu);
+    cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, "cortex-a9");
+
+    for (i = 0; i < s->num_cpu; i++) {
+        object_initialize(&s->cpu[i], sizeof(*s->cpu),
+                          object_class_get_name(cpu_oc));
+
+        object_property_add_alias(obj, "midr", OBJECT(&s->cpu[i]),
+                                  "midr", &error_abort);
+        object_property_add_alias(obj, "reset-cbar", OBJECT(&s->cpu[i]),
+                                  "reset-cbar", &error_abort);
+        object_property_add_alias(obj, "has_el3", OBJECT(&s->cpu[i]),
+                                  "has_el3", &error_abort);
+    }
+}
+
 static void a9mp_priv_initfn(Object *obj)
 {
     A9MPPrivState *s = A9MPCORE_PRIV(obj);
 
+    object_property_add(obj, "num-cpu", "int",
+                        NULL, a9mpcore_set_num_cpus,
+                        NULL, NULL, NULL);
+
     memory_region_init(&s->container, obj, "a9mp-priv-container", 0x2000);
     sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->container);
 
@@ -42,14 +110,18 @@ static void a9mp_priv_initfn(Object *obj)
 
 static void a9mp_priv_realize(DeviceState *dev, Error **errp)
 {
-    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
     A9MPPrivState *s = A9MPCORE_PRIV(dev);
     DeviceState *scudev, *gicdev, *gtimerdev, *mptimerdev, *wdtdev;
     SysBusDevice *scubusdev, *gicbusdev, *gtimerbusdev, *mptimerbusdev,
                  *wdtbusdev;
+    qemu_irq *gic_local_cpu_irqs;
     Error *err = NULL;
     int i;
 
+    if (!s->cpu) {
+        qdev_prop_set_uint32(dev, "num-cpu", 1);
+    }
+
     scudev = DEVICE(&s->scu);
     qdev_prop_set_uint32(scudev, "num-cpu", s->num_cpu);
     object_property_set_bool(OBJECT(&s->scu), true, "realized", &err);
@@ -69,12 +141,28 @@ static void a9mp_priv_realize(DeviceState *dev, Error 
**errp)
     }
     gicbusdev = SYS_BUS_DEVICE(&s->gic);
 
-    /* Pass through outbound IRQ lines from the GIC */
-    sysbus_pass_irq(sbd, gicbusdev);
-
     /* Pass through inbound GPIO lines to the GIC */
     qdev_init_gpio_in(dev, a9mp_priv_set_irq, s->num_irq - 32);
 
+    gic_local_cpu_irqs = qemu_allocate_irqs(a9mp_priv_set_gic_irq, OBJECT(dev),
+                                            s->num_cpu);
+    s->cpu_irq = g_new0(qemu_irq, s->num_cpu);
+    s->gic_pin_states = g_new0(bool, s->num_cpu);
+    s->ext_intc_states = g_new0(bool, s->num_cpu);
+    for (i = 0; i < s->num_cpu; i++) {
+        object_property_set_bool(OBJECT(&s->cpu[i]), true, "realized", &err);
+        if (err) {
+            error_propagate(errp, err);
+            return;
+        }
+        s->cpu_irq[i] = qdev_get_gpio_in(DEVICE(&s->cpu[i]), ARM_CPU_IRQ);
+        sysbus_connect_irq(gicbusdev, i + s->num_cpu,
+                           qdev_get_gpio_in(DEVICE(&s->cpu[i]), ARM_CPU_FIQ));
+        sysbus_connect_irq(gicbusdev, i, gic_local_cpu_irqs[i]);
+    }
+    qdev_init_gpio_in_named(dev, a9mp_priv_set_ext_irq, "ext-interrupt",
+                            s->num_cpu);
+
     gtimerdev = DEVICE(&s->gtimer);
     qdev_prop_set_uint32(gtimerdev, "num-cpu", s->num_cpu);
     object_property_set_bool(OBJECT(&s->gtimer), true, "realized", &err);
@@ -144,7 +232,6 @@ static void a9mp_priv_realize(DeviceState *dev, Error 
**errp)
 }
 
 static Property a9mp_priv_properties[] = {
-    DEFINE_PROP_UINT32("num-cpu", A9MPPrivState, num_cpu, 1),
     /* The Cortex-A9MP may have anything from 0 to 224 external interrupt
      * IRQ lines (with another 32 internal). We default to 64+32, which
      * is the number provided by the Cortex-A9MP test chip in the
diff --git a/hw/intc/exynos4210_gic.c b/hw/intc/exynos4210_gic.c
index b2a4950..75dd944 100644
--- a/hw/intc/exynos4210_gic.c
+++ b/hw/intc/exynos4210_gic.c
@@ -364,108 +364,3 @@ static void exynos4210_gic_register_types(void)
 }
 
 type_init(exynos4210_gic_register_types)
-
-/* IRQ OR Gate struct.
- *
- * This device models an OR gate. There are n_in input qdev gpio lines and one
- * output sysbus IRQ line. The output IRQ level is formed as OR between all
- * gpio inputs.
- */
-
-#define TYPE_EXYNOS4210_IRQ_GATE "exynos4210.irq_gate"
-#define EXYNOS4210_IRQ_GATE(obj) \
-    OBJECT_CHECK(Exynos4210IRQGateState, (obj), TYPE_EXYNOS4210_IRQ_GATE)
-
-typedef struct Exynos4210IRQGateState {
-    SysBusDevice parent_obj;
-
-    uint32_t n_in;      /* inputs amount */
-    uint32_t *level;    /* input levels */
-    qemu_irq out;       /* output IRQ */
-} Exynos4210IRQGateState;
-
-static Property exynos4210_irq_gate_properties[] = {
-    DEFINE_PROP_UINT32("n_in", Exynos4210IRQGateState, n_in, 1),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static const VMStateDescription vmstate_exynos4210_irq_gate = {
-    .name = "exynos4210.irq_gate",
-    .version_id = 2,
-    .minimum_version_id = 2,
-    .fields = (VMStateField[]) {
-        VMSTATE_VBUFFER_UINT32(level, Exynos4210IRQGateState, 1, NULL, 0, 
n_in),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-/* Process a change in IRQ input. */
-static void exynos4210_irq_gate_handler(void *opaque, int irq, int level)
-{
-    Exynos4210IRQGateState *s = (Exynos4210IRQGateState *)opaque;
-    uint32_t i;
-
-    assert(irq < s->n_in);
-
-    s->level[irq] = level;
-
-    for (i = 0; i < s->n_in; i++) {
-        if (s->level[i] >= 1) {
-            qemu_irq_raise(s->out);
-            return;
-        }
-    }
-
-    qemu_irq_lower(s->out);
-}
-
-static void exynos4210_irq_gate_reset(DeviceState *d)
-{
-    Exynos4210IRQGateState *s = EXYNOS4210_IRQ_GATE(d);
-
-    memset(s->level, 0, s->n_in * sizeof(*s->level));
-}
-
-/*
- * IRQ Gate initialization.
- */
-static int exynos4210_irq_gate_init(SysBusDevice *sbd)
-{
-    DeviceState *dev = DEVICE(sbd);
-    Exynos4210IRQGateState *s = EXYNOS4210_IRQ_GATE(dev);
-
-    /* Allocate general purpose input signals and connect a handler to each of
-     * them */
-    qdev_init_gpio_in(dev, exynos4210_irq_gate_handler, s->n_in);
-
-    s->level = g_malloc0(s->n_in * sizeof(*s->level));
-
-    sysbus_init_irq(sbd, &s->out);
-
-    return 0;
-}
-
-static void exynos4210_irq_gate_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = exynos4210_irq_gate_init;
-    dc->reset = exynos4210_irq_gate_reset;
-    dc->vmsd = &vmstate_exynos4210_irq_gate;
-    dc->props = exynos4210_irq_gate_properties;
-}
-
-static const TypeInfo exynos4210_irq_gate_info = {
-    .name          = TYPE_EXYNOS4210_IRQ_GATE,
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(Exynos4210IRQGateState),
-    .class_init    = exynos4210_irq_gate_class_init,
-};
-
-static void exynos4210_irq_gate_register_types(void)
-{
-    type_register_static(&exynos4210_irq_gate_info);
-}
-
-type_init(exynos4210_irq_gate_register_types)
diff --git a/include/hw/arm/exynos4210.h b/include/hw/arm/exynos4210.h
index 5c1820f..404ae65 100644
--- a/include/hw/arm/exynos4210.h
+++ b/include/hw/arm/exynos4210.h
@@ -56,7 +56,6 @@
 /*
  * exynos4210 IRQ subsystem stub definitions.
  */
-#define EXYNOS4210_IRQ_GATE_NINPUTS 2 /* Internal and External GIC */
 
 #define EXYNOS4210_MAX_INT_COMBINER_OUT_IRQ  64
 #define EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ  16
@@ -85,7 +84,6 @@ typedef struct Exynos4210Irq {
 } Exynos4210Irq;
 
 typedef struct Exynos4210State {
-    ARMCPU *cpu[EXYNOS4210_NCPUS];
     Exynos4210Irq irqs;
     qemu_irq *irq_table;
 
diff --git a/include/hw/cpu/a15mpcore.h b/include/hw/cpu/a15mpcore.h
index b423533..9613690 100644
--- a/include/hw/cpu/a15mpcore.h
+++ b/include/hw/cpu/a15mpcore.h
@@ -34,6 +34,8 @@ typedef struct A15MPPrivState {
     SysBusDevice parent_obj;
     /*< public >*/
 
+    ARMCPU *cpu;
+
     uint32_t num_cpu;
     uint32_t num_irq;
     MemoryRegion container;
diff --git a/include/hw/cpu/a9mpcore.h b/include/hw/cpu/a9mpcore.h
index 5d67ca2..97b3ea1 100644
--- a/include/hw/cpu/a9mpcore.h
+++ b/include/hw/cpu/a9mpcore.h
@@ -29,11 +29,17 @@ typedef struct A9MPPrivState {
     MemoryRegion container;
     uint32_t num_irq;
 
+    ARMCPU *cpu;
+
     A9SCUState scu;
     GICState gic;
     A9GTimerState gtimer;
     ARMMPTimerState mptimer;
     ARMMPTimerState wdt;
+
+    qemu_irq *cpu_irq;
+    bool *gic_pin_states;
+    bool *ext_intc_states;
 } A9MPPrivState;
 
 #endif
-- 
2.4.3.3.g905f831




reply via email to

[Prev in Thread] Current Thread [Next in Thread]