Commit e0effb5f authored by David S. Miller's avatar David S. Miller

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: default avatarDavid S. Miller <davem@davemloft.net>
parents dca73a65 62b1b3b3
...@@ -652,6 +652,7 @@ struct rtl8169_private { ...@@ -652,6 +652,7 @@ struct rtl8169_private {
unsigned irq_enabled:1; unsigned irq_enabled:1;
unsigned supports_gmii:1; unsigned supports_gmii:1;
unsigned aspm_manageable:1;
dma_addr_t counters_phys_addr; dma_addr_t counters_phys_addr;
struct rtl8169_counters *counters; struct rtl8169_counters *counters;
struct rtl8169_tc_offsets tc_offset; struct rtl8169_tc_offsets tc_offset;
...@@ -4286,7 +4287,8 @@ static void rtl_pcie_state_l2l3_disable(struct rtl8169_private *tp) ...@@ -4286,7 +4287,8 @@ static void rtl_pcie_state_l2l3_disable(struct rtl8169_private *tp)
static void rtl_hw_aspm_clkreq_enable(struct rtl8169_private *tp, bool enable) static void rtl_hw_aspm_clkreq_enable(struct rtl8169_private *tp, bool enable)
{ {
if (enable) { /* Don't enable ASPM in the chip if OS can't control ASPM */
if (enable && tp->aspm_manageable) {
RTL_W8(tp, Config5, RTL_R8(tp, Config5) | ASPM_en); RTL_W8(tp, Config5, RTL_R8(tp, Config5) | ASPM_en);
RTL_W8(tp, Config2, RTL_R8(tp, Config2) | ClkReqEn); RTL_W8(tp, Config2, RTL_R8(tp, Config2) | ClkReqEn);
} else { } else {
...@@ -6678,7 +6680,9 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -6678,7 +6680,9 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
/* Disable ASPM completely as that cause random device stop working /* Disable ASPM completely as that cause random device stop working
* problems as well as full system hangs for some PCIe devices users. * problems as well as full system hangs for some PCIe devices users.
*/ */
pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1); rc = pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S |
PCIE_LINK_STATE_L1);
tp->aspm_manageable = !rc;
/* enable device (incl. PCI PM wakeup and hotplug setup) */ /* enable device (incl. PCI PM wakeup and hotplug setup) */
rc = pcim_enable_device(pdev); rc = pcim_enable_device(pdev);
......
...@@ -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