ARM MPCore tweaks
authorPaul Brook <paul@codesourcery.com>
Fri, 13 Nov 2009 04:31:22 +0000 (04:31 +0000)
committerPaul Brook <paul@codesourcery.com>
Fri, 13 Nov 2009 04:31:22 +0000 (04:31 +0000)
Allow the user to specify the number of cores present on the
RealView EB + ARM11MPCore board.  Also split into its own config
rather than guessing from the CPU name.

Signed-off-by: Paul Brook <paul@codesourcery.com>
hw/arm_gic.c
hw/mpcore.c
hw/realview.c
qemu-doc.texi

index 12f5109924bd2bdbfdb762a436575c6d58875911..536112bff53a5455a870ff6e21d01356ddbe3227 100644 (file)
@@ -48,6 +48,11 @@ typedef struct gic_irq_state
 } gic_irq_state;
 
 #define ALL_CPU_MASK ((1 << NCPU) - 1)
+#if NCPU > 1
+#define NUM_CPU(s) ((s)->num_cpu)
+#else
+#define NUM_CPU(s) 1
+#endif
 
 #define GIC_SET_ENABLED(irq) s->irq_state[irq].enabled = 1
 #define GIC_CLEAR_ENABLED(irq) s->irq_state[irq].enabled = 0
@@ -95,6 +100,10 @@ typedef struct gic_state
     int running_priority[NCPU];
     int current_pending[NCPU];
 
+#if NCPU > 1
+    int num_cpu;
+#endif
+
     int iomemtype;
 } gic_state;
 
@@ -109,7 +118,7 @@ static void gic_update(gic_state *s)
     int cpu;
     int cm;
 
