Commit 4cfd2188 authored by Heiner Kallweit's avatar Heiner Kallweit Committed by David S. Miller

PCI: let pci_disable_link_state propagate errors

Drivers may rely on pci_disable_link_state() having disabled certain
ASPM link states. If OS can't control ASPM then pci_disable_link_state()
turns into a no-op w/o informing the caller. The driver therefore may
falsely assume the respective ASPM link states are disabled.
Let pci_disable_link_state() propagate errors to the caller, enabling
the caller to react accordingly.
Signed-off-by: default avatarHeiner Kallweit <hkallweit1@gmail.com>
Acked-by: default avatarBjorn Helgaas <bhelgaas@google.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent dca73a65
...@@ -1062,18 +1062,18 @@ void pcie_aspm_powersave_config_link(struct pci_dev *pdev) ...@@ -1062,18 +1062,18 @@ void pcie_aspm_powersave_config_link(struct pci_dev *pdev)
up_read(&pci_bus_sem); up_read(&pci_bus_sem);
} }
static void __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem) static int __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem)
{ {
struct pci_dev *parent = pdev->bus->self; struct pci_dev *parent = pdev->bus->self;
struct pcie_link_state *link; struct pcie_link_state *link;
if (!pci_is_pcie(pdev)) if (!pci_is_pcie(pdev))
return; return 0;
if (pdev->has_secondary_link) if (pdev->has_secondary_link)
parent = pdev; parent = pdev;
if (!parent || !parent->link_state) if (!parent || !parent->link_state)
return; return -EINVAL;
/* /*
* A driver requested that ASPM be disabled on this device, but * A driver requested that ASPM be disabled on this device, but
...@@ -1085,7 +1085,7 @@ static void __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem) ...@@ -1085,7 +1085,7 @@ static void __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem)
*/ */
if (aspm_disabled) { if (aspm_disabled) {
pci_warn(pdev, "can't disable ASPM; OS doesn't have ASPM control\n"); pci_warn(pdev, "can't disable ASPM; OS doesn't have ASPM control\n");
return; return -EPERM;
} }
if (sem) if (sem)
...@@ -1105,11 +1105,13 @@ static void __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem) ...@@ -1105,11 +1105,13 @@ static void __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem)
mutex_unlock(&aspm_lock); mutex_unlock(&aspm_lock);
if (sem) if (sem)
up_read(&pci_bus_sem); up_read(&pci_bus_sem);
return 0;
} }
void pci_disable_link_state_locked(struct pci_dev *pdev, int state) int pci_disable_link_state_locked(struct pci_dev *pdev, int state)
{ {
__pci_disable_link_state(pdev, state, false); return __pci_disable_link_state(pdev, state, false);
} }
EXPORT_SYMBOL(pci_disable_link_state_locked); EXPORT_SYMBOL(pci_disable_link_state_locked);
...@@ -1117,14 +1119,14 @@ EXPORT_SYMBOL(pci_disable_link_state_locked); ...@@ -1117,14 +1119,14 @@ EXPORT_SYMBOL(pci_disable_link_state_locked);
* pci_disable_link_state - Disable device's link state, so the link will * pci_disable_link_state - Disable device's link state, so the link will
* never enter specific states. Note that if the BIOS didn't grant ASPM * never enter specific states. Note that if the BIOS didn't grant ASPM
* control to the OS, this does nothing because we can't touch the LNKCTL * control to the OS, this does nothing because we can't touch the LNKCTL
* register. * register. Returns 0 or a negative errno.
* *
* @pdev: PCI device * @pdev: PCI device
* @state: ASPM link state to disable * @state: ASPM link state to disable
*/ */
void pci_disable_link_state(struct pci_dev *pdev, int state) int pci_disable_link_state(struct pci_dev *pdev, int state)
{ {
__pci_disable_link_state(pdev, state, true); return __pci_disable_link_state(pdev, state, true);
} }
EXPORT_SYMBOL(pci_disable_link_state); EXPORT_SYMBOL(pci_disable_link_state);
......
...@@ -24,11 +24,12 @@ ...@@ -24,11 +24,12 @@
#define PCIE_LINK_STATE_CLKPM 4 #define PCIE_LINK_STATE_CLKPM 4
#ifdef CONFIG_PCIEASPM #ifdef CONFIG_PCIEASPM
void pci_disable_link_state(struct pci_dev *pdev, int state); int pci_disable_link_state(struct pci_dev *pdev, int state);
void pci_disable_link_state_locked(struct pci_dev *pdev, int state); int pci_disable_link_state_locked(struct pci_dev *pdev, int state);
void pcie_no_aspm(void); void pcie_no_aspm(void);
#else #else
static inline void pci_disable_link_state(struct pci_dev *pdev, int state) { } static inline int pci_disable_link_state(struct pci_dev *pdev, int state)
{ return 0; }
static inline void pcie_no_aspm(void) { } static inline void pcie_no_aspm(void) { }
#endif #endif
......
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