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