Commit 77258d409ce4 ("ath10k: enable pci soc powersaving") introduced MMIO wake-up handling through ath10k_pci_wake(). Current code only logs MMIO wake-up failures and returns. This becomes a problem when a PCIe link-down leaves MMIO wake-up failures as the earliest indication that the device has stopped responding, because the existing recovery mechanism is not triggered until higher-layer timeout paths expire, for example: failed to wake target for read32 at 0x00036044: -110 failed to wake target for write32 of 0xfffff81f at 0x00034834: -110 Improve this by triggering recovery immediately on MMIO wake-up failures and by aborting MMIO-driven waits once the device enters ATH10K_STATE_WEDGED, because no further forward progress is possible after either condition. This shortens known-failed recovery attempts and helps avoid suspend watchdog timeouts on systems where recovery time is tightly constrained. Tested-on: QCA6174 hw3.2 PCI WLAN.RM.4.4.1-00288-QCARMSWPZ-1 Fixes: 77258d409ce4 ("ath10k: enable pci soc powersaving") Signed-off-by: Kang Yang --- drivers/net/wireless/ath/ath10k/pci.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 335bc7c488e4..0c671630cfc9 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -478,6 +478,10 @@ static int ath10k_pci_wake_wait(struct ath10k *ar) return 0; } + /* The device cannot wake once it is wedged. */ + if (ar->state == ATH10K_STATE_WEDGED) + return -ESHUTDOWN; + udelay(curr_delay); tot_delay += curr_delay; @@ -642,6 +646,16 @@ static void ath10k_bus_pci_write32(struct ath10k *ar, u32 offset, u32 value) if (ret) { ath10k_warn(ar, "failed to wake target for write32 of 0x%08x at 0x%08x: %d\n", value, offset, ret); + /* + * wake_wait timed out; the device is unresponsive at the + * MMIO level. write32 returns void so the write is + * silently dropped -- kick recovery here instead of + * letting an upper WMI wait notice it seconds later. + * Guards confine this to runtime; cmpxchg dedups. + */ + if (test_bit(ATH10K_FLAG_CORE_REGISTERED, &ar->dev_flags) && + ar->state == ATH10K_STATE_ON) + ath10k_core_start_recovery(ar); return; } @@ -665,6 +679,9 @@ static u32 ath10k_bus_pci_read32(struct ath10k *ar, u32 offset) if (ret) { ath10k_warn(ar, "failed to wake target for read32 at 0x%08x: %d\n", offset, ret); + if (test_bit(ATH10K_FLAG_CORE_REGISTERED, &ar->dev_flags) && + ar->state == ATH10K_STATE_ON) + ath10k_core_start_recovery(ar); return 0xffffffff; } @@ -2248,6 +2265,12 @@ static int ath10k_pci_bmi_wait(struct ath10k *ar, goto out; } + /* Stop waiting once the device is wedged. */ + if (ar->state == ATH10K_STATE_WEDGED) { + ret = -ESHUTDOWN; + goto out; + } + schedule(); } @@ -3308,6 +3331,10 @@ int ath10k_pci_wait_for_target_init(struct ath10k *ar) if (val & FW_IND_INITIALIZED) break; + /* Stop waiting once the device is wedged. */ + if (ar->state == ATH10K_STATE_WEDGED) + break; + if (ar_pci->oper_irq_mode == ATH10K_PCI_IRQ_INTX) /* Fix potential race by repeating CORE_BASE writes */ ath10k_pci_enable_intx_irq(ar); -- 2.34.1