1 /*
2 * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved.
3 * Copyright (c) 2021-2023 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 #include <cfr_defs_i.h>
21 #include <qdf_types.h>
22 #include <wlan_objmgr_pdev_obj.h>
23 #include <wlan_objmgr_vdev_obj.h>
24 #include <wlan_objmgr_peer_obj.h>
25 #include <wlan_cfr_tgt_api.h>
26 #include <qdf_streamfs.h>
27 #include <target_if.h>
28 #include <target_if_direct_buf_rx_api.h>
29 #include <wlan_osif_priv.h>
30 #include <cfg_ucfg_api.h>
31 #include "cfr_cfg.h"
32 #ifdef WLAN_CFR_PM
33 #include "host_diag_core_event.h"
34 #endif
35
36 /**
37 * wlan_cfr_is_ini_disabled() - Check if cfr feature is disabled
38 * @pdev: the physical device object.
39 *
40 * Return : true if cfr is disabled, else false.
41 */
42 static bool
wlan_cfr_is_ini_disabled(struct wlan_objmgr_pdev * pdev)43 wlan_cfr_is_ini_disabled(struct wlan_objmgr_pdev *pdev)
44 {
45 struct wlan_objmgr_psoc *psoc;
46 uint8_t cfr_disable_bitmap;
47
48 psoc = wlan_pdev_get_psoc(pdev);
49 if (!psoc) {
50 cfr_err("psoc is null");
51 return true;
52 }
53
54 cfr_disable_bitmap = cfg_get(psoc, CFG_CFR_DISABLE);
55
56 if (cfr_disable_bitmap & (1 << wlan_objmgr_pdev_get_pdev_id(pdev))) {
57 cfr_info("cfr is disabled for pdev[%d]",
58 wlan_objmgr_pdev_get_pdev_id(pdev));
59 return true;
60 }
61
62 return false;
63 }
64
65 /**
66 * wlan_cfr_get_dbr_num_entries() - Get entry number of DBR ring
67 * @pdev: the physical device object.
68 *
69 * Return : Entry number of DBR ring.
70 */
71 static uint32_t
wlan_cfr_get_dbr_num_entries(struct wlan_objmgr_pdev * pdev)72 wlan_cfr_get_dbr_num_entries(struct wlan_objmgr_pdev *pdev)
73 {
74 struct wlan_objmgr_psoc *psoc;
75 struct wlan_psoc_host_dbr_ring_caps *dbr_ring_cap;
76 uint8_t num_dbr_ring_caps, cap_idx, pdev_id;
77 struct target_psoc_info *tgt_psoc_info;
78 uint32_t num_entries = MAX_LUT_ENTRIES;
79
80 if (!pdev) {
81 cfr_err("Invalid pdev");
82 return num_entries;
83 }
84
85 psoc = wlan_pdev_get_psoc(pdev);
86 if (!psoc) {
87 cfr_err("psoc is null");
88 return num_entries;
89 }
90
91 tgt_psoc_info = wlan_psoc_get_tgt_if_handle(psoc);
92 if (!tgt_psoc_info) {
93 cfr_err("target_psoc_info is null");
94 return num_entries;
95 }
96
97 num_dbr_ring_caps = target_psoc_get_num_dbr_ring_caps(tgt_psoc_info);
98 dbr_ring_cap = target_psoc_get_dbr_ring_caps(tgt_psoc_info);
99 pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
100
101 for (cap_idx = 0; cap_idx < num_dbr_ring_caps; cap_idx++) {
102 if (dbr_ring_cap[cap_idx].pdev_id == pdev_id &&
103 dbr_ring_cap[cap_idx].mod_id == DBR_MODULE_CFR)
104 num_entries = dbr_ring_cap[cap_idx].ring_elems_min;
105 }
106
107 num_entries = QDF_MIN(num_entries, MAX_LUT_ENTRIES);
108 cfr_debug("pdev id %d, num_entries %d", pdev_id, num_entries);
109
110 return num_entries;
111 }
112
113 #ifdef WLAN_CFR_PM
114 /**
115 * cfr_wakelock_init(): Create/init wake lock for CFR
116 * @pcfr: CFR pdev context
117 *
118 * Create/init wake lock for CFR
119 *
120 * Return None
121 */
cfr_wakelock_init(struct pdev_cfr * pcfr)122 static void cfr_wakelock_init(struct pdev_cfr *pcfr)
123 {
124 if (!pcfr) {
125 cfr_debug("NULL pa");
126 return;
127 }
128
129 pcfr->is_prevent_suspend = false;
130 qdf_wake_lock_create(&pcfr->wake_lock, "wlan_cfr");
131 qdf_runtime_lock_init(&pcfr->runtime_lock);
132 }
133
134 /**
135 * cfr_wakelock_deinit(): Destroy/deinit wake lock for CFR
136 * @pcfr: CFR pdev context
137 *
138 * Destroy/deinit wake lock for CFR
139 *
140 * Return None
141 */
cfr_wakelock_deinit(struct pdev_cfr * pcfr)142 static void cfr_wakelock_deinit(struct pdev_cfr *pcfr)
143 {
144 if (!pcfr) {
145 cfr_debug("NULL pa");
146 return;
147 }
148
149 qdf_runtime_lock_deinit(&pcfr->runtime_lock);
150 qdf_wake_lock_destroy(&pcfr->wake_lock);
151 }
152 #else
cfr_wakelock_init(struct pdev_cfr * pcfr)153 static inline void cfr_wakelock_init(struct pdev_cfr *pcfr)
154 {
155 }
156
cfr_wakelock_deinit(struct pdev_cfr * pcfr)157 static inline void cfr_wakelock_deinit(struct pdev_cfr *pcfr)
158 {
159 }
160 #endif
161
162 QDF_STATUS
wlan_cfr_psoc_obj_create_handler(struct wlan_objmgr_psoc * psoc,void * arg)163 wlan_cfr_psoc_obj_create_handler(struct wlan_objmgr_psoc *psoc, void *arg)
164 {
165 struct psoc_cfr *cfr_sc = NULL;
166
167 cfr_sc = (struct psoc_cfr *)qdf_mem_malloc(sizeof(struct psoc_cfr));
168 if (!cfr_sc) {
169 cfr_err("Failed to allocate cfr_ctx object\n");
170 return QDF_STATUS_E_NOMEM;
171 }
172
173 cfr_sc->psoc_obj = psoc;
174
175 wlan_objmgr_psoc_component_obj_attach(psoc, WLAN_UMAC_COMP_CFR,
176 (void *)cfr_sc,
177 QDF_STATUS_SUCCESS);
178
179 return QDF_STATUS_SUCCESS;
180 }
181
182 QDF_STATUS
wlan_cfr_psoc_obj_destroy_handler(struct wlan_objmgr_psoc * psoc,void * arg)183 wlan_cfr_psoc_obj_destroy_handler(struct wlan_objmgr_psoc *psoc, void *arg)
184 {
185 struct psoc_cfr *cfr_sc = NULL;
186
187 cfr_sc = wlan_objmgr_psoc_get_comp_private_obj(psoc,
188 WLAN_UMAC_COMP_CFR);
189 if (cfr_sc) {
190 wlan_objmgr_psoc_component_obj_detach(psoc, WLAN_UMAC_COMP_CFR,
191 (void *)cfr_sc);
192 qdf_mem_free(cfr_sc);
193 }
194
195 return QDF_STATUS_SUCCESS;
196 }
197
198 #ifdef WLAN_RCC_ENHANCED_AOA_SUPPORT
wlan_cfr_get_aoa_caps(struct pdev_cfr * pa)199 static QDF_STATUS wlan_cfr_get_aoa_caps(struct pdev_cfr *pa)
200 {
201 struct wlan_objmgr_pdev *pdev = pa->pdev_obj;
202 struct wlan_objmgr_psoc *psoc;
203 struct target_psoc_info *tgt_psoc_info;
204 struct wlan_psoc_host_rcc_enh_aoa_caps_ext2 *aoa_caps;
205 uint32_t i, max_agc_gain_tbl_sz;
206
207 if (!pdev) {
208 cfr_err("Invalid pdev");
209 return QDF_STATUS_E_INVAL;
210 }
211
212 psoc = wlan_pdev_get_psoc(pdev);
213 if (!psoc) {
214 cfr_err("psoc is null");
215 return QDF_STATUS_E_INVAL;
216 }
217
218 tgt_psoc_info = wlan_psoc_get_tgt_if_handle(psoc);
219 if (!tgt_psoc_info) {
220 cfr_err("target_psoc_info is null");
221 return QDF_STATUS_E_INVAL;
222 }
223
224 pa->is_enh_aoa_data = false;
225
226 aoa_caps = target_psoc_get_aoa_caps(tgt_psoc_info);
227
228 if (!aoa_caps) {
229 cfr_info("NO enhanced AoA cap advertised");
230 return QDF_STATUS_SUCCESS;
231 }
232
233 max_agc_gain_tbl_sz = sizeof(uint16_t) * PSOC_MAX_NUM_AGC_GAIN_TBLS;
234 pa->max_entries_all_table = 0;
235 pa->max_agc_gain_tbls = aoa_caps->max_agc_gain_tbls;
236
237 if (pa->max_agc_gain_tbls > PSOC_MAX_NUM_AGC_GAIN_TBLS) {
238 cfr_err("Invalid num of tables advertised");
239 return QDF_STATUS_E_INVAL;
240 }
241
242 qdf_mem_copy(pa->max_agc_gain_per_tbl_2g,
243 aoa_caps->max_agc_gain_per_tbl_2g,
244 max_agc_gain_tbl_sz);
245 qdf_mem_copy(pa->max_agc_gain_per_tbl_5g,
246 aoa_caps->max_agc_gain_per_tbl_5g,
247 max_agc_gain_tbl_sz);
248 qdf_mem_copy(pa->max_agc_gain_per_tbl_6g,
249 aoa_caps->max_agc_gain_per_tbl_6g,
250 max_agc_gain_tbl_sz);
251 qdf_mem_copy(pa->max_bdf_entries_per_tbl,
252 aoa_caps->max_bdf_entries_per_tbl,
253 (sizeof(uint8_t) * PSOC_MAX_NUM_AGC_GAIN_TBLS));
254
255 /* table 0's data always starts at offset 0 */
256 pa->start_ent[0] = 0;
257 for (i = 0; i < pa->max_agc_gain_tbls; i++) {
258 pa->max_entries_all_table +=
259 pa->max_bdf_entries_per_tbl[i];
260 if ((i + 1) < pa->max_agc_gain_tbls) {
261 pa->start_ent[i + 1] = (pa->max_bdf_entries_per_tbl[i] +
262 pa->start_ent[i]);
263 }
264 }
265
266 pa->gain_stop_index_array = qdf_mem_malloc(sizeof(uint16_t) *
267 pa->max_entries_all_table *
268 HOST_MAX_CHAINS);
269 if (!pa->gain_stop_index_array) {
270 qdf_err("Failed to allocate gain stop array");
271 return QDF_STATUS_E_NOMEM;
272 }
273
274 pa->enh_phase_delta_array = qdf_mem_malloc(sizeof(uint16_t) *
275 pa->max_entries_all_table *
276 HOST_MAX_CHAINS);
277 if (!pa->enh_phase_delta_array) {
278 qdf_err("Failed to allocate phase delta array");
279 qdf_mem_free(pa->gain_stop_index_array);
280 return QDF_STATUS_E_NOMEM;
281 }
282
283 pa->is_enh_aoa_data = true;
284
285 return QDF_STATUS_SUCCESS;
286 }
287 #else
wlan_cfr_get_aoa_caps(struct pdev_cfr * pa)288 static QDF_STATUS wlan_cfr_get_aoa_caps(struct pdev_cfr *pa)
289 {
290 return QDF_STATUS_SUCCESS;
291 }
292 #endif /* WLAN_RCC_ENHANCED_AOA_SUPPORT */
293
294 QDF_STATUS
wlan_cfr_pdev_obj_create_handler(struct wlan_objmgr_pdev * pdev,void * arg)295 wlan_cfr_pdev_obj_create_handler(struct wlan_objmgr_pdev *pdev, void *arg)
296 {
297 struct pdev_cfr *pa = NULL;
298 uint32_t idx;
299 QDF_STATUS status;
300
301 if (!pdev) {
302 cfr_err("PDEV is NULL\n");
303 return QDF_STATUS_E_FAILURE;
304 }
305
306 if (wlan_cfr_is_ini_disabled(pdev)) {
307 wlan_pdev_nif_feat_ext_cap_clear(pdev, WLAN_PDEV_FEXT_CFR_EN);
308 return QDF_STATUS_E_NOSUPPORT;
309 }
310
311 wlan_pdev_nif_feat_ext_cap_set(pdev, WLAN_PDEV_FEXT_CFR_EN);
312
313 pa = (struct pdev_cfr *)qdf_mem_malloc(sizeof(struct pdev_cfr));
314 if (!pa) {
315 cfr_err("Failed to allocate pdev_cfr object\n");
316 return QDF_STATUS_E_NOMEM;
317 }
318 pa->pdev_obj = pdev;
319 pa->lut_num = wlan_cfr_get_dbr_num_entries(pdev);
320 if (!pa->lut_num) {
321 cfr_err("lut num is 0");
322 qdf_mem_free(pa);
323 return QDF_STATUS_E_INVAL;
324 }
325 pa->lut = (struct look_up_table **)qdf_mem_malloc(pa->lut_num *
326 sizeof(struct look_up_table *));
327 if (!pa->lut) {
328 cfr_err("Failed to allocate lut, lut num %d", pa->lut_num);
329 qdf_mem_free(pa);
330 return QDF_STATUS_E_NOMEM;
331 }
332 for (idx = 0; idx < pa->lut_num; idx++)
333 pa->lut[idx] = (struct look_up_table *)qdf_mem_malloc(
334 sizeof(struct look_up_table));
335
336 /* Allocate AoA related variables here based on FW capability */
337 status = wlan_cfr_get_aoa_caps(pa);
338 if (QDF_IS_STATUS_ERROR(status)) {
339 cfr_err("Failed to get aoa caps");
340 for (idx = 0; idx < pa->lut_num; idx++)
341 qdf_mem_free(pa->lut[idx]);
342 qdf_mem_free(pa);
343 return status;
344 }
345
346 cfr_wakelock_init(pa);
347 wlan_objmgr_pdev_component_obj_attach(pdev, WLAN_UMAC_COMP_CFR,
348 (void *)pa, QDF_STATUS_SUCCESS);
349
350 return QDF_STATUS_SUCCESS;
351 }
352
353 #ifdef WLAN_RCC_ENHANCED_AOA_SUPPORT
354 static inline
wlan_cfr_cleanup_enhanced_aoa(struct pdev_cfr * pa)355 void wlan_cfr_cleanup_enhanced_aoa(struct pdev_cfr *pa)
356 {
357 /**
358 * Free enahced AoA related allocations here.
359 * Caller of this API should ensure pa is not NULL
360 */
361 if (pa->gain_stop_index_array)
362 qdf_mem_free(pa->gain_stop_index_array);
363
364 if (pa->enh_phase_delta_array)
365 qdf_mem_free(pa->enh_phase_delta_array);
366 }
367 #else
368 static inline
wlan_cfr_cleanup_enhanced_aoa(struct pdev_cfr * pa)369 void wlan_cfr_cleanup_enhanced_aoa(struct pdev_cfr *pa)
370 {
371 }
372 #endif /* WLAN_RCC_ENHANCED_AOA_SUPPORT */
373
374 QDF_STATUS
wlan_cfr_pdev_obj_destroy_handler(struct wlan_objmgr_pdev * pdev,void * arg)375 wlan_cfr_pdev_obj_destroy_handler(struct wlan_objmgr_pdev *pdev, void *arg)
376 {
377 struct pdev_cfr *pa = NULL;
378 uint32_t idx;
379
380 if (!pdev) {
381 cfr_err("PDEV is NULL\n");
382 return QDF_STATUS_E_FAILURE;
383 }
384
385 if (wlan_cfr_is_feature_disabled(pdev)) {
386 cfr_info("cfr is disabled");
387 return QDF_STATUS_E_NOSUPPORT;
388 }
389
390 pa = wlan_objmgr_pdev_get_comp_private_obj(pdev, WLAN_UMAC_COMP_CFR);
391 if (pa) {
392 cfr_wakelock_deinit(pa);
393 wlan_objmgr_pdev_component_obj_detach(pdev, WLAN_UMAC_COMP_CFR,
394 (void *)pa);
395 if (pa->lut) {
396 for (idx = 0; idx < pa->lut_num; idx++)
397 qdf_mem_free(pa->lut[idx]);
398 qdf_mem_free(pa->lut);
399 }
400
401 wlan_cfr_cleanup_enhanced_aoa(pa);
402 qdf_mem_free(pa);
403 }
404
405 return QDF_STATUS_SUCCESS;
406 }
407
408 QDF_STATUS
wlan_cfr_peer_obj_create_handler(struct wlan_objmgr_peer * peer,void * arg)409 wlan_cfr_peer_obj_create_handler(struct wlan_objmgr_peer *peer, void *arg)
410 {
411 struct peer_cfr *pe = NULL;
412 struct wlan_objmgr_vdev *vdev;
413 struct wlan_objmgr_pdev *pdev = NULL;
414
415 if (!peer) {
416 cfr_err("PEER is NULL\n");
417 return QDF_STATUS_E_FAILURE;
418 }
419
420 vdev = wlan_peer_get_vdev(peer);
421 if (vdev)
422 pdev = wlan_vdev_get_pdev(vdev);
423
424 if (!pdev) {
425 cfr_err("PDEV is NULL\n");
426 return QDF_STATUS_E_FAILURE;
427 }
428
429 if (wlan_cfr_is_feature_disabled(pdev)) {
430 cfr_debug("cfr is disabled");
431 return QDF_STATUS_E_NOSUPPORT;
432 }
433
434 pe = (struct peer_cfr *)qdf_mem_malloc(sizeof(struct peer_cfr));
435 if (!pe) {
436 cfr_err("Failed to allocate peer_cfr object\n");
437 return QDF_STATUS_E_FAILURE;
438 }
439
440 pe->peer_obj = peer;
441
442 /* Remaining will be populated when we give CFR capture command */
443 wlan_objmgr_peer_component_obj_attach(peer, WLAN_UMAC_COMP_CFR,
444 (void *)pe, QDF_STATUS_SUCCESS);
445 return QDF_STATUS_SUCCESS;
446 }
447
448 QDF_STATUS
wlan_cfr_peer_obj_destroy_handler(struct wlan_objmgr_peer * peer,void * arg)449 wlan_cfr_peer_obj_destroy_handler(struct wlan_objmgr_peer *peer, void *arg)
450 {
451 struct peer_cfr *pe = NULL;
452 struct wlan_objmgr_vdev *vdev;
453 struct wlan_objmgr_pdev *pdev = NULL;
454 struct pdev_cfr *pa = NULL;
455
456 if (!peer) {
457 cfr_err("PEER is NULL\n");
458 return QDF_STATUS_E_FAILURE;
459 }
460
461 vdev = wlan_peer_get_vdev(peer);
462 if (vdev)
463 pdev = wlan_vdev_get_pdev(vdev);
464
465 if (wlan_cfr_is_feature_disabled(pdev)) {
466 cfr_info("cfr is disabled");
467 return QDF_STATUS_E_NOSUPPORT;
468 }
469
470 if (pdev)
471 pa = wlan_objmgr_pdev_get_comp_private_obj(pdev,
472 WLAN_UMAC_COMP_CFR);
473
474 pe = wlan_objmgr_peer_get_comp_private_obj(peer, WLAN_UMAC_COMP_CFR);
475
476 if (pa && pe) {
477 if (pe->period && pe->request)
478 pa->cfr_current_sta_count--;
479 }
480
481 if (pe) {
482 wlan_objmgr_peer_component_obj_detach(peer, WLAN_UMAC_COMP_CFR,
483 (void *)pe);
484 qdf_mem_free(pe);
485 }
486
487 return QDF_STATUS_SUCCESS;
488 }
489
490 #ifdef CFR_USE_FIXED_FOLDER
cfr_get_dev_name(struct wlan_objmgr_pdev * pdev)491 static char *cfr_get_dev_name(struct wlan_objmgr_pdev *pdev)
492 {
493 char *default_name = "wlan";
494
495 return default_name;
496 }
497 #else
498 /**
499 * cfr_get_dev_name() - Get net device name from pdev
500 * @pdev: objmgr pdev
501 *
502 * Return: netdev name
503 */
cfr_get_dev_name(struct wlan_objmgr_pdev * pdev)504 static char *cfr_get_dev_name(struct wlan_objmgr_pdev *pdev)
505 {
506 struct pdev_osif_priv *pdev_ospriv;
507 struct qdf_net_if *nif;
508
509 pdev_ospriv = wlan_pdev_get_ospriv(pdev);
510 if (!pdev_ospriv) {
511 cfr_err("pdev_ospriv is NULL\n");
512 return NULL;
513 }
514
515 nif = pdev_ospriv->nif;
516 if (!nif) {
517 cfr_err("pdev nif is NULL\n");
518 return NULL;
519 }
520
521 return qdf_net_if_get_devname(nif);
522 }
523 #endif
524
cfr_streamfs_init(struct wlan_objmgr_pdev * pdev)525 QDF_STATUS cfr_streamfs_init(struct wlan_objmgr_pdev *pdev)
526 {
527 struct pdev_cfr *pa = NULL;
528 char *devname;
529 char folder[32];
530
531 if (!pdev) {
532 cfr_err("PDEV is NULL\n");
533 return QDF_STATUS_E_FAILURE;
534 }
535
536 if (wlan_cfr_is_feature_disabled(pdev)) {
537 cfr_info("cfr is disabled");
538 return QDF_STATUS_COMP_DISABLED;
539 }
540
541 pa = wlan_objmgr_pdev_get_comp_private_obj(pdev, WLAN_UMAC_COMP_CFR);
542
543 if (pa == NULL) {
544 cfr_err("pdev_cfr is NULL\n");
545 return QDF_STATUS_E_FAILURE;
546 }
547
548 if (!pa->is_cfr_capable) {
549 cfr_err("CFR IS NOT SUPPORTED\n");
550 return QDF_STATUS_E_FAILURE;
551 }
552
553 devname = cfr_get_dev_name(pdev);
554 if (!devname) {
555 cfr_err("devname is NULL\n");
556 return QDF_STATUS_E_FAILURE;
557 }
558
559 snprintf(folder, sizeof(folder), "cfr%s", devname);
560
561 pa->dir_ptr = qdf_streamfs_create_dir((const char *)folder, NULL);
562
563 if (!pa->dir_ptr) {
564 cfr_err("Directory create failed");
565 return QDF_STATUS_E_FAILURE;
566 }
567
568 pa->chan_ptr = qdf_streamfs_open("cfr_dump", pa->dir_ptr,
569 pa->subbuf_size,
570 pa->num_subbufs, NULL);
571
572 if (!pa->chan_ptr) {
573 cfr_err("Chan create failed");
574 qdf_streamfs_remove_dir_recursive(pa->dir_ptr);
575 pa->dir_ptr = NULL;
576 return QDF_STATUS_E_FAILURE;
577 }
578
579 return QDF_STATUS_SUCCESS;
580 }
581
cfr_streamfs_remove(struct wlan_objmgr_pdev * pdev)582 QDF_STATUS cfr_streamfs_remove(struct wlan_objmgr_pdev *pdev)
583 {
584 struct pdev_cfr *pa = NULL;
585
586 if (wlan_cfr_is_feature_disabled(pdev)) {
587 cfr_info("cfr is disabled");
588 return QDF_STATUS_COMP_DISABLED;
589 }
590
591 pa = wlan_objmgr_pdev_get_comp_private_obj(pdev, WLAN_UMAC_COMP_CFR);
592 if (pa) {
593 if (pa->chan_ptr) {
594 qdf_streamfs_close(pa->chan_ptr);
595 pa->chan_ptr = NULL;
596 }
597
598 if (pa->dir_ptr) {
599 qdf_streamfs_remove_dir_recursive(pa->dir_ptr);
600 pa->dir_ptr = NULL;
601 }
602
603 } else
604 return QDF_STATUS_E_FAILURE;
605
606 return QDF_STATUS_SUCCESS;
607 }
608
cfr_streamfs_write(struct pdev_cfr * pa,const void * write_data,size_t write_len)609 QDF_STATUS cfr_streamfs_write(struct pdev_cfr *pa, const void *write_data,
610 size_t write_len)
611 {
612 if (pa->chan_ptr) {
613 /* write to channel buffer */
614 qdf_streamfs_write(pa->chan_ptr, (const void *)write_data,
615 write_len);
616 } else
617 return QDF_STATUS_E_FAILURE;
618
619 return QDF_STATUS_SUCCESS;
620 }
621
cfr_streamfs_flush(struct pdev_cfr * pa)622 QDF_STATUS cfr_streamfs_flush(struct pdev_cfr *pa)
623 {
624 if (pa->chan_ptr) {
625
626 /* Flush the data write to channel buffer */
627 qdf_streamfs_flush(pa->chan_ptr);
628 } else
629 return QDF_STATUS_E_FAILURE;
630
631 return QDF_STATUS_SUCCESS;
632 }
633
cfr_stop_indication(struct wlan_objmgr_vdev * vdev)634 QDF_STATUS cfr_stop_indication(struct wlan_objmgr_vdev *vdev)
635 {
636 struct pdev_cfr *pa;
637 uint32_t status;
638 struct wlan_objmgr_pdev *pdev;
639
640 pdev = wlan_vdev_get_pdev(vdev);
641 pa = wlan_objmgr_pdev_get_comp_private_obj(pdev, WLAN_UMAC_COMP_CFR);
642 if (!pa) {
643 cfr_err("pdev_cfr is NULL\n");
644 return QDF_STATUS_E_INVAL;
645 }
646
647 /* Don't write stop string if there is valid cfr_nl_cb. Since
648 * userspace needn't stop event string
649 */
650 if (pa->nl_cb.cfr_nl_cb)
651 return QDF_STATUS_SUCCESS;
652
653 status = cfr_streamfs_write(pa, (const void *)CFR_STOP_STR,
654 sizeof(CFR_STOP_STR));
655
656 status = cfr_streamfs_flush(pa);
657 cfr_debug("stop indication done");
658
659 return status;
660 }
661
662 #ifdef WLAN_CFR_PM
cfr_prevent_suspend(struct pdev_cfr * pcfr)663 QDF_STATUS cfr_prevent_suspend(struct pdev_cfr *pcfr)
664 {
665 if (!pcfr) {
666 cfr_debug("NULL pcfr");
667 return QDF_STATUS_E_INVAL;
668 }
669
670 if (pcfr->is_prevent_suspend) {
671 cfr_debug("acquired wake lock");
672 return QDF_STATUS_E_AGAIN;
673 }
674 qdf_wake_lock_acquire(&pcfr->wake_lock,
675 WIFI_POWER_EVENT_WAKELOCK_CFR);
676 qdf_runtime_pm_prevent_suspend(&pcfr->runtime_lock);
677 pcfr->is_prevent_suspend = true;
678
679 return QDF_STATUS_SUCCESS;
680 }
681
cfr_allow_suspend(struct pdev_cfr * pcfr)682 QDF_STATUS cfr_allow_suspend(struct pdev_cfr *pcfr)
683 {
684 if (!pcfr) {
685 cfr_debug("NULL pcfr");
686 return QDF_STATUS_E_INVAL;
687 }
688
689 if (!pcfr->is_prevent_suspend) {
690 cfr_debug("wake lock not acquired");
691 return QDF_STATUS_E_INVAL;
692 }
693 qdf_wake_lock_release(&pcfr->wake_lock,
694 WIFI_POWER_EVENT_WAKELOCK_CFR);
695 qdf_runtime_pm_allow_suspend(&pcfr->runtime_lock);
696 pcfr->is_prevent_suspend = false;
697
698 return QDF_STATUS_SUCCESS;
699 }
700 #endif
701