[PATCH 356/379][SRU][OEM-5.6] UBUNTU: SAUCE: ath11k: pci: support platforms with one MSI vector
You-Sheng Yang
vicamo.yang at canonical.com
Wed Dec 23 08:51:29 UTC 2020
From: Carl Huang <cjhuang at codeaurora.org>
BugLink: https://bugs.launchpad.net/bugs/1879633
Dell XPS 13 9310 has only one MSI vector available for QCA6390 device and ath11k fails with:
ath11k_pci 0000:56:00.0: failed to get 32 MSI vectors, only -28 available
ath11k_pci 0000:56:00.0: failed to enable msi: -28
ath11k_pci: probe of 0000:56:00.0 failed with error -28
This is a proof of concept patch for getting ath11k to work with QCA6390 using
only one MSI vector, not the final solution. Testing feedback more than
welcome. The patch applies to v5.10-rc2.
The idea here is to add a flag to indicate whether this ISR can be called
or not as all the ISR handlers are registered with IRQF_SHARED when ath11k can
only request 1 vector. This needs to be refined later.
In some scenarios, kernel crashed when the interrupt migration happens, so add
IRQF_NOBALANCING.
Also add debug messages to ath11k_qmi_respond_fw_mem_request() for helping to
debug mysterious firmware initialisation timeouts:
ath11k_pci 0000:05:00.0: qmi failed memory request, err = -110
ath11k_pci 0000:05:00.0: qmi failed to respond fw mem req:-110
If that happens, one way to workaround the problem is to revert this commit:
7fef431be9c9 mm/page_alloc: place pages to tail in __free_pages_core()
Link: https://lore.kernel.org/linux-pci/87mtzxkus5.fsf@nanos.tec.linutronix.de/
Link: http://lists.infradead.org/pipermail/ath11k/2020-November/000550.html
Signed-off-by: Carl Huang <cjhuang at codeaurora.org>
Signed-off-by: Kalle Valo <kvalo at codeaurora.org>
(cherry picked from commit 59c6d022df8efb450f82d33dd6a6812935bd022f
https://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git)
Signed-off-by: You-Sheng Yang <vicamo.yang at canonical.com>
---
drivers/bus/mhi/core/init.c | 4 +-
drivers/net/wireless/ath/ath11k/ce.c | 6 +-
drivers/net/wireless/ath/ath11k/core.h | 1 +
drivers/net/wireless/ath/ath11k/dp.c | 8 +-
drivers/net/wireless/ath/ath11k/hif.h | 1 +
drivers/net/wireless/ath/ath11k/mhi.c | 11 +-
drivers/net/wireless/ath/ath11k/pci.c | 169 ++++++++++++++++++++-----
drivers/net/wireless/ath/ath11k/pci.h | 1 +
8 files changed, 163 insertions(+), 38 deletions(-)
diff --git a/drivers/bus/mhi/core/init.c b/drivers/bus/mhi/core/init.c
index 0ffdebde8265..d182ffdbaf64 100644
--- a/drivers/bus/mhi/core/init.c
+++ b/drivers/bus/mhi/core/init.c
@@ -153,7 +153,7 @@ int mhi_init_irq_setup(struct mhi_controller *mhi_cntrl)
/* Setup BHI_INTVEC IRQ */
ret = request_threaded_irq(mhi_cntrl->irq[0], mhi_intvec_handler,
mhi_intvec_threaded_handler,
- IRQF_SHARED | IRQF_NO_SUSPEND,
+ IRQF_SHARED | IRQF_NOBALANCING,
"bhi", mhi_cntrl);
if (ret)
return ret;
@@ -171,7 +171,7 @@ int mhi_init_irq_setup(struct mhi_controller *mhi_cntrl)
ret = request_irq(mhi_cntrl->irq[mhi_event->irq],
mhi_irq_handler,
- IRQF_SHARED | IRQF_NO_SUSPEND,
+ IRQF_SHARED | IRQF_NOBALANCING,
"mhi", mhi_event);
if (ret) {
dev_err(dev, "Error requesting irq:%d for ev:%d\n",
diff --git a/drivers/net/wireless/ath/ath11k/ce.c b/drivers/net/wireless/ath/ath11k/ce.c
index 9d730f8ac816..46c717a344c3 100644
--- a/drivers/net/wireless/ath/ath11k/ce.c
+++ b/drivers/net/wireless/ath/ath11k/ce.c
@@ -459,20 +459,22 @@ static void ath11k_ce_srng_msi_ring_params_setup(struct ath11k_base *ab, u32 ce_
u32 msi_irq_start;
u32 addr_lo;
u32 addr_hi;
+ u32 vectors_32_capability;
int ret;
ret = ath11k_get_user_msi_vector(ab, "CE",
&msi_data_count, &msi_data_start,
&msi_irq_start);
-
if (ret)
return;
+ vectors_32_capability = ab->hif.ops->is_32_vecs_support(ab);
ath11k_get_msi_address(ab, &addr_lo, &addr_hi);
ring_params->msi_addr = addr_lo;
ring_params->msi_addr |= (dma_addr_t)(((uint64_t)addr_hi) << 32);
- ring_params->msi_data = (ce_id % msi_data_count) + msi_data_start;
+ ring_params->msi_data = vectors_32_capability ?
+ (ce_id % msi_data_count) + msi_data_start : msi_data_start;
ring_params->flags |= HAL_SRNG_FLAGS_MSI_INTR;
}
diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h
index 18b97420f0d8..0de6b2cd8c75 100644
--- a/drivers/net/wireless/ath/ath11k/core.h
+++ b/drivers/net/wireless/ath/ath11k/core.h
@@ -683,6 +683,7 @@ struct ath11k_base {
bool wmi_ready;
u32 wlan_init_status;
int irq_num[ATH11K_IRQ_NUM_MAX];
+ int irq_enable_flag[ATH11K_IRQ_NUM_MAX];
struct ath11k_ext_irq_grp ext_irq_grp[ATH11K_EXT_IRQ_GRP_NUM_MAX];
struct napi_struct *napi;
struct ath11k_targ_cap target_caps;
diff --git a/drivers/net/wireless/ath/ath11k/dp.c b/drivers/net/wireless/ath/ath11k/dp.c
index 59dd185a0cfc..b7288dc47199 100644
--- a/drivers/net/wireless/ath/ath11k/dp.c
+++ b/drivers/net/wireless/ath/ath11k/dp.c
@@ -180,13 +180,15 @@ static void ath11k_dp_srng_msi_setup(struct ath11k_base *ab,
{
int msi_group_number, msi_data_count;
u32 msi_data_start, msi_irq_start, addr_lo, addr_hi;
- int ret;
+ u32 vectors_32_capability;
+ int ret = -EINVAL;
ret = ath11k_get_user_msi_vector(ab, "DP",
&msi_data_count, &msi_data_start,
&msi_irq_start);
if (ret)
return;
+ vectors_32_capability = ab->hif.ops->is_32_vecs_support(ab);
msi_group_number = ath11k_dp_srng_calculate_msi_group(ab, type,
ring_num);
@@ -209,8 +211,8 @@ static void ath11k_dp_srng_msi_setup(struct ath11k_base *ab,
ring_params->msi_addr = addr_lo;
ring_params->msi_addr |= (dma_addr_t)(((uint64_t)addr_hi) << 32);
- ring_params->msi_data = (msi_group_number % msi_data_count)
- + msi_data_start;
+ ring_params->msi_data = vectors_32_capability ?
+ (msi_group_number % msi_data_count) + msi_data_start : msi_data_start;
ring_params->flags |= HAL_SRNG_FLAGS_MSI_INTR;
}
diff --git a/drivers/net/wireless/ath/ath11k/hif.h b/drivers/net/wireless/ath/ath11k/hif.h
index dbe5568916e8..b6bde194a390 100644
--- a/drivers/net/wireless/ath/ath11k/hif.h
+++ b/drivers/net/wireless/ath/ath11k/hif.h
@@ -24,6 +24,7 @@ struct ath11k_hif_ops {
u32 *base_vector);
void (*get_msi_address)(struct ath11k_base *ab, u32 *msi_addr_lo,
u32 *msi_addr_hi);
+ int (*is_32_vecs_support)(struct ath11k_base *ab);
};
static inline int ath11k_hif_start(struct ath11k_base *sc)
diff --git a/drivers/net/wireless/ath/ath11k/mhi.c b/drivers/net/wireless/ath/ath11k/mhi.c
index aded9a719d51..80d7dd18034d 100644
--- a/drivers/net/wireless/ath/ath11k/mhi.c
+++ b/drivers/net/wireless/ath/ath11k/mhi.c
@@ -156,14 +156,17 @@ static int ath11k_mhi_get_msi(struct ath11k_pci *ab_pci)
{
struct ath11k_base *ab = ab_pci->ab;
u32 user_base_data, base_vector;
+ u32 vectors_32_capability;
int ret, num_vectors, i;
int *irq;
+ unsigned int msi_data;
ret = ath11k_pci_get_user_msi_assignment(ab_pci,
"MHI", &num_vectors,
&user_base_data, &base_vector);
if (ret)
return ret;
+ vectors_32_capability = ab_pci->vectors_32_capability;
ath11k_dbg(ab, ATH11K_DBG_PCI, "Number of assigned MSI for MHI is %d, base vector is %d\n",
num_vectors, base_vector);
@@ -172,9 +175,13 @@ 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 = vectors_32_capability ?
+ i + base_vector : base_vector;
+
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;
diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c
index d887d1dc4c4a..a07ded84eec8 100644
--- a/drivers/net/wireless/ath/ath11k/pci.c
+++ b/drivers/net/wireless/ath/ath11k/pci.c
@@ -17,6 +17,7 @@
#define ATH11K_PCI_DMA_MASK 32
#define ATH11K_PCI_IRQ_CE0_OFFSET 3
+#define ATH11K_PCI_IRQ_DP_OFFSET 14
#define WINDOW_ENABLE_BIT 0x40000000
#define WINDOW_REG_ADDRESS 0x310c
@@ -283,14 +284,15 @@ int ath11k_pci_get_user_msi_assignment(struct ath11k_pci *ab_pci, char *user_nam
u32 *base_vector)
{
struct ath11k_base *ab = ab_pci->ab;
+ u32 msi_32_cap = ab_pci->vectors_32_capability;
int idx;
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_32_cap ?
+ msi_config.users[idx].base_vector : 0;
+ *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",
user_name, *num_vectors, *user_base_data,
@@ -344,20 +346,38 @@ static void ath11k_pci_free_irq(struct ath11k_base *ab)
ath11k_pci_free_ext_irq(ab);
}
+static void ath11k_pci_set_irq_enable_flag(struct ath11k_base *ab, u32 irq_idx, int flag)
+{
+ ab->irq_enable_flag[irq_idx] = flag;
+}
+
static void ath11k_pci_ce_irq_enable(struct ath11k_base *ab, u16 ce_id)
{
u32 irq_idx;
+ u32 vecs_32_cap;
- irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id;
- enable_irq(ab->irq_num[irq_idx]);
+ vecs_32_cap = ath11k_pci_priv(ab)->vectors_32_capability;
+ irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id;
+
+ if (vecs_32_cap)
+ enable_irq(ab->irq_num[irq_idx]);
+
+ ath11k_pci_set_irq_enable_flag(ab, irq_idx, 1);
}
static void ath11k_pci_ce_irq_disable(struct ath11k_base *ab, u16 ce_id)
{
u32 irq_idx;
+ u32 vecs_32_cap;
+ vecs_32_cap = ath11k_pci_priv(ab)->vectors_32_capability;
irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id;
- disable_irq_nosync(ab->irq_num[irq_idx]);
+
+ /* Cannot disable the irq when using one msi interrupt */
+ if (vecs_32_cap)
+ disable_irq_nosync(ab->irq_num[irq_idx]);
+
+ ath11k_pci_set_irq_enable_flag(ab, irq_idx, 0);
}
static void ath11k_pci_ce_irqs_disable(struct ath11k_base *ab)
@@ -387,18 +407,28 @@ static void ath11k_pci_sync_ce_irqs(struct ath11k_base *ab)
static void ath11k_pci_ce_tasklet(unsigned long data)
{
+
struct ath11k_ce_pipe *ce_pipe = (struct ath11k_ce_pipe *)data;
+ 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;
+
+ disable_irq_nosync(ab->irq_num[irq_idx]);
+
+ if (!ab->irq_enable_flag[irq_idx]) {
+ enable_irq(ab->irq_num[irq_idx]);
+ return IRQ_HANDLED;
+ }
- ath11k_pci_ce_irq_disable(ce_pipe->ab, ce_pipe->pipe_num);
tasklet_schedule(&ce_pipe->intr_tq);
return IRQ_HANDLED;
@@ -407,9 +437,16 @@ 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)
{
int i;
+ u32 vecs_32_cap;
- for (i = 0; i < irq_grp->num_irq; i++)
- disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
+ vecs_32_cap = ath11k_pci_priv(irq_grp->ab)->vectors_32_capability;
+
+ for (i = 0; i < irq_grp->num_irq; i++) {
+ if (vecs_32_cap)
+ disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
+
+ ath11k_pci_set_irq_enable_flag(irq_grp->ab, irq_grp->irqs[i], 0);
+ }
}
static void __ath11k_pci_ext_irq_disable(struct ath11k_base *sc)
@@ -429,9 +466,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)
{
int i;
+ u32 vecs_32_cap;
- for (i = 0; i < irq_grp->num_irq; i++)
- enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
+ vecs_32_cap = ath11k_pci_priv(irq_grp->ab)->vectors_32_capability;
+
+ for (i = 0; i < irq_grp->num_irq; i++) {
+ if (vecs_32_cap)
+ enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
+ ath11k_pci_set_irq_enable_flag(irq_grp->ab, irq_grp->irqs[i], 1);
+ }
}
static void ath11k_pci_ext_irq_enable(struct ath11k_base *ab)
@@ -473,11 +516,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)
@@ -489,10 +534,16 @@ 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;
+ int i;
- ath11k_dbg(irq_grp->ab, ATH11K_DBG_PCI, "ext irq:%d\n", irq);
+ for (i = 0; i < irq_grp->num_irq; i++)
+ disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
- ath11k_pci_ext_grp_disable(irq_grp);
+ if (!irq_grp->ab->irq_enable_flag[irq_grp->irqs[0]]) {
+ for (i = 0; i < irq_grp->num_irq; i++)
+ enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
+ return IRQ_HANDLED;
+ }
napi_schedule(&irq_grp->napi);
@@ -503,6 +554,7 @@ 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;
+ u32 vecs_32_cap;
ret = ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab), "DP",
&num_vectors,
@@ -511,6 +563,8 @@ static int ath11k_pci_ext_irq_config(struct ath11k_base *ab)
if (ret < 0)
return ret;
+ vecs_32_cap = ath11k_pci_priv(ab)->vectors_32_capability;
+
for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
u32 num_irq = 0;
@@ -533,11 +587,12 @@ static int ath11k_pci_ext_irq_config(struct ath11k_base *ab)
}
irq_grp->num_irq = num_irq;
- irq_grp->irqs[0] = base_vector + 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];
- int vector = (i % num_vectors) + base_vector;
+ int vector = vecs_32_cap ?
+ (i % num_vectors) + base_vector : base_vector;
int irq = ath11k_pci_get_msi_irq(ab->dev, vector);
ab->irq_num[irq_idx] = irq;
@@ -545,7 +600,7 @@ static int ath11k_pci_ext_irq_config(struct ath11k_base *ab)
ath11k_dbg(ab, ATH11K_DBG_PCI,
"irq:%d group:%d\n", irq, i);
ret = request_irq(irq, ath11k_pci_ext_interrupt_handler,
- IRQF_SHARED,
+ IRQF_SHARED | IRQF_NOBALANCING,
"DP_EXT_IRQ", irq_grp);
if (ret) {
ath11k_err(ab, "failed request irq %d: %d\n",
@@ -553,7 +608,11 @@ static int ath11k_pci_ext_irq_config(struct ath11k_base *ab)
return ret;
}
- disable_irq_nosync(ab->irq_num[irq_idx]);
+ /* balance irq_enable */
+ if (vecs_32_cap)
+ disable_irq_nosync(ab->irq_num[irq_idx]);
+
+ ath11k_pci_set_irq_enable_flag(ab, irq_idx, 0);
}
}
@@ -566,6 +625,7 @@ static int ath11k_pci_config_irq(struct ath11k_base *ab)
u32 msi_data_start;
u32 msi_data_count;
u32 msi_irq_start;
+ u32 vecs_32_cap;
unsigned int msi_data;
int irq, i, ret, irq_idx;
@@ -575,9 +635,13 @@ static int ath11k_pci_config_irq(struct ath11k_base *ab)
if (ret)
return ret;
+ vecs_32_cap = ath11k_pci_priv(ab)->vectors_32_capability;
+
/* Configure CE irqs */
for (i = 0; i < ab->hw_params.ce_count; i++) {
- msi_data = (i % msi_data_count) + msi_irq_start;
+ msi_data = vecs_32_cap ?
+ (i % msi_data_count) + msi_irq_start : msi_irq_start;
+
irq = ath11k_pci_get_msi_irq(ab->dev, msi_data);
ce_pipe = &ab->ce.ce_pipe[i];
@@ -590,7 +654,7 @@ static int ath11k_pci_config_irq(struct ath11k_base *ab)
(unsigned long)ce_pipe);
ret = request_irq(irq, ath11k_pci_ce_interrupt_handler,
- IRQF_SHARED, irq_name[irq_idx],
+ IRQF_SHARED | IRQF_NOBALANCING, irq_name[irq_idx],
ce_pipe);
if (ret) {
ath11k_err(ab, "failed to request irq %d: %d\n",
@@ -646,14 +710,19 @@ static int ath11k_pci_enable_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;
+
+ if (num_vectors == msi_config.total_vectors) {
+ ab_pci->vectors_32_capability = 1;
+ } else {
+ ab_pci->vectors_32_capability = 0;
+ num_vectors = pci_alloc_irq_vectors(ab_pci->pdev,
+ 1,
+ 1,
+ PCI_IRQ_MSI);
+ if (num_vectors < 0) {
+ ret = -EINVAL;
+ goto reset_msi_config;
+ }
}
msi_desc = irq_get_msi_desc(ab_pci->pdev->irq);
@@ -663,6 +732,8 @@ static int ath11k_pci_enable_msi(struct ath11k_pci *ab_pci)
goto free_msi_vector;
}
+ ath11k_info(ab, "MSI vectors: %d", num_vectors);
+
ab_pci->msi_ep_base_data = msi_desc->msg.data;
if (msi_desc->msi_attrib.is_64)
set_bit(ATH11K_PCI_FLAG_IS_MSI_64, &ab_pci->flags);
@@ -674,6 +745,7 @@ static int ath11k_pci_enable_msi(struct ath11k_pci *ab_pci)
free_msi_vector:
pci_free_irq_vectors(ab_pci->pdev);
+reset_msi_config:
return ret;
}
@@ -682,6 +754,32 @@ static void ath11k_pci_disable_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;
+ int ret;
+
+ msi_desc = irq_get_msi_desc(ab_pci->pdev->irq);
+
+ if (!msi_desc) {
+ ath11k_err(ab_pci->ab, "msi_desc is NULL!\n");
+ ret = -EINVAL;
+ goto free_msi_vector;
+ }
+
+ ab_pci->msi_ep_base_data = msi_desc->msg.data;
+
+ ath11k_dbg(ab_pci->ab, ATH11K_DBG_PCI, "msi base data is %d\n",
+ ab_pci->msi_ep_base_data);
+
+ return 0;
+
+ free_msi_vector:
+ pci_free_irq_vectors(ab_pci->pdev);
+
+ return ret;
+}
+
static int ath11k_pci_claim(struct ath11k_pci *ab_pci, struct pci_dev *pdev)
{
struct ath11k_base *ab = ab_pci->ab;
@@ -869,6 +967,11 @@ static int ath11k_pci_map_service_to_pipe(struct ath11k_base *ab, u16 service_id
return 0;
}
+static int ath11k_pci_is_32_vectors_support(struct ath11k_base *ab)
+{
+ return ath11k_pci_priv(ab)->vectors_32_capability;
+}
+
static const struct ath11k_hif_ops ath11k_pci_hif_ops = {
.start = ath11k_pci_start,
.stop = ath11k_pci_stop,
@@ -881,6 +984,7 @@ static const struct ath11k_hif_ops ath11k_pci_hif_ops = {
.get_msi_address = ath11k_pci_get_msi_address,
.get_user_msi_vector = ath11k_get_user_msi_assignment,
.map_service_to_pipe = ath11k_pci_map_service_to_pipe,
+ .is_32_vecs_support = ath11k_pci_is_32_vectors_support,
};
static int ath11k_pci_probe(struct pci_dev *pdev,
@@ -979,6 +1083,13 @@ static int ath11k_pci_probe(struct pci_dev *pdev,
goto err_ce_free;
}
+ /* Get the correct msi_data after request_irq() to avoid spurious interrupt */
+ ret = ath11k_pci_config_msi_data(ab_pci);
+ if (ret) {
+ ath11k_err(ab, "failed to config msi_data: %d\n", ret);
+ goto err_ce_free;
+ }
+
ret = ath11k_core_init(ab);
if (ret) {
ath11k_err(ab, "failed to init core: %d\n", ret);
diff --git a/drivers/net/wireless/ath/ath11k/pci.h b/drivers/net/wireless/ath/ath11k/pci.h
index 9c503a17c237..bdce32bd0136 100644
--- a/drivers/net/wireless/ath/ath11k/pci.h
+++ b/drivers/net/wireless/ath/ath11k/pci.h
@@ -47,6 +47,7 @@ struct ath11k_pci {
u16 dev_id;
char amss_path[100];
u32 msi_ep_base_data;
+ u32 vectors_32_capability;
struct mhi_controller *mhi_ctrl;
unsigned long mhi_state;
u32 register_window;
--
2.29.2
More information about the kernel-team
mailing list