|
@@ -68,7 +68,7 @@ struct pcie_link_state {
|
|
|
struct aspm_latency acceptable[8];
|
|
|
};
|
|
|
|
|
|
-static int aspm_disabled, aspm_force, aspm_clear_state;
|
|
|
+static int aspm_disabled, aspm_force;
|
|
|
static bool aspm_support_enabled = true;
|
|
|
static DEFINE_MUTEX(aspm_lock);
|
|
|
static LIST_HEAD(link_list);
|
|
@@ -500,9 +500,6 @@ static int pcie_aspm_sanity_check(struct pci_dev *pdev)
|
|
|
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
|
|
@@ -574,9 +571,6 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev)
|
|
|
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)
|
|
@@ -608,7 +602,7 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev)
|
|
|
* the BIOS's expectation, we'll do so once pci_enable_device() is
|
|
|
* called.
|
|
|
*/
|
|
|
- if (aspm_policy != POLICY_POWERSAVE || aspm_clear_state) {
|
|
|
+ if (aspm_policy != POLICY_POWERSAVE) {
|
|
|
pcie_config_aspm_path(link);
|
|
|
pcie_set_clkpm(link, policy_to_clkpm_state(link));
|
|
|
}
|
|
@@ -649,8 +643,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 && !aspm_clear_state) || !pci_is_pcie(pdev) ||
|
|
|
- !parent || !parent->link_state)
|
|
|
+ if (!pci_is_pcie(pdev) || !parent || !parent->link_state)
|
|
|
return;
|
|
|
if ((parent->pcie_type != PCI_EXP_TYPE_ROOT_PORT) &&
|
|
|
(parent->pcie_type != PCI_EXP_TYPE_DOWNSTREAM))
|
|
@@ -734,13 +727,18 @@ void pcie_aspm_powersave_config_link(struct pci_dev *pdev)
|
|
|
* pci_disable_link_state - disable pci device's link state, so the link will
|
|
|
* never enter specific states
|
|
|
*/
|
|
|
-static void __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem)
|
|
|
+static void __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem,
|
|
|
+ bool force)
|
|
|
{
|
|
|
struct pci_dev *parent = pdev->bus->self;
|
|
|
struct pcie_link_state *link;
|
|
|
|
|
|
- if (aspm_disabled || !pci_is_pcie(pdev))
|
|
|
+ if (aspm_disabled && !force)
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (!pci_is_pcie(pdev))
|
|
|
return;
|
|
|
+
|
|
|
if (pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT ||
|
|
|
pdev->pcie_type == PCI_EXP_TYPE_DOWNSTREAM)
|
|
|
parent = pdev;
|
|
@@ -768,16 +766,31 @@ static void __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem)
|
|
|
|
|
|
void pci_disable_link_state_locked(struct pci_dev *pdev, int state)
|
|
|
{
|
|
|
- __pci_disable_link_state(pdev, state, false);
|
|
|
+ __pci_disable_link_state(pdev, state, false, false);
|
|
|
}
|
|
|
EXPORT_SYMBOL(pci_disable_link_state_locked);
|
|
|
|
|
|
void pci_disable_link_state(struct pci_dev *pdev, int state)
|
|
|
{
|
|
|
- __pci_disable_link_state(pdev, state, true);
|
|
|
+ __pci_disable_link_state(pdev, state, true, false);
|
|
|
}
|
|
|
EXPORT_SYMBOL(pci_disable_link_state);
|
|
|
|
|
|
+void pcie_clear_aspm(struct pci_bus *bus)
|
|
|
+{
|
|
|
+ struct pci_dev *child;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Clear any ASPM setup that the firmware has carried out on this bus
|
|
|
+ */
|
|
|
+ list_for_each_entry(child, &bus->devices, bus_list) {
|
|
|
+ __pci_disable_link_state(child, PCIE_LINK_STATE_L0S |
|
|
|
+ PCIE_LINK_STATE_L1 |
|
|
|
+ PCIE_LINK_STATE_CLKPM,
|
|
|
+ false, true);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
static int pcie_aspm_set_policy(const char *val, struct kernel_param *kp)
|
|
|
{
|
|
|
int i;
|
|
@@ -935,6 +948,7 @@ void pcie_aspm_remove_sysfs_dev_files(struct pci_dev *pdev)
|
|
|
static int __init pcie_aspm_disable(char *str)
|
|
|
{
|
|
|
if (!strcmp(str, "off")) {
|
|
|
+ aspm_policy = POLICY_DEFAULT;
|
|
|
aspm_disabled = 1;
|
|
|
aspm_support_enabled = false;
|
|
|
printk(KERN_INFO "PCIe ASPM is disabled\n");
|
|
@@ -947,16 +961,18 @@ 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)
|
|
|
+ /*
|
|
|
+ * Disabling ASPM is intended to prevent the kernel from modifying
|
|
|
+ * existing hardware state, not to clear existing state. To that end:
|
|
|
+ * (a) set policy to POLICY_DEFAULT in order to avoid changing state
|
|
|
+ * (b) prevent userspace from changing policy
|
|
|
+ */
|
|
|
+ if (!aspm_force) {
|
|
|
+ aspm_policy = POLICY_DEFAULT;
|
|
|
aspm_disabled = 1;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/**
|