diff options
| -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 | } |
