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