Commit d4ecb90b authored by Carl Huang's avatar Carl Huang Committed by Kalle Valo

ath11k: enable DP interrupt setup for QCA6390

QCA6390 uses MSI interrupt, so need to configure msi_add and
msi_data to dp srngs. As there are so many DP srngs, so need
to group them. Each group shares one MSI interrupt.

Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1
Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.1.0.1-01238-QCAHKSWPL_SILICONZ-2
Signed-off-by: default avatarCarl Huang <cjhuang@codeaurora.org>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
Link: https://lore.kernel.org/r/1597555891-26112-2-git-send-email-kvalo@codeaurora.org
parent 13ecd81f
...@@ -49,7 +49,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { ...@@ -49,7 +49,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.max_radios = 3, .max_radios = 3,
.bdf_addr = 0x4B0C0000, .bdf_addr = 0x4B0C0000,
.hw_ops = &qca6390_ops, .hw_ops = &qca6390_ops,
.ring_mask = &ath11k_hw_ring_mask_ipq8074, .ring_mask = &ath11k_hw_ring_mask_qca6390,
.internal_sleep_clock = true, .internal_sleep_clock = true,
.regs = &qca6390_regs, .regs = &qca6390_regs,
.host_ce_config = ath11k_host_ce_config_qca6390, .host_ce_config = ath11k_host_ce_config_qca6390,
......
...@@ -107,6 +107,113 @@ void ath11k_dp_srng_cleanup(struct ath11k_base *ab, struct dp_srng *ring) ...@@ -107,6 +107,113 @@ void ath11k_dp_srng_cleanup(struct ath11k_base *ab, struct dp_srng *ring)
ring->vaddr_unaligned = NULL; ring->vaddr_unaligned = NULL;
} }
static int ath11k_dp_srng_find_ring_in_mask(int ring_num, const u8 *grp_mask)
{
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])
return ext_group_num;
}
return -ENOENT;
}
static int ath11k_dp_srng_calculate_msi_group(struct ath11k_base *ab,
enum hal_ring_type type, int ring_num)
{
const u8 *grp_mask;
switch (type) {
case HAL_WBM2SW_RELEASE:
if (ring_num < 3) {
grp_mask = &ab->hw_params.ring_mask->tx[0];
} else if (ring_num == 3) {
grp_mask = &ab->hw_params.ring_mask->rx_wbm_rel[0];
ring_num = 0;
} else {
return -ENOENT;
}
break;
case HAL_REO_EXCEPTION:
grp_mask = &ab->hw_params.ring_mask->rx_err[0];
break;
case HAL_REO_DST:
grp_mask = &ab->hw_params.ring_mask->rx[0];
break;
case HAL_REO_STATUS:
grp_mask = &ab->hw_params.ring_mask->reo_status[0];
break;
case HAL_RXDMA_MONITOR_STATUS:
case HAL_RXDMA_MONITOR_DST:
grp_mask = &ab->hw_params.ring_mask->rx_mon_status[0];
break;
case HAL_RXDMA_DST:
grp_mask = &ab->hw_params.ring_mask->rxdma2host[0];
break;
case HAL_RXDMA_BUF:
grp_mask = &ab->hw_params.ring_mask->host2rxdma[0];
break;
case HAL_RXDMA_MONITOR_BUF:
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;
}
return ath11k_dp_srng_find_ring_in_mask(ring_num, grp_mask);
}
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)
{
int msi_group_number, msi_data_count;
u32 msi_data_start, msi_irq_start, 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;
msi_group_number = ath11k_dp_srng_calculate_msi_group(ab, type,
ring_num);
if (msi_group_number < 0) {
ath11k_dbg(ab, ATH11K_DBG_PCI,
"ring not part of an ext_group; ring_type: %d,ring_num %d",
type, ring_num);
ring_params->msi_addr = 0;
ring_params->msi_data = 0;
return;
}
if (msi_group_number > msi_data_count) {
ath11k_dbg(ab, ATH11K_DBG_PCI,
"multiple msi_groups share one msi, msi_group_num %d",
msi_group_number);
}
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_group_number % 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, int ath11k_dp_srng_setup(struct ath11k_base *ab, struct dp_srng *ring,
enum hal_ring_type type, int ring_num, enum hal_ring_type type, int ring_num,
int mac_id, int num_entries) int mac_id, int num_entries)
...@@ -136,6 +243,7 @@ int ath11k_dp_srng_setup(struct ath11k_base *ab, struct dp_srng *ring, ...@@ -136,6 +243,7 @@ int ath11k_dp_srng_setup(struct ath11k_base *ab, struct dp_srng *ring,
params.ring_base_vaddr = ring->vaddr; params.ring_base_vaddr = ring->vaddr;
params.ring_base_paddr = ring->paddr; params.ring_base_paddr = ring->paddr;
params.num_entries = num_entries; params.num_entries = num_entries;
ath11k_dp_srng_msi_setup(ab, &params, type, ring_num + mac_id);
switch (type) { switch (type) {
case HAL_REO_DST: case HAL_REO_DST:
......
...@@ -208,6 +208,43 @@ const struct ath11k_hw_ring_mask ath11k_hw_ring_mask_ipq8074 = { ...@@ -208,6 +208,43 @@ const struct ath11k_hw_ring_mask ath11k_hw_ring_mask_ipq8074 = {
}, },
}; };
const struct ath11k_hw_ring_mask ath11k_hw_ring_mask_qca6390 = {
.tx = {
ATH11K_TX_RING_MASK_0,
ATH11K_TX_RING_MASK_1,
ATH11K_TX_RING_MASK_2,
},
.rx_mon_status = {
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,
},
.rx = {
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,
},
.rx_err = {
ATH11K_RX_ERR_RING_MASK_0,
},
.rx_wbm_rel = {
ATH11K_RX_WBM_REL_RING_MASK_0,
},
.reo_status = {
ATH11K_REO_STATUS_RING_MASK_0,
},
.rxdma2host = {
ATH11K_RXDMA2HOST_RING_MASK_0,
ATH11K_RXDMA2HOST_RING_MASK_1,
ATH11K_RXDMA2HOST_RING_MASK_2,
},
.host2rxdma = {
},
};
const struct ath11k_hw_regs ipq8074_regs = { const struct ath11k_hw_regs ipq8074_regs = {
/* SW2TCL(x) R0 ring configuration address */ /* SW2TCL(x) R0 ring configuration address */
.hal_tcl1_ring_base_lsb = 0x00000510, .hal_tcl1_ring_base_lsb = 0x00000510,
......
...@@ -158,6 +158,7 @@ extern const struct ath11k_hw_ops ipq6018_ops; ...@@ -158,6 +158,7 @@ extern const struct ath11k_hw_ops ipq6018_ops;
extern const struct ath11k_hw_ops qca6390_ops; extern const struct ath11k_hw_ops qca6390_ops;
extern const struct ath11k_hw_ring_mask ath11k_hw_ring_mask_ipq8074; extern const struct ath11k_hw_ring_mask ath11k_hw_ring_mask_ipq8074;
extern const struct ath11k_hw_ring_mask ath11k_hw_ring_mask_qca6390;
static inline static inline
int ath11k_hw_get_mac_from_pdev_id(struct ath11k_hw_params *hw, int ath11k_hw_get_mac_from_pdev_id(struct ath11k_hw_params *hw,
......
...@@ -389,6 +389,20 @@ static int ath11k_get_user_msi_assignment(struct ath11k_base *ab, char *user_nam ...@@ -389,6 +389,20 @@ static int ath11k_get_user_msi_assignment(struct ath11k_base *ab, char *user_nam
base_vector); 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);
netif_napi_del(&irq_grp->napi);
}
}
static void ath11k_pci_free_irq(struct ath11k_base *ab) static void ath11k_pci_free_irq(struct ath11k_base *ab)
{ {
int i, irq_idx; int i, irq_idx;
...@@ -399,6 +413,8 @@ static void ath11k_pci_free_irq(struct ath11k_base *ab) ...@@ -399,6 +413,8 @@ static void ath11k_pci_free_irq(struct ath11k_base *ab)
irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i; irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i;
free_irq(ab->irq_num[irq_idx], &ab->ce.ce_pipe[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) static void ath11k_pci_ce_irq_enable(struct ath11k_base *ab, u16 ce_id)
...@@ -461,6 +477,159 @@ static irqreturn_t ath11k_pci_ce_interrupt_handler(int irq, void *arg) ...@@ -461,6 +477,159 @@ static irqreturn_t ath11k_pci_ce_interrupt_handler(int irq, void *arg)
return IRQ_HANDLED; 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)
{
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, 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;
ath11k_dbg(irq_grp->ab, ATH11K_DBG_PCI, "ext irq:%d\n", irq);
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, ret, num_vectors = 0;
u32 user_base_data = 0, base_vector = 0;
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 (ab->hw_params.ring_mask->tx[i] ||
ab->hw_params.ring_mask->rx[i] ||
ab->hw_params.ring_mask->rx_err[i] ||
ab->hw_params.ring_mask->rx_wbm_rel[i] ||
ab->hw_params.ring_mask->reo_status[i] ||
ab->hw_params.ring_mask->rxdma2host[i] ||
ab->hw_params.ring_mask->host2rxdma[i] ||
ab->hw_params.ring_mask->rx_mon_status[i]) {
num_irq = 1;
}
irq_grp->num_irq = num_irq;
irq_grp->irqs[0] = base_vector + 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;
ath11k_dbg(ab, ATH11K_DBG_PCI,
"irq:%d group:%d\n", irq, i);
ret = request_irq(irq, ath11k_pci_ext_interrupt_handler,
IRQF_SHARED,
"DP_EXT_IRQ", irq_grp);
if (ret) {
ath11k_err(ab, "failed request irq %d: %d\n",
vector, ret);
return ret;
}
disable_irq_nosync(ab->irq_num[irq_idx]);
}
}
return 0;
}
static int ath11k_pci_config_irq(struct ath11k_base *ab) static int ath11k_pci_config_irq(struct ath11k_base *ab)
{ {
struct ath11k_ce_pipe *ce_pipe; struct ath11k_ce_pipe *ce_pipe;
...@@ -503,6 +672,10 @@ static int ath11k_pci_config_irq(struct ath11k_base *ab) ...@@ -503,6 +672,10 @@ static int ath11k_pci_config_irq(struct ath11k_base *ab)
ath11k_pci_ce_irq_disable(ab, i); ath11k_pci_ce_irq_disable(ab, i);
} }
ret = ath11k_pci_ext_irq_config(ab);
if (ret)
return ret;
return 0; return 0;
} }
...@@ -757,6 +930,8 @@ static const struct ath11k_hif_ops ath11k_pci_hif_ops = { ...@@ -757,6 +930,8 @@ static const struct ath11k_hif_ops ath11k_pci_hif_ops = {
.write32 = ath11k_pci_write32, .write32 = ath11k_pci_write32,
.power_down = ath11k_pci_power_down, .power_down = ath11k_pci_power_down,
.power_up = ath11k_pci_power_up, .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_msi_address = ath11k_pci_get_msi_address,
.get_user_msi_vector = ath11k_get_user_msi_assignment, .get_user_msi_vector = ath11k_get_user_msi_assignment,
.map_service_to_pipe = ath11k_pci_map_service_to_pipe, .map_service_to_pipe = ath11k_pci_map_service_to_pipe,
......
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