aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2008-05-19 18:49:04 -0400
committerJesse Barnes <jbarnes@virtuousgeek.org>2008-06-10 13:59:51 -0400
commitbbb44d9f23d868a2837c6b22b8dfb123d8e7800c (patch)
tree15573ad50a41601b0fda2f7d8568e6c94fee307b /drivers/pci
parent1eede070a59e1cc73da51e1aaa00d9ab86572cfc (diff)
PCI: implement new suspend/resume callbacks
Implement new suspend and hibernation callbacks for the PCI bus type. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Acked-by: Pavel Machek <pavel@ucw.cz> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/pci-driver.c392
1 files changed, 346 insertions, 46 deletions
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index 677fd9d6db12..8eb8a3091dc7 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -274,7 +274,57 @@ static int pci_device_remove(struct device * dev)
274 return 0; 274 return 0;
275} 275}
276 276
277static int pci_device_suspend(struct device * dev, pm_message_t state) 277static void pci_device_shutdown(struct device *dev)
278{
279 struct pci_dev *pci_dev = to_pci_dev(dev);
280 struct pci_driver *drv = pci_dev->driver;
281
282 if (drv && drv->shutdown)
283 drv->shutdown(pci_dev);
284 pci_msi_shutdown(pci_dev);
285 pci_msix_shutdown(pci_dev);
286}
287
288#ifdef CONFIG_PM_SLEEP
289
290/*
291 * Default "suspend" method for devices that have no driver provided suspend,
292 * or not even a driver at all.
293 */
294static void pci_default_pm_suspend(struct pci_dev *pci_dev)
295{
296 pci_save_state(pci_dev);
297 /*
298 * mark its power state as "unknown", since we don't know if
299 * e.g. the BIOS will change its device state when we suspend.
300 */
301 if (pci_dev->current_state == PCI_D0)
302 pci_dev->current_state = PCI_UNKNOWN;
303}
304
305/*
306 * Default "resume" method for devices that have no driver provided resume,
307 * or not even a driver at all.
308 */
309static int pci_default_pm_resume(struct pci_dev *pci_dev)
310{
311 int retval = 0;
312
313 /* restore the PCI config space */
314 pci_restore_state(pci_dev);
315 /* if the device was enabled before suspend, reenable */
316 retval = pci_reenable_device(pci_dev);
317 /*
318 * if the device was busmaster before the suspend, make it busmaster
319 * again
320 */
321 if (pci_dev->is_busmaster)
322 pci_set_master(pci_dev);
323
324 return retval;
325}
326
327static int pci_legacy_suspend(struct device *dev, pm_message_t state)
278{ 328{
279 struct pci_dev * pci_dev = to_pci_dev(dev); 329 struct pci_dev * pci_dev = to_pci_dev(dev);
280 struct pci_driver * drv = pci_dev->driver; 330 struct pci_driver * drv = pci_dev->driver;
@@ -284,21 +334,12 @@ static int pci_device_suspend(struct device * dev, pm_message_t state)
284 i = drv->suspend(pci_dev, state); 334 i = drv->suspend(pci_dev, state);
285 suspend_report_result(drv->suspend, i); 335 suspend_report_result(drv->suspend, i);
286 } else { 336 } else {
287 pci_save_state(pci_dev); 337 pci_default_pm_suspend(pci_dev);
288 /*
289 * mark its power state as "unknown", since we don't know if
290 * e.g. the BIOS will change its device state when we suspend.
291 */
292 if (pci_dev->current_state == PCI_D0)
293 pci_dev->current_state = PCI_UNKNOWN;
294 } 338 }
295
296 pci_fixup_device(pci_fixup_suspend, pci_dev);
297
298 return i; 339 return i;
299} 340}
300 341
301static int pci_device_suspend_late(struct device * dev, pm_message_t state) 342static int pci_legacy_suspend_late(struct device *dev, pm_message_t state)
302{ 343{
303 struct pci_dev * pci_dev = to_pci_dev(dev); 344 struct pci_dev * pci_dev = to_pci_dev(dev);
304 struct pci_driver * drv = pci_dev->driver; 345 struct pci_driver * drv = pci_dev->driver;
@@ -311,26 +352,7 @@ static int pci_device_suspend_late(struct device * dev, pm_message_t state)
311 return i; 352 return i;
312} 353}
313 354
314/* 355static int pci_legacy_resume(struct device *dev)
315 * Default resume method for devices that have no driver provided resume,
316 * or not even a driver at all.
317 */
318static int pci_default_resume(struct pci_dev *pci_dev)
319{
320 int retval = 0;
321
322 /* restore the PCI config space */
323 pci_restore_state(pci_dev);
324 /* if the device was enabled before suspend, reenable */
325 retval = pci_reenable_device(pci_dev);
326 /* if the device was busmaster before the suspend, make it busmaster again */
327 if (pci_dev->is_busmaster)
328 pci_set_master(pci_dev);
329
330 return retval;
331}
332
333static int pci_device_resume(struct device * dev)
334{ 356{
335 int error; 357 int error;
336 struct pci_dev * pci_dev = to_pci_dev(dev); 358 struct pci_dev * pci_dev = to_pci_dev(dev);
@@ -339,35 +361,313 @@ static int pci_device_resume(struct device * dev)
339 if (drv && drv->resume) 361 if (drv && drv->resume)
340 error = drv->resume(pci_dev); 362 error = drv->resume(pci_dev);
341 else 363 else
342 error = pci_default_resume(pci_dev); 364 error = pci_default_pm_resume(pci_dev);
343 pci_fixup_device(pci_fixup_resume, pci_dev);
344 return error; 365 return error;
345} 366}
346 367
347static int pci_device_resume_early(struct device * dev) 368static int pci_legacy_resume_early(struct device *dev)
348{ 369{
349 int error = 0; 370 int error = 0;
350 struct pci_dev * pci_dev = to_pci_dev(dev); 371 struct pci_dev * pci_dev = to_pci_dev(dev);
351 struct pci_driver * drv = pci_dev->driver; 372 struct pci_driver * drv = pci_dev->driver;
352 373
353 pci_fixup_device(pci_fixup_resume_early, pci_dev);
354
355 if (drv && drv->resume_early) 374 if (drv && drv->resume_early)
356 error = drv->resume_early(pci_dev); 375 error = drv->resume_early(pci_dev);
357 return error; 376 return error;
358} 377}
359 378
360static void pci_device_shutdown(struct device *dev) 379static int pci_pm_prepare(struct device *dev)
380{
381 struct device_driver *drv = dev->driver;
382 int error = 0;
383
384 if (drv && drv->pm && drv->pm->prepare)
385 error = drv->pm->prepare(dev);
386
387 return error;
388}
389
390static void pci_pm_complete(struct device *dev)
391{
392 struct device_driver *drv = dev->driver;
393
394 if (drv && drv->pm && drv->pm->complete)
395 drv->pm->complete(dev);
396}
397
398#ifdef CONFIG_SUSPEND
399
400static int pci_pm_suspend(struct device *dev)
401{
402 struct pci_dev *pci_dev = to_pci_dev(dev);
403 struct device_driver *drv = dev->driver;
404 int error = 0;
405
406 if (drv && drv->pm) {
407 if (drv->pm->suspend) {
408 error = drv->pm->suspend(dev);
409 suspend_report_result(drv->pm->suspend, error);
410 } else {
411 pci_default_pm_suspend(pci_dev);
412 }
413 } else {
414 error = pci_legacy_suspend(dev, PMSG_SUSPEND);
415 }
416 pci_fixup_device(pci_fixup_suspend, pci_dev);
417
418 return error;
419}
420
421static int pci_pm_suspend_noirq(struct device *dev)
361{ 422{
362 struct pci_dev *pci_dev = to_pci_dev(dev); 423 struct pci_dev *pci_dev = to_pci_dev(dev);
363 struct pci_driver *drv = pci_dev->driver; 424 struct pci_driver *drv = pci_dev->driver;
425 int error = 0;
364 426
365 if (drv && drv->shutdown) 427 if (drv && drv->pm) {
366 drv->shutdown(pci_dev); 428 if (drv->pm->suspend_noirq) {
367 pci_msi_shutdown(pci_dev); 429 error = drv->pm->suspend_noirq(dev);
368 pci_msix_shutdown(pci_dev); 430 suspend_report_result(drv->pm->suspend_noirq, error);
431 }
432 } else {
433 error = pci_legacy_suspend_late(dev, PMSG_SUSPEND);
434 }
435
436 return error;
437}
438
439static int pci_pm_resume(struct device *dev)
440{
441 struct pci_dev *pci_dev = to_pci_dev(dev);
442 struct device_driver *drv = dev->driver;
443 int error;
444
445 pci_fixup_device(pci_fixup_resume, pci_dev);
446
447 if (drv && drv->pm) {
448 error = drv->pm->resume ? drv->pm->resume(dev) :
449 pci_default_pm_resume(pci_dev);
450 } else {
451 error = pci_legacy_resume(dev);
452 }
453
454 return error;
455}
456
457static int pci_pm_resume_noirq(struct device *dev)
458{
459 struct pci_dev *pci_dev = to_pci_dev(dev);
460 struct pci_driver *drv = pci_dev->driver;
461 int error = 0;
462
463 pci_fixup_device(pci_fixup_resume_early, pci_dev);
464
465 if (drv && drv->pm) {
466 if (drv->pm->resume_noirq)
467 error = drv->pm->resume_noirq(dev);
468 } else {
469 error = pci_legacy_resume_early(dev);
470 }
471
472 return error;
473}
474
475#else /* !CONFIG_SUSPEND */
476
477#define pci_pm_suspend NULL
478#define pci_pm_suspend_noirq NULL
479#define pci_pm_resume NULL
480#define pci_pm_resume_noirq NULL
481
482#endif /* !CONFIG_SUSPEND */
483
484#ifdef CONFIG_HIBERNATION
485
486static int pci_pm_freeze(struct device *dev)
487{
488 struct pci_dev *pci_dev = to_pci_dev(dev);
489 struct device_driver *drv = dev->driver;
490 int error = 0;
491
492 if (drv && drv->pm) {
493 if (drv->pm->freeze) {
494 error = drv->pm->freeze(dev);
495 suspend_report_result(drv->pm->freeze, error);
496 } else {
497 pci_default_pm_suspend(pci_dev);
498 }
499 } else {
500 error = pci_legacy_suspend(dev, PMSG_FREEZE);
501 pci_fixup_device(pci_fixup_suspend, pci_dev);
502 }
503
504 return error;
505}
506
507static int pci_pm_freeze_noirq(struct device *dev)
508{
509 struct pci_dev *pci_dev = to_pci_dev(dev);
510 struct pci_driver *drv = pci_dev->driver;
511 int error = 0;
512
513 if (drv && drv->pm) {
514 if (drv->pm->freeze_noirq) {
515 error = drv->pm->freeze_noirq(dev);
516 suspend_report_result(drv->pm->freeze_noirq, error);
517 }
518 } else {
519 error = pci_legacy_suspend_late(dev, PMSG_FREEZE);
520 }
521
522 return error;
523}
524
525static int pci_pm_thaw(struct device *dev)
526{
527 struct device_driver *drv = dev->driver;
528 int error = 0;
529
530 if (drv && drv->pm) {
531 if (drv->pm->thaw)
532 error = drv->pm->thaw(dev);
533 } else {
534 pci_fixup_device(pci_fixup_resume, to_pci_dev(dev));
535 error = pci_legacy_resume(dev);
536 }
537
538 return error;
539}
540
541static int pci_pm_thaw_noirq(struct device *dev)
542{
543 struct pci_dev *pci_dev = to_pci_dev(dev);
544 struct pci_driver *drv = pci_dev->driver;
545 int error = 0;
546
547 if (drv && drv->pm) {
548 if (drv->pm->thaw_noirq)
549 error = drv->pm->thaw_noirq(dev);
550 } else {
551 pci_fixup_device(pci_fixup_resume_early, pci_dev);
552 error = pci_legacy_resume_early(dev);
553 }
554
555 return error;
556}
557
558static int pci_pm_poweroff(struct device *dev)
559{
560 struct device_driver *drv = dev->driver;
561 int error = 0;
562
563 pci_fixup_device(pci_fixup_suspend, to_pci_dev(dev));
564
565 if (drv && drv->pm) {
566 if (drv->pm->poweroff) {
567 error = drv->pm->poweroff(dev);
568 suspend_report_result(drv->pm->poweroff, error);
569 }
570 } else {
571 error = pci_legacy_suspend(dev, PMSG_HIBERNATE);
572 }
573
574 return error;
575}
576
577static int pci_pm_poweroff_noirq(struct device *dev)
578{
579 struct pci_dev *pci_dev = to_pci_dev(dev);
580 struct pci_driver *drv = pci_dev->driver;
581 int error = 0;
582
583 if (drv && drv->pm) {
584 if (drv->pm->poweroff_noirq) {
585 error = drv->pm->poweroff_noirq(dev);
586 suspend_report_result(drv->pm->poweroff_noirq, error);
587 }
588 } else {
589 error = pci_legacy_suspend_late(dev, PMSG_HIBERNATE);
590 }
591
592 return error;
593}
594
595static int pci_pm_restore(struct device *dev)
596{
597 struct pci_dev *pci_dev = to_pci_dev(dev);
598 struct device_driver *drv = dev->driver;
599 int error;
600
601 if (drv && drv->pm) {
602 error = drv->pm->restore ? drv->pm->restore(dev) :
603 pci_default_pm_resume(pci_dev);
604 } else {
605 error = pci_legacy_resume(dev);
606 }
607 pci_fixup_device(pci_fixup_resume, pci_dev);
608
609 return error;
610}
611
612static int pci_pm_restore_noirq(struct device *dev)
613{
614 struct pci_dev *pci_dev = to_pci_dev(dev);
615 struct pci_driver *drv = pci_dev->driver;
616 int error = 0;
617
618 pci_fixup_device(pci_fixup_resume, pci_dev);
619
620 if (drv && drv->pm) {
621 if (drv->pm->restore_noirq)
622 error = drv->pm->restore_noirq(dev);
623 } else {
624 error = pci_legacy_resume_early(dev);
625 }
626 pci_fixup_device(pci_fixup_resume_early, pci_dev);
627
628 return error;
369} 629}
370 630
631#else /* !CONFIG_HIBERNATION */
632
633#define pci_pm_freeze NULL
634#define pci_pm_freeze_noirq NULL
635#define pci_pm_thaw NULL
636#define pci_pm_thaw_noirq NULL
637#define pci_pm_poweroff NULL
638#define pci_pm_poweroff_noirq NULL
639#define pci_pm_restore NULL
640#define pci_pm_restore_noirq NULL
641
642#endif /* !CONFIG_HIBERNATION */
643
644struct pm_ext_ops pci_pm_ops = {
645 .base = {
646 .prepare = pci_pm_prepare,
647 .complete = pci_pm_complete,
648 .suspend = pci_pm_suspend,
649 .resume = pci_pm_resume,
650 .freeze = pci_pm_freeze,
651 .thaw = pci_pm_thaw,
652 .poweroff = pci_pm_poweroff,
653 .restore = pci_pm_restore,
654 },
655 .suspend_noirq = pci_pm_suspend_noirq,
656 .resume_noirq = pci_pm_resume_noirq,
657 .freeze_noirq = pci_pm_freeze_noirq,
658 .thaw_noirq = pci_pm_thaw_noirq,
659 .poweroff_noirq = pci_pm_poweroff_noirq,
660 .restore_noirq = pci_pm_restore_noirq,
661};
662
663#define PCI_PM_OPS_PTR &pci_pm_ops
664
665#else /* !CONFIG_PM_SLEEP */
666
667#define PCI_PM_OPS_PTR NULL
668
669#endif /* !CONFIG_PM_SLEEP */
670
371/** 671/**
372 * __pci_register_driver - register a new pci driver 672 * __pci_register_driver - register a new pci driver
373 * @drv: the driver structure to register 673 * @drv: the driver structure to register
@@ -390,6 +690,9 @@ int __pci_register_driver(struct pci_driver *drv, struct module *owner,
390 drv->driver.owner = owner; 690 drv->driver.owner = owner;
391 drv->driver.mod_name = mod_name; 691 drv->driver.mod_name = mod_name;
392 692
693 if (drv->pm)
694 drv->driver.pm = &drv->pm->base;
695
393 spin_lock_init(&drv->dynids.lock); 696 spin_lock_init(&drv->dynids.lock);
394 INIT_LIST_HEAD(&drv->dynids.list); 697 INIT_LIST_HEAD(&drv->dynids.list);
395 698
@@ -515,12 +818,9 @@ struct bus_type pci_bus_type = {
515 .uevent = pci_uevent, 818 .uevent = pci_uevent,
516 .probe = pci_device_probe, 819 .probe = pci_device_probe,
517 .remove = pci_device_remove, 820 .remove = pci_device_remove,
518 .suspend = pci_device_suspend,
519 .suspend_late = pci_device_suspend_late,
520 .resume_early = pci_device_resume_early,
521 .resume = pci_device_resume,
522 .shutdown = pci_device_shutdown, 821 .shutdown = pci_device_shutdown,
523 .dev_attrs = pci_dev_attrs, 822 .dev_attrs = pci_dev_attrs,
823 .pm = PCI_PM_OPS_PTR,
524}; 824};
525 825
526static int __init pci_driver_init(void) 826static int __init pci_driver_init(void)