From 2982c3a17af333750a4890e19a080f4f12278065 Mon Sep 17 00:00:00 2001 From: Arun Kumar Khandavalli Date: Thu, 26 Mar 2020 21:52:47 +0530 Subject: [PATCH] qcacmn: update the hang data for wmi whenever there is a wmi timeout and recovery is triggered, the wmi history gives insight into reason for the recovery, hence save the last 5 commands/events to understand the reason for the hang recovery. Change-Id: Ie4e0431a8fa6971e6b25b20a6f267341d3f3f4fd CRs-Fixed: 2650340 --- wmi/inc/wmi_hang_event.h | 54 ++++++++++++++++ wmi/src/wmi_hang_event.c | 136 +++++++++++++++++++++++++++++++++++++++ wmi/src/wmi_unified.c | 5 ++ 3 files changed, 195 insertions(+) create mode 100644 wmi/inc/wmi_hang_event.h create mode 100644 wmi/src/wmi_hang_event.c diff --git a/wmi/inc/wmi_hang_event.h b/wmi/inc/wmi_hang_event.h new file mode 100644 index 0000000000..96127ea6f6 --- /dev/null +++ b/wmi/inc/wmi_hang_event.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 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_HANG_EVENT_H +#define WMI_HANG_EVENT_H + +#include +#ifdef WLAN_HANG_EVENT + +/** + * wmi_hang_event_notifier_register() - wmi hang event notifier register + * @wmi_hdl: WMI Handle + * + * This function registers wmi layer notifier for the hang event notifier chain. + * + * Return: QDF_STATUS + */ +QDF_STATUS wmi_hang_event_notifier_register(struct wmi_unified *wmi_hdl); + +/** + * wmi_hang_event_notifier_unregister() - wmi hang event notifier unregister + * @wmi_hdl: WMI Handle + * + * This function unregisters wmi layer notifier for the hang event notifier + * chain. + * + * Return: QDF_STATUS + */ +QDF_STATUS wmi_hang_event_notifier_unregister(void); +#else +static inline +QDF_STATUS wmi_hang_event_notifier_register(struct wmi_unified *wmi_hdl) +{ + return 0; +} + +static inline QDF_STATUS wmi_hang_event_notifier_unregister(void) +{ + return 0; +} +#endif +#endif diff --git a/wmi/src/wmi_hang_event.c b/wmi/src/wmi_hang_event.c new file mode 100644 index 0000000000..d8ec2df6d0 --- /dev/null +++ b/wmi/src/wmi_hang_event.c @@ -0,0 +1,136 @@ +/* + * Copyright (c) 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 +#include +#include +#include +#include + +struct wmi_hang_data_fixed_param { + uint32_t tlv_header; /* tlv tag and length */ + uint32_t event; + uint32_t data; + uint64_t time; +} qdf_packed; + +#define WMI_EVT_HIST 0 +#define WMI_CMD_HIST 1 + +static void wmi_log_history(struct notifier_block *block, void *data, + uint8_t wmi_history) +{ + qdf_notif_block *notif_block = qdf_container_of(block, qdf_notif_block, + notif_block); + struct qdf_notifer_data *wmi_hang_data = data; + int nread, pos, total_len; + unsigned int wmi_ring_size = 3; + uint64_t secs, usecs; + struct wmi_event_debug *wmi_evt; + struct wmi_unified *wmi_handle; + struct wmi_log_buf_t *wmi_log; + struct wmi_hang_data_fixed_param *cmd; + struct wmi_command_debug *wmi_cmd; + uint8_t *wmi_buf_ptr; + + if (!wmi_hang_data) + return; + + wmi_handle = notif_block->priv_data; + if (!wmi_handle) + return; + + if (wmi_hang_data->offset >= QDF_WLAN_MAX_HOST_OFFSET) + return; + + if (wmi_history) + wmi_log = &wmi_handle->log_info.wmi_event_log_buf_info; + else + wmi_log = &wmi_handle->log_info.wmi_command_log_buf_info; + + total_len = sizeof(struct wmi_hang_data_fixed_param); + + 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; + + while (nread--) { + switch (wmi_history) { + case WMI_EVT_HIST: + wmi_buf_ptr = (wmi_hang_data->hang_data + + wmi_hang_data->offset); + cmd = ((struct wmi_hang_data_fixed_param *)wmi_buf_ptr); + QDF_HANG_EVT_SET_HDR(&cmd->tlv_header, + HANG_EVT_TAG_WMI_EVT_HIST, + QDF_HANG_GET_STRUCT_TLVLEN(struct wmi_hang_data_fixed_param)); + wmi_evt = &(((struct wmi_event_debug *)wmi_log->buf)[pos]); + cmd->event = wmi_evt->event; + qdf_log_timestamp_to_secs(wmi_evt->time, &secs, &usecs); + cmd->time = secs; + cmd->data = wmi_evt->data[0]; + break; + case WMI_CMD_HIST: + wmi_buf_ptr = (wmi_hang_data->hang_data + + wmi_hang_data->offset); + cmd = ((struct wmi_hang_data_fixed_param *)wmi_buf_ptr); + QDF_HANG_EVT_SET_HDR(&cmd->tlv_header, + HANG_EVT_TAG_WMI_CMD_HIST, + QDF_HANG_GET_STRUCT_TLVLEN(struct wmi_hang_data_fixed_param)); + wmi_cmd = &(((struct wmi_command_debug *)wmi_log->buf)[pos]); + cmd->event = wmi_cmd->command; + qdf_log_timestamp_to_secs(wmi_cmd->time, &secs, &usecs); + cmd->time = secs; + cmd->data = wmi_cmd->data[0]; + break; + } + if (pos == 0) + pos = wmi_ring_size - 1; + else + pos--; + wmi_hang_data->offset += total_len; + } +} + +static int wmi_recovery_notifier_call(struct notifier_block *block, + unsigned long state, + void *data) +{ + wmi_log_history(block, data, WMI_EVT_HIST); + wmi_log_history(block, data, WMI_CMD_HIST); + + return NOTIFY_OK; +} + +static qdf_notif_block wmi_recovery_notifier = { + .notif_block.notifier_call = wmi_recovery_notifier_call, +}; + +QDF_STATUS wmi_hang_event_notifier_register(struct wmi_unified *wmi_hdl) +{ + wmi_recovery_notifier.priv_data = wmi_hdl; + return qdf_hang_event_register_notifier(&wmi_recovery_notifier); +} + +QDF_STATUS wmi_hang_event_notifier_unregister(void) +{ + return qdf_hang_event_unregister_notifier(&wmi_recovery_notifier); +} diff --git a/wmi/src/wmi_unified.c b/wmi/src/wmi_unified.c index 9aee3a178b..8ec91be041 100644 --- a/wmi/src/wmi_unified.c +++ b/wmi/src/wmi_unified.c @@ -38,6 +38,7 @@ #include #include #include "wmi_filtered_logging.h" +#include /* 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 @@ -2814,6 +2815,8 @@ void *wmi_unified_attach(void *scn_handle, wmi_wbuff_register(wmi_handle); + wmi_hang_event_notifier_register(wmi_handle); + return wmi_handle; error: @@ -2836,6 +2839,8 @@ void wmi_unified_detach(struct wmi_unified *wmi_handle) struct wmi_soc *soc; uint8_t i; + wmi_hang_event_notifier_unregister(); + wmi_wbuff_deregister(wmi_handle); wmi_ext_dbgfs_deinit(wmi_handle);