[2/5] ppc/pnv: Introduce a POWER10 PnvChip and a powernv10 machine
diff mbox series

Message ID 20191205184454.10722-3-clg@kaod.org
State New
Headers show
Series
  • ppc/pnv: add a POWER10 PnvChip and a powernv10 machine
Related show

Commit Message

Cédric Le Goater Dec. 5, 2019, 6:44 p.m. UTC
This is an empty shell with the XSCOM bus and cores. The chip controllers
will come later.

Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 include/hw/ppc/pnv.h       |  33 ++++++++
 include/hw/ppc/pnv_xscom.h |  19 +++++
 hw/ppc/pnv.c               | 158 +++++++++++++++++++++++++++++++++++--
 hw/ppc/pnv_core.c          |  10 +++
 hw/ppc/pnv_xscom.c         |  23 ++++--
 5 files changed, 232 insertions(+), 11 deletions(-)

Comments

David Gibson Dec. 10, 2019, 3:34 a.m. UTC | #1
On Thu, Dec 05, 2019 at 07:44:51PM +0100, Cédric Le Goater wrote:
> This is an empty shell with the XSCOM bus and cores. The chip controllers
> will come later.
> 
> Signed-off-by: Cédric Le Goater <clg@kaod.org>
> ---
>  include/hw/ppc/pnv.h       |  33 ++++++++
>  include/hw/ppc/pnv_xscom.h |  19 +++++
>  hw/ppc/pnv.c               | 158 +++++++++++++++++++++++++++++++++++--
>  hw/ppc/pnv_core.c          |  10 +++
>  hw/ppc/pnv_xscom.c         |  23 ++++--
>  5 files changed, 232 insertions(+), 11 deletions(-)
> 
> diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
> index 3a7bc3c57e0d..bfa61edfbabd 100644
> --- a/include/hw/ppc/pnv.h
> +++ b/include/hw/ppc/pnv.h
> @@ -43,6 +43,7 @@ typedef enum PnvChipType {
>      PNV_CHIP_POWER8,      /* AKA Venice */
>      PNV_CHIP_POWER8NVL,   /* AKA Naples */
>      PNV_CHIP_POWER9,      /* AKA Nimbus */
> +    PNV_CHIP_POWER10,     /* AKA TBD */
>  } PnvChipType;
>  
>  typedef struct PnvChip {
> @@ -105,6 +106,14 @@ typedef struct Pnv9Chip {
>  #define PNV9_PIR2FUSEDCORE(pir) (((pir) >> 3) & 0xf)
>  #define PNV9_PIR2CHIP(pir)      (((pir) >> 8) & 0x7f)
>  
> +#define TYPE_PNV10_CHIP "pnv10-chip"
> +#define PNV10_CHIP(obj) OBJECT_CHECK(Pnv10Chip, (obj), TYPE_PNV10_CHIP)
> +
> +typedef struct Pnv10Chip {
> +    /*< private >*/
> +    PnvChip      parent_obj;
> +} Pnv10Chip;
> +
>  typedef struct PnvChipClass {
>      /*< private >*/
>      SysBusDeviceClass parent_class;
> @@ -144,6 +153,10 @@ typedef struct PnvChipClass {
>  #define PNV_CHIP_POWER9(obj) \
>      OBJECT_CHECK(PnvChip, (obj), TYPE_PNV_CHIP_POWER9)
>  
> +#define TYPE_PNV_CHIP_POWER10 PNV_CHIP_TYPE_NAME("power10_v1.0")
> +#define PNV_CHIP_POWER10(obj) \
> +    OBJECT_CHECK(PnvChip, (obj), TYPE_PNV_CHIP_POWER10)
> +
>  /*
>   * This generates a HW chip id depending on an index, as found on a
>   * two socket system with dual chip modules :
> @@ -203,6 +216,16 @@ PnvChip *pnv_get_chip(uint32_t chip_id);
>  #define PNV_FDT_ADDR          0x01000000
>  #define PNV_TIMEBASE_FREQ     512000000ULL
>  
> +static inline bool pnv_chip_is_power10(const PnvChip *chip)
> +{
> +    return PNV_CHIP_GET_CLASS(chip)->chip_type == PNV_CHIP_POWER10;
> +}
> +
> +static inline bool pnv_is_power10(PnvMachineState *pnv)
> +{
> +    return pnv_chip_is_power10(pnv->chips[0]);
> +}

It's not in scope for this series, but now that we have P8/9/10
specific chip object types and powernv8/powernv9, we should be able to
remove the ugly chip_type field, and just do object class checks on
the chip and or machine objects themselves.

> +
>  /*
>   * BMC helpers
>   */
> @@ -293,4 +316,14 @@ IPMIBmc *pnv_bmc_create(void);
>  #define PNV9_HOMER_SIZE              0x0000000000300000ull
>  #define PNV9_HOMER_BASE(chip)                                           \
>      (0x203ffd800000ull + ((uint64_t)PNV_CHIP_INDEX(chip)) * PNV9_HOMER_SIZE)
> +
> +/*
> + * POWER10 MMIO base addresses - 16TB stride per chip
> + */
> +#define PNV10_CHIP_BASE(chip, base)   \
> +    ((base) + ((uint64_t) (chip)->chip_id << 44))
> +
> +#define PNV10_XSCOM_SIZE             0x0000000400000000ull
> +#define PNV10_XSCOM_BASE(chip)       PNV10_CHIP_BASE(chip, 0x00603fc00000000ull)
> +
>  #endif /* PPC_PNV_H */
> diff --git a/include/hw/ppc/pnv_xscom.h b/include/hw/ppc/pnv_xscom.h
> index 67641ed27800..790eb3d8f3b0 100644
> --- a/include/hw/ppc/pnv_xscom.h
> +++ b/include/hw/ppc/pnv_xscom.h
> @@ -70,6 +70,9 @@ typedef struct PnvXScomInterfaceClass {
>  #define PNV_XSCOM_OCC_BASE        0x0066000
>  #define PNV_XSCOM_OCC_SIZE        0x6000
>  
> +/*
> + * Layout of the XSCOM PCB addresses (POWER 9)
> + */
>  #define PNV9_XSCOM_EC_BASE(core) \
>      ((uint64_t)(((core) & 0x1F) + 0x20) << 24)
>  #define PNV9_XSCOM_EC_SIZE        0x100000
> @@ -87,6 +90,22 @@ typedef struct PnvXScomInterfaceClass {
>  #define PNV9_XSCOM_XIVE_BASE      0x5013000
>  #define PNV9_XSCOM_XIVE_SIZE      0x300
>  
> +/*
> + * Layout of the XSCOM PCB addresses (POWER 10)
> + */
> +#define PNV10_XSCOM_EQ_CHIPLET(core)  (0x20 + ((core) >> 2))
> +#define PNV10_XSCOM_EQ(chiplet)       ((chiplet) << 24)
> +#define PNV10_XSCOM_EC(proc)                    \
> +    ((0x2 << 16) | ((1 << (3 - (proc))) << 12))
> +
> +#define PNV10_XSCOM_EQ_BASE(core)     \
> +    ((uint64_t) PNV10_XSCOM_EQ(PNV10_XSCOM_EQ_CHIPLET(core)))
> +#define PNV10_XSCOM_EQ_SIZE        0x100000
> +
> +#define PNV10_XSCOM_EC_BASE(core) \
> +    ((uint64_t) PNV10_XSCOM_EQ_BASE(core) | PNV10_XSCOM_EC(core & 0x3))
> +#define PNV10_XSCOM_EC_SIZE        0x100000
> +
>  extern void pnv_xscom_realize(PnvChip *chip, uint64_t size, Error **errp);
>  extern int pnv_dt_xscom(PnvChip *chip, void *fdt, int offset);
>  
> diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
> index fa656858b24a..d99cd72840be 100644
> --- a/hw/ppc/pnv.c
> +++ b/hw/ppc/pnv.c
> @@ -317,6 +317,23 @@ static void pnv_chip_power9_dt_populate(PnvChip *chip, void *fdt)
>      pnv_dt_lpc(chip, fdt, 0);
>  }
>  
> +static void pnv_chip_power10_dt_populate(PnvChip *chip, void *fdt)
> +{
> +    int i;
> +
> +    pnv_dt_xscom(chip, fdt, 0);
> +
> +    for (i = 0; i < chip->nr_cores; i++) {
> +        PnvCore *pnv_core = chip->cores[i];
> +
> +        pnv_dt_core(chip, pnv_core, fdt);
> +    }
> +
> +    if (chip->ram_size) {
> +        pnv_dt_memory(fdt, chip->chip_id, chip->ram_start, chip->ram_size);
> +    }
> +}
> +
>  static void pnv_dt_rtc(ISADevice *d, void *fdt, int lpc_off)
>  {
>      uint32_t io_base = d->ioport_id;
> @@ -467,6 +484,7 @@ static void *pnv_dt_create(MachineState *machine)
>  {
>      const char plat_compat8[] = "qemu,powernv8\0qemu,powernv\0ibm,powernv";
>      const char plat_compat9[] = "qemu,powernv9\0ibm,powernv";
> +    const char plat_compat10[] = "qemu,powernv10\0ibm,powernv";
>      PnvMachineState *pnv = PNV_MACHINE(machine);
>      void *fdt;
>      char *buf;
> @@ -484,7 +502,10 @@ static void *pnv_dt_create(MachineState *machine)
>      _FDT((fdt_setprop_cell(fdt, 0, "#size-cells", 0x2)));
>      _FDT((fdt_setprop_string(fdt, 0, "model",
>                               "IBM PowerNV (emulated by qemu)")));
> -    if (pnv_is_power9(pnv)) {
> +    if (pnv_is_power10(pnv)) {
> +        _FDT((fdt_setprop(fdt, 0, "compatible", plat_compat10,
> +                          sizeof(plat_compat10))));
> +    } else if (pnv_is_power9(pnv)) {
>          _FDT((fdt_setprop(fdt, 0, "compatible", plat_compat9,
>                            sizeof(plat_compat9))));
>      } else {
> @@ -528,8 +549,8 @@ static void *pnv_dt_create(MachineState *machine)
>          pnv_dt_bmc_sensors(pnv->bmc, fdt);
>      }
>  
> -    /* Create an extra node for power management on Power9 */
> -    if (pnv_is_power9(pnv)) {
> +    /* Create an extra node for power management on Power9 and Power10 */
> +    if (pnv_is_power9(pnv) || pnv_is_power10(pnv)) {
>          pnv_dt_power_mgt(fdt);
>      }
>  
> @@ -578,6 +599,12 @@ static ISABus *pnv_chip_power9_isa_create(PnvChip *chip, Error **errp)
>      return pnv_lpc_isa_create(&chip9->lpc, false, errp);
>  }
>  
> +static ISABus *pnv_chip_power10_isa_create(PnvChip *chip, Error **errp)
> +{
> +    error_setg(errp, "No ISA bus!");
> +    return NULL;
> +}
> +
>  static ISABus *pnv_isa_create(PnvChip *chip, Error **errp)
>  {
>      return PNV_CHIP_GET_CLASS(chip)->isa_create(chip, errp);
> @@ -618,6 +645,13 @@ static void pnv_ipmi_bt_init(ISABus *bus, IPMIBmc *bmc, uint32_t irq)
>      object_property_set_bool(obj, true, "realized", &error_fatal);
>  }
>  
> +static void pnv_chip_power10_pic_print_info(PnvChip *chip, Monitor *mon)
> +{
> +    /*
> +     * No interrupt controller yet
> +     */;
> +}
> +
>  static void pnv_init(MachineState *machine)
>  {
>      PnvMachineState *pnv = PNV_MACHINE(machine);
> @@ -822,6 +856,11 @@ static uint32_t pnv_chip_core_pir_p9(PnvChip *chip, uint32_t core_id)
>      return (chip->chip_id << 8) | (core_id << 2);
>  }
>  
> +static uint32_t pnv_chip_core_pir_p10(PnvChip *chip, uint32_t core_id)
> +{
> +    return (chip->chip_id << 8) | (core_id << 2);
> +}
> +
>  static void pnv_chip_power9_intc_create(PnvChip *chip, PowerPCCPU *cpu,
>                                          Error **errp)
>  {
> @@ -859,6 +898,27 @@ static void pnv_chip_power9_intc_destroy(PnvChip *chip, PowerPCCPU *cpu)
>      pnv_cpu->intc = NULL;
>  }
>  
> +static void pnv_chip_power10_intc_create(PnvChip *chip, PowerPCCPU *cpu,
> +                                        Error **errp)
> +{
> +    PnvCPUState *pnv_cpu = pnv_cpu_state(cpu);
> +
> +    /* Will be defined when the interrupt controller is */
> +    pnv_cpu->intc = NULL;
> +}
> +
> +static void pnv_chip_power10_intc_reset(PnvChip *chip, PowerPCCPU *cpu)
> +{
> +    ;
> +}
> +
> +static void pnv_chip_power10_intc_destroy(PnvChip *chip, PowerPCCPU *cpu)
> +{
> +    PnvCPUState *pnv_cpu = pnv_cpu_state(cpu);
> +
> +    pnv_cpu->intc = NULL;
> +}
> +
>  /*
>   * Allowed core identifiers on a POWER8 Processor Chip :
>   *
> @@ -886,6 +946,9 @@ static void pnv_chip_power9_intc_destroy(PnvChip *chip, PowerPCCPU *cpu)
>   */
>  #define POWER9_CORE_MASK   (0xffffffffffffffull)
>  
> +
> +#define POWER10_CORE_MASK  (0xffffffffffffffull)
> +
>  static void pnv_chip_power8_instance_init(Object *obj)
>  {
>      Pnv8Chip *chip8 = PNV8_CHIP(obj);
> @@ -1246,6 +1309,56 @@ static void pnv_chip_power9_class_init(ObjectClass *klass, void *data)
>                                      &k->parent_realize);
>  }
>  
> +static void pnv_chip_power10_instance_init(Object *obj)
> +{
> +    /*
> +     * No controllers yet
> +     */
> +    ;
> +}
> +
> +static void pnv_chip_power10_realize(DeviceState *dev, Error **errp)
> +{
> +    PnvChipClass *pcc = PNV_CHIP_GET_CLASS(dev);
> +    PnvChip *chip = PNV_CHIP(dev);
> +    Error *local_err = NULL;
> +
> +    /* XSCOM bridge is first */
> +    pnv_xscom_realize(chip, PNV10_XSCOM_SIZE, &local_err);
> +    if (local_err) {
> +        error_propagate(errp, local_err);
> +        return;
> +    }
> +    sysbus_mmio_map(SYS_BUS_DEVICE(chip), 0, PNV10_XSCOM_BASE(chip));
> +
> +    pcc->parent_realize(dev, &local_err);
> +    if (local_err) {
> +        error_propagate(errp, local_err);
> +        return;
> +    }
> +}
> +
> +static void pnv_chip_power10_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    PnvChipClass *k = PNV_CHIP_CLASS(klass);
> +
> +    k->chip_type = PNV_CHIP_POWER10;
> +    k->chip_cfam_id = 0x120da04900008000ull; /* P10 DD1.0 (with NX) */
> +    k->cores_mask = POWER10_CORE_MASK;
> +    k->core_pir = pnv_chip_core_pir_p10;
> +    k->intc_create = pnv_chip_power10_intc_create;
> +    k->intc_reset = pnv_chip_power10_intc_reset;
> +    k->intc_destroy = pnv_chip_power10_intc_destroy;
> +    k->isa_create = pnv_chip_power10_isa_create;
> +    k->dt_populate = pnv_chip_power10_dt_populate;
> +    k->pic_print_info = pnv_chip_power10_pic_print_info;
> +    dc->desc = "PowerNV Chip POWER10";
> +
> +    device_class_set_parent_realize(dc, pnv_chip_power10_realize,
> +                                    &k->parent_realize);
> +}
> +
>  static void pnv_chip_core_sanitize(PnvChip *chip, Error **errp)
>  {
>      PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
> @@ -1327,10 +1440,12 @@ static void pnv_chip_core_realize(PnvChip *chip, Error **errp)
>                                   &error_fatal);
>  
>          /* Each core has an XSCOM MMIO region */
> -        if (!pnv_chip_is_power9(chip)) {
> -            xscom_core_base = PNV_XSCOM_EX_BASE(core_hwid);
> -        } else {
> +        if (pnv_chip_is_power10(chip)) {
> +            xscom_core_base = PNV10_XSCOM_EC_BASE(core_hwid);
> +        } else if (pnv_chip_is_power9(chip)) {
>              xscom_core_base = PNV9_XSCOM_EC_BASE(core_hwid);
> +        } else {
> +            xscom_core_base = PNV_XSCOM_EX_BASE(core_hwid);
>          }
>  
>          pnv_xscom_add_subregion(chip, xscom_core_base,
> @@ -1558,6 +1673,14 @@ static void pnv_machine_power9_class_init(ObjectClass *oc, void *data)
>      mc->alias = "powernv";
>  }
>  
> +static void pnv_machine_power10_class_init(ObjectClass *oc, void *data)
> +{
> +    MachineClass *mc = MACHINE_CLASS(oc);
> +
> +    mc->desc = "IBM PowerNV (Non-Virtualized) POWER10";
> +    mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power10_v1.0");
> +}
> +
>  static void pnv_machine_class_init(ObjectClass *oc, void *data)
>  {
>      MachineClass *mc = MACHINE_CLASS(oc);
> @@ -1595,7 +1718,19 @@ static void pnv_machine_class_init(ObjectClass *oc, void *data)
>          .parent        = TYPE_PNV9_CHIP,          \
>      }
>  
> +#define DEFINE_PNV10_CHIP_TYPE(type, class_initfn) \
> +    {                                              \
> +        .name          = type,                     \
> +        .class_init    = class_initfn,             \
> +        .parent        = TYPE_PNV10_CHIP,          \
> +    }
> +
>  static const TypeInfo types[] = {
> +    {
> +        .name          = MACHINE_TYPE_NAME("powernv10"),
> +        .parent        = TYPE_PNV_MACHINE,
> +        .class_init    = pnv_machine_power10_class_init,
> +    },
>      {
>          .name          = MACHINE_TYPE_NAME("powernv9"),
>          .parent        = TYPE_PNV_MACHINE,
> @@ -1635,6 +1770,17 @@ static const TypeInfo types[] = {
>          .abstract      = true,
>      },
>  
> +    /*
> +     * P10 chip and variants
> +     */
> +    {
> +        .name          = TYPE_PNV10_CHIP,
> +        .parent        = TYPE_PNV_CHIP,
> +        .instance_init = pnv_chip_power10_instance_init,
> +        .instance_size = sizeof(Pnv10Chip),
> +    },
> +    DEFINE_PNV10_CHIP_TYPE(TYPE_PNV_CHIP_POWER10, pnv_chip_power10_class_init),
> +
>      /*
>       * P9 chip and variants
>       */
> diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c
> index 5ab75bde6cc5..2651044278ed 100644
> --- a/hw/ppc/pnv_core.c
> +++ b/hw/ppc/pnv_core.c
> @@ -247,6 +247,7 @@ static void pnv_core_realize(DeviceState *dev, Error **errp)
>      }
>  
>      snprintf(name, sizeof(name), "xscom-core.%d", cc->core_id);
> +    /* TODO: check PNV_XSCOM_EX_SIZE for p10 */
>      pnv_xscom_region_init(&pc->xscom_regs, OBJECT(dev), pcc->xscom_ops,
>                            pc, name, PNV_XSCOM_EX_SIZE);
>  
> @@ -308,6 +309,14 @@ static void pnv_core_power9_class_init(ObjectClass *oc, void *data)
>      pcc->xscom_ops = &pnv_core_power9_xscom_ops;
>  }
>  
> +static void pnv_core_power10_class_init(ObjectClass *oc, void *data)
> +{
> +    PnvCoreClass *pcc = PNV_CORE_CLASS(oc);
> +
> +    /* TODO: Use the P9 XSCOMs for now on P10 */
> +    pcc->xscom_ops = &pnv_core_power9_xscom_ops;
> +}
> +
>  static void pnv_core_class_init(ObjectClass *oc, void *data)
>  {
>      DeviceClass *dc = DEVICE_CLASS(oc);
> @@ -337,6 +346,7 @@ static const TypeInfo pnv_core_infos[] = {
>      DEFINE_PNV_CORE_TYPE(power8, "power8_v2.0"),
>      DEFINE_PNV_CORE_TYPE(power8, "power8nvl_v1.0"),
>      DEFINE_PNV_CORE_TYPE(power9, "power9_v2.0"),
> +    DEFINE_PNV_CORE_TYPE(power10, "power10_v1.0"),
>  };
>  
>  DEFINE_TYPES(pnv_core_infos)
> diff --git a/hw/ppc/pnv_xscom.c b/hw/ppc/pnv_xscom.c
> index f01d788a6545..b3d3b6e3507d 100644
> --- a/hw/ppc/pnv_xscom.c
> +++ b/hw/ppc/pnv_xscom.c
> @@ -69,10 +69,16 @@ static uint32_t pnv_xscom_pcba(PnvChip *chip, uint64_t addr)
>  {
>      addr &= (PNV_XSCOM_SIZE - 1);
>  
> -    if (pnv_chip_is_power9(chip)) {
> -        return addr >> 3;
> -    } else {
> +    switch (PNV_CHIP_GET_CLASS(chip)->chip_type) {
> +    case PNV_CHIP_POWER8E:
> +    case PNV_CHIP_POWER8:
> +    case PNV_CHIP_POWER8NVL:
>          return ((addr >> 4) & ~0xfull) | ((addr >> 3) & 0xf);
> +    case PNV_CHIP_POWER9:
> +    case PNV_CHIP_POWER10:
> +        return addr >> 3;
> +    default:
> +        g_assert_not_reached();
>      }
>  }
>  
> @@ -307,6 +313,7 @@ static int xscom_dt_child(Object *child, void *opaque)
>  
>  static const char compat_p8[] = "ibm,power8-xscom\0ibm,xscom";
>  static const char compat_p9[] = "ibm,power9-xscom\0ibm,xscom";
> +static const char compat_p10[] = "ibm,power10-xscom\0ibm,xscom";
>  
>  int pnv_dt_xscom(PnvChip *chip, void *fdt, int root_offset)
>  {
> @@ -315,7 +322,10 @@ int pnv_dt_xscom(PnvChip *chip, void *fdt, int root_offset)
>      ForeachPopulateArgs args;
>      char *name;
>  
> -    if (pnv_chip_is_power9(chip)) {
> +    if (pnv_chip_is_power10(chip)) {
> +        reg[0] = cpu_to_be64(PNV10_XSCOM_BASE(chip));
> +        reg[1] = cpu_to_be64(PNV10_XSCOM_SIZE);
> +    } else if (pnv_chip_is_power9(chip)) {
>          reg[0] = cpu_to_be64(PNV9_XSCOM_BASE(chip));
>          reg[1] = cpu_to_be64(PNV9_XSCOM_SIZE);
>      } else {
> @@ -332,7 +342,10 @@ int pnv_dt_xscom(PnvChip *chip, void *fdt, int root_offset)
>      _FDT((fdt_setprop_cell(fdt, xscom_offset, "#size-cells", 1)));
>      _FDT((fdt_setprop(fdt, xscom_offset, "reg", reg, sizeof(reg))));
>  
> -    if (pnv_chip_is_power9(chip)) {
> +    if (pnv_chip_is_power10(chip)) {
> +        _FDT((fdt_setprop(fdt, xscom_offset, "compatible", compat_p10,
> +                          sizeof(compat_p10))));
> +    } else if (pnv_chip_is_power9(chip)) {
>          _FDT((fdt_setprop(fdt, xscom_offset, "compatible", compat_p9,
>                            sizeof(compat_p9))));
>      } else {
Cédric Le Goater Dec. 10, 2019, 8:52 a.m. UTC | #2
On 10/12/2019 04:34, David Gibson wrote:
>> +static inline bool pnv_chip_is_power10(const PnvChip *chip)
>> +{
>> +    return PNV_CHIP_GET_CLASS(chip)->chip_type == PNV_CHIP_POWER10;
>> +}
>> +
>> +static inline bool pnv_is_power10(PnvMachineState *pnv)
>> +{
>> +    return pnv_chip_is_power10(pnv->chips[0]);
>> +}
>

I agree this is starting to be ugly.

> It's not in scope for this series, but now that we have P8/9/10
> specific chip object types and powernv8/powernv9, we should be able to
> remove the ugly chip_type field, and just do object class checks on
> the chip and or machine objects themselves.
 

So we would use object_class_dynamic_cast() instead of field chip_type ?

C.
David Gibson Dec. 10, 2019, 11:42 p.m. UTC | #3
On Tue, Dec 10, 2019 at 09:52:05AM +0100, Cédric Le Goater wrote:
> On 10/12/2019 04:34, David Gibson wrote:
> >> +static inline bool pnv_chip_is_power10(const PnvChip *chip)
> >> +{
> >> +    return PNV_CHIP_GET_CLASS(chip)->chip_type == PNV_CHIP_POWER10;
> >> +}
> >> +
> >> +static inline bool pnv_is_power10(PnvMachineState *pnv)
> >> +{
> >> +    return pnv_chip_is_power10(pnv->chips[0]);
> >> +}
> >
> 
> I agree this is starting to be ugly.
> 
> > It's not in scope for this series, but now that we have P8/9/10
> > specific chip object types and powernv8/powernv9, we should be able to
> > remove the ugly chip_type field, and just do object class checks on
> > the chip and or machine objects themselves.
>  
> 
> So we would use object_class_dynamic_cast() instead of field
> chip_type ?

Just object_dynamic_cast() should suffice, since you have access to
the chip and machine instances.

Patch
diff mbox series

diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
index 3a7bc3c57e0d..bfa61edfbabd 100644
--- a/include/hw/ppc/pnv.h
+++ b/include/hw/ppc/pnv.h
@@ -43,6 +43,7 @@  typedef enum PnvChipType {
     PNV_CHIP_POWER8,      /* AKA Venice */
     PNV_CHIP_POWER8NVL,   /* AKA Naples */
     PNV_CHIP_POWER9,      /* AKA Nimbus */
+    PNV_CHIP_POWER10,     /* AKA TBD */
 } PnvChipType;
 
 typedef struct PnvChip {
@@ -105,6 +106,14 @@  typedef struct Pnv9Chip {
 #define PNV9_PIR2FUSEDCORE(pir) (((pir) >> 3) & 0xf)
 #define PNV9_PIR2CHIP(pir)      (((pir) >> 8) & 0x7f)
 
+#define TYPE_PNV10_CHIP "pnv10-chip"
+#define PNV10_CHIP(obj) OBJECT_CHECK(Pnv10Chip, (obj), TYPE_PNV10_CHIP)
+
+typedef struct Pnv10Chip {
+    /*< private >*/
+    PnvChip      parent_obj;
+} Pnv10Chip;
+
 typedef struct PnvChipClass {
     /*< private >*/
     SysBusDeviceClass parent_class;
@@ -144,6 +153,10 @@  typedef struct PnvChipClass {
 #define PNV_CHIP_POWER9(obj) \
     OBJECT_CHECK(PnvChip, (obj), TYPE_PNV_CHIP_POWER9)
 
+#define TYPE_PNV_CHIP_POWER10 PNV_CHIP_TYPE_NAME("power10_v1.0")
+#define PNV_CHIP_POWER10(obj) \
+    OBJECT_CHECK(PnvChip, (obj), TYPE_PNV_CHIP_POWER10)
+
 /*
  * This generates a HW chip id depending on an index, as found on a
  * two socket system with dual chip modules :
@@ -203,6 +216,16 @@  PnvChip *pnv_get_chip(uint32_t chip_id);
 #define PNV_FDT_ADDR          0x01000000
 #define PNV_TIMEBASE_FREQ     512000000ULL
 
+static inline bool pnv_chip_is_power10(const PnvChip *chip)
+{
+    return PNV_CHIP_GET_CLASS(chip)->chip_type == PNV_CHIP_POWER10;
+}
+
+static inline bool pnv_is_power10(PnvMachineState *pnv)
+{
+    return pnv_chip_is_power10(pnv->chips[0]);
+}
+
 /*
  * BMC helpers
  */
@@ -293,4 +316,14 @@  IPMIBmc *pnv_bmc_create(void);
 #define PNV9_HOMER_SIZE              0x0000000000300000ull
 #define PNV9_HOMER_BASE(chip)                                           \
     (0x203ffd800000ull + ((uint64_t)PNV_CHIP_INDEX(chip)) * PNV9_HOMER_SIZE)
+
+/*
+ * POWER10 MMIO base addresses - 16TB stride per chip
+ */
+#define PNV10_CHIP_BASE(chip, base)   \
+    ((base) + ((uint64_t) (chip)->chip_id << 44))
+
+#define PNV10_XSCOM_SIZE             0x0000000400000000ull
+#define PNV10_XSCOM_BASE(chip)       PNV10_CHIP_BASE(chip, 0x00603fc00000000ull)
+
 #endif /* PPC_PNV_H */
diff --git a/include/hw/ppc/pnv_xscom.h b/include/hw/ppc/pnv_xscom.h
index 67641ed27800..790eb3d8f3b0 100644
--- a/include/hw/ppc/pnv_xscom.h
+++ b/include/hw/ppc/pnv_xscom.h
@@ -70,6 +70,9 @@  typedef struct PnvXScomInterfaceClass {
 #define PNV_XSCOM_OCC_BASE        0x0066000
 #define PNV_XSCOM_OCC_SIZE        0x6000
 
+/*
+ * Layout of the XSCOM PCB addresses (POWER 9)
+ */
 #define PNV9_XSCOM_EC_BASE(core) \
     ((uint64_t)(((core) & 0x1F) + 0x20) << 24)
 #define PNV9_XSCOM_EC_SIZE        0x100000
@@ -87,6 +90,22 @@  typedef struct PnvXScomInterfaceClass {
 #define PNV9_XSCOM_XIVE_BASE      0x5013000
 #define PNV9_XSCOM_XIVE_SIZE      0x300
 
+/*
+ * Layout of the XSCOM PCB addresses (POWER 10)
+ */
+#define PNV10_XSCOM_EQ_CHIPLET(core)  (0x20 + ((core) >> 2))
+#define PNV10_XSCOM_EQ(chiplet)       ((chiplet) << 24)
+#define PNV10_XSCOM_EC(proc)                    \
+    ((0x2 << 16) | ((1 << (3 - (proc))) << 12))
+
+#define PNV10_XSCOM_EQ_BASE(core)     \
+    ((uint64_t) PNV10_XSCOM_EQ(PNV10_XSCOM_EQ_CHIPLET(core)))
+#define PNV10_XSCOM_EQ_SIZE        0x100000
+
+#define PNV10_XSCOM_EC_BASE(core) \
+    ((uint64_t) PNV10_XSCOM_EQ_BASE(core) | PNV10_XSCOM_EC(core & 0x3))
+#define PNV10_XSCOM_EC_SIZE        0x100000
+
 extern void pnv_xscom_realize(PnvChip *chip, uint64_t size, Error **errp);
 extern int pnv_dt_xscom(PnvChip *chip, void *fdt, int offset);
 
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index fa656858b24a..d99cd72840be 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -317,6 +317,23 @@  static void pnv_chip_power9_dt_populate(PnvChip *chip, void *fdt)
     pnv_dt_lpc(chip, fdt, 0);
 }
 
+static void pnv_chip_power10_dt_populate(PnvChip *chip, void *fdt)
+{
+    int i;
+
+    pnv_dt_xscom(chip, fdt, 0);
+
+    for (i = 0; i < chip->nr_cores; i++) {
+        PnvCore *pnv_core = chip->cores[i];
+
+        pnv_dt_core(chip, pnv_core, fdt);
+    }
+
+    if (chip->ram_size) {
+        pnv_dt_memory(fdt, chip->chip_id, chip->ram_start, chip->ram_size);
+    }
+}
+
 static void pnv_dt_rtc(ISADevice *d, void *fdt, int lpc_off)
 {
     uint32_t io_base = d->ioport_id;
@@ -467,6 +484,7 @@  static void *pnv_dt_create(MachineState *machine)
 {
     const char plat_compat8[] = "qemu,powernv8\0qemu,powernv\0ibm,powernv";
     const char plat_compat9[] = "qemu,powernv9\0ibm,powernv";
+    const char plat_compat10[] = "qemu,powernv10\0ibm,powernv";
     PnvMachineState *pnv = PNV_MACHINE(machine);
     void *fdt;
     char *buf;
@@ -484,7 +502,10 @@  static void *pnv_dt_create(MachineState *machine)
     _FDT((fdt_setprop_cell(fdt, 0, "#size-cells", 0x2)));
     _FDT((fdt_setprop_string(fdt, 0, "model",
                              "IBM PowerNV (emulated by qemu)")));
-    if (pnv_is_power9(pnv)) {
+    if (pnv_is_power10(pnv)) {
+        _FDT((fdt_setprop(fdt, 0, "compatible", plat_compat10,
+                          sizeof(plat_compat10))));
+    } else if (pnv_is_power9(pnv)) {
         _FDT((fdt_setprop(fdt, 0, "compatible", plat_compat9,
                           sizeof(plat_compat9))));
     } else {
@@ -528,8 +549,8 @@  static void *pnv_dt_create(MachineState *machine)
         pnv_dt_bmc_sensors(pnv->bmc, fdt);
     }
 
-    /* Create an extra node for power management on Power9 */
-    if (pnv_is_power9(pnv)) {
+    /* Create an extra node for power management on Power9 and Power10 */
+    if (pnv_is_power9(pnv) || pnv_is_power10(pnv)) {
         pnv_dt_power_mgt(fdt);
     }
 
@@ -578,6 +599,12 @@  static ISABus *pnv_chip_power9_isa_create(PnvChip *chip, Error **errp)
     return pnv_lpc_isa_create(&chip9->lpc, false, errp);
 }
 
+static ISABus *pnv_chip_power10_isa_create(PnvChip *chip, Error **errp)
+{
+    error_setg(errp, "No ISA bus!");
+    return NULL;
+}
+
 static ISABus *pnv_isa_create(PnvChip *chip, Error **errp)
 {
     return PNV_CHIP_GET_CLASS(chip)->isa_create(chip, errp);
@@ -618,6 +645,13 @@  static void pnv_ipmi_bt_init(ISABus *bus, IPMIBmc *bmc, uint32_t irq)
     object_property_set_bool(obj, true, "realized", &error_fatal);
 }
 
+static void pnv_chip_power10_pic_print_info(PnvChip *chip, Monitor *mon)
+{
+    /*
+     * No interrupt controller yet
+     */;
+}
+
 static void pnv_init(MachineState *machine)
 {
     PnvMachineState *pnv = PNV_MACHINE(machine);
@@ -822,6 +856,11 @@  static uint32_t pnv_chip_core_pir_p9(PnvChip *chip, uint32_t core_id)
     return (chip->chip_id << 8) | (core_id << 2);
 }
 
+static uint32_t pnv_chip_core_pir_p10(PnvChip *chip, uint32_t core_id)
+{
+    return (chip->chip_id << 8) | (core_id << 2);
+}
+
 static void pnv_chip_power9_intc_create(PnvChip *chip, PowerPCCPU *cpu,
                                         Error **errp)
 {
@@ -859,6 +898,27 @@  static void pnv_chip_power9_intc_destroy(PnvChip *chip, PowerPCCPU *cpu)
     pnv_cpu->intc = NULL;
 }
 
+static void pnv_chip_power10_intc_create(PnvChip *chip, PowerPCCPU *cpu,
+                                        Error **errp)
+{
+    PnvCPUState *pnv_cpu = pnv_cpu_state(cpu);
+
+    /* Will be defined when the interrupt controller is */
+    pnv_cpu->intc = NULL;
+}
+
+static void pnv_chip_power10_intc_reset(PnvChip *chip, PowerPCCPU *cpu)
+{
+    ;
+}
+
+static void pnv_chip_power10_intc_destroy(PnvChip *chip, PowerPCCPU *cpu)
+{
+    PnvCPUState *pnv_cpu = pnv_cpu_state(cpu);
+
+    pnv_cpu->intc = NULL;
+}
+
 /*
  * Allowed core identifiers on a POWER8 Processor Chip :
  *
@@ -886,6 +946,9 @@  static void pnv_chip_power9_intc_destroy(PnvChip *chip, PowerPCCPU *cpu)
  */
 #define POWER9_CORE_MASK   (0xffffffffffffffull)
 
+
+#define POWER10_CORE_MASK  (0xffffffffffffffull)
+
 static void pnv_chip_power8_instance_init(Object *obj)
 {
     Pnv8Chip *chip8 = PNV8_CHIP(obj);
@@ -1246,6 +1309,56 @@  static void pnv_chip_power9_class_init(ObjectClass *klass, void *data)
                                     &k->parent_realize);
 }
 
+static void pnv_chip_power10_instance_init(Object *obj)
+{
+    /*
+     * No controllers yet
+     */
+    ;
+}
+
+static void pnv_chip_power10_realize(DeviceState *dev, Error **errp)
+{
+    PnvChipClass *pcc = PNV_CHIP_GET_CLASS(dev);
+    PnvChip *chip = PNV_CHIP(dev);
+    Error *local_err = NULL;
+
+    /* XSCOM bridge is first */
+    pnv_xscom_realize(chip, PNV10_XSCOM_SIZE, &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        return;
+    }
+    sysbus_mmio_map(SYS_BUS_DEVICE(chip), 0, PNV10_XSCOM_BASE(chip));
+
+    pcc->parent_realize(dev, &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        return;
+    }
+}
+
+static void pnv_chip_power10_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PnvChipClass *k = PNV_CHIP_CLASS(klass);
+
+    k->chip_type = PNV_CHIP_POWER10;
+    k->chip_cfam_id = 0x120da04900008000ull; /* P10 DD1.0 (with NX) */
+    k->cores_mask = POWER10_CORE_MASK;
+    k->core_pir = pnv_chip_core_pir_p10;
+    k->intc_create = pnv_chip_power10_intc_create;
+    k->intc_reset = pnv_chip_power10_intc_reset;
+    k->intc_destroy = pnv_chip_power10_intc_destroy;
+    k->isa_create = pnv_chip_power10_isa_create;
+    k->dt_populate = pnv_chip_power10_dt_populate;
+    k->pic_print_info = pnv_chip_power10_pic_print_info;
+    dc->desc = "PowerNV Chip POWER10";
+
+    device_class_set_parent_realize(dc, pnv_chip_power10_realize,
+                                    &k->parent_realize);
+}
+
 static void pnv_chip_core_sanitize(PnvChip *chip, Error **errp)
 {
     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
@@ -1327,10 +1440,12 @@  static void pnv_chip_core_realize(PnvChip *chip, Error **errp)
                                  &error_fatal);
 
         /* Each core has an XSCOM MMIO region */
-        if (!pnv_chip_is_power9(chip)) {
-            xscom_core_base = PNV_XSCOM_EX_BASE(core_hwid);
-        } else {
+        if (pnv_chip_is_power10(chip)) {
+            xscom_core_base = PNV10_XSCOM_EC_BASE(core_hwid);
+        } else if (pnv_chip_is_power9(chip)) {
             xscom_core_base = PNV9_XSCOM_EC_BASE(core_hwid);
+        } else {
+            xscom_core_base = PNV_XSCOM_EX_BASE(core_hwid);
         }
 
         pnv_xscom_add_subregion(chip, xscom_core_base,
@@ -1558,6 +1673,14 @@  static void pnv_machine_power9_class_init(ObjectClass *oc, void *data)
     mc->alias = "powernv";
 }
 
+static void pnv_machine_power10_class_init(ObjectClass *oc, void *data)
+{
+    MachineClass *mc = MACHINE_CLASS(oc);
+
+    mc->desc = "IBM PowerNV (Non-Virtualized) POWER10";
+    mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power10_v1.0");
+}
+
 static void pnv_machine_class_init(ObjectClass *oc, void *data)
 {
     MachineClass *mc = MACHINE_CLASS(oc);
@@ -1595,7 +1718,19 @@  static void pnv_machine_class_init(ObjectClass *oc, void *data)
         .parent        = TYPE_PNV9_CHIP,          \
     }
 
+#define DEFINE_PNV10_CHIP_TYPE(type, class_initfn) \
+    {                                              \
+        .name          = type,                     \
+        .class_init    = class_initfn,             \
+        .parent        = TYPE_PNV10_CHIP,          \
+    }
+
 static const TypeInfo types[] = {
+    {
+        .name          = MACHINE_TYPE_NAME("powernv10"),
+        .parent        = TYPE_PNV_MACHINE,
+        .class_init    = pnv_machine_power10_class_init,
+    },
     {
         .name          = MACHINE_TYPE_NAME("powernv9"),
         .parent        = TYPE_PNV_MACHINE,
@@ -1635,6 +1770,17 @@  static const TypeInfo types[] = {
         .abstract      = true,
     },
 
+    /*
+     * P10 chip and variants
+     */
+    {
+        .name          = TYPE_PNV10_CHIP,
+        .parent        = TYPE_PNV_CHIP,
+        .instance_init = pnv_chip_power10_instance_init,
+        .instance_size = sizeof(Pnv10Chip),
+    },
+    DEFINE_PNV10_CHIP_TYPE(TYPE_PNV_CHIP_POWER10, pnv_chip_power10_class_init),
+
     /*
      * P9 chip and variants
      */
diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c
index 5ab75bde6cc5..2651044278ed 100644
--- a/hw/ppc/pnv_core.c
+++ b/hw/ppc/pnv_core.c
@@ -247,6 +247,7 @@  static void pnv_core_realize(DeviceState *dev, Error **errp)
     }
 
     snprintf(name, sizeof(name), "xscom-core.%d", cc->core_id);
+    /* TODO: check PNV_XSCOM_EX_SIZE for p10 */
     pnv_xscom_region_init(&pc->xscom_regs, OBJECT(dev), pcc->xscom_ops,
                           pc, name, PNV_XSCOM_EX_SIZE);
 
@@ -308,6 +309,14 @@  static void pnv_core_power9_class_init(ObjectClass *oc, void *data)
     pcc->xscom_ops = &pnv_core_power9_xscom_ops;
 }
 
+static void pnv_core_power10_class_init(ObjectClass *oc, void *data)
+{
+    PnvCoreClass *pcc = PNV_CORE_CLASS(oc);
+
+    /* TODO: Use the P9 XSCOMs for now on P10 */
+    pcc->xscom_ops = &pnv_core_power9_xscom_ops;
+}
+
 static void pnv_core_class_init(ObjectClass *oc, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(oc);
@@ -337,6 +346,7 @@  static const TypeInfo pnv_core_infos[] = {
     DEFINE_PNV_CORE_TYPE(power8, "power8_v2.0"),
     DEFINE_PNV_CORE_TYPE(power8, "power8nvl_v1.0"),
     DEFINE_PNV_CORE_TYPE(power9, "power9_v2.0"),
+    DEFINE_PNV_CORE_TYPE(power10, "power10_v1.0"),
 };
 
 DEFINE_TYPES(pnv_core_infos)
diff --git a/hw/ppc/pnv_xscom.c b/hw/ppc/pnv_xscom.c
index f01d788a6545..b3d3b6e3507d 100644
--- a/hw/ppc/pnv_xscom.c
+++ b/hw/ppc/pnv_xscom.c
@@ -69,10 +69,16 @@  static uint32_t pnv_xscom_pcba(PnvChip *chip, uint64_t addr)
 {
     addr &= (PNV_XSCOM_SIZE - 1);
 
-    if (pnv_chip_is_power9(chip)) {
-        return addr >> 3;
-    } else {
+    switch (PNV_CHIP_GET_CLASS(chip)->chip_type) {
+    case PNV_CHIP_POWER8E:
+    case PNV_CHIP_POWER8:
+    case PNV_CHIP_POWER8NVL:
         return ((addr >> 4) & ~0xfull) | ((addr >> 3) & 0xf);
+    case PNV_CHIP_POWER9:
+    case PNV_CHIP_POWER10:
+        return addr >> 3;
+    default:
+        g_assert_not_reached();
     }
 }
 
@@ -307,6 +313,7 @@  static int xscom_dt_child(Object *child, void *opaque)
 
 static const char compat_p8[] = "ibm,power8-xscom\0ibm,xscom";
 static const char compat_p9[] = "ibm,power9-xscom\0ibm,xscom";
+static const char compat_p10[] = "ibm,power10-xscom\0ibm,xscom";
 
 int pnv_dt_xscom(PnvChip *chip, void *fdt, int root_offset)
 {
@@ -315,7 +322,10 @@  int pnv_dt_xscom(PnvChip *chip, void *fdt, int root_offset)
     ForeachPopulateArgs args;
     char *name;
 
-    if (pnv_chip_is_power9(chip)) {
+    if (pnv_chip_is_power10(chip)) {
+        reg[0] = cpu_to_be64(PNV10_XSCOM_BASE(chip));
+        reg[1] = cpu_to_be64(PNV10_XSCOM_SIZE);
+    } else if (pnv_chip_is_power9(chip)) {
         reg[0] = cpu_to_be64(PNV9_XSCOM_BASE(chip));
         reg[1] = cpu_to_be64(PNV9_XSCOM_SIZE);
     } else {
@@ -332,7 +342,10 @@  int pnv_dt_xscom(PnvChip *chip, void *fdt, int root_offset)
     _FDT((fdt_setprop_cell(fdt, xscom_offset, "#size-cells", 1)));
     _FDT((fdt_setprop(fdt, xscom_offset, "reg", reg, sizeof(reg))));
 
-    if (pnv_chip_is_power9(chip)) {
+    if (pnv_chip_is_power10(chip)) {
+        _FDT((fdt_setprop(fdt, xscom_offset, "compatible", compat_p10,
+                          sizeof(compat_p10))));
+    } else if (pnv_chip_is_power9(chip)) {
         _FDT((fdt_setprop(fdt, xscom_offset, "compatible", compat_p9,
                           sizeof(compat_p9))));
     } else {