@samitouri / QOSamiQemu / commits / b7d2329469

ppc/pnv: Add a nest MMU model

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. Use Power9 property for device tree to allow OPAL to work with Power9 and Power10. Reviewed-by: Chalapathi V <chalapathi.v@linux.ibm.com> Reviewed-by: Glenn Miles <milesg@linux.ibm.com> Signed-off-by: Frederic Barrat <fbarrat@linux.ibm.com> Signed-off-by: Chalapathi V <chalapathi.v@linux.ibm.com> Signed-off-by: Caleb Schlossin <calebs@linux.ibm.com> Reviewed-by: Aditya Gupta <adityag@linux.ibm.com> Link: https://lore.kernel.org/qemu-devel/20260120150139.714805-1-calebs@linux.ibm.com Signed-off-by: Harsh Prateek Bora <harshpb@linux.ibm.com>

Caleb Schlossin committed Jan 20, 2026 at 09:01 UTC b7d23294696e2da7006a63c1c7842ee8d469a82f
6 files changed +188
hw/ppc/meson.build
+1
@@ -57,6 +57,7 @@ ppc_ss.add(when: 'CONFIG_POWERNV', if_true: files(
57 'pnv_nest_pervasive.c',
58 'pnv_n1_chiplet.c',
59 'pnv_mpipl.c',
60 + 'pnv_nmmu.c'
61 ))
62 # PowerPC 4xx boards
63 ppc_ss.add(when: 'CONFIG_PPC405', if_true: files(
hw/ppc/pnv.c
+20
@@ -2297,6 +2297,11 @@ static void pnv_chip_power10_instance_init(Object *obj)
2297 TYPE_PNV_PHB5_PEC);
2298 }
2299
2300 + for (i = 0; i < PNV10_CHIP_MAX_NMMU; i++) {
2301 + object_initialize_child(obj, "nmmu[*]", &chip10->nmmu[i],
2302 + TYPE_PNV_NMMU);
2303 + }
2304 +
2305 for (i = 0; i < pcc->i2c_num_engines; i++) {
2306 object_initialize_child(obj, "i2c[*]", &chip10->i2c[i], TYPE_PNV_I2C);
2307 }
@@ -2511,6 +2516,21 @@ static void pnv_chip_power10_realize(DeviceState *dev, Error **errp)
2516 pnv_xscom_add_subregion(chip, PNV10_XSCOM_N1_PB_SCOM_ES_BASE,
2517 &chip10->n1_chiplet.xscom_pb_es_mr);
2518
2519 + /* nest0/1 MMU */
2520 + for (i = 0; i < PNV10_CHIP_MAX_NMMU; i++) {
2521 + object_property_set_int(OBJECT(&chip10->nmmu[i]), "nmmu_id",
2522 + i , &error_fatal);
2523 + object_property_set_link(OBJECT(&chip10->nmmu[i]), "chip",
2524 + OBJECT(chip), &error_abort);
2525 + if (!qdev_realize(DEVICE(&chip10->nmmu[i]), NULL, errp)) {
2526 + return;
2527 + }
2528 + }
2529 + pnv_xscom_add_subregion(chip, PNV10_XSCOM_NEST0_MMU_BASE,
2530 + &chip10->nmmu[0].xscom_regs);
2531 + pnv_xscom_add_subregion(chip, PNV10_XSCOM_NEST1_MMU_BASE,
2532 + &chip10->nmmu[1].xscom_regs);
2533 +
2534 /* PHBs */
2535 pnv_chip_power10_phb_realize(chip, &local_err);
2536 if (local_err) {
hw/ppc/pnv_nmmu.c new
+132
@@ -0,0 +1,132 @@
1 +/*
2 + * QEMU PowerPC nest MMU model
3 + *
4 + * Copyright (c) 2025, IBM Corporation.
5 + *
6 + * SPDX-License-Identifier: GPL-2.0-or-later
7 + *
8 + * This code is licensed under the GPL version 2 or later. See the
9 + * COPYING file in the top-level directory.
10 + */
11 +
12 +#include "qemu/osdep.h"
13 +#include "qemu/log.h"
14 +#include "hw/core/qdev-properties.h"
15 +
16 +#include "hw/ppc/pnv.h"
17 +#include "hw/ppc/pnv_xscom.h"
18 +#include "hw/ppc/pnv_nmmu.h"
19 +#include "hw/ppc/fdt.h"
20 +
21 +#include <libfdt.h>
22 +
23 +#define NMMU_XLAT_CTL_PTCR 0xb
24 +
25 +static uint64_t pnv_nmmu_xscom_read(void *opaque, hwaddr addr, unsigned size)
26 +{
27 + PnvNMMU *nmmu = PNV_NMMU(opaque);
28 + int reg = addr >> 3;
29 + uint64_t val;
30 +
31 + if (reg == NMMU_XLAT_CTL_PTCR) {
32 + val = nmmu->ptcr;
33 + } else {
34 + val = 0xffffffffffffffffull;
35 + qemu_log_mask(LOG_UNIMP, "nMMU: xscom read at 0x%" PRIx32 "\n", reg);
36 + }
37 + return val;
38 +}
39 +
40 +static void pnv_nmmu_xscom_write(void *opaque, hwaddr addr,
41 + uint64_t val, unsigned size)
42 +{
43 + PnvNMMU *nmmu = PNV_NMMU(opaque);
44 + int reg = addr >> 3;
45 +
46 + if (reg == NMMU_XLAT_CTL_PTCR) {
47 + nmmu->ptcr = val;
48 + } else {
49 + qemu_log_mask(LOG_UNIMP, "nMMU: xscom write at 0x%" PRIx32 "\n", reg);
50 + }
51 +}
52 +
53 +static const MemoryRegionOps pnv_nmmu_xscom_ops = {
54 + .read = pnv_nmmu_xscom_read,
55 + .write = pnv_nmmu_xscom_write,
56 + .valid.min_access_size = 8,
57 + .valid.max_access_size = 8,
58 + .impl.min_access_size = 8,
59 + .impl.max_access_size = 8,
60 + .endianness = DEVICE_BIG_ENDIAN,
61 +};
62 +
63 +static void pnv_nmmu_realize(DeviceState *dev, Error **errp)
64 +{
65 + PnvNMMU *nmmu = PNV_NMMU(dev);
66 +
67 + assert(nmmu->chip);
68 +
69 + /* NMMU xscom region */
70 + pnv_xscom_region_init(&nmmu->xscom_regs, OBJECT(nmmu),
71 + &pnv_nmmu_xscom_ops, nmmu,
72 + "xscom-nmmu",
73 + PNV10_XSCOM_NMMU_SIZE);
74 +}
75 +
76 +static int pnv_nmmu_dt_xscom(PnvXScomInterface *dev, void *fdt,
77 + int offset)
78 +{
79 + PnvNMMU *nmmu = PNV_NMMU(dev);
80 + char *name;
81 + int nmmu_offset;
82 + const char compat[] = "ibm,power9-nest-mmu";
83 + uint32_t nmmu_pcba = PNV10_XSCOM_NEST0_MMU_BASE + nmmu->nmmu_id * 0x1000000;
84 + uint32_t reg[2] = {
85 + cpu_to_be32(nmmu_pcba),
86 + cpu_to_be32(PNV10_XSCOM_NMMU_SIZE)
87 + };
88 +
89 + name = g_strdup_printf("nmmu@%x", nmmu_pcba);
90 + nmmu_offset = fdt_add_subnode(fdt, offset, name);
91 + _FDT(nmmu_offset);
92 + g_free(name);
93 +
94 + _FDT(fdt_setprop(fdt, nmmu_offset, "reg", reg, sizeof(reg)));
95 + _FDT(fdt_setprop(fdt, nmmu_offset, "compatible", compat, sizeof(compat)));
96 + return 0;
97 +}
98 +
99 +static const Property pnv_nmmu_properties[] = {
100 + DEFINE_PROP_UINT32("nmmu_id", PnvNMMU, nmmu_id, 0),
101 + DEFINE_PROP_LINK("chip", PnvNMMU, chip, TYPE_PNV_CHIP, PnvChip *),
102 +};
103 +
104 +static void pnv_nmmu_class_init(ObjectClass *klass, const void *data)
105 +{
106 + DeviceClass *dc = DEVICE_CLASS(klass);
107 + PnvXScomInterfaceClass *xscomc = PNV_XSCOM_INTERFACE_CLASS(klass);
108 +
109 + xscomc->dt_xscom = pnv_nmmu_dt_xscom;
110 +
111 + dc->desc = "PowerNV nest MMU";
112 + dc->realize = pnv_nmmu_realize;
113 + device_class_set_props(dc, pnv_nmmu_properties);
114 +}
115 +
116 +static const TypeInfo pnv_nmmu_info = {
117 + .name = TYPE_PNV_NMMU,
118 + .parent = TYPE_DEVICE,
119 + .instance_size = sizeof(PnvNMMU),
120 + .class_init = pnv_nmmu_class_init,
121 + .interfaces = (InterfaceInfo[]) {
122 + { TYPE_PNV_XSCOM_INTERFACE },
123 + { }
124 + }
125 +};
126 +
127 +static void pnv_nmmu_register_types(void)
128 +{
129 + type_register_static(&pnv_nmmu_info);
130 +}
131 +
132 +type_init(pnv_nmmu_register_types);
include/hw/ppc/pnv_chip.h
+3
@@ -7,6 +7,7 @@
7 #include "hw/ppc/pnv_core.h"
8 #include "hw/ppc/pnv_homer.h"
9 #include "hw/ppc/pnv_n1_chiplet.h"
10 +#include "hw/ppc/pnv_nmmu.h"
11 #include "hw/ssi/pnv_spi.h"
12 #include "hw/ppc/pnv_lpc.h"
13 #include "hw/ppc/pnv_occ.h"
@@ -126,6 +127,8 @@ struct Pnv10Chip {
127 PnvN1Chiplet n1_chiplet;
128 #define PNV10_CHIP_MAX_PIB_SPIC 6
129 PnvSpi pib_spic[PNV10_CHIP_MAX_PIB_SPIC];
130 +#define PNV10_CHIP_MAX_NMMU 2
131 + PnvNMMU nmmu[PNV10_CHIP_MAX_NMMU];
132
133 uint32_t nr_quads;
134 PnvQuad *quads;
include/hw/ppc/pnv_nmmu.h new
+28
@@ -0,0 +1,28 @@
1 +/*
2 + * QEMU PowerPC nest MMU model
3 + *
4 + * Copyright (c) 2025, IBM Corporation.
5 + *
6 + * SPDX-License-Identifier: GPL-2.0-or-later
7 + *
8 + * This code is licensed under the GPL version 2 or later. See the
9 + * COPYING file in the top-level directory.
10 + */
11 +
12 +#ifndef PPC_PNV_NMMU_H
13 +#define PPC_PNV_NMMU_H
14 +
15 +#define TYPE_PNV_NMMU "pnv-nmmu"
16 +#define PNV_NMMU(obj) OBJECT_CHECK(PnvNMMU, (obj), TYPE_PNV_NMMU)
17 +
18 +typedef struct PnvNMMU {
19 + DeviceState parent;
20 +
21 + struct PnvChip *chip;
22 +
23 + MemoryRegion xscom_regs;
24 + uint32_t nmmu_id;
25 + uint64_t ptcr;
26 +} PnvNMMU;
27 +
28 +#endif /*PPC_PNV_NMMU_H */
include/hw/ppc/pnv_xscom.h
+4
@@ -196,6 +196,10 @@ struct PnvXScomInterfaceClass {
196 #define PNV10_XSCOM_N1_PB_SCOM_ES_BASE 0x3011300
197 #define PNV10_XSCOM_N1_PB_SCOM_ES_SIZE 0x100
198
199 +#define PNV10_XSCOM_NEST0_MMU_BASE 0x2010c40
200 +#define PNV10_XSCOM_NEST1_MMU_BASE 0x3010c40
201 +#define PNV10_XSCOM_NMMU_SIZE 0x20
202 +
203 #define PNV10_XSCOM_PEC_NEST_BASE 0x3011800 /* index goes downwards ... */
204 #define PNV10_XSCOM_PEC_NEST_SIZE 0x100
205