diff options
author | Bjorn Helgaas <bhelgaas@google.com> | 2012-06-23 13:59:43 -0400 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2012-06-23 13:59:43 -0400 |
commit | 35e7f73c32ad44a931d918d04e317a7fb0c63e6e (patch) | |
tree | e3cb8c89c8230aaa45a0f1b101decdc3b9831938 /drivers/pci/pci.c | |
parent | e5028b52e46eb1379d78d136bd0890705f331183 (diff) | |
parent | 448bd857d48e69b33ef323739dc6d8ca20d4cda7 (diff) |
Merge branch 'topic/huang-d3cold-v7' into next
* topic/huang-d3cold-v7:
PCI/PM: add PCIe runtime D3cold support
PCI: do not call pci_set_power_state with PCI_D3cold
PCI/PM: add runtime PM support to PCIe port
ACPI/PM: specify lowest allowed state for device sleep state
Diffstat (limited to 'drivers/pci/pci.c')
-rw-r--r-- | drivers/pci/pci.c | 124 |
1 files changed, 115 insertions, 9 deletions
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 87928fde77b0..3f8b74f07147 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c | |||
@@ -587,7 +587,8 @@ static int pci_raw_set_power_state(struct pci_dev *dev, pci_power_t state) | |||
587 | dev_info(&dev->dev, "Refused to change power state, " | 587 | dev_info(&dev->dev, "Refused to change power state, " |
588 | "currently in D%d\n", dev->current_state); | 588 | "currently in D%d\n", dev->current_state); |
589 | 589 | ||
590 | /* According to section 5.4.1 of the "PCI BUS POWER MANAGEMENT | 590 | /* |
591 | * According to section 5.4.1 of the "PCI BUS POWER MANAGEMENT | ||
591 | * INTERFACE SPECIFICATION, REV. 1.2", a device transitioning | 592 | * INTERFACE SPECIFICATION, REV. 1.2", a device transitioning |
592 | * from D3hot to D0 _may_ perform an internal reset, thereby | 593 | * from D3hot to D0 _may_ perform an internal reset, thereby |
593 | * going to "D0 Uninitialized" rather than "D0 Initialized". | 594 | * going to "D0 Uninitialized" rather than "D0 Initialized". |
@@ -619,6 +620,16 @@ void pci_update_current_state(struct pci_dev *dev, pci_power_t state) | |||
619 | if (dev->pm_cap) { | 620 | if (dev->pm_cap) { |
620 | u16 pmcsr; | 621 | u16 pmcsr; |
621 | 622 | ||
623 | /* | ||
624 | * Configuration space is not accessible for device in | ||
625 | * D3cold, so just keep or set D3cold for safety | ||
626 | */ | ||
627 | if (dev->current_state == PCI_D3cold) | ||
628 | return; | ||
629 | if (state == PCI_D3cold) { | ||
630 | dev->current_state = PCI_D3cold; | ||
631 | return; | ||
632 | } | ||
622 | pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr); | 633 | pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr); |
623 | dev->current_state = (pmcsr & PCI_PM_CTRL_STATE_MASK); | 634 | dev->current_state = (pmcsr & PCI_PM_CTRL_STATE_MASK); |
624 | } else { | 635 | } else { |
@@ -659,8 +670,50 @@ static int pci_platform_power_transition(struct pci_dev *dev, pci_power_t state) | |||
659 | */ | 670 | */ |
660 | static void __pci_start_power_transition(struct pci_dev *dev, pci_power_t state) | 671 | static void __pci_start_power_transition(struct pci_dev *dev, pci_power_t state) |
661 | { | 672 | { |
662 | if (state == PCI_D0) | 673 | if (state == PCI_D0) { |
663 | pci_platform_power_transition(dev, PCI_D0); | 674 | pci_platform_power_transition(dev, PCI_D0); |
675 | /* | ||
676 | * Mandatory power management transition delays, see | ||
677 | * PCI Express Base Specification Revision 2.0 Section | ||
678 | * 6.6.1: Conventional Reset. Do not delay for | ||
679 | * devices powered on/off by corresponding bridge, | ||
680 | * because have already delayed for the bridge. | ||
681 | */ | ||
682 | if (dev->runtime_d3cold) { | ||
683 | msleep(dev->d3cold_delay); | ||
684 | /* | ||
685 | * When powering on a bridge from D3cold, the | ||
686 | * whole hierarchy may be powered on into | ||
687 | * D0uninitialized state, resume them to give | ||
688 | * them a chance to suspend again | ||
689 | */ | ||
690 | pci_wakeup_bus(dev->subordinate); | ||
691 | } | ||
692 | } | ||
693 | } | ||
694 | |||
695 | /** | ||
696 | * __pci_dev_set_current_state - Set current state of a PCI device | ||
697 | * @dev: Device to handle | ||
698 | * @data: pointer to state to be set | ||
699 | */ | ||
700 | static int __pci_dev_set_current_state(struct pci_dev *dev, void *data) | ||
701 | { | ||
702 | pci_power_t state = *(pci_power_t *)data; | ||
703 | |||
704 | dev->current_state = state; | ||
705 | return 0; | ||
706 | } | ||
707 | |||
708 | /** | ||
709 | * __pci_bus_set_current_state - Walk given bus and set current state of devices | ||
710 | * @bus: Top bus of the subtree to walk. | ||
711 | * @state: state to be set | ||
712 | */ | ||
713 | static void __pci_bus_set_current_state(struct pci_bus *bus, pci_power_t state) | ||
714 | { | ||
715 | if (bus) | ||
716 | pci_walk_bus(bus, __pci_dev_set_current_state, &state); | ||
664 | } | 717 | } |
665 | 718 | ||
666 | /** | 719 | /** |
@@ -672,8 +725,15 @@ static void __pci_start_power_transition(struct pci_dev *dev, pci_power_t state) | |||
672 | */ | 725 | */ |
673 | int __pci_complete_power_transition(struct pci_dev *dev, pci_power_t state) | 726 | int __pci_complete_power_transition(struct pci_dev *dev, pci_power_t state) |
674 | { | 727 | { |
675 | return state >= PCI_D0 ? | 728 | int ret; |
676 | pci_platform_power_transition(dev, state) : -EINVAL; | 729 | |
730 | if (state < PCI_D0) | ||
731 | return -EINVAL; | ||
732 | ret = pci_platform_power_transition(dev, state); | ||
733 | /* Power off the bridge may power off the whole hierarchy */ | ||
734 | if (!ret && state == PCI_D3cold) | ||
735 | __pci_bus_set_current_state(dev->subordinate, PCI_D3cold); | ||
736 | return ret; | ||
677 | } | 737 | } |
678 | EXPORT_SYMBOL_GPL(__pci_complete_power_transition); | 738 | EXPORT_SYMBOL_GPL(__pci_complete_power_transition); |
679 | 739 | ||
@@ -697,8 +757,8 @@ int pci_set_power_state(struct pci_dev *dev, pci_power_t state) | |||
697 | int error; | 757 | int error; |
698 | 758 | ||
699 | /* bound the state we're entering */ | 759 | /* bound the state we're entering */ |
700 | if (state > PCI_D3hot) | 760 | if (state > PCI_D3cold) |
701 | state = PCI_D3hot; | 761 | state = PCI_D3cold; |
702 | else if (state < PCI_D0) | 762 | else if (state < PCI_D0) |
703 | state = PCI_D0; | 763 | state = PCI_D0; |
704 | else if ((state == PCI_D1 || state == PCI_D2) && pci_no_d1d2(dev)) | 764 | else if ((state == PCI_D1 || state == PCI_D2) && pci_no_d1d2(dev)) |
@@ -713,10 +773,15 @@ int pci_set_power_state(struct pci_dev *dev, pci_power_t state) | |||
713 | 773 | ||
714 | /* This device is quirked not to be put into D3, so | 774 | /* This device is quirked not to be put into D3, so |
715 | don't put it in D3 */ | 775 | don't put it in D3 */ |
716 | if (state == PCI_D3hot && (dev->dev_flags & PCI_DEV_FLAGS_NO_D3)) | 776 | if (state >= PCI_D3hot && (dev->dev_flags & PCI_DEV_FLAGS_NO_D3)) |
717 | return 0; | 777 | return 0; |
718 | 778 | ||
719 | error = pci_raw_set_power_state(dev, state); | 779 | /* |
780 | * To put device in D3cold, we put device into D3hot in native | ||
781 | * way, then put device into D3cold with platform ops | ||
782 | */ | ||
783 | error = pci_raw_set_power_state(dev, state > PCI_D3hot ? | ||
784 | PCI_D3hot : state); | ||
720 | 785 | ||
721 | if (!__pci_complete_power_transition(dev, state)) | 786 | if (!__pci_complete_power_transition(dev, state)) |
722 | error = 0; | 787 | error = 0; |
@@ -1460,6 +1525,28 @@ void pci_pme_wakeup_bus(struct pci_bus *bus) | |||
1460 | } | 1525 | } |
1461 | 1526 | ||
1462 | /** | 1527 | /** |
1528 | * pci_wakeup - Wake up a PCI device | ||
1529 | * @dev: Device to handle. | ||
1530 | * @ign: ignored parameter | ||
1531 | */ | ||
1532 | static int pci_wakeup(struct pci_dev *pci_dev, void *ign) | ||
1533 | { | ||
1534 | pci_wakeup_event(pci_dev); | ||
1535 | pm_request_resume(&pci_dev->dev); | ||
1536 | return 0; | ||
1537 | } | ||
1538 | |||
1539 | /** | ||
1540 | * pci_wakeup_bus - Walk given bus and wake up devices on it | ||
1541 | * @bus: Top bus of the subtree to walk. | ||
1542 | */ | ||
1543 | void pci_wakeup_bus(struct pci_bus *bus) | ||
1544 | { | ||
1545 | if (bus) | ||
1546 | pci_walk_bus(bus, pci_wakeup, NULL); | ||
1547 | } | ||
1548 | |||
1549 | /** | ||
1463 | * pci_pme_capable - check the capability of PCI device to generate PME# | 1550 | * pci_pme_capable - check the capability of PCI device to generate PME# |
1464 | * @dev: PCI device to handle. | 1551 | * @dev: PCI device to handle. |
1465 | * @state: PCI state from which device will issue PME#. | 1552 | * @state: PCI state from which device will issue PME#. |
@@ -1480,6 +1567,16 @@ static void pci_pme_list_scan(struct work_struct *work) | |||
1480 | if (!list_empty(&pci_pme_list)) { | 1567 | if (!list_empty(&pci_pme_list)) { |
1481 | list_for_each_entry_safe(pme_dev, n, &pci_pme_list, list) { | 1568 | list_for_each_entry_safe(pme_dev, n, &pci_pme_list, list) { |
1482 | if (pme_dev->dev->pme_poll) { | 1569 | if (pme_dev->dev->pme_poll) { |
1570 | struct pci_dev *bridge; | ||
1571 | |||
1572 | bridge = pme_dev->dev->bus->self; | ||
1573 | /* | ||
1574 | * If bridge is in low power state, the | ||
1575 | * configuration space of subordinate devices | ||
1576 | * may be not accessible | ||
1577 | */ | ||
1578 | if (bridge && bridge->current_state != PCI_D0) | ||
1579 | continue; | ||
1483 | pci_pme_wakeup(pme_dev->dev, NULL); | 1580 | pci_pme_wakeup(pme_dev->dev, NULL); |
1484 | } else { | 1581 | } else { |
1485 | list_del(&pme_dev->list); | 1582 | list_del(&pme_dev->list); |
@@ -1706,6 +1803,10 @@ int pci_prepare_to_sleep(struct pci_dev *dev) | |||
1706 | if (target_state == PCI_POWER_ERROR) | 1803 | if (target_state == PCI_POWER_ERROR) |
1707 | return -EIO; | 1804 | return -EIO; |
1708 | 1805 | ||
1806 | /* D3cold during system suspend/hibernate is not supported */ | ||
1807 | if (target_state > PCI_D3hot) | ||
1808 | target_state = PCI_D3hot; | ||
1809 | |||
1709 | pci_enable_wake(dev, target_state, device_may_wakeup(&dev->dev)); | 1810 | pci_enable_wake(dev, target_state, device_may_wakeup(&dev->dev)); |
1710 | 1811 | ||
1711 | error = pci_set_power_state(dev, target_state); | 1812 | error = pci_set_power_state(dev, target_state); |
@@ -1743,12 +1844,16 @@ int pci_finish_runtime_suspend(struct pci_dev *dev) | |||
1743 | if (target_state == PCI_POWER_ERROR) | 1844 | if (target_state == PCI_POWER_ERROR) |
1744 | return -EIO; | 1845 | return -EIO; |
1745 | 1846 | ||
1847 | dev->runtime_d3cold = target_state == PCI_D3cold; | ||
1848 | |||
1746 | __pci_enable_wake(dev, target_state, true, pci_dev_run_wake(dev)); | 1849 | __pci_enable_wake(dev, target_state, true, pci_dev_run_wake(dev)); |
1747 | 1850 | ||
1748 | error = pci_set_power_state(dev, target_state); | 1851 | error = pci_set_power_state(dev, target_state); |
1749 | 1852 | ||
1750 | if (error) | 1853 | if (error) { |
1751 | __pci_enable_wake(dev, target_state, true, false); | 1854 | __pci_enable_wake(dev, target_state, true, false); |
1855 | dev->runtime_d3cold = false; | ||
1856 | } | ||
1752 | 1857 | ||
1753 | return error; | 1858 | return error; |
1754 | } | 1859 | } |
@@ -1818,6 +1923,7 @@ void pci_pm_init(struct pci_dev *dev) | |||
1818 | 1923 | ||
1819 | dev->pm_cap = pm; | 1924 | dev->pm_cap = pm; |
1820 | dev->d3_delay = PCI_PM_D3_WAIT; | 1925 | dev->d3_delay = PCI_PM_D3_WAIT; |
1926 | dev->d3cold_delay = PCI_PM_D3COLD_WAIT; | ||
1821 | 1927 | ||
1822 | dev->d1_support = false; | 1928 | dev->d1_support = false; |
1823 | dev->d2_support = false; | 1929 | dev->d2_support = false; |