瀏覽代碼

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
Arun Kumar Khandavalli 5 年之前
父節點
當前提交
2982c3a17a
共有 3 個文件被更改,包括 195 次插入0 次删除
  1. 54 0
      wmi/inc/wmi_hang_event.h
  2. 136 0
      wmi/src/wmi_hang_event.c
  3. 5 0
      wmi/src/wmi_unified.c

+ 54 - 0
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 <wmi_unified_priv.h>
+#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

+ 136 - 0
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 <qdf_hang_event_notifier.h>
+#include <qdf_notifier.h>
+#include <wmi_hang_event.h>
+#include <wmi_unified_priv.h>
+#include <qdf_trace.h>
+
+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);
+}

+ 5 - 0
wmi/src/wmi_unified.c

@@ -38,6 +38,7 @@
 #include <target_if.h>
 #include <target_if.h>
 #include <qdf_debugfs.h>
 #include <qdf_debugfs.h>
 #include "wmi_filtered_logging.h"
 #include "wmi_filtered_logging.h"
+#include <wmi_hang_event.h>
 
 
 /* This check for CONFIG_WIN temporary added due to redeclaration compilation
 /* 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
 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_wbuff_register(wmi_handle);
 
 
+	wmi_hang_event_notifier_register(wmi_handle);
+
 	return wmi_handle;
 	return wmi_handle;
 
 
 error:
 error:
@@ -2836,6 +2839,8 @@ void wmi_unified_detach(struct wmi_unified *wmi_handle)
 	struct wmi_soc *soc;
 	struct wmi_soc *soc;
 	uint8_t i;
 	uint8_t i;
 
 
+	wmi_hang_event_notifier_unregister();
+
 	wmi_wbuff_deregister(wmi_handle);
 	wmi_wbuff_deregister(wmi_handle);
 
 
 	wmi_ext_dbgfs_deinit(wmi_handle);
 	wmi_ext_dbgfs_deinit(wmi_handle);