diff options
Diffstat (limited to 'drivers/pci/access.c')
-rw-r--r-- | drivers/pci/access.c | 18 |
1 files changed, 10 insertions, 8 deletions
diff --git a/drivers/pci/access.c b/drivers/pci/access.c index 8449d6b58178..01b9d0a00abc 100644 --- a/drivers/pci/access.c +++ b/drivers/pci/access.c @@ -342,14 +342,15 @@ static size_t pci_vpd_size(struct pci_dev *dev, size_t old_size) static int pci_vpd_wait(struct pci_dev *dev) { struct pci_vpd *vpd = dev->vpd; - unsigned long timeout = jiffies + HZ/20 + 2; + unsigned long timeout = jiffies + msecs_to_jiffies(50); + unsigned long max_sleep = 16; u16 status; int ret; if (!vpd->busy) return 0; - for (;;) { + while (time_before(jiffies, timeout)) { ret = pci_user_read_config_word(dev, vpd->cap + PCI_VPD_ADDR, &status); if (ret < 0) @@ -360,15 +361,16 @@ static int pci_vpd_wait(struct pci_dev *dev) return 0; } - if (time_after(jiffies, timeout)) { - dev_printk(KERN_DEBUG, &dev->dev, "vpd r/w failed. This is likely a firmware bug on this device. Contact the card vendor for a firmware update\n"); - return -ETIMEDOUT; - } if (fatal_signal_pending(current)) return -EINTR; - if (!cond_resched()) - udelay(10); + + usleep_range(10, max_sleep); + if (max_sleep < 1024) + max_sleep *= 2; } + + dev_warn(&dev->dev, "VPD access failed. This is likely a firmware bug on this device. Contact the card vendor for a firmware update\n"); + return -ETIMEDOUT; } static ssize_t pci_vpd_read(struct pci_dev *dev, loff_t pos, size_t count, |