From 4cbfe92c1d89900c83bfb623b021871ee805b93f Mon Sep 17 00:00:00 2001 From: Anilkumar Kolli Date: Fri, 15 May 2020 14:44:16 +0530 Subject: [PATCH 180/187] ath11k: add support poll based dp service Add code to process lmac rings in polling. Signed-off-by: Karthikeyan Periyasamy Signed-off-by: Anilkumar Kolli --- drivers/net/wireless/ath/ath11k/core.c | 154 +++++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath11k/core.h | 19 ++++ drivers/net/wireless/ath/ath11k/dp.c | 39 +++++++++ drivers/net/wireless/ath/ath11k/dp.h | 3 + drivers/net/wireless/ath/ath11k/pci.c | 19 ++++ 5 files changed, 234 insertions(+) Index: backports-20200415-4.4.60-9de9a9b19d3f/drivers/net/wireless/ath/ath11k/core.c =================================================================== --- backports-20200415-4.4.60-9de9a9b19d3f.orig/drivers/net/wireless/ath/ath11k/core.c +++ backports-20200415-4.4.60-9de9a9b19d3f/drivers/net/wireless/ath/ath11k/core.c @@ -13,6 +13,8 @@ #include "debug.h" #include "hif.h" +#define ATH11K_POLL_TIMEOUT_MS (10) + unsigned int ath11k_debug_mask; EXPORT_SYMBOL(ath11k_debug_mask); unsigned int rawmode; @@ -901,6 +903,142 @@ static int ath11k_init_hw_params(struct return 0; } +static int ath11k_core_poll_timer_enable(struct ath11k_poll *poll) +{ + if (!poll->is_init) + return -EINVAL; + + spin_lock_bh(&poll->lock); + + mod_timer(&poll->timer, + jiffies + msecs_to_jiffies(ATH11K_POLL_TIMEOUT_MS)); + poll->is_enable = true; + + spin_unlock_bh(&poll->lock); + + return 0; +} + +static int ath11k_core_napi_poll(struct napi_struct *napi, int budget) +{ + struct ath11k_poll *poll = container_of(napi, struct ath11k_poll, napi); + struct ath11k_base *ab = poll->ab; + int work_done = 0; + + if (poll->lmac_poll) + work_done = ath11k_dp_service_lmac_srng(ab, napi, budget); + + if (work_done < budget) { + napi_complete_done(napi, work_done); + ath11k_core_poll_timer_enable(poll); + } + + if (work_done > budget) + work_done = budget; + + return work_done; +} + +static void ath11k_core_poll_handler(struct timer_list *timer) +{ + struct ath11k_poll *poll = from_timer(poll, timer, timer); + struct ath11k_base *ab; + + if (!poll) + return; + + ab = poll->ab; + poll->timestamp = jiffies; + + napi_schedule(&poll->napi); +} + +int ath11k_core_poll_enable(struct ath11k_poll *poll) +{ + if (!poll->is_init) + return -EINVAL; + + napi_enable(&poll->napi); + ath11k_core_poll_timer_enable(poll); + + return 0; +} +EXPORT_SYMBOL(ath11k_core_poll_enable); + +static void __ath11k_core_poll_timer_disable(struct ath11k_poll *poll) +{ + del_timer_sync(&poll->timer); +} + +static void ath11k_core_poll_timer_disable(struct ath11k_poll *poll) +{ + if (!poll->is_init) + return; + + spin_lock_bh(&poll->lock); + + if (poll->is_enable) { + __ath11k_core_poll_timer_disable(poll); + + poll->is_enable = false; + } + + spin_unlock_bh(&poll->lock); +} + +void ath11k_core_poll_disable(struct ath11k_poll *poll) +{ + if (!poll->is_init) + return; + + ath11k_core_poll_timer_disable(poll); + + napi_synchronize(&poll->napi); + napi_disable(&poll->napi); +} +EXPORT_SYMBOL(ath11k_core_poll_disable); + +int ath11k_core_poll_config(struct ath11k_base *ab) +{ + if (ab->poll.is_init) + return 0; + + spin_lock_init(&ab->poll.lock); + + ab->poll.ab = ab; + ab->poll.is_enable = false; + + timer_setup(&ab->poll.timer, ath11k_core_poll_handler, 0); + init_dummy_netdev(&ab->poll.napi_ndev); + netif_napi_add(&ab->poll.napi_ndev, &ab->poll.napi, + ath11k_core_napi_poll, NAPI_POLL_WEIGHT); + + ab->poll.is_init = true; + + return 0; +} +EXPORT_SYMBOL(ath11k_core_poll_config); + +void ath11k_core_poll_free(struct ath11k_base *ab) +{ + if (!ab->poll.is_init) + return; + + spin_lock_bh(&ab->poll.lock); + + if (ab->poll.is_enable) { + __ath11k_core_poll_timer_disable(&ab->poll); + + ab->poll.is_enable = false; + } + + ab->poll.ab = NULL; + ab->poll.is_init = false; + + spin_unlock_bh(&ab->poll.lock); +} +EXPORT_SYMBOL(ath11k_core_poll_free); + int ath11k_core_pre_init(struct ath11k_base *ab) { int ret; Index: backports-20200415-4.4.60-9de9a9b19d3f/drivers/net/wireless/ath/ath11k/core.h =================================================================== --- backports-20200415-4.4.60-9de9a9b19d3f.orig/drivers/net/wireless/ath/ath11k/core.h +++ backports-20200415-4.4.60-9de9a9b19d3f/drivers/net/wireless/ath/ath11k/core.h @@ -710,6 +710,18 @@ struct ath11k_soc_dp_stats { struct ath11k_soc_dp_tx_err_stats tx_err; }; +struct ath11k_poll { + spinlock_t lock; + struct timer_list timer; + struct ath11k_base *ab; + struct napi_struct napi; + struct net_device napi_ndev; + u64 timestamp; + bool is_enable; + bool is_init; + bool lmac_poll; +}; + /* Master structure to hold the hw data which may be used in core module */ struct ath11k_base { enum ath11k_hw_rev hw_rev; @@ -811,6 +823,8 @@ struct ath11k_base { bool use_register_windowing; bool static_window_map; const struct ath11k_hw_regs *regs; + bool is_poll; + struct ath11k_poll poll; /* must be last */ u8 drv_priv[0] __aligned(sizeof(void *)); @@ -961,6 +975,11 @@ void ath11k_core_free_bdf(struct ath11k_ void ath11k_core_halt(struct ath11k *ar); int ath11k_core_pre_init(struct ath11k_base *ab); +int ath11k_core_poll_config(struct ath11k_base *ab); +int ath11k_core_poll_enable(struct ath11k_poll *poll); +void ath11k_core_poll_disable(struct ath11k_poll *poll); +void ath11k_core_poll_free(struct ath11k_base *ab); + static inline const char *ath11k_scan_state_str(enum ath11k_scan_state state) { switch (state) { Index: backports-20200415-4.4.60-9de9a9b19d3f/drivers/net/wireless/ath/ath11k/dp.c =================================================================== --- backports-20200415-4.4.60-9de9a9b19d3f.orig/drivers/net/wireless/ath/ath11k/dp.c +++ backports-20200415-4.4.60-9de9a9b19d3f/drivers/net/wireless/ath/ath11k/dp.c @@ -736,6 +736,45 @@ fail_desc_bank_free: return ret; } +int ath11k_dp_service_lmac_srng(struct ath11k_base *ab, + struct napi_struct *napi, + int budget) +{ + struct ath11k_pdev_dp *dp; + struct dp_rxdma_ring *rx_ring; + int i, tot_work_done = 0, work_done = 0; + + for (i = 0; i < ab->num_radios; i++) { + work_done = ath11k_dp_rx_process_mon_rings(ab, i, napi, budget); + + budget -= work_done; + tot_work_done += work_done; + + if (budget <= 0) + goto done; + } + + for (i = 0; i < ab->num_radios; i++) { + dp = &ab->pdevs[i].ar->dp; + rx_ring = &dp->rx_refill_buf_ring; + + work_done = ath11k_dp_process_rxdma_err(ab, i, budget); + + budget -= work_done; + tot_work_done += work_done; + + if (budget <= 0) + goto done; + + ath11k_dp_rxbufs_replenish(ab, i, rx_ring, 0, + HAL_RX_BUF_RBM_SW3_BM, + GFP_ATOMIC); + } + +done: + return tot_work_done; +} + int ath11k_dp_service_srng(struct ath11k_base *ab, struct ath11k_ext_irq_grp *irq_grp, int budget) Index: backports-20200415-4.4.60-9de9a9b19d3f/drivers/net/wireless/ath/ath11k/dp.h =================================================================== --- backports-20200415-4.4.60-9de9a9b19d3f.orig/drivers/net/wireless/ath/ath11k/dp.h +++ backports-20200415-4.4.60-9de9a9b19d3f/drivers/net/wireless/ath/ath11k/dp.h @@ -1664,6 +1664,9 @@ static inline void ath11k_dp_get_mac_add memcpy(addr + 4, &addr_h16, ETH_ALEN - 4); } +int ath11k_dp_service_lmac_srng(struct ath11k_base *ab, + struct napi_struct *napi, + int budget); int ath11k_dp_service_srng(struct ath11k_base *ab, struct ath11k_ext_irq_grp *irq_grp, int budget); Index: backports-20200415-4.4.60-9de9a9b19d3f/drivers/net/wireless/ath/ath11k/pci.c =================================================================== --- backports-20200415-4.4.60-9de9a9b19d3f.orig/drivers/net/wireless/ath/ath11k/pci.c +++ backports-20200415-4.4.60-9de9a9b19d3f/drivers/net/wireless/ath/ath11k/pci.c @@ -535,6 +535,9 @@ static void ath11k_pci_free_ext_irq(stru for (j = 0; j < irq_grp->num_irq; j++) free_irq(ab->irq_num[irq_grp->irqs[j]], irq_grp); } + + if (ab->is_poll) + ath11k_core_poll_free(ab); } static void ath11k_pci_free_irq(struct ath11k_base *ab) @@ -656,6 +659,9 @@ static void ath11k_pci_ext_irq_enable(st napi_enable(&irq_grp->napi); ath11k_pci_ext_grp_enable(irq_grp); } + + if (ab->is_poll) + ath11k_core_poll_enable(&ab->poll); } static void ath11k_pci_sync_ext_irqs(struct ath11k_base *ab) @@ -677,6 +683,9 @@ static void ath11k_pci_ext_irq_disable(s { __ath11k_pci_ext_irq_disable(ab); ath11k_pci_sync_ext_irqs(ab); + + if (ab->is_poll) + ath11k_core_poll_disable(&ab->poll); } static int ath11k_pci_ext_grp_napi_poll(struct napi_struct *napi, int budget) @@ -773,6 +782,14 @@ static int ath11k_pci_ext_irq_config(str } } + if (ab->is_poll) { + ret = ath11k_core_poll_config(ab); + if (ret) { + ath11k_err(ab, "failed to config poll %d\n", ret); + return ret; + } + } + return 0; } @@ -1175,6 +1192,8 @@ static int ath11k_pci_probe(struct pci_d if (ab->hw_rev == ATH11K_HW_QCN90XX) { ab->fixed_mem_region = true; ab->static_window_map = true; + ab->is_poll = true; + ab->poll.lmac_poll = true; } else { ab->use_register_windowing = true; ab->fixed_mem_region = false;