From 9de1ee929dd2bce198ea9750d30e01fefa45e2fa Mon Sep 17 00:00:00 2001 From: Michael Tremer Date: Tue, 27 Sep 2022 15:47:24 +0000 Subject: [PATCH] linux: Backport patches from upstream to support QCN9074 Signed-off-by: Michael Tremer --- lfs/linux | 7 + ...ext-IRQ-flag-to-indicate-irq_handler.patch | 101 +++++++++ ...15-ath11k-add-support-one-MSI-vector.patch | 202 ++++++++++++++++++ ...re-ASPM-in-case-of-single-MSI-vector.patch | 48 +++++ ...ta-again-after-request_irq-is-called.patch | 83 +++++++ ...-MSI-enablement-during-rmmod-and-SSR.patch | 144 +++++++++++++ ...r-multiple-MSI-vector-implementation.patch | 180 ++++++++++++++++ ...-ATH11K_PCI_IRQ_DP_OFFSET-for-DP-IRQ.patch | 57 +++++ 8 files changed, 822 insertions(+) create mode 100644 src/patches/linux-5.15-ath11k-add-CE-and-ext-IRQ-flag-to-indicate-irq_handler.patch create mode 100644 src/patches/linux-5.15-ath11k-add-support-one-MSI-vector.patch create mode 100644 src/patches/linux-5.15-ath11k-do-not-restore-ASPM-in-case-of-single-MSI-vector.patch create mode 100644 src/patches/linux-5.15-ath11k-get_msi_data-again-after-request_irq-is-called.patch create mode 100644 src/patches/linux-5.15-ath11k-handle-MSI-enablement-during-rmmod-and-SSR.patch create mode 100644 src/patches/linux-5.15-ath11k-refactor-multiple-MSI-vector-implementation.patch create mode 100644 src/patches/linux-5.15-ath11k-use-ATH11K_PCI_IRQ_DP_OFFSET-for-DP-IRQ.patch diff --git a/lfs/linux b/lfs/linux index a1b32cc256..f9c96b6f8a 100644 --- 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 index 0000000000..8261c7682a --- /dev/null +++ b/src/patches/linux-5.15-ath11k-add-CE-and-ext-IRQ-flag-to-indicate-irq_handler.patch @@ -0,0 +1,101 @@ +From 01279bcd01d965b6526d575e036841778d8e3c4e Mon Sep 17 00:00:00 2001 +From: Carl Huang +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 +Signed-off-by: Kalle Valo +Signed-off-by: Baochen Qiang +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 index 0000000000..7a18fd6616 --- /dev/null +++ b/src/patches/linux-5.15-ath11k-add-support-one-MSI-vector.patch @@ -0,0 +1,202 @@ +From ac6e73483f7b4b5bde23b14fc3aaafc8341ae0c7 Mon Sep 17 00:00:00 2001 +From: Carl Huang +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 +Signed-off-by: Kalle Valo +Signed-off-by: Baochen Qiang +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 index 0000000000..d58ad6cf06 --- /dev/null +++ b/src/patches/linux-5.15-ath11k-do-not-restore-ASPM-in-case-of-single-MSI-vector.patch @@ -0,0 +1,48 @@ +From 915a081ff307d61d6551d6c16b542e03775353c4 Mon Sep 17 00:00:00 2001 +From: Carl Huang +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 +Signed-off-by: Kalle Valo +Signed-off-by: Baochen Qiang +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 index 0000000000..a7fdba3bae --- /dev/null +++ b/src/patches/linux-5.15-ath11k-get_msi_data-again-after-request_irq-is-called.patch @@ -0,0 +1,83 @@ +From 87b4072d7ef818e368b0f4162a1af2fb4727f51c Mon Sep 17 00:00:00 2001 +From: Carl Huang +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 +Signed-off-by: Kalle Valo +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 index 0000000000..51ac9e8380 --- /dev/null +++ b/src/patches/linux-5.15-ath11k-handle-MSI-enablement-during-rmmod-and-SSR.patch @@ -0,0 +1,144 @@ +From 96527d527b271d950367ad13e3de8b0673545622 Mon Sep 17 00:00:00 2001 +From: Baochen Qiang +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 +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +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 index 0000000000..6d7abc725b --- /dev/null +++ b/src/patches/linux-5.15-ath11k-refactor-multiple-MSI-vector-implementation.patch @@ -0,0 +1,180 @@ +From c41a6700b276ddf6ef93dcb43baca51ea0c4c7c1 Mon Sep 17 00:00:00 2001 +From: Carl Huang +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 +Signed-off-by: Kalle Valo +Signed-off-by: Baochen Qiang +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 index 0000000000..b92f5a9de2 --- /dev/null +++ b/src/patches/linux-5.15-ath11k-use-ATH11K_PCI_IRQ_DP_OFFSET-for-DP-IRQ.patch @@ -0,0 +1,57 @@ +From 4ab4693f327ad015c4637ae42dc53c8471aed9c8 Mon Sep 17 00:00:00 2001 +From: Carl Huang +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 +Signed-off-by: Kalle Valo +Signed-off-by: Baochen Qiang +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 + -- 2.39.5