Commit 2f5d8e4ff947ad6673397083b48719cd6c59cd61
Committed by
Jesse Barnes
1 parent
efdc87dab1
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
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>
Showing 1 changed file with 34 additions and 15 deletions Side-by-side Diff
drivers/pci/hotplug/pciehp_hpc.c
... | ... | @@ -265,10 +265,37 @@ |
265 | 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 | 294 | int pciehp_check_link_status(struct controller *ctrl) |
269 | 295 | { |
270 | 296 | u16 lnk_status; |
271 | 297 | int retval = 0; |
298 | + bool found = false; | |
272 | 299 | |
273 | 300 | /* |
274 | 301 | * Data Link Layer Link Active Reporting must be capable for |
... | ... | @@ -280,13 +307,10 @@ |
280 | 307 | else |
281 | 308 | msleep(1000); |
282 | 309 | |
283 | - /* | |
284 | - * Need to wait for 1000 ms after Data Link Layer Link Active | |
285 | - * (DLLLA) bit reads 1b before sending configuration request. | |
286 | - * We need it before checking Link Training (LT) bit becuase | |
287 | - * LT is still set even after DLLLA bit is set on some platform. | |
288 | - */ | |
289 | - msleep(1000); | |
310 | + /* wait 100ms before read pci conf, and try in 1s */ | |
311 | + msleep(100); | |
312 | + found = pci_bus_check_dev(ctrl->pcie->port->subordinate, | |
313 | + PCI_DEVFN(0, 0)); | |
290 | 314 | |
291 | 315 | retval = pciehp_readw(ctrl, PCI_EXP_LNKSTA, &lnk_status); |
292 | 316 | if (retval) { |
293 | 317 | |
... | ... | @@ -302,15 +326,10 @@ |
302 | 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 | 329 | pcie_update_link_speed(ctrl->pcie->port->subordinate, lnk_status); |
330 | + | |
331 | + if (!found && !retval) | |
332 | + retval = -1; | |
314 | 333 | |
315 | 334 | return retval; |
316 | 335 | } |