# Wlan Patches
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/linux/linux-4.14_ath_user_regd.patch
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/linux/linux-4.9.8-iwlwifi-noibss_only_on_radar_chan.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/linux-5.15-ath11k-handle-MSI-enablement-during-rmmod-and-SSR.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/linux-5.15-ath11k-get_msi_data-again-after-request_irq-is-called.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/linux-5.15-ath11k-add-CE-and-ext-IRQ-flag-to-indicate-irq_handler.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/linux-5.15-ath11k-use-ATH11K_PCI_IRQ_DP_OFFSET-for-DP-IRQ.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/linux-5.15-ath11k-refactor-multiple-MSI-vector-implementation.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/linux-5.15-ath11k-add-support-one-MSI-vector.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/linux-5.15-ath11k-do-not-restore-ASPM-in-case-of-single-MSI-vector.patch
# Fix igb and e1000e crash
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/linux/linux-4.14.1-igb-e1000e_fix_lock_at_update_stats.patch
--- /dev/null
+From 01279bcd01d965b6526d575e036841778d8e3c4e Mon Sep 17 00:00:00 2001
+From: Carl Huang <cjhuang@codeaurora.org>
+Date: Fri, 19 Nov 2021 15:36:26 +0200
+Subject: ath11k: add CE and ext IRQ flag to indicate irq_handler
+
+This change adds two flags to indicate whether IRQ handler for CE
+and DP can be called. This is because in one MSI vector case,
+interrupt is not disabled in hif_stop and hif_irq_disable. Otherwise,
+MHI interrupt is disabled too.
+
+Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1
+
+Signed-off-by: Carl Huang <cjhuang@codeaurora.org>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+Signed-off-by: Baochen Qiang <bqiang@codeaurora.org>
+Link: https://lore.kernel.org/r/20211026041646.5060-1-bqiang@codeaurora.org
+---
+ drivers/net/wireless/ath/ath11k/core.h | 2 ++
+ drivers/net/wireless/ath/ath11k/pci.c | 16 ++++++++++++++++
+ 2 files changed, 18 insertions(+)
+
+(limited to 'drivers/net/wireless/ath/ath11k')
+
+diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h
+index bbfc10fd5c6d..74dce3518e9b 100644
+--- a/drivers/net/wireless/ath/ath11k/core.h
++++ b/drivers/net/wireless/ath/ath11k/core.h
+@@ -199,6 +199,8 @@ enum ath11k_dev_flags {
+ ATH11K_FLAG_REGISTERED,
+ ATH11K_FLAG_QMI_FAIL,
+ ATH11K_FLAG_HTC_SUSPEND_COMPLETE,
++ ATH11K_FLAG_CE_IRQ_ENABLED,
++ ATH11K_FLAG_EXT_IRQ_ENABLED,
+ };
+
+ enum ath11k_monitor_flags {
+diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c
+index 305aa7a72c59..a51fc4300655 100644
+--- a/drivers/net/wireless/ath/ath11k/pci.c
++++ b/drivers/net/wireless/ath/ath11k/pci.c
+@@ -578,6 +578,8 @@ static void ath11k_pci_ce_irqs_disable(struct ath11k_base *ab)
+ {
+ int i;
+
++ clear_bit(ATH11K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags);
++
+ for (i = 0; i < ab->hw_params.ce_count; i++) {
+ if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
+ continue;
+@@ -611,6 +613,10 @@ static void ath11k_pci_ce_tasklet(struct tasklet_struct *t)
+ static irqreturn_t ath11k_pci_ce_interrupt_handler(int irq, void *arg)
+ {
+ struct ath11k_ce_pipe *ce_pipe = arg;
++ struct ath11k_base *ab = ce_pipe->ab;
++
++ if (!test_bit(ATH11K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags))
++ return IRQ_HANDLED;
+
+ /* last interrupt received for this CE */
+ ce_pipe->timestamp = jiffies;
+@@ -633,6 +639,8 @@ static void __ath11k_pci_ext_irq_disable(struct ath11k_base *sc)
+ {
+ int i;
+
++ clear_bit(ATH11K_FLAG_EXT_IRQ_ENABLED, &sc->dev_flags);
++
+ for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
+ struct ath11k_ext_irq_grp *irq_grp = &sc->ext_irq_grp[i];
+
+@@ -655,6 +663,8 @@ static void ath11k_pci_ext_irq_enable(struct ath11k_base *ab)
+ {
+ int i;
+
++ set_bit(ATH11K_FLAG_EXT_IRQ_ENABLED, &ab->dev_flags);
++
+ for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
+ struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
+
+@@ -706,6 +716,10 @@ static int ath11k_pci_ext_grp_napi_poll(struct napi_struct *napi, int budget)
+ static irqreturn_t ath11k_pci_ext_interrupt_handler(int irq, void *arg)
+ {
+ struct ath11k_ext_irq_grp *irq_grp = arg;
++ struct ath11k_base *ab = irq_grp->ab;
++
++ if (!test_bit(ATH11K_FLAG_EXT_IRQ_ENABLED, &ab->dev_flags))
++ return IRQ_HANDLED;
+
+ ath11k_dbg(irq_grp->ab, ATH11K_DBG_PCI, "ext irq:%d\n", irq);
+
+@@ -852,6 +866,8 @@ static void ath11k_pci_ce_irqs_enable(struct ath11k_base *ab)
+ {
+ int i;
+
++ set_bit(ATH11K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags);
++
+ for (i = 0; i < ab->hw_params.ce_count; i++) {
+ if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
+ continue;
+--
+cgit v1.2.3
+
--- /dev/null
+From ac6e73483f7b4b5bde23b14fc3aaafc8341ae0c7 Mon Sep 17 00:00:00 2001
+From: Carl Huang <cjhuang@codeaurora.org>
+Date: Fri, 19 Nov 2021 15:36:26 +0200
+Subject: [PATCH] ath11k: add support one MSI vector
+
+On some platforms it's not possible to allocate 32 MSI vectors for various
+reasons, be it kernel configuration, VT-d disabled, buggy BIOS etc. So
+ath11k was not able to use QCA6390 PCI devices on those platforms. Add
+support for one MSI vector to solve that.
+
+In case of one MSI vector, interrupt migration needs to be disabled. This
+is because when interrupt migration happens, the msi_data may change.
+However, msi_data is already programmed to rings during initial phase and
+ath11k has no way to know that msi_data is changed during run time and
+reprogram again.
+
+In case of one MSI vector, MHI subsystem should not use IRQF_NO_SUSPEND
+as QCA6390 doesn't set this flag too. Ath11k doesn't need to leave
+IRQ enabled in suspend state.
+
+Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1
+
+Signed-off-by: Carl Huang <cjhuang@codeaurora.org>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+Signed-off-by: Baochen Qiang <bqiang@codeaurora.org>
+Link: https://lore.kernel.org/r/20211026041714.5219-1-bqiang@codeaurora.org
+---
+ drivers/net/wireless/ath/ath11k/mhi.c | 14 ++++++--
+ drivers/net/wireless/ath/ath11k/pci.c | 52 ++++++++++++++++++++-------
+ 2 files changed, 51 insertions(+), 15 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath11k/mhi.c b/drivers/net/wireless/ath/ath11k/mhi.c
+index 26c7ae242db6..d0f94a785a59 100644
+--- a/drivers/net/wireless/ath/ath11k/mhi.c
++++ b/drivers/net/wireless/ath/ath11k/mhi.c
+@@ -248,6 +248,7 @@ static int ath11k_mhi_get_msi(struct ath11k_pci *ab_pci)
+ u32 user_base_data, base_vector;
+ int ret, num_vectors, i;
+ int *irq;
++ unsigned int msi_data;
+
+ ret = ath11k_pci_get_user_msi_assignment(ab_pci,
+ "MHI", &num_vectors,
+@@ -262,9 +263,15 @@ static int ath11k_mhi_get_msi(struct ath11k_pci *ab_pci)
+ if (!irq)
+ return -ENOMEM;
+
+- for (i = 0; i < num_vectors; i++)
++ for (i = 0; i < num_vectors; i++) {
++ msi_data = base_vector;
++
++ if (test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags))
++ msi_data += i;
++
+ irq[i] = ath11k_pci_get_msi_irq(ab->dev,
+- base_vector + i);
++ msi_data);
++ }
+
+ ab_pci->mhi_ctrl->irq = irq;
+ ab_pci->mhi_ctrl->nr_irqs = num_vectors;
+@@ -339,6 +346,9 @@ int ath11k_mhi_register(struct ath11k_pci *ab_pci)
+ return ret;
+ }
+
++ if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags))
++ mhi_ctrl->irq_flags = IRQF_SHARED | IRQF_NOBALANCING;
++
+ mhi_ctrl->iova_start = 0;
+ mhi_ctrl->iova_stop = 0xffffffff;
+ mhi_ctrl->sbl_size = SZ_512K;
+diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c
+index 825d2846d10b..671a80b03973 100644
+--- a/drivers/net/wireless/ath/ath11k/pci.c
++++ b/drivers/net/wireless/ath/ath11k/pci.c
+@@ -77,6 +77,17 @@ static const struct ath11k_msi_config ath11k_msi_config[] = {
+ },
+ };
+
++static const struct ath11k_msi_config msi_config_one_msi = {
++ .total_vectors = 1,
++ .total_users = 4,
++ .users = (struct ath11k_msi_user[]) {
++ { .name = "MHI", .num_vectors = 3, .base_vector = 0 },
++ { .name = "CE", .num_vectors = 1, .base_vector = 0 },
++ { .name = "WAKE", .num_vectors = 1, .base_vector = 0 },
++ { .name = "DP", .num_vectors = 1, .base_vector = 0 },
++ },
++};
++
+ static const char *irq_name[ATH11K_IRQ_NUM_MAX] = {
+ "bhi",
+ "mhi-er0",
+@@ -619,16 +630,18 @@ static void ath11k_pci_sync_ce_irqs(struct ath11k_base *ab)
+ static void ath11k_pci_ce_tasklet(struct tasklet_struct *t)
+ {
+ struct ath11k_ce_pipe *ce_pipe = from_tasklet(ce_pipe, t, intr_tq);
++ int irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_pipe->pipe_num;
+
+ ath11k_ce_per_engine_service(ce_pipe->ab, ce_pipe->pipe_num);
+
+- ath11k_pci_ce_irq_enable(ce_pipe->ab, ce_pipe->pipe_num);
++ enable_irq(ce_pipe->ab->irq_num[irq_idx]);
+ }
+
+ static irqreturn_t ath11k_pci_ce_interrupt_handler(int irq, void *arg)
+ {
+ struct ath11k_ce_pipe *ce_pipe = arg;
+ struct ath11k_base *ab = ce_pipe->ab;
++ int irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_pipe->pipe_num;
+
+ if (!test_bit(ATH11K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags))
+ return IRQ_HANDLED;
+@@ -636,7 +649,8 @@ static irqreturn_t ath11k_pci_ce_interrupt_handler(int irq, void *arg)
+ /* last interrupt received for this CE */
+ ce_pipe->timestamp = jiffies;
+
+- ath11k_pci_ce_irq_disable(ce_pipe->ab, ce_pipe->pipe_num);
++ disable_irq_nosync(ab->irq_num[irq_idx]);
++
+ tasklet_schedule(&ce_pipe->intr_tq);
+
+ return IRQ_HANDLED;
+@@ -729,11 +743,13 @@ static int ath11k_pci_ext_grp_napi_poll(struct napi_struct *napi, int budget)
+ napi);
+ struct ath11k_base *ab = irq_grp->ab;
+ int work_done;
++ int i;
+
+ work_done = ath11k_dp_service_srng(ab, irq_grp, budget);
+ if (work_done < budget) {
+ napi_complete_done(napi, work_done);
+- ath11k_pci_ext_grp_enable(irq_grp);
++ for (i = 0; i < irq_grp->num_irq; i++)
++ enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
+ }
+
+ if (work_done > budget)
+@@ -746,6 +762,7 @@ static irqreturn_t ath11k_pci_ext_interrupt_handler(int irq, void *arg)
+ {
+ struct ath11k_ext_irq_grp *irq_grp = arg;
+ struct ath11k_base *ab = irq_grp->ab;
++ int i;
+
+ if (!test_bit(ATH11K_FLAG_EXT_IRQ_ENABLED, &ab->dev_flags))
+ return IRQ_HANDLED;
+@@ -755,7 +772,8 @@ static irqreturn_t ath11k_pci_ext_interrupt_handler(int irq, void *arg)
+ /* last interrupt received for this group */
+ irq_grp->timestamp = jiffies;
+
+- ath11k_pci_ext_grp_disable(irq_grp);
++ for (i = 0; i < irq_grp->num_irq; i++)
++ disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
+
+ napi_schedule(&irq_grp->napi);
+
+@@ -941,18 +959,25 @@ static int ath11k_pci_alloc_msi(struct ath11k_pci *ab_pci)
+ msi_config->total_vectors,
+ msi_config->total_vectors,
+ PCI_IRQ_MSI);
+- if (num_vectors != msi_config->total_vectors) {
+- ath11k_err(ab, "failed to get %d MSI vectors, only %d available",
+- msi_config->total_vectors, num_vectors);
+-
+- if (num_vectors >= 0)
+- return -EINVAL;
+- else
+- return num_vectors;
+- } else {
++ if (num_vectors == msi_config->total_vectors) {
+ set_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags);
+ ab_pci->irq_flags = IRQF_SHARED;
++ } else {
++ num_vectors = pci_alloc_irq_vectors(ab_pci->pdev,
++ 1,
++ 1,
++ PCI_IRQ_MSI);
++ if (num_vectors < 0) {
++ ret = -EINVAL;
++ goto reset_msi_config;
++ }
++ clear_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags);
++ ab_pci->msi_config = &msi_config_one_msi;
++ ab_pci->irq_flags = IRQF_SHARED | IRQF_NOBALANCING;
++ ath11k_dbg(ab, ATH11K_DBG_PCI, "request MSI one vector\n");
+ }
++ ath11k_info(ab, "MSI vectors: %d\n", num_vectors);
++
+ ath11k_pci_msi_disable(ab_pci);
+
+ msi_desc = irq_get_msi_desc(ab_pci->pdev->irq);
+@@ -973,6 +998,7 @@ static int ath11k_pci_alloc_msi(struct ath11k_pci *ab_pci)
+ free_msi_vector:
+ pci_free_irq_vectors(ab_pci->pdev);
+
++reset_msi_config:
+ return ret;
+ }
+
+--
+2.30.2
+
--- /dev/null
+From 915a081ff307d61d6551d6c16b542e03775353c4 Mon Sep 17 00:00:00 2001
+From: Carl Huang <cjhuang@codeaurora.org>
+Date: Fri, 19 Nov 2021 15:36:26 +0200
+Subject: ath11k: do not restore ASPM in case of single MSI vector
+
+Current code enables ASPM by default, it allows MHI to enter M2 state.
+In case of one MSI vector, system hang is observed if ath11k does MHI
+register reading in this state. The issue was reported on Dell XPS 13
+9310 but is seen also on XPS 15 and XPS 17 laptops.
+
+The workaround here is to prevent MHI from entering M2 state, this can
+be done by disabling ASPM if only one MSI vector is used. When using 32
+vectors ASPM is enabled as before.
+
+Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1
+
+Signed-off-by: Carl Huang <cjhuang@codeaurora.org>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+Signed-off-by: Baochen Qiang <bqiang@codeaurora.org>
+Link: https://lore.kernel.org/r/20211026041722.5271-1-bqiang@codeaurora.org
+---
+ drivers/net/wireless/ath/ath11k/pci.c | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+(limited to 'drivers/net/wireless/ath/ath11k')
+
+diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c
+index 671a80b03973..fb74638f970f 100644
+--- a/drivers/net/wireless/ath/ath11k/pci.c
++++ b/drivers/net/wireless/ath/ath11k/pci.c
+@@ -1223,7 +1223,13 @@ static int ath11k_pci_start(struct ath11k_base *ab)
+
+ set_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags);
+
+- ath11k_pci_aspm_restore(ab_pci);
++ /* TODO: for now don't restore ASPM in case of single MSI
++ * vector as MHI register reading in M2 causes system hang.
++ */
++ if (test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags))
++ ath11k_pci_aspm_restore(ab_pci);
++ else
++ ath11k_info(ab, "leaving PCI ASPM disabled to avoid MHI M2 problems\n");
+
+ ath11k_pci_ce_irqs_enable(ab);
+ ath11k_ce_rx_post_buf(ab);
+--
+cgit v1.2.3
+
--- /dev/null
+From 87b4072d7ef818e368b0f4162a1af2fb4727f51c Mon Sep 17 00:00:00 2001
+From: Carl Huang <cjhuang@codeaurora.org>
+Date: Fri, 19 Nov 2021 15:36:26 +0200
+Subject: ath11k: get msi_data again after request_irq is called
+
+The reservation mode of interrupts in kernel assigns a dummy vector
+when the interrupt is allocated and assigns a real vector when the
+request_irq is called. The reservation mode helps to ease vector
+pressure when devices with a large amount of queues/interrupts
+are initialized, but only a minimal subset of those queues/interrupts
+is actually used.
+
+So on reservation mode, the msi_data may change after request_irq
+is called, so ath11k reads msi_data again after request_irq is called,
+and then the correct msi_data is programmed into QCA6390 hardware
+components. Without this change, spurious interrupt occurs in case of
+one MSI vector. When VT-d in BIOS is enabled and ath11k can get 32 MSI
+vectors, ath11k always get the same msi_data before and after request_irq,
+that's why this change is only required when one MSI vector is to be
+supported.
+
+Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1
+
+Signed-off-by: Carl Huang <cjhuang@codeaurora.org>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+Link: https://lore.kernel.org/r/20211026041636.5008-1-bqiang@codeaurora.org
+---
+ drivers/net/wireless/ath/ath11k/pci.c | 30 ++++++++++++++++++++++++++++++
+ 1 file changed, 30 insertions(+)
+
+(limited to 'drivers/net/wireless/ath/ath11k')
+
+diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c
+index c2af8184e4a2..305aa7a72c59 100644
+--- a/drivers/net/wireless/ath/ath11k/pci.c
++++ b/drivers/net/wireless/ath/ath11k/pci.c
+@@ -933,6 +933,25 @@ static void ath11k_pci_free_msi(struct ath11k_pci *ab_pci)
+ pci_free_irq_vectors(ab_pci->pdev);
+ }
+
++static int ath11k_pci_config_msi_data(struct ath11k_pci *ab_pci)
++{
++ struct msi_desc *msi_desc;
++
++ msi_desc = irq_get_msi_desc(ab_pci->pdev->irq);
++ if (!msi_desc) {
++ ath11k_err(ab_pci->ab, "msi_desc is NULL!\n");
++ pci_free_irq_vectors(ab_pci->pdev);
++ return -EINVAL;
++ }
++
++ ab_pci->msi_ep_base_data = msi_desc->msg.data;
++
++ ath11k_dbg(ab_pci->ab, ATH11K_DBG_PCI, "pci after request_irq msi_ep_base_data %d\n",
++ ab_pci->msi_ep_base_data);
++
++ return 0;
++}
++
+ static int ath11k_pci_claim(struct ath11k_pci *ab_pci, struct pci_dev *pdev)
+ {
+ struct ath11k_base *ab = ab_pci->ab;
+@@ -1342,6 +1361,17 @@ static int ath11k_pci_probe(struct pci_dev *pdev,
+ goto err_ce_free;
+ }
+
++ /* kernel may allocate a dummy vector before request_irq and
++ * then allocate a real vector when request_irq is called.
++ * So get msi_data here again to avoid spurious interrupt
++ * as msi_data will configured to srngs.
++ */
++ ret = ath11k_pci_config_msi_data(ab_pci);
++ if (ret) {
++ ath11k_err(ab, "failed to config msi_data: %d\n", ret);
++ goto err_free_irq;
++ }
++
+ ret = ath11k_core_init(ab);
+ if (ret) {
+ ath11k_err(ab, "failed to init core: %d\n", ret);
+--
+cgit v1.2.3
+
--- /dev/null
+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(-)
+
+diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c
+index 7b3bce0ba76e..3d353e7c9d5c 100644
+--- a/drivers/net/wireless/ath/ath11k/pci.c
++++ b/drivers/net/wireless/ath/ath11k/pci.c
+@@ -855,7 +855,32 @@ static void ath11k_pci_ce_irqs_enable(struct ath11k_base *ab)
+ }
+ }
+
+-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;
+@@ -876,6 +901,7 @@ static int ath11k_pci_enable_msi(struct ath11k_pci *ab_pci)
+ else
+ return num_vectors;
+ }
++ ath11k_pci_msi_disable(ab_pci);
+
+ msi_desc = irq_get_msi_desc(ab_pci->pdev->irq);
+ if (!msi_desc) {
+@@ -898,7 +924,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);
+ }
+@@ -1019,6 +1045,8 @@ static int ath11k_pci_power_up(struct ath11k_base *ab)
+ */
+ 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);
+@@ -1039,6 +1067,9 @@ static void ath11k_pci_power_down(struct ath11k_base *ab)
+ 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);
+@@ -1263,7 +1294,7 @@ static int ath11k_pci_probe(struct pci_dev *pdev,
+ 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;
+@@ -1317,7 +1348,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);
+@@ -1348,7 +1379,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);
+--
+2.30.2
+
--- /dev/null
+From c41a6700b276ddf6ef93dcb43baca51ea0c4c7c1 Mon Sep 17 00:00:00 2001
+From: Carl Huang <cjhuang@codeaurora.org>
+Date: Fri, 19 Nov 2021 15:36:26 +0200
+Subject: [PATCH] ath11k: refactor multiple MSI vector implementation
+
+This is to prepare for one MSI vector support. IRQ enable and disable
+of CE and DP are done only in case of multiple MSI vectors.
+
+Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1
+
+Signed-off-by: Carl Huang <cjhuang@codeaurora.org>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+Signed-off-by: Baochen Qiang <bqiang@codeaurora.org>
+Link: https://lore.kernel.org/r/20211026041705.5167-1-bqiang@codeaurora.org
+---
+ drivers/net/wireless/ath/ath11k/pci.c | 48 ++++++++++++++++++++++-----
+ drivers/net/wireless/ath/ath11k/pci.h | 3 ++
+ 2 files changed, 43 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c
+index c74e24ce0bd3..825d2846d10b 100644
+--- a/drivers/net/wireless/ath/ath11k/pci.c
++++ b/drivers/net/wireless/ath/ath11k/pci.c
+@@ -486,11 +486,11 @@ int ath11k_pci_get_user_msi_assignment(struct ath11k_pci *ab_pci, char *user_nam
+ for (idx = 0; idx < msi_config->total_users; idx++) {
+ if (strcmp(user_name, msi_config->users[idx].name) == 0) {
+ *num_vectors = msi_config->users[idx].num_vectors;
+- *user_base_data = msi_config->users[idx].base_vector
+- + ab_pci->msi_ep_base_data;
+- *base_vector = msi_config->users[idx].base_vector;
++ *base_vector = msi_config->users[idx].base_vector;
++ *user_base_data = *base_vector + ab_pci->msi_ep_base_data;
+
+- ath11k_dbg(ab, ATH11K_DBG_PCI, "Assign MSI to user: %s, num_vectors: %d, user_base_data: %u, base_vector: %u\n",
++ ath11k_dbg(ab, ATH11K_DBG_PCI,
++ "Assign MSI to user: %s, num_vectors: %d, user_base_data: %u, base_vector: %u\n",
+ user_name, *num_vectors, *user_base_data,
+ *base_vector);
+
+@@ -561,16 +561,30 @@ static void ath11k_pci_free_irq(struct ath11k_base *ab)
+
+ static void ath11k_pci_ce_irq_enable(struct ath11k_base *ab, u16 ce_id)
+ {
++ struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
+ u32 irq_idx;
+
++ /* In case of one MSI vector, we handle irq enable/disable in a
++ * uniform way since we only have one irq
++ */
++ if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags))
++ return;
++
+ irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id;
+ enable_irq(ab->irq_num[irq_idx]);
+ }
+
+ static void ath11k_pci_ce_irq_disable(struct ath11k_base *ab, u16 ce_id)
+ {
++ struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
+ u32 irq_idx;
+
++ /* In case of one MSI vector, we handle irq enable/disable in a
++ * uniform way since we only have one irq
++ */
++ if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags))
++ return;
++
+ irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id;
+ disable_irq_nosync(ab->irq_num[irq_idx]);
+ }
+@@ -630,8 +644,15 @@ static irqreturn_t ath11k_pci_ce_interrupt_handler(int irq, void *arg)
+
+ static void ath11k_pci_ext_grp_disable(struct ath11k_ext_irq_grp *irq_grp)
+ {
++ struct ath11k_pci *ab_pci = ath11k_pci_priv(irq_grp->ab);
+ int i;
+
++ /* In case of one MSI vector, we handle irq enable/disable
++ * in a uniform way since we only have one irq
++ */
++ if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags))
++ return;
++
+ for (i = 0; i < irq_grp->num_irq; i++)
+ disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
+ }
+@@ -654,8 +675,15 @@ static void __ath11k_pci_ext_irq_disable(struct ath11k_base *sc)
+
+ static void ath11k_pci_ext_grp_enable(struct ath11k_ext_irq_grp *irq_grp)
+ {
++ struct ath11k_pci *ab_pci = ath11k_pci_priv(irq_grp->ab);
+ int i;
+
++ /* In case of one MSI vector, we handle irq enable/disable in a
++ * uniform way since we only have one irq
++ */
++ if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags))
++ return;
++
+ for (i = 0; i < irq_grp->num_irq; i++)
+ enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
+ }
+@@ -736,6 +764,7 @@ static irqreturn_t ath11k_pci_ext_interrupt_handler(int irq, void *arg)
+
+ static int ath11k_pci_ext_irq_config(struct ath11k_base *ab)
+ {
++ struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
+ int i, j, ret, num_vectors = 0;
+ u32 user_base_data = 0, base_vector = 0;
+
+@@ -782,16 +811,15 @@ static int ath11k_pci_ext_irq_config(struct ath11k_base *ab)
+
+ irq_set_status_flags(irq, IRQ_DISABLE_UNLAZY);
+ ret = request_irq(irq, ath11k_pci_ext_interrupt_handler,
+- IRQF_SHARED,
++ ab_pci->irq_flags,
+ "DP_EXT_IRQ", irq_grp);
+ if (ret) {
+ ath11k_err(ab, "failed request irq %d: %d\n",
+ vector, ret);
+ return ret;
+ }
+-
+- disable_irq_nosync(ab->irq_num[irq_idx]);
+ }
++ ath11k_pci_ext_grp_disable(irq_grp);
+ }
+
+ return 0;
+@@ -799,6 +827,7 @@ static int ath11k_pci_ext_irq_config(struct ath11k_base *ab)
+
+ static int ath11k_pci_config_irq(struct ath11k_base *ab)
+ {
++ struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
+ struct ath11k_ce_pipe *ce_pipe;
+ u32 msi_data_start;
+ u32 msi_data_count, msi_data_idx;
+@@ -826,7 +855,7 @@ static int ath11k_pci_config_irq(struct ath11k_base *ab)
+ tasklet_setup(&ce_pipe->intr_tq, ath11k_pci_ce_tasklet);
+
+ ret = request_irq(irq, ath11k_pci_ce_interrupt_handler,
+- IRQF_SHARED, irq_name[irq_idx],
++ ab_pci->irq_flags, irq_name[irq_idx],
+ ce_pipe);
+ if (ret) {
+ ath11k_err(ab, "failed to request irq %d: %d\n",
+@@ -920,6 +949,9 @@ static int ath11k_pci_alloc_msi(struct ath11k_pci *ab_pci)
+ return -EINVAL;
+ else
+ return num_vectors;
++ } else {
++ set_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags);
++ ab_pci->irq_flags = IRQF_SHARED;
+ }
+ ath11k_pci_msi_disable(ab_pci);
+
+diff --git a/drivers/net/wireless/ath/ath11k/pci.h b/drivers/net/wireless/ath/ath11k/pci.h
+index f3e645891d19..61d67b20a0eb 100644
+--- a/drivers/net/wireless/ath/ath11k/pci.h
++++ b/drivers/net/wireless/ath/ath11k/pci.h
+@@ -68,6 +68,7 @@ enum ath11k_pci_flags {
+ ATH11K_PCI_FLAG_INIT_DONE,
+ ATH11K_PCI_FLAG_IS_MSI_64,
+ ATH11K_PCI_ASPM_RESTORE,
++ ATH11K_PCI_FLAG_MULTI_MSI_VECTORS,
+ };
+
+ struct ath11k_pci {
+@@ -87,6 +88,8 @@ struct ath11k_pci {
+ /* enum ath11k_pci_flags */
+ unsigned long flags;
+ u16 link_ctl;
++
++ unsigned long irq_flags;
+ };
+
+ static inline struct ath11k_pci *ath11k_pci_priv(struct ath11k_base *ab)
+--
+2.30.2
+
--- /dev/null
+From 4ab4693f327ad015c4637ae42dc53c8471aed9c8 Mon Sep 17 00:00:00 2001
+From: Carl Huang <cjhuang@codeaurora.org>
+Date: Fri, 19 Nov 2021 15:36:26 +0200
+Subject: ath11k: use ATH11K_PCI_IRQ_DP_OFFSET for DP IRQ
+
+Like ATH11K_PCI_IRQ_CE0_OFFSET, define ATH11K_PCI_IRQ_DP_OFFSET for
+DP to save the IRQ instead of base_vector from MSI config.
+
+Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1
+
+Signed-off-by: Carl Huang <cjhuang@codeaurora.org>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+Signed-off-by: Baochen Qiang <bqiang@codeaurora.org>
+Link: https://lore.kernel.org/r/20211026041655.5112-1-bqiang@codeaurora.org
+---
+ drivers/net/wireless/ath/ath11k/pci.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+(limited to 'drivers/net/wireless/ath/ath11k')
+
+diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c
+index a51fc4300655..c74e24ce0bd3 100644
+--- a/drivers/net/wireless/ath/ath11k/pci.c
++++ b/drivers/net/wireless/ath/ath11k/pci.c
+@@ -16,7 +16,8 @@
+ #define ATH11K_PCI_BAR_NUM 0
+ #define ATH11K_PCI_DMA_MASK 32
+
+-#define ATH11K_PCI_IRQ_CE0_OFFSET 3
++#define ATH11K_PCI_IRQ_CE0_OFFSET 3
++#define ATH11K_PCI_IRQ_DP_OFFSET 14
+
+ #define WINDOW_ENABLE_BIT 0x40000000
+ #define WINDOW_REG_ADDRESS 0x310c
+@@ -736,9 +737,8 @@ static irqreturn_t ath11k_pci_ext_interrupt_handler(int irq, void *arg)
+ static int ath11k_pci_ext_irq_config(struct ath11k_base *ab)
+ {
+ int i, j, ret, num_vectors = 0;
+- u32 user_base_data = 0, base_vector = 0, base_idx;
++ u32 user_base_data = 0, base_vector = 0;
+
+- base_idx = ATH11K_PCI_IRQ_CE0_OFFSET + CE_COUNT_MAX;
+ ret = ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab), "DP",
+ &num_vectors,
+ &user_base_data,
+@@ -768,7 +768,7 @@ static int ath11k_pci_ext_irq_config(struct ath11k_base *ab)
+ }
+
+ irq_grp->num_irq = num_irq;
+- irq_grp->irqs[0] = base_idx + i;
++ irq_grp->irqs[0] = ATH11K_PCI_IRQ_DP_OFFSET + i;
+
+ for (j = 0; j < irq_grp->num_irq; j++) {
+ int irq_idx = irq_grp->irqs[j];
+--
+cgit v1.2.3
+