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); } /*