Przeglądaj źródła

qcacmn: extend hif tasklet latency detection

Extend the feature to detect tasklet latency for all CEs.
And also introduce a build flag
DETECTION_LATENCY_TASKLET_MASK to control the enablement
of each, set bit-X to enable detection for CE-X, the
default value is 0x84(BIT(2) | BIT(7)).

Change-Id: I2874d1d50fc5febbf028ebb48ba64e11977c8c34
CRs-Fixed: 3474314
Yu Wang 2 lat temu
rodzic
commit
bfebabf7bd
4 zmienionych plików z 156 dodań i 88 usunięć
  1. 0 2
      hif/inc/hif.h
  2. 11 5
      hif/src/ce/ce_tasklet.c
  3. 111 75
      hif/src/hif_main.c
  4. 34 6
      hif/src/hif_main.h

+ 0 - 2
hif/inc/hif.h

@@ -2444,8 +2444,6 @@ void hif_latency_detect_credit_record_time(
 
 void hif_latency_detect_timer_start(struct hif_opaque_softc *hif_ctx);
 void hif_latency_detect_timer_stop(struct hif_opaque_softc *hif_ctx);
-void hif_tasklet_latency(struct hif_softc *scn, bool from_timer);
-void hif_credit_latency(struct hif_softc *scn, bool from_timer);
 void hif_check_detection_latency(struct hif_softc *scn,
 				 bool from_timer,
 				 uint32_t bitmap_type);

+ 11 - 5
hif/src/ce/ce_tasklet.c

@@ -368,11 +368,14 @@ void hif_latency_detect_tasklet_sched(
 	struct hif_softc *scn,
 	struct ce_tasklet_entry *tasklet_entry)
 {
-	if (tasklet_entry->ce_id != CE_ID_2)
+	int idx = tasklet_entry->ce_id;
+
+	if (idx >= HIF_TASKLET_IN_MONITOR ||
+	    !qdf_test_bit(idx, scn->latency_detect.tasklet_bmap))
 		return;
 
-	scn->latency_detect.ce2_tasklet_sched_cpuid = qdf_get_cpu();
-	scn->latency_detect.ce2_tasklet_sched_time = qdf_system_ticks();
+	scn->latency_detect.tasklet_info[idx].sched_cpuid = qdf_get_cpu();
+	scn->latency_detect.tasklet_info[idx].sched_time = qdf_system_ticks();
 }
 
 static inline
@@ -380,10 +383,13 @@ void hif_latency_detect_tasklet_exec(
 	struct hif_softc *scn,
 	struct ce_tasklet_entry *tasklet_entry)
 {
-	if (tasklet_entry->ce_id != CE_ID_2)
+	int idx = tasklet_entry->ce_id;
+
+	if (idx >= HIF_TASKLET_IN_MONITOR ||
+	    !qdf_test_bit(idx, scn->latency_detect.tasklet_bmap))
 		return;
 
-	scn->latency_detect.ce2_tasklet_exec_time = qdf_system_ticks();
+	scn->latency_detect.tasklet_info[idx].exec_time = qdf_system_ticks();
 	hif_check_detection_latency(scn, false, BIT(HIF_DETECT_TASKLET));
 }
 #else

+ 111 - 75
hif/src/hif_main.c

@@ -850,17 +850,25 @@ static void hif_cpuhp_unregister(struct hif_softc *scn)
 #endif /* ifdef HIF_CPU_PERF_AFFINE_MASK */
 
 #ifdef HIF_DETECTION_LATENCY_ENABLE
+/*
+ * Bitmask to control enablement of latency detection for the tasklets,
+ * bit-X represents for tasklet of WLAN_CE_X.
+ */
+#ifndef DETECTION_LATENCY_TASKLET_MASK
+#define DETECTION_LATENCY_TASKLET_MASK (BIT(2) | BIT(7))
+#endif
 
-void hif_tasklet_latency(struct hif_softc *scn, bool from_timer)
+static inline int
+__hif_tasklet_latency(struct hif_softc *scn, bool from_timer, int idx)
 {
-	qdf_time_t ce2_tasklet_sched_time =
-		scn->latency_detect.ce2_tasklet_sched_time;
-	qdf_time_t ce2_tasklet_exec_time =
-		scn->latency_detect.ce2_tasklet_exec_time;
-	qdf_time_t curr_jiffies = qdf_system_ticks();
-	uint32_t detect_latency_threshold =
-		scn->latency_detect.detect_latency_threshold;
-	int cpu_id = qdf_get_cpu();
+	qdf_time_t sched_time =
+		scn->latency_detect.tasklet_info[idx].sched_time;
+	qdf_time_t exec_time =
+		scn->latency_detect.tasklet_info[idx].exec_time;
+	qdf_time_t curr_time = qdf_system_ticks();
+	uint32_t threshold = scn->latency_detect.threshold;
+	qdf_time_t expect_exec_time =
+		sched_time + qdf_system_msecs_to_ticks(threshold);
 
 	/* 2 kinds of check here.
 	 * from_timer==true:  check if tasklet stall
@@ -868,36 +876,45 @@ void hif_tasklet_latency(struct hif_softc *scn, bool from_timer)
 	 */
 
 	if ((from_timer ?
-	    qdf_system_time_after(ce2_tasklet_sched_time,
-				  ce2_tasklet_exec_time) :
-	    qdf_system_time_after(ce2_tasklet_exec_time,
-				  ce2_tasklet_sched_time)) &&
-	    qdf_system_time_after(
-		curr_jiffies,
-		ce2_tasklet_sched_time +
-		qdf_system_msecs_to_ticks(detect_latency_threshold))) {
-		hif_err("tasklet ce2 latency: from_timer %d, curr_jiffies %lu, ce2_tasklet_sched_time %lu,ce2_tasklet_exec_time %lu, detect_latency_threshold %ums detect_latency_timer_timeout %ums, cpu_id %d, called: %ps",
-			from_timer, curr_jiffies, ce2_tasklet_sched_time,
-			ce2_tasklet_exec_time, detect_latency_threshold,
-			scn->latency_detect.detect_latency_timer_timeout,
-			cpu_id, (void *)_RET_IP_);
-		goto latency;
+	     qdf_system_time_after(sched_time, exec_time) :
+	     qdf_system_time_after(exec_time, sched_time)) &&
+	    qdf_system_time_after(curr_time, expect_exec_time)) {
+		hif_err("tasklet[%d] latency detected: from_timer %d, curr_time %lu, sched_time %lu, exec_time %lu, threshold %ums, timeout %ums, cpu_id %d, called: %ps",
+			idx, from_timer, curr_time, sched_time,
+			exec_time, threshold,
+			scn->latency_detect.timeout,
+			qdf_get_cpu(), (void *)_RET_IP_);
+		return -ETIMEDOUT;
 	}
-	return;
 
-latency:
-	qdf_trigger_self_recovery(NULL, QDF_TASKLET_CREDIT_LATENCY_DETECT);
+	return 0;
+}
+
+static inline void hif_tasklet_latency(struct hif_softc *scn, bool from_timer)
+{
+	int i, ret;
+
+	for (i = 0; i < HIF_TASKLET_IN_MONITOR; i++) {
+		if (!qdf_test_bit(i, scn->latency_detect.tasklet_bmap))
+			continue;
+
+		ret = __hif_tasklet_latency(scn, from_timer, i);
+		if (!ret)
+			continue;
+
+		qdf_trigger_self_recovery(NULL,
+					  QDF_TASKLET_CREDIT_LATENCY_DETECT);
+		return;
+	}
 }
 
