From 23fa18eaa71266feff7ba8d83022d9e1cc83c65a Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Fri, 10 May 2024 07:42:03 +0000
Subject: [PATCH] disable pwm7
---
kernel/drivers/pci/pcie/aspm.c | 102 ++++++++++++++++++++++++++++++---------------------
1 files changed, 60 insertions(+), 42 deletions(-)
diff --git a/kernel/drivers/pci/pcie/aspm.c b/kernel/drivers/pci/pcie/aspm.c
index ac0557a..ef6f0ce 100644
--- a/kernel/drivers/pci/pcie/aspm.c
+++ b/kernel/drivers/pci/pcie/aspm.c
@@ -192,11 +192,38 @@
link->clkpm_disable = blacklist ? 1 : 0;
}
-static bool pcie_retrain_link(struct pcie_link_state *link)
+static int pcie_wait_for_retrain(struct pci_dev *pdev)
{
- struct pci_dev *parent = link->pdev;
unsigned long end_jiffies;
u16 reg16;
+
+ /* Wait for Link Training to be cleared by hardware */
+ end_jiffies = jiffies + LINK_RETRAIN_TIMEOUT;
+ do {
+ pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, ®16);
+ if (!(reg16 & PCI_EXP_LNKSTA_LT))
+ return 0;
+ msleep(1);
+ } while (time_before(jiffies, end_jiffies));
+
+ return -ETIMEDOUT;
+}
+
+static int pcie_retrain_link(struct pcie_link_state *link)
+{
+ struct pci_dev *parent = link->pdev;
+ int rc;
+ u16 reg16;
+
+ /*
+ * Ensure the updated LNKCTL parameters are used during link
+ * training by checking that there is no ongoing link training to
+ * avoid LTSSM race as recommended in Implementation Note at the
+ * end of PCIe r6.0.1 sec 7.5.3.7.
+ */
+ rc = pcie_wait_for_retrain(parent);
+ if (rc)
+ return rc;
pcie_capability_read_word(parent, PCI_EXP_LNKCTL, ®16);
reg16 |= PCI_EXP_LNKCTL_RL;
@@ -211,15 +238,7 @@
pcie_capability_write_word(parent, PCI_EXP_LNKCTL, reg16);
}
- /* Wait for link training end. Break out after waiting for timeout */
- end_jiffies = jiffies + LINK_RETRAIN_TIMEOUT;
- do {
- pcie_capability_read_word(parent, PCI_EXP_LNKSTA, ®16);
- if (!(reg16 & PCI_EXP_LNKSTA_LT))
- break;
- msleep(1);
- } while (time_before(jiffies, end_jiffies));
- return !(reg16 & PCI_EXP_LNKSTA_LT);
+ return pcie_wait_for_retrain(parent);
}
/*
@@ -230,7 +249,7 @@
static void pcie_aspm_configure_common_clock(struct pcie_link_state *link)
{
int same_clock = 1;
- u16 reg16, parent_reg, child_reg[8];
+ u16 reg16, ccc, parent_old_ccc, child_old_ccc[8];
struct pci_dev *child, *parent = link->pdev;
struct pci_bus *linkbus = parent->subordinate;
/*
@@ -252,6 +271,7 @@
/* Port might be already in common clock mode */
pcie_capability_read_word(parent, PCI_EXP_LNKCTL, ®16);
+ parent_old_ccc = reg16 & PCI_EXP_LNKCTL_CCC;
if (same_clock && (reg16 & PCI_EXP_LNKCTL_CCC)) {
bool consistent = true;
@@ -268,35 +288,30 @@
pci_info(parent, "ASPM: current common clock configuration is inconsistent, reconfiguring\n");
}
+ ccc = same_clock ? PCI_EXP_LNKCTL_CCC : 0;
/* Configure downstream component, all functions */
list_for_each_entry(child, &linkbus->devices, bus_list) {
pcie_capability_read_word(child, PCI_EXP_LNKCTL, ®16);
- child_reg[PCI_FUNC(child->devfn)] = reg16;
- if (same_clock)
- reg16 |= PCI_EXP_LNKCTL_CCC;
- else
- reg16 &= ~PCI_EXP_LNKCTL_CCC;
- pcie_capability_write_word(child, PCI_EXP_LNKCTL, reg16);
+ child_old_ccc[PCI_FUNC(child->devfn)] = reg16 & PCI_EXP_LNKCTL_CCC;
+ pcie_capability_clear_and_set_word(child, PCI_EXP_LNKCTL,
+ PCI_EXP_LNKCTL_CCC, ccc);
}
/* Configure upstream component */
- pcie_capability_read_word(parent, PCI_EXP_LNKCTL, ®16);
- parent_reg = reg16;
- if (same_clock)
- reg16 |= PCI_EXP_LNKCTL_CCC;
- else
- reg16 &= ~PCI_EXP_LNKCTL_CCC;
- pcie_capability_write_word(parent, PCI_EXP_LNKCTL, reg16);
+ pcie_capability_clear_and_set_word(parent, PCI_EXP_LNKCTL,
+ PCI_EXP_LNKCTL_CCC, ccc);
- if (pcie_retrain_link(link))
- return;
+ if (pcie_retrain_link(link)) {
- /* Training failed. Restore common clock configurations */
- pci_err(parent, "ASPM: Could not configure common clock\n");
- list_for_each_entry(child, &linkbus->devices, bus_list)
- pcie_capability_write_word(child, PCI_EXP_LNKCTL,
- child_reg[PCI_FUNC(child->devfn)]);
- pcie_capability_write_word(parent, PCI_EXP_LNKCTL, parent_reg);
+ /* Training failed. Restore common clock configurations */
+ pci_err(parent, "ASPM: Could not configure common clock\n");
+ list_for_each_entry(child, &linkbus->devices, bus_list)
+ pcie_capability_clear_and_set_word(child, PCI_EXP_LNKCTL,
+ PCI_EXP_LNKCTL_CCC,
+ child_old_ccc[PCI_FUNC(child->devfn)]);
+ pcie_capability_clear_and_set_word(parent, PCI_EXP_LNKCTL,
+ PCI_EXP_LNKCTL_CCC, parent_old_ccc);
+ }
}
/* Convert L0s latency encoding to ns */
@@ -993,21 +1008,24 @@
down_read(&pci_bus_sem);
mutex_lock(&aspm_lock);
- /*
- * All PCIe functions are in one slot, remove one function will remove
- * the whole slot, so just wait until we are the last function left.
- */
- if (!list_empty(&parent->subordinate->devices))
- goto out;
link = parent->link_state;
root = link->root;
parent_link = link->parent;
- /* All functions are removed, so just disable ASPM for the link */
+ /*
+ * link->downstream is a pointer to the pci_dev of function 0. If
+ * we remove that function, the pci_dev is about to be deallocated,
+ * so we can't use link->downstream again. Free the link state to
+ * avoid this.
+ *
+ * If we're removing a non-0 function, it's possible we could
+ * retain the link state, but PCIe r6.0, sec 7.5.3.7, recommends
+ * programming the same ASPM Control value for all functions of
+ * multi-function devices, so disable ASPM for all of them.
+ */
pcie_config_aspm_link(link, 0);
list_del(&link->sibling);
- /* Clock PM is for endpoint device */
free_link_state(link);
/* Recheck latencies and configure upstream links */
@@ -1015,7 +1033,7 @@
pcie_update_aspm_capable(root);
pcie_config_aspm_path(parent_link);
}
-out:
+
mutex_unlock(&aspm_lock);
up_read(&pci_bus_sem);
}
--
Gitblit v1.6.2