ppc/pnv: introduce Pnv8Chip and Pnv9Chip models
It introduces a base PnvChip class from which the specific processor chip classes, Pnv8Chip and Pnv9Chip, inherit. Each of them needs to define an init and a realize routine which will create the controllers of the target processor. For the moment, the base PnvChip class handles the XSCOM bus and the cores. Signed-off-by: Cédric Le Goater <clg@kaod.org> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
This commit is contained in:
parent
7f9fe3f02d
commit
77864267c3
281
hw/ppc/pnv.c
281
hw/ppc/pnv.c
@ -531,12 +531,14 @@ static void pnv_reset(void)
|
||||
|
||||
static ISABus *pnv_chip_power8_isa_create(PnvChip *chip, Error **errp)
|
||||
{
|
||||
return pnv_lpc_isa_create(&chip->lpc, true, errp);
|
||||
Pnv8Chip *chip8 = PNV8_CHIP(chip);
|
||||
return pnv_lpc_isa_create(&chip8->lpc, true, errp);
|
||||
}
|
||||
|
||||
static ISABus *pnv_chip_power8nvl_isa_create(PnvChip *chip, Error **errp)
|
||||
{
|
||||
return pnv_lpc_isa_create(&chip->lpc, false, errp);
|
||||
Pnv8Chip *chip8 = PNV8_CHIP(chip);
|
||||
return pnv_lpc_isa_create(&chip8->lpc, false, errp);
|
||||
}
|
||||
|
||||
static ISABus *pnv_chip_power9_isa_create(PnvChip *chip, Error **errp)
|
||||
@ -725,6 +727,103 @@ static Object *pnv_chip_power9_intc_create(PnvChip *chip, Object *child,
|
||||
*/
|
||||
#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);
|
||||
@ -738,6 +837,9 @@ static void pnv_chip_power8e_class_init(ObjectClass *klass, void *data)
|
||||
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)
|
||||
@ -753,6 +855,9 @@ static void pnv_chip_power8_class_init(ObjectClass *klass, void *data)
|
||||
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)
|
||||
@ -768,6 +873,25 @@ static void pnv_chip_power8nvl_class_init(ObjectClass *klass, void *data)
|
||||
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)
|
||||
@ -783,6 +907,9 @@ static void pnv_chip_power9_class_init(ObjectClass *klass, void *data)
|
||||
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)
|
||||
@ -815,59 +942,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)
|
||||
@ -951,37 +1028,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[] = {
|
||||
@ -1009,8 +1055,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;
|
||||
@ -1022,7 +1070,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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1063,7 +1112,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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1098,7 +1148,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;
|
||||
@ -1138,11 +1188,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[] = {
|
||||
@ -1150,7 +1207,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 },
|
||||
@ -1162,16 +1219,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)
|
||||
|
@ -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,6 +95,8 @@ 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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user