Kyle McMartin 39ad3b9
From linux-kernel-owner@vger.kernel.org Mon Dec  6 14:01:17 2010
Kyle McMartin 39ad3b9
From:	Matthew Garrett <mjg@redhat.com>
Kyle McMartin 39ad3b9
To:	linux-pci@vger.kernel.org
Kyle McMartin 39ad3b9
Cc:	linux-kernel@vger.kernel.org, jbarnes@virtuousgeek.org,
Kyle McMartin 39ad3b9
	Matthew Garrett <mjg@redhat.com>
Kyle McMartin 39ad3b9
Subject: [PATCH v2] PCI: Disable ASPM if BIOS asks us to
Kyle McMartin 39ad3b9
Date:	Mon,  6 Dec 2010 14:00:56 -0500
Kyle McMartin 39ad3b9
Message-Id: <1291662056-6055-1-git-send-email-mjg@redhat.com>
Kyle McMartin 39ad3b9
Kyle McMartin 39ad3b9
We currently refuse to touch the ASPM registers if the BIOS tells us that
Kyle McMartin 39ad3b9
ASPM isn't supported. This can cause problems if the BIOS has (for any
Kyle McMartin 39ad3b9
reason) enabled ASPM on some devices anyway. Change the code such that we
Kyle McMartin 39ad3b9
explicitly clear ASPM if the FADT indicates that ASPM isn't supported,
Kyle McMartin 39ad3b9
and make sure we tidy up appropriately on device removal in order to deal
Kyle McMartin 39ad3b9
with the hotplug case. If ASPM is disabled because the BIOS doesn't hand
Kyle McMartin 39ad3b9
over control then we won't touch the registers.
Kyle McMartin 39ad3b9
Kyle McMartin 39ad3b9
Signed-off-by: Matthew Garrett <mjg@redhat.com>
Kyle McMartin 39ad3b9
---
Kyle McMartin 39ad3b9
Kyle McMartin 39ad3b9
Implement Rafael's suggestion to use two separate functions, and also
Kyle McMartin 39ad3b9
ensure that we clear the clkpm bit as well as the ASPM bits.
Kyle McMartin 39ad3b9
Kyle McMartin 39ad3b9
 drivers/pci/pci-acpi.c   |    1 +
Kyle McMartin 39ad3b9
 drivers/pci/pcie/aspm.c  |   21 +++++++++++++++++----
Kyle McMartin 39ad3b9
 include/linux/pci-aspm.h |    5 ++++-
Kyle McMartin 39ad3b9
 3 files changed, 22 insertions(+), 5 deletions(-)
Kyle McMartin 39ad3b9
Kyle McMartin 39ad3b9
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
Kyle McMartin 39ad3b9
index 24e19c5..d7ea699 100644
Kyle McMartin 39ad3b9
--- a/drivers/pci/pci-acpi.c
Kyle McMartin 39ad3b9
+++ b/drivers/pci/pci-acpi.c
Kyle McMartin 39ad3b9
@@ -399,6 +399,7 @@ static int __init acpi_pci_init(void)
Kyle McMartin 39ad3b9
 
Kyle McMartin 39ad3b9
 	if (acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_ASPM) {
Kyle McMartin 39ad3b9
 		printk(KERN_INFO"ACPI FADT declares the system doesn't support PCIe ASPM, so disable it\n");
Kyle McMartin 39ad3b9
+		pcie_clear_aspm();
Kyle McMartin 39ad3b9
 		pcie_no_aspm();
Kyle McMartin 39ad3b9
 	}
Kyle McMartin 39ad3b9
 
Kyle McMartin 39ad3b9
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
Kyle McMartin 39ad3b9
index 7122281..8112415 100644
Kyle McMartin 39ad3b9
--- a/drivers/pci/pcie/aspm.c
Kyle McMartin 39ad3b9
+++ b/drivers/pci/pcie/aspm.c
Kyle McMartin 39ad3b9
@@ -68,7 +68,7 @@ struct pcie_link_state {
Kyle McMartin 39ad3b9
 	struct aspm_latency acceptable[8];
Kyle McMartin 39ad3b9
 };
