Commit 2f671e2dbff6eb5ef4e2600adbec550c13b8fe72
Committed by
Jesse Barnes
1 parent
8d80528696
Exists in
master
and in
41 other branches
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>
Showing 3 changed files with 22 additions and 5 deletions Side-by-side Diff
drivers/pci/pci-acpi.c
drivers/pci/pcie/aspm.c
... | ... | @@ -68,7 +68,7 @@ |
68 | 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 | 72 | static DEFINE_MUTEX(aspm_lock); |
73 | 73 | static LIST_HEAD(link_list); |
74 | 74 | |
... | ... | @@ -139,7 +139,7 @@ |
139 | 139 | { |
140 | 140 | /* Don't enable Clock PM if the link is not Clock PM capable */ |
141 | 141 | if (!link->clkpm_capable && enable) |
142 | - return; | |
142 | + enable = 0; | |
143 | 143 | /* Need nothing if the specified equals to current state */ |
144 | 144 | if (link->clkpm_enabled == enable) |
145 | 145 | return; |
... | ... | @@ -498,6 +498,10 @@ |
498 | 498 | struct pci_dev *child; |
499 | 499 | int pos; |
500 | 500 | u32 reg32; |
501 | + | |
502 | + if (aspm_clear_state) | |
503 | + return -EINVAL; | |
504 | + | |
501 | 505 | /* |
502 | 506 | * Some functions in a slot might not all be PCIe functions, |
503 | 507 | * very strange. Disable ASPM for the whole slot |
504 | 508 | |
... | ... | @@ -563,12 +567,15 @@ |
563 | 567 | struct pcie_link_state *link; |
564 | 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 | 571 | return; |
568 | 572 | if (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT && |
569 | 573 | pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM) |
570 | 574 | return; |
571 | 575 | |
576 | + if (aspm_disabled && !aspm_clear_state) | |
577 | + return; | |
578 | + | |
572 | 579 | /* VIA has a strange chipset, root port is under a bridge */ |
573 | 580 | if (pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT && |
574 | 581 | pdev->bus->self) |
... | ... | @@ -641,7 +648,7 @@ |
641 | 648 | struct pci_dev *parent = pdev->bus->self; |
642 | 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 | 652 | !parent || !parent->link_state) |
646 | 653 | return; |
647 | 654 | if ((parent->pcie_type != PCI_EXP_TYPE_ROOT_PORT) && |
... | ... | @@ -898,6 +905,12 @@ |
898 | 905 | } |
899 | 906 | |
900 | 907 | __setup("pcie_aspm=", pcie_aspm_disable); |
908 | + | |
909 | +void pcie_clear_aspm(void) | |
910 | +{ | |
911 | + if (!aspm_force) | |
912 | + aspm_clear_state = 1; | |
913 | +} | |
901 | 914 | |
902 | 915 | void pcie_no_aspm(void) |
903 | 916 | { |
include/linux/pci-aspm.h
... | ... | @@ -27,6 +27,7 @@ |
27 | 27 | extern void pcie_aspm_exit_link_state(struct pci_dev *pdev); |
28 | 28 | extern void pcie_aspm_pm_state_change(struct pci_dev *pdev); |
29 | 29 | extern void pci_disable_link_state(struct pci_dev *pdev, int state); |
30 | +extern void pcie_clear_aspm(void); | |
30 | 31 | extern void pcie_no_aspm(void); |
31 | 32 | #else |
32 | 33 | static inline void pcie_aspm_init_link_state(struct pci_dev *pdev) |
... | ... | @@ -41,7 +42,9 @@ |
41 | 42 | static inline void pci_disable_link_state(struct pci_dev *pdev, int state) |
42 | 43 | { |
43 | 44 | } |
44 | - | |
45 | +static inline void pcie_clear_aspm(void) | |
46 | +{ | |
47 | +} | |
45 | 48 | static inline void pcie_no_aspm(void) |
46 | 49 | { |
47 | 50 | } |