Reviewed-by: Caleb Schlossin <[email protected]> On 8/31/26 7:30 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: Caleb Schlossin <[email protected]> > Reviewed-by: Aditya Gupta <[email protected]> > --- > hw/pci-host/pnv_phb4.c | 74 +++++++++++++++++++++++++++++++++++++++++- > 1 file changed, 73 insertions(+), 1 deletion(-) > > diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c > index b13165f84d..87446aedc8 100644 > --- a/hw/pci-host/pnv_phb4.c > +++ b/hw/pci-host/pnv_phb4.c > @@ -508,6 +508,34 @@ 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. > + * 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; > @@ -680,6 +708,11 @@ 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: > @@ -827,6 +860,10 @@ void pnv_phb4_reg_write(void *opaque, hwaddr off, > uint64_t val, > 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) { > @@ -895,8 +932,38 @@ 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; > > @@ -904,6 +971,11 @@ 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 */
