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 | up_read(&pci_bus_sem); | 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 | struct pci_dev *parent = pdev->bus->self; | 1067 | struct pci_dev *parent = pdev->bus->self; |
| 1068 | struct pcie_link_state *link; | 1068 | struct pcie_link_state *link; |
| 1069 | 1069 | ||
| 1070 | if (!pci_is_pcie(pdev)) | 1070 | if (!pci_is_pcie(pdev)) |
| 1071 | return; | 1071 | return 0; |
| 1072 | 1072 | ||
| 1073 | if (pdev->has_secondary_link) | 1073 | if (pdev->has_secondary_link) |
| 1074 | parent = pdev; | 1074 | parent = pdev; |
| 1075 | if (!parent || !parent->link_state) | 1075 | if (!parent || !parent->link_state) |
| 1076 | return; | 1076 | return -EINVAL; |
| 1077 | 1077 | ||
| 1078 | /* | 1078 | /* |
| 1079 | * A driver requested that ASPM be disabled on this device, but | 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 | if (aspm_disabled) { | 1086 | if (aspm_disabled) { |
| 1087 | pci_warn(pdev, "can't disable ASPM; OS doesn't have ASPM control\n"); | 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 | if (sem) | 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 | mutex_unlock(&aspm_lock); | 1105 | mutex_unlock(&aspm_lock); |
| 1106 | if (sem) | 1106 | if (sem) |
| 1107 | up_read(&pci_bus_sem); | 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 | EXPORT_SYMBOL(pci_disable_link_state_locked); | 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 | * pci_disable_link_state - Disable device's link state, so the link will | 1119 | * pci_disable_link_state - Disable device's link state, so the link will |
| 1118 | * never enter specific states. Note that if the BIOS didn't grant ASPM | 1120 | * never enter specific states. Note that if the BIOS didn't grant ASPM |
| 1119 | * control to the OS, this does nothing because we can't touch the LNKCTL | 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 | * @pdev: PCI device | 1124 | * @pdev: PCI device |
| 1123 | * @state: ASPM link state to disable | 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 | EXPORT_SYMBOL(pci_disable_link_state); | 1131 | EXPORT_SYMBOL(pci_disable_link_state); |
| 1130 | 1132 | ||
| @@ -24,11 +24,12 @@ · 23 unmodified lines | |||
| 24 | #define PCIE_LINK_STATE_CLKPM 4 | 24 | #define PCIE_LINK_STATE_CLKPM 4 |
| 25 | 25 | ||
| 26 | #ifdef CONFIG_PCIEASPM | 26 | #ifdef CONFIG_PCIEASPM |
| 27 | void pci_disable_link_state(struct pci_dev *pdev, int state); | 27 | int pci_disable_link_state(struct pci_dev *pdev, int state); |
| 28 | void pci_disable_link_state_locked(struct pci_dev *pdev, int state); | 28 | int pci_disable_link_state_locked(struct pci_dev *pdev, int state); |
| 29 | void pcie_no_aspm(void); | 29 | void pcie_no_aspm(void); |
| 30 | #else | 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 | static inline void pcie_no_aspm(void) { } | 33 | static inline void pcie_no_aspm(void) { } |
| 33 | #endif | 34 | #endif |
| 34 | 35 | ||