-void hif_credit_latency(struct hif_softc *scn, bool from_timer)
+static inline void hif_credit_latency(struct hif_softc *scn, bool from_timer)
 {
 	qdf_time_t credit_request_time =
 		scn->latency_detect.credit_request_time;
-	qdf_time_t credit_report_time =
-		scn->latency_detect.credit_report_time;
+	qdf_time_t credit_report_time = scn->latency_detect.credit_report_time;
 	qdf_time_t curr_jiffies = qdf_system_ticks();
-	uint32_t detect_latency_threshold =
-		scn->latency_detect.detect_latency_threshold;
+	uint32_t threshold = scn->latency_detect.threshold;
 	int cpu_id = qdf_get_cpu();
 
 	/* 2 kinds of check here.
@@ -906,18 +923,15 @@ void hif_credit_latency(struct hif_softc *scn, bool from_timer)
 	 */
 
 	if ((from_timer ?
-	    qdf_system_time_after(credit_request_time,
-				  credit_report_time) :
-	    qdf_system_time_after(credit_report_time,
-				  credit_request_time)) &&
-	    qdf_system_time_after(
-		curr_jiffies,
-		credit_request_time +
-		qdf_system_msecs_to_ticks(detect_latency_threshold))) {
-		hif_err("credit report latency: from timer %d, curr_jiffies %lu, credit_request_time %lu,credit_report_time %lu, detect_latency_threshold %ums, detect_latency_timer_timeout %ums, cpu_id %d, called: %ps",
+	     qdf_system_time_after(credit_request_time, credit_report_time) :
+	     qdf_system_time_after(credit_report_time, credit_request_time)) &&
+	    qdf_system_time_after(curr_jiffies,
+				  credit_request_time +
+				  qdf_system_msecs_to_ticks(threshold))) {
+		hif_err("credit report latency: from timer %d, curr_jiffies %lu, credit_request_time %lu, credit_report_time %lu, threshold %ums, timeout %ums, cpu_id %d, called: %ps",
 			from_timer, curr_jiffies, credit_request_time,
-			credit_report_time, detect_latency_threshold,
-			scn->latency_detect.detect_latency_timer_timeout,
+			credit_report_time, threshold,
+			scn->latency_detect.timeout,
 			cpu_id, (void *)_RET_IP_);
 		goto latency;
 	}
@@ -956,7 +970,9 @@ void hif_check_detection_latency(struct hif_softc *scn,
 static void hif_latency_detect_timeout_handler(void *arg)
 {
 	struct hif_softc *scn = (struct hif_softc *)arg;
-	int next_cpu;
+	int next_cpu, i;
+	qdf_cpu_mask cpu_mask = {0};
+	struct hif_latency_detect *detect = &scn->latency_detect;
 
 	hif_check_detection_latency(scn, true,
 				    BIT(HIF_DETECT_TASKLET) |
@@ -971,47 +987,40 @@ static void hif_latency_detect_timeout_handler(void *arg)
 	 * if tasklet stall, anyway other place will detect it, just
 	 * a little later.
 	 */
-	next_cpu = cpumask_any_but(
-			cpu_active_mask,
-			scn->latency_detect.ce2_tasklet_sched_cpuid);
+	qdf_cpumask_copy(&cpu_mask, (const qdf_cpu_mask *)cpu_active_mask);
+	for (i = 0; i < HIF_TASKLET_IN_MONITOR; i++) {
+		if (!qdf_test_bit(i, detect->tasklet_bmap))
+			continue;
 
+		qdf_cpumask_clear_cpu(detect->tasklet_info[i].sched_cpuid,
+				      &cpu_mask);
+	}
+
+	next_cpu = cpumask_first(&cpu_mask);
 	if (qdf_unlikely(next_cpu >= nr_cpu_ids)) {
 		hif_debug("start timer on local");
 		/* it doesn't found a available cpu, start on local cpu*/
-		qdf_timer_mod(
-			&scn->latency_detect.detect_latency_timer,
-			scn->latency_detect.detect_latency_timer_timeout);
+		qdf_timer_mod(&detect->timer, detect->timeout);
 	} else {
-		qdf_timer_start_on(
-			&scn->latency_detect.detect_latency_timer,
-			scn->latency_detect.detect_latency_timer_timeout,
-			next_cpu);
+		qdf_timer_start_on(&detect->timer, detect->timeout, next_cpu);
 	}
 }
 
 static void hif_latency_detect_timer_init(struct hif_softc *scn)
 {
-	if (!scn) {
-		hif_info_high("scn is null");
-		return;
-	}
-
-	if (QDF_GLOBAL_MISSION_MODE != hif_get_conparam(scn))
-		return;
-
-	scn->latency_detect.detect_latency_timer_timeout =
+	scn->latency_detect.timeout =
 		DETECTION_TIMER_TIMEOUT;
-	scn->latency_detect.detect_latency_threshold =
+	scn->latency_detect.threshold =
 		DETECTION_LATENCY_THRESHOLD;
 
 	hif_info("timer timeout %u, latency threshold %u",
-		 scn->latency_detect.detect_latency_timer_timeout,
-		 scn->latency_detect.detect_latency_threshold);
+		 scn->latency_detect.timeout,
+		 scn->latency_detect.threshold);
 
 	scn->latency_detect.is_timer_started = false;
 
 	qdf_timer_init(NULL,
-		       &scn->latency_detect.detect_latency_timer,
+		       &scn->latency_detect.timer,
 		       &hif_latency_detect_timeout_handler,
 		       scn,
 		       QDF_TIMER_TYPE_SW_SPIN);
@@ -1019,11 +1028,38 @@ static void hif_latency_detect_timer_init(struct hif_softc *scn)
 
 static void hif_latency_detect_timer_deinit(struct hif_softc *scn)
 {
+	hif_info("deinit timer");
+	qdf_timer_free(&scn->latency_detect.timer);
+}
+
+static void hif_latency_detect_init(struct hif_softc *scn)
+{
+	uint32_t tasklet_mask;
+	int i;
+
 	if (QDF_GLOBAL_MISSION_MODE != hif_get_conparam(scn))
 		return;
 
-	hif_info("deinit timer");
-	qdf_timer_free(&scn->latency_detect.detect_latency_timer);
+	tasklet_mask = DETECTION_LATENCY_TASKLET_MASK;
+	hif_info("tasklet mask is 0x%x", tasklet_mask);
+	for (i = 0; i < HIF_TASKLET_IN_MONITOR; i++) {
+		if (BIT(i) & tasklet_mask)
+			qdf_set_bit(i, scn->latency_detect.tasklet_bmap);
+	}
+
+	hif_latency_detect_timer_init(scn);
+}
+
+static void hif_latency_detect_deinit(struct hif_softc *scn)
+{
+	int i;
+
+	if (QDF_GLOBAL_MISSION_MODE != hif_get_conparam(scn))
+		return;
+
+	hif_latency_detect_timer_deinit(scn);
+	for (i = 0; i < HIF_TASKLET_IN_MONITOR; i++)
+		qdf_clear_bit(i, scn->latency_detect.tasklet_bmap);
 }
 
 void hif_latency_detect_timer_start(struct hif_opaque_softc *hif_ctx)
@@ -1039,8 +1075,8 @@ void hif_latency_detect_timer_start(struct hif_opaque_softc *hif_ctx)
 		return;
 	}
 
-	qdf_timer_start(&scn->latency_detect.detect_latency_timer,
-			scn->latency_detect.detect_latency_timer_timeout);
+	qdf_timer_start(&scn->latency_detect.timer,
+			scn->latency_detect.timeout);
 	scn->latency_detect.is_timer_started = true;
 }
 
@@ -1053,7 +1089,7 @@ void hif_latency_detect_timer_stop(struct hif_opaque_softc *hif_ctx)
 
 	hif_debug_rl("stop timer");
 
-	qdf_timer_sync_cancel(&scn->latency_detect.detect_latency_timer);
+	qdf_timer_sync_cancel(&scn->latency_detect.timer);
 	scn->latency_detect.is_timer_started = false;
 }
 
