diff options
author | Matthew Garrett <mjg@redhat.com> | 2010-12-06 14:00:56 -0500 |
---|---|---|
committer | Jesse Barnes <jbarnes@virtuousgeek.org> | 2010-12-23 15:53:08 -0500 |
commit | 2f671e2dbff6eb5ef4e2600adbec550c13b8fe72 (patch) | |
tree | fb5debb042218dcf1cbdf11eb4d8d603208c219f /drivers/pci/pcie/aspm.c | |
parent | 8d805286968811223cca002134ba3d81244d5313 (diff) |
PCI: Disable ASPM if BIOS asks us to
We currently refuse to touch the ASPM registers if the BIOS tells us that
ASPM isn't supported. This can cause problems if the BIOS has (for any
reason) enabled ASPM on some devices anyway. Change the code such that we
explicitly clear ASPM if the FADT indicates that ASPM isn't supported,
and make sure we tidy up appropriately on device removal in order to deal
with the hotplug case. If ASPM is disabled because the BIOS doesn't hand
over control then we won't touch the registers.
Signed-off-by: Matthew Garrett <mjg@redhat.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers/pci/pcie/aspm.c')
-rw-r--r-- | drivers/pci/pcie/aspm.c | 21 |
1 files changed, 17 insertions, 4 deletions
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 71222814c1ec..3188cd96b338 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c | |||
@@ -68,7 +68,7 @@ struct pcie_link_state { | |||
68 | struct aspm_latency acceptable[8]; | 68 | struct aspm_latency acceptable[8]; |
69 | }; | 69 | }; |
70 | 70 | ||
71 | static int aspm_disabled, aspm_force; | 71 | static int aspm_disabled, aspm_force, aspm_clear_state; |
72 | static DEFINE_MUTEX(aspm_lock); | 72 | static DEFINE_MUTEX(aspm_lock); |
73 | static LIST_HEAD(link_list); | 73 | static LIST_HEAD(link_list); |
74 | 74 | ||
@@ -139,7 +139,7 @@ static void pcie_set_clkpm(struct pcie_link_state *link, int enable) | |||
139 | { | 139 | { |
140 | /* Don't enable Clock PM if the link is not Clock PM capable */ | 140 | /* Don't enable Clock PM if the link is not Clock PM capable */ |
141 | if (!link->clkpm_capable && enable) | 141 | if (!link->clkpm_capable && enable) |
142 | return; | 142 | enable = 0; |
143 | /* Need nothing if the specified equals to current state */ | 143 | /* Need nothing if the specified equals to current state */ |
144 | if (link->clkpm_enabled == enable) | 144 | if (link->clkpm_enabled == enable) |
145 | return; | 145 | return; |
@@ -498,6 +498,10 @@ static int pcie_aspm_sanity_check(struct pci_dev *pdev) | |||
498 | struct pci_dev *child; | 498 | struct pci_dev *child; |
499 | int pos; | 499 | int pos; |
500 | u32 reg32; | 500 | u32 reg32; |
501 | |||
502 | if (aspm_clear_state) | ||
503 | return -EINVAL; | ||
504 | |||
501 | /* | 505 | /* |
502 | * Some functions in a slot might not all be PCIe functions, | 506 | * Some functions in a slot might not all be PCIe functions, |
503 | * very strange. Disable ASPM for the whole slot | 507 | * very strange. Disable ASPM for the whole slot |
@@ -563,12 +567,15 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev) | |||
563 | struct pcie_link_state *link; | 567 | struct pcie_link_state *link; |
564 | int blacklist = !!pcie_aspm_sanity_check(pdev); | 568 | int blacklist = !!pcie_aspm_sanity_check(pdev); |
565 | 569 | ||
566 | if (aspm_disabled || !pci_is_pcie(pdev) || pdev->link_state) | 570 | if (!pci_is_pcie(pdev) || pdev->link_state) |
567 | return; | 571 | return; |
568 | if (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT && | 572 | if (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT && |
569 | pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM) | 573 | pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM) |
570 | return; | 574 | return; |
571 | 575 | ||
576 | if (aspm_disabled && !aspm_clear_state) | ||
577 | return; | ||
578 | |||
572 | /* VIA has a strange chipset, root port is under a bridge */ | 579 | /* VIA has a strange chipset, root port is under a bridge */ |
573 | if (pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT && | 580 | if (pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT && |
574 | pdev->bus->self) | 581 | pdev->bus->self) |
@@ -641,7 +648,7 @@ void pcie_aspm_exit_link_state(struct pci_dev *pdev) | |||
641 | struct pci_dev *parent = pdev->bus->self; | 648 | struct pci_dev *parent = pdev->bus->self; |
642 | struct pcie_link_state *link, *root, *parent_link; | 649 | struct pcie_link_state *link, *root, *parent_link; |
643 | 650 | ||
644 | if (aspm_disabled || !pci_is_pcie(pdev) || | 651 | if ((aspm_disabled && !aspm_clear_state) || !pci_is_pcie(pdev) || |
645 | !parent || !parent->link_state) | 652 | !parent || !parent->link_state) |
646 | return; | 653 | return; |
647 | if ((parent->pcie_type != PCI_EXP_TYPE_ROOT_PORT) && | 654 | if ((parent->pcie_type != PCI_EXP_TYPE_ROOT_PORT) && |
@@ -899,6 +906,12 @@ static int __init pcie_aspm_disable(char *str) | |||
899 | 906 | ||
900 | __setup("pcie_aspm=", pcie_aspm_disable); | 907 | __setup("pcie_aspm=", pcie_aspm_disable); |
901 | 908 | ||
909 | void pcie_clear_aspm(void) | ||
910 | { | ||
911 | if (!aspm_force) | ||
912 | aspm_clear_state = 1; | ||
913 | } | ||
914 | |||
902 | void pcie_no_aspm(void) | 915 | void pcie_no_aspm(void) |
903 | { | 916 | { |
904 | if (!aspm_force) | 917 | if (!aspm_force) |