Reviewed-by: Glenn Miles <[email protected]> Thanks,
Glenn On Tue, 2025-12-23 at 08:59 -0600, Caleb Schlossin wrote: > The nest MMU is used for translations needed by I/O subsystems > on Power10. The nest is the shared, on-chip infrastructure > that connects CPU cores, memory controllers, and I/O. > > This patch sets up a basic skeleton with its xscom > area, mapping both needed xscom regions. Support required > for PowerVM bringup. > > Signed-off-by: Frederic Barrat <[email protected]> > Signed-off-by: Chalapathi V <[email protected]> > Signed-off-by: Caleb Schlossin <[email protected]> > --- > hw/ppc/meson.build | 1 + > hw/ppc/pnv.c | 20 ++++++ > hw/ppc/pnv_nmmu.c | 132 +++++++++++++++++++++++++++++++++++++ > include/hw/ppc/pnv_chip.h | 3 + > include/hw/ppc/pnv_nmmu.h | 28 ++++++++ > include/hw/ppc/pnv_xscom.h | 4 ++ > 6 files changed, 188 insertions(+) > create mode 100644 hw/ppc/pnv_nmmu.c > create mode 100644 include/hw/ppc/pnv_nmmu.h > > diff --git a/hw/ppc/meson.build b/hw/ppc/meson.build > index f7dac87a2a..69e2fc34c4 100644 > --- a/hw/ppc/meson.build > +++ b/hw/ppc/meson.build > @@ -56,6 +56,7 @@ ppc_ss.add(when: 'CONFIG_POWERNV', if_true: files( > 'pnv_pnor.c', > 'pnv_nest_pervasive.c', > 'pnv_n1_chiplet.c', > + 'pnv_nmmu.c' > )) > # PowerPC 4xx boards > ppc_ss.add(when: 'CONFIG_PPC405', if_true: files( > diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c > index 895132da91..8d24570607 100644 > --- a/hw/ppc/pnv.c > +++ b/hw/ppc/pnv.c > @@ -2195,6 +2195,11 @@ static void pnv_chip_power10_instance_init(Object *obj) > TYPE_PNV_PHB5_PEC); > } > > + for (i = 0; i < PNV10_CHIP_MAX_NMMU; i++) { > + object_initialize_child(obj, "nmmu[*]", &chip10->nmmu[i], > + TYPE_PNV_NMMU); > + } > + > for (i = 0; i < pcc->i2c_num_engines; i++) { > object_initialize_child(obj, "i2c[*]", &chip10->i2c[i], > TYPE_PNV_I2C); > } > @@ -2409,6 +2414,21 @@ static void pnv_chip_power10_realize(DeviceState *dev, > Error **errp) > pnv_xscom_add_subregion(chip, PNV10_XSCOM_N1_PB_SCOM_ES_BASE, > &chip10->n1_chiplet.xscom_pb_es_mr); > > + /* nest0/1 MMU */ > + for (i = 0; i < PNV10_CHIP_MAX_NMMU; i++) { > + object_property_set_int(OBJECT(&chip10->nmmu[i]), "nmmu_id", > + i , &error_fatal); > + object_property_set_link(OBJECT(&chip10->nmmu[i]), "chip", > + OBJECT(chip), &error_abort); > + if (!qdev_realize(DEVICE(&chip10->nmmu[i]), NULL, errp)) { > + return; > + } > + } > + pnv_xscom_add_subregion(chip, PNV10_XSCOM_NEST0_MMU_BASE, > + &chip10->nmmu[0].xscom_regs); > + pnv_xscom_add_subregion(chip, PNV10_XSCOM_NEST1_MMU_BASE, > + &chip10->nmmu[1].xscom_regs); > + > /* PHBs */ > pnv_chip_power10_phb_realize(chip, &local_err); > if (local_err) { > diff --git a/hw/ppc/pnv_nmmu.c b/hw/ppc/pnv_nmmu.c > new file mode 100644 > index 0000000000..37c739b242 > --- /dev/null > +++ b/hw/ppc/pnv_nmmu.c > @@ -0,0 +1,132 @@ > +/* > + * QEMU PowerPC nest MMU model > + * > + * Copyright (c) 2025, IBM Corporation. > + * > + * SPDX-License-Identifier: GPL-2.0-or-later > + * > + * This code is licensed under the GPL version 2 or later. See the > + * COPYING file in the top-level directory. > + */ > + > +#include "qemu/osdep.h" > +#include "qemu/log.h" > +#include "hw/qdev-properties.h" > + > +#include "hw/ppc/pnv.h" > +#include "hw/ppc/pnv_xscom.h" > +#include "hw/ppc/pnv_nmmu.h" > +#include "hw/ppc/fdt.h" > + > +#include <libfdt.h> > + > +#define NMMU_XLAT_CTL_PTCR 0xb > + > +static uint64_t pnv_nmmu_xscom_read(void *opaque, hwaddr addr, unsigned size) > +{ > + PnvNMMU *nmmu = PNV_NMMU(opaque); > + int reg = addr >> 3; > + uint64_t val; > + > + if (reg == NMMU_XLAT_CTL_PTCR) { > + val = nmmu->ptcr; > + } else { > + val = 0xffffffffffffffffull; > + qemu_log_mask(LOG_UNIMP, "nMMU: xscom read at 0x%" PRIx32 "\n", reg); > + } > + return val; > +} > + > +static void pnv_nmmu_xscom_write(void *opaque, hwaddr addr, > + uint64_t val, unsigned size) > +{ > + PnvNMMU *nmmu = PNV_NMMU(opaque); > + int reg = addr >> 3; > + > + if (reg == NMMU_XLAT_CTL_PTCR) { > + nmmu->ptcr = val; > + } else { > + qemu_log_mask(LOG_UNIMP, "nMMU: xscom write at 0x%" PRIx32 "\n", > reg); > + } > +} > + > +static const MemoryRegionOps pnv_nmmu_xscom_ops = { > + .read = pnv_nmmu_xscom_read, > + .write = pnv_nmmu_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_nmmu_realize(DeviceState *dev, Error **errp) > +{ > + PnvNMMU *nmmu = PNV_NMMU(dev); > + > + assert(nmmu->chip); > + > + /* NMMU xscom region */ > + pnv_xscom_region_init(&nmmu->xscom_regs, OBJECT(nmmu), > + &pnv_nmmu_xscom_ops, nmmu, > + "xscom-nmmu", > + PNV10_XSCOM_NMMU_SIZE); > +} > + > +static int pnv_nmmu_dt_xscom(PnvXScomInterface *dev, void *fdt, > + int offset) > +{ > + PnvNMMU *nmmu = PNV_NMMU(dev); > + char *name; > + int nmmu_offset; > + const char compat[] = "ibm,power10-nest-mmu"; > + uint32_t nmmu_pcba = PNV10_XSCOM_NEST0_MMU_BASE + nmmu->nmmu_id * > 0x1000000; > + uint32_t reg[2] = { > + cpu_to_be32(nmmu_pcba), > + cpu_to_be32(PNV10_XSCOM_NMMU_SIZE) > + }; > + > + name = g_strdup_printf("nmmu@%x", nmmu_pcba); > + nmmu_offset = fdt_add_subnode(fdt, offset, name); > + _FDT(nmmu_offset); > + g_free(name); > + > + _FDT(fdt_setprop(fdt, nmmu_offset, "reg", reg, sizeof(reg))); > + _FDT(fdt_setprop(fdt, nmmu_offset, "compatible", compat, > sizeof(compat))); > + return 0; > +} > + > +static const Property pnv_nmmu_properties[] = { > + DEFINE_PROP_UINT32("nmmu_id", PnvNMMU, nmmu_id, 0), > + DEFINE_PROP_LINK("chip", PnvNMMU, chip, TYPE_PNV_CHIP, PnvChip *), > +}; > + > +static void pnv_nmmu_class_init(ObjectClass *klass, const void *data) > +{ > + DeviceClass *dc = DEVICE_CLASS(klass); > + PnvXScomInterfaceClass *xscomc = PNV_XSCOM_INTERFACE_CLASS(klass); > + > + xscomc->dt_xscom = pnv_nmmu_dt_xscom; > + > + dc->desc = "PowerNV nest MMU"; > + dc->realize = pnv_nmmu_realize; > + device_class_set_props(dc, pnv_nmmu_properties); > +} > + > +static const TypeInfo pnv_nmmu_info = { > + .name = TYPE_PNV_NMMU, > + .parent = TYPE_DEVICE, > + .instance_size = sizeof(PnvNMMU), > + .class_init = pnv_nmmu_class_init, > + .interfaces = (InterfaceInfo[]) { > + { TYPE_PNV_XSCOM_INTERFACE }, > + { } > + } > +}; > + > +static void pnv_nmmu_register_types(void) > +{ > + type_register_static(&pnv_nmmu_info); > +} > + > +type_init(pnv_nmmu_register_types); > diff --git a/include/hw/ppc/pnv_chip.h b/include/hw/ppc/pnv_chip.h > index a5b8c49680..b6382407c9 100644 > --- a/include/hw/ppc/pnv_chip.h > +++ b/include/hw/ppc/pnv_chip.h > @@ -7,6 +7,7 @@ > #include "hw/ppc/pnv_core.h" > #include "hw/ppc/pnv_homer.h" > #include "hw/ppc/pnv_n1_chiplet.h" > +#include "hw/ppc/pnv_nmmu.h" > #include "hw/ssi/pnv_spi.h" > #include "hw/ppc/pnv_lpc.h" > #include "hw/ppc/pnv_occ.h" > @@ -126,6 +127,8 @@ struct Pnv10Chip { > PnvN1Chiplet n1_chiplet; > #define PNV10_CHIP_MAX_PIB_SPIC 6 > PnvSpi pib_spic[PNV10_CHIP_MAX_PIB_SPIC]; > +#define PNV10_CHIP_MAX_NMMU 2 > + PnvNMMU nmmu[PNV10_CHIP_MAX_NMMU]; > > uint32_t nr_quads; > PnvQuad *quads; > diff --git a/include/hw/ppc/pnv_nmmu.h b/include/hw/ppc/pnv_nmmu.h > new file mode 100644 > index 0000000000..d3ba46ecf4 > --- /dev/null > +++ b/include/hw/ppc/pnv_nmmu.h > @@ -0,0 +1,28 @@ > +/* > + * QEMU PowerPC nest MMU model > + * > + * Copyright (c) 2025, IBM Corporation. > + * > + * SPDX-License-Identifier: GPL-2.0-or-later > + * > + * This code is licensed under the GPL version 2 or later. See the > + * COPYING file in the top-level directory. > + */ > + > +#ifndef PPC_PNV_NMMU_H > +#define PPC_PNV_NMMU_H > + > +#define TYPE_PNV_NMMU "pnv-nmmu" > +#define PNV_NMMU(obj) OBJECT_CHECK(PnvNMMU, (obj), TYPE_PNV_NMMU) > + > +typedef struct PnvNMMU { > + DeviceState parent; > + > + struct PnvChip *chip; > + > + MemoryRegion xscom_regs; > + uint32_t nmmu_id; > + uint64_t ptcr; > +} PnvNMMU; > + > +#endif /*PPC_PNV_NMMU_H */ > diff --git a/include/hw/ppc/pnv_xscom.h b/include/hw/ppc/pnv_xscom.h > index 610b075a27..6dab803d1f 100644 > --- a/include/hw/ppc/pnv_xscom.h > +++ b/include/hw/ppc/pnv_xscom.h > @@ -196,6 +196,10 @@ struct PnvXScomInterfaceClass { > #define PNV10_XSCOM_N1_PB_SCOM_ES_BASE 0x3011300 > #define PNV10_XSCOM_N1_PB_SCOM_ES_SIZE 0x100 > > +#define PNV10_XSCOM_NEST0_MMU_BASE 0x2010c40 > +#define PNV10_XSCOM_NEST1_MMU_BASE 0x3010c40 > +#define PNV10_XSCOM_NMMU_SIZE 0x20 > + > #define PNV10_XSCOM_PEC_NEST_BASE 0x3011800 /* index goes downwards ... */ > #define PNV10_XSCOM_PEC_NEST_SIZE 0x100 >
