diff options
| author | Yinghai Lu <yinghai@kernel.org> | 2012-01-27 13:55:11 -0500 |
|---|---|---|
| committer | Jesse Barnes <jbarnes@virtuousgeek.org> | 2012-02-14 11:45:00 -0500 |
| commit | 2f5d8e4ff947ad6673397083b48719cd6c59cd61 (patch) | |
| tree | 46e1c6901937b7f983b511d6e14498000e2989bb /drivers/pci/hotplug | |
| parent | efdc87dab1cdf25ba631181ac0ead3fb2023dd10 (diff) | |
PCI: pciehp: replace unconditional sleep with config space access check
During reviewing
| PCI: pciehp: wait 1000 ms before Link Training check
Linus said:
>...
> That's a *long* time, and it's irritating to the user. It makes the
> user think "the machine is slow".
>...
> And quite frankly, an unconditional one-second delay here seems bad.
>Two seconds was unacceptable, one second is just bad.
Try to access the pci conf of a pci device that is supposed to show up
in 1s. If we can read back a valid vendor/device id, we can return
early.
Related discussion could be found:
https://lkml.org/lkml/2011/12/6/339
-v2: seperate code to pci_bus_read_dev_vendor_id() from pci_scan_device()
and reuse it from pciehp code. Suggested by Matthew Wilcox.
-v3: According to Kenj, don't use array in stack, and don't wait too long
for crs, also return fail status if not found.
Also separate pci_bus_dev_read_vendor_id() change to another patch.
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers/pci/hotplug')
| -rw-r--r-- | drivers/pci/hotplug/pciehp_hpc.c | 49 |
1 files changed, 34 insertions, 15 deletions
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index bcdbb164362..7dc9e33746a 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c | |||
| @@ -265,10 +265,37 @@ static void pcie_wait_link_active(struct controller *ctrl) | |||
| 265 | ctrl_dbg(ctrl, "Data Link Layer Link Active not set in 1000 msec\n"); | 265 | ctrl_dbg(ctrl, "Data Link Layer Link Active not set in 1000 msec\n"); |
| 266 | } | 266 | } |
| 267 | 267 | ||
| 268 | static bool pci_bus_check_dev(struct pci_bus *bus, int devfn) | ||
| 269 | { | ||
| 270 | u32 l; | ||
| 271 | int count = 0; | ||
| 272 | int delay = 1000, step = 20; | ||
| 273 | bool found = false; | ||
| 274 | |||
| 275 | do { | ||
| 276 | found = pci_bus_read_dev_vendor_id(bus, devfn, &l, 0); | ||
| 277 | count++; | ||
| 278 | |||
| 279 | if (found) | ||
| 280 | break; | ||
| 281 | |||
| 282 | msleep(step); | ||
| 283 | delay -= step; | ||
| 284 | } while (delay > 0); | ||
| 285 | |||
| 286 | if (count > 1 && pciehp_debug) | ||
| 287 | printk(KERN_DEBUG "pci %04x:%02x:%02x.%d id reading try %d times with interval %d ms to get %08x\n", | ||
| 288 | pci_domain_nr(bus), bus->number, PCI_SLOT(devfn), | ||
| 289 | PCI_FUNC(devfn), count, step, l); | ||
| 290 | |||
| 291 | return found; | ||
| 292 | } | ||
| 293 | |||
| 268 | int pciehp_check_link_status(struct controller *ctrl) | 294 | int pciehp_check_link_status(struct controller *ctrl) |
| 269 | { | 295 | { |
| 270 | u16 lnk_status; | 296 | u16 lnk_status; |
| 271 | int retval = 0; | 297 | int retval = 0; |
| 298 | bool found = false; | ||
| 272 | 299 | ||
| 273 | /* | 300 | /* |
| 274 | * Data Link Layer Link Active Reporting must be capable for | 301 | * Data Link Layer Link Active Reporting must be capable for |
| @@ -280,13 +307,10 @@ int pciehp_check_link_status(struct controller *ctrl) | |||
| 280 | else | 307 | else |
| 281 | msleep(1000); | 308 | msleep(1000); |
| 282 | 309 | ||
| 283 | /* | 310 | /* wait 100ms before read pci conf, and try in 1s */ |
| 284 | * Need to wait for 1000 ms after Data Link Layer Link Active | 311 | msleep(100); |
| 285 | * (DLLLA) bit reads 1b before sending configuration request. | 312 | found = pci_bus_check_dev(ctrl->pcie->port->subordinate, |
| 286 | * We need it before checking Link Training (LT) bit becuase | 313 | PCI_DEVFN(0, 0)); |
| 287 | * LT is still set even after DLLLA bit is set on some platform. | ||
| 288 | */ | ||
| 289 | msleep(1000); | ||
| 290 | 314 | ||
| 291 | retval = pciehp_readw(ctrl, PCI_EXP_LNKSTA, &lnk_status); | 315 | retval = pciehp_readw(ctrl, PCI_EXP_LNKSTA, &lnk_status); |
| 292 | if (retval) { | 316 | if (retval) { |
| @@ -302,16 +326,11 @@ int pciehp_check_link_status(struct controller *ctrl) | |||
| 302 | return retval; | 326 | return retval; |
| 303 | } | 327 | } |
| 304 | 328 | ||
| 305 | /* | ||
| 306 | * If the port supports Link speeds greater than 5.0 GT/s, we | ||
| 307 | * must wait for 100 ms after Link training completes before | ||
| 308 | * sending configuration request. | ||
| 309 | */ | ||
| 310 | if (ctrl->pcie->port->subordinate->max_bus_speed > PCIE_SPEED_5_0GT) | ||
| 311 | msleep(100); | ||
| 312 | |||
| 313 | pcie_update_link_speed(ctrl->pcie->port->subordinate, lnk_status); | 329 | pcie_update_link_speed(ctrl->pcie->port->subordinate, lnk_status); |
| 314 | 330 | ||
| 331 | if (!found && !retval) | ||
| 332 | retval = -1; | ||
| 333 | |||
| 315 | return retval; | 334 | return retval; |
| 316 | } | 335 | } |
| 317 | 336 | ||
