diff options
Diffstat (limited to 'drivers/usb/core/hcd-pci.c')
-rw-r--r-- | drivers/usb/core/hcd-pci.c | 56 |
1 files changed, 37 insertions, 19 deletions
diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index 64a035ba2eab..ce22f4a84ed0 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c | |||
@@ -192,13 +192,13 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) | |||
192 | "Found HC with no IRQ. Check BIOS/PCI %s setup!\n", | 192 | "Found HC with no IRQ. Check BIOS/PCI %s setup!\n", |
193 | pci_name(dev)); | 193 | pci_name(dev)); |
194 | retval = -ENODEV; | 194 | retval = -ENODEV; |
195 | goto err1; | 195 | goto disable_pci; |
196 | } | 196 | } |
197 | 197 | ||
198 | hcd = usb_create_hcd(driver, &dev->dev, pci_name(dev)); | 198 | hcd = usb_create_hcd(driver, &dev->dev, pci_name(dev)); |
199 | if (!hcd) { | 199 | if (!hcd) { |
200 | retval = -ENOMEM; | 200 | retval = -ENOMEM; |
201 | goto err1; | 201 | goto disable_pci; |
202 | } | 202 | } |
203 | 203 | ||
204 | if (driver->flags & HCD_MEMORY) { | 204 | if (driver->flags & HCD_MEMORY) { |
@@ -209,13 +209,13 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) | |||
209 | driver->description)) { | 209 | driver->description)) { |
210 | dev_dbg(&dev->dev, "controller already in use\n"); | 210 | dev_dbg(&dev->dev, "controller already in use\n"); |
211 | retval = -EBUSY; | 211 | retval = -EBUSY; |
212 | goto err2; | 212 | goto clear_companion; |
213 | } | 213 | } |
214 | hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len); | 214 | hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len); |
215 | if (hcd->regs == NULL) { | 215 | if (hcd->regs == NULL) { |
216 | dev_dbg(&dev->dev, "error mapping memory\n"); | 216 | dev_dbg(&dev->dev, "error mapping memory\n"); |
217 | retval = -EFAULT; | 217 | retval = -EFAULT; |
218 | goto err3; | 218 | goto release_mem_region; |
219 | } | 219 | } |
220 | 220 | ||
221 | } else { | 221 | } else { |
@@ -236,7 +236,7 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) | |||
236 | if (region == PCI_ROM_RESOURCE) { | 236 | if (region == PCI_ROM_RESOURCE) { |
237 | dev_dbg(&dev->dev, "no i/o regions available\n"); | 237 | dev_dbg(&dev->dev, "no i/o regions available\n"); |
238 | retval = -EBUSY; | 238 | retval = -EBUSY; |
239 | goto err2; | 239 | goto clear_companion; |
240 | } | 240 | } |
241 | } | 241 | } |
242 | 242 | ||
@@ -244,24 +244,24 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) | |||
244 | 244 | ||
245 | retval = usb_add_hcd(hcd, dev->irq, IRQF_DISABLED | IRQF_SHARED); | 245 | retval = usb_add_hcd(hcd, dev->irq, IRQF_DISABLED | IRQF_SHARED); |
246 | if (retval != 0) | 246 | if (retval != 0) |
247 | goto err4; | 247 | goto unmap_registers; |
248 | set_hs_companion(dev, hcd); | 248 | set_hs_companion(dev, hcd); |
249 | 249 | ||
250 | if (pci_dev_run_wake(dev)) | 250 | if (pci_dev_run_wake(dev)) |
251 | pm_runtime_put_noidle(&dev->dev); | 251 | pm_runtime_put_noidle(&dev->dev); |
252 | return retval; | 252 | return retval; |
253 | 253 | ||
254 | err4: | 254 | unmap_registers: |
255 | if (driver->flags & HCD_MEMORY) { | 255 | if (driver->flags & HCD_MEMORY) { |
256 | iounmap(hcd->regs); | 256 | iounmap(hcd->regs); |
257 | err3: | 257 | release_mem_region: |
258 | release_mem_region(hcd->rsrc_start, hcd->rsrc_len); | 258 | release_mem_region(hcd->rsrc_start, hcd->rsrc_len); |
259 | } else | 259 | } else |
260 | release_region(hcd->rsrc_start, hcd->rsrc_len); | 260 | release_region(hcd->rsrc_start, hcd->rsrc_len); |
261 | err2: | 261 | clear_companion: |
262 | clear_hs_companion(dev, hcd); | 262 | clear_hs_companion(dev, hcd); |
263 | usb_put_hcd(hcd); | 263 | usb_put_hcd(hcd); |
264 | err1: | 264 | disable_pci: |
265 | pci_disable_device(dev); | 265 | pci_disable_device(dev); |
266 | dev_err(&dev->dev, "init %s fail, %d\n", pci_name(dev), retval); | 266 | dev_err(&dev->dev, "init %s fail, %d\n", pci_name(dev), retval); |
267 | return retval; | 267 | return retval; |
@@ -363,11 +363,17 @@ static int check_root_hub_suspended(struct device *dev) | |||
363 | struct pci_dev *pci_dev = to_pci_dev(dev); | 363 | struct pci_dev *pci_dev = to_pci_dev(dev); |
364 | struct usb_hcd *hcd = pci_get_drvdata(pci_dev); | 364 | struct usb_hcd *hcd = pci_get_drvdata(pci_dev); |
365 | 365 | ||
366 | if (!(hcd->state == HC_STATE_SUSPENDED || | 366 | if (HCD_RH_RUNNING(hcd)) { |
367 | hcd->state == HC_STATE_HALT)) { | ||
368 | dev_warn(dev, "Root hub is not suspended\n"); | 367 | dev_warn(dev, "Root hub is not suspended\n"); |
369 | return -EBUSY; | 368 | return -EBUSY; |
370 | } | 369 | } |
370 | if (hcd->shared_hcd) { | ||
371 | hcd = hcd->shared_hcd; | ||
372 | if (HCD_RH_RUNNING(hcd)) { | ||
373 | dev_warn(dev, "Secondary root hub is not suspended\n"); | ||
374 | return -EBUSY; | ||
375 | } | ||
376 | } | ||
371 | return 0; | 377 | return 0; |
372 | } | 378 | } |
373 | 379 | ||
@@ -386,17 +392,22 @@ static int suspend_common(struct device *dev, bool do_wakeup) | |||
386 | if (retval) | 392 | if (retval) |
387 | return retval; | 393 | return retval; |
388 | 394 | ||
389 | if (hcd->driver->pci_suspend) { | 395 | if (hcd->driver->pci_suspend && !HCD_DEAD(hcd)) { |
390 | /* Optimization: Don't suspend if a root-hub wakeup is | 396 | /* Optimization: Don't suspend if a root-hub wakeup is |
391 | * pending and it would cause the HCD to wake up anyway. | 397 | * pending and it would cause the HCD to wake up anyway. |
392 | */ | 398 | */ |
393 | if (do_wakeup && HCD_WAKEUP_PENDING(hcd)) | 399 | if (do_wakeup && HCD_WAKEUP_PENDING(hcd)) |
394 | return -EBUSY; | 400 | return -EBUSY; |
401 | if (do_wakeup && hcd->shared_hcd && | ||
402 | HCD_WAKEUP_PENDING(hcd->shared_hcd)) | ||
403 | return -EBUSY; | ||
395 | retval = hcd->driver->pci_suspend(hcd, do_wakeup); | 404 | retval = hcd->driver->pci_suspend(hcd, do_wakeup); |
396 | suspend_report_result(hcd->driver->pci_suspend, retval); | 405 | suspend_report_result(hcd->driver->pci_suspend, retval); |
397 | 406 | ||
398 | /* Check again in case wakeup raced with pci_suspend */ | 407 | /* Check again in case wakeup raced with pci_suspend */ |
399 | if (retval == 0 && do_wakeup && HCD_WAKEUP_PENDING(hcd)) { | 408 | if ((retval == 0 && do_wakeup && HCD_WAKEUP_PENDING(hcd)) || |
409 | (retval == 0 && do_wakeup && hcd->shared_hcd && | ||
410 | HCD_WAKEUP_PENDING(hcd->shared_hcd))) { | ||
400 | if (hcd->driver->pci_resume) | 411 | if (hcd->driver->pci_resume) |
401 | hcd->driver->pci_resume(hcd, false); | 412 | hcd->driver->pci_resume(hcd, false); |
402 | retval = -EBUSY; | 413 | retval = -EBUSY; |
@@ -427,7 +438,9 @@ static int resume_common(struct device *dev, int event) | |||
427 | struct usb_hcd *hcd = pci_get_drvdata(pci_dev); | 438 | struct usb_hcd *hcd = pci_get_drvdata(pci_dev); |
428 | int retval; | 439 | int retval; |
429 | 440 | ||
430 | if (hcd->state != HC_STATE_SUSPENDED) { | 441 | if (HCD_RH_RUNNING(hcd) || |
442 | (hcd->shared_hcd && | ||
443 | HCD_RH_RUNNING(hcd->shared_hcd))) { | ||
431 | dev_dbg(dev, "can't resume, not suspended!\n"); | 444 | dev_dbg(dev, "can't resume, not suspended!\n"); |
432 | return 0; | 445 | return 0; |
433 | } | 446 | } |
@@ -441,8 +454,10 @@ static int resume_common(struct device *dev, int event) | |||
441 | pci_set_master(pci_dev); | 454 | pci_set_master(pci_dev); |
442 | 455 | ||
443 | clear_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); | 456 | clear_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); |
457 | if (hcd->shared_hcd) | ||
458 | clear_bit(HCD_FLAG_SAW_IRQ, &hcd->shared_hcd->flags); | ||
444 | 459 | ||
445 | if (hcd->driver->pci_resume) { | 460 | if (hcd->driver->pci_resume && !HCD_DEAD(hcd)) { |
446 | if (event != PM_EVENT_AUTO_RESUME) | 461 | if (event != PM_EVENT_AUTO_RESUME) |
447 | wait_for_companions(pci_dev, hcd); | 462 | wait_for_companions(pci_dev, hcd); |
448 | 463 | ||
@@ -450,6 +465,8 @@ static int resume_common(struct device *dev, int event) | |||
450 | event == PM_EVENT_RESTORE); | 465 | event == PM_EVENT_RESTORE); |
451 | if (retval) { | 466 | if (retval) { |
452 | dev_err(dev, "PCI post-resume error %d!\n", retval); | 467 | dev_err(dev, "PCI post-resume error %d!\n", retval); |
468 | if (hcd->shared_hcd) | ||
469 | usb_hc_died(hcd->shared_hcd); | ||
453 | usb_hc_died(hcd); | 470 | usb_hc_died(hcd); |
454 | } | 471 | } |
455 | } | 472 | } |
@@ -475,10 +492,11 @@ static int hcd_pci_suspend_noirq(struct device *dev) | |||
475 | 492 | ||
476 | pci_save_state(pci_dev); | 493 | pci_save_state(pci_dev); |
477 | 494 | ||
478 | /* If the root hub is HALTed rather than SUSPENDed, | 495 | /* If the root hub is dead rather than suspended, disallow remote |
479 | * disallow remote wakeup. | 496 | * wakeup. usb_hc_died() should ensure that both hosts are marked as |
497 | * dying, so we only need to check the primary roothub. | ||
480 | */ | 498 | */ |
481 | if (hcd->state == HC_STATE_HALT) | 499 | if (HCD_DEAD(hcd)) |
482 | device_set_wakeup_enable(dev, 0); | 500 | device_set_wakeup_enable(dev, 0); |
483 | dev_dbg(dev, "wakeup: %d\n", device_may_wakeup(dev)); | 501 | dev_dbg(dev, "wakeup: %d\n", device_may_wakeup(dev)); |
484 | 502 | ||