1 /* 2 * Copyright (c) 2016-2020 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. 4 * Copyright (c) 2002-2006, Atheros Communications Inc. 5 * 6 * Permission to use, copy, modify, and/or distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 /** 20 * DOC: This file contains the dfs_attach() and dfs_detach() functions as well 21 * as the dfs_control() function which is used to process ioctls related to DFS. 22 * For Linux/Mac, "radartool" is the command line tool that can be used to call 23 * various ioctls to set and get radar detection thresholds. 24 */ 25 26 #include "../dfs_zero_cac.h" 27 #include "wlan_dfs_lmac_api.h" 28 #include "wlan_dfs_mlme_api.h" 29 #include "wlan_dfs_tgt_api.h" 30 #include "../dfs_internal.h" 31 #include "../dfs_filter_init.h" 32 #include "../dfs_partial_offload_radar.h" 33 34 #ifndef WLAN_DFS_STATIC_MEM_ALLOC 35 /* 36 * dfs_alloc_dfs_events() - allocate dfs events buffer 37 * 38 * Return: events buffer, null on failure. 39 */ 40 static inline struct dfs_event *dfs_alloc_dfs_events(void) 41 { 42 return qdf_mem_malloc(sizeof(struct dfs_event) * DFS_MAX_EVENTS); 43 } 44 45 /* 46 * dfs_free_dfs_events() - Free events buffer 47 * @events: Events buffer pointer 48 * 49 * Return: None 50 */ 51 static inline void dfs_free_dfs_events(struct dfs_event *events) 52 { 53 qdf_mem_free(events); 54 } 55 56 /* 57 * dfs_alloc_dfs_pulseline() - allocate buffer for dfs pulses 58 * 59 * Return: events buffer, null on failure. 60 */ 61 static inline struct dfs_pulseline *dfs_alloc_dfs_pulseline(void) 62 { 63 return qdf_mem_malloc(sizeof(struct dfs_pulseline)); 64 } 65 66 /* 67 * dfs_free_dfs_pulseline() - Free pulse buffer 68 * @pulses: Pulses buffer pointer 69 * 70 * Return: None 71 */ 72 static inline void dfs_free_dfs_pulseline(struct dfs_pulseline *pulses) 73 { 74 qdf_mem_free(pulses); 75 } 76 #else 77 /* Static buffers for DFS objects */ 78 static struct dfs_event global_dfs_event[DFS_MAX_EVENTS]; 79 static struct dfs_pulseline global_dfs_pulseline; 80 81 static inline struct dfs_event *dfs_alloc_dfs_events(void) 82 { 83 return global_dfs_event; 84 } 85 86 static inline void dfs_free_dfs_events(struct dfs_event *events) 87 { 88 } 89 90 static inline struct dfs_pulseline *dfs_alloc_dfs_pulseline(void) 91 { 92 return &global_dfs_pulseline; 93 } 94 95 static inline void dfs_free_dfs_pulseline(struct dfs_pulseline *pulses) 96 { 97 } 98 #endif 99 100 /* 101 * Channel switch announcement (CSA) 102 * usenol=1 (default) make CSA and switch to a new channel on radar detect 103 * usenol=0, make CSA with next channel same as current on radar detect 104 * usenol=2, no CSA and stay on the same channel on radar detect 105 */ 106 107 /* 108 * dfs_task() - The timer function to process the radar pulses. 109 * 110 * NB: not using kernel-doc format since the kernel-doc script doesn't 111 * handle the os_timer_func() macro 112 */ 113 static os_timer_func(dfs_task) 114 { 115 struct wlan_dfs *dfs = NULL; 116 117 OS_GET_TIMER_ARG(dfs, struct wlan_dfs *); 118 119 if (!dfs) { 120 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "dfs is NULL"); 121 return; 122 } 123 124 /* Need to take a lock here since dfs filtering data structures are 125 * freed and re-allocated in dfs_init_radar_filters() during channel 126 * change which may happen in the middle of dfs pulse processing. 127 */ 128 WLAN_DFS_DATA_STRUCT_LOCK(dfs); 129 dfs_process_radarevent(dfs, dfs->dfs_curchan); 130 WLAN_DFS_DATA_STRUCT_UNLOCK(dfs); 131 132 dfs->wlan_radar_tasksched = 0; 133 } 134 135 /** 136 * dfs_main_task_timer_init() - Initialize dfs task timer. 137 * @dfs: Pointer to wlan_dfs structure. 138 */ 139 static void dfs_main_task_timer_init(struct wlan_dfs *dfs) 140 { 141 qdf_timer_init(NULL, 142 &(dfs->wlan_dfs_task_timer), 143 dfs_task, 144 (void *)(dfs), 145 QDF_TIMER_TYPE_WAKE_APPS); 146 } 147 148 /** 149 * dfs_free_filter() - free memory allocated for dfs ft_filters 150 * @radarf: pointer holding ft_filters. 151 * 152 * Return: None 153 */ 154 static void dfs_free_filter(struct dfs_filtertype *radarf) 155 { 156 uint8_t i; 157 158 for (i = 0; i < DFS_MAX_NUM_RADAR_FILTERS; i++) { 159 if (radarf->ft_filters[i]) { 160 qdf_mem_free(radarf->ft_filters[i]); 161 radarf->ft_filters[i] = NULL; 162 } 163 } 164 } 165 166 /** 167 * dfs_alloc_mem_filter() - allocate memory for dfs ft_filters 168 * @radarf: pointer holding ft_filters. 169 * 170 * Return: QDF_STATUS 171 */ 172 static QDF_STATUS dfs_alloc_mem_filter(struct dfs_filtertype *radarf) 173 { 174 uint8_t i; 175 176 for (i = 0; i < DFS_MAX_NUM_RADAR_FILTERS; i++) { 177 radarf->ft_filters[i] = qdf_mem_malloc(sizeof(struct 178 dfs_filter)); 179 if (!radarf->ft_filters[i]) { 180 /* Free all the filter if malloc failed */ 181 dfs_free_filter(radarf); 182 return QDF_STATUS_E_FAILURE; 183 } 184 } 185 186 return QDF_STATUS_SUCCESS; 187 } 188 189 int dfs_main_attach(struct wlan_dfs *dfs) 190 { 191 int i, n; 192 QDF_STATUS status; 193 struct wlan_dfs_radar_tab_info radar_info; 194 195 if (!dfs) { 196 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "dfs is NULL"); 197 return 0; 198 } 199 200 /* If ignore_dfs is set to 1 then Radar detection is disabled. */ 201 if (dfs->dfs_ignore_dfs) { 202 dfs_debug(dfs, WLAN_DEBUG_DFS1, "ignoring dfs"); 203 return 0; 204 } 205 206 /* 207 * Zero out radar_info. It's possible that the attach function 208 * won't fetch an initial regulatory configuration; you really 209 * do want to ensure that the contents indicates there aren't 210 * any filters. 211 */ 212 qdf_mem_zero(&radar_info, sizeof(radar_info)); 213 214 lmac_get_caps(dfs->dfs_pdev_obj, &(dfs->dfs_caps)); 215 216 dfs_clear_stats(dfs); 217 dfs->dfs_event_log_on = 1; 218 dfs_debug(dfs, WLAN_DEBUG_DFS_ALWAYS, "event log enabled by default"); 219 220 dfs->dfs_enable = 1; 221 222 /*Verify : Passing NULL to qdf_timer_init().*/ 223 dfs_main_task_timer_init(dfs); 224 225 dfs_allow_hw_pulses(dfs, true); 226 dfs_host_wait_timer_init(dfs); 227 228 WLAN_DFSQ_LOCK_CREATE(dfs); 229 STAILQ_INIT(&dfs->dfs_radarq); 230 WLAN_ARQ_LOCK_CREATE(dfs); 231 STAILQ_INIT(&dfs->dfs_arq); 232 STAILQ_INIT(&(dfs->dfs_eventq)); 233 WLAN_DFSEVENTQ_LOCK_CREATE(dfs); 234 WLAN_DFS_DATA_STRUCT_LOCK_CREATE(dfs); 235 236 dfs->events = dfs_alloc_dfs_events(); 237 if (!(dfs->events)) 238 return 1; 239 240 for (i = 0; i < DFS_MAX_EVENTS; i++) 241 STAILQ_INSERT_TAIL(&(dfs->dfs_eventq), &dfs->events[i], 242 re_list); 243 244 dfs->pulses = dfs_alloc_dfs_pulseline(); 245 if (!(dfs->pulses)) { 246 dfs_free_dfs_events(dfs->events); 247 dfs->events = NULL; 248 return 1; 249 } 250 251 dfs->pulses->pl_lastelem = DFS_MAX_PULSE_BUFFER_MASK; 252 253 /* Allocate memory for radar filters. */ 254 for (n = 0; n < DFS_MAX_RADAR_TYPES; n++) { 255 dfs->dfs_radarf[n] = (struct dfs_filtertype *) 256 qdf_mem_malloc(sizeof(struct dfs_filtertype)); 257 if (!(dfs->dfs_radarf[n])) 258 goto bad1; 259 260 qdf_mem_zero(dfs->dfs_radarf[n], 261 sizeof(struct dfs_filtertype)); 262 status = dfs_alloc_mem_filter(dfs->dfs_radarf[n]); 263 if (!QDF_IS_STATUS_SUCCESS(status)) { 264 dfs_alert(dfs, WLAN_DEBUG_DFS_ALWAYS, 265 "mem alloc for dfs_filter failed"); 266 goto bad1; 267 } 268 } 269 270 /* Allocate memory for radar table. */ 271 dfs->dfs_ftindextable = (int8_t **)qdf_mem_malloc( 272 DFS_NUM_FT_IDX_TBL_ROWS*sizeof(int8_t *)); 273 if (!(dfs->dfs_ftindextable)) 274 goto bad1; 275 276 for (n = 0; n < DFS_NUM_FT_IDX_TBL_ROWS; n++) { 277 dfs->dfs_ftindextable[n] = qdf_mem_malloc( 278 DFS_MAX_RADAR_OVERLAP*sizeof(int8_t)); 279 if (!(dfs->dfs_ftindextable[n])) 280 goto bad2; 281 } 282 283 dfs->dfs_use_nol = 1; 284 285 /* Init the cached extension channel busy for false alarm reduction */ 286 dfs->dfs_rinfo.ext_chan_busy_ts = lmac_get_tsf64(dfs->dfs_pdev_obj); 287 dfs->dfs_rinfo.dfs_ext_chan_busy = 0; 288 /* Init the Bin5 chirping related data */ 289 dfs->dfs_rinfo.dfs_bin5_chirp_ts = dfs->dfs_rinfo.ext_chan_busy_ts; 290 dfs->dfs_rinfo.dfs_last_bin5_dur = MAX_BIN5_DUR; 291 dfs->dfs_b5radars = NULL; 292 293 /* 294 * If dfs_init_radar_filters() fails, we can abort here and 295 * reconfigure when the first valid channel + radar config 296 * is available. 297 */ 298 if (dfs_init_radar_filters(dfs, &radar_info)) { 299 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "Radar Filter Initialization Failed"); 300 return 1; 301 } 302 303 dfs->wlan_dfs_false_rssi_thres = RSSI_POSSIBLY_FALSE; 304 dfs->wlan_dfs_peak_mag = SEARCH_FFT_REPORT_PEAK_MAG_THRSH; 305 dfs->dfs_phyerr_freq_min = 0x7fffffff; 306 dfs->dfs_phyerr_freq_max = 0; 307 dfs->dfs_phyerr_queued_count = 0; 308 dfs->dfs_phyerr_w53_counter = 0; 309 dfs->dfs_pri_multiplier = 2; 310 dfs_get_radars(dfs); 311 312 return 0; 313 314 bad2: 315 qdf_mem_free(dfs->dfs_ftindextable); 316 dfs->dfs_ftindextable = NULL; 317 bad1: 318 for (n = 0; n < DFS_MAX_RADAR_TYPES; n++) { 319 if (dfs->dfs_radarf[n]) { 320 dfs_free_filter(dfs->dfs_radarf[n]); 321 qdf_mem_free(dfs->dfs_radarf[n]); 322 dfs->dfs_radarf[n] = NULL; 323 } 324 } 325 if (dfs->pulses) { 326 dfs_free_dfs_pulseline(dfs->pulses); 327 dfs->pulses = NULL; 328 } 329 if (dfs->events) { 330 dfs_free_dfs_events(dfs->events); 331 dfs->events = NULL; 332 } 333 334 return 1; 335 } 336 337 void dfs_main_timer_reset(struct wlan_dfs *dfs) 338 { 339 if (dfs->wlan_radar_tasksched) { 340 qdf_timer_sync_cancel(&dfs->wlan_dfs_task_timer); 341 dfs->wlan_radar_tasksched = 0; 342 } 343 } 344 345 void dfs_main_timer_detach(struct wlan_dfs *dfs) 346 { 347 qdf_timer_free(&dfs->wlan_dfs_task_timer); 348 dfs->wlan_radar_tasksched = 0; 349 } 350 351 #if defined(WLAN_DFS_PARTIAL_OFFLOAD) && defined(HOST_DFS_SPOOF_TEST) 352 void dfs_host_wait_timer_detach(struct wlan_dfs *dfs) 353 { 354 qdf_timer_free(&dfs->dfs_host_wait_timer); 355 } 356 #endif 357 358 void dfs_main_detach(struct wlan_dfs *dfs) 359 { 360 int n, empty; 361 362 if (!dfs->dfs_enable) { 363 dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, "Already detached"); 364 return; 365 } 366 367 dfs->dfs_enable = 0; 368 369 dfs_reset_radarq(dfs); 370 dfs_reset_alldelaylines(dfs); 371 372 if (dfs->pulses) { 373 dfs_free_dfs_pulseline(dfs->pulses); 374 dfs->pulses = NULL; 375 } 376 377 for (n = 0; n < DFS_MAX_RADAR_TYPES; n++) { 378 if (dfs->dfs_radarf[n]) { 379 dfs_free_filter(dfs->dfs_radarf[n]); 380 qdf_mem_free(dfs->dfs_radarf[n]); 381 dfs->dfs_radarf[n] = NULL; 382 } 383 } 384 385 if (dfs->dfs_ftindextable) { 386 for (n = 0; n < DFS_NUM_FT_IDX_TBL_ROWS; n++) { 387 if (dfs->dfs_ftindextable[n]) { 388 qdf_mem_free(dfs->dfs_ftindextable[n]); 389 dfs->dfs_ftindextable[n] = NULL; 390 } 391 } 392 qdf_mem_free(dfs->dfs_ftindextable); 393 dfs->dfs_ftindextable = NULL; 394 dfs->wlan_dfs_isdfsregdomain = 0; 395 } 396 397 if (dfs->dfs_b5radars) { 398 qdf_mem_free(dfs->dfs_b5radars); 399 dfs->dfs_b5radars = NULL; 400 } 401 402 dfs_reset_ar(dfs); 403 404 WLAN_ARQ_LOCK(dfs); 405 empty = STAILQ_EMPTY(&(dfs->dfs_arq)); 406 WLAN_ARQ_UNLOCK(dfs); 407 if (!empty) 408 dfs_reset_arq(dfs); 409 410 if (dfs->events) { 411 dfs_free_dfs_events(dfs->events); 412 dfs->events = NULL; 413 } 414 415 WLAN_DFS_DATA_STRUCT_LOCK_DESTROY(dfs); 416 WLAN_DFSQ_LOCK_DESTROY(dfs); 417 WLAN_ARQ_LOCK_DESTROY(dfs); 418 WLAN_DFSEVENTQ_LOCK_DESTROY(dfs); 419 } 420