Reviewed-by: Caleb Schlossin <[email protected]>
On 6/17/26 4:50 AM, Saif Abrar wrote:
> From: Saif Abrar <[email protected]>
>
> 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 <[email protected]>
> Reviewed-by: Michael S. Tsirkin <[email protected]>
> Reviewed-by: Harsh Prateek Bora <[email protected]>
> Reviewed-by: Aditya Gupta <[email protected]>
> Reviewed-by: Jishnu Warrier <[email protected]>
> ---
> v5: Using be16_to_cpu as required.
> 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 | 61 +++++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 60 insertions(+), 1 deletion(-)
>
> diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c
> index 838f9d3c23..125f610790 100644
> --- a/hw/pci-host/pnv_phb4.c
> +++ b/hw/pci-host/pnv_phb4.c
> @@ -511,6 +511,21 @@ 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 (be16_to_cpu(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.
> @@ -727,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:
> @@ -874,6 +894,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) {
> @@ -942,8 +966,38 @@ 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 host format.
> + * Clear the Presence-status active low bit.
> + */
> + if (be16_to_cpu(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 +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 */