summary refs log tree commit diff stats
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-rw-r--r--hw/block/dataplane/xen-block.c4
-rw-r--r--hw/block/trace-events1
-rw-r--r--hw/block/xen-block.c40
-rw-r--r--hw/i2c/smbus_eeprom.c129
-rw-r--r--hw/intc/spapr_xive.c9
-rw-r--r--hw/intc/xics_spapr.c11
-rw-r--r--hw/intc/xive.c22
-rw-r--r--hw/ppc/Makefile.objs3
-rw-r--r--hw/ppc/mac_newworld.c1
-rw-r--r--hw/ppc/mac_oldworld.c1
-rw-r--r--hw/ppc/pnv.c7
-rw-r--r--hw/ppc/pnv_core.c12
-rw-r--r--hw/ppc/ppc.c58
-rw-r--r--hw/ppc/ppc405_uc.c58
-rw-r--r--hw/ppc/ppc440_bamboo.c2
-rw-r--r--hw/ppc/ppc440_uc.c76
-rw-r--r--hw/ppc/ppc4xx_devs.c48
-rw-r--r--hw/ppc/ppc_booke.c1
-rw-r--r--hw/ppc/sam460ex.c181
-rw-r--r--hw/ppc/spapr.c23
-rw-r--r--hw/ppc/spapr_cpu_core.c8
-rw-r--r--hw/ppc/spapr_irq.c17
-rw-r--r--hw/ppc/spapr_pci.c7
-rw-r--r--hw/ppc/spapr_vio.c47
-rw-r--r--hw/xen/xen-bus.c32
-rw-r--r--hw/xtensa/Makefile.objs1
-rw-r--r--hw/xtensa/mx_pic.c354
-rw-r--r--hw/xtensa/pic_cpu.c47
-rw-r--r--hw/xtensa/xtfpga.c65
29 files changed, 837 insertions, 428 deletions
diff --git a/hw/block/dataplane/xen-block.c b/hw/block/dataplane/xen-block.c
index d0d8905a33..c6a15da024 100644
--- a/hw/block/dataplane/xen-block.c
+++ b/hw/block/dataplane/xen-block.c
@@ -50,7 +50,6 @@ struct XenBlockDataPlane {
     unsigned int nr_ring_ref;
     void *sring;
     int64_t file_blk;
-    int64_t file_size;
     int protocol;
     blkif_back_rings_t rings;
     int more_work;
@@ -189,7 +188,7 @@ static int xen_block_parse_request(XenBlockRequest *request)
                request->req.seg[i].first_sect + 1) * dataplane->file_blk;
         request->size += len;
     }
-    if (request->start + request->size > dataplane->file_size) {
+    if (request->start + request->size > blk_getlength(dataplane->blk)) {
         error_report("error: access beyond end of file");
         goto err;
     }
@@ -638,7 +637,6 @@ XenBlockDataPlane *xen_block_dataplane_create(XenDevice *xendev,
     dataplane->xendev = xendev;
     dataplane->file_blk = conf->logical_block_size;
     dataplane->blk = conf->blk;
-    dataplane->file_size = blk_getlength(dataplane->blk);
 
     QLIST_INIT(&dataplane->inflight);
     QLIST_INIT(&dataplane->freelist);
diff --git a/hw/block/trace-events b/hw/block/trace-events
index d0851953c5..8020f9226a 100644
--- a/hw/block/trace-events
+++ b/hw/block/trace-events
@@ -126,6 +126,7 @@ xen_block_realize(const char *type, uint32_t disk, uint32_t partition) "%s d%up%
 xen_block_connect(const char *type, uint32_t disk, uint32_t partition) "%s d%up%u"
 xen_block_disconnect(const char *type, uint32_t disk, uint32_t partition) "%s d%up%u"
 xen_block_unrealize(const char *type, uint32_t disk, uint32_t partition) "%s d%up%u"
+xen_block_size(const char *type, uint32_t disk, uint32_t partition, int64_t sectors) "%s d%up%u %"PRIi64
 xen_disk_realize(void) ""
 xen_disk_unrealize(void) ""
 xen_cdrom_realize(void) ""
diff --git a/hw/block/xen-block.c b/hw/block/xen-block.c
index a636487b3e..5012af9cb6 100644
--- a/hw/block/xen-block.c
+++ b/hw/block/xen-block.c
@@ -144,6 +144,38 @@ static void xen_block_unrealize(XenDevice *xendev, Error **errp)
     }
 }
 
+static void xen_block_set_size(XenBlockDevice *blockdev)
+{
+    const char *type = object_get_typename(OBJECT(blockdev));
+    XenBlockVdev *vdev = &blockdev->props.vdev;
+    BlockConf *conf = &blockdev->props.conf;
+    int64_t sectors = blk_getlength(conf->blk) / conf->logical_block_size;
+    XenDevice *xendev = XEN_DEVICE(blockdev);
+
+    trace_xen_block_size(type, vdev->disk, vdev->partition, sectors);
+
+    xen_device_backend_printf(xendev, "sectors", "%"PRIi64, sectors);
+}
+
+static void xen_block_resize_cb(void *opaque)
+{
+    XenBlockDevice *blockdev = opaque;
+    XenDevice *xendev = XEN_DEVICE(blockdev);
+    enum xenbus_state state = xen_device_backend_get_state(xendev);
+
+    xen_block_set_size(blockdev);
+
+    /*
+     * Mimic the behaviour of Linux xen-blkback and re-write the state
+     * to trigger the frontend watch.
+     */
+    xen_device_backend_printf(xendev, "state", "%u", state);
+}
+
+static const BlockDevOps xen_block_dev_ops = {
+    .resize_cb = xen_block_resize_cb,
+};
+
 static void xen_block_realize(XenDevice *xendev, Error **errp)
 {
     XenBlockDevice *blockdev = XEN_BLOCK_DEVICE(xendev);
@@ -180,7 +212,7 @@ static void xen_block_realize(XenDevice *xendev, Error **errp)
     }
 
     if (!blkconf_apply_backend_options(conf, blockdev->info & VDISK_READONLY,
-                                       false, errp)) {
+                                       true, errp)) {
         return;
     }
 
@@ -197,6 +229,7 @@ static void xen_block_realize(XenDevice *xendev, Error **errp)
         return;
     }
 
+    blk_set_dev_ops(conf->blk, &xen_block_dev_ops, blockdev);
     blk_set_guest_block_size(conf->blk, conf->logical_block_size);
 
     if (conf->discard_granularity > 0) {
@@ -215,9 +248,8 @@ static void xen_block_realize(XenDevice *xendev, Error **errp)
 
     xen_device_backend_printf(xendev, "sector-size", "%u",
                               conf->logical_block_size);
-    xen_device_backend_printf(xendev, "sectors", "%"PRIi64,
-                              blk_getlength(conf->blk) /
-                              conf->logical_block_size);
+
+    xen_block_set_size(blockdev);
 
     blockdev->dataplane =
         xen_block_dataplane_create(xendev, conf, blockdev->props.iothread);
diff --git a/hw/i2c/smbus_eeprom.c b/hw/i2c/smbus_eeprom.c
index f18aa3de35..01b9439014 100644
--- a/hw/i2c/smbus_eeprom.c
+++ b/hw/i2c/smbus_eeprom.c
@@ -23,6 +23,8 @@
  */
 
 #include "qemu/osdep.h"
+#include "qemu/units.h"
+#include "qapi/error.h"
 #include "hw/hw.h"
 #include "hw/i2c/i2c.h"
 #include "hw/i2c/smbus.h"
@@ -162,3 +164,130 @@ void smbus_eeprom_init(I2CBus *smbus, int nb_eeprom,
         smbus_eeprom_init_one(smbus, 0x50 + i, eeprom_buf + (i * 256));
     }
 }
+
+/* Generate SDRAM SPD EEPROM data describing a module of type and size */
+uint8_t *spd_data_generate(enum sdram_type type, ram_addr_t ram_size,
+                           Error **errp)
+{
+    uint8_t *spd;
+    uint8_t nbanks;
+    uint16_t density;
+    uint32_t size;
+    int min_log2, max_log2, sz_log2;
+    int i;
+
+    switch (type) {
+    case SDR:
+        min_log2 = 2;
+        max_log2 = 9;
+        break;
+    case DDR:
+        min_log2 = 5;
+        max_log2 = 12;
+        break;
+    case DDR2:
+        min_log2 = 7;
+        max_log2 = 14;
+        break;
+    default:
+        g_assert_not_reached();
+    }
+    size = ram_size >> 20; /* work in terms of megabytes */
+    if (size < 4) {
+        error_setg(errp, "SDRAM size is too small");
+        return NULL;
+    }
+    sz_log2 = 31 - clz32(size);
+    size = 1U << sz_log2;
+    if (ram_size > size * MiB) {
+        error_setg(errp, "SDRAM size 0x"RAM_ADDR_FMT" is not a power of 2, "
+                   "truncating to %u MB", ram_size, size);
+    }
+    if (sz_log2 < min_log2) {
+        error_setg(errp,
+                   "Memory size is too small for SDRAM type, adjusting type");
+        if (size >= 32) {
+            type = DDR;
+            min_log2 = 5;
+            max_log2 = 12;
+        } else {
+            type = SDR;
+            min_log2 = 2;
+            max_log2 = 9;
+        }
+    }
+
+    nbanks = 1;
+    while (sz_log2 > max_log2 && nbanks < 8) {
+        sz_log2--;
+        nbanks++;
+    }
+
+    if (size > (1ULL << sz_log2) * nbanks) {
+        error_setg(errp, "Memory size is too big for SDRAM, truncating");
+    }
+
+    /* split to 2 banks if possible to avoid a bug in MIPS Malta firmware */
+    if (nbanks == 1 && sz_log2 > min_log2) {
+        sz_log2--;
+        nbanks++;
+    }
+
+    density = 1ULL << (sz_log2 - 2);
+    switch (type) {
+    case DDR2:
+        density = (density & 0xe0) | (density >> 8 & 0x1f);
+        break;
+    case DDR:
+        density = (density & 0xf8) | (density >> 8 & 0x07);
+        break;
+    case SDR:
+    default:
+        density &= 0xff;
+        break;
+    }
+
+    spd = g_malloc0(256);
+    spd[0] = 128;   /* data bytes in EEPROM */
+    spd[1] = 8;     /* log2 size of EEPROM */
+    spd[2] = type;
+    spd[3] = 13;    /* row address bits */
+    spd[4] = 10;    /* column address bits */
+    spd[5] = (type == DDR2 ? nbanks - 1 : nbanks);
+    spd[6] = 64;    /* module data width */
+                    /* reserved / data width high */
+    spd[8] = 4;     /* interface voltage level */
+    spd[9] = 0x25;  /* highest CAS latency */
+    spd[10] = 1;    /* access time */
+                    /* DIMM configuration 0 = non-ECC */
+    spd[12] = 0x82; /* refresh requirements */
+    spd[13] = 8;    /* primary SDRAM width */
+                    /* ECC SDRAM width */
+    spd[15] = (type == DDR2 ? 0 : 1); /* reserved / delay for random col rd */
+    spd[16] = 12;   /* burst lengths supported */
+    spd[17] = 4;    /* banks per SDRAM device */
+    spd[18] = 12;   /* ~CAS latencies supported */
+    spd[19] = (type == DDR2 ? 0 : 1); /* reserved / ~CS latencies supported */
+    spd[20] = 2;    /* DIMM type / ~WE latencies */
+                    /* module features */
+                    /* memory chip features */
+    spd[23] = 0x12; /* clock cycle time @ medium CAS latency */
+                    /* data access time */
+                    /* clock cycle time @ short CAS latency */
+                    /* data access time */
+    spd[27] = 20;   /* min. row precharge time */
+    spd[28] = 15;   /* min. row active row delay */
+    spd[29] = 20;   /* min. ~RAS to ~CAS delay */
+    spd[30] = 45;   /* min. active to precharge time */
+    spd[31] = density;
+    spd[32] = 20;   /* addr/cmd setup time */
+    spd[33] = 8;    /* addr/cmd hold time */
+    spd[34] = 20;   /* data input setup time */
+    spd[35] = 8;    /* data input hold time */
+
+    /* checksum */
+    for (i = 0; i < 63; i++) {
+        spd[63] += spd[i];
+    }
+    return spd;
+}
diff --git a/hw/intc/spapr_xive.c b/hw/intc/spapr_xive.c
index d391177ab8..a0f5ff9294 100644
--- a/hw/intc/spapr_xive.c
+++ b/hw/intc/spapr_xive.c
@@ -16,6 +16,7 @@
 #include "monitor/monitor.h"
 #include "hw/ppc/fdt.h"
 #include "hw/ppc/spapr.h"
