The Microsemi Switchtec PM8533 PFX 48xG3 [11f8:8533] PCIe switch system
was observed to incorrectly assert the Presence Detect Set bit in its
capabilities when tested on a Raptor Computing Systems Blackbird system,
resulting in the hot insert path never attempting a rescan of the bus
and any downstream devices not being re-detected.

Work around this by additionally checking whether the PCIe data link is
active or not when performing presence detection on downstream switches'
ports, similar to the pciehp_hpc.c driver.

Signed-off-by: Shawn Anastasio <sanasta...@raptorengineering.com>
---
 drivers/pci/hotplug/pnv_php.c | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/drivers/pci/hotplug/pnv_php.c b/drivers/pci/hotplug/pnv_php.c
index 2c07544216fb..1a734adb5b10 100644
--- a/drivers/pci/hotplug/pnv_php.c
+++ b/drivers/pci/hotplug/pnv_php.c
@@ -390,6 +390,20 @@ static int pnv_php_get_power_state(struct hotplug_slot 
*slot, u8 *state)
        return 0;
 }
 
+static int pcie_check_link_active(struct pci_dev *pdev)
+{
+       u16 lnk_status;
+       int ret;
+
+       ret = pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, &lnk_status);
+       if (ret == PCIBIOS_DEVICE_NOT_FOUND || PCI_POSSIBLE_ERROR(lnk_status))
+               return -ENODEV;
+
+       ret = !!(lnk_status & PCI_EXP_LNKSTA_DLLLA);
+
+       return ret;
+}
+
 static int pnv_php_get_adapter_state(struct hotplug_slot *slot, u8 *state)
 {
        struct pnv_php_slot *php_slot = to_pnv_php_slot(slot);
@@ -402,6 +416,19 @@ static int pnv_php_get_adapter_state(struct hotplug_slot 
*slot, u8 *state)
         */
        ret = pnv_pci_get_presence_state(php_slot->id, &presence);
        if (ret >= 0) {
+               if (pci_pcie_type(php_slot->pdev) == PCI_EXP_TYPE_DOWNSTREAM &&
+                       presence == OPAL_PCI_SLOT_EMPTY) {
+                       /*
+                        * Similar to pciehp_hpc, check whether the Link Active
+                        * bit is set to account for broken downstream bridges
+                        * that don't properly assert Presence Detect State, as
+                        * was observed on the Microsemi Switchtec PM8533 PFX
+                        * [11f8:8533].
+                        */
+                       if (pcie_check_link_active(php_slot->pdev) > 0)
+                               presence = OPAL_PCI_SLOT_PRESENT;
+               }
+
                *state = presence;
                ret = 0;
        } else {
-- 
2.30.2


Reply via email to