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]> --- 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
