Commit 83986543 authored by Kang Yang's avatar Kang Yang Committed by Kalle Valo

wifi: ath12k: add support one MSI vector

On some platforms it's not possible to allocate 32 MSI vectors for
various reasons, maybe kernel configuration, VT-d disabled, buggy BIOS
etc. So ath12k was not able to use WCN7850 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 ath12k 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 WCN7850 doesn't set this flag too. Ath12k doesn't need to leave IRQ
enabled in suspend state.

Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4
Signed-off-by: default avatarKang Yang <quic_kangyang@quicinc.com>
Acked-by: default avatarJeff Johnson <quic_jjohnson@quicinc.com>
Signed-off-by: default avatarKalle Valo <quic_kvalo@quicinc.com>
Link: https://lore.kernel.org/r/20231121021304.12966-6-quic_kangyang@quicinc.com
parent 6711b2a8
......@@ -251,6 +251,7 @@ static int ath12k_mhi_get_msi(struct ath12k_pci *ab_pci)
u32 user_base_data, base_vector;
int ret, num_vectors, i;
int *irq;
unsigned int msi_data;
ret = ath12k_pci_get_user_msi_assignment(ab,
"MHI", &num_vectors,
......@@ -265,9 +266,15 @@ static int ath12k_mhi_get_msi(struct ath12k_pci *ab_pci)
if (!irq)
return -ENOMEM;
for (i = 0; i < num_vectors; i++)
irq[i] = ath12k_pci_get_msi_irq(ab->dev,
base_vector + i);
msi_data = base_vector;
for (i = 0; i < num_vectors; i++) {
if (test_bit(ATH12K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags))
irq[i] = ath12k_pci_get_msi_irq(ab->dev,
msi_data++);
else
irq[i] = ath12k_pci_get_msi_irq(ab->dev,
msi_data);
}
ab_pci->mhi_ctrl->irq = irq;
ab_pci->mhi_ctrl->nr_irqs = num_vectors;
......@@ -374,6 +381,9 @@ int ath12k_mhi_register(struct ath12k_pci *ab_pci)
goto free_controller;
}
if (!test_bit(ATH12K_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;
......
......@@ -61,6 +61,17 @@ static const struct ath12k_msi_config ath12k_msi_config[] = {
},
};
static const struct ath12k_msi_config msi_config_one_msi = {
.total_vectors = 1,
.total_users = 4,
.users = (struct ath12k_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[ATH12K_IRQ_NUM_MAX] = {
"bhi",
"mhi-er0",
......@@ -414,16 +425,18 @@ static void ath12k_pci_sync_ce_irqs(struct ath12k_base *ab)
static void ath12k_pci_ce_tasklet(struct tasklet_struct *t)
{
struct ath12k_ce_pipe *ce_pipe = from_tasklet(ce_pipe, t, intr_tq);
int irq_idx = ATH12K_PCI_IRQ_CE0_OFFSET + ce_pipe->pipe_num;
ath12k_ce_per_engine_service(ce_pipe->ab, ce_pipe->pipe_num);
ath12k_pci_ce_irq_enable(ce_pipe->ab, ce_pipe->pipe_num);
enable_irq(ce_pipe->ab->irq_num[irq_idx]);
}
static irqreturn_t ath12k_pci_ce_interrupt_handler(int irq, void *arg)
{
struct ath12k_ce_pipe *ce_pipe = arg;
struct ath12k_base *ab = ce_pipe->ab;
int irq_idx = ATH12K_PCI_IRQ_CE0_OFFSET + ce_pipe->pipe_num;
if (!test_bit(ATH12K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags))
return IRQ_HANDLED;
......@@ -431,7 +444,8 @@ static irqreturn_t ath12k_pci_ce_interrupt_handler(int irq, void *arg)
/* last interrupt received for this CE */
ce_pipe->timestamp = jiffies;
ath12k_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;
......@@ -504,11 +518,13 @@ static int ath12k_pci_ext_grp_napi_poll(struct napi_struct *napi, int budget)
napi);
struct ath12k_base *ab = irq_grp->ab;
int work_done;
int i;
work_done = ath12k_dp_service_srng(ab, irq_grp, budget);
if (work_done < budget) {
napi_complete_done(napi, work_done);
ath12k_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)
......@@ -521,6 +537,7 @@ static irqreturn_t ath12k_pci_ext_interrupt_handler(int irq, void *arg)
{
struct ath12k_ext_irq_grp *irq_grp = arg;
struct ath12k_base *ab = irq_grp->ab;
int i;
if (!test_bit(ATH12K_FLAG_EXT_IRQ_ENABLED, &ab->dev_flags))
return IRQ_HANDLED;
......@@ -530,7 +547,8 @@ static irqreturn_t ath12k_pci_ext_interrupt_handler(int irq, void *arg)
/* last interrupt received for this group */
irq_grp->timestamp = jiffies;
ath12k_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);
......@@ -713,19 +731,27 @@ static int ath12k_pci_msi_alloc(struct ath12k_pci *ab_pci)
msi_config->total_vectors,
msi_config->total_vectors,
PCI_IRQ_MSI);
if (num_vectors != msi_config->total_vectors) {
ath12k_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(ATH12K_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(ATH12K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags);
ab_pci->msi_config = &msi_config_one_msi;
ab_pci->irq_flags = IRQF_SHARED | IRQF_NOBALANCING;
ath12k_dbg(ab, ATH12K_DBG_PCI, "request MSI one vector\n");
}
ath12k_info(ab, "MSI vectors: %d\n", num_vectors);
ath12k_pci_msi_disable(ab_pci);
msi_desc = irq_get_msi_desc(ab_pci->pdev->irq);
......@@ -746,6 +772,7 @@ static int ath12k_pci_msi_alloc(struct ath12k_pci *ab_pci)
free_msi_vector:
pci_free_irq_vectors(ab_pci->pdev);
reset_msi_config:
return ret;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment