aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthew Garrett <mjg59@coreos.com>2015-04-07 14:07:00 -0400
committerBjorn Helgaas <bhelgaas@google.com>2015-04-09 15:20:11 -0400
commit387d37577fdd05e9472c20885464c2a53b3c945f (patch)
tree5658630a603c2fa28fe5dc54502a0ac4c3bebe43
parent37a9c502c0af013aaae094556830100c2bb133ac (diff)
PCI: Don't clear ASPM bits when the FADT declares it's unsupported
Communications with a hardware vendor confirm that the expected behaviour on systems that set the FADT ASPM disable bit but which still grant full PCIe control is for the OS to leave any BIOS configuration intact and refuse to touch the ASPM bits. This mimics the behaviour of Windows. Signed-off-by: Matthew Garrett <mjg59@coreos.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
-rw-r--r--drivers/acpi/pci_root.c19
-rw-r--r--drivers/pci/pcie/aspm.c18
-rw-r--r--include/linux/pci-aspm.h4
3 files changed, 8 insertions, 33 deletions
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index 68a5f712cd19..1b5569c092c6 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -423,8 +423,7 @@ out:
423} 423}
424EXPORT_SYMBOL(acpi_pci_osc_control_set); 424EXPORT_SYMBOL(acpi_pci_osc_control_set);
425 425
426static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm, 426static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm)
427 int *clear_aspm)
428{ 427{
429 u32 support, control, requested; 428 u32 support, control, requested;
430 acpi_status status; 429 acpi_status status;
@@ -495,10 +494,12 @@ static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm,
495 decode_osc_control(root, "OS now controls", control); 494 decode_osc_control(root, "OS now controls", control);
496 if (acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_ASPM) { 495 if (acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_ASPM) {
497 /* 496 /*
498 * We have ASPM control, but the FADT indicates 497 * We have ASPM control, but the FADT indicates that
499 * that it's unsupported. Clear it. 498 * it's unsupported. Leave existing configuration
499 * intact and prevent the OS from touching it.
500 */ 500 */
501 *clear_aspm = 1; 501 dev_info(&device->dev, "FADT indicates ASPM is unsupported, using BIOS configuration\n");
502 *no_aspm = 1;
502 } 503 }
503 } else { 504 } else {
504 decode_osc_control(root, "OS requested", requested); 505 decode_osc_control(root, "OS requested", requested);
@@ -525,7 +526,7 @@ static int acpi_pci_root_add(struct acpi_device *device,
525 int result; 526 int result;
526 struct acpi_pci_root *root; 527 struct acpi_pci_root *root;
527 acpi_handle handle = device->handle; 528 acpi_handle handle = device->handle;
528 int no_aspm = 0, clear_aspm = 0; 529 int no_aspm = 0;
529 bool hotadd = system_state != SYSTEM_BOOTING; 530 bool hotadd = system_state != SYSTEM_BOOTING;
530 531
531 root = kzalloc(sizeof(struct acpi_pci_root), GFP_KERNEL); 532 root = kzalloc(sizeof(struct acpi_pci_root), GFP_KERNEL);
@@ -584,7 +585,7 @@ static int acpi_pci_root_add(struct acpi_device *device,
584 585
585 root->mcfg_addr = acpi_pci_root_get_mcfg_addr(handle); 586 root->mcfg_addr = acpi_pci_root_get_mcfg_addr(handle);
586 587
587 negotiate_os_control(root, &no_aspm, &clear_aspm); 588 negotiate_os_control(root, &no_aspm);
588 589
589 /* 590 /*
590 * TBD: Need PCI interface for enumeration/configuration of roots. 591 * TBD: Need PCI interface for enumeration/configuration of roots.
@@ -607,10 +608,6 @@ static int acpi_pci_root_add(struct acpi_device *device,
607 goto remove_dmar; 608 goto remove_dmar;
608 } 609 }
609 610
610 if (clear_aspm) {
611 dev_info(&device->dev, "Disabling ASPM (FADT indicates it is unsupported)\n");
612 pcie_clear_aspm(root->bus);
613 }
614 if (no_aspm) 611 if (no_aspm)
615 pcie_no_aspm(); 612 pcie_no_aspm();
616 613
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
index 820740a22e94..7d4fcdc512aa 100644
--- a/drivers/pci/pcie/aspm.c
+++ b/drivers/pci/pcie/aspm.c
@@ -782,24 +782,6 @@ void pci_disable_link_state(struct pci_dev *pdev, int state)
782} 782}
783EXPORT_SYMBOL(pci_disable_link_state); 783EXPORT_SYMBOL(pci_disable_link_state);
784 784
785void pcie_clear_aspm(struct pci_bus *bus)
786{
787 struct pci_dev *child;
788
789 if (aspm_force)
790 return;
791
792 /*
793 * Clear any ASPM setup that the firmware has carried out on this bus
794 */
795 list_for_each_entry(child, &bus->devices, bus_list) {
796 __pci_disable_link_state(child, PCIE_LINK_STATE_L0S |
797 PCIE_LINK_STATE_L1 |
798 PCIE_LINK_STATE_CLKPM,
799 false, true);
800 }
801}
802
803static int pcie_aspm_set_policy(const char *val, struct kernel_param *kp) 785static int pcie_aspm_set_policy(const char *val, struct kernel_param *kp)
804{ 786{
805 int i; 787 int i;
diff --git a/include/linux/pci-aspm.h b/include/linux/pci-aspm.h
index 8af4610c2e41..207c561fb40e 100644
--- a/include/linux/pci-aspm.h
+++ b/include/linux/pci-aspm.h
@@ -29,7 +29,6 @@ void pcie_aspm_pm_state_change(struct pci_dev *pdev);
29void pcie_aspm_powersave_config_link(struct pci_dev *pdev); 29void pcie_aspm_powersave_config_link(struct pci_dev *pdev);
30void pci_disable_link_state(struct pci_dev *pdev, int state); 30void pci_disable_link_state(struct pci_dev *pdev, int state);
31void pci_disable_link_state_locked(struct pci_dev *pdev, int state); 31void pci_disable_link_state_locked(struct pci_dev *pdev, int state);
32void pcie_clear_aspm(struct pci_bus *bus);
33void pcie_no_aspm(void); 32void pcie_no_aspm(void);
34#else 33#else
35static inline void pcie_aspm_init_link_state(struct pci_dev *pdev) 34static inline void pcie_aspm_init_link_state(struct pci_dev *pdev)
@@ -47,9 +46,6 @@ static inline void pcie_aspm_powersave_config_link(struct pci_dev *pdev)
47static inline void pci_disable_link_state(struct pci_dev *pdev, int state) 46static inline void pci_disable_link_state(struct pci_dev *pdev, int state)
48{ 47{
49} 48}
50static inline void pcie_clear_aspm(struct pci_bus *bus)
51{
52}
53static inline void pcie_no_aspm(void) 49static inline void pcie_no_aspm(void)
54{ 50{
55} 51}