@@ -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",
@@ -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;
}
@@ -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;
@@ -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;
}
@@ -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)
@@ -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;
@@ -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
@@ -265,12 +266,17 @@ static void ath11k_pci_get_msi_address(struct ath11k_base *ab, u32 *msi_addr_lo,
u32 *msi_addr_hi)
{
struct pci_dev *pci_dev = to_pci_dev(ab->dev);
+ u16 is_64bits;
pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_LO,
msi_addr_lo);
+ pci_read_config_word(pci_dev, pci_dev->msi_cap + PCI_MSI_FLAGS, &is_64bits);
- pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_HI,
- msi_addr_hi);
+ if (is_64bits & PCI_MSI_FLAGS_64BIT)
+ pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_HI,
+ msi_addr_hi);
+ else
+ *msi_addr_hi = 0;
}
int ath11k_pci_get_user_msi_assignment(struct ath11k_pci *ab_pci, char *user_name,
@@ -278,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,
@@ -339,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)
@@ -382,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;
@@ -402,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)
@@ -424,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)
@@ -468,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)
@@ -484,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);
@@ -498,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,
@@ -506,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;
@@ -528,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;
@@ -540,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",
@@ -548,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);
}
}
@@ -561,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;
@@ -570,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];
@@ -585,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",
@@ -641,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);
@@ -658,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;
ath11k_dbg(ab, ATH11K_DBG_PCI, "msi base data is %d\n", ab_pci->msi_ep_base_data);
@@ -667,6 +743,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;
}
@@ -675,6 +752,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;
@@ -862,6 +965,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,
@@ -874,6 +982,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,
@@ -972,6 +1081,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);
@@ -46,6 +46,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;
@@ -1675,6 +1675,10 @@ static int ath11k_qmi_respond_fw_mem_request(struct ath11k_base *ab)
req->mem_seg[i].addr = ab->qmi.target_mem[i].paddr;
req->mem_seg[i].size = ab->qmi.target_mem[i].size;
req->mem_seg[i].type = ab->qmi.target_mem[i].type;
+ ath11k_info(ab, "req mem_seg[%d] 0x%llx %u %u\n", i,
+ ab->qmi.target_mem[i].paddr,
+ ab->qmi.target_mem[i].size,
+ ab->qmi.target_mem[i].type);
}
}