1 /* 2 * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2011, 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 #include "../dfs.h" 19 #include "../dfs_zero_cac.h" 20 #include "../dfs_filter_init.h" 21 #include "wlan_dfs_mlme_api.h" 22 #include "wlan_dfs_lmac_api.h" 23 #include "../dfs_partial_offload_radar.h" 24 #include "../dfs_internal.h" 25 26 void dfs_get_radars(struct wlan_dfs *dfs) 27 { 28 struct wlan_objmgr_psoc *psoc; 29 30 if (!dfs) { 31 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "dfs is NULL"); 32 return; 33 } 34 35 psoc = wlan_pdev_get_psoc(dfs->dfs_pdev_obj); 36 if (!psoc) { 37 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "psoc is NULL"); 38 return; 39 } 40 41 if (wlan_objmgr_psoc_get_dev_type(psoc) == WLAN_DEV_OL) { 42 /* For Partial offload */ 43 dfs_get_po_radars(dfs); 44 } 45 } 46 47 int dfs_radar_disable(struct wlan_dfs *dfs) 48 { 49 dfs->dfs_proc_phyerr &= ~DFS_AR_EN; 50 dfs->dfs_proc_phyerr &= ~DFS_RADAR_EN; 51 52 return 0; 53 } 54 55 void dfs_phyerr_param_copy(struct wlan_dfs_phyerr_param *dst, 56 struct wlan_dfs_phyerr_param *src) 57 { 58 qdf_mem_copy(dst, src, sizeof(*dst)); 59 } 60 61 #ifdef CONFIG_CHAN_FREQ_API 62 struct dfs_state *dfs_getchanstate(struct wlan_dfs *dfs, uint8_t *index, 63 int ext_chan_flag) 64 { 65 struct dfs_state *rs = NULL; 66 struct dfs_channel *ch, cmp_ch1; 67 int i; 68 QDF_STATUS err; 69 70 if (!dfs) { 71 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "dfs is NULL"); 72 return NULL; 73 } 74 ch = &cmp_ch1; 75 if (ext_chan_flag) { 76 err = dfs_mlme_get_extchan_for_freq( 77 dfs->dfs_pdev_obj, 78 &ch->dfs_ch_freq, 79 &ch->dfs_ch_flags, 80 &ch->dfs_ch_flagext, 81 &ch->dfs_ch_ieee, 82 &ch->dfs_ch_vhtop_ch_freq_seg1, 83 &ch->dfs_ch_vhtop_ch_freq_seg2, 84 &ch->dfs_ch_mhz_freq_seg1, 85 &ch->dfs_ch_mhz_freq_seg2); 86 87 if (err == QDF_STATUS_SUCCESS) { 88 dfs_debug(dfs, WLAN_DEBUG_DFS2, 89 "Extension channel freq = %u flags=0x%x", 90 ch->dfs_ch_freq, 91 ch->dfs_ch_flagext); 92 } else { 93 return NULL; 94 } 95 } else { 96 ch = dfs->dfs_curchan; 97 dfs_debug(dfs, WLAN_DEBUG_DFS2, 98 "Primary channel freq = %u flags=0x%x", 99 ch->dfs_ch_freq, ch->dfs_ch_flagext); 100 } 101 102 for (i = 0; i < DFS_NUM_RADAR_STATES; i++) { 103 if ((dfs->dfs_radar[i].rs_chan.dfs_ch_freq == 104 ch->dfs_ch_freq) && 105 (dfs->dfs_radar[i].rs_chan.dfs_ch_flags == 106 ch->dfs_ch_flags)) { 107 if (index) 108 *index = (uint8_t)i; 109 return &dfs->dfs_radar[i]; 110 } 111 } 112 /* No existing channel found, look for first free channel state entry.*/ 113 for (i = 0; i < DFS_NUM_RADAR_STATES; i++) { 114 if (dfs->dfs_radar[i].rs_chan.dfs_ch_freq == 0) { 115 rs = &dfs->dfs_radar[i]; 116 /* Found one, set channel info and default thresholds.*/ 117 rs->rs_chan = *ch; 118 119 /* Copy the parameters from the default set. */ 120 dfs_phyerr_param_copy(&rs->rs_param, 121 &dfs->dfs_defaultparams); 122 123 if (index) 124 *index = (uint8_t)i; 125 126 return rs; 127 } 128 } 129 dfs_debug(dfs, WLAN_DEBUG_DFS2, "No more radar states left."); 130 131 return NULL; 132 } 133 #endif 134 135 #ifdef CONFIG_CHAN_FREQ_API 136 void dfs_radar_enable(struct wlan_dfs *dfs, int no_cac, uint32_t opmode) 137 { 138 int is_ext_ch; 139 int is_fastclk = 0; 140 struct dfs_channel *exch, extchan; 141 QDF_STATUS err = QDF_STATUS_E_FAILURE; 142 143 if (!dfs) { 144 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "dfs is NULL"); 145 return; 146 } 147 148 is_ext_ch = WLAN_IS_CHAN_11N_HT40(dfs->dfs_curchan); 149 lmac_dfs_disable(dfs->dfs_pdev_obj, no_cac); 150 /* 151 * In all modes, if the primary is DFS then we have to 152 * enable radar detection. In HT80_80, we can have 153 * primary non-DFS 80MHz with extension 80MHz DFS. 154 */ 155 if ((WLAN_IS_CHAN_DFS(dfs->dfs_curchan) || 156 ((WLAN_IS_CHAN_11AC_VHT160(dfs->dfs_curchan) || 157 WLAN_IS_CHAN_11AC_VHT80_80(dfs->dfs_curchan)) && 158 WLAN_IS_CHAN_DFS_CFREQ2(dfs->dfs_curchan))) || 159 (dfs_is_precac_timer_running(dfs))) { 160 struct dfs_state *rs_pri = NULL, *rs_ext = NULL; 161 uint8_t index_pri, index_ext; 162 163 dfs->dfs_proc_phyerr |= DFS_AR_EN; 164 dfs->dfs_proc_phyerr |= DFS_RADAR_EN; 165 dfs->dfs_proc_phyerr |= DFS_SECOND_SEGMENT_RADAR_EN; 166 167 exch = &extchan; 168 if (is_ext_ch) { 169 err = dfs_mlme_get_extchan_for_freq 170 ( 171 dfs->dfs_pdev_obj, 172 &exch->dfs_ch_freq, 173 &exch->dfs_ch_flags, 174 &exch->dfs_ch_flagext, 175 &exch->dfs_ch_ieee, 176 &exch->dfs_ch_vhtop_ch_freq_seg1, 177 &exch->dfs_ch_vhtop_ch_freq_seg2, 178 &exch->dfs_ch_mhz_freq_seg1, 179 &exch->dfs_ch_mhz_freq_seg2); 180 } 181 dfs_reset_alldelaylines(dfs); 182 183 rs_pri = dfs_getchanstate(dfs, &index_pri, 0); 184 if (err == QDF_STATUS_SUCCESS) 185 rs_ext = dfs_getchanstate(dfs, &index_ext, 1); 186 187 if (rs_pri && ((err == QDF_STATUS_E_FAILURE) || (rs_ext))) { 188 struct wlan_dfs_phyerr_param pe; 189 190 qdf_mem_set(&pe, sizeof(pe), '\0'); 191 192 if (index_pri != dfs->dfs_curchan_radindex) 193 dfs_reset_alldelaylines(dfs); 194 195 dfs->dfs_curchan_radindex = (int16_t)index_pri; 196 197 if (rs_ext) 198 dfs->dfs_extchan_radindex = (int16_t)index_ext; 199 200 dfs_phyerr_param_copy(&pe, &rs_pri->rs_param); 201 dfs_debug(dfs, WLAN_DEBUG_DFS3, 202 "firpwr=%d, rssi=%d, height=%d, prssi=%d, inband=%d, relpwr=%d, relstep=%d, maxlen=%d", 203 pe.pe_firpwr, 204 pe.pe_rrssi, pe.pe_height, 205 pe.pe_prssi, pe.pe_inband, 206 pe.pe_relpwr, pe.pe_relstep, 207 pe.pe_maxlen); 208 209 lmac_dfs_enable(dfs->dfs_pdev_obj, &is_fastclk, 210 &pe, dfs->dfsdomain); 211 dfs_debug(dfs, WLAN_DEBUG_DFS, 212 "Enabled radar detection on channel %d", 213 dfs->dfs_curchan->dfs_ch_freq); 214 215 dfs->dur_multiplier = is_fastclk ? 216 DFS_FAST_CLOCK_MULTIPLIER : 217 DFS_NO_FAST_CLOCK_MULTIPLIER; 218 219 dfs_debug(dfs, WLAN_DEBUG_DFS3, 220 "duration multiplier is %d", 221 dfs->dur_multiplier); 222 } else 223 dfs_debug(dfs, WLAN_DEBUG_DFS, 224 "No more radar states left"); 225 } 226 } 227 #endif 228 229 int dfs_set_thresholds(struct wlan_dfs *dfs, const uint32_t threshtype, 230 const uint32_t value) 231 { 232 int16_t chanindex; 233 struct dfs_state *rs; 234 struct wlan_dfs_phyerr_param pe; 235 int is_fastclk = 0; 236 237 if (!dfs) { 238 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "dfs is NULL"); 239 return 0; 240 } 241 242 chanindex = dfs->dfs_curchan_radindex; 243 if ((chanindex < 0) || (chanindex >= DFS_NUM_RADAR_STATES)) { 244 dfs_debug(dfs, WLAN_DEBUG_DFS1, 245 "chanindex = %d, DFS_NUM_RADAR_STATES=%d", 246 chanindex, 247 DFS_NUM_RADAR_STATES); 248 return 0; 249 } 250 251 dfs_debug(dfs, WLAN_DEBUG_DFS, 252 "threshtype=%d, value=%d", threshtype, value); 253 254 wlan_dfs_phyerr_init_noval(&pe); 255 256 rs = &(dfs->dfs_radar[chanindex]); 257 switch (threshtype) { 258 case DFS_PARAM_FIRPWR: 259 rs->rs_param.pe_firpwr = (int32_t) value; 260 pe.pe_firpwr = value; 261 break; 262 case DFS_PARAM_RRSSI: 263 rs->rs_param.pe_rrssi = value; 264 pe.pe_rrssi = value; 265 break; 266 case DFS_PARAM_HEIGHT: 267 rs->rs_param.pe_height = value; 268 pe.pe_height = value; 269 break; 270 case DFS_PARAM_PRSSI: 271 rs->rs_param.pe_prssi = value; 272 pe.pe_prssi = value; 273 break; 274 case DFS_PARAM_INBAND: 275 rs->rs_param.pe_inband = value; 276 pe.pe_inband = value; 277 break; 278 /* 5413 specific */ 279 case DFS_PARAM_RELPWR: 280 rs->rs_param.pe_relpwr = value; 281 pe.pe_relpwr = value; 282 break; 283 case DFS_PARAM_RELSTEP: 284 rs->rs_param.pe_relstep = value; 285 pe.pe_relstep = value; 286 break; 287 case DFS_PARAM_MAXLEN: 288 rs->rs_param.pe_maxlen = value; 289 pe.pe_maxlen = value; 290 break; 291 default: 292 dfs_debug(dfs, WLAN_DEBUG_DFS1, 293 "unknown threshtype (%d)", threshtype); 294 break; 295 } 296 297 298 /* 299 * The driver layer dfs_enable routine is tasked with translating 300 * values from the global format to the per-device (HAL, offload) 301 * format. 302 */ 303 lmac_dfs_enable(dfs->dfs_pdev_obj, &is_fastclk, 304 &pe, dfs->dfsdomain); 305 306 return 1; 307 } 308 309 int dfs_get_thresholds(struct wlan_dfs *dfs, 310 struct wlan_dfs_phyerr_param *param) 311 { 312 lmac_dfs_get_thresholds(dfs->dfs_pdev_obj, param); 313 314 return 1; 315 } 316 317 uint16_t dfs_chan2freq(struct dfs_channel *chan) 318 { 319 if (!chan) 320 return 0; 321 322 return chan == WLAN_CHAN_ANYC ? WLAN_CHAN_ANY : chan->dfs_ch_freq; 323 } 324