+#include "hw/ppc/spapr_cpu_core.h"
 #include "hw/ppc/spapr_xive.h"
 #include "hw/ppc/xive.h"
 #include "hw/ppc/xive_regs.h"
@@ -390,6 +391,13 @@ static int spapr_xive_write_nvt(XiveRouter *xrtr, uint8_t nvt_blk,
     g_assert_not_reached();
 }
 
+static XiveTCTX *spapr_xive_get_tctx(XiveRouter *xrtr, CPUState *cs)
+{
+    PowerPCCPU *cpu = POWERPC_CPU(cs);
+
+    return spapr_cpu_state(cpu)->tctx;
+}
+
 static const VMStateDescription vmstate_spapr_xive_end = {
     .name = TYPE_SPAPR_XIVE "/end",
     .version_id = 1,
@@ -454,6 +462,7 @@ static void spapr_xive_class_init(ObjectClass *klass, void *data)
     xrc->write_end = spapr_xive_write_end;
     xrc->get_nvt = spapr_xive_get_nvt;
     xrc->write_nvt = spapr_xive_write_nvt;
+    xrc->get_tctx = spapr_xive_get_tctx;
 }
 
 static const TypeInfo spapr_xive_info = {
diff --git a/hw/intc/xics_spapr.c b/hw/intc/xics_spapr.c
index de6cc15b64..e2d8b38183 100644
--- a/hw/intc/xics_spapr.c
+++ b/hw/intc/xics_spapr.c
@@ -31,6 +31,7 @@
 #include "trace.h"
 #include "qemu/timer.h"
 #include "hw/ppc/spapr.h"
+#include "hw/ppc/spapr_cpu_core.h"
 #include "hw/ppc/xics.h"
 #include "hw/ppc/xics_spapr.h"
 #include "hw/ppc/fdt.h"
@@ -45,7 +46,7 @@ static target_ulong h_cppr(PowerPCCPU *cpu, sPAPRMachineState *spapr,
 {
     target_ulong cppr = args[0];
 
-    icp_set_cppr(cpu->icp, cppr);
+    icp_set_cppr(spapr_cpu_state(cpu)->icp, cppr);
     return H_SUCCESS;
 }
 
@@ -66,7 +67,7 @@ static target_ulong h_ipi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
 static target_ulong h_xirr(PowerPCCPU *cpu, sPAPRMachineState *spapr,
                            target_ulong opcode, target_ulong *args)
 {
-    uint32_t xirr = icp_accept(cpu->icp);
+    uint32_t xirr = icp_accept(spapr_cpu_state(cpu)->icp);
 
     args[0] = xirr;
     return H_SUCCESS;
@@ -75,7 +76,7 @@ static target_ulong h_xirr(PowerPCCPU *cpu, sPAPRMachineState *spapr,
 static target_ulong h_xirr_x(PowerPCCPU *cpu, sPAPRMachineState *spapr,
                              target_ulong opcode, target_ulong *args)
 {
-    uint32_t xirr = icp_accept(cpu->icp);
+    uint32_t xirr = icp_accept(spapr_cpu_state(cpu)->icp);
 
     args[0] = xirr;
     args[1] = cpu_get_host_ticks();
@@ -87,7 +88,7 @@ static target_ulong h_eoi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
 {
     target_ulong xirr = args[0];
 
-    icp_eoi(cpu->icp, xirr);
+    icp_eoi(spapr_cpu_state(cpu)->icp, xirr);
     return H_SUCCESS;
 }
 
@@ -95,7 +96,7 @@ static target_ulong h_ipoll(PowerPCCPU *cpu, sPAPRMachineState *spapr,
                             target_ulong opcode, target_ulong *args)
 {
     uint32_t mfrr;
-    uint32_t xirr = icp_ipoll(cpu->icp, &mfrr);
+    uint32_t xirr = icp_ipoll(spapr_cpu_state(cpu)->icp, &mfrr);
 
     args[0] = xirr;
     args[1] = mfrr;
diff --git a/hw/intc/xive.c b/hw/intc/xive.c
index a3cb0cf0e3..2e9b8efd43 100644
--- a/hw/intc/xive.c
+++ b/hw/intc/xive.c
@@ -320,8 +320,7 @@ static const XiveTmOp *xive_tm_find_op(hwaddr offset, unsigned size, bool write)
 static void xive_tm_write(void *opaque, hwaddr offset,
                           uint64_t value, unsigned size)
 {
-    PowerPCCPU *cpu = POWERPC_CPU(current_cpu);
-    XiveTCTX *tctx = cpu->tctx;
+    XiveTCTX *tctx = xive_router_get_tctx(XIVE_ROUTER(opaque), current_cpu);
     const XiveTmOp *xto;
 
     /*
@@ -359,8 +358,7 @@ static void xive_tm_write(void *opaque, hwaddr offset,
 
 static uint64_t xive_tm_read(void *opaque, hwaddr offset, unsigned size)
 {
-    PowerPCCPU *cpu = POWERPC_CPU(current_cpu);
-    XiveTCTX *tctx = cpu->tctx;
+    XiveTCTX *tctx = xive_router_get_tctx(XIVE_ROUTER(opaque), current_cpu);
     const XiveTmOp *xto;
 
     /*
@@ -1107,6 +1105,13 @@ int xive_router_write_nvt(XiveRouter *xrtr, uint8_t nvt_blk, uint32_t nvt_idx,
    return xrc->write_nvt(xrtr, nvt_blk, nvt_idx, nvt, word_number);
 }
 
+XiveTCTX *xive_router_get_tctx(XiveRouter *xrtr, CPUState *cs)
+{
+    XiveRouterClass *xrc = XIVE_ROUTER_GET_CLASS(xrtr);
+
+    return xrc->get_tctx(xrtr, cs);
+}
+
 /*
  * The thread context register words are in big-endian format.
  */
@@ -1182,8 +1187,7 @@ static bool xive_presenter_match(XiveRouter *xrtr, uint8_t format,
      */
 
     CPU_FOREACH(cs) {
-        PowerPCCPU *cpu = POWERPC_CPU(cs);
-        XiveTCTX *tctx = cpu->tctx;
+        XiveTCTX *tctx = xive_router_get_tctx(xrtr, cs);
         int ring;
 
         /*
@@ -1576,9 +1580,9 @@ static const TypeInfo xive_end_source_info = {
 };
 
 /*
- * XIVE Fabric
+ * XIVE Notifier
  */
-static const TypeInfo xive_fabric_info = {
+static const TypeInfo xive_notifier_info = {
     .name = TYPE_XIVE_NOTIFIER,
     .parent = TYPE_INTERFACE,
     .class_size = sizeof(XiveNotifierClass),
@@ -1587,7 +1591,7 @@ static const TypeInfo xive_fabric_info = {
 static void xive_register_types(void)
 {
     type_register_static(&xive_source_info);
-    type_register_static(&xive_fabric_info);
+    type_register_static(&xive_notifier_info);
     type_register_static(&xive_router_info);
     type_register_static(&xive_end_source_info);
     type_register_static(&xive_tctx_info);
diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs
index 4e0c1c0941..1e753de09b 100644
--- a/hw/ppc/Makefile.objs
+++ b/hw/ppc/Makefile.objs
@@ -13,8 +13,7 @@ obj-y += spapr_pci_vfio.o
 endif
 obj-$(CONFIG_PSERIES) += spapr_rtas_ddw.o
 # PowerPC 4xx boards
-obj-y += ppc4xx_devs.o ppc405_uc.o
-obj-$(CONFIG_PPC4XX) += ppc4xx_pci.o ppc405_boards.o
+obj-$(CONFIG_PPC4XX) += ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o
 obj-$(CONFIG_PPC4XX) += ppc440_bamboo.o ppc440_pcix.o ppc440_uc.o
 obj-$(CONFIG_SAM460EX) += sam460ex.o
 # PReP
diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c
index bb19eaba36..f1c8400efd 100644
--- a/hw/ppc/mac_newworld.c
+++ b/hw/ppc/mac_newworld.c
@@ -53,7 +53,6 @@
 #include "hw/ppc/mac.h"
 #include "hw/input/adb.h"
 #include "hw/ppc/mac_dbdma.h"
-#include "hw/timer/m48t59.h"
 #include "hw/pci/pci.h"
 #include "net/net.h"
 #include "sysemu/sysemu.h"
diff --git a/hw/ppc/mac_oldworld.c b/hw/ppc/mac_oldworld.c
index 817f70e52c..98d531d114 100644
--- a/hw/ppc/mac_oldworld.c
+++ b/hw/ppc/mac_oldworld.c
@@ -30,7 +30,6 @@
 #include "hw/ppc/ppc.h"
 #include "mac.h"
 #include "hw/input/adb.h"
-#include "hw/timer/m48t59.h"
 #include "sysemu/sysemu.h"
 #include "net/net.h"
 #include "hw/isa/isa.h"
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index d84acef55b..da540860a2 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -673,6 +673,7 @@ static void pnv_chip_power8_intc_create(PnvChip *chip, PowerPCCPU *cpu,
 {
     Error *local_err = NULL;
     Object *obj;
+    PnvCPUState *pnv_cpu = pnv_cpu_state(cpu);
 
     obj = icp_create(OBJECT(cpu), TYPE_PNV_ICP, XICS_FABRIC(qdev_get_machine()),
                      &local_err);
@@ -681,7 +682,7 @@ static void pnv_chip_power8_intc_create(PnvChip *chip, PowerPCCPU *cpu,
         return;
     }
 
-    cpu->icp = ICP(obj);
+    pnv_cpu->icp = ICP(obj);
 }
 
 /*
@@ -1099,7 +1100,7 @@ static ICPState *pnv_icp_get(XICSFabric *xi, int pir)
 {
     PowerPCCPU *cpu = ppc_get_vcpu_by_pir(pir);
 
-    return cpu ? cpu->icp : NULL;
+    return cpu ? pnv_cpu_state(cpu)->icp : NULL;
 }
 
 static void pnv_pic_print_info(InterruptStatsProvider *obj,
@@ -1112,7 +1113,7 @@ static void pnv_pic_print_info(InterruptStatsProvider *obj,
     CPU_FOREACH(cs) {
         PowerPCCPU *cpu = POWERPC_CPU(cs);
 
-        icp_pic_print_info(cpu->icp, mon);
+        icp_pic_print_info(pnv_cpu_state(cpu)->icp, mon);
     }
 
     for (i = 0; i < pnv->num_chips; i++) {
diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c
index b98f277f1e..7c806da720 100644
--- a/hw/ppc/pnv_core.c
+++ b/hw/ppc/pnv_core.c
@@ -155,7 +155,10 @@ static void pnv_core_realize(DeviceState *dev, Error **errp)
 
     pc->threads = g_new(PowerPCCPU *, cc->nr_threads);
     for (i = 0; i < cc->nr_threads; i++) {
+        PowerPCCPU *cpu;
+
         obj = object_new(typename);
+        cpu = POWERPC_CPU(obj);
 
         pc->threads[i] = POWERPC_CPU(obj);
 
@@ -163,6 +166,9 @@ static void pnv_core_realize(DeviceState *dev, Error **errp)
         object_property_add_child(OBJECT(pc), name, obj, &error_abort);
         object_property_add_alias(obj, "core-pir", OBJECT(pc),
                                   "pir", &error_abort);
+
+        cpu->machine_data = g_new0(PnvCPUState, 1);
+
         object_unref(obj);
     }
 
@@ -189,9 +195,13 @@ err:
 
 static void pnv_unrealize_vcpu(PowerPCCPU *cpu)
 {
+    PnvCPUState *pnv_cpu = pnv_cpu_state(cpu);
+
     qemu_unregister_reset(pnv_cpu_reset, cpu);
-    object_unparent(OBJECT(cpu->icp));
+    object_unparent(OBJECT(pnv_cpu_state(cpu)->icp));
     cpu_remove_sync(CPU(cpu));
+    cpu->machine_data = NULL;
+    g_free(pnv_cpu);
     object_unparent(OBJECT(cpu));
 }
 
diff --git a/hw/ppc/ppc.c b/hw/ppc/ppc.c
index ec4be25f49..cffdc3914a 100644
--- a/hw/ppc/ppc.c
+++ b/hw/ppc/ppc.c
@@ -30,10 +30,8 @@
 #include "qemu/timer.h"
 #include "sysemu/sysemu.h"
 #include "sysemu/cpus.h"
-#include "hw/timer/m48t59.h"
 #include "qemu/log.h"
 #include "qemu/error-report.h"
-#include "hw/loader.h"
 #include "sysemu/kvm.h"
 #include "kvm_ppc.h"
 #include "trace.h"
@@ -310,6 +308,62 @@ void ppcPOWER7_irq_init(PowerPCCPU *cpu)
 }
 #endif /* defined(TARGET_PPC64) */
 
+void ppc40x_core_reset(PowerPCCPU *cpu)
+{
+    CPUPPCState *env = &cpu->env;
+    target_ulong dbsr;
+
+    qemu_log_mask(CPU_LOG_RESET, "Reset PowerPC core\n");
+    cpu_interrupt(CPU(cpu), CPU_INTERRUPT_RESET);
+    dbsr = env->spr[SPR_40x_DBSR];
+    dbsr &= ~0x00000300;
+    dbsr |= 0x00000100;
+    env->spr[SPR_40x_DBSR] = dbsr;
+}
+
+void ppc40x_chip_reset(PowerPCCPU *cpu)
+{
+    CPUPPCState *env = &cpu->env;
+    target_ulong dbsr;
+
+    qemu_log_mask(CPU_LOG_RESET, "Reset PowerPC chip\n");
+    cpu_interrupt(CPU(cpu), CPU_INTERRUPT_RESET);
+    /* XXX: TODO reset all internal peripherals */
+    dbsr = env->spr[SPR_40x_DBSR];
+    dbsr &= ~0x00000300;
+    dbsr |= 0x00000200;
+    env->spr[SPR_40x_DBSR] = dbsr;
+}
+
+void ppc40x_system_reset(PowerPCCPU *cpu)
+{
+    qemu_log_mask(CPU_LOG_RESET, "Reset PowerPC system\n");
+    qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
+}
+
+void store_40x_dbcr0(CPUPPCState *env, uint32_t val)
+{
+    PowerPCCPU *cpu = ppc_env_get_cpu(env);
+
+    switch ((val >> 28) & 0x3) {
+    case 0x0:
+        /* No action */
+        break;
+    case 0x1:
+        /* Core reset */
+        ppc40x_core_reset(cpu);
+        break;
+    case 0x2:
+        /* Chip reset */
+        ppc40x_chip_reset(cpu);
+        break;
+    case 0x3:
+        /* System reset */
+        ppc40x_system_reset(cpu);
+        break;
+    }
+}
+
 /* PowerPC 40x internal IRQ controller */
 static void ppc40x_set_irq(void *opaque, int pin, int level)
 {
diff --git a/hw/ppc/ppc405_uc.c b/hw/ppc/ppc405_uc.c
index 8d3a797cb8..3ae7f6d4df 100644
--- a/hw/ppc/ppc405_uc.c
+++ b/hw/ppc/ppc405_uc.c
@@ -1156,64 +1156,6 @@ static void ppc4xx_gpt_init(hwaddr base, qemu_irq irqs[5])
 }
 
 /*****************************************************************************/
-/* SPR */
-void ppc40x_core_reset(PowerPCCPU *cpu)
-{
-    CPUPPCState *env = &cpu->env;
-    target_ulong dbsr;
-
-    printf("Reset PowerPC core\n");
-    cpu_interrupt(CPU(cpu), CPU_INTERRUPT_RESET);
-    dbsr = env->spr[SPR_40x_DBSR];
-    dbsr &= ~0x00000300;
-    dbsr |= 0x00000100;
-    env->spr[SPR_40x_DBSR] = dbsr;
-}
-
-void ppc40x_chip_reset(PowerPCCPU *cpu)
-{
-    CPUPPCState *env = &cpu->env;
-    target_ulong dbsr;
-
-    printf("Reset PowerPC chip\n");
-    cpu_interrupt(CPU(cpu), CPU_INTERRUPT_RESET);
-    /* XXX: TODO reset all internal peripherals */
-    dbsr = env->spr[SPR_40x_DBSR];
-    dbsr &= ~0x00000300;
-    dbsr |= 0x00000200;
-    env->spr[SPR_40x_DBSR] = dbsr;
-}
-
-void ppc40x_system_reset(PowerPCCPU *cpu)
-{
-    printf("Reset PowerPC system\n");
-    qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
-}
-
-void store_40x_dbcr0 (CPUPPCState *env, uint32_t val)
-{
-    PowerPCCPU *cpu = ppc_env_get_cpu(env);
-
-    switch ((val >> 28) & 0x3) {
-    case 0x0:
-        /* No action */
-        break;
-    case 0x1:
-        /* Core reset */
-        ppc40x_core_reset(cpu);
-        break;
-    case 0x2:
-        /* Chip reset */
-        ppc40x_chip_reset(cpu);
-        break;
-    case 0x3:
-        /* System reset */
-        ppc40x_system_reset(cpu);
-        break;
-    }
-}
-
-/*****************************************************************************/
 /* PowerPC 405CR */
 enum {
     PPC405CR_CPC0_PLLMR  = 0x0B0,
diff --git a/hw/ppc/ppc440_bamboo.c b/hw/ppc/ppc440_bamboo.c
index fc06191588..4b547eaf77 100644
--- a/hw/ppc/ppc440_bamboo.c
+++ b/hw/ppc/ppc440_bamboo.c
@@ -49,7 +49,7 @@
 
 #define PPC440EP_SDRAM_NR_BANKS 4
 
-static const unsigned int ppc440ep_sdram_bank_sizes[] = {
+static const ram_addr_t ppc440ep_sdram_bank_sizes[] = {
     256 * MiB, 128 * MiB, 64 * MiB, 32 * MiB, 16 * MiB, 8 * MiB, 0
 };
 
diff --git a/hw/ppc/ppc440_uc.c b/hw/ppc/ppc440_uc.c
index 9360f781ce..9130eb314c 100644
--- a/hw/ppc/ppc440_uc.c
+++ b/hw/ppc/ppc440_uc.c
@@ -2,7 +2,7 @@
  * QEMU PowerPC 440 embedded processors emulation
  *
  * Copyright (c) 2012 François Revol
- * Copyright (c) 2016-2018 BALATON Zoltan
+ * Copyright (c) 2016-2019 BALATON Zoltan
  *
  * This work is licensed under the GNU GPL license version 2 or later.
  *
@@ -481,7 +481,7 @@ void ppc4xx_sdr_init(CPUPPCState *env)
 
 /*****************************************************************************/
 /* SDRAM controller */
-typedef struct ppc4xx_sdram_t {
+typedef struct ppc440_sdram_t {
     uint32_t addr;
     int nbanks;
     MemoryRegion containers[4]; /* used for clipping */
@@ -489,7 +489,7 @@ typedef struct ppc4xx_sdram_t {
     hwaddr ram_bases[4];
     hwaddr ram_sizes[4];
     uint32_t bcr[4];
-} ppc4xx_sdram_t;
+} ppc440_sdram_t;
 
 enum {
     SDRAM0_CFGADDR = 0x10,
@@ -505,10 +505,6 @@ enum {
     SDRAM_PLBADDUHB = 0x50,
 };
 
-/* XXX: TOFIX: some patches have made this code become inconsistent:
- *      there are type inconsistencies, mixing hwaddr, target_ulong
- *      and uint32_t
- */
 static uint32_t sdram_bcr(hwaddr ram_base, hwaddr ram_size)
 {
     uint32_t bcr;
@@ -538,11 +534,17 @@ static uint32_t sdram_bcr(hwaddr ram_base, hwaddr ram_size)
     case (1 * GiB):
         bcr = 0xe000;
         break;
+    case (2 * GiB):
+        bcr = 0xc000;
+        break;
+    case (4 * GiB):
+        bcr = 0x8000;
+        break;
     default:
         error_report("invalid RAM size " TARGET_FMT_plx, ram_size);
         return 0;
     }
-    bcr |= ram_base & 0xFF800000;
+    bcr |= ram_base >> 2 & 0xffe00000;
     bcr |= 1;
 
     return bcr;
@@ -550,12 +552,12 @@ static uint32_t sdram_bcr(hwaddr ram_base, hwaddr ram_size)
 
 static inline hwaddr sdram_base(uint32_t bcr)
 {
-    return bcr & 0xFF800000;
+    return (bcr & 0xffe00000) << 2;
 }
 
-static target_ulong sdram_size(uint32_t bcr)
+static uint64_t sdram_size(uint32_t bcr)
 {
-    target_ulong size;
+    uint64_t size;
     int sh;
 
     sh = 1024 - ((bcr >> 6) & 0x3ff);
@@ -564,50 +566,46 @@ static target_ulong sdram_size(uint32_t bcr)
     return size;
 }
 
-static void sdram_set_bcr(ppc4xx_sdram_t *sdram,
-                          uint32_t *bcrp, uint32_t bcr, int enabled)
+static void sdram_set_bcr(ppc440_sdram_t *sdram, int i,
+                          uint32_t bcr, int enabled)
 {
-    unsigned n = bcrp - sdram->bcr;
-
-    if (*bcrp & 1) {
-        /* Unmap RAM */
+    if (sdram->bcr[i] & 1) {
+        /* First unmap RAM if enabled */
         memory_region_del_subregion(get_system_memory(),
-                                    &sdram->containers[n]);
-        memory_region_del_subregion(&sdram->containers[n],
-                                    &sdram->ram_memories[n]);
-        object_unparent(OBJECT(&sdram->containers[n]));
+                                    &sdram->containers[i]);
+        memory_region_del_subregion(&sdram->containers[i],
+                                    &sdram->ram_memories[i]);
+        object_unparent(OBJECT(&sdram->containers[i]));
     }
-    *bcrp = bcr & 0xFFDEE001;
+    sdram->bcr[i] = bcr & 0xffe0ffc1;
     if (enabled && (bcr & 1)) {
-        memory_region_init(&sdram->containers[n], NULL, "sdram-containers",
+        memory_region_init(&sdram->containers[i], NULL, "sdram-containers",
                            sdram_size(bcr));
-        memory_region_add_subregion(&sdram->containers[n], 0,
-                                    &sdram->ram_memories[n]);
+        memory_region_add_subregion(&sdram->containers[i], 0,
+                                    &sdram->ram_memories[i]);
         memory_region_add_subregion(get_system_memory(),
                                     sdram_base(bcr),
-                                    &sdram->containers[n]);
+                                    &sdram->containers[i]);
     }
 }
 
-static void sdram_map_bcr(ppc4xx_sdram_t *sdram)
+static void sdram_map_bcr(ppc440_sdram_t *sdram)
 {
     int i;
 
     for (i = 0; i < sdram->nbanks; i++) {
         if (sdram->ram_sizes[i] != 0) {
-            sdram_set_bcr(sdram,
-                          &sdram->bcr[i],
-                          sdram_bcr(sdram->ram_bases[i], sdram->ram_sizes[i]),
-                          1);
+            sdram_set_bcr(sdram, i, sdram_bcr(sdram->ram_bases[i],
+                                              sdram->ram_sizes[i]), 1);
         } else {
-            sdram_set_bcr(sdram, &sdram->bcr[i], 0, 0);
+            sdram_set_bcr(sdram, i, 0, 0);
         }
     }
 }
 
 static uint32_t dcr_read_sdram(void *opaque, int dcrn)
 {
-    ppc4xx_sdram_t *sdram = opaque;
+    ppc440_sdram_t *sdram = opaque;
     uint32_t ret = 0;
 
     switch (dcrn) {
@@ -615,8 +613,10 @@ static uint32_t dcr_read_sdram(void *opaque, int dcrn)
     case SDRAM_R1BAS:
     case SDRAM_R2BAS:
     case SDRAM_R3BAS:
-        ret = sdram_bcr(sdram->ram_bases[dcrn - SDRAM_R0BAS],
-                        sdram->ram_sizes[dcrn - SDRAM_R0BAS]);
+        if (sdram->ram_sizes[dcrn - SDRAM_R0BAS]) {
+            ret = sdram_bcr(sdram->ram_bases[dcrn - SDRAM_R0BAS],
+                            sdram->ram_sizes[dcrn - SDRAM_R0BAS]);
+        }
         break;
     case SDRAM_CONF1HB:
     case SDRAM_CONF1LL:
@@ -658,7 +658,7 @@ static uint32_t dcr_read_sdram(void *opaque, int dcrn)
 
 static void dcr_write_sdram(void *opaque, int dcrn, uint32_t val)
 {
-    ppc4xx_sdram_t *sdram = opaque;
+    ppc440_sdram_t *sdram = opaque;
 
     switch (dcrn) {
     case SDRAM_R0BAS:
@@ -689,7 +689,7 @@ static void dcr_write_sdram(void *opaque, int dcrn, uint32_t val)
 
 static void sdram_reset(void *opaque)
 {
-    ppc4xx_sdram_t *sdram = opaque;
+    ppc440_sdram_t *sdram = opaque;
 
     sdram->addr = 0;
 }
@@ -699,7 +699,7 @@ void ppc440_sdram_init(CPUPPCState *env, int nbanks,
                        hwaddr *ram_bases, hwaddr *ram_sizes,
                        int do_init)
 {
-    ppc4xx_sdram_t *sdram;
+    ppc440_sdram_t *sdram;
 
     sdram = g_malloc0(sizeof(*sdram));
     sdram->nbanks = nbanks;
diff --git a/hw/ppc/ppc4xx_devs.c b/hw/ppc/ppc4xx_devs.c
index 9b6e4c60fa..fdfeb67e65 100644
--- a/hw/ppc/ppc4xx_devs.c
+++ b/hw/ppc/ppc4xx_devs.c
@@ -405,36 +405,34 @@ static target_ulong sdram_size (uint32_t bcr)
     return size;
 }
 
-static void sdram_set_bcr(ppc4xx_sdram_t *sdram,
-                          uint32_t *bcrp, uint32_t bcr, int enabled)
+static void sdram_set_bcr(ppc4xx_sdram_t *sdram, int i,
+                          uint32_t bcr, int enabled)
 {
-    unsigned n = bcrp - sdram->bcr;
-
-    if (*bcrp & 0x00000001) {
+    if (sdram->bcr[i] & 0x00000001) {
         /* Unmap RAM */
 #ifdef DEBUG_SDRAM
         printf("%s: unmap RAM area " TARGET_FMT_plx " " TARGET_FMT_lx "\n",
-               __func__, sdram_base(*bcrp), sdram_size(*bcrp));
+               __func__, sdram_base(sdram->bcr[i]), sdram_size(sdram->bcr[i]));
 #endif
         memory_region_del_subregion(get_system_memory(),
-                                    &sdram->containers[n]);
-        memory_region_del_subregion(&sdram->containers[n],
-                                    &sdram->ram_memories[n]);
-        object_unparent(OBJECT(&sdram->containers[n]));
+                                    &sdram->containers[i]);
+        memory_region_del_subregion(&sdram->containers[i],
+                                    &sdram->ram_memories[i]);
+        object_unparent(OBJECT(&sdram->containers[i]));
     }
-    *bcrp = bcr & 0xFFDEE001;
+    sdram->bcr[i] = bcr & 0xFFDEE001;
     if (enabled && (bcr & 0x00000001)) {
 #ifdef DEBUG_SDRAM
         printf("%s: Map RAM area " TARGET_FMT_plx " " TARGET_FMT_lx "\n",
                __func__, sdram_base(bcr), sdram_size(bcr));
 #endif
-        memory_region_init(&sdram->containers[n], NULL, "sdram-containers",
+        memory_region_init(&sdram->containers[i], NULL, "sdram-containers",
                            sdram_size(bcr));
-        memory_region_add_subregion(&sdram->containers[n], 0,
-                                    &sdram->ram_memories[n]);
+        memory_region_add_subregion(&sdram->containers[i], 0,
+                                    &sdram->ram_memories[i]);
         memory_region_add_subregion(get_system_memory(),
                                     sdram_base(bcr),
-                                    &sdram->containers[n]);
+                                    &sdram->containers[i]);
     }
 }
 
@@ -444,12 +442,10 @@ static void sdram_map_bcr (ppc4xx_sdram_t *sdram)
 
     for (i = 0; i < sdram->nbanks; i++) {
         if (sdram->ram_sizes[i] != 0) {
-            sdram_set_bcr(sdram,
-                          &sdram->bcr[i],
-                          sdram_bcr(sdram->ram_bases[i], sdram->ram_sizes[i]),
-                          1);
+            sdram_set_bcr(sdram, i, sdram_bcr(sdram->ram_bases[i],
+                                              sdram->ram_sizes[i]), 1);
         } else {
-            sdram_set_bcr(sdram, &sdram->bcr[i], 0x00000000, 0);
+            sdram_set_bcr(sdram, i, 0x00000000, 0);
         }
     }
 }
@@ -589,16 +585,16 @@ static void dcr_write_sdram (void *opaque, int dcrn, uint32_t val)
             sdram->pmit = (val & 0xF8000000) | 0x07C00000;
             break;
         case 0x40: /* SDRAM_B0CR */
-            sdram_set_bcr(sdram, &sdram->bcr[0], val, sdram->cfg & 0x80000000);
+            sdram_set_bcr(sdram, 0, val, sdram->cfg & 0x80000000);
             break;
         case 0x44: /* SDRAM_B1CR */
-            sdram_set_bcr(sdram, &sdram->bcr[1], val, sdram->cfg & 0x80000000);
+            sdram_set_bcr(sdram, 1, val, sdram->cfg & 0x80000000);
             break;
         case 0x48: /* SDRAM_B2CR */
-            sdram_set_bcr(sdram, &sdram->bcr[2], val, sdram->cfg & 0x80000000);
+            sdram_set_bcr(sdram, 2, val, sdram->cfg & 0x80000000);
             break;
         case 0x4C: /* SDRAM_B3CR */
-            sdram_set_bcr(sdram, &sdram->bcr[3], val, sdram->cfg & 0x80000000);
+            sdram_set_bcr(sdram, 3, val, sdram->cfg & 0x80000000);
             break;
         case 0x80: /* SDRAM_TR */
             sdram->tr = val & 0x018FC01F;
@@ -679,12 +675,12 @@ ram_addr_t ppc4xx_sdram_adjust(ram_addr_t ram_size, int nr_banks,
                                MemoryRegion ram_memories[],
                                hwaddr ram_bases[],
                                hwaddr ram_sizes[],
-                               const unsigned int sdram_bank_sizes[])
+                               const ram_addr_t sdram_bank_sizes[])
 {
     MemoryRegion *ram = g_malloc0(sizeof(*ram));
     ram_addr_t size_left = ram_size;
     ram_addr_t base = 0;
-    unsigned int bank_size;
+    ram_addr_t bank_size;
     int i;
     int j;
 
diff --git a/hw/ppc/ppc_booke.c b/hw/ppc/ppc_booke.c
index 23bcf1b138..4f11e00a17 100644
--- a/hw/ppc/ppc_booke.c
+++ b/hw/ppc/ppc_booke.c
@@ -28,7 +28,6 @@
 #include "hw/ppc/ppc.h"
 #include "qemu/timer.h"
 #include "sysemu/sysemu.h"
-#include "hw/timer/m48t59.h"
 #include "qemu/log.h"
 #include "hw/loader.h"
 #include "kvm_ppc.h"
diff --git a/hw/ppc/sam460ex.c b/hw/ppc/sam460ex.c
index 84ea592749..202ed14bcf 100644
--- a/hw/ppc/sam460ex.c
+++ b/hw/ppc/sam460ex.c
@@ -2,7 +2,7 @@
  * QEMU aCube Sam460ex board emulation
  *
  * Copyright (c) 2012 François Revol
- * Copyright (c) 2016-2018 BALATON Zoltan
+ * Copyright (c) 2016-2019 BALATON Zoltan
  *
  * This file is derived from hw/ppc440_bamboo.c,
  * the copyright for that material belongs to the original owners.
@@ -76,9 +76,11 @@
 #define UART_FREQ 11059200
 #define SDRAM_NR_BANKS 4
 
-/* FIXME: See u-boot.git 8ac41e, also fix in ppc440_uc.c */
-static const unsigned int ppc460ex_sdram_bank_sizes[] = {
-    1 * GiB, 512 * MiB, 256 * MiB, 128 * MiB, 64 * MiB, 32 * MiB, 0
+/* The SoC could also handle 4 GiB but firmware does not work with that. */
+/* Maybe it overflows a signed 32 bit number somewhere? */
+static const ram_addr_t ppc460ex_sdram_bank_sizes[] = {
+    2 * GiB, 1 * GiB, 512 * MiB, 256 * MiB, 128 * MiB, 64 * MiB,
+    32 * MiB, 0
 };
 
 struct boot_info {
@@ -87,135 +89,6 @@ struct boot_info {
     uint32_t entry;
 };
 
-/*****************************************************************************/
-/* SPD eeprom content from mips_malta.c */
-
-struct _eeprom24c0x_t {
-  uint8_t tick;
-  uint8_t address;
-  uint8_t command;
-  uint8_t ack;
-  uint8_t scl;
-  uint8_t sda;
-  uint8_t data;
-  uint8_t contents[256];
-};
-
-typedef struct _eeprom24c0x_t eeprom24c0x_t;
-
-static eeprom24c0x_t spd_eeprom = {
-    .contents = {
-        /* 00000000: */ 0x80, 0x08, 0xFF, 0x0D, 0x0A, 0xFF, 0x40, 0x00,
-        /* 00000008: */ 0x04, 0x75, 0x54, 0x00, 0x82, 0x08, 0x00, 0x01,
-        /* 00000010: */ 0x8F, 0x04, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00,
-        /* 00000018: */ 0x00, 0x00, 0x00, 0x14, 0x0F, 0x14, 0x2D, 0xFF,
-        /* 00000020: */ 0x15, 0x08, 0x15, 0x08, 0x00, 0x00, 0x00, 0x00,
-        /* 00000028: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        /* 00000030: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        /* 00000038: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0xD0,
-        /* 00000040: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        /* 00000048: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        /* 00000050: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        /* 00000058: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        /* 00000060: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        /* 00000068: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        /* 00000070: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        /* 00000078: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xF4,
-    },
-};
-
-static void generate_eeprom_spd(uint8_t *eeprom, ram_addr_t ram_size)
-{
-    enum { SDR = 0x4, DDR1 = 0x7, DDR2 = 0x8 } type;
-    uint8_t *spd = spd_eeprom.contents;
-    uint8_t nbanks = 0;
-    uint16_t density = 0;
-    int i;
-
-    /* work in terms of MB */
-    ram_size /= MiB;
-
-    while ((ram_size >= 4) && (nbanks <= 2)) {
-        int sz_log2 = MIN(31 - clz32(ram_size), 14);
-        nbanks++;
-        density |= 1 << (sz_log2 - 2);
-        ram_size -= 1 << sz_log2;
-    }
-
-    /* split to 2 banks if possible */
-    if ((nbanks == 1) && (density > 1)) {
-        nbanks++;
-        density >>= 1;
-    }
-
-    if (density & 0xff00) {
-        density = (density & 0xe0) | ((density >> 8) & 0x1f);
-        type = DDR2;
-    } else if (!(density & 0x1f)) {
-        type = DDR2;
-    } else {
-        type = SDR;
-    }
-
-    if (ram_size) {
-        warn_report("SPD cannot represent final " RAM_ADDR_FMT "MB"
-                    " of SDRAM", ram_size);
-    }
-
-    /* fill in SPD memory information */
-    spd[2] = type;
-    spd[5] = nbanks;
-    spd[31] = density;
-
-    /* XXX: this is totally random */
-    spd[9] = 0x10; /* CAS tcyc */
-    spd[18] = 0x20; /* CAS bit */
-    spd[23] = 0x10; /* CAS tcyc */
-    spd[25] = 0x10; /* CAS tcyc */
-
-    /* checksum */
-    spd[63] = 0;
-    for (i = 0; i < 63; i++) {
-        spd[63] += spd[i];
-    }
-
-    /* copy for SMBUS */
-    memcpy(eeprom, spd, sizeof(spd_eeprom.contents));
-}
-
-static void generate_eeprom_serial(uint8_t *eeprom)
-{
-    int i, pos = 0;
-    uint8_t mac[6] = { 0x00 };
-    uint8_t sn[5] = { 0x01, 0x23, 0x45, 0x67, 0x89 };
-
-    /* version */
-    eeprom[pos++] = 0x01;
-
-    /* count */
-    eeprom[pos++] = 0x02;
-
-    /* MAC address */
-    eeprom[pos++] = 0x01; /* MAC */
-    eeprom[pos++] = 0x06; /* length */
-    memcpy(&eeprom[pos], mac, sizeof(mac));
-    pos += sizeof(mac);
-
-    /* serial number */
-    eeprom[pos++] = 0x02; /* serial */
-    eeprom[pos++] = 0x05; /* length */
-    memcpy(&eeprom[pos], sn, sizeof(sn));
-    pos += sizeof(sn);
-
-    /* checksum */
-    eeprom[pos] = 0;
-    for (i = 0; i < pos; i++) {
-        eeprom[pos] += eeprom[i];
-    }
-}
-
-/*****************************************************************************/
-
 static int sam460ex_load_uboot(void)
 {
     DriveInfo *dinfo;
@@ -393,24 +266,23 @@ static void sam460ex_init(MachineState *machine)
     MemoryRegion *address_space_mem = get_system_memory();
     MemoryRegion *isa = g_new(MemoryRegion, 1);
     MemoryRegion *ram_memories = g_new(MemoryRegion, SDRAM_NR_BANKS);
-    hwaddr ram_bases[SDRAM_NR_BANKS];
-    hwaddr ram_sizes[SDRAM_NR_BANKS];
+    hwaddr ram_bases[SDRAM_NR_BANKS] = {0};
+    hwaddr ram_sizes[SDRAM_NR_BANKS] = {0};
     MemoryRegion *l2cache_ram = g_new(MemoryRegion, 1);
     qemu_irq *irqs, *uic[4];
     PCIBus *pci_bus;
     PowerPCCPU *cpu;
     CPUPPCState *env;
-    PPC4xxI2CState *i2c[2];
+    I2CBus *i2c;
     hwaddr entry = UBOOT_ENTRY;
     hwaddr loadaddr = LOAD_UIMAGE_LOADADDR_INVALID;
     target_long initrd_size = 0;
     DeviceState *dev;
     SysBusDevice *sbdev;
-    int success;
-    int i;
     struct boot_info *boot_info;
-    const size_t smbus_eeprom_size = 8 * 256;
-    uint8_t *smbus_eeprom_buf = g_malloc0(smbus_eeprom_size);
+    uint8_t *spd_data;
+    Error *err = NULL;
+    int success;
 
     cpu = POWERPC_CPU(cpu_create(machine->cpu_type));
     env = &cpu->env;
@@ -439,8 +311,6 @@ static void sam460ex_init(MachineState *machine)
     uic[3] = ppcuic_init(env, &uic[0][16], 0xf0, 0, 1);
 
     /* SDRAM controller */
-    memset(ram_bases, 0, sizeof(ram_bases));
-    memset(ram_sizes, 0, sizeof(ram_sizes));
     /* put all RAM on first bank because board has one slot
      * and firmware only checks that */
     machine->ram_size = ppc4xx_sdram_adjust(machine->ram_size, 1,
@@ -451,23 +321,22 @@ static void sam460ex_init(MachineState *machine)
     ppc440_sdram_init(env, SDRAM_NR_BANKS, ram_memories,
                       ram_bases, ram_sizes, 1);
 
-    /* generate SPD EEPROM data */
-    for (i = 0; i < SDRAM_NR_BANKS; i++) {
-        generate_eeprom_spd(&smbus_eeprom_buf[i * 256], ram_sizes[i]);
-    }
-    generate_eeprom_serial(&smbus_eeprom_buf[4 * 256]);
-    generate_eeprom_serial(&smbus_eeprom_buf[6 * 256]);
-
-    /* IIC controllers */
+    /* IIC controllers and devices */
     dev = sysbus_create_simple(TYPE_PPC4xx_I2C, 0x4ef600700, uic[0][2]);
-    i2c[0] = PPC4xx_I2C(dev);
-    object_property_set_bool(OBJECT(dev), true, "realized", NULL);
-    smbus_eeprom_init(i2c[0]->bus, 8, smbus_eeprom_buf, smbus_eeprom_size);
-    g_free(smbus_eeprom_buf);
-    i2c_create_slave(i2c[0]->bus, "m41t80", 0x68);
+    i2c = PPC4xx_I2C(dev)->bus;
+    /* SPD EEPROM on RAM module */
+    spd_data = spd_data_generate(DDR2, ram_sizes[0], &err);
+    if (err) {
+        warn_report_err(err);
+    }
+    if (spd_data) {
+        spd_data[20] = 4; /* SO-DIMM module */
+        smbus_eeprom_init_one(i2c, 0x50, spd_data);
+    }
+    /* RTC */
+    i2c_create_slave(i2c, "m41t80", 0x68);
 
     dev = sysbus_create_simple(TYPE_PPC4xx_I2C, 0x4ef600800, uic[0][3]);
-    i2c[1] = PPC4xx_I2C(dev);
 
     /* External bus controller */
     ppc405_ebc_init(env);
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 0942f35bf8..0fcdd35cbe 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -1225,9 +1225,7 @@ static void spapr_dt_hypervisor(sPAPRMachineState *spapr, void *fdt)
     }
 }
 
-static void *spapr_build_fdt(sPAPRMachineState *spapr,
-                             hwaddr rtas_addr,
-                             hwaddr rtas_size)
+static void *spapr_build_fdt(sPAPRMachineState *spapr)
 {
     MachineState *machine = MACHINE(spapr);
     MachineClass *mc = MACHINE_GET_CLASS(machine);
@@ -1644,14 +1642,14 @@ static void spapr_machine_reset(void)
 
     /*
      * We place the device tree and RTAS just below either the top of the RMA,
-     * or just below 2GB, whichever is lowere, so that it can be
+     * or just below 2GB, whichever is lower, so that it can be
      * processed with 32-bit real mode code if necessary
      */
     rtas_limit = MIN(spapr->rma_size, RTAS_MAX_ADDR);
     rtas_addr = rtas_limit - RTAS_MAX_SIZE;
     fdt_addr = rtas_addr - FDT_MAX_SIZE;
 
-    fdt = spapr_build_fdt(spapr, rtas_addr, spapr->rtas_size);
+    fdt = spapr_build_fdt(spapr);
 
     spapr_load_rtas(spapr, fdt, rtas_addr);
 
@@ -1717,6 +1715,7 @@ static bool spapr_vga_init(PCIBus *pci_bus, Error **errp)
         return true;
     case VGA_STD:
     case VGA_VIRTIO:
+    case VGA_CIRRUS:
         return pci_vga_init(pci_bus) != NULL;
     default:
         error_setg(errp,
@@ -2959,10 +2958,11 @@ static char *spapr_get_fw_dev_path(FWPathProvider *p, BusState *bus,
         if (spapr) {
             /*
              * Replace "channel@0/disk@0,0" with "disk@8000000000000000":
-             * We use SRP luns of the form 8000 | (bus << 8) | (id << 5) | lun
-             * in the top 16 bits of the 64-bit LUN
+             * In the top 16 bits of the 64-bit LUN, we use SRP luns of the form
+             * 0x8000 | (target << 8) | (bus << 5) | lun
+             * (see the "Logical unit addressing format" table in SAM5)
              */
-            unsigned id = 0x8000 | (d->id << 8) | d->lun;
+            unsigned id = 0x8000 | (d->id << 8) | (d->channel << 5) | d->lun;
             return g_strdup_printf("%s@%"PRIX64, qdev_fw_name(dev),
                                    (uint64_t)id << 48);
         } else if (virtio) {
@@ -3126,6 +3126,11 @@ static void spapr_set_ic_mode(Object *obj, const char *value, Error **errp)
 {
     sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
 
+    if (SPAPR_MACHINE_GET_CLASS(spapr)->legacy_irq_allocation) {
+        error_setg(errp, "This machine only uses the legacy XICS backend, don't pass ic-mode");
+        return;
+    }
+
     /* The legacy IRQ backend can not be set */
     if (strcmp(value, "xics") == 0) {
         spapr->irq = &spapr_irq_xics;
@@ -3896,7 +3901,7 @@ static ICPState *spapr_icp_get(XICSFabric *xi, int vcpu_id)
 {
     PowerPCCPU *cpu = spapr_find_cpu(vcpu_id);
 
-    return cpu ? cpu->icp : NULL;
+    return cpu ? spapr_cpu_state(cpu)->icp : NULL;
 }
 
 static void spapr_pic_print_info(InterruptStatsProvider *obj,
diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c
index 0405306d1e..ef6cbb9c29 100644
--- a/hw/ppc/spapr_cpu_core.c
+++ b/hw/ppc/spapr_cpu_core.c
@@ -194,11 +194,11 @@ static void spapr_unrealize_vcpu(PowerPCCPU *cpu, sPAPRCPUCore *sc)
         vmstate_unregister(NULL, &vmstate_spapr_cpu_state, cpu->machine_data);
     }
     qemu_unregister_reset(spapr_cpu_reset, cpu);
-    if (cpu->icp) {
-        object_unparent(OBJECT(cpu->icp));
+    if (spapr_cpu_state(cpu)->icp) {
+        object_unparent(OBJECT(spapr_cpu_state(cpu)->icp));
     }
-    if (cpu->tctx) {
-        object_unparent(OBJECT(cpu->tctx));
+    if (spapr_cpu_state(cpu)->tctx) {
+        object_unparent(OBJECT(spapr_cpu_state(cpu)->tctx));
     }
     cpu_remove_sync(CPU(cpu));
     object_unparent(OBJECT(cpu));
diff --git a/hw/ppc/spapr_irq.c b/hw/ppc/spapr_irq.c
index 1da7a32348..2d7a7c1638 100644
--- a/hw/ppc/spapr_irq.c
+++ b/hw/ppc/spapr_irq.c
@@ -12,6 +12,7 @@
 #include "qemu/error-report.h"
 #include "qapi/error.h"
 #include "hw/ppc/spapr.h"
+#include "hw/ppc/spapr_cpu_core.h"
 #include "hw/ppc/spapr_xive.h"
 #include "hw/ppc/xics.h"
 #include "hw/ppc/xics_spapr.h"
@@ -185,7 +186,7 @@ static void spapr_irq_print_info_xics(sPAPRMachineState *spapr, Monitor *mon)
     CPU_FOREACH(cs) {
         PowerPCCPU *cpu = POWERPC_CPU(cs);
 
-        icp_pic_print_info(cpu->icp, mon);
+        icp_pic_print_info(spapr_cpu_state(cpu)->icp, mon);
     }
 
     ics_pic_print_info(spapr->ics, mon);
@@ -196,6 +197,7 @@ static void spapr_irq_cpu_intc_create_xics(sPAPRMachineState *spapr,
 {
     Error *local_err = NULL;
     Object *obj;
+    sPAPRCPUState *spapr_cpu = spapr_cpu_state(cpu);
 
     obj = icp_create(OBJECT(cpu), spapr->icp_type, XICS_FABRIC(spapr),
                      &local_err);
@@ -204,7 +206,7 @@ static void spapr_irq_cpu_intc_create_xics(sPAPRMachineState *spapr,
         return;
     }
 
-    cpu->icp = ICP(obj);
+    spapr_cpu->icp = ICP(obj);
 }
 
 static int spapr_irq_post_load_xics(sPAPRMachineState *spapr, int version_id)
@@ -213,7 +215,7 @@ static int spapr_irq_post_load_xics(sPAPRMachineState *spapr, int version_id)
         CPUState *cs;
         CPU_FOREACH(cs) {
             PowerPCCPU *cpu = POWERPC_CPU(cs);
-            icp_resend(cpu->icp);
+            icp_resend(spapr_cpu_state(cpu)->icp);
         }
     }
     return 0;
@@ -334,7 +336,7 @@ static void spapr_irq_print_info_xive(sPAPRMachineState *spapr,
     CPU_FOREACH(cs) {
         PowerPCCPU *cpu = POWERPC_CPU(cs);
 
-        xive_tctx_pic_print_info(cpu->tctx, mon);
+        xive_tctx_pic_print_info(spapr_cpu_state(cpu)->tctx, mon);
     }
 
     spapr_xive_pic_print_info(spapr->xive, mon);
@@ -345,6 +347,7 @@ static void spapr_irq_cpu_intc_create_xive(sPAPRMachineState *spapr,
 {
     Error *local_err = NULL;
     Object *obj;
+    sPAPRCPUState *spapr_cpu = spapr_cpu_state(cpu);
 
     obj = xive_tctx_create(OBJECT(cpu), XIVE_ROUTER(spapr->xive), &local_err);
     if (local_err) {
@@ -352,13 +355,13 @@ static void spapr_irq_cpu_intc_create_xive(sPAPRMachineState *spapr,
         return;
     }
 
-    cpu->tctx = XIVE_TCTX(obj);
+    spapr_cpu->tctx = XIVE_TCTX(obj);
 
     /*
      * (TCG) Early setting the OS CAM line for hotplugged CPUs as they
      * don't beneficiate from the reset of the XIVE IRQ backend
      */
-    spapr_xive_set_tctx_os_cam(cpu->tctx);
+    spapr_xive_set_tctx_os_cam(spapr_cpu->tctx);
 }
 
 static int spapr_irq_post_load_xive(sPAPRMachineState *spapr, int version_id)
@@ -374,7 +377,7 @@ static void spapr_irq_reset_xive(sPAPRMachineState *spapr, Error **errp)
         PowerPCCPU *cpu = POWERPC_CPU(cs);
 
         /* (TCG) Set the OS CAM line of the thread interrupt context. */
-        spapr_xive_set_tctx_os_cam(cpu->tctx);
+        spapr_xive_set_tctx_os_cam(spapr_cpu_state(cpu)->tctx);
     }
 
     /* Activate the XIVE MMIOs */
diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
index b74f2632ec..c99721cde8 100644
--- a/hw/ppc/spapr_pci.c
+++ b/hw/ppc/spapr_pci.c
@@ -964,7 +964,7 @@ static void populate_resource_props(PCIDevice *d, ResourceProps *rp)
         }
 
         assigned = &rp->assigned[assigned_idx++];
-        assigned->phys_hi = cpu_to_be32(reg->phys_hi | b_n(1));
+        assigned->phys_hi = cpu_to_be32(be32_to_cpu(reg->phys_hi) | b_n(1));
         assigned->phys_mid = cpu_to_be32(d->io_regions[i].addr >> 32);
         assigned->phys_lo = cpu_to_be32(d->io_regions[i].addr);
         assigned->size_hi = reg->size_hi;
@@ -2030,8 +2030,6 @@ static void spapr_phb_pci_enumerate_bridge(PCIBus *bus, PCIDevice *pdev,
                                            void *opaque)
 {
     unsigned int *bus_no = opaque;
-    unsigned int primary = *bus_no;
-    unsigned int subordinate = 0xff;
     PCIBus *sec_bus = NULL;
 
     if ((pci_default_read_config(pdev, PCI_HEADER_TYPE, 1) !=
@@ -2040,7 +2038,7 @@ static void spapr_phb_pci_enumerate_bridge(PCIBus *bus, PCIDevice *pdev,
     }
 
     (*bus_no)++;
-    pci_default_write_config(pdev, PCI_PRIMARY_BUS, primary, 1);
+    pci_default_write_config(pdev, PCI_PRIMARY_BUS, pci_dev_bus_num(pdev), 1);
     pci_default_write_config(pdev, PCI_SECONDARY_BUS, *bus_no, 1);
     pci_default_write_config(pdev, PCI_SUBORDINATE_BUS, *bus_no, 1);
 
@@ -2049,7 +2047,6 @@ static void spapr_phb_pci_enumerate_bridge(PCIBus *bus, PCIDevice *pdev,
         return;
     }
 
-    pci_default_write_config(pdev, PCI_SUBORDINATE_BUS, subordinate, 1);
     pci_for_each_device(sec_bus, pci_bus_num(sec_bus),
                         spapr_phb_pci_enumerate_bridge, bus_no);
     pci_default_write_config(pdev, PCI_SUBORDINATE_BUS, *bus_no, 1);
diff --git a/hw/ppc/spapr_vio.c b/hw/ppc/spapr_vio.c
index 7e8a9ad093..414673d313 100644
--- a/hw/ppc/spapr_vio.c
+++ b/hw/ppc/spapr_vio.c
@@ -44,38 +44,6 @@
 
 #define SPAPR_VIO_REG_BASE 0x71000000
 
-static void spapr_vio_get_irq(Object *obj, Visitor *v, const char *name,
-                              void *opaque, Error **errp)
-{
-    Property *prop = opaque;
-    uint32_t *ptr = qdev_get_prop_ptr(DEVICE(obj), prop);
-
-    visit_type_uint32(v, name, ptr, errp);
-}
-
-static void spapr_vio_set_irq(Object *obj, Visitor *v, const char *name,
-                              void *opaque, Error **errp)
-{
-    Property *prop = opaque;
-    uint32_t *ptr = qdev_get_prop_ptr(DEVICE(obj), prop);
-
-    if (!qtest_enabled()) {
-        warn_report(TYPE_VIO_SPAPR_DEVICE " '%s' property is deprecated", name);
-    }
-    visit_type_uint32(v, name, ptr, errp);
-}
-
-static const PropertyInfo spapr_vio_irq_propinfo = {
-    .name = "irq",
-    .get = spapr_vio_get_irq,
-    .set = spapr_vio_set_irq,
-};
-
-static Property spapr_vio_props[] = {
-    DEFINE_PROP("irq", VIOsPAPRDevice, irq, spapr_vio_irq_propinfo, uint32_t),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
 static char *spapr_vio_get_dev_name(DeviceState *qdev)
 {
     VIOsPAPRDevice *dev = VIO_SPAPR_DEVICE(qdev);
@@ -534,15 +502,13 @@ static void spapr_vio_busdev_realize(DeviceState *qdev, Error **errp)
         dev->qdev.id = id;
     }
 
-    if (!dev->irq) {
-        dev->irq = spapr_vio_reg_to_irq(dev->reg);
+    dev->irq = spapr_vio_reg_to_irq(dev->reg);
 
-        if (SPAPR_MACHINE_GET_CLASS(spapr)->legacy_irq_allocation) {
-            dev->irq = spapr_irq_findone(spapr, &local_err);
-            if (local_err) {
-                error_propagate(errp, local_err);
-                return;
-            }
+    if (SPAPR_MACHINE_GET_CLASS(spapr)->legacy_irq_allocation) {
+        dev->irq = spapr_irq_findone(spapr, &local_err);
+        if (local_err) {
+            error_propagate(errp, local_err);
+            return;
         }
     }
 
@@ -668,7 +634,6 @@ static void vio_spapr_device_class_init(ObjectClass *klass, void *data)
     k->realize = spapr_vio_busdev_realize;
     k->reset = spapr_vio_busdev_reset;
     k->bus_type = TYPE_SPAPR_VIO_BUS;
-    k->props = spapr_vio_props;
 }
 
 static const TypeInfo spapr_vio_type_info = {
diff --git a/hw/xen/xen-bus.c b/hw/xen/xen-bus.c
index 3aeccec69c..49a725e8c7 100644
--- a/hw/xen/xen-bus.c
+++ b/hw/xen/xen-bus.c
@@ -547,20 +547,15 @@ static void xen_device_backend_changed(void *opaque)
     }
 
     /*
-     * If a backend is still 'online' then its state should be cycled
-     * back round to InitWait in order for a new frontend instance to
-     * connect. This may happen when, for example, a frontend driver is
-     * re-installed or updated.
-     * If a backend is not 'online' then the device should be destroyed.
+     * If a backend is still 'online' then we should leave it alone but,
+     * if a backend is not 'online', then the device should be destroyed
+     * once the state is Closed.
      */
-    if (xendev->backend_online &&
-        xendev->backend_state == XenbusStateClosed) {
-        xen_device_backend_set_state(xendev, XenbusStateInitWait);
-    } else if (!xendev->backend_online &&
-               (xendev->backend_state == XenbusStateClosed ||
-                xendev->backend_state == XenbusStateInitialising ||
-                xendev->backend_state == XenbusStateInitWait ||
-                xendev->backend_state == XenbusStateUnknown)) {
+    if (!xendev->backend_online &&
+        (xendev->backend_state == XenbusStateClosed ||
+         xendev->backend_state == XenbusStateInitialising ||
+         xendev->backend_state == XenbusStateInitWait ||
+         xendev->backend_state == XenbusStateUnknown)) {
         Error *local_err = NULL;
 
         if (!xen_backend_try_device_destroy(xendev, &local_err)) {
@@ -715,6 +710,17 @@ static void xen_device_frontend_changed(void *opaque)
 
     xen_device_frontend_set_state(xendev, state);
 
+    if (state == XenbusStateInitialising &&
+        xendev->backend_state == XenbusStateClosed &&
+        xendev->backend_online) {
+        /*
+         * The frontend is re-initializing so switch back to
+         * InitWait.
+         */
+        xen_device_backend_set_state(xendev, XenbusStateInitWait);
+        return;
+    }
+
     if (xendev_class->frontend_changed) {
         Error *local_err = NULL;
 
diff --git a/hw/xtensa/Makefile.objs b/hw/xtensa/Makefile.objs
index cb4998d2bf..f30e4a7e07 100644
--- a/hw/xtensa/Makefile.objs
+++ b/hw/xtensa/Makefile.objs
@@ -1,3 +1,4 @@
+obj-y += mx_pic.o
 obj-y += pic_cpu.o
 obj-y += sim.o
 obj-y += xtensa_memory.o
diff --git a/hw/xtensa/mx_pic.c b/hw/xtensa/mx_pic.c
new file mode 100644
index 0000000000..7075db9d4b
--- /dev/null
+++ b/hw/xtensa/mx_pic.c
@@ -0,0 +1,354 @@
+/*
+ * Copyright (c) 2013 - 2019, Max Filippov, Open Source and Linux Lab.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Open Source and Linux Lab nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/hw.h"
+#include "hw/xtensa/mx_pic.h"
+#include "qemu/log.h"
+
+#define MX_MAX_CPU 32
+#define MX_MAX_IRQ 32
+
+#define MIROUT 0x0
+#define MIPICAUSE 0x100
+#define MIPISET 0x140
+#define MIENG 0x180
+#define MIENGSET 0x184
+#define MIASG 0x188
+#define MIASGSET 0x18c
+#define MIPIPART 0x190
+#define SYSCFGID 0x1a0
+#define MPSCORE 0x200
+#define CCON 0x220
+
+struct XtensaMxPic {
+    unsigned n_cpu;
+    unsigned n_irq;
+
+    uint32_t ext_irq_state;
+    uint32_t mieng;
+    uint32_t miasg;
+    uint32_t mirout[MX_MAX_IRQ];
+    uint32_t mipipart;
+    uint32_t runstall;
+
+    qemu_irq *irq_inputs;
+    struct XtensaMxPicCpu {
+        XtensaMxPic *mx;
+        qemu_irq *irq;
+        qemu_irq runstall;
+        uint32_t mipicause;
+        uint32_t mirout_cache;
+        uint32_t irq_state_cache;
+        uint32_t ccon;
+        MemoryRegion reg;
+    } cpu[MX_MAX_CPU];
+};
+
+static uint64_t xtensa_mx_pic_ext_reg_read(void *opaque, hwaddr offset,
+                                           unsigned size)
+{
+    struct XtensaMxPicCpu *mx_cpu = opaque;
+    struct XtensaMxPic *mx = mx_cpu->mx;
+
+    if (offset < MIROUT + MX_MAX_IRQ) {
+        return mx->mirout[offset - MIROUT];
+    } else if (offset >= MIPICAUSE && offset < MIPICAUSE + MX_MAX_CPU) {
+        return mx->cpu[offset - MIPICAUSE].mipicause;
+    } else {
+        switch (offset) {
+        case MIENG:
+            return mx->mieng;
+
+        case MIASG:
+            return mx->miasg;
+
+        case MIPIPART:
+            return mx->mipipart;
+
+        case SYSCFGID:
+            return ((mx->n_cpu - 1) << 18) | (mx_cpu - mx->cpu);
+
+        case MPSCORE:
+            return mx->runstall;
+
+        case CCON:
+            return mx_cpu->ccon;
+
+        default:
+            qemu_log_mask(LOG_GUEST_ERROR,
+                          "unknown RER in MX PIC range: 0x%08x\n",
+                          (uint32_t)offset);
+            return 0;
+        }
+    }
+}
+
+static uint32_t xtensa_mx_pic_get_ipi_for_cpu(const XtensaMxPic *mx,
+                                              unsigned cpu)
+{
+    uint32_t mipicause = mx->cpu[cpu].mipicause;
+    uint32_t mipipart = mx->mipipart;
+
+    return (((mipicause & 1) << (mipipart & 3)) |
+            ((mipicause & 0x000e) != 0) << ((mipipart >> 2) & 3) |
+            ((mipicause & 0x00f0) != 0) << ((mipipart >> 4) & 3) |
+            ((mipicause & 0xff00) != 0) << ((mipipart >> 6) & 3)) & 0x7;
+}
+
+static uint32_t xtensa_mx_pic_get_ext_irq_for_cpu(const XtensaMxPic *mx,
+                                                  unsigned cpu)
+{
+    return ((((mx->ext_irq_state & mx->mieng) | mx->miasg) &
+             mx->cpu[cpu].mirout_cache) << 2) |
+        xtensa_mx_pic_get_ipi_for_cpu(mx, cpu);
+}
+
+static void xtensa_mx_pic_update_cpu(XtensaMxPic *mx, unsigned cpu)
+{
+    uint32_t irq = xtensa_mx_pic_get_ext_irq_for_cpu(mx, cpu);
+    uint32_t changed_irq = mx->cpu[cpu].irq_state_cache ^ irq;
+    unsigned i;
+
+    qemu_log_mask(CPU_LOG_INT, "%s: CPU %d, irq: %08x, changed_irq: %08x\n",
+                  __func__, cpu, irq, changed_irq);
+    mx->cpu[cpu].irq_state_cache = irq;
+    for (i = 0; changed_irq; ++i) {
+        uint32_t mask = 1u << i;
+
+        if (changed_irq & mask) {
+            changed_irq ^= mask;
+            qemu_set_irq(mx->cpu[cpu].irq[i], irq & mask);
+        }
+    }
+}
+
+static void xtensa_mx_pic_update_all(XtensaMxPic *mx)
+{
+    unsigned cpu;
+
+    for (cpu = 0; cpu < mx->n_cpu; ++cpu) {
+        xtensa_mx_pic_update_cpu(mx, cpu);
+    }
+}
+
+static void xtensa_mx_pic_ext_reg_write(void *opaque, hwaddr offset,
+                                        uint64_t v, unsigned size)
+{
+    struct XtensaMxPicCpu *mx_cpu = opaque;
+    struct XtensaMxPic *mx = mx_cpu->mx;
+    unsigned cpu;
+
+    if (offset < MIROUT + mx->n_irq) {
+        mx->mirout[offset - MIROUT] = v;
+        for (cpu = 0; cpu < mx->n_cpu; ++cpu) {
+            uint32_t mask = 1u << (offset - MIROUT);
+
+            if (!(mx->cpu[cpu].mirout_cache & mask) != !(v & (1u << cpu))) {
+                mx->cpu[cpu].mirout_cache ^= mask;
+                xtensa_mx_pic_update_cpu(mx, cpu);
+            }
+        }
+    } else if (offset >= MIPICAUSE && offset < MIPICAUSE + mx->n_cpu) {
+        cpu = offset - MIPICAUSE;
+        mx->cpu[cpu].mipicause &= ~v;
+        xtensa_mx_pic_update_cpu(mx, cpu);
+    } else if (offset >= MIPISET && offset < MIPISET + 16) {
+        for (cpu = 0; cpu < mx->n_cpu; ++cpu) {
+            if (v & (1u << cpu)) {
+                mx->cpu[cpu].mipicause |= 1u << (offset - MIPISET);
+                xtensa_mx_pic_update_cpu(mx, cpu);
+            }
+        }
+    } else {
+        uint32_t change = 0;
+        uint32_t oldv, newv;
+        const char *name = "???";
+
+        switch (offset) {
+        case MIENG:
+            change = mx->mieng & v;
+            oldv = mx->mieng;
+            mx->mieng &= ~v;
+            newv = mx->mieng;
+            name = "MIENG";
+            break;
+
+        case MIENGSET:
+            change = ~mx->mieng & v;
+            oldv = mx->mieng;
+            mx->mieng |= v;
+            newv = mx->mieng;
+            name = "MIENG";
+            break;
+
+        case MIASG:
+            change = mx->miasg & v;
+            oldv = mx->miasg;
+            mx->miasg &= ~v;
+            newv = mx->miasg;
+            name = "MIASG";
+            break;
+
+        case MIASGSET:
+            change = ~mx->miasg & v;
+            oldv = mx->miasg;
+            mx->miasg |= v;
+            newv = mx->miasg;
+            name = "MIASG";
+            break;
+
+        case MIPIPART:
+            change = mx->mipipart ^ v;
+            oldv = mx->mipipart;
+            mx->mipipart = v;
+            newv = mx->mipipart;
+            name = "MIPIPART";
+            break;
+
+        case MPSCORE:
+            change = mx->runstall ^ v;
+            oldv = mx->runstall;
+            mx->runstall = v;
+            newv = mx->runstall;
+            name = "RUNSTALL";
+            for (cpu = 0; cpu < mx->n_cpu; ++cpu) {
+                if (change & (1u << cpu)) {
+                    qemu_set_irq(mx->cpu[cpu].runstall, v & (1u << cpu));
+                }
+            }
+            break;
+
+        case CCON:
+            mx_cpu->ccon = v & 0x1;
+            break;
+
+        default:
+            qemu_log_mask(LOG_GUEST_ERROR,
+                          "unknown WER in MX PIC range: 0x%08x = 0x%08x\n",
+                          (uint32_t)offset, (uint32_t)v);
+            break;
+        }
+        if (change) {
+            qemu_log_mask(CPU_LOG_INT,
+                          "%s: %s changed by CPU %d: %08x -> %08x\n",
+                          __func__, name, (int)(mx_cpu - mx->cpu),
+                          oldv, newv);
+            xtensa_mx_pic_update_all(mx);
+        }
+    }
+}
+
+static const MemoryRegionOps xtensa_mx_pic_ops = {
+    .read = xtensa_mx_pic_ext_reg_read,
+    .write = xtensa_mx_pic_ext_reg_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .unaligned = true,
+    },
+};
+
+MemoryRegion *xtensa_mx_pic_register_cpu(XtensaMxPic *mx,
+                                         qemu_irq *irq,
+                                         qemu_irq runstall)
+{
+    struct XtensaMxPicCpu *mx_cpu = mx->cpu + mx->n_cpu;
+
+    mx_cpu->mx = mx;
+    mx_cpu->irq = irq;
+    mx_cpu->runstall = runstall;
+
+    memory_region_init_io(&mx_cpu->reg, NULL, &xtensa_mx_pic_ops, mx_cpu,
+                          "mx_pic", 0x280);
+
+    ++mx->n_cpu;
+    return &mx_cpu->reg;
+}
+
+static void xtensa_mx_pic_set_irq(void *opaque, int irq, int active)
+{
+    XtensaMxPic *mx = opaque;
+
+    if (irq < mx->n_irq) {
+        uint32_t old_irq_state = mx->ext_irq_state;
+
+        if (active) {
+            mx->ext_irq_state |= 1u << irq;
+        } else {
+            mx->ext_irq_state &= ~(1u << irq);
+        }
+        if (old_irq_state != mx->ext_irq_state) {
+            qemu_log_mask(CPU_LOG_INT,
+                          "%s: IRQ %d, active: %d, ext_irq_state: %08x -> %08x\n",
+                          __func__, irq, active,
+                          old_irq_state, mx->ext_irq_state);
+            xtensa_mx_pic_update_all(mx);
+        }
+    } else {
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: IRQ %d out of range\n",
+                      __func__, irq);
+    }
+}
+
+XtensaMxPic *xtensa_mx_pic_init(unsigned n_irq)
+{
+    XtensaMxPic *mx = calloc(1, sizeof(XtensaMxPic));
+
+    mx->n_irq = n_irq + 1;
+    mx->irq_inputs = qemu_allocate_irqs(xtensa_mx_pic_set_irq, mx,
+                                        mx->n_irq);
+    return mx;
+}
+
+void xtensa_mx_pic_reset(void *opaque)
+{
+    XtensaMxPic *mx = opaque;
+    unsigned i;
+
+    mx->ext_irq_state = 0;
+    mx->mieng = mx->n_irq < 32 ? (1u << mx->n_irq) - 1 : ~0u;
+    mx->miasg = 0;
+    mx->mipipart = 0;
+    for (i = 0; i < mx->n_irq; ++i) {
+        mx->mirout[i] = 1;
+    }
+    for (i = 0; i < mx->n_cpu; ++i) {
+        mx->cpu[i].mipicause = 0;
+        mx->cpu[i].mirout_cache = i ? 0 : mx->mieng;
+        mx->cpu[i].irq_state_cache = 0;
+        mx->cpu[i].ccon = 0;
+    }
+    mx->runstall = (1u << mx->n_cpu) - 2;
+    for (i = 0; i < mx->n_cpu; ++i) {
+        qemu_set_irq(mx->cpu[i].runstall, i > 0);
+    }
+}
+
+qemu_irq *xtensa_mx_pic_get_extints(XtensaMxPic *mx)
+{
+    return mx->irq_inputs + 1;
+}
diff --git a/hw/xtensa/pic_cpu.c b/hw/xtensa/pic_cpu.c
index 0e812d7f06..a8939f5e58 100644
--- a/hw/xtensa/pic_cpu.c
+++ b/hw/xtensa/pic_cpu.c
@@ -68,36 +68,37 @@ static void xtensa_set_irq(void *opaque, int irq, int active)
         uint32_t irq_bit = 1 << irq;
 
         if (active) {
-            env->sregs[INTSET] |= irq_bit;
+            atomic_or(&env->sregs[INTSET], irq_bit);
         } else if (env->config->interrupt[irq].inttype == INTTYPE_LEVEL) {
-            env->sregs[INTSET] &= ~irq_bit;
+            atomic_and(&env->sregs[INTSET], ~irq_bit);
         }
 
         check_interrupts(env);
     }
 }
 
-void xtensa_timer_irq(CPUXtensaState *env, uint32_t id, uint32_t active)
-{
-    qemu_set_irq(env->irq_inputs[env->config->timerint[id]], active);
-}
-
 static void xtensa_ccompare_cb(void *opaque)
 {
     XtensaCcompareTimer *ccompare = opaque;
     CPUXtensaState *env = ccompare->env;
     unsigned i = ccompare - env->ccompare;
 
-    xtensa_timer_irq(env, i, 1);
+    qemu_set_irq(env->irq_inputs[env->config->timerint[i]], 1);
+}
+
+static void xtensa_set_runstall(void *opaque, int irq, int active)
+{
+    CPUXtensaState *env = opaque;
+    xtensa_runstall(env, active);
 }
 
 void xtensa_irq_init(CPUXtensaState *env)
 {
-    env->irq_inputs = (void **)qemu_allocate_irqs(
-            xtensa_set_irq, env, env->config->ninterrupt);
-    if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT)) {
-        unsigned i;
+    unsigned i;
 
+    env->irq_inputs = qemu_allocate_irqs(xtensa_set_irq, env,
+                                         env->config->ninterrupt);
+    if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT)) {
         env->time_base = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
         env->ccount_base = env->sregs[CCOUNT];
         for (i = 0; i < env->config->nccompare; ++i) {
@@ -106,16 +107,20 @@ void xtensa_irq_init(CPUXtensaState *env)
                     xtensa_ccompare_cb, env->ccompare + i);
         }
     }
+    for (i = 0; i < env->config->nextint; ++i) {
+        unsigned irq = env->config->extint[i];
+
+        env->ext_irq_inputs[i] = env->irq_inputs[irq];
+    }
+    env->runstall_irq = qemu_allocate_irq(xtensa_set_runstall, env, 0);
 }
 
-void *xtensa_get_extint(CPUXtensaState *env, unsigned extint)
+qemu_irq *xtensa_get_extints(CPUXtensaState *env)
 {
-    if (extint < env->config->nextint) {
-        unsigned irq = env->config->extint[extint];
-        return env->irq_inputs[irq];
-    } else {
-        qemu_log("%s: trying to acquire invalid external interrupt %d\n",
-                __func__, extint);
-        return NULL;
-    }
+    return env->ext_irq_inputs;
+}
+
+qemu_irq xtensa_get_runstall(CPUXtensaState *env)
+{
+    return env->runstall_irq;
 }
diff --git a/hw/xtensa/xtfpga.c b/hw/xtensa/xtfpga.c
index 21094319a6..1d21162a27 100644
--- a/hw/xtensa/xtfpga.c
+++ b/hw/xtensa/xtfpga.c
@@ -45,6 +45,7 @@
 #include "qemu/option.h"
 #include "bootparam.h"
 #include "xtensa_memory.h"
+#include "hw/xtensa/mx_pic.h"
 
 typedef struct XtfpgaFlashDesc {
     hwaddr base;
@@ -61,6 +62,7 @@ typedef struct XtfpgaBoardDesc {
 
 typedef struct XtfpgaFpgaState {
     MemoryRegion iomem;
+    uint32_t freq;
     uint32_t leds;
     uint32_t switches;
 } XtfpgaFpgaState;
@@ -83,7 +85,7 @@ static uint64_t xtfpga_fpga_read(void *opaque, hwaddr addr,
         return 0x09272011;
 
     case 0x4: /*processor clock frequency, Hz*/
-        return 10000000;
+        return s->freq;
 
     case 0x8: /*LEDs (off = 0, on = 1)*/
         return s->leds;
@@ -119,13 +121,14 @@ static const MemoryRegionOps xtfpga_fpga_ops = {
 };
 
 static XtfpgaFpgaState *xtfpga_fpga_init(MemoryRegion *address_space,
-        hwaddr base)
+                                         hwaddr base, uint32_t freq)
 {
     XtfpgaFpgaState *s = g_malloc(sizeof(XtfpgaFpgaState));
 
     memory_region_init_io(&s->iomem, NULL, &xtfpga_fpga_ops, s,
-            "xtfpga.fpga", 0x10000);
+                          "xtfpga.fpga", 0x10000);
     memory_region_add_subregion(address_space, base, &s->iomem);
+    s->freq = freq;
     xtfpga_fpga_reset(s);
     qemu_register_reset(xtfpga_fpga_reset, s);
     return s;
@@ -223,6 +226,8 @@ static void xtfpga_init(const XtfpgaBoardDesc *board, MachineState *machine)
     XtensaCPU *cpu = NULL;
     CPUXtensaState *env = NULL;
     MemoryRegion *system_io;
+    XtensaMxPic *mx_pic = NULL;
+    qemu_irq *extints;
     DriveInfo *dinfo;
     pflash_t *flash = NULL;
     QemuOpts *machine_opts = qemu_get_machine_opts();
@@ -231,19 +236,45 @@ static void xtfpga_init(const XtfpgaBoardDesc *board, MachineState *machine)
     const char *dtb_filename = qemu_opt_get(machine_opts, "dtb");
     const char *initrd_filename = qemu_opt_get(machine_opts, "initrd");
     const unsigned system_io_size = 224 * MiB;
+    uint32_t freq = 10000000;
     int n;
 
+    if (smp_cpus > 1) {
+        mx_pic = xtensa_mx_pic_init(31);
+        qemu_register_reset(xtensa_mx_pic_reset, mx_pic);
+    }
     for (n = 0; n < smp_cpus; n++) {
+        CPUXtensaState *cenv = NULL;
+
         cpu = XTENSA_CPU(cpu_create(machine->cpu_type));
-        env = &cpu->env;
+        cenv = &cpu->env;
+        if (!env) {
+            env = cenv;
+            freq = env->config->clock_freq_khz * 1000;
+        }
+
+        if (mx_pic) {
+            MemoryRegion *mx_eri;
 
-        env->sregs[PRID] = n;
+            mx_eri = xtensa_mx_pic_register_cpu(mx_pic,
+                                                xtensa_get_extints(cenv),
+                                                xtensa_get_runstall(cenv));
+            memory_region_add_subregion(xtensa_get_er_region(cenv),
+                                        0, mx_eri);
+        }
+        cenv->sregs[PRID] = n;
+        xtensa_select_static_vectors(cenv, n != 0);
         qemu_register_reset(xtfpga_reset, cpu);
         /* Need MMU initialized prior to ELF loading,
          * so that ELF gets loaded into virtual addresses
          */
         cpu_reset(CPU(cpu));
     }
+    if (smp_cpus > 1) {
+        extints = xtensa_mx_pic_get_extints(mx_pic);
+    } else {
+        extints = xtensa_get_extints(env);
+    }
 
     if (env) {
         XtensaMemory sysram = env->config->sysram;
@@ -272,14 +303,14 @@ static void xtfpga_init(const XtfpgaBoardDesc *board, MachineState *machine)
                                  system_io, 0, system_io_size);
         memory_region_add_subregion(system_memory, board->io[1], io);
     }
-    xtfpga_fpga_init(system_io, 0x0d020000);
+    xtfpga_fpga_init(system_io, 0x0d020000, freq);
     if (nd_table[0].used) {
         xtfpga_net_init(system_io, 0x0d030000, 0x0d030400, 0x0d800000,
-                xtensa_get_extint(env, 1), nd_table);
+                        extints[1], nd_table);
     }
 
-    serial_mm_init(system_io, 0x0d050020, 2, xtensa_get_extint(env, 0),
-            115200, serial_hd(0), DEVICE_NATIVE_ENDIAN);
+    serial_mm_init(system_io, 0x0d050020, 2, extints[0],
+                   115200, serial_hd(0), DEVICE_NATIVE_ENDIAN);
 
     dinfo = drive_get(IF_PFLASH, 0, 0);
     if (dinfo) {
@@ -568,7 +599,7 @@ static void xtfpga_lx60_class_init(ObjectClass *oc, void *data)
 
     mc->desc = "lx60 EVB (" XTENSA_DEFAULT_CPU_MODEL ")";
     mc->init = xtfpga_lx60_init;
-    mc->max_cpus = 4;
+    mc->max_cpus = 32;
     mc->default_cpu_type = XTENSA_DEFAULT_CPU_TYPE;
     mc->default_ram_size = 64 * MiB;
 }
@@ -585,7 +616,7 @@ static void xtfpga_lx60_nommu_class_init(ObjectClass *oc, void *data)
 
     mc->desc = "lx60 noMMU EVB (" XTENSA_DEFAULT_CPU_NOMMU_MODEL ")";
     mc->init = xtfpga_lx60_nommu_init;
-    mc->max_cpus = 4;
+    mc->max_cpus = 32;
     mc->default_cpu_type = XTENSA_DEFAULT_CPU_NOMMU_TYPE;
     mc->default_ram_size = 64 * MiB;
 }
@@ -602,7 +633,7 @@ static void xtfpga_lx200_class_init(ObjectClass *oc, void *data)
 
     mc->desc = "lx200 EVB (" XTENSA_DEFAULT_CPU_MODEL ")";
     mc->init = xtfpga_lx200_init;
-    mc->max_cpus = 4;
+    mc->max_cpus = 32;
     mc->default_cpu_type = XTENSA_DEFAULT_CPU_TYPE;
     mc->default_ram_size = 96 * MiB;
 }
@@ -619,7 +650,7 @@ static void xtfpga_lx200_nommu_class_init(ObjectClass *oc, void *data)
 
     mc->desc = "lx200 noMMU EVB (" XTENSA_DEFAULT_CPU_NOMMU_MODEL ")";
     mc->init = xtfpga_lx200_nommu_init;
-    mc->max_cpus = 4;
+    mc->max_cpus = 32;
     mc->default_cpu_type = XTENSA_DEFAULT_CPU_NOMMU_TYPE;
     mc->default_ram_size = 96 * MiB;
 }
@@ -636,7 +667,7 @@ static void xtfpga_ml605_class_init(ObjectClass *oc, void *data)
 
     mc->desc = "ml605 EVB (" XTENSA_DEFAULT_CPU_MODEL ")";
     mc->init = xtfpga_ml605_init;
-    mc->max_cpus = 4;
+    mc->max_cpus = 32;
     mc->default_cpu_type = XTENSA_DEFAULT_CPU_TYPE;
     mc->default_ram_size = 512 * MiB - XTFPGA_MMU_RESERVED_MEMORY_SIZE;
 }
@@ -653,7 +684,7 @@ static void xtfpga_ml605_nommu_class_init(ObjectClass *oc, void *data)
 
     mc->desc = "ml605 noMMU EVB (" XTENSA_DEFAULT_CPU_NOMMU_MODEL ")";
     mc->init = xtfpga_ml605_nommu_init;
-    mc->max_cpus = 4;
+    mc->max_cpus = 32;
     mc->default_cpu_type = XTENSA_DEFAULT_CPU_NOMMU_TYPE;
     mc->default_ram_size = 256 * MiB;
 }
@@ -670,7 +701,7 @@ static void xtfpga_kc705_class_init(ObjectClass *oc, void *data)
 
     mc->desc = "kc705 EVB (" XTENSA_DEFAULT_CPU_MODEL ")";
     mc->init = xtfpga_kc705_init;
-    mc->max_cpus = 4;
+    mc->max_cpus = 32;
     mc->default_cpu_type = XTENSA_DEFAULT_CPU_TYPE;
     mc->default_ram_size = 1 * GiB - XTFPGA_MMU_RESERVED_MEMORY_SIZE;
 }
@@ -687,7 +718,7 @@ static void xtfpga_kc705_nommu_class_init(ObjectClass *oc, void *data)
 
     mc->desc = "kc705 noMMU EVB (" XTENSA_DEFAULT_CPU_NOMMU_MODEL ")";
     mc->init = xtfpga_kc705_nommu_init;
-    mc->max_cpus = 4;
+    mc->max_cpus = 32;
     mc->default_cpu_type = XTENSA_DEFAULT_CPU_NOMMU_TYPE;
     mc->default_ram_size = 256 * MiB;
 }