aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2018-06-22 15:14:08 +0100
committerPeter Maydell <peter.maydell@linaro.org>2018-06-22 15:14:08 +0100
commitc52e53f429aa562539f5da2e7c21c66c6f9a8a16 (patch)
tree796b50aff53f4895e1d83708756a97ff37e76e97
parent45eb6fb6cea28cdc937764aac6585751047bb294 (diff)
parente5ca28ecab5c69b7578e22391a66c97c3979ffd8 (diff)
downloadqemu-c52e53f429aa562539f5da2e7c21c66c6f9a8a16.zip
qemu-c52e53f429aa562539f5da2e7c21c66c6f9a8a16.tar.gz
qemu-c52e53f429aa562539f5da2e7c21c66c6f9a8a16.tar.bz2
Merge remote-tracking branch 'remotes/dgibson/tags/ppc-for-3.0-20180622' into staging
ppc patch queue 2018-06-22 Another assorted patch of patches for ppc and spapr. * Rework of guest pagesize handling for ppc, which avoids guest visibly different behaviour between accelerators * A number of Pnv cleanups, working towards more complete POWER9 support * Migration of VPA data, a significant bugfix # gpg: Signature made Fri 22 Jun 2018 05:23:16 BST # gpg: using RSA key 6C38CACA20D9B392 # gpg: Good signature from "David Gibson <david@gibson.dropbear.id.au>" # gpg: aka "David Gibson (Red Hat) <dgibson@redhat.com>" # gpg: aka "David Gibson (ozlabs.org) <dgibson@ozlabs.org>" # gpg: aka "David Gibson (kernel.org) <dwg@kernel.org>" # Primary key fingerprint: 75F4 6586 AE61 A66C C44E 87DC 6C38 CACA 20D9 B392 * remotes/dgibson/tags/ppc-for-3.0-20180622: (23 commits) spapr: Don't rewrite mmu capabilities in KVM mode spapr: Limit available pagesizes to provide a consistent guest environment target/ppc: Add ppc_hash64_filter_pagesizes() spapr: Use maximum page size capability to simplify memory backend checking spapr: Maximum (HPT) pagesize property pseries: Update SLOF firmware image to qemu-slof-20180621 target/ppc: Add missing opcode for icbt on PPC440 ppc4xx_i2c: Implement directcntl register ppc4xx_i2c: Remove unimplemented sdata and intr registers sm501: Fix hardware cursor color conversion fpu_helper.c: fix helper_fpscr_clrbit() function spapr: remove unused spapr_irq routines spapr: split the IRQ allocation sequence target/ppc: Add kvmppc_hpt_needs_host_contiguous_pages() helper spapr: Add cpu_apply hook to capabilities spapr: Compute effective capability values earlier target/ppc: Allow cpu compatiblity checks based on type, not instance ppc/pnv: consolidate the creation of the ISA bus device tree ppc/pnv: introduce Pnv8Chip and Pnv9Chip models spapr_cpu_core: migrate VPA related state ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r--default-configs/ppc-softmmu.mak1
-rw-r--r--default-configs/ppcemb-softmmu.mak1
-rw-r--r--hw/display/sm501.c6
-rw-r--r--hw/i2c/ppc4xx_i2c.c30
-rw-r--r--hw/ppc/pnv.c383
-rw-r--r--hw/ppc/pnv_core.c18
-rw-r--r--hw/ppc/pnv_lpc.c30
-rw-r--r--hw/ppc/spapr.c122
-rw-r--r--hw/ppc/spapr_caps.c158
-rw-r--r--hw/ppc/spapr_cpu_core.c91
-rw-r--r--hw/ppc/spapr_events.c18
-rw-r--r--hw/ppc/spapr_pci.c23
-rw-r--r--hw/ppc/spapr_vio.c10
-rw-r--r--include/hw/i2c/ppc4xx_i2c.h8
-rw-r--r--include/hw/ppc/pnv.h26
-rw-r--r--include/hw/ppc/pnv_lpc.h3
-rw-r--r--include/hw/ppc/spapr.h19
-rw-r--r--include/hw/ppc/spapr_cpu_core.h1
-rw-r--r--pc-bios/README2
-rw-r--r--pc-bios/slof.binbin913880 -> 924840 bytes
m---------roms/SLOF0
-rw-r--r--target/ppc/compat.c27
-rw-r--r--target/ppc/cpu.h4
-rw-r--r--target/ppc/fpu_helper.c28
-rw-r--r--target/ppc/kvm.c146
-rw-r--r--target/ppc/kvm_ppc.h11
-rw-r--r--target/ppc/mmu-hash64.c59
-rw-r--r--target/ppc/mmu-hash64.h3
-rw-r--r--target/ppc/translate.c2
29 files changed, 864 insertions, 366 deletions
diff --git a/default-configs/ppc-softmmu.mak b/default-configs/ppc-softmmu.mak
index abeeb04..851b4af 100644
--- a/default-configs/ppc-softmmu.mak
+++ b/default-configs/ppc-softmmu.mak
@@ -26,6 +26,7 @@ CONFIG_USB_EHCI_SYSBUS=y
CONFIG_SM501=y
CONFIG_IDE_SII3112=y
CONFIG_I2C=y
+CONFIG_BITBANG_I2C=y
# For Macs
CONFIG_MAC=y
diff --git a/default-configs/ppcemb-softmmu.mak b/default-configs/ppcemb-softmmu.mak
index 67d18b2..37af193 100644
--- a/default-configs/ppcemb-softmmu.mak
+++ b/default-configs/ppcemb-softmmu.mak
@@ -19,3 +19,4 @@ CONFIG_USB_EHCI_SYSBUS=y
CONFIG_SM501=y
CONFIG_IDE_SII3112=y
CONFIG_I2C=y
+CONFIG_BITBANG_I2C=y
diff --git a/hw/display/sm501.c b/hw/display/sm501.c
index ca0840f..8206ae8 100644
--- a/hw/display/sm501.c
+++ b/hw/display/sm501.c
@@ -652,9 +652,9 @@ static inline void get_hwc_palette(SM501State *state, int crt, uint8_t *palette)
} else {
rgb565 = color_reg & 0xFFFF;
}
- palette[i * 3 + 0] = (rgb565 << 3) & 0xf8; /* red */
- palette[i * 3 + 1] = (rgb565 >> 3) & 0xfc; /* green */
- palette[i * 3 + 2] = (rgb565 >> 8) & 0xf8; /* blue */
+ palette[i * 3 + 0] = ((rgb565 >> 11) * 527 + 23) >> 6; /* r */
+ palette[i * 3 + 1] = (((rgb565 >> 5) & 0x3f) * 259 + 33) >> 6; /* g */
+ palette[i * 3 + 2] = ((rgb565 & 0x1f) * 527 + 23) >> 6; /* b */
}
}
diff --git a/hw/i2c/ppc4xx_i2c.c b/hw/i2c/ppc4xx_i2c.c
index d1936db..fca80d6 100644
--- a/hw/i2c/ppc4xx_i2c.c
+++ b/hw/i2c/ppc4xx_i2c.c
@@ -3,7 +3,7 @@
*
* Copyright (c) 2007 Jocelyn Mayer
* Copyright (c) 2012 François Revol
- * Copyright (c) 2016 BALATON Zoltan
+ * Copyright (c) 2016-2018 BALATON Zoltan
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -30,6 +30,7 @@
#include "cpu.h"
#include "hw/hw.h"
#include "hw/i2c/ppc4xx_i2c.h"
+#include "bitbang_i2c.h"
#define PPC4xx_I2C_MEM_SIZE 18
@@ -46,6 +47,11 @@
#define IIC_XTCNTLSS_SRST (1 << 0)
+#define IIC_DIRECTCNTL_SDAC (1 << 3)
+#define IIC_DIRECTCNTL_SCLC (1 << 2)
+#define IIC_DIRECTCNTL_MSDA (1 << 1)
+#define IIC_DIRECTCNTL_MSCL (1 << 0)
+
static void ppc4xx_i2c_reset(DeviceState *s)
{
PPC4xxI2CState *i2c = PPC4xx_I2C(s);
@@ -63,7 +69,6 @@ static void ppc4xx_i2c_reset(DeviceState *s)
i2c->mdcntl = 0;
i2c->sts = 0;
i2c->extsts = 0x8f;
- i2c->sdata = 0;
i2c->lsadr = 0;
i2c->hsadr = 0;
i2c->clkdiv = 0;
@@ -71,7 +76,6 @@ static void ppc4xx_i2c_reset(DeviceState *s)
i2c->xfrcnt = 0;
i2c->xtcntlss = 0;
i2c->directcntl = 0xf;
- i2c->intr = 0;
}
static inline bool ppc4xx_i2c_is_master(PPC4xxI2CState *i2c)
@@ -139,9 +143,6 @@ static uint64_t ppc4xx_i2c_readb(void *opaque, hwaddr addr, unsigned int size)
TYPE_PPC4xx_I2C, __func__);
}
break;
- case 2:
- ret = i2c->sdata;
- break;
case 4:
ret = i2c->lmadr;
break;
@@ -181,9 +182,6 @@ static uint64_t ppc4xx_i2c_readb(void *opaque, hwaddr addr, unsigned int size)
case 16:
ret = i2c->directcntl;
break;
- case 17:
- ret = i2c->intr;
- break;
default:
if (addr < PPC4xx_I2C_MEM_SIZE) {
qemu_log_mask(LOG_UNIMP, "%s: Unimplemented register 0x%"
@@ -229,9 +227,6 @@ static void ppc4xx_i2c_writeb(void *opaque, hwaddr addr, uint64_t value,
}
}
break;
- case 2:
- i2c->sdata = value;
- break;
case 4:
i2c->lmadr = value;
if (i2c_bus_busy(i2c->bus)) {
@@ -300,10 +295,12 @@ static void ppc4xx_i2c_writeb(void *opaque, hwaddr addr, uint64_t value,
i2c->xtcntlss = value;
break;
case 16:
- i2c->directcntl = value & 0x7;
- break;
- case 17:
- i2c->intr = value;
+ i2c->directcntl = value & (IIC_DIRECTCNTL_SDAC & IIC_DIRECTCNTL_SCLC);
+ i2c->directcntl |= (value & IIC_DIRECTCNTL_SCLC ? 1 : 0);
+ bitbang_i2c_set(i2c->bitbang, BITBANG_I2C_SCL,
+ i2c->directcntl & IIC_DIRECTCNTL_MSCL);
+ i2c->directcntl |= bitbang_i2c_set(i2c->bitbang, BITBANG_I2C_SDA,
+ (value & IIC_DIRECTCNTL_SDAC) != 0) << 1;
break;
default:
if (addr < PPC4xx_I2C_MEM_SIZE) {
@@ -336,6 +333,7 @@ static void ppc4xx_i2c_init(Object *o)
sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
sysbus_init_irq(SYS_BUS_DEVICE(s), &s->irq);
s->bus = i2c_init_bus(DEVICE(s), "i2c");
+ s->bitbang = bitbang_i2c_init(s->bus);
}
static void ppc4xx_i2c_class_init(ObjectClass *klass, void *data)
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index 0d2b79f..7401ffe 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -265,18 +265,6 @@ static void pnv_dt_icp(PnvChip *chip, void *fdt, uint32_t pir,
g_free(reg);
}
-static int pnv_chip_lpc_offset(PnvChip *chip, void *fdt)
-{
- char *name;
- int offset;
-
- name = g_strdup_printf("/xscom@%" PRIx64 "/isa@%x",
- (uint64_t) PNV_XSCOM_BASE(chip), PNV_XSCOM_LPC_BASE);
- offset = fdt_path_offset(fdt, name);
- g_free(name);
- return offset;
-}
-
static void pnv_dt_chip(PnvChip *chip, void *fdt)
{
const char *typename = pnv_chip_core_typename(chip);
@@ -285,16 +273,6 @@ static void pnv_dt_chip(PnvChip *chip, void *fdt)
pnv_dt_xscom(chip, fdt, 0);
- /* The default LPC bus of a multichip system is on chip 0. It's
- * recognized by the firmware (skiboot) using a "primary"
- * property.
- */
- if (chip->chip_id == 0x0) {
- int lpc_offset = pnv_chip_lpc_offset(chip, fdt);
-
- _FDT((fdt_setprop(fdt, lpc_offset, "primary", NULL, 0)));
- }
-
for (i = 0; i < chip->nr_cores; i++) {
PnvCore *pnv_core = PNV_CORE(chip->cores + i * typesize);
@@ -418,16 +396,35 @@ static int pnv_dt_isa_device(DeviceState *dev, void *opaque)
return 0;
}
-static void pnv_dt_isa(ISABus *bus, void *fdt, int lpc_offset)
+static int pnv_chip_isa_offset(PnvChip *chip, void *fdt)
{
+ char *name;
+ int offset;
+
+ name = g_strdup_printf("/xscom@%" PRIx64 "/isa@%x",
+ (uint64_t) PNV_XSCOM_BASE(chip), PNV_XSCOM_LPC_BASE);
+ offset = fdt_path_offset(fdt, name);
+ g_free(name);
+ return offset;
+}
+
+/* The default LPC bus of a multichip system is on chip 0. It's
+ * recognized by the firmware (skiboot) using a "primary" property.
+ */
+static void pnv_dt_isa(PnvMachineState *pnv, void *fdt)
+{
+ int isa_offset = pnv_chip_isa_offset(pnv->chips[0], fdt);
ForeachPopulateArgs args = {
.fdt = fdt,
- .offset = lpc_offset,
+ .offset = isa_offset,
};
+ _FDT((fdt_setprop(fdt, isa_offset, "primary", NULL, 0)));
+
/* ISA devices are not necessarily parented to the ISA bus so we
* can not use object_child_foreach() */
- qbus_walk_children(BUS(bus), pnv_dt_isa_device, NULL, NULL, NULL, &args);
+ qbus_walk_children(BUS(pnv->isa_bus), pnv_dt_isa_device, NULL, NULL, NULL,
+ &args);
}
static void *pnv_dt_create(MachineState *machine)
@@ -438,7 +435,6 @@ static void *pnv_dt_create(MachineState *machine)
char *buf;
int off;
int i;
- int lpc_offset;
fdt = g_malloc0(FDT_MAX_SIZE);
_FDT((fdt_create_empty_tree(fdt, FDT_MAX_SIZE)));
@@ -480,8 +476,7 @@ static void *pnv_dt_create(MachineState *machine)
}
/* Populate ISA devices on chip 0 */
- lpc_offset = pnv_chip_lpc_offset(pnv->chips[0], fdt);
- pnv_dt_isa(pnv->isa_bus, fdt, lpc_offset);
+ pnv_dt_isa(pnv, fdt);
if (pnv->bmc) {
pnv_dt_bmc_sensors(pnv->bmc, fdt);
@@ -529,24 +524,26 @@ static void pnv_reset(void)
cpu_physical_memory_write(PNV_FDT_ADDR, fdt, fdt_totalsize(fdt));
}
-static ISABus *pnv_isa_create(PnvChip *chip)
+static ISABus *pnv_chip_power8_isa_create(PnvChip *chip, Error **errp)
{
- PnvLpcController *lpc = &chip->lpc;
- ISABus *isa_bus;
- qemu_irq *irqs;
- PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
+ Pnv8Chip *chip8 = PNV8_CHIP(chip);
+ return pnv_lpc_isa_create(&chip8->lpc, true, errp);
+}
- /* let isa_bus_new() create its own bridge on SysBus otherwise
- * devices speficied on the command line won't find the bus and
- * will fail to create.
- */
- isa_bus = isa_bus_new(NULL, &lpc->isa_mem, &lpc->isa_io,
- &error_fatal);
+static ISABus *pnv_chip_power8nvl_isa_create(PnvChip *chip, Error **errp)
+{
+ Pnv8Chip *chip8 = PNV8_CHIP(chip);
+ return pnv_lpc_isa_create(&chip8->lpc, false, errp);
+}
- irqs = pnv_lpc_isa_irq_create(lpc, pcc->chip_type, ISA_NUM_IRQS);
+static ISABus *pnv_chip_power9_isa_create(PnvChip *chip, Error **errp)
+{
+ return NULL;
+}
- isa_bus_irqs(isa_bus, irqs);
- return isa_bus;
+static ISABus *pnv_isa_create(PnvChip *chip, Error **errp)
+{
+ return PNV_CHIP_GET_CLASS(chip)->isa_create(chip, errp);
}
static void pnv_init(MachineState *machine)
@@ -646,7 +643,7 @@ static void pnv_init(MachineState *machine)
g_free(chip_typename);
/* Instantiate ISA bus on chip 0 */
- pnv->isa_bus = pnv_isa_create(pnv->chips[0]);
+ pnv->isa_bus = pnv_isa_create(pnv->chips[0], &error_fatal);
/* Create serial port */
serial_hds_isa_init(pnv->isa_bus, 0, MAX_ISA_SERIAL_PORTS);
@@ -671,6 +668,13 @@ static uint32_t pnv_chip_core_pir_p8(PnvChip *chip, uint32_t core_id)
return (chip->chip_id << 7) | (core_id << 3);
}
+static Object *pnv_chip_power8_intc_create(PnvChip *chip, Object *child,
+ Error **errp)
+{
+ return icp_create(child, TYPE_PNV_ICP, XICS_FABRIC(qdev_get_machine()),
+ errp);
+}
+
/*
* 0:48 Reserved - Read as zeroes
* 49:52 Node ID
@@ -686,6 +690,12 @@ static uint32_t pnv_chip_core_pir_p9(PnvChip *chip, uint32_t core_id)
return (chip->chip_id << 8) | (core_id << 2);
}
+static Object *pnv_chip_power9_intc_create(PnvChip *chip, Object *child,
+ Error **errp)
+{
+ return NULL;
+}
+
/* Allowed core identifiers on a POWER8 Processor Chip :
*
* <EX0 reserved>
@@ -712,6 +722,103 @@ static uint32_t pnv_chip_core_pir_p9(PnvChip *chip, uint32_t core_id)
*/
#define POWER9_CORE_MASK (0xffffffffffffffull)
+static void pnv_chip_power8_instance_init(Object *obj)
+{
+ Pnv8Chip *chip8 = PNV8_CHIP(obj);
+
+ object_initialize(&chip8->psi, sizeof(chip8->psi), TYPE_PNV_PSI);
+ object_property_add_child(obj, "psi", OBJECT(&chip8->psi), NULL);
+ object_property_add_const_link(OBJECT(&chip8->psi), "xics",
+ OBJECT(qdev_get_machine()), &error_abort);
+
+ object_initialize(&chip8->lpc, sizeof(chip8->lpc), TYPE_PNV_LPC);
+ object_property_add_child(obj, "lpc", OBJECT(&chip8->lpc), NULL);
+ object_property_add_const_link(OBJECT(&chip8->lpc), "psi",
+ OBJECT(&chip8->psi), &error_abort);
+
+ object_initialize(&chip8->occ, sizeof(chip8->occ), TYPE_PNV_OCC);
+ object_property_add_child(obj, "occ", OBJECT(&chip8->occ), NULL);
+ object_property_add_const_link(OBJECT(&chip8->occ), "psi",
+ OBJECT(&chip8->psi), &error_abort);
+}
+
+static void pnv_chip_icp_realize(Pnv8Chip *chip8, Error **errp)
+ {
+ PnvChip *chip = PNV_CHIP(chip8);
+ PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
+ const char *typename = pnv_chip_core_typename(chip);
+ size_t typesize = object_type_get_instance_size(typename);
+ int i, j;
+ char *name;
+ XICSFabric *xi = XICS_FABRIC(qdev_get_machine());
+
+ name = g_strdup_printf("icp-%x", chip->chip_id);
+ memory_region_init(&chip8->icp_mmio, OBJECT(chip), name, PNV_ICP_SIZE);
+ sysbus_init_mmio(SYS_BUS_DEVICE(chip), &chip8->icp_mmio);
+ g_free(name);
+
+ sysbus_mmio_map(SYS_BUS_DEVICE(chip), 1, PNV_ICP_BASE(chip));
+
+ /* Map the ICP registers for each thread */
+ for (i = 0; i < chip->nr_cores; i++) {
+ PnvCore *pnv_core = PNV_CORE(chip->cores + i * typesize);
+ int core_hwid = CPU_CORE(pnv_core)->core_id;
+
+ for (j = 0; j < CPU_CORE(pnv_core)->nr_threads; j++) {
+ uint32_t pir = pcc->core_pir(chip, core_hwid) + j;
+ PnvICPState *icp = PNV_ICP(xics_icp_get(xi, pir));
+
+ memory_region_add_subregion(&chip8->icp_mmio, pir << 12,
+ &icp->mmio);
+ }
+ }
+}
+
+static void pnv_chip_power8_realize(DeviceState *dev, Error **errp)
+{
+ PnvChipClass *pcc = PNV_CHIP_GET_CLASS(dev);
+ PnvChip *chip = PNV_CHIP(dev);
+ Pnv8Chip *chip8 = PNV8_CHIP(dev);
+ Error *local_err = NULL;
+
+ pcc->parent_realize(dev, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ /* Processor Service Interface (PSI) Host Bridge */
+ object_property_set_int(OBJECT(&chip8->psi), PNV_PSIHB_BASE(chip),
+ "bar", &error_fatal);
+ object_property_set_bool(OBJECT(&chip8->psi), true, "realized", &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+ pnv_xscom_add_subregion(chip, PNV_XSCOM_PSIHB_BASE, &chip8->psi.xscom_regs);
+
+ /* Create LPC controller */
+ object_property_set_bool(OBJECT(&chip8->lpc), true, "realized",
+ &error_fatal);
+ pnv_xscom_add_subregion(chip, PNV_XSCOM_LPC_BASE, &chip8->lpc.xscom_regs);
+
+ /* Interrupt Management Area. This is the memory region holding
+ * all the Interrupt Control Presenter (ICP) registers */
+ pnv_chip_icp_realize(chip8, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ /* Create the simplified OCC model */
+ object_property_set_bool(OBJECT(&chip8->occ), true, "realized", &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+ pnv_xscom_add_subregion(chip, PNV_XSCOM_OCC_BASE, &chip8->occ.xscom_regs);
+}
+
static void pnv_chip_power8e_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -721,8 +828,13 @@ static void pnv_chip_power8e_class_init(ObjectClass *klass, void *data)
k->chip_cfam_id = 0x221ef04980000000ull; /* P8 Murano DD2.1 */
k->cores_mask = POWER8E_CORE_MASK;
k->core_pir = pnv_chip_core_pir_p8;
+ k->intc_create = pnv_chip_power8_intc_create;
+ k->isa_create = pnv_chip_power8_isa_create;
k->xscom_base = 0x003fc0000000000ull;
dc->desc = "PowerNV Chip POWER8E";
+
+ device_class_set_parent_realize(dc, pnv_chip_power8_realize,
+ &k->parent_realize);
}
static void pnv_chip_power8_class_init(ObjectClass *klass, void *data)
@@ -734,8 +846,13 @@ static void pnv_chip_power8_class_init(ObjectClass *klass, void *data)
k->chip_cfam_id = 0x220ea04980000000ull; /* P8 Venice DD2.0 */
k->cores_mask = POWER8_CORE_MASK;
k->core_pir = pnv_chip_core_pir_p8;
+ k->intc_create = pnv_chip_power8_intc_create;
+ k->isa_create = pnv_chip_power8_isa_create;
k->xscom_base = 0x003fc0000000000ull;
dc->desc = "PowerNV Chip POWER8";
+
+ device_class_set_parent_realize(dc, pnv_chip_power8_realize,
+ &k->parent_realize);
}
static void pnv_chip_power8nvl_class_init(ObjectClass *klass, void *data)
@@ -747,8 +864,29 @@ static void pnv_chip_power8nvl_class_init(ObjectClass *klass, void *data)
k->chip_cfam_id = 0x120d304980000000ull; /* P8 Naples DD1.0 */
k->cores_mask = POWER8_CORE_MASK;
k->core_pir = pnv_chip_core_pir_p8;
+ k->intc_create = pnv_chip_power8_intc_create;
+ k->isa_create = pnv_chip_power8nvl_isa_create;
k->xscom_base = 0x003fc0000000000ull;
dc->desc = "PowerNV Chip POWER8NVL";
+
+ device_class_set_parent_realize(dc, pnv_chip_power8_realize,
+ &k->parent_realize);
+}
+
+static void pnv_chip_power9_instance_init(Object *obj)
+{
+}
+
+static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
+{
+ PnvChipClass *pcc = PNV_CHIP_GET_CLASS(dev);
+ Error *local_err = NULL;
+
+ pcc->parent_realize(dev, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
}
static void pnv_chip_power9_class_init(ObjectClass *klass, void *data)
@@ -760,8 +898,13 @@ static void pnv_chip_power9_class_init(ObjectClass *klass, void *data)
k->chip_cfam_id = 0x220d104900008000ull; /* P9 Nimbus DD2.0 */
k->cores_mask = POWER9_CORE_MASK;
k->core_pir = pnv_chip_core_pir_p9;
+ k->intc_create = pnv_chip_power9_intc_create;
+ k->isa_create = pnv_chip_power9_isa_create;
k->xscom_base = 0x00603fc00000000ull;
dc->desc = "PowerNV Chip POWER9";
+
+ device_class_set_parent_realize(dc, pnv_chip_power9_realize,
+ &k->parent_realize);
}
static void pnv_chip_core_sanitize(PnvChip *chip, Error **errp)
@@ -794,59 +937,9 @@ static void pnv_chip_core_sanitize(PnvChip *chip, Error **errp)
}
}
-static void pnv_chip_init(Object *obj)
+static void pnv_chip_instance_init(Object *obj)
{
- PnvChip *chip = PNV_CHIP(obj);
- PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
-
- chip->xscom_base = pcc->xscom_base;
-
- object_initialize(&chip->lpc, sizeof(chip->lpc), TYPE_PNV_LPC);
- object_property_add_child(obj, "lpc", OBJECT(&chip->lpc), NULL);
-
- object_initialize(&chip->psi, sizeof(chip->psi), TYPE_PNV_PSI);
- object_property_add_child(obj, "psi", OBJECT(&chip->psi), NULL);
- object_property_add_const_link(OBJECT(&chip->psi), "xics",
- OBJECT(qdev_get_machine()), &error_abort);
-
- object_initialize(&chip->occ, sizeof(chip->occ), TYPE_PNV_OCC);
- object_property_add_child(obj, "occ", OBJECT(&chip->occ), NULL);
- object_property_add_const_link(OBJECT(&chip->occ), "psi",
- OBJECT(&chip->psi), &error_abort);
-
- /* The LPC controller needs PSI to generate interrupts */
- object_property_add_const_link(OBJECT(&chip->lpc), "psi",
- OBJECT(&chip->psi), &error_abort);
-}
-
-static void pnv_chip_icp_realize(PnvChip *chip, Error **errp)
-{
- PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
- const char *typename = pnv_chip_core_typename(chip);
- size_t typesize = object_type_get_instance_size(typename);
- int i, j;
- char *name;
- XICSFabric *xi = XICS_FABRIC(qdev_get_machine());
-
- name = g_strdup_printf("icp-%x", chip->chip_id);
- memory_region_init(&chip->icp_mmio, OBJECT(chip), name, PNV_ICP_SIZE);
- sysbus_init_mmio(SYS_BUS_DEVICE(chip), &chip->icp_mmio);
- g_free(name);
-
- sysbus_mmio_map(SYS_BUS_DEVICE(chip), 1, PNV_ICP_BASE(chip));
-
- /* Map the ICP registers for each thread */
- for (i = 0; i < chip->nr_cores; i++) {
- PnvCore *pnv_core = PNV_CORE(chip->cores + i * typesize);
- int core_hwid = CPU_CORE(pnv_core)->core_id;
-
- for (j = 0; j < CPU_CORE(pnv_core)->nr_threads; j++) {
- uint32_t pir = pcc->core_pir(chip, core_hwid) + j;
- PnvICPState *icp = PNV_ICP(xics_icp_get(xi, pir));
-
- memory_region_add_subregion(&chip->icp_mmio, pir << 12, &icp->mmio);
- }
- }
+ PNV_CHIP(obj)->xscom_base = PNV_CHIP_GET_CLASS(obj)->xscom_base;
}
static void pnv_chip_core_realize(PnvChip *chip, Error **errp)
@@ -892,8 +985,8 @@ static void pnv_chip_core_realize(PnvChip *chip, Error **errp)
object_property_set_int(OBJECT(pnv_core),
pcc->core_pir(chip, core_hwid),
"pir", &error_fatal);
- object_property_add_const_link(OBJECT(pnv_core), "xics",
- qdev_get_machine(), &error_fatal);
+ object_property_add_const_link(OBJECT(pnv_core), "chip",
+ OBJECT(chip), &error_fatal);
object_property_set_bool(OBJECT(pnv_core), true, "realized",
&error_fatal);
object_unref(OBJECT(pnv_core));
@@ -930,37 +1023,6 @@ static void pnv_chip_realize(DeviceState *dev, Error **errp)
error_propagate(errp, error);
return;
}
-
- /* Create LPC controller */
- object_property_set_bool(OBJECT(&chip->lpc), true, "realized",
- &error_fatal);
- pnv_xscom_add_subregion(chip, PNV_XSCOM_LPC_BASE, &chip->lpc.xscom_regs);
-
- /* Interrupt Management Area. This is the memory region holding
- * all the Interrupt Control Presenter (ICP) registers */
- pnv_chip_icp_realize(chip, &error);
- if (error) {
- error_propagate(errp, error);
- return;
- }
-
- /* Processor Service Interface (PSI) Host Bridge */
- object_property_set_int(OBJECT(&chip->psi), PNV_PSIHB_BASE(chip),
- "bar", &error_fatal);
- object_property_set_bool(OBJECT(&chip->psi), true, "realized", &error);
- if (error) {
- error_propagate(errp, error);
- return;
- }
- pnv_xscom_add_subregion(chip, PNV_XSCOM_PSIHB_BASE, &chip->psi.xscom_regs);
-
- /* Create the simplified OCC model */
- object_property_set_bool(OBJECT(&chip->occ), true, "realized", &error);
- if (error) {
- error_propagate(errp, error);
- return;
- }
- pnv_xscom_add_subregion(chip, PNV_XSCOM_OCC_BASE, &chip->occ.xscom_regs);
}
static Property pnv_chip_properties[] = {
@@ -988,8 +1050,10 @@ static ICSState *pnv_ics_get(XICSFabric *xi, int irq)
int i;
for (i = 0; i < pnv->num_chips; i++) {
- if (ics_valid_irq(&pnv->chips[i]->psi.ics, irq)) {
- return &pnv->chips[i]->psi.ics;
+ Pnv8Chip *chip8 = PNV8_CHIP(pnv->chips[i]);
+
+ if (ics_valid_irq(&chip8->psi.ics, irq)) {
+ return &chip8->psi.ics;
}
}
return NULL;
@@ -1001,7 +1065,8 @@ static void pnv_ics_resend(XICSFabric *xi)
int i;
for (i = 0; i < pnv->num_chips; i++) {
- ics_resend(&pnv->chips[i]->psi.ics);
+ Pnv8Chip *chip8 = PNV8_CHIP(pnv->chips[i]);
+ ics_resend(&chip8->psi.ics);
}
}
@@ -1042,7 +1107,8 @@ static void pnv_pic_print_info(InterruptStatsProvider *obj,
}
for (i = 0; i < pnv->num_chips; i++) {
- ics_pic_print_info(&pnv->chips[i]->psi.ics, mon);
+ Pnv8Chip *chip8 = PNV8_CHIP(pnv->chips[i]);
+ ics_pic_print_info(&chip8->psi.ics, mon);
}
}
@@ -1077,7 +1143,7 @@ static void pnv_set_num_chips(Object *obj, Visitor *v, const char *name,
pnv->num_chips = num_chips;
}
-static void pnv_machine_initfn(Object *obj)
+static void pnv_machine_instance_init(Object *obj)
{
PnvMachineState *pnv = PNV_MACHINE(obj);
pnv->num_chips = 1;
@@ -1117,11 +1183,18 @@ static void pnv_machine_class_init(ObjectClass *oc, void *data)
pnv_machine_class_props_init(oc);
}
-#define DEFINE_PNV_CHIP_TYPE(type, class_initfn) \
- { \
- .name = type, \
- .class_init = class_initfn, \
- .parent = TYPE_PNV_CHIP, \
+#define DEFINE_PNV8_CHIP_TYPE(type, class_initfn) \
+ { \
+ .name = type, \
+ .class_init = class_initfn, \
+ .parent = TYPE_PNV8_CHIP, \
+ }
+
+#define DEFINE_PNV9_CHIP_TYPE(type, class_initfn) \
+ { \
+ .name = type, \
+ .class_init = class_initfn, \
+ .parent = TYPE_PNV9_CHIP, \
}
static const TypeInfo types[] = {
@@ -1129,7 +1202,7 @@ static const TypeInfo types[] = {
.name = TYPE_PNV_MACHINE,
.parent = TYPE_MACHINE,
.instance_size = sizeof(PnvMachineState),
- .instance_init = pnv_machine_initfn,
+ .instance_init = pnv_machine_instance_init,
.class_init = pnv_machine_class_init,
.interfaces = (InterfaceInfo[]) {
{ TYPE_XICS_FABRIC },
@@ -1141,16 +1214,36 @@ static const TypeInfo types[] = {
.name = TYPE_PNV_CHIP,
.parent = TYPE_SYS_BUS_DEVICE,
.class_init = pnv_chip_class_init,
- .instance_init = pnv_chip_init,
+ .instance_init = pnv_chip_instance_init,
.instance_size = sizeof(PnvChip),
.class_size = sizeof(PnvChipClass),
.abstract = true,
},
- DEFINE_PNV_CHIP_TYPE(TYPE_PNV_CHIP_POWER9, pnv_chip_power9_class_init),
- DEFINE_PNV_CHIP_TYPE(TYPE_PNV_CHIP_POWER8, pnv_chip_power8_class_init),
- DEFINE_PNV_CHIP_TYPE(TYPE_PNV_CHIP_POWER8E, pnv_chip_power8e_class_init),
- DEFINE_PNV_CHIP_TYPE(TYPE_PNV_CHIP_POWER8NVL,
- pnv_chip_power8nvl_class_init),
+
+ /*
+ * P9 chip and variants
+ */
+ {
+ .name = TYPE_PNV9_CHIP,
+ .parent = TYPE_PNV_CHIP,
+ .instance_init = pnv_chip_power9_instance_init,
+ .instance_size = sizeof(Pnv9Chip),
+ },
+ DEFINE_PNV9_CHIP_TYPE(TYPE_PNV_CHIP_POWER9, pnv_chip_power9_class_init),
+
+ /*
+ * P8 chip and variants
+ */
+ {
+ .name = TYPE_PNV8_CHIP,
+ .parent = TYPE_PNV_CHIP,
+ .instance_init = pnv_chip_power8_instance_init,
+ .instance_size = sizeof(Pnv8Chip),
+ },
+ DEFINE_PNV8_CHIP_TYPE(TYPE_PNV_CHIP_POWER8, pnv_chip_power8_class_init),
+ DEFINE_PNV8_CHIP_TYPE(TYPE_PNV_CHIP_POWER8E, pnv_chip_power8e_class_init),
+ DEFINE_PNV8_CHIP_TYPE(TYPE_PNV_CHIP_POWER8NVL,
+ pnv_chip_power8nvl_class_init),
};
DEFINE_TYPES(types)
diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c
index f7cf33f..a9f129f 100644
--- a/hw/ppc/pnv_core.c
+++ b/hw/ppc/pnv_core.c
@@ -99,13 +99,14 @@ static const MemoryRegionOps pnv_core_xscom_ops = {
.endianness = DEVICE_BIG_ENDIAN,
};
-static void pnv_realize_vcpu(PowerPCCPU *cpu, XICSFabric *xi, Error **errp)
+static void pnv_realize_vcpu(PowerPCCPU *cpu, PnvChip *chip, Error **errp)
{
CPUPPCState *env = &cpu->env;
int core_pir;
int thread_index = 0; /* TODO: TCG supports only one thread */
ppc_spr_t *pir = &env->spr_cb[SPR_PIR];
Error *local_err = NULL;
+ PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
object_property_set_bool(OBJECT(cpu), true, "realized", &local_err);
if (local_err) {
@@ -113,7 +114,7 @@ static void pnv_realize_vcpu(PowerPCCPU *cpu, XICSFabric *xi, Error **errp)
return;
}
- cpu->intc = icp_create(OBJECT(cpu), TYPE_PNV_ICP, xi, &local_err);
+ cpu->intc = pcc->intc_create(chip, OBJECT(cpu), &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
@@ -143,13 +144,12 @@ static void pnv_core_realize(DeviceState *dev, Error **errp)
void *obj;
int i, j;
char name[32];
- Object *xi;
+ Object *chip;
- xi = object_property_get_link(OBJECT(dev), "xics", &local_err);
- if (!xi) {
- error_setg(errp, "%s: required link 'xics' not found: %s",
- __func__, error_get_pretty(local_err));
- return;
+ chip = object_property_get_link(OBJECT(dev), "chip", &local_err);
+ if (!chip) {
+ error_propagate(errp, local_err);
+ error_prepend(errp, "required link 'chip' not found: ");
}
pc->threads = g_new(PowerPCCPU *, cc->nr_threads);
@@ -166,7 +166,7 @@ static void pnv_core_realize(DeviceState *dev, Error **errp)
}
for (j = 0; j < cc->nr_threads; j++) {
- pnv_realize_vcpu(pc->threads[j], XICS_FABRIC(xi), &local_err);
+ pnv_realize_vcpu(pc->threads[j], PNV_CHIP(chip), &local_err);
if (local_err) {
goto err;
}
diff --git a/hw/ppc/pnv_lpc.c b/hw/ppc/pnv_lpc.c
index 402c4fe..d772132 100644
--- a/hw/ppc/pnv_lpc.c
+++ b/hw/ppc/pnv_lpc.c
@@ -22,6 +22,7 @@
#include "target/ppc/cpu.h"
#include "qapi/error.h"
#include "qemu/log.h"
+#include "hw/isa/isa.h"
#include "hw/ppc/pnv.h"
#include "hw/ppc/pnv_lpc.h"
@@ -535,16 +536,35 @@ static void pnv_lpc_isa_irq_handler(void *opaque, int n, int level)
}
}
-qemu_irq *pnv_lpc_isa_irq_create(PnvLpcController *lpc, int chip_type,
- int nirqs)
+ISABus *pnv_lpc_isa_create(PnvLpcController *lpc, bool use_cpld, Error **errp)
{
+ Error *local_err = NULL;
+ ISABus *isa_bus;
+ qemu_irq *irqs;
+ qemu_irq_handler handler;
+
+ /* let isa_bus_new() create its own bridge on SysBus otherwise
+ * devices speficied on the command line won't find the bus and
+ * will fail to create.
+ */
+ isa_bus = isa_bus_new(NULL, &lpc->isa_mem, &lpc->isa_io, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return NULL;
+ }
+
/* Not all variants have a working serial irq decoder. If not,
* handling of LPC interrupts becomes a platform issue (some
* platforms have a CPLD to do it).
*/
- if (chip_type == PNV_CHIP_POWER8NVL) {
- return qemu_allocate_irqs(pnv_lpc_isa_irq_handler, lpc, nirqs);
+ if (use_cpld) {
+ handler = pnv_lpc_isa_irq_handler_cpld;
} else {
- return qemu_allocate_irqs(pnv_lpc_isa_irq_handler_cpld, lpc, nirqs);
+ handler = pnv_lpc_isa_irq_handler;
}
+
+ irqs = qemu_allocate_irqs(handler, lpc, ISA_NUM_IRQS);
+
+ isa_bus_irqs(isa_bus, irqs);
+ return isa_bus;
}
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index db0fb38..0d032a1 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -63,6 +63,7 @@
#include "hw/virtio/vhost-scsi-common.h"
#include "exec/address-spaces.h"
+#include "exec/ram_addr.h"
#include "hw/usb.h"
#include "qemu/config-file.h"
#include "qemu/error-report.h"
@@ -1612,12 +1613,12 @@ static void spapr_machine_reset(void)
void *fdt;
int rc;
- spapr_caps_reset(spapr);
+ spapr_caps_apply(spapr);
first_ppc_cpu = POWERPC_CPU(first_cpu);
if (kvm_enabled() && kvmppc_has_cap_mmu_radix() &&
- ppc_check_compat(first_ppc_cpu, CPU_POWERPC_LOGICAL_3_00, 0,
- spapr->max_compat_pvr)) {
+ ppc_type_check_compat(machine->cpu_type, CPU_POWERPC_LOGICAL_3_00, 0,
+ spapr->max_compat_pvr)) {
/* If using KVM with radix mode available, VCPUs can be started
* without a HPT because KVM will start them in radix mode.
* Set the GR bit in PATB so that we know there is no HPT. */
@@ -2520,14 +2521,15 @@ static void spapr_machine_init(MachineState *machine)
long load_limit, fw_size;
char *filename;
Error *resize_hpt_err = NULL;
- PowerPCCPU *first_ppc_cpu;
msi_nonbroken = true;
QLIST_INIT(&spapr->phbs);
QTAILQ_INIT(&spapr->pending_dimm_unplugs);
- /* Check HPT resizing availability */
+ /* Determine capabilities to run with */
+ spapr_caps_init(spapr);
+
kvmppc_check_papr_resize_hpt(&resize_hpt_err);
if (spapr->resize_hpt == SPAPR_RESIZE_HPT_DEFAULT) {
/*
@@ -2618,10 +2620,9 @@ static void spapr_machine_init(MachineState *machine)
/* init CPUs */
spapr_init_cpus(spapr);
- first_ppc_cpu = POWERPC_CPU(first_cpu);
if ((!kvm_enabled() || kvmppc_has_cap_mmu_radix()) &&
- ppc_check_compat(first_ppc_cpu, CPU_POWERPC_LOGICAL_3_00, 0,
- spapr->max_compat_pvr)) {
+ ppc_type_check_compat(machine->cpu_type, CPU_POWERPC_LOGICAL_3_00, 0,
+ spapr->max_compat_pvr)) {
/* KVM and TCG always allow GTSE with radix... */
spapr_ovec_set(spapr->ov5, OV5_MMU_RADIX_GTSE);
}
@@ -3191,11 +3192,13 @@ static void spapr_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
Error **errp)
{
const sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(hotplug_dev);
+ sPAPRMachineState *spapr = SPAPR_MACHINE(hotplug_dev);
PCDIMMDevice *dimm = PC_DIMM(dev);
PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(dimm);
MemoryRegion *mr;
uint64_t size;
- char *mem_dev;
+ Object *memdev;
+ hwaddr pagesize;
if (!smc->dr_lmb_enabled) {
error_setg(errp, "Memory hotplug not supported for this machine");
@@ -3214,15 +3217,10 @@ static void spapr_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
return;
}
- mem_dev = object_property_get_str(OBJECT(dimm), PC_DIMM_MEMDEV_PROP, NULL);
- if (mem_dev && !kvmppc_is_mem_backend_page_size_ok(mem_dev)) {
- error_setg(errp, "Memory backend has bad page size. "
- "Use 'memory-backend-file' with correct mem-path.");
- goto out;
- }
-
-out:
- g_free(mem_dev);
+ memdev = object_property_get_link(OBJECT(dimm), PC_DIMM_MEMDEV_PROP,
+ &error_abort);
+ pagesize = host_memory_backend_pagesize(MEMORY_BACKEND(memdev));
+ spapr_check_pagesize(spapr, pagesize, errp);
}
struct sPAPRDIMMState {
@@ -3816,52 +3814,10 @@ static int ics_find_free_block(ICSState *ics, int num, int alignnum)
return -1;
}
-/*
- * Allocate the IRQ number and set the IRQ type, LSI or MSI
- */
-static void spapr_irq_set_lsi(sPAPRMachineState *spapr, int irq, bool lsi)
-{
- ics_set_irq_type(spapr->ics, irq - spapr->ics->offset, lsi);
-}
-
-int spapr_irq_alloc(sPAPRMachineState *spapr, int irq_hint, bool lsi,
- Error **errp)
-{
- ICSState *ics = spapr->ics;
- int irq;
-
- assert(ics);
-
- if (irq_hint) {
- if (!ICS_IRQ_FREE(ics, irq_hint - ics->offset)) {
- error_setg(errp, "can't allocate IRQ %d: already in use", irq_hint);
- return -1;
- }
- irq = irq_hint;
- } else {
- irq = ics_find_free_block(ics, 1, 1);
- if (irq < 0) {
- error_setg(errp, "can't allocate IRQ: no IRQ left");
- return -1;
- }
- irq += ics->offset;
- }
-
- spapr_irq_set_lsi(spapr, irq, lsi);
- trace_spapr_irq_alloc(irq);
-
- return irq;
-}
-
-/*
- * Allocate block of consecutive IRQs, and return the number of the first IRQ in
- * the block. If align==true, aligns the first IRQ number to num.
- */
-int spapr_irq_alloc_block(sPAPRMachineState *spapr, int num, bool lsi,
- bool align, Error **errp)
+int spapr_irq_find(sPAPRMachineState *spapr, int num, bool align, Error **errp)
{
ICSState *ics = spapr->ics;
- int i, first = -1;
+ int first = -1;
assert(ics);
@@ -3879,19 +3835,33 @@ int spapr_irq_alloc_block(sPAPRMachineState *spapr, int num, bool lsi,
} else {
first = ics_find_free_block(ics, num, 1);
}
+
if (first < 0) {
error_setg(errp, "can't find a free %d-IRQ block", num);
return -1;
}
- first += ics->offset;
- for (i = first; i < first + num; ++i) {
- spapr_irq_set_lsi(spapr, i, lsi);
+ return first + ics->offset;
+}
+
+int spapr_irq_claim(sPAPRMachineState *spapr, int irq, bool lsi, Error **errp)
+{
+ ICSState *ics = spapr->ics;
+
+ assert(ics);
+
+ if (!ics_valid_irq(ics, irq)) {
+ error_setg(errp, "IRQ %d is invalid", irq);
+ return -1;
}
- trace_spapr_irq_alloc_block(first, num, lsi, align);
+ if (!ICS_IRQ_FREE(ics, irq - ics->offset)) {
+ error_setg(errp, "IRQ %d is not free", irq);
+ return -1;
+ }
- return first;
+ ics_set_irq_type(ics, irq - ics->offset, lsi);
+ return 0;
}
void spapr_irq_free(sPAPRMachineState *spapr, int irq, int num)
@@ -4043,6 +4013,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data)
smc->default_caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_BROKEN;
smc->default_caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_BROKEN;
smc->default_caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_BROKEN;
+ smc->default_caps.caps[SPAPR_CAP_HPT_MAXPAGESIZE] = 16; /* 64kiB */
spapr_caps_add_properties(smc, &error_abort);
}
@@ -4115,7 +4086,12 @@ DEFINE_SPAPR_MACHINE(3_0, "3.0", true);
HW_COMPAT_2_12 \
{ \
.driver = TYPE_POWERPC_CPU, \
- .property = "pre-3.0-migration", \
+ .property = "pre-3.0-migration", \
+ .value = "on", \
+ }, \
+ { \
+ .driver = TYPE_SPAPR_CPU_CORE, \
+ .property = "pre-3.0-migration", \
.value = "on", \
},
@@ -4126,8 +4102,18 @@ static void spapr_machine_2_12_instance_options(MachineState *machine)
static void spapr_machine_2_12_class_options(MachineClass *mc)
{
+ sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
+ uint8_t mps;
+
spapr_machine_3_0_class_options(mc);
SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_12);
+
+ if (kvmppc_hpt_needs_host_contiguous_pages()) {
+ mps = ctz64(qemu_getrampagesize());
+ } else {
+ mps = 34; /* allow everything up to 16GiB, i.e. everything */
+ }
+ smc->default_caps.caps[SPAPR_CAP_HPT_MAXPAGESIZE] = mps;
}
DEFINE_SPAPR_MACHINE(2_12, "2.12", false);
diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c
index 00e43a9..62663eb 100644
--- a/hw/ppc/spapr_caps.c
+++ b/hw/ppc/spapr_caps.c
@@ -26,7 +26,9 @@
#include "qapi/error.h"
#include "qapi/visitor.h"
#include "sysemu/hw_accel.h"
+#include "exec/ram_addr.h"
#include "target/ppc/cpu.h"
+#include "target/ppc/mmu-hash64.h"
#include "cpu-models.h"
#include "kvm_ppc.h"
@@ -59,6 +61,8 @@ typedef struct sPAPRCapabilityInfo {
sPAPRCapPossible *possible;
/* Make sure the virtual hardware can support this capability */
void (*apply)(sPAPRMachineState *spapr, uint8_t val, Error **errp);
+ void (*cpu_apply)(sPAPRMachineState *spapr, PowerPCCPU *cpu,
+ uint8_t val, Error **errp);
} sPAPRCapabilityInfo;
static void spapr_cap_get_bool(Object *obj, Visitor *v, const char *name,
@@ -142,6 +146,42 @@ out:
g_free(val);
}
+static void spapr_cap_get_pagesize(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ sPAPRCapabilityInfo *cap = opaque;
+ sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
+ uint8_t val = spapr_get_cap(spapr, cap->index);
+ uint64_t pagesize = (1ULL << val);
+
+ visit_type_size(v, name, &pagesize, errp);
+}
+
+static void spapr_cap_set_pagesize(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ sPAPRCapabilityInfo *cap = opaque;
+ sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
+ uint64_t pagesize;
+ uint8_t val;
+ Error *local_err = NULL;
+
+ visit_type_size(v, name, &pagesize, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ if (!is_power_of_2(pagesize)) {
+ error_setg(errp, "cap-%s must be a power of 2", cap->name);
+ return;
+ }
+
+ val = ctz64(pagesize);
+ spapr->cmd_line_caps[cap->index] = true;
+ spapr->eff.caps[cap->index] = val;
+}
+
static void cap_htm_apply(sPAPRMachineState *spapr, uint8_t val, Error **errp)
{
if (!val) {
@@ -265,6 +305,69 @@ static void cap_safe_indirect_branch_apply(sPAPRMachineState *spapr,
#define VALUE_DESC_TRISTATE " (broken, workaround, fixed)"
+void spapr_check_pagesize(sPAPRMachineState *spapr, hwaddr pagesize,
+ Error **errp)
+{
+ hwaddr maxpagesize = (1ULL << spapr->eff.caps[SPAPR_CAP_HPT_MAXPAGESIZE]);
+
+ if (!kvmppc_hpt_needs_host_contiguous_pages()) {
+ return;
+ }
+
+ if (maxpagesize > pagesize) {
+ error_setg(errp,
+ "Can't support %"HWADDR_PRIu" kiB guest pages with %"
+ HWADDR_PRIu" kiB host pages with this KVM implementation",
+ maxpagesize >> 10, pagesize >> 10);
+ }
+}
+
+static void cap_hpt_maxpagesize_apply(sPAPRMachineState *spapr,
+ uint8_t val, Error **errp)
+{
+ if (val < 12) {
+ error_setg(errp, "Require at least 4kiB hpt-max-page-size");
+ return;
+ } else if (val < 16) {
+ warn_report("Many guests require at least 64kiB hpt-max-page-size");
+ }
+
+ spapr_check_pagesize(spapr, qemu_getrampagesize(), errp);
+}
+
+static bool spapr_pagesize_cb(void *opaque, uint32_t seg_pshift,
+ uint32_t pshift)
+{
+ unsigned maxshift = *((unsigned *)opaque);
+
+ assert(pshift >= seg_pshift);
+
+ /* Don't allow the guest to use pages bigger than the configured
+ * maximum size */
+ if (pshift > maxshift) {
+ return false;
+ }
+
+ /* For whatever reason, KVM doesn't allow multiple pagesizes
+ * within a segment, *except* for the case of 16M pages in a 4k or
+ * 64k segment. Always exclude other cases, so that TCG and KVM
+ * guests see a consistent environment */
+ if ((pshift != seg_pshift) && (pshift != 24)) {
+ return false;
+ }
+
+ return true;
+}
+
+static void cap_hpt_maxpagesize_cpu_apply(sPAPRMachineState *spapr,
+ PowerPCCPU *cpu,
+ uint8_t val, Error **errp)
+{
+ unsigned maxshift = val;
+
+ ppc_hash64_filter_pagesizes(cpu, spapr_pagesize_cb, &maxshift);
+}
+
sPAPRCapabilityInfo capability_table[SPAPR_CAP_NUM] = {
[SPAPR_CAP_HTM] = {
.name = "htm",
@@ -324,30 +427,39 @@ sPAPRCapabilityInfo capability_table[SPAPR_CAP_NUM] = {
.possible = &cap_ibs_possible,
.apply = cap_safe_indirect_branch_apply,
},
+ [SPAPR_CAP_HPT_MAXPAGESIZE] = {
+ .name = "hpt-max-page-size",
+ .description = "Maximum page size for Hash Page Table guests",
+ .index = SPAPR_CAP_HPT_MAXPAGESIZE,
+ .get = spapr_cap_get_pagesize,
+ .set = spapr_cap_set_pagesize,
+ .type = "int",
+ .apply = cap_hpt_maxpagesize_apply,
+ .cpu_apply = cap_hpt_maxpagesize_cpu_apply,
+ },
};
static sPAPRCapabilities default_caps_with_cpu(sPAPRMachineState *spapr,
- CPUState *cs)
+ const char *cputype)
{
sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
- PowerPCCPU *cpu = POWERPC_CPU(cs);
sPAPRCapabilities caps;
caps = smc->default_caps;
- if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_07,
- 0, spapr->max_compat_pvr)) {
+ if (!ppc_type_check_compat(cputype, CPU_POWERPC_LOGICAL_2_07,
+ 0, spapr->max_compat_pvr)) {
caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_OFF;
caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_BROKEN;
}
- if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_06_PLUS,
- 0, spapr->max_compat_pvr)) {
+ if (!ppc_type_check_compat(cputype, CPU_POWERPC_LOGICAL_2_06_PLUS,
+ 0, spapr->max_compat_pvr)) {
caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_BROKEN;
}
- if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_06,
- 0, spapr->max_compat_pvr)) {
+ if (!ppc_type_check_compat(cputype, CPU_POWERPC_LOGICAL_2_06,
+ 0, spapr->max_compat_pvr)) {
caps.caps[SPAPR_CAP_VSX] = SPAPR_CAP_OFF;
caps.caps[SPAPR_CAP_DFP] = SPAPR_CAP_OFF;
caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_BROKEN;
@@ -384,7 +496,7 @@ int spapr_caps_post_migration(sPAPRMachineState *spapr)
sPAPRCapabilities dstcaps = spapr->eff;
sPAPRCapabilities srccaps;
- srccaps = default_caps_with_cpu(spapr, first_cpu);
+ srccaps = default_caps_with_cpu(spapr, MACHINE(spapr)->cpu_type);
for (i = 0; i < SPAPR_CAP_NUM; i++) {
/* If not default value then assume came in with the migration */
if (spapr->mig.caps[i] != spapr->def.caps[i]) {
@@ -440,13 +552,13 @@ SPAPR_CAP_MIG_STATE(cfpc, SPAPR_CAP_CFPC);
SPAPR_CAP_MIG_STATE(sbbc, SPAPR_CAP_SBBC);
SPAPR_CAP_MIG_STATE(ibs, SPAPR_CAP_IBS);
-void spapr_caps_reset(sPAPRMachineState *spapr)
+void spapr_caps_init(sPAPRMachineState *spapr)
{
sPAPRCapabilities default_caps;
int i;
- /* First compute the actual set of caps we're running with.. */
- default_caps = default_caps_with_cpu(spapr, first_cpu);
+ /* Compute the actual set of caps we should run with */
+ default_caps = default_caps_with_cpu(spapr, MACHINE(spapr)->cpu_type);
for (i = 0; i < SPAPR_CAP_NUM; i++) {
/* Store the defaults */
@@ -456,8 +568,11 @@ void spapr_caps_reset(sPAPRMachineState *spapr)
spapr->eff.caps[i] = default_caps.caps[i];
}
}
+}
- /* .. then apply those caps to the virtual hardware */
+void spapr_caps_apply(sPAPRMachineState *spapr)
+{
+ int i;
for (i = 0; i < SPAPR_CAP_NUM; i++) {
sPAPRCapabilityInfo *info = &capability_table[i];
@@ -470,6 +585,23 @@ void spapr_caps_reset(sPAPRMachineState *spapr)
}
}
+void spapr_caps_cpu_apply(sPAPRMachineState *spapr, PowerPCCPU *cpu)
+{
+ int i;
+
+ for (i = 0; i < SPAPR_CAP_NUM; i++) {
+ sPAPRCapabilityInfo *info = &capability_table[i];
+
+ /*
+ * If the apply function can't set the desired level and thinks it's
+ * fatal, it should cause that.
+ */
+ if (info->cpu_apply) {
+ info->cpu_apply(spapr, cpu, spapr->eff.caps[i], &error_fatal);
+ }
+ }
+}
+
void spapr_caps_add_properties(sPAPRMachineClass *smc, Error **errp)
{
Error *local_err = NULL;
diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c
index aef3be3..993759d 100644
--- a/hw/ppc/spapr_cpu_core.c
+++ b/hw/ppc/spapr_cpu_core.c
@@ -76,6 +76,10 @@ static void spapr_cpu_reset(void *opaque)
spapr_cpu->slb_shadow_size = 0;
spapr_cpu->dtl_addr = 0;
spapr_cpu->dtl_size = 0;
+
+ spapr_caps_cpu_apply(SPAPR_MACHINE(qdev_get_machine()), cpu);
+
+ kvm_check_mmu(cpu, &error_fatal);
}
void spapr_cpu_set_entry_state(PowerPCCPU *cpu, target_ulong nip, target_ulong r3)
@@ -129,6 +133,80 @@ static void spapr_cpu_core_unrealize(DeviceState *dev, Error **errp)
g_free(sc->threads);
}
+static bool slb_shadow_needed(void *opaque)
+{
+ sPAPRCPUState *spapr_cpu = opaque;
+
+ return spapr_cpu->slb_shadow_addr != 0;
+}
+
+static const VMStateDescription vmstate_spapr_cpu_slb_shadow = {
+ .name = "spapr_cpu/vpa/slb_shadow",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = slb_shadow_needed,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT64(slb_shadow_addr, sPAPRCPUState),
+ VMSTATE_UINT64(slb_shadow_size, sPAPRCPUState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static bool dtl_needed(void *opaque)
+{
+ sPAPRCPUState *spapr_cpu = opaque;
+
+ return spapr_cpu->dtl_addr != 0;
+}
+
+static const VMStateDescription vmstate_spapr_cpu_dtl = {
+ .name = "spapr_cpu/vpa/dtl",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = dtl_needed,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT64(dtl_addr, sPAPRCPUState),
+ VMSTATE_UINT64(dtl_size, sPAPRCPUState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static bool vpa_needed(void *opaque)
+{
+ sPAPRCPUState *spapr_cpu = opaque;
+
+ return spapr_cpu->vpa_addr != 0;
+}
+
+static const VMStateDescription vmstate_spapr_cpu_vpa = {
+ .name = "spapr_cpu/vpa",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = vpa_needed,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT64(vpa_addr, sPAPRCPUState),
+ VMSTATE_END_OF_LIST()
+ },
+ .subsections = (const VMStateDescription * []) {
+ &vmstate_spapr_cpu_slb_shadow,
+ &vmstate_spapr_cpu_dtl,
+ NULL
+ }
+};
+
+static const VMStateDescription vmstate_spapr_cpu_state = {
+ .name = "spapr_cpu",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_END_OF_LIST()
+ },
+ .subsections = (const VMStateDescription * []) {
+ &vmstate_spapr_cpu_vpa,
+ NULL
+ }
+};
+
static void spapr_realize_vcpu(PowerPCCPU *cpu, sPAPRMachineState *spapr,
Error **errp)
{
@@ -194,6 +272,10 @@ static PowerPCCPU *spapr_create_vcpu(sPAPRCPUCore *sc, int i, Error **errp)
}
cpu->machine_data = g_new0(sPAPRCPUState, 1);
+ if (!sc->pre_3_0_migration) {
+ vmstate_register(NULL, cs->cpu_index, &vmstate_spapr_cpu_state,
+ cpu->machine_data);
+ }
object_unref(obj);
return cpu;
@@ -204,10 +286,13 @@ err:
return NULL;
}
-static void spapr_delete_vcpu(PowerPCCPU *cpu)
+static void spapr_delete_vcpu(PowerPCCPU *cpu, sPAPRCPUCore *sc)
{
sPAPRCPUState *spapr_cpu = spapr_cpu_state(cpu);
+ if (!sc->pre_3_0_migration) {
+ vmstate_unregister(NULL, &vmstate_spapr_cpu_state, cpu->machine_data);
+ }
cpu->machine_data = NULL;
g_free(spapr_cpu);
object_unparent(OBJECT(cpu));
@@ -253,7 +338,7 @@ err_unrealize:
}
err:
while (--i >= 0) {
- spapr_delete_vcpu(sc->threads[i]);
+ spapr_delete_vcpu(sc->threads[i], sc);
}
g_free(sc->threads);
error_propagate(errp, local_err);
@@ -261,6 +346,8 @@ err:
static Property spapr_cpu_core_properties[] = {
DEFINE_PROP_INT32("node-id", sPAPRCPUCore, node_id, CPU_UNSET_NUMA_NODE_ID),
+ DEFINE_PROP_BOOL("pre-3.0-migration", sPAPRCPUCore, pre_3_0_migration,
+ false),
DEFINE_PROP_END_OF_LIST()
};
diff --git a/hw/ppc/spapr_events.c b/hw/ppc/spapr_events.c
index 86836f0..e4f5946 100644
--- a/hw/ppc/spapr_events.c
+++ b/hw/ppc/spapr_events.c
@@ -707,13 +707,18 @@ void spapr_clear_pending_events(sPAPRMachineState *spapr)
void spapr_events_init(sPAPRMachineState *spapr)
{
+ int epow_irq;
+
+ epow_irq = spapr_irq_findone(spapr, &error_fatal);
+
+ spapr_irq_claim(spapr, epow_irq, false, &error_fatal);
+
QTAILQ_INIT(&spapr->pending_events);
spapr->event_sources = spapr_event_sources_new();
spapr_event_sources_register(spapr->event_sources, EVENT_CLASS_EPOW,
- spapr_irq_alloc(spapr, 0, false,
- &error_fatal));
+ epow_irq);
/* NOTE: if machine supports modern/dedicated hotplug event source,
* we add it to the device-tree unconditionally. This means we may
@@ -724,9 +729,14 @@ void spapr_events_init(sPAPRMachineState *spapr)
* checking that it's enabled.
*/
if (spapr->use_hotplug_event_source) {
+ int hp_irq;
+
+ hp_irq = spapr_irq_findone(spapr, &error_fatal);
+
+ spapr_irq_claim(spapr, hp_irq, false, &error_fatal);
+
spapr_event_sources_register(spapr->event_sources, EVENT_CLASS_HOT_PLUG,
- spapr_irq_alloc(spapr, 0, false,
- &error_fatal));
+ hp_irq);
}
spapr->epow_notifier.notify = spapr_powerdown_req;
diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
index f936ce6..497b896 100644
--- a/hw/ppc/spapr_pci.c
+++ b/hw/ppc/spapr_pci.c
@@ -279,6 +279,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
spapr_pci_msi *msi;
int *config_addr_key;
Error *err = NULL;
+ int i;
/* Fins sPAPRPHBState */
phb = spapr_pci_find_phb(spapr, buid);
@@ -371,8 +372,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
}
/* Allocate MSIs */
- irq = spapr_irq_alloc_block(spapr, req_num, false,
- ret_intr_type == RTAS_TYPE_MSI, &err);
+ irq = spapr_irq_find(spapr, req_num, ret_intr_type == RTAS_TYPE_MSI, &err);
if (err) {
error_reportf_err(err, "Can't allocate MSIs for device %x: ",
config_addr);
@@ -380,6 +380,16 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
return;
}
+ for (i = 0; i < req_num; i++) {
+ spapr_irq_claim(spapr, irq + i, false, &err);
+ if (err) {
+ error_reportf_err(err, "Can't allocate MSIs for device %x: ",
+ config_addr);
+ rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
+ return;
+ }
+ }
+
/* Release previous MSIs */
if (msi) {
spapr_irq_free(spapr, msi->first_irq, msi->num);
@@ -1698,7 +1708,14 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)
uint32_t irq;
Error *local_err = NULL;
- irq = spapr_irq_alloc_block(spapr, 1, true, false, &local_err);
+ irq = spapr_irq_findone(spapr, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ error_prepend(errp, "can't allocate LSIs: ");
+ return;
+ }
+
+ spapr_irq_claim(spapr, irq, true, &local_err);
if (local_err) {
error_propagate(errp, local_err);
error_prepend(errp, "can't allocate LSIs: ");
diff --git a/hw/ppc/spapr_vio.c b/hw/ppc/spapr_vio.c
index 4555c64..daf8513 100644
--- a/hw/ppc/spapr_vio.c
+++ b/hw/ppc/spapr_vio.c
@@ -475,7 +475,15 @@ static void spapr_vio_busdev_realize(DeviceState *qdev, Error **errp)
dev->qdev.id = id;
}
- dev->irq = spapr_irq_alloc(spapr, dev->irq, false, &local_err);
+ if (!dev->irq) {
+ dev->irq = spapr_irq_findone(spapr, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+ }
+
+ spapr_irq_claim(spapr, dev->irq, false, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
diff --git a/include/hw/i2c/ppc4xx_i2c.h b/include/hw/i2c/ppc4xx_i2c.h
index 3c60307..ea6c8e1 100644
--- a/include/hw/i2c/ppc4xx_i2c.h
+++ b/include/hw/i2c/ppc4xx_i2c.h
@@ -3,7 +3,7 @@
*
* Copyright (c) 2007 Jocelyn Mayer
* Copyright (c) 2012 François Revol
- * Copyright (c) 2016 BALATON Zoltan
+ * Copyright (c) 2016-2018 BALATON Zoltan
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -31,6 +31,9 @@
#include "hw/sysbus.h"
#include "hw/i2c/i2c.h"
+/* from hw/i2c/bitbang_i2c.h */
+typedef struct bitbang_i2c_interface bitbang_i2c_interface;
+
#define TYPE_PPC4xx_I2C "ppc4xx-i2c"
#define PPC4xx_I2C(obj) OBJECT_CHECK(PPC4xxI2CState, (obj), TYPE_PPC4xx_I2C)
@@ -42,6 +45,7 @@ typedef struct PPC4xxI2CState {
I2CBus *bus;
qemu_irq irq;
MemoryRegion iomem;
+ bitbang_i2c_interface *bitbang;
uint8_t mdata;
uint8_t lmadr;
uint8_t hmadr;
@@ -49,7 +53,6 @@ typedef struct PPC4xxI2CState {
uint8_t mdcntl;
uint8_t sts;
uint8_t extsts;
- uint8_t sdata;
uint8_t lsadr;
uint8_t hsadr;
uint8_t clkdiv;
@@ -57,7 +60,6 @@ typedef struct PPC4xxI2CState {
uint8_t xfrcnt;
uint8_t xtcntlss;
uint8_t directcntl;
- uint8_t intr;
} PPC4xxI2CState;
#endif /* PPC4XX_I2C_H */
diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
index 9075924..86d5f54 100644
--- a/include/hw/ppc/pnv.h
+++ b/include/hw/ppc/pnv.h
@@ -57,12 +57,32 @@ typedef struct PnvChip {
MemoryRegion xscom_mmio;
MemoryRegion xscom;
AddressSpace xscom_as;
+} PnvChip;
+
+#define TYPE_PNV8_CHIP "pnv8-chip"
+#define PNV8_CHIP(obj) OBJECT_CHECK(Pnv8Chip, (obj), TYPE_PNV8_CHIP)
+
+typedef struct Pnv8Chip {
+ /*< private >*/
+ PnvChip parent_obj;
+
+ /*< public >*/
MemoryRegion icp_mmio;
PnvLpcController lpc;
PnvPsi psi;
PnvOCC occ;
-} PnvChip;
+} Pnv8Chip;
+
+#define TYPE_PNV9_CHIP "pnv9-chip"
+#define PNV9_CHIP(obj) OBJECT_CHECK(Pnv9Chip, (obj), TYPE_PNV9_CHIP)
+
+typedef struct Pnv9Chip {
+ /*< private >*/
+ PnvChip parent_obj;
+
+ /*< public >*/
+} Pnv9Chip;
typedef struct PnvChipClass {
/*< private >*/
@@ -75,7 +95,11 @@ typedef struct PnvChipClass {
hwaddr xscom_base;
+ DeviceRealize parent_realize;
+
uint32_t (*core_pir)(PnvChip *chip, uint32_t core_id);
+ Object *(*intc_create)(PnvChip *chip, Object *child, Error **errp);
+ ISABus *(*isa_create)(PnvChip *chip, Error **errp);
} PnvChipClass;
#define PNV_CHIP_TYPE_SUFFIX "-" TYPE_PNV_CHIP
diff --git a/include/hw/ppc/pnv_lpc.h b/include/hw/ppc/pnv_lpc.h
index 53fdd5b..d657489 100644
--- a/include/hw/ppc/pnv_lpc.h
+++ b/include/hw/ppc/pnv_lpc.h
@@ -70,7 +70,6 @@ typedef struct PnvLpcController {
PnvPsi *psi;
} PnvLpcController;
-qemu_irq *pnv_lpc_isa_irq_create(PnvLpcController *lpc, int chip_type,
- int nirqs);
+ISABus *pnv_lpc_isa_create(PnvLpcController *lpc, bool use_cpld, Error **errp);
#endif /* _PPC_PNV_LPC_H */
diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h
index 3388750..7e02816 100644
--- a/include/hw/ppc/spapr.h
+++ b/include/hw/ppc/spapr.h
@@ -66,8 +66,10 @@ typedef enum {
#define SPAPR_CAP_SBBC 0x04
/* Indirect Branch Serialisation */
#define SPAPR_CAP_IBS 0x05
+/* HPT Maximum Page Size (encoded as a shift) */
+#define SPAPR_CAP_HPT_MAXPAGESIZE 0x06
/* Num Caps */
-#define SPAPR_CAP_NUM (SPAPR_CAP_IBS + 1)
+#define SPAPR_CAP_NUM (SPAPR_CAP_HPT_MAXPAGESIZE + 1)
/*
* Capability Values
@@ -772,10 +774,10 @@ int spapr_get_vcpu_id(PowerPCCPU *cpu);
void spapr_set_vcpu_id(PowerPCCPU *cpu, int cpu_index, Error **errp);
PowerPCCPU *spapr_find_cpu(int vcpu_id);
-int spapr_irq_alloc(sPAPRMachineState *spapr, int irq_hint, bool lsi,
- Error **errp);
-int spapr_irq_alloc_block(sPAPRMachineState *spapr, int num, bool lsi,
- bool align, Error **errp);
+int spapr_irq_find(sPAPRMachineState *spapr, int num, bool align,
+ Error **errp);
+#define spapr_irq_findone(spapr, errp) spapr_irq_find(spapr, 1, false, errp)
+int spapr_irq_claim(sPAPRMachineState *spapr, int irq, bool lsi, Error **errp);
void spapr_irq_free(sPAPRMachineState *spapr, int irq, int num);
qemu_irq spapr_qirq(sPAPRMachineState *spapr, int irq);
@@ -798,8 +800,13 @@ static inline uint8_t spapr_get_cap(sPAPRMachineState *spapr, int cap)
return spapr->eff.caps[cap];
}
-void spapr_caps_reset(sPAPRMachineState *spapr);
+void spapr_caps_init(sPAPRMachineState *spapr);
+void spapr_caps_apply(sPAPRMachineState *spapr);
+void spapr_caps_cpu_apply(sPAPRMachineState *spapr, PowerPCCPU *cpu);
void spapr_caps_add_properties(sPAPRMachineClass *smc, Error **errp);
int spapr_caps_post_migration(sPAPRMachineState *spapr);
+void spapr_check_pagesize(sPAPRMachineState *spapr, hwaddr pagesize,
+ Error **errp);
+
#endif /* HW_SPAPR_H */
diff --git a/include/hw/ppc/spapr_cpu_core.h b/include/hw/ppc/spapr_cpu_core.h
index 8ceea29..9e2821e 100644
--- a/include/hw/ppc/spapr_cpu_core.h
+++ b/include/hw/ppc/spapr_cpu_core.h
@@ -31,6 +31,7 @@ typedef struct sPAPRCPUCore {
/*< public >*/
PowerPCCPU **threads;
int node_id;
+ bool pre_3_0_migration; /* older machine don't know about sPAPRCPUState */
} sPAPRCPUCore;
typedef struct sPAPRCPUCoreClass {
diff --git a/pc-bios/README b/pc-bios/README
index a843e1e..99e15a7 100644
--- a/pc-bios/README
+++ b/pc-bios/README
@@ -17,7 +17,7 @@
- SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware
implementation for certain IBM POWER hardware. The sources are at
https://github.com/aik/SLOF, and the image currently in qemu is
- built from git tag qemu-slof-20171214.
+ built from git tag qemu-slof-20180621.
- sgabios (the Serial Graphics Adapter option ROM) provides a means for
legacy x86 software to communicate with an attached serial console as
diff --git a/pc-bios/slof.bin b/pc-bios/slof.bin
index d46c83e..4e0e33f 100644
--- a/pc-bios/slof.bin
+++ b/pc-bios/slof.bin
Binary files differ
diff --git a/roms/SLOF b/roms/SLOF
-Subproject 2317427ce76006723f7ae103a6998ab41dd79c6
+Subproject 7d37babcfa48a6eb08e726a8d13b745cb2eebe1
diff --git a/target/ppc/compat.c b/target/ppc/compat.c
index 807c906..7de4bf3 100644
--- a/target/ppc/compat.c
+++ b/target/ppc/compat.c
@@ -105,17 +105,13 @@ static const CompatInfo *compat_by_pvr(uint32_t pvr)
return NULL;
}
-bool ppc_check_compat(PowerPCCPU *cpu, uint32_t compat_pvr,
- uint32_t min_compat_pvr, uint32_t max_compat_pvr)
+static bool pcc_compat(PowerPCCPUClass *pcc, uint32_t compat_pvr,
+ uint32_t min_compat_pvr, uint32_t max_compat_pvr)
{
- PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
const CompatInfo *compat = compat_by_pvr(compat_pvr);
const CompatInfo *min = compat_by_pvr(min_compat_pvr);
const CompatInfo *max = compat_by_pvr(max_compat_pvr);
-#if !defined(CONFIG_USER_ONLY)
- g_assert(cpu->vhyp);
-#endif
g_assert(!min_compat_pvr || min);
g_assert(!max_compat_pvr || max);
@@ -134,6 +130,25 @@ bool ppc_check_compat(PowerPCCPU *cpu, uint32_t compat_pvr,
return true;
}
+bool ppc_check_compat(PowerPCCPU *cpu, uint32_t compat_pvr,
+ uint32_t min_compat_pvr, uint32_t max_compat_pvr)
+{
+ PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
+
+#if !defined(CONFIG_USER_ONLY)
+ g_assert(cpu->vhyp);
+#endif
+
+ return pcc_compat(pcc, compat_pvr, min_compat_pvr, max_compat_pvr);
+}
+
+bool ppc_type_check_compat(const char *cputype, uint32_t compat_pvr,
+ uint32_t min_compat_pvr, uint32_t max_compat_pvr)
+{
+ PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(object_class_by_name(cputype));
+ return pcc_compat(pcc, compat_pvr, min_compat_pvr, max_compat_pvr);
+}
+
void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp)
{
const CompatInfo *compat = compat_by_pvr(compat_pvr);
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index 874da6e..c7f3fb6 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -1369,7 +1369,11 @@ static inline int cpu_mmu_index (CPUPPCState *env, bool ifetch)
#if defined(TARGET_PPC64)
bool ppc_check_compat(PowerPCCPU *cpu, uint32_t compat_pvr,
uint32_t min_compat_pvr, uint32_t max_compat_pvr);
+bool ppc_type_check_compat(const char *cputype, uint32_t compat_pvr,
+ uint32_t min_compat_pvr, uint32_t max_compat_pvr);
+
void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp);
+
#if !defined(CONFIG_USER_ONLY)
void ppc_set_compat_all(uint32_t compat_pvr, Error **errp);
#endif
diff --git a/target/ppc/fpu_helper.c b/target/ppc/fpu_helper.c
index d31a933..7714bfe 100644
--- a/target/ppc/fpu_helper.c
+++ b/target/ppc/fpu_helper.c
@@ -325,6 +325,34 @@ void helper_fpscr_clrbit(CPUPPCState *env, uint32_t bit)
case FPSCR_RN:
fpscr_set_rounding_mode(env);
break;
+ case FPSCR_VXSNAN:
+ case FPSCR_VXISI:
+ case FPSCR_VXIDI:
+ case FPSCR_VXZDZ:
+ case FPSCR_VXIMZ:
+ case FPSCR_VXVC:
+ case FPSCR_VXSOFT:
+ case FPSCR_VXSQRT:
+ case FPSCR_VXCVI:
+ if (!fpscr_ix) {
+ /* Set VX bit to zero */
+ env->fpscr &= ~(1 << FPSCR_VX);
+ }
+ break;
+ case FPSCR_OX:
+ case FPSCR_UX:
+ case FPSCR_ZX:
+ case FPSCR_XX:
+ case FPSCR_VE:
+ case FPSCR_OE:
+ case FPSCR_UE:
+ case FPSCR_ZE:
+ case FPSCR_XE:
+ if (!fpscr_eex) {
+ /* Set the FEX bit */
+ env->fpscr &= ~(1 << FPSCR_FEX);
+ }
+ break;
default:
break;
}
diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
index 5c0e313..4df4ff6 100644
--- a/target/ppc/kvm.c
+++ b/target/ppc/kvm.c
@@ -406,107 +406,106 @@ target_ulong kvmppc_configure_v3_mmu(PowerPCCPU *cpu,
}
}
-static bool kvm_valid_page_size(uint32_t flags, long rampgsize, uint32_t shift)
+bool kvmppc_hpt_needs_host_contiguous_pages(void)
{
- if (!(flags & KVM_PPC_PAGE_SIZES_REAL)) {
- return true;
+ PowerPCCPU *cpu = POWERPC_CPU(first_cpu);
+ static struct kvm_ppc_smmu_info smmu_info;
+
+ if (!kvm_enabled()) {
+ return false;
}
- return (1ul << shift) <= rampgsize;
+ kvm_get_smmu_info(cpu, &smmu_info);
+ return !!(smmu_info.flags & KVM_PPC_PAGE_SIZES_REAL);
}
-static long max_cpu_page_size;
-
-static void kvm_fixup_page_sizes(PowerPCCPU *cpu)
+void kvm_check_mmu(PowerPCCPU *cpu, Error **errp)
{
- static struct kvm_ppc_smmu_info smmu_info;
- static bool has_smmu_info;
- CPUPPCState *env = &cpu->env;
+ struct kvm_ppc_smmu_info smmu_info;
int iq, ik, jq, jk;
- /* We only handle page sizes for 64-bit server guests for now */
- if (!(env->mmu_model & POWERPC_MMU_64)) {
+ /* For now, we only have anything to check on hash64 MMUs */
+ if (!cpu->hash64_opts || !kvm_enabled()) {
return;
}
- /* Collect MMU info from kernel if not already */
- if (!has_smmu_info) {
- kvm_get_smmu_info(cpu, &smmu_info);
- has_smmu_info = true;
- }
+ kvm_get_smmu_info(cpu, &smmu_info);
- if (!max_cpu_page_size) {
- max_cpu_page_size = qemu_getrampagesize();
+ if (ppc_hash64_has(cpu, PPC_HASH64_1TSEG)
+ && !(smmu_info.flags & KVM_PPC_1T_SEGMENTS)) {
+ error_setg(errp,
+ "KVM does not support 1TiB segments which guest expects");
+ return;
}
- /* Convert to QEMU form */
- memset(cpu->hash64_opts->sps, 0, sizeof(*cpu->hash64_opts->sps));
-
- /* If we have HV KVM, we need to forbid CI large pages if our
- * host page size is smaller than 64K.
- */
- if (smmu_info.flags & KVM_PPC_PAGE_SIZES_REAL) {
- if (getpagesize() >= 0x10000) {
- cpu->hash64_opts->flags |= PPC_HASH64_CI_LARGEPAGE;
- } else {
- cpu->hash64_opts->flags &= ~PPC_HASH64_CI_LARGEPAGE;
- }
+ if (smmu_info.slb_size < cpu->hash64_opts->slb_size) {
+ error_setg(errp, "KVM only supports %u SLB entries, but guest needs %u",
+ smmu_info.slb_size, cpu->hash64_opts->slb_size);
+ return;
}
/*
- * XXX This loop should be an entry wide AND of the capabilities that
- * the selected CPU has with the capabilities that KVM supports.
+ * Verify that every pagesize supported by the cpu model is
+ * supported by KVM with the same encodings
*/
- for (ik = iq = 0; ik < KVM_PPC_PAGE_SIZES_MAX_SZ; ik++) {
+ for (iq = 0; iq < ARRAY_SIZE(cpu->hash64_opts->sps); iq++) {
PPCHash64SegmentPageSizes *qsps = &cpu->hash64_opts->sps[iq];
- struct kvm_ppc_one_seg_page_size *ksps = &smmu_info.sps[ik];
+ struct kvm_ppc_one_seg_page_size *ksps;
- if (!kvm_valid_page_size(smmu_info.flags, max_cpu_page_size,
- ksps->page_shift)) {
- continue;
- }
- qsps->page_shift = ksps->page_shift;
- qsps->slb_enc = ksps->slb_enc;
- for (jk = jq = 0; jk < KVM_PPC_PAGE_SIZES_MAX_SZ; jk++) {
- if (!kvm_valid_page_size(smmu_info.flags, max_cpu_page_size,
- ksps->enc[jk].page_shift)) {
- continue;
- }
- qsps->enc[jq].page_shift = ksps->enc[jk].page_shift;
- qsps->enc[jq].pte_enc = ksps->enc[jk].pte_enc;
- if (++jq >= PPC_PAGE_SIZES_MAX_SZ) {
+ for (ik = 0; ik < ARRAY_SIZE(smmu_info.sps); ik++) {
+ if (qsps->page_shift == smmu_info.sps[ik].page_shift) {
break;
}
}
- if (++iq >= PPC_PAGE_SIZES_MAX_SZ) {
- break;
+ if (ik >= ARRAY_SIZE(smmu_info.sps)) {
+ error_setg(errp, "KVM doesn't support for base page shift %u",
+ qsps->page_shift);
+ return;
}
- }
- cpu->hash64_opts->slb_size = smmu_info.slb_size;
- if (!(smmu_info.flags & KVM_PPC_1T_SEGMENTS)) {
- cpu->hash64_opts->flags &= ~PPC_HASH64_1TSEG;
- }
-}
-
-bool kvmppc_is_mem_backend_page_size_ok(const char *obj_path)
-{
- Object *mem_obj = object_resolve_path(obj_path, NULL);
- long pagesize = host_memory_backend_pagesize(MEMORY_BACKEND(mem_obj));
- return pagesize >= max_cpu_page_size;
-}
+ ksps = &smmu_info.sps[ik];
+ if (ksps->slb_enc != qsps->slb_enc) {
+ error_setg(errp,
+"KVM uses SLB encoding 0x%x for page shift %u, but guest expects 0x%x",
+ ksps->slb_enc, ksps->page_shift, qsps->slb_enc);
+ return;
+ }
-#else /* defined (TARGET_PPC64) */
+ for (jq = 0; jq < ARRAY_SIZE(qsps->enc); jq++) {
+ for (jk = 0; jk < ARRAY_SIZE(ksps->enc); jk++) {
+ if (qsps->enc[jq].page_shift == ksps->enc[jk].page_shift) {
+ break;
+ }
+ }
-static inline void kvm_fixup_page_sizes(PowerPCCPU *cpu)
-{
-}
+ if (jk >= ARRAY_SIZE(ksps->enc)) {
+ error_setg(errp, "KVM doesn't support page shift %u/%u",
+ qsps->enc[jq].page_shift, qsps->page_shift);
+ return;
+ }
+ if (qsps->enc[jq].pte_enc != ksps->enc[jk].pte_enc) {
+ error_setg(errp,
+"KVM uses PTE encoding 0x%x for page shift %u/%u, but guest expects 0x%x",
+ ksps->enc[jk].pte_enc, qsps->enc[jq].page_shift,
+ qsps->page_shift, qsps->enc[jq].pte_enc);
+ return;
+ }
+ }
+ }
-bool kvmppc_is_mem_backend_page_size_ok(const char *obj_path)
-{
- return true;
+ if (ppc_hash64_has(cpu, PPC_HASH64_CI_LARGEPAGE)) {
+ /* Mostly what guest pagesizes we can use are related to the
+ * host pages used to map guest RAM, which is handled in the
+ * platform code. Cache-Inhibited largepages (64k) however are
+ * used for I/O, so if they're mapped to the host at all it
+ * will be a normal mapping, not a special hugepage one used
+ * for RAM. */
+ if (getpagesize() < 0x10000) {
+ error_setg(errp,
+ "KVM can't supply 64kiB CI pages, which guest expects");
+ }
+ }
}
-
#endif /* !defined (TARGET_PPC64) */
unsigned long kvm_arch_vcpu_id(CPUState *cpu)
@@ -552,9 +551,6 @@ int kvm_arch_init_vcpu(CPUState *cs)
CPUPPCState *cenv = &cpu->env;
int ret;
- /* Gather server mmu info from KVM and update the CPU state */
- kvm_fixup_page_sizes(cpu);
-
/* Synchronize sregs with kvm */
ret = kvm_arch_sync_sregs(cpu);
if (ret) {
diff --git a/target/ppc/kvm_ppc.h b/target/ppc/kvm_ppc.h
index e2840e1..657582b 100644
--- a/target/ppc/kvm_ppc.h
+++ b/target/ppc/kvm_ppc.h
@@ -70,7 +70,8 @@ int kvmppc_resize_hpt_prepare(PowerPCCPU *cpu, target_ulong flags, int shift);
int kvmppc_resize_hpt_commit(PowerPCCPU *cpu, target_ulong flags, int shift);
bool kvmppc_pvr_workaround_required(PowerPCCPU *cpu);
-bool kvmppc_is_mem_backend_page_size_ok(const char *obj_path);
+bool kvmppc_hpt_needs_host_contiguous_pages(void);
+void kvm_check_mmu(PowerPCCPU *cpu, Error **errp);
#else
@@ -222,9 +223,13 @@ static inline uint64_t kvmppc_rma_size(uint64_t current_size,
return ram_size;
}
-static inline bool kvmppc_is_mem_backend_page_size_ok(const char *obj_path)
+static inline bool kvmppc_hpt_needs_host_contiguous_pages(void)
+{
+ return false;
+}
+
+static inline void kvm_check_mmu(PowerPCCPU *cpu, Error **errp)
{
- return true;
}
static inline bool kvmppc_has_cap_spapr_vfio(void)
diff --git a/target/ppc/mmu-hash64.c b/target/ppc/mmu-hash64.c
index aa200cb..276d901 100644
--- a/target/ppc/mmu-hash64.c
+++ b/target/ppc/mmu-hash64.c
@@ -1166,3 +1166,62 @@ const PPCHash64Options ppc_hash64_opts_POWER7 = {
},
}
};
+
+void ppc_hash64_filter_pagesizes(PowerPCCPU *cpu,
+ bool (*cb)(void *, uint32_t, uint32_t),
+ void *opaque)
+{
+ PPCHash64Options *opts = cpu->hash64_opts;
+ int i;
+ int n = 0;
+ bool ci_largepage = false;
+
+ assert(opts);
+
+ n = 0;
+ for (i = 0; i < ARRAY_SIZE(opts->sps); i++) {
+ PPCHash64SegmentPageSizes *sps = &opts->sps[i];
+ int j;
+ int m = 0;
+
+ assert(n <= i);
+
+ if (!sps->page_shift) {
+ break;
+ }
+
+ for (j = 0; j < ARRAY_SIZE(sps->enc); j++) {
+ PPCHash64PageSize *ps = &sps->enc[j];
+
+ assert(m <= j);
+ if (!ps->page_shift) {
+ break;
+ }
+
+ if (cb(opaque, sps->page_shift, ps->page_shift)) {
+ if (ps->page_shift >= 16) {
+ ci_largepage = true;
+ }
+ sps->enc[m++] = *ps;
+ }
+ }
+
+ /* Clear rest of the row */
+ for (j = m; j < ARRAY_SIZE(sps->enc); j++) {
+ memset(&sps->enc[j], 0, sizeof(sps->enc[j]));
+ }
+
+ if (m) {
+ n++;
+ }
+ }
+
+ /* Clear the rest of the table */
+ for (i = n; i < ARRAY_SIZE(opts->sps); i++) {
+ memset(&opts->sps[i], 0, sizeof(opts->sps[i]));
+ }
+
+ if (!ci_largepage) {
+ opts->flags &= ~PPC_HASH64_CI_LARGEPAGE;
+ }
+}
diff --git a/target/ppc/mmu-hash64.h b/target/ppc/mmu-hash64.h
index 53dcec5..f11efc9 100644
--- a/target/ppc/mmu-hash64.h
+++ b/target/ppc/mmu-hash64.h
@@ -20,6 +20,9 @@ unsigned ppc_hash64_hpte_page_shift_noslb(PowerPCCPU *cpu,
void ppc_store_lpcr(PowerPCCPU *cpu, target_ulong val);
void ppc_hash64_init(PowerPCCPU *cpu);
void ppc_hash64_finalize(PowerPCCPU *cpu);
+void ppc_hash64_filter_pagesizes(PowerPCCPU *cpu,
+ bool (*cb)(void *, uint32_t, uint32_t),
+ void *opaque);
#endif
/*
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index 5fe1ba6..3a215a1 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -6707,6 +6707,8 @@ GEN_HANDLER_E(mbar, 0x1F, 0x16, 0x1a, 0x001FF801,
GEN_HANDLER(msync_4xx, 0x1F, 0x16, 0x12, 0x03FFF801, PPC_BOOKE),
GEN_HANDLER2_E(icbt_440, "icbt", 0x1F, 0x16, 0x00, 0x03E00001,
PPC_BOOKE, PPC2_BOOKE206),
+GEN_HANDLER2(icbt_440, "icbt", 0x1F, 0x06, 0x08, 0x03E00001,
+ PPC_440_SPEC),
GEN_HANDLER(lvsl, 0x1f, 0x06, 0x00, 0x00000001, PPC_ALTIVEC),
GEN_HANDLER(lvsr, 0x1f, 0x06, 0x01, 0x00000001, PPC_ALTIVEC),
GEN_HANDLER(mfvscr, 0x04, 0x2, 0x18, 0x001ff800, PPC_ALTIVEC),