]> git.ipfire.org Git - people/ms/ipfire-2.x.git/commitdiff
linux: Backport patches from upstream to support QCN9074
authorMichael Tremer <michael.tremer@ipfire.org>
Tue, 27 Sep 2022 15:47:24 +0000 (15:47 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Tue, 27 Sep 2022 15:47:24 +0000 (15:47 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
lfs/linux
src/patches/linux-5.15-ath11k-add-CE-and-ext-IRQ-flag-to-indicate-irq_handler.patch [new file with mode: 0644]
src/patches/linux-5.15-ath11k-add-support-one-MSI-vector.patch [new file with mode: 0644]
src/patches/linux-5.15-ath11k-do-not-restore-ASPM-in-case-of-single-MSI-vector.patch [new file with mode: 0644]
src/patches/linux-5.15-ath11k-get_msi_data-again-after-request_irq-is-called.patch [new file with mode: 0644]
src/patches/linux-5.15-ath11k-handle-MSI-enablement-during-rmmod-and-SSR.patch [new file with mode: 0644]
src/patches/linux-5.15-ath11k-refactor-multiple-MSI-vector-implementation.patch [new file with mode: 0644]
src/patches/linux-5.15-ath11k-use-ATH11K_PCI_IRQ_DP_OFFSET-for-DP-IRQ.patch [new file with mode: 0644]

index a1b32cc25668ef2642c4b764273b6f4bf29bc1cd..f9c96b6f8a376318c739859e2f3180f2098abe44 100644 (file)
--- a/lfs/linux
+++ b/lfs/linux
@@ -124,6 +124,13 @@ $(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects))
        # 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
diff --git a/src/patches/linux-5.15-ath11k-add-CE-and-ext-IRQ-flag-to-indicate-irq_handler.patch b/src/patches/linux-5.15-ath11k-add-CE-and-ext-IRQ-flag-to-indicate-irq_handler.patch
new file mode 100644 (file)
index 0000000..8261c76
--- /dev/null
@@ -0,0 +1,101 @@
+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
+
diff --git a/src/patches/linux-5.15-ath11k-add-support-one-MSI-vector.patch b/src/patches/linux-5.15-ath11k-add-support-one-MSI-vector.patch
new file mode 100644 (file)
index 0000000..7a18fd6
--- /dev/null
@@ -0,0 +1,202 @@
+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
+
diff --git a/src/patches/linux-5.15-ath11k-do-not-restore-ASPM-in-case-of-single-MSI-vector.patch b/src/patches/linux-5.15-ath11k-do-not-restore-ASPM-in-case-of-single-MSI-vector.patch
new file mode 100644 (file)
index 0000000..d58ad6c
--- /dev/null
@@ -0,0 +1,48 @@
+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
+
diff --git a/src/patches/linux-5.15-ath11k-get_msi_data-again-after-request_irq-is-called.patch b/src/patches/linux-5.15-ath11k-get_msi_data-again-after-request_irq-is-called.patch
new file mode 100644 (file)
index 0000000..a7fdba3
--- /dev/null
@@ -0,0 +1,83 @@
+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
+
diff --git a/src/patches/linux-5.15-ath11k-handle-MSI-enablement-during-rmmod-and-SSR.patch b/src/patches/linux-5.15-ath11k-handle-MSI-enablement-during-rmmod-and-SSR.patch
new file mode 100644 (file)
index 0000000..51ac9e8
--- /dev/null
@@ -0,0 +1,144 @@
+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
+
diff --git a/src/patches/linux-5.15-ath11k-refactor-multiple-MSI-vector-implementation.patch b/src/patches/linux-5.15-ath11k-refactor-multiple-MSI-vector-implementation.patch
new file mode 100644 (file)
index 0000000..6d7abc7
--- /dev/null
@@ -0,0 +1,180 @@
+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
+
diff --git a/src/patches/linux-5.15-ath11k-use-ATH11K_PCI_IRQ_DP_OFFSET-for-DP-IRQ.patch b/src/patches/linux-5.15-ath11k-use-ATH11K_PCI_IRQ_DP_OFFSET-for-DP-IRQ.patch
new file mode 100644 (file)
index 0000000..b92f5a9
--- /dev/null
@@ -0,0 +1,57 @@
+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
+