瀏覽代碼

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
Rakesh Pillai 5 年之前
父節點
當前提交
962dd74800
共有 2 個文件被更改,包括 75 次插入5 次删除
  1. 17 1
      dp/wifi3.0/dp_internal.h
  2. 58 4
      dp/wifi3.0/dp_main.c

+ 17 - 1
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 <stdarg.h>       /* va_list */
 #include <qdf_types.h> /* 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__); \

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