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
此提交包含在:
@@ -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);
|
||||
|
@@ -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
|
||||
*
|
||||
|
新增問題並參考
封鎖使用者