PCI: let pci_disable_link_state propagate errors
authorHeiner Kallweit <hkallweit1@gmail.com>
Tue, 18 Jun 2019 21:13:48 +0000 (23:13 +0200)
committerDavid S. Miller <davem@davemloft.net>
Sat, 22 Jun 2019 02:05:42 +0000 (22:05 -0400)
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: Heiner Kallweit <hkallweit1@gmail.com>
Acked-by: Bjorn Helgaas <bhelgaas@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/pci/pcie/aspm.c
include/linux/pci-aspm.h

index fd4cb75088f9b5432c68c8db0b75bd169291cb8d..e44af7f4d37ff48c050daeaeab33326ec1a52067 100644 (file)
@@ -1062,18 +1062,18 @@ void pcie_aspm_powersave_config_link(struct pci_dev *pdev)
        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 pcie_link_state *link;
 
        if (!pci_is_pcie(pdev))
-               return;
+               return 0;
 
        if (pdev->has_secondary_link)
                parent = pdev;
        if (!parent || !parent->link_state)
-               return;
+               return -EINVAL;
 
        /*
         * 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)
         */
        if (aspm_disabled) {
                pci_warn(pdev, "can't disable ASPM; OS doesn't have ASPM control\n");
-               return;
+               return -EPERM;
        }
 
        if (sem)
@@ -1105,11 +1105,13 @@ static void __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem)
        mutex_unlock(&aspm_lock);
        if (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);
 
@@ -1117,14 +1119,14 @@ EXPORT_SYMBOL(pci_disable_link_state_locked);
  * 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
  * 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
  * @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);
 
index df28af5cef21082afca93776f083d23c15161ab2..67064145d76e01a97f0288dcdd3d40a3c78c2f70 100644 (file)
 #define PCIE_LINK_STATE_CLKPM  4
 
 #ifdef CONFIG_PCIEASPM
-void 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(struct pci_dev *pdev, int state);
+int pci_disable_link_state_locked(struct pci_dev *pdev, int state);
 void pcie_no_aspm(void);
 #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) { }
 #endif