aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci
diff options
context:
space:
mode:
authorNaga Chumbalkar <nagananda.chumbalkar@hp.com>2011-03-20 23:29:08 -0400
committerJesse Barnes <jbarnes@virtuousgeek.org>2011-03-21 12:40:43 -0400
commit1a680b7c325882188865f05b9a88d32f75f26495 (patch)
treeeb3844655f9ff01630157e4b2c039759970b1a94 /drivers/pci
parent8b8bae901ce23addbdcdb54fa1696fb2d049feb5 (diff)
PCI: PCIe links may not get configured for ASPM under POWERSAVE mode
v3 -> v2: Moved ASPM enabling logic to pci_set_power_state() v2 -> v1: Preserved the logic in pci_raw_set_power_state() : Added ASPM enabling logic after scanning Root Bridge : http://marc.info/?l=linux-pci&m=130046996216391&w=2 v1 : http://marc.info/?l=linux-pci&m=130013164703283&w=2 The assumption made in commit 41cd766b065970ff6f6c89dd1cf55fa706c84a3d (PCI: Don't enable aspm before drivers have had a chance to veto it) that pci_enable_device() will result in re-configuring ASPM when aspm_policy is POWERSAVE is no longer valid. This is due to commit 97c145f7c87453cec90e91238fba5fe2c1561b32 (PCI: read current power state at enable time) which resets dev->current_state to D0. Due to this the call to pcie_aspm_pm_state_change() is never made. Note the equality check (below) that returns early: ./drivers/pci/pci.c: pci_raw_set_pci_power_state() 546 /* Check if we're already there */ 547 if (dev->current_state == state) 548 return 0; Therefore OSPM never configures the PCIe links for ASPM to turn them "on". Fix it by configuring ASPM from the pci_enable_device() code path. This also allows a driver such as the e1000e networking driver a chance to disable ASPM (L0s, L1), if need be, prior to enabling the device. A driver may perform this action if the device is known to mis-behave wrt ASPM. Signed-off-by: Naga Chumbalkar <nagananda.chumbalkar@hp.com> Acked-by: Rafael J. Wysocki <rjw@sisk.pl> Cc: Matthew Garrett <mjg59@srcf.ucam.org> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/pci.c6
-rw-r--r--drivers/pci/pcie/aspm.c22
2 files changed, 28 insertions, 0 deletions
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index b714d787bddd..2472e7177b4b 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -740,6 +740,12 @@ int pci_set_power_state(struct pci_dev *dev, pci_power_t state)
740 740
741 if (!__pci_complete_power_transition(dev, state)) 741 if (!__pci_complete_power_transition(dev, state))
742 error = 0; 742 error = 0;
743 /*
744 * When aspm_policy is "powersave" this call ensures
745 * that ASPM is configured.
746 */
747 if (!error && dev->bus->self)
748 pcie_aspm_powersave_config_link(dev->bus->self);
743 749
744 return error; 750 return error;
745} 751}
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
index bbdb4fd85b9c..e61b82e611c2 100644
--- a/drivers/pci/pcie/aspm.c
+++ b/drivers/pci/pcie/aspm.c
@@ -708,6 +708,28 @@ void pcie_aspm_pm_state_change(struct pci_dev *pdev)
708 up_read(&pci_bus_sem); 708 up_read(&pci_bus_sem);
709} 709}
710 710
711void pcie_aspm_powersave_config_link(struct pci_dev *pdev)
712{
713 struct pcie_link_state *link = pdev->link_state;
714
715 if (aspm_disabled || !pci_is_pcie(pdev) || !link)
716 return;
717
718 if (aspm_policy != POLICY_POWERSAVE)
719 return;
720
721 if ((pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT) &&
722 (pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM))
723 return;
724
725 down_read(&pci_bus_sem);
726 mutex_lock(&aspm_lock);
727 pcie_config_aspm_path(link);
728 pcie_set_clkpm(link, policy_to_clkpm_state(link));
729 mutex_unlock(&aspm_lock);
730 up_read(&pci_bus_sem);
731}
732
711/* 733/*
712 * pci_disable_link_state - disable pci device's link state, so the link will 734 * pci_disable_link_state - disable pci device's link state, so the link will
713 * never enter specific states 735 * never enter specific states