Browse Source

qcacmn: refine hif tasklet latency detection

When one of the enabled CE tasklet is executed, it will
check latency of all the others which are enabled, it's
redundant. Add a new API to check latency for a single
tasklet.
Add API to record sched time for a tasklet, which will
check the enablement of detection before recording the
time.

Change-Id: I515ca27fc2e97231397573b4903c001d29326bd2
CRs-Fixed: 3514285
Yu Wang 2 năm trước cách đây
mục cha
commit
1632797f1c
3 tập tin đã thay đổi với 98 bổ sung63 xóa
  1. 27 0
      hif/inc/hif.h
  2. 3 47
      hif/src/ce/ce_tasklet.c
  3. 68 16
      hif/src/hif_main.c

+ 27 - 0
hif/inc/hif.h

@@ -2507,6 +2507,25 @@ void hif_check_detection_latency(struct hif_softc *scn,
 				 bool from_timer,
 				 uint32_t bitmap_type);
 void hif_set_enable_detection(struct hif_opaque_softc *hif_ctx, bool value);
+
+/**
+ * hif_tasklet_latency_record_exec() - record execute time and
+ * check the latency
+ * @scn: HIF opaque context
+ * @idx: CE id
+ *
+ * Return: None
+ */
+void hif_tasklet_latency_record_exec(struct hif_softc *scn, int idx);
+
+/**
+ * hif_tasklet_latency_record_sched() - record schedule time of a tasklet
+ * @scn: HIF opaque context
+ * @idx: CE id
+ *
+ * Return: None
+ */
+void hif_tasklet_latency_record_sched(struct hif_softc *scn, int idx);
 #else
 static inline
 void hif_latency_detect_timer_start(struct hif_opaque_softc *hif_ctx)
@@ -2530,6 +2549,14 @@ void hif_check_detection_latency(struct hif_softc *scn,
 static inline
 void hif_set_enable_detection(struct hif_opaque_softc *hif_ctx, bool value)
 {}
+
+static inline
+void hif_tasklet_latency_record_exec(struct hif_softc *scn, int idx)
+{}
+
+static inline
+void hif_tasklet_latency_record_sched(struct hif_softc *scn, int idx)
+{}
 #endif
 
 #ifdef SYSTEM_PM_CHECK

+ 3 - 47
hif/src/ce/ce_tasklet.c

@@ -362,50 +362,6 @@ hif_reset_ce_full_count(struct hif_softc *scn, uint8_t ce_id)
 }
 #endif
 
-#ifdef HIF_DETECTION_LATENCY_ENABLE
-static inline
-void hif_latency_detect_tasklet_sched(
-	struct hif_softc *scn,
-	struct ce_tasklet_entry *tasklet_entry)
-{
-	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.tasklet_info[idx].sched_cpuid = qdf_get_cpu();
-	scn->latency_detect.tasklet_info[idx].sched_time = qdf_system_ticks();
-}
-
-static inline
-void hif_latency_detect_tasklet_exec(
-	struct hif_softc *scn,
-	struct ce_tasklet_entry *tasklet_entry)
-{
-	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.tasklet_info[idx].exec_time = qdf_system_ticks();
-	hif_check_detection_latency(scn, false, BIT(HIF_DETECT_TASKLET));
-}
-#else
-static inline
-void hif_latency_detect_tasklet_sched(
-	struct hif_softc *scn,
-	struct ce_tasklet_entry *tasklet_entry)
-{}
-
-static inline
-void hif_latency_detect_tasklet_exec(
-	struct hif_softc *scn,
-	struct ce_tasklet_entry *tasklet_entry)
-{}
-#endif
-
 #ifdef CUSTOM_CB_SCHEDULER_SUPPORT
 /**
  * ce_get_custom_cb_pending() - Helper API to check whether the custom
@@ -466,7 +422,7 @@ static void ce_tasklet(unsigned long data)
 	if (scn->ce_latency_stats)
 		hif_record_tasklet_exec_entry_ts(scn, tasklet_entry->ce_id);
 
-	hif_latency_detect_tasklet_exec(scn, tasklet_entry);
+	hif_tasklet_latency_record_exec(scn, tasklet_entry->ce_id);
 
 	if (qdf_atomic_read(&scn->link_suspended)) {
 		hif_err("ce %d tasklet fired after link suspend",
@@ -497,7 +453,7 @@ static void ce_tasklet(unsigned long data)
 					 NULL, NULL, -1, 0);
 
 		ce_tasklet_schedule(tasklet_entry);
-		hif_latency_detect_tasklet_sched(scn, tasklet_entry);
+		hif_tasklet_latency_record_sched(scn, tasklet_entry->ce_id);
 
 		hif_reset_ce_full_count(scn, tasklet_entry->ce_id);
 		if (scn->ce_latency_stats) {
@@ -792,7 +748,7 @@ static inline bool hif_tasklet_schedule(struct hif_opaque_softc *hif_ctx,
 	/* keep it before tasklet_schedule, this is to happy whunt.
 	 * in whunt, tasklet may run before finished hif_tasklet_schedule.
 	 */
