xref: /wlan-dirver/qca-wifi-host-cmn/umac/cfr/core/src/cfr_common.c (revision 6d768494e5ce14eb1603a695c86739d12ecc6ec2)
1 /*
2  * Copyright (c) 2019-2020 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 #include <cfr_defs_i.h>
20 #include <qdf_types.h>
21 #include <wlan_objmgr_pdev_obj.h>
22 #include <wlan_objmgr_vdev_obj.h>
23 #include <wlan_objmgr_peer_obj.h>
24 #include <wlan_cfr_tgt_api.h>
25 #include <qdf_streamfs.h>
26 #include <target_if.h>
27 #include <target_if_direct_buf_rx_api.h>
28 #include <wlan_osif_priv.h>
29 #include <cfg_ucfg_api.h>
30 #include "cfr_cfg.h"
31 
32 /**
33  * wlan_cfr_is_ini_disabled() - Check if cfr feature is disabled
34  * @pdev - the physical device object.
35  *
36  * Return : true if cfr is disabled, else false.
37  */
38 static bool
39 wlan_cfr_is_ini_disabled(struct wlan_objmgr_pdev *pdev)
40 {
41 	struct wlan_objmgr_psoc *psoc;
42 	uint8_t cfr_disable_bitmap;
43 
44 	psoc = wlan_pdev_get_psoc(pdev);
45 	if (!psoc) {
46 		cfr_err("psoc is null");
47 		return true;
48 	}
49 
50 	cfr_disable_bitmap = cfg_get(psoc, CFG_CFR_DISABLE);
51 
52 	if (cfr_disable_bitmap & (1 << wlan_objmgr_pdev_get_pdev_id(pdev))) {
53 		cfr_info("cfr is disabled for pdev[%d]",
54 			 wlan_objmgr_pdev_get_pdev_id(pdev));
55 		return true;
56 	}
57 
58 	return false;
59 }
60 
61 /**
62  * wlan_cfr_get_dbr_num_entries() - Get entry number of DBR ring
63  * @pdev - the physical device object.
64  *
65  * Return : Entry number of DBR ring.
66  */
67 static uint32_t
68 wlan_cfr_get_dbr_num_entries(struct wlan_objmgr_pdev *pdev)
69 {
70 	struct wlan_objmgr_psoc *psoc;
71 	struct wlan_psoc_host_dbr_ring_caps *dbr_ring_cap;
72 	uint8_t num_dbr_ring_caps, cap_idx, pdev_id;
73 	struct target_psoc_info *tgt_psoc_info;
74 	uint32_t num_entries = MAX_LUT_ENTRIES;
75 
76 	if (!pdev) {
77 		cfr_err("Invalid pdev");
78 		return num_entries;
79 	}
80 
81 	psoc = wlan_pdev_get_psoc(pdev);
82 	if (!psoc) {
83 		cfr_err("psoc is null");
84 		return num_entries;
85 	}
86 
87 	tgt_psoc_info = wlan_psoc_get_tgt_if_handle(psoc);
88 	if (!tgt_psoc_info) {
89 		cfr_err("target_psoc_info is null");
90 		return num_entries;
91 	}
92 
93 	num_dbr_ring_caps = target_psoc_get_num_dbr_ring_caps(tgt_psoc_info);
94 	dbr_ring_cap = target_psoc_get_dbr_ring_caps(tgt_psoc_info);
95 	pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
96 
97 	for (cap_idx = 0; cap_idx < num_dbr_ring_caps; cap_idx++) {
98 		if (dbr_ring_cap[cap_idx].pdev_id == pdev_id &&
99 		    dbr_ring_cap[cap_idx].mod_id == DBR_MODULE_CFR)
100 			num_entries = dbr_ring_cap[cap_idx].ring_elems_min;
101 	}
102 
103 	num_entries = QDF_MIN(num_entries, MAX_LUT_ENTRIES);
104 	cfr_debug("pdev id %d, num_entries %d", pdev_id, num_entries);
105 
106 	return num_entries;
107 }
108 
109 QDF_STATUS
110 wlan_cfr_psoc_obj_create_handler(struct wlan_objmgr_psoc *psoc, void *arg)
111 {
112 	struct psoc_cfr *cfr_sc = NULL;
113 
114 	cfr_sc = (struct psoc_cfr *)qdf_mem_malloc(sizeof(struct psoc_cfr));
115 	if (!cfr_sc) {
116 		cfr_err("Failed to allocate cfr_ctx object\n");
117 		return QDF_STATUS_E_NOMEM;
118 	}
119 
120 	cfr_sc->psoc_obj = psoc;
121 
122 	wlan_objmgr_psoc_component_obj_attach(psoc, WLAN_UMAC_COMP_CFR,
123 					      (void *)cfr_sc,
124 					      QDF_STATUS_SUCCESS);
125 
126 	return QDF_STATUS_SUCCESS;
127 }
128 
129 QDF_STATUS
130 wlan_cfr_psoc_obj_destroy_handler(struct wlan_objmgr_psoc *psoc, void *arg)
131 {
132 	struct psoc_cfr *cfr_sc = NULL;
133 
134 	cfr_sc = wlan_objmgr_psoc_get_comp_private_obj(psoc,
135 						       WLAN_UMAC_COMP_CFR);
136 	if (cfr_sc) {
137 		wlan_objmgr_psoc_component_obj_detach(psoc, WLAN_UMAC_COMP_CFR,
138 						      (void *)cfr_sc);
139 		qdf_mem_free(cfr_sc);
140 	}
141 
142 	return QDF_STATUS_SUCCESS;
143 }
144 
145 QDF_STATUS
146 wlan_cfr_pdev_obj_create_handler(struct wlan_objmgr_pdev *pdev, void *arg)
147 {
148 	struct pdev_cfr *pa = NULL;
149 	uint32_t idx;
150 
151 	if (!pdev) {
152 		cfr_err("PDEV is NULL\n");
153 		return QDF_STATUS_E_FAILURE;
154 	}
155 
156 	if (wlan_cfr_is_ini_disabled(pdev)) {
157 		wlan_pdev_nif_feat_ext_cap_clear(pdev, WLAN_PDEV_FEXT_CFR_EN);
158 		return QDF_STATUS_E_NOSUPPORT;
159 	}
160 
161 	wlan_pdev_nif_feat_ext_cap_set(pdev, WLAN_PDEV_FEXT_CFR_EN);
162 
163 	pa = (struct pdev_cfr *)qdf_mem_malloc(sizeof(struct pdev_cfr));
164 	if (!pa) {
165 		cfr_err("Failed to allocate pdev_cfr object\n");
166 		return QDF_STATUS_E_NOMEM;
167 	}
168 	pa->pdev_obj = pdev;
169 	pa->lut_num = wlan_cfr_get_dbr_num_entries(pdev);
170 	if (!pa->lut_num) {
171 		cfr_err("lut num is 0");
172 		return QDF_STATUS_E_INVAL;
173 	}
174 	pa->lut = (struct look_up_table **)qdf_mem_malloc(pa->lut_num *
175 			sizeof(struct look_up_table *));
176 	if (!pa->lut) {
177 		cfr_err("Failed to allocate lut, lut num %d", pa->lut_num);
178 		qdf_mem_free(pa);
179 		return QDF_STATUS_E_NOMEM;
180 	}
181 	for (idx = 0; idx < pa->lut_num; idx++)
182 		pa->lut[idx] = (struct look_up_table *)qdf_mem_malloc(
183 			sizeof(struct look_up_table));
184 
185 	wlan_objmgr_pdev_component_obj_attach(pdev, WLAN_UMAC_COMP_CFR,
186 					      (void *)pa, QDF_STATUS_SUCCESS);
187 
188 	return QDF_STATUS_SUCCESS;
189 }
190 
191 QDF_STATUS
192 wlan_cfr_pdev_obj_destroy_handler(struct wlan_objmgr_pdev *pdev, void *arg)
193 {
194 	struct pdev_cfr *pa = NULL;
195 	uint32_t idx;
196 
197 	if (!pdev) {
198 		cfr_err("PDEV is NULL\n");
199 		return QDF_STATUS_E_FAILURE;
200 	}
201 
202 	if (wlan_cfr_is_feature_disabled(pdev)) {
203 		cfr_info("cfr is disabled");
204 		return QDF_STATUS_E_NOSUPPORT;
205 	}
206 
207 	pa = wlan_objmgr_pdev_get_comp_private_obj(pdev, WLAN_UMAC_COMP_CFR);
208 	if (pa) {
209 		wlan_objmgr_pdev_component_obj_detach(pdev, WLAN_UMAC_COMP_CFR,
210 						      (void *)pa);
211 		if (pa->lut) {
212 			for (idx = 0; idx < pa->lut_num; idx++)
213 				qdf_mem_free(pa->lut[idx]);
214 			qdf_mem_free(pa->lut);
215 		}
216 		qdf_mem_free(pa);
217 	}
218 
219 	return QDF_STATUS_SUCCESS;
220 }
221 
222 QDF_STATUS
223 wlan_cfr_peer_obj_create_handler(struct wlan_objmgr_peer *peer, void *arg)
224 {
225 	struct peer_cfr *pe = NULL;
226 	struct wlan_objmgr_vdev *vdev;
227 	struct wlan_objmgr_pdev *pdev = NULL;
228 
229 	if (!peer) {
230 		cfr_err("PEER is NULL\n");
231 		return QDF_STATUS_E_FAILURE;
232 	}
233 
234 	vdev = wlan_peer_get_vdev(peer);
235 	if (vdev)
236 		pdev = wlan_vdev_get_pdev(vdev);
237 
238 	if (!pdev) {
239 		cfr_err("PDEV is NULL\n");
240 		return QDF_STATUS_E_FAILURE;
241 	}
242 
243 	if (wlan_cfr_is_feature_disabled(pdev)) {
244 		cfr_info("cfr is disabled");
245 		return QDF_STATUS_E_NOSUPPORT;
246 	}
247 
248 	pe = (struct peer_cfr *)qdf_mem_malloc(sizeof(struct peer_cfr));
249 	if (!pe) {
250 		cfr_err("Failed to allocate peer_cfr object\n");
251 		return QDF_STATUS_E_FAILURE;
252 	}
253 
254 	pe->peer_obj = peer;
255 
256 	/* Remaining will be populated when we give CFR capture command */
257 	wlan_objmgr_peer_component_obj_attach(peer, WLAN_UMAC_COMP_CFR,
258 					      (void *)pe, QDF_STATUS_SUCCESS);
259 	return QDF_STATUS_SUCCESS;
260 }
261 
262 QDF_STATUS
263 wlan_cfr_peer_obj_destroy_handler(struct wlan_objmgr_peer *peer, void *arg)
264 {
265 	struct peer_cfr *pe = NULL;
266 	struct wlan_objmgr_vdev *vdev;
267 	struct wlan_objmgr_pdev *pdev = NULL;
268 	struct pdev_cfr *pa = NULL;
269 
270 	if (!peer) {
271 		cfr_err("PEER is NULL\n");
272 		return QDF_STATUS_E_FAILURE;
273 	}
274 
275 	vdev = wlan_peer_get_vdev(peer);
276 	if (vdev)
277 		pdev = wlan_vdev_get_pdev(vdev);
278 
279 	if (wlan_cfr_is_feature_disabled(pdev)) {
280 		cfr_info("cfr is disabled");
281 		return QDF_STATUS_E_NOSUPPORT;
282 	}
283 
284 	if (pdev)
285 		pa = wlan_objmgr_pdev_get_comp_private_obj(pdev,
286 							   WLAN_UMAC_COMP_CFR);
287 
288 	pe = wlan_objmgr_peer_get_comp_private_obj(peer, WLAN_UMAC_COMP_CFR);
289 
290 	if (pa && pe) {
291 		if (pe->period && pe->request)
292 			pa->cfr_current_sta_count--;
293 	}
294 
295 	if (pe) {
296 		wlan_objmgr_peer_component_obj_detach(peer, WLAN_UMAC_COMP_CFR,
297 						      (void *)pe);
298 		qdf_mem_free(pe);
299 	}
300 
301 	return QDF_STATUS_SUCCESS;
302 }
303 
304 #ifdef CFR_USE_FIXED_FOLDER
305 static char *cfr_get_dev_name(struct wlan_objmgr_pdev *pdev)
306 {
307 	char *default_name = "wlan";
308 
309 	return default_name;
310 }
311 #else
312 /**
313  * cfr_get_dev_name() - Get net device name from pdev
314  *  @pdev: objmgr pdev
315  *
316  *  Return: netdev name
317  */
318 static char *cfr_get_dev_name(struct wlan_objmgr_pdev *pdev)
319 {
320 	struct pdev_osif_priv *pdev_ospriv;
321 	struct qdf_net_if *nif;
322 
323 	pdev_ospriv = wlan_pdev_get_ospriv(pdev);
324 	if (!pdev_ospriv) {
325 		cfr_err("pdev_ospriv is NULL\n");
326 		return NULL;
327 	}
328 
329 	nif = pdev_ospriv->nif;
330 	if (!nif) {
331 		cfr_err("pdev nif is NULL\n");
332 		return NULL;
333 	}
334 
335 	return  qdf_net_if_get_devname(nif);
336 }
337 #endif
338 
339 QDF_STATUS cfr_streamfs_init(struct wlan_objmgr_pdev *pdev)
340 {
341 	struct pdev_cfr *pa = NULL;
342 	char *devname;
343 	char folder[32];
344 
345 	if (!pdev) {
346 		cfr_err("PDEV is NULL\n");
347 		return QDF_STATUS_E_FAILURE;
348 	}
349 
350 	if (wlan_cfr_is_feature_disabled(pdev)) {
351 		cfr_info("cfr is disabled");
352 		return QDF_STATUS_COMP_DISABLED;
353 	}
354 
355 	pa = wlan_objmgr_pdev_get_comp_private_obj(pdev, WLAN_UMAC_COMP_CFR);
356 
357 	if (pa == NULL) {
358 		cfr_err("pdev_cfr is NULL\n");
359 		return QDF_STATUS_E_FAILURE;
360 	}
361 
362 	if (!pa->is_cfr_capable) {
363 		cfr_err("CFR IS NOT SUPPORTED\n");
364 		return QDF_STATUS_E_FAILURE;
365 	}
366 
367 	devname = cfr_get_dev_name(pdev);
368 	if (!devname) {
369 		cfr_err("devname is NULL\n");
370 		return QDF_STATUS_E_FAILURE;
371 	}
372 
373 	snprintf(folder, sizeof(folder), "cfr%s", devname);
374 
375 	pa->dir_ptr = qdf_streamfs_create_dir((const char *)folder, NULL);
376 
377 	if (!pa->dir_ptr) {
378 		cfr_err("Directory create failed");
379 		return QDF_STATUS_E_FAILURE;
380 	}
381 
382 	pa->chan_ptr = qdf_streamfs_open("cfr_dump", pa->dir_ptr,
383 					 pa->subbuf_size,
384 					 pa->num_subbufs, NULL);
385 
386 	if (!pa->chan_ptr) {
387 		cfr_err("Chan create failed");
388 		qdf_streamfs_remove_dir_recursive(pa->dir_ptr);
389 		pa->dir_ptr = NULL;
390 		return QDF_STATUS_E_FAILURE;
391 	}
392 
393 	return QDF_STATUS_SUCCESS;
394 }
395 
396 QDF_STATUS cfr_streamfs_remove(struct wlan_objmgr_pdev *pdev)
397 {
398 	struct pdev_cfr *pa = NULL;
399 
400 	if (wlan_cfr_is_feature_disabled(pdev)) {
401 		cfr_info("cfr is disabled");
402 		return QDF_STATUS_COMP_DISABLED;
403 	}
404 
405 	pa = wlan_objmgr_pdev_get_comp_private_obj(pdev, WLAN_UMAC_COMP_CFR);
406 	if (pa) {
407 		if (pa->chan_ptr) {
408 			qdf_streamfs_close(pa->chan_ptr);
409 			pa->chan_ptr = NULL;
410 		}
411 
412 		if (pa->dir_ptr) {
413 			qdf_streamfs_remove_dir_recursive(pa->dir_ptr);
414 			pa->dir_ptr = NULL;
415 		}
416 
417 	} else
418 		return QDF_STATUS_E_FAILURE;
419 
420 	return QDF_STATUS_SUCCESS;
421 }
422 
423 QDF_STATUS cfr_streamfs_write(struct pdev_cfr *pa, const void *write_data,
424 			      size_t write_len)
425 {
426 	if (pa->chan_ptr) {
427 
428 	/* write to channel buffer */
429 		qdf_streamfs_write(pa->chan_ptr, (const void *)write_data,
430 				   write_len);
431 	} else
432 		return QDF_STATUS_E_FAILURE;
433 
434 	return QDF_STATUS_SUCCESS;
435 }
436 
437 QDF_STATUS cfr_streamfs_flush(struct pdev_cfr *pa)
438 {
439 	if (pa->chan_ptr) {
440 
441 	/* Flush the data write to channel buffer */
442 		qdf_streamfs_flush(pa->chan_ptr);
443 	} else
444 		return QDF_STATUS_E_FAILURE;
445 
446 	return QDF_STATUS_SUCCESS;
447 }
448 
449 QDF_STATUS cfr_stop_indication(struct wlan_objmgr_vdev *vdev)
450 {
451 	struct pdev_cfr *pa;
452 	uint32_t status;
453 	struct wlan_objmgr_pdev *pdev;
454 
455 	pdev = wlan_vdev_get_pdev(vdev);
456 	pa = wlan_objmgr_pdev_get_comp_private_obj(pdev, WLAN_UMAC_COMP_CFR);
457 	if (!pa) {
458 		cfr_err("pdev_cfr is NULL\n");
459 		return QDF_STATUS_E_INVAL;
460 	}
461 
462 	status = cfr_streamfs_write(pa, (const void *)CFR_STOP_STR,
463 				    sizeof(CFR_STOP_STR));
464 
465 	status = cfr_streamfs_flush(pa);
466 	cfr_debug("stop indication done");
467 
468 	return status;
469 }
470