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