On 05/03/26 11:39 am, Saif Abrar wrote:
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]>
---
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 | 59 +++++++++++++++++++++++++++++++++++++++++-
  1 file changed, 58 insertions(+), 1 deletion(-)

diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c
index 25539b7c32..c35f632e64 100644
--- a/hw/pci-host/pnv_phb4.c
+++ b/hw/pci-host/pnv_phb4.c
@@ -511,6 +511,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);

Shouldn't we be reading only 16 bits for PCI_EXP_LNKSTA ?

+}
+
  /*
   * 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:
@@ -876,6 +895,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) {
@@ -944,8 +967,37 @@ 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 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;
@@ -953,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 */


Reply via email to