Re: [git pull] PCI fixes

From: Yinghai Lu
Date: Tue Dec 06 2011 - 17:36:37 EST


On Tue, Dec 6, 2011 at 8:14 AM, Linus Torvalds
<torvalds@xxxxxxxxxxxxxxxxxxxx> wrote:
> Please try to make something like that work. Instead of always waiting
> for one second, wait for up to one second only for failure cases. Any
> possibility of that?

i had another version that was not send out. that worked on my test setups too.
it will try to read pci conf several times in 1s.

please check refreshed version against your tree.

Thanks

Yinghai
---
drivers/pci/hotplug/pciehp_hpc.c | 47 ++++++++++++++++++++++++++-------------
1 file changed, 32 insertions(+), 15 deletions(-)

Index: linux-2.6/drivers/pci/hotplug/pciehp_hpc.c
===================================================================
--- linux-2.6.orig/drivers/pci/hotplug/pciehp_hpc.c
+++ linux-2.6/drivers/pci/hotplug/pciehp_hpc.c
@@ -265,6 +265,35 @@ static void pcie_wait_link_active(struct
ctrl_dbg(ctrl, "Data Link Layer Link Active not set in 1000 msec\n");
}

+static bool pci_bus_check_dev(struct pci_bus *bus, int devfn)
+{
+ u32 l;
+ int delay = 1000;
+
+again:
+ if (pci_bus_read_config_dword(bus, devfn, PCI_VENDOR_ID, &l))
+ goto wait;
+
+ /* some broken boards return 0 or ~0 if a slot is empty: */
+ if (l == 0xffffffff || l == 0x00000000 ||
+ l == 0x0000ffff || l == 0xffff0000)
+ goto wait;
+
+ /* Configuration request Retry Status */
+ if (l == 0xffff0001)
+ goto wait;
+
+ return true;
+
+wait:
+ mdelay(100);
+ delay -= 100;
+ if (delay > 0)
+ goto again;
+
+ return false;
+}
+
int pciehp_check_link_status(struct controller *ctrl)
{
u16 lnk_status;
@@ -280,13 +309,9 @@ int pciehp_check_link_status(struct cont
else
msleep(1000);

- /*
- * Need to wait for 1000 ms after Data Link Layer Link Active
- * (DLLLA) bit reads 1b before sending configuration request.
- * We need it before checking Link Training (LT) bit becuase
- * LT is still set even after DLLLA bit is set on some platform.
- */
- msleep(1000);
+ /* wait 100ms before read pci conf, and try in 1s */
+ msleep(100);
+ pci_bus_check_dev(ctrl->pcie->port->subordinate, PCI_DEVFN(0, 0));

retval = pciehp_readw(ctrl, PCI_EXP_LNKSTA, &lnk_status);
if (retval) {
@@ -302,14 +327,6 @@ int pciehp_check_link_status(struct cont
return retval;
}

- /*
- * If the port supports Link speeds greater than 5.0 GT/s, we
- * must wait for 100 ms after Link training completes before
- * sending configuration request.
- */
- if (ctrl->pcie->port->subordinate->max_bus_speed > PCIE_SPEED_5_0GT)
- msleep(100);
-
pcie_update_link_speed(ctrl->pcie->port->subordinate, lnk_status);

return retval;