From: Bryan O'Donoghue bryan.odonoghue@linaro.org
commit d239380196c4e27a26fa4bea73d2bf994c14ec2d upstream.
ath10k_pci_dump_memory_reg() will try to access memory of type ATH10K_MEM_REGION_TYPE_IOREG however, if a hardware restart is in progress this can crash a system.
Individual ioread32() time has been observed to jump from 15-20 ticks to > 80k ticks followed by a secure-watchdog bite and a system reset.
Work around this corner case by only issuing the read transaction when the driver state is ATH10K_STATE_ON.
Tested-on: QCA9988 PCI 10.4-3.9.0.2-00044
Fixes: 219cc084c6706 ("ath10k: add memory dump support QCA9984") Signed-off-by: Bryan O'Donoghue bryan.odonoghue@linaro.org Signed-off-by: Kalle Valo kvalo@codeaurora.org Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- drivers/net/wireless/ath/ath10k/pci.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 2a503aa..caece83 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -1613,11 +1613,22 @@ static int ath10k_pci_dump_memory_reg(struct ath10k *ar, { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); u32 i; + int ret; + + mutex_lock(&ar->conf_mutex); + if (ar->state != ATH10K_STATE_ON) { + ath10k_warn(ar, "Skipping pci_dump_memory_reg invalid state\n"); + ret = -EIO; + goto done; + }
for (i = 0; i < region->len; i += 4) *(u32 *)(buf + i) = ioread32(ar_pci->mem + region->start + i);
- return region->len; + ret = region->len; +done: + mutex_unlock(&ar->conf_mutex); + return ret; }
/* if an error happened returns < 0, otherwise the length */ @@ -1713,7 +1724,11 @@ static void ath10k_pci_dump_memory(struct ath10k *ar, count = ath10k_pci_dump_memory_sram(ar, current_region, buf); break; case ATH10K_MEM_REGION_TYPE_IOREG: - count = ath10k_pci_dump_memory_reg(ar, current_region, buf); + ret = ath10k_pci_dump_memory_reg(ar, current_region, buf); + if (ret < 0) + break; + + count = ret; break; default: ret = ath10k_pci_dump_memory_generic(ar, current_region, buf);