Commit 2f671e2dbff6eb5ef4e2600adbec550c13b8fe72

Authored by Matthew Garrett
Committed by Jesse Barnes
1 parent 8d80528696

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
... ... @@ -399,6 +399,7 @@
399 399  
400 400 if (acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_ASPM) {
401 401 printk(KERN_INFO"ACPI FADT declares the system doesn't support PCIe ASPM, so disable it\n");
  402 + pcie_clear_aspm();
402 403 pcie_no_aspm();
403 404 }
404 405  
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 }