blob: e25a0b05596f23889bfc5eeba11679f721545b74 [file] [log] [blame]
Arun Kumar Khandavalli9e36f122020-04-08 15:12:33 +05301/*
2 * Copyright (c) 2020, The Linux Foundation. All rights reserved.
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
Stephen Hines5b4ca182017-01-26 00:43:34 -080016
17/* Suppress -Waddress-of-packed-member for new toolchain update.
18 * Bug: http://b/33566695
19 */
20#if __clang_major__ >= 4
21#pragma clang diagnostic ignored "-Waddress-of-packed-member"
22#endif
23
Arun Kumar Khandavalli9e36f122020-04-08 15:12:33 +053024#include <qdf_hang_event_notifier.h>
25#include <qdf_notifier.h>
26#include <wmi_hang_event.h>
27#include <wmi_unified_priv.h>
28#include <qdf_trace.h>
29
30struct wmi_hang_data_fixed_param {
Arun Kumar Khandavallif70da7f2020-08-12 17:38:58 +053031 uint16_t tlv_header; /* tlv tag and length */
Arun Kumar Khandavalli9e36f122020-04-08 15:12:33 +053032 uint32_t event;
33 uint32_t data;
34 uint64_t time;
35} qdf_packed;
36
37#define WMI_EVT_HIST 0
38#define WMI_CMD_HIST 1
39
40static void wmi_log_history(struct notifier_block *block, void *data,
41 uint8_t wmi_history)
42{
43 qdf_notif_block *notif_block = qdf_container_of(block, qdf_notif_block,
44 notif_block);
45 struct qdf_notifer_data *wmi_hang_data = data;
46 int nread, pos, total_len;
Arun Kumar Khandavalli75cf49f2020-08-08 16:16:35 +053047 unsigned int wmi_ring_size = 1;
Arun Kumar Khandavalli9e36f122020-04-08 15:12:33 +053048 uint64_t secs, usecs;
49 struct wmi_event_debug *wmi_evt;
50 struct wmi_unified *wmi_handle;
51 struct wmi_log_buf_t *wmi_log;
52 struct wmi_hang_data_fixed_param *cmd;
53 struct wmi_command_debug *wmi_cmd;
54 uint8_t *wmi_buf_ptr;
55
56 if (!wmi_hang_data)
57 return;
58
59 wmi_handle = notif_block->priv_data;
60 if (!wmi_handle)
61 return;
62
Arun Kumar Khandavalli9e36f122020-04-08 15:12:33 +053063 if (wmi_history)
64 wmi_log = &wmi_handle->log_info.wmi_event_log_buf_info;
65 else
66 wmi_log = &wmi_handle->log_info.wmi_command_log_buf_info;
67
68 total_len = sizeof(struct wmi_hang_data_fixed_param);
69
70 if (wmi_log->length <= wmi_ring_size)
71 nread = wmi_log->length;
72 else
73 nread = wmi_ring_size;
74
75 if (*wmi_log->p_buf_tail_idx == 0)
76 /* tail can be 0 after wrap-around */
77 pos = wmi_ring_size - 1;
78 else
79 pos = *wmi_log->p_buf_tail_idx - 1;
80
81 while (nread--) {
Kai Liud5038632020-10-21 23:43:17 +080082 if (wmi_hang_data->offset + total_len > QDF_WLAN_HANG_FW_OFFSET)
83 return;
84
Arun Kumar Khandavalli9e36f122020-04-08 15:12:33 +053085 switch (wmi_history) {
86 case WMI_EVT_HIST:
87 wmi_buf_ptr = (wmi_hang_data->hang_data +
88 wmi_hang_data->offset);
89 cmd = ((struct wmi_hang_data_fixed_param *)wmi_buf_ptr);
90 QDF_HANG_EVT_SET_HDR(&cmd->tlv_header,
91 HANG_EVT_TAG_WMI_EVT_HIST,
92 QDF_HANG_GET_STRUCT_TLVLEN(struct wmi_hang_data_fixed_param));
93 wmi_evt = &(((struct wmi_event_debug *)wmi_log->buf)[pos]);
94 cmd->event = wmi_evt->event;
95 qdf_log_timestamp_to_secs(wmi_evt->time, &secs, &usecs);
96 cmd->time = secs;
97 cmd->data = wmi_evt->data[0];
98 break;
99 case WMI_CMD_HIST:
100 wmi_buf_ptr = (wmi_hang_data->hang_data +
101 wmi_hang_data->offset);
102 cmd = ((struct wmi_hang_data_fixed_param *)wmi_buf_ptr);
103 QDF_HANG_EVT_SET_HDR(&cmd->tlv_header,
104 HANG_EVT_TAG_WMI_CMD_HIST,
105 QDF_HANG_GET_STRUCT_TLVLEN(struct wmi_hang_data_fixed_param));
106 wmi_cmd = &(((struct wmi_command_debug *)wmi_log->buf)[pos]);
107 cmd->event = wmi_cmd->command;
108 qdf_log_timestamp_to_secs(wmi_cmd->time, &secs, &usecs);
109 cmd->time = secs;
110 cmd->data = wmi_cmd->data[0];
111 break;
112 }
113 if (pos == 0)
114 pos = wmi_ring_size - 1;
115 else
116 pos--;
117 wmi_hang_data->offset += total_len;
118 }
119}
120
121static int wmi_recovery_notifier_call(struct notifier_block *block,
122 unsigned long state,
123 void *data)
124{
125 wmi_log_history(block, data, WMI_EVT_HIST);
126 wmi_log_history(block, data, WMI_CMD_HIST);
127
128 return NOTIFY_OK;
129}
130
131static qdf_notif_block wmi_recovery_notifier = {
132 .notif_block.notifier_call = wmi_recovery_notifier_call,
133};
134
135QDF_STATUS wmi_hang_event_notifier_register(struct wmi_unified *wmi_hdl)
136{
137 wmi_recovery_notifier.priv_data = wmi_hdl;
138 return qdf_hang_event_register_notifier(&wmi_recovery_notifier);
139}
140
141QDF_STATUS wmi_hang_event_notifier_unregister(void)
142{
143 return qdf_hang_event_unregister_notifier(&wmi_recovery_notifier);
144}