aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/core/hcd-pci.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/core/hcd-pci.c')
-rw-r--r--drivers/usb/core/hcd-pci.c202
1 files changed, 136 insertions, 66 deletions
diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c
index 1cf2d1e79a5..c3f98543caa 100644
--- a/drivers/usb/core/hcd-pci.c
+++ b/drivers/usb/core/hcd-pci.c
@@ -66,10 +66,7 @@ static void companion_common(struct pci_dev *pdev, struct usb_hcd *hcd,
66 * vice versa. 66 * vice versa.
67 */ 67 */
68 companion = NULL; 68 companion = NULL;
69 for (;;) { 69 for_each_pci_dev(companion) {
70 companion = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, companion);
71 if (!companion)
72 break;
73 if (companion->bus != pdev->bus || 70 if (companion->bus != pdev->bus ||
74 PCI_SLOT(companion->devfn) != slot) 71 PCI_SLOT(companion->devfn) != slot)
75 continue; 72 continue;
@@ -250,6 +247,9 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
250 if (retval != 0) 247 if (retval != 0)
251 goto err4; 248 goto err4;
252 set_hs_companion(dev, hcd); 249 set_hs_companion(dev, hcd);
250
251 if (pci_dev_run_wake(dev))
252 pm_runtime_put_noidle(&dev->dev);
253 return retval; 253 return retval;
254 254
255 err4: 255 err4:
@@ -292,6 +292,17 @@ void usb_hcd_pci_remove(struct pci_dev *dev)
292 if (!hcd) 292 if (!hcd)
293 return; 293 return;
294 294
295 if (pci_dev_run_wake(dev))
296 pm_runtime_get_noresume(&dev->dev);
297
298 /* Fake an interrupt request in order to give the driver a chance
299 * to test whether the controller hardware has been removed (e.g.,
300 * cardbus physical eject).
301 */
302 local_irq_disable();
303 usb_hcd_irq(0, hcd);
304 local_irq_enable();
305
295 usb_remove_hcd(hcd); 306 usb_remove_hcd(hcd);
296 if (hcd->driver->flags & HCD_MEMORY) { 307 if (hcd->driver->flags & HCD_MEMORY) {
297 iounmap(hcd->regs); 308 iounmap(hcd->regs);
@@ -317,12 +328,34 @@ void usb_hcd_pci_shutdown(struct pci_dev *dev)
317 if (!hcd) 328 if (!hcd)
318 return; 329 return;
319 330
320 if (hcd->driver->shutdown) 331 if (test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags) &&
332 hcd->driver->shutdown)
321 hcd->driver->shutdown(hcd); 333 hcd->driver->shutdown(hcd);
322} 334}
323EXPORT_SYMBOL_GPL(usb_hcd_pci_shutdown); 335EXPORT_SYMBOL_GPL(usb_hcd_pci_shutdown);
324 336
325#ifdef CONFIG_PM_SLEEP 337#ifdef CONFIG_PM_OPS
338
339#ifdef CONFIG_PPC_PMAC
340static void powermac_set_asic(struct pci_dev *pci_dev, int enable)
341{
342 /* Enanble or disable ASIC clocks for USB */
343 if (machine_is(powermac)) {
344 struct device_node *of_node;
345
346 of_node = pci_device_to_OF_node(pci_dev);
347 if (of_node)
348 pmac_call_feature(PMAC_FTR_USB_ENABLE,
349 of_node, 0, enable);
350 }
351}
352
353#else
354
355static inline void powermac_set_asic(struct pci_dev *pci_dev, int enable)
356{}
357
358#endif /* CONFIG_PPC_PMAC */
326 359
327static int check_root_hub_suspended(struct device *dev) 360static int check_root_hub_suspended(struct device *dev)
328{ 361{
@@ -337,7 +370,7 @@ static int check_root_hub_suspended(struct device *dev)
337 return 0; 370 return 0;
338} 371}
339 372
340static int hcd_pci_suspend(struct device *dev) 373static int suspend_common(struct device *dev, bool do_wakeup)
341{ 374{
342 struct pci_dev *pci_dev = to_pci_dev(dev); 375 struct pci_dev *pci_dev = to_pci_dev(dev);
343 struct usb_hcd *hcd = pci_get_drvdata(pci_dev); 376 struct usb_hcd *hcd = pci_get_drvdata(pci_dev);
@@ -352,13 +385,21 @@ static int hcd_pci_suspend(struct device *dev)
352 if (retval) 385 if (retval)
353 return retval; 386 return retval;
354 387
355 /* We might already be suspended (runtime PM -- not yet written) */
356 if (pci_dev->current_state != PCI_D0)
357 return retval;
358
359 if (hcd->driver->pci_suspend) { 388 if (hcd->driver->pci_suspend) {
360 retval = hcd->driver->pci_suspend(hcd); 389 /* Optimization: Don't suspend if a root-hub wakeup is
390 * pending and it would cause the HCD to wake up anyway.
391 */
392 if (do_wakeup && HCD_WAKEUP_PENDING(hcd))
393 return -EBUSY;
394 retval = hcd->driver->pci_suspend(hcd, do_wakeup);
361 suspend_report_result(hcd->driver->pci_suspend, retval); 395 suspend_report_result(hcd->driver->pci_suspend, retval);
396
397 /* Check again in case wakeup raced with pci_suspend */
398 if (retval == 0 && do_wakeup && HCD_WAKEUP_PENDING(hcd)) {
399 if (hcd->driver->pci_resume)
400 hcd->driver->pci_resume(hcd, false);
401 retval = -EBUSY;
402 }
362 if (retval) 403 if (retval)
363 return retval; 404 return retval;
364 } 405 }
@@ -374,6 +415,48 @@ static int hcd_pci_suspend(struct device *dev)
374 return retval; 415 return retval;
375} 416}
376 417
418static int resume_common(struct device *dev, int event)
419{
420 struct pci_dev *pci_dev = to_pci_dev(dev);
421 struct usb_hcd *hcd = pci_get_drvdata(pci_dev);
422 int retval;
423
424 if (hcd->state != HC_STATE_SUSPENDED) {
425 dev_dbg(dev, "can't resume, not suspended!\n");
426 return 0;
427 }
428
429 retval = pci_enable_device(pci_dev);
430 if (retval < 0) {
431 dev_err(dev, "can't re-enable after resume, %d!\n", retval);
432 return retval;
433 }
434
435 pci_set_master(pci_dev);
436
437 clear_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
438
439 if (hcd->driver->pci_resume) {
440 if (event != PM_EVENT_AUTO_RESUME)
441 wait_for_companions(pci_dev, hcd);
442
443 retval = hcd->driver->pci_resume(hcd,
444 event == PM_EVENT_RESTORE);
445 if (retval) {
446 dev_err(dev, "PCI post-resume error %d!\n", retval);
447 usb_hc_died(hcd);
448 }
449 }
450 return retval;
451}
452
453#ifdef CONFIG_PM_SLEEP
454
455static int hcd_pci_suspend(struct device *dev)
456{
457 return suspend_common(dev, device_may_wakeup(dev));
458}
459
377static int hcd_pci_suspend_noirq(struct device *dev) 460static int hcd_pci_suspend_noirq(struct device *dev)
378{ 461{
379 struct pci_dev *pci_dev = to_pci_dev(dev); 462 struct pci_dev *pci_dev = to_pci_dev(dev);
@@ -408,16 +491,7 @@ static int hcd_pci_suspend_noirq(struct device *dev)
408 return retval; 491 return retval;
409 } 492 }
410 493
411#ifdef CONFIG_PPC_PMAC 494 powermac_set_asic(pci_dev, 0);
412 /* Disable ASIC clocks for USB */
413 if (machine_is(powermac)) {
414 struct device_node *of_node;
415
416 of_node = pci_device_to_OF_node(pci_dev);
417 if (of_node)
418 pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 0);
419 }
420#endif
421 return retval; 495 return retval;
422} 496}
423 497
@@ -425,69 +499,63 @@ static int hcd_pci_resume_noirq(struct device *dev)
425{ 499{
426 struct pci_dev *pci_dev = to_pci_dev(dev); 500 struct pci_dev *pci_dev = to_pci_dev(dev);
427 501
428#ifdef CONFIG_PPC_PMAC 502 powermac_set_asic(pci_dev, 1);
429 /* Reenable ASIC clocks for USB */
430 if (machine_is(powermac)) {
431 struct device_node *of_node;
432
433 of_node = pci_device_to_OF_node(pci_dev);
434 if (of_node)
435 pmac_call_feature(PMAC_FTR_USB_ENABLE,
436 of_node, 0, 1);
437 }
438#endif
439 503
440 /* Go back to D0 and disable remote wakeup */ 504 /* Go back to D0 and disable remote wakeup */
441 pci_back_from_sleep(pci_dev); 505 pci_back_from_sleep(pci_dev);
442 return 0; 506 return 0;
443} 507}
444 508
445static int resume_common(struct device *dev, bool hibernated) 509static int hcd_pci_resume(struct device *dev)
446{ 510{
447 struct pci_dev *pci_dev = to_pci_dev(dev); 511 return resume_common(dev, PM_EVENT_RESUME);
448 struct usb_hcd *hcd = pci_get_drvdata(pci_dev); 512}
449 int retval;
450 513
451 if (hcd->state != HC_STATE_SUSPENDED) { 514static int hcd_pci_restore(struct device *dev)
452 dev_dbg(dev, "can't resume, not suspended!\n"); 515{
453 return 0; 516 return resume_common(dev, PM_EVENT_RESTORE);
454 } 517}
455 518
456 retval = pci_enable_device(pci_dev); 519#else
457 if (retval < 0) {
458 dev_err(dev, "can't re-enable after resume, %d!\n", retval);
459 return retval;
460 }
461 520
462 pci_set_master(pci_dev); 521#define hcd_pci_suspend NULL
522#define hcd_pci_suspend_noirq NULL
523#define hcd_pci_resume_noirq NULL
524#define hcd_pci_resume NULL
525#define hcd_pci_restore NULL
463 526
464 clear_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); 527#endif /* CONFIG_PM_SLEEP */
465 528
466 if (hcd->driver->pci_resume) { 529#ifdef CONFIG_PM_RUNTIME
467 /* This call should be made only during system resume,
468 * not during runtime resume.
469 */
470 wait_for_companions(pci_dev, hcd);
471 530
472 retval = hcd->driver->pci_resume(hcd, hibernated); 531static int hcd_pci_runtime_suspend(struct device *dev)
473 if (retval) { 532{
474 dev_err(dev, "PCI post-resume error %d!\n", retval); 533 int retval;
475 usb_hc_died(hcd); 534
476 } 535 retval = suspend_common(dev, true);
477 } 536 if (retval == 0)
537 powermac_set_asic(to_pci_dev(dev), 0);
538 dev_dbg(dev, "hcd_pci_runtime_suspend: %d\n", retval);
478 return retval; 539 return retval;
479} 540}
480 541
481static int hcd_pci_resume(struct device *dev) 542static int hcd_pci_runtime_resume(struct device *dev)
482{ 543{
483 return resume_common(dev, false); 544 int retval;
484}
485 545
486static int hcd_pci_restore(struct device *dev) 546 powermac_set_asic(to_pci_dev(dev), 1);
487{ 547 retval = resume_common(dev, PM_EVENT_AUTO_RESUME);
488 return resume_common(dev, true); 548 dev_dbg(dev, "hcd_pci_runtime_resume: %d\n", retval);
549 return retval;
489} 550}
490 551
552#else
553
554#define hcd_pci_runtime_suspend NULL
555#define hcd_pci_runtime_resume NULL
556
557#endif /* CONFIG_PM_RUNTIME */
558
491const struct dev_pm_ops usb_hcd_pci_pm_ops = { 559const struct dev_pm_ops usb_hcd_pci_pm_ops = {
492 .suspend = hcd_pci_suspend, 560 .suspend = hcd_pci_suspend,
493 .suspend_noirq = hcd_pci_suspend_noirq, 561 .suspend_noirq = hcd_pci_suspend_noirq,
@@ -501,7 +569,9 @@ const struct dev_pm_ops usb_hcd_pci_pm_ops = {
501 .poweroff_noirq = hcd_pci_suspend_noirq, 569 .poweroff_noirq = hcd_pci_suspend_noirq,
502 .restore_noirq = hcd_pci_resume_noirq, 570 .restore_noirq = hcd_pci_resume_noirq,
503 .restore = hcd_pci_restore, 571 .restore = hcd_pci_restore,
572 .runtime_suspend = hcd_pci_runtime_suspend,
573 .runtime_resume = hcd_pci_runtime_resume,
504}; 574};
505EXPORT_SYMBOL_GPL(usb_hcd_pci_pm_ops); 575EXPORT_SYMBOL_GPL(usb_hcd_pci_pm_ops);
506 576
507#endif /* CONFIG_PM_SLEEP */ 577#endif /* CONFIG_PM_OPS */