| From d239380196c4e27a26fa4bea73d2bf994c14ec2d Mon Sep 17 00:00:00 2001 |
| From: Bryan O'Donoghue <bryan.odonoghue@linaro.org> |
| Date: Thu, 19 Dec 2019 13:15:38 +0000 |
| Subject: ath10k: pci: Only dump ATH10K_MEM_REGION_TYPE_IOREG when safe |
| |
| 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> |
| |
| --- |
| drivers/net/wireless/ath/ath10k/pci.c | 19 +++++++++++++++++-- |
| 1 file changed, 17 insertions(+), 2 deletions(-) |
| |
| --- a/drivers/net/wireless/ath/ath10k/pci.c |
| +++ b/drivers/net/wireless/ath/ath10k/pci.c |
| @@ -1604,11 +1604,22 @@ static int ath10k_pci_dump_memory_reg(st |
| { |
| 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 */ |
| @@ -1704,7 +1715,11 @@ static void ath10k_pci_dump_memory(struc |
| 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); |