-	hif_latency_detect_tasklet_sched(scn, tasklet_entry);
+	hif_tasklet_latency_record_sched(scn, tasklet_entry->ce_id);
 	ce_tasklet_schedule(tasklet_entry);
 
 	hif_reset_ce_full_count(scn, tasklet_entry->ce_id);

+ 68 - 16
hif/src/hif_main.c

@@ -884,38 +884,76 @@ __hif_tasklet_latency(struct hif_softc *scn, bool from_timer, int idx)
 	 * from_timer==true:  check if tasklet stall
 	 * from_timer==false: check tasklet execute comes late
 	 */
-
-	if ((from_timer ?
-	     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)) {
+	if (from_timer ?
+	    (qdf_system_time_after(sched_time, exec_time) &&
+	     qdf_system_time_after(curr_time, expect_exec_time)) :
+	    qdf_system_time_after(exec_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_);
+		qdf_trigger_self_recovery(NULL,
+					  QDF_TASKLET_CREDIT_LATENCY_DETECT);
 		return -ETIMEDOUT;
 	}
 
 	return 0;
 }
 
-static inline void hif_tasklet_latency(struct hif_softc *scn, bool from_timer)
+/**
+ * hif_tasklet_latency_detect_enabled() - check whether latency detect
+ * is enabled for the tasklet which is specified by idx
+ * @scn: HIF opaque context
+ * @idx: CE id
+ *
+ * Return: true if latency detect is enabled for the specified tasklet,
+ * false otherwise.
+ */
+static inline bool
+hif_tasklet_latency_detect_enabled(struct hif_softc *scn, int idx)
 {
-	int i, ret;
+	if (QDF_GLOBAL_MISSION_MODE != hif_get_conparam(scn))
+		return false;
 
-	for (i = 0; i < HIF_TASKLET_IN_MONITOR; i++) {
-		if (!qdf_test_bit(i, scn->latency_detect.tasklet_bmap))
-			continue;
+	if (!scn->latency_detect.enable_detection)
+		return false;
 
-		ret = __hif_tasklet_latency(scn, from_timer, i);
-		if (!ret)
-			continue;
+	if (idx < 0 || idx >= HIF_TASKLET_IN_MONITOR ||
+	    !qdf_test_bit(idx, scn->latency_detect.tasklet_bmap))
+		return false;
 
-		qdf_trigger_self_recovery(NULL,
-					  QDF_TASKLET_CREDIT_LATENCY_DETECT);
+	return true;
+}
+
+void hif_tasklet_latency_record_exec(struct hif_softc *scn, int idx)
+{
+	if (!hif_tasklet_latency_detect_enabled(scn, idx))
 		return;
-	}
+
+	/*
+	 * hif_set_enable_detection(true) might come between
+	 * hif_tasklet_latency_record_sched() and
+	 * hif_tasklet_latency_record_exec() during wlan startup, then the
+	 * sched_time is 0 but exec_time is not, and hit the timeout case in
+	 * __hif_tasklet_latency().
+	 * To avoid such issue, skip exec_time recording if sched_time has not
+	 * been recorded.
+	 */
+	if (!scn->latency_detect.tasklet_info[idx].sched_time)
+		return;
+
+	scn->latency_detect.tasklet_info[idx].exec_time = qdf_system_ticks();
+	__hif_tasklet_latency(scn, false, idx);
+}
+
+void hif_tasklet_latency_record_sched(struct hif_softc *scn, int idx)
+{
+	if (!hif_tasklet_latency_detect_enabled(scn, idx))
+		return;
+
+	scn->latency_detect.tasklet_info[idx].sched_cpuid = qdf_get_cpu();
+	scn->latency_detect.tasklet_info[idx].sched_time = qdf_system_ticks();
 }
 
 static inline void hif_credit_latency(struct hif_softc *scn, bool from_timer)
@@ -951,6 +989,20 @@ latency:
 	qdf_trigger_self_recovery(NULL, QDF_TASKLET_CREDIT_LATENCY_DETECT);
 }
 
+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)
+			return;
+	}
+}
+
 /**
  * hif_check_detection_latency(): to check if latency for tasklet/credit
  *