From 962dd748000244d9ddbd76338f2a34f51b2ca81b Mon Sep 17 00:00:00 2001 From: Rakesh Pillai Date: Thu, 2 Apr 2020 18:38:48 +0530 Subject: [PATCH] qcacmn: Reap more monitor ring entries before rescheduling timer Currently, in monitor mode, once the status ring is reaped we do not check again if there are new entries added in the ring during the monitor ring descriptor processing. This can cause backpressure on monitor rings when there is very high throughput or a bursty inflow of packets. Add the logic to continue reaping the monitor rings, until the work budget or a time quota is not exhausted. Change-Id: Iee95ac8aec92eabb3a8037b1dd9cf0c6e1dbe10b CRs-Fixed: 2650480 --- dp/wifi3.0/dp_internal.h | 18 +++++++++++- dp/wifi3.0/dp_main.c | 62 +++++++++++++++++++++++++++++++++++++--- 2 files changed, 75 insertions(+), 5 deletions(-) diff --git a/dp/wifi3.0/dp_internal.h b/dp/wifi3.0/dp_internal.h index ad422ea694..9160f2fa57 100644 --- a/dp/wifi3.0/dp_internal.h +++ b/dp/wifi3.0/dp_internal.h @@ -109,6 +109,23 @@ extern uint8_t dp_cpu_ring_map[DP_NSS_CPU_RING_MAP_MAX][WLAN_CFG_INT_NUM_CONTEXTS_MAX]; #endif +#define DP_MAX_TIMER_EXEC_TIME_TICKS \ + (QDF_LOG_TIMESTAMP_CYCLES_PER_10_US * 100 * 20) + +/** + * enum timer_yield_status - yield status code used in monitor mode timer. + * @DP_TIMER_NO_YIELD: do not yield + * @DP_TIMER_WORK_DONE: yield because work is done + * @DP_TIMER_WORK_EXHAUST: yield because work quota is exhausted + * @DP_TIMER_TIME_EXHAUST: yield due to time slot exhausted + */ +enum timer_yield_status { + DP_TIMER_NO_YIELD, + DP_TIMER_WORK_DONE, + DP_TIMER_WORK_EXHAUST, + DP_TIMER_TIME_EXHAUST, +}; + #if DP_PRINT_ENABLE #include /* va_list */ #include /* qdf_vprint */ @@ -131,7 +148,6 @@ enum { DP_PRINT_LEVEL_INFO2, }; - #define dp_print(level, fmt, ...) do { \ if (level <= g_txrx_print_level) \ qdf_print(fmt, ## __VA_ARGS__); \ diff --git a/dp/wifi3.0/dp_main.c b/dp/wifi3.0/dp_main.c index 4f09795ce4..3f345be315 100644 --- a/dp/wifi3.0/dp_main.c +++ b/dp/wifi3.0/dp_main.c @@ -1538,6 +1538,29 @@ void dp_srng_access_end(struct dp_intr *int_ctx, struct dp_soc *dp_soc, } #endif /* WLAN_FEATURE_DP_EVENT_HISTORY */ +/* + * dp_should_timer_irq_yield() - Decide if the bottom half should yield + * @soc: DP soc handle + * @work_done: work done in softirq context + * @start_time: start time for the softirq + * + * Return: enum with yield code + */ +static enum timer_yield_status +dp_should_timer_irq_yield(struct dp_soc *soc, uint32_t work_done, + uint64_t start_time) +{ + uint32_t cur_time = qdf_get_log_timestamp(); + + if (!work_done) + return DP_TIMER_WORK_DONE; + + if (cur_time - start_time > DP_MAX_TIMER_EXEC_TIME_TICKS) + return DP_TIMER_TIME_EXHAUST; + + return DP_TIMER_TIME_EXHAUST; +} + /** * dp_process_lmac_rings() - Process LMAC rings * @int_ctx: interrupt context @@ -1751,17 +1774,48 @@ budget_done: static void dp_interrupt_timer(void *arg) { struct dp_soc *soc = (struct dp_soc *) arg; + enum timer_yield_status yield = DP_TIMER_NO_YIELD; + uint32_t work_done = 0, total_work_done = 0; + int budget = 0xffff; + uint32_t remaining_quota = budget; + uint64_t start_time; int i; if (!qdf_atomic_read(&soc->cmn_init_done)) return; - for (i = 0; i < wlan_cfg_get_num_contexts(soc->wlan_cfg_ctx); i++) { - if (soc->intr_ctx[i].rx_mon_ring_mask) - dp_process_lmac_rings(&soc->intr_ctx[i], 0xffff); + start_time = qdf_get_log_timestamp(); + + while (yield == DP_TIMER_NO_YIELD) { + for (i = 0; + i < wlan_cfg_get_num_contexts(soc->wlan_cfg_ctx); i++) { + if (!soc->intr_ctx[i].rx_mon_ring_mask) + continue; + + work_done = dp_process_lmac_rings(&soc->intr_ctx[i], + remaining_quota); + if (work_done) { + budget -= work_done; + if (budget <= 0) { + yield = DP_TIMER_WORK_EXHAUST; + goto budget_done; + } + remaining_quota = budget; + total_work_done += work_done; + } + } + + yield = dp_should_timer_irq_yield(soc, total_work_done, + start_time); + total_work_done = 0; } - qdf_timer_mod(&soc->int_timer, DP_INTR_POLL_TIMER_MS); +budget_done: + if (yield == DP_TIMER_WORK_EXHAUST || + yield == DP_TIMER_TIME_EXHAUST) + qdf_timer_mod(&soc->int_timer, 1); + else + qdf_timer_mod(&soc->int_timer, DP_INTR_POLL_TIMER_MS); } /*