Reviewed-by: Caleb Schlossin <[email protected]>

On 6/17/26 4:50 AM, Saif Abrar wrote:
> From: Saif Abrar <[email protected]>
> 
> 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 <[email protected]>
> Reviewed-by: Harsh Prateek Bora <[email protected]>
> Reviewed-by: Aditya Gupta <[email protected]>
> Reviewed-by: Jishnu Warrier <[email protected]>
> ---
> v5:
> - Replaced phb4 by phb5.
> - Using be16_to_cpu as required.
> v3: Updates for coding guidelines.
> 
> 
>  hw/pci-host/pnv_phb4.c              | 124 +++++++++++++++++++++++++++-
>  include/hw/pci-host/pnv_phb4_regs.h |  20 ++++-
>  tests/qtest/pnv-phb-test.c          |  41 +++++++++
>  3 files changed, 180 insertions(+), 5 deletions(-)
> 
> diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c
> index c9f3b02b39..4d4e239deb 100644
> --- a/hw/pci-host/pnv_phb4.c
> +++ b/hw/pci-host/pnv_phb4.c
> @@ -511,6 +511,19 @@ 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), be16_to_cpu( \
> +                     (be16_to_cpu(pci_get_word(conf + (a))) & (s)) | \
> +                     ((v) & ~(s)))))
> +
>  void pnv_phb4_cfg_core_reset(PCIDevice *d)
>  {
>      uint8_t *conf = d->config;
> @@ -557,14 +570,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;
> @@ -698,6 +753,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:
> @@ -1618,11 +1684,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-phb-test.c b/tests/qtest/pnv-phb-test.c
> index 54fe1838a7..fe1ac27264 100644
> --- a/tests/qtest/pnv-phb-test.c
> +++ b/tests/qtest/pnv-phb-test.c
> @@ -23,6 +23,19 @@
>  /* SCOM to PCBA address conversion */
>  #define SCOM_TO_PCBA(scom, addr) (((scom) >> 3) + (addr))
>  
> +/*
> + * 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.
> @@ -38,6 +51,11 @@ static uint64_t pnv_phb_xscom_read(QTestState *qts, const 
> PnvChip *chip,
>                                                                
> indirect_data)));
>  }
>  
> +#define PHB5_XSCOM_WRITE(a, v) pnv_phb_xscom_write(qts, \
> +                                   &pnv_chips[PNV_P10_CHIP_INDEX], 
> PHB5_XSCOM, \
> +                                   PHB_SCOM_HV_IND_ADDR, 
> PHB_SCOM_HV_IND_DATA, \
> +                                   PPC_BIT(0) | (a), (v))
> +
>  #define PHB5_XSCOM_READ(a) pnv_phb_xscom_read(qts, \
>                                     &pnv_chips[PNV_P10_CHIP_INDEX], 
> PHB5_XSCOM, \
>                                     PHB_SCOM_HV_IND_ADDR, 
> PHB_SCOM_HV_IND_DATA, \
> @@ -49,6 +67,26 @@ static void phb5_reset_test(QTestState *qts)
>      g_assert_cmpuint(PHB5_XSCOM_READ(PHB_PBL_CONTROL), ==, 
> 0xC009000000000000);
>  }
>  
> +/* Check sticky-reset */
> +static void phb5_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.
> +     */
> +    PHB5_XSCOM_WRITE(PHB_PBL_ERR_INJECT, PPC_BITMASK(0, 63));
> +    PHB5_XSCOM_WRITE(PHB_PCIE_CRESET, PHB_PCIE_CRESET_PBL); /*Reset*/
> +    val = PHB5_XSCOM_READ(PHB_PBL_ERR_STATUS);
> +    g_assert_cmpuint(val, ==, (PPC_BITMASK(0, 9) | PPC_BITMASK(12, 63)));
> +}
> +
>  static void phb5_tests(void)
>  {
>      QTestState *qts = NULL;
> @@ -58,6 +96,9 @@ static void phb5_tests(void)
>      /* Check reset value of a register */
>      phb5_reset_test(qts);
>  
> +    /* Check sticky reset of a register */
> +    phb5_sticky_rst_test(qts);
> +
>      qtest_quit(qts);
>  }
>  


Reply via email to