Skip to content

Commit 3da7cff

Browse files
AlanSterngregkh
authored andcommitted
USB: add runtime PM for PCI-based host controllers
This patch (as1386) adds runtime-PM support for PCI-based USB host controllers. By default autosuspend is disallowed; the user must enable it by writing "auto" to the controller's power/control sysfs attribute. Signed-off-by: Alan Stern <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 0d436b4 commit 3da7cff

File tree

1 file changed

+62
-14
lines changed

1 file changed

+62
-14
lines changed

drivers/usb/core/hcd-pci.c

Lines changed: 62 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,9 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
250250
if (retval != 0)
251251
goto err4;
252252
set_hs_companion(dev, hcd);
253+
254+
if (pci_dev_run_wake(dev))
255+
pm_runtime_put_noidle(&dev->dev);
253256
return retval;
254257

255258
err4:
@@ -292,6 +295,9 @@ void usb_hcd_pci_remove(struct pci_dev *dev)
292295
if (!hcd)
293296
return;
294297

298+
if (pci_dev_run_wake(dev))
299+
pm_runtime_get_noresume(&dev->dev);
300+
295301
/* Fake an interrupt request in order to give the driver a chance
296302
* to test whether the controller hardware has been removed (e.g.,
297303
* cardbus physical eject).
@@ -325,12 +331,13 @@ void usb_hcd_pci_shutdown(struct pci_dev *dev)
325331
if (!hcd)
326332
return;
327333

328-
if (hcd->driver->shutdown)
334+
if (test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags) &&
335+
hcd->driver->shutdown)
329336
hcd->driver->shutdown(hcd);
330337
}
331338
EXPORT_SYMBOL_GPL(usb_hcd_pci_shutdown);
332339

333-
#ifdef CONFIG_PM_SLEEP
340+
#ifdef CONFIG_PM_OPS
334341

335342
#ifdef CONFIG_PPC_PMAC
336343
static void powermac_set_asic(struct pci_dev *pci_dev, int enable)
@@ -366,7 +373,7 @@ static int check_root_hub_suspended(struct device *dev)
366373
return 0;
367374
}
368375

369-
static int hcd_pci_suspend(struct device *dev)
376+
static int suspend_common(struct device *dev, bool do_wakeup)
370377
{
371378
struct pci_dev *pci_dev = to_pci_dev(dev);
372379
struct usb_hcd *hcd = pci_get_drvdata(pci_dev);
@@ -381,13 +388,7 @@ static int hcd_pci_suspend(struct device *dev)
381388
if (retval)
382389
return retval;
383390

384-
/* We might already be suspended (runtime PM -- not yet written) */
385-
if (pci_dev->current_state != PCI_D0)
386-
return retval;
387-
388391
if (hcd->driver->pci_suspend) {
389-
bool do_wakeup = device_may_wakeup(dev);
390-
391392
/* Optimization: Don't suspend if a root-hub wakeup is
392393
* pending and it would cause the HCD to wake up anyway.
393394
*/
@@ -439,10 +440,8 @@ static int resume_common(struct device *dev, int event)
439440
clear_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
440441

441442
if (hcd->driver->pci_resume) {
442-
/* This call should be made only during system resume,
443-
* not during runtime resume.
444-
*/
445-
wait_for_companions(pci_dev, hcd);
443+
if (event != PM_EVENT_AUTO_RESUME)
444+
wait_for_companions(pci_dev, hcd);
446445

447446
retval = hcd->driver->pci_resume(hcd,
448447
event == PM_EVENT_RESTORE);
@@ -454,6 +453,13 @@ static int resume_common(struct device *dev, int event)
454453
return retval;
455454
}
456455

456+
#ifdef CONFIG_PM_SLEEP
457+
458+
static int hcd_pci_suspend(struct device *dev)
459+
{
460+
return suspend_common(dev, device_may_wakeup(dev));
461+
}
462+
457463
static int hcd_pci_suspend_noirq(struct device *dev)
458464
{
459465
struct pci_dev *pci_dev = to_pci_dev(dev);
@@ -513,6 +519,46 @@ static int hcd_pci_restore(struct device *dev)
513519
return resume_common(dev, PM_EVENT_RESTORE);
514520
}
515521

522+
#else
523+
524+
#define hcd_pci_suspend NULL
525+
#define hcd_pci_suspend_noirq NULL
526+
#define hcd_pci_resume_noirq NULL
527+
#define hcd_pci_resume NULL
528+
#define hcd_pci_restore NULL
529+
530+
#endif /* CONFIG_PM_SLEEP */
531+
532+
#ifdef CONFIG_PM_RUNTIME
533+
534+
static int hcd_pci_runtime_suspend(struct device *dev)
535+
{
536+
int retval;
537+
538+
retval = suspend_common(dev, true);
539+
if (retval == 0)
540+
powermac_set_asic(to_pci_dev(dev), 0);
541+
dev_dbg(dev, "hcd_pci_runtime_suspend: %d\n", retval);
542+
return retval;
543+
}
544+
545+
static int hcd_pci_runtime_resume(struct device *dev)
546+
{
547+
int retval;
548+
549+
powermac_set_asic(to_pci_dev(dev), 1);
550+
retval = resume_common(dev, PM_EVENT_AUTO_RESUME);
551+
dev_dbg(dev, "hcd_pci_runtime_resume: %d\n", retval);
552+
return retval;
553+
}
554+
555+
#else
556+
557+
#define hcd_pci_runtime_suspend NULL
558+
#define hcd_pci_runtime_resume NULL
559+
560+
#endif /* CONFIG_PM_RUNTIME */
561+
516562
const struct dev_pm_ops usb_hcd_pci_pm_ops = {
517563
.suspend = hcd_pci_suspend,
518564
.suspend_noirq = hcd_pci_suspend_noirq,
@@ -526,7 +572,9 @@ const struct dev_pm_ops usb_hcd_pci_pm_ops = {
526572
.poweroff_noirq = hcd_pci_suspend_noirq,
527573
.restore_noirq = hcd_pci_resume_noirq,
528574
.restore = hcd_pci_restore,
575+
.runtime_suspend = hcd_pci_runtime_suspend,
576+
.runtime_resume = hcd_pci_runtime_resume,
529577
};
530578
EXPORT_SYMBOL_GPL(usb_hcd_pci_pm_ops);
531579

532-
#endif /* CONFIG_PM_SLEEP */
580+
#endif /* CONFIG_PM_OPS */

0 commit comments

Comments
 (0)