+
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);
}