Re: [Qemu-devel] [PATCH v2 04/15] ppc/pnv: add a LPC Controller class model

2019-03-07 Thread David Gibson
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

2019-03-07 Thread Cédric Le Goater
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,