Kyle McMartin 39ad3b9
 
Kyle McMartin 39ad3b9
-static int aspm_disabled, aspm_force;
Kyle McMartin 39ad3b9
+static int aspm_disabled, aspm_force, aspm_clear_state;
Kyle McMartin 39ad3b9
 static DEFINE_MUTEX(aspm_lock);
Kyle McMartin 39ad3b9
 static LIST_HEAD(link_list);
Kyle McMartin 39ad3b9
 
Kyle McMartin 39ad3b9
@@ -139,7 +139,7 @@ static void pcie_set_clkpm(struct pcie_link_state *link, int enable)
Kyle McMartin 39ad3b9
 {
Kyle McMartin 39ad3b9
 	/* Don't enable Clock PM if the link is not Clock PM capable */
Kyle McMartin 39ad3b9
 	if (!link->clkpm_capable && enable)
Kyle McMartin 39ad3b9
-		return;
Kyle McMartin 39ad3b9
+		enable = 0;
Kyle McMartin 39ad3b9
 	/* Need nothing if the specified equals to current state */
Kyle McMartin 39ad3b9
 	if (link->clkpm_enabled == enable)
Kyle McMartin 39ad3b9
 		return;
Kyle McMartin 39ad3b9
@@ -498,6 +498,10 @@ static int pcie_aspm_sanity_check(struct pci_dev *pdev)
Kyle McMartin 39ad3b9
 	struct pci_dev *child;
Kyle McMartin 39ad3b9
 	int pos;
Kyle McMartin 39ad3b9
 	u32 reg32;
Kyle McMartin 39ad3b9
+
Kyle McMartin 39ad3b9
+	if (aspm_clear_state)
Kyle McMartin 39ad3b9
+		return -EINVAL;
Kyle McMartin 39ad3b9
+
Kyle McMartin 39ad3b9
 	/*
Kyle McMartin 39ad3b9
 	 * Some functions in a slot might not all be PCIe functions,
Kyle McMartin 39ad3b9
 	 * very strange. Disable ASPM for the whole slot
Kyle McMartin 39ad3b9
@@ -563,12 +567,15 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev)
Kyle McMartin 39ad3b9
 	struct pcie_link_state *link;
Kyle McMartin 39ad3b9
 	int blacklist = !!pcie_aspm_sanity_check(pdev);
Kyle McMartin 39ad3b9
 
Kyle McMartin 39ad3b9
-	if (aspm_disabled || !pci_is_pcie(pdev) || pdev->link_state)
Kyle McMartin 39ad3b9
+	if (!pci_is_pcie(pdev) || pdev->link_state)
Kyle McMartin 39ad3b9
 		return;
Kyle McMartin 39ad3b9
 	if (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT &&
Kyle McMartin 39ad3b9
 	    pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM)
Kyle McMartin 39ad3b9
 		return;
Kyle McMartin 39ad3b9
 
Kyle McMartin 39ad3b9
+	if (aspm_disabled && !aspm_clear_state)
Kyle McMartin 39ad3b9
+		return;
Kyle McMartin 39ad3b9
+
Kyle McMartin 39ad3b9
 	/* VIA has a strange chipset, root port is under a bridge */
Kyle McMartin 39ad3b9
 	if (pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT &&
Kyle McMartin 39ad3b9
 	    pdev->bus->self)
Kyle McMartin 39ad3b9
@@ -641,7 +648,7 @@ void pcie_aspm_exit_link_state(struct pci_dev *pdev)
Kyle McMartin 39ad3b9
 	struct pci_dev *parent = pdev->bus->self;
Kyle McMartin 39ad3b9
 	struct pcie_link_state *link, *root, *parent_link;
Kyle McMartin 39ad3b9
 
Kyle McMartin 39ad3b9
-	if (aspm_disabled || !pci_is_pcie(pdev) ||
Kyle McMartin 39ad3b9
+	if ((aspm_disabled && !aspm_clear_state) || !pci_is_pcie(pdev) ||
Kyle McMartin 39ad3b9
 	    !parent || !parent->link_state)
Kyle McMartin 39ad3b9
 		return;
Kyle McMartin 39ad3b9
 	if ((parent->pcie_type != PCI_EXP_TYPE_ROOT_PORT) &&
Kyle McMartin 39ad3b9
@@ -899,6 +906,12 @@ static int __init pcie_aspm_disable(char *str)
Kyle McMartin 39ad3b9
 
Kyle McMartin 39ad3b9
 __setup("pcie_aspm=", pcie_aspm_disable);
Kyle McMartin 39ad3b9
 
Kyle McMartin a6caae2
+void pcie_clear_aspm(void)
Kyle McMartin 39ad3b9
+{
Kyle McMartin 39ad3b9
+	if (!aspm_force)
Kyle McMartin 39ad3b9
+		aspm_clear_state = 1;
Kyle McMartin 39ad3b9
+}
Kyle McMartin 39ad3b9
+
Kyle McMartin 39ad3b9
 void pcie_no_aspm(void)
Kyle McMartin 39ad3b9
 {
Kyle McMartin 39ad3b9
 	if (!aspm_force)
Kyle McMartin 39ad3b9
diff --git a/include/linux/pci-aspm.h b/include/linux/pci-aspm.h
Kyle McMartin 39ad3b9
index 91ba0b3..ce68105 100644
Kyle McMartin 39ad3b9
--- a/include/linux/pci-aspm.h
Kyle McMartin 39ad3b9
+++ b/include/linux/pci-aspm.h
Kyle McMartin 39ad3b9
@@ -27,6 +27,7 @@ extern void pcie_aspm_init_link_state(struct pci_dev *pdev);
Kyle McMartin 39ad3b9
 extern void pcie_aspm_exit_link_state(struct pci_dev *pdev);
Kyle McMartin 39ad3b9
 extern void pcie_aspm_pm_state_change(struct pci_dev *pdev);
Kyle McMartin 39ad3b9
 extern void pci_disable_link_state(struct pci_dev *pdev, int state);
Kyle McMartin 39ad3b9
+extern void pcie_clear_aspm(void);
Kyle McMartin 39ad3b9
 extern void pcie_no_aspm(void);
Kyle McMartin 39ad3b9
 #else
Kyle McMartin 39ad3b9
 static inline void pcie_aspm_init_link_state(struct pci_dev *pdev)
Kyle McMartin 39ad3b9
@@ -41,7 +42,9 @@ static inline void pcie_aspm_pm_state_change(struct pci_dev *pdev)
Kyle McMartin 39ad3b9
 static inline void pci_disable_link_state(struct pci_dev *pdev, int state)
Kyle McMartin 39ad3b9
 {
Kyle McMartin 39ad3b9
 }
Kyle McMartin 39ad3b9
-
Kyle McMartin 39ad3b9
+static inline void pcie_clear_aspm(void)
Kyle McMartin 39ad3b9
+{
Kyle McMartin 39ad3b9
+}
Kyle McMartin 39ad3b9
 static inline void pcie_no_aspm(void)
Kyle McMartin 39ad3b9
 {
Kyle McMartin 39ad3b9
 }
Kyle McMartin 39ad3b9
-- 
Kyle McMartin 39ad3b9
1.7.3.2
Kyle McMartin 39ad3b9
Kyle McMartin 39ad3b9
--
Kyle McMartin 39ad3b9
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
Kyle McMartin 39ad3b9
the body of a message to majordomo@vger.kernel.org
Kyle McMartin 39ad3b9
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Kyle McMartin 39ad3b9
Please read the FAQ at  http://www.tux.org/lkml/
Kyle McMartin 39ad3b9