On Thu, Mar 07, 2019 at 11:35:44PM +0100, Cédric Le Goater wrote: > The POWER9 processor does not support per-core frequency control. The > cores are arranged in groups of four, along with their respective L2 > and L3 caches, into a structure known as a Quad. The frequency must be > managed at the Quad level. > > Provide a basic Quad model to fake the settings done by the firmware > on the Non-Cacheable Unit (NCU). Each core pair (EX) needs a special > BAR setting for the TIMA area of XIVE because it resides on the same > address on all chips. > > Signed-off-by: Cédric Le Goater Applied, thanks. > --- > include/hw/ppc/pnv.h | 4 ++ > include/hw/ppc/pnv_core.h | 10 +++++ > include/hw/ppc/pnv_xscom.h | 12 ++++-- > hw/ppc/pnv.c | 38 ++++++++++++++++- > hw/ppc/pnv_core.c | 87 ++++++++++++++++++++++++++++++++++++++ > 5 files changed, 146 insertions(+), 5 deletions(-) > > diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h > index 39888f9d52c1..e5b00d373ed2 100644 > --- a/include/hw/ppc/pnv.h > +++ b/include/hw/ppc/pnv.h > @@ -26,6 +26,7 @@ > #include "hw/ppc/pnv_psi.h" > #include "hw/ppc/pnv_occ.h" > #include "hw/ppc/pnv_xive.h" > +#include "hw/ppc/pnv_core.h" > > #define TYPE_PNV_CHIP "pnv-chip" > #define PNV_CHIP(obj) OBJECT_CHECK(PnvChip, (obj), TYPE_PNV_CHIP) > @@ -89,6 +90,9 @@ typedef struct Pnv9Chip { > Pnv9Psi psi; > PnvLpcController lpc; > PnvOCC occ; > + > + uint32_t nr_quads; > + PnvQuad *quads; > } Pnv9Chip; > > typedef struct PnvChipClass { > diff --git a/include/hw/ppc/pnv_core.h b/include/hw/ppc/pnv_core.h > index cbe9ad36f32c..50cdb2b35838 100644 > --- a/include/hw/ppc/pnv_core.h > +++ b/include/hw/ppc/pnv_core.h > @@ -58,4 +58,14 @@ static inline PnvCPUState *pnv_cpu_state(PowerPCCPU *cpu) > return (PnvCPUState *)cpu->machine_data; > } > > +#define TYPE_PNV_QUAD "powernv-cpu-quad" > +#define PNV_QUAD(obj) \ > + OBJECT_CHECK(PnvQuad, (obj), TYPE_PNV_QUAD) > + > +typedef struct PnvQuad { > + DeviceState parent_obj; > + > + uint32_t id; > + MemoryRegion xscom_regs; > +} PnvQuad; > #endif /* _PPC_PNV_CORE_H */ > diff --git a/include/hw/ppc/pnv_xscom.h b/include/hw/ppc/pnv_xscom.h > index 3292459fbb78..68dfae0dfe41 100644 > --- a/include/hw/ppc/pnv_xscom.h > +++ b/include/hw/ppc/pnv_xscom.h > @@ -60,10 +60,6 @@ typedef struct PnvXScomInterfaceClass { > (PNV_XSCOM_EX_CORE_BASE | ((uint64_t)(core) << 24)) > #define PNV_XSCOM_EX_SIZE 0x100000 > > -#define PNV_XSCOM_P9_EC_BASE(core) \ > - ((uint64_t)(((core) & 0x1F) + 0x20) << 24) > -#define PNV_XSCOM_P9_EC_SIZE 0x100000 > - > #define PNV_XSCOM_LPC_BASE 0xb0020 > #define PNV_XSCOM_LPC_SIZE 0x4 > > @@ -73,6 +69,14 @@ typedef struct PnvXScomInterfaceClass { > #define PNV_XSCOM_OCC_BASE 0x0066000 > #define PNV_XSCOM_OCC_SIZE 0x6000 > > +#define PNV9_XSCOM_EC_BASE(core) \ > + ((uint64_t)(((core) & 0x1F) + 0x20) << 24) > +#define PNV9_XSCOM_EC_SIZE 0x100000 > + > +#define PNV9_XSCOM_EQ_BASE(core) \ > + ((uint64_t)(((core) & 0x1C) + 0x40) << 22) > +#define PNV9_XSCOM_EQ_SIZE 0x100000 > + > #define PNV9_XSCOM_OCC_BASE PNV_XSCOM_OCC_BASE > #define PNV9_XSCOM_OCC_SIZE 0x8000 > > diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c > index 1559a733235b..e68d419203e8 100644 > --- a/hw/ppc/pnv.c > +++ b/hw/ppc/pnv.c > @@ -963,6 +963,36 @@ static void pnv_chip_power9_instance_init(Object *obj) > OBJECT(&chip9->psi), &error_abort); > } > > +static void pnv_chip_quad_realize(Pnv9Chip *chip9, Error **errp) > +{ > + PnvChip *chip = PNV_CHIP(chip9); > + const char *typename = pnv_chip_core_typename(chip); > + size_t typesize = object_type_get_instance_size(typename); > + int i; > + > + chip9->nr_quads = DIV_ROUND_UP(chip->nr_cores, 4); > + chip9->quads = g_new0(PnvQuad, chip9->nr_quads); > + > + for (i = 0; i < chip9->nr_quads; i++) { > + char eq_name[32]; > + PnvQuad *eq = &chip9->quads[i]; > + PnvCore *pnv_core = PNV_CORE(chip->cores + (i * 4) * typesize); > + int core_id = CPU_CORE(pnv_core)->core_id; > + > + object_initialize(eq, sizeof(*eq), TYPE_PNV_QUAD); > + snprintf(eq_name, sizeof(eq_name), "eq[%d]", core_id); > + > + object_property_add_child(OBJECT(chip), eq_name, OBJECT(eq), > + &error_fatal); > + object_property_set_int(OBJECT(eq), core_id, "id", &error_fatal); > + object_property_set_bool(OBJECT(eq), true, "realized", &error_fatal); > + object_unref(OBJECT(eq)); > + > + pnv_xscom_add_subregion(chip, PNV9_XSCOM_EQ_BASE(eq->id), > + &eq->xscom_regs); > + } > +} > + > static void pnv_chip_power9_realize(DeviceState *dev, Error **errp) > { > PnvChipClass *pcc = PNV_CHIP_GET_CLASS(dev); > @@ -977,6 +1007,12 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp) > return; > } > > + pnv_chip_quad_realize(chip9, &local_err); > + if (local_err) { > + error_propagate(errp, local_err); > + return; > + } > + > /* XIVE interrupt controller (POWER9) */ > object_property_set_int(OBJECT(&chip9->xive), PNV9_XIVE_IC_BASE(chip), > "ic-bar", &error_fatal); > @@ -1135,7 +1171,7 @@ static void pnv_chip_core_realize(PnvChip *chip, Error **errp) > if (!pnv_chip_is_power9(chip)) { > xscom_core_base = PNV_XSCOM_EX_BASE(core_hwid); > } else { > - xscom_core_base = PNV_XSCOM_P9_EC_BASE(core_hwid); > + xscom_core_base = PNV9_XSCOM_EC_BASE(core_hwid); > } > > pnv_xscom_add_subregion(chip, xscom_core_base, > diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c > index 171474e0805c..5feeed6bc463 100644 > --- a/hw/ppc/pnv_core.c > +++ b/hw/ppc/pnv_core.c > @@ -327,3 +327,90 @@ static const TypeInfo pnv_core_infos[] = { > }; > > DEFINE_TYPES(pnv_core_infos) > + > +/* > + * POWER9 Quads > + */ > + > +#define P9X_EX_NCU_SPEC_BAR 0x11010 > + > +static uint64_t pnv_quad_xscom_read(void *opaque, hwaddr addr, > + unsigned int width) > +{ > + uint32_t offset = addr >> 3; > + uint64_t val = -1; > + > + switch (offset) { > + case P9X_EX_NCU_SPEC_BAR: > + case P9X_EX_NCU_SPEC_BAR + 0x400: /* Second EX */ > + val = 0; > + break; > + default: > + qemu_log_mask(LOG_UNIMP, "%s: writing @0x%08x\n", __func__, > + offset); > + } > + > + return val; > +} > + > +static void pnv_quad_xscom_write(void *opaque, hwaddr addr, uint64_t val, > + unsigned int width) > +{ > + uint32_t offset = addr >> 3; > + > + switch (offset) { > + case P9X_EX_NCU_SPEC_BAR: > + case P9X_EX_NCU_SPEC_BAR + 0x400: /* Second EX */ > + break; > + default: > + qemu_log_mask(LOG_UNIMP, "%s: writing @0x%08x\n", __func__, > + offset); > + } > +} > + > +static const MemoryRegionOps pnv_quad_xscom_ops = { > + .read = pnv_quad_xscom_read, > + .write = pnv_quad_xscom_write, > + .valid.min_access_size = 8, > + .valid.max_access_size = 8, > + .impl.min_access_size = 8, > + .impl.max_access_size = 8, > + .endianness = DEVICE_BIG_ENDIAN, > +}; > + > +static void pnv_quad_realize(DeviceState *dev, Error **errp) > +{ > + PnvQuad *eq = PNV_QUAD(dev); > + char name[32]; > + > + snprintf(name, sizeof(name), "xscom-quad.%d", eq->id); > + pnv_xscom_region_init(&eq->xscom_regs, OBJECT(dev), &pnv_quad_xscom_ops, > + eq, name, PNV9_XSCOM_EQ_SIZE); > +} > + > +static Property pnv_quad_properties[] = { > + DEFINE_PROP_UINT32("id", PnvQuad, id, 0), > + DEFINE_PROP_END_OF_LIST(), > +}; > + > +static void pnv_quad_class_init(ObjectClass *oc, void *data) > +{ > + DeviceClass *dc = DEVICE_CLASS(oc); > + > + dc->realize = pnv_quad_realize; > + dc->props = pnv_quad_properties; > +} > + > +static const TypeInfo pnv_quad_info = { > + .name = TYPE_PNV_QUAD, > + .parent = TYPE_DEVICE, > + .instance_size = sizeof(PnvQuad), > + .class_init = pnv_quad_class_init, > +}; > + > +static void pnv_core_register_types(void) > +{ > + type_register_static(&pnv_quad_info); > +} > + > +type_init(pnv_core_register_types) -- David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson