From b976076b3b196fd7d8aa635cc60b206fab1df44b Mon Sep 17 00:00:00 2001 From: Surya Prakash Raajen Date: Thu, 2 Jan 2020 20:02:52 +0530 Subject: [PATCH] qcacmn: Track tasklet execution and total time (sched+exec) Add support to track tasklet execution and total time in different buckets for debugging purposes Change-Id: Ide459c385b2a44c0f16d05b37879c8b462782d72 CRs-Fixed: 2589199 --- hif/src/ce/ce_internal.h | 4 +- hif/src/ce/ce_main.h | 52 +++++++- hif/src/ce/ce_tasklet.c | 209 +++++++++++++++++++++++++++++- hif/src/ce/ce_tasklet.h | 4 +- hif/src/dispatcher/ahb_api.h | 4 +- hif/src/dispatcher/multibus_ahb.c | 5 +- hif/src/pcie/if_pci.c | 2 +- hif/src/snoc/if_ahb.c | 20 +++ hif/src/snoc/if_snoc.c | 8 +- htc/htc.c | 12 +- htc/htc_api.h | 11 +- wmi/src/wmi_unified.c | 3 +- 12 files changed, 312 insertions(+), 22 deletions(-) diff --git a/hif/src/ce/ce_internal.h b/hif/src/ce/ce_internal.h index a5edd14934..0de6feb3ae 100644 --- a/hif/src/ce/ce_internal.h +++ b/hif/src/ce/ce_internal.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2020 The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -468,6 +468,8 @@ enum hif_ce_event_type { HIF_RX_DESC_PRE_NBUF_ALLOC, HIF_RX_DESC_PRE_NBUF_MAP, HIF_RX_DESC_POST_NBUF_MAP, + + HIF_EVENT_TYPE_MAX, }; void ce_init_ce_desc_event_log(struct hif_softc *scn, int ce_id, int size); diff --git a/hif/src/ce/ce_main.h b/hif/src/ce/ce_main.h index c943feb5ee..f3feb76158 100644 --- a/hif/src/ce/ce_main.h +++ b/hif/src/ce/ce_main.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2020 The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -49,6 +49,7 @@ #define CE_USEFUL_SIZE 0x00000058 #define CE_ALL_BITMAP 0xFFFF +#define HIF_REQUESTED_EVENTS 20 /** * enum ce_id_type * @@ -70,6 +71,30 @@ enum ce_id_type { CE_ID_MAX }; +/** + * enum ce_buckets + * + * @ce_buckets: CE tasklet time buckets + * @CE_BUCKET_500_US: tasklet bucket to store 0-0.5ms + * @CE_BUCKET_1_MS: tasklet bucket to store 0.5-1ms + * @CE_BUCKET_2_MS: tasklet bucket to store 1-2ms + * @CE_BUCKET_5_MS: tasklet bucket to store 2-5ms + * @CE_BUCKET_10_MS: tasklet bucket to store 5-10ms + * @CE_BUCKET_BEYOND: tasklet bucket to store > 10ms + * @CE_BUCKET_MAX: enum max value + */ +#ifdef CE_TASKLET_DEBUG_ENABLE +enum ce_buckets { + CE_BUCKET_500_US, + CE_BUCKET_1_MS, + CE_BUCKET_2_MS, + CE_BUCKET_5_MS, + CE_BUCKET_10_MS, + CE_BUCKET_BEYOND, + CE_BUCKET_MAX, +}; +#endif + enum ce_target_type { CE_SVC_LEGACY, CE_SVC_SRNG, @@ -134,8 +159,33 @@ static inline bool hif_dummy_grp_done(struct hif_exec_context *grp_entry, int extern struct hif_execution_ops tasklet_sched_ops; extern struct hif_execution_ops napi_sched_ops; +/** + * struct ce_stats + * + * @ce_per_cpu: Stats of the CEs running per CPU + * @record_index: Current index to store in time record + * @tasklet_sched_entry_ts: Timestamp when tasklet is scheduled + * @tasklet_exec_entry_ts: Timestamp when tasklet is started execuiton + * @tasklet_exec_time_record: Last N number of tasklets execution time + * @tasklet_sched_time_record: Last N number of tasklets scheduled time + * @ce_tasklet_exec_bucket: Tasklet execution time buckets + * @ce_tasklet_sched_bucket: Tasklet time in queue buckets + * @ce_tasklet_exec_last_update: Latest timestamp when bucket is updated + * @ce_tasklet_sched_last_update: Latest timestamp when bucket is updated + */ struct ce_stats { uint32_t ce_per_cpu[CE_COUNT_MAX][QDF_MAX_AVAILABLE_CPU]; +#ifdef CE_TASKLET_DEBUG_ENABLE + uint32_t record_index[CE_COUNT_MAX]; + uint64_t tasklet_sched_entry_ts[CE_COUNT_MAX]; + uint64_t tasklet_exec_entry_ts[CE_COUNT_MAX]; + uint64_t tasklet_exec_time_record[CE_COUNT_MAX][HIF_REQUESTED_EVENTS]; + uint64_t tasklet_sched_time_record[CE_COUNT_MAX][HIF_REQUESTED_EVENTS]; + uint64_t ce_tasklet_exec_bucket[CE_COUNT_MAX][CE_BUCKET_MAX]; + uint64_t ce_tasklet_sched_bucket[CE_COUNT_MAX][CE_BUCKET_MAX]; + uint64_t ce_tasklet_exec_last_update[CE_COUNT_MAX][CE_BUCKET_MAX]; + uint64_t ce_tasklet_sched_last_update[CE_COUNT_MAX][CE_BUCKET_MAX]; +#endif }; struct HIF_CE_state { diff --git a/hif/src/ce/ce_tasklet.c b/hif/src/ce/ce_tasklet.c index 9a5b61599d..c0bf80e3a8 100644 --- a/hif/src/ce/ce_tasklet.c +++ b/hif/src/ce/ce_tasklet.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2020 The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -35,7 +35,6 @@ #include "hif_debug.h" #include "hif_napi.h" - /** * struct tasklet_work * @@ -139,6 +138,199 @@ static inline void ce_schedule_tasklet(struct ce_tasklet_entry *tasklet_entry) tasklet_schedule(&tasklet_entry->intr_tq); } +#ifdef CE_TASKLET_DEBUG_ENABLE +/** + * hif_record_tasklet_exec_entry_ts() - Record ce tasklet execution + * entry time + * @scn: hif_softc + * @ce_id: ce_id + * + * Return: None + */ +static inline void +hif_record_tasklet_exec_entry_ts(struct hif_softc *scn, uint8_t ce_id) +{ + struct HIF_CE_state *hif_ce_state = HIF_GET_CE_STATE(scn); + + hif_ce_state->stats.tasklet_exec_entry_ts[ce_id] = + qdf_get_log_timestamp_usecs(); +} + +/** + * hif_record_tasklet_sched_entry_ts() - Record ce tasklet scheduled + * entry time + * @scn: hif_softc + * @ce_id: ce_id + * + * Return: None + */ +static inline void +hif_record_tasklet_sched_entry_ts(struct hif_softc *scn, uint8_t ce_id) +{ + struct HIF_CE_state *hif_ce_state = HIF_GET_CE_STATE(scn); + + hif_ce_state->stats.tasklet_sched_entry_ts[ce_id] = + qdf_get_log_timestamp_usecs(); +} + +/** + * hif_ce_latency_stats() - Display ce latency information + * @hif_ctx: hif_softc struct + * + * Return: None + */ +static void +hif_ce_latency_stats(struct hif_softc *hif_ctx) +{ + uint8_t i, j; + uint32_t index, start_index; + static const char * const buck_str[] = {"0 - 0.5", "0.5 - 1", "1 - 2", + "2 - 5", "5 - 10", " > 10"}; + struct HIF_CE_state *hif_ce_state = HIF_GET_CE_STATE(hif_ctx); + struct ce_stats *stats = &hif_ce_state->stats; + + for (i = 0; i < CE_COUNT_MAX; i++) { + qdf_nofl_info("\n\t\tCE Ring %d Tasklet Execution Bucket", i); + for (j = 0; j < CE_BUCKET_MAX; j++) { + qdf_nofl_info("\t Bucket %sms :%llu\t last update:%llu", + buck_str[j], + stats->ce_tasklet_exec_bucket[i][j], + stats->ce_tasklet_exec_last_update[i][j]); + } + + qdf_nofl_info("\n\t\tCE Ring %d Tasklet Scheduled Bucket", i); + for (j = 0; j < CE_BUCKET_MAX; j++) { + qdf_nofl_info("\t Bucket %sms :%llu\t last update :%lld", + buck_str[j], + stats->ce_tasklet_sched_bucket[i][j], + stats-> + ce_tasklet_sched_last_update[i][j]); + } + + qdf_nofl_info("\n\t\t CE RING %d Last %d time records", + i, HIF_REQUESTED_EVENTS); + index = stats->record_index[i]; + start_index = stats->record_index[i]; + + for (j = 0; j < HIF_REQUESTED_EVENTS; j++) { + qdf_nofl_info("\t Execuiton time: %luus Total Scheduled time: %luus", + stats->tasklet_exec_time_record[i][index], + stats-> + tasklet_sched_time_record[i][index]); + index = (index - 1) % HIF_REQUESTED_EVENTS; + if (index == start_index) + break; + } + } +} + +/** + * ce_tasklet_update_bucket() - update ce execution and scehduled time latency + * in corresponding time buckets + * @stats: struct ce_stats + * @ce_id: ce_id_type + * @entry_us: timestamp when tasklet is started to execute + * @exit_us: timestamp when tasklet is completed execution + * + * Return: N/A + */ +static void ce_tasklet_update_bucket(struct HIF_CE_state *hif_ce_state, + uint8_t ce_id) +{ + uint32_t index; + uint64_t exec_time, exec_ms; + uint64_t sched_time, sched_ms; + uint64_t curr_time = qdf_get_log_timestamp_usecs(); + struct ce_stats *stats = &hif_ce_state->stats; + + exec_time = curr_time - (stats->tasklet_exec_entry_ts[ce_id]); + sched_time = (stats->tasklet_exec_entry_ts[ce_id]) - + (stats->tasklet_sched_entry_ts[ce_id]); + + index = stats->record_index[ce_id]; + index = (index + 1) % HIF_REQUESTED_EVENTS; + + stats->tasklet_exec_time_record[ce_id][index] = exec_time; + stats->tasklet_sched_time_record[ce_id][index] = sched_time; + stats->record_index[ce_id] = index; + + exec_ms = (exec_time) / (1000); + sched_ms = (sched_time) / (1000); + + if (exec_ms > 10) { + stats->ce_tasklet_exec_bucket[ce_id][CE_BUCKET_BEYOND]++; + stats->ce_tasklet_exec_last_update[ce_id][CE_BUCKET_BEYOND] + = curr_time; + } else if (exec_ms > 5) { + stats->ce_tasklet_exec_bucket[ce_id][CE_BUCKET_10_MS]++; + stats->ce_tasklet_exec_last_update[ce_id][CE_BUCKET_10_MS] + = curr_time; + } else if (exec_ms > 2) { + stats->ce_tasklet_exec_bucket[ce_id][CE_BUCKET_5_MS]++; + stats->ce_tasklet_exec_last_update[ce_id][CE_BUCKET_5_MS] + = curr_time; + } else if (exec_ms > 1) { + stats->ce_tasklet_exec_bucket[ce_id][CE_BUCKET_2_MS]++; + stats->ce_tasklet_exec_last_update[ce_id][CE_BUCKET_2_MS] + = curr_time; + } else if (exec_time > 500) { + stats->ce_tasklet_exec_bucket[ce_id][CE_BUCKET_1_MS]++; + stats->ce_tasklet_exec_last_update[ce_id][CE_BUCKET_1_MS] + = curr_time; + } else { + stats->ce_tasklet_exec_bucket[ce_id][CE_BUCKET_500_US]++; + stats->ce_tasklet_exec_last_update[ce_id][CE_BUCKET_500_US] + = curr_time; + } + + if (sched_ms > 10) { + stats->ce_tasklet_sched_bucket[ce_id][CE_BUCKET_BEYOND]++; + stats->ce_tasklet_sched_last_update[ce_id][CE_BUCKET_BEYOND] + = curr_time; + } else if (sched_ms > 5) { + stats->ce_tasklet_sched_bucket[ce_id][CE_BUCKET_10_MS]++; + stats->ce_tasklet_sched_last_update[ce_id][CE_BUCKET_10_MS] + = curr_time; + } else if (sched_ms > 2) { + stats->ce_tasklet_sched_bucket[ce_id][CE_BUCKET_5_MS]++; + stats->ce_tasklet_sched_last_update[ce_id][CE_BUCKET_5_MS] + = curr_time; + } else if (sched_ms > 1) { + stats->ce_tasklet_sched_bucket[ce_id][CE_BUCKET_2_MS]++; + stats->ce_tasklet_sched_last_update[ce_id][CE_BUCKET_2_MS] + = curr_time; + } else if (sched_time > 500) { + stats->ce_tasklet_sched_bucket[ce_id][CE_BUCKET_1_MS]++; + stats->ce_tasklet_sched_last_update[ce_id][CE_BUCKET_1_MS] + = curr_time; + } else { + stats->ce_tasklet_sched_bucket[ce_id][CE_BUCKET_500_US]++; + stats->ce_tasklet_sched_last_update[ce_id][CE_BUCKET_500_US] + = curr_time; + } +} +#else +static inline void +hif_record_tasklet_exec_entry_ts(struct hif_softc *scn, uint8_t ce_id) +{ +} + +static void ce_tasklet_update_bucket(struct HIF_CE_state *hif_ce_state, + uint8_t ce_id) +{ +} + +static inline void +hif_record_tasklet_sched_entry_ts(struct hif_softc *scn, uint8_t ce_id) +{ +} + +static void +hif_ce_latency_stats(struct hif_softc *hif_ctx) +{ +} +#endif /*CE_TASKLET_DEBUG_ENABLE*/ + /** * ce_tasklet() - ce_tasklet * @data: data @@ -153,8 +345,9 @@ static void ce_tasklet(unsigned long data) struct hif_softc *scn = HIF_GET_SOFTC(hif_ce_state); struct CE_state *CE_state = scn->ce_id_to_state[tasklet_entry->ce_id]; + hif_record_tasklet_exec_entry_ts(scn, tasklet_entry->ce_id); hif_record_ce_desc_event(scn, tasklet_entry->ce_id, - HIF_CE_TASKLET_ENTRY, NULL, NULL, -1, 0); + HIF_CE_TASKLET_ENTRY, NULL, NULL, -1, 0); if (qdf_atomic_read(&scn->link_suspended)) { HIF_ERROR("%s: ce %d tasklet fired after link suspend.", @@ -182,7 +375,7 @@ static void ce_tasklet(unsigned long data) hif_record_ce_desc_event(scn, tasklet_entry->ce_id, HIF_CE_TASKLET_EXIT, NULL, NULL, -1, 0); - + ce_tasklet_update_bucket(hif_ce_state, tasklet_entry->ce_id); qdf_atomic_dec(&scn->active_tasklet_cnt); } @@ -339,12 +532,13 @@ hif_ce_increment_interrupt_count(struct HIF_CE_state *hif_ce_state, int ce_id) * * Return: none */ -void hif_display_ce_stats(struct HIF_CE_state *hif_ce_state) +void hif_display_ce_stats(struct hif_softc *hif_ctx) { #define STR_SIZE 128 uint8_t i, j, pos; char str_buffer[STR_SIZE]; int size, ret; + struct HIF_CE_state *hif_ce_state = HIF_GET_CE_STATE(hif_ctx); qdf_debug("CE interrupt statistics:"); for (i = 0; i < CE_COUNT_MAX; i++) { @@ -352,7 +546,7 @@ void hif_display_ce_stats(struct HIF_CE_state *hif_ce_state) pos = 0; for (j = 0; j < QDF_MAX_AVAILABLE_CPU; j++) { ret = snprintf(str_buffer + pos, size, "[%d]:%d ", - j, hif_ce_state->stats.ce_per_cpu[i][j]); + j, hif_ce_state->stats.ce_per_cpu[i][j]); if (ret <= 0 || ret >= size) break; size -= ret; @@ -360,6 +554,8 @@ void hif_display_ce_stats(struct HIF_CE_state *hif_ce_state) } qdf_debug("CE id[%2d] - %s", i, str_buffer); } + + hif_ce_latency_stats(hif_ctx); #undef STR_SIZE } @@ -393,6 +589,7 @@ static inline bool hif_tasklet_schedule(struct hif_opaque_softc *hif_ctx, } tasklet_schedule(&tasklet_entry->intr_tq); + hif_record_tasklet_sched_entry_ts(scn, tasklet_entry->ce_id); return true; } diff --git a/hif/src/ce/ce_tasklet.h b/hif/src/ce/ce_tasklet.h index 05da168727..d5ab58cefb 100644 --- a/hif/src/ce/ce_tasklet.h +++ b/hif/src/ce/ce_tasklet.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2016,2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2016,2018,2020 The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -28,6 +28,6 @@ QDF_STATUS ce_register_irq(struct HIF_CE_state *hif_ce_state, uint32_t mask); QDF_STATUS ce_unregister_irq(struct HIF_CE_state *hif_ce_state, uint32_t mask); irqreturn_t ce_dispatch_interrupt(int irq, struct ce_tasklet_entry *tasklet_entry); -void hif_display_ce_stats(struct HIF_CE_state *hif_ce_state); +void hif_display_ce_stats(struct hif_softc *hif_ctx); void hif_clear_ce_stats(struct HIF_CE_state *hif_ce_state); #endif /* __CE_TASKLET_H__ */ diff --git a/hif/src/dispatcher/ahb_api.h b/hif/src/dispatcher/ahb_api.h index 103114b87e..1657cbc337 100644 --- a/hif/src/dispatcher/ahb_api.h +++ b/hif/src/dispatcher/ahb_api.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2018,2020 The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -50,4 +50,6 @@ int hif_ahb_configure_irq(struct hif_pci_softc *sc); int hif_ahb_configure_grp_irq(struct hif_softc *scn, struct hif_exec_context *hif_ext_grp); bool hif_ahb_needs_bmi(struct hif_softc *scn); +void hif_ahb_display_stats(struct hif_softc *scn); +void hif_ahb_clear_stats(struct hif_softc *scn); #endif diff --git a/hif/src/dispatcher/multibus_ahb.c b/hif/src/dispatcher/multibus_ahb.c index 04bf46d7f9..fe46d5bd73 100644 --- a/hif/src/dispatcher/multibus_ahb.c +++ b/hif/src/dispatcher/multibus_ahb.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2018,2020 The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -69,7 +69,8 @@ QDF_STATUS hif_initialize_ahb_ops(struct hif_bus_ops *bus_ops) bus_ops->hif_grp_irq_configure = &hif_ahb_configure_grp_irq; bus_ops->hif_addr_in_boundary = &hif_dummy_addr_in_boundary; bus_ops->hif_needs_bmi = &hif_ahb_needs_bmi; - + bus_ops->hif_display_stats = &hif_ahb_display_stats; + bus_ops->hif_clear_stats = &hif_ahb_clear_stats; return QDF_STATUS_SUCCESS; } diff --git a/hif/src/pcie/if_pci.c b/hif/src/pcie/if_pci.c index d095cfa39c..eb36e19b71 100644 --- a/hif/src/pcie/if_pci.c +++ b/hif/src/pcie/if_pci.c @@ -1395,7 +1395,7 @@ void hif_pci_display_stats(struct hif_softc *hif_ctx) HIF_ERROR("%s, hif_ctx null", __func__); return; } - hif_display_ce_stats(&pci_ctx->ce_sc); + hif_display_ce_stats(hif_ctx); hif_print_pci_stats(pci_ctx); } diff --git a/hif/src/snoc/if_ahb.c b/hif/src/snoc/if_ahb.c index 01682447bb..568f61eab5 100644 --- a/hif/src/snoc/if_ahb.c +++ b/hif/src/snoc/if_ahb.c @@ -835,3 +835,23 @@ bool hif_ahb_needs_bmi(struct hif_softc *scn) { return !ce_srng_based(scn); } + +void hif_ahb_display_stats(struct hif_softc *scn) +{ + if (!scn) { + HIF_ERROR("%s, hif_scn null", __func__); + return; + } + hif_display_ce_stats(scn); +} + +void hif_ahb_clear_stats(struct hif_softc *scn) +{ + struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn); + + if (!hif_state) { + HIF_ERROR("%s, hif_state null", __func__); + return; + } + hif_clear_ce_stats(hif_state); +} diff --git a/hif/src/snoc/if_snoc.c b/hif/src/snoc/if_snoc.c index 119db8af3b..51350887fe 100644 --- a/hif/src/snoc/if_snoc.c +++ b/hif/src/snoc/if_snoc.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2020 The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -78,13 +78,11 @@ int hif_snoc_dump_registers(struct hif_softc *hif_ctx) void hif_snoc_display_stats(struct hif_softc *hif_ctx) { - struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(hif_ctx); - - if (!hif_state) { + if (!hif_ctx) { HIF_ERROR("%s, hif_ctx null", __func__); return; } - hif_display_ce_stats(hif_state); + hif_display_ce_stats(hif_ctx); } void hif_snoc_clear_stats(struct hif_softc *hif_ctx) diff --git a/htc/htc.c b/htc/htc.c index 2a40fea64f..06c1ea4ff3 100644 --- a/htc/htc.c +++ b/htc/htc.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2020 The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -134,6 +134,16 @@ void htc_dump(HTC_HANDLE HTCHandle, uint8_t CmdId, bool start) hif_dump(target->hif_dev, CmdId, start); } +void htc_ce_tasklet_debug_dump(HTC_HANDLE htc_handle) +{ + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(htc_handle); + + if (!target->hif_dev) + return; + + hif_display_stats(target->hif_dev); +} + /* cleanup the HTC instance */ static void htc_cleanup(HTC_TARGET *target) { diff --git a/htc/htc_api.h b/htc/htc_api.h index 9c06ac4d33..8adabc65a7 100644 --- a/htc/htc_api.h +++ b/htc/htc_api.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2014, 2016-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2014, 2016-2020 The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -481,6 +481,15 @@ QDF_STATUS htc_connect_service(HTC_HANDLE HTCHandle, */ void htc_dump(HTC_HANDLE HTCHandle, uint8_t CmdId, bool start); +/** + * htc_ce_taklet_debug_dump - Dump ce tasklet rings debug data + * @HTCHandle - HTC handle + * + * Debug logs will be printed. + * Return: None + */ +void htc_ce_tasklet_debug_dump(HTC_HANDLE htc_handle); + /** * htc_send_pkt - Send an HTC packet * @HTCHandle - HTC handle diff --git a/wmi/src/wmi_unified.c b/wmi/src/wmi_unified.c index f509dfa64e..f60319ee88 100644 --- a/wmi/src/wmi_unified.c +++ b/wmi/src/wmi_unified.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2020 The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -1808,6 +1808,7 @@ QDF_STATUS wmi_unified_cmd_send_fl(wmi_unified_t wmi_handle, wmi_buf_t buf, wmi_nofl_err("%s:%d, MAX %d WMI Pending cmds reached", func, line, wmi_handle->wmi_max_cmds); wmi_unified_debug_dump(wmi_handle); + htc_ce_tasklet_debug_dump(wmi_handle->htc_handle); qdf_trigger_self_recovery(QDF_WMI_EXCEED_MAX_PENDING_CMDS); return QDF_STATUS_E_BUSY; }