@@ -1094,10 +1130,10 @@ void hif_set_enable_detection(struct hif_opaque_softc *hif_ctx, bool value)
 	scn->latency_detect.enable_detection = value;
 }
 #else
-static void hif_latency_detect_timer_init(struct hif_softc *scn)
+static inline void hif_latency_detect_init(struct hif_softc *scn)
 {}
 
-static void hif_latency_detect_timer_deinit(struct hif_softc *scn)
+static inline void hif_latency_detect_deinit(struct hif_softc *scn)
 {}
 #endif
 struct hif_opaque_softc *hif_open(qdf_device_t qdf_ctx,
@@ -1147,7 +1183,7 @@ struct hif_opaque_softc *hif_open(qdf_device_t qdf_ctx,
 	hif_rtpm_lock_init(scn);
 
 	hif_cpuhp_register(scn);
-	hif_latency_detect_timer_init(scn);
+	hif_latency_detect_init(scn);
 
 out:
 	return GET_HIF_OPAQUE_HDL(scn);
@@ -1186,7 +1222,7 @@ void hif_close(struct hif_opaque_softc *hif_ctx)
 		return;
 	}
 
-	hif_latency_detect_timer_deinit(scn);
+	hif_latency_detect_deinit(scn);
 
 	if (scn->athdiag_procfs_inited) {
 		athdiag_procfs_remove();

+ 34 - 6
hif/src/hif_main.h

@@ -176,16 +176,44 @@ struct hif_ce_stats {
 };
 
 #ifdef HIF_DETECTION_LATENCY_ENABLE
+/**
+ * struct hif_tasklet_running_info - running info of tasklet
+ * @sched_cpuid: id of cpu on which the tasklet was scheduled
+ * @sched_time: time when the tasklet was scheduled
+ * @exec_time: time when the tasklet was executed
+ */
+struct hif_tasklet_running_info {
+	int sched_cpuid;
+	qdf_time_t sched_time;
+	qdf_time_t exec_time;
+};
+
+#define HIF_TASKLET_IN_MONITOR CE_COUNT_MAX
+
 struct hif_latency_detect {
-	qdf_timer_t detect_latency_timer;
-	uint32_t detect_latency_timer_timeout;
+	qdf_timer_t timer;
+	uint32_t timeout;
 	bool is_timer_started;
 	bool enable_detection;
 	/* threshold when stall happens */
-	uint32_t detect_latency_threshold;
-	int ce2_tasklet_sched_cpuid;
-	qdf_time_t ce2_tasklet_sched_time;
-	qdf_time_t ce2_tasklet_exec_time;
+	uint32_t threshold;
+
+	/*
+	 * Bitmap to indicate the enablement of latency detection for
+	 * the tasklets. bit-X represents for tasklet of WLAN_CE_X,
+	 * latency detection is enabled on the corresponding tasklet
+	 * when a bit is set.
+	 * At the same time, this bitmap also indicates the validity of
+	 * elements in array 'tasklet_info', bit-X represents for index-X,
+	 * the corresponding element is valid when a bit is set.
+	 */
+	qdf_bitmap(tasklet_bmap, HIF_TASKLET_IN_MONITOR);
+
+	/*
+	 * Array to record running info of tasklets, info of tasklet
+	 * for WLAN_CE_X is stored at index-X.
+	 */
+	struct hif_tasklet_running_info tasklet_info[HIF_TASKLET_IN_MONITOR];
 	qdf_time_t credit_request_time;
 	qdf_time_t credit_report_time;
 };