mirror of
https://github.com/coolsnowwolf/lede.git
synced 2025-04-16 04:13:31 +00:00
196 lines
6.3 KiB
Diff
196 lines
6.3 KiB
Diff
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 108/120] 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(-)
|
|
|
|
--- 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 ath
|
|
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 ath
|
|
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;
|
|
@@ -341,6 +348,9 @@ int ath11k_mhi_register(struct ath11k_pc
|
|
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;
|
|
--- 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 at
|
|
},
|
|
};
|
|
|
|
+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(stru
|
|
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_interru
|
|
/* 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(
|
|
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_interr
|
|
{
|
|
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_interr
|
|
/* 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 a
|
|
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 a
|
|
free_msi_vector:
|
|
pci_free_irq_vectors(ab_pci->pdev);
|
|
|
|
+reset_msi_config:
|
|
return ret;
|
|
}
|
|
|