Commit 718ab822 authored by Johan Hovold's avatar Johan Hovold Committed by Bjorn Helgaas

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: f492edb4 ("PCI: vmd: Add quirk to configure PCIe ASPM and LTR")
Link: https://lore.kernel.org/r/20231128081512.19387-2-johan+linaro@kernel.orgSigned-off-by: default avatarJohan Hovold <johan+linaro@kernel.org>
[bhelgaas: include helper name in subject, commit log]
Signed-off-by: default avatarBjorn Helgaas <bhelgaas@google.com>
Reviewed-by: default avatarManivannan 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>
parent ef61a040
...@@ -1109,17 +1109,7 @@ int pci_disable_link_state(struct pci_dev *pdev, int state) ...@@ -1109,17 +1109,7 @@ int pci_disable_link_state(struct pci_dev *pdev, int state)
} }
EXPORT_SYMBOL(pci_disable_link_state); EXPORT_SYMBOL(pci_disable_link_state);
/** static int __pci_enable_link_state(struct pci_dev *pdev, int state, bool locked)
* pci_enable_link_state - Clear and set the default device link state so that
* the link may be allowed to enter the specified states. Note that if the
* BIOS didn't grant ASPM control to the OS, this does nothing because we can't
* touch the LNKCTL register. Also note that this does not enable states
* disabled by pci_disable_link_state(). Return 0 or a negative errno.
*
* @pdev: PCI device
* @state: Mask of ASPM link states to enable
*/
int pci_enable_link_state(struct pci_dev *pdev, int state)
{ {
struct pcie_link_state *link = pcie_aspm_get_link(pdev); struct pcie_link_state *link = pcie_aspm_get_link(pdev);
...@@ -1136,7 +1126,8 @@ int pci_enable_link_state(struct pci_dev *pdev, int state) ...@@ -1136,7 +1126,8 @@ int pci_enable_link_state(struct pci_dev *pdev, int state)
return -EPERM; return -EPERM;
} }
down_read(&pci_bus_sem); if (!locked)
down_read(&pci_bus_sem);
mutex_lock(&aspm_lock); mutex_lock(&aspm_lock);
link->aspm_default = 0; link->aspm_default = 0;
if (state & PCIE_LINK_STATE_L0S) if (state & PCIE_LINK_STATE_L0S)
...@@ -1157,12 +1148,48 @@ int pci_enable_link_state(struct pci_dev *pdev, int state) ...@@ -1157,12 +1148,48 @@ int pci_enable_link_state(struct pci_dev *pdev, int state)
link->clkpm_default = (state & PCIE_LINK_STATE_CLKPM) ? 1 : 0; link->clkpm_default = (state & PCIE_LINK_STATE_CLKPM) ? 1 : 0;
pcie_set_clkpm(link, policy_to_clkpm_state(link)); pcie_set_clkpm(link, policy_to_clkpm_state(link));
mutex_unlock(&aspm_lock); mutex_unlock(&aspm_lock);
up_read(&pci_bus_sem); if (!locked)
up_read(&pci_bus_sem);
return 0; return 0;
} }
/**
* pci_enable_link_state - Clear and set the default device link state so that
* the link may be allowed to enter the specified states. Note that if the
* BIOS didn't grant ASPM control to the OS, this does nothing because we can't
* touch the LNKCTL register. Also note that this does not enable states
* disabled by pci_disable_link_state(). Return 0 or a negative errno.
*
* @pdev: PCI device
* @state: Mask of ASPM link states to enable
*/
int pci_enable_link_state(struct pci_dev *pdev, int state)
{
return __pci_enable_link_state(pdev, state, false);
}
EXPORT_SYMBOL(pci_enable_link_state); EXPORT_SYMBOL(pci_enable_link_state);
/**
* pci_enable_link_state_locked - Clear and set the default device link state
* so that the link may be allowed to enter the specified states. Note that if
* the BIOS didn't grant ASPM control to the OS, this does nothing because we
* can't touch the LNKCTL register. Also note that this does not enable states
* disabled by pci_disable_link_state(). Return 0 or a negative errno.
*
* @pdev: PCI device
* @state: Mask of ASPM link states to enable
*
* Context: Caller holds pci_bus_sem read lock.
*/
int pci_enable_link_state_locked(struct pci_dev *pdev, int state)
{
lockdep_assert_held_read(&pci_bus_sem);
return __pci_enable_link_state(pdev, state, true);
}
EXPORT_SYMBOL(pci_enable_link_state_locked);
static int pcie_aspm_set_policy(const char *val, static int pcie_aspm_set_policy(const char *val,
const struct kernel_param *kp) const struct kernel_param *kp)
{ {
......
...@@ -1829,6 +1829,7 @@ extern bool pcie_ports_native; ...@@ -1829,6 +1829,7 @@ extern bool pcie_ports_native;
int pci_disable_link_state(struct pci_dev *pdev, int state); int pci_disable_link_state(struct pci_dev *pdev, int state);
int pci_disable_link_state_locked(struct pci_dev *pdev, int state); int pci_disable_link_state_locked(struct pci_dev *pdev, int state);
int pci_enable_link_state(struct pci_dev *pdev, int state); int pci_enable_link_state(struct pci_dev *pdev, int state);
int pci_enable_link_state_locked(struct pci_dev *pdev, int state);
void pcie_no_aspm(void); void pcie_no_aspm(void);
bool pcie_aspm_support_enabled(void); bool pcie_aspm_support_enabled(void);
bool pcie_aspm_enabled(struct pci_dev *pdev); 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) ...@@ -1839,6 +1840,8 @@ static inline int pci_disable_link_state_locked(struct pci_dev *pdev, int state)
{ return 0; } { return 0; }
static inline int pci_enable_link_state(struct pci_dev *pdev, int state) static inline int pci_enable_link_state(struct pci_dev *pdev, int state)
{ return 0; } { return 0; }
static inline int pci_enable_link_state_locked(struct pci_dev *pdev, int state)
{ return 0; }
static inline void pcie_no_aspm(void) { } static inline void pcie_no_aspm(void) { }
static inline bool pcie_aspm_support_enabled(void) { return false; } static inline bool pcie_aspm_support_enabled(void) { return false; }
static inline bool pcie_aspm_enabled(struct pci_dev *pdev) { return false; } static inline bool pcie_aspm_enabled(struct pci_dev *pdev) { return false; }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment