diff options
Diffstat (limited to 'drivers/pci/pci-driver.c')
-rw-r--r-- | drivers/pci/pci-driver.c | 116 |
1 files changed, 75 insertions, 41 deletions
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 750ee79c178f..2e76945a1cd8 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c | |||
@@ -318,7 +318,7 @@ static void pci_device_shutdown(struct device *dev) | |||
318 | * Default "suspend" method for devices that have no driver provided suspend, | 318 | * Default "suspend" method for devices that have no driver provided suspend, |
319 | * or not even a driver at all (second part). | 319 | * or not even a driver at all (second part). |
320 | */ | 320 | */ |
321 | static void pci_default_pm_suspend_late(struct pci_dev *pci_dev) | 321 | static void pci_pm_set_unknown_state(struct pci_dev *pci_dev) |
322 | { | 322 | { |
323 | /* | 323 | /* |
324 | * mark its power state as "unknown", since we don't know if | 324 | * mark its power state as "unknown", since we don't know if |
@@ -332,7 +332,7 @@ static void pci_default_pm_suspend_late(struct pci_dev *pci_dev) | |||
332 | * Default "resume" method for devices that have no driver provided resume, | 332 | * Default "resume" method for devices that have no driver provided resume, |
333 | * or not even a driver at all (second part). | 333 | * or not even a driver at all (second part). |
334 | */ | 334 | */ |
335 | static int pci_default_pm_resume_late(struct pci_dev *pci_dev) | 335 | static int pci_pm_reenable_device(struct pci_dev *pci_dev) |
336 | { | 336 | { |
337 | int retval; | 337 | int retval; |
338 | 338 | ||
@@ -363,7 +363,7 @@ static int pci_legacy_suspend(struct device *dev, pm_message_t state) | |||
363 | * This is for compatibility with existing code with legacy PM | 363 | * This is for compatibility with existing code with legacy PM |
364 | * support. | 364 | * support. |
365 | */ | 365 | */ |
366 | pci_default_pm_suspend_late(pci_dev); | 366 | pci_pm_set_unknown_state(pci_dev); |
367 | } | 367 | } |
368 | return i; | 368 | return i; |
369 | } | 369 | } |
@@ -392,7 +392,7 @@ static int pci_legacy_resume(struct device *dev) | |||
392 | } else { | 392 | } else { |
393 | /* restore the PCI config space */ | 393 | /* restore the PCI config space */ |
394 | pci_restore_state(pci_dev); | 394 | pci_restore_state(pci_dev); |
395 | error = pci_default_pm_resume_late(pci_dev); | 395 | error = pci_pm_reenable_device(pci_dev); |
396 | } | 396 | } |
397 | return error; | 397 | return error; |
398 | } | 398 | } |
@@ -459,7 +459,7 @@ static int pci_pm_default_resume(struct pci_dev *pci_dev) | |||
459 | if (!pci_is_bridge(pci_dev)) | 459 | if (!pci_is_bridge(pci_dev)) |
460 | pci_enable_wake(pci_dev, PCI_D0, false); | 460 | pci_enable_wake(pci_dev, PCI_D0, false); |
461 | 461 | ||
462 | return pci_default_pm_resume_late(pci_dev); | 462 | return pci_pm_reenable_device(pci_dev); |
463 | } | 463 | } |
464 | 464 | ||
465 | static void pci_pm_default_suspend_generic(struct pci_dev *pci_dev) | 465 | static void pci_pm_default_suspend_generic(struct pci_dev *pci_dev) |
@@ -484,9 +484,17 @@ static void pci_pm_default_suspend(struct pci_dev *pci_dev) | |||
484 | static bool pci_has_legacy_pm_support(struct pci_dev *pci_dev) | 484 | static bool pci_has_legacy_pm_support(struct pci_dev *pci_dev) |
485 | { | 485 | { |
486 | struct pci_driver *drv = pci_dev->driver; | 486 | struct pci_driver *drv = pci_dev->driver; |
487 | 487 | bool ret = drv && (drv->suspend || drv->suspend_late || drv->resume | |
488 | return drv && (drv->suspend || drv->suspend_late || drv->resume | ||
489 | || drv->resume_early); | 488 | || drv->resume_early); |
489 | |||
490 | /* | ||
491 | * Legacy PM support is used by default, so warn if the new framework is | ||
492 | * supported as well. Drivers are supposed to support either the | ||
493 | * former, or the latter, but not both at the same time. | ||
494 | */ | ||
495 | WARN_ON(ret && drv->driver.pm); | ||
496 | |||
497 | return ret; | ||
490 | } | 498 | } |
491 | 499 | ||
492 | /* New power management framework */ | 500 | /* New power management framework */ |
@@ -518,17 +526,21 @@ static int pci_pm_suspend(struct device *dev) | |||
518 | struct device_driver *drv = dev->driver; | 526 | struct device_driver *drv = dev->driver; |
519 | int error = 0; | 527 | int error = 0; |
520 | 528 | ||
529 | if (pci_has_legacy_pm_support(pci_dev)) { | ||
530 | error = pci_legacy_suspend(dev, PMSG_SUSPEND); | ||
531 | goto Exit; | ||
532 | } | ||
533 | |||
521 | if (drv && drv->pm) { | 534 | if (drv && drv->pm) { |
522 | if (drv->pm->suspend) { | 535 | if (drv->pm->suspend) { |
523 | error = drv->pm->suspend(dev); | 536 | error = drv->pm->suspend(dev); |
524 | suspend_report_result(drv->pm->suspend, error); | 537 | suspend_report_result(drv->pm->suspend, error); |
525 | } | 538 | } |
526 | } else if (pci_has_legacy_pm_support(pci_dev)) { | ||
527 | error = pci_legacy_suspend(dev, PMSG_SUSPEND); | ||
528 | } else { | 539 | } else { |
529 | pci_pm_default_suspend(pci_dev); | 540 | pci_pm_default_suspend(pci_dev); |
530 | } | 541 | } |
531 | 542 | ||
543 | Exit: | ||
532 | pci_fixup_device(pci_fixup_suspend, pci_dev); | 544 | pci_fixup_device(pci_fixup_suspend, pci_dev); |
533 | 545 | ||
534 | return error; | 546 | return error; |
@@ -540,15 +552,16 @@ static int pci_pm_suspend_noirq(struct device *dev) | |||
540 | struct device_driver *drv = dev->driver; | 552 | struct device_driver *drv = dev->driver; |
541 | int error = 0; | 553 | int error = 0; |
542 | 554 | ||
555 | if (pci_has_legacy_pm_support(pci_dev)) | ||
556 | return pci_legacy_suspend_late(dev, PMSG_SUSPEND); | ||
557 | |||
543 | if (drv && drv->pm) { | 558 | if (drv && drv->pm) { |
544 | if (drv->pm->suspend_noirq) { | 559 | if (drv->pm->suspend_noirq) { |
545 | error = drv->pm->suspend_noirq(dev); | 560 | error = drv->pm->suspend_noirq(dev); |
546 | suspend_report_result(drv->pm->suspend_noirq, error); | 561 | suspend_report_result(drv->pm->suspend_noirq, error); |
547 | } | 562 | } |
548 | } else if (pci_has_legacy_pm_support(pci_dev)) { | ||
549 | error = pci_legacy_suspend_late(dev, PMSG_SUSPEND); | ||
550 | } else { | 563 | } else { |
551 | pci_default_pm_suspend_late(pci_dev); | 564 | pci_pm_set_unknown_state(pci_dev); |
552 | } | 565 | } |
553 | 566 | ||
554 | return error; | 567 | return error; |
@@ -560,14 +573,16 @@ static int pci_pm_resume(struct device *dev) | |||
560 | struct device_driver *drv = dev->driver; | 573 | struct device_driver *drv = dev->driver; |
561 | int error = 0; | 574 | int error = 0; |
562 | 575 | ||
576 | if (pci_has_legacy_pm_support(pci_dev)) { | ||
577 | pci_fixup_device(pci_fixup_resume, pci_dev); | ||
578 | return pci_legacy_resume(dev); | ||
579 | } | ||
580 | |||
563 | if (drv && drv->pm) { | 581 | if (drv && drv->pm) { |
564 | pci_fixup_device(pci_fixup_resume, pci_dev); | 582 | pci_fixup_device(pci_fixup_resume, pci_dev); |
565 | 583 | ||
566 | if (drv->pm->resume) | 584 | if (drv->pm->resume) |
567 | error = drv->pm->resume(dev); | 585 | error = drv->pm->resume(dev); |
568 | } else if (pci_has_legacy_pm_support(pci_dev)) { | ||
569 | pci_fixup_device(pci_fixup_resume, pci_dev); | ||
570 | error = pci_legacy_resume(dev); | ||
571 | } else { | 586 | } else { |
572 | error = pci_pm_default_resume(pci_dev); | 587 | error = pci_pm_default_resume(pci_dev); |
573 | } | 588 | } |
@@ -581,14 +596,16 @@ static int pci_pm_resume_noirq(struct device *dev) | |||
581 | struct device_driver *drv = dev->driver; | 596 | struct device_driver *drv = dev->driver; |
582 | int error = 0; | 597 | int error = 0; |
583 | 598 | ||
599 | if (pci_has_legacy_pm_support(pci_dev)) { | ||
600 | pci_fixup_device(pci_fixup_resume_early, pci_dev); | ||
601 | return pci_legacy_resume_early(dev); | ||
602 | } | ||
603 | |||
584 | if (drv && drv->pm) { | 604 | if (drv && drv->pm) { |
585 | pci_fixup_device(pci_fixup_resume_early, pci_dev); | 605 | pci_fixup_device(pci_fixup_resume_early, pci_dev); |
586 | 606 | ||
587 | if (drv->pm->resume_noirq) | 607 | if (drv->pm->resume_noirq) |
588 | error = drv->pm->resume_noirq(dev); | 608 | error = drv->pm->resume_noirq(dev); |
589 | } else if (pci_has_legacy_pm_support(pci_dev)) { | ||
590 | pci_fixup_device(pci_fixup_resume_early, pci_dev); | ||
591 | error = pci_legacy_resume_early(dev); | ||
592 | } else { | 609 | } else { |
593 | pci_pm_default_resume_noirq(pci_dev); | 610 | pci_pm_default_resume_noirq(pci_dev); |
594 | } | 611 | } |
@@ -613,14 +630,17 @@ static int pci_pm_freeze(struct device *dev) | |||
613 | struct device_driver *drv = dev->driver; | 630 | struct device_driver *drv = dev->driver; |
614 | int error = 0; | 631 | int error = 0; |
615 | 632 | ||
633 | if (pci_has_legacy_pm_support(pci_dev)) { | ||
634 | error = pci_legacy_suspend(dev, PMSG_FREEZE); | ||
635 | pci_fixup_device(pci_fixup_suspend, pci_dev); | ||
636 | return error; | ||
637 | } | ||
638 | |||
616 | if (drv && drv->pm) { | 639 | if (drv && drv->pm) { |
617 | if (drv->pm->freeze) { | 640 | if (drv->pm->freeze) { |
618 | error = drv->pm->freeze(dev); | 641 | error = drv->pm->freeze(dev); |
619 | suspend_report_result(drv->pm->freeze, error); | 642 | suspend_report_result(drv->pm->freeze, error); |
620 | } | 643 | } |
621 | } else if (pci_has_legacy_pm_support(pci_dev)) { | ||
622 | error = pci_legacy_suspend(dev, PMSG_FREEZE); | ||
623 | pci_fixup_device(pci_fixup_suspend, pci_dev); | ||
624 | } else { | 644 | } else { |
625 | pci_pm_default_suspend_generic(pci_dev); | 645 | pci_pm_default_suspend_generic(pci_dev); |
626 | } | 646 | } |
@@ -634,15 +654,16 @@ static int pci_pm_freeze_noirq(struct device *dev) | |||
634 | struct device_driver *drv = dev->driver; | 654 | struct device_driver *drv = dev->driver; |
635 | int error = 0; | 655 | int error = 0; |
636 | 656 | ||
657 | if (pci_has_legacy_pm_support(pci_dev)) | ||
658 | return pci_legacy_suspend_late(dev, PMSG_FREEZE); | ||
659 | |||
637 | if (drv && drv->pm) { | 660 | if (drv && drv->pm) { |
638 | if (drv->pm->freeze_noirq) { | 661 | if (drv->pm->freeze_noirq) { |
639 | error = drv->pm->freeze_noirq(dev); | 662 | error = drv->pm->freeze_noirq(dev); |
640 | suspend_report_result(drv->pm->freeze_noirq, error); | 663 | suspend_report_result(drv->pm->freeze_noirq, error); |
641 | } | 664 | } |
642 | } else if (pci_has_legacy_pm_support(pci_dev)) { | ||
643 | error = pci_legacy_suspend_late(dev, PMSG_FREEZE); | ||
644 | } else { | 665 | } else { |
645 | pci_default_pm_suspend_late(pci_dev); | 666 | pci_pm_set_unknown_state(pci_dev); |
646 | } | 667 | } |
647 | 668 | ||
648 | return error; | 669 | return error; |
@@ -654,14 +675,16 @@ static int pci_pm_thaw(struct device *dev) | |||
654 | struct device_driver *drv = dev->driver; | 675 | struct device_driver *drv = dev->driver; |
655 | int error = 0; | 676 | int error = 0; |
656 | 677 | ||
678 | if (pci_has_legacy_pm_support(pci_dev)) { | ||
679 | pci_fixup_device(pci_fixup_resume, pci_dev); | ||
680 | return pci_legacy_resume(dev); | ||
681 | } | ||
682 | |||
657 | if (drv && drv->pm) { | 683 | if (drv && drv->pm) { |
658 | if (drv->pm->thaw) | 684 | if (drv->pm->thaw) |
659 | error = drv->pm->thaw(dev); | 685 | error = drv->pm->thaw(dev); |
660 | } else if (pci_has_legacy_pm_support(pci_dev)) { | ||
661 | pci_fixup_device(pci_fixup_resume, pci_dev); | ||
662 | error = pci_legacy_resume(dev); | ||
663 | } else { | 686 | } else { |
664 | pci_default_pm_resume_late(pci_dev); | 687 | pci_pm_reenable_device(pci_dev); |
665 | } | 688 | } |
666 | 689 | ||
667 | return error; | 690 | return error; |
@@ -673,12 +696,14 @@ static int pci_pm_thaw_noirq(struct device *dev) | |||
673 | struct device_driver *drv = dev->driver; | 696 | struct device_driver *drv = dev->driver; |
674 | int error = 0; | 697 | int error = 0; |
675 | 698 | ||
699 | if (pci_has_legacy_pm_support(pci_dev)) { | ||
700 | pci_fixup_device(pci_fixup_resume_early, to_pci_dev(dev)); | ||
701 | return pci_legacy_resume_early(dev); | ||
702 | } | ||
703 | |||
676 | if (drv && drv->pm) { | 704 | if (drv && drv->pm) { |
677 | if (drv->pm->thaw_noirq) | 705 | if (drv->pm->thaw_noirq) |
678 | error = drv->pm->thaw_noirq(dev); | 706 | error = drv->pm->thaw_noirq(dev); |
679 | } else if (pci_has_legacy_pm_support(pci_dev)) { | ||
680 | pci_fixup_device(pci_fixup_resume_early, to_pci_dev(dev)); | ||
681 | error = pci_legacy_resume_early(dev); | ||
682 | } else { | 707 | } else { |
683 | pci_update_current_state(pci_dev, PCI_D0); | 708 | pci_update_current_state(pci_dev, PCI_D0); |
684 | } | 709 | } |
@@ -692,17 +717,21 @@ static int pci_pm_poweroff(struct device *dev) | |||
692 | struct device_driver *drv = dev->driver; | 717 | struct device_driver *drv = dev->driver; |
693 | int error = 0; | 718 | int error = 0; |
694 | 719 | ||
720 | if (pci_has_legacy_pm_support(pci_dev)) { | ||
721 | error = pci_legacy_suspend(dev, PMSG_HIBERNATE); | ||
722 | goto Exit; | ||
723 | } | ||
724 | |||
695 | if (drv && drv->pm) { | 725 | if (drv && drv->pm) { |
696 | if (drv->pm->poweroff) { | 726 | if (drv->pm->poweroff) { |
697 | error = drv->pm->poweroff(dev); | 727 | error = drv->pm->poweroff(dev); |
698 | suspend_report_result(drv->pm->poweroff, error); | 728 | suspend_report_result(drv->pm->poweroff, error); |
699 | } | 729 | } |
700 | } else if (pci_has_legacy_pm_support(pci_dev)) { | ||
701 | error = pci_legacy_suspend(dev, PMSG_HIBERNATE); | ||
702 | } else { | 730 | } else { |
703 | pci_pm_default_suspend(pci_dev); | 731 | pci_pm_default_suspend(pci_dev); |
704 | } | 732 | } |
705 | 733 | ||
734 | Exit: | ||
706 | pci_fixup_device(pci_fixup_suspend, pci_dev); | 735 | pci_fixup_device(pci_fixup_suspend, pci_dev); |
707 | 736 | ||
708 | return error; | 737 | return error; |
@@ -713,13 +742,14 @@ static int pci_pm_poweroff_noirq(struct device *dev) | |||
713 | struct device_driver *drv = dev->driver; | 742 | struct device_driver *drv = dev->driver; |
714 | int error = 0; | 743 | int error = 0; |
715 | 744 | ||
745 | if (pci_has_legacy_pm_support(to_pci_dev(dev))) | ||
746 | return pci_legacy_suspend_late(dev, PMSG_HIBERNATE); | ||
747 | |||
716 | if (drv && drv->pm) { | 748 | if (drv && drv->pm) { |
717 | if (drv->pm->poweroff_noirq) { | 749 | if (drv->pm->poweroff_noirq) { |
718 | error = drv->pm->poweroff_noirq(dev); | 750 | error = drv->pm->poweroff_noirq(dev); |
719 | suspend_report_result(drv->pm->poweroff_noirq, error); | 751 | suspend_report_result(drv->pm->poweroff_noirq, error); |
720 | } | 752 | } |
721 | } else if (pci_has_legacy_pm_support(to_pci_dev(dev))) { | ||
722 | error = pci_legacy_suspend_late(dev, PMSG_HIBERNATE); | ||
723 | } | 753 | } |
724 | 754 | ||
725 | return error; | 755 | return error; |
@@ -731,14 +761,16 @@ static int pci_pm_restore(struct device *dev) | |||
731 | struct device_driver *drv = dev->driver; | 761 | struct device_driver *drv = dev->driver; |
732 | int error = 0; | 762 | int error = 0; |
733 | 763 | ||
764 | if (pci_has_legacy_pm_support(pci_dev)) { | ||
765 | pci_fixup_device(pci_fixup_resume, pci_dev); | ||
766 | return pci_legacy_resume(dev); | ||
767 | } | ||
768 | |||
734 | if (drv && drv->pm) { | 769 | if (drv && drv->pm) { |
735 | pci_fixup_device(pci_fixup_resume, pci_dev); | 770 | pci_fixup_device(pci_fixup_resume, pci_dev); |
736 | 771 | ||
737 | if (drv->pm->restore) | 772 | if (drv->pm->restore) |
738 | error = drv->pm->restore(dev); | 773 | error = drv->pm->restore(dev); |
739 | } else if (pci_has_legacy_pm_support(pci_dev)) { | ||
740 | pci_fixup_device(pci_fixup_resume, pci_dev); | ||
741 | error = pci_legacy_resume(dev); | ||
742 | } else { | 774 | } else { |
743 | error = pci_pm_default_resume(pci_dev); | 775 | error = pci_pm_default_resume(pci_dev); |
744 | } | 776 | } |
@@ -752,14 +784,16 @@ static int pci_pm_restore_noirq(struct device *dev) | |||
752 | struct device_driver *drv = dev->driver; | 784 | struct device_driver *drv = dev->driver; |
753 | int error = 0; | 785 | int error = 0; |
754 | 786 | ||
787 | if (pci_has_legacy_pm_support(pci_dev)) { | ||
788 | pci_fixup_device(pci_fixup_resume_early, pci_dev); | ||
789 | return pci_legacy_resume_early(dev); | ||
790 | } | ||
791 | |||
755 | if (drv && drv->pm) { | 792 | if (drv && drv->pm) { |
756 | pci_fixup_device(pci_fixup_resume_early, pci_dev); | 793 | pci_fixup_device(pci_fixup_resume_early, pci_dev); |
757 | 794 | ||
758 | if (drv->pm->restore_noirq) | 795 | if (drv->pm->restore_noirq) |
759 | error = drv->pm->restore_noirq(dev); | 796 | error = drv->pm->restore_noirq(dev); |
760 | } else if (pci_has_legacy_pm_support(pci_dev)) { | ||
761 | pci_fixup_device(pci_fixup_resume_early, pci_dev); | ||
762 | error = pci_legacy_resume_early(dev); | ||
763 | } else { | 797 | } else { |
764 | pci_pm_default_resume_noirq(pci_dev); | 798 | pci_pm_default_resume_noirq(pci_dev); |
765 | } | 799 | } |