diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/acpi/pci_root.c | 7 | ||||
-rw-r--r-- | drivers/pci/pci-acpi.c | 1 | ||||
-rw-r--r-- | drivers/pci/pcie/aspm.c | 58 |
3 files changed, 44 insertions, 22 deletions
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 2672c798272f..7aff6312ce7c 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c | |||
@@ -596,6 +596,13 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device) | |||
596 | if (ACPI_SUCCESS(status)) { | 596 | if (ACPI_SUCCESS(status)) { |
597 | dev_info(root->bus->bridge, | 597 | dev_info(root->bus->bridge, |
598 | "ACPI _OSC control (0x%02x) granted\n", flags); | 598 | "ACPI _OSC control (0x%02x) granted\n", flags); |
599 | if (acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_ASPM) { | ||
600 | /* | ||
601 | * We have ASPM control, but the FADT indicates | ||
602 | * that it's unsupported. Clear it. | ||
603 | */ | ||
604 | pcie_clear_aspm(root->bus); | ||
605 | } | ||
599 | } else { | 606 | } else { |
600 | dev_info(root->bus->bridge, | 607 | dev_info(root->bus->bridge, |
601 | "ACPI _OSC request failed (%s), " | 608 | "ACPI _OSC request failed (%s), " |
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index 4ecb6408b0d6..c8e75851a314 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c | |||
@@ -395,7 +395,6 @@ static int __init acpi_pci_init(void) | |||
395 | 395 | ||
396 | if (acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_ASPM) { | 396 | if (acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_ASPM) { |
397 | printk(KERN_INFO"ACPI FADT declares the system doesn't support PCIe ASPM, so disable it\n"); | 397 | printk(KERN_INFO"ACPI FADT declares the system doesn't support PCIe ASPM, so disable it\n"); |
398 | pcie_clear_aspm(); | ||
399 | pcie_no_aspm(); | 398 | pcie_no_aspm(); |
400 | } | 399 | } |
401 | 400 | ||
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index cbfbab18be91..1cfbf228fbb1 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, aspm_clear_state; | 71 | static int aspm_disabled, aspm_force; |
72 | static bool aspm_support_enabled = true; | 72 | static bool aspm_support_enabled = true; |
73 | static DEFINE_MUTEX(aspm_lock); | 73 | static DEFINE_MUTEX(aspm_lock); |
74 | static LIST_HEAD(link_list); | 74 | static LIST_HEAD(link_list); |
@@ -500,9 +500,6 @@ static int pcie_aspm_sanity_check(struct pci_dev *pdev) | |||
500 | int pos; | 500 | int pos; |
501 | u32 reg32; | 501 | u32 reg32; |
502 | 502 | ||
503 | if (aspm_clear_state) | ||
504 | return -EINVAL; | ||
505 | |||
506 | /* | 503 | /* |
507 | * Some functions in a slot might not all be PCIe functions, | 504 | * Some functions in a slot might not all be PCIe functions, |
508 | * very strange. Disable ASPM for the whole slot | 505 | * very strange. Disable ASPM for the whole slot |
@@ -574,9 +571,6 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev) | |||
574 | pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM) | 571 | pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM) |
575 | return; | 572 | return; |
576 | 573 | ||
577 | if (aspm_disabled && !aspm_clear_state) | ||
578 | return; | ||
579 | |||
580 | /* VIA has a strange chipset, root port is under a bridge */ | 574 | /* VIA has a strange chipset, root port is under a bridge */ |
581 | if (pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT && | 575 | if (pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT && |
582 | pdev->bus->self) | 576 | pdev->bus->self) |
@@ -608,7 +602,7 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev) | |||
608 | * the BIOS's expectation, we'll do so once pci_enable_device() is | 602 | * the BIOS's expectation, we'll do so once pci_enable_device() is |
609 | * called. | 603 | * called. |
610 | */ | 604 | */ |
611 | if (aspm_policy != POLICY_POWERSAVE || aspm_clear_state) { | 605 | if (aspm_policy != POLICY_POWERSAVE) { |
612 | pcie_config_aspm_path(link); | 606 | pcie_config_aspm_path(link); |
613 | pcie_set_clkpm(link, policy_to_clkpm_state(link)); | 607 | pcie_set_clkpm(link, policy_to_clkpm_state(link)); |
614 | } | 608 | } |
@@ -649,8 +643,7 @@ void pcie_aspm_exit_link_state(struct pci_dev *pdev) | |||
649 | struct pci_dev *parent = pdev->bus->self; | 643 | struct pci_dev *parent = pdev->bus->self; |
650 | struct pcie_link_state *link, *root, *parent_link; | 644 | struct pcie_link_state *link, *root, *parent_link; |
651 | 645 | ||
652 | if ((aspm_disabled && !aspm_clear_state) || !pci_is_pcie(pdev) || | 646 | if (!pci_is_pcie(pdev) || !parent || !parent->link_state) |
653 | !parent || !parent->link_state) | ||
654 | return; | 647 | return; |
655 | if ((parent->pcie_type != PCI_EXP_TYPE_ROOT_PORT) && | 648 | if ((parent->pcie_type != PCI_EXP_TYPE_ROOT_PORT) && |
656 | (parent->pcie_type != PCI_EXP_TYPE_DOWNSTREAM)) | 649 | (parent->pcie_type != PCI_EXP_TYPE_DOWNSTREAM)) |
@@ -734,13 +727,18 @@ void pcie_aspm_powersave_config_link(struct pci_dev *pdev) | |||
734 | * pci_disable_link_state - disable pci device's link state, so the link will | 727 | * pci_disable_link_state - disable pci device's link state, so the link will |
735 | * never enter specific states | 728 | * never enter specific states |
736 | */ | 729 | */ |
737 | static void __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem) | 730 | static void __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem, |
731 | bool force) | ||
738 | { | 732 | { |
739 | struct pci_dev *parent = pdev->bus->self; | 733 | struct pci_dev *parent = pdev->bus->self; |
740 | struct pcie_link_state *link; | 734 | struct pcie_link_state *link; |
741 | 735 | ||
742 | if (aspm_disabled || !pci_is_pcie(pdev)) | 736 | if (aspm_disabled && !force) |
737 | return; | ||
738 | |||
739 | if (!pci_is_pcie(pdev)) | ||
743 | return; | 740 | return; |
741 | |||
744 | if (pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT || | 742 | if (pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT || |
745 | pdev->pcie_type == PCI_EXP_TYPE_DOWNSTREAM) | 743 | pdev->pcie_type == PCI_EXP_TYPE_DOWNSTREAM) |
746 | parent = pdev; | 744 | parent = pdev; |
@@ -768,16 +766,31 @@ static void __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem) | |||
768 | 766 | ||
769 | void pci_disable_link_state_locked(struct pci_dev *pdev, int state) | 767 | void pci_disable_link_state_locked(struct pci_dev *pdev, int state) |
770 | { | 768 | { |
771 | __pci_disable_link_state(pdev, state, false); | 769 | __pci_disable_link_state(pdev, state, false, false); |
772 | } | 770 | } |
773 | EXPORT_SYMBOL(pci_disable_link_state_locked); | 771 | EXPORT_SYMBOL(pci_disable_link_state_locked); |
774 | 772 | ||
775 | void pci_disable_link_state(struct pci_dev *pdev, int state) | 773 | void pci_disable_link_state(struct pci_dev *pdev, int state) |
776 | { | 774 | { |
777 | __pci_disable_link_state(pdev, state, true); | 775 | __pci_disable_link_state(pdev, state, true, false); |
778 | } | 776 | } |
779 | EXPORT_SYMBOL(pci_disable_link_state); | 777 | EXPORT_SYMBOL(pci_disable_link_state); |
780 | 778 | ||
779 | void pcie_clear_aspm(struct pci_bus *bus) | ||
780 | { | ||
781 | struct pci_dev *child; | ||
782 | |||
783 | /* | ||
784 | * Clear any ASPM setup that the firmware has carried out on this bus | ||
785 | */ | ||
786 | list_for_each_entry(child, &bus->devices, bus_list) { | ||
787 | __pci_disable_link_state(child, PCIE_LINK_STATE_L0S | | ||
788 | PCIE_LINK_STATE_L1 | | ||
789 | PCIE_LINK_STATE_CLKPM, | ||
790 | false, true); | ||
791 | } | ||
792 | } | ||
793 | |||
781 | static int pcie_aspm_set_policy(const char *val, struct kernel_param *kp) | 794 | static int pcie_aspm_set_policy(const char *val, struct kernel_param *kp) |
782 | { | 795 | { |
783 | int i; | 796 | int i; |
@@ -935,6 +948,7 @@ void pcie_aspm_remove_sysfs_dev_files(struct pci_dev *pdev) | |||
935 | static int __init pcie_aspm_disable(char *str) | 948 | static int __init pcie_aspm_disable(char *str) |
936 | { | 949 | { |
937 | if (!strcmp(str, "off")) { | 950 | if (!strcmp(str, "off")) { |
951 | aspm_policy = POLICY_DEFAULT; | ||
938 | aspm_disabled = 1; | 952 | aspm_disabled = 1; |
939 | aspm_support_enabled = false; | 953 | aspm_support_enabled = false; |
940 | printk(KERN_INFO "PCIe ASPM is disabled\n"); | 954 | printk(KERN_INFO "PCIe ASPM is disabled\n"); |
@@ -947,16 +961,18 @@ static int __init pcie_aspm_disable(char *str) | |||
947 | 961 | ||
948 | __setup("pcie_aspm=", pcie_aspm_disable); | 962 | __setup("pcie_aspm=", pcie_aspm_disable); |
949 | 963 | ||
950 | void pcie_clear_aspm(void) | ||
951 | { | ||
952 | if (!aspm_force) | ||
953 | aspm_clear_state = 1; | ||
954 | } | ||
955 | |||
956 | void pcie_no_aspm(void) | 964 | void pcie_no_aspm(void) |
957 | { | 965 | { |
958 | if (!aspm_force) | 966 | /* |
967 | * Disabling ASPM is intended to prevent the kernel from modifying | ||
968 | * existing hardware state, not to clear existing state. To that end: | ||
969 | * (a) set policy to POLICY_DEFAULT in order to avoid changing state | ||
970 | * (b) prevent userspace from changing policy | ||
971 | */ | ||
972 | if (!aspm_force) { | ||
973 | aspm_policy = POLICY_DEFAULT; | ||
959 | aspm_disabled = 1; | 974 | aspm_disabled = 1; |
975 | } | ||
960 | } | 976 | } |
961 | 977 | ||
962 | /** | 978 | /** |