1 /*
2  * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for
6  * any purpose with or without fee is hereby granted, provided that the
7  * above copyright notice and this permission notice appear in all
8  * copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17  * PERFORMANCE OF THIS SOFTWARE.
18  */
19 /**
20  * DOC: wlan_serialization_debug.c
21  * This file defines the debug functions for serialization component.
22  */
23 
24 #include <wlan_objmgr_vdev_obj.h>
25 #include <wlan_objmgr_pdev_obj.h>
26 #include <wlan_utility.h>
27 #include "wlan_serialization_utils_i.h"
28 #include "wlan_serialization_main_i.h"
29 #include "wlan_serialization_queue_i.h"
30 #include "wlan_serialization_debug_i.h"
31 
32 #ifdef WLAN_SER_DEBUG
33 const char *ser_reason_string[SER_QUEUE_ACTION_MAX] = {
34 	"REQUEST",
35 	"REMOVE",
36 	"CANCEL",
37 	"TIMEOUT",
38 	"ACTIVATION_FAILED",
39 	"PENDING_TO_ACTIVE",
40 };
41 
wlan_ser_print_queues(qdf_list_t * queue,enum wlan_serialization_node node_type,bool is_active_queue)42 static void wlan_ser_print_queues(
43 		qdf_list_t *queue,
44 		enum wlan_serialization_node node_type,
45 		bool is_active_queue)
46 {
47 	struct wlan_serialization_command_list *cmd_list = NULL;
48 	uint32_t queuelen;
49 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
50 	qdf_list_node_t *nnode = NULL;
51 	bool is_pdev_queue = false;
52 
53 	if (node_type == WLAN_SER_PDEV_NODE)
54 		is_pdev_queue = true;
55 
56 	ser_err_no_fl(WLAN_SER_LINE);
57 	ser_err_no_fl("%s %s Queue", (is_pdev_queue) ? "PDEV" : "VDEV",
58 		      (is_active_queue ? "Active" : "Pending"));
59 
60 	ser_err_no_fl(WLAN_SER_LINE);
61 	ser_err_no_fl("|CMD_TYPE|CMD_ID|VDEV_ID|BLOCKING|PRIORITY|");
62 	ser_err_no_fl(WLAN_SER_LINE);
63 
64 	queuelen = wlan_serialization_list_size(queue);
65 	while (queuelen--) {
66 		status = wlan_serialization_get_cmd_from_queue(queue, &nnode);
67 		if (status != QDF_STATUS_SUCCESS)
68 			break;
69 
70 	if (node_type == WLAN_SER_PDEV_NODE)
71 		cmd_list = qdf_container_of(
72 				nnode,
73 				struct wlan_serialization_command_list,
74 				pdev_node);
75 	else
76 		cmd_list = qdf_container_of(
77 				nnode,
78 				struct wlan_serialization_command_list,
79 				vdev_node);
80 
81 	ser_err_no_fl("|%8u|%6u|%6u|%8u|%8u|",
82 		      cmd_list->cmd.cmd_type,
83 		cmd_list->cmd.cmd_id,
84 		wlan_vdev_get_id(cmd_list->cmd.vdev),
85 		cmd_list->cmd.is_blocking,
86 		cmd_list->cmd.is_high_priority);
87 	}
88 }
89 
wlan_ser_print_pdev_queue(struct wlan_serialization_pdev_queue * ser_pdev_q_obj,enum wlan_serialization_node node_type)90 static void wlan_ser_print_pdev_queue(
91 		struct wlan_serialization_pdev_queue *ser_pdev_q_obj,
92 		enum wlan_serialization_node node_type)
93 {
94 	/*Dump the active queue*/
95 	wlan_ser_print_queues(&ser_pdev_q_obj->active_list,
96 			      node_type, true);
97 
98 	/*Dump the pending queue*/
99 	wlan_ser_print_queues(&ser_pdev_q_obj->pending_list,
100 			      node_type, false);
101 }
102 
wlan_ser_print_vdev_queue(struct wlan_serialization_vdev_queue * ser_vdev_q_obj,enum wlan_serialization_node node_type)103 static void wlan_ser_print_vdev_queue(
104 		struct wlan_serialization_vdev_queue *ser_vdev_q_obj,
105 		enum wlan_serialization_node node_type)
106 {
107 	/*Dump the active queue*/
108 	wlan_ser_print_queues(&ser_vdev_q_obj->active_list,
109 			      node_type, true);
110 
111 	/*Dump the pending queue*/
112 	wlan_ser_print_queues(&ser_vdev_q_obj->pending_list,
113 			      node_type, false);
114 }
115 
wlan_ser_print_all_history(struct wlan_serialization_pdev_queue * pdev_queue,bool for_vdev_queue,uint32_t vdev_id)116 static void wlan_ser_print_all_history(
117 		struct wlan_serialization_pdev_queue *pdev_queue,
118 		bool for_vdev_queue,
119 		uint32_t vdev_id)
120 {
121 	uint8_t idx;
122 	uint8_t data_idx;
123 	struct ser_history *history_info;
124 	struct ser_data *data;
125 
126 	history_info = &pdev_queue->history;
127 
128 	ser_err_no_fl(WLAN_SER_LINE WLAN_SER_LINE);
129 	ser_err_no_fl("Queue Commands History");
130 	ser_err_no_fl(WLAN_SER_LINE WLAN_SER_LINE);
131 	ser_err_no_fl(WLAN_SER_HISTORY_HEADER);
132 	ser_err_no_fl(WLAN_SER_LINE WLAN_SER_LINE);
133 
134 	for (idx = 0; idx < SER_MAX_HISTORY_CMDS; idx++) {
135 		data_idx = (history_info->index + idx) % SER_MAX_HISTORY_CMDS;
136 
137 		data = &history_info->data[data_idx];
138 
139 		if (data->ser_reason >= SER_QUEUE_ACTION_MAX) {
140 			ser_debug("Invalid Serialization Reason");
141 			continue;
142 		}
143 
144 		if (!data->data_updated)
145 			continue;
146 
147 		if (for_vdev_queue) {
148 			if (vdev_id != data->vdev_id)
149 				continue;
150 		}
151 		ser_err_no_fl(
152 			"|0x%016llx|%8d|%6d|%7d|%8d|%8d|%6s|%7s|%17s|",
153 			data->time,
154 			data->cmd_type,
155 			data->cmd_id,
156 			data->vdev_id,
157 			data->is_blocking,
158 			data->is_high_priority,
159 			data->add_remove ? "ADD" : "REMOVE",
160 			data->active_pending ? "ACTIVE" : "PENDING",
161 			ser_reason_string[data->ser_reason]);
162 	}
163 }
164 
wlan_ser_print_history(struct wlan_objmgr_vdev * vdev,uint8_t val,uint32_t sub_val)165 QDF_STATUS wlan_ser_print_history(
166 		struct wlan_objmgr_vdev *vdev, uint8_t val,
167 		uint32_t sub_val)
168 {
169 	struct wlan_ser_pdev_obj *ser_pdev;
170 	struct wlan_ser_vdev_obj *ser_vdev;
171 	struct wlan_serialization_pdev_queue *pdev_q;
172 	struct wlan_serialization_vdev_queue *vdev_q;
173 	bool for_vdev_queue = false;
174 	uint32_t vdev_id = WLAN_INVALID_VDEV_ID;
175 
176 	ser_pdev = wlan_serialization_get_pdev_obj(
177 			wlan_vdev_get_pdev(vdev));
178 
179 	ser_vdev = wlan_serialization_get_vdev_obj(vdev);
180 
181 	switch (val) {
182 	/*
183 	 * Print scan pdev queues
184 	 */
185 	case SER_PDEV_QUEUE_COMP_SCAN:
186 		ser_err_no_fl("Serialization SCAN Queues(LIVE)");
187 		pdev_q = &ser_pdev->pdev_q[SER_PDEV_QUEUE_COMP_SCAN];
188 		wlan_ser_print_pdev_queue(pdev_q, WLAN_SER_PDEV_NODE);
189 		break;
190 	/*
191 	 * Print non scan queues
192 	 */
193 	case SER_PDEV_QUEUE_COMP_NON_SCAN:
194 		pdev_q = &ser_pdev->pdev_q[SER_PDEV_QUEUE_COMP_NON_SCAN];
195 		ser_err_no_fl("Serialization NON SCAN Queues(LIVE)");
196 		switch (sub_val) {
197 		/*
198 		 * Print non scan pdev queues
199 		 */
200 		case SER_PDEV_QUEUE_TYPE:
201 			wlan_ser_print_pdev_queue(pdev_q, WLAN_SER_PDEV_NODE);
202 			break;
203 		/*
204 		 * Print non scan pdev queues
205 		 */
206 		case SER_VDEV_QUEUE_TYPE:
207 			vdev_q =
208 			    &ser_vdev->vdev_q[SER_VDEV_QUEUE_COMP_NON_SCAN];
209 			for_vdev_queue = true;
210 			vdev_id = wlan_vdev_get_id(vdev);
211 			wlan_ser_print_vdev_queue(vdev_q, WLAN_SER_VDEV_NODE);
212 			break;
213 		default:
214 			ser_err("Invalid parameter for queue type(pdev/vdev)");
215 		}
216 		break;
217 	default:
218 		ser_err("Invalid parameter for queue type(scan/non_scan");
219 		goto error;
220 	}
221 
222 	wlan_ser_print_all_history(pdev_q, for_vdev_queue, vdev_id);
223 error:
224 	return QDF_STATUS_SUCCESS;
225 }
226 
227 qdf_export_symbol(wlan_ser_print_history);
228 
wlan_ser_update_cmd_history(struct wlan_serialization_pdev_queue * pdev_queue,struct wlan_serialization_command * cmd,enum ser_queue_reason ser_reason,bool add_remove,bool active_queue)229 void wlan_ser_update_cmd_history(
230 		struct wlan_serialization_pdev_queue *pdev_queue,
231 		struct wlan_serialization_command *cmd,
232 		enum ser_queue_reason ser_reason,
233 		bool add_remove,
234 		bool active_queue)
235 {
236 	struct ser_data *ser_data_info;
237 	struct ser_history *ser_history_info;
238 
239 	ser_history_info = &pdev_queue->history;
240 	ser_history_info->index %= SER_MAX_HISTORY_CMDS;
241 
242 	ser_data_info = &ser_history_info->data[ser_history_info->index];
243 
244 	ser_data_info->cmd_type = cmd->cmd_type;
245 	ser_data_info->cmd_id = cmd->cmd_id;
246 	ser_data_info->is_blocking = cmd->is_blocking;
247 	ser_data_info->is_high_priority = cmd->is_high_priority;
248 	ser_data_info->add_remove = add_remove;
249 	ser_data_info->active_pending = active_queue;
250 	ser_data_info->ser_reason = ser_reason;
251 	ser_data_info->vdev_id = wlan_vdev_get_id(cmd->vdev);
252 	ser_data_info->data_updated = true;
253 	ser_data_info->time = qdf_get_log_timestamp();
254 
255 	ser_history_info->index++;
256 }
257 #endif
258