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: Carl Huang <cjhuang@codeaurora.org> Signed-off-by: Kalle Valo <kvalo@codeaurora.org> Link: https://lore.kernel.org/r/1597555891-26112-2-git-send-email-kvalo@codeaurora.org
This commit is contained in:
parent
13ecd81fba
commit
d4ecb90b38
5 changed files with 322 additions and 1 deletions
|
@ -49,7 +49,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
|
|||
.max_radios = 3,
|
||||
.bdf_addr = 0x4B0C0000,
|
||||
.hw_ops = &qca6390_ops,
|
||||
.ring_mask = &ath11k_hw_ring_mask_ipq8074,
|
||||
.ring_mask = &ath11k_hw_ring_mask_qca6390,
|
||||
.internal_sleep_clock = true,
|
||||
.regs = &qca6390_regs,
|
||||
.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)
|
|||
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,
|
||||
enum hal_ring_type type, int ring_num,
|
||||
int mac_id, int num_entries)
|
||||
|
@ -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_paddr = ring->paddr;
|
||||
params.num_entries = num_entries;
|
||||
ath11k_dp_srng_msi_setup(ab, ¶ms, type, ring_num + mac_id);
|
||||
|
||||
switch (type) {
|
||||
case HAL_REO_DST:
|
||||
|
|
|
@ -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 = {
|
||||
/* SW2TCL(x) R0 ring configuration address */
|
||||
.hal_tcl1_ring_base_lsb = 0x00000510,
|
||||
|
|
|
@ -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_ring_mask ath11k_hw_ring_mask_ipq8074;
|
||||
extern const struct ath11k_hw_ring_mask ath11k_hw_ring_mask_qca6390;
|
||||
|
||||
static inline
|
||||
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
|
|||
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)
|
||||
{
|
||||
int i, irq_idx;
|
||||
|
@ -399,6 +413,8 @@ static void ath11k_pci_free_irq(struct ath11k_base *ab)
|
|||
irq_idx = ATH11K_PCI_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)
|
||||
|
@ -461,6 +477,159 @@ static irqreturn_t ath11k_pci_ce_interrupt_handler(int irq, void *arg)
|
|||
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)
|
||||
{
|
||||
struct ath11k_ce_pipe *ce_pipe;
|
||||
|
@ -503,6 +672,10 @@ static int ath11k_pci_config_irq(struct ath11k_base *ab)
|
|||
ath11k_pci_ce_irq_disable(ab, i);
|
||||
}
|
||||
|
||||
ret = ath11k_pci_ext_irq_config(ab);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -757,6 +930,8 @@ static const struct ath11k_hif_ops ath11k_pci_hif_ops = {
|
|||
.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,
|
||||
|
|
Loading…
Add table
Reference in a new issue