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:
Peter Maydell 2018-06-22 15:14:08 +01:00
commit c52e53f429
29 changed files with 868 additions and 370 deletions

View File

@ -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

View File

@ -19,3 +19,4 @@ CONFIG_USB_EHCI_SYSBUS=y
CONFIG_SM501=y
CONFIG_IDE_SII3112=y
CONFIG_I2C=y
CONFIG_BITBANG_I2C=y

View File

@ -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 */
}
}

View File

@ -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)

View File

@ -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)

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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;

View File

@ -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()
};

View File

@ -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;

View File

@ -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: ");

View File

@ -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;

View File

@ -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 */

View File

@ -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

View File

@ -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 */

View File

@ -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 */

View File

@ -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 {

View File

@ -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

Binary file not shown.

@ -1 +1 @@
Subproject commit 2317427ce76006723f7ae103a6998ab41dd79c68
Subproject commit 7d37babcfa48a6eb08e726a8d13b745cb2eebe1c

View File

@ -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);

View File

@ -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

View File

@ -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;
}

View File

@ -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) {

View File

@ -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)

View File

@ -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;
}
}

View File

@ -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
/*

View File

@ -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),