wlan-ap-Telecominfraproject/feeds/ipq807x/mac80211/patches/179-ath11k-abstract-ext-interrupts.patch
John Crispin 3affbc1cad QualComm/AX: add Hawkeye and Cypress support
This series is based on
* 2020-07-10 ipq6018-ilq-11-0_qca_oem-034672b0676c37b1f4519e5720e18e95fe6236ef

Add support for
* qsdk kernel/v4.4
* qsdk ethernet subsystem
* v5.7 ath11k backport + QualComm staging patches (wlan_ap_1.0)
* ath11k-firmware
* hostapd/iw/...

Feature support
* full boot, system detection
* sysupgrade to nand
* HE support via latest hostapd
* driver support for usb, crypto, hwmon, cpufreq, ...

Missing
* NSS/HW flow offloading - FW blob is not redistributable

Using the qsdk v4.4 is an intermediate solution while the vanilla is being
tested. Vanilla kernel is almost on feature par. Work has already started
to upstream the ethernet and switch drivers. Once complete the target will
be fully upstream.

Signed-off-by: John Crispin <john@phrozen.org>
2020-07-23 18:54:03 +02:00

648 lines
18 KiB
Diff

From c62991534012b71651ccc909090d97c06e6a3c8d Mon Sep 17 00:00:00 2001
From: Anilkumar Kolli <akolli@codeaurora.org>
Date: Tue, 24 Mar 2020 23:21:23 +0530
Subject: [PATCH 1179/1179] ath11k abstract ext interrupts
---
drivers/net/wireless/ath/ath11k/ahb.c | 54 +++++++++
drivers/net/wireless/ath/ath11k/core.h | 8 ++
drivers/net/wireless/ath/ath11k/dp.c | 141 ++++++++++++++++++++--
drivers/net/wireless/ath/ath11k/dp_tx.c | 6 +-
drivers/net/wireless/ath/ath11k/hif.h | 45 -------
drivers/net/wireless/ath/ath11k/pci.c | 202 +++++++++++++++++++++++++++++++-
6 files changed, 396 insertions(+), 60 deletions(-)
--- a/drivers/net/wireless/ath/ath11k/ahb.c
+++ b/drivers/net/wireless/ath/ath11k/ahb.c
@@ -13,6 +13,51 @@
#include "hif.h"
#include <linux/remoteproc.h>
+static const u8 ath11k_tx_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX] = {
+ ATH11K_TX_RING_MASK_0,
+ ATH11K_TX_RING_MASK_1,
+ ATH11K_TX_RING_MASK_2,
+};
+
+static const u8 rx_mon_status_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX] = {
+ 0, 0, 0, 0,
+ ATH11K_RX_MON_STATUS_RING_MASK_0,
+ ATH11K_RX_MON_STATUS_RING_MASK_1,
+ ATH11K_RX_MON_STATUS_RING_MASK_2,
+};
+
+static const u8 ath11k_rx_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX] = {
+ 0, 0, 0, 0, 0, 0, 0,
+ ATH11K_RX_RING_MASK_0,
+ ATH11K_RX_RING_MASK_1,
+ ATH11K_RX_RING_MASK_2,
+ ATH11K_RX_RING_MASK_3,
+};
+
+static const u8 ath11k_rx_err_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX] = {
+ ATH11K_RX_ERR_RING_MASK_0,
+};
+
+static const u8 ath11k_rx_wbm_rel_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX] = {
+ ATH11K_RX_WBM_REL_RING_MASK_0,
+};
+
+static const u8 ath11k_reo_status_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX] = {
+ ATH11K_REO_STATUS_RING_MASK_0,
+};
+
+static const u8 ath11k_rxdma2host_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX] = {
+ ATH11K_RXDMA2HOST_RING_MASK_0,
+ ATH11K_RXDMA2HOST_RING_MASK_1,
+ ATH11K_RXDMA2HOST_RING_MASK_2,
+};
+
+static const u8 ath11k_host2rxdma_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX] = {
+ ATH11K_HOST2RXDMA_RING_MASK_0,
+ ATH11K_HOST2RXDMA_RING_MASK_1,
+ ATH11K_HOST2RXDMA_RING_MASK_2,
+};
+
static const struct of_device_id ath11k_ahb_of_match[] = {
/* TODO: Should we change the compatible string to something similar
* to one that ath10k uses?
@@ -637,6 +682,15 @@ static int ath11k_ahb_ext_irq_config(str
int irq;
int ret;
+ ab->tx_ring_mask = ath11k_tx_ring_mask;
+ ab->rx_mon_status_ring_mask = rx_mon_status_ring_mask;
+ ab->rx_ring_mask = ath11k_rx_ring_mask;
+ ab->rx_err_ring_mask = ath11k_rx_err_ring_mask;
+ ab->rx_wbm_rel_ring_mask = ath11k_rx_wbm_rel_ring_mask;
+ ab->reo_status_ring_mask = ath11k_reo_status_ring_mask;
+ ab->rxdma2host_ring_mask = ath11k_rxdma2host_ring_mask;
+ ab->host2rxdma_ring_mask = ath11k_host2rxdma_ring_mask;
+
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;
--- a/drivers/net/wireless/ath/ath11k/core.h
+++ b/drivers/net/wireless/ath/ath11k/core.h
@@ -750,6 +750,14 @@ struct ath11k_base {
u32 wlan_init_status;
int irq_num[ATH11K_IRQ_NUM_MAX];
struct ath11k_ext_irq_grp ext_irq_grp[ATH11K_EXT_IRQ_GRP_NUM_MAX];
+ const u8 *tx_ring_mask;
+ const u8 *rx_mon_status_ring_mask;
+ const u8 *rx_ring_mask;
+ const u8 *rx_err_ring_mask;
+ const u8 *rx_wbm_rel_ring_mask;
+ const u8 *reo_status_ring_mask;
+ const u8 *rxdma2host_ring_mask;
+ const u8 *host2rxdma_ring_mask;
struct napi_struct *napi;
struct ath11k_targ_cap target_caps;
u32 ext_service_bitmap[WMI_SERVICE_EXT_BM_SIZE];
--- a/drivers/net/wireless/ath/ath11k/dp.c
+++ b/drivers/net/wireless/ath/ath11k/dp.c
@@ -107,6 +107,124 @@ void ath11k_dp_srng_cleanup(struct ath11
ring->vaddr_unaligned = NULL;
}
+static
+int ath11k_dp_srng_find_ring_in_mask(int ring_num, const u8 *grp_mask, u32 *grp_num)
+{
+ int ext_group_num;
+ u8 mask = 1 << ring_num;
+
+ for (ext_group_num = 0; ext_group_num < ATH11K_EXT_IRQ_GRP_NUM_MAX;
+ ext_group_num++) {
+ if (mask & grp_mask[ext_group_num]) {
+ *grp_num = ext_group_num;
+
+ return 0;
+ }
+ }
+
+ return -ENOENT;
+}
+
+static
+int ath11k_dp_srng_calculate_msi_group(struct ath11k_base *ab, enum hal_ring_type type,
+ int ring_num, u32 *msi_grp_num)
+{
+ const u8 *grp_mask;
+
+ switch (type) {
+ case HAL_WBM2SW_RELEASE:
+ if (ring_num < 3) {
+ grp_mask = ab->tx_ring_mask;
+ } else if (ring_num == 3) {
+ /* sw treats this as a separate ring type */
+ grp_mask = ab->rx_wbm_rel_ring_mask;
+ ring_num = 0;
+ } else {
+ return -ENOENT;
+ }
+ break;
+ case HAL_REO_EXCEPTION:
+ grp_mask = ab->rx_err_ring_mask;
+ break;
+ case HAL_REO_DST:
+ grp_mask = ab->rx_ring_mask;
+ break;
+ case HAL_REO_STATUS:
+ grp_mask = ab->reo_status_ring_mask;
+ break;
+ case HAL_RXDMA_MONITOR_STATUS:
+ case HAL_RXDMA_MONITOR_DST:
+ grp_mask = ab->rx_mon_status_ring_mask;
+ break;
+ case HAL_RXDMA_DST:
+ grp_mask = ab->rxdma2host_ring_mask;
+ break;
+ case HAL_RXDMA_BUF:
+ grp_mask = ab->host2rxdma_ring_mask;
+ break;
+ case HAL_RXDMA_MONITOR_BUF:
+ /* TODO: support low_thresh interrupt */
+ return -ENOENT;
+ break;
+ case HAL_TCL_DATA:
+ case HAL_TCL_CMD:
+ case HAL_REO_CMD:
+ case HAL_SW2WBM_RELEASE:
+ case HAL_WBM_IDLE_LINK:
+ case HAL_TCL_STATUS:
+ case HAL_REO_REINJECT:
+ case HAL_CE_SRC:
+ case HAL_CE_DST:
+ case HAL_CE_DST_STATUS:
+ default:
+ return -ENOENT;
+ break;
+ }
+
+ return ath11k_dp_srng_find_ring_in_mask(ring_num, grp_mask, msi_grp_num);
+}
+
+static
+void ath11k_dp_srng_msi_setup(struct ath11k_base *ab, struct hal_srng_params *ring_params,
+ enum hal_ring_type type, int ring_num)
+{
+ u32 msi_data_start, msi_data_count, msi_irq_start, msi_grp_num;
+ u32 addr_lo, addr_hi;
+ int ret;
+
+ ret = ath11k_get_user_msi_vector(ab, "DP",
+ &msi_data_count, &msi_data_start,
+ &msi_irq_start);
+ if (ret)
+ return;
+
+ ret = ath11k_dp_srng_calculate_msi_group(ab, type, ring_num, &msi_grp_num);
+ if (ret) {
+ ath11k_dbg(ab, ATH11K_DBG_BOOT,
+ "dp ring type %d num %d not part of the ext grp\n",
+ type, ring_num);
+
+ ring_params->msi_addr = 0;
+ ring_params->msi_data = 0;
+
+ return;
+ }
+
+ if (msi_grp_num > msi_data_count) {
+ ath11k_warn(ab, "2 msi_groups will share an msi; msi_grp_num %d\n",
+ msi_grp_num);
+
+ return;
+ }
+
+ 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 = (msi_grp_num % msi_data_count) + msi_data_start;
+ ring_params->flags |= HAL_SRNG_FLAGS_MSI_INTR;
+}
+
int ath11k_dp_srng_setup(struct ath11k_base *ab, struct dp_srng *ring,
enum hal_ring_type type, int ring_num,
int mac_id, int num_entries)
@@ -137,6 +255,8 @@ int ath11k_dp_srng_setup(struct ath11k_b
params.ring_base_paddr = ring->paddr;
params.num_entries = num_entries;
+ ath11k_dp_srng_msi_setup(ab, &params, type, ring_num);
+
switch (type) {
case HAL_REO_DST:
params.intr_batch_cntr_thres_entries =
@@ -626,13 +746,13 @@ int ath11k_dp_service_srng(struct ath11k
int i = 0;
int tot_work_done = 0;
- while (ath11k_tx_ring_mask[grp_id] >> i) {
- if (ath11k_tx_ring_mask[grp_id] & BIT(i))
+ while (ab->tx_ring_mask[grp_id] >> i) {
+ if (ab->tx_ring_mask[grp_id] & BIT(i))
ath11k_dp_tx_completion_handler(ab, i);
i++;
}
- if (ath11k_rx_err_ring_mask[grp_id]) {
+ if (ab->rx_err_ring_mask[grp_id]) {
work_done = ath11k_dp_process_rx_err(ab, napi, budget);
budget -= work_done;
tot_work_done += work_done;
@@ -640,7 +760,7 @@ int ath11k_dp_service_srng(struct ath11k
goto done;
}
- if (ath11k_rx_wbm_rel_ring_mask[grp_id]) {
+ if (ab->rx_wbm_rel_ring_mask[grp_id]) {
work_done = ath11k_dp_rx_process_wbm_err(ab,
napi,
budget);
@@ -651,8 +771,8 @@ int ath11k_dp_service_srng(struct ath11k
goto done;
}
- if (ath11k_rx_ring_mask[grp_id]) {
- i = fls(ath11k_rx_ring_mask[grp_id]) - 1;
+ if (ab->rx_ring_mask[grp_id]) {
+ i = fls(ab->rx_ring_mask[grp_id]) - 1;
work_done = ath11k_dp_process_rx(ab, i, napi,
budget);
budget -= work_done;
@@ -661,9 +781,9 @@ int ath11k_dp_service_srng(struct ath11k
goto done;
}
- if (rx_mon_status_ring_mask[grp_id]) {
+ if (ab->rx_mon_status_ring_mask[grp_id]) {
for (i = 0; i < ab->num_radios; i++) {
- if (rx_mon_status_ring_mask[grp_id] & BIT(i)) {
+ if (ab->rx_mon_status_ring_mask[grp_id] & BIT(i)) {
work_done =
ath11k_dp_rx_process_mon_rings(ab,
i, napi,
@@ -676,11 +796,11 @@ int ath11k_dp_service_srng(struct ath11k
}
}
- if (ath11k_reo_status_ring_mask[grp_id])
+ if (ab->reo_status_ring_mask[grp_id])
ath11k_dp_process_reo_status(ab);
for (i = 0; i < ab->num_radios; i++) {
- if (ath11k_rxdma2host_ring_mask[grp_id] & BIT(i)) {
+ if (ab->rxdma2host_ring_mask[grp_id] & BIT(i)) {
work_done = ath11k_dp_process_rxdma_err(ab, i, budget);
budget -= work_done;
tot_work_done += work_done;
@@ -689,7 +809,7 @@ int ath11k_dp_service_srng(struct ath11k
if (budget <= 0)
goto done;
- if (ath11k_host2rxdma_ring_mask[grp_id] & BIT(i)) {
+ if (ab->host2rxdma_ring_mask[grp_id] & BIT(i)) {
struct ath11k_pdev_dp *dp = &ab->pdevs[i].ar->dp;
struct dp_rxdma_ring *rx_ring = &dp->rx_refill_buf_ring;
--- a/drivers/net/wireless/ath/ath11k/dp_tx.c
+++ b/drivers/net/wireless/ath/ath11k/dp_tx.c
@@ -796,9 +796,9 @@ int ath11k_dp_tx_htt_srng_setup(struct a
cmd->ring_tail_off32_remote_addr_hi = (u64)tp_addr >>
HAL_ADDR_MSB_REG_SHIFT;
- cmd->ring_msi_addr_lo = 0;
- cmd->ring_msi_addr_hi = 0;
- cmd->msi_data = 0;
+ cmd->ring_msi_addr_lo = lower_32_bits(params.msi_addr);
+ cmd->ring_msi_addr_hi = upper_32_bits(params.msi_addr);
+ cmd->msi_data = params.msi_data;
cmd->intr_info = FIELD_PREP(
HTT_SRNG_SETUP_CMD_INTR_INFO_BATCH_COUNTER_THRESH,
--- a/drivers/net/wireless/ath/ath11k/hif.h
+++ b/drivers/net/wireless/ath/ath11k/hif.h
@@ -33,51 +33,6 @@
#define ATH11K_RX_MON_STATUS_RING_MASK_1 0x2
#define ATH11K_RX_MON_STATUS_RING_MASK_2 0x4
-static const u8 ath11k_tx_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX] = {
- ATH11K_TX_RING_MASK_0,
- ATH11K_TX_RING_MASK_1,
- ATH11K_TX_RING_MASK_2,
-};
-
-static const u8 rx_mon_status_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX] = {
- 0, 0, 0, 0,
- ATH11K_RX_MON_STATUS_RING_MASK_0,
- ATH11K_RX_MON_STATUS_RING_MASK_1,
- ATH11K_RX_MON_STATUS_RING_MASK_2,
-};
-
-static const u8 ath11k_rx_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX] = {
- 0, 0, 0, 0, 0, 0, 0,
- ATH11K_RX_RING_MASK_0,
- ATH11K_RX_RING_MASK_1,
- ATH11K_RX_RING_MASK_2,
- ATH11K_RX_RING_MASK_3,
-};
-
-static const u8 ath11k_rx_err_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX] = {
- ATH11K_RX_ERR_RING_MASK_0,
-};
-
-static const u8 ath11k_rx_wbm_rel_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX] = {
- ATH11K_RX_WBM_REL_RING_MASK_0,
-};
-
-static const u8 ath11k_reo_status_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX] = {
- ATH11K_REO_STATUS_RING_MASK_0,
-};
-
-static const u8 ath11k_rxdma2host_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX] = {
- ATH11K_RXDMA2HOST_RING_MASK_0,
- ATH11K_RXDMA2HOST_RING_MASK_1,
- ATH11K_RXDMA2HOST_RING_MASK_2,
-};
-
-static const u8 ath11k_host2rxdma_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX] = {
- ATH11K_HOST2RXDMA_RING_MASK_0,
- ATH11K_HOST2RXDMA_RING_MASK_1,
- ATH11K_HOST2RXDMA_RING_MASK_2,
-};
-
struct ath11k_hif_ops {
u32 (*read32)(struct ath11k_base *sc, u32 address);
void (*write32)(struct ath11k_base *sc, u32 address, u32 data);
--- a/drivers/net/wireless/ath/ath11k/pci.c
+++ b/drivers/net/wireless/ath/ath11k/pci.c
@@ -13,6 +13,43 @@
#include "pci.h"
#include "debug.h"
+static const u8 ath11k_tx_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX] = {
+ ATH11K_TX_RING_MASK_0,
+ ATH11K_TX_RING_MASK_1,
+ ATH11K_TX_RING_MASK_2,
+};
+
+static const u8 rx_mon_status_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX] = {
+ 0,
+};
+
+static const u8 ath11k_rx_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX] = {
+ ATH11K_RX_RING_MASK_0,
+ ATH11K_RX_RING_MASK_1,
+ ATH11K_RX_RING_MASK_2,
+ ATH11K_RX_RING_MASK_3,
+};
+
+static const u8 ath11k_rx_err_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX] = {
+ ATH11K_RX_ERR_RING_MASK_0,
+};
+
+static const u8 ath11k_rx_wbm_rel_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX] = {
+ ATH11K_RX_WBM_REL_RING_MASK_0,
+};
+
+static const u8 ath11k_reo_status_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX] = {
+ ATH11K_REO_STATUS_RING_MASK_0,
+};
+
+static const u8 ath11k_rxdma2host_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX] = {
+ 0,
+};
+
+static const u8 ath11k_host2rxdma_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX] = {
+ 0,
+};
+
const char *irq_name[ATH11K_IRQ_NUM_MAX] = {
"bhi",
"mhi-er0",
@@ -488,6 +525,18 @@ int ath11k_get_user_msi_assignment(struc
base_vector);
}
+static void ath11k_pci_free_ext_irq(struct ath11k_base *ab)
+{
+ int i, j;
+
+ for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
+ struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
+
+ for (j = 0; j < irq_grp->num_irq; j++)
+ free_irq(ab->irq_num[irq_grp->irqs[j]], irq_grp);
+ }
+}
+
static void ath11k_pci_free_irq(struct ath11k_base *ab)
{
int irq_idx;
@@ -499,6 +548,8 @@ static void ath11k_pci_free_irq(struct a
irq_idx = ATH11K_IRQ_CE0_OFFSET + i;
free_irq(ab->irq_num[irq_idx], &ab->ce.ce_pipe[i]);
}
+
+ ath11k_pci_free_ext_irq(ab);
}
static void ath11k_pci_ce_irq_enable(struct ath11k_base *ab, u16 ce_id)
@@ -555,12 +606,176 @@ static irqreturn_t ath11k_pci_ce_interru
{
struct ath11k_ce_pipe *ce_pipe = arg;
+ /* last interrupt received for this CE */
+ ce_pipe->timestamp = jiffies;
+
ath11k_pci_ce_irq_disable(ce_pipe->ab, ce_pipe->pipe_num);
tasklet_schedule(&ce_pipe->intr_tq);
return IRQ_HANDLED;
}
+static void ath11k_pci_ext_grp_disable(struct ath11k_ext_irq_grp *irq_grp)
+{
+ int i;
+
+ for (i = 0; i < irq_grp->num_irq; i++)
+ disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
+}
+
+static void __ath11k_pci_ext_irq_disable(struct ath11k_base *sc)
+{
+ struct sk_buff *skb;
+ int i;
+
+ for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
+ struct ath11k_ext_irq_grp *irq_grp = &sc->ext_irq_grp[i];
+
+ ath11k_pci_ext_grp_disable(irq_grp);
+
+ napi_synchronize(&irq_grp->napi);
+ napi_disable(&irq_grp->napi);
+ }
+}
+
+static void ath11k_pci_ext_grp_enable(struct ath11k_ext_irq_grp *irq_grp)
+{
+ int i;
+
+ for (i = 0; i < irq_grp->num_irq; i++)
+ enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
+}
+
+static void ath11k_pci_ext_irq_enable(struct ath11k_base *ab)
+{
+ int i;
+
+ for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
+ struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
+
+ napi_enable(&irq_grp->napi);
+ ath11k_pci_ext_grp_enable(irq_grp);
+ }
+}
+
+static void ath11k_pci_sync_ext_irqs(struct ath11k_base *ab)
+{
+ int i, j;
+ int irq_idx;
+
+ for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
+ struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
+
+ for (j = 0; j < irq_grp->num_irq; j++) {
+ irq_idx = irq_grp->irqs[j];
+ synchronize_irq(ab->irq_num[irq_idx]);
+ }
+ }
+}
+
+static void ath11k_pci_ext_irq_disable(struct ath11k_base *ab)
+{
+ __ath11k_pci_ext_irq_disable(ab);
+ ath11k_pci_sync_ext_irqs(ab);
+}
+
+static int ath11k_pci_ext_grp_napi_poll(struct napi_struct *napi, int budget)
+{
+ struct ath11k_ext_irq_grp *irq_grp = container_of(napi,
+ struct ath11k_ext_irq_grp,
+ napi);
+ struct ath11k_base *ab = irq_grp->ab;
+ int work_done;
+
+ 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);
+ }
+
+ if (work_done > budget)
+ work_done = budget;
+
+ return work_done;
+}
+
+static irqreturn_t ath11k_pci_ext_interrupt_handler(int irq, void *arg)
+{
+ struct ath11k_ext_irq_grp *irq_grp = arg;
+
+ /* last interrupt received for this group */
+ irq_grp->timestamp = jiffies;
+
+ ath11k_pci_ext_grp_disable(irq_grp);
+
+ napi_schedule(&irq_grp->napi);
+
+ return IRQ_HANDLED;
+}
+
+static int ath11k_pci_ext_irq_config(struct ath11k_base *ab)
+{
+ int i, j;
+ int ret;
+ int num_vectors = 0;
+ u32 user_base_data = 0, base_vector = 0, base_idx;
+
+ ab->tx_ring_mask = ath11k_tx_ring_mask;
+ ab->rx_mon_status_ring_mask = rx_mon_status_ring_mask;
+ ab->rx_ring_mask = ath11k_rx_ring_mask;
+ ab->rx_err_ring_mask = ath11k_rx_err_ring_mask;
+ ab->rx_wbm_rel_ring_mask = ath11k_rx_wbm_rel_ring_mask;
+ ab->reo_status_ring_mask = ath11k_reo_status_ring_mask;
+ ab->rxdma2host_ring_mask = ath11k_rxdma2host_ring_mask;
+ ab->host2rxdma_ring_mask = ath11k_host2rxdma_ring_mask;
+
+ base_idx = ATH11K_IRQ_CE0_OFFSET + MAX_CE_COUNT;
+
+ ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab), "DP",
+ &num_vectors, &user_base_data,
+ &base_vector);
+
+ 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;
+
+ irq_grp->ab = ab;
+ irq_grp->grp_id = i;
+ init_dummy_netdev(&irq_grp->napi_ndev);
+ netif_napi_add(&irq_grp->napi_ndev, &irq_grp->napi,
+ ath11k_pci_ext_grp_napi_poll, NAPI_POLL_WEIGHT);
+
+ if (ath11k_tx_ring_mask[i] || ath11k_rx_ring_mask[i] ||
+ ath11k_rx_err_ring_mask[i] || ath11k_rx_wbm_rel_ring_mask[i] ||
+ ath11k_reo_status_ring_mask[i] || ath11k_rxdma2host_ring_mask[i] ||
+ ath11k_host2rxdma_ring_mask[i] || rx_mon_status_ring_mask[i]) {
+ num_irq = 1;
+ }
+
+ irq_grp->num_irq = num_irq;
+ irq_grp->irqs[0] = base_idx + 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 irq = ath11k_pci_get_msi_irq(ab->dev, vector);
+
+ ab->irq_num[irq_idx] = irq;
+
+ irq_set_status_flags(irq, IRQ_NOAUTOEN);
+ ret = request_irq(irq, ath11k_pci_ext_interrupt_handler,
+ IRQF_SHARED | IRQF_NO_SUSPEND,
+ "DP_EXT_IRQ", irq_grp);
+ if (ret) {
+ ath11k_err(ab, "failed request_irq for %d\n",
+ vector);
+ }
+ }
+ }
+
+ return 0;
+}
+
static int ath11k_pci_config_irq(struct ath11k_base *ab)
{
struct ath11k_ce_pipe *ce_pipe;
@@ -600,7 +815,7 @@ static int ath11k_pci_config_irq(struct
msi_data_idx++;
}
- /* To Do Configure external interrupts */
+ ath11k_pci_ext_irq_config(ab);
return ret;
}
@@ -904,6 +1119,8 @@ static const struct ath11k_hif_ops ath11
.write32 = ath11k_pci_write32,
.power_down = ath11k_pci_power_down,
.power_up = ath11k_pci_power_up,
+ .irq_enable = ath11k_pci_ext_irq_enable,
+ .irq_disable = ath11k_pci_ext_irq_disable,
.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,