Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

PCI: Wait for up to 1000ms after FLR reset

Some devices take longer than the spec indicates to return from FLR reset,
a notable case of this is Intel integrated graphics (IGD), which can often
take an additional 300ms powering down an attached LCD panel as part of the
FLR. Allow devices up to 1000ms, testing every 100ms whether the second
dword of config space is read as -1.

Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>

authored by

Alex Williamson and committed by
Bjorn Helgaas
5adecf81 0a3d00b3

+25 -2
+25 -2
drivers/pci/pci.c
··· 3414 3414 } 3415 3415 EXPORT_SYMBOL(pci_wait_for_pending_transaction); 3416 3416 3417 + /* 3418 + * We should only need to wait 100ms after FLR, but some devices take longer. 3419 + * Wait for up to 1000ms for config space to return something other than -1. 3420 + * Intel IGD requires this when an LCD panel is attached. We read the 2nd 3421 + * dword because VFs don't implement the 1st dword. 3422 + */ 3423 + static void pci_flr_wait(struct pci_dev *dev) 3424 + { 3425 + int i = 0; 3426 + u32 id; 3427 + 3428 + do { 3429 + msleep(100); 3430 + pci_read_config_dword(dev, PCI_COMMAND, &id); 3431 + } while (i++ < 10 && id == ~0); 3432 + 3433 + if (id == ~0) 3434 + dev_warn(&dev->dev, "Failed to return from FLR\n"); 3435 + else if (i > 1) 3436 + dev_info(&dev->dev, "Required additional %dms to return from FLR\n", 3437 + (i - 1) * 100); 3438 + } 3439 + 3417 3440 static int pcie_flr(struct pci_dev *dev, int probe) 3418 3441 { 3419 3442 u32 cap; ··· 3452 3429 dev_err(&dev->dev, "timed out waiting for pending transaction; performing function level reset anyway\n"); 3453 3430 3454 3431 pcie_capability_set_word(dev, PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_BCR_FLR); 3455 - msleep(100); 3432 + pci_flr_wait(dev); 3456 3433 return 0; 3457 3434 } 3458 3435 ··· 3482 3459 dev_err(&dev->dev, "timed out waiting for pending transaction; performing AF function level reset anyway\n"); 3483 3460 3484 3461 pci_write_config_byte(dev, pos + PCI_AF_CTRL, PCI_AF_CTRL_FLR); 3485 - msleep(100); 3462 + pci_flr_wait(dev); 3486 3463 return 0; 3487 3464 } 3488 3465