-    for (cpu = 0; cpu < NCPU; cpu++) {
+    for (cpu = 0; cpu < NUM_CPU(s); cpu++) {
         cm = 1 << cpu;
         s->current_pending[cpu] = 1023;
         if (!s->enabled || !s->cpu_enabled[cpu]) {
@@ -255,7 +264,7 @@ static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset)
         if (offset == 0)
             return s->enabled;
         if (offset == 4)
-            return ((GIC_NIRQ / 32) - 1) | ((NCPU - 1) << 5);
+            return ((GIC_NIRQ / 32) - 1) | ((NUM_CPU(s) - 1) << 5);
         if (offset < 0x08)
             return 0;
 #endif
@@ -620,7 +629,7 @@ static void gic_reset(gic_state *s)
 {
     int i;
     memset(s->irq_state, 0, GIC_NIRQ * sizeof(gic_irq_state));
-    for (i = 0 ; i < NCPU; i++) {
+    for (i = 0 ; i < NUM_CPU(s); i++) {
         s->priority_mask[i] = 0xf0;
         s->current_pending[i] = 1023;
         s->running_irq[i] = 1023;
@@ -651,7 +660,7 @@ static void gic_save(QEMUFile *f, void *opaque)
     int j;
 
     qemu_put_be32(f, s->enabled);
-    for (i = 0; i < NCPU; i++) {
+    for (i = 0; i < NUM_CPU(s); i++) {
         qemu_put_be32(f, s->cpu_enabled[i]);
 #ifndef NVIC
         qemu_put_be32(f, s->irq_target[i]);
@@ -688,7 +697,7 @@ static int gic_load(QEMUFile *f, void *opaque, int version_id)
         return -EINVAL;
 
     s->enabled = qemu_get_be32(f);
-    for (i = 0; i < NCPU; i++) {
+    for (i = 0; i < NUM_CPU(s); i++) {
         s->cpu_enabled[i] = qemu_get_be32(f);
 #ifndef NVIC
         s->irq_target[i] = qemu_get_be32(f);
@@ -717,12 +726,19 @@ static int gic_load(QEMUFile *f, void *opaque, int version_id)
     return 0;
 }
 
+#if NCPU > 1
+static void gic_init(gic_state *s, int num_cpu)
+#else
 static void gic_init(gic_state *s)
+#endif
 {
     int i;
 
+#if NCPU > 1
+    s->num_cpu = num_cpu;
+#endif
     qdev_init_gpio_in(&s->busdev.qdev, gic_set_irq, GIC_NIRQ - 32);
-    for (i = 0; i < NCPU; i++) {
+    for (i = 0; i < NUM_CPU(s); i++) {
         sysbus_init_irq(&s->busdev, &s->parent_irq[i]);
     }
     s->iomemtype = cpu_register_io_memory(gic_dist_readfn,
index 46c2b9d994da9f190bc040c8cfa0381d38930ed5..eccb2e188df4b12547ffa187fa7ff67f0f187b01 100644 (file)
@@ -44,6 +44,7 @@ typedef struct mpcore_priv_state {
     uint32_t scu_control;
     int iomemtype;
     mpcore_timer_state timer[8];
+    uint32_t num_cpu;
 } mpcore_priv_state;
 
 /* Per-CPU Timers.  */
@@ -166,7 +167,8 @@ static uint32_t mpcore_priv_read(void *opaque, target_phys_addr_t offset)
         case 0x00: /* Control.  */
             return s->scu_control;
         case 0x04: /* Configuration.  */
-            return 0xf3;
+            id = ((1 << s->num_cpu) - 1) << 4;
+            return id | (s->num_cpu - 1);
         case 0x08: /* CPU status.  */
             return 0;
         case 0x0c: /* Invalidate all.  */
@@ -180,6 +182,9 @@ static uint32_t mpcore_priv_read(void *opaque, target_phys_addr_t offset)
             id = gic_get_current_cpu();
         } else {
             id = (offset - 0x200) >> 8;
+            if (id >= s->num_cpu) {
+                return 0;
+            }
         }
         return gic_cpu_read(&s->gic, id, offset & 0xff);
     } else if (offset < 0xb00) {
@@ -188,6 +193,9 @@ static uint32_t mpcore_priv_read(void *opaque, target_phys_addr_t offset)
             id = gic_get_current_cpu();
         } else {
             id = (offset - 0x700) >> 8;
+            if (id >= s->num_cpu) {
+                return 0;
+            }
         }
         id <<= 1;
         if (offset & 0x20)
@@ -224,7 +232,9 @@ static void mpcore_priv_write(void *opaque, target_phys_addr_t offset,
         } else {
             id = (offset - 0x200) >> 8;
         }
-        gic_cpu_write(&s->gic, id, offset & 0xff, value);
+        if (id < s->num_cpu) {
+            gic_cpu_write(&s->gic, id, offset & 0xff, value);
+        }
     } else if (offset < 0xb00) {
         /* Timers.  */
         if (offset < 0x700) {
@@ -232,10 +242,12 @@ static void mpcore_priv_write(void *opaque, target_phys_addr_t offset,
         } else {
             id = (offset - 0x700) >> 8;
         }
-        id <<= 1;
-        if (offset & 0x20)
-          id++;
-        mpcore_timer_write(&s->timer[id], offset & 0xf, value);
+        if (id < s->num_cpu) {
+            id <<= 1;
+            if (offset & 0x20)
+              id++;
+            mpcore_timer_write(&s->timer[id], offset & 0xf, value);
+        }
         return;
     }
     return;
@@ -267,11 +279,11 @@ static int mpcore_priv_init(SysBusDevice *dev)
     mpcore_priv_state *s = FROM_SYSBUSGIC(mpcore_priv_state, dev);
     int i;
 
-    gic_init(&s->gic);
+    gic_init(&s->gic, s->num_cpu);
     s->iomemtype = cpu_register_io_memory(mpcore_priv_readfn,
                                           mpcore_priv_writefn, s);
     sysbus_init_mmio_cb(dev, 0x2000, mpcore_priv_map);
-    for (i = 0; i < 8; i++) {
+    for (i = 0; i < s->num_cpu * 2; i++) {
         mpcore_timer_init(s, &s->timer[i], i);
     }
     return 0;
@@ -284,6 +296,7 @@ typedef struct {
     SysBusDevice busdev;
     qemu_irq cpuic[32];
     qemu_irq rvic[4][64];
+    uint32_t num_cpu;
 } mpcore_rirq_state;
 
 /* Map baseboard IRQs onto CPU IRQ lines.  */
@@ -315,11 +328,16 @@ static int realview_mpcore_init(SysBusDevice *dev)
     mpcore_rirq_state *s = FROM_SYSBUS(mpcore_rirq_state, dev);
     DeviceState *gic;
     DeviceState *priv;
+    SysBusDevice *bus_priv;
     int n;
     int i;
 
-    priv = sysbus_create_simple("arm11mpcore_priv", MPCORE_PRIV_BASE, NULL);
-    sysbus_pass_irq(dev, sysbus_from_qdev(priv));
+    priv = qdev_create(NULL, "arm11mpcore_priv");
+    qdev_prop_set_uint32(priv, "num-cpu", s->num_cpu);
+    qdev_init_nofail(priv);
+    bus_priv = sysbus_from_qdev(priv);
+    sysbus_mmio_map(bus_priv, 0, MPCORE_PRIV_BASE);
+    sysbus_pass_irq(dev, bus_priv);
     for (i = 0; i < 32; i++) {
         s->cpuic[i] = qdev_get_gpio_in(priv, i);
     }
@@ -335,12 +353,30 @@ static int realview_mpcore_init(SysBusDevice *dev)
     return 0;
 }
 
+static SysBusDeviceInfo mpcore_rirq_info = {
+    .init = realview_mpcore_init,
+    .qdev.name  = "realview_mpcore",
+    .qdev.size  = sizeof(mpcore_rirq_state),
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("num-cpu", mpcore_rirq_state, num_cpu, 1),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static SysBusDeviceInfo mpcore_priv_info = {
+    .init = mpcore_priv_init,
+    .qdev.name  = "arm11mpcore_priv",
+    .qdev.size  = sizeof(mpcore_priv_state),
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("num-cpu", mpcore_priv_state, num_cpu, 1),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
 static void mpcore_register_devices(void)
 {
-    sysbus_register_dev("realview_mpcore", sizeof(mpcore_rirq_state),
-                        realview_mpcore_init);
-    sysbus_register_dev("arm11mpcore_priv", sizeof(mpcore_priv_state),
-                        mpcore_priv_init);
+    sysbus_register_withprop(&mpcore_rirq_info);
+    sysbus_register_withprop(&mpcore_priv_info);
 }
 
 device_init(mpcore_register_devices)
index a14c8a08c9eb7b385455ec44743e7ee25daa61c6..0e57b5085409ff05def095b0d17b017b2094250b 100644 (file)
@@ -35,14 +35,21 @@ static void secondary_cpu_reset(void *opaque)
   env->regs[15] = 0x80000000;
 }
 
+enum realview_board_type {
+    BOARD_EB,
+    BOARD_EB_MPCORE
+};
+
 static void realview_init(ram_addr_t ram_size,
                      const char *boot_device,
                      const char *kernel_filename, const char *kernel_cmdline,
-                     const char *initrd_filename, const char *cpu_model)
+                     const char *initrd_filename, const char *cpu_model,
+                     enum realview_board_type board_type)
 {
-    CPUState *env;
+    CPUState *env = NULL;
     ram_addr_t ram_offset;
     DeviceState *dev;
+    SysBusDevice *busdev;
     qemu_irq *irqp;
     qemu_irq pic[64];
     PCIBus *pci_bus;
@@ -50,19 +57,10 @@ static void realview_init(ram_addr_t ram_size,
     int n;
     int done_smc = 0;
     qemu_irq cpu_irq[4];
-    int ncpu;
+    int is_mpcore = (board_type == BOARD_EB_MPCORE);
     uint32_t proc_id = 0;
 
-    if (!cpu_model)
-        cpu_model = "arm926";
-    /* FIXME: obey smp_cpus.  */
-    if (strcmp(cpu_model, "arm11mpcore") == 0) {
-        ncpu = 4;
-    } else {
-        ncpu = 1;
-    }
-
-    for (n = 0; n < ncpu; n++) {
+    for (n = 0; n < smp_cpus; n++) {
         env = cpu_init(cpu_model);
         if (!env) {
             fprintf(stderr, "Unable to find CPU definition\n");
@@ -91,15 +89,16 @@ static void realview_init(ram_addr_t ram_size,
 
     arm_sysctl_init(0x10000000, 0xc1400400, proc_id);
 
-    if (ncpu == 1) {
-        /* ??? The documentation says GIC1 is nFIQ and either GIC2 or GIC3
-           is nIRQ (there are inconsistencies).  However Linux 2.6.17 expects
-           GIC1 to be nIRQ and ignores all the others, so do that for now.  */
-        dev = sysbus_create_simple("realview_gic", 0x10040000, cpu_irq[0]);
+    if (is_mpcore) {
+        dev = qdev_create(NULL, "realview_mpcore");
+        qdev_prop_set_uint32(dev, "num-cpu", smp_cpus);
+        qdev_init_nofail(dev);
+        busdev = sysbus_from_qdev(dev);
+        for (n = 0; n < smp_cpus; n++) {
+            sysbus_connect_irq(busdev, n, cpu_irq[n]);
+        }
     } else {
-        dev = sysbus_create_varargs("realview_mpcore", -1,
-                                    cpu_irq[0], cpu_irq[1], cpu_irq[2],
-                                    cpu_irq[3], NULL);
+        dev = sysbus_create_simple("realview_gic", 0x10040000, cpu_irq[0]);
     }
     for (n = 0; n < 64; n++) {
         pic[n] = qdev_get_gpio_in(dev, n);
@@ -210,20 +209,53 @@ static void realview_init(ram_addr_t ram_size,
     realview_binfo.kernel_filename = kernel_filename;
     realview_binfo.kernel_cmdline = kernel_cmdline;
     realview_binfo.initrd_filename = initrd_filename;
-    realview_binfo.nb_cpus = ncpu;
+    realview_binfo.nb_cpus = smp_cpus;
     arm_load_kernel(first_cpu, &realview_binfo);
 }
 
-static QEMUMachine realview_machine = {
-    .name = "realview",
+static void realview_eb_init(ram_addr_t ram_size,
+                     const char *boot_device,
+                     const char *kernel_filename, const char *kernel_cmdline,
+                     const char *initrd_filename, const char *cpu_model)
+{
+    if (!cpu_model) {
+        cpu_model = "arm926";
+    }
+    realview_init(ram_size, boot_device, kernel_filename, kernel_cmdline,
+                  initrd_filename, cpu_model, BOARD_EB);
+}
+
+static void realview_eb_mpcore_init(ram_addr_t ram_size,
+                     const char *boot_device,
+                     const char *kernel_filename, const char *kernel_cmdline,
+                     const char *initrd_filename, const char *cpu_model)
+{
+    if (!cpu_model) {
+        cpu_model = "arm11mpcore";
+    }
+    realview_init(ram_size, boot_device, kernel_filename, kernel_cmdline,
+                  initrd_filename, cpu_model, BOARD_EB_MPCORE);
+}
+
+static QEMUMachine realview_eb_machine = {
+    .name = "realview-eb",
     .desc = "ARM RealView Emulation Baseboard (ARM926EJ-S)",
-    .init = realview_init,
+    .init = realview_eb_init,
+    .use_scsi = 1,
+};
+
+static QEMUMachine realview_eb_mpcore_machine = {
+    .name = "realview-eb-mpcore",
+    .desc = "ARM RealView Emulation Baseboard (ARM11MPCore)",
+    .init = realview_eb_mpcore_init,
     .use_scsi = 1,
+    .max_cpus = 4,
 };
 
 static void realview_machine_init(void)
 {
-    qemu_register_machine(&realview_machine);
+    qemu_register_machine(&realview_eb_machine);
+    qemu_register_machine(&realview_eb_mpcore_machine);
 }
 
 machine_init(realview_machine_init);
index 7d3240c63a697c8d917cca20c790330487b31c48..38dbda7b247ad2ea6abe2f14a06d2a062bfa9fc5 100644 (file)
@@ -1663,7 +1663,7 @@ The ARM RealView Emulation baseboard is emulated with the following devices:
 
 @itemize @minus
 @item
-ARM926E, ARM1136, ARM11MPCORE(x4) or Cortex-A8 CPU
+ARM926E, ARM1136, ARM11MPCORE or Cortex-A8 CPU
 @item
 ARM AMBA Generic/Distributed Interrupt Controller
 @item