diff --git a/hif/inc/hif.h b/hif/inc/hif.h index 626b73e751..f935d0faae 100644 --- a/hif/inc/hif.h +++ b/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); diff --git a/hif/src/ce/ce_tasklet.c b/hif/src/ce/ce_tasklet.c index 4e008602bd..b7d62e1d2c 100644 --- a/hif/src/ce/ce_tasklet.c +++ b/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 diff --git a/hif/src/hif_main.c b/hif/src/hif_main.c index 5cf62f2953..69284bc8d1 100644 --- a/hif/src/hif_main.c +++ b/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; } -void hif_credit_latency(struct hif_softc *scn, bool from_timer) +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; + } +} + +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(); diff --git a/hif/src/hif_main.h b/hif/src/hif_main.h index 9d2009b3d2..4cfb14f5cb 100644 --- a/hif/src/hif_main.h +++ b/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; };