Skip to content

Commit 718ab82

Browse files
jhovoldbjorn-helgaas
authored andcommitted
PCI/ASPM: Add pci_enable_link_state_locked()
Add pci_enable_link_state_locked() for enabling link states that can be used in contexts where a pci_bus_sem read lock is already held (e.g. from pci_walk_bus()). This helper will be used to fix a couple of potential deadlocks where the current helper is called with the lock already held, hence the CC stable tag. Fixes: f492edb ("PCI: vmd: Add quirk to configure PCIe ASPM and LTR") Link: https://lore.kernel.org/r/20231128081512.19387-2-johan+linaro@kernel.org Signed-off-by: Johan Hovold <johan+linaro@kernel.org> [bhelgaas: include helper name in subject, commit log] Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> Cc: <stable@vger.kernel.org> # 6.3 Cc: Michael Bottini <michael.a.bottini@linux.intel.com> Cc: David E. Box <david.e.box@linux.intel.com>
1 parent ef61a04 commit 718ab82

2 files changed

Lines changed: 43 additions & 13 deletions

File tree

drivers/pci/pcie/aspm.c

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1109,17 +1109,7 @@ int pci_disable_link_state(struct pci_dev *pdev, int state)
11091109
}
11101110
EXPORT_SYMBOL(pci_disable_link_state);
11111111

1112-
/**
1113-
* pci_enable_link_state - Clear and set the default device link state so that
1114-
* the link may be allowed to enter the specified states. Note that if the
1115-
* BIOS didn't grant ASPM control to the OS, this does nothing because we can't
1116-
* touch the LNKCTL register. Also note that this does not enable states
1117-
* disabled by pci_disable_link_state(). Return 0 or a negative errno.
1118-
*
1119-
* @pdev: PCI device
1120-
* @state: Mask of ASPM link states to enable
1121-
*/
1122-
int pci_enable_link_state(struct pci_dev *pdev, int state)
1112+
static int __pci_enable_link_state(struct pci_dev *pdev, int state, bool locked)
11231113
{
11241114
struct pcie_link_state *link = pcie_aspm_get_link(pdev);
11251115

@@ -1136,7 +1126,8 @@ int pci_enable_link_state(struct pci_dev *pdev, int state)
11361126
return -EPERM;
11371127
}
11381128

1139-
down_read(&pci_bus_sem);
1129+
if (!locked)
1130+
down_read(&pci_bus_sem);
11401131
mutex_lock(&aspm_lock);
11411132
link->aspm_default = 0;
11421133
if (state & PCIE_LINK_STATE_L0S)
@@ -1157,12 +1148,48 @@ int pci_enable_link_state(struct pci_dev *pdev, int state)
11571148
link->clkpm_default = (state & PCIE_LINK_STATE_CLKPM) ? 1 : 0;
11581149
pcie_set_clkpm(link, policy_to_clkpm_state(link));
11591150
mutex_unlock(&aspm_lock);
1160-
up_read(&pci_bus_sem);
1151+
if (!locked)
1152+
up_read(&pci_bus_sem);
11611153

11621154
return 0;
11631155
}
1156+
1157+
/**
1158+
* pci_enable_link_state - Clear and set the default device link state so that
1159+
* the link may be allowed to enter the specified states. Note that if the
1160+
* BIOS didn't grant ASPM control to the OS, this does nothing because we can't
1161+
* touch the LNKCTL register. Also note that this does not enable states
1162+
* disabled by pci_disable_link_state(). Return 0 or a negative errno.
1163+
*
1164+
* @pdev: PCI device
1165+
* @state: Mask of ASPM link states to enable
1166+
*/
1167+
int pci_enable_link_state(struct pci_dev *pdev, int state)
1168+
{
1169+
return __pci_enable_link_state(pdev, state, false);
1170+
}
11641171
EXPORT_SYMBOL(pci_enable_link_state);
11651172

1173+
/**
1174+
* pci_enable_link_state_locked - Clear and set the default device link state
1175+
* so that the link may be allowed to enter the specified states. Note that if
1176+
* the BIOS didn't grant ASPM control to the OS, this does nothing because we
1177+
* can't touch the LNKCTL register. Also note that this does not enable states
1178+
* disabled by pci_disable_link_state(). Return 0 or a negative errno.
1179+
*
1180+
* @pdev: PCI device
1181+
* @state: Mask of ASPM link states to enable
1182+
*
1183+
* Context: Caller holds pci_bus_sem read lock.
1184+
*/
1185+
int pci_enable_link_state_locked(struct pci_dev *pdev, int state)
1186+
{
1187+
lockdep_assert_held_read(&pci_bus_sem);
1188+
1189+
return __pci_enable_link_state(pdev, state, true);
1190+
}
1191+
EXPORT_SYMBOL(pci_enable_link_state_locked);
1192+
11661193
static int pcie_aspm_set_policy(const char *val,
11671194
const struct kernel_param *kp)
11681195
{

include/linux/pci.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1829,6 +1829,7 @@ extern bool pcie_ports_native;
18291829
int pci_disable_link_state(struct pci_dev *pdev, int state);
18301830
int pci_disable_link_state_locked(struct pci_dev *pdev, int state);
18311831
int pci_enable_link_state(struct pci_dev *pdev, int state);
1832+
int pci_enable_link_state_locked(struct pci_dev *pdev, int state);
18321833
void pcie_no_aspm(void);
18331834
bool pcie_aspm_support_enabled(void);
18341835
bool pcie_aspm_enabled(struct pci_dev *pdev);
@@ -1839,6 +1840,8 @@ static inline int pci_disable_link_state_locked(struct pci_dev *pdev, int state)
18391840
{ return 0; }
18401841
static inline int pci_enable_link_state(struct pci_dev *pdev, int state)
18411842
{ return 0; }
1843+
static inline int pci_enable_link_state_locked(struct pci_dev *pdev, int state)
1844+
{ return 0; }
18421845
static inline void pcie_no_aspm(void) { }
18431846
static inline bool pcie_aspm_support_enabled(void) { return false; }
18441847
static inline bool pcie_aspm_enabled(struct pci_dev *pdev) { return false; }

0 commit comments

Comments
 (0)