提交 ac6e7348 编写于 作者: C Carl Huang 提交者: Kalle Valo

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: NCarl Huang <cjhuang@codeaurora.org>
Signed-off-by: NKalle Valo <kvalo@codeaurora.org>
Signed-off-by: NBaochen Qiang <bqiang@codeaurora.org>
Link: https://lore.kernel.org/r/20211026041714.5219-1-bqiang@codeaurora.org
上级 c41a6700
...@@ -248,6 +248,7 @@ static int ath11k_mhi_get_msi(struct ath11k_pci *ab_pci) ...@@ -248,6 +248,7 @@ static int ath11k_mhi_get_msi(struct ath11k_pci *ab_pci)
u32 user_base_data, base_vector; u32 user_base_data, base_vector;
int ret, num_vectors, i; int ret, num_vectors, i;
int *irq; int *irq;
unsigned int msi_data;
ret = ath11k_pci_get_user_msi_assignment(ab_pci, ret = ath11k_pci_get_user_msi_assignment(ab_pci,
"MHI", &num_vectors, "MHI", &num_vectors,
...@@ -262,9 +263,15 @@ static int ath11k_mhi_get_msi(struct ath11k_pci *ab_pci) ...@@ -262,9 +263,15 @@ static int ath11k_mhi_get_msi(struct ath11k_pci *ab_pci)
if (!irq) if (!irq)
return -ENOMEM; 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, irq[i] = ath11k_pci_get_msi_irq(ab->dev,
base_vector + i); msi_data);
}
ab_pci->mhi_ctrl->irq = irq; ab_pci->mhi_ctrl->irq = irq;
ab_pci->mhi_ctrl->nr_irqs = num_vectors; ab_pci->mhi_ctrl->nr_irqs = num_vectors;
...@@ -339,6 +346,9 @@ int ath11k_mhi_register(struct ath11k_pci *ab_pci) ...@@ -339,6 +346,9 @@ int ath11k_mhi_register(struct ath11k_pci *ab_pci)
return ret; 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_start = 0;
mhi_ctrl->iova_stop = 0xffffffff; mhi_ctrl->iova_stop = 0xffffffff;
mhi_ctrl->sbl_size = SZ_512K; mhi_ctrl->sbl_size = SZ_512K;
......
...@@ -77,6 +77,17 @@ static const struct ath11k_msi_config ath11k_msi_config[] = { ...@@ -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] = { static const char *irq_name[ATH11K_IRQ_NUM_MAX] = {
"bhi", "bhi",
"mhi-er0", "mhi-er0",
...@@ -619,16 +630,18 @@ static void ath11k_pci_sync_ce_irqs(struct ath11k_base *ab) ...@@ -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) static void ath11k_pci_ce_tasklet(struct tasklet_struct *t)
{ {
struct ath11k_ce_pipe *ce_pipe = from_tasklet(ce_pipe, t, intr_tq); 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_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) static irqreturn_t ath11k_pci_ce_interrupt_handler(int irq, void *arg)
{ {
struct ath11k_ce_pipe *ce_pipe = arg; struct ath11k_ce_pipe *ce_pipe = arg;
struct ath11k_base *ab = ce_pipe->ab; 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)) if (!test_bit(ATH11K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags))
return IRQ_HANDLED; return IRQ_HANDLED;
...@@ -636,7 +649,8 @@ static irqreturn_t ath11k_pci_ce_interrupt_handler(int irq, void *arg) ...@@ -636,7 +649,8 @@ static irqreturn_t ath11k_pci_ce_interrupt_handler(int irq, void *arg)
/* last interrupt received for this CE */ /* last interrupt received for this CE */
ce_pipe->timestamp = jiffies; 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); tasklet_schedule(&ce_pipe->intr_tq);
return IRQ_HANDLED; return IRQ_HANDLED;
...@@ -729,11 +743,13 @@ static int ath11k_pci_ext_grp_napi_poll(struct napi_struct *napi, int budget) ...@@ -729,11 +743,13 @@ static int ath11k_pci_ext_grp_napi_poll(struct napi_struct *napi, int budget)
napi); napi);
struct ath11k_base *ab = irq_grp->ab; struct ath11k_base *ab = irq_grp->ab;
int work_done; int work_done;
int i;
work_done = ath11k_dp_service_srng(ab, irq_grp, budget); work_done = ath11k_dp_service_srng(ab, irq_grp, budget);
if (work_done < budget) { if (work_done < budget) {
napi_complete_done(napi, work_done); 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) if (work_done > budget)
...@@ -746,6 +762,7 @@ static irqreturn_t ath11k_pci_ext_interrupt_handler(int irq, void *arg) ...@@ -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_ext_irq_grp *irq_grp = arg;
struct ath11k_base *ab = irq_grp->ab; struct ath11k_base *ab = irq_grp->ab;
int i;
if (!test_bit(ATH11K_FLAG_EXT_IRQ_ENABLED, &ab->dev_flags)) if (!test_bit(ATH11K_FLAG_EXT_IRQ_ENABLED, &ab->dev_flags))
return IRQ_HANDLED; return IRQ_HANDLED;
...@@ -755,7 +772,8 @@ static irqreturn_t ath11k_pci_ext_interrupt_handler(int irq, void *arg) ...@@ -755,7 +772,8 @@ static irqreturn_t ath11k_pci_ext_interrupt_handler(int irq, void *arg)
/* last interrupt received for this group */ /* last interrupt received for this group */
irq_grp->timestamp = jiffies; 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); napi_schedule(&irq_grp->napi);
...@@ -941,18 +959,25 @@ static int ath11k_pci_alloc_msi(struct ath11k_pci *ab_pci) ...@@ -941,18 +959,25 @@ static int ath11k_pci_alloc_msi(struct ath11k_pci *ab_pci)
msi_config->total_vectors, msi_config->total_vectors,
msi_config->total_vectors, msi_config->total_vectors,
PCI_IRQ_MSI); PCI_IRQ_MSI);
if (num_vectors != msi_config->total_vectors) { 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 {
set_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags); set_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags);
ab_pci->irq_flags = IRQF_SHARED; 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); ath11k_pci_msi_disable(ab_pci);
msi_desc = irq_get_msi_desc(ab_pci->pdev->irq); 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) ...@@ -973,6 +998,7 @@ static int ath11k_pci_alloc_msi(struct ath11k_pci *ab_pci)
free_msi_vector: free_msi_vector:
pci_free_irq_vectors(ab_pci->pdev); pci_free_irq_vectors(ab_pci->pdev);
reset_msi_config:
return ret; return ret;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册