1 /* 2 * Copyright (c) 2013, 2016-2018 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2002-2010, Atheros Communications Inc. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 /** 19 * DOC: This file contains initialization functions and functions that reset 20 * internal data structures. 21 */ 22 23 #include "../dfs.h" 24 #include "wlan_dfs_lmac_api.h" 25 26 /** 27 * dfs_reset_filtertype() - Reset filtertype. 28 * @ft: Pointer to dfs_filtertype structure. 29 */ 30 static inline void dfs_reset_filtertype( 31 struct dfs_filtertype *ft) 32 { 33 int j; 34 struct dfs_filter *rf; 35 struct dfs_delayline *dl; 36 37 for (j = 0; j < ft->ft_numfilters; j++) { 38 rf = &(ft->ft_filters[j]); 39 dl = &(rf->rf_dl); 40 if (dl != NULL) { 41 qdf_mem_zero(dl, sizeof(*dl)); 42 dl->dl_lastelem = (0xFFFFFFFF) & DFS_MAX_DL_MASK; 43 } 44 } 45 } 46 47 void dfs_reset_alldelaylines(struct wlan_dfs *dfs) 48 { 49 struct dfs_filtertype *ft = NULL; 50 struct dfs_pulseline *pl; 51 int i; 52 53 if (!dfs) { 54 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "dfs is NULL"); 55 return; 56 } 57 pl = dfs->pulses; 58 59 if (!pl) { 60 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "pl is NULL"); 61 return; 62 } 63 64 /* Reset the pulse log. */ 65 pl->pl_firstelem = pl->pl_numelems = 0; 66 pl->pl_lastelem = DFS_MAX_PULSE_BUFFER_MASK; 67 68 for (i = 0; i < DFS_MAX_RADAR_TYPES; i++) { 69 if (dfs->dfs_radarf[i] != NULL) { 70 ft = dfs->dfs_radarf[i]; 71 dfs_reset_filtertype(ft); 72 } 73 } 74 75 if (!(dfs->dfs_b5radars)) { 76 if (dfs->dfs_rinfo.rn_numbin5radars > 0) 77 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, 78 "null dfs_b5radars, numbin5radars=%d domain=%d", 79 dfs->dfs_rinfo.rn_numbin5radars, 80 dfs->dfsdomain); 81 return; 82 } 83 84 for (i = 0; i < dfs->dfs_rinfo.rn_numbin5radars; i++) { 85 qdf_mem_zero(&(dfs->dfs_b5radars[i].br_elems[0]), 86 sizeof(struct dfs_bin5elem) * DFS_MAX_B5_SIZE); 87 dfs->dfs_b5radars[i].br_firstelem = 0; 88 dfs->dfs_b5radars[i].br_numelems = 0; 89 dfs->dfs_b5radars[i].br_lastelem = 90 (0xFFFFFFFF) & DFS_MAX_B5_MASK; 91 } 92 } 93 94 void dfs_reset_delayline(struct dfs_delayline *dl) 95 { 96 qdf_mem_zero(&(dl->dl_elems[0]), sizeof(dl->dl_elems)); 97 dl->dl_lastelem = (0xFFFFFFFF) & DFS_MAX_DL_MASK; 98 } 99 100 void dfs_reset_filter_delaylines(struct dfs_filtertype *dft) 101 { 102 struct dfs_filter *df; 103 int i; 104 105 for (i = 0; i < DFS_MAX_NUM_RADAR_FILTERS; i++) { 106 df = &dft->ft_filters[i]; 107 dfs_reset_delayline(&(df->rf_dl)); 108 } 109 } 110 111 void dfs_reset_radarq(struct wlan_dfs *dfs) 112 { 113 struct dfs_event *event; 114 115 if (!dfs) { 116 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "dfs is NULL"); 117 return; 118 } 119 120 WLAN_DFSQ_LOCK(dfs); 121 WLAN_DFSEVENTQ_LOCK(dfs); 122 while (!STAILQ_EMPTY(&(dfs->dfs_radarq))) { 123 event = STAILQ_FIRST(&(dfs->dfs_radarq)); 124 STAILQ_REMOVE_HEAD(&(dfs->dfs_radarq), re_list); 125 qdf_mem_zero(event, sizeof(struct dfs_event)); 126 STAILQ_INSERT_TAIL(&(dfs->dfs_eventq), event, re_list); 127 } 128 WLAN_DFSEVENTQ_UNLOCK(dfs); 129 WLAN_DFSQ_UNLOCK(dfs); 130 } 131 132 /** 133 * dfs_fill_ft_index_table() - DFS fill ft index table. 134 * @dfs: Pointer to wlan_dfs structure. 135 * @i: Duration used as an index. 136 * 137 * Return: 1 if too many overlapping radar filters else 0. 138 */ 139 static inline bool dfs_fill_ft_index_table( 140 struct wlan_dfs *dfs, 141 int i) 142 { 143 uint32_t stop = 0, tableindex = 0; 144 145 while ((tableindex < DFS_MAX_RADAR_OVERLAP) && (!stop)) { 146 if ((dfs->dfs_ftindextable[i])[tableindex] == -1) 147 stop = 1; 148 else 149 tableindex++; 150 } 151 152 if (stop) { 153 (dfs->dfs_ftindextable[i])[tableindex] = 154 (int8_t)(dfs->dfs_rinfo.rn_ftindex); 155 } else { 156 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "Too many overlapping radar filters"); 157 return 1; 158 } 159 160 return 0; 161 } 162 163 /** 164 * dfs_fill_filter_type() - DFS fill filter type. 165 * @dfs: Pointer to wlan_dfs structure. 166 * @ft: Double pointer to dfs_filtertype structure. 167 * @dfs_radars: Pointer to dfs_pulse structure. 168 * @min_rssithresh: Minimum RSSI threshold. 169 * @max_pulsedur: Maximum RSSI threshold. 170 * @p: Index to dfs_pulse structure. 171 * 172 * Return: 1 if too many overlapping radar filters else 0. 173 */ 174 static inline bool dfs_fill_filter_type( 175 struct wlan_dfs *dfs, 176 struct dfs_filtertype **ft, 177 struct dfs_pulse *dfs_radars, 178 int32_t *min_rssithresh, 179 uint32_t *max_pulsedur, 180 int p) 181 { 182 int i; 183 184 /* No filter of the appropriate dur was found. */ 185 if ((dfs->dfs_rinfo.rn_ftindex + 1) > DFS_MAX_RADAR_TYPES) { 186 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "Too many filter types"); 187 return 1; 188 } 189 (*ft) = dfs->dfs_radarf[dfs->dfs_rinfo.rn_ftindex]; 190 (*ft)->ft_numfilters = 0; 191 (*ft)->ft_numpulses = dfs_radars[p].rp_numpulses; 192 (*ft)->ft_patterntype = dfs_radars[p].rp_patterntype; 193 (*ft)->ft_mindur = dfs_radars[p].rp_mindur; 194 (*ft)->ft_maxdur = dfs_radars[p].rp_maxdur; 195 (*ft)->ft_filterdur = dfs_radars[p].rp_pulsedur; 196 (*ft)->ft_rssithresh = dfs_radars[p].rp_rssithresh; 197 (*ft)->ft_rssimargin = dfs_radars[p].rp_rssimargin; 198 (*ft)->ft_minpri = 1000000; 199 200 if ((*ft)->ft_rssithresh < *min_rssithresh) 201 *min_rssithresh = (*ft)->ft_rssithresh; 202 203 if ((*ft)->ft_maxdur > *max_pulsedur) 204 *max_pulsedur = (*ft)->ft_maxdur; 205 206 for (i = (*ft)->ft_mindur; i <= (*ft)->ft_maxdur; i++) { 207 if (dfs_fill_ft_index_table(dfs, i)) 208 return 1; 209 } 210 211 dfs->dfs_rinfo.rn_ftindex++; 212 213 return 0; 214 } 215 216 int dfs_init_radar_filters(struct wlan_dfs *dfs, 217 struct wlan_dfs_radar_tab_info *radar_info) 218 { 219 struct dfs_filtertype *ft = NULL; 220 struct dfs_filter *rf = NULL; 221 struct dfs_pulse *dfs_radars; 222 struct dfs_bin5pulse *b5pulses = NULL; 223 uint32_t T, Tmax; 224 int32_t min_rssithresh = DFS_MAX_RSSI_VALUE; 225 uint32_t max_pulsedur = 0; 226 int numpulses, p, n, i; 227 int numradars = 0, numb5radars = 0; 228 int retval; 229 230 if (!dfs) { 231 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "dfs is NULL"); 232 return 1; 233 } 234 235 dfs_debug(dfs, WLAN_DEBUG_DFS, 236 "dfsdomain=%d, numradars=%d, numb5radars=%d", 237 radar_info->dfsdomain, 238 radar_info->numradars, radar_info->numb5radars); 239 240 /* Clear up the dfs domain flag first. */ 241 dfs->wlan_dfs_isdfsregdomain = 0; 242 243 /* 244 * If radar_info is NULL or dfsdomain is NULL, treat the 245 * rest of the radar configuration as suspect. 246 */ 247 if (!radar_info || radar_info->dfsdomain == 0) { 248 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "Unknown dfs domain %d", 249 dfs->dfsdomain); 250 /* Disable radar detection since we don't have a radar domain.*/ 251 dfs->dfs_proc_phyerr &= ~DFS_RADAR_EN; 252 dfs->dfs_proc_phyerr &= ~DFS_SECOND_SEGMENT_RADAR_EN; 253 return 0; 254 } 255 256 dfs->dfsdomain = radar_info->dfsdomain; 257 dfs_radars = radar_info->dfs_radars; 258 numradars = radar_info->numradars; 259 b5pulses = radar_info->b5pulses; 260 numb5radars = radar_info->numb5radars; 261 262 dfs->dfs_defaultparams = radar_info->dfs_defaultparams; 263 264 dfs->wlan_dfs_isdfsregdomain = 1; 265 dfs->dfs_rinfo.rn_ftindex = 0; 266 /* Clear filter type table. */ 267 for (n = 0; n < 256; n++) { 268 for (i = 0; i < DFS_MAX_RADAR_OVERLAP; i++) 269 (dfs->dfs_ftindextable[n])[i] = -1; 270 } 271 272 /* Now, initialize the radar filters. */ 273 for (p = 0; p < numradars; p++) { 274 ft = NULL; 275 for (n = 0; n < dfs->dfs_rinfo.rn_ftindex; n++) { 276 if ((dfs_radars[p].rp_pulsedur == 277 dfs->dfs_radarf[n]->ft_filterdur) && 278 (dfs_radars[p].rp_numpulses == 279 dfs->dfs_radarf[n]->ft_numpulses) && 280 (dfs_radars[p].rp_mindur == 281 dfs->dfs_radarf[n]->ft_mindur) && 282 (dfs_radars[p].rp_maxdur == 283 dfs->dfs_radarf[n]->ft_maxdur)) { 284 ft = dfs->dfs_radarf[n]; 285 break; 286 } 287 } 288 289 if (!ft) { 290 retval = dfs_fill_filter_type(dfs, &ft, dfs_radars, 291 &min_rssithresh, &max_pulsedur, p); 292 if (retval == 1) 293 goto bad4; 294 } 295 296 rf = &(ft->ft_filters[ft->ft_numfilters++]); 297 dfs_reset_delayline(&rf->rf_dl); 298 numpulses = dfs_radars[p].rp_numpulses; 299 300 rf->rf_numpulses = numpulses; 301 rf->rf_patterntype = dfs_radars[p].rp_patterntype; 302 rf->rf_sidx_spread = dfs_radars[p].rp_sidx_spread; 303 rf->rf_check_delta_peak = dfs_radars[p].rp_check_delta_peak; 304 rf->rf_pulseid = dfs_radars[p].rp_pulseid; 305 rf->rf_mindur = dfs_radars[p].rp_mindur; 306 rf->rf_maxdur = dfs_radars[p].rp_maxdur; 307 rf->rf_numpulses = dfs_radars[p].rp_numpulses; 308 rf->rf_ignore_pri_window = dfs_radars[p].rp_ignore_pri_window; 309 T = (100000000 / dfs_radars[p].rp_max_pulsefreq) - 310 100 * (dfs_radars[p].rp_meanoffset); 311 rf->rf_minpri = dfs_round((int32_t)T - 312 (100 * (dfs_radars[p].rp_pulsevar))); 313 Tmax = (100000000 / dfs_radars[p].rp_pulsefreq) - 314 100 * (dfs_radars[p].rp_meanoffset); 315 rf->rf_maxpri = dfs_round((int32_t)Tmax + 316 (100 * (dfs_radars[p].rp_pulsevar))); 317 318 if (rf->rf_minpri < ft->ft_minpri) 319 ft->ft_minpri = rf->rf_minpri; 320 321 rf->rf_fixed_pri_radar_pulse = ( 322 dfs_radars[p].rp_max_pulsefreq == 323 dfs_radars[p].rp_pulsefreq) ? 1 : 0; 324 rf->rf_threshold = dfs_radars[p].rp_threshold; 325 rf->rf_filterlen = rf->rf_maxpri * rf->rf_numpulses; 326 327 dfs_debug(dfs, WLAN_DEBUG_DFS2, 328 "minprf = %d maxprf = %d pulsevar = %d thresh=%d", 329 dfs_radars[p].rp_pulsefreq, 330 dfs_radars[p].rp_max_pulsefreq, 331 dfs_radars[p].rp_pulsevar, 332 rf->rf_threshold); 333 334 dfs_debug(dfs, WLAN_DEBUG_DFS2, 335 "minpri = %d maxpri = %d filterlen = %d filterID = %d", 336 rf->rf_minpri, rf->rf_maxpri, 337 rf->rf_filterlen, rf->rf_pulseid); 338 } 339 340 dfs_print_filters(dfs); 341 342 dfs->dfs_rinfo.rn_numbin5radars = numb5radars; 343 if (dfs->dfs_b5radars) { 344 qdf_mem_free(dfs->dfs_b5radars); 345 dfs->dfs_b5radars = NULL; 346 } 347 348 if (numb5radars) { 349 dfs->dfs_b5radars = (struct dfs_bin5radars *)qdf_mem_malloc( 350 numb5radars * sizeof(struct dfs_bin5radars)); 351 /* 352 * Malloc can return NULL if numb5radars is zero. But we still 353 * want to reset the delay lines. 354 */ 355 if (!(dfs->dfs_b5radars)) { 356 dfs_alert(dfs, WLAN_DEBUG_DFS_ALWAYS, 357 "cannot allocate memory for bin5 radars"); 358 goto bad4; 359 } 360 } 361 362 for (n = 0; n < numb5radars; n++) { 363 dfs->dfs_b5radars[n].br_pulse = b5pulses[n]; 364 dfs->dfs_b5radars[n].br_pulse.b5_timewindow *= 1000000; 365 if (dfs->dfs_b5radars[n].br_pulse.b5_rssithresh < 366 min_rssithresh) 367 min_rssithresh = 368 dfs->dfs_b5radars[n].br_pulse.b5_rssithresh; 369 370 if (dfs->dfs_b5radars[n].br_pulse.b5_maxdur > max_pulsedur) 371 max_pulsedur = dfs->dfs_b5radars[n].br_pulse.b5_maxdur; 372 } 373 dfs_reset_alldelaylines(dfs); 374 dfs_reset_radarq(dfs); 375 dfs->dfs_curchan_radindex = -1; 376 dfs->dfs_extchan_radindex = -1; 377 dfs->dfs_rinfo.rn_minrssithresh = min_rssithresh; 378 379 /* Convert durations to TSF ticks. */ 380 dfs->dfs_rinfo.rn_maxpulsedur = 381 dfs_round((int32_t)((max_pulsedur * 100/80) * 100)); 382 /* 383 * Relax the max pulse duration a little bit due to inaccuracy 384 * caused by chirping. 385 */ 386 dfs->dfs_rinfo.rn_maxpulsedur = dfs->dfs_rinfo.rn_maxpulsedur + 20; 387 388 dfs_debug(dfs, WLAN_DEBUG_DFS, "DFS min filter rssiThresh = %d", 389 min_rssithresh); 390 391 dfs_debug(dfs, WLAN_DEBUG_DFS, "DFS max pulse dur = %d ticks", 392 dfs->dfs_rinfo.rn_maxpulsedur); 393 394 return 0; 395 396 bad4: 397 return 1; 398 } 399 400 void dfs_clear_stats(struct wlan_dfs *dfs) 401 { 402 if (!dfs) 403 return; 404 405 qdf_mem_zero(&dfs->wlan_dfs_stats, sizeof(struct dfs_stats)); 406 dfs->wlan_dfs_stats.last_reset_tstamp = 407 lmac_get_tsf64(dfs->dfs_pdev_obj); 408 } 409