mirror of
https://github.com/coolsnowwolf/lede.git
synced 2025-04-16 14:23:38 +00:00
140 lines
4.3 KiB
Diff
140 lines
4.3 KiB
Diff
From 96527d527b271d950367ad13e3de8b0673545622 Mon Sep 17 00:00:00 2001
|
|
From: Baochen Qiang <bqiang@codeaurora.org>
|
|
Date: Mon, 11 Oct 2021 09:33:08 +0300
|
|
Subject: [PATCH] ath11k: Handle MSI enablement during rmmod and SSR
|
|
|
|
When doing "rmmod ath11k_pci", ath11k performs global SOC reset
|
|
and MHI reset, where 0 address access is captured by IOMMU. See
|
|
log below:
|
|
|
|
...
|
|
[ 133.953860] ath11k_pci 0000:02:00.0: setting mhi state: DEINIT(1)
|
|
[ 133.959714] ath11k_pci 0000:02:00.0: AMD-Vi: Event logged [IO_PAGE_FAULT domain=0x000a address=0x0 flags=0x0020]
|
|
[ 133.973854] ath11k_pci 0000:02:00.0: MHISTATUS 0xff04
|
|
[ 133.974095] ath11k_pci 0000:02:00.0: AMD-Vi: Event logged [IO_PAGE_FAULT domain=0x000a address=0x0 flags=0x0020]
|
|
...
|
|
|
|
This issue is also observed in SSR process, cause a similar
|
|
sequence as above is performed.
|
|
|
|
Such an invalid access occurs because, during rmmod or SSR, MSI
|
|
address is cleared but HW MSI functionality not disabled, thus HW
|
|
target is able to raise an MSI transaction with 0 as MSI address.
|
|
|
|
So it can be fixed by simply disabling MSI before reset. For SSR,
|
|
since MSI functionality is still needed after target is brought
|
|
back, we need to reenable it.
|
|
|
|
Also change naming of some interfaces related.
|
|
|
|
Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1
|
|
Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1
|
|
|
|
Signed-off-by: Baochen Qiang <bqiang@codeaurora.org>
|
|
Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
|
|
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
|
Link: https://lore.kernel.org/r/20210913180246.193388-5-jouni@codeaurora.org
|
|
---
|
|
drivers/net/wireless/ath/ath11k/pci.c | 41 +++++++++++++++++++++++----
|
|
1 file changed, 36 insertions(+), 5 deletions(-)
|
|
|
|
--- a/drivers/net/wireless/ath/ath11k/pci.c
|
|
+++ b/drivers/net/wireless/ath/ath11k/pci.c
|
|
@@ -861,7 +861,32 @@ static void ath11k_pci_ce_irqs_enable(st
|
|
}
|
|
}
|
|
|
|
-static int ath11k_pci_enable_msi(struct ath11k_pci *ab_pci)
|
|
+static void ath11k_pci_msi_config(struct ath11k_pci *ab_pci, bool enable)
|
|
+{
|
|
+ struct pci_dev *dev = ab_pci->pdev;
|
|
+ u16 control;
|
|
+
|
|
+ pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &control);
|
|
+
|
|
+ if (enable)
|
|
+ control |= PCI_MSI_FLAGS_ENABLE;
|
|
+ else
|
|
+ control &= ~PCI_MSI_FLAGS_ENABLE;
|
|
+
|
|
+ pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, control);
|
|
+}
|
|
+
|
|
+static void ath11k_pci_msi_enable(struct ath11k_pci *ab_pci)
|
|
+{
|
|
+ ath11k_pci_msi_config(ab_pci, true);
|
|
+}
|
|
+
|
|
+static void ath11k_pci_msi_disable(struct ath11k_pci *ab_pci)
|
|
+{
|
|
+ ath11k_pci_msi_config(ab_pci, false);
|
|
+}
|
|
+
|
|
+static int ath11k_pci_alloc_msi(struct ath11k_pci *ab_pci)
|
|
{
|
|
struct ath11k_base *ab = ab_pci->ab;
|
|
const struct ath11k_msi_config *msi_config = ab_pci->msi_config;
|
|
@@ -882,6 +907,7 @@ static int ath11k_pci_enable_msi(struct
|
|
else
|
|
return num_vectors;
|
|
}
|
|
+ ath11k_pci_msi_disable(ab_pci);
|
|
|
|
msi_desc = irq_get_msi_desc(ab_pci->pdev->irq);
|
|
if (!msi_desc) {
|
|
@@ -904,7 +930,7 @@ free_msi_vector:
|
|
return ret;
|
|
}
|
|
|
|
-static void ath11k_pci_disable_msi(struct ath11k_pci *ab_pci)
|
|
+static void ath11k_pci_free_msi(struct ath11k_pci *ab_pci)
|
|
{
|
|
pci_free_irq_vectors(ab_pci->pdev);
|
|
}
|
|
@@ -1025,6 +1051,8 @@ static int ath11k_pci_power_up(struct at
|
|
*/
|
|
ath11k_pci_aspm_disable(ab_pci);
|
|
|
|
+ ath11k_pci_msi_enable(ab_pci);
|
|
+
|
|
ret = ath11k_mhi_start(ab_pci);
|
|
if (ret) {
|
|
ath11k_err(ab, "failed to start mhi: %d\n", ret);
|
|
@@ -1045,6 +1073,9 @@ static void ath11k_pci_power_down(struct
|
|
ath11k_pci_aspm_restore(ab_pci);
|
|
|
|
ath11k_pci_force_wake(ab_pci->ab);
|
|
+
|
|
+ ath11k_pci_msi_disable(ab_pci);
|
|
+
|
|
ath11k_mhi_stop(ab_pci);
|
|
clear_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags);
|
|
ath11k_pci_sw_reset(ab_pci->ab, false);
|
|
@@ -1279,7 +1310,7 @@ static int ath11k_pci_probe(struct pci_d
|
|
goto err_pci_free_region;
|
|
}
|
|
|
|
- ret = ath11k_pci_enable_msi(ab_pci);
|
|
+ ret = ath11k_pci_alloc_msi(ab_pci);
|
|
if (ret) {
|
|
ath11k_err(ab, "failed to enable msi: %d\n", ret);
|
|
goto err_pci_free_region;
|
|
@@ -1333,7 +1364,7 @@ err_mhi_unregister:
|
|
ath11k_mhi_unregister(ab_pci);
|
|
|
|
err_pci_disable_msi:
|
|
- ath11k_pci_disable_msi(ab_pci);
|
|
+ ath11k_pci_free_msi(ab_pci);
|
|
|
|
err_pci_free_region:
|
|
ath11k_pci_free_region(ab_pci);
|
|
@@ -1364,7 +1395,7 @@ qmi_fail:
|
|
ath11k_mhi_unregister(ab_pci);
|
|
|
|
ath11k_pci_free_irq(ab);
|
|
- ath11k_pci_disable_msi(ab_pci);
|
|
+ ath11k_pci_free_msi(ab_pci);
|
|
ath11k_pci_free_region(ab_pci);
|
|
|
|
ath11k_hal_srng_deinit(ab);
|