From b666fe52b7f836932613fd034217c310830ffaba Mon Sep 17 00:00:00 2001 From: nwzhao Date: Wed, 11 Dec 2019 16:30:50 -0800 Subject: [PATCH] qcacmn: DebugFS Improvements for WMI logs 1)Configurable number of bytes to log 2)Add support to record only specific WMI command/events Separate buffers are added to save user specified WMI commands and events 1.To record specific wmi cmd, e.g. WMI_VDEV_START_REQUEST_CMDID echo 0x5003 > /sys/kernel/debug/WMI_SOC0_PDEV0/filtered_wmi_cmds 2.To record specific wmi evt, e.g. WMI_MGMT_RX_EVENTID echo 0x7001 > /sys/kernel/debug/WMI_SOC0_PDEV0/filtered_wmi_evts Results of recorded specific WMI command/events: 1. WMI commands, e.g.: cat /sys/kernel/debug/WMI_SOC0_PDEV0/wmi_filtered_command_log 2. WMI events, e.g.: cat /sys/kernel/debug/WMI_SOC0_PDEV0/wmi_filtered_event_log CRs-Fixed: 2597854 Change-Id: I1e90a13ac0717f1f37ba998fb1d06a990d3f4fa2 --- wmi/inc/wmi_filtered_logging.h | 199 +++++++++++++ wmi/inc/wmi_unified_priv.h | 46 +++ wmi/src/wmi_filtered_logging.c | 513 +++++++++++++++++++++++++++++++++ wmi/src/wmi_unified.c | 38 ++- 4 files changed, 789 insertions(+), 7 deletions(-) create mode 100644 wmi/inc/wmi_filtered_logging.h create mode 100644 wmi/src/wmi_filtered_logging.c diff --git a/wmi/inc/wmi_filtered_logging.h b/wmi/inc/wmi_filtered_logging.h new file mode 100644 index 000000000000..087002757012 --- /dev/null +++ b/wmi/inc/wmi_filtered_logging.h @@ -0,0 +1,199 @@ +/* + * 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 + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef WMI_FILTERED_LOGGING_H +#define WMI_FILTERED_LOGGING_H + +#include +#include "wmi_unified_priv.h" + +#ifdef WMI_INTERFACE_FILTERED_EVENT_LOGGING +/** + * wmi_specific_cmd_record() - Record user specified command + * @wmi_handle: handle to WMI + * @id: cmd id + * @buf: buf containing cmd details + * + * Check if the command id is in target list, + * if found, record it. + * + * Context: the function will not sleep, caller is expected to hold + * proper locking. + * + * Return: none + */ +void wmi_specific_cmd_record(wmi_unified_t wmi_handle, + uint32_t id, uint8_t *buf); + +/** + * wmi_specific_evt_record() - Record user specified event + * @wmi_handle: handle to WMI + * @id: cmd id + * @buf: buf containing event details + * + * Check if the event id is in target list, + * if found, record it. + * + * Context: the function will not sleep, caller is expected to hold + * proper locking. + * + * Return: none + */ +void wmi_specific_evt_record(wmi_unified_t wmi_handle, + uint32_t id, uint8_t *buf); + +/** + * wmi_filtered_logging_init() - initialize filtered logging + * @wmi_handle: handle to WMI + * + * Context: the function will not sleep, no lock needed + * + * Return: none + */ +void wmi_filtered_logging_init(wmi_unified_t wmi_handle); + +/** + * wmi_filtered_logging_free() - free the buffers for filtered logging + * @wmi_handle: handle to WMI + * + * Context: the function will not sleep, no lock needed + * + * Return: none + */ +void wmi_filtered_logging_free(wmi_unified_t wmi_handle); + +/* + * Debugfs read/write functions + */ +/** + * debug_filtered_wmi_cmds_show() - debugfs read function for filtered_wmi_cmds + * @m: seq_file handle + * @v: not used, offset of read + * Return: number of bytes read + */ +int debug_filtered_wmi_cmds_show(qdf_debugfs_file_t m, void *v); + +/** + * debug_filtered_wmi_evts_show() - debugfs read function for filtered_wmi_evts + * @m: seq_file handle + * @v: not used, offset of read + * Return: number of bytes read + */ +int debug_filtered_wmi_evts_show(qdf_debugfs_file_t m, void *v); + +/** + * debug_wmi_filtered_command_log_show() - debugfs read function for + * wmi_filtered_command_log + * @m: seq_file handle + * @v: not used, offset of read + * Return: number of bytes read + */ +int debug_wmi_filtered_command_log_show(qdf_debugfs_file_t m, void *v); + +/** + * debug_wmi_filtered_event_log_show() - debugfs read function for + * wmi_filtered_event_log + * @m: seq_file handle + * @v: not used, offset of read + * Return: number of bytes read + */ +int debug_wmi_filtered_event_log_show(qdf_debugfs_file_t m, void *v); + +/** + * debug_wmi_filtered_wmi_cmds_write() - debugfs write for filtered_wmi_cmds + * + * @file: file handler to access wmi_handle + * @buf: received data buffer + * @count: length of received buffer + * @ppos: Not used + * + * Return: count + */ +ssize_t debug_filtered_wmi_cmds_write(struct file *file, + const char __user *buf, + size_t count, loff_t *ppos); + +/** + * debug_wmi_filtered_wmi_evts_write() - debugfs write for filtered_wmi_evts + * + * @file: file handler to access wmi_handle + * @buf: received data buffer + * @count: length of received buffer + * @ppos: Not used + * + * Return: count + */ +ssize_t debug_filtered_wmi_evts_write(struct file *file, + const char __user *buf, + size_t count, loff_t *ppos); + +/** + * debug_wmi_filtered_command_log_write() - debugfs write for + * filtered_command_log + * + * @file: file handler to access wmi_handle + * @buf: received data buffer + * @count: length of received buffer + * @ppos: Not used + * + * Return: count + */ +ssize_t debug_wmi_filtered_command_log_write(struct file *file, + const char __user *buf, + size_t count, loff_t *ppos); + +/** + * debug_wmi_filtered_event_log_write() - debugfs write for filtered_event_log + * + * @file: file handler to access wmi_handle + * @buf: received data buffer + * @count: length of received buffer + * @ppos: Not used + * + * Return: count + */ +ssize_t debug_wmi_filtered_event_log_write(struct file *file, + const char __user *buf, + size_t count, loff_t *ppos); + +#else /* WMI_INTERFACE_FILTERED_EVENT_LOGGING */ + +static inline void wmi_specific_cmd_record(wmi_unified_t wmi_handle, + uint32_t id, uint8_t *buf) +{ + /* do nothing */ +} + +static inline void wmi_specific_evt_record(wmi_unified_t wmi_handle, + uint32_t id, uint8_t *buf) +{ + /* do nothing */ +} + +static inline void wmi_filtered_logging_init(wmi_unified_t wmi_handle) +{ + /* do nothing */ +} + +static inline void wmi_filtered_logging_free(wmi_unified_t wmi_handle) +{ + /* do nothing */ +} +#endif /* end of WMI_INTERFACE_FILTERED_EVENT_LOGGING */ + +#endif /*WMI_FILTERED_LOGGING_H*/ diff --git a/wmi/inc/wmi_unified_priv.h b/wmi/inc/wmi_unified_priv.h index f9d6f5f613a5..6ca4bca6c9d2 100644 --- a/wmi/inc/wmi_unified_priv.h +++ b/wmi/inc/wmi_unified_priv.h @@ -116,7 +116,9 @@ struct wmi_ext_dbg_msg { #define WMI_EVENT_DEBUG_MAX_ENTRY (1024) #endif +#ifndef WMI_EVENT_DEBUG_ENTRY_MAX_LENGTH #define WMI_EVENT_DEBUG_ENTRY_MAX_LENGTH (16) +#endif /* wmi_mgmt commands */ #ifndef WMI_MGMT_EVENT_DEBUG_MAX_ENTRY @@ -127,6 +129,16 @@ struct wmi_ext_dbg_msg { #define WMI_DIAG_RX_EVENT_DEBUG_MAX_ENTRY (256) #endif +#ifdef WMI_INTERFACE_FILTERED_EVENT_LOGGING +#ifndef WMI_FILTERED_CMD_EVT_SUPPORTED +#define WMI_FILTERED_CMD_EVT_SUPPORTED (10) +#endif + +#ifndef WMI_FILTERED_CMD_EVT_MAX_NUM_ENTRY +#define WMI_FILTERED_CMD_EVT_MAX_NUM_ENTRY (1024) +#endif +#endif /* WMI_INTERFACE_FILTERED_EVENT_LOGGING */ + #define wmi_alert(params...) QDF_TRACE_FATAL(QDF_MODULE_ID_WMI, ## params) #define wmi_err(params...) QDF_TRACE_ERROR(QDF_MODULE_ID_WMI, ## params) #define wmi_warn(params...) QDF_TRACE_WARN(QDF_MODULE_ID_WMI, ## params) @@ -234,6 +246,14 @@ struct wmi_log_buf_t { * @wmi_id_to_name - Function refernce to API to convert Command id to * string name * @wmi_log_debugfs_dir - refernce to debugfs directory + * @filtered_wmi_cmds - Buffer to save inputs from user on + * which WMI commands to record + * @filtered_wmi_cmds_idx - target cmd index + * @filtered_wmi_evts - Buffer to save inputs from user on + * which WMI event to record + * @filtered_wmi_evts_idx - target evt index + * @wmi_filtered_command_log - buffer to record user specified WMI commands + * @wmi_filtered_event_log - buffer to record user specified WMI events */ struct wmi_debug_log_info { struct wmi_log_buf_t wmi_command_log_buf_info; @@ -250,6 +270,25 @@ struct wmi_debug_log_info { qdf_spinlock_t wmi_record_lock; bool wmi_logging_enable; struct dentry *wmi_log_debugfs_dir; + +#ifdef WMI_INTERFACE_FILTERED_EVENT_LOGGING + uint32_t *filtered_wmi_cmds; + uint32_t filtered_wmi_cmds_idx; + uint32_t *filtered_wmi_evts; + uint32_t filtered_wmi_evts_idx; + struct wmi_log_buf_t *wmi_filtered_command_log; + struct wmi_log_buf_t *wmi_filtered_event_log; +#endif +}; + +/** + * enum WMI_RECORD_TYPE - User specified WMI logging types + * @ WMI_CMD - wmi command id + * @ WMI_EVT - wmi event id + */ +enum WMI_RECORD_TYPE { + WMI_CMD = 1, + WMI_EVT = 2, }; #endif /*WMI_INTERFACE_EVENT_LOGGING */ @@ -2210,7 +2249,14 @@ struct wmi_host_abi_version { uint32_t abi_version_ns_3; }; +/* number of debugfs entries used */ +#ifdef WMI_INTERFACE_FILTERED_EVENT_LOGGING +/* filtered logging added 4 more entries */ +#define NUM_DEBUG_INFOS 13 +#else #define NUM_DEBUG_INFOS 9 +#endif + struct wmi_unified { void *scn_handle; /* handle to device */ osdev_t osdev; /* handle to use OS-independent services */ diff --git a/wmi/src/wmi_filtered_logging.c b/wmi/src/wmi_filtered_logging.c new file mode 100644 index 000000000000..46bfe651bc40 --- /dev/null +++ b/wmi/src/wmi_filtered_logging.c @@ -0,0 +1,513 @@ +/* + * 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 + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "wmi_filtered_logging.h" + +static struct wmi_log_buf_t *wmi_log_buf_allocate(void) +{ + struct wmi_log_buf_t *cmd_log_buf; + int buf_size = WMI_FILTERED_CMD_EVT_MAX_NUM_ENTRY * + sizeof(struct wmi_command_debug); + + cmd_log_buf = qdf_mem_malloc(sizeof(struct wmi_log_buf_t)); + if (!cmd_log_buf) + return NULL; + + cmd_log_buf->buf = qdf_mem_malloc(buf_size); + if (!cmd_log_buf->buf) { + qdf_mem_free(cmd_log_buf); + return NULL; + } + cmd_log_buf->length = 0; + cmd_log_buf->buf_tail_idx = 0; + cmd_log_buf->size = WMI_FILTERED_CMD_EVT_MAX_NUM_ENTRY; + cmd_log_buf->p_buf_tail_idx = &cmd_log_buf->buf_tail_idx; + + return cmd_log_buf; +} + +void wmi_filtered_logging_init(wmi_unified_t wmi_handle) +{ + int buf_size = WMI_FILTERED_CMD_EVT_SUPPORTED * sizeof(int); + + /* alloc buffer to save user inputs, for WMI_CMD */ + wmi_handle->log_info.filtered_wmi_cmds = + qdf_mem_malloc(buf_size); + if (!wmi_handle->log_info.filtered_wmi_cmds) + return; + + wmi_handle->log_info.filtered_wmi_cmds_idx = 0; + + /* alloc buffer to save user interested WMI commands */ + wmi_handle->log_info.wmi_filtered_command_log = wmi_log_buf_allocate(); + if (!wmi_handle->log_info.wmi_filtered_command_log) + goto fail1; + + /* alloc buffer to save user inputs, for WMI_EVT */ + wmi_handle->log_info.filtered_wmi_evts = + qdf_mem_malloc(buf_size); + if (!wmi_handle->log_info.filtered_wmi_evts) + goto fail2; + + wmi_handle->log_info.filtered_wmi_evts_idx = 0; + + /* alloc buffer to save user interested WMI events */ + wmi_handle->log_info.wmi_filtered_event_log = wmi_log_buf_allocate(); + if (!wmi_handle->log_info.wmi_filtered_event_log) + goto fail3; + + return; + +fail3: + qdf_mem_free(wmi_handle->log_info.filtered_wmi_evts); + wmi_handle->log_info.filtered_wmi_evts = NULL; +fail2: + qdf_mem_free(wmi_handle->log_info.wmi_filtered_command_log); + wmi_handle->log_info.wmi_filtered_command_log = NULL; +fail1: + qdf_mem_free(wmi_handle->log_info.filtered_wmi_cmds); + wmi_handle->log_info.filtered_wmi_cmds = NULL; +} + +void wmi_filtered_logging_free(wmi_unified_t wmi_handle) +{ + if (!wmi_handle) + return; + + qdf_mem_free(wmi_handle->log_info.filtered_wmi_cmds); + wmi_handle->log_info.filtered_wmi_cmds = NULL; + qdf_mem_free(wmi_handle->log_info.filtered_wmi_evts); + wmi_handle->log_info.filtered_wmi_evts = NULL; + + if (wmi_handle->log_info.wmi_filtered_command_log) { + qdf_mem_free(wmi_handle->log_info. + wmi_filtered_command_log->buf); + wmi_handle->log_info.wmi_filtered_command_log->buf = NULL; + qdf_mem_free(wmi_handle->log_info.wmi_filtered_command_log); + wmi_handle->log_info.wmi_filtered_command_log = NULL; + } + if (wmi_handle->log_info.wmi_filtered_event_log) { + qdf_mem_free(wmi_handle->log_info. + wmi_filtered_event_log->buf); + wmi_handle->log_info.wmi_filtered_event_log->buf = NULL; + qdf_mem_free(wmi_handle->log_info.wmi_filtered_event_log); + wmi_handle->log_info.wmi_filtered_event_log = NULL; + } +} + +/* + * Reset the buffer which saves user interested cmds/evts + */ +static int wmi_reset_filtered_buffers(wmi_unified_t wmi_handle, + struct wmi_log_buf_t *cmd_log_buf) +{ + int buf_size = WMI_FILTERED_CMD_EVT_MAX_NUM_ENTRY * + sizeof(struct wmi_command_debug); + + if (!cmd_log_buf) + return 0; + + cmd_log_buf->length = 0; + cmd_log_buf->buf_tail_idx = 0; + cmd_log_buf->size = WMI_FILTERED_CMD_EVT_MAX_NUM_ENTRY; + cmd_log_buf->p_buf_tail_idx = &cmd_log_buf->buf_tail_idx; + qdf_mem_zero(cmd_log_buf->buf, buf_size); + return 0; +} + +/* + * Check if id is in id list, + * return true if found. + */ +static bool wmi_id_in_list(uint32_t *id_list, uint32_t id) +{ + int i; + + if (!id_list) + return false; + + for (i = 0; i < WMI_FILTERED_CMD_EVT_SUPPORTED; i++) { + if (id == id_list[i]) { + /* id already in target list */ + return true; + } + } + return false; +} + +/* + * Add command or event ids to list to be recorded + */ +static int wmi_add_to_record_list(wmi_unified_t wmi_handle, + uint32_t id, + enum WMI_RECORD_TYPE record_type) +{ + uint32_t *target_list; + + if (record_type == WMI_CMD) { + target_list = wmi_handle->log_info.filtered_wmi_cmds; + /* check if id already in target list */ + if (wmi_id_in_list(target_list, id)) + return 0; + if (wmi_handle->log_info.filtered_wmi_cmds_idx >= + WMI_FILTERED_CMD_EVT_SUPPORTED) { + wmi_handle->log_info.filtered_wmi_cmds_idx = 0; + } + target_list[wmi_handle->log_info.filtered_wmi_cmds_idx] = id; + wmi_handle->log_info.filtered_wmi_cmds_idx++; + } else if (record_type == WMI_EVT) { + target_list = wmi_handle->log_info.filtered_wmi_evts; + /* check if id already in target list */ + if (wmi_id_in_list(target_list, id)) + return 0; + if (wmi_handle->log_info.filtered_wmi_evts_idx >= + WMI_FILTERED_CMD_EVT_SUPPORTED) { + wmi_handle->log_info.filtered_wmi_evts_idx = 0; + } + target_list[wmi_handle->log_info.filtered_wmi_evts_idx] = id; + wmi_handle->log_info.filtered_wmi_evts_idx++; + } else { + return -EINVAL; + } + return 0; +} + +static void wmi_specific_cmd_evt_record(uint32_t id, uint8_t *buf, + struct wmi_log_buf_t *log_buffer) +{ + int idx; + struct wmi_command_debug *tmpbuf = + (struct wmi_command_debug *)log_buffer->buf; + + if (*log_buffer->p_buf_tail_idx >= WMI_FILTERED_CMD_EVT_MAX_NUM_ENTRY) + *log_buffer->p_buf_tail_idx = 0; + + idx = *log_buffer->p_buf_tail_idx; + tmpbuf[idx].command = id; + qdf_mem_copy(tmpbuf[idx].data, buf, + WMI_EVENT_DEBUG_ENTRY_MAX_LENGTH); + tmpbuf[idx].time = qdf_get_log_timestamp(); + (*log_buffer->p_buf_tail_idx)++; + log_buffer->length++; +} + +void wmi_specific_cmd_record(wmi_unified_t wmi_handle, + uint32_t id, uint8_t *buf) +{ + uint32_t *target_list; + struct wmi_log_buf_t *log_buffer; + + target_list = wmi_handle->log_info.filtered_wmi_cmds; + if (!target_list) + return; + + log_buffer = wmi_handle->log_info.wmi_filtered_command_log; + if (!log_buffer) + return; + + if (wmi_id_in_list(target_list, id)) { + /* id in target list, need to be recorded */ + wmi_specific_cmd_evt_record(id, buf, log_buffer); + } +} + +void wmi_specific_evt_record(wmi_unified_t wmi_handle, + uint32_t id, uint8_t *buf) +{ + uint32_t *target_list; + struct wmi_log_buf_t *log_buffer; + + target_list = wmi_handle->log_info.filtered_wmi_evts; + if (!target_list) + return; + + log_buffer = wmi_handle->log_info.wmi_filtered_event_log; + if (!log_buffer) + return; + + if (wmi_id_in_list(target_list, id)) { + /* id in target list, need to be recorded */ + wmi_specific_cmd_evt_record(id, buf, log_buffer); + } +} + +/* + * Debugfs read/write functions + */ +static int wmi_filtered_seq_printf(qdf_debugfs_file_t m, const char *f, ...) +{ + va_list args; + + va_start(args, f); + seq_vprintf(m, f, args); + va_end(args); + + return 0; +} + +/* + * debugfs show/read for filtered_wmi_cmds + */ +int debug_filtered_wmi_cmds_show(qdf_debugfs_file_t m, void *v) +{ + wmi_unified_t wmi_handle = (wmi_unified_t)m->private; + int i; + int *target_list; + + target_list = wmi_handle->log_info.filtered_wmi_cmds; + if (!target_list) + return 0; + + for (i = 0; i < WMI_FILTERED_CMD_EVT_SUPPORTED; i++) { + if (target_list[i] != 0) { + wmi_filtered_seq_printf(m, "0x%x ", + target_list[i]); + } + } + wmi_filtered_seq_printf(m, "\n"); + + return 0; +} + +int debug_filtered_wmi_evts_show(qdf_debugfs_file_t m, void *v) +{ + wmi_unified_t wmi_handle = (wmi_unified_t)m->private; + int i; + int *target_list; + + target_list = wmi_handle->log_info.filtered_wmi_evts; + if (!target_list) + return 0; + for (i = 0; i < WMI_FILTERED_CMD_EVT_SUPPORTED; i++) { + if (target_list[i] != 0) { + wmi_filtered_seq_printf(m, "0x%x ", + target_list[i]); + } + } + wmi_filtered_seq_printf(m, "\n"); + + return 0; +} + +static int wmi_log_show(wmi_unified_t wmi_handle, void *buf, + qdf_debugfs_file_t m) +{ + struct wmi_log_buf_t *wmi_log = (struct wmi_log_buf_t *)buf; + int pos, nread, outlen; + int i; + uint64_t secs, usecs; + int wmi_ring_size = 100; + + qdf_spin_lock_bh(&wmi_handle->log_info.wmi_record_lock); + if (!wmi_log->length) { + qdf_spin_unlock_bh(&wmi_handle->log_info.wmi_record_lock); + return wmi_filtered_seq_printf(m, + "Nothing to read!\n"); + } + if (wmi_log->length <= wmi_ring_size) + nread = wmi_log->length; + else + nread = wmi_ring_size; + + if (*wmi_log->p_buf_tail_idx == 0) + /* tail can be 0 after wrap-around */ + pos = wmi_ring_size - 1; + else + pos = *wmi_log->p_buf_tail_idx - 1; + + outlen = wmi_filtered_seq_printf(m, "Length = %d\n", wmi_log->length); + qdf_spin_unlock_bh(&wmi_handle->log_info.wmi_record_lock); + while (nread--) { + struct wmi_event_debug *wmi_record; + + wmi_record = &(((struct wmi_event_debug *)wmi_log->buf)[pos]); + qdf_log_timestamp_to_secs(wmi_record->time, &secs, + &usecs); + outlen += wmi_filtered_seq_printf(m, "Event ID = %x\n", + (wmi_record->event)); + outlen += + wmi_filtered_seq_printf(m, + "Event TIME = [%llu.%06llu]\n", + secs, usecs); + outlen += wmi_filtered_seq_printf(m, "CMD = "); + for (i = 0; i < (WMI_EVENT_DEBUG_ENTRY_MAX_LENGTH / + sizeof(uint32_t)); i++) + outlen += wmi_filtered_seq_printf(m, "%x ", + wmi_record->data[i]); + outlen += wmi_filtered_seq_printf(m, "\n"); + if (pos == 0) + pos = wmi_ring_size - 1; + else + pos--; + } + return outlen; +} + +int debug_wmi_filtered_command_log_show(qdf_debugfs_file_t m, void *v) +{ + wmi_unified_t wmi_handle = (wmi_unified_t)m->private; + struct wmi_log_buf_t *wmi_log = + wmi_handle->log_info.wmi_filtered_command_log; + + if (!wmi_log) + return 0; + return wmi_log_show(wmi_handle, wmi_log, m); +} + +int debug_wmi_filtered_event_log_show(qdf_debugfs_file_t m, void *v) +{ + wmi_unified_t wmi_handle = (wmi_unified_t)m->private; + struct wmi_log_buf_t *wmi_log = + wmi_handle->log_info.wmi_filtered_event_log; + + if (!wmi_log) + return 0; + return wmi_log_show(wmi_handle, wmi_log, m); +} + +ssize_t debug_filtered_wmi_cmds_write(struct file *file, + const char __user *buf, + size_t count, loff_t *ppos) +{ + wmi_unified_t wmi_handle = + ((struct seq_file *)file->private_data)->private; + int k, ret; + char locbuf[12] = {0}; + int buf_size = WMI_FILTERED_CMD_EVT_SUPPORTED * sizeof(int); + + if ((!buf) || (count > 8 || count <= 0)) + return -EFAULT; + + if (!wmi_handle->log_info.filtered_wmi_cmds) + return -EFAULT; + + if (copy_from_user(locbuf, buf, count)) + return -EFAULT; + + ret = qdf_kstrtoint(locbuf, 16, &k); + if (ret) + return -EINVAL; + + if (k == 0xffff) { + qdf_mem_zero(wmi_handle->log_info.filtered_wmi_cmds, buf_size); + wmi_handle->log_info.filtered_wmi_cmds_idx = 0; + return count; + } + + if (wmi_add_to_record_list(wmi_handle, k, WMI_CMD)) { + WMI_LOGE("Add cmd %d to WMI_CMD list failed"); + return 0; + } + + return count; +} + +ssize_t debug_filtered_wmi_evts_write(struct file *file, + const char __user *buf, + size_t count, loff_t *ppos) +{ + wmi_unified_t wmi_handle = + ((struct seq_file *)file->private_data)->private; + int k, ret; + char locbuf[12] = {0}; + int buf_size = WMI_FILTERED_CMD_EVT_SUPPORTED * sizeof(int); + + if ((!buf) || (count > 8 || count <= 0)) + return -EFAULT; + + if (!wmi_handle->log_info.filtered_wmi_evts) + return -EFAULT; + + if (copy_from_user(locbuf, buf, count)) + return -EFAULT; + + ret = qdf_kstrtoint(locbuf, 16, &k); + if (ret) + return -EINVAL; + + if (k == 0xffff) { + qdf_mem_zero(wmi_handle->log_info.filtered_wmi_evts, buf_size); + wmi_handle->log_info.filtered_wmi_evts_idx = 0; + return count; + } + + if (wmi_add_to_record_list(wmi_handle, k, WMI_EVT)) { + WMI_LOGE("Add cmd %d to WMI_EVT list failed"); + return 0; + } + + return count; +} + +ssize_t debug_wmi_filtered_command_log_write(struct file *file, + const char __user *buf, + size_t count, loff_t *ppos) +{ + wmi_unified_t wmi_handle = + ((struct seq_file *)file->private_data)->private; + int k, ret; + char locbuf[12] = {0}; + struct wmi_log_buf_t *cmd_log_buf; + + if ((!buf) || (count > 8 || count <= 0)) + return -EFAULT; + + if (copy_from_user(locbuf, buf, count)) + return -EFAULT; + + ret = qdf_kstrtoint(locbuf, 16, &k); + if (ret) + return -EINVAL; + + if (k != 0xffff) + return -EINVAL; + + cmd_log_buf = wmi_handle->log_info.wmi_filtered_command_log; + if (wmi_reset_filtered_buffers(wmi_handle, cmd_log_buf)) + WMI_LOGE("reset WMI CMD filtered_buffers failed"); + return count; +} + +ssize_t debug_wmi_filtered_event_log_write(struct file *file, + const char __user *buf, + size_t count, loff_t *ppos) +{ + wmi_unified_t wmi_handle = + ((struct seq_file *)file->private_data)->private; + int k, ret; + char locbuf[12] = {0}; + struct wmi_log_buf_t *cmd_log_buf; + + if ((!buf) || (count > 8 || count <= 0)) + return -EFAULT; + + if (copy_from_user(locbuf, buf, count)) + return -EFAULT; + + ret = qdf_kstrtoint(locbuf, 16, &k); + if (ret) + return -EINVAL; + + if (k != 0xffff) + return -EINVAL; + + cmd_log_buf = wmi_handle->log_info.wmi_filtered_event_log; + if (wmi_reset_filtered_buffers(wmi_handle, cmd_log_buf)) + WMI_LOGE("reset WMI EVT filtered_buffers failed"); + return count; +} diff --git a/wmi/src/wmi_unified.c b/wmi/src/wmi_unified.c index e4fbab3b9e12..ee7a415d483e 100644 --- a/wmi/src/wmi_unified.c +++ b/wmi/src/wmi_unified.c @@ -36,6 +36,8 @@ #include #include +#include +#include "wmi_filtered_logging.h" /* This check for CONFIG_WIN temporary added due to redeclaration compilation error in MCL. Error is caused due to inclusion of wmi.h in wmi_unified_api.h @@ -101,7 +103,7 @@ typedef PREPACK struct { #ifdef WMI_INTERFACE_EVENT_LOGGING #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0)) /* TODO Cleanup this backported function */ -static int wmi_bp_seq_printf(struct seq_file *m, const char *f, ...) +static int wmi_bp_seq_printf(qdf_debugfs_file_t m, const char *f, ...) { va_list args; @@ -813,6 +815,8 @@ static QDF_STATUS wmi_log_init(struct wmi_unified *wmi_handle) qdf_spinlock_create(&wmi_handle->log_info.wmi_record_lock); wmi_handle->log_info.wmi_logging_enable = 1; + wmi_filtered_logging_init(wmi_handle); + return QDF_STATUS_SUCCESS; } #endif @@ -827,6 +831,8 @@ static QDF_STATUS wmi_log_init(struct wmi_unified *wmi_handle) #ifdef WMI_INTERFACE_EVENT_LOGGING_DYNAMIC_ALLOC static inline void wmi_log_buffer_free(struct wmi_unified *wmi_handle) { + wmi_filtered_logging_free(wmi_handle); + if (wmi_handle->log_info.wmi_command_log_buf_info.buf) qdf_mem_free(wmi_handle->log_info.wmi_command_log_buf_info.buf); if (wmi_handle->log_info.wmi_command_tx_cmp_log_buf_info.buf) @@ -850,6 +856,7 @@ static inline void wmi_log_buffer_free(struct wmi_unified *wmi_handle) qdf_mem_free( wmi_handle->log_info.wmi_diag_event_log_buf_info.buf); wmi_handle->log_info.wmi_logging_enable = 0; + qdf_spinlock_destroy(&wmi_handle->log_info.wmi_record_lock); } #else @@ -1357,6 +1364,12 @@ GENERATE_DEBUG_STRUCTS(wmi_mgmt_command_tx_cmp_log); GENERATE_DEBUG_STRUCTS(wmi_mgmt_event_log); GENERATE_DEBUG_STRUCTS(wmi_enable); GENERATE_DEBUG_STRUCTS(wmi_log_size); +#ifdef WMI_INTERFACE_FILTERED_EVENT_LOGGING +GENERATE_DEBUG_STRUCTS(filtered_wmi_cmds); +GENERATE_DEBUG_STRUCTS(filtered_wmi_evts); +GENERATE_DEBUG_STRUCTS(wmi_filtered_command_log); +GENERATE_DEBUG_STRUCTS(wmi_filtered_event_log); +#endif struct wmi_debugfs_info wmi_debugfs_infos[NUM_DEBUG_INFOS] = { DEBUG_FOO(wmi_command_log), @@ -1368,6 +1381,12 @@ struct wmi_debugfs_info wmi_debugfs_infos[NUM_DEBUG_INFOS] = { DEBUG_FOO(wmi_mgmt_event_log), DEBUG_FOO(wmi_enable), DEBUG_FOO(wmi_log_size), +#ifdef WMI_INTERFACE_FILTERED_EVENT_LOGGING + DEBUG_FOO(filtered_wmi_cmds), + DEBUG_FOO(filtered_wmi_evts), + DEBUG_FOO(wmi_filtered_command_log), + DEBUG_FOO(wmi_filtered_event_log), +#endif }; @@ -1484,7 +1503,7 @@ void wmi_mgmt_cmd_record(wmi_unified_t wmi_handle, uint32_t cmd, qdf_spin_lock_bh(&wmi_handle->log_info.wmi_record_lock); WMI_MGMT_COMMAND_RECORD(wmi_handle, cmd, (uint8_t *)data); - + wmi_specific_cmd_record(wmi_handle, cmd, (uint8_t *)data); qdf_spin_unlock_bh(&wmi_handle->log_info.wmi_record_lock); } #else @@ -1839,9 +1858,11 @@ QDF_STATUS wmi_unified_cmd_send_fl(wmi_unified_t wmi_handle, wmi_buf_t buf, * WMI mgmt command already recorded in wmi_mgmt_cmd_record */ if (wmi_handle->ops->is_management_record(cmd_id) == false) { - WMI_COMMAND_RECORD(wmi_handle, cmd_id, - qdf_nbuf_data(buf) + - wmi_handle->soc->buf_offset_command); + uint8_t *tmpbuf = (uint8_t *)qdf_nbuf_data(buf) + + wmi_handle->soc->buf_offset_command; + + WMI_COMMAND_RECORD(wmi_handle, cmd_id, tmpbuf); + wmi_specific_cmd_record(wmi_handle, cmd_id, tmpbuf); } qdf_spin_unlock_bh(&wmi_handle->log_info.wmi_record_lock); } @@ -2430,8 +2451,11 @@ void __wmi_control_rx(struct wmi_unified *wmi_handle, wmi_buf_t evt_buf) * as its already logged in WMI RX event buffer */ } else { - WMI_EVENT_RECORD(wmi_handle, id, ((uint8_t *) data + - wmi_handle->soc->buf_offset_event)); + uint8_t *tmpbuf = (uint8_t *)data + + wmi_handle->soc->buf_offset_event; + + WMI_EVENT_RECORD(wmi_handle, id, tmpbuf); + wmi_specific_evt_record(wmi_handle, id, tmpbuf); } qdf_spin_unlock_bh(&wmi_handle->log_info.wmi_record_lock); }