diff --git a/htc/htc_api.h b/htc/htc_api.h index 0fcc2c9b21..2b8f3b1cad 100644 --- a/htc/htc_api.h +++ b/htc/htc_api.h @@ -802,4 +802,10 @@ void htc_set_wmi_endpoint_count(HTC_HANDLE htc_handle, uint8_t wmi_ep_count); * return: WMI enpoint count */ uint8_t htc_get_wmi_endpoint_count(HTC_HANDLE htc_handle); + +#ifdef WMI_INTERFACE_EVENT_LOGGING +void htc_print_credit_history(HTC_HANDLE htc, uint32_t count, + qdf_abstract_print * print, void *print_priv); +#endif + #endif /* _HTC_API_H_ */ diff --git a/htc/htc_internal.h b/htc/htc_internal.h index c37008cc74..1d5bfc0a68 100644 --- a/htc/htc_internal.h +++ b/htc/htc_internal.h @@ -92,6 +92,25 @@ typedef enum { HTC_INITIAL_WAKE_UP, } htc_credit_exchange_type; +static inline const char* +htc_credit_exchange_type_str(htc_credit_exchange_type type) +{ + switch (type) { + case HTC_REQUEST_CREDIT: + return "HTC_REQUEST_CREDIT"; + case HTC_PROCESS_CREDIT_REPORT: + return "HTC_PROCESS_CREDIT_REPORT"; + case HTC_SUSPEND_ACK: + return "HTC_SUSPEND_ACK"; + case HTC_SUSPEND_NACK: + return "HTC_SUSPEND_NACK"; + case HTC_INITIAL_WAKE_UP: + return "HTC_INITIAL_WAKE_UP"; + default: + return "Unknown htc_credit_exchange_type"; + } +} + typedef struct { htc_credit_exchange_type type; uint64_t time; diff --git a/htc/htc_send.c b/htc/htc_send.c index a65e0ce0ac..79f6f47211 100644 --- a/htc/htc_send.c +++ b/htc/htc_send.c @@ -55,6 +55,7 @@ static unsigned ep_debug_mask = /* HTC Control Path Credit History */ uint32_t g_htc_credit_history_idx = 0; +uint32_t g_htc_credit_history_length; HTC_CREDIT_HISTORY htc_credit_history_buffer[HTC_CREDIT_HISTORY_MAX]; /** @@ -85,9 +86,53 @@ void htc_credit_record(htc_credit_exchange_type type, uint32_t tx_credit, tx_credit; htc_credit_history_buffer[g_htc_credit_history_idx].htc_tx_queue_depth = htc_tx_queue_depth; + g_htc_credit_history_idx++; + g_htc_credit_history_length++; } +#ifdef WMI_INTERFACE_EVENT_LOGGING +void htc_print_credit_history(HTC_HANDLE htc, uint32_t count, + qdf_abstract_print *print, void *print_priv) +{ + uint32_t idx; + HTC_TARGET *target; + + target = GET_HTC_TARGET_FROM_HANDLE(htc); + LOCK_HTC_CREDIT(target); + + if (count > HTC_CREDIT_HISTORY_MAX) + count = HTC_CREDIT_HISTORY_MAX; + if (count > g_htc_credit_history_length) + count = g_htc_credit_history_length; + + /* subtract count from index, and wrap if necessary */ + idx = HTC_CREDIT_HISTORY_MAX + g_htc_credit_history_idx - count; + idx %= HTC_CREDIT_HISTORY_MAX; + + print(print_priv, + "Time (seconds) Type Credits Queue Depth"); + while (count) { + HTC_CREDIT_HISTORY *hist = &htc_credit_history_buffer[idx]; + long long us = qdf_log_timestamp_to_usecs(hist->time); + + print(print_priv, "% 8lld.%06lld %-25s %-7.d %d", + us / 1000000, + us % 1000000, + htc_credit_exchange_type_str(hist->type), + hist->tx_credit, + hist->htc_tx_queue_depth); + + --count; + ++idx; + if (idx >= HTC_CREDIT_HISTORY_MAX) + idx = 0; + } + + UNLOCK_HTC_CREDIT(target); +} +#endif /* WMI_INTERFACE_EVENT_LOGGING */ + void htc_dump_counter_info(HTC_HANDLE HTCHandle) { HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); diff --git a/qdf/inc/qdf_trace.h b/qdf/inc/qdf_trace.h index 44d0bff687..884f4d3cb3 100644 --- a/qdf/inc/qdf_trace.h +++ b/qdf/inc/qdf_trace.h @@ -53,6 +53,8 @@ #define QDF_DEFAULT_TRACE_LEVEL (1 << QDF_TRACE_LEVEL_INFO) #endif +typedef int (qdf_abstract_print)(void *priv, const char *fmt, ...); + /* * Log levels */ diff --git a/wmi/inc/wmi_unified_api.h b/wmi/inc/wmi_unified_api.h index e0800051f3..a57e6e6ed7 100644 --- a/wmi/inc/wmi_unified_api.h +++ b/wmi/inc/wmi_unified_api.h @@ -1435,4 +1435,28 @@ QDF_STATUS wmi_unified_dfs_phyerr_offload_en_cmd(void *wmi_hdl, */ QDF_STATUS wmi_unified_dfs_phyerr_offload_dis_cmd(void *wmi_hdl, uint32_t pdev_id); + +#ifdef WMI_INTERFACE_EVENT_LOGGING +void wmi_print_cmd_log(wmi_unified_t wmi, uint32_t count, + qdf_abstract_print *print, void *print_priv); + +void wmi_print_cmd_tx_cmp_log(wmi_unified_t wmi, uint32_t count, + qdf_abstract_print *print, void *print_priv); + +void wmi_print_mgmt_cmd_log(wmi_unified_t wmi, uint32_t count, + qdf_abstract_print *print, void *print_priv); + +void wmi_print_mgmt_cmd_tx_cmp_log(wmi_unified_t wmi, uint32_t count, + qdf_abstract_print *print, void *print_priv); + +void wmi_print_event_log(wmi_unified_t wmi, uint32_t count, + qdf_abstract_print *print, void *print_priv); + +void wmi_print_rx_event_log(wmi_unified_t wmi, uint32_t count, + qdf_abstract_print *print, void *print_priv); + +void wmi_print_mgmt_event_log(wmi_unified_t wmi, uint32_t count, + qdf_abstract_print *print, void *print_priv); +#endif /* WMI_INTERFACE_EVENT_LOGGING */ + #endif /* _WMI_UNIFIED_API_H_ */ diff --git a/wmi/inc/wmi_unified_priv.h b/wmi/inc/wmi_unified_priv.h index 5aaa06b309..c58664d7c4 100644 --- a/wmi/inc/wmi_unified_priv.h +++ b/wmi/inc/wmi_unified_priv.h @@ -113,12 +113,14 @@ struct wmi_command_header { * @ buf_tail_idx - Tail index of buffer * @ p_buf_tail_idx - refernce to buffer tail index. It is added to accommodate * unified design since MCL uses global variable for buffer tail index + * @ size - the size of the buffer in number of entries */ struct wmi_log_buf_t { void *buf; uint32_t length; uint32_t buf_tail_idx; uint32_t *p_buf_tail_idx; + uint32_t size; }; /** diff --git a/wmi/src/wmi_unified.c b/wmi/src/wmi_unified.c index f0c8a064e6..48c69b31f6 100644 --- a/wmi/src/wmi_unified.c +++ b/wmi/src/wmi_unified.c @@ -342,30 +342,35 @@ static QDF_STATUS wmi_log_init(struct wmi_unified *wmi_handle) cmd_log_buf->buf_tail_idx = 0; cmd_log_buf->buf = wmi_command_log_buffer; cmd_log_buf->p_buf_tail_idx = &g_wmi_command_buf_idx; + cmd_log_buf->size = WMI_EVENT_DEBUG_MAX_ENTRY; /* WMI commands TX completed */ cmd_tx_cmpl_log_buf->length = 0; cmd_tx_cmpl_log_buf->buf_tail_idx = 0; cmd_tx_cmpl_log_buf->buf = wmi_command_tx_cmp_log_buffer; cmd_tx_cmpl_log_buf->p_buf_tail_idx = &g_wmi_command_tx_cmp_buf_idx; + cmd_tx_cmpl_log_buf->size = WMI_EVENT_DEBUG_MAX_ENTRY; /* WMI events when processed */ event_log_buf->length = 0; event_log_buf->buf_tail_idx = 0; event_log_buf->buf = wmi_event_log_buffer; event_log_buf->p_buf_tail_idx = &g_wmi_event_buf_idx; + event_log_buf->size = WMI_EVENT_DEBUG_MAX_ENTRY; /* WMI events when queued */ rx_event_log_buf->length = 0; rx_event_log_buf->buf_tail_idx = 0; rx_event_log_buf->buf = wmi_rx_event_log_buffer; rx_event_log_buf->p_buf_tail_idx = &g_wmi_rx_event_buf_idx; + rx_event_log_buf->size = WMI_EVENT_DEBUG_MAX_ENTRY; /* WMI Management commands */ mgmt_cmd_log_buf->length = 0; mgmt_cmd_log_buf->buf_tail_idx = 0; mgmt_cmd_log_buf->buf = wmi_mgmt_command_log_buffer; mgmt_cmd_log_buf->p_buf_tail_idx = &g_wmi_mgmt_command_buf_idx; + mgmt_cmd_log_buf->size = WMI_MGMT_EVENT_DEBUG_MAX_ENTRY; /* WMI Management commands Tx completed*/ mgmt_cmd_tx_cmp_log_buf->length = 0; @@ -373,12 +378,14 @@ static QDF_STATUS wmi_log_init(struct wmi_unified *wmi_handle) mgmt_cmd_tx_cmp_log_buf->buf = wmi_mgmt_command_tx_cmp_log_buffer; mgmt_cmd_tx_cmp_log_buf->p_buf_tail_idx = &g_wmi_mgmt_command_tx_cmp_buf_idx; + mgmt_cmd_tx_cmp_log_buf->size = WMI_MGMT_EVENT_DEBUG_MAX_ENTRY; /* WMI Management events when processed*/ mgmt_event_log_buf->length = 0; mgmt_event_log_buf->buf_tail_idx = 0; mgmt_event_log_buf->buf = wmi_mgmt_event_log_buffer; mgmt_event_log_buf->p_buf_tail_idx = &g_wmi_mgmt_event_buf_idx; + mgmt_event_log_buf->size = WMI_MGMT_EVENT_DEBUG_MAX_ENTRY; qdf_spinlock_create(&wmi_handle->log_info.wmi_record_lock); wmi_handle->log_info.wmi_logging_enable = 1; @@ -412,6 +419,7 @@ static QDF_STATUS wmi_log_init(struct wmi_unified *wmi_handle) cmd_log_buf->buf_tail_idx = 0; cmd_log_buf->buf = (struct wmi_command_debug *) qdf_mem_malloc( wmi_log_max_entry * sizeof(struct wmi_command_debug)); + cmd_log_buf->size = wmi_log_max_entry; if (!cmd_log_buf->buf) { qdf_print("no memory for WMI command log buffer..\n"); @@ -424,6 +432,7 @@ static QDF_STATUS wmi_log_init(struct wmi_unified *wmi_handle) cmd_tx_cmpl_log_buf->buf_tail_idx = 0; cmd_tx_cmpl_log_buf->buf = (struct wmi_command_debug *) qdf_mem_malloc( wmi_log_max_entry * sizeof(struct wmi_command_debug)); + cmd_tx_cmpl_log_buf->size = wmi_log_max_entry; if (!cmd_tx_cmpl_log_buf->buf) { qdf_print("no memory for WMI Command Tx Complete log buffer..\n"); @@ -437,6 +446,7 @@ static QDF_STATUS wmi_log_init(struct wmi_unified *wmi_handle) event_log_buf->buf_tail_idx = 0; event_log_buf->buf = (struct wmi_event_debug *) qdf_mem_malloc( wmi_log_max_entry * sizeof(struct wmi_event_debug)); + event_log_buf->size = wmi_log_max_entry; if (!event_log_buf->buf) { qdf_print("no memory for WMI Event log buffer..\n"); @@ -449,6 +459,7 @@ static QDF_STATUS wmi_log_init(struct wmi_unified *wmi_handle) rx_event_log_buf->buf_tail_idx = 0; rx_event_log_buf->buf = (struct wmi_event_debug *) qdf_mem_malloc( wmi_log_max_entry * sizeof(struct wmi_event_debug)); + rx_event_log_buf->size = wmi_log_max_entry; if (!rx_event_log_buf->buf) { qdf_print("no memory for WMI Event Rx log buffer..\n"); @@ -460,8 +471,8 @@ static QDF_STATUS wmi_log_init(struct wmi_unified *wmi_handle) mgmt_cmd_log_buf->length = 0; mgmt_cmd_log_buf->buf_tail_idx = 0; mgmt_cmd_log_buf->buf = (struct wmi_command_debug *) qdf_mem_malloc( - wmi_mgmt_log_max_entry * - sizeof(struct wmi_command_debug)); + wmi_mgmt_log_max_entry * sizeof(struct wmi_command_debug)); + mgmt_cmd_log_buf->size = wmi_mgmt_log_max_entry; if (!mgmt_cmd_log_buf->buf) { qdf_print("no memory for WMI Management Command log buffer..\n"); @@ -476,6 +487,7 @@ static QDF_STATUS wmi_log_init(struct wmi_unified *wmi_handle) qdf_mem_malloc( wmi_mgmt_log_max_entry * sizeof(struct wmi_command_debug)); + mgmt_cmd_tx_cmp_log_buf->size = wmi_mgmt_log_max_entry; if (!mgmt_cmd_tx_cmp_log_buf->buf) { qdf_print("no memory for WMI Management Command Tx complete log buffer..\n"); @@ -491,6 +503,7 @@ static QDF_STATUS wmi_log_init(struct wmi_unified *wmi_handle) mgmt_event_log_buf->buf = (struct wmi_event_debug *) qdf_mem_malloc( wmi_mgmt_log_max_entry * sizeof(struct wmi_event_debug)); + mgmt_event_log_buf->size = wmi_mgmt_log_max_entry; if (!mgmt_event_log_buf->buf) { qdf_print("no memory for WMI Management Event log buffer..\n"); @@ -544,6 +557,175 @@ static inline void wmi_log_buffer_free(struct wmi_unified *wmi_handle) } #endif +/** + * wmi_print_cmd_log_buffer() - an output agnostic wmi command log printer + * @log_buffer: the command log buffer metadata of the buffer to print + * @count: the maximum number of entries to print + * @print: an abstract print method, e.g. a qdf_print() or seq_printf() wrapper + * @print_priv: any data required by the print method, e.g. a file handle + * + * Return: None + */ +static void +wmi_print_cmd_log_buffer(struct wmi_log_buf_t *log_buffer, uint32_t count, + qdf_abstract_print *print, void *print_priv) +{ + static const int data_len = + WMI_EVENT_DEBUG_ENTRY_MAX_LENGTH / sizeof(uint32_t); + char str[128]; + uint32_t idx; + + if (count > log_buffer->size) + count = log_buffer->size; + if (count > log_buffer->length) + count = log_buffer->length; + + /* subtract count from index, and wrap if necessary */ + idx = log_buffer->size + *log_buffer->p_buf_tail_idx - count; + idx %= log_buffer->size; + + print(print_priv, "Time (seconds) Cmd Id Payload"); + while (count) { + struct wmi_command_debug *cmd_log = (struct wmi_command_debug *) + &((struct wmi_command_debug *)log_buffer->buf)[idx]; + long long us = qdf_log_timestamp_to_usecs(cmd_log->time); + int len = 0; + int i; + + len += scnprintf(str + len, sizeof(str) - len, + "% 8lld.%06lld %6u (0x%06x) ", + us / 1000000, us % 1000000, + cmd_log->command, cmd_log->command); + for (i = 0; i < data_len; ++i) { + len += scnprintf(str + len, sizeof(str) - len, + "0x%08x ", cmd_log->data[i]); + } + + print(print_priv, str); + + --count; + ++idx; + if (idx >= log_buffer->size) + idx = 0; + } +} + +/** + * wmi_print_event_log_buffer() - an output agnostic wmi event log printer + * @log_buffer: the event log buffer metadata of the buffer to print + * @count: the maximum number of entries to print + * @print: an abstract print method, e.g. a qdf_print() or seq_printf() wrapper + * @print_priv: any data required by the print method, e.g. a file handle + * + * Return: None + */ +static void +wmi_print_event_log_buffer(struct wmi_log_buf_t *log_buffer, uint32_t count, + qdf_abstract_print *print, void *print_priv) +{ + static const int data_len = + WMI_EVENT_DEBUG_ENTRY_MAX_LENGTH / sizeof(uint32_t); + char str[128]; + uint32_t idx; + + if (count > log_buffer->size) + count = log_buffer->size; + if (count > log_buffer->length) + count = log_buffer->length; + + /* subtract count from index, and wrap if necessary */ + idx = log_buffer->size + *log_buffer->p_buf_tail_idx - count; + idx %= log_buffer->size; + + print(print_priv, "Time (seconds) Event Id Payload"); + while (count) { + struct wmi_event_debug *event_log = (struct wmi_event_debug *) + &((struct wmi_event_debug *)log_buffer->buf)[idx]; + long long us = qdf_log_timestamp_to_usecs(event_log->time); + int len = 0; + int i; + + len += scnprintf(str + len, sizeof(str) - len, + "% 8lld.%06lld %6u (0x%06x) ", + us / 1000000, us % 1000000, + event_log->event, event_log->event); + for (i = 0; i < data_len; ++i) { + len += scnprintf(str + len, sizeof(str) - len, + "0x%08x ", event_log->data[i]); + } + + print(print_priv, str); + + --count; + ++idx; + if (idx >= log_buffer->size) + idx = 0; + } +} + +inline void +wmi_print_cmd_log(wmi_unified_t wmi, uint32_t count, + qdf_abstract_print *print, void *print_priv) +{ + wmi_print_cmd_log_buffer( + &wmi->log_info.wmi_command_log_buf_info, + count, print, print_priv); +} + +inline void +wmi_print_cmd_tx_cmp_log(wmi_unified_t wmi, uint32_t count, + qdf_abstract_print *print, void *print_priv) +{ + wmi_print_cmd_log_buffer( + &wmi->log_info.wmi_command_tx_cmp_log_buf_info, + count, print, print_priv); +} + +inline void +wmi_print_mgmt_cmd_log(wmi_unified_t wmi, uint32_t count, + qdf_abstract_print *print, void *print_priv) +{ + wmi_print_cmd_log_buffer( + &wmi->log_info.wmi_mgmt_command_log_buf_info, + count, print, print_priv); +} + +inline void +wmi_print_mgmt_cmd_tx_cmp_log(wmi_unified_t wmi, uint32_t count, + qdf_abstract_print *print, void *print_priv) +{ + wmi_print_cmd_log_buffer( + &wmi->log_info.wmi_mgmt_command_tx_cmp_log_buf_info, + count, print, print_priv); +} + +inline void +wmi_print_event_log(wmi_unified_t wmi, uint32_t count, + qdf_abstract_print *print, void *print_priv) +{ + wmi_print_event_log_buffer( + &wmi->log_info.wmi_event_log_buf_info, + count, print, print_priv); +} + +inline void +wmi_print_rx_event_log(wmi_unified_t wmi, uint32_t count, + qdf_abstract_print *print, void *print_priv) +{ + wmi_print_event_log_buffer( + &wmi->log_info.wmi_rx_event_log_buf_info, + count, print, print_priv); +} + +inline void +wmi_print_mgmt_event_log(wmi_unified_t wmi, uint32_t count, + qdf_abstract_print *print, void *print_priv) +{ + wmi_print_event_log_buffer( + &wmi->log_info.wmi_mgmt_event_log_buf_info, + count, print, print_priv); +} + #ifdef CONFIG_MCL const int8_t * const debugfs_dir[MAX_WMI_INSTANCES] = {"WMI0"}; #else