Commit 80f9fc23 authored by Timothy Pearson's avatar Timothy Pearson Committed by Madhavan Srinivasan
Browse files

PCI: pnv_php: Work around switches with broken presence detection



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: default avatarShawn Anastasio <sanastasio@raptorengineering.com>
Signed-off-by: default avatarTimothy Pearson <tpearson@raptorengineering.com>
Signed-off-by: default avatarBjorn Helgaas <bhelgaas@google.com>
Signed-off-by: default avatarMadhavan Srinivasan <maddy@linux.ibm.com>
Link: https://patch.msgid.link/505981576.1359853.1752615415117.JavaMail.zimbra@raptorengineeringinc.com
parent 46686190
Loading
Loading
Loading
Loading
+27 −0
Original line number Diff line number Diff line
@@ -391,6 +391,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);
@@ -403,6 +417,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 {