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.
Unified · Split
| @@ -1062,18 +1062,18 @@ void pcie_aspm_powersave_config_link(struct pci_dev *pdev) · 1061 unmodified lines | ||
| 1062 | 1062 | up_read(&pci_bus_sem); |
| 1063 | 1063 | } |
| 1064 | 1064 | |
| 1065 | −static void __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem) | |
| 1065 | +static int __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem) | |
| 1066 | 1066 | { |
| 1067 | 1067 | struct pci_dev *parent = pdev->bus->self; |
| 1068 | 1068 | struct pcie_link_state *link; |
| 1069 | 1069 | |
| 1070 | 1070 | if (!pci_is_pcie(pdev)) |
| 1071 | − return; | |
| 1071 | + return 0; | |
| 1072 | 1072 | |
| 1073 | 1073 | if (pdev->has_secondary_link) |
| 1074 | 1074 | parent = pdev; |
| 1075 | 1075 | if (!parent || !parent->link_state) |
| 1076 | − return; | |
| 1076 | + return -EINVAL; | |
| 1077 | 1077 | |
| 1078 | 1078 | /* |
| 1079 | 1079 | * 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) · 5 unmodified lines | ||
| 1085 | 1085 | */ |
| 1086 | 1086 | if (aspm_disabled) { |
| 1087 | 1087 | pci_warn(pdev, "can't disable ASPM; OS doesn't have ASPM control\n"); |
| 1088 | − return; | |
| 1088 | + return -EPERM; | |
| 1089 | 1089 | } |
| 1090 | 1090 | |
| 1091 | 1091 | if (sem) |
| @@ -1105,11 +1105,13 @@ static void __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem) · 13 unmodified lines | ||
| 1105 | 1105 | mutex_unlock(&aspm_lock); |
| 1106 | 1106 | if (sem) |
| 1107 | 1107 | up_read(&pci_bus_sem); |
| 1108 | + | |
| 1109 | + return 0; | |
| 1108 | 1110 | } |
| 1109 | 1111 | |
| 1110 | −void pci_disable_link_state_locked(struct pci_dev *pdev, int state) | |
| 1112 | +int pci_disable_link_state_locked(struct pci_dev *pdev, int state) | |
| 1111 | 1113 | { |
| 1112 | − __pci_disable_link_state(pdev, state, false); | |
| 1114 | + return __pci_disable_link_state(pdev, state, false); | |
| 1113 | 1115 | } |
| 1114 | 1116 | EXPORT_SYMBOL(pci_disable_link_state_locked); |
| 1115 | 1117 | |
| @@ -1117,14 +1119,14 @@ EXPORT_SYMBOL(pci_disable_link_state_locked); · 1 unmodified line | ||
| 1117 | 1119 | * pci_disable_link_state - Disable device's link state, so the link will |
| 1118 | 1120 | * never enter specific states. Note that if the BIOS didn't grant ASPM |
| 1119 | 1121 | * control to the OS, this does nothing because we can't touch the LNKCTL |
| 1120 | − * register. | |
| 1122 | + * register. Returns 0 or a negative errno. | |
| 1121 | 1123 | * |
| 1122 | 1124 | * @pdev: PCI device |
| 1123 | 1125 | * @state: ASPM link state to disable |
| 1124 | 1126 | */ |
| 1125 | −void pci_disable_link_state(struct pci_dev *pdev, int state) | |
| 1127 | +int pci_disable_link_state(struct pci_dev *pdev, int state) | |
| 1126 | 1128 | { |
| 1127 | − __pci_disable_link_state(pdev, state, true); | |
| 1129 | + return __pci_disable_link_state(pdev, state, true); | |
| 1128 | 1130 | } |
| 1129 | 1131 | EXPORT_SYMBOL(pci_disable_link_state); |
| 1130 | 1132 | |
| @@ -24,11 +24,12 @@ · 23 unmodified lines | ||
| 24 | 24 | #define PCIE_LINK_STATE_CLKPM 4 |
| 25 | 25 | |
| 26 | 26 | #ifdef CONFIG_PCIEASPM |
| 27 | −void pci_disable_link_state(struct pci_dev *pdev, int state); | |
| 28 | −void pci_disable_link_state_locked(struct pci_dev *pdev, int state); | |
| 27 | +int pci_disable_link_state(struct pci_dev *pdev, int state); | |
| 28 | +int pci_disable_link_state_locked(struct pci_dev *pdev, int state); | |
| 29 | 29 | void pcie_no_aspm(void); |
| 30 | 30 | #else |
| 31 | −static inline void pci_disable_link_state(struct pci_dev *pdev, int state) { } | |
| 31 | +static inline int pci_disable_link_state(struct pci_dev *pdev, int state) | |
| 32 | +{ return 0; } | |
| 32 | 33 | static inline void pcie_no_aspm(void) { } |
| 33 | 34 | #endif |
| 34 | 35 | |