aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/pcie/aspm.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pci/pcie/aspm.c')
-rw-r--r--drivers/pci/pcie/aspm.c75
1 files changed, 67 insertions, 8 deletions
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
index 71222814c1ec..6892601fc76f 100644
--- a/drivers/pci/pcie/aspm.c
+++ b/drivers/pci/pcie/aspm.c
@@ -68,7 +68,8 @@ struct pcie_link_state {
68 struct aspm_latency acceptable[8]; 68 struct aspm_latency acceptable[8];
69}; 69};
70 70
71static int aspm_disabled, aspm_force; 71static int aspm_disabled, aspm_force, aspm_clear_state;
72static bool aspm_support_enabled = true;
72static DEFINE_MUTEX(aspm_lock); 73static DEFINE_MUTEX(aspm_lock);
73static LIST_HEAD(link_list); 74static LIST_HEAD(link_list);
74 75
@@ -139,7 +140,7 @@ static void pcie_set_clkpm(struct pcie_link_state *link, int enable)
139{ 140{
140 /* Don't enable Clock PM if the link is not Clock PM capable */ 141 /* Don't enable Clock PM if the link is not Clock PM capable */
141 if (!link->clkpm_capable && enable) 142 if (!link->clkpm_capable && enable)
142 return; 143 enable = 0;
143 /* Need nothing if the specified equals to current state */ 144 /* Need nothing if the specified equals to current state */
144 if (link->clkpm_enabled == enable) 145 if (link->clkpm_enabled == enable)
145 return; 146 return;
@@ -498,6 +499,10 @@ static int pcie_aspm_sanity_check(struct pci_dev *pdev)
498 struct pci_dev *child; 499 struct pci_dev *child;
499 int pos; 500 int pos;
500 u32 reg32; 501 u32 reg32;
502
503 if (aspm_clear_state)
504 return -EINVAL;
505
501 /* 506 /*
502 * Some functions in a slot might not all be PCIe functions, 507 * Some functions in a slot might not all be PCIe functions,
503 * very strange. Disable ASPM for the whole slot 508 * very strange. Disable ASPM for the whole slot
@@ -563,12 +568,15 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev)
563 struct pcie_link_state *link; 568 struct pcie_link_state *link;
564 int blacklist = !!pcie_aspm_sanity_check(pdev); 569 int blacklist = !!pcie_aspm_sanity_check(pdev);
565 570
566 if (aspm_disabled || !pci_is_pcie(pdev) || pdev->link_state) 571 if (!pci_is_pcie(pdev) || pdev->link_state)
567 return; 572 return;
568 if (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT && 573 if (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT &&
569 pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM) 574 pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM)
570 return; 575 return;
571 576
577 if (aspm_disabled && !aspm_clear_state)
578 return;
579
572 /* VIA has a strange chipset, root port is under a bridge */ 580 /* VIA has a strange chipset, root port is under a bridge */
573 if (pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT && 581 if (pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT &&
574 pdev->bus->self) 582 pdev->bus->self)
@@ -600,7 +608,7 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev)
600 * the BIOS's expectation, we'll do so once pci_enable_device() is 608 * the BIOS's expectation, we'll do so once pci_enable_device() is
601 * called. 609 * called.
602 */ 610 */
603 if (aspm_policy != POLICY_POWERSAVE) { 611 if (aspm_policy != POLICY_POWERSAVE || aspm_clear_state) {
604 pcie_config_aspm_path(link); 612 pcie_config_aspm_path(link);
605 pcie_set_clkpm(link, policy_to_clkpm_state(link)); 613 pcie_set_clkpm(link, policy_to_clkpm_state(link));
606 } 614 }
@@ -641,7 +649,7 @@ void pcie_aspm_exit_link_state(struct pci_dev *pdev)
641 struct pci_dev *parent = pdev->bus->self; 649 struct pci_dev *parent = pdev->bus->self;
642 struct pcie_link_state *link, *root, *parent_link; 650 struct pcie_link_state *link, *root, *parent_link;
643 651
644 if (aspm_disabled || !pci_is_pcie(pdev) || 652 if ((aspm_disabled && !aspm_clear_state) || !pci_is_pcie(pdev) ||
645 !parent || !parent->link_state) 653 !parent || !parent->link_state)
646 return; 654 return;
647 if ((parent->pcie_type != PCI_EXP_TYPE_ROOT_PORT) && 655 if ((parent->pcie_type != PCI_EXP_TYPE_ROOT_PORT) &&
@@ -700,11 +708,33 @@ void pcie_aspm_pm_state_change(struct pci_dev *pdev)
700 up_read(&pci_bus_sem); 708 up_read(&pci_bus_sem);
701} 709}
702 710
711void pcie_aspm_powersave_config_link(struct pci_dev *pdev)
712{
713 struct pcie_link_state *link = pdev->link_state;
714
715 if (aspm_disabled || !pci_is_pcie(pdev) || !link)
716 return;
717
718 if (aspm_policy != POLICY_POWERSAVE)
719 return;
720
721 if ((pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT) &&
722 (pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM))
723 return;
724
725 down_read(&pci_bus_sem);
726 mutex_lock(&aspm_lock);
727 pcie_config_aspm_path(link);
728 pcie_set_clkpm(link, policy_to_clkpm_state(link));
729 mutex_unlock(&aspm_lock);
730 up_read(&pci_bus_sem);
731}
732
703/* 733/*
704 * pci_disable_link_state - disable pci device's link state, so the link will 734 * pci_disable_link_state - disable pci device's link state, so the link will
705 * never enter specific states 735 * never enter specific states
706 */ 736 */
707void pci_disable_link_state(struct pci_dev *pdev, int state) 737static void __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem)
708{ 738{
709 struct pci_dev *parent = pdev->bus->self; 739 struct pci_dev *parent = pdev->bus->self;
710 struct pcie_link_state *link; 740 struct pcie_link_state *link;
@@ -717,7 +747,8 @@ void pci_disable_link_state(struct pci_dev *pdev, int state)
717 if (!parent || !parent->link_state) 747 if (!parent || !parent->link_state)
718 return; 748 return;
719 749
720 down_read(&pci_bus_sem); 750 if (sem)
751 down_read(&pci_bus_sem);
721 mutex_lock(&aspm_lock); 752 mutex_lock(&aspm_lock);
722 link = parent->link_state; 753 link = parent->link_state;
723 if (state & PCIE_LINK_STATE_L0S) 754 if (state & PCIE_LINK_STATE_L0S)
@@ -731,7 +762,19 @@ void pci_disable_link_state(struct pci_dev *pdev, int state)
731 pcie_set_clkpm(link, 0); 762 pcie_set_clkpm(link, 0);
732 } 763 }
733 mutex_unlock(&aspm_lock); 764 mutex_unlock(&aspm_lock);
734 up_read(&pci_bus_sem); 765 if (sem)
766 up_read(&pci_bus_sem);
767}
768
769void pci_disable_link_state_locked(struct pci_dev *pdev, int state)
770{
771 __pci_disable_link_state(pdev, state, false);
772}
773EXPORT_SYMBOL(pci_disable_link_state_locked);
774
775void pci_disable_link_state(struct pci_dev *pdev, int state)
776{
777 __pci_disable_link_state(pdev, state, true);
735} 778}
736EXPORT_SYMBOL(pci_disable_link_state); 779EXPORT_SYMBOL(pci_disable_link_state);
737 780
@@ -740,6 +783,8 @@ static int pcie_aspm_set_policy(const char *val, struct kernel_param *kp)
740 int i; 783 int i;
741 struct pcie_link_state *link; 784 struct pcie_link_state *link;
742 785
786 if (aspm_disabled)
787 return -EPERM;
743 for (i = 0; i < ARRAY_SIZE(policy_str); i++) 788 for (i = 0; i < ARRAY_SIZE(policy_str); i++)
744 if (!strncmp(val, policy_str[i], strlen(policy_str[i]))) 789 if (!strncmp(val, policy_str[i], strlen(policy_str[i])))
745 break; 790 break;
@@ -794,6 +839,8 @@ static ssize_t link_state_store(struct device *dev,
794 struct pcie_link_state *link, *root = pdev->link_state->root; 839 struct pcie_link_state *link, *root = pdev->link_state->root;
795 u32 val = buf[0] - '0', state = 0; 840 u32 val = buf[0] - '0', state = 0;
796 841
842 if (aspm_disabled)
843 return -EPERM;
797 if (n < 1 || val > 3) 844 if (n < 1 || val > 3)
798 return -EINVAL; 845 return -EINVAL;
799 846
@@ -889,6 +936,7 @@ static int __init pcie_aspm_disable(char *str)
889{ 936{
890 if (!strcmp(str, "off")) { 937 if (!strcmp(str, "off")) {
891 aspm_disabled = 1; 938 aspm_disabled = 1;
939 aspm_support_enabled = false;
892 printk(KERN_INFO "PCIe ASPM is disabled\n"); 940 printk(KERN_INFO "PCIe ASPM is disabled\n");
893 } else if (!strcmp(str, "force")) { 941 } else if (!strcmp(str, "force")) {
894 aspm_force = 1; 942 aspm_force = 1;
@@ -899,6 +947,12 @@ static int __init pcie_aspm_disable(char *str)
899 947
900__setup("pcie_aspm=", pcie_aspm_disable); 948__setup("pcie_aspm=", pcie_aspm_disable);
901 949
950void pcie_clear_aspm(void)
951{
952 if (!aspm_force)
953 aspm_clear_state = 1;
954}
955
902void pcie_no_aspm(void) 956void pcie_no_aspm(void)
903{ 957{
904 if (!aspm_force) 958 if (!aspm_force)
@@ -917,3 +971,8 @@ int pcie_aspm_enabled(void)
917} 971}
918EXPORT_SYMBOL(pcie_aspm_enabled); 972EXPORT_SYMBOL(pcie_aspm_enabled);
919 973
974bool pcie_aspm_support_enabled(void)
975{
976 return aspm_support_enabled;
977}
978EXPORT_SYMBOL(pcie_aspm_support_enabled);