diff options
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/pci-driver.c | 145 |
1 files changed, 93 insertions, 52 deletions
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index ac6c9e493f4c..93eac1423585 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c | |||
@@ -430,39 +430,22 @@ static void pci_pm_default_resume_noirq(struct pci_dev *pci_dev) | |||
430 | pci_fixup_device(pci_fixup_resume_early, pci_dev); | 430 | pci_fixup_device(pci_fixup_resume_early, pci_dev); |
431 | } | 431 | } |
432 | 432 | ||
433 | static int pci_pm_default_resume(struct pci_dev *pci_dev) | 433 | static void pci_pm_default_resume(struct pci_dev *pci_dev) |
434 | { | 434 | { |
435 | pci_fixup_device(pci_fixup_resume, pci_dev); | 435 | pci_fixup_device(pci_fixup_resume, pci_dev); |
436 | 436 | ||
437 | if (pci_is_bridge(pci_dev)) | 437 | if (!pci_is_bridge(pci_dev)) |
438 | return 0; | 438 | pci_enable_wake(pci_dev, PCI_D0, false); |
439 | |||
440 | pci_enable_wake(pci_dev, PCI_D0, false); | ||
441 | return pci_pm_reenable_device(pci_dev); | ||
442 | } | 439 | } |
443 | 440 | ||
444 | static void pci_pm_default_suspend_generic(struct pci_dev *pci_dev) | 441 | static void pci_pm_default_suspend(struct pci_dev *pci_dev) |
445 | { | 442 | { |
446 | /* If a non-bridge device is enabled at this point, disable it */ | 443 | /* Disable non-bridge devices without PM support */ |
447 | if (!pci_is_bridge(pci_dev)) | 444 | if (!pci_is_bridge(pci_dev)) |
448 | pci_disable_enabled_device(pci_dev); | 445 | pci_disable_enabled_device(pci_dev); |
449 | /* | ||
450 | * Save state with interrupts enabled, because in principle the bus the | ||
451 | * device is on may be put into a low power state after this code runs. | ||
452 | */ | ||
453 | pci_save_state(pci_dev); | 446 | pci_save_state(pci_dev); |
454 | } | 447 | } |
455 | 448 | ||
456 | static void pci_pm_default_suspend(struct pci_dev *pci_dev, bool prepare) | ||
457 | { | ||
458 | pci_pm_default_suspend_generic(pci_dev); | ||
459 | |||
460 | if (prepare && !pci_is_bridge(pci_dev)) | ||
461 | pci_prepare_to_sleep(pci_dev); | ||
462 | |||
463 | pci_fixup_device(pci_fixup_suspend, pci_dev); | ||
464 | } | ||
465 | |||
466 | static bool pci_has_legacy_pm_support(struct pci_dev *pci_dev) | 449 | static bool pci_has_legacy_pm_support(struct pci_dev *pci_dev) |
467 | { | 450 | { |
468 | struct pci_driver *drv = pci_dev->driver; | 451 | struct pci_driver *drv = pci_dev->driver; |
@@ -506,20 +489,48 @@ static int pci_pm_suspend(struct device *dev) | |||
506 | { | 489 | { |
507 | struct pci_dev *pci_dev = to_pci_dev(dev); | 490 | struct pci_dev *pci_dev = to_pci_dev(dev); |
508 | struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; | 491 | struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; |
509 | int error = 0; | ||
510 | 492 | ||
511 | if (pci_has_legacy_pm_support(pci_dev)) | 493 | if (pci_has_legacy_pm_support(pci_dev)) |
512 | return pci_legacy_suspend(dev, PMSG_SUSPEND); | 494 | return pci_legacy_suspend(dev, PMSG_SUSPEND); |
513 | 495 | ||
514 | if (pm && pm->suspend) { | 496 | if (!pm) { |
497 | pci_pm_default_suspend(pci_dev); | ||
498 | goto Fixup; | ||
499 | } | ||
500 | |||
501 | pci_dev->state_saved = false; | ||
502 | |||
503 | if (pm->suspend) { | ||
504 | pci_power_t prev = pci_dev->current_state; | ||
505 | int error; | ||
506 | |||
515 | error = pm->suspend(dev); | 507 | error = pm->suspend(dev); |
516 | suspend_report_result(pm->suspend, error); | 508 | suspend_report_result(pm->suspend, error); |
509 | if (error) | ||
510 | return error; | ||
511 | |||
512 | if (pci_dev->state_saved) | ||
513 | goto Fixup; | ||
514 | |||
515 | if (pci_dev->current_state != PCI_D0 | ||
516 | && pci_dev->current_state != PCI_UNKNOWN) { | ||
517 | WARN_ONCE(pci_dev->current_state != prev, | ||
518 | "PCI PM: State of device not saved by %pF\n", | ||
519 | pm->suspend); | ||
520 | goto Fixup; | ||
521 | } | ||
517 | } | 522 | } |
518 | 523 | ||
519 | if (!error) | 524 | if (!pci_dev->state_saved) { |
520 | pci_pm_default_suspend(pci_dev, !!pm); | 525 | pci_save_state(pci_dev); |
526 | if (!pci_is_bridge(pci_dev)) | ||
527 | pci_prepare_to_sleep(pci_dev); | ||
528 | } | ||
521 | 529 | ||
522 | return error; | 530 | Fixup: |
531 | pci_fixup_device(pci_fixup_suspend, pci_dev); | ||
532 | |||
533 | return 0; | ||
523 | } | 534 | } |
524 | 535 | ||
525 | static int pci_pm_suspend_noirq(struct device *dev) | 536 | static int pci_pm_suspend_noirq(struct device *dev) |
@@ -562,7 +573,7 @@ static int pci_pm_resume_noirq(struct device *dev) | |||
562 | static int pci_pm_resume(struct device *dev) | 573 | static int pci_pm_resume(struct device *dev) |
563 | { | 574 | { |
564 | struct pci_dev *pci_dev = to_pci_dev(dev); | 575 | struct pci_dev *pci_dev = to_pci_dev(dev); |
565 | struct device_driver *drv = dev->driver; | 576 | struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; |
566 | int error = 0; | 577 | int error = 0; |
567 | 578 | ||
568 | /* | 579 | /* |
@@ -575,12 +586,16 @@ static int pci_pm_resume(struct device *dev) | |||
575 | if (pci_has_legacy_pm_support(pci_dev)) | 586 | if (pci_has_legacy_pm_support(pci_dev)) |
576 | return pci_legacy_resume(dev); | 587 | return pci_legacy_resume(dev); |
577 | 588 | ||
578 | error = pci_pm_default_resume(pci_dev); | 589 | pci_pm_default_resume(pci_dev); |
579 | 590 | ||
580 | if (!error && drv && drv->pm && drv->pm->resume) | 591 | if (pm) { |
581 | error = drv->pm->resume(dev); | 592 | if (pm->resume) |
593 | error = pm->resume(dev); | ||
594 | } else { | ||
595 | pci_pm_reenable_device(pci_dev); | ||
596 | } | ||
582 | 597 | ||
583 | return error; | 598 | return 0; |
584 | } | 599 | } |
585 | 600 | ||
586 | #else /* !CONFIG_SUSPEND */ | 601 | #else /* !CONFIG_SUSPEND */ |
@@ -597,21 +612,31 @@ static int pci_pm_resume(struct device *dev) | |||
597 | static int pci_pm_freeze(struct device *dev) | 612 | static int pci_pm_freeze(struct device *dev) |
598 | { | 613 | { |
599 | struct pci_dev *pci_dev = to_pci_dev(dev); | 614 | struct pci_dev *pci_dev = to_pci_dev(dev); |
600 | struct device_driver *drv = dev->driver; | 615 | struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; |
601 | int error = 0; | ||
602 | 616 | ||
603 | if (pci_has_legacy_pm_support(pci_dev)) | 617 | if (pci_has_legacy_pm_support(pci_dev)) |
604 | return pci_legacy_suspend(dev, PMSG_FREEZE); | 618 | return pci_legacy_suspend(dev, PMSG_FREEZE); |
605 | 619 | ||
606 | if (drv && drv->pm && drv->pm->freeze) { | 620 | if (!pm) { |
607 | error = drv->pm->freeze(dev); | 621 | pci_pm_default_suspend(pci_dev); |
608 | suspend_report_result(drv->pm->freeze, error); | 622 | return 0; |
609 | } | 623 | } |
610 | 624 | ||
611 | if (!error) | 625 | pci_dev->state_saved = false; |
612 | pci_pm_default_suspend_generic(pci_dev); | ||
613 | 626 | ||
614 | return error; | 627 | if (pm->freeze) { |
628 | int error; | ||
629 | |||
630 | error = pm->freeze(dev); | ||
631 | suspend_report_result(pm->freeze, error); | ||
632 | if (error) | ||
633 | return error; | ||
634 | } | ||
635 | |||
636 | if (!pci_dev->state_saved) | ||
637 | pci_save_state(pci_dev); | ||
638 | |||
639 | return 0; | ||
615 | } | 640 | } |
616 | 641 | ||
617 | static int pci_pm_freeze_noirq(struct device *dev) | 642 | static int pci_pm_freeze_noirq(struct device *dev) |
@@ -654,16 +679,18 @@ static int pci_pm_thaw_noirq(struct device *dev) | |||
654 | static int pci_pm_thaw(struct device *dev) | 679 | static int pci_pm_thaw(struct device *dev) |
655 | { | 680 | { |
656 | struct pci_dev *pci_dev = to_pci_dev(dev); | 681 | struct pci_dev *pci_dev = to_pci_dev(dev); |
657 | struct device_driver *drv = dev->driver; | 682 | struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; |
658 | int error = 0; | 683 | int error = 0; |
659 | 684 | ||
660 | if (pci_has_legacy_pm_support(pci_dev)) | 685 | if (pci_has_legacy_pm_support(pci_dev)) |
661 | return pci_legacy_resume(dev); | 686 | return pci_legacy_resume(dev); |
662 | 687 | ||
663 | pci_pm_reenable_device(pci_dev); | 688 | if (pm) { |
664 | 689 | if (pm->thaw) | |
665 | if (drv && drv->pm && drv->pm->thaw) | 690 | error = pm->thaw(dev); |
666 | error = drv->pm->thaw(dev); | 691 | } else { |
692 | pci_pm_reenable_device(pci_dev); | ||
693 | } | ||
667 | 694 | ||
668 | return error; | 695 | return error; |
669 | } | 696 | } |
@@ -677,13 +704,23 @@ static int pci_pm_poweroff(struct device *dev) | |||
677 | if (pci_has_legacy_pm_support(pci_dev)) | 704 | if (pci_has_legacy_pm_support(pci_dev)) |
678 | return pci_legacy_suspend(dev, PMSG_HIBERNATE); | 705 | return pci_legacy_suspend(dev, PMSG_HIBERNATE); |
679 | 706 | ||
680 | if (pm && pm->poweroff) { | 707 | if (!pm) { |
708 | pci_pm_default_suspend(pci_dev); | ||
709 | goto Fixup; | ||
710 | } | ||
711 | |||
712 | pci_dev->state_saved = false; | ||
713 | |||
714 | if (pm->poweroff) { | ||
681 | error = pm->poweroff(dev); | 715 | error = pm->poweroff(dev); |
682 | suspend_report_result(pm->poweroff, error); | 716 | suspend_report_result(pm->poweroff, error); |
683 | } | 717 | } |
684 | 718 | ||
685 | if (!error) | 719 | if (!pci_dev->state_saved && !pci_is_bridge(pci_dev)) |
686 | pci_pm_default_suspend(pci_dev, !!pm); | 720 | pci_prepare_to_sleep(pci_dev); |
721 | |||
722 | Fixup: | ||
723 | pci_fixup_device(pci_fixup_suspend, pci_dev); | ||
687 | 724 | ||
688 | return error; | 725 | return error; |
689 | } | 726 | } |
@@ -724,7 +761,7 @@ static int pci_pm_restore_noirq(struct device *dev) | |||
724 | static int pci_pm_restore(struct device *dev) | 761 | static int pci_pm_restore(struct device *dev) |
725 | { | 762 | { |
726 | struct pci_dev *pci_dev = to_pci_dev(dev); | 763 | struct pci_dev *pci_dev = to_pci_dev(dev); |
727 | struct device_driver *drv = dev->driver; | 764 | struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; |
728 | int error = 0; | 765 | int error = 0; |
729 | 766 | ||
730 | /* | 767 | /* |
@@ -737,10 +774,14 @@ static int pci_pm_restore(struct device *dev) | |||
737 | if (pci_has_legacy_pm_support(pci_dev)) | 774 | if (pci_has_legacy_pm_support(pci_dev)) |
738 | return pci_legacy_resume(dev); | 775 | return pci_legacy_resume(dev); |
739 | 776 | ||
740 | error = pci_pm_default_resume(pci_dev); | 777 | pci_pm_default_resume(pci_dev); |
741 | 778 | ||
742 | if (!error && drv && drv->pm && drv->pm->restore) | 779 | if (pm) { |
743 | error = drv->pm->restore(dev); | 780 | if (pm->restore) |
781 | error = pm->restore(dev); | ||
782 | } else { | ||
783 | pci_pm_reenable_device(pci_dev); | ||
784 | } | ||
744 | 785 | ||
745 | return error; | 786 | return error; |
746 | } | 787 | } |