aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2019-06-21 22:05:42 -0400
committerDavid S. Miller <davem@davemloft.net>2019-06-21 22:05:42 -0400
commite0effb5fbd56a8b2b8917611cbf4fcd9aba92b8f (patch)
tree5db41c7be5d6888479c5d853171951418c3e7e57
parentdca73a65a68329ee386d3ff473152bac66eaab39 (diff)
parent62b1b3b3b6d3ef309b1024aea95265c01929933c (diff)
Merge branch 'PCI-let-pci_disable_link_state-propagate-errors'
Heiner Kallweit says: ==================== PCI: let pci_disable_link_state propagate errors Drivers like r8169 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. I'd propose to let this series go through the netdev tree if the PCI core extension is acked by the PCI people. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/realtek/r8169_main.c8
-rw-r--r--drivers/pci/pcie/aspm.c20
-rw-r--r--include/linux/pci-aspm.h7
3 files changed, 21 insertions, 14 deletions
diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c
index 2e2a74aa025c..48b8a90f7057 100644
--- a/drivers/net/ethernet/realtek/r8169_main.c
+++ b/drivers/net/ethernet/realtek/r8169_main.c
@@ -652,6 +652,7 @@ struct rtl8169_private {
652 652
653 unsigned irq_enabled:1; 653 unsigned irq_enabled:1;
654 unsigned supports_gmii:1; 654 unsigned supports_gmii:1;
655 unsigned aspm_manageable:1;
655 dma_addr_t counters_phys_addr; 656 dma_addr_t counters_phys_addr;
656 struct rtl8169_counters *counters; 657 struct rtl8169_counters *counters;
657 struct rtl8169_tc_offsets tc_offset; 658 struct rtl8169_tc_offsets tc_offset;
@@ -4286,7 +4287,8 @@ static void rtl_pcie_state_l2l3_disable(struct rtl8169_private *tp)
4286 4287
4287static void rtl_hw_aspm_clkreq_enable(struct rtl8169_private *tp, bool enable) 4288static void rtl_hw_aspm_clkreq_enable(struct rtl8169_private *tp, bool enable)
4288{ 4289{
4289 if (enable) { 4290 /* Don't enable ASPM in the chip if OS can't control ASPM */
4291 if (enable && tp->aspm_manageable) {
4290 RTL_W8(tp, Config5, RTL_R8(tp, Config5) | ASPM_en); 4292 RTL_W8(tp, Config5, RTL_R8(tp, Config5) | ASPM_en);
4291 RTL_W8(tp, Config2, RTL_R8(tp, Config2) | ClkReqEn); 4293 RTL_W8(tp, Config2, RTL_R8(tp, Config2) | ClkReqEn);
4292 } else { 4294 } else {
@@ -6678,7 +6680,9 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
6678 /* Disable ASPM completely as that cause random device stop working 6680 /* Disable ASPM completely as that cause random device stop working
6679 * problems as well as full system hangs for some PCIe devices users. 6681 * problems as well as full system hangs for some PCIe devices users.
6680 */ 6682 */
6681 pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1); 6683 rc = pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S |
6684 PCIE_LINK_STATE_L1);
6685 tp->aspm_manageable = !rc;
6682 6686
6683 /* enable device (incl. PCI PM wakeup and hotplug setup) */ 6687 /* enable device (incl. PCI PM wakeup and hotplug setup) */
6684 rc = pcim_enable_device(pdev); 6688 rc = pcim_enable_device(pdev);
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
index fd4cb75088f9..e44af7f4d37f 100644
--- a/drivers/pci/pcie/aspm.c
+++ b/drivers/pci/pcie/aspm.c
@@ -1062,18 +1062,18 @@ void pcie_aspm_powersave_config_link(struct pci_dev *pdev)
1062 up_read(&pci_bus_sem); 1062 up_read(&pci_bus_sem);
1063} 1063}
1064 1064
1065static void __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem) 1065static 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)
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)
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
1110void pci_disable_link_state_locked(struct pci_dev *pdev, int state) 1112int 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}
1114EXPORT_SYMBOL(pci_disable_link_state_locked); 1116EXPORT_SYMBOL(pci_disable_link_state_locked);
1115 1117
@@ -1117,14 +1119,14 @@ EXPORT_SYMBOL(pci_disable_link_state_locked);
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 */
1125void pci_disable_link_state(struct pci_dev *pdev, int state) 1127int 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}
1129EXPORT_SYMBOL(pci_disable_link_state); 1131EXPORT_SYMBOL(pci_disable_link_state);
1130 1132
diff --git a/include/linux/pci-aspm.h b/include/linux/pci-aspm.h
index df28af5cef21..67064145d76e 100644
--- a/include/linux/pci-aspm.h
+++ b/include/linux/pci-aspm.h
@@ -24,11 +24,12 @@
24#define PCIE_LINK_STATE_CLKPM 4 24#define PCIE_LINK_STATE_CLKPM 4
25 25
26#ifdef CONFIG_PCIEASPM 26#ifdef CONFIG_PCIEASPM
27void pci_disable_link_state(struct pci_dev *pdev, int state); 27int pci_disable_link_state(struct pci_dev *pdev, int state);
28void pci_disable_link_state_locked(struct pci_dev *pdev, int state); 28int pci_disable_link_state_locked(struct pci_dev *pdev, int state);
29void pcie_no_aspm(void); 29void pcie_no_aspm(void);
30#else 30#else
31static inline void pci_disable_link_state(struct pci_dev *pdev, int state) { } 31static inline int pci_disable_link_state(struct pci_dev *pdev, int state)
32{ return 0; }
32static inline void pcie_no_aspm(void) { } 33static inline void pcie_no_aspm(void) { }
33#endif 34#endif
34 35