mirror of
https://github.com/qemu/qemu.git
synced 2025-01-16 02:24:00 +08:00
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 -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEdfRlhq5hpmzETofcbDjKyiDZs5IFAlssebQACgkQbDjKyiDZ s5IMUA/+MUejq1eIAE3z4POijm0nNS5r7gce4b6M4G0vV1cC3eY9GA/kir4r3XU5 LoBGJx96pSXph69tzI7WIdn8vHpE2AkvWr4DT36ndxW0H7V630BCHk7vWMuBrfHf 5l+bKgKKnfM5MaptnKDsosvfSk7NaH+7cqSa97h2PUGFaTKmD2XyTXQqBkReBzoC lBYVUVLjc6l9Y3P+DT+3uF+5lR7QOuqJ+2q31DvuNcTFoYhHc4DPXmDb5PfjY/DG 3oBIcFC6dqjkRzWAAT65Zk1P/hrKcYmmE382hwsFg76GTGR893MhE0vx0EjqrFbr Tdkwj8v6Uto9/iatRz/nBSEg96oDmvSmz97Omh4JwHPKOpHRZ+QjCxccK63Jp1Yv xgwV52YIw/5LIQYLw6eArDKfU9iLZ/Nh+rtAZxaCb/Bvsmv2vljbDpHbuhk1uJ8i NaJ4Pe9aDt7tew39Sl/ohdUmgOYBal3WwVBNE5JNn5cO6GxzEG8U5JuFDY+RzpUV Xh2ksy1n6F7Q3XOqf4CgF/0Gpy5mrUXSRyCVIx47E+DNwFvkexNwX8PqANJqKJFo cxBBZbvaHRjpUGUN/yjixPqx7xWWfC698Urgdzg7LMcn3SjaRztT834DhlH46gh6 1KBf2RrkPXEJD+O4YMb5CowDXrPL4yYXSLN0GxGUknW0nQF3v2g= =vjK1 -----END PGP SIGNATURE----- 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>
This commit is contained in:
commit
c52e53f429
@ -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
|
||||
|
@ -19,3 +19,4 @@ CONFIG_USB_EHCI_SYSBUS=y
|
||||
CONFIG_SM501=y
|
||||
CONFIG_IDE_SII3112=y
|
||||
CONFIG_I2C=y
|
||||
CONFIG_BITBANG_I2C=y
|
||||
|
@ -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 */
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
383
hw/ppc/pnv.c
383
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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
122
hw/ppc/spapr.c
122
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)
|
||||
int spapr_irq_find(sPAPRMachineState *spapr, int num, bool align, 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)
|
||||
{
|
||||
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);
|
||||
|
@ -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;
|
||||
|
@ -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()
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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: ");
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
BIN
pc-bios/slof.bin
BIN
pc-bios/slof.bin
Binary file not shown.
@ -1 +1 @@
|
||||
Subproject commit 2317427ce76006723f7ae103a6998ab41dd79c68
|
||||
Subproject commit 7d37babcfa48a6eb08e726a8d13b745cb2eebe1c
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
152
target/ppc/kvm.c
152
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 (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;
|
||||
}
|
||||
|
||||
if (!max_cpu_page_size) {
|
||||
max_cpu_page_size = qemu_getrampagesize();
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
cpu->hash64_opts->slb_size = smmu_info.slb_size;
|
||||
if (!(smmu_info.flags & KVM_PPC_1T_SEGMENTS)) {
|
||||
cpu->hash64_opts->flags &= ~PPC_HASH64_1TSEG;
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#else /* defined (TARGET_PPC64) */
|
||||
|
||||
static inline void kvm_fixup_page_sizes(PowerPCCPU *cpu)
|
||||
{
|
||||
}
|
||||
|
||||
bool kvmppc_is_mem_backend_page_size_ok(const char *obj_path)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
#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) {
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
/*
|
||||
|
@ -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),
|
||||
|
Loading…
Reference in New Issue
Block a user