xref: /wlan-dirver/qca-wifi-host-cmn/target_if/cp_stats/src/target_if_cp_stats.c (revision 2f4b444fb7e689b83a4ab0e7b3b38f0bf4def8e0)
1 /*
2  * Copyright (c) 2018, 2021 The Linux Foundation. All rights reserved.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for
5  * any purpose with or without fee is hereby granted, provided that the
6  * above copyright notice and this permission notice appear in all
7  * copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16  * PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /**
20  * DOC: target_if_cp_stats.c
21  *
22  * This file provide definition for APIs registered through lmac Tx Ops
23  */
24 
25 #include <qdf_mem.h>
26 #include <qdf_status.h>
27 #include <target_if_cp_stats.h>
28 #include <wmi_unified_priv.h>
29 #include <wmi_unified_param.h>
30 #include <target_if.h>
31 #include <wlan_tgt_def_config.h>
32 #include <wmi_unified_api.h>
33 #include <wlan_osif_priv.h>
34 #include <wlan_cp_stats_utils_api.h>
35 
36 #ifdef WLAN_SUPPORT_INFRA_CTRL_PATH_STATS
37 
38 uint32_t get_infra_cp_stats_id(enum infra_cp_stats_id type)
39 {
40 	switch (type) {
41 	case TYPE_REQ_CTRL_PATH_PDEV_TX_STAT:
42 		return WMI_REQUEST_CTRL_PATH_PDEV_TX_STAT;
43 	case TYPE_REQ_CTRL_PATH_VDEV_EXTD_STAT:
44 		return WMI_REQUEST_CTRL_PATH_VDEV_EXTD_STAT;
45 	case TYPE_REQ_CTRL_PATH_MEM_STAT:
46 		return WMI_REQUEST_CTRL_PATH_MEM_STAT;
47 	case TYPE_REQ_CTRL_PATH_TWT_STAT:
48 		return WMI_REQUEST_CTRL_PATH_TWT_STAT;
49 	default:
50 		return -EINVAL;
51 	}
52 }
53 
54 uint32_t get_infra_cp_stats_action(enum infra_cp_stats_action action)
55 {
56 	switch (action) {
57 	case ACTION_REQ_CTRL_PATH_STAT_GET:
58 		return WMI_REQUEST_CTRL_PATH_STAT_GET;
59 	case ACTION_REQ_CTRL_PATH_STAT_RESET:
60 		return WMI_REQUEST_CTRL_PATH_STAT_RESET;
61 	case ACTION_REQ_CTRL_PATH_STAT_START:
62 		return WMI_REQUEST_CTRL_PATH_STAT_START;
63 	case ACTION_REQ_CTRL_PATH_STAT_STOP:
64 		return WMI_REQUEST_CTRL_PATH_STAT_STOP;
65 	default:
66 		return -EINVAL;
67 	}
68 }
69 
70 #ifdef WLAN_SUPPORT_TWT
71 /**
72  * target_if_infra_cp_stats_twt_event_free() - Free event buffer
73  * @ev: pointer to infra cp stats event structure
74  *
75  * Return: None
76  */
77 static
78 void target_if_infra_cp_stats_twt_event_free(struct infra_cp_stats_event *ev)
79 {
80 	qdf_mem_free(ev->twt_infra_cp_stats);
81 	ev->twt_infra_cp_stats = NULL;
82 }
83 
84 /**
85  * target_if_infra_cp_stats_twt_event_alloc() - Allocate event buffer for TWT
86  * parameters
87  * @ev: pointer to infra cp stats event structure
88  *
89  * Return: QDF_STATUS_SUCCESS on Success, other QDF_STATUS error codes on
90  * failure
91  */
92 static QDF_STATUS
93 target_if_infra_cp_stats_twt_event_alloc(struct infra_cp_stats_event *ev)
94 {
95 	ev->twt_infra_cp_stats =
96 			qdf_mem_malloc(sizeof(*ev->twt_infra_cp_stats) *
97 			INFRA_CP_STATS_MAX_RESP_TWT_DIALOG_ID);
98 	if (!ev->twt_infra_cp_stats) {
99 		cp_stats_err("mem alloc failed for ev.twt_infra_cp_stats");
100 		return QDF_STATUS_E_NOMEM;
101 	}
102 
103 	return QDF_STATUS_SUCCESS;
104 }
105 #else
106 static inline
107 void target_if_infra_cp_stats_twt_event_free(struct infra_cp_stats_event *ev)
108 {
109 }
110 
111 static inline QDF_STATUS
112 target_if_infra_cp_stats_twt_event_alloc(struct infra_cp_stats_event *ev)
113 {
114 	return QDF_STATUS_SUCCESS;
115 }
116 
117 static inline
118 void target_if_infra_cp_stats_free_stats_event(struct infra_cp_stats_event *ev)
119 {
120 }
121 #endif /* WLAN_SUPPORT_TWT */
122 
123 /**
124  * target_if_extract_infra_cp_stats_event() - Extract data from stats event
125  * @wmi_hdl: WMI Handle
126  * @data: pointer to event data buffer from firmware
127  * @data_len: length of the data buffer
128  * @ev: pointer of output structure to be filled with extracted values
129  *
130  * Return: QDF_STATUS_SUCCESS on Success, other QDF_STATUS error codes
131  * on failure
132  */
133 static QDF_STATUS
134 target_if_extract_infra_cp_stats_event(struct wmi_unified *wmi_hdl,
135 				       uint8_t *data, uint32_t data_len,
136 				       struct infra_cp_stats_event *ev)
137 {
138 	QDF_STATUS status;
139 	uint32_t more_flag = 0;
140 
141 	status = wmi_unified_extract_cp_stats_more_pending(wmi_hdl, data,
142 							   &more_flag);
143 
144 	status = wmi_unified_extract_infra_cp_stats(wmi_hdl, data,
145 						    data_len, ev);
146 
147 	cp_stats_debug("request_id %d", ev->request_id);
148 
149 	return QDF_STATUS_SUCCESS;
150 }
151 
152 /**
153  * target_if_infra_cp_stats_event_handler() - Handle
154  * wmi_pdev_cp_fwstats_eventid
155  * @scn: opaque scn handle
156  * @data: event buffer received from fw
157  * @datalen: length of event buffer
158  *
159  * Return: 0 for success or non zero error codes for failure
160  */
161 static
162 int target_if_infra_cp_stats_event_handler(ol_scn_t scn, uint8_t *data,
163 					   uint32_t datalen)
164 {
165 	QDF_STATUS status;
166 	struct infra_cp_stats_event ev = {0};
167 	struct wlan_objmgr_psoc *psoc;
168 	struct wmi_unified *wmi_handle;
169 	struct wlan_lmac_if_cp_stats_rx_ops *rx_ops;
170 
171 	cp_stats_debug("Enter");
172 
173 	if (!scn || !data) {
174 		cp_stats_err("scn: 0x%pK, data: 0x%pK", scn, data);
175 		return -EINVAL;
176 	}
177 
178 	psoc = target_if_get_psoc_from_scn_hdl(scn);
179 	if (!psoc) {
180 		cp_stats_err("null psoc");
181 		return -EINVAL;
182 	}
183 
184 	rx_ops = target_if_cp_stats_get_rx_ops(psoc);
185 	if (!rx_ops || !rx_ops->process_stats_event) {
186 		cp_stats_err("callback not registered");
187 		return -EINVAL;
188 	}
189 
190 	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
191 	if (!wmi_handle) {
192 		cp_stats_err("wmi_handle is null");
193 		return -EINVAL;
194 	}
195 	status = target_if_infra_cp_stats_twt_event_alloc(&ev);
196 	if (QDF_IS_STATUS_ERROR(status)) {
197 		cp_stats_err("Alloc TWT event mem failed");
198 		goto end;
199 	}
200 
201 	status = target_if_extract_infra_cp_stats_event(wmi_handle, data,
202 							datalen, &ev);
203 	if (QDF_IS_STATUS_ERROR(status)) {
204 		cp_stats_err("extract event failed");
205 		goto end;
206 	}
207 
208 	status = rx_ops->process_infra_stats_event(psoc, &ev);
209 
210 end:
211 	target_if_infra_cp_stats_twt_event_free(&ev);
212 
213 	return qdf_status_to_os_return(status);
214 }
215 #else
216 static
217 int target_if_infra_cp_stats_event_handler(ol_scn_t scn, uint8_t *data,
218 					   uint32_t datalen)
219 {
220 	return 0;
221 }
222 #endif /* WLAN_SUPPORT_INFRA_CTRL_PATH_STATS */
223 
224 #ifdef WLAN_SUPPORT_INFRA_CTRL_PATH_STATS
225 static QDF_STATUS
226 target_if_cp_stats_register_event_handler(struct wlan_objmgr_psoc *psoc)
227 {
228 	struct wmi_unified *wmi_handle;
229 	QDF_STATUS ret_val;
230 
231 	if (!psoc) {
232 		cp_stats_err("PSOC is NULL!");
233 		return QDF_STATUS_E_INVAL;
234 	}
235 
236 	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
237 	if (!wmi_handle) {
238 		cp_stats_err("wmi_handle is null");
239 		return QDF_STATUS_E_INVAL;
240 	}
241 
242 	ret_val = wmi_unified_register_event_handler(wmi_handle,
243 			    wmi_pdev_cp_fwstats_eventid,
244 			    target_if_infra_cp_stats_event_handler,
245 			    WMI_RX_WORK_CTX);
246 	if (QDF_IS_STATUS_ERROR(ret_val))
247 		cp_stats_err("Failed to register for pdev_cp_fwstats_event");
248 
249 	return QDF_STATUS_SUCCESS;
250 }
251 
252 static QDF_STATUS
253 target_if_cp_stats_unregister_event_handler(struct wlan_objmgr_psoc *psoc)
254 {
255 	struct wmi_unified *wmi_handle;
256 
257 	if (!psoc) {
258 		cp_stats_err("PSOC is NULL!");
259 		return QDF_STATUS_E_INVAL;
260 	}
261 
262 	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
263 	if (!wmi_handle) {
264 		cp_stats_err("wmi_handle is null");
265 		return QDF_STATUS_E_INVAL;
266 	}
267 
268 	wmi_unified_unregister_event_handler(wmi_handle,
269 					     wmi_pdev_cp_fwstats_eventid);
270 	return QDF_STATUS_SUCCESS;
271 }
272 #else
273 static QDF_STATUS
274 target_if_cp_stats_register_event_handler(struct wlan_objmgr_psoc *psoc)
275 {
276 	if (!psoc) {
277 		cp_stats_err("PSOC is NULL!");
278 		return QDF_STATUS_E_INVAL;
279 	}
280 
281 	return QDF_STATUS_SUCCESS;
282 }
283 
284 static QDF_STATUS
285 target_if_cp_stats_unregister_event_handler(struct wlan_objmgr_psoc *psoc)
286 {
287 	if (!psoc) {
288 		cp_stats_err("PSOC is NULL!");
289 		return QDF_STATUS_E_INVAL;
290 	}
291 
292 	return QDF_STATUS_SUCCESS;
293 }
294 #endif /* WLAN_SUPPORT_INFRA_CTRL_PATH_STATS */
295 
296 #ifdef WLAN_SUPPORT_INFRA_CTRL_PATH_STATS
297 /**
298  * target_if_infra_cp_stats_req() - API to send stats request to wmi
299  * @psoc: pointer to psoc object
300  * @req: pointer to object containing stats request parameters
301  *
302  * Return: QDF_STATUS_SUCCESS on success, else other qdf error values
303  */
304 static
305 QDF_STATUS target_if_infra_cp_stats_req(struct wlan_objmgr_psoc *psoc,
306 					struct infra_cp_stats_cmd_info *req)
307 
308 {
309 	struct wmi_unified *wmi_handle;
310 
311 	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
312 	if (!wmi_handle) {
313 		cp_stats_err("wmi_handle is null.");
314 		return QDF_STATUS_E_NULL_VALUE;
315 	}
316 
317 	return wmi_unified_infra_cp_stats_request_send(wmi_handle, req);
318 }
319 
320 static void target_if_register_infra_cp_stats_txops(
321 				struct wlan_lmac_if_cp_stats_tx_ops *tx_ops)
322 {
323 	tx_ops->send_req_infra_cp_stats = target_if_infra_cp_stats_req;
324 }
325 #else
326 static void target_if_register_infra_cp_stats_txops(
327 				struct wlan_lmac_if_cp_stats_tx_ops *tx_ops)
328 {
329 }
330 #endif /* WLAN_SUPPORT_INFRA_CTRL_PATH_STATS */
331 
332 QDF_STATUS
333 target_if_cp_stats_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops)
334 {
335 	struct wlan_lmac_if_cp_stats_tx_ops *cp_stats_tx_ops;
336 
337 	if (!tx_ops) {
338 		cp_stats_err("lmac tx ops is NULL!");
339 		return QDF_STATUS_E_INVAL;
340 	}
341 
342 	cp_stats_tx_ops = &tx_ops->cp_stats_tx_ops;
343 	if (!cp_stats_tx_ops) {
344 		cp_stats_err("lmac tx ops is NULL!");
345 		return QDF_STATUS_E_FAILURE;
346 	}
347 	target_if_register_infra_cp_stats_txops(cp_stats_tx_ops);
348 
349 	cp_stats_tx_ops->cp_stats_attach =
350 		target_if_cp_stats_register_event_handler;
351 	cp_stats_tx_ops->cp_stats_detach =
352 		target_if_cp_stats_unregister_event_handler;
353 	cp_stats_tx_ops->cp_stats_legacy_attach =
354 		target_if_cp_stats_register_legacy_event_handler;
355 	cp_stats_tx_ops->cp_stats_legacy_detach =
356 		target_if_cp_stats_unregister_legacy_event_handler;
357 	return QDF_STATUS_SUCCESS;
358 }
359