* [PATCH v2 0/9] pnv/phb4: Update PHB4 to the latest PHB5 spec
@ 2025-12-30 10:21 Saif Abrar
2025-12-30 10:21 ` [PATCH v2 1/9] qtest/phb4: Add testbench for PHB4 Saif Abrar
` (9 more replies)
0 siblings, 10 replies; 60+ messages in thread
From: Saif Abrar @ 2025-12-30 10:21 UTC (permalink / raw)
To: qemu-ppc, qemu-devel
Cc: clg, npiggin, fbarrat, mst, marcel.apfelbaum, cohuck, pbonzini,
thuth, lvivier, danielhb413, saif.abrar
Hello,
Addressing the review comments for the series v1:
https://lists.gnu.org/archive/html/qemu-devel/2024-03/msg05277.html
This series updates the existing PHB4 model to the latest spec:
"Power Systems Host Bridge 5 (PHB5) Functional Specification Version 0.5_00".
Updates include the following:
- implemented sticky reset logic
- implemented read-only, write-only, W1C and WxC logic
- return all 1's on read to unimplemented registers
- update PCIE registers for link status, speed and width
- implement IODA PCT debug table without any functionality
- update LSI Source-ID register based on small/big PHB number of interrupts
Also, a new testbench for PHB4 model is added that does XSCOM read/writes
to various registers of interest and verifies the values.
Regards.
Saif Abrar (9):
qtest/phb4: Add testbench for PHB4
pnv/phb4: Add reset logic to PHB4
pnv/phb4: Implement sticky reset logic in PHB4
pnv/phb4: Implement read-only and write-only bits of registers
pnv/phb4: Implement write-clear and return 1's on unimplemented reg read
pnv/phb4: Set link-active status in HPSTAT and LMR registers
pnv/phb4: Set link speed and width in the DLP training control register
pnv/phb4: Implement IODA PCT table
pnv/phb4: Mask off LSI Source-ID based on number of interrupts
hw/pci-host/pnv_phb.c | 1 +
hw/pci-host/pnv_phb4.c | 579 +++++++++++++++++++++++++---
include/hw/pci-host/pnv_phb4.h | 16 +-
include/hw/pci-host/pnv_phb4_regs.h | 66 +++-
tests/qtest/meson.build | 1 +
tests/qtest/pnv-phb4-test.c | 229 +++++++++++
6 files changed, 834 insertions(+), 58 deletions(-)
create mode 100644 tests/qtest/pnv-phb4-test.c
--
2.47.3
^ permalink raw reply [flat|nested] 60+ messages in thread
* [PATCH v2 1/9] qtest/phb4: Add testbench for PHB4
2025-12-30 10:21 [PATCH v2 0/9] pnv/phb4: Update PHB4 to the latest PHB5 spec Saif Abrar
@ 2025-12-30 10:21 ` Saif Abrar
2025-12-30 10:21 ` [PATCH v2 2/9] pnv/phb4: Add reset logic to PHB4 Saif Abrar
` (8 subsequent siblings)
9 siblings, 0 replies; 60+ messages in thread
From: Saif Abrar @ 2025-12-30 10:21 UTC (permalink / raw)
To: qemu-ppc, qemu-devel
Cc: clg, npiggin, fbarrat, mst, marcel.apfelbaum, cohuck, pbonzini,
thuth, lvivier, danielhb413, saif.abrar
New qtest testbench added for PHB[345].
Testbench reads PHB Version register and asserts that
bits[24:31] have value 0xA3, 0xA4 and 0xA5 respectively.
Signed-off-by: Saif Abrar <saif.abrar@linux.vnet.ibm.com>
Reviewed-by: Cédric Le Goater <clg@kaod.org>
---
v1 -> v2: Added version check for PHB3 and PHB4 also.
tests/qtest/meson.build | 1 +
tests/qtest/pnv-phb4-test.c | 99 +++++++++++++++++++++++++++++++++++++
2 files changed, 100 insertions(+)
create mode 100644 tests/qtest/pnv-phb4-test.c
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index 08fba9695b..690d34913e 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -183,6 +183,7 @@ qtests_ppc64 = \
(config_all_devices.has_key('CONFIG_POWERNV') ? ['pnv-xive2-test'] : []) + \
(config_all_devices.has_key('CONFIG_POWERNV') ? ['pnv-spi-seeprom-test'] : []) + \
(config_all_devices.has_key('CONFIG_POWERNV') ? ['pnv-host-i2c-test'] : []) + \
+ (config_all_devices.has_key('CONFIG_POWERNV') ? ['pnv-phb4-test'] : []) + \
(config_all_devices.has_key('CONFIG_PSERIES') ? ['numa-test'] : []) + \
(config_all_devices.has_key('CONFIG_PSERIES') ? ['rtas-test'] : []) + \
(slirp.found() ? ['pxe-test'] : []) + \
diff --git a/tests/qtest/pnv-phb4-test.c b/tests/qtest/pnv-phb4-test.c
new file mode 100644
index 0000000000..3890b4f970
--- /dev/null
+++ b/tests/qtest/pnv-phb4-test.c
@@ -0,0 +1,99 @@
+/*
+ * QTest testcase for PowerNV PHB4
+ *
+ * Copyright (c) 2025, IBM Corporation.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "hw/pci-host/pnv_phb4_regs.h"
+#include "pnv-xscom.h"
+
+#define PPC_BIT(bit) (0x8000000000000000ULL >> (bit))
+#define PPC_BITMASK(bs, be) ((PPC_BIT(bs) - PPC_BIT(be)) | PPC_BIT(bs))
+
+#define PHB3_PBCQ_SPCI_ASB_ADDR 0x0
+#define PHB3_PBCQ_SPCI_ASB_DATA 0x2
+
+/* Index of PNV_CHIP_POWER10 in pnv_chips[] within "pnv-xscom.h" */
+#define PNV_P10_CHIP_INDEX 3
+#define PHB4_XSCOM 0x40084800ull
+
+/*
+ * Indirect XSCOM read::
+ * - Write 'Indirect Address Register' with register-offset to read.
+ * - Read 'Indirect Data Register' to get the value.
+ */
+static uint64_t pnv_phb_xscom_read(QTestState *qts, const PnvChip *chip,
+ uint64_t scom, uint32_t indirect_addr, uint32_t indirect_data,
+ uint64_t reg)
+{
+ qtest_writeq(qts, pnv_xscom_addr(chip, (scom >> 3) + indirect_addr), reg);
+ return qtest_readq(qts, pnv_xscom_addr(chip, (scom >> 3) + indirect_data));
+}
+
+/* Assert that 'PHB - Version Register' bits-[24:31] are as expected */
+static void phb_version_test(const void *data)
+{
+ const PnvChip *chip = (PnvChip *)data;
+ QTestState *qts;
+ const char *machine = "powernv8";
+ uint64_t phb_xscom = 0x4809e000;
+ uint64_t reg_phb_version = PHB_VERSION;
+ uint32_t indirect_addr = PHB3_PBCQ_SPCI_ASB_ADDR;
+ uint32_t indirect_data = PHB3_PBCQ_SPCI_ASB_DATA;
+ uint32_t expected_ver = 0xA3;
+
+ if (chip->chip_type == PNV_CHIP_POWER9) {
+ machine = "powernv9";
+ phb_xscom = 0x68084800;
+ indirect_addr = PHB_SCOM_HV_IND_ADDR;
+ indirect_data = PHB_SCOM_HV_IND_DATA;
+ reg_phb_version |= PPC_BIT(0);
+ expected_ver = 0xA4;
+ } else if (chip->chip_type == PNV_CHIP_POWER10) {
+ machine = "powernv10";
+ phb_xscom = PHB4_XSCOM;
+ indirect_addr = PHB_SCOM_HV_IND_ADDR;
+ indirect_data = PHB_SCOM_HV_IND_DATA;
+ reg_phb_version |= PPC_BIT(0);
+ expected_ver = 0xA5;
+ }
+
+ qts = qtest_initf("-M %s -accel tcg -cpu %s", machine, chip->cpu_model);
+
+ uint64_t ver = pnv_phb_xscom_read(qts, chip, phb_xscom,
+ indirect_addr, indirect_data, reg_phb_version);
+
+ /* PHB Version register bits [24:31] */
+ ver = ver >> (63 - 31);
+ g_assert_cmpuint(ver, ==, expected_ver);
+
+ qtest_quit(qts);
+}
+
+/* Verify versions of all supported PHB's */
+static void add_phbX_version_test(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(pnv_chips); i++) {
+ char *tname = g_strdup_printf("pnv-phb/%s",
+ pnv_chips[i].cpu_model);
+ qtest_add_data_func(tname, &pnv_chips[i], phb_version_test);
+ g_free(tname);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ g_test_init(&argc, &argv, NULL);
+
+ /* PHB[345] tests */
+ add_phbX_version_test();
+
+ return g_test_run();
+}
--
2.47.3
^ permalink raw reply related [flat|nested] 60+ messages in thread
* [PATCH v2 2/9] pnv/phb4: Add reset logic to PHB4
2025-12-30 10:21 [PATCH v2 0/9] pnv/phb4: Update PHB4 to the latest PHB5 spec Saif Abrar
2025-12-30 10:21 ` [PATCH v2 1/9] qtest/phb4: Add testbench for PHB4 Saif Abrar
@ 2025-12-30 10:21 ` Saif Abrar
2025-12-30 12:04 ` Michael S. Tsirkin
2025-12-30 10:21 ` [PATCH v2 3/9] pnv/phb4: Implement sticky reset logic in PHB4 Saif Abrar
` (7 subsequent siblings)
9 siblings, 1 reply; 60+ messages in thread
From: Saif Abrar @ 2025-12-30 10:21 UTC (permalink / raw)
To: qemu-ppc, qemu-devel
Cc: clg, npiggin, fbarrat, mst, marcel.apfelbaum, cohuck, pbonzini,
thuth, lvivier, danielhb413, saif.abrar
Add a method to be invoked on QEMU reset.
Also add CFG and PBL core-blocks reset logic using
appropriate bits of PHB_PCIE_CRESET register.
Tested by reading the reset value of a register.
Signed-off-by: Saif Abrar <saif.abrar@linux.vnet.ibm.com>
Reviewed-by: Cédric Le Goater <clg@kaod.org>
---
v1 -> v2:
- Using the ResettableClass.
- Reset of the root complex registers done in pnv_phb_root_port_reset_hold().
hw/pci-host/pnv_phb.c | 1 +
hw/pci-host/pnv_phb4.c | 101 +++++++++++++++++++++++++++-
include/hw/pci-host/pnv_phb4.h | 1 +
include/hw/pci-host/pnv_phb4_regs.h | 16 ++++-
tests/qtest/pnv-phb4-test.c | 28 +++++++-
5 files changed, 143 insertions(+), 4 deletions(-)
diff --git a/hw/pci-host/pnv_phb.c b/hw/pci-host/pnv_phb.c
index 85fcc3b686..bc08d7488d 100644
--- a/hw/pci-host/pnv_phb.c
+++ b/hw/pci-host/pnv_phb.c
@@ -233,6 +233,7 @@ static void pnv_phb_root_port_reset_hold(Object *obj, ResetType type)
pci_set_long(conf + PCI_PREF_BASE_UPPER32, 0x1); /* Hack */
pci_set_long(conf + PCI_PREF_LIMIT_UPPER32, 0xffffffff);
pci_config_set_interrupt_pin(conf, 0);
+ pnv_phb4_cfg_core_reset(d);
}
static void pnv_phb_root_port_realize(DeviceState *dev, Error **errp)
diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c
index 396bc47817..bf21f955c8 100644
--- a/hw/pci-host/pnv_phb4.c
+++ b/hw/pci-host/pnv_phb4.c
@@ -1,7 +1,8 @@
/*
* QEMU PowerPC PowerNV (POWER9) PHB4 model
+ * QEMU PowerPC PowerNV (POWER10) PHB5 model
*
- * Copyright (c) 2018-2020, IBM Corporation.
+ * Copyright (c) 2018-2025, IBM Corporation.
*
* This code is licensed under the GPL version 2 or later. See the
* COPYING file in the top-level directory.
@@ -22,6 +23,7 @@
#include "hw/core/qdev-properties.h"
#include "qom/object.h"
#include "trace.h"
+#include "system/reset.h"
#define phb_error(phb, fmt, ...) \
qemu_log_mask(LOG_GUEST_ERROR, "phb4[%d:%d]: " fmt "\n", \
@@ -499,6 +501,81 @@ static void pnv_phb4_update_xsrc(PnvPHB4 *phb)
}
}
+/*
+ * Get the PCI-E capability offset from the root-port
+ */
+static uint32_t get_exp_offset(PCIDevice *pdev)
+{
+ PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(pdev);
+ return rpc->exp_offset;
+}
+
+void pnv_phb4_cfg_core_reset(PCIDevice *d)
+{
+ uint8_t *conf = d->config;
+ pci_set_word(conf + PCI_COMMAND, PCI_COMMAND_SERR);
+ pci_set_word(conf + PCI_STATUS, PCI_STATUS_CAP_LIST);
+ pci_set_long(conf + PCI_CLASS_REVISION, 0x06040000);
+ pci_set_long(conf + PCI_CACHE_LINE_SIZE, BIT(16));
+ pci_set_word(conf + PCI_MEMORY_BASE, BIT(4));
+ pci_set_word(conf + PCI_PREF_MEMORY_BASE, BIT(0) | BIT(4));
+ pci_set_word(conf + PCI_PREF_MEMORY_LIMIT, PCI_PREF_RANGE_TYPE_64);
+ pci_set_long(conf + PCI_CAPABILITY_LIST, BIT(6));
+ pci_set_long(conf + PCI_CAPABILITY_LIST, BIT(6));
+ pci_set_word(conf + PCI_BRIDGE_CONTROL, PCI_BRIDGE_CTL_SERR);
+ pci_set_long(conf + PCI_BRIDGE_CONTROL + PCI_PM_PMC, 0xC8034801);
+
+ uint32_t exp_offset = get_exp_offset(d);
+ pci_set_long(conf + exp_offset, 0x420010);
+ pci_set_long(conf + exp_offset + PCI_EXP_DEVCAP, 0x8022);
+ pci_set_long(conf + exp_offset + PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_EXT_TAG
+ | PCI_EXP_DEVCTL_PAYLOAD_512B);
+ pci_set_long(conf + exp_offset + PCI_EXP_LNKCAP, PCI_EXP_LNKCAP_LBNC
+ | PCI_EXP_LNKCAP_DLLLARC | BIT(8) | PCI_EXP_LNKCAP_SLS_32_0GB);
+ pci_set_word(conf + exp_offset + PCI_EXP_LNKCTL, PCI_EXP_LNKCTL_RCB);
+ pci_set_word(conf + exp_offset + PCI_EXP_LNKSTA,
+ (PCI_EXP_LNKSTA_NLW_X8 << 2) | PCI_EXP_LNKSTA_CLS_2_5GB);
+ pci_set_long(conf + exp_offset + PCI_EXP_SLTCTL,
+ PCI_EXP_SLTCTL_ASPL_DISABLE);
+ pci_set_long(conf + exp_offset + PCI_EXP_DEVCAP2, BIT(16)
+ | PCI_EXP_DEVCAP2_ARI | PCI_EXP_DEVCAP2_COMP_TMOUT_DIS | 0xF);
+ pci_set_long(conf + exp_offset + PCI_EXP_DEVCTL2, PCI_EXP_DEVCTL2_ARI);
+ pci_set_long(conf + exp_offset + PCI_EXP_LNKCAP2, BIT(23)
+ | PCI_EXP_LNKCAP2_SLS_32_0GB
+ | PCI_EXP_LNKCAP2_SLS_16_0GB | PCI_EXP_LNKCAP2_SLS_8_0GB
+ | PCI_EXP_LNKCAP2_SLS_5_0GB | PCI_EXP_LNKCAP2_SLS_2_5GB);
+ pci_set_long(conf + PHB_AER_ECAP, PCI_EXT_CAP(0x1, 0x1, 0x148));
+ pci_set_long(conf + PHB_SEC_ECAP, (0x1A0 << 20) | BIT(16)
+ | PCI_EXT_CAP_ID_SECPCI);
+ pci_set_long(conf + PHB_LMR_ECAP, 0x1E810027);
+ /* LMR - Margining Lane Control / Status Register # 2 to 16 */
+ int i;
+ for (i = PHB_LMR_CTLSTA_2 ; i <= PHB_LMR_CTLSTA_16 ; i += 4) {
+ pci_set_long(conf + i, 0x9C38);
+ }
+
+ pci_set_long(conf + PHB_DLF_ECAP, 0x1F410025);
+ pci_set_long(conf + PHB_DLF_CAP, 0x80000001);
+ pci_set_long(conf + P16_ECAP, 0x22410026);
+ pci_set_long(conf + P32_ECAP, 0x1002A);
+ pci_set_long(conf + P32_CAP, 0x103);
+}
+
+static void pnv_phb4_pbl_core_reset(PnvPHB4 *phb)
+{
+ /* Zero all registers initially */
+ int i;
+ for (i = PHB_PBL_CONTROL ; i <= PHB_PBL_ERR1_STATUS_MASK ; i += 8) {
+ phb->regs[i >> 3] = 0x0;
+ }
+
+ /* Set specific register values */
+ phb->regs[PHB_PBL_CONTROL >> 3] = 0xC009000000000000;
+ phb->regs[PHB_PBL_TIMEOUT_CTRL >> 3] = 0x2020000000000000;
+ phb->regs[PHB_PBL_NPTAG_ENABLE >> 3] = 0xFFFFFFFF00000000;
+ phb->regs[PHB_PBL_SYS_LINK_INIT >> 3] = 0x80088B4642473000;
+}
+
static void pnv_phb4_reg_write(void *opaque, hwaddr off, uint64_t val,
unsigned size)
{
@@ -612,6 +689,17 @@ static void pnv_phb4_reg_write(void *opaque, hwaddr off, uint64_t val,
pnv_phb4_update_xsrc(phb);
break;
+ /* Reset core blocks */
+ case PHB_PCIE_CRESET:
+ if (val & PHB_PCIE_CRESET_CFG_CORE) {
+ PCIHostState *pci = PCI_HOST_BRIDGE(phb->phb_base);
+ pnv_phb4_cfg_core_reset(pci_find_device(pci->bus, 0, 0));
+ }
+ if (val & PHB_PCIE_CRESET_PBL) {
+ pnv_phb4_pbl_core_reset(phb);
+ }
+ break;
+
/* Silent simple writes */
case PHB_ASN_CMPM:
case PHB_CONFIG_ADDRESS:
@@ -1532,6 +1620,12 @@ static PCIIOMMUOps pnv_phb4_iommu_ops = {
.get_address_space = pnv_phb4_dma_iommu,
};
+static void pnv_phb4_reset(Object *obj, ResetType type)
+{
+ PnvPHB4 *phb = PNV_PHB4(obj);
+ pnv_phb4_pbl_core_reset(phb);
+}
+
static void pnv_phb4_instance_init(Object *obj)
{
PnvPHB4 *phb = PNV_PHB4(obj);
@@ -1608,6 +1702,8 @@ static void pnv_phb4_realize(DeviceState *dev, Error **errp)
phb->qirqs = qemu_allocate_irqs(xive_source_set_irq, xsrc, xsrc->nr_irqs);
pnv_phb4_xscom_realize(phb);
+
+ qemu_register_resettable(OBJECT(dev));
}
/*
@@ -1707,6 +1803,9 @@ static void pnv_phb4_class_init(ObjectClass *klass, const void *data)
dc->user_creatable = false;
xfc->notify = pnv_phb4_xive_notify;
+
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
+ rc->phases.enter = pnv_phb4_reset;
}
static const TypeInfo pnv_phb4_type_info = {
diff --git a/include/hw/pci-host/pnv_phb4.h b/include/hw/pci-host/pnv_phb4.h
index de996e718b..47a5c3edf5 100644
--- a/include/hw/pci-host/pnv_phb4.h
+++ b/include/hw/pci-host/pnv_phb4.h
@@ -160,6 +160,7 @@ void pnv_phb4_pic_print_info(PnvPHB4 *phb, GString *buf);
int pnv_phb4_pec_get_phb_id(PnvPhb4PecState *pec, int stack_index);
PnvPhb4PecState *pnv_pec_add_phb(PnvChip *chip, PnvPHB *phb, Error **errp);
void pnv_phb4_bus_init(DeviceState *dev, PnvPHB4 *phb);
+void pnv_phb4_cfg_core_reset(PCIDevice *d);
extern const MemoryRegionOps pnv_phb4_xscom_ops;
/*
diff --git a/include/hw/pci-host/pnv_phb4_regs.h b/include/hw/pci-host/pnv_phb4_regs.h
index bea96f4d91..6892e21cc9 100644
--- a/include/hw/pci-host/pnv_phb4_regs.h
+++ b/include/hw/pci-host/pnv_phb4_regs.h
@@ -343,6 +343,18 @@
#define PHB_RC_CONFIG_BASE 0x1000
#define PHB_RC_CONFIG_SIZE 0x800
+#define PHB_AER_ECAP 0x100
+#define PHB_AER_CAPCTRL 0x118
+#define PHB_SEC_ECAP 0x148
+#define PHB_LMR_ECAP 0x1A0
+#define PHB_LMR_CTLSTA_2 0x1AC
+#define PHB_LMR_CTLSTA_16 0x1E4
+#define PHB_DLF_ECAP 0x1E8
+#define PHB_DLF_CAP 0x1EC
+#define P16_ECAP 0x1F4
+#define P32_ECAP 0x224
+#define P32_CAP 0x228
+
/* PHB4 REGB registers */
/* PBL core */
@@ -368,7 +380,7 @@
#define PHB_PCIE_SCR 0x1A00
#define PHB_PCIE_SCR_SLOT_CAP PPC_BIT(15)
#define PHB_PCIE_SCR_MAXLINKSPEED PPC_BITMASK(32, 35)
-
+#define PHB_PCIE_BNR 0x1A08
#define PHB_PCIE_CRESET 0x1A10
#define PHB_PCIE_CRESET_CFG_CORE PPC_BIT(0)
@@ -423,6 +435,8 @@
#define PHB_PCIE_LANE_EQ_CNTL23 0x1B08 /* DD1 only */
#define PHB_PCIE_TRACE_CTRL 0x1B20
#define PHB_PCIE_MISC_STRAP 0x1B30
+#define PHB_PCIE_PHY_RXEQ_STAT_G3_00_03 0x1B40
+#define PHB_PCIE_PHY_RXEQ_STAT_G5_12_15 0x1B98
/* Error */
#define PHB_REGB_ERR_STATUS 0x1C00
diff --git a/tests/qtest/pnv-phb4-test.c b/tests/qtest/pnv-phb4-test.c
index 3890b4f970..3957c743a3 100644
--- a/tests/qtest/pnv-phb4-test.c
+++ b/tests/qtest/pnv-phb4-test.c
@@ -35,6 +35,29 @@ static uint64_t pnv_phb_xscom_read(QTestState *qts, const PnvChip *chip,
return qtest_readq(qts, pnv_xscom_addr(chip, (scom >> 3) + indirect_data));
}
+#define phb4_xscom_read(a) pnv_phb_xscom_read(qts, \
+ &pnv_chips[PNV_P10_CHIP_INDEX], PHB4_XSCOM, \
+ PHB_SCOM_HV_IND_ADDR, PHB_SCOM_HV_IND_DATA, \
+ PPC_BIT(0) | a)
+
+/* Assert that 'PHB PBL Control' register has correct reset value */
+static void phb4_reset_test(QTestState *qts)
+{
+ g_assert_cmpuint(phb4_xscom_read(PHB_PBL_CONTROL), ==, 0xC009000000000000);
+}
+
+static void phb4_tests(void)
+{
+ QTestState *qts = NULL;
+
+ qts = qtest_initf("-machine powernv10 -accel tcg");
+
+ /* Check reset value of a register */
+ phb4_reset_test(qts);
+
+ qtest_quit(qts);
+}
+
/* Assert that 'PHB - Version Register' bits-[24:31] are as expected */
static void phb_version_test(const void *data)
{
@@ -71,8 +94,6 @@ static void phb_version_test(const void *data)
/* PHB Version register bits [24:31] */
ver = ver >> (63 - 31);
g_assert_cmpuint(ver, ==, expected_ver);
-
- qtest_quit(qts);
}
/* Verify versions of all supported PHB's */
@@ -95,5 +116,8 @@ int main(int argc, char **argv)
/* PHB[345] tests */
add_phbX_version_test();
+ /* PHB4 specific tests */
+ qtest_add_func("phb4", phb4_tests);
+
return g_test_run();
}
--
2.47.3
^ permalink raw reply related [flat|nested] 60+ messages in thread
* [PATCH v2 3/9] pnv/phb4: Implement sticky reset logic in PHB4
2025-12-30 10:21 [PATCH v2 0/9] pnv/phb4: Update PHB4 to the latest PHB5 spec Saif Abrar
2025-12-30 10:21 ` [PATCH v2 1/9] qtest/phb4: Add testbench for PHB4 Saif Abrar
2025-12-30 10:21 ` [PATCH v2 2/9] pnv/phb4: Add reset logic to PHB4 Saif Abrar
@ 2025-12-30 10:21 ` Saif Abrar
2025-12-30 10:21 ` [PATCH v2 4/9] pnv/phb4: Implement read-only and write-only bits of registers Saif Abrar
` (6 subsequent siblings)
9 siblings, 0 replies; 60+ messages in thread
From: Saif Abrar @ 2025-12-30 10:21 UTC (permalink / raw)
To: qemu-ppc, qemu-devel
Cc: clg, npiggin, fbarrat, mst, marcel.apfelbaum, cohuck, pbonzini,
thuth, lvivier, danielhb413, saif.abrar
Sticky bits retain their values on reset and are not overwritten with
the reset value.
Added sticky reset logic for all required registers,
i.e. CFG core, PBL core, PHB error registers, PCIE stack registers and
REGB error registers.
Tested by writing all 1's to the reg PHB_PBL_ERR_INJECT.
This will set the bits in the reg PHB_PBL_ERR_STATUS.
Reset the PBL core by setting PHB_PCIE_CRESET_PBL in reg PHB_PCIE_CRESET.
Verify that the sticky bits in the PHB_PBL_ERR_STATUS reg are still set.
Signed-off-by: Saif Abrar <saif.abrar@linux.vnet.ibm.com>
---
hw/pci-host/pnv_phb4.c | 123 +++++++++++++++++++++++++++-
include/hw/pci-host/pnv_phb4_regs.h | 20 ++++-
tests/qtest/pnv-phb4-test.c | 41 ++++++++++
3 files changed, 179 insertions(+), 5 deletions(-)
diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c
index bf21f955c8..70f5af21fa 100644
--- a/hw/pci-host/pnv_phb4.c
+++ b/hw/pci-host/pnv_phb4.c
@@ -510,6 +510,18 @@ static uint32_t get_exp_offset(PCIDevice *pdev)
return rpc->exp_offset;
}
+/*
+ * Apply sticky-mask 's' to the reset-value 'v' and write to the address 'a'.
+ * RC-config space values and masks are LE.
+ * Method pnv_phb4_rc_config_read() returns BE, hence convert to LE.
+ * Compute new value in LE domain.
+ * New value computation using sticky-mask is in LE.
+ * Convert the computed value from LE to BE before writing back.
+ */
+#define RC_CONFIG_STICKY_RESET(a, v, s) \
+ (pci_set_word(conf + a, bswap32( \
+ (bswap32(pci_get_word(conf + a)) & s) | (v & ~s))))
+
void pnv_phb4_cfg_core_reset(PCIDevice *d)
{
uint8_t *conf = d->config;
@@ -559,15 +571,57 @@ void pnv_phb4_cfg_core_reset(PCIDevice *d)
pci_set_long(conf + P16_ECAP, 0x22410026);
pci_set_long(conf + P32_ECAP, 0x1002A);
pci_set_long(conf + P32_CAP, 0x103);
+
+ /* Sticky reset */
+ RC_CONFIG_STICKY_RESET(exp_offset + PCI_EXP_LNKCTL2,
+ PCI_EXP_LNKCTL2_TLS_32_0GT, 0xFEFFBF);
+ RC_CONFIG_STICKY_RESET(PHB_AER_UERR, 0, 0x1FF030);
+ RC_CONFIG_STICKY_RESET(PHB_AER_UERR_MASK, 0, 0x1FF030);
+ RC_CONFIG_STICKY_RESET(PHB_AER_CERR, 0, 0x11C1);
+ RC_CONFIG_STICKY_RESET(PHB_AER_ECAP + PCI_ERR_CAP, (PCI_ERR_CAP_ECRC_CHKC
+ | PCI_ERR_CAP_ECRC_GENC), 0x15F);
+ RC_CONFIG_STICKY_RESET(PHB_AER_HLOG_1, 0, 0xFFFFFFFF);
+ RC_CONFIG_STICKY_RESET(PHB_AER_HLOG_2, 0, 0xFFFFFFFF);
+ RC_CONFIG_STICKY_RESET(PHB_AER_HLOG_3, 0, 0xFFFFFFFF);
+ RC_CONFIG_STICKY_RESET(PHB_AER_HLOG_4, 0, 0xFFFFFFFF);
+ RC_CONFIG_STICKY_RESET(PHB_AER_RERR, 0, 0x7F);
+ RC_CONFIG_STICKY_RESET(PHB_AER_ESID, 0, 0xFFFFFFFF);
+ RC_CONFIG_STICKY_RESET(PHB_DLF_STAT, 0, 0x807FFFFF);
+ RC_CONFIG_STICKY_RESET(P16_STAT, 0, 0x1F);
+ RC_CONFIG_STICKY_RESET(P16_LDPM, 0, 0xFFFF);
+ RC_CONFIG_STICKY_RESET(P16_FRDPM, 0, 0xFFFF);
+ RC_CONFIG_STICKY_RESET(P16_SRDPM, 0, 0xFFFF);
+ RC_CONFIG_STICKY_RESET(P32_CTL, 0, 0x3);
}
+/* Apply sticky-mask to the reset-value and write to the reg-address */
+#define STICKY_RST(addr, rst_val, sticky_mask) (phb->regs[addr >> 3] = \
+ ((phb->regs[addr >> 3] & sticky_mask) | (rst_val & ~sticky_mask)))
+
static void pnv_phb4_pbl_core_reset(PnvPHB4 *phb)
{
- /* Zero all registers initially */
+ /*
+ * Zero all registers initially,
+ * with sticky reset of certain registers.
+ */
int i;
for (i = PHB_PBL_CONTROL ; i <= PHB_PBL_ERR1_STATUS_MASK ; i += 8) {
- phb->regs[i >> 3] = 0x0;
+ switch (i) {
+ case PHB_PBL_ERR_STATUS:
+ break;
+ case PHB_PBL_ERR1_STATUS:
+ case PHB_PBL_ERR_LOG_0:
+ case PHB_PBL_ERR_LOG_1:
+ case PHB_PBL_ERR_STATUS_MASK:
+ case PHB_PBL_ERR1_STATUS_MASK:
+ STICKY_RST(i, 0, PPC_BITMASK(0, 63));
+ break;
+ default:
+ phb->regs[i >> 3] = 0x0;
+ }
}
+ STICKY_RST(PHB_PBL_ERR_STATUS, 0, \
+ (PPC_BITMASK(0, 9) | PPC_BITMASK(12, 63)));
/* Set specific register values */
phb->regs[PHB_PBL_CONTROL >> 3] = 0xC009000000000000;
@@ -700,6 +754,17 @@ static void pnv_phb4_reg_write(void *opaque, hwaddr off, uint64_t val,
}
break;
+ /*
+ * Writing bits to a 1 in this register will inject the error corresponding
+ * to the bit that is written. The bits will automatically clear to 0 after
+ * the error is injected. The corresponding bit in the Error Status Reg
+ * should also be set automatically when the error occurs.
+ */
+ case PHB_PBL_ERR_INJECT:
+ phb->regs[PHB_PBL_ERR_STATUS >> 3] = phb->regs[off >> 3];
+ phb->regs[off >> 3] = 0;
+ break;
+
/* Silent simple writes */
case PHB_ASN_CMPM:
case PHB_CONFIG_ADDRESS:
@@ -1620,10 +1685,64 @@ static PCIIOMMUOps pnv_phb4_iommu_ops = {
.get_address_space = pnv_phb4_dma_iommu,
};
+static void pnv_phb4_err_reg_reset(PnvPHB4 *phb)
+{
+ STICKY_RST(PHB_ERR_STATUS, 0, PPC_BITMASK(0, 33));
+ STICKY_RST(PHB_ERR1_STATUS, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_ERR_STATUS_MASK, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_ERR1_STATUS_MASK, 0, PPC_BITMASK(0, 63));
+
+ STICKY_RST(PHB_TXE_ERR_STATUS, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_TXE_ERR1_STATUS, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_TXE_ERR_STATUS_MASK, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_TXE_ERR1_STATUS_MASK, 0, PPC_BITMASK(0, 63));
+
+ STICKY_RST(PHB_RXE_ARB_ERR_STATUS, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_RXE_ARB_ERR1_STATUS, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_RXE_ARB_ERR_LOG_0, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_RXE_ARB_ERR_LOG_1, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_RXE_ARB_ERR_STATUS_MASK, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_RXE_ARB_ERR1_STATUS_MASK, 0, PPC_BITMASK(0, 63));
+
+ STICKY_RST(PHB_RXE_MRG_ERR_STATUS, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_RXE_MRG_ERR1_STATUS, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_RXE_MRG_ERR_STATUS_MASK, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_RXE_MRG_ERR1_STATUS_MASK, 0, PPC_BITMASK(0, 63));
+
+ STICKY_RST(PHB_RXE_TCE_ERR_STATUS, 0, PPC_BITMASK(0, 35));
+ STICKY_RST(PHB_RXE_TCE_ERR1_STATUS, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_RXE_TCE_ERR_LOG_0, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_RXE_TCE_ERR_LOG_1, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_RXE_TCE_ERR_STATUS_MASK, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_RXE_TCE_ERR1_STATUS_MASK, 0, PPC_BITMASK(0, 63));
+}
+
+static void pnv_phb4_pcie_stack_reg_reset(PnvPHB4 *phb)
+{
+ STICKY_RST(PHB_PCIE_CRESET, 0xE000000000000000, \
+ (PHB_PCIE_CRESET_PERST_N | PHB_PCIE_CRESET_REFCLK_N));
+ STICKY_RST(PHB_PCIE_DLP_ERRLOG1, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_PCIE_DLP_ERRLOG2, 0, PPC_BITMASK(0, 31));
+ STICKY_RST(PHB_PCIE_DLP_ERR_STATUS, 0, PPC_BITMASK(0, 15));
+}
+
+static void pnv_phb4_regb_err_reg_reset(PnvPHB4 *phb)
+{
+ STICKY_RST(PHB_REGB_ERR_STATUS, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_REGB_ERR1_STATUS, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_REGB_ERR_LOG_0, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_REGB_ERR_LOG_1, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_REGB_ERR_STATUS_MASK, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_REGB_ERR1_STATUS_MASK, 0, PPC_BITMASK(0, 63));
+}
+
static void pnv_phb4_reset(Object *obj, ResetType type)
{
PnvPHB4 *phb = PNV_PHB4(obj);
pnv_phb4_pbl_core_reset(phb);
+ pnv_phb4_err_reg_reset(phb);
+ pnv_phb4_pcie_stack_reg_reset(phb);
+ pnv_phb4_regb_err_reg_reset(phb);
}
static void pnv_phb4_instance_init(Object *obj)
diff --git a/include/hw/pci-host/pnv_phb4_regs.h b/include/hw/pci-host/pnv_phb4_regs.h
index 6892e21cc9..df5e86d29a 100644
--- a/include/hw/pci-host/pnv_phb4_regs.h
+++ b/include/hw/pci-host/pnv_phb4_regs.h
@@ -344,17 +344,32 @@
#define PHB_RC_CONFIG_SIZE 0x800
#define PHB_AER_ECAP 0x100
+#define PHB_AER_UERR 0x104
+#define PHB_AER_UERR_MASK 0x108
+#define PHB_AER_CERR 0x110
#define PHB_AER_CAPCTRL 0x118
+#define PHB_AER_HLOG_1 0x11C
+#define PHB_AER_HLOG_2 0x120
+#define PHB_AER_HLOG_3 0x124
+#define PHB_AER_HLOG_4 0x128
+#define PHB_AER_RERR 0x130
+#define PHB_AER_ESID 0x134
#define PHB_SEC_ECAP 0x148
#define PHB_LMR_ECAP 0x1A0
#define PHB_LMR_CTLSTA_2 0x1AC
#define PHB_LMR_CTLSTA_16 0x1E4
#define PHB_DLF_ECAP 0x1E8
#define PHB_DLF_CAP 0x1EC
+#define PHB_DLF_STAT 0x1F0
#define P16_ECAP 0x1F4
+#define P16_STAT 0x200
+#define P16_LDPM 0x204
+#define P16_FRDPM 0x208
+#define P16_SRDPM 0x20C
#define P32_ECAP 0x224
#define P32_CAP 0x228
-
+#define P32_CTL 0x22C
+#define P32_STAT 0x230
/* PHB4 REGB registers */
/* PBL core */
@@ -388,8 +403,7 @@
#define PHB_PCIE_CRESET_PBL PPC_BIT(2)
#define PHB_PCIE_CRESET_PERST_N PPC_BIT(3)
#define PHB_PCIE_CRESET_PIPE_N PPC_BIT(4)
-
-
+#define PHB_PCIE_CRESET_REFCLK_N PPC_BIT(8)
#define PHB_PCIE_HOTPLUG_STATUS 0x1A20
#define PHB_PCIE_HPSTAT_PRESENCE PPC_BIT(10)
diff --git a/tests/qtest/pnv-phb4-test.c b/tests/qtest/pnv-phb4-test.c
index 3957c743a3..f186efaf0d 100644
--- a/tests/qtest/pnv-phb4-test.c
+++ b/tests/qtest/pnv-phb4-test.c
@@ -22,6 +22,19 @@
#define PNV_P10_CHIP_INDEX 3
#define PHB4_XSCOM 0x40084800ull
+/*
+ * Indirect XSCOM write:
+ * - Write 'Indirect Address Register' with register-offset to write.
+ * - Write 'Indirect Data Register' with the value.
+ */
+static void pnv_phb_xscom_write(QTestState *qts, const PnvChip *chip,
+ uint64_t scom, uint32_t indirect_addr, uint32_t indirect_data,
+ uint64_t reg, uint64_t val)
+{
+ qtest_writeq(qts, pnv_xscom_addr(chip, (scom >> 3) + indirect_addr), reg);
+ qtest_writeq(qts, pnv_xscom_addr(chip, (scom >> 3) + indirect_data), val);
+}
+
/*
* Indirect XSCOM read::
* - Write 'Indirect Address Register' with register-offset to read.
@@ -35,6 +48,11 @@ static uint64_t pnv_phb_xscom_read(QTestState *qts, const PnvChip *chip,
return qtest_readq(qts, pnv_xscom_addr(chip, (scom >> 3) + indirect_data));
}
+#define phb4_xscom_write(a, v) pnv_phb_xscom_write(qts, \
+ &pnv_chips[PNV_P10_CHIP_INDEX], PHB4_XSCOM, \
+ PHB_SCOM_HV_IND_ADDR, PHB_SCOM_HV_IND_DATA, \
+ PPC_BIT(0) | a, v)
+
#define phb4_xscom_read(a) pnv_phb_xscom_read(qts, \
&pnv_chips[PNV_P10_CHIP_INDEX], PHB4_XSCOM, \
PHB_SCOM_HV_IND_ADDR, PHB_SCOM_HV_IND_DATA, \
@@ -46,6 +64,26 @@ static void phb4_reset_test(QTestState *qts)
g_assert_cmpuint(phb4_xscom_read(PHB_PBL_CONTROL), ==, 0xC009000000000000);
}
+/* Check sticky-reset */
+static void phb4_sticky_rst_test(QTestState *qts)
+{
+ uint64_t val;
+
+ /*
+ * Sticky reset test of PHB_PBL_ERR_STATUS.
+ *
+ * Write all 1's to reg PHB_PBL_ERR_INJECT.
+ * Updated value will be copied to reg PHB_PBL_ERR_STATUS.
+ *
+ * Reset PBL core by setting PHB_PCIE_CRESET_PBL in reg PHB_PCIE_CRESET.
+ * Verify the sticky bits are still set.
+ */
+ phb4_xscom_write(PHB_PBL_ERR_INJECT, PPC_BITMASK(0, 63));
+ phb4_xscom_write(PHB_PCIE_CRESET, PHB_PCIE_CRESET_PBL); /*Reset*/
+ val = phb4_xscom_read(PHB_PBL_ERR_STATUS);
+ g_assert_cmpuint(val, ==, (PPC_BITMASK(0, 9) | PPC_BITMASK(12, 63)));
+}
+
static void phb4_tests(void)
{
QTestState *qts = NULL;
@@ -55,6 +93,9 @@ static void phb4_tests(void)
/* Check reset value of a register */
phb4_reset_test(qts);
+ /* Check sticky reset of a register */
+ phb4_sticky_rst_test(qts);
+
qtest_quit(qts);
}
--
2.47.3
^ permalink raw reply related [flat|nested] 60+ messages in thread
* [PATCH v2 4/9] pnv/phb4: Implement read-only and write-only bits of registers
2025-12-30 10:21 [PATCH v2 0/9] pnv/phb4: Update PHB4 to the latest PHB5 spec Saif Abrar
` (2 preceding siblings ...)
2025-12-30 10:21 ` [PATCH v2 3/9] pnv/phb4: Implement sticky reset logic in PHB4 Saif Abrar
@ 2025-12-30 10:21 ` Saif Abrar
2026-02-04 5:04 ` Michael S. Tsirkin
2025-12-30 10:21 ` [PATCH v2 5/9] pnv/phb4: Implement write-clear and return 1's on unimplemented reg read Saif Abrar
` (5 subsequent siblings)
9 siblings, 1 reply; 60+ messages in thread
From: Saif Abrar @ 2025-12-30 10:21 UTC (permalink / raw)
To: qemu-ppc, qemu-devel
Cc: clg, npiggin, fbarrat, mst, marcel.apfelbaum, cohuck, pbonzini,
thuth, lvivier, danielhb413, saif.abrar
SW cannot write the read-only(RO) bits of a register
and write-only(WO) bits of a register return 0 when read.
Added ro_mask[] for each register that defines which
bits in that register are RO.
When writing to a register, the RO-bits are not updated.
When reading a register, clear the WO bits and return the updated value.
Tested the registers PHB_DMA_SYNC, PHB_PCIE_HOTPLUG_STATUS, PHB_PCIE_LMR,
PHB_PCIE_DLP_TRWCTL, PHB_LEM_ERROR_AND_MASK and PHB_LEM_ERROR_OR_MASK
by writing all 1's and reading back the value.
The WO bits in these registers should read back as 0.
Signed-off-by: Saif Abrar <saif.abrar@linux.vnet.ibm.com>
Reviewed-by: Cédric Le Goater <clg@kaod.org>
---
v1 -> v2: New PnvPHB4Class to hold each register's RO mask.
hw/pci-host/pnv_phb4.c | 78 ++++++++++++++++++++++++++---
include/hw/pci-host/pnv_phb4.h | 13 ++++-
include/hw/pci-host/pnv_phb4_regs.h | 20 ++++++--
tests/qtest/pnv-phb4-test.c | 60 +++++++++++++++++++++-
4 files changed, 157 insertions(+), 14 deletions(-)
diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c
index 70f5af21fa..48caba9e79 100644
--- a/hw/pci-host/pnv_phb4.c
+++ b/hw/pci-host/pnv_phb4.c
@@ -707,6 +707,11 @@ static void pnv_phb4_reg_write(void *opaque, hwaddr off, uint64_t val,
return;
}
+ /* Update 'val' according to the register's RO-mask */
+ PnvPHB4Class *k = PNV_PHB4_GET_CLASS(phb);
+ val = (phb->regs[off >> 3] & k->ro_mask[off >> 3]) |
+ (val & ~(k->ro_mask[off >> 3]));
+
/* Record whether it changed */
changed = phb->regs[off >> 3] != val;
@@ -781,7 +786,7 @@ static void pnv_phb4_reg_write(void *opaque, hwaddr off, uint64_t val,
case PHB_TCE_TAG_ENABLE:
case PHB_INT_NOTIFY_ADDR:
case PHB_INT_NOTIFY_INDEX:
- case PHB_DMARD_SYNC:
+ case PHB_DMA_SYNC:
break;
/* Noise on anything else */
@@ -819,7 +824,7 @@ static uint64_t pnv_phb4_reg_read(void *opaque, hwaddr off, unsigned size)
case PHB_VERSION:
return PNV_PHB4_PEC_GET_CLASS(phb->pec)->version;
- /* Read-only */
+ /* Read-only */
case PHB_PHB4_GEN_CAP:
return 0xe4b8000000000000ull;
case PHB_PHB4_TCE_CAP:
@@ -829,18 +834,49 @@ static uint64_t pnv_phb4_reg_read(void *opaque, hwaddr off, unsigned size)
case PHB_PHB4_EEH_CAP:
return phb->big_phb ? 0x2000000000000000ull : 0x1000000000000000ull;
+ /* Write-only, read will return zeros */
+ case PHB_LEM_ERROR_AND_MASK:
+ case PHB_LEM_ERROR_OR_MASK:
+ return 0;
+ case PHB_PCIE_DLP_TRWCTL:
+ val &= ~PHB_PCIE_DLP_TRWCTL_WREN;
+ return val;
/* IODA table accesses */
case PHB_IODA_DATA0:
return pnv_phb4_ioda_read(phb);
+ /*
+ * DMA sync: make it look like it's complete,
+ * clear write-only read/write start sync bits.
+ */
+ case PHB_DMA_SYNC:
+ val = PHB_DMA_SYNC_RD_COMPLETE |
+ ~(PHB_DMA_SYNC_RD_START | PHB_DMA_SYNC_WR_START);
+ return val;
+
+ /*
+ * PCI-E Stack registers
+ */
+ case PHB_PCIE_SCR:
+ val |= PHB_PCIE_SCR_PLW_X16; /* RO bit */
+ break;
+
/* Link training always appears trained */
case PHB_PCIE_DLP_TRAIN_CTL:
/* TODO: Do something sensible with speed ? */
- return PHB_PCIE_DLP_INBAND_PRESENCE | PHB_PCIE_DLP_TL_LINKACT;
+ val |= PHB_PCIE_DLP_INBAND_PRESENCE | PHB_PCIE_DLP_TL_LINKACT;
+ return val;
+
+ case PHB_PCIE_HOTPLUG_STATUS:
+ /* Clear write-only bit */
+ val &= ~PHB_PCIE_HPSTAT_RESAMPLE;
+ return val;
- /* DMA read sync: make it look like it's complete */
- case PHB_DMARD_SYNC:
- return PHB_DMARD_SYNC_COMPLETE;
+ /* Link Management Register */
+ case PHB_PCIE_LMR:
+ /* These write-only bits always read as 0 */
+ val &= ~(PHB_PCIE_LMR_CHANGELW | PHB_PCIE_LMR_RETRAINLINK);
+ return val;
/* Silent simple reads */
case PHB_LSI_SOURCE_ID:
@@ -1685,6 +1721,32 @@ static PCIIOMMUOps pnv_phb4_iommu_ops = {
.get_address_space = pnv_phb4_dma_iommu,
};
+static void pnv_phb4_ro_mask_init(PnvPHB4 *phb)
+{
+ PnvPHB4Class *phb4c = PNV_PHB4_GET_CLASS(phb);
+
+ /*
+ * Set register specific RO-masks
+ */
+
+ /* PBL - Error Injection Register (0x1910) */
+ phb4c->ro_mask[PHB_PBL_ERR_INJECT >> 3] =
+ PPC_BITMASK(0, 23) | PPC_BITMASK(28, 35) | PPC_BIT(38) | PPC_BIT(46) |
+ PPC_BITMASK(49, 51) | PPC_BITMASK(55, 63);
+
+ /* Reserved bits[60:63] */
+ phb4c->ro_mask[PHB_TXE_ERR_LEM_ENABLE >> 3] =
+ phb4c->ro_mask[PHB_TXE_ERR_AIB_FENCE_ENABLE >> 3] = PPC_BITMASK(60, 63);
+ /* Reserved bits[36:63] */
+ phb4c->ro_mask[PHB_RXE_TCE_ERR_LEM_ENABLE >> 3] =
+ phb4c->ro_mask[PHB_RXE_TCE_ERR_AIB_FENCE_ENABLE >> 3] = PPC_BITMASK(36, 63);
+ /* Reserved bits[40:63] */
+ phb4c->ro_mask[PHB_ERR_LEM_ENABLE >> 3] =
+ phb4c->ro_mask[PHB_ERR_AIB_FENCE_ENABLE >> 3] = PPC_BITMASK(40, 63);
+
+ /* TODO: Add more RO-masks as regs are implemented in the model */
+}
+
static void pnv_phb4_err_reg_reset(PnvPHB4 *phb)
{
STICKY_RST(PHB_ERR_STATUS, 0, PPC_BITMASK(0, 33));
@@ -1743,6 +1805,7 @@ static void pnv_phb4_reset(Object *obj, ResetType type)
pnv_phb4_err_reg_reset(phb);
pnv_phb4_pcie_stack_reg_reset(phb);
pnv_phb4_regb_err_reg_reset(phb);
+ phb->regs[PHB_PCIE_CRESET >> 3] = 0xE000000000000000;
}
static void pnv_phb4_instance_init(Object *obj)
@@ -1753,6 +1816,9 @@ static void pnv_phb4_instance_init(Object *obj)
/* XIVE interrupt source object */
object_initialize_child(obj, "source", &phb->xsrc, TYPE_XIVE_SOURCE);
+
+ /* Initialize RO-mask of registers */
+ pnv_phb4_ro_mask_init(phb);
}
void pnv_phb4_bus_init(DeviceState *dev, PnvPHB4 *phb)
diff --git a/include/hw/pci-host/pnv_phb4.h b/include/hw/pci-host/pnv_phb4.h
index 47a5c3edf5..bea0684724 100644
--- a/include/hw/pci-host/pnv_phb4.h
+++ b/include/hw/pci-host/pnv_phb4.h
@@ -19,7 +19,7 @@
#define TYPE_PNV_PHB4 "pnv-phb4"
-OBJECT_DECLARE_SIMPLE_TYPE(PnvPHB4, PNV_PHB4)
+OBJECT_DECLARE_TYPE(PnvPHB4, PnvPHB4Class, PNV_PHB4)
typedef struct PnvPhb4PecStack PnvPhb4PecStack;
@@ -156,6 +156,17 @@ struct PnvPHB4 {
QLIST_HEAD(, PnvPhb4DMASpace) dma_spaces;
};
+typedef struct PnvPHB4Class {
+ DeviceClass parent_class;
+
+ /*
+ * Read-only bitmask for registers
+ * Bit value: 1 => RO bit
+ * 0 => RW bit
+ */
+ uint64_t ro_mask[PNV_PHB4_NUM_REGS];
+} PnvPHB4Class;
+
void pnv_phb4_pic_print_info(PnvPHB4 *phb, GString *buf);
int pnv_phb4_pec_get_phb_id(PnvPhb4PecState *pec, int stack_index);
PnvPhb4PecState *pnv_pec_add_phb(PnvChip *chip, PnvPHB *phb, Error **errp);
diff --git a/include/hw/pci-host/pnv_phb4_regs.h b/include/hw/pci-host/pnv_phb4_regs.h
index df5e86d29a..dfd0e01d1e 100644
--- a/include/hw/pci-host/pnv_phb4_regs.h
+++ b/include/hw/pci-host/pnv_phb4_regs.h
@@ -180,9 +180,11 @@
#define PHB_M64_AOMASK 0x1d0
#define PHB_M64_UPPER_BITS 0x1f0
#define PHB_NXLATE_PREFIX 0x1f8
-#define PHB_DMARD_SYNC 0x200
-#define PHB_DMARD_SYNC_START PPC_BIT(0)
-#define PHB_DMARD_SYNC_COMPLETE PPC_BIT(1)
+#define PHB_DMA_SYNC 0x200
+#define PHB_DMA_SYNC_RD_START PPC_BIT(0)
+#define PHB_DMA_SYNC_RD_COMPLETE PPC_BIT(1)
+#define PHB_DMA_SYNC_WR_START PPC_BIT(2)
+#define PHB_DMA_SYNC_WR_COMPLETE PPC_BIT(3)
#define PHB_RTC_INVALIDATE 0x208
#define PHB_RTC_INVALIDATE_ALL PPC_BIT(0)
#define PHB_RTC_INVALIDATE_RID PPC_BITMASK(16, 31)
@@ -370,6 +372,7 @@
#define P32_CAP 0x228
#define P32_CTL 0x22C
#define P32_STAT 0x230
+
/* PHB4 REGB registers */
/* PBL core */
@@ -395,8 +398,8 @@
#define PHB_PCIE_SCR 0x1A00
#define PHB_PCIE_SCR_SLOT_CAP PPC_BIT(15)
#define PHB_PCIE_SCR_MAXLINKSPEED PPC_BITMASK(32, 35)
+#define PHB_PCIE_SCR_PLW_X16 PPC_BIT(41) /* x16 */
#define PHB_PCIE_BNR 0x1A08
-
#define PHB_PCIE_CRESET 0x1A10
#define PHB_PCIE_CRESET_CFG_CORE PPC_BIT(0)
#define PHB_PCIE_CRESET_TLDLP PPC_BIT(1)
@@ -405,7 +408,14 @@
#define PHB_PCIE_CRESET_PIPE_N PPC_BIT(4)
#define PHB_PCIE_CRESET_REFCLK_N PPC_BIT(8)
#define PHB_PCIE_HOTPLUG_STATUS 0x1A20
+#define PHB_PCIE_HPSTAT_SIMDIAG PPC_BIT(3)
+#define PHB_PCIE_HPSTAT_RESAMPLE PPC_BIT(9)
#define PHB_PCIE_HPSTAT_PRESENCE PPC_BIT(10)
+#define PHB_PCIE_HPSTAT_LINKACTIVE PPC_BIT(12)
+#define PHB_PCIE_LMR 0x1A30
+#define PHB_PCIE_LMR_CHANGELW PPC_BIT(0)
+#define PHB_PCIE_LMR_RETRAINLINK PPC_BIT(1)
+#define PHB_PCIE_LMR_LINKACTIVE PPC_BIT(8)
#define PHB_PCIE_DLP_TRAIN_CTL 0x1A40
#define PHB_PCIE_DLP_LINK_WIDTH PPC_BITMASK(30, 35)
@@ -433,7 +443,7 @@
#define PHB_PCIE_DLP_TRWCTL 0x1A80
#define PHB_PCIE_DLP_TRWCTL_EN PPC_BIT(0)
-
+#define PHB_PCIE_DLP_TRWCTL_WREN PPC_BIT(1)
#define PHB_PCIE_DLP_ERRLOG1 0x1AA0
#define PHB_PCIE_DLP_ERRLOG2 0x1AA8
#define PHB_PCIE_DLP_ERR_STATUS 0x1AB0
diff --git a/tests/qtest/pnv-phb4-test.c b/tests/qtest/pnv-phb4-test.c
index f186efaf0d..841306ae3f 100644
--- a/tests/qtest/pnv-phb4-test.c
+++ b/tests/qtest/pnv-phb4-test.c
@@ -73,7 +73,8 @@ static void phb4_sticky_rst_test(QTestState *qts)
* Sticky reset test of PHB_PBL_ERR_STATUS.
*
* Write all 1's to reg PHB_PBL_ERR_INJECT.
- * Updated value will be copied to reg PHB_PBL_ERR_STATUS.
+ * RO-only bits will not be written and
+ * updated value will be copied to reg PHB_PBL_ERR_STATUS.
*
* Reset PBL core by setting PHB_PCIE_CRESET_PBL in reg PHB_PCIE_CRESET.
* Verify the sticky bits are still set.
@@ -81,7 +82,59 @@ static void phb4_sticky_rst_test(QTestState *qts)
phb4_xscom_write(PHB_PBL_ERR_INJECT, PPC_BITMASK(0, 63));
phb4_xscom_write(PHB_PCIE_CRESET, PHB_PCIE_CRESET_PBL); /*Reset*/
val = phb4_xscom_read(PHB_PBL_ERR_STATUS);
- g_assert_cmpuint(val, ==, (PPC_BITMASK(0, 9) | PPC_BITMASK(12, 63)));
+ g_assert_cmpuint(val, ==, 0xF00DFD8E00);
+}
+
+/* Check that write-only bits/regs return 0 when read */
+static void phb4_writeonly_read_test(QTestState *qts)
+{
+ uint64_t val;
+
+ /*
+ * Set all bits of PHB_DMA_SYNC,
+ * bits 0 and 2 are write-only and should be read as 0.
+ */
+ phb4_xscom_write(PHB_DMA_SYNC, PPC_BITMASK(0, 63));
+ val = phb4_xscom_read(PHB_DMA_SYNC);
+ g_assert_cmpuint(val & PPC_BIT(0), ==, 0x0);
+ g_assert_cmpuint(val & PPC_BIT(2), ==, 0x0);
+
+ /*
+ * Set all bits of PHB_PCIE_HOTPLUG_STATUS,
+ * bit 9 is write-only and should be read as 0.
+ */
+ phb4_xscom_write(PHB_PCIE_HOTPLUG_STATUS, PPC_BITMASK(0, 63));
+ val = phb4_xscom_read(PHB_PCIE_HOTPLUG_STATUS);
+ g_assert_cmpuint(val & PPC_BIT(9), ==, 0x0);
+
+ /*
+ * Set all bits of PHB_PCIE_LMR,
+ * bits 0 and 1 are write-only and should be read as 0.
+ */
+ phb4_xscom_write(PHB_PCIE_LMR, PPC_BITMASK(0, 63));
+ val = phb4_xscom_read(PHB_PCIE_LMR);
+ g_assert_cmpuint(val & PPC_BIT(0), ==, 0x0);
+ g_assert_cmpuint(val & PPC_BIT(1), ==, 0x0);
+
+ /*
+ * Set all bits of PHB_PCIE_DLP_TRWCTL,
+ * write-only bit-1 should be read as 0.
+ */
+ phb4_xscom_write(PHB_PCIE_DLP_TRWCTL, PPC_BITMASK(0, 63));
+ val = phb4_xscom_read(PHB_PCIE_DLP_TRWCTL);
+ g_assert_cmpuint(val & PPC_BIT(1), ==, 0x0);
+
+ /*
+ * Set all bits of PHB_LEM_ERROR_AND_MASK, PHB_LEM_ERROR_OR_MASK,
+ * both regs are write-only and should be read as 0.
+ */
+ phb4_xscom_write(PHB_LEM_ERROR_AND_MASK, PPC_BITMASK(0, 63));
+ val = phb4_xscom_read(PHB_LEM_ERROR_AND_MASK);
+ g_assert_cmpuint(val, ==, 0x0);
+
+ phb4_xscom_write(PHB_LEM_ERROR_OR_MASK, PPC_BITMASK(0, 63));
+ val = phb4_xscom_read(PHB_LEM_ERROR_OR_MASK);
+ g_assert_cmpuint(val, ==, 0x0);
}
static void phb4_tests(void)
@@ -96,6 +149,9 @@ static void phb4_tests(void)
/* Check sticky reset of a register */
phb4_sticky_rst_test(qts);
+ /* Check write-only logic */
+ phb4_writeonly_read_test(qts);
+
qtest_quit(qts);
}
--
2.47.3
^ permalink raw reply related [flat|nested] 60+ messages in thread
* [PATCH v2 5/9] pnv/phb4: Implement write-clear and return 1's on unimplemented reg read
2025-12-30 10:21 [PATCH v2 0/9] pnv/phb4: Update PHB4 to the latest PHB5 spec Saif Abrar
` (3 preceding siblings ...)
2025-12-30 10:21 ` [PATCH v2 4/9] pnv/phb4: Implement read-only and write-only bits of registers Saif Abrar
@ 2025-12-30 10:21 ` Saif Abrar
2025-12-30 10:21 ` [PATCH v2 6/9] pnv/phb4: Set link-active status in HPSTAT and LMR registers Saif Abrar
` (4 subsequent siblings)
9 siblings, 0 replies; 60+ messages in thread
From: Saif Abrar @ 2025-12-30 10:21 UTC (permalink / raw)
To: qemu-ppc, qemu-devel
Cc: clg, npiggin, fbarrat, mst, marcel.apfelbaum, cohuck, pbonzini,
thuth, lvivier, danielhb413, saif.abrar
Implement write-1-to-clear and write-X-to-clear logic.
Update registers with silent simple read and write.
Return all 1's when an unimplemented/reserved register is read.
Test that reading address 0x0 returns all 1's (i.e. -1).
Signed-off-by: Saif Abrar <saif.abrar@linux.vnet.ibm.com>
Reviewed-by: Cédric Le Goater <clg@kaod.org>
---
hw/pci-host/pnv_phb4.c | 190 ++++++++++++++++++++++------
include/hw/pci-host/pnv_phb4_regs.h | 11 +-
tests/qtest/pnv-phb4-test.c | 9 ++
3 files changed, 169 insertions(+), 41 deletions(-)
diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c
index 48caba9e79..5f260b0b20 100644
--- a/hw/pci-host/pnv_phb4.c
+++ b/hw/pci-host/pnv_phb4.c
@@ -655,8 +655,41 @@ static void pnv_phb4_reg_write(void *opaque, hwaddr off, uint64_t val,
return;
}
- /* Handle masking */
+ /* Handle RO, W1C, WxC and masking */
switch (off) {
+ /* W1C: Write-1-to-Clear registers */
+ case PHB_TXE_ERR_STATUS:
+ case PHB_RXE_ARB_ERR_STATUS:
+ case PHB_RXE_MRG_ERR_STATUS:
+ case PHB_RXE_TCE_ERR_STATUS:
+ case PHB_ERR_STATUS:
+ case PHB_REGB_ERR_STATUS:
+ case PHB_PCIE_DLP_ERRLOG1:
+ case PHB_PCIE_DLP_ERRLOG2:
+ case PHB_PCIE_DLP_ERR_STATUS:
+ case PHB_PBL_ERR_STATUS:
+ phb->regs[off >> 3] &= ~val;
+ return;
+
+ /* WxC: Clear register on any write */
+ case PHB_PBL_ERR1_STATUS:
+ case PHB_PBL_ERR_LOG_0 ... PHB_PBL_ERR_LOG_1:
+ case PHB_REGB_ERR1_STATUS:
+ case PHB_REGB_ERR_LOG_0 ... PHB_REGB_ERR_LOG_1:
+ case PHB_TXE_ERR1_STATUS:
+ case PHB_TXE_ERR_LOG_0 ... PHB_TXE_ERR_LOG_1:
+ case PHB_RXE_ARB_ERR1_STATUS:
+ case PHB_RXE_ARB_ERR_LOG_0 ... PHB_RXE_ARB_ERR_LOG_1:
+ case PHB_RXE_MRG_ERR1_STATUS:
+ case PHB_RXE_MRG_ERR_LOG_0 ... PHB_RXE_MRG_ERR_LOG_1:
+ case PHB_RXE_TCE_ERR1_STATUS:
+ case PHB_RXE_TCE_ERR_LOG_0 ... PHB_RXE_TCE_ERR_LOG_1:
+ case PHB_ERR1_STATUS:
+ case PHB_ERR_LOG_0 ... PHB_ERR_LOG_1:
+ phb->regs[off >> 3] = 0;
+ return;
+
+ /* Write value updated by masks */
case PHB_LSI_SOURCE_ID:
val &= PHB_LSI_SRC_ID;
break;
@@ -695,7 +728,6 @@ static void pnv_phb4_reg_write(void *opaque, hwaddr off, uint64_t val,
case PHB_LEM_WOF:
val = 0;
break;
- /* TODO: More regs ..., maybe create a table with masks... */
/* Read only registers */
case PHB_CPU_LOADSTORE_STATUS:
@@ -704,6 +736,12 @@ static void pnv_phb4_reg_write(void *opaque, hwaddr off, uint64_t val,
case PHB_PHB4_TCE_CAP:
case PHB_PHB4_IRQ_CAP:
case PHB_PHB4_EEH_CAP:
+ case PHB_VERSION:
+ case PHB_DMA_CHAN_STATUS:
+ case PHB_TCE_TAG_STATUS:
+ case PHB_PBL_BUF_STATUS:
+ case PHB_PCIE_BNR:
+ case PHB_PCIE_PHY_RXEQ_STAT_G3_00_03 ... PHB_PCIE_PHY_RXEQ_STAT_G5_12_15:
return;
}
@@ -725,6 +763,7 @@ static void pnv_phb4_reg_write(void *opaque, hwaddr off, uint64_t val,
pnv_phb4_update_all_msi_regions(phb);
}
break;
+
case PHB_M32_START_ADDR:
case PHB_M64_UPPER_BITS:
if (changed) {
@@ -771,27 +810,63 @@ static void pnv_phb4_reg_write(void *opaque, hwaddr off, uint64_t val,
break;
/* Silent simple writes */
- case PHB_ASN_CMPM:
- case PHB_CONFIG_ADDRESS:
- case PHB_IODA_ADDR:
- case PHB_TCE_KILL:
- case PHB_TCE_SPEC_CTL:
- case PHB_PEST_BAR:
- case PHB_PELTV_BAR:
+ /* PHB Fundamental register set A */
+ case PHB_CONFIG_DATA ... PHB_LOCK1:
case PHB_RTT_BAR:
- case PHB_LEM_FIR_ACCUM:
- case PHB_LEM_ERROR_MASK:
- case PHB_LEM_ACTION0:
- case PHB_LEM_ACTION1:
- case PHB_TCE_TAG_ENABLE:
+ case PHB_PELTV_BAR:
+ case PHB_PEST_BAR:
+ case PHB_CAPI_CMPM ... PHB_M64_AOMASK:
+ case PHB_NXLATE_PREFIX ... PHB_DMA_SYNC:
+ case PHB_TCE_KILL ... PHB_IODA_ADDR:
+ case PHB_PAPR_ERR_INJ_CTL ... PHB_PAPR_ERR_INJ_MASK:
case PHB_INT_NOTIFY_ADDR:
case PHB_INT_NOTIFY_INDEX:
- case PHB_DMA_SYNC:
- break;
+ /* Fundamental register set B */
+ case PHB_AIB_FENCE_CTRL ... PHB_Q_DMA_R:
+ /* FIR & Error registers */
+ case PHB_LEM_FIR_ACCUM:
+ case PHB_LEM_ERROR_MASK:
+ case PHB_LEM_ACTION0 ... PHB_LEM_WOF:
+ case PHB_ERR_INJECT ... PHB_ERR_AIB_FENCE_ENABLE:
+ case PHB_ERR_STATUS_MASK ... PHB_ERR1_STATUS_MASK:
+ case PHB_TXE_ERR_INJECT ... PHB_TXE_ERR_AIB_FENCE_ENABLE:
+ case PHB_TXE_ERR_STATUS_MASK ... PHB_TXE_ERR1_STATUS_MASK:
+ case PHB_RXE_ARB_ERR_INJECT ... PHB_RXE_ARB_ERR_AIB_FENCE_ENABLE:
+ case PHB_RXE_ARB_ERR_STATUS_MASK ... PHB_RXE_ARB_ERR1_STATUS_MASK:
+ case PHB_RXE_MRG_ERR_INJECT ... PHB_RXE_MRG_ERR_AIB_FENCE_ENABLE:
+ case PHB_RXE_MRG_ERR_STATUS_MASK ... PHB_RXE_MRG_ERR1_STATUS_MASK:
+ case PHB_RXE_TCE_ERR_INJECT ... PHB_RXE_TCE_ERR_AIB_FENCE_ENABLE:
+ case PHB_RXE_TCE_ERR_STATUS_MASK ... PHB_RXE_TCE_ERR1_STATUS_MASK:
+ /* Performance monitor & Debug registers */
+ case PHB_TRACE_CONTROL ... PHB_PERFMON_CTR1:
+ /* REGB Registers */
+ /* PBL core */
+ case PHB_PBL_CONTROL:
+ case PHB_PBL_TIMEOUT_CTRL:
+ case PHB_PBL_NPTAG_ENABLE:
+ case PHB_PBL_SYS_LINK_INIT:
+ case PHB_PBL_ERR_INF_ENABLE ... PHB_PBL_ERR_FAT_ENABLE:
+ case PHB_PBL_ERR_STATUS_MASK ... PHB_PBL_ERR1_STATUS_MASK:
+ /* PCI-E stack */
+ case PHB_PCIE_SCR:
+ case PHB_PCIE_DLP_STR ... PHB_PCIE_HOTPLUG_STATUS:
+ case PHB_PCIE_LMR ... PHB_PCIE_DLP_LSR:
+ case PHB_PCIE_DLP_RXMGN:
+ case PHB_PCIE_DLP_LANEZEROCTL ... PHB_PCIE_DLP_TRCRDDATA:
+ case PHB_PCIE_DLP_ERR_COUNTERS:
+ case PHB_PCIE_DLP_EIC ... PHB_PCIE_LANE_EQ_CNTL23:
+ case PHB_PCIE_TRACE_CTRL:
+ case PHB_PCIE_MISC_STRAP ... PHB_PCIE_PHY_EQ_CTL:
+ /* Error registers */
+ case PHB_REGB_ERR_INJECT:
+ case PHB_REGB_ERR_INF_ENABLE ... PHB_REGB_ERR_FAT_ENABLE:
+ case PHB_REGB_ERR_STATUS_MASK ... PHB_REGB_ERR1_STATUS_MASK:
+ break;
/* Noise on anything else */
default:
- qemu_log_mask(LOG_UNIMP, "phb4: reg_write 0x%"PRIx64"=%"PRIx64"\n",
+ qemu_log_mask(LOG_UNIMP,
+ "phb4: unimplemented reg_write 0x%"PRIx64"=%"PRIx64"\n",
off, val);
}
}
@@ -879,36 +954,75 @@ static uint64_t pnv_phb4_reg_read(void *opaque, hwaddr off, unsigned size)
return val;
/* Silent simple reads */
+ /* PHB Fundamental register set A */
case PHB_LSI_SOURCE_ID:
+ case PHB_DMA_CHAN_STATUS:
case PHB_CPU_LOADSTORE_STATUS:
- case PHB_ASN_CMPM:
+ case PHB_CONFIG_DATA ... PHB_LOCK1:
case PHB_PHB4_CONFIG:
+ case PHB_RTT_BAR:
+ case PHB_PELTV_BAR:
case PHB_M32_START_ADDR:
- case PHB_CONFIG_ADDRESS:
- case PHB_IODA_ADDR:
- case PHB_RTC_INVALIDATE:
- case PHB_TCE_KILL:
- case PHB_TCE_SPEC_CTL:
case PHB_PEST_BAR:
- case PHB_PELTV_BAR:
- case PHB_RTT_BAR:
+ case PHB_CAPI_CMPM:
+ case PHB_M64_AOMASK:
case PHB_M64_UPPER_BITS:
- case PHB_CTRLR:
- case PHB_LEM_FIR_ACCUM:
- case PHB_LEM_ERROR_MASK:
- case PHB_LEM_ACTION0:
- case PHB_LEM_ACTION1:
- case PHB_TCE_TAG_ENABLE:
+ case PHB_NXLATE_PREFIX:
+ case PHB_RTC_INVALIDATE ... PHB_IODA_ADDR:
+ case PHB_PAPR_ERR_INJ_CTL ... PHB_ETU_ERR_SUMMARY:
case PHB_INT_NOTIFY_ADDR:
case PHB_INT_NOTIFY_INDEX:
- case PHB_Q_DMA_R:
- case PHB_ETU_ERR_SUMMARY:
- break;
-
- /* Noise on anything else */
+ /* Fundamental register set B */
+ case PHB_CTRLR:
+ case PHB_AIB_FENCE_CTRL ... PHB_Q_DMA_R:
+ case PHB_TCE_TAG_STATUS:
+ /* FIR & Error registers */
+ case PHB_LEM_FIR_ACCUM ... PHB_LEM_ERROR_MASK:
+ case PHB_LEM_ACTION0 ... PHB_LEM_WOF:
+ case PHB_ERR_STATUS ... PHB_ERR_AIB_FENCE_ENABLE:
+ case PHB_ERR_LOG_0 ... PHB_ERR1_STATUS_MASK:
+ case PHB_TXE_ERR_STATUS ... PHB_TXE_ERR_AIB_FENCE_ENABLE:
+ case PHB_TXE_ERR_LOG_0 ... PHB_TXE_ERR1_STATUS_MASK:
+ case PHB_RXE_ARB_ERR_STATUS ... PHB_RXE_ARB_ERR_AIB_FENCE_ENABLE:
+ case PHB_RXE_ARB_ERR_LOG_0 ... PHB_RXE_ARB_ERR1_STATUS_MASK:
+ case PHB_RXE_MRG_ERR_STATUS ... PHB_RXE_MRG_ERR_AIB_FENCE_ENABLE:
+ case PHB_RXE_MRG_ERR_LOG_0 ... PHB_RXE_MRG_ERR1_STATUS_MASK:
+ case PHB_RXE_TCE_ERR_STATUS ... PHB_RXE_TCE_ERR_AIB_FENCE_ENABLE:
+ case PHB_RXE_TCE_ERR_LOG_0 ... PHB_RXE_TCE_ERR1_STATUS_MASK:
+ /* Performance monitor & Debug registers */
+ case PHB_TRACE_CONTROL ... PHB_PERFMON_CTR1:
+ /* REGB Registers */
+ /* PBL core */
+ case PHB_PBL_CONTROL:
+ case PHB_PBL_TIMEOUT_CTRL:
+ case PHB_PBL_NPTAG_ENABLE:
+ case PHB_PBL_SYS_LINK_INIT:
+ case PHB_PBL_BUF_STATUS:
+ case PHB_PBL_ERR_STATUS ... PHB_PBL_ERR_INJECT:
+ case PHB_PBL_ERR_INF_ENABLE ... PHB_PBL_ERR_FAT_ENABLE:
+ case PHB_PBL_ERR_LOG_0 ... PHB_PBL_ERR1_STATUS_MASK:
+ /* PCI-E stack */
+ case PHB_PCIE_BNR ... PHB_PCIE_DLP_STR:
+ case PHB_PCIE_DLP_LANE_PWR:
+ case PHB_PCIE_DLP_LSR:
+ case PHB_PCIE_DLP_RXMGN:
+ case PHB_PCIE_DLP_LANEZEROCTL ... PHB_PCIE_DLP_CTL:
+ case PHB_PCIE_DLP_TRCRDDATA:
+ case PHB_PCIE_DLP_ERRLOG1 ... PHB_PCIE_DLP_ERR_COUNTERS:
+ case PHB_PCIE_DLP_EIC ... PHB_PCIE_LANE_EQ_CNTL23:
+ case PHB_PCIE_TRACE_CTRL:
+ case PHB_PCIE_MISC_STRAP ... PHB_PCIE_PHY_RXEQ_STAT_G5_12_15:
+ /* Error registers */
+ case PHB_REGB_ERR_STATUS ... PHB_REGB_ERR_INJECT:
+ case PHB_REGB_ERR_INF_ENABLE ... PHB_REGB_ERR_FAT_ENABLE:
+ case PHB_REGB_ERR_LOG_0 ... PHB_REGB_ERR1_STATUS_MASK:
+ break;
+
+ /* Noise on unimplemented read, return all 1's */
default:
- qemu_log_mask(LOG_UNIMP, "phb4: reg_read 0x%"PRIx64"=%"PRIx64"\n",
- off, val);
+ qemu_log_mask(LOG_UNIMP, "phb4: unimplemented reg_read 0x%"PRIx64"\n",
+ off);
+ val = ~0ull;
}
return val;
}
diff --git a/include/hw/pci-host/pnv_phb4_regs.h b/include/hw/pci-host/pnv_phb4_regs.h
index dfd0e01d1e..c1d5a83271 100644
--- a/include/hw/pci-host/pnv_phb4_regs.h
+++ b/include/hw/pci-host/pnv_phb4_regs.h
@@ -407,6 +407,7 @@
#define PHB_PCIE_CRESET_PERST_N PPC_BIT(3)
#define PHB_PCIE_CRESET_PIPE_N PPC_BIT(4)
#define PHB_PCIE_CRESET_REFCLK_N PPC_BIT(8)
+#define PHB_PCIE_DLP_STR 0x1A18
#define PHB_PCIE_HOTPLUG_STATUS 0x1A20
#define PHB_PCIE_HPSTAT_SIMDIAG PPC_BIT(3)
#define PHB_PCIE_HPSTAT_RESAMPLE PPC_BIT(9)
@@ -417,6 +418,7 @@
#define PHB_PCIE_LMR_RETRAINLINK PPC_BIT(1)
#define PHB_PCIE_LMR_LINKACTIVE PPC_BIT(8)
+#define PHB_PCIE_DLP_LANE_PWR 0x1A38
#define PHB_PCIE_DLP_TRAIN_CTL 0x1A40
#define PHB_PCIE_DLP_LINK_WIDTH PPC_BITMASK(30, 35)
#define PHB_PCIE_DLP_LINK_SPEED PPC_BITMASK(36, 39)
@@ -436,18 +438,21 @@
#define PHB_PCIE_DLP_DL_PGRESET PPC_BIT(22)
#define PHB_PCIE_DLP_TRAINING PPC_BIT(20)
#define PHB_PCIE_DLP_INBAND_PRESENCE PPC_BIT(19)
-
+#define PHB_PCIE_DLP_LSR 0x1A48
+#define PHB_PCIE_DLP_RXMGN 0x1A50
+#define PHB_PCIE_DLP_LANEZEROCTL 0x1A70
#define PHB_PCIE_DLP_CTL 0x1A78
#define PHB_PCIE_DLP_CTL_BYPASS_PH2 PPC_BIT(4)
#define PHB_PCIE_DLP_CTL_BYPASS_PH3 PPC_BIT(5)
-
#define PHB_PCIE_DLP_TRWCTL 0x1A80
#define PHB_PCIE_DLP_TRWCTL_EN PPC_BIT(0)
#define PHB_PCIE_DLP_TRWCTL_WREN PPC_BIT(1)
+#define PHB_PCIE_DLP_TRCRDDATA 0x1A88
#define PHB_PCIE_DLP_ERRLOG1 0x1AA0
#define PHB_PCIE_DLP_ERRLOG2 0x1AA8
#define PHB_PCIE_DLP_ERR_STATUS 0x1AB0
#define PHB_PCIE_DLP_ERR_COUNTERS 0x1AB8
+#define PHB_PCIE_DLP_EIC 0x1AC8
#define PHB_PCIE_LANE_EQ_CNTL0 0x1AD0
#define PHB_PCIE_LANE_EQ_CNTL1 0x1AD8
@@ -459,6 +464,7 @@
#define PHB_PCIE_LANE_EQ_CNTL23 0x1B08 /* DD1 only */
#define PHB_PCIE_TRACE_CTRL 0x1B20
#define PHB_PCIE_MISC_STRAP 0x1B30
+#define PHB_PCIE_PHY_EQ_CTL 0x1B38
#define PHB_PCIE_PHY_RXEQ_STAT_G3_00_03 0x1B40
#define PHB_PCIE_PHY_RXEQ_STAT_G5_12_15 0x1B98
@@ -592,5 +598,4 @@
#define IODA3_PEST1_FAIL_ADDR PPC_BITMASK(3, 63)
-
#endif /* PCI_HOST_PNV_PHB4_REGS_H */
diff --git a/tests/qtest/pnv-phb4-test.c b/tests/qtest/pnv-phb4-test.c
index 841306ae3f..fbbd1ae8e4 100644
--- a/tests/qtest/pnv-phb4-test.c
+++ b/tests/qtest/pnv-phb4-test.c
@@ -137,6 +137,12 @@ static void phb4_writeonly_read_test(QTestState *qts)
g_assert_cmpuint(val, ==, 0x0);
}
+/* Check that reading an unimplemented address 0x0 returns -1 */
+static void phb4_unimplemented_read_test(QTestState *qts)
+{
+ g_assert_cmpint(phb4_xscom_read(0x0), ==, -1);
+}
+
static void phb4_tests(void)
{
QTestState *qts = NULL;
@@ -152,6 +158,9 @@ static void phb4_tests(void)
/* Check write-only logic */
phb4_writeonly_read_test(qts);
+ /* Check unimplemented register read */
+ phb4_unimplemented_read_test(qts);
+
qtest_quit(qts);
}
--
2.47.3
^ permalink raw reply related [flat|nested] 60+ messages in thread
* [PATCH v2 6/9] pnv/phb4: Set link-active status in HPSTAT and LMR registers
2025-12-30 10:21 [PATCH v2 0/9] pnv/phb4: Update PHB4 to the latest PHB5 spec Saif Abrar
` (4 preceding siblings ...)
2025-12-30 10:21 ` [PATCH v2 5/9] pnv/phb4: Implement write-clear and return 1's on unimplemented reg read Saif Abrar
@ 2025-12-30 10:21 ` Saif Abrar
2025-12-30 10:21 ` [PATCH v2 7/9] pnv/phb4: Set link speed and width in the DLP training control register Saif Abrar
` (3 subsequent siblings)
9 siblings, 0 replies; 60+ messages in thread
From: Saif Abrar @ 2025-12-30 10:21 UTC (permalink / raw)
To: qemu-ppc, qemu-devel
Cc: clg, npiggin, fbarrat, mst, marcel.apfelbaum, cohuck, pbonzini,
thuth, lvivier, danielhb413, saif.abrar
Config-read the link-status register in the PCI-E macro,
Depending on the link-active bit, set the link-active status
in the HOTPLUG_STATUS and LINK_MANAGEMENT registers
Also, clear the Presence-status active low bit in HOTPLUG_STATUS reg
after config-reading the slot-status in the PCI-E macro.
Signed-off-by: Saif Abrar <saif.abrar@linux.vnet.ibm.com>
---
hw/pci-host/pnv_phb4.c | 60 +++++++++++++++++++++++++++++++++++++++++-
1 file changed, 59 insertions(+), 1 deletion(-)
diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c
index 5f260b0b20..be273c067a 100644
--- a/hw/pci-host/pnv_phb4.c
+++ b/hw/pci-host/pnv_phb4.c
@@ -510,6 +510,20 @@ static uint32_t get_exp_offset(PCIDevice *pdev)
return rpc->exp_offset;
}
+/*
+ * Config-read the link-status register in the PCI-E macro,
+ * convert to LE and check the link-active bit.
+ */
+static uint32_t is_link_active(PnvPHB4 *phb)
+{
+ PCIHostState *pci = PCI_HOST_BRIDGE(phb->phb_base);
+ PCIDevice *pdev = pci_find_device(pci->bus, 0, 0);
+ uint32_t exp_offset = get_exp_offset(pdev);
+
+ return (bswap32(pnv_phb4_rc_config_read(phb, exp_offset + PCI_EXP_LNKSTA, 4)
+ ) & PCI_EXP_LNKSTA_DLLLA);
+}
+
/*
* Apply sticky-mask 's' to the reset-value 'v' and write to the address 'a'.
* RC-config space values and masks are LE.
@@ -729,6 +743,11 @@ static void pnv_phb4_reg_write(void *opaque, hwaddr off, uint64_t val,
val = 0;
break;
+ case PHB_PCIE_HOTPLUG_STATUS:
+ /* For normal operations, Simspeed diagnostic bit is always zero */
+ val &= PHB_PCIE_HPSTAT_SIMDIAG;
+ break;
+
/* Read only registers */
case PHB_CPU_LOADSTORE_STATUS:
case PHB_ETU_ERR_SUMMARY:
@@ -942,8 +961,42 @@ static uint64_t pnv_phb4_reg_read(void *opaque, hwaddr off, unsigned size)
val |= PHB_PCIE_DLP_INBAND_PRESENCE | PHB_PCIE_DLP_TL_LINKACT;
return val;
+ /*
+ * Read PCI-E registers and set status for:
+ * - Card present (active low bit 10)
+ * - Link active (bit 12)
+ */
case PHB_PCIE_HOTPLUG_STATUS:
- /* Clear write-only bit */
+ /*
+ * Presence-status bit hpi_present_n is active-low, with reset value 1.
+ * Start by setting this bit to 1, indicating the card is not present.
+ * Then check the PCI-E register and clear the bit if card is present.
+ */
+ val |= PHB_PCIE_HPSTAT_PRESENCE;
+
+ /* Get the PCI-E capability offset from the root-port */
+ PCIHostState *pci = PCI_HOST_BRIDGE(phb->phb_base);
+ PCIDevice *pdev = pci_find_device(pci->bus, 0, 0);
+ uint32_t exp_base = get_exp_offset(pdev);
+
+ /*
+ * Config-read the PCI-E macro register for slot-status.
+ * Method for config-read converts to BE value.
+ * To check actual bit in the PCI-E register,
+ * convert the value back to LE using bswap32().
+ * Clear the Presence-status active low bit.
+ */
+ if (bswap32(pnv_phb4_rc_config_read(phb, exp_base + PCI_EXP_SLTSTA, 4))
+ & PCI_EXP_SLTSTA_PDS) {
+ val &= ~PHB_PCIE_HPSTAT_PRESENCE;
+ }
+
+ /* Check if link is active and set the bit */
+ if (is_link_active(phb)) {
+ val |= PHB_PCIE_HPSTAT_LINKACTIVE;
+ }
+
+ /* Clear write-only resample-bit */
val &= ~PHB_PCIE_HPSTAT_RESAMPLE;
return val;
@@ -951,6 +1004,11 @@ static uint64_t pnv_phb4_reg_read(void *opaque, hwaddr off, unsigned size)
case PHB_PCIE_LMR:
/* These write-only bits always read as 0 */
val &= ~(PHB_PCIE_LMR_CHANGELW | PHB_PCIE_LMR_RETRAINLINK);
+
+ /* Check if link is active and set the bit */
+ if (is_link_active(phb)) {
+ val |= PHB_PCIE_LMR_LINKACTIVE;
+ }
return val;
/* Silent simple reads */
--
2.47.3
^ permalink raw reply related [flat|nested] 60+ messages in thread
* [PATCH v2 7/9] pnv/phb4: Set link speed and width in the DLP training control register
2025-12-30 10:21 [PATCH v2 0/9] pnv/phb4: Update PHB4 to the latest PHB5 spec Saif Abrar
` (5 preceding siblings ...)
2025-12-30 10:21 ` [PATCH v2 6/9] pnv/phb4: Set link-active status in HPSTAT and LMR registers Saif Abrar
@ 2025-12-30 10:21 ` Saif Abrar
2025-12-30 10:21 ` [PATCH v2 8/9] pnv/phb4: Implement IODA PCT table Saif Abrar
` (2 subsequent siblings)
9 siblings, 0 replies; 60+ messages in thread
From: Saif Abrar @ 2025-12-30 10:21 UTC (permalink / raw)
To: qemu-ppc, qemu-devel
Cc: clg, npiggin, fbarrat, mst, marcel.apfelbaum, cohuck, pbonzini,
thuth, lvivier, danielhb413, saif.abrar
Get the current link-status from PCIE macro.
Extract link-speed and link-width from the link-status
and set in the DLP training control (PCIE_DLP_TCR) register.
Signed-off-by: Saif Abrar <saif.abrar@linux.vnet.ibm.com>
Reviewed-by: Cédric Le Goater <clg@kaod.org>
---
hw/pci-host/pnv_phb4.c | 27 +++++++++++++++++++++++----
1 file changed, 23 insertions(+), 4 deletions(-)
diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c
index be273c067a..ba351bb147 100644
--- a/hw/pci-host/pnv_phb4.c
+++ b/hw/pci-host/pnv_phb4.c
@@ -955,10 +955,29 @@ static uint64_t pnv_phb4_reg_read(void *opaque, hwaddr off, unsigned size)
val |= PHB_PCIE_SCR_PLW_X16; /* RO bit */
break;
- /* Link training always appears trained */
case PHB_PCIE_DLP_TRAIN_CTL:
- /* TODO: Do something sensible with speed ? */
+ /* Link training always appears trained */
val |= PHB_PCIE_DLP_INBAND_PRESENCE | PHB_PCIE_DLP_TL_LINKACT;
+
+ /* Get the current link-status from PCIE */
+ PCIHostState *pci = PCI_HOST_BRIDGE(phb->phb_base);
+ PCIDevice *pdev = pci_find_device(pci->bus, 0, 0);
+ uint32_t exp_offset = get_exp_offset(pdev);
+ uint32_t lnkstatus = bswap32(pnv_phb4_rc_config_read(phb,
+ exp_offset + PCI_EXP_LNKSTA, 4));
+
+ /* Extract link-speed from the link-status */
+ uint32_t v = lnkstatus & PCI_EXP_LNKSTA_CLS;
+ /* Set the current link-speed at the LINK_SPEED position */
+ val = SETFIELD(PHB_PCIE_DLP_LINK_SPEED, val, v);
+
+ /*
+ * Extract link-width from the link-status,
+ * after shifting the required bitfields.
+ */
+ v = (lnkstatus & PCI_EXP_LNKSTA_NLW) >> PCI_EXP_LNKSTA_NLW_SHIFT;
+ /* Set the current link-width at the LINK_WIDTH position */
+ val = SETFIELD(PHB_PCIE_DLP_LINK_WIDTH, val, v);
return val;
/*
@@ -975,8 +994,8 @@ static uint64_t pnv_phb4_reg_read(void *opaque, hwaddr off, unsigned size)
val |= PHB_PCIE_HPSTAT_PRESENCE;
/* Get the PCI-E capability offset from the root-port */
- PCIHostState *pci = PCI_HOST_BRIDGE(phb->phb_base);
- PCIDevice *pdev = pci_find_device(pci->bus, 0, 0);
+ pci = PCI_HOST_BRIDGE(phb->phb_base);
+ pdev = pci_find_device(pci->bus, 0, 0);
uint32_t exp_base = get_exp_offset(pdev);
/*
--
2.47.3
^ permalink raw reply related [flat|nested] 60+ messages in thread
* [PATCH v2 8/9] pnv/phb4: Implement IODA PCT table
2025-12-30 10:21 [PATCH v2 0/9] pnv/phb4: Update PHB4 to the latest PHB5 spec Saif Abrar
` (6 preceding siblings ...)
2025-12-30 10:21 ` [PATCH v2 7/9] pnv/phb4: Set link speed and width in the DLP training control register Saif Abrar
@ 2025-12-30 10:21 ` Saif Abrar
2025-12-30 10:21 ` [PATCH v2 9/9] pnv/phb4: Mask off LSI Source-ID based on number of interrupts Saif Abrar
2026-02-10 13:40 ` [PATCH v3 0/9] : pnv/phb4: Update PHB4 to the latest PHB5 spec Saif Abrar
9 siblings, 0 replies; 60+ messages in thread
From: Saif Abrar @ 2025-12-30 10:21 UTC (permalink / raw)
To: qemu-ppc, qemu-devel
Cc: clg, npiggin, fbarrat, mst, marcel.apfelbaum, cohuck, pbonzini,
thuth, lvivier, danielhb413, saif.abrar
IODA PCT table (#3) is implemented
without any functionality, being a debug table.
Signed-off-by: Saif Abrar <saif.abrar@linux.vnet.ibm.com>
Reviewed-by: Cédric Le Goater <clg@kaod.org>
---
hw/pci-host/pnv_phb4.c | 6 ++++++
include/hw/pci-host/pnv_phb4.h | 2 ++
include/hw/pci-host/pnv_phb4_regs.h | 1 +
3 files changed, 9 insertions(+)
diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c
index ba351bb147..528117f409 100644
--- a/hw/pci-host/pnv_phb4.c
+++ b/hw/pci-host/pnv_phb4.c
@@ -264,6 +264,10 @@ static uint64_t *pnv_phb4_ioda_access(PnvPHB4 *phb,
mask = phb->big_phb ? PNV_PHB4_MAX_MIST : (PNV_PHB4_MAX_MIST >> 1);
mask -= 1;
break;
+ case IODA3_TBL_PCT:
+ tptr = phb->ioda_PCT;
+ mask = 7;
+ break;
case IODA3_TBL_RCAM:
mask = phb->big_phb ? 127 : 63;
break;
@@ -362,6 +366,8 @@ static void pnv_phb4_ioda_write(PnvPHB4 *phb, uint64_t val)
/* Handle side effects */
switch (table) {
case IODA3_TBL_LIST:
+ case IODA3_TBL_PCT:
+ /* No action for debug tables */
break;
case IODA3_TBL_MIST: {
/* Special mask for MIST partial write */
diff --git a/include/hw/pci-host/pnv_phb4.h b/include/hw/pci-host/pnv_phb4.h
index bea0684724..6bb75edeef 100644
--- a/include/hw/pci-host/pnv_phb4.h
+++ b/include/hw/pci-host/pnv_phb4.h
@@ -65,6 +65,7 @@ OBJECT_DECLARE_SIMPLE_TYPE(PnvPHB4RootBus, PNV_PHB4_ROOT_BUS)
#define PNV_PHB4_MAX_LSIs 8
#define PNV_PHB4_MAX_INTs 4096
#define PNV_PHB4_MAX_MIST (PNV_PHB4_MAX_INTs >> 2)
+#define PNV_PHB4_MAX_PCT 128
#define PNV_PHB4_MAX_MMIO_WINDOWS 32
#define PNV_PHB4_MIN_MMIO_WINDOWS 16
#define PNV_PHB4_NUM_REGS (0x3000 >> 3)
@@ -138,6 +139,7 @@ struct PnvPHB4 {
/* On-chip IODA tables */
uint64_t ioda_LIST[PNV_PHB4_MAX_LSIs];
uint64_t ioda_MIST[PNV_PHB4_MAX_MIST];
+ uint64_t ioda_PCT[PNV_PHB4_MAX_PCT];
uint64_t ioda_TVT[PNV_PHB4_MAX_TVEs];
uint64_t ioda_MBT[PNV_PHB4_MAX_MBEs];
uint64_t ioda_MDT[PNV_PHB4_MAX_PEs];
diff --git a/include/hw/pci-host/pnv_phb4_regs.h b/include/hw/pci-host/pnv_phb4_regs.h
index c1d5a83271..e30adff7b2 100644
--- a/include/hw/pci-host/pnv_phb4_regs.h
+++ b/include/hw/pci-host/pnv_phb4_regs.h
@@ -486,6 +486,7 @@
#define IODA3_TBL_LIST 1
#define IODA3_TBL_MIST 2
+#define IODA3_TBL_PCT 3
#define IODA3_TBL_RCAM 5
#define IODA3_TBL_MRT 6
#define IODA3_TBL_PESTA 7
--
2.47.3
^ permalink raw reply related [flat|nested] 60+ messages in thread
* [PATCH v2 9/9] pnv/phb4: Mask off LSI Source-ID based on number of interrupts
2025-12-30 10:21 [PATCH v2 0/9] pnv/phb4: Update PHB4 to the latest PHB5 spec Saif Abrar
` (7 preceding siblings ...)
2025-12-30 10:21 ` [PATCH v2 8/9] pnv/phb4: Implement IODA PCT table Saif Abrar
@ 2025-12-30 10:21 ` Saif Abrar
2026-02-10 13:40 ` [PATCH v3 0/9] : pnv/phb4: Update PHB4 to the latest PHB5 spec Saif Abrar
9 siblings, 0 replies; 60+ messages in thread
From: Saif Abrar @ 2025-12-30 10:21 UTC (permalink / raw)
To: qemu-ppc, qemu-devel
Cc: clg, npiggin, fbarrat, mst, marcel.apfelbaum, cohuck, pbonzini,
thuth, lvivier, danielhb413, saif.abrar
Add a method to reset the value of LSI Source-ID.
Mask off LSI source-id based on number of interrupts in the big/small PHB.
Signed-off-by: Saif Abrar <saif.abrar@linux.vnet.ibm.com>
Reviewed-by: Cédric Le Goater <clg@kaod.org>
---
v1 -> v2: Introduced method pnv_phb4_xsrc_reset().
hw/pci-host/pnv_phb4.c | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c
index 528117f409..ad8047cdfb 100644
--- a/hw/pci-host/pnv_phb4.c
+++ b/hw/pci-host/pnv_phb4.c
@@ -490,6 +490,7 @@ static void pnv_phb4_update_xsrc(PnvPHB4 *phb)
lsi_base = GETFIELD(PHB_LSI_SRC_ID, phb->regs[PHB_LSI_SOURCE_ID >> 3]);
lsi_base <<= 3;
+ lsi_base &= (xsrc->nr_irqs - 1);
/* TODO: handle reset values of PHB_LSI_SRC_ID */
if (!lsi_base) {
@@ -1944,6 +1945,12 @@ static void pnv_phb4_ro_mask_init(PnvPHB4 *phb)
/* TODO: Add more RO-masks as regs are implemented in the model */
}
+static void pnv_phb4_xsrc_reset(PnvPHB4 *phb)
+{
+ phb->regs[PHB_LSI_SOURCE_ID >> 3] = PPC_BITMASK(4, 12);
+ pnv_phb4_update_xsrc(phb);
+}
+
static void pnv_phb4_err_reg_reset(PnvPHB4 *phb)
{
STICKY_RST(PHB_ERR_STATUS, 0, PPC_BITMASK(0, 33));
@@ -1999,10 +2006,11 @@ static void pnv_phb4_reset(Object *obj, ResetType type)
{
PnvPHB4 *phb = PNV_PHB4(obj);
pnv_phb4_pbl_core_reset(phb);
+
+ pnv_phb4_xsrc_reset(phb);
pnv_phb4_err_reg_reset(phb);
pnv_phb4_pcie_stack_reg_reset(phb);
pnv_phb4_regb_err_reg_reset(phb);
- phb->regs[PHB_PCIE_CRESET >> 3] = 0xE000000000000000;
}
static void pnv_phb4_instance_init(Object *obj)
@@ -2079,8 +2087,6 @@ static void pnv_phb4_realize(DeviceState *dev, Error **errp)
return;
}
- pnv_phb4_update_xsrc(phb);
-
phb->qirqs = qemu_allocate_irqs(xive_source_set_irq, xsrc, xsrc->nr_irqs);
pnv_phb4_xscom_realize(phb);
--
2.47.3
^ permalink raw reply related [flat|nested] 60+ messages in thread
* Re: [PATCH v2 2/9] pnv/phb4: Add reset logic to PHB4
2025-12-30 10:21 ` [PATCH v2 2/9] pnv/phb4: Add reset logic to PHB4 Saif Abrar
@ 2025-12-30 12:04 ` Michael S. Tsirkin
0 siblings, 0 replies; 60+ messages in thread
From: Michael S. Tsirkin @ 2025-12-30 12:04 UTC (permalink / raw)
To: Saif Abrar
Cc: qemu-ppc, qemu-devel, clg, npiggin, fbarrat, marcel.apfelbaum,
cohuck, pbonzini, thuth, lvivier, danielhb413
On Tue, Dec 30, 2025 at 04:21:20AM -0600, Saif Abrar wrote:
> Add a method to be invoked on QEMU reset.
> Also add CFG and PBL core-blocks reset logic using
> appropriate bits of PHB_PCIE_CRESET register.
>
> Tested by reading the reset value of a register.
>
> Signed-off-by: Saif Abrar <saif.abrar@linux.vnet.ibm.com>
> Reviewed-by: Cédric Le Goater <clg@kaod.org>
> ---
> v1 -> v2:
> - Using the ResettableClass.
> - Reset of the root complex registers done in pnv_phb_root_port_reset_hold().
>
> hw/pci-host/pnv_phb.c | 1 +
> hw/pci-host/pnv_phb4.c | 101 +++++++++++++++++++++++++++-
> include/hw/pci-host/pnv_phb4.h | 1 +
> include/hw/pci-host/pnv_phb4_regs.h | 16 ++++-
> tests/qtest/pnv-phb4-test.c | 28 +++++++-
> 5 files changed, 143 insertions(+), 4 deletions(-)
>
> diff --git a/hw/pci-host/pnv_phb.c b/hw/pci-host/pnv_phb.c
> index 85fcc3b686..bc08d7488d 100644
> --- a/hw/pci-host/pnv_phb.c
> +++ b/hw/pci-host/pnv_phb.c
> @@ -233,6 +233,7 @@ static void pnv_phb_root_port_reset_hold(Object *obj, ResetType type)
> pci_set_long(conf + PCI_PREF_BASE_UPPER32, 0x1); /* Hack */
> pci_set_long(conf + PCI_PREF_LIMIT_UPPER32, 0xffffffff);
> pci_config_set_interrupt_pin(conf, 0);
> + pnv_phb4_cfg_core_reset(d);
> }
>
> static void pnv_phb_root_port_realize(DeviceState *dev, Error **errp)
> diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c
> index 396bc47817..bf21f955c8 100644
> --- a/hw/pci-host/pnv_phb4.c
> +++ b/hw/pci-host/pnv_phb4.c
> @@ -1,7 +1,8 @@
> /*
> * QEMU PowerPC PowerNV (POWER9) PHB4 model
> + * QEMU PowerPC PowerNV (POWER10) PHB5 model
> *
> - * Copyright (c) 2018-2020, IBM Corporation.
> + * Copyright (c) 2018-2025, IBM Corporation.
> *
> * This code is licensed under the GPL version 2 or later. See the
> * COPYING file in the top-level directory.
> @@ -22,6 +23,7 @@
> #include "hw/core/qdev-properties.h"
> #include "qom/object.h"
> #include "trace.h"
> +#include "system/reset.h"
>
> #define phb_error(phb, fmt, ...) \
> qemu_log_mask(LOG_GUEST_ERROR, "phb4[%d:%d]: " fmt "\n", \
> @@ -499,6 +501,81 @@ static void pnv_phb4_update_xsrc(PnvPHB4 *phb)
> }
> }
>
> +/*
> + * Get the PCI-E capability offset from the root-port
> + */
> +static uint32_t get_exp_offset(PCIDevice *pdev)
> +{
> + PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(pdev);
> + return rpc->exp_offset;
> +}
> +
> +void pnv_phb4_cfg_core_reset(PCIDevice *d)
> +{
> + uint8_t *conf = d->config;
add an empty line here after declaration.
> + pci_set_word(conf + PCI_COMMAND, PCI_COMMAND_SERR);
> + pci_set_word(conf + PCI_STATUS, PCI_STATUS_CAP_LIST);
> + pci_set_long(conf + PCI_CLASS_REVISION, 0x06040000);
> + pci_set_long(conf + PCI_CACHE_LINE_SIZE, BIT(16));
> + pci_set_word(conf + PCI_MEMORY_BASE, BIT(4));
> + pci_set_word(conf + PCI_PREF_MEMORY_BASE, BIT(0) | BIT(4));
> + pci_set_word(conf + PCI_PREF_MEMORY_LIMIT, PCI_PREF_RANGE_TYPE_64);
> + pci_set_long(conf + PCI_CAPABILITY_LIST, BIT(6));
> + pci_set_long(conf + PCI_CAPABILITY_LIST, BIT(6));
> + pci_set_word(conf + PCI_BRIDGE_CONTROL, PCI_BRIDGE_CTL_SERR);
> + pci_set_long(conf + PCI_BRIDGE_CONTROL + PCI_PM_PMC, 0xC8034801);
> +
> + uint32_t exp_offset = get_exp_offset(d);
> + pci_set_long(conf + exp_offset, 0x420010);
> + pci_set_long(conf + exp_offset + PCI_EXP_DEVCAP, 0x8022);
> + pci_set_long(conf + exp_offset + PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_EXT_TAG
> + | PCI_EXP_DEVCTL_PAYLOAD_512B);
> + pci_set_long(conf + exp_offset + PCI_EXP_LNKCAP, PCI_EXP_LNKCAP_LBNC
> + | PCI_EXP_LNKCAP_DLLLARC | BIT(8) | PCI_EXP_LNKCAP_SLS_32_0GB);
> + pci_set_word(conf + exp_offset + PCI_EXP_LNKCTL, PCI_EXP_LNKCTL_RCB);
> + pci_set_word(conf + exp_offset + PCI_EXP_LNKSTA,
> + (PCI_EXP_LNKSTA_NLW_X8 << 2) | PCI_EXP_LNKSTA_CLS_2_5GB);
> + pci_set_long(conf + exp_offset + PCI_EXP_SLTCTL,
> + PCI_EXP_SLTCTL_ASPL_DISABLE);
> + pci_set_long(conf + exp_offset + PCI_EXP_DEVCAP2, BIT(16)
> + | PCI_EXP_DEVCAP2_ARI | PCI_EXP_DEVCAP2_COMP_TMOUT_DIS | 0xF);
> + pci_set_long(conf + exp_offset + PCI_EXP_DEVCTL2, PCI_EXP_DEVCTL2_ARI);
> + pci_set_long(conf + exp_offset + PCI_EXP_LNKCAP2, BIT(23)
> + | PCI_EXP_LNKCAP2_SLS_32_0GB
> + | PCI_EXP_LNKCAP2_SLS_16_0GB | PCI_EXP_LNKCAP2_SLS_8_0GB
> + | PCI_EXP_LNKCAP2_SLS_5_0GB | PCI_EXP_LNKCAP2_SLS_2_5GB);
> + pci_set_long(conf + PHB_AER_ECAP, PCI_EXT_CAP(0x1, 0x1, 0x148));
> + pci_set_long(conf + PHB_SEC_ECAP, (0x1A0 << 20) | BIT(16)
> + | PCI_EXT_CAP_ID_SECPCI);
> + pci_set_long(conf + PHB_LMR_ECAP, 0x1E810027);
> + /* LMR - Margining Lane Control / Status Register # 2 to 16 */
> + int i;
declare at the beginning of the block please.
and add an empty line here after declaration.
Or, declare inside the for loop.
> + for (i = PHB_LMR_CTLSTA_2 ; i <= PHB_LMR_CTLSTA_16 ; i += 4) {
> + pci_set_long(conf + i, 0x9C38);
> + }
> +
> + pci_set_long(conf + PHB_DLF_ECAP, 0x1F410025);
> + pci_set_long(conf + PHB_DLF_CAP, 0x80000001);
> + pci_set_long(conf + P16_ECAP, 0x22410026);
> + pci_set_long(conf + P32_ECAP, 0x1002A);
> + pci_set_long(conf + P32_CAP, 0x103);
> +}
> +
> +static void pnv_phb4_pbl_core_reset(PnvPHB4 *phb)
> +{
> + /* Zero all registers initially */
> + int i;
an empty line here after declaration.
Or, declare inside the for loop.
> + for (i = PHB_PBL_CONTROL ; i <= PHB_PBL_ERR1_STATUS_MASK ; i += 8) {
> + phb->regs[i >> 3] = 0x0;
> + }
> +
> + /* Set specific register values */
> + phb->regs[PHB_PBL_CONTROL >> 3] = 0xC009000000000000;
> + phb->regs[PHB_PBL_TIMEOUT_CTRL >> 3] = 0x2020000000000000;
> + phb->regs[PHB_PBL_NPTAG_ENABLE >> 3] = 0xFFFFFFFF00000000;
> + phb->regs[PHB_PBL_SYS_LINK_INIT >> 3] = 0x80088B4642473000;
> +}
> +
> static void pnv_phb4_reg_write(void *opaque, hwaddr off, uint64_t val,
> unsigned size)
> {
> @@ -612,6 +689,17 @@ static void pnv_phb4_reg_write(void *opaque, hwaddr off, uint64_t val,
> pnv_phb4_update_xsrc(phb);
> break;
>
> + /* Reset core blocks */
> + case PHB_PCIE_CRESET:
> + if (val & PHB_PCIE_CRESET_CFG_CORE) {
> + PCIHostState *pci = PCI_HOST_BRIDGE(phb->phb_base);
an empty line here after declaration.
> + pnv_phb4_cfg_core_reset(pci_find_device(pci->bus, 0, 0));
> + }
> + if (val & PHB_PCIE_CRESET_PBL) {
> + pnv_phb4_pbl_core_reset(phb);
> + }
> + break;
> +
> /* Silent simple writes */
> case PHB_ASN_CMPM:
> case PHB_CONFIG_ADDRESS:
> @@ -1532,6 +1620,12 @@ static PCIIOMMUOps pnv_phb4_iommu_ops = {
> .get_address_space = pnv_phb4_dma_iommu,
> };
>
> +static void pnv_phb4_reset(Object *obj, ResetType type)
> +{
> + PnvPHB4 *phb = PNV_PHB4(obj);
en emoty line here after declaration
> + pnv_phb4_pbl_core_reset(phb);
> +}
> +
> static void pnv_phb4_instance_init(Object *obj)
> {
> PnvPHB4 *phb = PNV_PHB4(obj);
> @@ -1608,6 +1702,8 @@ static void pnv_phb4_realize(DeviceState *dev, Error **errp)
> phb->qirqs = qemu_allocate_irqs(xive_source_set_irq, xsrc, xsrc->nr_irqs);
>
> pnv_phb4_xscom_realize(phb);
> +
> + qemu_register_resettable(OBJECT(dev));
> }
>
> /*
> @@ -1707,6 +1803,9 @@ static void pnv_phb4_class_init(ObjectClass *klass, const void *data)
> dc->user_creatable = false;
>
> xfc->notify = pnv_phb4_xive_notify;
> +
> + ResettableClass *rc = RESETTABLE_CLASS(klass);
declarations at the beginning of the block please.
> + rc->phases.enter = pnv_phb4_reset;
> }
>
> static const TypeInfo pnv_phb4_type_info = {
> diff --git a/include/hw/pci-host/pnv_phb4.h b/include/hw/pci-host/pnv_phb4.h
> index de996e718b..47a5c3edf5 100644
> --- a/include/hw/pci-host/pnv_phb4.h
> +++ b/include/hw/pci-host/pnv_phb4.h
> @@ -160,6 +160,7 @@ void pnv_phb4_pic_print_info(PnvPHB4 *phb, GString *buf);
> int pnv_phb4_pec_get_phb_id(PnvPhb4PecState *pec, int stack_index);
> PnvPhb4PecState *pnv_pec_add_phb(PnvChip *chip, PnvPHB *phb, Error **errp);
> void pnv_phb4_bus_init(DeviceState *dev, PnvPHB4 *phb);
> +void pnv_phb4_cfg_core_reset(PCIDevice *d);
> extern const MemoryRegionOps pnv_phb4_xscom_ops;
>
> /*
> diff --git a/include/hw/pci-host/pnv_phb4_regs.h b/include/hw/pci-host/pnv_phb4_regs.h
> index bea96f4d91..6892e21cc9 100644
> --- a/include/hw/pci-host/pnv_phb4_regs.h
> +++ b/include/hw/pci-host/pnv_phb4_regs.h
> @@ -343,6 +343,18 @@
> #define PHB_RC_CONFIG_BASE 0x1000
> #define PHB_RC_CONFIG_SIZE 0x800
>
> +#define PHB_AER_ECAP 0x100
> +#define PHB_AER_CAPCTRL 0x118
> +#define PHB_SEC_ECAP 0x148
> +#define PHB_LMR_ECAP 0x1A0
> +#define PHB_LMR_CTLSTA_2 0x1AC
> +#define PHB_LMR_CTLSTA_16 0x1E4
> +#define PHB_DLF_ECAP 0x1E8
> +#define PHB_DLF_CAP 0x1EC
> +#define P16_ECAP 0x1F4
> +#define P32_ECAP 0x224
> +#define P32_CAP 0x228
> +
> /* PHB4 REGB registers */
>
> /* PBL core */
> @@ -368,7 +380,7 @@
> #define PHB_PCIE_SCR 0x1A00
> #define PHB_PCIE_SCR_SLOT_CAP PPC_BIT(15)
> #define PHB_PCIE_SCR_MAXLINKSPEED PPC_BITMASK(32, 35)
> -
> +#define PHB_PCIE_BNR 0x1A08
>
> #define PHB_PCIE_CRESET 0x1A10
> #define PHB_PCIE_CRESET_CFG_CORE PPC_BIT(0)
> @@ -423,6 +435,8 @@
> #define PHB_PCIE_LANE_EQ_CNTL23 0x1B08 /* DD1 only */
> #define PHB_PCIE_TRACE_CTRL 0x1B20
> #define PHB_PCIE_MISC_STRAP 0x1B30
> +#define PHB_PCIE_PHY_RXEQ_STAT_G3_00_03 0x1B40
> +#define PHB_PCIE_PHY_RXEQ_STAT_G5_12_15 0x1B98
>
> /* Error */
> #define PHB_REGB_ERR_STATUS 0x1C00
> diff --git a/tests/qtest/pnv-phb4-test.c b/tests/qtest/pnv-phb4-test.c
> index 3890b4f970..3957c743a3 100644
> --- a/tests/qtest/pnv-phb4-test.c
> +++ b/tests/qtest/pnv-phb4-test.c
> @@ -35,6 +35,29 @@ static uint64_t pnv_phb_xscom_read(QTestState *qts, const PnvChip *chip,
> return qtest_readq(qts, pnv_xscom_addr(chip, (scom >> 3) + indirect_data));
> }
>
> +#define phb4_xscom_read(a) pnv_phb_xscom_read(qts, \
> + &pnv_chips[PNV_P10_CHIP_INDEX], PHB4_XSCOM, \
> + PHB_SCOM_HV_IND_ADDR, PHB_SCOM_HV_IND_DATA, \
> + PPC_BIT(0) | a)
macros in UPPER CASE please, and parameters should be in ():
PPC_BIT(0) | (a)
> +
> +/* Assert that 'PHB PBL Control' register has correct reset value */
> +static void phb4_reset_test(QTestState *qts)
> +{
> + g_assert_cmpuint(phb4_xscom_read(PHB_PBL_CONTROL), ==, 0xC009000000000000);
> +}
> +
> +static void phb4_tests(void)
> +{
> + QTestState *qts = NULL;
> +
> + qts = qtest_initf("-machine powernv10 -accel tcg");
> +
> + /* Check reset value of a register */
> + phb4_reset_test(qts);
> +
> + qtest_quit(qts);
> +}
> +
> /* Assert that 'PHB - Version Register' bits-[24:31] are as expected */
> static void phb_version_test(const void *data)
> {
> @@ -71,8 +94,6 @@ static void phb_version_test(const void *data)
> /* PHB Version register bits [24:31] */
> ver = ver >> (63 - 31);
> g_assert_cmpuint(ver, ==, expected_ver);
> -
> - qtest_quit(qts);
> }
>
> /* Verify versions of all supported PHB's */
> @@ -95,5 +116,8 @@ int main(int argc, char **argv)
> /* PHB[345] tests */
> add_phbX_version_test();
>
> + /* PHB4 specific tests */
> + qtest_add_func("phb4", phb4_tests);
> +
> return g_test_run();
> }
> --
> 2.47.3
^ permalink raw reply [flat|nested] 60+ messages in thread
* Re: [PATCH v2 4/9] pnv/phb4: Implement read-only and write-only bits of registers
2025-12-30 10:21 ` [PATCH v2 4/9] pnv/phb4: Implement read-only and write-only bits of registers Saif Abrar
@ 2026-02-04 5:04 ` Michael S. Tsirkin
2026-02-04 5:11 ` Michael S. Tsirkin
0 siblings, 1 reply; 60+ messages in thread
From: Michael S. Tsirkin @ 2026-02-04 5:04 UTC (permalink / raw)
To: Saif Abrar
Cc: qemu-ppc, qemu-devel, clg, npiggin, fbarrat, marcel.apfelbaum,
cohuck, pbonzini, thuth, lvivier, danielhb413
On Tue, Dec 30, 2025 at 04:21:22AM -0600, Saif Abrar wrote:
> SW cannot write the read-only(RO) bits of a register
> and write-only(WO) bits of a register return 0 when read.
>
> Added ro_mask[] for each register that defines which
> bits in that register are RO.
> When writing to a register, the RO-bits are not updated.
>
> When reading a register, clear the WO bits and return the updated value.
>
> Tested the registers PHB_DMA_SYNC, PHB_PCIE_HOTPLUG_STATUS, PHB_PCIE_LMR,
> PHB_PCIE_DLP_TRWCTL, PHB_LEM_ERROR_AND_MASK and PHB_LEM_ERROR_OR_MASK
> by writing all 1's and reading back the value.
> The WO bits in these registers should read back as 0.
>
> Signed-off-by: Saif Abrar <saif.abrar@linux.vnet.ibm.com>
> Reviewed-by: Cédric Le Goater <clg@kaod.org>
causes a crash in boot-serial-test:
https://gitlab.com/mstredhat/qemu/-/jobs/12975819193
bisect script:
#!/bin/bash
cd /scm/qemu-bisect/build
make -j$(nproc) || exit 125
ninja tests/qtest/boot-serial-test || exit 125
QTEST_QEMU_BINARY=./qemu-system-ppc64 timeout 60 ./tests/qtest/boot-serial-test -p /ppc64/boot-serial/powernv9 && exit 0 || exit 1
> ---
> v1 -> v2: New PnvPHB4Class to hold each register's RO mask.
>
> hw/pci-host/pnv_phb4.c | 78 ++++++++++++++++++++++++++---
> include/hw/pci-host/pnv_phb4.h | 13 ++++-
> include/hw/pci-host/pnv_phb4_regs.h | 20 ++++++--
> tests/qtest/pnv-phb4-test.c | 60 +++++++++++++++++++++-
> 4 files changed, 157 insertions(+), 14 deletions(-)
>
> diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c
> index 70f5af21fa..48caba9e79 100644
> --- a/hw/pci-host/pnv_phb4.c
> +++ b/hw/pci-host/pnv_phb4.c
> @@ -707,6 +707,11 @@ static void pnv_phb4_reg_write(void *opaque, hwaddr off, uint64_t val,
> return;
> }
>
> + /* Update 'val' according to the register's RO-mask */
> + PnvPHB4Class *k = PNV_PHB4_GET_CLASS(phb);
> + val = (phb->regs[off >> 3] & k->ro_mask[off >> 3]) |
> + (val & ~(k->ro_mask[off >> 3]));
> +
> /* Record whether it changed */
> changed = phb->regs[off >> 3] != val;
>
> @@ -781,7 +786,7 @@ static void pnv_phb4_reg_write(void *opaque, hwaddr off, uint64_t val,
> case PHB_TCE_TAG_ENABLE:
> case PHB_INT_NOTIFY_ADDR:
> case PHB_INT_NOTIFY_INDEX:
> - case PHB_DMARD_SYNC:
> + case PHB_DMA_SYNC:
> break;
>
> /* Noise on anything else */
> @@ -819,7 +824,7 @@ static uint64_t pnv_phb4_reg_read(void *opaque, hwaddr off, unsigned size)
> case PHB_VERSION:
> return PNV_PHB4_PEC_GET_CLASS(phb->pec)->version;
>
> - /* Read-only */
> + /* Read-only */
> case PHB_PHB4_GEN_CAP:
> return 0xe4b8000000000000ull;
> case PHB_PHB4_TCE_CAP:
> @@ -829,18 +834,49 @@ static uint64_t pnv_phb4_reg_read(void *opaque, hwaddr off, unsigned size)
> case PHB_PHB4_EEH_CAP:
> return phb->big_phb ? 0x2000000000000000ull : 0x1000000000000000ull;
>
> + /* Write-only, read will return zeros */
> + case PHB_LEM_ERROR_AND_MASK:
> + case PHB_LEM_ERROR_OR_MASK:
> + return 0;
> + case PHB_PCIE_DLP_TRWCTL:
> + val &= ~PHB_PCIE_DLP_TRWCTL_WREN;
> + return val;
> /* IODA table accesses */
> case PHB_IODA_DATA0:
> return pnv_phb4_ioda_read(phb);
>
> + /*
> + * DMA sync: make it look like it's complete,
> + * clear write-only read/write start sync bits.
> + */
> + case PHB_DMA_SYNC:
> + val = PHB_DMA_SYNC_RD_COMPLETE |
> + ~(PHB_DMA_SYNC_RD_START | PHB_DMA_SYNC_WR_START);
> + return val;
> +
> + /*
> + * PCI-E Stack registers
> + */
> + case PHB_PCIE_SCR:
> + val |= PHB_PCIE_SCR_PLW_X16; /* RO bit */
> + break;
> +
> /* Link training always appears trained */
> case PHB_PCIE_DLP_TRAIN_CTL:
> /* TODO: Do something sensible with speed ? */
> - return PHB_PCIE_DLP_INBAND_PRESENCE | PHB_PCIE_DLP_TL_LINKACT;
> + val |= PHB_PCIE_DLP_INBAND_PRESENCE | PHB_PCIE_DLP_TL_LINKACT;
> + return val;
> +
> + case PHB_PCIE_HOTPLUG_STATUS:
> + /* Clear write-only bit */
> + val &= ~PHB_PCIE_HPSTAT_RESAMPLE;
> + return val;
>
> - /* DMA read sync: make it look like it's complete */
> - case PHB_DMARD_SYNC:
> - return PHB_DMARD_SYNC_COMPLETE;
> + /* Link Management Register */
> + case PHB_PCIE_LMR:
> + /* These write-only bits always read as 0 */
> + val &= ~(PHB_PCIE_LMR_CHANGELW | PHB_PCIE_LMR_RETRAINLINK);
> + return val;
>
> /* Silent simple reads */
> case PHB_LSI_SOURCE_ID:
> @@ -1685,6 +1721,32 @@ static PCIIOMMUOps pnv_phb4_iommu_ops = {
> .get_address_space = pnv_phb4_dma_iommu,
> };
>
> +static void pnv_phb4_ro_mask_init(PnvPHB4 *phb)
> +{
> + PnvPHB4Class *phb4c = PNV_PHB4_GET_CLASS(phb);
> +
> + /*
> + * Set register specific RO-masks
> + */
> +
> + /* PBL - Error Injection Register (0x1910) */
> + phb4c->ro_mask[PHB_PBL_ERR_INJECT >> 3] =
> + PPC_BITMASK(0, 23) | PPC_BITMASK(28, 35) | PPC_BIT(38) | PPC_BIT(46) |
> + PPC_BITMASK(49, 51) | PPC_BITMASK(55, 63);
> +
> + /* Reserved bits[60:63] */
> + phb4c->ro_mask[PHB_TXE_ERR_LEM_ENABLE >> 3] =
> + phb4c->ro_mask[PHB_TXE_ERR_AIB_FENCE_ENABLE >> 3] = PPC_BITMASK(60, 63);
> + /* Reserved bits[36:63] */
> + phb4c->ro_mask[PHB_RXE_TCE_ERR_LEM_ENABLE >> 3] =
> + phb4c->ro_mask[PHB_RXE_TCE_ERR_AIB_FENCE_ENABLE >> 3] = PPC_BITMASK(36, 63);
> + /* Reserved bits[40:63] */
> + phb4c->ro_mask[PHB_ERR_LEM_ENABLE >> 3] =
> + phb4c->ro_mask[PHB_ERR_AIB_FENCE_ENABLE >> 3] = PPC_BITMASK(40, 63);
> +
> + /* TODO: Add more RO-masks as regs are implemented in the model */
> +}
> +
> static void pnv_phb4_err_reg_reset(PnvPHB4 *phb)
> {
> STICKY_RST(PHB_ERR_STATUS, 0, PPC_BITMASK(0, 33));
> @@ -1743,6 +1805,7 @@ static void pnv_phb4_reset(Object *obj, ResetType type)
> pnv_phb4_err_reg_reset(phb);
> pnv_phb4_pcie_stack_reg_reset(phb);
> pnv_phb4_regb_err_reg_reset(phb);
> + phb->regs[PHB_PCIE_CRESET >> 3] = 0xE000000000000000;
> }
>
> static void pnv_phb4_instance_init(Object *obj)
> @@ -1753,6 +1816,9 @@ static void pnv_phb4_instance_init(Object *obj)
>
> /* XIVE interrupt source object */
> object_initialize_child(obj, "source", &phb->xsrc, TYPE_XIVE_SOURCE);
> +
> + /* Initialize RO-mask of registers */
> + pnv_phb4_ro_mask_init(phb);
> }
>
> void pnv_phb4_bus_init(DeviceState *dev, PnvPHB4 *phb)
> diff --git a/include/hw/pci-host/pnv_phb4.h b/include/hw/pci-host/pnv_phb4.h
> index 47a5c3edf5..bea0684724 100644
> --- a/include/hw/pci-host/pnv_phb4.h
> +++ b/include/hw/pci-host/pnv_phb4.h
> @@ -19,7 +19,7 @@
>
>
> #define TYPE_PNV_PHB4 "pnv-phb4"
> -OBJECT_DECLARE_SIMPLE_TYPE(PnvPHB4, PNV_PHB4)
> +OBJECT_DECLARE_TYPE(PnvPHB4, PnvPHB4Class, PNV_PHB4)
>
> typedef struct PnvPhb4PecStack PnvPhb4PecStack;
>
> @@ -156,6 +156,17 @@ struct PnvPHB4 {
> QLIST_HEAD(, PnvPhb4DMASpace) dma_spaces;
> };
>
> +typedef struct PnvPHB4Class {
> + DeviceClass parent_class;
> +
> + /*
> + * Read-only bitmask for registers
> + * Bit value: 1 => RO bit
> + * 0 => RW bit
> + */
> + uint64_t ro_mask[PNV_PHB4_NUM_REGS];
> +} PnvPHB4Class;
> +
> void pnv_phb4_pic_print_info(PnvPHB4 *phb, GString *buf);
> int pnv_phb4_pec_get_phb_id(PnvPhb4PecState *pec, int stack_index);
> PnvPhb4PecState *pnv_pec_add_phb(PnvChip *chip, PnvPHB *phb, Error **errp);
> diff --git a/include/hw/pci-host/pnv_phb4_regs.h b/include/hw/pci-host/pnv_phb4_regs.h
> index df5e86d29a..dfd0e01d1e 100644
> --- a/include/hw/pci-host/pnv_phb4_regs.h
> +++ b/include/hw/pci-host/pnv_phb4_regs.h
> @@ -180,9 +180,11 @@
> #define PHB_M64_AOMASK 0x1d0
> #define PHB_M64_UPPER_BITS 0x1f0
> #define PHB_NXLATE_PREFIX 0x1f8
> -#define PHB_DMARD_SYNC 0x200
> -#define PHB_DMARD_SYNC_START PPC_BIT(0)
> -#define PHB_DMARD_SYNC_COMPLETE PPC_BIT(1)
> +#define PHB_DMA_SYNC 0x200
> +#define PHB_DMA_SYNC_RD_START PPC_BIT(0)
> +#define PHB_DMA_SYNC_RD_COMPLETE PPC_BIT(1)
> +#define PHB_DMA_SYNC_WR_START PPC_BIT(2)
> +#define PHB_DMA_SYNC_WR_COMPLETE PPC_BIT(3)
> #define PHB_RTC_INVALIDATE 0x208
> #define PHB_RTC_INVALIDATE_ALL PPC_BIT(0)
> #define PHB_RTC_INVALIDATE_RID PPC_BITMASK(16, 31)
> @@ -370,6 +372,7 @@
> #define P32_CAP 0x228
> #define P32_CTL 0x22C
> #define P32_STAT 0x230
> +
> /* PHB4 REGB registers */
>
> /* PBL core */
> @@ -395,8 +398,8 @@
> #define PHB_PCIE_SCR 0x1A00
> #define PHB_PCIE_SCR_SLOT_CAP PPC_BIT(15)
> #define PHB_PCIE_SCR_MAXLINKSPEED PPC_BITMASK(32, 35)
> +#define PHB_PCIE_SCR_PLW_X16 PPC_BIT(41) /* x16 */
> #define PHB_PCIE_BNR 0x1A08
> -
> #define PHB_PCIE_CRESET 0x1A10
> #define PHB_PCIE_CRESET_CFG_CORE PPC_BIT(0)
> #define PHB_PCIE_CRESET_TLDLP PPC_BIT(1)
> @@ -405,7 +408,14 @@
> #define PHB_PCIE_CRESET_PIPE_N PPC_BIT(4)
> #define PHB_PCIE_CRESET_REFCLK_N PPC_BIT(8)
> #define PHB_PCIE_HOTPLUG_STATUS 0x1A20
> +#define PHB_PCIE_HPSTAT_SIMDIAG PPC_BIT(3)
> +#define PHB_PCIE_HPSTAT_RESAMPLE PPC_BIT(9)
> #define PHB_PCIE_HPSTAT_PRESENCE PPC_BIT(10)
> +#define PHB_PCIE_HPSTAT_LINKACTIVE PPC_BIT(12)
> +#define PHB_PCIE_LMR 0x1A30
> +#define PHB_PCIE_LMR_CHANGELW PPC_BIT(0)
> +#define PHB_PCIE_LMR_RETRAINLINK PPC_BIT(1)
> +#define PHB_PCIE_LMR_LINKACTIVE PPC_BIT(8)
>
> #define PHB_PCIE_DLP_TRAIN_CTL 0x1A40
> #define PHB_PCIE_DLP_LINK_WIDTH PPC_BITMASK(30, 35)
> @@ -433,7 +443,7 @@
>
> #define PHB_PCIE_DLP_TRWCTL 0x1A80
> #define PHB_PCIE_DLP_TRWCTL_EN PPC_BIT(0)
> -
> +#define PHB_PCIE_DLP_TRWCTL_WREN PPC_BIT(1)
> #define PHB_PCIE_DLP_ERRLOG1 0x1AA0
> #define PHB_PCIE_DLP_ERRLOG2 0x1AA8
> #define PHB_PCIE_DLP_ERR_STATUS 0x1AB0
> diff --git a/tests/qtest/pnv-phb4-test.c b/tests/qtest/pnv-phb4-test.c
> index f186efaf0d..841306ae3f 100644
> --- a/tests/qtest/pnv-phb4-test.c
> +++ b/tests/qtest/pnv-phb4-test.c
> @@ -73,7 +73,8 @@ static void phb4_sticky_rst_test(QTestState *qts)
> * Sticky reset test of PHB_PBL_ERR_STATUS.
> *
> * Write all 1's to reg PHB_PBL_ERR_INJECT.
> - * Updated value will be copied to reg PHB_PBL_ERR_STATUS.
> + * RO-only bits will not be written and
> + * updated value will be copied to reg PHB_PBL_ERR_STATUS.
> *
> * Reset PBL core by setting PHB_PCIE_CRESET_PBL in reg PHB_PCIE_CRESET.
> * Verify the sticky bits are still set.
> @@ -81,7 +82,59 @@ static void phb4_sticky_rst_test(QTestState *qts)
> phb4_xscom_write(PHB_PBL_ERR_INJECT, PPC_BITMASK(0, 63));
> phb4_xscom_write(PHB_PCIE_CRESET, PHB_PCIE_CRESET_PBL); /*Reset*/
> val = phb4_xscom_read(PHB_PBL_ERR_STATUS);
> - g_assert_cmpuint(val, ==, (PPC_BITMASK(0, 9) | PPC_BITMASK(12, 63)));
> + g_assert_cmpuint(val, ==, 0xF00DFD8E00);
> +}
> +
> +/* Check that write-only bits/regs return 0 when read */
> +static void phb4_writeonly_read_test(QTestState *qts)
> +{
> + uint64_t val;
> +
> + /*
> + * Set all bits of PHB_DMA_SYNC,
> + * bits 0 and 2 are write-only and should be read as 0.
> + */
> + phb4_xscom_write(PHB_DMA_SYNC, PPC_BITMASK(0, 63));
> + val = phb4_xscom_read(PHB_DMA_SYNC);
> + g_assert_cmpuint(val & PPC_BIT(0), ==, 0x0);
> + g_assert_cmpuint(val & PPC_BIT(2), ==, 0x0);
> +
> + /*
> + * Set all bits of PHB_PCIE_HOTPLUG_STATUS,
> + * bit 9 is write-only and should be read as 0.
> + */
> + phb4_xscom_write(PHB_PCIE_HOTPLUG_STATUS, PPC_BITMASK(0, 63));
> + val = phb4_xscom_read(PHB_PCIE_HOTPLUG_STATUS);
> + g_assert_cmpuint(val & PPC_BIT(9), ==, 0x0);
> +
> + /*
> + * Set all bits of PHB_PCIE_LMR,
> + * bits 0 and 1 are write-only and should be read as 0.
> + */
> + phb4_xscom_write(PHB_PCIE_LMR, PPC_BITMASK(0, 63));
> + val = phb4_xscom_read(PHB_PCIE_LMR);
> + g_assert_cmpuint(val & PPC_BIT(0), ==, 0x0);
> + g_assert_cmpuint(val & PPC_BIT(1), ==, 0x0);
> +
> + /*
> + * Set all bits of PHB_PCIE_DLP_TRWCTL,
> + * write-only bit-1 should be read as 0.
> + */
> + phb4_xscom_write(PHB_PCIE_DLP_TRWCTL, PPC_BITMASK(0, 63));
> + val = phb4_xscom_read(PHB_PCIE_DLP_TRWCTL);
> + g_assert_cmpuint(val & PPC_BIT(1), ==, 0x0);
> +
> + /*
> + * Set all bits of PHB_LEM_ERROR_AND_MASK, PHB_LEM_ERROR_OR_MASK,
> + * both regs are write-only and should be read as 0.
> + */
> + phb4_xscom_write(PHB_LEM_ERROR_AND_MASK, PPC_BITMASK(0, 63));
> + val = phb4_xscom_read(PHB_LEM_ERROR_AND_MASK);
> + g_assert_cmpuint(val, ==, 0x0);
> +
> + phb4_xscom_write(PHB_LEM_ERROR_OR_MASK, PPC_BITMASK(0, 63));
> + val = phb4_xscom_read(PHB_LEM_ERROR_OR_MASK);
> + g_assert_cmpuint(val, ==, 0x0);
> }
>
> static void phb4_tests(void)
> @@ -96,6 +149,9 @@ static void phb4_tests(void)
> /* Check sticky reset of a register */
> phb4_sticky_rst_test(qts);
>
> + /* Check write-only logic */
> + phb4_writeonly_read_test(qts);
> +
> qtest_quit(qts);
> }
>
> --
> 2.47.3
^ permalink raw reply [flat|nested] 60+ messages in thread
* Re: [PATCH v2 4/9] pnv/phb4: Implement read-only and write-only bits of registers
2026-02-04 5:04 ` Michael S. Tsirkin
@ 2026-02-04 5:11 ` Michael S. Tsirkin
2026-02-04 6:42 ` Michael S. Tsirkin
0 siblings, 1 reply; 60+ messages in thread
From: Michael S. Tsirkin @ 2026-02-04 5:11 UTC (permalink / raw)
To: Saif Abrar
Cc: qemu-ppc, qemu-devel, clg, npiggin, fbarrat, marcel.apfelbaum,
cohuck, pbonzini, thuth, lvivier, danielhb413
On Wed, Feb 04, 2026 at 12:04:20AM -0500, Michael S. Tsirkin wrote:
> On Tue, Dec 30, 2025 at 04:21:22AM -0600, Saif Abrar wrote:
> > SW cannot write the read-only(RO) bits of a register
> > and write-only(WO) bits of a register return 0 when read.
> >
> > Added ro_mask[] for each register that defines which
> > bits in that register are RO.
> > When writing to a register, the RO-bits are not updated.
> >
> > When reading a register, clear the WO bits and return the updated value.
> >
> > Tested the registers PHB_DMA_SYNC, PHB_PCIE_HOTPLUG_STATUS, PHB_PCIE_LMR,
> > PHB_PCIE_DLP_TRWCTL, PHB_LEM_ERROR_AND_MASK and PHB_LEM_ERROR_OR_MASK
> > by writing all 1's and reading back the value.
> > The WO bits in these registers should read back as 0.
> >
> > Signed-off-by: Saif Abrar <saif.abrar@linux.vnet.ibm.com>
> > Reviewed-by: Cédric Le Goater <clg@kaod.org>
>
> causes a crash in boot-serial-test:
> https://gitlab.com/mstredhat/qemu/-/jobs/12975819193
I forgot to say - with tci:
../configure --enable-tcg-interpreter --target-list=ppc64-softmmu
> bisect script:
>
> #!/bin/bash
> cd /scm/qemu-bisect/build
> make -j$(nproc) || exit 125
> ninja tests/qtest/boot-serial-test || exit 125
> QTEST_QEMU_BINARY=./qemu-system-ppc64 timeout 60 ./tests/qtest/boot-serial-test -p /ppc64/boot-serial/powernv9 && exit 0 || exit 1
>
>
> > ---
> > v1 -> v2: New PnvPHB4Class to hold each register's RO mask.
> >
> > hw/pci-host/pnv_phb4.c | 78 ++++++++++++++++++++++++++---
> > include/hw/pci-host/pnv_phb4.h | 13 ++++-
> > include/hw/pci-host/pnv_phb4_regs.h | 20 ++++++--
> > tests/qtest/pnv-phb4-test.c | 60 +++++++++++++++++++++-
> > 4 files changed, 157 insertions(+), 14 deletions(-)
> >
> > diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c
> > index 70f5af21fa..48caba9e79 100644
> > --- a/hw/pci-host/pnv_phb4.c
> > +++ b/hw/pci-host/pnv_phb4.c
> > @@ -707,6 +707,11 @@ static void pnv_phb4_reg_write(void *opaque, hwaddr off, uint64_t val,
> > return;
> > }
> >
> > + /* Update 'val' according to the register's RO-mask */
> > + PnvPHB4Class *k = PNV_PHB4_GET_CLASS(phb);
> > + val = (phb->regs[off >> 3] & k->ro_mask[off >> 3]) |
> > + (val & ~(k->ro_mask[off >> 3]));
> > +
> > /* Record whether it changed */
> > changed = phb->regs[off >> 3] != val;
> >
> > @@ -781,7 +786,7 @@ static void pnv_phb4_reg_write(void *opaque, hwaddr off, uint64_t val,
> > case PHB_TCE_TAG_ENABLE:
> > case PHB_INT_NOTIFY_ADDR:
> > case PHB_INT_NOTIFY_INDEX:
> > - case PHB_DMARD_SYNC:
> > + case PHB_DMA_SYNC:
> > break;
> >
> > /* Noise on anything else */
> > @@ -819,7 +824,7 @@ static uint64_t pnv_phb4_reg_read(void *opaque, hwaddr off, unsigned size)
> > case PHB_VERSION:
> > return PNV_PHB4_PEC_GET_CLASS(phb->pec)->version;
> >
> > - /* Read-only */
> > + /* Read-only */
> > case PHB_PHB4_GEN_CAP:
> > return 0xe4b8000000000000ull;
> > case PHB_PHB4_TCE_CAP:
> > @@ -829,18 +834,49 @@ static uint64_t pnv_phb4_reg_read(void *opaque, hwaddr off, unsigned size)
> > case PHB_PHB4_EEH_CAP:
> > return phb->big_phb ? 0x2000000000000000ull : 0x1000000000000000ull;
> >
> > + /* Write-only, read will return zeros */
> > + case PHB_LEM_ERROR_AND_MASK:
> > + case PHB_LEM_ERROR_OR_MASK:
> > + return 0;
> > + case PHB_PCIE_DLP_TRWCTL:
> > + val &= ~PHB_PCIE_DLP_TRWCTL_WREN;
> > + return val;
> > /* IODA table accesses */
> > case PHB_IODA_DATA0:
> > return pnv_phb4_ioda_read(phb);
> >
> > + /*
> > + * DMA sync: make it look like it's complete,
> > + * clear write-only read/write start sync bits.
> > + */
> > + case PHB_DMA_SYNC:
> > + val = PHB_DMA_SYNC_RD_COMPLETE |
> > + ~(PHB_DMA_SYNC_RD_START | PHB_DMA_SYNC_WR_START);
> > + return val;
> > +
> > + /*
> > + * PCI-E Stack registers
> > + */
> > + case PHB_PCIE_SCR:
> > + val |= PHB_PCIE_SCR_PLW_X16; /* RO bit */
> > + break;
> > +
> > /* Link training always appears trained */
> > case PHB_PCIE_DLP_TRAIN_CTL:
> > /* TODO: Do something sensible with speed ? */
> > - return PHB_PCIE_DLP_INBAND_PRESENCE | PHB_PCIE_DLP_TL_LINKACT;
> > + val |= PHB_PCIE_DLP_INBAND_PRESENCE | PHB_PCIE_DLP_TL_LINKACT;
> > + return val;
> > +
> > + case PHB_PCIE_HOTPLUG_STATUS:
> > + /* Clear write-only bit */
> > + val &= ~PHB_PCIE_HPSTAT_RESAMPLE;
> > + return val;
> >
> > - /* DMA read sync: make it look like it's complete */
> > - case PHB_DMARD_SYNC:
> > - return PHB_DMARD_SYNC_COMPLETE;
> > + /* Link Management Register */
> > + case PHB_PCIE_LMR:
> > + /* These write-only bits always read as 0 */
> > + val &= ~(PHB_PCIE_LMR_CHANGELW | PHB_PCIE_LMR_RETRAINLINK);
> > + return val;
> >
> > /* Silent simple reads */
> > case PHB_LSI_SOURCE_ID:
> > @@ -1685,6 +1721,32 @@ static PCIIOMMUOps pnv_phb4_iommu_ops = {
> > .get_address_space = pnv_phb4_dma_iommu,
> > };
> >
> > +static void pnv_phb4_ro_mask_init(PnvPHB4 *phb)
> > +{
> > + PnvPHB4Class *phb4c = PNV_PHB4_GET_CLASS(phb);
> > +
> > + /*
> > + * Set register specific RO-masks
> > + */
> > +
> > + /* PBL - Error Injection Register (0x1910) */
> > + phb4c->ro_mask[PHB_PBL_ERR_INJECT >> 3] =
> > + PPC_BITMASK(0, 23) | PPC_BITMASK(28, 35) | PPC_BIT(38) | PPC_BIT(46) |
> > + PPC_BITMASK(49, 51) | PPC_BITMASK(55, 63);
> > +
> > + /* Reserved bits[60:63] */
> > + phb4c->ro_mask[PHB_TXE_ERR_LEM_ENABLE >> 3] =
> > + phb4c->ro_mask[PHB_TXE_ERR_AIB_FENCE_ENABLE >> 3] = PPC_BITMASK(60, 63);
> > + /* Reserved bits[36:63] */
> > + phb4c->ro_mask[PHB_RXE_TCE_ERR_LEM_ENABLE >> 3] =
> > + phb4c->ro_mask[PHB_RXE_TCE_ERR_AIB_FENCE_ENABLE >> 3] = PPC_BITMASK(36, 63);
> > + /* Reserved bits[40:63] */
> > + phb4c->ro_mask[PHB_ERR_LEM_ENABLE >> 3] =
> > + phb4c->ro_mask[PHB_ERR_AIB_FENCE_ENABLE >> 3] = PPC_BITMASK(40, 63);
> > +
> > + /* TODO: Add more RO-masks as regs are implemented in the model */
> > +}
> > +
> > static void pnv_phb4_err_reg_reset(PnvPHB4 *phb)
> > {
> > STICKY_RST(PHB_ERR_STATUS, 0, PPC_BITMASK(0, 33));
> > @@ -1743,6 +1805,7 @@ static void pnv_phb4_reset(Object *obj, ResetType type)
> > pnv_phb4_err_reg_reset(phb);
> > pnv_phb4_pcie_stack_reg_reset(phb);
> > pnv_phb4_regb_err_reg_reset(phb);
> > + phb->regs[PHB_PCIE_CRESET >> 3] = 0xE000000000000000;
> > }
> >
> > static void pnv_phb4_instance_init(Object *obj)
> > @@ -1753,6 +1816,9 @@ static void pnv_phb4_instance_init(Object *obj)
> >
> > /* XIVE interrupt source object */
> > object_initialize_child(obj, "source", &phb->xsrc, TYPE_XIVE_SOURCE);
> > +
> > + /* Initialize RO-mask of registers */
> > + pnv_phb4_ro_mask_init(phb);
> > }
> >
> > void pnv_phb4_bus_init(DeviceState *dev, PnvPHB4 *phb)
> > diff --git a/include/hw/pci-host/pnv_phb4.h b/include/hw/pci-host/pnv_phb4.h
> > index 47a5c3edf5..bea0684724 100644
> > --- a/include/hw/pci-host/pnv_phb4.h
> > +++ b/include/hw/pci-host/pnv_phb4.h
> > @@ -19,7 +19,7 @@
> >
> >
> > #define TYPE_PNV_PHB4 "pnv-phb4"
> > -OBJECT_DECLARE_SIMPLE_TYPE(PnvPHB4, PNV_PHB4)
> > +OBJECT_DECLARE_TYPE(PnvPHB4, PnvPHB4Class, PNV_PHB4)
> >
> > typedef struct PnvPhb4PecStack PnvPhb4PecStack;
> >
> > @@ -156,6 +156,17 @@ struct PnvPHB4 {
> > QLIST_HEAD(, PnvPhb4DMASpace) dma_spaces;
> > };
> >
> > +typedef struct PnvPHB4Class {
> > + DeviceClass parent_class;
> > +
> > + /*
> > + * Read-only bitmask for registers
> > + * Bit value: 1 => RO bit
> > + * 0 => RW bit
> > + */
> > + uint64_t ro_mask[PNV_PHB4_NUM_REGS];
> > +} PnvPHB4Class;
> > +
> > void pnv_phb4_pic_print_info(PnvPHB4 *phb, GString *buf);
> > int pnv_phb4_pec_get_phb_id(PnvPhb4PecState *pec, int stack_index);
> > PnvPhb4PecState *pnv_pec_add_phb(PnvChip *chip, PnvPHB *phb, Error **errp);
> > diff --git a/include/hw/pci-host/pnv_phb4_regs.h b/include/hw/pci-host/pnv_phb4_regs.h
> > index df5e86d29a..dfd0e01d1e 100644
> > --- a/include/hw/pci-host/pnv_phb4_regs.h
> > +++ b/include/hw/pci-host/pnv_phb4_regs.h
> > @@ -180,9 +180,11 @@
> > #define PHB_M64_AOMASK 0x1d0
> > #define PHB_M64_UPPER_BITS 0x1f0
> > #define PHB_NXLATE_PREFIX 0x1f8
> > -#define PHB_DMARD_SYNC 0x200
> > -#define PHB_DMARD_SYNC_START PPC_BIT(0)
> > -#define PHB_DMARD_SYNC_COMPLETE PPC_BIT(1)
> > +#define PHB_DMA_SYNC 0x200
> > +#define PHB_DMA_SYNC_RD_START PPC_BIT(0)
> > +#define PHB_DMA_SYNC_RD_COMPLETE PPC_BIT(1)
> > +#define PHB_DMA_SYNC_WR_START PPC_BIT(2)
> > +#define PHB_DMA_SYNC_WR_COMPLETE PPC_BIT(3)
> > #define PHB_RTC_INVALIDATE 0x208
> > #define PHB_RTC_INVALIDATE_ALL PPC_BIT(0)
> > #define PHB_RTC_INVALIDATE_RID PPC_BITMASK(16, 31)
> > @@ -370,6 +372,7 @@
> > #define P32_CAP 0x228
> > #define P32_CTL 0x22C
> > #define P32_STAT 0x230
> > +
> > /* PHB4 REGB registers */
> >
> > /* PBL core */
> > @@ -395,8 +398,8 @@
> > #define PHB_PCIE_SCR 0x1A00
> > #define PHB_PCIE_SCR_SLOT_CAP PPC_BIT(15)
> > #define PHB_PCIE_SCR_MAXLINKSPEED PPC_BITMASK(32, 35)
> > +#define PHB_PCIE_SCR_PLW_X16 PPC_BIT(41) /* x16 */
> > #define PHB_PCIE_BNR 0x1A08
> > -
> > #define PHB_PCIE_CRESET 0x1A10
> > #define PHB_PCIE_CRESET_CFG_CORE PPC_BIT(0)
> > #define PHB_PCIE_CRESET_TLDLP PPC_BIT(1)
> > @@ -405,7 +408,14 @@
> > #define PHB_PCIE_CRESET_PIPE_N PPC_BIT(4)
> > #define PHB_PCIE_CRESET_REFCLK_N PPC_BIT(8)
> > #define PHB_PCIE_HOTPLUG_STATUS 0x1A20
> > +#define PHB_PCIE_HPSTAT_SIMDIAG PPC_BIT(3)
> > +#define PHB_PCIE_HPSTAT_RESAMPLE PPC_BIT(9)
> > #define PHB_PCIE_HPSTAT_PRESENCE PPC_BIT(10)
> > +#define PHB_PCIE_HPSTAT_LINKACTIVE PPC_BIT(12)
> > +#define PHB_PCIE_LMR 0x1A30
> > +#define PHB_PCIE_LMR_CHANGELW PPC_BIT(0)
> > +#define PHB_PCIE_LMR_RETRAINLINK PPC_BIT(1)
> > +#define PHB_PCIE_LMR_LINKACTIVE PPC_BIT(8)
> >
> > #define PHB_PCIE_DLP_TRAIN_CTL 0x1A40
> > #define PHB_PCIE_DLP_LINK_WIDTH PPC_BITMASK(30, 35)
> > @@ -433,7 +443,7 @@
> >
> > #define PHB_PCIE_DLP_TRWCTL 0x1A80
> > #define PHB_PCIE_DLP_TRWCTL_EN PPC_BIT(0)
> > -
> > +#define PHB_PCIE_DLP_TRWCTL_WREN PPC_BIT(1)
> > #define PHB_PCIE_DLP_ERRLOG1 0x1AA0
> > #define PHB_PCIE_DLP_ERRLOG2 0x1AA8
> > #define PHB_PCIE_DLP_ERR_STATUS 0x1AB0
> > diff --git a/tests/qtest/pnv-phb4-test.c b/tests/qtest/pnv-phb4-test.c
> > index f186efaf0d..841306ae3f 100644
> > --- a/tests/qtest/pnv-phb4-test.c
> > +++ b/tests/qtest/pnv-phb4-test.c
> > @@ -73,7 +73,8 @@ static void phb4_sticky_rst_test(QTestState *qts)
> > * Sticky reset test of PHB_PBL_ERR_STATUS.
> > *
> > * Write all 1's to reg PHB_PBL_ERR_INJECT.
> > - * Updated value will be copied to reg PHB_PBL_ERR_STATUS.
> > + * RO-only bits will not be written and
> > + * updated value will be copied to reg PHB_PBL_ERR_STATUS.
> > *
> > * Reset PBL core by setting PHB_PCIE_CRESET_PBL in reg PHB_PCIE_CRESET.
> > * Verify the sticky bits are still set.
> > @@ -81,7 +82,59 @@ static void phb4_sticky_rst_test(QTestState *qts)
> > phb4_xscom_write(PHB_PBL_ERR_INJECT, PPC_BITMASK(0, 63));
> > phb4_xscom_write(PHB_PCIE_CRESET, PHB_PCIE_CRESET_PBL); /*Reset*/
> > val = phb4_xscom_read(PHB_PBL_ERR_STATUS);
> > - g_assert_cmpuint(val, ==, (PPC_BITMASK(0, 9) | PPC_BITMASK(12, 63)));
> > + g_assert_cmpuint(val, ==, 0xF00DFD8E00);
> > +}
> > +
> > +/* Check that write-only bits/regs return 0 when read */
> > +static void phb4_writeonly_read_test(QTestState *qts)
> > +{
> > + uint64_t val;
> > +
> > + /*
> > + * Set all bits of PHB_DMA_SYNC,
> > + * bits 0 and 2 are write-only and should be read as 0.
> > + */
> > + phb4_xscom_write(PHB_DMA_SYNC, PPC_BITMASK(0, 63));
> > + val = phb4_xscom_read(PHB_DMA_SYNC);
> > + g_assert_cmpuint(val & PPC_BIT(0), ==, 0x0);
> > + g_assert_cmpuint(val & PPC_BIT(2), ==, 0x0);
> > +
> > + /*
> > + * Set all bits of PHB_PCIE_HOTPLUG_STATUS,
> > + * bit 9 is write-only and should be read as 0.
> > + */
> > + phb4_xscom_write(PHB_PCIE_HOTPLUG_STATUS, PPC_BITMASK(0, 63));
> > + val = phb4_xscom_read(PHB_PCIE_HOTPLUG_STATUS);
> > + g_assert_cmpuint(val & PPC_BIT(9), ==, 0x0);
> > +
> > + /*
> > + * Set all bits of PHB_PCIE_LMR,
> > + * bits 0 and 1 are write-only and should be read as 0.
> > + */
> > + phb4_xscom_write(PHB_PCIE_LMR, PPC_BITMASK(0, 63));
> > + val = phb4_xscom_read(PHB_PCIE_LMR);
> > + g_assert_cmpuint(val & PPC_BIT(0), ==, 0x0);
> > + g_assert_cmpuint(val & PPC_BIT(1), ==, 0x0);
> > +
> > + /*
> > + * Set all bits of PHB_PCIE_DLP_TRWCTL,
> > + * write-only bit-1 should be read as 0.
> > + */
> > + phb4_xscom_write(PHB_PCIE_DLP_TRWCTL, PPC_BITMASK(0, 63));
> > + val = phb4_xscom_read(PHB_PCIE_DLP_TRWCTL);
> > + g_assert_cmpuint(val & PPC_BIT(1), ==, 0x0);
> > +
> > + /*
> > + * Set all bits of PHB_LEM_ERROR_AND_MASK, PHB_LEM_ERROR_OR_MASK,
> > + * both regs are write-only and should be read as 0.
> > + */
> > + phb4_xscom_write(PHB_LEM_ERROR_AND_MASK, PPC_BITMASK(0, 63));
> > + val = phb4_xscom_read(PHB_LEM_ERROR_AND_MASK);
> > + g_assert_cmpuint(val, ==, 0x0);
> > +
> > + phb4_xscom_write(PHB_LEM_ERROR_OR_MASK, PPC_BITMASK(0, 63));
> > + val = phb4_xscom_read(PHB_LEM_ERROR_OR_MASK);
> > + g_assert_cmpuint(val, ==, 0x0);
> > }
> >
> > static void phb4_tests(void)
> > @@ -96,6 +149,9 @@ static void phb4_tests(void)
> > /* Check sticky reset of a register */
> > phb4_sticky_rst_test(qts);
> >
> > + /* Check write-only logic */
> > + phb4_writeonly_read_test(qts);
> > +
> > qtest_quit(qts);
> > }
> >
> > --
> > 2.47.3
^ permalink raw reply [flat|nested] 60+ messages in thread
* Re: [PATCH v2 4/9] pnv/phb4: Implement read-only and write-only bits of registers
2026-02-04 5:11 ` Michael S. Tsirkin
@ 2026-02-04 6:42 ` Michael S. Tsirkin
2026-02-09 5:35 ` Saif Abrar
0 siblings, 1 reply; 60+ messages in thread
From: Michael S. Tsirkin @ 2026-02-04 6:42 UTC (permalink / raw)
To: Saif Abrar
Cc: qemu-ppc, qemu-devel, clg, npiggin, fbarrat, marcel.apfelbaum,
cohuck, pbonzini, thuth, lvivier, danielhb413
On Wed, Feb 04, 2026 at 12:12:01AM -0500, Michael S. Tsirkin wrote:
> On Wed, Feb 04, 2026 at 12:04:20AM -0500, Michael S. Tsirkin wrote:
> > On Tue, Dec 30, 2025 at 04:21:22AM -0600, Saif Abrar wrote:
> > > SW cannot write the read-only(RO) bits of a register
> > > and write-only(WO) bits of a register return 0 when read.
> > >
> > > Added ro_mask[] for each register that defines which
> > > bits in that register are RO.
> > > When writing to a register, the RO-bits are not updated.
> > >
> > > When reading a register, clear the WO bits and return the updated value.
> > >
> > > Tested the registers PHB_DMA_SYNC, PHB_PCIE_HOTPLUG_STATUS, PHB_PCIE_LMR,
> > > PHB_PCIE_DLP_TRWCTL, PHB_LEM_ERROR_AND_MASK and PHB_LEM_ERROR_OR_MASK
> > > by writing all 1's and reading back the value.
> > > The WO bits in these registers should read back as 0.
> > >
> > > Signed-off-by: Saif Abrar <saif.abrar@linux.vnet.ibm.com>
> > > Reviewed-by: Cédric Le Goater <clg@kaod.org>
> >
> > causes a crash in boot-serial-test:
> > https://gitlab.com/mstredhat/qemu/-/jobs/12975819193
>
> I forgot to say - with tci:
>
> ../configure --enable-tcg-interpreter --target-list=ppc64-softmmu
triggered with tcg now, too.
Core was generated by `/scm/qemu-bisect/build/qemu-system-ppc64 -qtest unix:/tmp/qtest-194326.sock -qtest-log /dev/null -chardev
socket,path=/tmp/qtest-194326.qmp,id=char0 -mon chardev=char0,mode=control -display none -audio none -run-with
exit-with-parent=on -M powernv9 -no-shutdown -chardev file,id=serial0,path=/tmp/qtest-boot-serial-sVOZKK3 -serial
chardev:serial0 -accel tcg -accel kvm -accel qtest'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0 0x000055fe6e84bcc8 in object_link_get_targetp (obj=0x55fe8ebbca10, lprop=0xf) at ../qom/object.c:1871
1871 if (lprop->flags & OBJ_PROP_LINK_DIRECT) {
[Current thread is 1 (Thread 0x7f2716e774c0 (LWP 194336))]
warning: File "/scm/qemu/.gdbinit" auto-loading has been declined by your `auto-load safe-path' set to
"$debugdir:$datadir/auto-load:/usr/lib/golang/src/runtime/runtime-gdb.py".
To enable execution of this file add
add-auto-load-safe-path /scm/qemu/.gdbinit
line to your configuration file "/home/mst/.config/gdb/gdbinit".
To completely disable this security protection add
set auto-load safe-path /
line to your configuration file "/home/mst/.config/gdb/gdbinit".
For more information about this security protection see the
"Auto-loading safe path" section in the GDB manual. E.g., run from the shell:
info "(gdb)Auto-loading safe path"
#0 0x000055fe6e84bcc8 in object_link_get_targetp (obj=0x55fe8ebbca10, lprop=0xf) at ../qom/object.c:1871
#1 0x000055fe6e84c00f in object_set_link_property (obj=0x55fe8ebbca10, v=0x55fe8ebc81a0, name=0x55fe6ef9d504 "pec", opaque=0xf,
errp=0x7ffe749d2a00) at ../qom/object.c:1945
#2 0x000055fe6e84aad7 in object_property_set (obj=0x55fe8ebbca10, name=0x55fe6ef9d504 "pec", v=0x55fe8ebc81a0,
errp=0x7ffe749d2a00) at ../qom/object.c:1450
#3 0x000055fe6e84fcc3 in object_property_set_qobject (obj=0x55fe8ebbca10, name=0x55fe6ef9d504 "pec", value=0x55fe8ebc8520,
errp=0x7ffe749d2a00) at ../qom/qom-qobject.c:28
#4 0x000055fe6e84ab7b in object_property_set_str (obj=0x55fe8ebbca10, name=0x55fe6ef9d504 "pec", value=0x55fe8ebbc8e0
"/machine/chip[0]/pec[0]", errp=0x7ffe749d2a00) at ../qom/object.c:1458
#5 0x000055fe6e84ad30 in object_property_set_link (obj=0x55fe8ebbca10, name=0x55fe6ef9d504 "pec", value=0x55fe8e654330,
errp=0x7ffe749d2a00) at ../qom/object.c:1495
#6 0x000055fe6e7fb1ff in pnv_phb_realize (dev=0x55fe8ebbb960, errp=0x7ffe749d2a00) at ../hw/pci-host/pnv_phb.c:156
#7 0x000055fe6e8435be in device_set_realized (obj=0x55fe8ebbb960, value=true, errp=0x7ffe749d2d60) at ../hw/core/qdev.c:523
#8 0x000055fe6e84d060 in property_set_bool (obj=0x55fe8ebbb960, v=0x55fe8e70db20, name=0x55fe6efb2979 "realized",
opaque=0x55fe8e2595f0, errp=0x7ffe749d2d60) at ../qom/object.c:2376
#9 0x000055fe6e84aad7 in object_property_set (obj=0x55fe8ebbb960, name=0x55fe6efb2979 "realized", v=0x55fe8e70db20,
errp=0x7ffe749d2d60) at ../qom/object.c:1450
#10 0x000055fe6e84fcc3 in object_property_set_qobject (obj=0x55fe8ebbb960, name=0x55fe6efb2979 "realized", value=0x55fe8ebbc860,
errp=0x7ffe749d2d60) at ../qom/qom-qobject.c:28
#11 0x000055fe6e84ae8a in object_property_set_bool (obj=0x55fe8ebbb960, name=0x55fe6efb2979 "realized", value=true,
errp=0x7ffe749d2d60) at ../qom/object.c:1520
#12 0x000055fe6e842c6b in qdev_realize (dev=0x55fe8ebbb960, bus=0x55fe8e6164d0, errp=0x7ffe749d2d60) at ../hw/core/qdev.c:276
#13 0x000055fe6e1ee440 in sysbus_realize (dev=0x55fe8ebbb960, errp=0x7ffe749d2d60) at ../hw/core/sysbus.c:249
#14 0x000055fe6e7f9901 in pnv_pec_default_phb_realize (pec=0x55fe8e654330, stack_no=0, errp=0x7ffe749d2d60) at
../hw/pci-host/pnv_phb4_pec.c:194
#15 0x000055fe6e7f9bc0 in pnv_pec_realize (dev=0x55fe8e654330, errp=0x7ffe749d2d60) at ../hw/pci-host/pnv_phb4_pec.c:258
#16 0x000055fe6e8435be in device_set_realized (obj=0x55fe8e654330, value=true, errp=0x7ffe749d2fe8) at ../hw/core/qdev.c:523
#17 0x000055fe6e84d060 in property_set_bool (obj=0x55fe8e654330, v=0x55fe8e63ea90, name=0x55fe6efb2979 "realized",
opaque=0x55fe8e2595f0, errp=0x7ffe749d2fe8) at ../qom/object.c:2376
#18 0x000055fe6e84aad7 in object_property_set (obj=0x55fe8e654330, name=0x55fe6efb2979 "realized", v=0x55fe8e63ea90,
errp=0x7ffe749d2fe8) at ../qom/object.c:1450
#19 0x000055fe6e84fcc3 in object_property_set_qobject (obj=0x55fe8e654330, name=0x55fe6efb2979 "realized", value=0x55fe8ebbb0f0,
errp=0x7ffe749d2fe8) at ../qom/qom-qobject.c:28
#20 0x000055fe6e84ae8a in object_property_set_bool (obj=0x55fe8e654330, name=0x55fe6efb2979 "realized", value=true,
errp=0x7ffe749d2fe8) at ../qom/object.c:1520
#21 0x000055fe6e842c6b in qdev_realize (dev=0x55fe8e654330, bus=0x0, errp=0x7ffe749d2fe8) at ../hw/core/qdev.c:276
#22 0x000055fe6e676fef in pnv_chip_power9_pec_realize (chip=0x55fe8e64e4f0, errp=0x7ffe749d2fe8) at ../hw/ppc/pnv.c:1892
#23 0x000055fe6e677b1b in pnv_chip_power9_realize (dev=0x55fe8e64e4f0, errp=0x7ffe749d3080) at ../hw/ppc/pnv.c:2108
#24 0x000055fe6e8435be in device_set_realized (obj=0x55fe8e64e4f0, value=true, errp=0x7ffe749d3190) at ../hw/core/qdev.c:523
#25 0x000055fe6e84d060 in property_set_bool (obj=0x55fe8e64e4f0, v=0x55fe8e623cf0, name=0x55fe6efb2979 "realized",
opaque=0x55fe8e2595f0, errp=0x7ffe749d3190) at ../qom/object.c:2376
#26 0x000055fe6e84aad7 in object_property_set (obj=0x55fe8e64e4f0, name=0x55fe6efb2979 "realized", v=0x55fe8e623cf0,
errp=0x7ffe749d3190) at ../qom/object.c:1450
#27 0x000055fe6e84fcc3 in object_property_set_qobject (obj=0x55fe8e64e4f0, name=0x55fe6efb2979 "realized", value=0x55fe8e63eb90,
errp=0x55fe6f599380 <error_fatal>) at ../qom/qom-qobject.c:28
#28 0x000055fe6e84ae8a in object_property_set_bool (obj=0x55fe8e64e4f0, name=0x55fe6efb2979 "realized", value=true,
errp=0x55fe6f599380 <error_fatal>) at ../qom/object.c:1520
#29 0x000055fe6e842c6b in qdev_realize (dev=0x55fe8e64e4f0, bus=0x55fe8e6164d0, errp=0x55fe6f599380 <error_fatal>) at
../hw/core/qdev.c:276
#30 0x000055fe6e842ca4 in qdev_realize_and_unref (dev=0x55fe8e64e4f0, bus=0x55fe8e6164d0, errp=0x55fe6f599380 <error_fatal>) at
../hw/core/qdev.c:283
#31 0x000055fe6e1ee488 in sysbus_realize_and_unref (dev=0x55fe8e64e4f0, errp=0x55fe6f599380 <error_fatal>) at
../hw/core/sysbus.c:254
#32 0x000055fe6e675245 in pnv_init (machine=0x55fe8e615c80) at ../hw/ppc/pnv.c:1221
#33 0x000055fe6e1e62de in machine_run_board_init (machine=0x55fe8e615c80, mem_path=0x0, errp=0x7ffe749d3420) at
../hw/core/machine.c:1747
#34 0x000055fe6e44f235 in qemu_init_board () at ../system/vl.c:2715
#35 0x000055fe6e44f5c8 in qmp_x_exit_preconfig (errp=0x55fe6f599380 <error_fatal>) at ../system/vl.c:2809
#36 0x000055fe6e452a22 in qemu_init (argc=28, argv=0x7ffe749d37d8) at ../system/vl.c:3849
#37 0x000055fe6e99bb52 in main (argc=28, argv=0x7ffe749d37d8) at ../system/main.c:71
Looking at it:
#0 0x000055fe6e84bcc8 in object_link_get_targetp (obj=0x55fe8ebbca10, lprop=0xf) at ../qom/object.c:1871
#1 0x000055fe6e84c00f in object_set_link_property (obj=0x55fe8ebbca10, v=0x55fe8ebc81a0, name=0x55fe6ef9d504 "pec", opaque=0xf,
errp=0x7ffe749d2a00) at ../qom/object.c:1945
The opaque=0xf (15) is being passed as lprop but it should be a pointer to an ObjectLinkProperty.
Could be this:
-OBJECT_DECLARE_SIMPLE_TYPE(PnvPHB4, PNV_PHB4)
+OBJECT_DECLARE_TYPE(PnvPHB4, PnvPHB4Class, PNV_PHB4)
The following seems to fix it:
$ git diff
diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c
index 48caba9e79..0eb1e7c2bf 100644
--- a/hw/pci-host/pnv_phb4.c
+++ b/hw/pci-host/pnv_phb4.c
@@ -1998,6 +1998,7 @@ static const TypeInfo pnv_phb4_type_info = {
.parent = TYPE_DEVICE,
.instance_init = pnv_phb4_instance_init,
.instance_size = sizeof(PnvPHB4),
+ .class_size = sizeof(PnvPHB4Class),
.class_init = pnv_phb4_class_init,
.interfaces = (const InterfaceInfo[]) {
{ TYPE_XIVE_NOTIFIER },
without .class_size, QOM will allocate sizeof(DeviceClass) and heap is
corrupted.
>
> > bisect script:
> >
> > #!/bin/bash
> > cd /scm/qemu-bisect/build
> > make -j$(nproc) || exit 125
> > ninja tests/qtest/boot-serial-test || exit 125
> > QTEST_QEMU_BINARY=./qemu-system-ppc64 timeout 60 ./tests/qtest/boot-serial-test -p /ppc64/boot-serial/powernv9 && exit 0 || exit 1
> >
> >
> > > ---
> > > v1 -> v2: New PnvPHB4Class to hold each register's RO mask.
> > >
> > > hw/pci-host/pnv_phb4.c | 78 ++++++++++++++++++++++++++---
> > > include/hw/pci-host/pnv_phb4.h | 13 ++++-
> > > include/hw/pci-host/pnv_phb4_regs.h | 20 ++++++--
> > > tests/qtest/pnv-phb4-test.c | 60 +++++++++++++++++++++-
> > > 4 files changed, 157 insertions(+), 14 deletions(-)
> > >
> > > diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c
> > > index 70f5af21fa..48caba9e79 100644
> > > --- a/hw/pci-host/pnv_phb4.c
> > > +++ b/hw/pci-host/pnv_phb4.c
> > > @@ -707,6 +707,11 @@ static void pnv_phb4_reg_write(void *opaque, hwaddr off, uint64_t val,
> > > return;
> > > }
> > >
> > > + /* Update 'val' according to the register's RO-mask */
> > > + PnvPHB4Class *k = PNV_PHB4_GET_CLASS(phb);
> > > + val = (phb->regs[off >> 3] & k->ro_mask[off >> 3]) |
> > > + (val & ~(k->ro_mask[off >> 3]));
> > > +
> > > /* Record whether it changed */
> > > changed = phb->regs[off >> 3] != val;
> > >
> > > @@ -781,7 +786,7 @@ static void pnv_phb4_reg_write(void *opaque, hwaddr off, uint64_t val,
> > > case PHB_TCE_TAG_ENABLE:
> > > case PHB_INT_NOTIFY_ADDR:
> > > case PHB_INT_NOTIFY_INDEX:
> > > - case PHB_DMARD_SYNC:
> > > + case PHB_DMA_SYNC:
> > > break;
> > >
> > > /* Noise on anything else */
> > > @@ -819,7 +824,7 @@ static uint64_t pnv_phb4_reg_read(void *opaque, hwaddr off, unsigned size)
> > > case PHB_VERSION:
> > > return PNV_PHB4_PEC_GET_CLASS(phb->pec)->version;
> > >
> > > - /* Read-only */
> > > + /* Read-only */
> > > case PHB_PHB4_GEN_CAP:
> > > return 0xe4b8000000000000ull;
> > > case PHB_PHB4_TCE_CAP:
> > > @@ -829,18 +834,49 @@ static uint64_t pnv_phb4_reg_read(void *opaque, hwaddr off, unsigned size)
> > > case PHB_PHB4_EEH_CAP:
> > > return phb->big_phb ? 0x2000000000000000ull : 0x1000000000000000ull;
> > >
> > > + /* Write-only, read will return zeros */
> > > + case PHB_LEM_ERROR_AND_MASK:
> > > + case PHB_LEM_ERROR_OR_MASK:
> > > + return 0;
> > > + case PHB_PCIE_DLP_TRWCTL:
> > > + val &= ~PHB_PCIE_DLP_TRWCTL_WREN;
> > > + return val;
> > > /* IODA table accesses */
> > > case PHB_IODA_DATA0:
> > > return pnv_phb4_ioda_read(phb);
> > >
> > > + /*
> > > + * DMA sync: make it look like it's complete,
> > > + * clear write-only read/write start sync bits.
> > > + */
> > > + case PHB_DMA_SYNC:
> > > + val = PHB_DMA_SYNC_RD_COMPLETE |
> > > + ~(PHB_DMA_SYNC_RD_START | PHB_DMA_SYNC_WR_START);
> > > + return val;
> > > +
> > > + /*
> > > + * PCI-E Stack registers
> > > + */
> > > + case PHB_PCIE_SCR:
> > > + val |= PHB_PCIE_SCR_PLW_X16; /* RO bit */
> > > + break;
> > > +
> > > /* Link training always appears trained */
> > > case PHB_PCIE_DLP_TRAIN_CTL:
> > > /* TODO: Do something sensible with speed ? */
> > > - return PHB_PCIE_DLP_INBAND_PRESENCE | PHB_PCIE_DLP_TL_LINKACT;
> > > + val |= PHB_PCIE_DLP_INBAND_PRESENCE | PHB_PCIE_DLP_TL_LINKACT;
> > > + return val;
> > > +
> > > + case PHB_PCIE_HOTPLUG_STATUS:
> > > + /* Clear write-only bit */
> > > + val &= ~PHB_PCIE_HPSTAT_RESAMPLE;
> > > + return val;
> > >
> > > - /* DMA read sync: make it look like it's complete */
> > > - case PHB_DMARD_SYNC:
> > > - return PHB_DMARD_SYNC_COMPLETE;
> > > + /* Link Management Register */
> > > + case PHB_PCIE_LMR:
> > > + /* These write-only bits always read as 0 */
> > > + val &= ~(PHB_PCIE_LMR_CHANGELW | PHB_PCIE_LMR_RETRAINLINK);
> > > + return val;
> > >
> > > /* Silent simple reads */
> > > case PHB_LSI_SOURCE_ID:
> > > @@ -1685,6 +1721,32 @@ static PCIIOMMUOps pnv_phb4_iommu_ops = {
> > > .get_address_space = pnv_phb4_dma_iommu,
> > > };
> > >
> > > +static void pnv_phb4_ro_mask_init(PnvPHB4 *phb)
> > > +{
> > > + PnvPHB4Class *phb4c = PNV_PHB4_GET_CLASS(phb);
> > > +
> > > + /*
> > > + * Set register specific RO-masks
> > > + */
> > > +
> > > + /* PBL - Error Injection Register (0x1910) */
> > > + phb4c->ro_mask[PHB_PBL_ERR_INJECT >> 3] =
> > > + PPC_BITMASK(0, 23) | PPC_BITMASK(28, 35) | PPC_BIT(38) | PPC_BIT(46) |
> > > + PPC_BITMASK(49, 51) | PPC_BITMASK(55, 63);
> > > +
> > > + /* Reserved bits[60:63] */
> > > + phb4c->ro_mask[PHB_TXE_ERR_LEM_ENABLE >> 3] =
> > > + phb4c->ro_mask[PHB_TXE_ERR_AIB_FENCE_ENABLE >> 3] = PPC_BITMASK(60, 63);
> > > + /* Reserved bits[36:63] */
> > > + phb4c->ro_mask[PHB_RXE_TCE_ERR_LEM_ENABLE >> 3] =
> > > + phb4c->ro_mask[PHB_RXE_TCE_ERR_AIB_FENCE_ENABLE >> 3] = PPC_BITMASK(36, 63);
> > > + /* Reserved bits[40:63] */
> > > + phb4c->ro_mask[PHB_ERR_LEM_ENABLE >> 3] =
> > > + phb4c->ro_mask[PHB_ERR_AIB_FENCE_ENABLE >> 3] = PPC_BITMASK(40, 63);
> > > +
> > > + /* TODO: Add more RO-masks as regs are implemented in the model */
> > > +}
> > > +
> > > static void pnv_phb4_err_reg_reset(PnvPHB4 *phb)
> > > {
> > > STICKY_RST(PHB_ERR_STATUS, 0, PPC_BITMASK(0, 33));
> > > @@ -1743,6 +1805,7 @@ static void pnv_phb4_reset(Object *obj, ResetType type)
> > > pnv_phb4_err_reg_reset(phb);
> > > pnv_phb4_pcie_stack_reg_reset(phb);
> > > pnv_phb4_regb_err_reg_reset(phb);
> > > + phb->regs[PHB_PCIE_CRESET >> 3] = 0xE000000000000000;
> > > }
> > >
> > > static void pnv_phb4_instance_init(Object *obj)
> > > @@ -1753,6 +1816,9 @@ static void pnv_phb4_instance_init(Object *obj)
> > >
> > > /* XIVE interrupt source object */
> > > object_initialize_child(obj, "source", &phb->xsrc, TYPE_XIVE_SOURCE);
> > > +
> > > + /* Initialize RO-mask of registers */
> > > + pnv_phb4_ro_mask_init(phb);
> > > }
> > >
> > > void pnv_phb4_bus_init(DeviceState *dev, PnvPHB4 *phb)
> > > diff --git a/include/hw/pci-host/pnv_phb4.h b/include/hw/pci-host/pnv_phb4.h
> > > index 47a5c3edf5..bea0684724 100644
> > > --- a/include/hw/pci-host/pnv_phb4.h
> > > +++ b/include/hw/pci-host/pnv_phb4.h
> > > @@ -19,7 +19,7 @@
> > >
> > >
> > > #define TYPE_PNV_PHB4 "pnv-phb4"
> > > -OBJECT_DECLARE_SIMPLE_TYPE(PnvPHB4, PNV_PHB4)
> > > +OBJECT_DECLARE_TYPE(PnvPHB4, PnvPHB4Class, PNV_PHB4)
> > >
> > > typedef struct PnvPhb4PecStack PnvPhb4PecStack;
> > >
> > > @@ -156,6 +156,17 @@ struct PnvPHB4 {
> > > QLIST_HEAD(, PnvPhb4DMASpace) dma_spaces;
> > > };
> > >
> > > +typedef struct PnvPHB4Class {
> > > + DeviceClass parent_class;
> > > +
> > > + /*
> > > + * Read-only bitmask for registers
> > > + * Bit value: 1 => RO bit
> > > + * 0 => RW bit
> > > + */
> > > + uint64_t ro_mask[PNV_PHB4_NUM_REGS];
> > > +} PnvPHB4Class;
> > > +
> > > void pnv_phb4_pic_print_info(PnvPHB4 *phb, GString *buf);
> > > int pnv_phb4_pec_get_phb_id(PnvPhb4PecState *pec, int stack_index);
> > > PnvPhb4PecState *pnv_pec_add_phb(PnvChip *chip, PnvPHB *phb, Error **errp);
> > > diff --git a/include/hw/pci-host/pnv_phb4_regs.h b/include/hw/pci-host/pnv_phb4_regs.h
> > > index df5e86d29a..dfd0e01d1e 100644
> > > --- a/include/hw/pci-host/pnv_phb4_regs.h
> > > +++ b/include/hw/pci-host/pnv_phb4_regs.h
> > > @@ -180,9 +180,11 @@
> > > #define PHB_M64_AOMASK 0x1d0
> > > #define PHB_M64_UPPER_BITS 0x1f0
> > > #define PHB_NXLATE_PREFIX 0x1f8
> > > -#define PHB_DMARD_SYNC 0x200
> > > -#define PHB_DMARD_SYNC_START PPC_BIT(0)
> > > -#define PHB_DMARD_SYNC_COMPLETE PPC_BIT(1)
> > > +#define PHB_DMA_SYNC 0x200
> > > +#define PHB_DMA_SYNC_RD_START PPC_BIT(0)
> > > +#define PHB_DMA_SYNC_RD_COMPLETE PPC_BIT(1)
> > > +#define PHB_DMA_SYNC_WR_START PPC_BIT(2)
> > > +#define PHB_DMA_SYNC_WR_COMPLETE PPC_BIT(3)
> > > #define PHB_RTC_INVALIDATE 0x208
> > > #define PHB_RTC_INVALIDATE_ALL PPC_BIT(0)
> > > #define PHB_RTC_INVALIDATE_RID PPC_BITMASK(16, 31)
> > > @@ -370,6 +372,7 @@
> > > #define P32_CAP 0x228
> > > #define P32_CTL 0x22C
> > > #define P32_STAT 0x230
> > > +
> > > /* PHB4 REGB registers */
> > >
> > > /* PBL core */
> > > @@ -395,8 +398,8 @@
> > > #define PHB_PCIE_SCR 0x1A00
> > > #define PHB_PCIE_SCR_SLOT_CAP PPC_BIT(15)
> > > #define PHB_PCIE_SCR_MAXLINKSPEED PPC_BITMASK(32, 35)
> > > +#define PHB_PCIE_SCR_PLW_X16 PPC_BIT(41) /* x16 */
> > > #define PHB_PCIE_BNR 0x1A08
> > > -
> > > #define PHB_PCIE_CRESET 0x1A10
> > > #define PHB_PCIE_CRESET_CFG_CORE PPC_BIT(0)
> > > #define PHB_PCIE_CRESET_TLDLP PPC_BIT(1)
> > > @@ -405,7 +408,14 @@
> > > #define PHB_PCIE_CRESET_PIPE_N PPC_BIT(4)
> > > #define PHB_PCIE_CRESET_REFCLK_N PPC_BIT(8)
> > > #define PHB_PCIE_HOTPLUG_STATUS 0x1A20
> > > +#define PHB_PCIE_HPSTAT_SIMDIAG PPC_BIT(3)
> > > +#define PHB_PCIE_HPSTAT_RESAMPLE PPC_BIT(9)
> > > #define PHB_PCIE_HPSTAT_PRESENCE PPC_BIT(10)
> > > +#define PHB_PCIE_HPSTAT_LINKACTIVE PPC_BIT(12)
> > > +#define PHB_PCIE_LMR 0x1A30
> > > +#define PHB_PCIE_LMR_CHANGELW PPC_BIT(0)
> > > +#define PHB_PCIE_LMR_RETRAINLINK PPC_BIT(1)
> > > +#define PHB_PCIE_LMR_LINKACTIVE PPC_BIT(8)
> > >
> > > #define PHB_PCIE_DLP_TRAIN_CTL 0x1A40
> > > #define PHB_PCIE_DLP_LINK_WIDTH PPC_BITMASK(30, 35)
> > > @@ -433,7 +443,7 @@
> > >
> > > #define PHB_PCIE_DLP_TRWCTL 0x1A80
> > > #define PHB_PCIE_DLP_TRWCTL_EN PPC_BIT(0)
> > > -
> > > +#define PHB_PCIE_DLP_TRWCTL_WREN PPC_BIT(1)
> > > #define PHB_PCIE_DLP_ERRLOG1 0x1AA0
> > > #define PHB_PCIE_DLP_ERRLOG2 0x1AA8
> > > #define PHB_PCIE_DLP_ERR_STATUS 0x1AB0
> > > diff --git a/tests/qtest/pnv-phb4-test.c b/tests/qtest/pnv-phb4-test.c
> > > index f186efaf0d..841306ae3f 100644
> > > --- a/tests/qtest/pnv-phb4-test.c
> > > +++ b/tests/qtest/pnv-phb4-test.c
> > > @@ -73,7 +73,8 @@ static void phb4_sticky_rst_test(QTestState *qts)
> > > * Sticky reset test of PHB_PBL_ERR_STATUS.
> > > *
> > > * Write all 1's to reg PHB_PBL_ERR_INJECT.
> > > - * Updated value will be copied to reg PHB_PBL_ERR_STATUS.
> > > + * RO-only bits will not be written and
> > > + * updated value will be copied to reg PHB_PBL_ERR_STATUS.
> > > *
> > > * Reset PBL core by setting PHB_PCIE_CRESET_PBL in reg PHB_PCIE_CRESET.
> > > * Verify the sticky bits are still set.
> > > @@ -81,7 +82,59 @@ static void phb4_sticky_rst_test(QTestState *qts)
> > > phb4_xscom_write(PHB_PBL_ERR_INJECT, PPC_BITMASK(0, 63));
> > > phb4_xscom_write(PHB_PCIE_CRESET, PHB_PCIE_CRESET_PBL); /*Reset*/
> > > val = phb4_xscom_read(PHB_PBL_ERR_STATUS);
> > > - g_assert_cmpuint(val, ==, (PPC_BITMASK(0, 9) | PPC_BITMASK(12, 63)));
> > > + g_assert_cmpuint(val, ==, 0xF00DFD8E00);
> > > +}
> > > +
> > > +/* Check that write-only bits/regs return 0 when read */
> > > +static void phb4_writeonly_read_test(QTestState *qts)
> > > +{
> > > + uint64_t val;
> > > +
> > > + /*
> > > + * Set all bits of PHB_DMA_SYNC,
> > > + * bits 0 and 2 are write-only and should be read as 0.
> > > + */
> > > + phb4_xscom_write(PHB_DMA_SYNC, PPC_BITMASK(0, 63));
> > > + val = phb4_xscom_read(PHB_DMA_SYNC);
> > > + g_assert_cmpuint(val & PPC_BIT(0), ==, 0x0);
> > > + g_assert_cmpuint(val & PPC_BIT(2), ==, 0x0);
> > > +
> > > + /*
> > > + * Set all bits of PHB_PCIE_HOTPLUG_STATUS,
> > > + * bit 9 is write-only and should be read as 0.
> > > + */
> > > + phb4_xscom_write(PHB_PCIE_HOTPLUG_STATUS, PPC_BITMASK(0, 63));
> > > + val = phb4_xscom_read(PHB_PCIE_HOTPLUG_STATUS);
> > > + g_assert_cmpuint(val & PPC_BIT(9), ==, 0x0);
> > > +
> > > + /*
> > > + * Set all bits of PHB_PCIE_LMR,
> > > + * bits 0 and 1 are write-only and should be read as 0.
> > > + */
> > > + phb4_xscom_write(PHB_PCIE_LMR, PPC_BITMASK(0, 63));
> > > + val = phb4_xscom_read(PHB_PCIE_LMR);
> > > + g_assert_cmpuint(val & PPC_BIT(0), ==, 0x0);
> > > + g_assert_cmpuint(val & PPC_BIT(1), ==, 0x0);
> > > +
> > > + /*
> > > + * Set all bits of PHB_PCIE_DLP_TRWCTL,
> > > + * write-only bit-1 should be read as 0.
> > > + */
> > > + phb4_xscom_write(PHB_PCIE_DLP_TRWCTL, PPC_BITMASK(0, 63));
> > > + val = phb4_xscom_read(PHB_PCIE_DLP_TRWCTL);
> > > + g_assert_cmpuint(val & PPC_BIT(1), ==, 0x0);
> > > +
> > > + /*
> > > + * Set all bits of PHB_LEM_ERROR_AND_MASK, PHB_LEM_ERROR_OR_MASK,
> > > + * both regs are write-only and should be read as 0.
> > > + */
> > > + phb4_xscom_write(PHB_LEM_ERROR_AND_MASK, PPC_BITMASK(0, 63));
> > > + val = phb4_xscom_read(PHB_LEM_ERROR_AND_MASK);
> > > + g_assert_cmpuint(val, ==, 0x0);
> > > +
> > > + phb4_xscom_write(PHB_LEM_ERROR_OR_MASK, PPC_BITMASK(0, 63));
> > > + val = phb4_xscom_read(PHB_LEM_ERROR_OR_MASK);
> > > + g_assert_cmpuint(val, ==, 0x0);
> > > }
> > >
> > > static void phb4_tests(void)
> > > @@ -96,6 +149,9 @@ static void phb4_tests(void)
> > > /* Check sticky reset of a register */
> > > phb4_sticky_rst_test(qts);
> > >
> > > + /* Check write-only logic */
> > > + phb4_writeonly_read_test(qts);
> > > +
> > > qtest_quit(qts);
> > > }
> > >
> > > --
> > > 2.47.3
^ permalink raw reply related [flat|nested] 60+ messages in thread
* Re: [PATCH v2 4/9] pnv/phb4: Implement read-only and write-only bits of registers
2026-02-04 6:42 ` Michael S. Tsirkin
@ 2026-02-09 5:35 ` Saif Abrar
0 siblings, 0 replies; 60+ messages in thread
From: Saif Abrar @ 2026-02-09 5:35 UTC (permalink / raw)
To: Michael S. Tsirkin
Cc: qemu-ppc, qemu-devel, clg, npiggin, fbarrat, marcel.apfelbaum,
cohuck, pbonzini, thuth, lvivier, danielhb413
[-- Attachment #1: Type: text/plain, Size: 23775 bytes --]
Hello Michael,
Thanks for the analysis!
I'll send the next patchset with your fix.
Regards,
Saif
On 04-02-2026 12:12 pm, Michael S. Tsirkin wrote:
> On Wed, Feb 04, 2026 at 12:12:01AM -0500, Michael S. Tsirkin wrote:
>> On Wed, Feb 04, 2026 at 12:04:20AM -0500, Michael S. Tsirkin wrote:
>>> On Tue, Dec 30, 2025 at 04:21:22AM -0600, Saif Abrar wrote:
>>>> SW cannot write the read-only(RO) bits of a register
>>>> and write-only(WO) bits of a register return 0 when read.
>>>>
>>>> Added ro_mask[] for each register that defines which
>>>> bits in that register are RO.
>>>> When writing to a register, the RO-bits are not updated.
>>>>
>>>> When reading a register, clear the WO bits and return the updated value.
>>>>
>>>> Tested the registers PHB_DMA_SYNC, PHB_PCIE_HOTPLUG_STATUS, PHB_PCIE_LMR,
>>>> PHB_PCIE_DLP_TRWCTL, PHB_LEM_ERROR_AND_MASK and PHB_LEM_ERROR_OR_MASK
>>>> by writing all 1's and reading back the value.
>>>> The WO bits in these registers should read back as 0.
>>>>
>>>> Signed-off-by: Saif Abrar<saif.abrar@linux.vnet.ibm.com>
>>>> Reviewed-by: Cédric Le Goater<clg@kaod.org>
>>> causes a crash in boot-serial-test:
>>> https://gitlab.com/mstredhat/qemu/-/jobs/12975819193
>> I forgot to say - with tci:
>>
>> ../configure --enable-tcg-interpreter --target-list=ppc64-softmmu
> triggered with tcg now, too.
>
> Core was generated by `/scm/qemu-bisect/build/qemu-system-ppc64 -qtest unix:/tmp/qtest-194326.sock -qtest-log /dev/null -chardev
> socket,path=/tmp/qtest-194326.qmp,id=char0 -mon chardev=char0,mode=control -display none -audio none -run-with
> exit-with-parent=on -M powernv9 -no-shutdown -chardev file,id=serial0,path=/tmp/qtest-boot-serial-sVOZKK3 -serial
> chardev:serial0 -accel tcg -accel kvm -accel qtest'.
> Program terminated with signal SIGSEGV, Segmentation fault.
> #0 0x000055fe6e84bcc8 in object_link_get_targetp (obj=0x55fe8ebbca10, lprop=0xf) at ../qom/object.c:1871
> 1871 if (lprop->flags & OBJ_PROP_LINK_DIRECT) {
> [Current thread is 1 (Thread 0x7f2716e774c0 (LWP 194336))]
> warning: File "/scm/qemu/.gdbinit" auto-loading has been declined by your `auto-load safe-path' set to
> "$debugdir:$datadir/auto-load:/usr/lib/golang/src/runtime/runtime-gdb.py".
> To enable execution of this file add
> add-auto-load-safe-path /scm/qemu/.gdbinit
> line to your configuration file "/home/mst/.config/gdb/gdbinit".
> To completely disable this security protection add
> set auto-load safe-path /
> line to your configuration file "/home/mst/.config/gdb/gdbinit".
> For more information about this security protection see the
> "Auto-loading safe path" section in the GDB manual. E.g., run from the shell:
> info "(gdb)Auto-loading safe path"
> #0 0x000055fe6e84bcc8 in object_link_get_targetp (obj=0x55fe8ebbca10, lprop=0xf) at ../qom/object.c:1871
> #1 0x000055fe6e84c00f in object_set_link_property (obj=0x55fe8ebbca10, v=0x55fe8ebc81a0, name=0x55fe6ef9d504 "pec", opaque=0xf,
> errp=0x7ffe749d2a00) at ../qom/object.c:1945
> #2 0x000055fe6e84aad7 in object_property_set (obj=0x55fe8ebbca10, name=0x55fe6ef9d504 "pec", v=0x55fe8ebc81a0,
> errp=0x7ffe749d2a00) at ../qom/object.c:1450
> #3 0x000055fe6e84fcc3 in object_property_set_qobject (obj=0x55fe8ebbca10, name=0x55fe6ef9d504 "pec", value=0x55fe8ebc8520,
> errp=0x7ffe749d2a00) at ../qom/qom-qobject.c:28
> #4 0x000055fe6e84ab7b in object_property_set_str (obj=0x55fe8ebbca10, name=0x55fe6ef9d504 "pec", value=0x55fe8ebbc8e0
> "/machine/chip[0]/pec[0]", errp=0x7ffe749d2a00) at ../qom/object.c:1458
> #5 0x000055fe6e84ad30 in object_property_set_link (obj=0x55fe8ebbca10, name=0x55fe6ef9d504 "pec", value=0x55fe8e654330,
> errp=0x7ffe749d2a00) at ../qom/object.c:1495
> #6 0x000055fe6e7fb1ff in pnv_phb_realize (dev=0x55fe8ebbb960, errp=0x7ffe749d2a00) at ../hw/pci-host/pnv_phb.c:156
> #7 0x000055fe6e8435be in device_set_realized (obj=0x55fe8ebbb960, value=true, errp=0x7ffe749d2d60) at ../hw/core/qdev.c:523
> #8 0x000055fe6e84d060 in property_set_bool (obj=0x55fe8ebbb960, v=0x55fe8e70db20, name=0x55fe6efb2979 "realized",
> opaque=0x55fe8e2595f0, errp=0x7ffe749d2d60) at ../qom/object.c:2376
> #9 0x000055fe6e84aad7 in object_property_set (obj=0x55fe8ebbb960, name=0x55fe6efb2979 "realized", v=0x55fe8e70db20,
> errp=0x7ffe749d2d60) at ../qom/object.c:1450
> #10 0x000055fe6e84fcc3 in object_property_set_qobject (obj=0x55fe8ebbb960, name=0x55fe6efb2979 "realized", value=0x55fe8ebbc860,
> errp=0x7ffe749d2d60) at ../qom/qom-qobject.c:28
> #11 0x000055fe6e84ae8a in object_property_set_bool (obj=0x55fe8ebbb960, name=0x55fe6efb2979 "realized", value=true,
> errp=0x7ffe749d2d60) at ../qom/object.c:1520
> #12 0x000055fe6e842c6b in qdev_realize (dev=0x55fe8ebbb960, bus=0x55fe8e6164d0, errp=0x7ffe749d2d60) at ../hw/core/qdev.c:276
> #13 0x000055fe6e1ee440 in sysbus_realize (dev=0x55fe8ebbb960, errp=0x7ffe749d2d60) at ../hw/core/sysbus.c:249
> #14 0x000055fe6e7f9901 in pnv_pec_default_phb_realize (pec=0x55fe8e654330, stack_no=0, errp=0x7ffe749d2d60) at
> ../hw/pci-host/pnv_phb4_pec.c:194
> #15 0x000055fe6e7f9bc0 in pnv_pec_realize (dev=0x55fe8e654330, errp=0x7ffe749d2d60) at ../hw/pci-host/pnv_phb4_pec.c:258
> #16 0x000055fe6e8435be in device_set_realized (obj=0x55fe8e654330, value=true, errp=0x7ffe749d2fe8) at ../hw/core/qdev.c:523
> #17 0x000055fe6e84d060 in property_set_bool (obj=0x55fe8e654330, v=0x55fe8e63ea90, name=0x55fe6efb2979 "realized",
> opaque=0x55fe8e2595f0, errp=0x7ffe749d2fe8) at ../qom/object.c:2376
> #18 0x000055fe6e84aad7 in object_property_set (obj=0x55fe8e654330, name=0x55fe6efb2979 "realized", v=0x55fe8e63ea90,
> errp=0x7ffe749d2fe8) at ../qom/object.c:1450
> #19 0x000055fe6e84fcc3 in object_property_set_qobject (obj=0x55fe8e654330, name=0x55fe6efb2979 "realized", value=0x55fe8ebbb0f0,
> errp=0x7ffe749d2fe8) at ../qom/qom-qobject.c:28
> #20 0x000055fe6e84ae8a in object_property_set_bool (obj=0x55fe8e654330, name=0x55fe6efb2979 "realized", value=true,
> errp=0x7ffe749d2fe8) at ../qom/object.c:1520
> #21 0x000055fe6e842c6b in qdev_realize (dev=0x55fe8e654330, bus=0x0, errp=0x7ffe749d2fe8) at ../hw/core/qdev.c:276
> #22 0x000055fe6e676fef in pnv_chip_power9_pec_realize (chip=0x55fe8e64e4f0, errp=0x7ffe749d2fe8) at ../hw/ppc/pnv.c:1892
> #23 0x000055fe6e677b1b in pnv_chip_power9_realize (dev=0x55fe8e64e4f0, errp=0x7ffe749d3080) at ../hw/ppc/pnv.c:2108
> #24 0x000055fe6e8435be in device_set_realized (obj=0x55fe8e64e4f0, value=true, errp=0x7ffe749d3190) at ../hw/core/qdev.c:523
> #25 0x000055fe6e84d060 in property_set_bool (obj=0x55fe8e64e4f0, v=0x55fe8e623cf0, name=0x55fe6efb2979 "realized",
> opaque=0x55fe8e2595f0, errp=0x7ffe749d3190) at ../qom/object.c:2376
> #26 0x000055fe6e84aad7 in object_property_set (obj=0x55fe8e64e4f0, name=0x55fe6efb2979 "realized", v=0x55fe8e623cf0,
> errp=0x7ffe749d3190) at ../qom/object.c:1450
> #27 0x000055fe6e84fcc3 in object_property_set_qobject (obj=0x55fe8e64e4f0, name=0x55fe6efb2979 "realized", value=0x55fe8e63eb90,
> errp=0x55fe6f599380 <error_fatal>) at ../qom/qom-qobject.c:28
> #28 0x000055fe6e84ae8a in object_property_set_bool (obj=0x55fe8e64e4f0, name=0x55fe6efb2979 "realized", value=true,
> errp=0x55fe6f599380 <error_fatal>) at ../qom/object.c:1520
> #29 0x000055fe6e842c6b in qdev_realize (dev=0x55fe8e64e4f0, bus=0x55fe8e6164d0, errp=0x55fe6f599380 <error_fatal>) at
> ../hw/core/qdev.c:276
> #30 0x000055fe6e842ca4 in qdev_realize_and_unref (dev=0x55fe8e64e4f0, bus=0x55fe8e6164d0, errp=0x55fe6f599380 <error_fatal>) at
> ../hw/core/qdev.c:283
> #31 0x000055fe6e1ee488 in sysbus_realize_and_unref (dev=0x55fe8e64e4f0, errp=0x55fe6f599380 <error_fatal>) at
> ../hw/core/sysbus.c:254
> #32 0x000055fe6e675245 in pnv_init (machine=0x55fe8e615c80) at ../hw/ppc/pnv.c:1221
> #33 0x000055fe6e1e62de in machine_run_board_init (machine=0x55fe8e615c80, mem_path=0x0, errp=0x7ffe749d3420) at
> ../hw/core/machine.c:1747
> #34 0x000055fe6e44f235 in qemu_init_board () at ../system/vl.c:2715
> #35 0x000055fe6e44f5c8 in qmp_x_exit_preconfig (errp=0x55fe6f599380 <error_fatal>) at ../system/vl.c:2809
> #36 0x000055fe6e452a22 in qemu_init (argc=28, argv=0x7ffe749d37d8) at ../system/vl.c:3849
> #37 0x000055fe6e99bb52 in main (argc=28, argv=0x7ffe749d37d8) at ../system/main.c:71
>
>
>
> Looking at it:
>
> #0 0x000055fe6e84bcc8 in object_link_get_targetp (obj=0x55fe8ebbca10, lprop=0xf) at ../qom/object.c:1871
> #1 0x000055fe6e84c00f in object_set_link_property (obj=0x55fe8ebbca10, v=0x55fe8ebc81a0, name=0x55fe6ef9d504 "pec", opaque=0xf,
> errp=0x7ffe749d2a00) at ../qom/object.c:1945
>
>
> The opaque=0xf (15) is being passed as lprop but it should be a pointer to an ObjectLinkProperty.
>
> Could be this:
> -OBJECT_DECLARE_SIMPLE_TYPE(PnvPHB4, PNV_PHB4)
> +OBJECT_DECLARE_TYPE(PnvPHB4, PnvPHB4Class, PNV_PHB4)
>
> The following seems to fix it:
>
> $ git diff
> diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c
> index 48caba9e79..0eb1e7c2bf 100644
> --- a/hw/pci-host/pnv_phb4.c
> +++ b/hw/pci-host/pnv_phb4.c
> @@ -1998,6 +1998,7 @@ static const TypeInfo pnv_phb4_type_info = {
> .parent = TYPE_DEVICE,
> .instance_init = pnv_phb4_instance_init,
> .instance_size = sizeof(PnvPHB4),
> + .class_size = sizeof(PnvPHB4Class),
> .class_init = pnv_phb4_class_init,
> .interfaces = (const InterfaceInfo[]) {
> { TYPE_XIVE_NOTIFIER },
>
>
> without .class_size, QOM will allocate sizeof(DeviceClass) and heap is
> corrupted.
>
>>> bisect script:
>>>
>>> #!/bin/bash
>>> cd /scm/qemu-bisect/build
>>> make -j$(nproc) || exit 125
>>> ninja tests/qtest/boot-serial-test || exit 125
>>> QTEST_QEMU_BINARY=./qemu-system-ppc64 timeout 60 ./tests/qtest/boot-serial-test -p /ppc64/boot-serial/powernv9 && exit 0 || exit 1
>>>
>>>
>>>> ---
>>>> v1 -> v2: New PnvPHB4Class to hold each register's RO mask.
>>>>
>>>> hw/pci-host/pnv_phb4.c | 78 ++++++++++++++++++++++++++---
>>>> include/hw/pci-host/pnv_phb4.h | 13 ++++-
>>>> include/hw/pci-host/pnv_phb4_regs.h | 20 ++++++--
>>>> tests/qtest/pnv-phb4-test.c | 60 +++++++++++++++++++++-
>>>> 4 files changed, 157 insertions(+), 14 deletions(-)
>>>>
>>>> diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c
>>>> index 70f5af21fa..48caba9e79 100644
>>>> --- a/hw/pci-host/pnv_phb4.c
>>>> +++ b/hw/pci-host/pnv_phb4.c
>>>> @@ -707,6 +707,11 @@ static void pnv_phb4_reg_write(void *opaque, hwaddr off, uint64_t val,
>>>> return;
>>>> }
>>>>
>>>> + /* Update 'val' according to the register's RO-mask */
>>>> + PnvPHB4Class *k = PNV_PHB4_GET_CLASS(phb);
>>>> + val = (phb->regs[off >> 3] & k->ro_mask[off >> 3]) |
>>>> + (val & ~(k->ro_mask[off >> 3]));
>>>> +
>>>> /* Record whether it changed */
>>>> changed = phb->regs[off >> 3] != val;
>>>>
>>>> @@ -781,7 +786,7 @@ static void pnv_phb4_reg_write(void *opaque, hwaddr off, uint64_t val,
>>>> case PHB_TCE_TAG_ENABLE:
>>>> case PHB_INT_NOTIFY_ADDR:
>>>> case PHB_INT_NOTIFY_INDEX:
>>>> - case PHB_DMARD_SYNC:
>>>> + case PHB_DMA_SYNC:
>>>> break;
>>>>
>>>> /* Noise on anything else */
>>>> @@ -819,7 +824,7 @@ static uint64_t pnv_phb4_reg_read(void *opaque, hwaddr off, unsigned size)
>>>> case PHB_VERSION:
>>>> return PNV_PHB4_PEC_GET_CLASS(phb->pec)->version;
>>>>
>>>> - /* Read-only */
>>>> + /* Read-only */
>>>> case PHB_PHB4_GEN_CAP:
>>>> return 0xe4b8000000000000ull;
>>>> case PHB_PHB4_TCE_CAP:
>>>> @@ -829,18 +834,49 @@ static uint64_t pnv_phb4_reg_read(void *opaque, hwaddr off, unsigned size)
>>>> case PHB_PHB4_EEH_CAP:
>>>> return phb->big_phb ? 0x2000000000000000ull : 0x1000000000000000ull;
>>>>
>>>> + /* Write-only, read will return zeros */
>>>> + case PHB_LEM_ERROR_AND_MASK:
>>>> + case PHB_LEM_ERROR_OR_MASK:
>>>> + return 0;
>>>> + case PHB_PCIE_DLP_TRWCTL:
>>>> + val &= ~PHB_PCIE_DLP_TRWCTL_WREN;
>>>> + return val;
>>>> /* IODA table accesses */
>>>> case PHB_IODA_DATA0:
>>>> return pnv_phb4_ioda_read(phb);
>>>>
>>>> + /*
>>>> + * DMA sync: make it look like it's complete,
>>>> + * clear write-only read/write start sync bits.
>>>> + */
>>>> + case PHB_DMA_SYNC:
>>>> + val = PHB_DMA_SYNC_RD_COMPLETE |
>>>> + ~(PHB_DMA_SYNC_RD_START | PHB_DMA_SYNC_WR_START);
>>>> + return val;
>>>> +
>>>> + /*
>>>> + * PCI-E Stack registers
>>>> + */
>>>> + case PHB_PCIE_SCR:
>>>> + val |= PHB_PCIE_SCR_PLW_X16; /* RO bit */
>>>> + break;
>>>> +
>>>> /* Link training always appears trained */
>>>> case PHB_PCIE_DLP_TRAIN_CTL:
>>>> /* TODO: Do something sensible with speed ? */
>>>> - return PHB_PCIE_DLP_INBAND_PRESENCE | PHB_PCIE_DLP_TL_LINKACT;
>>>> + val |= PHB_PCIE_DLP_INBAND_PRESENCE | PHB_PCIE_DLP_TL_LINKACT;
>>>> + return val;
>>>> +
>>>> + case PHB_PCIE_HOTPLUG_STATUS:
>>>> + /* Clear write-only bit */
>>>> + val &= ~PHB_PCIE_HPSTAT_RESAMPLE;
>>>> + return val;
>>>>
>>>> - /* DMA read sync: make it look like it's complete */
>>>> - case PHB_DMARD_SYNC:
>>>> - return PHB_DMARD_SYNC_COMPLETE;
>>>> + /* Link Management Register */
>>>> + case PHB_PCIE_LMR:
>>>> + /* These write-only bits always read as 0 */
>>>> + val &= ~(PHB_PCIE_LMR_CHANGELW | PHB_PCIE_LMR_RETRAINLINK);
>>>> + return val;
>>>>
>>>> /* Silent simple reads */
>>>> case PHB_LSI_SOURCE_ID:
>>>> @@ -1685,6 +1721,32 @@ static PCIIOMMUOps pnv_phb4_iommu_ops = {
>>>> .get_address_space = pnv_phb4_dma_iommu,
>>>> };
>>>>
>>>> +static void pnv_phb4_ro_mask_init(PnvPHB4 *phb)
>>>> +{
>>>> + PnvPHB4Class *phb4c = PNV_PHB4_GET_CLASS(phb);
>>>> +
>>>> + /*
>>>> + * Set register specific RO-masks
>>>> + */
>>>> +
>>>> + /* PBL - Error Injection Register (0x1910) */
>>>> + phb4c->ro_mask[PHB_PBL_ERR_INJECT >> 3] =
>>>> + PPC_BITMASK(0, 23) | PPC_BITMASK(28, 35) | PPC_BIT(38) | PPC_BIT(46) |
>>>> + PPC_BITMASK(49, 51) | PPC_BITMASK(55, 63);
>>>> +
>>>> + /* Reserved bits[60:63] */
>>>> + phb4c->ro_mask[PHB_TXE_ERR_LEM_ENABLE >> 3] =
>>>> + phb4c->ro_mask[PHB_TXE_ERR_AIB_FENCE_ENABLE >> 3] = PPC_BITMASK(60, 63);
>>>> + /* Reserved bits[36:63] */
>>>> + phb4c->ro_mask[PHB_RXE_TCE_ERR_LEM_ENABLE >> 3] =
>>>> + phb4c->ro_mask[PHB_RXE_TCE_ERR_AIB_FENCE_ENABLE >> 3] = PPC_BITMASK(36, 63);
>>>> + /* Reserved bits[40:63] */
>>>> + phb4c->ro_mask[PHB_ERR_LEM_ENABLE >> 3] =
>>>> + phb4c->ro_mask[PHB_ERR_AIB_FENCE_ENABLE >> 3] = PPC_BITMASK(40, 63);
>>>> +
>>>> + /* TODO: Add more RO-masks as regs are implemented in the model */
>>>> +}
>>>> +
>>>> static void pnv_phb4_err_reg_reset(PnvPHB4 *phb)
>>>> {
>>>> STICKY_RST(PHB_ERR_STATUS, 0, PPC_BITMASK(0, 33));
>>>> @@ -1743,6 +1805,7 @@ static void pnv_phb4_reset(Object *obj, ResetType type)
>>>> pnv_phb4_err_reg_reset(phb);
>>>> pnv_phb4_pcie_stack_reg_reset(phb);
>>>> pnv_phb4_regb_err_reg_reset(phb);
>>>> + phb->regs[PHB_PCIE_CRESET >> 3] = 0xE000000000000000;
>>>> }
>>>>
>>>> static void pnv_phb4_instance_init(Object *obj)
>>>> @@ -1753,6 +1816,9 @@ static void pnv_phb4_instance_init(Object *obj)
>>>>
>>>> /* XIVE interrupt source object */
>>>> object_initialize_child(obj, "source", &phb->xsrc, TYPE_XIVE_SOURCE);
>>>> +
>>>> + /* Initialize RO-mask of registers */
>>>> + pnv_phb4_ro_mask_init(phb);
>>>> }
>>>>
>>>> void pnv_phb4_bus_init(DeviceState *dev, PnvPHB4 *phb)
>>>> diff --git a/include/hw/pci-host/pnv_phb4.h b/include/hw/pci-host/pnv_phb4.h
>>>> index 47a5c3edf5..bea0684724 100644
>>>> --- a/include/hw/pci-host/pnv_phb4.h
>>>> +++ b/include/hw/pci-host/pnv_phb4.h
>>>> @@ -19,7 +19,7 @@
>>>>
>>>>
>>>> #define TYPE_PNV_PHB4 "pnv-phb4"
>>>> -OBJECT_DECLARE_SIMPLE_TYPE(PnvPHB4, PNV_PHB4)
>>>> +OBJECT_DECLARE_TYPE(PnvPHB4, PnvPHB4Class, PNV_PHB4)
>>>>
>>>> typedef struct PnvPhb4PecStack PnvPhb4PecStack;
>>>>
>>>> @@ -156,6 +156,17 @@ struct PnvPHB4 {
>>>> QLIST_HEAD(, PnvPhb4DMASpace) dma_spaces;
>>>> };
>>>>
>>>> +typedef struct PnvPHB4Class {
>>>> + DeviceClass parent_class;
>>>> +
>>>> + /*
>>>> + * Read-only bitmask for registers
>>>> + * Bit value: 1 => RO bit
>>>> + * 0 => RW bit
>>>> + */
>>>> + uint64_t ro_mask[PNV_PHB4_NUM_REGS];
>>>> +} PnvPHB4Class;
>>>> +
>>>> void pnv_phb4_pic_print_info(PnvPHB4 *phb, GString *buf);
>>>> int pnv_phb4_pec_get_phb_id(PnvPhb4PecState *pec, int stack_index);
>>>> PnvPhb4PecState *pnv_pec_add_phb(PnvChip *chip, PnvPHB *phb, Error **errp);
>>>> diff --git a/include/hw/pci-host/pnv_phb4_regs.h b/include/hw/pci-host/pnv_phb4_regs.h
>>>> index df5e86d29a..dfd0e01d1e 100644
>>>> --- a/include/hw/pci-host/pnv_phb4_regs.h
>>>> +++ b/include/hw/pci-host/pnv_phb4_regs.h
>>>> @@ -180,9 +180,11 @@
>>>> #define PHB_M64_AOMASK 0x1d0
>>>> #define PHB_M64_UPPER_BITS 0x1f0
>>>> #define PHB_NXLATE_PREFIX 0x1f8
>>>> -#define PHB_DMARD_SYNC 0x200
>>>> -#define PHB_DMARD_SYNC_START PPC_BIT(0)
>>>> -#define PHB_DMARD_SYNC_COMPLETE PPC_BIT(1)
>>>> +#define PHB_DMA_SYNC 0x200
>>>> +#define PHB_DMA_SYNC_RD_START PPC_BIT(0)
>>>> +#define PHB_DMA_SYNC_RD_COMPLETE PPC_BIT(1)
>>>> +#define PHB_DMA_SYNC_WR_START PPC_BIT(2)
>>>> +#define PHB_DMA_SYNC_WR_COMPLETE PPC_BIT(3)
>>>> #define PHB_RTC_INVALIDATE 0x208
>>>> #define PHB_RTC_INVALIDATE_ALL PPC_BIT(0)
>>>> #define PHB_RTC_INVALIDATE_RID PPC_BITMASK(16, 31)
>>>> @@ -370,6 +372,7 @@
>>>> #define P32_CAP 0x228
>>>> #define P32_CTL 0x22C
>>>> #define P32_STAT 0x230
>>>> +
>>>> /* PHB4 REGB registers */
>>>>
>>>> /* PBL core */
>>>> @@ -395,8 +398,8 @@
>>>> #define PHB_PCIE_SCR 0x1A00
>>>> #define PHB_PCIE_SCR_SLOT_CAP PPC_BIT(15)
>>>> #define PHB_PCIE_SCR_MAXLINKSPEED PPC_BITMASK(32, 35)
>>>> +#define PHB_PCIE_SCR_PLW_X16 PPC_BIT(41) /* x16 */
>>>> #define PHB_PCIE_BNR 0x1A08
>>>> -
>>>> #define PHB_PCIE_CRESET 0x1A10
>>>> #define PHB_PCIE_CRESET_CFG_CORE PPC_BIT(0)
>>>> #define PHB_PCIE_CRESET_TLDLP PPC_BIT(1)
>>>> @@ -405,7 +408,14 @@
>>>> #define PHB_PCIE_CRESET_PIPE_N PPC_BIT(4)
>>>> #define PHB_PCIE_CRESET_REFCLK_N PPC_BIT(8)
>>>> #define PHB_PCIE_HOTPLUG_STATUS 0x1A20
>>>> +#define PHB_PCIE_HPSTAT_SIMDIAG PPC_BIT(3)
>>>> +#define PHB_PCIE_HPSTAT_RESAMPLE PPC_BIT(9)
>>>> #define PHB_PCIE_HPSTAT_PRESENCE PPC_BIT(10)
>>>> +#define PHB_PCIE_HPSTAT_LINKACTIVE PPC_BIT(12)
>>>> +#define PHB_PCIE_LMR 0x1A30
>>>> +#define PHB_PCIE_LMR_CHANGELW PPC_BIT(0)
>>>> +#define PHB_PCIE_LMR_RETRAINLINK PPC_BIT(1)
>>>> +#define PHB_PCIE_LMR_LINKACTIVE PPC_BIT(8)
>>>>
>>>> #define PHB_PCIE_DLP_TRAIN_CTL 0x1A40
>>>> #define PHB_PCIE_DLP_LINK_WIDTH PPC_BITMASK(30, 35)
>>>> @@ -433,7 +443,7 @@
>>>>
>>>> #define PHB_PCIE_DLP_TRWCTL 0x1A80
>>>> #define PHB_PCIE_DLP_TRWCTL_EN PPC_BIT(0)
>>>> -
>>>> +#define PHB_PCIE_DLP_TRWCTL_WREN PPC_BIT(1)
>>>> #define PHB_PCIE_DLP_ERRLOG1 0x1AA0
>>>> #define PHB_PCIE_DLP_ERRLOG2 0x1AA8
>>>> #define PHB_PCIE_DLP_ERR_STATUS 0x1AB0
>>>> diff --git a/tests/qtest/pnv-phb4-test.c b/tests/qtest/pnv-phb4-test.c
>>>> index f186efaf0d..841306ae3f 100644
>>>> --- a/tests/qtest/pnv-phb4-test.c
>>>> +++ b/tests/qtest/pnv-phb4-test.c
>>>> @@ -73,7 +73,8 @@ static void phb4_sticky_rst_test(QTestState *qts)
>>>> * Sticky reset test of PHB_PBL_ERR_STATUS.
>>>> *
>>>> * Write all 1's to reg PHB_PBL_ERR_INJECT.
>>>> - * Updated value will be copied to reg PHB_PBL_ERR_STATUS.
>>>> + * RO-only bits will not be written and
>>>> + * updated value will be copied to reg PHB_PBL_ERR_STATUS.
>>>> *
>>>> * Reset PBL core by setting PHB_PCIE_CRESET_PBL in reg PHB_PCIE_CRESET.
>>>> * Verify the sticky bits are still set.
>>>> @@ -81,7 +82,59 @@ static void phb4_sticky_rst_test(QTestState *qts)
>>>> phb4_xscom_write(PHB_PBL_ERR_INJECT, PPC_BITMASK(0, 63));
>>>> phb4_xscom_write(PHB_PCIE_CRESET, PHB_PCIE_CRESET_PBL); /*Reset*/
>>>> val = phb4_xscom_read(PHB_PBL_ERR_STATUS);
>>>> - g_assert_cmpuint(val, ==, (PPC_BITMASK(0, 9) | PPC_BITMASK(12, 63)));
>>>> + g_assert_cmpuint(val, ==, 0xF00DFD8E00);
>>>> +}
>>>> +
>>>> +/* Check that write-only bits/regs return 0 when read */
>>>> +static void phb4_writeonly_read_test(QTestState *qts)
>>>> +{
>>>> + uint64_t val;
>>>> +
>>>> + /*
>>>> + * Set all bits of PHB_DMA_SYNC,
>>>> + * bits 0 and 2 are write-only and should be read as 0.
>>>> + */
>>>> + phb4_xscom_write(PHB_DMA_SYNC, PPC_BITMASK(0, 63));
>>>> + val = phb4_xscom_read(PHB_DMA_SYNC);
>>>> + g_assert_cmpuint(val & PPC_BIT(0), ==, 0x0);
>>>> + g_assert_cmpuint(val & PPC_BIT(2), ==, 0x0);
>>>> +
>>>> + /*
>>>> + * Set all bits of PHB_PCIE_HOTPLUG_STATUS,
>>>> + * bit 9 is write-only and should be read as 0.
>>>> + */
>>>> + phb4_xscom_write(PHB_PCIE_HOTPLUG_STATUS, PPC_BITMASK(0, 63));
>>>> + val = phb4_xscom_read(PHB_PCIE_HOTPLUG_STATUS);
>>>> + g_assert_cmpuint(val & PPC_BIT(9), ==, 0x0);
>>>> +
>>>> + /*
>>>> + * Set all bits of PHB_PCIE_LMR,
>>>> + * bits 0 and 1 are write-only and should be read as 0.
>>>> + */
>>>> + phb4_xscom_write(PHB_PCIE_LMR, PPC_BITMASK(0, 63));
>>>> + val = phb4_xscom_read(PHB_PCIE_LMR);
>>>> + g_assert_cmpuint(val & PPC_BIT(0), ==, 0x0);
>>>> + g_assert_cmpuint(val & PPC_BIT(1), ==, 0x0);
>>>> +
>>>> + /*
>>>> + * Set all bits of PHB_PCIE_DLP_TRWCTL,
>>>> + * write-only bit-1 should be read as 0.
>>>> + */
>>>> + phb4_xscom_write(PHB_PCIE_DLP_TRWCTL, PPC_BITMASK(0, 63));
>>>> + val = phb4_xscom_read(PHB_PCIE_DLP_TRWCTL);
>>>> + g_assert_cmpuint(val & PPC_BIT(1), ==, 0x0);
>>>> +
>>>> + /*
>>>> + * Set all bits of PHB_LEM_ERROR_AND_MASK, PHB_LEM_ERROR_OR_MASK,
>>>> + * both regs are write-only and should be read as 0.
>>>> + */
>>>> + phb4_xscom_write(PHB_LEM_ERROR_AND_MASK, PPC_BITMASK(0, 63));
>>>> + val = phb4_xscom_read(PHB_LEM_ERROR_AND_MASK);
>>>> + g_assert_cmpuint(val, ==, 0x0);
>>>> +
>>>> + phb4_xscom_write(PHB_LEM_ERROR_OR_MASK, PPC_BITMASK(0, 63));
>>>> + val = phb4_xscom_read(PHB_LEM_ERROR_OR_MASK);
>>>> + g_assert_cmpuint(val, ==, 0x0);
>>>> }
>>>>
>>>> static void phb4_tests(void)
>>>> @@ -96,6 +149,9 @@ static void phb4_tests(void)
>>>> /* Check sticky reset of a register */
>>>> phb4_sticky_rst_test(qts);
>>>>
>>>> + /* Check write-only logic */
>>>> + phb4_writeonly_read_test(qts);
>>>> +
>>>> qtest_quit(qts);
>>>> }
>>>>
>>>> --
>>>> 2.47.3
[-- Attachment #2: Type: text/html, Size: 28297 bytes --]
^ permalink raw reply [flat|nested] 60+ messages in thread
* [PATCH v3 0/9] : pnv/phb4: Update PHB4 to the latest PHB5 spec
2025-12-30 10:21 [PATCH v2 0/9] pnv/phb4: Update PHB4 to the latest PHB5 spec Saif Abrar
` (8 preceding siblings ...)
2025-12-30 10:21 ` [PATCH v2 9/9] pnv/phb4: Mask off LSI Source-ID based on number of interrupts Saif Abrar
@ 2026-02-10 13:40 ` Saif Abrar
2026-02-10 13:40 ` [PATCH v3 1/9] qtest/phb4: Add testbench for PHB4 Saif Abrar
` (11 more replies)
9 siblings, 12 replies; 60+ messages in thread
From: Saif Abrar @ 2026-02-10 13:40 UTC (permalink / raw)
To: qemu-ppc, qemu-devel
Cc: clg, npiggin, fbarrat, mst, marcel.apfelbaum, cohuck, pbonzini,
thuth, lvivier, danielhb413, saif.abrar
Hello,
Addressing the review comments for the series v2:
https://lists.gnu.org/archive/html/qemu-devel/2025-12/msg03768.html
This series updates the existing PHB4 model to the latest spec:
"Power Systems Host Bridge 5 (PHB5) Functional Specification Version 0.5_00".
Updates include the following:
- implemented sticky reset logic
- implemented read-only, write-only, W1C and WxC logic
- return all 1's on read to unimplemented registers
- update PCIE registers for link status, speed and width
- implement IODA PCT debug table without any functionality
- update LSI Source-ID register based on small/big PHB number of interrupts
Also, a new testbench for PHB4 model is added that does XSCOM read/writes
to various registers of interest and verifies the values.
Regards.
Saif Abrar (9):
qtest/phb4: Add testbench for PHB4
pnv/phb4: Add reset logic to PHB4
pnv/phb4: Implement sticky reset logic in PHB4
pnv/phb4: Implement read-only and write-only bits of registers
pnv/phb4: Implement write-clear and return 1's on unimplemented reg read
pnv/phb4: Set link-active status in HPSTAT and LMR registers
pnv/phb4: Set link speed and width in the DLP training control register
pnv/phb4: Implement IODA PCT table
pnv/phb4: Mask off LSI Source-ID based on number of interrupts
hw/pci-host/pnv_phb.c | 1 +
hw/pci-host/pnv_phb4.c | 583 +++++++++++++++++++++++++---
include/hw/pci-host/pnv_phb4.h | 16 +-
include/hw/pci-host/pnv_phb4_regs.h | 66 +++-
tests/qtest/meson.build | 1 +
tests/qtest/pnv-phb4-test.c | 228 +++++++++++
6 files changed, 837 insertions(+), 58 deletions(-)
create mode 100644 tests/qtest/pnv-phb4-test.c
--
2.47.3
^ permalink raw reply [flat|nested] 60+ messages in thread
* [PATCH v3 1/9] qtest/phb4: Add testbench for PHB4
2026-02-10 13:40 ` [PATCH v3 0/9] : pnv/phb4: Update PHB4 to the latest PHB5 spec Saif Abrar
@ 2026-02-10 13:40 ` Saif Abrar
2026-02-10 13:40 ` [PATCH v3 2/9] pnv/phb4: Add reset logic to PHB4 Saif Abrar
` (10 subsequent siblings)
11 siblings, 0 replies; 60+ messages in thread
From: Saif Abrar @ 2026-02-10 13:40 UTC (permalink / raw)
To: qemu-ppc, qemu-devel
Cc: clg, npiggin, fbarrat, mst, marcel.apfelbaum, cohuck, pbonzini,
thuth, lvivier, danielhb413, saif.abrar
New qtest testbench added for PHB[345].
Testbench reads PHB Version register and asserts that
bits[24:31] have value 0xA3, 0xA4 and 0xA5 respectively.
Signed-off-by: Saif Abrar <saif.abrar@linux.vnet.ibm.com>
Reviewed-by: Cédric Le Goater <clg@kaod.org>
---
v3: Updates for coding guidelines.
v2: Added version check for PHB3 and PHB4 also.
tests/qtest/meson.build | 1 +
tests/qtest/pnv-phb4-test.c | 98 +++++++++++++++++++++++++++++++++++++
2 files changed, 99 insertions(+)
create mode 100644 tests/qtest/pnv-phb4-test.c
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index dfb83650c6..593c3c4560 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -184,6 +184,7 @@ qtests_ppc64 = \
(config_all_devices.has_key('CONFIG_POWERNV') ? ['pnv-xive2-test'] : []) + \
(config_all_devices.has_key('CONFIG_POWERNV') ? ['pnv-spi-seeprom-test'] : []) + \
(config_all_devices.has_key('CONFIG_POWERNV') ? ['pnv-host-i2c-test'] : []) + \
+ (config_all_devices.has_key('CONFIG_POWERNV') ? ['pnv-phb4-test'] : []) + \
(config_all_devices.has_key('CONFIG_PSERIES') ? ['numa-test'] : []) + \
(config_all_devices.has_key('CONFIG_PSERIES') ? ['rtas-test'] : []) + \
(slirp.found() ? ['pxe-test'] : []) + \
diff --git a/tests/qtest/pnv-phb4-test.c b/tests/qtest/pnv-phb4-test.c
new file mode 100644
index 0000000000..797f6b6c87
--- /dev/null
+++ b/tests/qtest/pnv-phb4-test.c
@@ -0,0 +1,98 @@
+/*
+ * QTest testcase for PowerNV PHB4
+ *
+ * Copyright (c) 2025, IBM Corporation.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "hw/pci-host/pnv_phb4_regs.h"
+#include "pnv-xscom.h"
+
+#define PPC_BIT(bit) (0x8000000000000000ULL >> (bit))
+#define PPC_BITMASK(bs, be) ((PPC_BIT(bs) - PPC_BIT(be)) | PPC_BIT(bs))
+
+#define PHB3_PBCQ_SPCI_ASB_ADDR 0x0
+#define PHB3_PBCQ_SPCI_ASB_DATA 0x2
+
+/* Index of PNV_CHIP_POWER10 in pnv_chips[] within "pnv-xscom.h" */
+#define PNV_P10_CHIP_INDEX 3
+#define PHB4_XSCOM 0x40084800ull
+
+/*
+ * Indirect XSCOM read::
+ * - Write 'Indirect Address Register' with register-offset to read.
+ * - Read 'Indirect Data Register' to get the value.
+ */
+static uint64_t pnv_phb_xscom_read(QTestState *qts, const PnvChip *chip,
+ uint64_t scom, uint32_t indirect_addr, uint32_t indirect_data,
+ uint64_t reg)
+{
+ qtest_writeq(qts, pnv_xscom_addr(chip, (scom >> 3) + indirect_addr), reg);
+ return qtest_readq(qts, pnv_xscom_addr(chip, (scom >> 3) + indirect_data));
+}
+
+/* Assert that 'PHB - Version Register' bits[24:31] are as expected */
+static void phb_version_test(const void *data)
+{
+ const PnvChip *chip = (PnvChip *)data;
+ QTestState *qts;
+ const char *machine = "powernv8";
+ uint64_t phb_xscom = 0x4809e000;
+ uint64_t reg_phb_version = PHB_VERSION;
+ uint32_t indirect_addr = PHB3_PBCQ_SPCI_ASB_ADDR;
+ uint32_t indirect_data = PHB3_PBCQ_SPCI_ASB_DATA;
+ uint32_t expected_ver = 0xA3;
+ uint64_t ver;
+
+ if (chip->chip_type == PNV_CHIP_POWER9) {
+ machine = "powernv9";
+ phb_xscom = 0x68084800;
+ indirect_addr = PHB_SCOM_HV_IND_ADDR;
+ indirect_data = PHB_SCOM_HV_IND_DATA;
+ reg_phb_version |= PPC_BIT(0);
+ expected_ver = 0xA4;
+ } else if (chip->chip_type == PNV_CHIP_POWER10) {
+ machine = "powernv10";
+ phb_xscom = PHB4_XSCOM;
+ indirect_addr = PHB_SCOM_HV_IND_ADDR;
+ indirect_data = PHB_SCOM_HV_IND_DATA;
+ reg_phb_version |= PPC_BIT(0);
+ expected_ver = 0xA5;
+ }
+
+ qts = qtest_initf("-M %s -accel tcg -cpu %s", machine, chip->cpu_model);
+
+ ver = pnv_phb_xscom_read(qts, chip, phb_xscom,
+ indirect_addr, indirect_data, reg_phb_version);
+
+ /* PHB Version register bits [24:31] */
+ ver = ver >> (63 - 31);
+ g_assert_cmpuint(ver, ==, expected_ver);
+
+ qtest_quit(qts);
+}
+
+/* Verify versions of all supported PHB's */
+static void add_phbX_version_test(void)
+{
+ for (int i = 0; i < ARRAY_SIZE(pnv_chips); i++) {
+ char *tname = g_strdup_printf("pnv-phb/%s",
+ pnv_chips[i].cpu_model);
+ qtest_add_data_func(tname, &pnv_chips[i], phb_version_test);
+ g_free(tname);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ g_test_init(&argc, &argv, NULL);
+
+ /* PHB[345] tests */
+ add_phbX_version_test();
+
+ return g_test_run();
+}
--
2.47.3
^ permalink raw reply related [flat|nested] 60+ messages in thread
* [PATCH v3 2/9] pnv/phb4: Add reset logic to PHB4
2026-02-10 13:40 ` [PATCH v3 0/9] : pnv/phb4: Update PHB4 to the latest PHB5 spec Saif Abrar
2026-02-10 13:40 ` [PATCH v3 1/9] qtest/phb4: Add testbench for PHB4 Saif Abrar
@ 2026-02-10 13:40 ` Saif Abrar
2026-02-10 13:40 ` [PATCH v3 3/9] pnv/phb4: Implement sticky reset logic in PHB4 Saif Abrar
` (9 subsequent siblings)
11 siblings, 0 replies; 60+ messages in thread
From: Saif Abrar @ 2026-02-10 13:40 UTC (permalink / raw)
To: qemu-ppc, qemu-devel
Cc: clg, npiggin, fbarrat, mst, marcel.apfelbaum, cohuck, pbonzini,
thuth, lvivier, danielhb413, saif.abrar
Add a method to be invoked on QEMU reset.
Also add CFG and PBL core-blocks reset logic using
appropriate bits of PHB_PCIE_CRESET register.
Tested by reading the reset value of a register.
Signed-off-by: Saif Abrar <saif.abrar@linux.vnet.ibm.com>
Reviewed-by: Cédric Le Goater <clg@kaod.org>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
---
v3: Updates for coding guidelines.
v2:
- Using the ResettableClass.
- Reset of the root complex registers done in pnv_phb_root_port_reset_hold().
hw/pci-host/pnv_phb.c | 1 +
hw/pci-host/pnv_phb4.c | 102 +++++++++++++++++++++++++++-
include/hw/pci-host/pnv_phb4.h | 1 +
include/hw/pci-host/pnv_phb4_regs.h | 16 ++++-
tests/qtest/pnv-phb4-test.c | 28 +++++++-
5 files changed, 144 insertions(+), 4 deletions(-)
diff --git a/hw/pci-host/pnv_phb.c b/hw/pci-host/pnv_phb.c
index 0b556d1bf5..d4f452d7b2 100644
--- a/hw/pci-host/pnv_phb.c
+++ b/hw/pci-host/pnv_phb.c
@@ -232,6 +232,7 @@ static void pnv_phb_root_port_reset_hold(Object *obj, ResetType type)
pci_set_long(conf + PCI_PREF_BASE_UPPER32, 0x1); /* Hack */
pci_set_long(conf + PCI_PREF_LIMIT_UPPER32, 0xffffffff);
pci_config_set_interrupt_pin(conf, 0);
+ pnv_phb4_cfg_core_reset(d);
}
static void pnv_phb_root_port_realize(DeviceState *dev, Error **errp)
diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c
index 396bc47817..8334ffe42f 100644
--- a/hw/pci-host/pnv_phb4.c
+++ b/hw/pci-host/pnv_phb4.c
@@ -1,7 +1,8 @@
/*
* QEMU PowerPC PowerNV (POWER9) PHB4 model
+ * QEMU PowerPC PowerNV (POWER10) PHB5 model
*
- * Copyright (c) 2018-2020, IBM Corporation.
+ * Copyright (c) 2018-2025, IBM Corporation.
*
* This code is licensed under the GPL version 2 or later. See the
* COPYING file in the top-level directory.
@@ -22,6 +23,7 @@
#include "hw/core/qdev-properties.h"
#include "qom/object.h"
#include "trace.h"
+#include "system/reset.h"
#define phb_error(phb, fmt, ...) \
qemu_log_mask(LOG_GUEST_ERROR, "phb4[%d:%d]: " fmt "\n", \
@@ -499,6 +501,80 @@ static void pnv_phb4_update_xsrc(PnvPHB4 *phb)
}
}
+/*
+ * Get the PCI-E capability offset from the root-port
+ */
+static uint32_t get_exp_offset(PCIDevice *pdev)
+{
+ PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(pdev);
+ return rpc->exp_offset;
+}
+
+void pnv_phb4_cfg_core_reset(PCIDevice *d)
+{
+ uint8_t *conf = d->config;
+
+ pci_set_word(conf + PCI_COMMAND, PCI_COMMAND_SERR);
+ pci_set_word(conf + PCI_STATUS, PCI_STATUS_CAP_LIST);
+ pci_set_long(conf + PCI_CLASS_REVISION, 0x06040000);
+ pci_set_long(conf + PCI_CACHE_LINE_SIZE, BIT(16));
+ pci_set_word(conf + PCI_MEMORY_BASE, BIT(4));
+ pci_set_word(conf + PCI_PREF_MEMORY_BASE, BIT(0) | BIT(4));
+ pci_set_word(conf + PCI_PREF_MEMORY_LIMIT, PCI_PREF_RANGE_TYPE_64);
+ pci_set_long(conf + PCI_CAPABILITY_LIST, BIT(6));
+ pci_set_long(conf + PCI_CAPABILITY_LIST, BIT(6));
+ pci_set_word(conf + PCI_BRIDGE_CONTROL, PCI_BRIDGE_CTL_SERR);
+ pci_set_long(conf + PCI_BRIDGE_CONTROL + PCI_PM_PMC, 0xC8034801);
+
+ uint32_t exp_offset = get_exp_offset(d);
+ pci_set_long(conf + exp_offset, 0x420010);
+ pci_set_long(conf + exp_offset + PCI_EXP_DEVCAP, 0x8022);
+ pci_set_long(conf + exp_offset + PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_EXT_TAG
+ | PCI_EXP_DEVCTL_PAYLOAD_512B);
+ pci_set_long(conf + exp_offset + PCI_EXP_LNKCAP, PCI_EXP_LNKCAP_LBNC
+ | PCI_EXP_LNKCAP_DLLLARC | BIT(8) | PCI_EXP_LNKCAP_SLS_32_0GB);
+ pci_set_word(conf + exp_offset + PCI_EXP_LNKCTL, PCI_EXP_LNKCTL_RCB);
+ pci_set_word(conf + exp_offset + PCI_EXP_LNKSTA,
+ (PCI_EXP_LNKSTA_NLW_X8 << 2) | PCI_EXP_LNKSTA_CLS_2_5GB);
+ pci_set_long(conf + exp_offset + PCI_EXP_SLTCTL,
+ PCI_EXP_SLTCTL_ASPL_DISABLE);
+ pci_set_long(conf + exp_offset + PCI_EXP_DEVCAP2, BIT(16)
+ | PCI_EXP_DEVCAP2_ARI | PCI_EXP_DEVCAP2_COMP_TMOUT_DIS | 0xF);
+ pci_set_long(conf + exp_offset + PCI_EXP_DEVCTL2, PCI_EXP_DEVCTL2_ARI);
+ pci_set_long(conf + exp_offset + PCI_EXP_LNKCAP2, BIT(23)
+ | PCI_EXP_LNKCAP2_SLS_32_0GB
+ | PCI_EXP_LNKCAP2_SLS_16_0GB | PCI_EXP_LNKCAP2_SLS_8_0GB
+ | PCI_EXP_LNKCAP2_SLS_5_0GB | PCI_EXP_LNKCAP2_SLS_2_5GB);
+ pci_set_long(conf + PHB_AER_ECAP, PCI_EXT_CAP(0x1, 0x1, 0x148));
+ pci_set_long(conf + PHB_SEC_ECAP, (0x1A0 << 20) | BIT(16)
+ | PCI_EXT_CAP_ID_SECPCI);
+ pci_set_long(conf + PHB_LMR_ECAP, 0x1E810027);
+ /* LMR - Margining Lane Control / Status Register # 2 to 16 */
+ for (int i = PHB_LMR_CTLSTA_2 ; i <= PHB_LMR_CTLSTA_16 ; i += 4) {
+ pci_set_long(conf + i, 0x9C38);
+ }
+
+ pci_set_long(conf + PHB_DLF_ECAP, 0x1F410025);
+ pci_set_long(conf + PHB_DLF_CAP, 0x80000001);
+ pci_set_long(conf + P16_ECAP, 0x22410026);
+ pci_set_long(conf + P32_ECAP, 0x1002A);
+ pci_set_long(conf + P32_CAP, 0x103);
+}
+
+static void pnv_phb4_pbl_core_reset(PnvPHB4 *phb)
+{
+ /* Zero all registers initially */
+ for (int i = PHB_PBL_CONTROL ; i <= PHB_PBL_ERR1_STATUS_MASK ; i += 8) {
+ phb->regs[i >> 3] = 0x0;
+ }
+
+ /* Set specific register values */
+ phb->regs[PHB_PBL_CONTROL >> 3] = 0xC009000000000000;
+ phb->regs[PHB_PBL_TIMEOUT_CTRL >> 3] = 0x2020000000000000;
+ phb->regs[PHB_PBL_NPTAG_ENABLE >> 3] = 0xFFFFFFFF00000000;
+ phb->regs[PHB_PBL_SYS_LINK_INIT >> 3] = 0x80088B4642473000;
+}
+
static void pnv_phb4_reg_write(void *opaque, hwaddr off, uint64_t val,
unsigned size)
{
@@ -612,6 +688,18 @@ static void pnv_phb4_reg_write(void *opaque, hwaddr off, uint64_t val,
pnv_phb4_update_xsrc(phb);
break;
+ /* Reset core blocks */
+ case PHB_PCIE_CRESET:
+ if (val & PHB_PCIE_CRESET_CFG_CORE) {
+ PCIHostState *pci = PCI_HOST_BRIDGE(phb->phb_base);
+
+ pnv_phb4_cfg_core_reset(pci_find_device(pci->bus, 0, 0));
+ }
+ if (val & PHB_PCIE_CRESET_PBL) {
+ pnv_phb4_pbl_core_reset(phb);
+ }
+ break;
+
/* Silent simple writes */
case PHB_ASN_CMPM:
case PHB_CONFIG_ADDRESS:
@@ -1532,6 +1620,13 @@ static PCIIOMMUOps pnv_phb4_iommu_ops = {
.get_address_space = pnv_phb4_dma_iommu,
};
+static void pnv_phb4_reset(Object *obj, ResetType type)
+{
+ PnvPHB4 *phb = PNV_PHB4(obj);
+
+ pnv_phb4_pbl_core_reset(phb);
+}
+
static void pnv_phb4_instance_init(Object *obj)
{
PnvPHB4 *phb = PNV_PHB4(obj);
@@ -1608,6 +1703,8 @@ static void pnv_phb4_realize(DeviceState *dev, Error **errp)
phb->qirqs = qemu_allocate_irqs(xive_source_set_irq, xsrc, xsrc->nr_irqs);
pnv_phb4_xscom_realize(phb);
+
+ qemu_register_resettable(OBJECT(dev));
}
/*
@@ -1701,12 +1798,15 @@ static void pnv_phb4_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
XiveNotifierClass *xfc = XIVE_NOTIFIER_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
dc->realize = pnv_phb4_realize;
device_class_set_props(dc, pnv_phb4_properties);
dc->user_creatable = false;
xfc->notify = pnv_phb4_xive_notify;
+
+ rc->phases.enter = pnv_phb4_reset;
}
static const TypeInfo pnv_phb4_type_info = {
diff --git a/include/hw/pci-host/pnv_phb4.h b/include/hw/pci-host/pnv_phb4.h
index de996e718b..47a5c3edf5 100644
--- a/include/hw/pci-host/pnv_phb4.h
+++ b/include/hw/pci-host/pnv_phb4.h
@@ -160,6 +160,7 @@ void pnv_phb4_pic_print_info(PnvPHB4 *phb, GString *buf);
int pnv_phb4_pec_get_phb_id(PnvPhb4PecState *pec, int stack_index);
PnvPhb4PecState *pnv_pec_add_phb(PnvChip *chip, PnvPHB *phb, Error **errp);
void pnv_phb4_bus_init(DeviceState *dev, PnvPHB4 *phb);
+void pnv_phb4_cfg_core_reset(PCIDevice *d);
extern const MemoryRegionOps pnv_phb4_xscom_ops;
/*
diff --git a/include/hw/pci-host/pnv_phb4_regs.h b/include/hw/pci-host/pnv_phb4_regs.h
index bea96f4d91..6892e21cc9 100644
--- a/include/hw/pci-host/pnv_phb4_regs.h
+++ b/include/hw/pci-host/pnv_phb4_regs.h
@@ -343,6 +343,18 @@
#define PHB_RC_CONFIG_BASE 0x1000
#define PHB_RC_CONFIG_SIZE 0x800
+#define PHB_AER_ECAP 0x100
+#define PHB_AER_CAPCTRL 0x118
+#define PHB_SEC_ECAP 0x148
+#define PHB_LMR_ECAP 0x1A0
+#define PHB_LMR_CTLSTA_2 0x1AC
+#define PHB_LMR_CTLSTA_16 0x1E4
+#define PHB_DLF_ECAP 0x1E8
+#define PHB_DLF_CAP 0x1EC
+#define P16_ECAP 0x1F4
+#define P32_ECAP 0x224
+#define P32_CAP 0x228
+
/* PHB4 REGB registers */
/* PBL core */
@@ -368,7 +380,7 @@
#define PHB_PCIE_SCR 0x1A00
#define PHB_PCIE_SCR_SLOT_CAP PPC_BIT(15)
#define PHB_PCIE_SCR_MAXLINKSPEED PPC_BITMASK(32, 35)
-
+#define PHB_PCIE_BNR 0x1A08
#define PHB_PCIE_CRESET 0x1A10
#define PHB_PCIE_CRESET_CFG_CORE PPC_BIT(0)
@@ -423,6 +435,8 @@
#define PHB_PCIE_LANE_EQ_CNTL23 0x1B08 /* DD1 only */
#define PHB_PCIE_TRACE_CTRL 0x1B20
#define PHB_PCIE_MISC_STRAP 0x1B30
+#define PHB_PCIE_PHY_RXEQ_STAT_G3_00_03 0x1B40
+#define PHB_PCIE_PHY_RXEQ_STAT_G5_12_15 0x1B98
/* Error */
#define PHB_REGB_ERR_STATUS 0x1C00
diff --git a/tests/qtest/pnv-phb4-test.c b/tests/qtest/pnv-phb4-test.c
index 797f6b6c87..8cd6c1bc59 100644
--- a/tests/qtest/pnv-phb4-test.c
+++ b/tests/qtest/pnv-phb4-test.c
@@ -35,6 +35,29 @@ static uint64_t pnv_phb_xscom_read(QTestState *qts, const PnvChip *chip,
return qtest_readq(qts, pnv_xscom_addr(chip, (scom >> 3) + indirect_data));
}
+#define PHB4_XSCOM_READ(a) pnv_phb_xscom_read(qts, \
+ &pnv_chips[PNV_P10_CHIP_INDEX], PHB4_XSCOM, \
+ PHB_SCOM_HV_IND_ADDR, PHB_SCOM_HV_IND_DATA, \
+ PPC_BIT(0) | (a))
+
+/* Assert that 'PHB PBL Control' register has correct reset value */
+static void phb4_reset_test(QTestState *qts)
+{
+ g_assert_cmpuint(PHB4_XSCOM_READ(PHB_PBL_CONTROL), ==, 0xC009000000000000);
+}
+
+static void phb4_tests(void)
+{
+ QTestState *qts = NULL;
+
+ qts = qtest_initf("-machine powernv10 -accel tcg");
+
+ /* Check reset value of a register */
+ phb4_reset_test(qts);
+
+ qtest_quit(qts);
+}
+
/* Assert that 'PHB - Version Register' bits[24:31] are as expected */
static void phb_version_test(const void *data)
{
@@ -72,8 +95,6 @@ static void phb_version_test(const void *data)
/* PHB Version register bits [24:31] */
ver = ver >> (63 - 31);
g_assert_cmpuint(ver, ==, expected_ver);
-
- qtest_quit(qts);
}
/* Verify versions of all supported PHB's */
@@ -94,5 +115,8 @@ int main(int argc, char **argv)
/* PHB[345] tests */
add_phbX_version_test();
+ /* PHB4 specific tests */
+ qtest_add_func("phb4", phb4_tests);
+
return g_test_run();
}
--
2.47.3
^ permalink raw reply related [flat|nested] 60+ messages in thread
* [PATCH v3 3/9] pnv/phb4: Implement sticky reset logic in PHB4
2026-02-10 13:40 ` [PATCH v3 0/9] : pnv/phb4: Update PHB4 to the latest PHB5 spec Saif Abrar
2026-02-10 13:40 ` [PATCH v3 1/9] qtest/phb4: Add testbench for PHB4 Saif Abrar
2026-02-10 13:40 ` [PATCH v3 2/9] pnv/phb4: Add reset logic to PHB4 Saif Abrar
@ 2026-02-10 13:40 ` Saif Abrar
2026-02-10 13:40 ` [PATCH v3 4/9] pnv/phb4: Implement read-only and write-only bits of registers Saif Abrar
` (8 subsequent siblings)
11 siblings, 0 replies; 60+ messages in thread
From: Saif Abrar @ 2026-02-10 13:40 UTC (permalink / raw)
To: qemu-ppc, qemu-devel
Cc: clg, npiggin, fbarrat, mst, marcel.apfelbaum, cohuck, pbonzini,
thuth, lvivier, danielhb413, saif.abrar
Sticky bits retain their values on reset and are not overwritten with
the reset value.
Added sticky reset logic for all required registers,
i.e. CFG core, PBL core, PHB error registers, PCIE stack registers and
REGB error registers.
Tested by writing all 1's to the reg PHB_PBL_ERR_INJECT.
This will set the bits in the reg PHB_PBL_ERR_STATUS.
Reset the PBL core by setting PHB_PCIE_CRESET_PBL in reg PHB_PCIE_CRESET.
Verify that the sticky bits in the PHB_PBL_ERR_STATUS reg are still set.
Signed-off-by: Saif Abrar <saif.abrar@linux.vnet.ibm.com>
---
v3: Updates for coding guidelines.
hw/pci-host/pnv_phb4.c | 125 +++++++++++++++++++++++++++-
include/hw/pci-host/pnv_phb4_regs.h | 20 ++++-
tests/qtest/pnv-phb4-test.c | 41 +++++++++
3 files changed, 180 insertions(+), 6 deletions(-)
diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c
index 8334ffe42f..961888e952 100644
--- a/hw/pci-host/pnv_phb4.c
+++ b/hw/pci-host/pnv_phb4.c
@@ -510,9 +510,22 @@ static uint32_t get_exp_offset(PCIDevice *pdev)
return rpc->exp_offset;
}
+/*
+ * Apply sticky-mask 's' to the reset-value 'v' and write to the address 'a'.
+ * RC-config space values and masks are LE.
+ * Method pnv_phb4_rc_config_read() returns BE, hence convert to LE.
+ * Compute new value in LE domain.
+ * New value computation using sticky-mask is in LE.
+ * Convert the computed value from LE to BE before writing back.
+ */
+#define RC_CONFIG_STICKY_RESET(a, v, s) \
+ (pci_set_word(conf + (a), bswap32( \
+ (bswap32(pci_get_word(conf + (a))) & (s)) | ((v) & ~(s)))))
+
void pnv_phb4_cfg_core_reset(PCIDevice *d)
{
uint8_t *conf = d->config;
+ uint32_t exp_offset = get_exp_offset(d);
pci_set_word(conf + PCI_COMMAND, PCI_COMMAND_SERR);
pci_set_word(conf + PCI_STATUS, PCI_STATUS_CAP_LIST);
@@ -526,7 +539,6 @@ void pnv_phb4_cfg_core_reset(PCIDevice *d)
pci_set_word(conf + PCI_BRIDGE_CONTROL, PCI_BRIDGE_CTL_SERR);
pci_set_long(conf + PCI_BRIDGE_CONTROL + PCI_PM_PMC, 0xC8034801);
- uint32_t exp_offset = get_exp_offset(d);
pci_set_long(conf + exp_offset, 0x420010);
pci_set_long(conf + exp_offset + PCI_EXP_DEVCAP, 0x8022);
pci_set_long(conf + exp_offset + PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_EXT_TAG
@@ -559,14 +571,56 @@ void pnv_phb4_cfg_core_reset(PCIDevice *d)
pci_set_long(conf + P16_ECAP, 0x22410026);
pci_set_long(conf + P32_ECAP, 0x1002A);
pci_set_long(conf + P32_CAP, 0x103);
+
+ /* Sticky reset */
+ RC_CONFIG_STICKY_RESET(exp_offset + PCI_EXP_LNKCTL2,
+ PCI_EXP_LNKCTL2_TLS_32_0GT, 0xFEFFBF);
+ RC_CONFIG_STICKY_RESET(PHB_AER_UERR, 0, 0x1FF030);
+ RC_CONFIG_STICKY_RESET(PHB_AER_UERR_MASK, 0, 0x1FF030);
+ RC_CONFIG_STICKY_RESET(PHB_AER_CERR, 0, 0x11C1);
+ RC_CONFIG_STICKY_RESET(PHB_AER_ECAP + PCI_ERR_CAP, (PCI_ERR_CAP_ECRC_CHKC
+ | PCI_ERR_CAP_ECRC_GENC), 0x15F);
+ RC_CONFIG_STICKY_RESET(PHB_AER_HLOG_1, 0, 0xFFFFFFFF);
+ RC_CONFIG_STICKY_RESET(PHB_AER_HLOG_2, 0, 0xFFFFFFFF);
+ RC_CONFIG_STICKY_RESET(PHB_AER_HLOG_3, 0, 0xFFFFFFFF);
+ RC_CONFIG_STICKY_RESET(PHB_AER_HLOG_4, 0, 0xFFFFFFFF);
+ RC_CONFIG_STICKY_RESET(PHB_AER_RERR, 0, 0x7F);
+ RC_CONFIG_STICKY_RESET(PHB_AER_ESID, 0, 0xFFFFFFFF);
+ RC_CONFIG_STICKY_RESET(PHB_DLF_STAT, 0, 0x807FFFFF);
+ RC_CONFIG_STICKY_RESET(P16_STAT, 0, 0x1F);
+ RC_CONFIG_STICKY_RESET(P16_LDPM, 0, 0xFFFF);
+ RC_CONFIG_STICKY_RESET(P16_FRDPM, 0, 0xFFFF);
+ RC_CONFIG_STICKY_RESET(P16_SRDPM, 0, 0xFFFF);
+ RC_CONFIG_STICKY_RESET(P32_CTL, 0, 0x3);
}
+/* Apply sticky-mask to the reset-value and write to the reg-address */
+#define STICKY_RST(addr, rst_val, sticky_mask) (phb->regs[addr >> 3] = \
+ ((phb->regs[addr >> 3] & sticky_mask) | (rst_val & ~sticky_mask)))
+
static void pnv_phb4_pbl_core_reset(PnvPHB4 *phb)
{
- /* Zero all registers initially */
+ /*
+ * Zero all registers initially,
+ * with sticky reset of certain registers.
+ */
for (int i = PHB_PBL_CONTROL ; i <= PHB_PBL_ERR1_STATUS_MASK ; i += 8) {
- phb->regs[i >> 3] = 0x0;
+ switch (i) {
+ case PHB_PBL_ERR_STATUS:
+ break;
+ case PHB_PBL_ERR1_STATUS:
+ case PHB_PBL_ERR_LOG_0:
+ case PHB_PBL_ERR_LOG_1:
+ case PHB_PBL_ERR_STATUS_MASK:
+ case PHB_PBL_ERR1_STATUS_MASK:
+ STICKY_RST(i, 0, PPC_BITMASK(0, 63));
+ break;
+ default:
+ phb->regs[i >> 3] = 0x0;
+ }
}
+ STICKY_RST(PHB_PBL_ERR_STATUS, 0, \
+ (PPC_BITMASK(0, 9) | PPC_BITMASK(12, 63)));
/* Set specific register values */
phb->regs[PHB_PBL_CONTROL >> 3] = 0xC009000000000000;
@@ -700,6 +754,17 @@ static void pnv_phb4_reg_write(void *opaque, hwaddr off, uint64_t val,
}
break;
+ /*
+ * Writing bits to a 1 in this register will inject the error corresponding
+ * to the bit that is written. The bits will automatically clear to 0 after
+ * the error is injected. The corresponding bit in the Error Status Reg
+ * should also be set automatically when the error occurs.
+ */
+ case PHB_PBL_ERR_INJECT:
+ phb->regs[PHB_PBL_ERR_STATUS >> 3] = phb->regs[off >> 3];
+ phb->regs[off >> 3] = 0;
+ break;
+
/* Silent simple writes */
case PHB_ASN_CMPM:
case PHB_CONFIG_ADDRESS:
@@ -1620,11 +1685,65 @@ static PCIIOMMUOps pnv_phb4_iommu_ops = {
.get_address_space = pnv_phb4_dma_iommu,
};
+static void pnv_phb4_err_reg_reset(PnvPHB4 *phb)
+{
+ STICKY_RST(PHB_ERR_STATUS, 0, PPC_BITMASK(0, 33));
+ STICKY_RST(PHB_ERR1_STATUS, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_ERR_STATUS_MASK, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_ERR1_STATUS_MASK, 0, PPC_BITMASK(0, 63));
+
+ STICKY_RST(PHB_TXE_ERR_STATUS, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_TXE_ERR1_STATUS, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_TXE_ERR_STATUS_MASK, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_TXE_ERR1_STATUS_MASK, 0, PPC_BITMASK(0, 63));
+
+ STICKY_RST(PHB_RXE_ARB_ERR_STATUS, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_RXE_ARB_ERR1_STATUS, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_RXE_ARB_ERR_LOG_0, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_RXE_ARB_ERR_LOG_1, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_RXE_ARB_ERR_STATUS_MASK, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_RXE_ARB_ERR1_STATUS_MASK, 0, PPC_BITMASK(0, 63));
+
+ STICKY_RST(PHB_RXE_MRG_ERR_STATUS, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_RXE_MRG_ERR1_STATUS, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_RXE_MRG_ERR_STATUS_MASK, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_RXE_MRG_ERR1_STATUS_MASK, 0, PPC_BITMASK(0, 63));
+
+ STICKY_RST(PHB_RXE_TCE_ERR_STATUS, 0, PPC_BITMASK(0, 35));
+ STICKY_RST(PHB_RXE_TCE_ERR1_STATUS, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_RXE_TCE_ERR_LOG_0, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_RXE_TCE_ERR_LOG_1, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_RXE_TCE_ERR_STATUS_MASK, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_RXE_TCE_ERR1_STATUS_MASK, 0, PPC_BITMASK(0, 63));
+}
+
+static void pnv_phb4_pcie_stack_reg_reset(PnvPHB4 *phb)
+{
+ STICKY_RST(PHB_PCIE_CRESET, 0xE000000000000000, \
+ (PHB_PCIE_CRESET_PERST_N | PHB_PCIE_CRESET_REFCLK_N));
+ STICKY_RST(PHB_PCIE_DLP_ERRLOG1, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_PCIE_DLP_ERRLOG2, 0, PPC_BITMASK(0, 31));
+ STICKY_RST(PHB_PCIE_DLP_ERR_STATUS, 0, PPC_BITMASK(0, 15));
+}
+
+static void pnv_phb4_regb_err_reg_reset(PnvPHB4 *phb)
+{
+ STICKY_RST(PHB_REGB_ERR_STATUS, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_REGB_ERR1_STATUS, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_REGB_ERR_LOG_0, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_REGB_ERR_LOG_1, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_REGB_ERR_STATUS_MASK, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_REGB_ERR1_STATUS_MASK, 0, PPC_BITMASK(0, 63));
+}
+
static void pnv_phb4_reset(Object *obj, ResetType type)
{
PnvPHB4 *phb = PNV_PHB4(obj);
pnv_phb4_pbl_core_reset(phb);
+ pnv_phb4_err_reg_reset(phb);
+ pnv_phb4_pcie_stack_reg_reset(phb);
+ pnv_phb4_regb_err_reg_reset(phb);
}
static void pnv_phb4_instance_init(Object *obj)
diff --git a/include/hw/pci-host/pnv_phb4_regs.h b/include/hw/pci-host/pnv_phb4_regs.h
index 6892e21cc9..df5e86d29a 100644
--- a/include/hw/pci-host/pnv_phb4_regs.h
+++ b/include/hw/pci-host/pnv_phb4_regs.h
@@ -344,17 +344,32 @@
#define PHB_RC_CONFIG_SIZE 0x800
#define PHB_AER_ECAP 0x100
+#define PHB_AER_UERR 0x104
+#define PHB_AER_UERR_MASK 0x108
+#define PHB_AER_CERR 0x110
#define PHB_AER_CAPCTRL 0x118
+#define PHB_AER_HLOG_1 0x11C
+#define PHB_AER_HLOG_2 0x120
+#define PHB_AER_HLOG_3 0x124
+#define PHB_AER_HLOG_4 0x128
+#define PHB_AER_RERR 0x130
+#define PHB_AER_ESID 0x134
#define PHB_SEC_ECAP 0x148
#define PHB_LMR_ECAP 0x1A0
#define PHB_LMR_CTLSTA_2 0x1AC
#define PHB_LMR_CTLSTA_16 0x1E4
#define PHB_DLF_ECAP 0x1E8
#define PHB_DLF_CAP 0x1EC
+#define PHB_DLF_STAT 0x1F0
#define P16_ECAP 0x1F4
+#define P16_STAT 0x200
+#define P16_LDPM 0x204
+#define P16_FRDPM 0x208
+#define P16_SRDPM 0x20C
#define P32_ECAP 0x224
#define P32_CAP 0x228
-
+#define P32_CTL 0x22C
+#define P32_STAT 0x230
/* PHB4 REGB registers */
/* PBL core */
@@ -388,8 +403,7 @@
#define PHB_PCIE_CRESET_PBL PPC_BIT(2)
#define PHB_PCIE_CRESET_PERST_N PPC_BIT(3)
#define PHB_PCIE_CRESET_PIPE_N PPC_BIT(4)
-
-
+#define PHB_PCIE_CRESET_REFCLK_N PPC_BIT(8)
#define PHB_PCIE_HOTPLUG_STATUS 0x1A20
#define PHB_PCIE_HPSTAT_PRESENCE PPC_BIT(10)
diff --git a/tests/qtest/pnv-phb4-test.c b/tests/qtest/pnv-phb4-test.c
index 8cd6c1bc59..419f34987a 100644
--- a/tests/qtest/pnv-phb4-test.c
+++ b/tests/qtest/pnv-phb4-test.c
@@ -22,6 +22,19 @@
#define PNV_P10_CHIP_INDEX 3
#define PHB4_XSCOM 0x40084800ull
+/*
+ * Indirect XSCOM write:
+ * - Write 'Indirect Address Register' with register-offset to write.
+ * - Write 'Indirect Data Register' with the value.
+ */
+static void pnv_phb_xscom_write(QTestState *qts, const PnvChip *chip,
+ uint64_t scom, uint32_t indirect_addr, uint32_t indirect_data,
+ uint64_t reg, uint64_t val)
+{
+ qtest_writeq(qts, pnv_xscom_addr(chip, (scom >> 3) + indirect_addr), reg);
+ qtest_writeq(qts, pnv_xscom_addr(chip, (scom >> 3) + indirect_data), val);
+}
+
/*
* Indirect XSCOM read::
* - Write 'Indirect Address Register' with register-offset to read.
@@ -35,6 +48,11 @@ static uint64_t pnv_phb_xscom_read(QTestState *qts, const PnvChip *chip,
return qtest_readq(qts, pnv_xscom_addr(chip, (scom >> 3) + indirect_data));
}
+#define PHB4_XSCOM_WRITE(a, v) pnv_phb_xscom_write(qts, \
+ &pnv_chips[PNV_P10_CHIP_INDEX], PHB4_XSCOM, \
+ PHB_SCOM_HV_IND_ADDR, PHB_SCOM_HV_IND_DATA, \
+ PPC_BIT(0) | (a), (v))
+
#define PHB4_XSCOM_READ(a) pnv_phb_xscom_read(qts, \
&pnv_chips[PNV_P10_CHIP_INDEX], PHB4_XSCOM, \
PHB_SCOM_HV_IND_ADDR, PHB_SCOM_HV_IND_DATA, \
@@ -46,6 +64,26 @@ static void phb4_reset_test(QTestState *qts)
g_assert_cmpuint(PHB4_XSCOM_READ(PHB_PBL_CONTROL), ==, 0xC009000000000000);
}
+/* Check sticky-reset */
+static void phb4_sticky_rst_test(QTestState *qts)
+{
+ uint64_t val;
+
+ /*
+ * Sticky reset test of PHB_PBL_ERR_STATUS.
+ *
+ * Write all 1's to reg PHB_PBL_ERR_INJECT.
+ * Updated value will be copied to reg PHB_PBL_ERR_STATUS.
+ *
+ * Reset PBL core by setting PHB_PCIE_CRESET_PBL in reg PHB_PCIE_CRESET.
+ * Verify the sticky bits are still set.
+ */
+ PHB4_XSCOM_WRITE(PHB_PBL_ERR_INJECT, PPC_BITMASK(0, 63));
+ PHB4_XSCOM_WRITE(PHB_PCIE_CRESET, PHB_PCIE_CRESET_PBL); /*Reset*/
+ val = PHB4_XSCOM_READ(PHB_PBL_ERR_STATUS);
+ g_assert_cmpuint(val, ==, (PPC_BITMASK(0, 9) | PPC_BITMASK(12, 63)));
+}
+
static void phb4_tests(void)
{
QTestState *qts = NULL;
@@ -55,6 +93,9 @@ static void phb4_tests(void)
/* Check reset value of a register */
phb4_reset_test(qts);
+ /* Check sticky reset of a register */
+ phb4_sticky_rst_test(qts);
+
qtest_quit(qts);
}
--
2.47.3
^ permalink raw reply related [flat|nested] 60+ messages in thread
* [PATCH v3 4/9] pnv/phb4: Implement read-only and write-only bits of registers
2026-02-10 13:40 ` [PATCH v3 0/9] : pnv/phb4: Update PHB4 to the latest PHB5 spec Saif Abrar
` (2 preceding siblings ...)
2026-02-10 13:40 ` [PATCH v3 3/9] pnv/phb4: Implement sticky reset logic in PHB4 Saif Abrar
@ 2026-02-10 13:40 ` Saif Abrar
2026-02-10 13:40 ` [PATCH v3 5/9] pnv/phb4: Implement write-clear and return 1's on unimplemented reg read Saif Abrar
` (7 subsequent siblings)
11 siblings, 0 replies; 60+ messages in thread
From: Saif Abrar @ 2026-02-10 13:40 UTC (permalink / raw)
To: qemu-ppc, qemu-devel
Cc: clg, npiggin, fbarrat, mst, marcel.apfelbaum, cohuck, pbonzini,
thuth, lvivier, danielhb413, saif.abrar
SW cannot write the read-only(RO) bits of a register
and write-only(WO) bits of a register return 0 when read.
Added ro_mask[] for each register that defines which
bits in that register are RO.
When writing to a register, the RO-bits are not updated.
When reading a register, clear the WO bits and return the updated value.
Tested the registers PHB_DMA_SYNC, PHB_PCIE_HOTPLUG_STATUS, PHB_PCIE_LMR,
PHB_PCIE_DLP_TRWCTL, PHB_LEM_ERROR_AND_MASK and PHB_LEM_ERROR_OR_MASK
by writing all 1's and reading back the value.
The WO bits in these registers should read back as 0.
Added .class_size in pnv_phb4_type_info for PnvPHB4Class.
Signed-off-by: Saif Abrar <saif.abrar@linux.vnet.ibm.com>
Reviewed-by: Cédric Le Goater <clg@kaod.org>
Reviewed-by: "Michael S. Tsirkin" <mst@redhat.com>
---
v3:
- Updates for coding guidelines.
- Added class size for PnvPHB4Class.
v2: New PnvPHB4Class to hold each register's RO mask.
hw/pci-host/pnv_phb4.c | 80 ++++++++++++++++++++++++++---
include/hw/pci-host/pnv_phb4.h | 13 ++++-
include/hw/pci-host/pnv_phb4_regs.h | 20 ++++++--
tests/qtest/pnv-phb4-test.c | 60 +++++++++++++++++++++-
4 files changed, 159 insertions(+), 14 deletions(-)
diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c
index 961888e952..07479346c2 100644
--- a/hw/pci-host/pnv_phb4.c
+++ b/hw/pci-host/pnv_phb4.c
@@ -706,6 +706,12 @@ static void pnv_phb4_reg_write(void *opaque, hwaddr off, uint64_t val,
return;
}
+ /* Update 'val' according to the register's RO-mask */
+ PnvPHB4Class *k = PNV_PHB4_GET_CLASS(phb);
+
+ val = (phb->regs[off >> 3] & k->ro_mask[off >> 3]) |
+ (val & ~(k->ro_mask[off >> 3]));
+
/* Record whether it changed */
changed = phb->regs[off >> 3] != val;
@@ -781,7 +787,7 @@ static void pnv_phb4_reg_write(void *opaque, hwaddr off, uint64_t val,
case PHB_TCE_TAG_ENABLE:
case PHB_INT_NOTIFY_ADDR:
case PHB_INT_NOTIFY_INDEX:
- case PHB_DMARD_SYNC:
+ case PHB_DMA_SYNC:
break;
/* Noise on anything else */
@@ -819,7 +825,7 @@ static uint64_t pnv_phb4_reg_read(void *opaque, hwaddr off, unsigned size)
case PHB_VERSION:
return PNV_PHB4_PEC_GET_CLASS(phb->pec)->version;
- /* Read-only */
+ /* Read-only */
case PHB_PHB4_GEN_CAP:
return 0xe4b8000000000000ull;
case PHB_PHB4_TCE_CAP:
@@ -829,18 +835,49 @@ static uint64_t pnv_phb4_reg_read(void *opaque, hwaddr off, unsigned size)
case PHB_PHB4_EEH_CAP:
return phb->big_phb ? 0x2000000000000000ull : 0x1000000000000000ull;
+ /* Write-only, read will return zeros */
+ case PHB_LEM_ERROR_AND_MASK:
+ case PHB_LEM_ERROR_OR_MASK:
+ return 0;
+ case PHB_PCIE_DLP_TRWCTL:
+ val &= ~PHB_PCIE_DLP_TRWCTL_WREN;
+ return val;
/* IODA table accesses */
case PHB_IODA_DATA0:
return pnv_phb4_ioda_read(phb);
+ /*
+ * DMA sync: make it look like it's complete,
+ * clear write-only read/write start sync bits.
+ */
+ case PHB_DMA_SYNC:
+ val = PHB_DMA_SYNC_RD_COMPLETE |
+ ~(PHB_DMA_SYNC_RD_START | PHB_DMA_SYNC_WR_START);
+ return val;
+
+ /*
+ * PCI-E Stack registers
+ */
+ case PHB_PCIE_SCR:
+ val |= PHB_PCIE_SCR_PLW_X16; /* RO bit */
+ break;
+
/* Link training always appears trained */
case PHB_PCIE_DLP_TRAIN_CTL:
/* TODO: Do something sensible with speed ? */
- return PHB_PCIE_DLP_INBAND_PRESENCE | PHB_PCIE_DLP_TL_LINKACT;
+ val |= PHB_PCIE_DLP_INBAND_PRESENCE | PHB_PCIE_DLP_TL_LINKACT;
+ return val;
- /* DMA read sync: make it look like it's complete */
- case PHB_DMARD_SYNC:
- return PHB_DMARD_SYNC_COMPLETE;
+ case PHB_PCIE_HOTPLUG_STATUS:
+ /* Clear write-only bit */
+ val &= ~PHB_PCIE_HPSTAT_RESAMPLE;
+ return val;
+
+ /* Link Management Register */
+ case PHB_PCIE_LMR:
+ /* These write-only bits always read as 0 */
+ val &= ~(PHB_PCIE_LMR_CHANGELW | PHB_PCIE_LMR_RETRAINLINK);
+ return val;
/* Silent simple reads */
case PHB_LSI_SOURCE_ID:
@@ -1685,6 +1722,32 @@ static PCIIOMMUOps pnv_phb4_iommu_ops = {
.get_address_space = pnv_phb4_dma_iommu,
};
+static void pnv_phb4_ro_mask_init(PnvPHB4 *phb)
+{
+ PnvPHB4Class *phb4c = PNV_PHB4_GET_CLASS(phb);
+
+ /*
+ * Set register specific RO-masks
+ */
+
+ /* PBL - Error Injection Register (0x1910) */
+ phb4c->ro_mask[PHB_PBL_ERR_INJECT >> 3] =
+ PPC_BITMASK(0, 23) | PPC_BITMASK(28, 35) | PPC_BIT(38) | PPC_BIT(46) |
+ PPC_BITMASK(49, 51) | PPC_BITMASK(55, 63);
+
+ /* Reserved bits[60:63] */
+ phb4c->ro_mask[PHB_TXE_ERR_LEM_ENABLE >> 3] =
+ phb4c->ro_mask[PHB_TXE_ERR_AIB_FENCE_ENABLE >> 3] = PPC_BITMASK(60, 63);
+ /* Reserved bits[36:63] */
+ phb4c->ro_mask[PHB_RXE_TCE_ERR_LEM_ENABLE >> 3] =
+ phb4c->ro_mask[PHB_RXE_TCE_ERR_AIB_FENCE_ENABLE >> 3] = PPC_BITMASK(36, 63);
+ /* Reserved bits[40:63] */
+ phb4c->ro_mask[PHB_ERR_LEM_ENABLE >> 3] =
+ phb4c->ro_mask[PHB_ERR_AIB_FENCE_ENABLE >> 3] = PPC_BITMASK(40, 63);
+
+ /* TODO: Add more RO-masks as regs are implemented in the model */
+}
+
static void pnv_phb4_err_reg_reset(PnvPHB4 *phb)
{
STICKY_RST(PHB_ERR_STATUS, 0, PPC_BITMASK(0, 33));
@@ -1744,6 +1807,7 @@ static void pnv_phb4_reset(Object *obj, ResetType type)
pnv_phb4_err_reg_reset(phb);
pnv_phb4_pcie_stack_reg_reset(phb);
pnv_phb4_regb_err_reg_reset(phb);
+ phb->regs[PHB_PCIE_CRESET >> 3] = 0xE000000000000000;
}
static void pnv_phb4_instance_init(Object *obj)
@@ -1754,6 +1818,9 @@ static void pnv_phb4_instance_init(Object *obj)
/* XIVE interrupt source object */
object_initialize_child(obj, "source", &phb->xsrc, TYPE_XIVE_SOURCE);
+
+ /* Initialize RO-mask of registers */
+ pnv_phb4_ro_mask_init(phb);
}
void pnv_phb4_bus_init(DeviceState *dev, PnvPHB4 *phb)
@@ -1933,6 +2000,7 @@ static const TypeInfo pnv_phb4_type_info = {
.parent = TYPE_DEVICE,
.instance_init = pnv_phb4_instance_init,
.instance_size = sizeof(PnvPHB4),
+ .class_size = sizeof(PnvPHB4Class),
.class_init = pnv_phb4_class_init,
.interfaces = (const InterfaceInfo[]) {
{ TYPE_XIVE_NOTIFIER },
diff --git a/include/hw/pci-host/pnv_phb4.h b/include/hw/pci-host/pnv_phb4.h
index 47a5c3edf5..bea0684724 100644
--- a/include/hw/pci-host/pnv_phb4.h
+++ b/include/hw/pci-host/pnv_phb4.h
@@ -19,7 +19,7 @@
#define TYPE_PNV_PHB4 "pnv-phb4"
-OBJECT_DECLARE_SIMPLE_TYPE(PnvPHB4, PNV_PHB4)
+OBJECT_DECLARE_TYPE(PnvPHB4, PnvPHB4Class, PNV_PHB4)
typedef struct PnvPhb4PecStack PnvPhb4PecStack;
@@ -156,6 +156,17 @@ struct PnvPHB4 {
QLIST_HEAD(, PnvPhb4DMASpace) dma_spaces;
};
+typedef struct PnvPHB4Class {
+ DeviceClass parent_class;
+
+ /*
+ * Read-only bitmask for registers
+ * Bit value: 1 => RO bit
+ * 0 => RW bit
+ */
+ uint64_t ro_mask[PNV_PHB4_NUM_REGS];
+} PnvPHB4Class;
+
void pnv_phb4_pic_print_info(PnvPHB4 *phb, GString *buf);
int pnv_phb4_pec_get_phb_id(PnvPhb4PecState *pec, int stack_index);
PnvPhb4PecState *pnv_pec_add_phb(PnvChip *chip, PnvPHB *phb, Error **errp);
diff --git a/include/hw/pci-host/pnv_phb4_regs.h b/include/hw/pci-host/pnv_phb4_regs.h
index df5e86d29a..dfd0e01d1e 100644
--- a/include/hw/pci-host/pnv_phb4_regs.h
+++ b/include/hw/pci-host/pnv_phb4_regs.h
@@ -180,9 +180,11 @@
#define PHB_M64_AOMASK 0x1d0
#define PHB_M64_UPPER_BITS 0x1f0
#define PHB_NXLATE_PREFIX 0x1f8
-#define PHB_DMARD_SYNC 0x200
-#define PHB_DMARD_SYNC_START PPC_BIT(0)
-#define PHB_DMARD_SYNC_COMPLETE PPC_BIT(1)
+#define PHB_DMA_SYNC 0x200
+#define PHB_DMA_SYNC_RD_START PPC_BIT(0)
+#define PHB_DMA_SYNC_RD_COMPLETE PPC_BIT(1)
+#define PHB_DMA_SYNC_WR_START PPC_BIT(2)
+#define PHB_DMA_SYNC_WR_COMPLETE PPC_BIT(3)
#define PHB_RTC_INVALIDATE 0x208
#define PHB_RTC_INVALIDATE_ALL PPC_BIT(0)
#define PHB_RTC_INVALIDATE_RID PPC_BITMASK(16, 31)
@@ -370,6 +372,7 @@
#define P32_CAP 0x228
#define P32_CTL 0x22C
#define P32_STAT 0x230
+
/* PHB4 REGB registers */
/* PBL core */
@@ -395,8 +398,8 @@
#define PHB_PCIE_SCR 0x1A00
#define PHB_PCIE_SCR_SLOT_CAP PPC_BIT(15)
#define PHB_PCIE_SCR_MAXLINKSPEED PPC_BITMASK(32, 35)
+#define PHB_PCIE_SCR_PLW_X16 PPC_BIT(41) /* x16 */
#define PHB_PCIE_BNR 0x1A08
-
#define PHB_PCIE_CRESET 0x1A10
#define PHB_PCIE_CRESET_CFG_CORE PPC_BIT(0)
#define PHB_PCIE_CRESET_TLDLP PPC_BIT(1)
@@ -405,7 +408,14 @@
#define PHB_PCIE_CRESET_PIPE_N PPC_BIT(4)
#define PHB_PCIE_CRESET_REFCLK_N PPC_BIT(8)
#define PHB_PCIE_HOTPLUG_STATUS 0x1A20
+#define PHB_PCIE_HPSTAT_SIMDIAG PPC_BIT(3)
+#define PHB_PCIE_HPSTAT_RESAMPLE PPC_BIT(9)
#define PHB_PCIE_HPSTAT_PRESENCE PPC_BIT(10)
+#define PHB_PCIE_HPSTAT_LINKACTIVE PPC_BIT(12)
+#define PHB_PCIE_LMR 0x1A30
+#define PHB_PCIE_LMR_CHANGELW PPC_BIT(0)
+#define PHB_PCIE_LMR_RETRAINLINK PPC_BIT(1)
+#define PHB_PCIE_LMR_LINKACTIVE PPC_BIT(8)
#define PHB_PCIE_DLP_TRAIN_CTL 0x1A40
#define PHB_PCIE_DLP_LINK_WIDTH PPC_BITMASK(30, 35)
@@ -433,7 +443,7 @@
#define PHB_PCIE_DLP_TRWCTL 0x1A80
#define PHB_PCIE_DLP_TRWCTL_EN PPC_BIT(0)
-
+#define PHB_PCIE_DLP_TRWCTL_WREN PPC_BIT(1)
#define PHB_PCIE_DLP_ERRLOG1 0x1AA0
#define PHB_PCIE_DLP_ERRLOG2 0x1AA8
#define PHB_PCIE_DLP_ERR_STATUS 0x1AB0
diff --git a/tests/qtest/pnv-phb4-test.c b/tests/qtest/pnv-phb4-test.c
index 419f34987a..2078fab9a9 100644
--- a/tests/qtest/pnv-phb4-test.c
+++ b/tests/qtest/pnv-phb4-test.c
@@ -73,7 +73,8 @@ static void phb4_sticky_rst_test(QTestState *qts)
* Sticky reset test of PHB_PBL_ERR_STATUS.
*
* Write all 1's to reg PHB_PBL_ERR_INJECT.
- * Updated value will be copied to reg PHB_PBL_ERR_STATUS.
+ * RO-only bits will not be written and
+ * updated value will be copied to reg PHB_PBL_ERR_STATUS.
*
* Reset PBL core by setting PHB_PCIE_CRESET_PBL in reg PHB_PCIE_CRESET.
* Verify the sticky bits are still set.
@@ -81,7 +82,59 @@ static void phb4_sticky_rst_test(QTestState *qts)
PHB4_XSCOM_WRITE(PHB_PBL_ERR_INJECT, PPC_BITMASK(0, 63));
PHB4_XSCOM_WRITE(PHB_PCIE_CRESET, PHB_PCIE_CRESET_PBL); /*Reset*/
val = PHB4_XSCOM_READ(PHB_PBL_ERR_STATUS);
- g_assert_cmpuint(val, ==, (PPC_BITMASK(0, 9) | PPC_BITMASK(12, 63)));
+ g_assert_cmpuint(val, ==, 0xF00DFD8E00);
+}
+
+/* Check that write-only bits/regs return 0 when read */
+static void phb4_writeonly_read_test(QTestState *qts)
+{
+ uint64_t val;
+
+ /*
+ * Set all bits of PHB_DMA_SYNC,
+ * bits 0 and 2 are write-only and should be read as 0.
+ */
+ PHB4_XSCOM_WRITE(PHB_DMA_SYNC, PPC_BITMASK(0, 63));
+ val = PHB4_XSCOM_READ(PHB_DMA_SYNC);
+ g_assert_cmpuint(val & PPC_BIT(0), ==, 0x0);
+ g_assert_cmpuint(val & PPC_BIT(2), ==, 0x0);
+
+ /*
+ * Set all bits of PHB_PCIE_HOTPLUG_STATUS,
+ * bit 9 is write-only and should be read as 0.
+ */
+ PHB4_XSCOM_WRITE(PHB_PCIE_HOTPLUG_STATUS, PPC_BITMASK(0, 63));
+ val = PHB4_XSCOM_READ(PHB_PCIE_HOTPLUG_STATUS);
+ g_assert_cmpuint(val & PPC_BIT(9), ==, 0x0);
+
+ /*
+ * Set all bits of PHB_PCIE_LMR,
+ * bits 0 and 1 are write-only and should be read as 0.
+ */
+ PHB4_XSCOM_WRITE(PHB_PCIE_LMR, PPC_BITMASK(0, 63));
+ val = PHB4_XSCOM_READ(PHB_PCIE_LMR);
+ g_assert_cmpuint(val & PPC_BIT(0), ==, 0x0);
+ g_assert_cmpuint(val & PPC_BIT(1), ==, 0x0);
+
+ /*
+ * Set all bits of PHB_PCIE_DLP_TRWCTL,
+ * write-only bit-1 should be read as 0.
+ */
+ PHB4_XSCOM_WRITE(PHB_PCIE_DLP_TRWCTL, PPC_BITMASK(0, 63));
+ val = PHB4_XSCOM_READ(PHB_PCIE_DLP_TRWCTL);
+ g_assert_cmpuint(val & PPC_BIT(1), ==, 0x0);
+
+ /*
+ * Set all bits of PHB_LEM_ERROR_AND_MASK, PHB_LEM_ERROR_OR_MASK,
+ * both regs are write-only and should be read as 0.
+ */
+ PHB4_XSCOM_WRITE(PHB_LEM_ERROR_AND_MASK, PPC_BITMASK(0, 63));
+ val = PHB4_XSCOM_READ(PHB_LEM_ERROR_AND_MASK);
+ g_assert_cmpuint(val, ==, 0x0);
+
+ PHB4_XSCOM_WRITE(PHB_LEM_ERROR_OR_MASK, PPC_BITMASK(0, 63));
+ val = PHB4_XSCOM_READ(PHB_LEM_ERROR_OR_MASK);
+ g_assert_cmpuint(val, ==, 0x0);
}
static void phb4_tests(void)
@@ -96,6 +149,9 @@ static void phb4_tests(void)
/* Check sticky reset of a register */
phb4_sticky_rst_test(qts);
+ /* Check write-only logic */
+ phb4_writeonly_read_test(qts);
+
qtest_quit(qts);
}
--
2.47.3
^ permalink raw reply related [flat|nested] 60+ messages in thread
* [PATCH v3 5/9] pnv/phb4: Implement write-clear and return 1's on unimplemented reg read
2026-02-10 13:40 ` [PATCH v3 0/9] : pnv/phb4: Update PHB4 to the latest PHB5 spec Saif Abrar
` (3 preceding siblings ...)
2026-02-10 13:40 ` [PATCH v3 4/9] pnv/phb4: Implement read-only and write-only bits of registers Saif Abrar
@ 2026-02-10 13:40 ` Saif Abrar
2026-02-10 13:40 ` [PATCH v3 6/9] pnv/phb4: Set link-active status in HPSTAT and LMR registers Saif Abrar
` (6 subsequent siblings)
11 siblings, 0 replies; 60+ messages in thread
From: Saif Abrar @ 2026-02-10 13:40 UTC (permalink / raw)
To: qemu-ppc, qemu-devel
Cc: clg, npiggin, fbarrat, mst, marcel.apfelbaum, cohuck, pbonzini,
thuth, lvivier, danielhb413, saif.abrar
Implement write-1-to-clear and write-X-to-clear logic.
Update registers with silent simple read and write.
Return all 1's when an unimplemented/reserved register is read.
Test that reading address 0x0 returns all 1's (i.e. -1).
Signed-off-by: Saif Abrar <saif.abrar@linux.vnet.ibm.com>
Reviewed-by: Cédric Le Goater <clg@kaod.org>
---
v3: Updates for coding guidelines.
hw/pci-host/pnv_phb4.c | 190 ++++++++++++++++++++++------
include/hw/pci-host/pnv_phb4_regs.h | 11 +-
tests/qtest/pnv-phb4-test.c | 9 ++
3 files changed, 169 insertions(+), 41 deletions(-)
diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c
index 07479346c2..c044e9d2a3 100644
--- a/hw/pci-host/pnv_phb4.c
+++ b/hw/pci-host/pnv_phb4.c
@@ -654,8 +654,41 @@ static void pnv_phb4_reg_write(void *opaque, hwaddr off, uint64_t val,
return;
}
- /* Handle masking */
+ /* Handle RO, W1C, WxC and masking */
switch (off) {
+ /* W1C: Write-1-to-Clear registers */
+ case PHB_TXE_ERR_STATUS:
+ case PHB_RXE_ARB_ERR_STATUS:
+ case PHB_RXE_MRG_ERR_STATUS:
+ case PHB_RXE_TCE_ERR_STATUS:
+ case PHB_ERR_STATUS:
+ case PHB_REGB_ERR_STATUS:
+ case PHB_PCIE_DLP_ERRLOG1:
+ case PHB_PCIE_DLP_ERRLOG2:
+ case PHB_PCIE_DLP_ERR_STATUS:
+ case PHB_PBL_ERR_STATUS:
+ phb->regs[off >> 3] &= ~val;
+ return;
+
+ /* WxC: Clear register on any write */
+ case PHB_PBL_ERR1_STATUS:
+ case PHB_PBL_ERR_LOG_0 ... PHB_PBL_ERR_LOG_1:
+ case PHB_REGB_ERR1_STATUS:
+ case PHB_REGB_ERR_LOG_0 ... PHB_REGB_ERR_LOG_1:
+ case PHB_TXE_ERR1_STATUS:
+ case PHB_TXE_ERR_LOG_0 ... PHB_TXE_ERR_LOG_1:
+ case PHB_RXE_ARB_ERR1_STATUS:
+ case PHB_RXE_ARB_ERR_LOG_0 ... PHB_RXE_ARB_ERR_LOG_1:
+ case PHB_RXE_MRG_ERR1_STATUS:
+ case PHB_RXE_MRG_ERR_LOG_0 ... PHB_RXE_MRG_ERR_LOG_1:
+ case PHB_RXE_TCE_ERR1_STATUS:
+ case PHB_RXE_TCE_ERR_LOG_0 ... PHB_RXE_TCE_ERR_LOG_1:
+ case PHB_ERR1_STATUS:
+ case PHB_ERR_LOG_0 ... PHB_ERR_LOG_1:
+ phb->regs[off >> 3] = 0;
+ return;
+
+ /* Write value updated by masks */
case PHB_LSI_SOURCE_ID:
val &= PHB_LSI_SRC_ID;
break;
@@ -694,7 +727,6 @@ static void pnv_phb4_reg_write(void *opaque, hwaddr off, uint64_t val,
case PHB_LEM_WOF:
val = 0;
break;
- /* TODO: More regs ..., maybe create a table with masks... */
/* Read only registers */
case PHB_CPU_LOADSTORE_STATUS:
@@ -703,6 +735,12 @@ static void pnv_phb4_reg_write(void *opaque, hwaddr off, uint64_t val,
case PHB_PHB4_TCE_CAP:
case PHB_PHB4_IRQ_CAP:
case PHB_PHB4_EEH_CAP:
+ case PHB_VERSION:
+ case PHB_DMA_CHAN_STATUS:
+ case PHB_TCE_TAG_STATUS:
+ case PHB_PBL_BUF_STATUS:
+ case PHB_PCIE_BNR:
+ case PHB_PCIE_PHY_RXEQ_STAT_G3_00_03 ... PHB_PCIE_PHY_RXEQ_STAT_G5_12_15:
return;
}
@@ -725,6 +763,7 @@ static void pnv_phb4_reg_write(void *opaque, hwaddr off, uint64_t val,
pnv_phb4_update_all_msi_regions(phb);
}
break;
+
case PHB_M32_START_ADDR:
case PHB_M64_UPPER_BITS:
if (changed) {
@@ -772,27 +811,63 @@ static void pnv_phb4_reg_write(void *opaque, hwaddr off, uint64_t val,
break;
/* Silent simple writes */
- case PHB_ASN_CMPM:
- case PHB_CONFIG_ADDRESS:
- case PHB_IODA_ADDR:
- case PHB_TCE_KILL:
- case PHB_TCE_SPEC_CTL:
- case PHB_PEST_BAR:
- case PHB_PELTV_BAR:
+ /* PHB Fundamental register set A */
+ case PHB_CONFIG_DATA ... PHB_LOCK1:
case PHB_RTT_BAR:
- case PHB_LEM_FIR_ACCUM:
- case PHB_LEM_ERROR_MASK:
- case PHB_LEM_ACTION0:
- case PHB_LEM_ACTION1:
- case PHB_TCE_TAG_ENABLE:
+ case PHB_PELTV_BAR:
+ case PHB_PEST_BAR:
+ case PHB_CAPI_CMPM ... PHB_M64_AOMASK:
+ case PHB_NXLATE_PREFIX ... PHB_DMA_SYNC:
+ case PHB_TCE_KILL ... PHB_IODA_ADDR:
+ case PHB_PAPR_ERR_INJ_CTL ... PHB_PAPR_ERR_INJ_MASK:
case PHB_INT_NOTIFY_ADDR:
case PHB_INT_NOTIFY_INDEX:
- case PHB_DMA_SYNC:
- break;
+ /* Fundamental register set B */
+ case PHB_AIB_FENCE_CTRL ... PHB_Q_DMA_R:
+ /* FIR & Error registers */
+ case PHB_LEM_FIR_ACCUM:
+ case PHB_LEM_ERROR_MASK:
+ case PHB_LEM_ACTION0 ... PHB_LEM_WOF:
+ case PHB_ERR_INJECT ... PHB_ERR_AIB_FENCE_ENABLE:
+ case PHB_ERR_STATUS_MASK ... PHB_ERR1_STATUS_MASK:
+ case PHB_TXE_ERR_INJECT ... PHB_TXE_ERR_AIB_FENCE_ENABLE:
+ case PHB_TXE_ERR_STATUS_MASK ... PHB_TXE_ERR1_STATUS_MASK:
+ case PHB_RXE_ARB_ERR_INJECT ... PHB_RXE_ARB_ERR_AIB_FENCE_ENABLE:
+ case PHB_RXE_ARB_ERR_STATUS_MASK ... PHB_RXE_ARB_ERR1_STATUS_MASK:
+ case PHB_RXE_MRG_ERR_INJECT ... PHB_RXE_MRG_ERR_AIB_FENCE_ENABLE:
+ case PHB_RXE_MRG_ERR_STATUS_MASK ... PHB_RXE_MRG_ERR1_STATUS_MASK:
+ case PHB_RXE_TCE_ERR_INJECT ... PHB_RXE_TCE_ERR_AIB_FENCE_ENABLE:
+ case PHB_RXE_TCE_ERR_STATUS_MASK ... PHB_RXE_TCE_ERR1_STATUS_MASK:
+ /* Performance monitor & Debug registers */
+ case PHB_TRACE_CONTROL ... PHB_PERFMON_CTR1:
+ /* REGB Registers */
+ /* PBL core */
+ case PHB_PBL_CONTROL:
+ case PHB_PBL_TIMEOUT_CTRL:
+ case PHB_PBL_NPTAG_ENABLE:
+ case PHB_PBL_SYS_LINK_INIT:
+ case PHB_PBL_ERR_INF_ENABLE ... PHB_PBL_ERR_FAT_ENABLE:
+ case PHB_PBL_ERR_STATUS_MASK ... PHB_PBL_ERR1_STATUS_MASK:
+ /* PCI-E stack */
+ case PHB_PCIE_SCR:
+ case PHB_PCIE_DLP_STR ... PHB_PCIE_HOTPLUG_STATUS:
+ case PHB_PCIE_LMR ... PHB_PCIE_DLP_LSR:
+ case PHB_PCIE_DLP_RXMGN:
+ case PHB_PCIE_DLP_LANEZEROCTL ... PHB_PCIE_DLP_TRCRDDATA:
+ case PHB_PCIE_DLP_ERR_COUNTERS:
+ case PHB_PCIE_DLP_EIC ... PHB_PCIE_LANE_EQ_CNTL23:
+ case PHB_PCIE_TRACE_CTRL:
+ case PHB_PCIE_MISC_STRAP ... PHB_PCIE_PHY_EQ_CTL:
+ /* Error registers */
+ case PHB_REGB_ERR_INJECT:
+ case PHB_REGB_ERR_INF_ENABLE ... PHB_REGB_ERR_FAT_ENABLE:
+ case PHB_REGB_ERR_STATUS_MASK ... PHB_REGB_ERR1_STATUS_MASK:
+ break;
/* Noise on anything else */
default:
- qemu_log_mask(LOG_UNIMP, "phb4: reg_write 0x%"PRIx64"=%"PRIx64"\n",
+ qemu_log_mask(LOG_UNIMP,
+ "phb4: unimplemented reg_write 0x%"PRIx64"=%"PRIx64"\n",
off, val);
}
}
@@ -880,36 +955,75 @@ static uint64_t pnv_phb4_reg_read(void *opaque, hwaddr off, unsigned size)
return val;
/* Silent simple reads */
+ /* PHB Fundamental register set A */
case PHB_LSI_SOURCE_ID:
+ case PHB_DMA_CHAN_STATUS:
case PHB_CPU_LOADSTORE_STATUS:
- case PHB_ASN_CMPM:
+ case PHB_CONFIG_DATA ... PHB_LOCK1:
case PHB_PHB4_CONFIG:
+ case PHB_RTT_BAR:
+ case PHB_PELTV_BAR:
case PHB_M32_START_ADDR:
- case PHB_CONFIG_ADDRESS:
- case PHB_IODA_ADDR:
- case PHB_RTC_INVALIDATE:
- case PHB_TCE_KILL:
- case PHB_TCE_SPEC_CTL:
case PHB_PEST_BAR:
- case PHB_PELTV_BAR:
- case PHB_RTT_BAR:
+ case PHB_CAPI_CMPM:
+ case PHB_M64_AOMASK:
case PHB_M64_UPPER_BITS:
- case PHB_CTRLR:
- case PHB_LEM_FIR_ACCUM:
- case PHB_LEM_ERROR_MASK:
- case PHB_LEM_ACTION0:
- case PHB_LEM_ACTION1:
- case PHB_TCE_TAG_ENABLE:
+ case PHB_NXLATE_PREFIX:
+ case PHB_RTC_INVALIDATE ... PHB_IODA_ADDR:
+ case PHB_PAPR_ERR_INJ_CTL ... PHB_ETU_ERR_SUMMARY:
case PHB_INT_NOTIFY_ADDR:
case PHB_INT_NOTIFY_INDEX:
- case PHB_Q_DMA_R:
- case PHB_ETU_ERR_SUMMARY:
- break;
-
- /* Noise on anything else */
+ /* Fundamental register set B */
+ case PHB_CTRLR:
+ case PHB_AIB_FENCE_CTRL ... PHB_Q_DMA_R:
+ case PHB_TCE_TAG_STATUS:
+ /* FIR & Error registers */
+ case PHB_LEM_FIR_ACCUM ... PHB_LEM_ERROR_MASK:
+ case PHB_LEM_ACTION0 ... PHB_LEM_WOF:
+ case PHB_ERR_STATUS ... PHB_ERR_AIB_FENCE_ENABLE:
+ case PHB_ERR_LOG_0 ... PHB_ERR1_STATUS_MASK:
+ case PHB_TXE_ERR_STATUS ... PHB_TXE_ERR_AIB_FENCE_ENABLE:
+ case PHB_TXE_ERR_LOG_0 ... PHB_TXE_ERR1_STATUS_MASK:
+ case PHB_RXE_ARB_ERR_STATUS ... PHB_RXE_ARB_ERR_AIB_FENCE_ENABLE:
+ case PHB_RXE_ARB_ERR_LOG_0 ... PHB_RXE_ARB_ERR1_STATUS_MASK:
+ case PHB_RXE_MRG_ERR_STATUS ... PHB_RXE_MRG_ERR_AIB_FENCE_ENABLE:
+ case PHB_RXE_MRG_ERR_LOG_0 ... PHB_RXE_MRG_ERR1_STATUS_MASK:
+ case PHB_RXE_TCE_ERR_STATUS ... PHB_RXE_TCE_ERR_AIB_FENCE_ENABLE:
+ case PHB_RXE_TCE_ERR_LOG_0 ... PHB_RXE_TCE_ERR1_STATUS_MASK:
+ /* Performance monitor & Debug registers */
+ case PHB_TRACE_CONTROL ... PHB_PERFMON_CTR1:
+ /* REGB Registers */
+ /* PBL core */
+ case PHB_PBL_CONTROL:
+ case PHB_PBL_TIMEOUT_CTRL:
+ case PHB_PBL_NPTAG_ENABLE:
+ case PHB_PBL_SYS_LINK_INIT:
+ case PHB_PBL_BUF_STATUS:
+ case PHB_PBL_ERR_STATUS ... PHB_PBL_ERR_INJECT:
+ case PHB_PBL_ERR_INF_ENABLE ... PHB_PBL_ERR_FAT_ENABLE:
+ case PHB_PBL_ERR_LOG_0 ... PHB_PBL_ERR1_STATUS_MASK:
+ /* PCI-E stack */
+ case PHB_PCIE_BNR ... PHB_PCIE_DLP_STR:
+ case PHB_PCIE_DLP_LANE_PWR:
+ case PHB_PCIE_DLP_LSR:
+ case PHB_PCIE_DLP_RXMGN:
+ case PHB_PCIE_DLP_LANEZEROCTL ... PHB_PCIE_DLP_CTL:
+ case PHB_PCIE_DLP_TRCRDDATA:
+ case PHB_PCIE_DLP_ERRLOG1 ... PHB_PCIE_DLP_ERR_COUNTERS:
+ case PHB_PCIE_DLP_EIC ... PHB_PCIE_LANE_EQ_CNTL23:
+ case PHB_PCIE_TRACE_CTRL:
+ case PHB_PCIE_MISC_STRAP ... PHB_PCIE_PHY_RXEQ_STAT_G5_12_15:
+ /* Error registers */
+ case PHB_REGB_ERR_STATUS ... PHB_REGB_ERR_INJECT:
+ case PHB_REGB_ERR_INF_ENABLE ... PHB_REGB_ERR_FAT_ENABLE:
+ case PHB_REGB_ERR_LOG_0 ... PHB_REGB_ERR1_STATUS_MASK:
+ break;
+
+ /* Noise on unimplemented read, return all 1's */
default:
- qemu_log_mask(LOG_UNIMP, "phb4: reg_read 0x%"PRIx64"=%"PRIx64"\n",
- off, val);
+ qemu_log_mask(LOG_UNIMP, "phb4: unimplemented reg_read 0x%"PRIx64"\n",
+ off);
+ val = ~0ull;
}
return val;
}
diff --git a/include/hw/pci-host/pnv_phb4_regs.h b/include/hw/pci-host/pnv_phb4_regs.h
index dfd0e01d1e..c1d5a83271 100644
--- a/include/hw/pci-host/pnv_phb4_regs.h
+++ b/include/hw/pci-host/pnv_phb4_regs.h
@@ -407,6 +407,7 @@
#define PHB_PCIE_CRESET_PERST_N PPC_BIT(3)
#define PHB_PCIE_CRESET_PIPE_N PPC_BIT(4)
#define PHB_PCIE_CRESET_REFCLK_N PPC_BIT(8)
+#define PHB_PCIE_DLP_STR 0x1A18
#define PHB_PCIE_HOTPLUG_STATUS 0x1A20
#define PHB_PCIE_HPSTAT_SIMDIAG PPC_BIT(3)
#define PHB_PCIE_HPSTAT_RESAMPLE PPC_BIT(9)
@@ -417,6 +418,7 @@
#define PHB_PCIE_LMR_RETRAINLINK PPC_BIT(1)
#define PHB_PCIE_LMR_LINKACTIVE PPC_BIT(8)
+#define PHB_PCIE_DLP_LANE_PWR 0x1A38
#define PHB_PCIE_DLP_TRAIN_CTL 0x1A40
#define PHB_PCIE_DLP_LINK_WIDTH PPC_BITMASK(30, 35)
#define PHB_PCIE_DLP_LINK_SPEED PPC_BITMASK(36, 39)
@@ -436,18 +438,21 @@
#define PHB_PCIE_DLP_DL_PGRESET PPC_BIT(22)
#define PHB_PCIE_DLP_TRAINING PPC_BIT(20)
#define PHB_PCIE_DLP_INBAND_PRESENCE PPC_BIT(19)
-
+#define PHB_PCIE_DLP_LSR 0x1A48
+#define PHB_PCIE_DLP_RXMGN 0x1A50
+#define PHB_PCIE_DLP_LANEZEROCTL 0x1A70
#define PHB_PCIE_DLP_CTL 0x1A78
#define PHB_PCIE_DLP_CTL_BYPASS_PH2 PPC_BIT(4)
#define PHB_PCIE_DLP_CTL_BYPASS_PH3 PPC_BIT(5)
-
#define PHB_PCIE_DLP_TRWCTL 0x1A80
#define PHB_PCIE_DLP_TRWCTL_EN PPC_BIT(0)
#define PHB_PCIE_DLP_TRWCTL_WREN PPC_BIT(1)
+#define PHB_PCIE_DLP_TRCRDDATA 0x1A88
#define PHB_PCIE_DLP_ERRLOG1 0x1AA0
#define PHB_PCIE_DLP_ERRLOG2 0x1AA8
#define PHB_PCIE_DLP_ERR_STATUS 0x1AB0
#define PHB_PCIE_DLP_ERR_COUNTERS 0x1AB8
+#define PHB_PCIE_DLP_EIC 0x1AC8
#define PHB_PCIE_LANE_EQ_CNTL0 0x1AD0
#define PHB_PCIE_LANE_EQ_CNTL1 0x1AD8
@@ -459,6 +464,7 @@
#define PHB_PCIE_LANE_EQ_CNTL23 0x1B08 /* DD1 only */
#define PHB_PCIE_TRACE_CTRL 0x1B20
#define PHB_PCIE_MISC_STRAP 0x1B30
+#define PHB_PCIE_PHY_EQ_CTL 0x1B38
#define PHB_PCIE_PHY_RXEQ_STAT_G3_00_03 0x1B40
#define PHB_PCIE_PHY_RXEQ_STAT_G5_12_15 0x1B98
@@ -592,5 +598,4 @@
#define IODA3_PEST1_FAIL_ADDR PPC_BITMASK(3, 63)
-
#endif /* PCI_HOST_PNV_PHB4_REGS_H */
diff --git a/tests/qtest/pnv-phb4-test.c b/tests/qtest/pnv-phb4-test.c
index 2078fab9a9..9ccb75cd5a 100644
--- a/tests/qtest/pnv-phb4-test.c
+++ b/tests/qtest/pnv-phb4-test.c
@@ -137,6 +137,12 @@ static void phb4_writeonly_read_test(QTestState *qts)
g_assert_cmpuint(val, ==, 0x0);
}
+/* Check that reading an unimplemented address 0x0 returns -1 */
+static void phb4_unimplemented_read_test(QTestState *qts)
+{
+ g_assert_cmpint(PHB4_XSCOM_READ(0x0), ==, -1);
+}
+
static void phb4_tests(void)
{
QTestState *qts = NULL;
@@ -152,6 +158,9 @@ static void phb4_tests(void)
/* Check write-only logic */
phb4_writeonly_read_test(qts);
+ /* Check unimplemented register read */
+ phb4_unimplemented_read_test(qts);
+
qtest_quit(qts);
}
--
2.47.3
^ permalink raw reply related [flat|nested] 60+ messages in thread
* [PATCH v3 6/9] pnv/phb4: Set link-active status in HPSTAT and LMR registers
2026-02-10 13:40 ` [PATCH v3 0/9] : pnv/phb4: Update PHB4 to the latest PHB5 spec Saif Abrar
` (4 preceding siblings ...)
2026-02-10 13:40 ` [PATCH v3 5/9] pnv/phb4: Implement write-clear and return 1's on unimplemented reg read Saif Abrar
@ 2026-02-10 13:40 ` Saif Abrar
2026-02-10 13:40 ` [PATCH v3 7/9] pnv/phb4: Set link speed and width in the DLP training control register Saif Abrar
` (5 subsequent siblings)
11 siblings, 0 replies; 60+ messages in thread
From: Saif Abrar @ 2026-02-10 13:40 UTC (permalink / raw)
To: qemu-ppc, qemu-devel
Cc: clg, npiggin, fbarrat, mst, marcel.apfelbaum, cohuck, pbonzini,
thuth, lvivier, danielhb413, saif.abrar
Config-read the link-status register in the PCI-E macro,
Depending on the link-active bit, set the link-active status
in the HOTPLUG_STATUS and LINK_MANAGEMENT registers
Also, clear the Presence-status active low bit in HOTPLUG_STATUS reg
after config-reading the slot-status in the PCI-E macro.
Signed-off-by: Saif Abrar <saif.abrar@linux.vnet.ibm.com>
---
v3: Updates for coding guidelines.
hw/pci-host/pnv_phb4.c | 60 +++++++++++++++++++++++++++++++++++++++++-
1 file changed, 59 insertions(+), 1 deletion(-)
diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c
index c044e9d2a3..ebbdaf77b3 100644
--- a/hw/pci-host/pnv_phb4.c
+++ b/hw/pci-host/pnv_phb4.c
@@ -510,6 +510,20 @@ static uint32_t get_exp_offset(PCIDevice *pdev)
return rpc->exp_offset;
}
+/*
+ * Config-read the link-status register in the PCI-E macro,
+ * convert to LE and check the link-active bit.
+ */
+static uint32_t is_link_active(PnvPHB4 *phb)
+{
+ PCIHostState *pci = PCI_HOST_BRIDGE(phb->phb_base);
+ PCIDevice *pdev = pci_find_device(pci->bus, 0, 0);
+ uint32_t exp_offset = get_exp_offset(pdev);
+
+ return (bswap32(pnv_phb4_rc_config_read(phb, exp_offset + PCI_EXP_LNKSTA, 4)
+ ) & PCI_EXP_LNKSTA_DLLLA);
+}
+
/*
* Apply sticky-mask 's' to the reset-value 'v' and write to the address 'a'.
* RC-config space values and masks are LE.
@@ -728,6 +742,11 @@ static void pnv_phb4_reg_write(void *opaque, hwaddr off, uint64_t val,
val = 0;
break;
+ case PHB_PCIE_HOTPLUG_STATUS:
+ /* For normal operations, Simspeed diagnostic bit is always zero */
+ val &= PHB_PCIE_HPSTAT_SIMDIAG;
+ break;
+
/* Read only registers */
case PHB_CPU_LOADSTORE_STATUS:
case PHB_ETU_ERR_SUMMARY:
@@ -943,8 +962,42 @@ static uint64_t pnv_phb4_reg_read(void *opaque, hwaddr off, unsigned size)
val |= PHB_PCIE_DLP_INBAND_PRESENCE | PHB_PCIE_DLP_TL_LINKACT;
return val;
+ /*
+ * Read PCI-E registers and set status for:
+ * - Card present (active low bit 10)
+ * - Link active (bit 12)
+ */
case PHB_PCIE_HOTPLUG_STATUS:
- /* Clear write-only bit */
+ /*
+ * Presence-status bit hpi_present_n is active-low, with reset value 1.
+ * Start by setting this bit to 1, indicating the card is not present.
+ * Then check the PCI-E register and clear the bit if card is present.
+ */
+ val |= PHB_PCIE_HPSTAT_PRESENCE;
+
+ /* Get the PCI-E capability offset from the root-port */
+ PCIHostState *pci = PCI_HOST_BRIDGE(phb->phb_base);
+ PCIDevice *pdev = pci_find_device(pci->bus, 0, 0);
+ uint32_t exp_base = get_exp_offset(pdev);
+
+ /*
+ * Config-read the PCI-E macro register for slot-status.
+ * Method for config-read converts to BE value.
+ * To check actual bit in the PCI-E register,
+ * convert the value back to LE using bswap32().
+ * Clear the Presence-status active low bit.
+ */
+ if (bswap32(pnv_phb4_rc_config_read(phb, exp_base + PCI_EXP_SLTSTA, 4))
+ & PCI_EXP_SLTSTA_PDS) {
+ val &= ~PHB_PCIE_HPSTAT_PRESENCE;
+ }
+
+ /* Check if link is active and set the bit */
+ if (is_link_active(phb)) {
+ val |= PHB_PCIE_HPSTAT_LINKACTIVE;
+ }
+
+ /* Clear write-only resample-bit */
val &= ~PHB_PCIE_HPSTAT_RESAMPLE;
return val;
@@ -952,6 +1005,11 @@ static uint64_t pnv_phb4_reg_read(void *opaque, hwaddr off, unsigned size)
case PHB_PCIE_LMR:
/* These write-only bits always read as 0 */
val &= ~(PHB_PCIE_LMR_CHANGELW | PHB_PCIE_LMR_RETRAINLINK);
+
+ /* Check if link is active and set the bit */
+ if (is_link_active(phb)) {
+ val |= PHB_PCIE_LMR_LINKACTIVE;
+ }
return val;
/* Silent simple reads */
--
2.47.3
^ permalink raw reply related [flat|nested] 60+ messages in thread
* [PATCH v3 7/9] pnv/phb4: Set link speed and width in the DLP training control register
2026-02-10 13:40 ` [PATCH v3 0/9] : pnv/phb4: Update PHB4 to the latest PHB5 spec Saif Abrar
` (5 preceding siblings ...)
2026-02-10 13:40 ` [PATCH v3 6/9] pnv/phb4: Set link-active status in HPSTAT and LMR registers Saif Abrar
@ 2026-02-10 13:40 ` Saif Abrar
2026-02-10 13:40 ` [PATCH v3 8/9] pnv/phb4: Implement IODA PCT table Saif Abrar
` (4 subsequent siblings)
11 siblings, 0 replies; 60+ messages in thread
From: Saif Abrar @ 2026-02-10 13:40 UTC (permalink / raw)
To: qemu-ppc, qemu-devel
Cc: clg, npiggin, fbarrat, mst, marcel.apfelbaum, cohuck, pbonzini,
thuth, lvivier, danielhb413, saif.abrar
Get the current link-status from PCIE macro.
Extract link-speed and link-width from the link-status
and set in the DLP training control (PCIE_DLP_TCR) register.
Signed-off-by: Saif Abrar <saif.abrar@linux.vnet.ibm.com>
Reviewed-by: Cédric Le Goater <clg@kaod.org>
---
v3: Updates for coding guidelines.
hw/pci-host/pnv_phb4.c | 34 +++++++++++++++++++++++++++-------
1 file changed, 27 insertions(+), 7 deletions(-)
diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c
index ebbdaf77b3..a7a4ba46db 100644
--- a/hw/pci-host/pnv_phb4.c
+++ b/hw/pci-host/pnv_phb4.c
@@ -956,10 +956,30 @@ static uint64_t pnv_phb4_reg_read(void *opaque, hwaddr off, unsigned size)
val |= PHB_PCIE_SCR_PLW_X16; /* RO bit */
break;
- /* Link training always appears trained */
case PHB_PCIE_DLP_TRAIN_CTL:
- /* TODO: Do something sensible with speed ? */
+ /* Get the current link-status from PCIE */
+ PCIHostState *pci = PCI_HOST_BRIDGE(phb->phb_base);
+ PCIDevice *pdev = pci_find_device(pci->bus, 0, 0);
+ uint32_t exp_offset = get_exp_offset(pdev);
+ uint32_t lnkstatus = bswap32(pnv_phb4_rc_config_read(phb,
+ exp_offset + PCI_EXP_LNKSTA, 4));
+
+ /* Extract link-speed from the link-status */
+ uint32_t v = lnkstatus & PCI_EXP_LNKSTA_CLS;
+
+ /* Link training always appears trained */
val |= PHB_PCIE_DLP_INBAND_PRESENCE | PHB_PCIE_DLP_TL_LINKACT;
+
+ /* Set the current link-speed at the LINK_SPEED position */
+ val = SETFIELD(PHB_PCIE_DLP_LINK_SPEED, val, v);
+
+ /*
+ * Extract link-width from the link-status,
+ * after shifting the required bitfields.
+ */
+ v = (lnkstatus & PCI_EXP_LNKSTA_NLW) >> PCI_EXP_LNKSTA_NLW_SHIFT;
+ /* Set the current link-width at the LINK_WIDTH position */
+ val = SETFIELD(PHB_PCIE_DLP_LINK_WIDTH, val, v);
return val;
/*
@@ -968,6 +988,11 @@ static uint64_t pnv_phb4_reg_read(void *opaque, hwaddr off, unsigned size)
* - Link active (bit 12)
*/
case PHB_PCIE_HOTPLUG_STATUS:
+ /* Get the PCI-E capability offset from the root-port */
+ pci = PCI_HOST_BRIDGE(phb->phb_base);
+ pdev = pci_find_device(pci->bus, 0, 0);
+ uint32_t exp_base = get_exp_offset(pdev);
+
/*
* Presence-status bit hpi_present_n is active-low, with reset value 1.
* Start by setting this bit to 1, indicating the card is not present.
@@ -975,11 +1000,6 @@ static uint64_t pnv_phb4_reg_read(void *opaque, hwaddr off, unsigned size)
*/
val |= PHB_PCIE_HPSTAT_PRESENCE;
- /* Get the PCI-E capability offset from the root-port */
- PCIHostState *pci = PCI_HOST_BRIDGE(phb->phb_base);
- PCIDevice *pdev = pci_find_device(pci->bus, 0, 0);
- uint32_t exp_base = get_exp_offset(pdev);
-
/*
* Config-read the PCI-E macro register for slot-status.
* Method for config-read converts to BE value.
--
2.47.3
^ permalink raw reply related [flat|nested] 60+ messages in thread
* [PATCH v3 8/9] pnv/phb4: Implement IODA PCT table
2026-02-10 13:40 ` [PATCH v3 0/9] : pnv/phb4: Update PHB4 to the latest PHB5 spec Saif Abrar
` (6 preceding siblings ...)
2026-02-10 13:40 ` [PATCH v3 7/9] pnv/phb4: Set link speed and width in the DLP training control register Saif Abrar
@ 2026-02-10 13:40 ` Saif Abrar
2026-02-10 13:40 ` [PATCH v3 9/9] pnv/phb4: Mask off LSI Source-ID based on number of interrupts Saif Abrar
` (3 subsequent siblings)
11 siblings, 0 replies; 60+ messages in thread
From: Saif Abrar @ 2026-02-10 13:40 UTC (permalink / raw)
To: qemu-ppc, qemu-devel
Cc: clg, npiggin, fbarrat, mst, marcel.apfelbaum, cohuck, pbonzini,
thuth, lvivier, danielhb413, saif.abrar
IODA PCT table (#3) is implemented
without any functionality, being a debug table.
Signed-off-by: Saif Abrar <saif.abrar@linux.vnet.ibm.com>
Reviewed-by: Cédric Le Goater <clg@kaod.org>
---
v3: Updates for coding guidelines.
hw/pci-host/pnv_phb4.c | 6 ++++++
include/hw/pci-host/pnv_phb4.h | 2 ++
include/hw/pci-host/pnv_phb4_regs.h | 1 +
3 files changed, 9 insertions(+)
diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c
index a7a4ba46db..fdc49c9eef 100644
--- a/hw/pci-host/pnv_phb4.c
+++ b/hw/pci-host/pnv_phb4.c
@@ -264,6 +264,10 @@ static uint64_t *pnv_phb4_ioda_access(PnvPHB4 *phb,
mask = phb->big_phb ? PNV_PHB4_MAX_MIST : (PNV_PHB4_MAX_MIST >> 1);
mask -= 1;
break;
+ case IODA3_TBL_PCT:
+ tptr = phb->ioda_PCT;
+ mask = 7;
+ break;
case IODA3_TBL_RCAM:
mask = phb->big_phb ? 127 : 63;
break;
@@ -362,6 +366,8 @@ static void pnv_phb4_ioda_write(PnvPHB4 *phb, uint64_t val)
/* Handle side effects */
switch (table) {
case IODA3_TBL_LIST:
+ case IODA3_TBL_PCT:
+ /* No action for debug tables */
break;
case IODA3_TBL_MIST: {
/* Special mask for MIST partial write */
diff --git a/include/hw/pci-host/pnv_phb4.h b/include/hw/pci-host/pnv_phb4.h
index bea0684724..6bb75edeef 100644
--- a/include/hw/pci-host/pnv_phb4.h
+++ b/include/hw/pci-host/pnv_phb4.h
@@ -65,6 +65,7 @@ OBJECT_DECLARE_SIMPLE_TYPE(PnvPHB4RootBus, PNV_PHB4_ROOT_BUS)
#define PNV_PHB4_MAX_LSIs 8
#define PNV_PHB4_MAX_INTs 4096
#define PNV_PHB4_MAX_MIST (PNV_PHB4_MAX_INTs >> 2)
+#define PNV_PHB4_MAX_PCT 128
#define PNV_PHB4_MAX_MMIO_WINDOWS 32
#define PNV_PHB4_MIN_MMIO_WINDOWS 16
#define PNV_PHB4_NUM_REGS (0x3000 >> 3)
@@ -138,6 +139,7 @@ struct PnvPHB4 {
/* On-chip IODA tables */
uint64_t ioda_LIST[PNV_PHB4_MAX_LSIs];
uint64_t ioda_MIST[PNV_PHB4_MAX_MIST];
+ uint64_t ioda_PCT[PNV_PHB4_MAX_PCT];
uint64_t ioda_TVT[PNV_PHB4_MAX_TVEs];
uint64_t ioda_MBT[PNV_PHB4_MAX_MBEs];
uint64_t ioda_MDT[PNV_PHB4_MAX_PEs];
diff --git a/include/hw/pci-host/pnv_phb4_regs.h b/include/hw/pci-host/pnv_phb4_regs.h
index c1d5a83271..e30adff7b2 100644
--- a/include/hw/pci-host/pnv_phb4_regs.h
+++ b/include/hw/pci-host/pnv_phb4_regs.h
@@ -486,6 +486,7 @@
#define IODA3_TBL_LIST 1
#define IODA3_TBL_MIST 2
+#define IODA3_TBL_PCT 3
#define IODA3_TBL_RCAM 5
#define IODA3_TBL_MRT 6
#define IODA3_TBL_PESTA 7
--
2.47.3
^ permalink raw reply related [flat|nested] 60+ messages in thread
* [PATCH v3 9/9] pnv/phb4: Mask off LSI Source-ID based on number of interrupts
2026-02-10 13:40 ` [PATCH v3 0/9] : pnv/phb4: Update PHB4 to the latest PHB5 spec Saif Abrar
` (7 preceding siblings ...)
2026-02-10 13:40 ` [PATCH v3 8/9] pnv/phb4: Implement IODA PCT table Saif Abrar
@ 2026-02-10 13:40 ` Saif Abrar
2026-02-10 13:43 ` [PATCH v3 0/9] : pnv/phb4: Update PHB4 to the latest PHB5 spec Michael S. Tsirkin
` (2 subsequent siblings)
11 siblings, 0 replies; 60+ messages in thread
From: Saif Abrar @ 2026-02-10 13:40 UTC (permalink / raw)
To: qemu-ppc, qemu-devel
Cc: clg, npiggin, fbarrat, mst, marcel.apfelbaum, cohuck, pbonzini,
thuth, lvivier, danielhb413, saif.abrar
Add a method to reset the value of LSI Source-ID.
Mask off LSI source-id based on number of interrupts in the big/small PHB.
Signed-off-by: Saif Abrar <saif.abrar@linux.vnet.ibm.com>
Reviewed-by: Cédric Le Goater <clg@kaod.org>
---
v3: Updates for coding guidelines.
v2: Introduced method pnv_phb4_xsrc_reset().
hw/pci-host/pnv_phb4.c | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c
index fdc49c9eef..6e88c20a66 100644
--- a/hw/pci-host/pnv_phb4.c
+++ b/hw/pci-host/pnv_phb4.c
@@ -490,6 +490,7 @@ static void pnv_phb4_update_xsrc(PnvPHB4 *phb)
lsi_base = GETFIELD(PHB_LSI_SRC_ID, phb->regs[PHB_LSI_SOURCE_ID >> 3]);
lsi_base <<= 3;
+ lsi_base &= (xsrc->nr_irqs - 1);
/* TODO: handle reset values of PHB_LSI_SRC_ID */
if (!lsi_base) {
@@ -1946,6 +1947,12 @@ static void pnv_phb4_ro_mask_init(PnvPHB4 *phb)
/* TODO: Add more RO-masks as regs are implemented in the model */
}
+static void pnv_phb4_xsrc_reset(PnvPHB4 *phb)
+{
+ phb->regs[PHB_LSI_SOURCE_ID >> 3] = PPC_BITMASK(4, 12);
+ pnv_phb4_update_xsrc(phb);
+}
+
static void pnv_phb4_err_reg_reset(PnvPHB4 *phb)
{
STICKY_RST(PHB_ERR_STATUS, 0, PPC_BITMASK(0, 33));
@@ -2002,10 +2009,11 @@ static void pnv_phb4_reset(Object *obj, ResetType type)
PnvPHB4 *phb = PNV_PHB4(obj);
pnv_phb4_pbl_core_reset(phb);
+
+ pnv_phb4_xsrc_reset(phb);
pnv_phb4_err_reg_reset(phb);
pnv_phb4_pcie_stack_reg_reset(phb);
pnv_phb4_regb_err_reg_reset(phb);
- phb->regs[PHB_PCIE_CRESET >> 3] = 0xE000000000000000;
}
static void pnv_phb4_instance_init(Object *obj)
@@ -2082,8 +2090,6 @@ static void pnv_phb4_realize(DeviceState *dev, Error **errp)
return;
}
- pnv_phb4_update_xsrc(phb);
-
phb->qirqs = qemu_allocate_irqs(xive_source_set_irq, xsrc, xsrc->nr_irqs);
pnv_phb4_xscom_realize(phb);
--
2.47.3
^ permalink raw reply related [flat|nested] 60+ messages in thread
* Re: [PATCH v3 0/9] : pnv/phb4: Update PHB4 to the latest PHB5 spec
2026-02-10 13:40 ` [PATCH v3 0/9] : pnv/phb4: Update PHB4 to the latest PHB5 spec Saif Abrar
` (8 preceding siblings ...)
2026-02-10 13:40 ` [PATCH v3 9/9] pnv/phb4: Mask off LSI Source-ID based on number of interrupts Saif Abrar
@ 2026-02-10 13:43 ` Michael S. Tsirkin
2026-02-11 5:30 ` Saif Abrar
2026-02-20 16:22 ` Michael S. Tsirkin
2026-03-05 6:09 ` [PATCH v4 0/9] " Saif Abrar
11 siblings, 1 reply; 60+ messages in thread
From: Michael S. Tsirkin @ 2026-02-10 13:43 UTC (permalink / raw)
To: Saif Abrar
Cc: qemu-ppc, qemu-devel, clg, npiggin, fbarrat, marcel.apfelbaum,
cohuck, pbonzini, thuth, lvivier, danielhb413
On Tue, Feb 10, 2026 at 07:40:50AM -0600, Saif Abrar wrote:
> Hello,
>
> Addressing the review comments for the series v2:
> https://lists.gnu.org/archive/html/qemu-devel/2025-12/msg03768.html
pls include a detailed changelog.
No one wants to plough through all of it on each revision.
> This series updates the existing PHB4 model to the latest spec:
> "Power Systems Host Bridge 5 (PHB5) Functional Specification Version 0.5_00".
>
> Updates include the following:
> - implemented sticky reset logic
> - implemented read-only, write-only, W1C and WxC logic
> - return all 1's on read to unimplemented registers
> - update PCIE registers for link status, speed and width
> - implement IODA PCT debug table without any functionality
> - update LSI Source-ID register based on small/big PHB number of interrupts
>
> Also, a new testbench for PHB4 model is added that does XSCOM read/writes
> to various registers of interest and verifies the values.
>
> Regards.
>
> Saif Abrar (9):
> qtest/phb4: Add testbench for PHB4
> pnv/phb4: Add reset logic to PHB4
> pnv/phb4: Implement sticky reset logic in PHB4
> pnv/phb4: Implement read-only and write-only bits of registers
> pnv/phb4: Implement write-clear and return 1's on unimplemented reg read
> pnv/phb4: Set link-active status in HPSTAT and LMR registers
> pnv/phb4: Set link speed and width in the DLP training control register
> pnv/phb4: Implement IODA PCT table
> pnv/phb4: Mask off LSI Source-ID based on number of interrupts
>
> hw/pci-host/pnv_phb.c | 1 +
> hw/pci-host/pnv_phb4.c | 583 +++++++++++++++++++++++++---
> include/hw/pci-host/pnv_phb4.h | 16 +-
> include/hw/pci-host/pnv_phb4_regs.h | 66 +++-
> tests/qtest/meson.build | 1 +
> tests/qtest/pnv-phb4-test.c | 228 +++++++++++
> 6 files changed, 837 insertions(+), 58 deletions(-)
> create mode 100644 tests/qtest/pnv-phb4-test.c
>
> --
> 2.47.3
^ permalink raw reply [flat|nested] 60+ messages in thread
* Re: [PATCH v3 0/9] : pnv/phb4: Update PHB4 to the latest PHB5 spec
2026-02-10 13:43 ` [PATCH v3 0/9] : pnv/phb4: Update PHB4 to the latest PHB5 spec Michael S. Tsirkin
@ 2026-02-11 5:30 ` Saif Abrar
0 siblings, 0 replies; 60+ messages in thread
From: Saif Abrar @ 2026-02-11 5:30 UTC (permalink / raw)
To: Michael S. Tsirkin
Cc: qemu-ppc, qemu-devel, clg, npiggin, fbarrat, marcel.apfelbaum,
cohuck, pbonzini, thuth, lvivier, danielhb413
On 10-02-2026 07:13 pm, Michael S. Tsirkin wrote:
> On Tue, Feb 10, 2026 at 07:40:50AM -0600, Saif Abrar wrote:
>> Hello,
>>
>> Addressing the review comments for the series v2:
>> https://lists.gnu.org/archive/html/qemu-devel/2025-12/msg03768.html
> pls include a detailed changelog.
> No one wants to plough through all of it on each revision.
Please see individual patches for the detailed changelogs.
Each patch has its own changelog mentioned therein.
>> This series updates the existing PHB4 model to the latest spec:
>> "Power Systems Host Bridge 5 (PHB5) Functional Specification Version 0.5_00".
>>
>> Updates include the following:
>> - implemented sticky reset logic
>> - implemented read-only, write-only, W1C and WxC logic
>> - return all 1's on read to unimplemented registers
>> - update PCIE registers for link status, speed and width
>> - implement IODA PCT debug table without any functionality
>> - update LSI Source-ID register based on small/big PHB number of interrupts
>>
>> Also, a new testbench for PHB4 model is added that does XSCOM read/writes
>> to various registers of interest and verifies the values.
>>
>> Regards.
>>
>> Saif Abrar (9):
>> qtest/phb4: Add testbench for PHB4
>> pnv/phb4: Add reset logic to PHB4
>> pnv/phb4: Implement sticky reset logic in PHB4
>> pnv/phb4: Implement read-only and write-only bits of registers
>> pnv/phb4: Implement write-clear and return 1's on unimplemented reg read
>> pnv/phb4: Set link-active status in HPSTAT and LMR registers
>> pnv/phb4: Set link speed and width in the DLP training control register
>> pnv/phb4: Implement IODA PCT table
>> pnv/phb4: Mask off LSI Source-ID based on number of interrupts
>>
>> hw/pci-host/pnv_phb.c | 1 +
>> hw/pci-host/pnv_phb4.c | 583 +++++++++++++++++++++++++---
>> include/hw/pci-host/pnv_phb4.h | 16 +-
>> include/hw/pci-host/pnv_phb4_regs.h | 66 +++-
>> tests/qtest/meson.build | 1 +
>> tests/qtest/pnv-phb4-test.c | 228 +++++++++++
>> 6 files changed, 837 insertions(+), 58 deletions(-)
>> create mode 100644 tests/qtest/pnv-phb4-test.c
>>
>> --
>> 2.47.3
^ permalink raw reply [flat|nested] 60+ messages in thread
* Re: [PATCH v3 0/9] : pnv/phb4: Update PHB4 to the latest PHB5 spec
2026-02-10 13:40 ` [PATCH v3 0/9] : pnv/phb4: Update PHB4 to the latest PHB5 spec Saif Abrar
` (9 preceding siblings ...)
2026-02-10 13:43 ` [PATCH v3 0/9] : pnv/phb4: Update PHB4 to the latest PHB5 spec Michael S. Tsirkin
@ 2026-02-20 16:22 ` Michael S. Tsirkin
[not found] ` <d65ab628-99e3-47af-839c-e059207b692e@linux.vnet.ibm.com>
2026-03-05 6:09 ` [PATCH v4 0/9] " Saif Abrar
11 siblings, 1 reply; 60+ messages in thread
From: Michael S. Tsirkin @ 2026-02-20 16:22 UTC (permalink / raw)
To: Saif Abrar
Cc: qemu-ppc, qemu-devel, clg, npiggin, fbarrat, marcel.apfelbaum,
cohuck, pbonzini, thuth, lvivier, danielhb413
On Tue, Feb 10, 2026 at 07:40:50AM -0600, Saif Abrar wrote:
> Hello,
>
> Addressing the review comments for the series v2:
> https://lists.gnu.org/archive/html/qemu-devel/2025-12/msg03768.html
breaks tsan build:
https://gitlab.com/mstredhat/qemu/-/jobs/13201554945
../hw/pci-host/pnv_phb4.c:968:9: error: expected expression
PCIHostState *pci = PCI_HOST_BRIDGE(phb->phb_base);
^
../hw/pci-host/pnv_phb4.c:969:43: error: use of undeclared identifier 'pci'
PCIDevice *pdev = pci_find_device(pci->bus, 0, 0);
^
../hw/pci-host/pnv_phb4.c:999:9: error: use of undeclared identifier 'pci'
pci = PCI_HOST_BRIDGE(phb->phb_base);
^
../hw/pci-host/pnv_phb4.c:1000:32: error: use of undeclared identifier 'pci'
pdev = pci_find_device(pci->bus, 0, 0);
^
4 errors generated.
> This series updates the existing PHB4 model to the latest spec:
> "Power Systems Host Bridge 5 (PHB5) Functional Specification Version 0.5_00".
>
> Updates include the following:
> - implemented sticky reset logic
> - implemented read-only, write-only, W1C and WxC logic
> - return all 1's on read to unimplemented registers
> - update PCIE registers for link status, speed and width
> - implement IODA PCT debug table without any functionality
> - update LSI Source-ID register based on small/big PHB number of interrupts
>
> Also, a new testbench for PHB4 model is added that does XSCOM read/writes
> to various registers of interest and verifies the values.
>
> Regards.
>
> Saif Abrar (9):
> qtest/phb4: Add testbench for PHB4
> pnv/phb4: Add reset logic to PHB4
> pnv/phb4: Implement sticky reset logic in PHB4
> pnv/phb4: Implement read-only and write-only bits of registers
> pnv/phb4: Implement write-clear and return 1's on unimplemented reg read
> pnv/phb4: Set link-active status in HPSTAT and LMR registers
> pnv/phb4: Set link speed and width in the DLP training control register
> pnv/phb4: Implement IODA PCT table
> pnv/phb4: Mask off LSI Source-ID based on number of interrupts
>
> hw/pci-host/pnv_phb.c | 1 +
> hw/pci-host/pnv_phb4.c | 583 +++++++++++++++++++++++++---
> include/hw/pci-host/pnv_phb4.h | 16 +-
> include/hw/pci-host/pnv_phb4_regs.h | 66 +++-
> tests/qtest/meson.build | 1 +
> tests/qtest/pnv-phb4-test.c | 228 +++++++++++
> 6 files changed, 837 insertions(+), 58 deletions(-)
> create mode 100644 tests/qtest/pnv-phb4-test.c
>
> --
> 2.47.3
^ permalink raw reply [flat|nested] 60+ messages in thread
* Re: [PATCH v3 0/9] : pnv/phb4: Update PHB4 to the latest PHB5 spec
[not found] ` <d65ab628-99e3-47af-839c-e059207b692e@linux.vnet.ibm.com>
@ 2026-02-22 14:38 ` Michael S. Tsirkin
0 siblings, 0 replies; 60+ messages in thread
From: Michael S. Tsirkin @ 2026-02-22 14:38 UTC (permalink / raw)
To: Saif Abrar; +Cc: qemu-devel
On Sat, Feb 21, 2026 at 12:35:15PM +0530, Saif Abrar wrote:
> Hello Michael,
>
> Thanks for informing!
>
> Trying to understand why it's breaking now? (as it must be building earlier)
>
> Any insights will be helpful.
>
> Regards,
>
> Saif
I think clang rejects declarations placed directly after case labels in a switch.
clang sees this pattern:
case PHB_PCIE_DLP_TRAIN_CTL:
PCIHostState *pci = ...
as invalid, so it throws "expected expression"
>
> On 20-02-2026 09:52 pm, Michael S. Tsirkin wrote:
> > On Tue, Feb 10, 2026 at 07:40:50AM -0600, Saif Abrar wrote:
> > > Hello,
> > >
> > > Addressing the review comments for the series v2:
> > > https://lists.gnu.org/archive/html/qemu-devel/2025-12/msg03768.html
> >
> > breaks tsan build:
> >
> >
> > https://gitlab.com/mstredhat/qemu/-/jobs/13201554945
> >
> > ../hw/pci-host/pnv_phb4.c:968:9: error: expected expression
> > PCIHostState *pci = PCI_HOST_BRIDGE(phb->phb_base);
> > ^
> > ../hw/pci-host/pnv_phb4.c:969:43: error: use of undeclared identifier 'pci'
> > PCIDevice *pdev = pci_find_device(pci->bus, 0, 0);
> > ^
> > ../hw/pci-host/pnv_phb4.c:999:9: error: use of undeclared identifier 'pci'
> > pci = PCI_HOST_BRIDGE(phb->phb_base);
> > ^
> > ../hw/pci-host/pnv_phb4.c:1000:32: error: use of undeclared identifier 'pci'
> > pdev = pci_find_device(pci->bus, 0, 0);
> > ^
> > 4 errors generated.
> >
> >
> > > This series updates the existing PHB4 model to the latest spec:
> > > "Power Systems Host Bridge 5 (PHB5) Functional Specification Version 0.5_00".
> > >
> > > Updates include the following:
> > > - implemented sticky reset logic
> > > - implemented read-only, write-only, W1C and WxC logic
> > > - return all 1's on read to unimplemented registers
> > > - update PCIE registers for link status, speed and width
> > > - implement IODA PCT debug table without any functionality
> > > - update LSI Source-ID register based on small/big PHB number of interrupts
> > >
> > > Also, a new testbench for PHB4 model is added that does XSCOM read/writes
> > > to various registers of interest and verifies the values.
> > >
> > > Regards.
> > >
> > > Saif Abrar (9):
> > > qtest/phb4: Add testbench for PHB4
> > > pnv/phb4: Add reset logic to PHB4
> > > pnv/phb4: Implement sticky reset logic in PHB4
> > > pnv/phb4: Implement read-only and write-only bits of registers
> > > pnv/phb4: Implement write-clear and return 1's on unimplemented reg read
> > > pnv/phb4: Set link-active status in HPSTAT and LMR registers
> > > pnv/phb4: Set link speed and width in the DLP training control register
> > > pnv/phb4: Implement IODA PCT table
> > > pnv/phb4: Mask off LSI Source-ID based on number of interrupts
> > >
> > > hw/pci-host/pnv_phb.c | 1 +
> > > hw/pci-host/pnv_phb4.c | 583 +++++++++++++++++++++++++---
> > > include/hw/pci-host/pnv_phb4.h | 16 +-
> > > include/hw/pci-host/pnv_phb4_regs.h | 66 +++-
> > > tests/qtest/meson.build | 1 +
> > > tests/qtest/pnv-phb4-test.c | 228 +++++++++++
> > > 6 files changed, 837 insertions(+), 58 deletions(-)
> > > create mode 100644 tests/qtest/pnv-phb4-test.c
> > >
> > > --
> > > 2.47.3
^ permalink raw reply [flat|nested] 60+ messages in thread
* [PATCH v4 0/9] pnv/phb4: Update PHB4 to the latest PHB5 spec
2026-02-10 13:40 ` [PATCH v3 0/9] : pnv/phb4: Update PHB4 to the latest PHB5 spec Saif Abrar
` (10 preceding siblings ...)
2026-02-20 16:22 ` Michael S. Tsirkin
@ 2026-03-05 6:09 ` Saif Abrar
2026-03-05 6:09 ` [PATCH v4 1/9] qtest/phb4: Add testbench for PHB4 Saif Abrar
` (10 more replies)
11 siblings, 11 replies; 60+ messages in thread
From: Saif Abrar @ 2026-03-05 6:09 UTC (permalink / raw)
To: qemu-ppc, qemu-devel
Cc: clg, npiggin, fbarrat, mst, marcel.apfelbaum, cohuck, pbonzini,
thuth, lvivier, danielhb413, saif.abrar
Hello,
This patchset v4 resolves the tsan build failure seen in
https://gitlab.com/mstredhat/qemu/-/jobs/13201554945
Few variables were declared directly after a case label inside a switch,
causing the compilation failure.
These are now moved to the top of the block.
This series updates the existing PHB4 model to the latest spec:
"Power Systems Host Bridge 5 (PHB5) Functional Specification Version 0.5_00".
Updates include the following:
- implemented sticky reset logic
- implemented read-only, write-only, W1C and WxC logic
- return all 1's on read to unimplemented registers
- update PCIE registers for link status, speed and width
- implement IODA PCT debug table without any functionality
- update LSI Source-ID register based on small/big PHB number of interrupts
Also, a new testbench for PHB4 model is added that does XSCOM read/writes
to various registers of interest and verifies the values.
Regards.
Saif Abrar (9):
qtest/phb4: Add testbench for PHB4
pnv/phb4: Add reset logic to PHB4
pnv/phb4: Implement sticky reset logic in PHB4
pnv/phb4: Implement read-only and write-only bits of registers
pnv/phb4: Implement write-clear and return 1's on unimplemented reg
read
pnv/phb4: Set link-active status in HPSTAT and LMR registers
pnv/phb4: Set link speed and width in the DLP training control
register
pnv/phb4: Implement IODA PCT table
pnv/phb4: Mask off LSI Source-ID based on number of interrupts
hw/pci-host/pnv_phb.c | 1 +
hw/pci-host/pnv_phb4.c | 581 +++++++++++++++++++++++++---
include/hw/pci-host/pnv_phb4.h | 16 +-
include/hw/pci-host/pnv_phb4_regs.h | 66 +++-
tests/qtest/meson.build | 1 +
tests/qtest/pnv-phb4-test.c | 228 +++++++++++
6 files changed, 835 insertions(+), 58 deletions(-)
create mode 100644 tests/qtest/pnv-phb4-test.c
--
2.47.3
^ permalink raw reply [flat|nested] 60+ messages in thread
* [PATCH v4 1/9] qtest/phb4: Add testbench for PHB4
2026-03-05 6:09 ` [PATCH v4 0/9] " Saif Abrar
@ 2026-03-05 6:09 ` Saif Abrar
2026-05-01 13:59 ` Harsh Prateek Bora
2026-05-09 14:33 ` Aditya Gupta
2026-03-05 6:09 ` [PATCH v4 2/9] pnv/phb4: Add reset logic to PHB4 Saif Abrar
` (9 subsequent siblings)
10 siblings, 2 replies; 60+ messages in thread
From: Saif Abrar @ 2026-03-05 6:09 UTC (permalink / raw)
To: qemu-ppc, qemu-devel
Cc: clg, npiggin, fbarrat, mst, marcel.apfelbaum, cohuck, pbonzini,
thuth, lvivier, danielhb413, saif.abrar
New qtest testbench added for PHB[345].
Testbench reads PHB Version register and asserts that
bits[24:31] have value 0xA3, 0xA4 and 0xA5 respectively.
Signed-off-by: Saif Abrar <saif.abrar@linux.vnet.ibm.com>
Reviewed-by: Cédric Le Goater <clg@kaod.org>
---
v3: Updates for coding guidelines.
v2: Added version check for PHB3 and PHB4 also.
tests/qtest/meson.build | 1 +
tests/qtest/pnv-phb4-test.c | 98 +++++++++++++++++++++++++++++++++++++
2 files changed, 99 insertions(+)
create mode 100644 tests/qtest/pnv-phb4-test.c
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index ba9f59d2f8..030f3f4fc6 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -182,6 +182,7 @@ qtests_ppc64 = \
(config_all_devices.has_key('CONFIG_POWERNV') ? ['pnv-xive2-test'] : []) + \
(config_all_devices.has_key('CONFIG_POWERNV') ? ['pnv-spi-seeprom-test'] : []) + \
(config_all_devices.has_key('CONFIG_POWERNV') ? ['pnv-host-i2c-test'] : []) + \
+ (config_all_devices.has_key('CONFIG_POWERNV') ? ['pnv-phb4-test'] : []) + \
(config_all_devices.has_key('CONFIG_PSERIES') ? ['numa-test'] : []) + \
(config_all_devices.has_key('CONFIG_PSERIES') ? ['rtas-test'] : []) + \
(slirp.found() ? ['pxe-test'] : []) + \
diff --git a/tests/qtest/pnv-phb4-test.c b/tests/qtest/pnv-phb4-test.c
new file mode 100644
index 0000000000..797f6b6c87
--- /dev/null
+++ b/tests/qtest/pnv-phb4-test.c
@@ -0,0 +1,98 @@
+/*
+ * QTest testcase for PowerNV PHB4
+ *
+ * Copyright (c) 2025, IBM Corporation.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "hw/pci-host/pnv_phb4_regs.h"
+#include "pnv-xscom.h"
+
+#define PPC_BIT(bit) (0x8000000000000000ULL >> (bit))
+#define PPC_BITMASK(bs, be) ((PPC_BIT(bs) - PPC_BIT(be)) | PPC_BIT(bs))
+
+#define PHB3_PBCQ_SPCI_ASB_ADDR 0x0
+#define PHB3_PBCQ_SPCI_ASB_DATA 0x2
+
+/* Index of PNV_CHIP_POWER10 in pnv_chips[] within "pnv-xscom.h" */
+#define PNV_P10_CHIP_INDEX 3
+#define PHB4_XSCOM 0x40084800ull
+
+/*
+ * Indirect XSCOM read::
+ * - Write 'Indirect Address Register' with register-offset to read.
+ * - Read 'Indirect Data Register' to get the value.
+ */
+static uint64_t pnv_phb_xscom_read(QTestState *qts, const PnvChip *chip,
+ uint64_t scom, uint32_t indirect_addr, uint32_t indirect_data,
+ uint64_t reg)
+{
+ qtest_writeq(qts, pnv_xscom_addr(chip, (scom >> 3) + indirect_addr), reg);
+ return qtest_readq(qts, pnv_xscom_addr(chip, (scom >> 3) + indirect_data));
+}
+
+/* Assert that 'PHB - Version Register' bits[24:31] are as expected */
+static void phb_version_test(const void *data)
+{
+ const PnvChip *chip = (PnvChip *)data;
+ QTestState *qts;
+ const char *machine = "powernv8";
+ uint64_t phb_xscom = 0x4809e000;
+ uint64_t reg_phb_version = PHB_VERSION;
+ uint32_t indirect_addr = PHB3_PBCQ_SPCI_ASB_ADDR;
+ uint32_t indirect_data = PHB3_PBCQ_SPCI_ASB_DATA;
+ uint32_t expected_ver = 0xA3;
+ uint64_t ver;
+
+ if (chip->chip_type == PNV_CHIP_POWER9) {
+ machine = "powernv9";
+ phb_xscom = 0x68084800;
+ indirect_addr = PHB_SCOM_HV_IND_ADDR;
+ indirect_data = PHB_SCOM_HV_IND_DATA;
+ reg_phb_version |= PPC_BIT(0);
+ expected_ver = 0xA4;
+ } else if (chip->chip_type == PNV_CHIP_POWER10) {
+ machine = "powernv10";
+ phb_xscom = PHB4_XSCOM;
+ indirect_addr = PHB_SCOM_HV_IND_ADDR;
+ indirect_data = PHB_SCOM_HV_IND_DATA;
+ reg_phb_version |= PPC_BIT(0);
+ expected_ver = 0xA5;
+ }
+
+ qts = qtest_initf("-M %s -accel tcg -cpu %s", machine, chip->cpu_model);
+
+ ver = pnv_phb_xscom_read(qts, chip, phb_xscom,
+ indirect_addr, indirect_data, reg_phb_version);
+
+ /* PHB Version register bits [24:31] */
+ ver = ver >> (63 - 31);
+ g_assert_cmpuint(ver, ==, expected_ver);
+
+ qtest_quit(qts);
+}
+
+/* Verify versions of all supported PHB's */
+static void add_phbX_version_test(void)
+{
+ for (int i = 0; i < ARRAY_SIZE(pnv_chips); i++) {
+ char *tname = g_strdup_printf("pnv-phb/%s",
+ pnv_chips[i].cpu_model);
+ qtest_add_data_func(tname, &pnv_chips[i], phb_version_test);
+ g_free(tname);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ g_test_init(&argc, &argv, NULL);
+
+ /* PHB[345] tests */
+ add_phbX_version_test();
+
+ return g_test_run();
+}
--
2.47.3
^ permalink raw reply related [flat|nested] 60+ messages in thread
* [PATCH v4 2/9] pnv/phb4: Add reset logic to PHB4
2026-03-05 6:09 ` [PATCH v4 0/9] " Saif Abrar
2026-03-05 6:09 ` [PATCH v4 1/9] qtest/phb4: Add testbench for PHB4 Saif Abrar
@ 2026-03-05 6:09 ` Saif Abrar
2026-05-01 14:37 ` Harsh Prateek Bora
` (2 more replies)
2026-03-05 6:09 ` [PATCH v4 3/9] pnv/phb4: Implement sticky reset logic in PHB4 Saif Abrar
` (8 subsequent siblings)
10 siblings, 3 replies; 60+ messages in thread
From: Saif Abrar @ 2026-03-05 6:09 UTC (permalink / raw)
To: qemu-ppc, qemu-devel
Cc: clg, npiggin, fbarrat, mst, marcel.apfelbaum, cohuck, pbonzini,
thuth, lvivier, danielhb413, saif.abrar
Add a method to be invoked on QEMU reset.
Also add CFG and PBL core-blocks reset logic using
appropriate bits of PHB_PCIE_CRESET register.
Tested by reading the reset value of a register.
Signed-off-by: Saif Abrar <saif.abrar@linux.vnet.ibm.com>
Reviewed-by: Cédric Le Goater <clg@kaod.org>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
---
v3: Updates for coding guidelines.
v2:
- Using the ResettableClass.
- Reset of the root complex registers done in pnv_phb_root_port_reset_hold().
hw/pci-host/pnv_phb.c | 1 +
hw/pci-host/pnv_phb4.c | 103 +++++++++++++++++++++++++++-
include/hw/pci-host/pnv_phb4.h | 1 +
include/hw/pci-host/pnv_phb4_regs.h | 16 ++++-
tests/qtest/pnv-phb4-test.c | 28 +++++++-
5 files changed, 145 insertions(+), 4 deletions(-)
diff --git a/hw/pci-host/pnv_phb.c b/hw/pci-host/pnv_phb.c
index 0b556d1bf5..d4f452d7b2 100644
--- a/hw/pci-host/pnv_phb.c
+++ b/hw/pci-host/pnv_phb.c
@@ -232,6 +232,7 @@ static void pnv_phb_root_port_reset_hold(Object *obj, ResetType type)
pci_set_long(conf + PCI_PREF_BASE_UPPER32, 0x1); /* Hack */
pci_set_long(conf + PCI_PREF_LIMIT_UPPER32, 0xffffffff);
pci_config_set_interrupt_pin(conf, 0);
+ pnv_phb4_cfg_core_reset(d);
}
static void pnv_phb_root_port_realize(DeviceState *dev, Error **errp)
diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c
index 396bc47817..763e9c9776 100644
--- a/hw/pci-host/pnv_phb4.c
+++ b/hw/pci-host/pnv_phb4.c
@@ -1,7 +1,8 @@
/*
* QEMU PowerPC PowerNV (POWER9) PHB4 model
+ * QEMU PowerPC PowerNV (POWER10) PHB5 model
*
- * Copyright (c) 2018-2020, IBM Corporation.
+ * Copyright (c) 2018-2025, IBM Corporation.
*
* This code is licensed under the GPL version 2 or later. See the
* COPYING file in the top-level directory.
@@ -22,6 +23,7 @@
#include "hw/core/qdev-properties.h"
#include "qom/object.h"
#include "trace.h"
+#include "system/reset.h"
#define phb_error(phb, fmt, ...) \
qemu_log_mask(LOG_GUEST_ERROR, "phb4[%d:%d]: " fmt "\n", \
@@ -499,6 +501,81 @@ static void pnv_phb4_update_xsrc(PnvPHB4 *phb)
}
}
+/*
+ * Get the PCI-E capability offset from the root-port
+ */
+static uint32_t get_exp_offset(PCIDevice *pdev)
+{
+ PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(pdev);
+
+ return rpc->exp_offset;
+}
+
+void pnv_phb4_cfg_core_reset(PCIDevice *d)
+{
+ uint8_t *conf = d->config;
+ uint32_t exp_offset = get_exp_offset(d);
+
+ pci_set_word(conf + PCI_COMMAND, PCI_COMMAND_SERR);
+ pci_set_word(conf + PCI_STATUS, PCI_STATUS_CAP_LIST);
+ pci_set_long(conf + PCI_CLASS_REVISION, 0x06040000);
+ pci_set_long(conf + PCI_CACHE_LINE_SIZE, BIT(16));
+ pci_set_word(conf + PCI_MEMORY_BASE, BIT(4));
+ pci_set_word(conf + PCI_PREF_MEMORY_BASE, BIT(0) | BIT(4));
+ pci_set_word(conf + PCI_PREF_MEMORY_LIMIT, PCI_PREF_RANGE_TYPE_64);
+ pci_set_long(conf + PCI_CAPABILITY_LIST, BIT(6));
+ pci_set_long(conf + PCI_CAPABILITY_LIST, BIT(6));
+ pci_set_word(conf + PCI_BRIDGE_CONTROL, PCI_BRIDGE_CTL_SERR);
+ pci_set_long(conf + PCI_BRIDGE_CONTROL + PCI_PM_PMC, 0xC8034801);
+
+ pci_set_long(conf + exp_offset, 0x420010);
+ pci_set_long(conf + exp_offset + PCI_EXP_DEVCAP, 0x8022);
+ pci_set_long(conf + exp_offset + PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_EXT_TAG
+ | PCI_EXP_DEVCTL_PAYLOAD_512B);
+ pci_set_long(conf + exp_offset + PCI_EXP_LNKCAP, PCI_EXP_LNKCAP_LBNC
+ | PCI_EXP_LNKCAP_DLLLARC | BIT(8) | PCI_EXP_LNKCAP_SLS_32_0GB);
+ pci_set_word(conf + exp_offset + PCI_EXP_LNKCTL, PCI_EXP_LNKCTL_RCB);
+ pci_set_word(conf + exp_offset + PCI_EXP_LNKSTA,
+ (PCI_EXP_LNKSTA_NLW_X8 << 2) | PCI_EXP_LNKSTA_CLS_2_5GB);
+ pci_set_long(conf + exp_offset + PCI_EXP_SLTCTL,
+ PCI_EXP_SLTCTL_ASPL_DISABLE);
+ pci_set_long(conf + exp_offset + PCI_EXP_DEVCAP2, BIT(16)
+ | PCI_EXP_DEVCAP2_ARI | PCI_EXP_DEVCAP2_COMP_TMOUT_DIS | 0xF);
+ pci_set_long(conf + exp_offset + PCI_EXP_DEVCTL2, PCI_EXP_DEVCTL2_ARI);
+ pci_set_long(conf + exp_offset + PCI_EXP_LNKCAP2, BIT(23)
+ | PCI_EXP_LNKCAP2_SLS_32_0GB
+ | PCI_EXP_LNKCAP2_SLS_16_0GB | PCI_EXP_LNKCAP2_SLS_8_0GB
+ | PCI_EXP_LNKCAP2_SLS_5_0GB | PCI_EXP_LNKCAP2_SLS_2_5GB);
+ pci_set_long(conf + PHB_AER_ECAP, PCI_EXT_CAP(0x1, 0x1, 0x148));
+ pci_set_long(conf + PHB_SEC_ECAP, (0x1A0 << 20) | BIT(16)
+ | PCI_EXT_CAP_ID_SECPCI);
+ pci_set_long(conf + PHB_LMR_ECAP, 0x1E810027);
+ /* LMR - Margining Lane Control / Status Register # 2 to 16 */
+ for (int i = PHB_LMR_CTLSTA_2 ; i <= PHB_LMR_CTLSTA_16 ; i += 4) {
+ pci_set_long(conf + i, 0x9C38);
+ }
+
+ pci_set_long(conf + PHB_DLF_ECAP, 0x1F410025);
+ pci_set_long(conf + PHB_DLF_CAP, 0x80000001);
+ pci_set_long(conf + P16_ECAP, 0x22410026);
+ pci_set_long(conf + P32_ECAP, 0x1002A);
+ pci_set_long(conf + P32_CAP, 0x103);
+}
+
+static void pnv_phb4_pbl_core_reset(PnvPHB4 *phb)
+{
+ /* Zero all registers initially */
+ for (int i = PHB_PBL_CONTROL ; i <= PHB_PBL_ERR1_STATUS_MASK ; i += 8) {
+ phb->regs[i >> 3] = 0x0;
+ }
+
+ /* Set specific register values */
+ phb->regs[PHB_PBL_CONTROL >> 3] = 0xC009000000000000;
+ phb->regs[PHB_PBL_TIMEOUT_CTRL >> 3] = 0x2020000000000000;
+ phb->regs[PHB_PBL_NPTAG_ENABLE >> 3] = 0xFFFFFFFF00000000;
+ phb->regs[PHB_PBL_SYS_LINK_INIT >> 3] = 0x80088B4642473000;
+}
+
static void pnv_phb4_reg_write(void *opaque, hwaddr off, uint64_t val,
unsigned size)
{
@@ -612,6 +689,18 @@ static void pnv_phb4_reg_write(void *opaque, hwaddr off, uint64_t val,
pnv_phb4_update_xsrc(phb);
break;
+ /* Reset core blocks */
+ case PHB_PCIE_CRESET:
+ if (val & PHB_PCIE_CRESET_CFG_CORE) {
+ PCIHostState *pci = PCI_HOST_BRIDGE(phb->phb_base);
+
+ pnv_phb4_cfg_core_reset(pci_find_device(pci->bus, 0, 0));
+ }
+ if (val & PHB_PCIE_CRESET_PBL) {
+ pnv_phb4_pbl_core_reset(phb);
+ }
+ break;
+
/* Silent simple writes */
case PHB_ASN_CMPM:
case PHB_CONFIG_ADDRESS:
@@ -1532,6 +1621,13 @@ static PCIIOMMUOps pnv_phb4_iommu_ops = {
.get_address_space = pnv_phb4_dma_iommu,
};
+static void pnv_phb4_reset(Object *obj, ResetType type)
+{
+ PnvPHB4 *phb = PNV_PHB4(obj);
+
+ pnv_phb4_pbl_core_reset(phb);
+}
+
static void pnv_phb4_instance_init(Object *obj)
{
PnvPHB4 *phb = PNV_PHB4(obj);
@@ -1608,6 +1704,8 @@ static void pnv_phb4_realize(DeviceState *dev, Error **errp)
phb->qirqs = qemu_allocate_irqs(xive_source_set_irq, xsrc, xsrc->nr_irqs);
pnv_phb4_xscom_realize(phb);
+
+ qemu_register_resettable(OBJECT(dev));
}
/*
@@ -1701,12 +1799,15 @@ static void pnv_phb4_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
XiveNotifierClass *xfc = XIVE_NOTIFIER_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
dc->realize = pnv_phb4_realize;
device_class_set_props(dc, pnv_phb4_properties);
dc->user_creatable = false;
xfc->notify = pnv_phb4_xive_notify;
+
+ rc->phases.enter = pnv_phb4_reset;
}
static const TypeInfo pnv_phb4_type_info = {
diff --git a/include/hw/pci-host/pnv_phb4.h b/include/hw/pci-host/pnv_phb4.h
index de996e718b..47a5c3edf5 100644
--- a/include/hw/pci-host/pnv_phb4.h
+++ b/include/hw/pci-host/pnv_phb4.h
@@ -160,6 +160,7 @@ void pnv_phb4_pic_print_info(PnvPHB4 *phb, GString *buf);
int pnv_phb4_pec_get_phb_id(PnvPhb4PecState *pec, int stack_index);
PnvPhb4PecState *pnv_pec_add_phb(PnvChip *chip, PnvPHB *phb, Error **errp);
void pnv_phb4_bus_init(DeviceState *dev, PnvPHB4 *phb);
+void pnv_phb4_cfg_core_reset(PCIDevice *d);
extern const MemoryRegionOps pnv_phb4_xscom_ops;
/*
diff --git a/include/hw/pci-host/pnv_phb4_regs.h b/include/hw/pci-host/pnv_phb4_regs.h
index bea96f4d91..6892e21cc9 100644
--- a/include/hw/pci-host/pnv_phb4_regs.h
+++ b/include/hw/pci-host/pnv_phb4_regs.h
@@ -343,6 +343,18 @@
#define PHB_RC_CONFIG_BASE 0x1000
#define PHB_RC_CONFIG_SIZE 0x800
+#define PHB_AER_ECAP 0x100
+#define PHB_AER_CAPCTRL 0x118
+#define PHB_SEC_ECAP 0x148
+#define PHB_LMR_ECAP 0x1A0
+#define PHB_LMR_CTLSTA_2 0x1AC
+#define PHB_LMR_CTLSTA_16 0x1E4
+#define PHB_DLF_ECAP 0x1E8
+#define PHB_DLF_CAP 0x1EC
+#define P16_ECAP 0x1F4
+#define P32_ECAP 0x224
+#define P32_CAP 0x228
+
/* PHB4 REGB registers */
/* PBL core */
@@ -368,7 +380,7 @@
#define PHB_PCIE_SCR 0x1A00
#define PHB_PCIE_SCR_SLOT_CAP PPC_BIT(15)
#define PHB_PCIE_SCR_MAXLINKSPEED PPC_BITMASK(32, 35)
-
+#define PHB_PCIE_BNR 0x1A08
#define PHB_PCIE_CRESET 0x1A10
#define PHB_PCIE_CRESET_CFG_CORE PPC_BIT(0)
@@ -423,6 +435,8 @@
#define PHB_PCIE_LANE_EQ_CNTL23 0x1B08 /* DD1 only */
#define PHB_PCIE_TRACE_CTRL 0x1B20
#define PHB_PCIE_MISC_STRAP 0x1B30
+#define PHB_PCIE_PHY_RXEQ_STAT_G3_00_03 0x1B40
+#define PHB_PCIE_PHY_RXEQ_STAT_G5_12_15 0x1B98
/* Error */
#define PHB_REGB_ERR_STATUS 0x1C00
diff --git a/tests/qtest/pnv-phb4-test.c b/tests/qtest/pnv-phb4-test.c
index 797f6b6c87..8cd6c1bc59 100644
--- a/tests/qtest/pnv-phb4-test.c
+++ b/tests/qtest/pnv-phb4-test.c
@@ -35,6 +35,29 @@ static uint64_t pnv_phb_xscom_read(QTestState *qts, const PnvChip *chip,
return qtest_readq(qts, pnv_xscom_addr(chip, (scom >> 3) + indirect_data));
}
+#define PHB4_XSCOM_READ(a) pnv_phb_xscom_read(qts, \
+ &pnv_chips[PNV_P10_CHIP_INDEX], PHB4_XSCOM, \
+ PHB_SCOM_HV_IND_ADDR, PHB_SCOM_HV_IND_DATA, \
+ PPC_BIT(0) | (a))
+
+/* Assert that 'PHB PBL Control' register has correct reset value */
+static void phb4_reset_test(QTestState *qts)
+{
+ g_assert_cmpuint(PHB4_XSCOM_READ(PHB_PBL_CONTROL), ==, 0xC009000000000000);
+}
+
+static void phb4_tests(void)
+{
+ QTestState *qts = NULL;
+
+ qts = qtest_initf("-machine powernv10 -accel tcg");
+
+ /* Check reset value of a register */
+ phb4_reset_test(qts);
+
+ qtest_quit(qts);
+}
+
/* Assert that 'PHB - Version Register' bits[24:31] are as expected */
static void phb_version_test(const void *data)
{
@@ -72,8 +95,6 @@ static void phb_version_test(const void *data)
/* PHB Version register bits [24:31] */
ver = ver >> (63 - 31);
g_assert_cmpuint(ver, ==, expected_ver);
-
- qtest_quit(qts);
}
/* Verify versions of all supported PHB's */
@@ -94,5 +115,8 @@ int main(int argc, char **argv)
/* PHB[345] tests */
add_phbX_version_test();
+ /* PHB4 specific tests */
+ qtest_add_func("phb4", phb4_tests);
+
return g_test_run();
}
--
2.47.3
^ permalink raw reply related [flat|nested] 60+ messages in thread
* [PATCH v4 3/9] pnv/phb4: Implement sticky reset logic in PHB4
2026-03-05 6:09 ` [PATCH v4 0/9] " Saif Abrar
2026-03-05 6:09 ` [PATCH v4 1/9] qtest/phb4: Add testbench for PHB4 Saif Abrar
2026-03-05 6:09 ` [PATCH v4 2/9] pnv/phb4: Add reset logic to PHB4 Saif Abrar
@ 2026-03-05 6:09 ` Saif Abrar
2026-05-05 14:29 ` Harsh Prateek Bora
2026-05-09 14:48 ` Aditya Gupta
2026-03-05 6:09 ` [PATCH v4 4/9] pnv/phb4: Implement read-only and write-only bits of registers Saif Abrar
` (7 subsequent siblings)
10 siblings, 2 replies; 60+ messages in thread
From: Saif Abrar @ 2026-03-05 6:09 UTC (permalink / raw)
To: qemu-ppc, qemu-devel
Cc: clg, npiggin, fbarrat, mst, marcel.apfelbaum, cohuck, pbonzini,
thuth, lvivier, danielhb413, saif.abrar
Sticky bits retain their values on reset and are not overwritten with
the reset value.
Added sticky reset logic for all required registers,
i.e. CFG core, PBL core, PHB error registers, PCIE stack registers and
REGB error registers.
Tested by writing all 1's to the reg PHB_PBL_ERR_INJECT.
This will set the bits in the reg PHB_PBL_ERR_STATUS.
Reset the PBL core by setting PHB_PCIE_CRESET_PBL in reg PHB_PCIE_CRESET.
Verify that the sticky bits in the PHB_PBL_ERR_STATUS reg are still set.
Signed-off-by: Saif Abrar <saif.abrar@linux.vnet.ibm.com>
---
v3: Updates for coding guidelines.
hw/pci-host/pnv_phb4.c | 123 +++++++++++++++++++++++++++-
include/hw/pci-host/pnv_phb4_regs.h | 20 ++++-
tests/qtest/pnv-phb4-test.c | 41 ++++++++++
3 files changed, 179 insertions(+), 5 deletions(-)
diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c
index 763e9c9776..b3f46f7fe1 100644
--- a/hw/pci-host/pnv_phb4.c
+++ b/hw/pci-host/pnv_phb4.c
@@ -511,6 +511,18 @@ static uint32_t get_exp_offset(PCIDevice *pdev)
return rpc->exp_offset;
}
+/*
+ * Apply sticky-mask 's' to the reset-value 'v' and write to the address 'a'.
+ * RC-config space values and masks are LE.
+ * Method pnv_phb4_rc_config_read() returns BE, hence convert to LE.
+ * Compute new value in LE domain.
+ * New value computation using sticky-mask is in LE.
+ * Convert the computed value from LE to BE before writing back.
+ */
+#define RC_CONFIG_STICKY_RESET(a, v, s) \
+ (pci_set_word(conf + (a), bswap32( \
+ (bswap32(pci_get_word(conf + (a))) & (s)) | ((v) & ~(s)))))
+
void pnv_phb4_cfg_core_reset(PCIDevice *d)
{
uint8_t *conf = d->config;
@@ -560,14 +572,56 @@ void pnv_phb4_cfg_core_reset(PCIDevice *d)
pci_set_long(conf + P16_ECAP, 0x22410026);
pci_set_long(conf + P32_ECAP, 0x1002A);
pci_set_long(conf + P32_CAP, 0x103);
+
+ /* Sticky reset */
+ RC_CONFIG_STICKY_RESET(exp_offset + PCI_EXP_LNKCTL2,
+ PCI_EXP_LNKCTL2_TLS_32_0GT, 0xFEFFBF);
+ RC_CONFIG_STICKY_RESET(PHB_AER_UERR, 0, 0x1FF030);
+ RC_CONFIG_STICKY_RESET(PHB_AER_UERR_MASK, 0, 0x1FF030);
+ RC_CONFIG_STICKY_RESET(PHB_AER_CERR, 0, 0x11C1);
+ RC_CONFIG_STICKY_RESET(PHB_AER_ECAP + PCI_ERR_CAP, (PCI_ERR_CAP_ECRC_CHKC
+ | PCI_ERR_CAP_ECRC_GENC), 0x15F);
+ RC_CONFIG_STICKY_RESET(PHB_AER_HLOG_1, 0, 0xFFFFFFFF);
+ RC_CONFIG_STICKY_RESET(PHB_AER_HLOG_2, 0, 0xFFFFFFFF);
+ RC_CONFIG_STICKY_RESET(PHB_AER_HLOG_3, 0, 0xFFFFFFFF);
+ RC_CONFIG_STICKY_RESET(PHB_AER_HLOG_4, 0, 0xFFFFFFFF);
+ RC_CONFIG_STICKY_RESET(PHB_AER_RERR, 0, 0x7F);
+ RC_CONFIG_STICKY_RESET(PHB_AER_ESID, 0, 0xFFFFFFFF);
+ RC_CONFIG_STICKY_RESET(PHB_DLF_STAT, 0, 0x807FFFFF);
+ RC_CONFIG_STICKY_RESET(P16_STAT, 0, 0x1F);
+ RC_CONFIG_STICKY_RESET(P16_LDPM, 0, 0xFFFF);
+ RC_CONFIG_STICKY_RESET(P16_FRDPM, 0, 0xFFFF);
+ RC_CONFIG_STICKY_RESET(P16_SRDPM, 0, 0xFFFF);
+ RC_CONFIG_STICKY_RESET(P32_CTL, 0, 0x3);
}
+/* Apply sticky-mask to the reset-value and write to the reg-address */
+#define STICKY_RST(addr, rst_val, sticky_mask) (phb->regs[addr >> 3] = \
+ ((phb->regs[addr >> 3] & sticky_mask) | (rst_val & ~sticky_mask)))
+
static void pnv_phb4_pbl_core_reset(PnvPHB4 *phb)
{
- /* Zero all registers initially */
+ /*
+ * Zero all registers initially,
+ * with sticky reset of certain registers.
+ */
for (int i = PHB_PBL_CONTROL ; i <= PHB_PBL_ERR1_STATUS_MASK ; i += 8) {
- phb->regs[i >> 3] = 0x0;
+ switch (i) {
+ case PHB_PBL_ERR_STATUS:
+ break;
+ case PHB_PBL_ERR1_STATUS:
+ case PHB_PBL_ERR_LOG_0:
+ case PHB_PBL_ERR_LOG_1:
+ case PHB_PBL_ERR_STATUS_MASK:
+ case PHB_PBL_ERR1_STATUS_MASK:
+ STICKY_RST(i, 0, PPC_BITMASK(0, 63));
+ break;
+ default:
+ phb->regs[i >> 3] = 0x0;
+ }
}
+ STICKY_RST(PHB_PBL_ERR_STATUS, 0, \
+ (PPC_BITMASK(0, 9) | PPC_BITMASK(12, 63)));
/* Set specific register values */
phb->regs[PHB_PBL_CONTROL >> 3] = 0xC009000000000000;
@@ -701,6 +755,17 @@ static void pnv_phb4_reg_write(void *opaque, hwaddr off, uint64_t val,
}
break;
+ /*
+ * Writing bits to a 1 in this register will inject the error corresponding
+ * to the bit that is written. The bits will automatically clear to 0 after
+ * the error is injected. The corresponding bit in the Error Status Reg
+ * should also be set automatically when the error occurs.
+ */
+ case PHB_PBL_ERR_INJECT:
+ phb->regs[PHB_PBL_ERR_STATUS >> 3] = phb->regs[off >> 3];
+ phb->regs[off >> 3] = 0;
+ break;
+
/* Silent simple writes */
case PHB_ASN_CMPM:
case PHB_CONFIG_ADDRESS:
@@ -1621,11 +1686,65 @@ static PCIIOMMUOps pnv_phb4_iommu_ops = {
.get_address_space = pnv_phb4_dma_iommu,
};
+static void pnv_phb4_err_reg_reset(PnvPHB4 *phb)
+{
+ STICKY_RST(PHB_ERR_STATUS, 0, PPC_BITMASK(0, 33));
+ STICKY_RST(PHB_ERR1_STATUS, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_ERR_STATUS_MASK, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_ERR1_STATUS_MASK, 0, PPC_BITMASK(0, 63));
+
+ STICKY_RST(PHB_TXE_ERR_STATUS, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_TXE_ERR1_STATUS, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_TXE_ERR_STATUS_MASK, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_TXE_ERR1_STATUS_MASK, 0, PPC_BITMASK(0, 63));
+
+ STICKY_RST(PHB_RXE_ARB_ERR_STATUS, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_RXE_ARB_ERR1_STATUS, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_RXE_ARB_ERR_LOG_0, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_RXE_ARB_ERR_LOG_1, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_RXE_ARB_ERR_STATUS_MASK, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_RXE_ARB_ERR1_STATUS_MASK, 0, PPC_BITMASK(0, 63));
+
+ STICKY_RST(PHB_RXE_MRG_ERR_STATUS, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_RXE_MRG_ERR1_STATUS, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_RXE_MRG_ERR_STATUS_MASK, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_RXE_MRG_ERR1_STATUS_MASK, 0, PPC_BITMASK(0, 63));
+
+ STICKY_RST(PHB_RXE_TCE_ERR_STATUS, 0, PPC_BITMASK(0, 35));
+ STICKY_RST(PHB_RXE_TCE_ERR1_STATUS, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_RXE_TCE_ERR_LOG_0, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_RXE_TCE_ERR_LOG_1, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_RXE_TCE_ERR_STATUS_MASK, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_RXE_TCE_ERR1_STATUS_MASK, 0, PPC_BITMASK(0, 63));
+}
+
+static void pnv_phb4_pcie_stack_reg_reset(PnvPHB4 *phb)
+{
+ STICKY_RST(PHB_PCIE_CRESET, 0xE000000000000000, \
+ (PHB_PCIE_CRESET_PERST_N | PHB_PCIE_CRESET_REFCLK_N));
+ STICKY_RST(PHB_PCIE_DLP_ERRLOG1, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_PCIE_DLP_ERRLOG2, 0, PPC_BITMASK(0, 31));
+ STICKY_RST(PHB_PCIE_DLP_ERR_STATUS, 0, PPC_BITMASK(0, 15));
+}
+
+static void pnv_phb4_regb_err_reg_reset(PnvPHB4 *phb)
+{
+ STICKY_RST(PHB_REGB_ERR_STATUS, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_REGB_ERR1_STATUS, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_REGB_ERR_LOG_0, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_REGB_ERR_LOG_1, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_REGB_ERR_STATUS_MASK, 0, PPC_BITMASK(0, 63));
+ STICKY_RST(PHB_REGB_ERR1_STATUS_MASK, 0, PPC_BITMASK(0, 63));
+}
+
static void pnv_phb4_reset(Object *obj, ResetType type)
{
PnvPHB4 *phb = PNV_PHB4(obj);
pnv_phb4_pbl_core_reset(phb);
+ pnv_phb4_err_reg_reset(phb);
+ pnv_phb4_pcie_stack_reg_reset(phb);
+ pnv_phb4_regb_err_reg_reset(phb);
}
static void pnv_phb4_instance_init(Object *obj)
diff --git a/include/hw/pci-host/pnv_phb4_regs.h b/include/hw/pci-host/pnv_phb4_regs.h
index 6892e21cc9..df5e86d29a 100644
--- a/include/hw/pci-host/pnv_phb4_regs.h
+++ b/include/hw/pci-host/pnv_phb4_regs.h
@@ -344,17 +344,32 @@
#define PHB_RC_CONFIG_SIZE 0x800
#define PHB_AER_ECAP 0x100
+#define PHB_AER_UERR 0x104
+#define PHB_AER_UERR_MASK 0x108
+#define PHB_AER_CERR 0x110
#define PHB_AER_CAPCTRL 0x118
+#define PHB_AER_HLOG_1 0x11C
+#define PHB_AER_HLOG_2 0x120
+#define PHB_AER_HLOG_3 0x124
+#define PHB_AER_HLOG_4 0x128
+#define PHB_AER_RERR 0x130
+#define PHB_AER_ESID 0x134
#define PHB_SEC_ECAP 0x148
#define PHB_LMR_ECAP 0x1A0
#define PHB_LMR_CTLSTA_2 0x1AC
#define PHB_LMR_CTLSTA_16 0x1E4
#define PHB_DLF_ECAP 0x1E8
#define PHB_DLF_CAP 0x1EC
+#define PHB_DLF_STAT 0x1F0
#define P16_ECAP 0x1F4
+#define P16_STAT 0x200
+#define P16_LDPM 0x204
+#define P16_FRDPM 0x208
+#define P16_SRDPM 0x20C
#define P32_ECAP 0x224
#define P32_CAP 0x228
-
+#define P32_CTL 0x22C
+#define P32_STAT 0x230
/* PHB4 REGB registers */
/* PBL core */
@@ -388,8 +403,7 @@
#define PHB_PCIE_CRESET_PBL PPC_BIT(2)
#define PHB_PCIE_CRESET_PERST_N PPC_BIT(3)
#define PHB_PCIE_CRESET_PIPE_N PPC_BIT(4)
-
-
+#define PHB_PCIE_CRESET_REFCLK_N PPC_BIT(8)
#define PHB_PCIE_HOTPLUG_STATUS 0x1A20
#define PHB_PCIE_HPSTAT_PRESENCE PPC_BIT(10)
diff --git a/tests/qtest/pnv-phb4-test.c b/tests/qtest/pnv-phb4-test.c
index 8cd6c1bc59..419f34987a 100644
--- a/tests/qtest/pnv-phb4-test.c
+++ b/tests/qtest/pnv-phb4-test.c
@@ -22,6 +22,19 @@
#define PNV_P10_CHIP_INDEX 3
#define PHB4_XSCOM 0x40084800ull
+/*
+ * Indirect XSCOM write:
+ * - Write 'Indirect Address Register' with register-offset to write.
+ * - Write 'Indirect Data Register' with the value.
+ */
+static void pnv_phb_xscom_write(QTestState *qts, const PnvChip *chip,
+ uint64_t scom, uint32_t indirect_addr, uint32_t indirect_data,
+ uint64_t reg, uint64_t val)
+{
+ qtest_writeq(qts, pnv_xscom_addr(chip, (scom >> 3) + indirect_addr), reg);
+ qtest_writeq(qts, pnv_xscom_addr(chip, (scom >> 3) + indirect_data), val);
+}
+
/*
* Indirect XSCOM read::
* - Write 'Indirect Address Register' with register-offset to read.
@@ -35,6 +48,11 @@ static uint64_t pnv_phb_xscom_read(QTestState *qts, const PnvChip *chip,
return qtest_readq(qts, pnv_xscom_addr(chip, (scom >> 3) + indirect_data));
}
+#define PHB4_XSCOM_WRITE(a, v) pnv_phb_xscom_write(qts, \
+ &pnv_chips[PNV_P10_CHIP_INDEX], PHB4_XSCOM, \
+ PHB_SCOM_HV_IND_ADDR, PHB_SCOM_HV_IND_DATA, \
+ PPC_BIT(0) | (a), (v))
+
#define PHB4_XSCOM_READ(a) pnv_phb_xscom_read(qts, \
&pnv_chips[PNV_P10_CHIP_INDEX], PHB4_XSCOM, \
PHB_SCOM_HV_IND_ADDR, PHB_SCOM_HV_IND_DATA, \
@@ -46,6 +64,26 @@ static void phb4_reset_test(QTestState *qts)
g_assert_cmpuint(PHB4_XSCOM_READ(PHB_PBL_CONTROL), ==, 0xC009000000000000);
}
+/* Check sticky-reset */
+static void phb4_sticky_rst_test(QTestState *qts)
+{
+ uint64_t val;
+
+ /*
+ * Sticky reset test of PHB_PBL_ERR_STATUS.
+ *
+ * Write all 1's to reg PHB_PBL_ERR_INJECT.
+ * Updated value will be copied to reg PHB_PBL_ERR_STATUS.
+ *
+ * Reset PBL core by setting PHB_PCIE_CRESET_PBL in reg PHB_PCIE_CRESET.
+ * Verify the sticky bits are still set.
+ */
+ PHB4_XSCOM_WRITE(PHB_PBL_ERR_INJECT, PPC_BITMASK(0, 63));
+ PHB4_XSCOM_WRITE(PHB_PCIE_CRESET, PHB_PCIE_CRESET_PBL); /*Reset*/
+ val = PHB4_XSCOM_READ(PHB_PBL_ERR_STATUS);
+ g_assert_cmpuint(val, ==, (PPC_BITMASK(0, 9) | PPC_BITMASK(12, 63)));
+}
+
static void phb4_tests(void)
{
QTestState *qts = NULL;
@@ -55,6 +93,9 @@ static void phb4_tests(void)
/* Check reset value of a register */
phb4_reset_test(qts);
+ /* Check sticky reset of a register */
+ phb4_sticky_rst_test(qts);
+
qtest_quit(qts);
}
--
2.47.3
^ permalink raw reply related [flat|nested] 60+ messages in thread
* [PATCH v4 4/9] pnv/phb4: Implement read-only and write-only bits of registers
2026-03-05 6:09 ` [PATCH v4 0/9] " Saif Abrar
` (2 preceding siblings ...)
2026-03-05 6:09 ` [PATCH v4 3/9] pnv/phb4: Implement sticky reset logic in PHB4 Saif Abrar
@ 2026-03-05 6:09 ` Saif Abrar
2026-05-05 14:55 ` Harsh Prateek Bora
2026-05-09 14:54 ` Aditya Gupta
2026-03-05 6:09 ` [PATCH v4 5/9] pnv/phb4: Implement write-clear and return 1's on unimplemented reg read Saif Abrar
` (6 subsequent siblings)
10 siblings, 2 replies; 60+ messages in thread
From: Saif Abrar @ 2026-03-05 6:09 UTC (permalink / raw)
To: qemu-ppc, qemu-devel
Cc: clg, npiggin, fbarrat, mst, marcel.apfelbaum, cohuck, pbonzini,
thuth, lvivier, danielhb413, saif.abrar
SW cannot write the read-only(RO) bits of a register
and write-only(WO) bits of a register return 0 when read.
Added ro_mask[] for each register that defines which
bits in that register are RO.
When writing to a register, the RO-bits are not updated.
When reading a register, clear the WO bits and return the updated value.
Tested the registers PHB_DMA_SYNC, PHB_PCIE_HOTPLUG_STATUS, PHB_PCIE_LMR,
PHB_PCIE_DLP_TRWCTL, PHB_LEM_ERROR_AND_MASK and PHB_LEM_ERROR_OR_MASK
by writing all 1's and reading back the value.
The WO bits in these registers should read back as 0.
Add .class_size in pnv_phb4_type_info.
Signed-off-by: Saif Abrar <saif.abrar@linux.vnet.ibm.com>
Reviewed-by: Cédric Le Goater <clg@kaod.org>
Reviewed-by: "Michael S. Tsirkin" <mst@redhat.com>
---
v3:
- Updates for coding guidelines.
- Added class size for PnvPHB4Class.
v2: New PnvPHB4Class to hold each register's RO mask.
hw/pci-host/pnv_phb4.c | 80 ++++++++++++++++++++++++++---
include/hw/pci-host/pnv_phb4.h | 13 ++++-
include/hw/pci-host/pnv_phb4_regs.h | 20 ++++++--
tests/qtest/pnv-phb4-test.c | 60 +++++++++++++++++++++-
4 files changed, 159 insertions(+), 14 deletions(-)
diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c
index b3f46f7fe1..7656c9cc19 100644
--- a/hw/pci-host/pnv_phb4.c
+++ b/hw/pci-host/pnv_phb4.c
@@ -707,6 +707,12 @@ static void pnv_phb4_reg_write(void *opaque, hwaddr off, uint64_t val,
return;
}
+ /* Update 'val' according to the register's RO-mask */
+ PnvPHB4Class *k = PNV_PHB4_GET_CLASS(phb);
+
+ val = (phb->regs[off >> 3] & k->ro_mask[off >> 3]) |
+ (val & ~(k->ro_mask[off >> 3]));
+
/* Record whether it changed */
changed = phb->regs[off >> 3] != val;
@@ -782,7 +788,7 @@ static void pnv_phb4_reg_write(void *opaque, hwaddr off, uint64_t val,
case PHB_TCE_TAG_ENABLE:
case PHB_INT_NOTIFY_ADDR:
case PHB_INT_NOTIFY_INDEX:
- case PHB_DMARD_SYNC:
+ case PHB_DMA_SYNC:
break;
/* Noise on anything else */
@@ -820,7 +826,7 @@ static uint64_t pnv_phb4_reg_read(void *opaque, hwaddr off, unsigned size)
case PHB_VERSION:
return PNV_PHB4_PEC_GET_CLASS(phb->pec)->version;
- /* Read-only */
+ /* Read-only */
case PHB_PHB4_GEN_CAP:
return 0xe4b8000000000000ull;
case PHB_PHB4_TCE_CAP:
@@ -830,18 +836,49 @@ static uint64_t pnv_phb4_reg_read(void *opaque, hwaddr off, unsigned size)
case PHB_PHB4_EEH_CAP:
return phb->big_phb ? 0x2000000000000000ull : 0x1000000000000000ull;
+ /* Write-only, read will return zeros */
+ case PHB_LEM_ERROR_AND_MASK:
+ case PHB_LEM_ERROR_OR_MASK:
+ return 0;
+ case PHB_PCIE_DLP_TRWCTL:
+ val &= ~PHB_PCIE_DLP_TRWCTL_WREN;
+ return val;
/* IODA table accesses */
case PHB_IODA_DATA0:
return pnv_phb4_ioda_read(phb);
+ /*
+ * DMA sync: make it look like it's complete,
+ * clear write-only read/write start sync bits.
+ */
+ case PHB_DMA_SYNC:
+ val = PHB_DMA_SYNC_RD_COMPLETE |
+ ~(PHB_DMA_SYNC_RD_START | PHB_DMA_SYNC_WR_START);
+ return val;
+
+ /*
+ * PCI-E Stack registers
+ */
+ case PHB_PCIE_SCR:
+ val |= PHB_PCIE_SCR_PLW_X16; /* RO bit */
+ break;
+
/* Link training always appears trained */
case PHB_PCIE_DLP_TRAIN_CTL:
/* TODO: Do something sensible with speed ? */
- return PHB_PCIE_DLP_INBAND_PRESENCE | PHB_PCIE_DLP_TL_LINKACT;
+ val |= PHB_PCIE_DLP_INBAND_PRESENCE | PHB_PCIE_DLP_TL_LINKACT;
+ return val;
- /* DMA read sync: make it look like it's complete */
- case PHB_DMARD_SYNC:
- return PHB_DMARD_SYNC_COMPLETE;
+ case PHB_PCIE_HOTPLUG_STATUS:
+ /* Clear write-only bit */
+ val &= ~PHB_PCIE_HPSTAT_RESAMPLE;
+ return val;
+
+ /* Link Management Register */
+ case PHB_PCIE_LMR:
+ /* These write-only bits always read as 0 */
+ val &= ~(PHB_PCIE_LMR_CHANGELW | PHB_PCIE_LMR_RETRAINLINK);
+ return val;
/* Silent simple reads */
case PHB_LSI_SOURCE_ID:
@@ -1686,6 +1723,32 @@ static PCIIOMMUOps pnv_phb4_iommu_ops = {
.get_address_space = pnv_phb4_dma_iommu,
};
+static void pnv_phb4_ro_mask_init(PnvPHB4 *phb)
+{
+ PnvPHB4Class *phb4c = PNV_PHB4_GET_CLASS(phb);
+
+ /*
+ * Set register specific RO-masks
+ */
+
+ /* PBL - Error Injection Register (0x1910) */
+ phb4c->ro_mask[PHB_PBL_ERR_INJECT >> 3] =
+ PPC_BITMASK(0, 23) | PPC_BITMASK(28, 35) | PPC_BIT(38) | PPC_BIT(46) |
+ PPC_BITMASK(49, 51) | PPC_BITMASK(55, 63);
+
+ /* Reserved bits[60:63] */
+ phb4c->ro_mask[PHB_TXE_ERR_LEM_ENABLE >> 3] =
+ phb4c->ro_mask[PHB_TXE_ERR_AIB_FENCE_ENABLE >> 3] = PPC_BITMASK(60, 63);
+ /* Reserved bits[36:63] */
+ phb4c->ro_mask[PHB_RXE_TCE_ERR_LEM_ENABLE >> 3] =
+ phb4c->ro_mask[PHB_RXE_TCE_ERR_AIB_FENCE_ENABLE >> 3] = PPC_BITMASK(36, 63);
+ /* Reserved bits[40:63] */
+ phb4c->ro_mask[PHB_ERR_LEM_ENABLE >> 3] =
+ phb4c->ro_mask[PHB_ERR_AIB_FENCE_ENABLE >> 3] = PPC_BITMASK(40, 63);
+
+ /* TODO: Add more RO-masks as regs are implemented in the model */
+}
+
static void pnv_phb4_err_reg_reset(PnvPHB4 *phb)
{
STICKY_RST(PHB_ERR_STATUS, 0, PPC_BITMASK(0, 33));
@@ -1745,6 +1808,7 @@ static void pnv_phb4_reset(Object *obj, ResetType type)
pnv_phb4_err_reg_reset(phb);
pnv_phb4_pcie_stack_reg_reset(phb);
pnv_phb4_regb_err_reg_reset(phb);
+ phb->regs[PHB_PCIE_CRESET >> 3] = 0xE000000000000000;
}
static void pnv_phb4_instance_init(Object *obj)
@@ -1755,6 +1819,9 @@ static void pnv_phb4_instance_init(Object *obj)
/* XIVE interrupt source object */
object_initialize_child(obj, "source", &phb->xsrc, TYPE_XIVE_SOURCE);
+
+ /* Initialize RO-mask of registers */
+ pnv_phb4_ro_mask_init(phb);
}
void pnv_phb4_bus_init(DeviceState *dev, PnvPHB4 *phb)
@@ -1934,6 +2001,7 @@ static const TypeInfo pnv_phb4_type_info = {
.parent = TYPE_DEVICE,
.instance_init = pnv_phb4_instance_init,
.instance_size = sizeof(PnvPHB4),
+ .class_size = sizeof(PnvPHB4Class),
.class_init = pnv_phb4_class_init,
.interfaces = (const InterfaceInfo[]) {
{ TYPE_XIVE_NOTIFIER },
diff --git a/include/hw/pci-host/pnv_phb4.h b/include/hw/pci-host/pnv_phb4.h
index 47a5c3edf5..bea0684724 100644
--- a/include/hw/pci-host/pnv_phb4.h
+++ b/include/hw/pci-host/pnv_phb4.h
@@ -19,7 +19,7 @@
#define TYPE_PNV_PHB4 "pnv-phb4"
-OBJECT_DECLARE_SIMPLE_TYPE(PnvPHB4, PNV_PHB4)
+OBJECT_DECLARE_TYPE(PnvPHB4, PnvPHB4Class, PNV_PHB4)
typedef struct PnvPhb4PecStack PnvPhb4PecStack;
@@ -156,6 +156,17 @@ struct PnvPHB4 {
QLIST_HEAD(, PnvPhb4DMASpace) dma_spaces;
};
+typedef struct PnvPHB4Class {
+ DeviceClass parent_class;
+
+ /*
+ * Read-only bitmask for registers
+ * Bit value: 1 => RO bit
+ * 0 => RW bit
+ */
+ uint64_t ro_mask[PNV_PHB4_NUM_REGS];
+} PnvPHB4Class;
+
void pnv_phb4_pic_print_info(PnvPHB4 *phb, GString *buf);
int pnv_phb4_pec_get_phb_id(PnvPhb4PecState *pec, int stack_index);
PnvPhb4PecState *pnv_pec_add_phb(PnvChip *chip, PnvPHB *phb, Error **errp);
diff --git a/include/hw/pci-host/pnv_phb4_regs.h b/include/hw/pci-host/pnv_phb4_regs.h
index df5e86d29a..dfd0e01d1e 100644
--- a/include/hw/pci-host/pnv_phb4_regs.h
+++ b/include/hw/pci-host/pnv_phb4_regs.h
@@ -180,9 +180,11 @@
#define PHB_M64_AOMASK 0x1d0
#define PHB_M64_UPPER_BITS 0x1f0
#define PHB_NXLATE_PREFIX 0x1f8
-#define PHB_DMARD_SYNC 0x200
-#define PHB_DMARD_SYNC_START PPC_BIT(0)
-#define PHB_DMARD_SYNC_COMPLETE PPC_BIT(1)
+#define PHB_DMA_SYNC 0x200
+#define PHB_DMA_SYNC_RD_START PPC_BIT(0)
+#define PHB_DMA_SYNC_RD_COMPLETE PPC_BIT(1)
+#define PHB_DMA_SYNC_WR_START PPC_BIT(2)
+#define PHB_DMA_SYNC_WR_COMPLETE PPC_BIT(3)
#define PHB_RTC_INVALIDATE 0x208
#define PHB_RTC_INVALIDATE_ALL PPC_BIT(0)
#define PHB_RTC_INVALIDATE_RID PPC_BITMASK(16, 31)
@@ -370,6 +372,7 @@
#define P32_CAP 0x228
#define P32_CTL 0x22C
#define P32_STAT 0x230
+
/* PHB4 REGB registers */
/* PBL core */
@@ -395,8 +398,8 @@
#define PHB_PCIE_SCR 0x1A00
#define PHB_PCIE_SCR_SLOT_CAP PPC_BIT(15)
#define PHB_PCIE_SCR_MAXLINKSPEED PPC_BITMASK(32, 35)
+#define PHB_PCIE_SCR_PLW_X16 PPC_BIT(41) /* x16 */
#define PHB_PCIE_BNR 0x1A08
-
#define PHB_PCIE_CRESET 0x1A10
#define PHB_PCIE_CRESET_CFG_CORE PPC_BIT(0)
#define PHB_PCIE_CRESET_TLDLP PPC_BIT(1)
@@ -405,7 +408,14 @@
#define PHB_PCIE_CRESET_PIPE_N PPC_BIT(4)
#define PHB_PCIE_CRESET_REFCLK_N PPC_BIT(8)
#define PHB_PCIE_HOTPLUG_STATUS 0x1A20
+#define PHB_PCIE_HPSTAT_SIMDIAG PPC_BIT(3)
+#define PHB_PCIE_HPSTAT_RESAMPLE PPC_BIT(9)
#define PHB_PCIE_HPSTAT_PRESENCE PPC_BIT(10)
+#define PHB_PCIE_HPSTAT_LINKACTIVE PPC_BIT(12)
+#define PHB_PCIE_LMR 0x1A30
+#define PHB_PCIE_LMR_CHANGELW PPC_BIT(0)
+#define PHB_PCIE_LMR_RETRAINLINK PPC_BIT(1)
+#define PHB_PCIE_LMR_LINKACTIVE PPC_BIT(8)
#define PHB_PCIE_DLP_TRAIN_CTL 0x1A40
#define PHB_PCIE_DLP_LINK_WIDTH PPC_BITMASK(30, 35)
@@ -433,7 +443,7 @@
#define PHB_PCIE_DLP_TRWCTL 0x1A80
#define PHB_PCIE_DLP_TRWCTL_EN PPC_BIT(0)
-
+#define PHB_PCIE_DLP_TRWCTL_WREN PPC_BIT(1)
#define PHB_PCIE_DLP_ERRLOG1 0x1AA0
#define PHB_PCIE_DLP_ERRLOG2 0x1AA8
#define PHB_PCIE_DLP_ERR_STATUS 0x1AB0
diff --git a/tests/qtest/pnv-phb4-test.c b/tests/qtest/pnv-phb4-test.c
index 419f34987a..2078fab9a9 100644
--- a/tests/qtest/pnv-phb4-test.c
+++ b/tests/qtest/pnv-phb4-test.c
@@ -73,7 +73,8 @@ static void phb4_sticky_rst_test(QTestState *qts)
* Sticky reset test of PHB_PBL_ERR_STATUS.
*
* Write all 1's to reg PHB_PBL_ERR_INJECT.
- * Updated value will be copied to reg PHB_PBL_ERR_STATUS.
+ * RO-only bits will not be written and
+ * updated value will be copied to reg PHB_PBL_ERR_STATUS.
*
* Reset PBL core by setting PHB_PCIE_CRESET_PBL in reg PHB_PCIE_CRESET.
* Verify the sticky bits are still set.
@@ -81,7 +82,59 @@ static void phb4_sticky_rst_test(QTestState *qts)
PHB4_XSCOM_WRITE(PHB_PBL_ERR_INJECT, PPC_BITMASK(0, 63));
PHB4_XSCOM_WRITE(PHB_PCIE_CRESET, PHB_PCIE_CRESET_PBL); /*Reset*/
val = PHB4_XSCOM_READ(PHB_PBL_ERR_STATUS);
- g_assert_cmpuint(val, ==, (PPC_BITMASK(0, 9) | PPC_BITMASK(12, 63)));
+ g_assert_cmpuint(val, ==, 0xF00DFD8E00);
+}
+
+/* Check that write-only bits/regs return 0 when read */
+static void phb4_writeonly_read_test(QTestState *qts)
+{
+ uint64_t val;
+
+ /*
+ * Set all bits of PHB_DMA_SYNC,
+ * bits 0 and 2 are write-only and should be read as 0.
+ */
+ PHB4_XSCOM_WRITE(PHB_DMA_SYNC, PPC_BITMASK(0, 63));
+ val = PHB4_XSCOM_READ(PHB_DMA_SYNC);
+ g_assert_cmpuint(val & PPC_BIT(0), ==, 0x0);
+ g_assert_cmpuint(val & PPC_BIT(2), ==, 0x0);
+
+ /*
+ * Set all bits of PHB_PCIE_HOTPLUG_STATUS,
+ * bit 9 is write-only and should be read as 0.
+ */
+ PHB4_XSCOM_WRITE(PHB_PCIE_HOTPLUG_STATUS, PPC_BITMASK(0, 63));
+ val = PHB4_XSCOM_READ(PHB_PCIE_HOTPLUG_STATUS);
+ g_assert_cmpuint(val & PPC_BIT(9), ==, 0x0);
+
+ /*
+ * Set all bits of PHB_PCIE_LMR,
+ * bits 0 and 1 are write-only and should be read as 0.
+ */
+ PHB4_XSCOM_WRITE(PHB_PCIE_LMR, PPC_BITMASK(0, 63));
+ val = PHB4_XSCOM_READ(PHB_PCIE_LMR);
+ g_assert_cmpuint(val & PPC_BIT(0), ==, 0x0);
+ g_assert_cmpuint(val & PPC_BIT(1), ==, 0x0);
+
+ /*
+ * Set all bits of PHB_PCIE_DLP_TRWCTL,
+ * write-only bit-1 should be read as 0.
+ */
+ PHB4_XSCOM_WRITE(PHB_PCIE_DLP_TRWCTL, PPC_BITMASK(0, 63));
+ val = PHB4_XSCOM_READ(PHB_PCIE_DLP_TRWCTL);
+ g_assert_cmpuint(val & PPC_BIT(1), ==, 0x0);
+
+ /*
+ * Set all bits of PHB_LEM_ERROR_AND_MASK, PHB_LEM_ERROR_OR_MASK,
+ * both regs are write-only and should be read as 0.
+ */
+ PHB4_XSCOM_WRITE(PHB_LEM_ERROR_AND_MASK, PPC_BITMASK(0, 63));
+ val = PHB4_XSCOM_READ(PHB_LEM_ERROR_AND_MASK);
+ g_assert_cmpuint(val, ==, 0x0);
+
+ PHB4_XSCOM_WRITE(PHB_LEM_ERROR_OR_MASK, PPC_BITMASK(0, 63));
+ val = PHB4_XSCOM_READ(PHB_LEM_ERROR_OR_MASK);
+ g_assert_cmpuint(val, ==, 0x0);
}
static void phb4_tests(void)
@@ -96,6 +149,9 @@ static void phb4_tests(void)
/* Check sticky reset of a register */
phb4_sticky_rst_test(qts);
+ /* Check write-only logic */
+ phb4_writeonly_read_test(qts);
+
qtest_quit(qts);
}
--
2.47.3
^ permalink raw reply related [flat|nested] 60+ messages in thread
* [PATCH v4 5/9] pnv/phb4: Implement write-clear and return 1's on unimplemented reg read
2026-03-05 6:09 ` [PATCH v4 0/9] " Saif Abrar
` (3 preceding siblings ...)
2026-03-05 6:09 ` [PATCH v4 4/9] pnv/phb4: Implement read-only and write-only bits of registers Saif Abrar
@ 2026-03-05 6:09 ` Saif Abrar
2026-05-09 14:56 ` Aditya Gupta
2026-03-05 6:09 ` [PATCH v4 6/9] pnv/phb4: Set link-active status in HPSTAT and LMR registers Saif Abrar
` (5 subsequent siblings)
10 siblings, 1 reply; 60+ messages in thread
From: Saif Abrar @ 2026-03-05 6:09 UTC (permalink / raw)
To: qemu-ppc, qemu-devel
Cc: clg, npiggin, fbarrat, mst, marcel.apfelbaum, cohuck, pbonzini,
thuth, lvivier, danielhb413, saif.abrar
Implement write-1-to-clear and write-X-to-clear logic.
Update registers with silent simple read and write.
Return all 1's when an unimplemented/reserved register is read.
Test that reading address 0x0 returns all 1's (i.e. -1).
Signed-off-by: Saif Abrar <saif.abrar@linux.vnet.ibm.com>
Reviewed-by: Cédric Le Goater <clg@kaod.org>
---
v3: Updates for coding guidelines.
hw/pci-host/pnv_phb4.c | 190 ++++++++++++++++++++++------
include/hw/pci-host/pnv_phb4_regs.h | 11 +-
tests/qtest/pnv-phb4-test.c | 9 ++
3 files changed, 169 insertions(+), 41 deletions(-)
diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c
index 7656c9cc19..25539b7c32 100644
--- a/hw/pci-host/pnv_phb4.c
+++ b/hw/pci-host/pnv_phb4.c
@@ -655,8 +655,41 @@ static void pnv_phb4_reg_write(void *opaque, hwaddr off, uint64_t val,
return;
}
- /* Handle masking */
+ /* Handle RO, W1C, WxC and masking */
switch (off) {
+ /* W1C: Write-1-to-Clear registers */
+ case PHB_TXE_ERR_STATUS:
+ case PHB_RXE_ARB_ERR_STATUS:
+ case PHB_RXE_MRG_ERR_STATUS:
+ case PHB_RXE_TCE_ERR_STATUS:
+ case PHB_ERR_STATUS:
+ case PHB_REGB_ERR_STATUS:
+ case PHB_PCIE_DLP_ERRLOG1:
+ case PHB_PCIE_DLP_ERRLOG2:
+ case PHB_PCIE_DLP_ERR_STATUS:
+ case PHB_PBL_ERR_STATUS:
+ phb->regs[off >> 3] &= ~val;
+ return;
+
+ /* WxC: Clear register on any write */
+ case PHB_PBL_ERR1_STATUS:
+ case PHB_PBL_ERR_LOG_0 ... PHB_PBL_ERR_LOG_1:
+ case PHB_REGB_ERR1_STATUS:
+ case PHB_REGB_ERR_LOG_0 ... PHB_REGB_ERR_LOG_1:
+ case PHB_TXE_ERR1_STATUS:
+ case PHB_TXE_ERR_LOG_0 ... PHB_TXE_ERR_LOG_1:
+ case PHB_RXE_ARB_ERR1_STATUS:
+ case PHB_RXE_ARB_ERR_LOG_0 ... PHB_RXE_ARB_ERR_LOG_1:
+ case PHB_RXE_MRG_ERR1_STATUS:
+ case PHB_RXE_MRG_ERR_LOG_0 ... PHB_RXE_MRG_ERR_LOG_1:
+ case PHB_RXE_TCE_ERR1_STATUS:
+ case PHB_RXE_TCE_ERR_LOG_0 ... PHB_RXE_TCE_ERR_LOG_1:
+ case PHB_ERR1_STATUS:
+ case PHB_ERR_LOG_0 ... PHB_ERR_LOG_1:
+ phb->regs[off >> 3] = 0;
+ return;
+
+ /* Write value updated by masks */
case PHB_LSI_SOURCE_ID:
val &= PHB_LSI_SRC_ID;
break;
@@ -695,7 +728,6 @@ static void pnv_phb4_reg_write(void *opaque, hwaddr off, uint64_t val,
case PHB_LEM_WOF:
val = 0;
break;
- /* TODO: More regs ..., maybe create a table with masks... */
/* Read only registers */
case PHB_CPU_LOADSTORE_STATUS:
@@ -704,6 +736,12 @@ static void pnv_phb4_reg_write(void *opaque, hwaddr off, uint64_t val,
case PHB_PHB4_TCE_CAP:
case PHB_PHB4_IRQ_CAP:
case PHB_PHB4_EEH_CAP:
+ case PHB_VERSION:
+ case PHB_DMA_CHAN_STATUS:
+ case PHB_TCE_TAG_STATUS:
+ case PHB_PBL_BUF_STATUS:
+ case PHB_PCIE_BNR:
+ case PHB_PCIE_PHY_RXEQ_STAT_G3_00_03 ... PHB_PCIE_PHY_RXEQ_STAT_G5_12_15:
return;
}
@@ -726,6 +764,7 @@ static void pnv_phb4_reg_write(void *opaque, hwaddr off, uint64_t val,
pnv_phb4_update_all_msi_regions(phb);
}
break;
+
case PHB_M32_START_ADDR:
case PHB_M64_UPPER_BITS:
if (changed) {
@@ -773,27 +812,63 @@ static void pnv_phb4_reg_write(void *opaque, hwaddr off, uint64_t val,
break;
/* Silent simple writes */
- case PHB_ASN_CMPM:
- case PHB_CONFIG_ADDRESS:
- case PHB_IODA_ADDR:
- case PHB_TCE_KILL:
- case PHB_TCE_SPEC_CTL:
- case PHB_PEST_BAR:
- case PHB_PELTV_BAR:
+ /* PHB Fundamental register set A */
+ case PHB_CONFIG_DATA ... PHB_LOCK1:
case PHB_RTT_BAR:
- case PHB_LEM_FIR_ACCUM:
- case PHB_LEM_ERROR_MASK:
- case PHB_LEM_ACTION0:
- case PHB_LEM_ACTION1:
- case PHB_TCE_TAG_ENABLE:
+ case PHB_PELTV_BAR:
+ case PHB_PEST_BAR:
+ case PHB_CAPI_CMPM ... PHB_M64_AOMASK:
+ case PHB_NXLATE_PREFIX ... PHB_DMA_SYNC:
+ case PHB_TCE_KILL ... PHB_IODA_ADDR:
+ case PHB_PAPR_ERR_INJ_CTL ... PHB_PAPR_ERR_INJ_MASK:
case PHB_INT_NOTIFY_ADDR:
case PHB_INT_NOTIFY_INDEX:
- case PHB_DMA_SYNC:
- break;
+ /* Fundamental register set B */
+ case PHB_AIB_FENCE_CTRL ... PHB_Q_DMA_R:
+ /* FIR & Error registers */
+ case PHB_LEM_FIR_ACCUM:
+ case PHB_LEM_ERROR_MASK:
+ case PHB_LEM_ACTION0 ... PHB_LEM_WOF:
+ case PHB_ERR_INJECT ... PHB_ERR_AIB_FENCE_ENABLE:
+ case PHB_ERR_STATUS_MASK ... PHB_ERR1_STATUS_MASK:
+ case PHB_TXE_ERR_INJECT ... PHB_TXE_ERR_AIB_FENCE_ENABLE:
+ case PHB_TXE_ERR_STATUS_MASK ... PHB_TXE_ERR1_STATUS_MASK:
+ case PHB_RXE_ARB_ERR_INJECT ... PHB_RXE_ARB_ERR_AIB_FENCE_ENABLE:
+ case PHB_RXE_ARB_ERR_STATUS_MASK ... PHB_RXE_ARB_ERR1_STATUS_MASK:
+ case PHB_RXE_MRG_ERR_INJECT ... PHB_RXE_MRG_ERR_AIB_FENCE_ENABLE:
+ case PHB_RXE_MRG_ERR_STATUS_MASK ... PHB_RXE_MRG_ERR1_STATUS_MASK:
+ case PHB_RXE_TCE_ERR_INJECT ... PHB_RXE_TCE_ERR_AIB_FENCE_ENABLE:
+ case PHB_RXE_TCE_ERR_STATUS_MASK ... PHB_RXE_TCE_ERR1_STATUS_MASK:
+ /* Performance monitor & Debug registers */
+ case PHB_TRACE_CONTROL ... PHB_PERFMON_CTR1:
+ /* REGB Registers */
+ /* PBL core */
+ case PHB_PBL_CONTROL:
+ case PHB_PBL_TIMEOUT_CTRL:
+ case PHB_PBL_NPTAG_ENABLE:
+ case PHB_PBL_SYS_LINK_INIT:
+ case PHB_PBL_ERR_INF_ENABLE ... PHB_PBL_ERR_FAT_ENABLE:
+ case PHB_PBL_ERR_STATUS_MASK ... PHB_PBL_ERR1_STATUS_MASK:
+ /* PCI-E stack */
+ case PHB_PCIE_SCR:
+ case PHB_PCIE_DLP_STR ... PHB_PCIE_HOTPLUG_STATUS:
+ case PHB_PCIE_LMR ... PHB_PCIE_DLP_LSR:
+ case PHB_PCIE_DLP_RXMGN:
+ case PHB_PCIE_DLP_LANEZEROCTL ... PHB_PCIE_DLP_TRCRDDATA:
+ case PHB_PCIE_DLP_ERR_COUNTERS:
+ case PHB_PCIE_DLP_EIC ... PHB_PCIE_LANE_EQ_CNTL23:
+ case PHB_PCIE_TRACE_CTRL:
+ case PHB_PCIE_MISC_STRAP ... PHB_PCIE_PHY_EQ_CTL:
+ /* Error registers */
+ case PHB_REGB_ERR_INJECT:
+ case PHB_REGB_ERR_INF_ENABLE ... PHB_REGB_ERR_FAT_ENABLE:
+ case PHB_REGB_ERR_STATUS_MASK ... PHB_REGB_ERR1_STATUS_MASK:
+ break;
/* Noise on anything else */
default:
- qemu_log_mask(LOG_UNIMP, "phb4: reg_write 0x%"PRIx64"=%"PRIx64"\n",
+ qemu_log_mask(LOG_UNIMP,
+ "phb4: unimplemented reg_write 0x%"PRIx64"=%"PRIx64"\n",
off, val);
}
}
@@ -881,36 +956,75 @@ static uint64_t pnv_phb4_reg_read(void *opaque, hwaddr off, unsigned size)
return val;
/* Silent simple reads */
+ /* PHB Fundamental register set A */
case PHB_LSI_SOURCE_ID:
+ case PHB_DMA_CHAN_STATUS:
case PHB_CPU_LOADSTORE_STATUS:
- case PHB_ASN_CMPM:
+ case PHB_CONFIG_DATA ... PHB_LOCK1:
case PHB_PHB4_CONFIG:
+ case PHB_RTT_BAR:
+ case PHB_PELTV_BAR:
case PHB_M32_START_ADDR:
- case PHB_CONFIG_ADDRESS:
- case PHB_IODA_ADDR:
- case PHB_RTC_INVALIDATE:
- case PHB_TCE_KILL:
- case PHB_TCE_SPEC_CTL:
case PHB_PEST_BAR:
- case PHB_PELTV_BAR:
- case PHB_RTT_BAR:
+ case PHB_CAPI_CMPM:
+ case PHB_M64_AOMASK:
case PHB_M64_UPPER_BITS:
- case PHB_CTRLR:
- case PHB_LEM_FIR_ACCUM:
- case PHB_LEM_ERROR_MASK:
- case PHB_LEM_ACTION0:
- case PHB_LEM_ACTION1:
- case PHB_TCE_TAG_ENABLE:
+ case PHB_NXLATE_PREFIX:
+ case PHB_RTC_INVALIDATE ... PHB_IODA_ADDR:
+ case PHB_PAPR_ERR_INJ_CTL ... PHB_ETU_ERR_SUMMARY:
case PHB_INT_NOTIFY_ADDR:
case PHB_INT_NOTIFY_INDEX:
- case PHB_Q_DMA_R:
- case PHB_ETU_ERR_SUMMARY:
- break;
-
- /* Noise on anything else */
+ /* Fundamental register set B */
+ case PHB_CTRLR:
+ case PHB_AIB_FENCE_CTRL ... PHB_Q_DMA_R:
+ case PHB_TCE_TAG_STATUS:
+ /* FIR & Error registers */
+ case PHB_LEM_FIR_ACCUM ... PHB_LEM_ERROR_MASK:
+ case PHB_LEM_ACTION0 ... PHB_LEM_WOF:
+ case PHB_ERR_STATUS ... PHB_ERR_AIB_FENCE_ENABLE:
+ case PHB_ERR_LOG_0 ... PHB_ERR1_STATUS_MASK:
+ case PHB_TXE_ERR_STATUS ... PHB_TXE_ERR_AIB_FENCE_ENABLE:
+ case PHB_TXE_ERR_LOG_0 ... PHB_TXE_ERR1_STATUS_MASK:
+ case PHB_RXE_ARB_ERR_STATUS ... PHB_RXE_ARB_ERR_AIB_FENCE_ENABLE:
+ case PHB_RXE_ARB_ERR_LOG_0 ... PHB_RXE_ARB_ERR1_STATUS_MASK:
+ case PHB_RXE_MRG_ERR_STATUS ... PHB_RXE_MRG_ERR_AIB_FENCE_ENABLE:
+ case PHB_RXE_MRG_ERR_LOG_0 ... PHB_RXE_MRG_ERR1_STATUS_MASK:
+ case PHB_RXE_TCE_ERR_STATUS ... PHB_RXE_TCE_ERR_AIB_FENCE_ENABLE:
+ case PHB_RXE_TCE_ERR_LOG_0 ... PHB_RXE_TCE_ERR1_STATUS_MASK:
+ /* Performance monitor & Debug registers */
+ case PHB_TRACE_CONTROL ... PHB_PERFMON_CTR1:
+ /* REGB Registers */
+ /* PBL core */
+ case PHB_PBL_CONTROL:
+ case PHB_PBL_TIMEOUT_CTRL:
+ case PHB_PBL_NPTAG_ENABLE:
+ case PHB_PBL_SYS_LINK_INIT:
+ case PHB_PBL_BUF_STATUS:
+ case PHB_PBL_ERR_STATUS ... PHB_PBL_ERR_INJECT:
+ case PHB_PBL_ERR_INF_ENABLE ... PHB_PBL_ERR_FAT_ENABLE:
+ case PHB_PBL_ERR_LOG_0 ... PHB_PBL_ERR1_STATUS_MASK:
+ /* PCI-E stack */
+ case PHB_PCIE_BNR ... PHB_PCIE_DLP_STR:
+ case PHB_PCIE_DLP_LANE_PWR:
+ case PHB_PCIE_DLP_LSR:
+ case PHB_PCIE_DLP_RXMGN:
+ case PHB_PCIE_DLP_LANEZEROCTL ... PHB_PCIE_DLP_CTL:
+ case PHB_PCIE_DLP_TRCRDDATA:
+ case PHB_PCIE_DLP_ERRLOG1 ... PHB_PCIE_DLP_ERR_COUNTERS:
+ case PHB_PCIE_DLP_EIC ... PHB_PCIE_LANE_EQ_CNTL23:
+ case PHB_PCIE_TRACE_CTRL:
+ case PHB_PCIE_MISC_STRAP ... PHB_PCIE_PHY_RXEQ_STAT_G5_12_15:
+ /* Error registers */
+ case PHB_REGB_ERR_STATUS ... PHB_REGB_ERR_INJECT:
+ case PHB_REGB_ERR_INF_ENABLE ... PHB_REGB_ERR_FAT_ENABLE:
+ case PHB_REGB_ERR_LOG_0 ... PHB_REGB_ERR1_STATUS_MASK:
+ break;
+
+ /* Noise on unimplemented read, return all 1's */
default:
- qemu_log_mask(LOG_UNIMP, "phb4: reg_read 0x%"PRIx64"=%"PRIx64"\n",
- off, val);
+ qemu_log_mask(LOG_UNIMP, "phb4: unimplemented reg_read 0x%"PRIx64"\n",
+ off);
+ val = ~0ull;
}
return val;
}
diff --git a/include/hw/pci-host/pnv_phb4_regs.h b/include/hw/pci-host/pnv_phb4_regs.h
index dfd0e01d1e..c1d5a83271 100644
--- a/include/hw/pci-host/pnv_phb4_regs.h
+++ b/include/hw/pci-host/pnv_phb4_regs.h
@@ -407,6 +407,7 @@
#define PHB_PCIE_CRESET_PERST_N PPC_BIT(3)
#define PHB_PCIE_CRESET_PIPE_N PPC_BIT(4)
#define PHB_PCIE_CRESET_REFCLK_N PPC_BIT(8)
+#define PHB_PCIE_DLP_STR 0x1A18
#define PHB_PCIE_HOTPLUG_STATUS 0x1A20
#define PHB_PCIE_HPSTAT_SIMDIAG PPC_BIT(3)
#define PHB_PCIE_HPSTAT_RESAMPLE PPC_BIT(9)
@@ -417,6 +418,7 @@
#define PHB_PCIE_LMR_RETRAINLINK PPC_BIT(1)
#define PHB_PCIE_LMR_LINKACTIVE PPC_BIT(8)
+#define PHB_PCIE_DLP_LANE_PWR 0x1A38
#define PHB_PCIE_DLP_TRAIN_CTL 0x1A40
#define PHB_PCIE_DLP_LINK_WIDTH PPC_BITMASK(30, 35)
#define PHB_PCIE_DLP_LINK_SPEED PPC_BITMASK(36, 39)
@@ -436,18 +438,21 @@
#define PHB_PCIE_DLP_DL_PGRESET PPC_BIT(22)
#define PHB_PCIE_DLP_TRAINING PPC_BIT(20)
#define PHB_PCIE_DLP_INBAND_PRESENCE PPC_BIT(19)
-
+#define PHB_PCIE_DLP_LSR 0x1A48
+#define PHB_PCIE_DLP_RXMGN 0x1A50
+#define PHB_PCIE_DLP_LANEZEROCTL 0x1A70
#define PHB_PCIE_DLP_CTL 0x1A78
#define PHB_PCIE_DLP_CTL_BYPASS_PH2 PPC_BIT(4)
#define PHB_PCIE_DLP_CTL_BYPASS_PH3 PPC_BIT(5)
-
#define PHB_PCIE_DLP_TRWCTL 0x1A80
#define PHB_PCIE_DLP_TRWCTL_EN PPC_BIT(0)
#define PHB_PCIE_DLP_TRWCTL_WREN PPC_BIT(1)
+#define PHB_PCIE_DLP_TRCRDDATA 0x1A88
#define PHB_PCIE_DLP_ERRLOG1 0x1AA0
#define PHB_PCIE_DLP_ERRLOG2 0x1AA8
#define PHB_PCIE_DLP_ERR_STATUS 0x1AB0
#define PHB_PCIE_DLP_ERR_COUNTERS 0x1AB8
+#define PHB_PCIE_DLP_EIC 0x1AC8
#define PHB_PCIE_LANE_EQ_CNTL0 0x1AD0
#define PHB_PCIE_LANE_EQ_CNTL1 0x1AD8
@@ -459,6 +464,7 @@
#define PHB_PCIE_LANE_EQ_CNTL23 0x1B08 /* DD1 only */
#define PHB_PCIE_TRACE_CTRL 0x1B20
#define PHB_PCIE_MISC_STRAP 0x1B30
+#define PHB_PCIE_PHY_EQ_CTL 0x1B38
#define PHB_PCIE_PHY_RXEQ_STAT_G3_00_03 0x1B40
#define PHB_PCIE_PHY_RXEQ_STAT_G5_12_15 0x1B98
@@ -592,5 +598,4 @@
#define IODA3_PEST1_FAIL_ADDR PPC_BITMASK(3, 63)
-
#endif /* PCI_HOST_PNV_PHB4_REGS_H */
diff --git a/tests/qtest/pnv-phb4-test.c b/tests/qtest/pnv-phb4-test.c
index 2078fab9a9..9ccb75cd5a 100644
--- a/tests/qtest/pnv-phb4-test.c
+++ b/tests/qtest/pnv-phb4-test.c
@@ -137,6 +137,12 @@ static void phb4_writeonly_read_test(QTestState *qts)
g_assert_cmpuint(val, ==, 0x0);
}
+/* Check that reading an unimplemented address 0x0 returns -1 */
+static void phb4_unimplemented_read_test(QTestState *qts)
+{
+ g_assert_cmpint(PHB4_XSCOM_READ(0x0), ==, -1);
+}
+
static void phb4_tests(void)
{
QTestState *qts = NULL;
@@ -152,6 +158,9 @@ static void phb4_tests(void)
/* Check write-only logic */
phb4_writeonly_read_test(qts);
+ /* Check unimplemented register read */
+ phb4_unimplemented_read_test(qts);
+
qtest_quit(qts);
}
--
2.47.3
^ permalink raw reply related [flat|nested] 60+ messages in thread
* [PATCH v4 6/9] pnv/phb4: Set link-active status in HPSTAT and LMR registers
2026-03-05 6:09 ` [PATCH v4 0/9] " Saif Abrar
` (4 preceding siblings ...)
2026-03-05 6:09 ` [PATCH v4 5/9] pnv/phb4: Implement write-clear and return 1's on unimplemented reg read Saif Abrar
@ 2026-03-05 6:09 ` Saif Abrar
2026-05-05 17:46 ` Harsh Prateek Bora
2026-05-09 15:00 ` Aditya Gupta
2026-03-05 6:09 ` [PATCH v4 7/9] pnv/phb4: Set link speed and width in the DLP training control register Saif Abrar
` (4 subsequent siblings)
10 siblings, 2 replies; 60+ messages in thread
From: Saif Abrar @ 2026-03-05 6:09 UTC (permalink / raw)
To: qemu-ppc, qemu-devel
Cc: clg, npiggin, fbarrat, mst, marcel.apfelbaum, cohuck, pbonzini,
thuth, lvivier, danielhb413, saif.abrar
Config-read the link-status register in the PCI-E macro,
Depending on the link-active bit, set the link-active status
in the HOTPLUG_STATUS and LINK_MANAGEMENT registers
Also, clear the Presence-status active low bit in HOTPLUG_STATUS reg
after config-reading the slot-status in the PCI-E macro.
Signed-off-by: Saif Abrar <saif.abrar@linux.vnet.ibm.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
---
v4: Variables declaration moved to the top of the method pnv_phb4_reg_read().
v3: Updates for coding guidelines.
hw/pci-host/pnv_phb4.c | 59 +++++++++++++++++++++++++++++++++++++++++-
1 file changed, 58 insertions(+), 1 deletion(-)
diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c
index 25539b7c32..c35f632e64 100644
--- a/hw/pci-host/pnv_phb4.c
+++ b/hw/pci-host/pnv_phb4.c
@@ -511,6 +511,20 @@ static uint32_t get_exp_offset(PCIDevice *pdev)
return rpc->exp_offset;
}
+/*
+ * Config-read the link-status register in the PCI-E macro,
+ * convert to LE and check the link-active bit.
+ */
+static uint32_t is_link_active(PnvPHB4 *phb)
+{
+ PCIHostState *pci = PCI_HOST_BRIDGE(phb->phb_base);
+ PCIDevice *pdev = pci_find_device(pci->bus, 0, 0);
+ uint32_t exp_offset = get_exp_offset(pdev);
+
+ return (bswap32(pnv_phb4_rc_config_read(phb, exp_offset + PCI_EXP_LNKSTA, 4)
+ ) & PCI_EXP_LNKSTA_DLLLA);
+}
+
/*
* Apply sticky-mask 's' to the reset-value 'v' and write to the address 'a'.
* RC-config space values and masks are LE.
@@ -729,6 +743,11 @@ static void pnv_phb4_reg_write(void *opaque, hwaddr off, uint64_t val,
val = 0;
break;
+ case PHB_PCIE_HOTPLUG_STATUS:
+ /* For normal operations, Simspeed diagnostic bit is always zero */
+ val &= PHB_PCIE_HPSTAT_SIMDIAG;
+ break;
+
/* Read only registers */
case PHB_CPU_LOADSTORE_STATUS:
case PHB_ETU_ERR_SUMMARY:
@@ -876,6 +895,10 @@ static void pnv_phb4_reg_write(void *opaque, hwaddr off, uint64_t val,
static uint64_t pnv_phb4_reg_read(void *opaque, hwaddr off, unsigned size)
{
PnvPHB4 *phb = PNV_PHB4(opaque);
+ /* Get the PCI-E capability offset from the root-port */
+ PCIHostState *pci = PCI_HOST_BRIDGE(phb->phb_base);
+ PCIDevice *pdev = pci_find_device(pci->bus, 0, 0);
+ uint32_t exp_base = get_exp_offset(pdev);
uint64_t val;
if ((off & 0xfffc) == PHB_CONFIG_DATA) {
@@ -944,8 +967,37 @@ static uint64_t pnv_phb4_reg_read(void *opaque, hwaddr off, unsigned size)
val |= PHB_PCIE_DLP_INBAND_PRESENCE | PHB_PCIE_DLP_TL_LINKACT;
return val;
+ /*
+ * Read PCI-E registers and set status for:
+ * - Card present (active low bit 10)
+ * - Link active (bit 12)
+ */
case PHB_PCIE_HOTPLUG_STATUS:
- /* Clear write-only bit */
+ /*
+ * Presence-status bit hpi_present_n is active-low, with reset value 1.
+ * Start by setting this bit to 1, indicating the card is not present.
+ * Then check the PCI-E register and clear the bit if card is present.
+ */
+ val |= PHB_PCIE_HPSTAT_PRESENCE;
+
+ /*
+ * Config-read the PCI-E macro register for slot-status.
+ * Method for config-read converts to BE value.
+ * To check actual bit in the PCI-E register,
+ * convert the value back to LE using bswap32().
+ * Clear the Presence-status active low bit.
+ */
+ if (bswap32(pnv_phb4_rc_config_read(phb, exp_base + PCI_EXP_SLTSTA, 4))
+ & PCI_EXP_SLTSTA_PDS) {
+ val &= ~PHB_PCIE_HPSTAT_PRESENCE;
+ }
+
+ /* Check if link is active and set the bit */
+ if (is_link_active(phb)) {
+ val |= PHB_PCIE_HPSTAT_LINKACTIVE;
+ }
+
+ /* Clear write-only resample-bit */
val &= ~PHB_PCIE_HPSTAT_RESAMPLE;
return val;
@@ -953,6 +1005,11 @@ static uint64_t pnv_phb4_reg_read(void *opaque, hwaddr off, unsigned size)
case PHB_PCIE_LMR:
/* These write-only bits always read as 0 */
val &= ~(PHB_PCIE_LMR_CHANGELW | PHB_PCIE_LMR_RETRAINLINK);
+
+ /* Check if link is active and set the bit */
+ if (is_link_active(phb)) {
+ val |= PHB_PCIE_LMR_LINKACTIVE;
+ }
return val;
/* Silent simple reads */
--
2.47.3
^ permalink raw reply related [flat|nested] 60+ messages in thread
* [PATCH v4 7/9] pnv/phb4: Set link speed and width in the DLP training control register
2026-03-05 6:09 ` [PATCH v4 0/9] " Saif Abrar
` (5 preceding siblings ...)
2026-03-05 6:09 ` [PATCH v4 6/9] pnv/phb4: Set link-active status in HPSTAT and LMR registers Saif Abrar
@ 2026-03-05 6:09 ` Saif Abrar
2026-05-09 15:02 ` Aditya Gupta
2026-03-05 6:09 ` [PATCH v4 8/9] pnv/phb4: Implement IODA PCT table Saif Abrar
` (3 subsequent siblings)
10 siblings, 1 reply; 60+ messages in thread
From: Saif Abrar @ 2026-03-05 6:09 UTC (permalink / raw)
To: qemu-ppc, qemu-devel
Cc: clg, npiggin, fbarrat, mst, marcel.apfelbaum, cohuck, pbonzini,
thuth, lvivier, danielhb413, saif.abrar
Get the current link-status from PCIE macro.
Extract link-speed and link-width from the link-status
and set in the DLP training control (PCIE_DLP_TCR) register.
Signed-off-by: Saif Abrar <saif.abrar@linux.vnet.ibm.com>
Reviewed-by: Cédric Le Goater <clg@kaod.org>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
---
v4: Variables declaration moved to the top of the method pnv_phb4_reg_read().
v3: Updates for coding guidelines.
hw/pci-host/pnv_phb4.c | 22 ++++++++++++++++++++--
1 file changed, 20 insertions(+), 2 deletions(-)
diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c
index c35f632e64..a6fa578e85 100644
--- a/hw/pci-host/pnv_phb4.c
+++ b/hw/pci-host/pnv_phb4.c
@@ -900,6 +900,7 @@ static uint64_t pnv_phb4_reg_read(void *opaque, hwaddr off, unsigned size)
PCIDevice *pdev = pci_find_device(pci->bus, 0, 0);
uint32_t exp_base = get_exp_offset(pdev);
uint64_t val;
+ uint32_t v, lnkstatus;
if ((off & 0xfffc) == PHB_CONFIG_DATA) {
return pnv_phb4_config_read(phb, off & 0x3, size);
@@ -961,10 +962,27 @@ static uint64_t pnv_phb4_reg_read(void *opaque, hwaddr off, unsigned size)
val |= PHB_PCIE_SCR_PLW_X16; /* RO bit */
break;
- /* Link training always appears trained */
case PHB_PCIE_DLP_TRAIN_CTL:
- /* TODO: Do something sensible with speed ? */
+ /* Get the current link-status from PCIE */
+ lnkstatus = bswap32(pnv_phb4_rc_config_read(phb,
+ exp_base + PCI_EXP_LNKSTA, 4));
+
+ /* Extract link-speed from the link-status */
+ v = lnkstatus & PCI_EXP_LNKSTA_CLS;
+
+ /* Link training always appears trained */
val |= PHB_PCIE_DLP_INBAND_PRESENCE | PHB_PCIE_DLP_TL_LINKACT;
+
+ /* Set the current link-speed at the LINK_SPEED position */
+ val = SETFIELD(PHB_PCIE_DLP_LINK_SPEED, val, v);
+
+ /*
+ * Extract link-width from the link-status,
+ * after shifting the required bitfields.
+ */
+ v = (lnkstatus & PCI_EXP_LNKSTA_NLW) >> PCI_EXP_LNKSTA_NLW_SHIFT;
+ /* Set the current link-width at the LINK_WIDTH position */
+ val = SETFIELD(PHB_PCIE_DLP_LINK_WIDTH, val, v);
return val;
/*
--
2.47.3
^ permalink raw reply related [flat|nested] 60+ messages in thread
* [PATCH v4 8/9] pnv/phb4: Implement IODA PCT table
2026-03-05 6:09 ` [PATCH v4 0/9] " Saif Abrar
` (6 preceding siblings ...)
2026-03-05 6:09 ` [PATCH v4 7/9] pnv/phb4: Set link speed and width in the DLP training control register Saif Abrar
@ 2026-03-05 6:09 ` Saif Abrar
2026-05-09 15:03 ` Aditya Gupta
2026-05-11 7:24 ` Jishnu Warrier
2026-03-05 6:09 ` [PATCH v4 9/9] pnv/phb4: Mask off LSI Source-ID based on number of interrupts Saif Abrar
` (2 subsequent siblings)
10 siblings, 2 replies; 60+ messages in thread
From: Saif Abrar @ 2026-03-05 6:09 UTC (permalink / raw)
To: qemu-ppc, qemu-devel
Cc: clg, npiggin, fbarrat, mst, marcel.apfelbaum, cohuck, pbonzini,
thuth, lvivier, danielhb413, saif.abrar
IODA PCT table (#3) is implemented
without any functionality, being a debug table.
Signed-off-by: Saif Abrar <saif.abrar@linux.vnet.ibm.com>
Reviewed-by: Cédric Le Goater <clg@kaod.org>
---
v3: Updates for coding guidelines.
hw/pci-host/pnv_phb4.c | 6 ++++++
include/hw/pci-host/pnv_phb4.h | 2 ++
include/hw/pci-host/pnv_phb4_regs.h | 1 +
3 files changed, 9 insertions(+)
diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c
index a6fa578e85..254bbe4089 100644
--- a/hw/pci-host/pnv_phb4.c
+++ b/hw/pci-host/pnv_phb4.c
@@ -264,6 +264,10 @@ static uint64_t *pnv_phb4_ioda_access(PnvPHB4 *phb,
mask = phb->big_phb ? PNV_PHB4_MAX_MIST : (PNV_PHB4_MAX_MIST >> 1);
mask -= 1;
break;
+ case IODA3_TBL_PCT:
+ tptr = phb->ioda_PCT;
+ mask = 7;
+ break;
case IODA3_TBL_RCAM:
mask = phb->big_phb ? 127 : 63;
break;
@@ -362,6 +366,8 @@ static void pnv_phb4_ioda_write(PnvPHB4 *phb, uint64_t val)
/* Handle side effects */
switch (table) {
case IODA3_TBL_LIST:
+ case IODA3_TBL_PCT:
+ /* No action for debug tables */
break;
case IODA3_TBL_MIST: {
/* Special mask for MIST partial write */
diff --git a/include/hw/pci-host/pnv_phb4.h b/include/hw/pci-host/pnv_phb4.h
index bea0684724..6bb75edeef 100644
--- a/include/hw/pci-host/pnv_phb4.h
+++ b/include/hw/pci-host/pnv_phb4.h
@@ -65,6 +65,7 @@ OBJECT_DECLARE_SIMPLE_TYPE(PnvPHB4RootBus, PNV_PHB4_ROOT_BUS)
#define PNV_PHB4_MAX_LSIs 8
#define PNV_PHB4_MAX_INTs 4096
#define PNV_PHB4_MAX_MIST (PNV_PHB4_MAX_INTs >> 2)
+#define PNV_PHB4_MAX_PCT 128
#define PNV_PHB4_MAX_MMIO_WINDOWS 32
#define PNV_PHB4_MIN_MMIO_WINDOWS 16
#define PNV_PHB4_NUM_REGS (0x3000 >> 3)
@@ -138,6 +139,7 @@ struct PnvPHB4 {
/* On-chip IODA tables */
uint64_t ioda_LIST[PNV_PHB4_MAX_LSIs];
uint64_t ioda_MIST[PNV_PHB4_MAX_MIST];
+ uint64_t ioda_PCT[PNV_PHB4_MAX_PCT];
uint64_t ioda_TVT[PNV_PHB4_MAX_TVEs];
uint64_t ioda_MBT[PNV_PHB4_MAX_MBEs];
uint64_t ioda_MDT[PNV_PHB4_MAX_PEs];
diff --git a/include/hw/pci-host/pnv_phb4_regs.h b/include/hw/pci-host/pnv_phb4_regs.h
index c1d5a83271..e30adff7b2 100644
--- a/include/hw/pci-host/pnv_phb4_regs.h
+++ b/include/hw/pci-host/pnv_phb4_regs.h
@@ -486,6 +486,7 @@
#define IODA3_TBL_LIST 1
#define IODA3_TBL_MIST 2
+#define IODA3_TBL_PCT 3
#define IODA3_TBL_RCAM 5
#define IODA3_TBL_MRT 6
#define IODA3_TBL_PESTA 7
--
2.47.3
^ permalink raw reply related [flat|nested] 60+ messages in thread
* [PATCH v4 9/9] pnv/phb4: Mask off LSI Source-ID based on number of interrupts
2026-03-05 6:09 ` [PATCH v4 0/9] " Saif Abrar
` (7 preceding siblings ...)
2026-03-05 6:09 ` [PATCH v4 8/9] pnv/phb4: Implement IODA PCT table Saif Abrar
@ 2026-03-05 6:09 ` Saif Abrar
2026-05-09 15:04 ` Aditya Gupta
2026-05-11 8:46 ` Jishnu Warrier
2026-05-08 16:00 ` [PATCH v4 0/9] pnv/phb4: Update PHB4 to the latest PHB5 spec Aditya Gupta
2026-05-19 5:52 ` Saif Abrar
10 siblings, 2 replies; 60+ messages in thread
From: Saif Abrar @ 2026-03-05 6:09 UTC (permalink / raw)
To: qemu-ppc, qemu-devel
Cc: clg, npiggin, fbarrat, mst, marcel.apfelbaum, cohuck, pbonzini,
thuth, lvivier, danielhb413, saif.abrar
Add a method to reset the value of LSI Source-ID.
Mask off LSI source-id based on number of interrupts in the big/small PHB.
Signed-off-by: Saif Abrar <saif.abrar@linux.vnet.ibm.com>
Reviewed-by: Cédric Le Goater <clg@kaod.org>
---
v3: Updates for coding guidelines.
v2: Introduced method pnv_phb4_xsrc_reset().
hw/pci-host/pnv_phb4.c | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c
index 254bbe4089..5e885cb89d 100644
--- a/hw/pci-host/pnv_phb4.c
+++ b/hw/pci-host/pnv_phb4.c
@@ -490,6 +490,7 @@ static void pnv_phb4_update_xsrc(PnvPHB4 *phb)
lsi_base = GETFIELD(PHB_LSI_SRC_ID, phb->regs[PHB_LSI_SOURCE_ID >> 3]);
lsi_base <<= 3;
+ lsi_base &= (xsrc->nr_irqs - 1);
/* TODO: handle reset values of PHB_LSI_SRC_ID */
if (!lsi_base) {
@@ -1944,6 +1945,12 @@ static void pnv_phb4_ro_mask_init(PnvPHB4 *phb)
/* TODO: Add more RO-masks as regs are implemented in the model */
}
+static void pnv_phb4_xsrc_reset(PnvPHB4 *phb)
+{
+ phb->regs[PHB_LSI_SOURCE_ID >> 3] = PPC_BITMASK(4, 12);
+ pnv_phb4_update_xsrc(phb);
+}
+
static void pnv_phb4_err_reg_reset(PnvPHB4 *phb)
{
STICKY_RST(PHB_ERR_STATUS, 0, PPC_BITMASK(0, 33));
@@ -2000,10 +2007,11 @@ static void pnv_phb4_reset(Object *obj, ResetType type)
PnvPHB4 *phb = PNV_PHB4(obj);
pnv_phb4_pbl_core_reset(phb);
+
+ pnv_phb4_xsrc_reset(phb);
pnv_phb4_err_reg_reset(phb);
pnv_phb4_pcie_stack_reg_reset(phb);
pnv_phb4_regb_err_reg_reset(phb);
- phb->regs[PHB_PCIE_CRESET >> 3] = 0xE000000000000000;
}
static void pnv_phb4_instance_init(Object *obj)
@@ -2080,8 +2088,6 @@ static void pnv_phb4_realize(DeviceState *dev, Error **errp)
return;
}
- pnv_phb4_update_xsrc(phb);
-
phb->qirqs = qemu_allocate_irqs(xive_source_set_irq, xsrc, xsrc->nr_irqs);
pnv_phb4_xscom_realize(phb);
--
2.47.3
^ permalink raw reply related [flat|nested] 60+ messages in thread
* Re: [PATCH v4 1/9] qtest/phb4: Add testbench for PHB4
2026-03-05 6:09 ` [PATCH v4 1/9] qtest/phb4: Add testbench for PHB4 Saif Abrar
@ 2026-05-01 13:59 ` Harsh Prateek Bora
2026-05-09 14:33 ` Aditya Gupta
1 sibling, 0 replies; 60+ messages in thread
From: Harsh Prateek Bora @ 2026-05-01 13:59 UTC (permalink / raw)
To: Saif Abrar, qemu-ppc, qemu-devel
Cc: clg, npiggin, fbarrat, mst, marcel.apfelbaum, cohuck, pbonzini,
thuth, lvivier, danielhb413, Michael Kowal, chalapathi.v,
Caleb Schlossin, Glenn Miles, jishnuvw, Aditya Gupta, amachhiw
<Adding folks working in this area or who might be interested in it>
On 05/03/26 11:39 am, Saif Abrar wrote:
> New qtest testbench added for PHB[345].
> Testbench reads PHB Version register and asserts that
> bits[24:31] have value 0xA3, 0xA4 and 0xA5 respectively.
>
> Signed-off-by: Saif Abrar <saif.abrar@linux.vnet.ibm.com>
> Reviewed-by: Cédric Le Goater <clg@kaod.org>
> ---
> v3: Updates for coding guidelines.
> v2: Added version check for PHB3 and PHB4 also.
>
> tests/qtest/meson.build | 1 +
> tests/qtest/pnv-phb4-test.c | 98 +++++++++++++++++++++++++++++++++++++
> 2 files changed, 99 insertions(+)
> create mode 100644 tests/qtest/pnv-phb4-test.c
>
> diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
> index ba9f59d2f8..030f3f4fc6 100644
> --- a/tests/qtest/meson.build
> +++ b/tests/qtest/meson.build
> @@ -182,6 +182,7 @@ qtests_ppc64 = \
> (config_all_devices.has_key('CONFIG_POWERNV') ? ['pnv-xive2-test'] : []) + \
> (config_all_devices.has_key('CONFIG_POWERNV') ? ['pnv-spi-seeprom-test'] : []) + \
> (config_all_devices.has_key('CONFIG_POWERNV') ? ['pnv-host-i2c-test'] : []) + \
> + (config_all_devices.has_key('CONFIG_POWERNV') ? ['pnv-phb4-test'] : []) + \
Should we just call it pnv-phb-test as it takes care of all PHB 3/4/5.
Also, need to audit all the patches whether to keep the naming as just
phb or phb{3,4,5} as applicable.
> (config_all_devices.has_key('CONFIG_PSERIES') ? ['numa-test'] : []) + \
> (config_all_devices.has_key('CONFIG_PSERIES') ? ['rtas-test'] : []) + \
> (slirp.found() ? ['pxe-test'] : []) + \
> diff --git a/tests/qtest/pnv-phb4-test.c b/tests/qtest/pnv-phb4-test.c
> new file mode 100644
> index 0000000000..797f6b6c87
> --- /dev/null
> +++ b/tests/qtest/pnv-phb4-test.c
> @@ -0,0 +1,98 @@
> +/*
> + * QTest testcase for PowerNV PHB4
> + *
> + * Copyright (c) 2025, IBM Corporation.
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + *
> + */
> +
> +#include "qemu/osdep.h"
> +#include "libqtest.h"
> +#include "hw/pci-host/pnv_phb4_regs.h"
> +#include "pnv-xscom.h"
> +
> +#define PPC_BIT(bit) (0x8000000000000000ULL >> (bit))
> +#define PPC_BITMASK(bs, be) ((PPC_BIT(bs) - PPC_BIT(be)) | PPC_BIT(bs))
Looks like we already have 2 files in tests/qtest folder which contains
these macros. Time to cleanup common code into a common header ?
> +
> +#define PHB3_PBCQ_SPCI_ASB_ADDR 0x0
> +#define PHB3_PBCQ_SPCI_ASB_DATA 0x2
> +
> +/* Index of PNV_CHIP_POWER10 in pnv_chips[] within "pnv-xscom.h" */
> +#define PNV_P10_CHIP_INDEX 3
Where is this being used and do we really need it?
> +#define PHB4_XSCOM 0x40084800ull
> +
> +/*
> + * Indirect XSCOM read::
> + * - Write 'Indirect Address Register' with register-offset to read.
> + * - Read 'Indirect Data Register' to get the value.
> + */
> +static uint64_t pnv_phb_xscom_read(QTestState *qts, const PnvChip *chip,
> + uint64_t scom, uint32_t indirect_addr, uint32_t indirect_data,
> + uint64_t reg)
> +{
> + qtest_writeq(qts, pnv_xscom_addr(chip, (scom >> 3) + indirect_addr), reg);
What does bit shift 3 signify here, can we have a self explanatory macro
for this?
> + return qtest_readq(qts, pnv_xscom_addr(chip, (scom >> 3) + indirect_data));
> +}
> +
> +/* Assert that 'PHB - Version Register' bits[24:31] are as expected */
> +static void phb_version_test(const void *data)
> +{
> + const PnvChip *chip = (PnvChip *)data;
> + QTestState *qts;
> + const char *machine = "powernv8";
> + uint64_t phb_xscom = 0x4809e000;
> + uint64_t reg_phb_version = PHB_VERSION;
> + uint32_t indirect_addr = PHB3_PBCQ_SPCI_ASB_ADDR;
> + uint32_t indirect_data = PHB3_PBCQ_SPCI_ASB_DATA;
> + uint32_t expected_ver = 0xA3;
> + uint64_t ver;
> +
> + if (chip->chip_type == PNV_CHIP_POWER9) {
> + machine = "powernv9";
> + phb_xscom = 0x68084800;
> + indirect_addr = PHB_SCOM_HV_IND_ADDR;
> + indirect_data = PHB_SCOM_HV_IND_DATA;
> + reg_phb_version |= PPC_BIT(0);
> + expected_ver = 0xA4;
> + } else if (chip->chip_type == PNV_CHIP_POWER10) {
What about POWER11? Also, could the check be based on PHB type supported
(need new attribute?) so that we dont need to add checks for every next
PnvChip->chip_type which supports the existing PHB type?
> + machine = "powernv10";
> + phb_xscom = PHB4_XSCOM;
> + indirect_addr = PHB_SCOM_HV_IND_ADDR;
> + indirect_data = PHB_SCOM_HV_IND_DATA;
> + reg_phb_version |= PPC_BIT(0);
> + expected_ver = 0xA5;
> + }
> +
> + qts = qtest_initf("-M %s -accel tcg -cpu %s", machine, chip->cpu_model);
> +
> + ver = pnv_phb_xscom_read(qts, chip, phb_xscom,
> + indirect_addr, indirect_data, reg_phb_version);
> +
> + /* PHB Version register bits [24:31] */
> + ver = ver >> (63 - 31);
It is always preferable to mask the remaining bits before extracting.
> + g_assert_cmpuint(ver, ==, expected_ver);
> +
> + qtest_quit(qts);
> +}
> +
> +/* Verify versions of all supported PHB's */
> +static void add_phbX_version_test(void)
> +{
> + for (int i = 0; i < ARRAY_SIZE(pnv_chips); i++) {
> + char *tname = g_strdup_printf("pnv-phb/%s",
> + pnv_chips[i].cpu_model);
> + qtest_add_data_func(tname, &pnv_chips[i], phb_version_test);
> + g_free(tname);
> + }
> +}
> +
> +int main(int argc, char **argv)
> +{
> + g_test_init(&argc, &argv, NULL);
> +
> + /* PHB[345] tests */
> + add_phbX_version_test();
> +
> + return g_test_run();
> +}
^ permalink raw reply [flat|nested] 60+ messages in thread
* Re: [PATCH v4 2/9] pnv/phb4: Add reset logic to PHB4
2026-03-05 6:09 ` [PATCH v4 2/9] pnv/phb4: Add reset logic to PHB4 Saif Abrar
@ 2026-05-01 14:37 ` Harsh Prateek Bora
2026-05-05 14:16 ` Harsh Prateek Bora
2026-05-09 14:42 ` Aditya Gupta
2 siblings, 0 replies; 60+ messages in thread
From: Harsh Prateek Bora @ 2026-05-01 14:37 UTC (permalink / raw)
To: Saif Abrar, qemu-ppc, qemu-devel
Cc: clg, npiggin, fbarrat, mst, marcel.apfelbaum, cohuck, pbonzini,
thuth, lvivier, danielhb413
On 05/03/26 11:39 am, Saif Abrar wrote:
> Add a method to be invoked on QEMU reset.
> Also add CFG and PBL core-blocks reset logic using
> appropriate bits of PHB_PCIE_CRESET register.
>
> Tested by reading the reset value of a register.
>
> Signed-off-by: Saif Abrar <saif.abrar@linux.vnet.ibm.com>
> Reviewed-by: Cédric Le Goater <clg@kaod.org>
> Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
> ---
> v3: Updates for coding guidelines.
> v2:
> - Using the ResettableClass.
> - Reset of the root complex registers done in pnv_phb_root_port_reset_hold().
>
> hw/pci-host/pnv_phb.c | 1 +
> hw/pci-host/pnv_phb4.c | 103 +++++++++++++++++++++++++++-
> include/hw/pci-host/pnv_phb4.h | 1 +
> include/hw/pci-host/pnv_phb4_regs.h | 16 ++++-
> tests/qtest/pnv-phb4-test.c | 28 +++++++-
> 5 files changed, 145 insertions(+), 4 deletions(-)
>
> diff --git a/hw/pci-host/pnv_phb.c b/hw/pci-host/pnv_phb.c
> index 0b556d1bf5..d4f452d7b2 100644
> --- a/hw/pci-host/pnv_phb.c
> +++ b/hw/pci-host/pnv_phb.c
> @@ -232,6 +232,7 @@ static void pnv_phb_root_port_reset_hold(Object *obj, ResetType type)
> pci_set_long(conf + PCI_PREF_BASE_UPPER32, 0x1); /* Hack */
> pci_set_long(conf + PCI_PREF_LIMIT_UPPER32, 0xffffffff);
> pci_config_set_interrupt_pin(conf, 0);
> + pnv_phb4_cfg_core_reset(d);
Cover letter says updating to PHB5 spec, but here we are calling phb4
specific reset in common phb code?
If the reset logic applies to all versions of PHBs, we should better
call it just pnv_phb_cfg_core_reset(). Otherwise, need to better
refactor code such that pnv_phb.{h,c} contains only common code which
applies to all versions of phb, keep phb4 specific code in pnv_phb4.c,
export reusable routines from common code which can be called from
phb{4,5} specific code in pnv_phb{4,5}.c files respectively.
I understand we already have phb5 specific code in pnv_phb4.c, but we
need to reorg it at some point of time, and it will be great if we can
do it sometime soon, preferably along with this series. However, I am
fine if you wish to take it as a follow-up work. Having said that we
need to get the naming corrected as applicable (i.e. just phb vs
phb{3,4,5}), so that later we would only need to take care of moving
phb5 specific code to pnv_phb5.c.
> }
>
> static void pnv_phb_root_port_realize(DeviceState *dev, Error **errp)
<snipped>
> +
> +static void phb4_tests(void)
> +{
I guess you meant phb5_tests here since using machine powernv10 inside ?
> + QTestState *qts = NULL;
> +
> + qts = qtest_initf("-machine powernv10 -accel tcg");
> +
> + /* Check reset value of a register */
> + phb4_reset_test(qts);
> +
> + qtest_quit(qts);
> +}
> +
> /* Assert that 'PHB - Version Register' bits[24:31] are as expected */
> static void phb_version_test(const void *data)
> {
> @@ -72,8 +95,6 @@ static void phb_version_test(const void *data)
> /* PHB Version register bits [24:31] */
> ver = ver >> (63 - 31);
> g_assert_cmpuint(ver, ==, expected_ver);
> -
> - qtest_quit(qts);
This should be cleaned up in the prev patch where it was introduced.
Also, whenever sending next version of patches, please avoid sending as
reply to previous series. You can keep updating changelog in cover
letter with links to previous version when sending the next version.
Thanks for looking into it, significant work!
regards,
Harsh
> }
>
> /* Verify versions of all supported PHB's */
> @@ -94,5 +115,8 @@ int main(int argc, char **argv)
> /* PHB[345] tests */
> add_phbX_version_test();
>
> + /* PHB4 specific tests */
> + qtest_add_func("phb4", phb4_tests);
> +
> return g_test_run();
> }
^ permalink raw reply [flat|nested] 60+ messages in thread
* Re: [PATCH v4 2/9] pnv/phb4: Add reset logic to PHB4
2026-03-05 6:09 ` [PATCH v4 2/9] pnv/phb4: Add reset logic to PHB4 Saif Abrar
2026-05-01 14:37 ` Harsh Prateek Bora
@ 2026-05-05 14:16 ` Harsh Prateek Bora
2026-05-09 14:42 ` Aditya Gupta
2 siblings, 0 replies; 60+ messages in thread
From: Harsh Prateek Bora @ 2026-05-05 14:16 UTC (permalink / raw)
To: Saif Abrar, qemu-ppc, qemu-devel
Cc: clg, npiggin, fbarrat, mst, marcel.apfelbaum, cohuck, pbonzini,
thuth, lvivier, danielhb413
On 05/03/26 11:39 am, Saif Abrar wrote:
> +void pnv_phb4_cfg_core_reset(PCIDevice *d)
> +{
> + uint8_t *conf = d->config;
> + uint32_t exp_offset = get_exp_offset(d);
> +
> + pci_set_word(conf + PCI_COMMAND, PCI_COMMAND_SERR);
> + pci_set_word(conf + PCI_STATUS, PCI_STATUS_CAP_LIST);
> + pci_set_long(conf + PCI_CLASS_REVISION, 0x06040000);
> + pci_set_long(conf + PCI_CACHE_LINE_SIZE, BIT(16));
> + pci_set_word(conf + PCI_MEMORY_BASE, BIT(4));
> + pci_set_word(conf + PCI_PREF_MEMORY_BASE, BIT(0) | BIT(4));
> + pci_set_word(conf + PCI_PREF_MEMORY_LIMIT, PCI_PREF_RANGE_TYPE_64);
> + pci_set_long(conf + PCI_CAPABILITY_LIST, BIT(6));
> + pci_set_long(conf + PCI_CAPABILITY_LIST, BIT(6));
This duplicate looks like a copy-paste error ?
^ permalink raw reply [flat|nested] 60+ messages in thread
* Re: [PATCH v4 3/9] pnv/phb4: Implement sticky reset logic in PHB4
2026-03-05 6:09 ` [PATCH v4 3/9] pnv/phb4: Implement sticky reset logic in PHB4 Saif Abrar
@ 2026-05-05 14:29 ` Harsh Prateek Bora
2026-05-05 15:08 ` Harsh Prateek Bora
2026-05-09 14:48 ` Aditya Gupta
1 sibling, 1 reply; 60+ messages in thread
From: Harsh Prateek Bora @ 2026-05-05 14:29 UTC (permalink / raw)
To: Saif Abrar, qemu-ppc, qemu-devel
Cc: clg, npiggin, fbarrat, mst, marcel.apfelbaum, cohuck, pbonzini,
thuth, lvivier, danielhb413
On 05/03/26 11:39 am, Saif Abrar wrote:
> Sticky bits retain their values on reset and are not overwritten with
> the reset value.
> Added sticky reset logic for all required registers,
> i.e. CFG core, PBL core, PHB error registers, PCIE stack registers and
> REGB error registers.
>
> Tested by writing all 1's to the reg PHB_PBL_ERR_INJECT.
> This will set the bits in the reg PHB_PBL_ERR_STATUS.
> Reset the PBL core by setting PHB_PCIE_CRESET_PBL in reg PHB_PCIE_CRESET.
> Verify that the sticky bits in the PHB_PBL_ERR_STATUS reg are still set.
>
> Signed-off-by: Saif Abrar <saif.abrar@linux.vnet.ibm.com>
> ---
> v3: Updates for coding guidelines.
>
> hw/pci-host/pnv_phb4.c | 123 +++++++++++++++++++++++++++-
> include/hw/pci-host/pnv_phb4_regs.h | 20 ++++-
> tests/qtest/pnv-phb4-test.c | 41 ++++++++++
> 3 files changed, 179 insertions(+), 5 deletions(-)
>
> diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c
> index 763e9c9776..b3f46f7fe1 100644
> --- a/hw/pci-host/pnv_phb4.c
> +++ b/hw/pci-host/pnv_phb4.c
> @@ -511,6 +511,18 @@ static uint32_t get_exp_offset(PCIDevice *pdev)
> return rpc->exp_offset;
> }
>
> +/*
> + * Apply sticky-mask 's' to the reset-value 'v' and write to the address 'a'.
> + * RC-config space values and masks are LE.
> + * Method pnv_phb4_rc_config_read() returns BE, hence convert to LE.
> + * Compute new value in LE domain.
> + * New value computation using sticky-mask is in LE.
> + * Convert the computed value from LE to BE before writing back.
> + */
> +#define RC_CONFIG_STICKY_RESET(a, v, s) \
> + (pci_set_word(conf + (a), bswap32( \
> + (bswap32(pci_get_word(conf + (a))) & (s)) | ((v) & ~(s)))))
Shouldn't we be using bswap16 here ?
> +
> void pnv_phb4_cfg_core_reset(PCIDevice *d)
> {
> uint8_t *conf = d->config;
> @@ -560,14 +572,56 @@ void pnv_phb4_cfg_core_reset(PCIDevice *d)
> pci_set_long(conf + P16_ECAP, 0x22410026);
> pci_set_long(conf + P32_ECAP, 0x1002A);
> pci_set_long(conf + P32_CAP, 0x103);
> +
> + /* Sticky reset */
> + RC_CONFIG_STICKY_RESET(exp_offset + PCI_EXP_LNKCTL2,
> + PCI_EXP_LNKCTL2_TLS_32_0GT, 0xFEFFBF);
> + RC_CONFIG_STICKY_RESET(PHB_AER_UERR, 0, 0x1FF030);
> + RC_CONFIG_STICKY_RESET(PHB_AER_UERR_MASK, 0, 0x1FF030);
> + RC_CONFIG_STICKY_RESET(PHB_AER_CERR, 0, 0x11C1);
> + RC_CONFIG_STICKY_RESET(PHB_AER_ECAP + PCI_ERR_CAP, (PCI_ERR_CAP_ECRC_CHKC
> + | PCI_ERR_CAP_ECRC_GENC), 0x15F);
> + RC_CONFIG_STICKY_RESET(PHB_AER_HLOG_1, 0, 0xFFFFFFFF);
> + RC_CONFIG_STICKY_RESET(PHB_AER_HLOG_2, 0, 0xFFFFFFFF);
> + RC_CONFIG_STICKY_RESET(PHB_AER_HLOG_3, 0, 0xFFFFFFFF);
> + RC_CONFIG_STICKY_RESET(PHB_AER_HLOG_4, 0, 0xFFFFFFFF);
> + RC_CONFIG_STICKY_RESET(PHB_AER_RERR, 0, 0x7F);
> + RC_CONFIG_STICKY_RESET(PHB_AER_ESID, 0, 0xFFFFFFFF);
> + RC_CONFIG_STICKY_RESET(PHB_DLF_STAT, 0, 0x807FFFFF);
> + RC_CONFIG_STICKY_RESET(P16_STAT, 0, 0x1F);
> + RC_CONFIG_STICKY_RESET(P16_LDPM, 0, 0xFFFF);
> + RC_CONFIG_STICKY_RESET(P16_FRDPM, 0, 0xFFFF);
> + RC_CONFIG_STICKY_RESET(P16_SRDPM, 0, 0xFFFF);
> + RC_CONFIG_STICKY_RESET(P32_CTL, 0, 0x3);
> }
>
> +/* Apply sticky-mask to the reset-value and write to the reg-address */
> +#define STICKY_RST(addr, rst_val, sticky_mask) (phb->regs[addr >> 3] = \
> + ((phb->regs[addr >> 3] & sticky_mask) | (rst_val & ~sticky_mask)))
> +
> static void pnv_phb4_pbl_core_reset(PnvPHB4 *phb)
> {
> - /* Zero all registers initially */
> + /*
> + * Zero all registers initially,
> + * with sticky reset of certain registers.
> + */
> for (int i = PHB_PBL_CONTROL ; i <= PHB_PBL_ERR1_STATUS_MASK ; i += 8) {
> - phb->regs[i >> 3] = 0x0;
> + switch (i) {
> + case PHB_PBL_ERR_STATUS:
> + break;
> + case PHB_PBL_ERR1_STATUS:
> + case PHB_PBL_ERR_LOG_0:
> + case PHB_PBL_ERR_LOG_1:
> + case PHB_PBL_ERR_STATUS_MASK:
> + case PHB_PBL_ERR1_STATUS_MASK:
> + STICKY_RST(i, 0, PPC_BITMASK(0, 63));
> + break;
> + default:
> + phb->regs[i >> 3] = 0x0;
> + }
> }
> + STICKY_RST(PHB_PBL_ERR_STATUS, 0, \
> + (PPC_BITMASK(0, 9) | PPC_BITMASK(12, 63)));
>
> /* Set specific register values */
> phb->regs[PHB_PBL_CONTROL >> 3] = 0xC009000000000000;
> @@ -701,6 +755,17 @@ static void pnv_phb4_reg_write(void *opaque, hwaddr off, uint64_t val,
> }
> break;
>
> + /*
> + * Writing bits to a 1 in this register will inject the error corresponding
> + * to the bit that is written. The bits will automatically clear to 0 after
> + * the error is injected. The corresponding bit in the Error Status Reg
> + * should also be set automatically when the error occurs.
> + */
> + case PHB_PBL_ERR_INJECT:
> + phb->regs[PHB_PBL_ERR_STATUS >> 3] = phb->regs[off >> 3];
> + phb->regs[off >> 3] = 0;
> + break;
> +
> /* Silent simple writes */
> case PHB_ASN_CMPM:
> case PHB_CONFIG_ADDRESS:
> @@ -1621,11 +1686,65 @@ static PCIIOMMUOps pnv_phb4_iommu_ops = {
> .get_address_space = pnv_phb4_dma_iommu,
> };
>
> +static void pnv_phb4_err_reg_reset(PnvPHB4 *phb)
> +{
> + STICKY_RST(PHB_ERR_STATUS, 0, PPC_BITMASK(0, 33));
> + STICKY_RST(PHB_ERR1_STATUS, 0, PPC_BITMASK(0, 63));
> + STICKY_RST(PHB_ERR_STATUS_MASK, 0, PPC_BITMASK(0, 63));
> + STICKY_RST(PHB_ERR1_STATUS_MASK, 0, PPC_BITMASK(0, 63));
> +
> + STICKY_RST(PHB_TXE_ERR_STATUS, 0, PPC_BITMASK(0, 63));
> + STICKY_RST(PHB_TXE_ERR1_STATUS, 0, PPC_BITMASK(0, 63));
> + STICKY_RST(PHB_TXE_ERR_STATUS_MASK, 0, PPC_BITMASK(0, 63));
> + STICKY_RST(PHB_TXE_ERR1_STATUS_MASK, 0, PPC_BITMASK(0, 63));
> +
> + STICKY_RST(PHB_RXE_ARB_ERR_STATUS, 0, PPC_BITMASK(0, 63));
> + STICKY_RST(PHB_RXE_ARB_ERR1_STATUS, 0, PPC_BITMASK(0, 63));
> + STICKY_RST(PHB_RXE_ARB_ERR_LOG_0, 0, PPC_BITMASK(0, 63));
> + STICKY_RST(PHB_RXE_ARB_ERR_LOG_1, 0, PPC_BITMASK(0, 63));
> + STICKY_RST(PHB_RXE_ARB_ERR_STATUS_MASK, 0, PPC_BITMASK(0, 63));
> + STICKY_RST(PHB_RXE_ARB_ERR1_STATUS_MASK, 0, PPC_BITMASK(0, 63));
> +
> + STICKY_RST(PHB_RXE_MRG_ERR_STATUS, 0, PPC_BITMASK(0, 63));
> + STICKY_RST(PHB_RXE_MRG_ERR1_STATUS, 0, PPC_BITMASK(0, 63));
> + STICKY_RST(PHB_RXE_MRG_ERR_STATUS_MASK, 0, PPC_BITMASK(0, 63));
> + STICKY_RST(PHB_RXE_MRG_ERR1_STATUS_MASK, 0, PPC_BITMASK(0, 63));
> +
> + STICKY_RST(PHB_RXE_TCE_ERR_STATUS, 0, PPC_BITMASK(0, 35));
> + STICKY_RST(PHB_RXE_TCE_ERR1_STATUS, 0, PPC_BITMASK(0, 63));
> + STICKY_RST(PHB_RXE_TCE_ERR_LOG_0, 0, PPC_BITMASK(0, 63));
> + STICKY_RST(PHB_RXE_TCE_ERR_LOG_1, 0, PPC_BITMASK(0, 63));
> + STICKY_RST(PHB_RXE_TCE_ERR_STATUS_MASK, 0, PPC_BITMASK(0, 63));
> + STICKY_RST(PHB_RXE_TCE_ERR1_STATUS_MASK, 0, PPC_BITMASK(0, 63));
> +}
> +
> +static void pnv_phb4_pcie_stack_reg_reset(PnvPHB4 *phb)
> +{
> + STICKY_RST(PHB_PCIE_CRESET, 0xE000000000000000, \
> + (PHB_PCIE_CRESET_PERST_N | PHB_PCIE_CRESET_REFCLK_N));
> + STICKY_RST(PHB_PCIE_DLP_ERRLOG1, 0, PPC_BITMASK(0, 63));
> + STICKY_RST(PHB_PCIE_DLP_ERRLOG2, 0, PPC_BITMASK(0, 31));
> + STICKY_RST(PHB_PCIE_DLP_ERR_STATUS, 0, PPC_BITMASK(0, 15));
> +}
> +
> +static void pnv_phb4_regb_err_reg_reset(PnvPHB4 *phb)
> +{
> + STICKY_RST(PHB_REGB_ERR_STATUS, 0, PPC_BITMASK(0, 63));
> + STICKY_RST(PHB_REGB_ERR1_STATUS, 0, PPC_BITMASK(0, 63));
> + STICKY_RST(PHB_REGB_ERR_LOG_0, 0, PPC_BITMASK(0, 63));
> + STICKY_RST(PHB_REGB_ERR_LOG_1, 0, PPC_BITMASK(0, 63));
> + STICKY_RST(PHB_REGB_ERR_STATUS_MASK, 0, PPC_BITMASK(0, 63));
> + STICKY_RST(PHB_REGB_ERR1_STATUS_MASK, 0, PPC_BITMASK(0, 63));
> +}
> +
> static void pnv_phb4_reset(Object *obj, ResetType type)
> {
> PnvPHB4 *phb = PNV_PHB4(obj);
>
> pnv_phb4_pbl_core_reset(phb);
> + pnv_phb4_err_reg_reset(phb);
> + pnv_phb4_pcie_stack_reg_reset(phb);
> + pnv_phb4_regb_err_reg_reset(phb);
> }
>
> static void pnv_phb4_instance_init(Object *obj)
> diff --git a/include/hw/pci-host/pnv_phb4_regs.h b/include/hw/pci-host/pnv_phb4_regs.h
> index 6892e21cc9..df5e86d29a 100644
> --- a/include/hw/pci-host/pnv_phb4_regs.h
> +++ b/include/hw/pci-host/pnv_phb4_regs.h
> @@ -344,17 +344,32 @@
> #define PHB_RC_CONFIG_SIZE 0x800
>
> #define PHB_AER_ECAP 0x100
> +#define PHB_AER_UERR 0x104
> +#define PHB_AER_UERR_MASK 0x108
> +#define PHB_AER_CERR 0x110
> #define PHB_AER_CAPCTRL 0x118
> +#define PHB_AER_HLOG_1 0x11C
> +#define PHB_AER_HLOG_2 0x120
> +#define PHB_AER_HLOG_3 0x124
> +#define PHB_AER_HLOG_4 0x128
> +#define PHB_AER_RERR 0x130
> +#define PHB_AER_ESID 0x134
> #define PHB_SEC_ECAP 0x148
> #define PHB_LMR_ECAP 0x1A0
> #define PHB_LMR_CTLSTA_2 0x1AC
> #define PHB_LMR_CTLSTA_16 0x1E4
> #define PHB_DLF_ECAP 0x1E8
> #define PHB_DLF_CAP 0x1EC
> +#define PHB_DLF_STAT 0x1F0
> #define P16_ECAP 0x1F4
> +#define P16_STAT 0x200
> +#define P16_LDPM 0x204
> +#define P16_FRDPM 0x208
> +#define P16_SRDPM 0x20C
> #define P32_ECAP 0x224
> #define P32_CAP 0x228
> -
> +#define P32_CTL 0x22C
> +#define P32_STAT 0x230
> /* PHB4 REGB registers */
>
> /* PBL core */
> @@ -388,8 +403,7 @@
> #define PHB_PCIE_CRESET_PBL PPC_BIT(2)
> #define PHB_PCIE_CRESET_PERST_N PPC_BIT(3)
> #define PHB_PCIE_CRESET_PIPE_N PPC_BIT(4)
> -
> -
> +#define PHB_PCIE_CRESET_REFCLK_N PPC_BIT(8)
> #define PHB_PCIE_HOTPLUG_STATUS 0x1A20
> #define PHB_PCIE_HPSTAT_PRESENCE PPC_BIT(10)
>
> diff --git a/tests/qtest/pnv-phb4-test.c b/tests/qtest/pnv-phb4-test.c
> index 8cd6c1bc59..419f34987a 100644
> --- a/tests/qtest/pnv-phb4-test.c
> +++ b/tests/qtest/pnv-phb4-test.c
> @@ -22,6 +22,19 @@
> #define PNV_P10_CHIP_INDEX 3
> #define PHB4_XSCOM 0x40084800ull
>
> +/*
> + * Indirect XSCOM write:
> + * - Write 'Indirect Address Register' with register-offset to write.
> + * - Write 'Indirect Data Register' with the value.
> + */
> +static void pnv_phb_xscom_write(QTestState *qts, const PnvChip *chip,
> + uint64_t scom, uint32_t indirect_addr, uint32_t indirect_data,
> + uint64_t reg, uint64_t val)
> +{
> + qtest_writeq(qts, pnv_xscom_addr(chip, (scom >> 3) + indirect_addr), reg);
> + qtest_writeq(qts, pnv_xscom_addr(chip, (scom >> 3) + indirect_data), val);
> +}
> +
> /*
> * Indirect XSCOM read::
> * - Write 'Indirect Address Register' with register-offset to read.
> @@ -35,6 +48,11 @@ static uint64_t pnv_phb_xscom_read(QTestState *qts, const PnvChip *chip,
> return qtest_readq(qts, pnv_xscom_addr(chip, (scom >> 3) + indirect_data));
> }
>
> +#define PHB4_XSCOM_WRITE(a, v) pnv_phb_xscom_write(qts, \
> + &pnv_chips[PNV_P10_CHIP_INDEX], PHB4_XSCOM, \
> + PHB_SCOM_HV_IND_ADDR, PHB_SCOM_HV_IND_DATA, \
> + PPC_BIT(0) | (a), (v))
> +
> #define PHB4_XSCOM_READ(a) pnv_phb_xscom_read(qts, \
> &pnv_chips[PNV_P10_CHIP_INDEX], PHB4_XSCOM, \
> PHB_SCOM_HV_IND_ADDR, PHB_SCOM_HV_IND_DATA, \
> @@ -46,6 +64,26 @@ static void phb4_reset_test(QTestState *qts)
> g_assert_cmpuint(PHB4_XSCOM_READ(PHB_PBL_CONTROL), ==, 0xC009000000000000);
> }
>
> +/* Check sticky-reset */
> +static void phb4_sticky_rst_test(QTestState *qts)
> +{
> + uint64_t val;
> +
> + /*
> + * Sticky reset test of PHB_PBL_ERR_STATUS.
> + *
> + * Write all 1's to reg PHB_PBL_ERR_INJECT.
> + * Updated value will be copied to reg PHB_PBL_ERR_STATUS.
> + *
> + * Reset PBL core by setting PHB_PCIE_CRESET_PBL in reg PHB_PCIE_CRESET.
> + * Verify the sticky bits are still set.
> + */
> + PHB4_XSCOM_WRITE(PHB_PBL_ERR_INJECT, PPC_BITMASK(0, 63));
> + PHB4_XSCOM_WRITE(PHB_PCIE_CRESET, PHB_PCIE_CRESET_PBL); /*Reset*/
> + val = PHB4_XSCOM_READ(PHB_PBL_ERR_STATUS);
> + g_assert_cmpuint(val, ==, (PPC_BITMASK(0, 9) | PPC_BITMASK(12, 63)));
> +}
> +
> static void phb4_tests(void)
> {
> QTestState *qts = NULL;
> @@ -55,6 +93,9 @@ static void phb4_tests(void)
> /* Check reset value of a register */
> phb4_reset_test(qts);
>
> + /* Check sticky reset of a register */
> + phb4_sticky_rst_test(qts);
> +
> qtest_quit(qts);
> }
>
^ permalink raw reply [flat|nested] 60+ messages in thread
* Re: [PATCH v4 4/9] pnv/phb4: Implement read-only and write-only bits of registers
2026-03-05 6:09 ` [PATCH v4 4/9] pnv/phb4: Implement read-only and write-only bits of registers Saif Abrar
@ 2026-05-05 14:55 ` Harsh Prateek Bora
2026-05-09 14:54 ` Aditya Gupta
1 sibling, 0 replies; 60+ messages in thread
From: Harsh Prateek Bora @ 2026-05-05 14:55 UTC (permalink / raw)
To: Saif Abrar, qemu-ppc, qemu-devel
Cc: clg, npiggin, fbarrat, mst, marcel.apfelbaum, cohuck, pbonzini,
thuth, lvivier, danielhb413
On 05/03/26 11:39 am, Saif Abrar wrote:
> @@ -1755,6 +1819,9 @@ static void pnv_phb4_instance_init(Object *obj)
>
> /* XIVE interrupt source object */
> object_initialize_child(obj, "source", &phb->xsrc, TYPE_XIVE_SOURCE);
> +
> + /* Initialize RO-mask of registers */
> + pnv_phb4_ro_mask_init(phb);
> }
>
> void pnv_phb4_bus_init(DeviceState *dev, PnvPHB4 *phb)
> @@ -1934,6 +2001,7 @@ static const TypeInfo pnv_phb4_type_info = {
> .parent = TYPE_DEVICE,
> .instance_init = pnv_phb4_instance_init,
> .instance_size = sizeof(PnvPHB4),
> + .class_size = sizeof(PnvPHB4Class),
> .class_init = pnv_phb4_class_init,
PnvPHB4Class is introducing per-register RO masks which is supposed to
be a class data, but this is being initialized in instance_init which is
odd. Shouldn't this be taken care via class_init ?
I am not a QOM expert, but this looks like a design issue.
^ permalink raw reply [flat|nested] 60+ messages in thread
* Re: [PATCH v4 3/9] pnv/phb4: Implement sticky reset logic in PHB4
2026-05-05 14:29 ` Harsh Prateek Bora
@ 2026-05-05 15:08 ` Harsh Prateek Bora
0 siblings, 0 replies; 60+ messages in thread
From: Harsh Prateek Bora @ 2026-05-05 15:08 UTC (permalink / raw)
To: Saif Abrar, qemu-ppc, qemu-devel
Cc: clg, npiggin, fbarrat, mst, marcel.apfelbaum, cohuck, pbonzini,
thuth, lvivier, danielhb413
On 05/05/26 7:59 pm, Harsh Prateek Bora wrote:
>
>
> On 05/03/26 11:39 am, Saif Abrar wrote:
>> Sticky bits retain their values on reset and are not overwritten with
>> the reset value.
>> Added sticky reset logic for all required registers,
>> i.e. CFG core, PBL core, PHB error registers, PCIE stack registers and
>> REGB error registers.
>>
>> Tested by writing all 1's to the reg PHB_PBL_ERR_INJECT.
>> This will set the bits in the reg PHB_PBL_ERR_STATUS.
>> Reset the PBL core by setting PHB_PCIE_CRESET_PBL in reg PHB_PCIE_CRESET.
>> Verify that the sticky bits in the PHB_PBL_ERR_STATUS reg are still set.
>>
>> Signed-off-by: Saif Abrar <saif.abrar@linux.vnet.ibm.com>
>> ---
>> v3: Updates for coding guidelines.
>>
>> hw/pci-host/pnv_phb4.c | 123 +++++++++++++++++++++++++++-
>> include/hw/pci-host/pnv_phb4_regs.h | 20 ++++-
>> tests/qtest/pnv-phb4-test.c | 41 ++++++++++
>> 3 files changed, 179 insertions(+), 5 deletions(-)
>>
>> diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c
>> index 763e9c9776..b3f46f7fe1 100644
>> --- a/hw/pci-host/pnv_phb4.c
>> +++ b/hw/pci-host/pnv_phb4.c
>> @@ -511,6 +511,18 @@ static uint32_t get_exp_offset(PCIDevice *pdev)
>> return rpc->exp_offset;
>> }
>> +/*
>> + * Apply sticky-mask 's' to the reset-value 'v' and write to the
>> address 'a'.
>> + * RC-config space values and masks are LE.
>> + * Method pnv_phb4_rc_config_read() returns BE, hence convert to LE.
>> + * Compute new value in LE domain.
>> + * New value computation using sticky-mask is in LE.
>> + * Convert the computed value from LE to BE before writing back.
>> + */
>> +#define RC_CONFIG_STICKY_RESET(a, v, s) \
>> + (pci_set_word(conf + (a), bswap32( \
>> + (bswap32(pci_get_word(conf + (a))) & (s)) | ((v)
>> & ~(s)))))
>
> Shouldn't we be using bswap16 here ?
If 32-bit helper is needed, we need to use pci_[get|set]_long instead.
^ permalink raw reply [flat|nested] 60+ messages in thread
* Re: [PATCH v4 6/9] pnv/phb4: Set link-active status in HPSTAT and LMR registers
2026-03-05 6:09 ` [PATCH v4 6/9] pnv/phb4: Set link-active status in HPSTAT and LMR registers Saif Abrar
@ 2026-05-05 17:46 ` Harsh Prateek Bora
2026-05-09 15:00 ` Aditya Gupta
1 sibling, 0 replies; 60+ messages in thread
From: Harsh Prateek Bora @ 2026-05-05 17:46 UTC (permalink / raw)
To: Saif Abrar, qemu-ppc, qemu-devel
Cc: clg, npiggin, fbarrat, mst, marcel.apfelbaum, cohuck, pbonzini,
thuth, lvivier, danielhb413
On 05/03/26 11:39 am, Saif Abrar wrote:
> Config-read the link-status register in the PCI-E macro,
> Depending on the link-active bit, set the link-active status
> in the HOTPLUG_STATUS and LINK_MANAGEMENT registers
> Also, clear the Presence-status active low bit in HOTPLUG_STATUS reg
> after config-reading the slot-status in the PCI-E macro.
>
> Signed-off-by: Saif Abrar <saif.abrar@linux.vnet.ibm.com>
> Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
> ---
> v4: Variables declaration moved to the top of the method pnv_phb4_reg_read().
> v3: Updates for coding guidelines.
>
> hw/pci-host/pnv_phb4.c | 59 +++++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 58 insertions(+), 1 deletion(-)
>
> diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c
> index 25539b7c32..c35f632e64 100644
> --- a/hw/pci-host/pnv_phb4.c
> +++ b/hw/pci-host/pnv_phb4.c
> @@ -511,6 +511,20 @@ static uint32_t get_exp_offset(PCIDevice *pdev)
> return rpc->exp_offset;
> }
>
> +/*
> + * Config-read the link-status register in the PCI-E macro,
> + * convert to LE and check the link-active bit.
> + */
> +static uint32_t is_link_active(PnvPHB4 *phb)
> +{
> + PCIHostState *pci = PCI_HOST_BRIDGE(phb->phb_base);
> + PCIDevice *pdev = pci_find_device(pci->bus, 0, 0);
> + uint32_t exp_offset = get_exp_offset(pdev);
> +
> + return (bswap32(pnv_phb4_rc_config_read(phb, exp_offset + PCI_EXP_LNKSTA, 4)
> + ) & PCI_EXP_LNKSTA_DLLLA);
Shouldn't we be reading only 16 bits for PCI_EXP_LNKSTA ?
> +}
> +
> /*
> * Apply sticky-mask 's' to the reset-value 'v' and write to the address 'a'.
> * RC-config space values and masks are LE.
> @@ -729,6 +743,11 @@ static void pnv_phb4_reg_write(void *opaque, hwaddr off, uint64_t val,
> val = 0;
> break;
>
> + case PHB_PCIE_HOTPLUG_STATUS:
> + /* For normal operations, Simspeed diagnostic bit is always zero */
> + val &= PHB_PCIE_HPSTAT_SIMDIAG;
> + break;
> +
> /* Read only registers */
> case PHB_CPU_LOADSTORE_STATUS:
> case PHB_ETU_ERR_SUMMARY:
> @@ -876,6 +895,10 @@ static void pnv_phb4_reg_write(void *opaque, hwaddr off, uint64_t val,
> static uint64_t pnv_phb4_reg_read(void *opaque, hwaddr off, unsigned size)
> {
> PnvPHB4 *phb = PNV_PHB4(opaque);
> + /* Get the PCI-E capability offset from the root-port */
> + PCIHostState *pci = PCI_HOST_BRIDGE(phb->phb_base);
> + PCIDevice *pdev = pci_find_device(pci->bus, 0, 0);
> + uint32_t exp_base = get_exp_offset(pdev);
> uint64_t val;
>
> if ((off & 0xfffc) == PHB_CONFIG_DATA) {
> @@ -944,8 +967,37 @@ static uint64_t pnv_phb4_reg_read(void *opaque, hwaddr off, unsigned size)
> val |= PHB_PCIE_DLP_INBAND_PRESENCE | PHB_PCIE_DLP_TL_LINKACT;
> return val;
>
> + /*
> + * Read PCI-E registers and set status for:
> + * - Card present (active low bit 10)
> + * - Link active (bit 12)
> + */
> case PHB_PCIE_HOTPLUG_STATUS:
> - /* Clear write-only bit */
> + /*
> + * Presence-status bit hpi_present_n is active-low, with reset value 1.
> + * Start by setting this bit to 1, indicating the card is not present.
> + * Then check the PCI-E register and clear the bit if card is present.
> + */
> + val |= PHB_PCIE_HPSTAT_PRESENCE;
> +
> + /*
> + * Config-read the PCI-E macro register for slot-status.
> + * Method for config-read converts to BE value.
> + * To check actual bit in the PCI-E register,
> + * convert the value back to LE using bswap32().
> + * Clear the Presence-status active low bit.
> + */
> + if (bswap32(pnv_phb4_rc_config_read(phb, exp_base + PCI_EXP_SLTSTA, 4))
> + & PCI_EXP_SLTSTA_PDS) {
> + val &= ~PHB_PCIE_HPSTAT_PRESENCE;
> + }
> +
> + /* Check if link is active and set the bit */
> + if (is_link_active(phb)) {
> + val |= PHB_PCIE_HPSTAT_LINKACTIVE;
> + }
> +
> + /* Clear write-only resample-bit */
> val &= ~PHB_PCIE_HPSTAT_RESAMPLE;
> return val;
>
> @@ -953,6 +1005,11 @@ static uint64_t pnv_phb4_reg_read(void *opaque, hwaddr off, unsigned size)
> case PHB_PCIE_LMR:
> /* These write-only bits always read as 0 */
> val &= ~(PHB_PCIE_LMR_CHANGELW | PHB_PCIE_LMR_RETRAINLINK);
> +
> + /* Check if link is active and set the bit */
> + if (is_link_active(phb)) {
> + val |= PHB_PCIE_LMR_LINKACTIVE;
> + }
> return val;
>
> /* Silent simple reads */
^ permalink raw reply [flat|nested] 60+ messages in thread
* Re: [PATCH v4 0/9] pnv/phb4: Update PHB4 to the latest PHB5 spec
2026-03-05 6:09 ` [PATCH v4 0/9] " Saif Abrar
` (8 preceding siblings ...)
2026-03-05 6:09 ` [PATCH v4 9/9] pnv/phb4: Mask off LSI Source-ID based on number of interrupts Saif Abrar
@ 2026-05-08 16:00 ` Aditya Gupta
2026-05-19 5:52 ` Saif Abrar
10 siblings, 0 replies; 60+ messages in thread
From: Aditya Gupta @ 2026-05-08 16:00 UTC (permalink / raw)
To: Saif Abrar
Cc: qemu-ppc, qemu-devel, clg, npiggin, fbarrat, mst,
marcel.apfelbaum, cohuck, pbonzini, thuth, lvivier, danielhb413,
Harsh Prateek Bora, jishnu
On 26/03/05 12:09AM, Saif Abrar wrote:
> Hello,
>
> This patchset v4 resolves the tsan build failure seen in
> https://gitlab.com/mstredhat/qemu/-/jobs/13201554945
>
> Few variables were declared directly after a case label inside a switch,
> causing the compilation failure.
> These are now moved to the top of the block.
>
> This series updates the existing PHB4 model to the latest spec:
> "Power Systems Host Bridge 5 (PHB5) Functional Specification Version 0.5_00".
>
> Updates include the following:
> - implemented sticky reset logic
> - implemented read-only, write-only, W1C and WxC logic
> - return all 1's on read to unimplemented registers
> - update PCIE registers for link status, speed and width
> - implement IODA PCT debug table without any functionality
> - update LSI Source-ID register based on small/big PHB number of interrupts
>
> Also, a new testbench for PHB4 model is added that does XSCOM read/writes
> to various registers of interest and verifies the values.
Thanks for introducing phb5, saif.
I am currently seeing powernv functional tests failing with the patches
applied:
1/16 qemu:func-thorough+func-ppc64-thorough+thorough / func-ppc64-hv SKIP 0.17s 0 subtests passed
▶ 2/16 test_powernv.PowernvMachine.test_powernv10 FAIL
▶ 2/16 test_powernv.PowernvMachine.test_powernv11 FAIL
3/16 qemu:func-thorough+func-ppc64-thorough+thorough / func-ppc64-fadump OK 166.62s 1 subtests passed
▶ 2/16 test_powernv.PowernvMachine.test_powernv9 FAIL
2/16 qemu:func-thorough+func-ppc64-thorough+thorough / func-ppc64-powernv ERROR 182.93s exit status 1
Able to consistently reproduce it with: 'make check-functional-ppc64 -j4'
Bisect points to below commit:
commit 9b95949d3eb9e733973c692b0e8e0b9043df98e9
Author: Saif Abrar <saif.abrar@linux.vnet.ibm.com>
Date: Thu Mar 5 00:09:04 2026 -0600
pnv/phb4: Add reset logic to PHB4
Can you fix the above failure ?
Meanwhile, will be reviewing the series.
Thanks,
- Aditya G
^ permalink raw reply [flat|nested] 60+ messages in thread
* Re: [PATCH v4 1/9] qtest/phb4: Add testbench for PHB4
2026-03-05 6:09 ` [PATCH v4 1/9] qtest/phb4: Add testbench for PHB4 Saif Abrar
2026-05-01 13:59 ` Harsh Prateek Bora
@ 2026-05-09 14:33 ` Aditya Gupta
2026-05-09 14:45 ` Aditya Gupta
1 sibling, 1 reply; 60+ messages in thread
From: Aditya Gupta @ 2026-05-09 14:33 UTC (permalink / raw)
To: Saif Abrar
Cc: qemu-ppc, qemu-devel, clg, npiggin, fbarrat, mst,
marcel.apfelbaum, cohuck, pbonzini, thuth, lvivier, danielhb413
On 26/03/05 12:09AM, Saif Abrar wrote:
> <...snip...>
>
> +#define PHB3_PBCQ_SPCI_ASB_ADDR 0x0
> +#define PHB3_PBCQ_SPCI_ASB_DATA 0x2
> +
> +/* Index of PNV_CHIP_POWER10 in pnv_chips[] within "pnv-xscom.h" */
> +#define PNV_P10_CHIP_INDEX 3
nit: this is unused as of this patch.
rest looks good to me. i had comment about using p11, but noticed none
of the qtest having it, maybe that can be done separately.
Thanks,
- Aditya G
^ permalink raw reply [flat|nested] 60+ messages in thread
* Re: [PATCH v4 2/9] pnv/phb4: Add reset logic to PHB4
2026-03-05 6:09 ` [PATCH v4 2/9] pnv/phb4: Add reset logic to PHB4 Saif Abrar
2026-05-01 14:37 ` Harsh Prateek Bora
2026-05-05 14:16 ` Harsh Prateek Bora
@ 2026-05-09 14:42 ` Aditya Gupta
2 siblings, 0 replies; 60+ messages in thread
From: Aditya Gupta @ 2026-05-09 14:42 UTC (permalink / raw)
To: Saif Abrar
Cc: qemu-ppc, qemu-devel, clg, npiggin, fbarrat, mst,
marcel.apfelbaum, cohuck, pbonzini, thuth, lvivier, danielhb413,
Harsh Prateek Bora, jishnuvw
On 26/03/05 12:09AM, Saif Abrar wrote:
> Add a method to be invoked on QEMU reset.
> Also add CFG and PBL core-blocks reset logic using
> appropriate bits of PHB_PCIE_CRESET register.
>
> Tested by reading the reset value of a register.
>
> Signed-off-by: Saif Abrar <saif.abrar@linux.vnet.ibm.com>
> Reviewed-by: Cédric Le Goater <clg@kaod.org>
> Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
> ---
> v3: Updates for coding guidelines.
> v2:
> - Using the ResettableClass.
> - Reset of the root complex registers done in pnv_phb_root_port_reset_hold().
>
> hw/pci-host/pnv_phb.c | 1 +
> hw/pci-host/pnv_phb4.c | 103 +++++++++++++++++++++++++++-
> include/hw/pci-host/pnv_phb4.h | 1 +
> include/hw/pci-host/pnv_phb4_regs.h | 16 ++++-
> tests/qtest/pnv-phb4-test.c | 28 +++++++-
> 5 files changed, 145 insertions(+), 4 deletions(-)
>
> diff --git a/hw/pci-host/pnv_phb.c b/hw/pci-host/pnv_phb.c
> index 0b556d1bf5..d4f452d7b2 100644
> --- a/hw/pci-host/pnv_phb.c
> +++ b/hw/pci-host/pnv_phb.c
> @@ -232,6 +232,7 @@ static void pnv_phb_root_port_reset_hold(Object *obj, ResetType type)
> pci_set_long(conf + PCI_PREF_BASE_UPPER32, 0x1); /* Hack */
> pci_set_long(conf + PCI_PREF_LIMIT_UPPER32, 0xffffffff);
> pci_config_set_interrupt_pin(conf, 0);
> + pnv_phb4_cfg_core_reset(d);
seems these are common steps for phb4/5 now, if that's the case, do you
think this small change makes sense ?
diff --git a/hw/pci-host/pnv_phb.c b/hw/pci-host/pnv_phb.c
index d4f452d7b2fe..0432466b249f 100644
--- a/hw/pci-host/pnv_phb.c
+++ b/hw/pci-host/pnv_phb.c
@@ -220,7 +220,7 @@ static void pnv_phb_root_port_reset_hold(Object *obj, ResetType type)
return;
}
- /* PHB4 and later requires these extra reset steps */
+ /* PHB4/5 and later requires these extra reset steps */
pci_byte_test_and_set_mask(conf + PCI_IO_BASE,
PCI_IO_RANGE_MASK & 0xff);
pci_byte_test_and_clear_mask(conf + PCI_IO_LIMIT,
> }
>
> <...snip...>
> +void pnv_phb4_cfg_core_reset(PCIDevice *d)
> +{
> + uint8_t *conf = d->config;
> + uint32_t exp_offset = get_exp_offset(d);
> +
> + pci_set_word(conf + PCI_COMMAND, PCI_COMMAND_SERR);
> + pci_set_word(conf + PCI_STATUS, PCI_STATUS_CAP_LIST);
> + pci_set_long(conf + PCI_CLASS_REVISION, 0x06040000);
> + pci_set_long(conf + PCI_CACHE_LINE_SIZE, BIT(16));
> + pci_set_word(conf + PCI_MEMORY_BASE, BIT(4));
> + pci_set_word(conf + PCI_PREF_MEMORY_BASE, BIT(0) | BIT(4));
> + pci_set_word(conf + PCI_PREF_MEMORY_LIMIT, PCI_PREF_RANGE_TYPE_64);
Above 3 configs are set twice, in this function as well as the callee
Also, these were set to different values before this patch, such as
PCI_MEMORY_BASE being set to BIT(0) in 'pnv_phb_root_port_reset_hold'.
Can this cause any issues ?
Also, can you help me find which section in spec contains the sequence
for core/pbl core reset ?
> + pci_set_long(conf + PCI_CAPABILITY_LIST, BIT(6));
> + pci_set_long(conf + PCI_CAPABILITY_LIST, BIT(6));
nit: duplicates
> <...snip...>
> + pci_set_long(conf + PHB_DLF_ECAP, 0x1F410025);
> + pci_set_long(conf + PHB_DLF_CAP, 0x80000001);
> + pci_set_long(conf + P16_ECAP, 0x22410026);
> + pci_set_long(conf + P32_ECAP, 0x1002A);
> + pci_set_long(conf + P32_CAP, 0x103);
the current patch has lots of hardcoded values (above ones and below
this line too), does it make sense to have macros or ppc_bitmasks for
some of them ?
> +}
> +
> +static void pnv_phb4_pbl_core_reset(PnvPHB4 *phb)
> +{
> + /* Zero all registers initially */
> + for (int i = PHB_PBL_CONTROL ; i <= PHB_PBL_ERR1_STATUS_MASK ; i += 8) {
> + phb->regs[i >> 3] = 0x0;
> + }
> +
> + /* Set specific register values */
> + phb->regs[PHB_PBL_CONTROL >> 3] = 0xC009000000000000;
> + phb->regs[PHB_PBL_TIMEOUT_CTRL >> 3] = 0x2020000000000000;
> + phb->regs[PHB_PBL_NPTAG_ENABLE >> 3] = 0xFFFFFFFF00000000;
> + phb->regs[PHB_PBL_SYS_LINK_INIT >> 3] = 0x80088B4642473000;
> +}
> +
> <...snip...>
> @@ -72,8 +95,6 @@ static void phb_version_test(const void *data)
> /* PHB Version register bits [24:31] */
> ver = ver >> (63 - 31);
> g_assert_cmpuint(ver, ==, expected_ver);
> -
> - qtest_quit(qts);
qtest_quit is removed here, won't it cause issues where QTestState is
not terminated properly ?
Thanks,
- Aditya G
^ permalink raw reply [flat|nested] 60+ messages in thread
* Re: [PATCH v4 1/9] qtest/phb4: Add testbench for PHB4
2026-05-09 14:33 ` Aditya Gupta
@ 2026-05-09 14:45 ` Aditya Gupta
0 siblings, 0 replies; 60+ messages in thread
From: Aditya Gupta @ 2026-05-09 14:45 UTC (permalink / raw)
To: Saif Abrar
Cc: qemu-ppc, qemu-devel, clg, npiggin, fbarrat, mst,
marcel.apfelbaum, cohuck, pbonzini, thuth, lvivier, danielhb413,
Harsh Prateek Bora, jishnuvw
On 09/05/26 20:03, Aditya Gupta wrote:
> On 26/03/05 12:09AM, Saif Abrar wrote:
>> <...snip...>
>>
>> +#define PHB3_PBCQ_SPCI_ASB_ADDR 0x0
>> +#define PHB3_PBCQ_SPCI_ASB_DATA 0x2
>> +
>> +/* Index of PNV_CHIP_POWER10 in pnv_chips[] within "pnv-xscom.h" */
>> +#define PNV_P10_CHIP_INDEX 3
> nit: this is unused as of this patch.
>
> rest looks good to me. i had comment about using p11, but noticed none
> of the qtest having it, maybe that can be done separately.
>
> Thanks,
> - Aditya G
Cc: +harsh +jishnu
^ permalink raw reply [flat|nested] 60+ messages in thread
* Re: [PATCH v4 3/9] pnv/phb4: Implement sticky reset logic in PHB4
2026-03-05 6:09 ` [PATCH v4 3/9] pnv/phb4: Implement sticky reset logic in PHB4 Saif Abrar
2026-05-05 14:29 ` Harsh Prateek Bora
@ 2026-05-09 14:48 ` Aditya Gupta
1 sibling, 0 replies; 60+ messages in thread
From: Aditya Gupta @ 2026-05-09 14:48 UTC (permalink / raw)
To: Saif Abrar
Cc: qemu-ppc, qemu-devel, clg, npiggin, fbarrat, mst,
marcel.apfelbaum, cohuck, pbonzini, thuth, lvivier, danielhb413,
Harsh Prateek Bora, jishnuvw
On 26/03/05 12:09AM, Saif Abrar wrote:
> <...snip...>
> +/*
> + * Apply sticky-mask 's' to the reset-value 'v' and write to the address 'a'.
> + * RC-config space values and masks are LE.
> + * Method pnv_phb4_rc_config_read() returns BE, hence convert to LE.
> + * Compute new value in LE domain.
> + * New value computation using sticky-mask is in LE.
> + * Convert the computed value from LE to BE before writing back.
> + */
> +#define RC_CONFIG_STICKY_RESET(a, v, s) \
> + (pci_set_word(conf + (a), bswap32( \
> + (bswap32(pci_get_word(conf + (a))) & (s)) | ((v) & ~(s)))))
should be32_to_cpu be used here instead of bswap32 ?
- Aditya G
^ permalink raw reply [flat|nested] 60+ messages in thread
* Re: [PATCH v4 4/9] pnv/phb4: Implement read-only and write-only bits of registers
2026-03-05 6:09 ` [PATCH v4 4/9] pnv/phb4: Implement read-only and write-only bits of registers Saif Abrar
2026-05-05 14:55 ` Harsh Prateek Bora
@ 2026-05-09 14:54 ` Aditya Gupta
1 sibling, 0 replies; 60+ messages in thread
From: Aditya Gupta @ 2026-05-09 14:54 UTC (permalink / raw)
To: Saif Abrar
Cc: qemu-ppc, qemu-devel, clg, npiggin, fbarrat, mst,
marcel.apfelbaum, cohuck, pbonzini, thuth, lvivier, danielhb413,
Harsh Prateek Bora, jishnuvw
nice functionality !
On 26/03/05 12:09AM, Saif Abrar wrote:
> <...snip...>
> + /*
> + * DMA sync: make it look like it's complete,
> + * clear write-only read/write start sync bits.
> + */
> + case PHB_DMA_SYNC:
> + val = PHB_DMA_SYNC_RD_COMPLETE |
> + ~(PHB_DMA_SYNC_RD_START | PHB_DMA_SYNC_WR_START);
> + return val;
> +
> + /*
> + * PCI-E Stack registers
nit: s/Stack registers/System Config Register/ ?
> + */
> + case PHB_PCIE_SCR:
> + val |= PHB_PCIE_SCR_PLW_X16; /* RO bit */
> + break;
> +
> /* Link training always appears trained */
> <...snip...>
> diff --git a/tests/qtest/pnv-phb4-test.c b/tests/qtest/pnv-phb4-test.c
> index 419f34987a..2078fab9a9 100644
> --- a/tests/qtest/pnv-phb4-test.c
> +++ b/tests/qtest/pnv-phb4-test.c
> @@ -73,7 +73,8 @@ static void phb4_sticky_rst_test(QTestState *qts)
> * Sticky reset test of PHB_PBL_ERR_STATUS.
> *
> * Write all 1's to reg PHB_PBL_ERR_INJECT.
> - * Updated value will be copied to reg PHB_PBL_ERR_STATUS.
> + * RO-only bits will not be written and
> + * updated value will be copied to reg PHB_PBL_ERR_STATUS.
> *
> * Reset PBL core by setting PHB_PCIE_CRESET_PBL in reg PHB_PCIE_CRESET.
> * Verify the sticky bits are still set.
> @@ -81,7 +82,59 @@ static void phb4_sticky_rst_test(QTestState *qts)
> PHB4_XSCOM_WRITE(PHB_PBL_ERR_INJECT, PPC_BITMASK(0, 63));
> PHB4_XSCOM_WRITE(PHB_PCIE_CRESET, PHB_PCIE_CRESET_PBL); /*Reset*/
> val = PHB4_XSCOM_READ(PHB_PBL_ERR_STATUS);
> - g_assert_cmpuint(val, ==, (PPC_BITMASK(0, 9) | PPC_BITMASK(12, 63)));
> + g_assert_cmpuint(val, ==, 0xF00DFD8E00);
instead of this hardcoded value, can it be PPC_BITMASKs as previously
used ?
- Aditya G
^ permalink raw reply [flat|nested] 60+ messages in thread
* Re: [PATCH v4 5/9] pnv/phb4: Implement write-clear and return 1's on unimplemented reg read
2026-03-05 6:09 ` [PATCH v4 5/9] pnv/phb4: Implement write-clear and return 1's on unimplemented reg read Saif Abrar
@ 2026-05-09 14:56 ` Aditya Gupta
0 siblings, 0 replies; 60+ messages in thread
From: Aditya Gupta @ 2026-05-09 14:56 UTC (permalink / raw)
To: Saif Abrar
Cc: qemu-ppc, qemu-devel, clg, npiggin, fbarrat, mst,
marcel.apfelbaum, cohuck, pbonzini, thuth, lvivier, danielhb413,
Harsh Prateek Bora, jishnuvw
On 26/03/05 12:09AM, Saif Abrar wrote:
> <...snip...>
> @@ -773,27 +812,63 @@ static void pnv_phb4_reg_write(void *opaque, hwaddr off, uint64_t val,
> break;
>
> /* Silent simple writes */
> - case PHB_ASN_CMPM:
few registers removed from the switch never got added back, eg.
ASN_CMPM, is it expected ?
- Aditya G
^ permalink raw reply [flat|nested] 60+ messages in thread
* Re: [PATCH v4 6/9] pnv/phb4: Set link-active status in HPSTAT and LMR registers
2026-03-05 6:09 ` [PATCH v4 6/9] pnv/phb4: Set link-active status in HPSTAT and LMR registers Saif Abrar
2026-05-05 17:46 ` Harsh Prateek Bora
@ 2026-05-09 15:00 ` Aditya Gupta
1 sibling, 0 replies; 60+ messages in thread
From: Aditya Gupta @ 2026-05-09 15:00 UTC (permalink / raw)
To: Saif Abrar
Cc: qemu-ppc, qemu-devel, clg, npiggin, fbarrat, mst,
marcel.apfelbaum, cohuck, pbonzini, thuth, lvivier, danielhb413,
Harsh Prateek Bora, jishnuvw
On 26/03/05 12:09AM, Saif Abrar wrote:
> <...snip...>
> --- a/hw/pci-host/pnv_phb4.c
> +++ b/hw/pci-host/pnv_phb4.c
> @@ -511,6 +511,20 @@ static uint32_t get_exp_offset(PCIDevice *pdev)
> return rpc->exp_offset;
> }
>
> +/*
> + * Config-read the link-status register in the PCI-E macro,
> + * convert to LE and check the link-active bit.
> + */
> +static uint32_t is_link_active(PnvPHB4 *phb)
> +{
> + PCIHostState *pci = PCI_HOST_BRIDGE(phb->phb_base);
> + PCIDevice *pdev = pci_find_device(pci->bus, 0, 0);
> + uint32_t exp_offset = get_exp_offset(pdev);
> +
> + return (bswap32(pnv_phb4_rc_config_read(phb, exp_offset + PCI_EXP_LNKSTA, 4)
> + ) & PCI_EXP_LNKSTA_DLLLA);
should it be be32_to_cpu instead of bswap ?
> +}
> +
> /*
> * Apply sticky-mask 's' to the reset-value 'v' and write to the address 'a'.
> * RC-config space values and masks are LE.
> @@ -729,6 +743,11 @@ static void pnv_phb4_reg_write(void *opaque, hwaddr off, uint64_t val,
> val = 0;
> break;
>
> + case PHB_PCIE_HOTPLUG_STATUS:
> + /* For normal operations, Simspeed diagnostic bit is always zero */
> + val &= PHB_PCIE_HPSTAT_SIMDIAG;
> + break;
spec says this about HPSTAT_SIMDIAG bit in Hot Plug Status register:
NOTE: if simulation code changes this bit (Simspeed diagnostic bit)
it should also write bit '9' so that the input status signal
will re-sample correctly.".
i don't think bit 9 makes a difference for us currently, but i think
good to set bit 9 too. what do you say ?
> <...snip...>
>
> + /*
> + * Config-read the PCI-E macro register for slot-status.
> + * Method for config-read converts to BE value.
> + * To check actual bit in the PCI-E register,
> + * convert the value back to LE using bswap32().
> + * Clear the Presence-status active low bit.
> + */
> + if (bswap32(pnv_phb4_rc_config_read(phb, exp_base + PCI_EXP_SLTSTA, 4))
> + & PCI_EXP_SLTSTA_PDS) {
> + val &= ~PHB_PCIE_HPSTAT_PRESENCE;
be*_to_cpu makes more sense than bswap32 here, as PCI_EXP_SLTSTA_PDS is
in qemu endianness
- Aditya G
^ permalink raw reply [flat|nested] 60+ messages in thread
* Re: [PATCH v4 7/9] pnv/phb4: Set link speed and width in the DLP training control register
2026-03-05 6:09 ` [PATCH v4 7/9] pnv/phb4: Set link speed and width in the DLP training control register Saif Abrar
@ 2026-05-09 15:02 ` Aditya Gupta
0 siblings, 0 replies; 60+ messages in thread
From: Aditya Gupta @ 2026-05-09 15:02 UTC (permalink / raw)
To: Saif Abrar
Cc: qemu-ppc, qemu-devel, clg, npiggin, fbarrat, mst,
marcel.apfelbaum, cohuck, pbonzini, thuth, lvivier, danielhb413,
Harsh Prateek Bora, jishnuvw
On 26/03/05 12:09AM, Saif Abrar wrote:
> Get the current link-status from PCIE macro.
> Extract link-speed and link-width from the link-status
> and set in the DLP training control (PCIE_DLP_TCR) register.
>
> Signed-off-by: Saif Abrar <saif.abrar@linux.vnet.ibm.com>
> Reviewed-by: Cédric Le Goater <clg@kaod.org>
> Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
> ---
> v4: Variables declaration moved to the top of the method pnv_phb4_reg_read().
> v3: Updates for coding guidelines.
>
> hw/pci-host/pnv_phb4.c | 22 ++++++++++++++++++++--
> 1 file changed, 20 insertions(+), 2 deletions(-)
>
> diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c
> index c35f632e64..a6fa578e85 100644
> --- a/hw/pci-host/pnv_phb4.c
> +++ b/hw/pci-host/pnv_phb4.c
> @@ -900,6 +900,7 @@ static uint64_t pnv_phb4_reg_read(void *opaque, hwaddr off, unsigned size)
> PCIDevice *pdev = pci_find_device(pci->bus, 0, 0);
> uint32_t exp_base = get_exp_offset(pdev);
> uint64_t val;
> + uint32_t v, lnkstatus;
>
> if ((off & 0xfffc) == PHB_CONFIG_DATA) {
> return pnv_phb4_config_read(phb, off & 0x3, size);
> @@ -961,10 +962,27 @@ static uint64_t pnv_phb4_reg_read(void *opaque, hwaddr off, unsigned size)
> val |= PHB_PCIE_SCR_PLW_X16; /* RO bit */
> break;
>
> - /* Link training always appears trained */
> case PHB_PCIE_DLP_TRAIN_CTL:
> - /* TODO: Do something sensible with speed ? */
> + /* Get the current link-status from PCIE */
> + lnkstatus = bswap32(pnv_phb4_rc_config_read(phb,
> + exp_base + PCI_EXP_LNKSTA, 4));
nit: s/bswap32/be32_to_cpu/ ?
> +
> + /* Extract link-speed from the link-status */
> + v = lnkstatus & PCI_EXP_LNKSTA_CLS;
> +
> + /* Link training always appears trained */
> val |= PHB_PCIE_DLP_INBAND_PRESENCE | PHB_PCIE_DLP_TL_LINKACT;
> +
> + /* Set the current link-speed at the LINK_SPEED position */
> + val = SETFIELD(PHB_PCIE_DLP_LINK_SPEED, val, v);
> +
> + /*
> + * Extract link-width from the link-status,
> + * after shifting the required bitfields.
> + */
> + v = (lnkstatus & PCI_EXP_LNKSTA_NLW) >> PCI_EXP_LNKSTA_NLW_SHIFT;
> + /* Set the current link-width at the LINK_WIDTH position */
> + val = SETFIELD(PHB_PCIE_DLP_LINK_WIDTH, val, v);
v is little-endian, while val is supposed to be big-endian, is it correct ?
if so, should v be converted to big-endian before SETFIELDs ?
> return val;
>
> /*
- Aditya G
^ permalink raw reply [flat|nested] 60+ messages in thread
* Re: [PATCH v4 8/9] pnv/phb4: Implement IODA PCT table
2026-03-05 6:09 ` [PATCH v4 8/9] pnv/phb4: Implement IODA PCT table Saif Abrar
@ 2026-05-09 15:03 ` Aditya Gupta
2026-05-11 7:24 ` Jishnu Warrier
1 sibling, 0 replies; 60+ messages in thread
From: Aditya Gupta @ 2026-05-09 15:03 UTC (permalink / raw)
To: Saif Abrar
Cc: qemu-ppc, qemu-devel, clg, npiggin, fbarrat, mst,
marcel.apfelbaum, cohuck, pbonzini, thuth, lvivier, danielhb413,
Harsh Prateek Bora, jishnuvw
On 26/03/05 12:09AM, Saif Abrar wrote:
> IODA PCT table (#3) is implemented
nit: '#3' is probably from github, can remove
> without any functionality, being a debug table.
>
> Signed-off-by: Saif Abrar <saif.abrar@linux.vnet.ibm.com>
> Reviewed-by: Cédric Le Goater <clg@kaod.org>
rest of the patch looks good to me.
Reviewed-by: Aditya Gupta <adityag@linux.ibm.com>
- Aditya G
^ permalink raw reply [flat|nested] 60+ messages in thread
* Re: [PATCH v4 9/9] pnv/phb4: Mask off LSI Source-ID based on number of interrupts
2026-03-05 6:09 ` [PATCH v4 9/9] pnv/phb4: Mask off LSI Source-ID based on number of interrupts Saif Abrar
@ 2026-05-09 15:04 ` Aditya Gupta
2026-05-11 8:46 ` Jishnu Warrier
1 sibling, 0 replies; 60+ messages in thread
From: Aditya Gupta @ 2026-05-09 15:04 UTC (permalink / raw)
To: Saif Abrar
Cc: qemu-ppc, qemu-devel, clg, npiggin, fbarrat, mst,
marcel.apfelbaum, cohuck, pbonzini, thuth, lvivier, danielhb413,
Harsh Prateek Bora, jishnuvw
On 26/03/05 12:09AM, Saif Abrar wrote:
> Add a method to reset the value of LSI Source-ID.
> Mask off LSI source-id based on number of interrupts in the big/small PHB.
>
> Signed-off-by: Saif Abrar <saif.abrar@linux.vnet.ibm.com>
> Reviewed-by: Cédric Le Goater <clg@kaod.org>
> ---
> v3: Updates for coding guidelines.
> v2: Introduced method pnv_phb4_xsrc_reset().
>
> hw/pci-host/pnv_phb4.c | 12 +++++++++---
> 1 file changed, 9 insertions(+), 3 deletions(-)
>
> diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c
> index 254bbe4089..5e885cb89d 100644
> --- a/hw/pci-host/pnv_phb4.c
> +++ b/hw/pci-host/pnv_phb4.c
> @@ -490,6 +490,7 @@ static void pnv_phb4_update_xsrc(PnvPHB4 *phb)
>
> lsi_base = GETFIELD(PHB_LSI_SRC_ID, phb->regs[PHB_LSI_SOURCE_ID >> 3]);
> lsi_base <<= 3;
> + lsi_base &= (xsrc->nr_irqs - 1);
>
> /* TODO: handle reset values of PHB_LSI_SRC_ID */
> if (!lsi_base) {
> @@ -1944,6 +1945,12 @@ static void pnv_phb4_ro_mask_init(PnvPHB4 *phb)
> /* TODO: Add more RO-masks as regs are implemented in the model */
> }
>
> +static void pnv_phb4_xsrc_reset(PnvPHB4 *phb)
> +{
> + phb->regs[PHB_LSI_SOURCE_ID >> 3] = PPC_BITMASK(4, 12);
> + pnv_phb4_update_xsrc(phb);
> +}
> +
> static void pnv_phb4_err_reg_reset(PnvPHB4 *phb)
> {
> STICKY_RST(PHB_ERR_STATUS, 0, PPC_BITMASK(0, 33));
> @@ -2000,10 +2007,11 @@ static void pnv_phb4_reset(Object *obj, ResetType type)
> PnvPHB4 *phb = PNV_PHB4(obj);
>
> pnv_phb4_pbl_core_reset(phb);
> +
> + pnv_phb4_xsrc_reset(phb);
> pnv_phb4_err_reg_reset(phb);
> pnv_phb4_pcie_stack_reg_reset(phb);
> pnv_phb4_regb_err_reg_reset(phb);
> - phb->regs[PHB_PCIE_CRESET >> 3] = 0xE000000000000000;
why is resetting PHB_PCIE_CRESET removed here, is it not expected to
change during reset ?
- Aditya G
^ permalink raw reply [flat|nested] 60+ messages in thread
* Re: [PATCH v4 8/9] pnv/phb4: Implement IODA PCT table
2026-03-05 6:09 ` [PATCH v4 8/9] pnv/phb4: Implement IODA PCT table Saif Abrar
2026-05-09 15:03 ` Aditya Gupta
@ 2026-05-11 7:24 ` Jishnu Warrier
1 sibling, 0 replies; 60+ messages in thread
From: Jishnu Warrier @ 2026-05-11 7:24 UTC (permalink / raw)
To: Saif Abrar
Cc: qemu-ppc, qemu-devel, clg, npiggin, fbarrat, mst,
marcel.apfelbaum, cohuck, pbonzini, thuth, lvivier, danielhb413,
harshpb, adityag
On Thu, Mar 05, 2026 at 12:09:10AM -0600, Saif Abrar wrote:
> IODA PCT table (#3) is implemented
> without any functionality, being a debug table.
>
> Signed-off-by: Saif Abrar <saif.abrar@linux.vnet.ibm.com>
> Reviewed-by: Cédric Le Goater <clg@kaod.org>
> ---
> v3: Updates for coding guidelines.
>
> hw/pci-host/pnv_phb4.c | 6 ++++++
> include/hw/pci-host/pnv_phb4.h | 2 ++
> include/hw/pci-host/pnv_phb4_regs.h | 1 +
> 3 files changed, 9 insertions(+)
>
> diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c
> index a6fa578e85..254bbe4089 100644
> --- a/hw/pci-host/pnv_phb4.c
> +++ b/hw/pci-host/pnv_phb4.c
> @@ -264,6 +264,10 @@ static uint64_t *pnv_phb4_ioda_access(PnvPHB4 *phb,
> mask = phb->big_phb ? PNV_PHB4_MAX_MIST : (PNV_PHB4_MAX_MIST >> 1);
> mask -= 1;
> break;
> + case IODA3_TBL_PCT:
> + tptr = phb->ioda_PCT;
> + mask = 7;
According to PHB5 spec (lines 13568-13580):
- Small PHB: 64 entries (mask should be 63)
- Big PHB: 128 entries (mask should be 127)
- Each entry has 2 parts, so total is 128/256
> + break;
> case IODA3_TBL_RCAM:
> mask = phb->big_phb ? 127 : 63;
> break;
> @@ -362,6 +366,8 @@ static void pnv_phb4_ioda_write(PnvPHB4 *phb, uint64_t val)
> /* Handle side effects */
> switch (table) {
> case IODA3_TBL_LIST:
> + case IODA3_TBL_PCT:
> + /* No action for debug tables */
> break;
> case IODA3_TBL_MIST: {
> /* Special mask for MIST partial write */
> diff --git a/include/hw/pci-host/pnv_phb4.h b/include/hw/pci-host/pnv_phb4.h
> index bea0684724..6bb75edeef 100644
> --- a/include/hw/pci-host/pnv_phb4.h
> +++ b/include/hw/pci-host/pnv_phb4.h
> @@ -65,6 +65,7 @@ OBJECT_DECLARE_SIMPLE_TYPE(PnvPHB4RootBus, PNV_PHB4_ROOT_BUS)
> #define PNV_PHB4_MAX_LSIs 8
> #define PNV_PHB4_MAX_INTs 4096
> #define PNV_PHB4_MAX_MIST (PNV_PHB4_MAX_INTs >> 2)
> +#define PNV_PHB4_MAX_PCT 128
Question: Is PCT table 8 or 128 entries? Check PHB5 spec.
- If 8 entries: mask=7 is correct
- If 128 entries: mask should be 127
Thanks,
Jishnu
> #define PNV_PHB4_MAX_MMIO_WINDOWS 32
> #define PNV_PHB4_MIN_MMIO_WINDOWS 16
> #define PNV_PHB4_NUM_REGS (0x3000 >> 3)
> @@ -138,6 +139,7 @@ struct PnvPHB4 {
> /* On-chip IODA tables */
> uint64_t ioda_LIST[PNV_PHB4_MAX_LSIs];
> uint64_t ioda_MIST[PNV_PHB4_MAX_MIST];
> + uint64_t ioda_PCT[PNV_PHB4_MAX_PCT];
> uint64_t ioda_TVT[PNV_PHB4_MAX_TVEs];
> uint64_t ioda_MBT[PNV_PHB4_MAX_MBEs];
> uint64_t ioda_MDT[PNV_PHB4_MAX_PEs];
> diff --git a/include/hw/pci-host/pnv_phb4_regs.h b/include/hw/pci-host/pnv_phb4_regs.h
> index c1d5a83271..e30adff7b2 100644
> --- a/include/hw/pci-host/pnv_phb4_regs.h
> +++ b/include/hw/pci-host/pnv_phb4_regs.h
> @@ -486,6 +486,7 @@
>
> #define IODA3_TBL_LIST 1
> #define IODA3_TBL_MIST 2
> +#define IODA3_TBL_PCT 3
> #define IODA3_TBL_RCAM 5
> #define IODA3_TBL_MRT 6
> #define IODA3_TBL_PESTA 7
> --
> 2.47.3
>
>
^ permalink raw reply [flat|nested] 60+ messages in thread
* Re: [PATCH v4 9/9] pnv/phb4: Mask off LSI Source-ID based on number of interrupts
2026-03-05 6:09 ` [PATCH v4 9/9] pnv/phb4: Mask off LSI Source-ID based on number of interrupts Saif Abrar
2026-05-09 15:04 ` Aditya Gupta
@ 2026-05-11 8:46 ` Jishnu Warrier
1 sibling, 0 replies; 60+ messages in thread
From: Jishnu Warrier @ 2026-05-11 8:46 UTC (permalink / raw)
To: Saif Abrar
Cc: qemu-ppc, qemu-devel, clg, npiggin, fbarrat, mst,
marcel.apfelbaum, cohuck, pbonzini, thuth, lvivier, danielhb413,
harshpb, adityag
On Thu, Mar 05, 2026 at 12:09:11AM -0600, Saif Abrar wrote:
> Add a method to reset the value of LSI Source-ID.
> Mask off LSI source-id based on number of interrupts in the big/small PHB.
>
> Signed-off-by: Saif Abrar <saif.abrar@linux.vnet.ibm.com>
> Reviewed-by: Cédric Le Goater <clg@kaod.org>
> ---
> v3: Updates for coding guidelines.
> v2: Introduced method pnv_phb4_xsrc_reset().
>
> hw/pci-host/pnv_phb4.c | 12 +++++++++---
> 1 file changed, 9 insertions(+), 3 deletions(-)
>
> diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c
> index 254bbe4089..5e885cb89d 100644
> --- a/hw/pci-host/pnv_phb4.c
> +++ b/hw/pci-host/pnv_phb4.c
> @@ -490,6 +490,7 @@ static void pnv_phb4_update_xsrc(PnvPHB4 *phb)
>
> lsi_base = GETFIELD(PHB_LSI_SRC_ID, phb->regs[PHB_LSI_SOURCE_ID >> 3]);
> lsi_base <<= 3;
> + lsi_base &= (xsrc->nr_irqs - 1);
>
> /* TODO: handle reset values of PHB_LSI_SRC_ID */
> if (!lsi_base) {
> @@ -1944,6 +1945,12 @@ static void pnv_phb4_ro_mask_init(PnvPHB4 *phb)
> /* TODO: Add more RO-masks as regs are implemented in the model */
> }
>
> +static void pnv_phb4_xsrc_reset(PnvPHB4 *phb)
> +{
> + phb->regs[PHB_LSI_SOURCE_ID >> 3] = PPC_BITMASK(4, 12);
If I am not wrong, according to PHB5 spec page 104, the LSI Source ID field should be bits 3-15:
PPC_BITMASK(3, 15) // 0x1FF8000000000000ULL
03:12 LSI Source ID(00:09)
RW
13:15 LSI Source ID(10:12)
R0
> + pnv_phb4_update_xsrc(phb);
> +}
> +
> static void pnv_phb4_err_reg_reset(PnvPHB4 *phb)
> {
> STICKY_RST(PHB_ERR_STATUS, 0, PPC_BITMASK(0, 33));
> @@ -2000,10 +2007,11 @@ static void pnv_phb4_reset(Object *obj, ResetType type)
> PnvPHB4 *phb = PNV_PHB4(obj);
>
> pnv_phb4_pbl_core_reset(phb);
> +
> + pnv_phb4_xsrc_reset(phb);
> pnv_phb4_err_reg_reset(phb);
> pnv_phb4_pcie_stack_reg_reset(phb);
> pnv_phb4_regb_err_reg_reset(phb);
> - phb->regs[PHB_PCIE_CRESET >> 3] = 0xE000000000000000;
> }
>
> static void pnv_phb4_instance_init(Object *obj)
> @@ -2080,8 +2088,6 @@ static void pnv_phb4_realize(DeviceState *dev, Error **errp)
> return;
> }
>
> - pnv_phb4_update_xsrc(phb);
> -
> phb->qirqs = qemu_allocate_irqs(xive_source_set_irq, xsrc, xsrc->nr_irqs);
>
> pnv_phb4_xscom_realize(phb);
> --
> 2.47.3
>
>
^ permalink raw reply [flat|nested] 60+ messages in thread
* Re: [PATCH v4 0/9] pnv/phb4: Update PHB4 to the latest PHB5 spec
2026-03-05 6:09 ` [PATCH v4 0/9] " Saif Abrar
` (9 preceding siblings ...)
2026-05-08 16:00 ` [PATCH v4 0/9] pnv/phb4: Update PHB4 to the latest PHB5 spec Aditya Gupta
@ 2026-05-19 5:52 ` Saif Abrar
10 siblings, 0 replies; 60+ messages in thread
From: Saif Abrar @ 2026-05-19 5:52 UTC (permalink / raw)
To: qemu-ppc, qemu-devel
Cc: clg, npiggin, fbarrat, mst, marcel.apfelbaum, cohuck, pbonzini,
thuth, lvivier, danielhb413, Harsh Prateek Bora, Aditya Gupta,
mahesh, Jishnu Warrier, milesg
Dear all,
Thanks for your review comments.
I am currently occupied with another high priority task at the moment.
Shall get back to addressing the review comments by mid June.
Hence, please expect delay in response.
Regards.
Saif
On 05-03-2026 11:39, Saif Abrar wrote:
> Hello,
>
> This patchset v4 resolves the tsan build failure seen in
> https://gitlab.com/mstredhat/qemu/-/jobs/13201554945
>
> Few variables were declared directly after a case label inside a switch,
> causing the compilation failure.
> These are now moved to the top of the block.
>
> This series updates the existing PHB4 model to the latest spec:
> "Power Systems Host Bridge 5 (PHB5) Functional Specification Version 0.5_00".
>
> Updates include the following:
> - implemented sticky reset logic
> - implemented read-only, write-only, W1C and WxC logic
> - return all 1's on read to unimplemented registers
> - update PCIE registers for link status, speed and width
> - implement IODA PCT debug table without any functionality
> - update LSI Source-ID register based on small/big PHB number of interrupts
>
> Also, a new testbench for PHB4 model is added that does XSCOM read/writes
> to various registers of interest and verifies the values.
>
> Regards.
>
>
> Saif Abrar (9):
> qtest/phb4: Add testbench for PHB4
> pnv/phb4: Add reset logic to PHB4
> pnv/phb4: Implement sticky reset logic in PHB4
> pnv/phb4: Implement read-only and write-only bits of registers
> pnv/phb4: Implement write-clear and return 1's on unimplemented reg
> read
> pnv/phb4: Set link-active status in HPSTAT and LMR registers
> pnv/phb4: Set link speed and width in the DLP training control
> register
> pnv/phb4: Implement IODA PCT table
> pnv/phb4: Mask off LSI Source-ID based on number of interrupts
>
> hw/pci-host/pnv_phb.c | 1 +
> hw/pci-host/pnv_phb4.c | 581 +++++++++++++++++++++++++---
> include/hw/pci-host/pnv_phb4.h | 16 +-
> include/hw/pci-host/pnv_phb4_regs.h | 66 +++-
> tests/qtest/meson.build | 1 +
> tests/qtest/pnv-phb4-test.c | 228 +++++++++++
> 6 files changed, 835 insertions(+), 58 deletions(-)
> create mode 100644 tests/qtest/pnv-phb4-test.c
>
^ permalink raw reply [flat|nested] 60+ messages in thread
end of thread, other threads:[~2026-05-19 5:53 UTC | newest]
Thread overview: 60+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-12-30 10:21 [PATCH v2 0/9] pnv/phb4: Update PHB4 to the latest PHB5 spec Saif Abrar
2025-12-30 10:21 ` [PATCH v2 1/9] qtest/phb4: Add testbench for PHB4 Saif Abrar
2025-12-30 10:21 ` [PATCH v2 2/9] pnv/phb4: Add reset logic to PHB4 Saif Abrar
2025-12-30 12:04 ` Michael S. Tsirkin
2025-12-30 10:21 ` [PATCH v2 3/9] pnv/phb4: Implement sticky reset logic in PHB4 Saif Abrar
2025-12-30 10:21 ` [PATCH v2 4/9] pnv/phb4: Implement read-only and write-only bits of registers Saif Abrar
2026-02-04 5:04 ` Michael S. Tsirkin
2026-02-04 5:11 ` Michael S. Tsirkin
2026-02-04 6:42 ` Michael S. Tsirkin
2026-02-09 5:35 ` Saif Abrar
2025-12-30 10:21 ` [PATCH v2 5/9] pnv/phb4: Implement write-clear and return 1's on unimplemented reg read Saif Abrar
2025-12-30 10:21 ` [PATCH v2 6/9] pnv/phb4: Set link-active status in HPSTAT and LMR registers Saif Abrar
2025-12-30 10:21 ` [PATCH v2 7/9] pnv/phb4: Set link speed and width in the DLP training control register Saif Abrar
2025-12-30 10:21 ` [PATCH v2 8/9] pnv/phb4: Implement IODA PCT table Saif Abrar
2025-12-30 10:21 ` [PATCH v2 9/9] pnv/phb4: Mask off LSI Source-ID based on number of interrupts Saif Abrar
2026-02-10 13:40 ` [PATCH v3 0/9] : pnv/phb4: Update PHB4 to the latest PHB5 spec Saif Abrar
2026-02-10 13:40 ` [PATCH v3 1/9] qtest/phb4: Add testbench for PHB4 Saif Abrar
2026-02-10 13:40 ` [PATCH v3 2/9] pnv/phb4: Add reset logic to PHB4 Saif Abrar
2026-02-10 13:40 ` [PATCH v3 3/9] pnv/phb4: Implement sticky reset logic in PHB4 Saif Abrar
2026-02-10 13:40 ` [PATCH v3 4/9] pnv/phb4: Implement read-only and write-only bits of registers Saif Abrar
2026-02-10 13:40 ` [PATCH v3 5/9] pnv/phb4: Implement write-clear and return 1's on unimplemented reg read Saif Abrar
2026-02-10 13:40 ` [PATCH v3 6/9] pnv/phb4: Set link-active status in HPSTAT and LMR registers Saif Abrar
2026-02-10 13:40 ` [PATCH v3 7/9] pnv/phb4: Set link speed and width in the DLP training control register Saif Abrar
2026-02-10 13:40 ` [PATCH v3 8/9] pnv/phb4: Implement IODA PCT table Saif Abrar
2026-02-10 13:40 ` [PATCH v3 9/9] pnv/phb4: Mask off LSI Source-ID based on number of interrupts Saif Abrar
2026-02-10 13:43 ` [PATCH v3 0/9] : pnv/phb4: Update PHB4 to the latest PHB5 spec Michael S. Tsirkin
2026-02-11 5:30 ` Saif Abrar
2026-02-20 16:22 ` Michael S. Tsirkin
[not found] ` <d65ab628-99e3-47af-839c-e059207b692e@linux.vnet.ibm.com>
2026-02-22 14:38 ` Michael S. Tsirkin
2026-03-05 6:09 ` [PATCH v4 0/9] " Saif Abrar
2026-03-05 6:09 ` [PATCH v4 1/9] qtest/phb4: Add testbench for PHB4 Saif Abrar
2026-05-01 13:59 ` Harsh Prateek Bora
2026-05-09 14:33 ` Aditya Gupta
2026-05-09 14:45 ` Aditya Gupta
2026-03-05 6:09 ` [PATCH v4 2/9] pnv/phb4: Add reset logic to PHB4 Saif Abrar
2026-05-01 14:37 ` Harsh Prateek Bora
2026-05-05 14:16 ` Harsh Prateek Bora
2026-05-09 14:42 ` Aditya Gupta
2026-03-05 6:09 ` [PATCH v4 3/9] pnv/phb4: Implement sticky reset logic in PHB4 Saif Abrar
2026-05-05 14:29 ` Harsh Prateek Bora
2026-05-05 15:08 ` Harsh Prateek Bora
2026-05-09 14:48 ` Aditya Gupta
2026-03-05 6:09 ` [PATCH v4 4/9] pnv/phb4: Implement read-only and write-only bits of registers Saif Abrar
2026-05-05 14:55 ` Harsh Prateek Bora
2026-05-09 14:54 ` Aditya Gupta
2026-03-05 6:09 ` [PATCH v4 5/9] pnv/phb4: Implement write-clear and return 1's on unimplemented reg read Saif Abrar
2026-05-09 14:56 ` Aditya Gupta
2026-03-05 6:09 ` [PATCH v4 6/9] pnv/phb4: Set link-active status in HPSTAT and LMR registers Saif Abrar
2026-05-05 17:46 ` Harsh Prateek Bora
2026-05-09 15:00 ` Aditya Gupta
2026-03-05 6:09 ` [PATCH v4 7/9] pnv/phb4: Set link speed and width in the DLP training control register Saif Abrar
2026-05-09 15:02 ` Aditya Gupta
2026-03-05 6:09 ` [PATCH v4 8/9] pnv/phb4: Implement IODA PCT table Saif Abrar
2026-05-09 15:03 ` Aditya Gupta
2026-05-11 7:24 ` Jishnu Warrier
2026-03-05 6:09 ` [PATCH v4 9/9] pnv/phb4: Mask off LSI Source-ID based on number of interrupts Saif Abrar
2026-05-09 15:04 ` Aditya Gupta
2026-05-11 8:46 ` Jishnu Warrier
2026-05-08 16:00 ` [PATCH v4 0/9] pnv/phb4: Update PHB4 to the latest PHB5 spec Aditya Gupta
2026-05-19 5:52 ` Saif Abrar
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.