PCI: Disable ASPM if BIOS asks us to
[~shefty/rdma-dev.git] / drivers / pci / pcie / aspm.c
index 71222814c1ecf602880352d8cb3df7ff7930d5db..3188cd96b3386c2992d2b3df1d5a7bb0e363c266 100644 (file)
@@ -68,7 +68,7 @@ struct pcie_link_state {
        struct aspm_latency acceptable[8];
 };
 
-static int aspm_disabled, aspm_force;
+static int aspm_disabled, aspm_force, aspm_clear_state;
 static DEFINE_MUTEX(aspm_lock);
 static LIST_HEAD(link_list);
 
@@ -139,7 +139,7 @@ static void pcie_set_clkpm(struct pcie_link_state *link, int enable)
 {
        /* Don't enable Clock PM if the link is not Clock PM capable */
        if (!link->clkpm_capable && enable)
-               return;
+               enable = 0;
        /* Need nothing if the specified equals to current state */
        if (link->clkpm_enabled == enable)
                return;
@@ -498,6 +498,10 @@ static int pcie_aspm_sanity_check(struct pci_dev *pdev)
        struct pci_dev *child;
        int pos;
        u32 reg32;
+
+       if (aspm_clear_state)
+               return -EINVAL;
+
        /*
         * Some functions in a slot might not all be PCIe functions,
         * very strange. Disable ASPM for the whole slot
@@ -563,12 +567,15 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev)
        struct pcie_link_state *link;
        int blacklist = !!pcie_aspm_sanity_check(pdev);
 
-       if (aspm_disabled || !pci_is_pcie(pdev) || pdev->link_state)
+       if (!pci_is_pcie(pdev) || pdev->link_state)
                return;
        if (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT &&
            pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM)
                return;
 
+       if (aspm_disabled && !aspm_clear_state)
+               return;
+
        /* VIA has a strange chipset, root port is under a bridge */
        if (pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT &&
            pdev->bus->self)
@@ -641,7 +648,7 @@ void pcie_aspm_exit_link_state(struct pci_dev *pdev)
        struct pci_dev *parent = pdev->bus->self;
        struct pcie_link_state *link, *root, *parent_link;
 
-       if (aspm_disabled || !pci_is_pcie(pdev) ||
+       if ((aspm_disabled && !aspm_clear_state) || !pci_is_pcie(pdev) ||
            !parent || !parent->link_state)
                return;
        if ((parent->pcie_type != PCI_EXP_TYPE_ROOT_PORT) &&
@@ -899,6 +906,12 @@ static int __init pcie_aspm_disable(char *str)
 
 __setup("pcie_aspm=", pcie_aspm_disable);
 
+void pcie_clear_aspm(void)
+{
+       if (!aspm_force)
+               aspm_clear_state = 1;
+}
+
 void pcie_no_aspm(void)
 {
        if (!aspm_force)