Re: [Qemu-devel] [PATCH v2 04/15] ppc/pnv: add a LPC Controller class model
On Thu, Mar 07, 2019 at 11:35:37PM +0100, Cédric Le Goater wrote: > It will ease the introduction of the LPC Controller model for POWER9. > > Signed-off-by: Cédric Le Goater > Reviewed-by: David Gibson Applied, thanks. > --- > include/hw/ppc/pnv_lpc.h | 15 +++ > hw/ppc/pnv.c | 2 +- > hw/ppc/pnv_lpc.c | 85 > 3 files changed, 77 insertions(+), 25 deletions(-) > > diff --git a/include/hw/ppc/pnv_lpc.h b/include/hw/ppc/pnv_lpc.h > index d657489b07ce..f3f24419b19a 100644 > --- a/include/hw/ppc/pnv_lpc.h > +++ b/include/hw/ppc/pnv_lpc.h > @@ -24,6 +24,8 @@ > #define TYPE_PNV_LPC "pnv-lpc" > #define PNV_LPC(obj) \ > OBJECT_CHECK(PnvLpcController, (obj), TYPE_PNV_LPC) > +#define TYPE_PNV8_LPC TYPE_PNV_LPC "-POWER8" > +#define PNV8_LPC(obj) OBJECT_CHECK(PnvLpcController, (obj), TYPE_PNV8_LPC) > > typedef struct PnvLpcController { > DeviceState parent; > @@ -70,6 +72,19 @@ typedef struct PnvLpcController { > PnvPsi *psi; > } PnvLpcController; > > +#define PNV_LPC_CLASS(klass) \ > + OBJECT_CLASS_CHECK(PnvLpcClass, (klass), TYPE_PNV_LPC) > +#define PNV_LPC_GET_CLASS(obj) \ > + OBJECT_GET_CLASS(PnvLpcClass, (obj), TYPE_PNV_LPC) > + > +typedef struct PnvLpcClass { > +DeviceClass parent_class; > + > +int psi_irq; > + > +DeviceRealize parent_realize; > +} PnvLpcClass; > + > ISABus *pnv_lpc_isa_create(PnvLpcController *lpc, bool use_cpld, Error > **errp); > > #endif /* _PPC_PNV_LPC_H */ > diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c > index 1cc454cbbc27..922e3ec48bb5 100644 > --- a/hw/ppc/pnv.c > +++ b/hw/ppc/pnv.c > @@ -794,7 +794,7 @@ static void pnv_chip_power8_instance_init(Object *obj) > OBJECT(qdev_get_machine()), _abort); > > object_initialize_child(obj, "lpc", >lpc, sizeof(chip8->lpc), > -TYPE_PNV_LPC, _abort, NULL); > +TYPE_PNV8_LPC, _abort, NULL); > object_property_add_const_link(OBJECT(>lpc), "psi", > OBJECT(>psi), _abort); > > diff --git a/hw/ppc/pnv_lpc.c b/hw/ppc/pnv_lpc.c > index 547be609cafe..3c509a30a0af 100644 > --- a/hw/ppc/pnv_lpc.c > +++ b/hw/ppc/pnv_lpc.c > @@ -245,6 +245,7 @@ static const MemoryRegionOps pnv_lpc_xscom_ops = { > static void pnv_lpc_eval_irqs(PnvLpcController *lpc) > { > bool lpc_to_opb_irq = false; > +PnvLpcClass *plc = PNV_LPC_GET_CLASS(lpc); > > /* Update LPC controller to OPB line */ > if (lpc->lpc_hc_irqser_ctrl & LPC_HC_IRQSER_EN) { > @@ -267,7 +268,7 @@ static void pnv_lpc_eval_irqs(PnvLpcController *lpc) > lpc->opb_irq_stat |= lpc->opb_irq_input & lpc->opb_irq_mask; > > /* Reflect the interrupt */ > -pnv_psi_irq_set(lpc->psi, PSIHB_IRQ_LPC_I2C, lpc->opb_irq_stat != 0); > +pnv_psi_irq_set(lpc->psi, plc->psi_irq, lpc->opb_irq_stat != 0); > } > > static uint64_t lpc_hc_read(void *opaque, hwaddr addr, unsigned size) > @@ -419,11 +420,65 @@ static const MemoryRegionOps opb_master_ops = { > }, > }; > > +static void pnv_lpc_power8_realize(DeviceState *dev, Error **errp) > +{ > +PnvLpcController *lpc = PNV_LPC(dev); > +PnvLpcClass *plc = PNV_LPC_GET_CLASS(dev); > +Error *local_err = NULL; > + > +plc->parent_realize(dev, _err); > +if (local_err) { > +error_propagate(errp, local_err); > +return; > +} > + > +/* P8 uses a XSCOM region for LPC registers */ > +pnv_xscom_region_init(>xscom_regs, OBJECT(lpc), > + _lpc_xscom_ops, lpc, "xscom-lpc", > + PNV_XSCOM_LPC_SIZE); > +} > + > +static void pnv_lpc_power8_class_init(ObjectClass *klass, void *data) > +{ > +DeviceClass *dc = DEVICE_CLASS(klass); > +PnvXScomInterfaceClass *xdc = PNV_XSCOM_INTERFACE_CLASS(klass); > +PnvLpcClass *plc = PNV_LPC_CLASS(klass); > + > +dc->desc = "PowerNV LPC Controller POWER8"; > + > +xdc->dt_xscom = pnv_lpc_dt_xscom; > + > +plc->psi_irq = PSIHB_IRQ_LPC_I2C; > + > +device_class_set_parent_realize(dc, pnv_lpc_power8_realize, > +>parent_realize); > +} > + > +static const TypeInfo pnv_lpc_power8_info = { > +.name = TYPE_PNV8_LPC, > +.parent= TYPE_PNV_LPC, > +.instance_size = sizeof(PnvLpcController), > +.class_init= pnv_lpc_power8_class_init, > +.interfaces = (InterfaceInfo[]) { > +{ TYPE_PNV_XSCOM_INTERFACE }, > +{ } > +} > +}; > + > static void pnv_lpc_realize(DeviceState *dev, Error **errp) > { > PnvLpcController *lpc = PNV_LPC(dev); > Object *obj; > -Error *error = NULL; > +Error *local_err = NULL; > + > +obj = object_property_get_link(OBJECT(dev), "psi", _err); > +if (!obj) { > +error_propagate(errp, local_err); > +error_prepend(errp, "required link 'psi' not found: "); > +return; > +} > +/* The LPC controller needs PSI
[Qemu-devel] [PATCH v2 04/15] ppc/pnv: add a LPC Controller class model
It will ease the introduction of the LPC Controller model for POWER9. Signed-off-by: Cédric Le Goater Reviewed-by: David Gibson --- include/hw/ppc/pnv_lpc.h | 15 +++ hw/ppc/pnv.c | 2 +- hw/ppc/pnv_lpc.c | 85 3 files changed, 77 insertions(+), 25 deletions(-) diff --git a/include/hw/ppc/pnv_lpc.h b/include/hw/ppc/pnv_lpc.h index d657489b07ce..f3f24419b19a 100644 --- a/include/hw/ppc/pnv_lpc.h +++ b/include/hw/ppc/pnv_lpc.h @@ -24,6 +24,8 @@ #define TYPE_PNV_LPC "pnv-lpc" #define PNV_LPC(obj) \ OBJECT_CHECK(PnvLpcController, (obj), TYPE_PNV_LPC) +#define TYPE_PNV8_LPC TYPE_PNV_LPC "-POWER8" +#define PNV8_LPC(obj) OBJECT_CHECK(PnvLpcController, (obj), TYPE_PNV8_LPC) typedef struct PnvLpcController { DeviceState parent; @@ -70,6 +72,19 @@ typedef struct PnvLpcController { PnvPsi *psi; } PnvLpcController; +#define PNV_LPC_CLASS(klass) \ + OBJECT_CLASS_CHECK(PnvLpcClass, (klass), TYPE_PNV_LPC) +#define PNV_LPC_GET_CLASS(obj) \ + OBJECT_GET_CLASS(PnvLpcClass, (obj), TYPE_PNV_LPC) + +typedef struct PnvLpcClass { +DeviceClass parent_class; + +int psi_irq; + +DeviceRealize parent_realize; +} PnvLpcClass; + ISABus *pnv_lpc_isa_create(PnvLpcController *lpc, bool use_cpld, Error **errp); #endif /* _PPC_PNV_LPC_H */ diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index 1cc454cbbc27..922e3ec48bb5 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -794,7 +794,7 @@ static void pnv_chip_power8_instance_init(Object *obj) OBJECT(qdev_get_machine()), _abort); object_initialize_child(obj, "lpc", >lpc, sizeof(chip8->lpc), -TYPE_PNV_LPC, _abort, NULL); +TYPE_PNV8_LPC, _abort, NULL); object_property_add_const_link(OBJECT(>lpc), "psi", OBJECT(>psi), _abort); diff --git a/hw/ppc/pnv_lpc.c b/hw/ppc/pnv_lpc.c index 547be609cafe..3c509a30a0af 100644 --- a/hw/ppc/pnv_lpc.c +++ b/hw/ppc/pnv_lpc.c @@ -245,6 +245,7 @@ static const MemoryRegionOps pnv_lpc_xscom_ops = { static void pnv_lpc_eval_irqs(PnvLpcController *lpc) { bool lpc_to_opb_irq = false; +PnvLpcClass *plc = PNV_LPC_GET_CLASS(lpc); /* Update LPC controller to OPB line */ if (lpc->lpc_hc_irqser_ctrl & LPC_HC_IRQSER_EN) { @@ -267,7 +268,7 @@ static void pnv_lpc_eval_irqs(PnvLpcController *lpc) lpc->opb_irq_stat |= lpc->opb_irq_input & lpc->opb_irq_mask; /* Reflect the interrupt */ -pnv_psi_irq_set(lpc->psi, PSIHB_IRQ_LPC_I2C, lpc->opb_irq_stat != 0); +pnv_psi_irq_set(lpc->psi, plc->psi_irq, lpc->opb_irq_stat != 0); } static uint64_t lpc_hc_read(void *opaque, hwaddr addr, unsigned size) @@ -419,11 +420,65 @@ static const MemoryRegionOps opb_master_ops = { }, }; +static void pnv_lpc_power8_realize(DeviceState *dev, Error **errp) +{ +PnvLpcController *lpc = PNV_LPC(dev); +PnvLpcClass *plc = PNV_LPC_GET_CLASS(dev); +Error *local_err = NULL; + +plc->parent_realize(dev, _err); +if (local_err) { +error_propagate(errp, local_err); +return; +} + +/* P8 uses a XSCOM region for LPC registers */ +pnv_xscom_region_init(>xscom_regs, OBJECT(lpc), + _lpc_xscom_ops, lpc, "xscom-lpc", + PNV_XSCOM_LPC_SIZE); +} + +static void pnv_lpc_power8_class_init(ObjectClass *klass, void *data) +{ +DeviceClass *dc = DEVICE_CLASS(klass); +PnvXScomInterfaceClass *xdc = PNV_XSCOM_INTERFACE_CLASS(klass); +PnvLpcClass *plc = PNV_LPC_CLASS(klass); + +dc->desc = "PowerNV LPC Controller POWER8"; + +xdc->dt_xscom = pnv_lpc_dt_xscom; + +plc->psi_irq = PSIHB_IRQ_LPC_I2C; + +device_class_set_parent_realize(dc, pnv_lpc_power8_realize, +>parent_realize); +} + +static const TypeInfo pnv_lpc_power8_info = { +.name = TYPE_PNV8_LPC, +.parent= TYPE_PNV_LPC, +.instance_size = sizeof(PnvLpcController), +.class_init= pnv_lpc_power8_class_init, +.interfaces = (InterfaceInfo[]) { +{ TYPE_PNV_XSCOM_INTERFACE }, +{ } +} +}; + static void pnv_lpc_realize(DeviceState *dev, Error **errp) { PnvLpcController *lpc = PNV_LPC(dev); Object *obj; -Error *error = NULL; +Error *local_err = NULL; + +obj = object_property_get_link(OBJECT(dev), "psi", _err); +if (!obj) { +error_propagate(errp, local_err); +error_prepend(errp, "required link 'psi' not found: "); +return; +} +/* The LPC controller needs PSI to generate interrupts */ +lpc->psi = PNV_PSI(obj); /* Reg inits */ lpc->lpc_hc_fw_rd_acc_size = LPC_HC_FW_RD_4B; @@ -463,46 +518,28 @@ static void pnv_lpc_realize(DeviceState *dev, Error **errp) "lpc-hc", LPC_HC_REGS_OPB_SIZE); memory_region_add_subregion(>opb_mr, LPC_HC_REGS_OPB_ADDR,