1 /*- 2 * SPDX-License-Identifier: ISC 3 * 4 * Copyright (c) 2010-2011 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 * $FreeBSD$ 19 */ 20 #include "opt_ah.h" 21 22 #include "ah.h" 23 #include "ah_internal.h" 24 #include "ah_devid.h" 25 #include "ah_desc.h" /* NB: for HAL_PHYERR* */ 26 27 #include "ar5416/ar5416.h" 28 #include "ar5416/ar5416reg.h" 29 #include "ar5416/ar5416phy.h" 30 31 #include "ah_eeprom_v14.h" /* for owl_get_ntxchains() */ 32 33 /* 34 * These are default parameters for the AR5416 and 35 * later 802.11n NICs. They simply enable some 36 * radar pulse event generation. 37 * 38 * These are very likely not valid for the AR5212 era 39 * NICs. 40 * 41 * Since these define signal sizing and threshold 42 * parameters, they may need changing based on the 43 * specific antenna and receive amplifier 44 * configuration. 45 */ 46 #define AR5416_DFS_FIRPWR -33 47 #define AR5416_DFS_RRSSI 20 48 #define AR5416_DFS_HEIGHT 10 49 #define AR5416_DFS_PRSSI 15 50 #define AR5416_DFS_INBAND 15 51 #define AR5416_DFS_RELPWR 8 52 #define AR5416_DFS_RELSTEP 12 53 #define AR5416_DFS_MAXLEN 255 54 55 HAL_BOOL 56 ar5416GetDfsDefaultThresh(struct ath_hal *ah, HAL_PHYERR_PARAM *pe) 57 { 58 59 /* 60 * These are general examples of the parameter values 61 * to use when configuring radar pulse detection for 62 * the AR5416, AR91xx, AR92xx NICs. They are only 63 * for testing and do require tuning depending upon the 64 * hardware and deployment specifics. 65 */ 66 pe->pe_firpwr = AR5416_DFS_FIRPWR; 67 pe->pe_rrssi = AR5416_DFS_RRSSI; 68 pe->pe_height = AR5416_DFS_HEIGHT; 69 pe->pe_prssi = AR5416_DFS_PRSSI; 70 pe->pe_inband = AR5416_DFS_INBAND; 71 pe->pe_relpwr = AR5416_DFS_RELPWR; 72 pe->pe_relstep = AR5416_DFS_RELSTEP; 73 pe->pe_maxlen = AR5416_DFS_MAXLEN; 74 75 return (AH_TRUE); 76 } 77 78 /* 79 * Get the radar parameter values and return them in the pe 80 * structure 81 */ 82 void 83 ar5416GetDfsThresh(struct ath_hal *ah, HAL_PHYERR_PARAM *pe) 84 { 85 uint32_t val, temp; 86 87 val = OS_REG_READ(ah, AR_PHY_RADAR_0); 88 89 temp = MS(val,AR_PHY_RADAR_0_FIRPWR); 90 temp |= 0xFFFFFF80; 91 pe->pe_firpwr = temp; 92 pe->pe_rrssi = MS(val, AR_PHY_RADAR_0_RRSSI); 93 pe->pe_height = MS(val, AR_PHY_RADAR_0_HEIGHT); 94 pe->pe_prssi = MS(val, AR_PHY_RADAR_0_PRSSI); 95 pe->pe_inband = MS(val, AR_PHY_RADAR_0_INBAND); 96 97 /* RADAR_1 values */ 98 val = OS_REG_READ(ah, AR_PHY_RADAR_1); 99 pe->pe_relpwr = MS(val, AR_PHY_RADAR_1_RELPWR_THRESH); 100 pe->pe_relstep = MS(val, AR_PHY_RADAR_1_RELSTEP_THRESH); 101 pe->pe_maxlen = MS(val, AR_PHY_RADAR_1_MAXLEN); 102 103 pe->pe_extchannel = !! (OS_REG_READ(ah, AR_PHY_RADAR_EXT) & 104 AR_PHY_RADAR_EXT_ENA); 105 106 pe->pe_usefir128 = !! (OS_REG_READ(ah, AR_PHY_RADAR_1) & 107 AR_PHY_RADAR_1_USE_FIR128); 108 pe->pe_blockradar = !! (OS_REG_READ(ah, AR_PHY_RADAR_1) & 109 AR_PHY_RADAR_1_BLOCK_CHECK); 110 pe->pe_enmaxrssi = !! (OS_REG_READ(ah, AR_PHY_RADAR_1) & 111 AR_PHY_RADAR_1_MAX_RRSSI); 112 pe->pe_enabled = !! 113 (OS_REG_READ(ah, AR_PHY_RADAR_0) & AR_PHY_RADAR_0_ENA); 114 pe->pe_enrelpwr = !! (OS_REG_READ(ah, AR_PHY_RADAR_1) & 115 AR_PHY_RADAR_1_RELPWR_ENA); 116 pe->pe_en_relstep_check = !! (OS_REG_READ(ah, AR_PHY_RADAR_1) & 117 AR_PHY_RADAR_1_RELSTEP_CHECK); 118 } 119 120 /* 121 * Enable radar detection and set the radar parameters per the 122 * values in pe 123 */ 124 void 125 ar5416EnableDfs(struct ath_hal *ah, HAL_PHYERR_PARAM *pe) 126 { 127 uint32_t val; 128 129 val = OS_REG_READ(ah, AR_PHY_RADAR_0); 130 131 if (pe->pe_firpwr != HAL_PHYERR_PARAM_NOVAL) { 132 val &= ~AR_PHY_RADAR_0_FIRPWR; 133 val |= SM(pe->pe_firpwr, AR_PHY_RADAR_0_FIRPWR); 134 } 135 if (pe->pe_rrssi != HAL_PHYERR_PARAM_NOVAL) { 136 val &= ~AR_PHY_RADAR_0_RRSSI; 137 val |= SM(pe->pe_rrssi, AR_PHY_RADAR_0_RRSSI); 138 } 139 if (pe->pe_height != HAL_PHYERR_PARAM_NOVAL) { 140 val &= ~AR_PHY_RADAR_0_HEIGHT; 141 val |= SM(pe->pe_height, AR_PHY_RADAR_0_HEIGHT); 142 } 143 if (pe->pe_prssi != HAL_PHYERR_PARAM_NOVAL) { 144 val &= ~AR_PHY_RADAR_0_PRSSI; 145 val |= SM(pe->pe_prssi, AR_PHY_RADAR_0_PRSSI); 146 } 147 if (pe->pe_inband != HAL_PHYERR_PARAM_NOVAL) { 148 val &= ~AR_PHY_RADAR_0_INBAND; 149 val |= SM(pe->pe_inband, AR_PHY_RADAR_0_INBAND); 150 } 151 152 /*Enable FFT data*/ 153 val |= AR_PHY_RADAR_0_FFT_ENA; 154 OS_REG_WRITE(ah, AR_PHY_RADAR_0, val); 155 156 /* Implicitly enable */ 157 if (pe->pe_enabled == 1) 158 OS_REG_SET_BIT(ah, AR_PHY_RADAR_0, AR_PHY_RADAR_0_ENA); 159 else if (pe->pe_enabled == 0) 160 OS_REG_CLR_BIT(ah, AR_PHY_RADAR_0, AR_PHY_RADAR_0_ENA); 161 162 if (pe->pe_usefir128 == 1) 163 OS_REG_SET_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_USE_FIR128); 164 else if (pe->pe_usefir128 == 0) 165 OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_USE_FIR128); 166 167 if (pe->pe_enmaxrssi == 1) 168 OS_REG_SET_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_MAX_RRSSI); 169 else if (pe->pe_enmaxrssi == 0) 170 OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_MAX_RRSSI); 171 172 if (pe->pe_blockradar == 1) 173 OS_REG_SET_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_BLOCK_CHECK); 174 else if (pe->pe_blockradar == 0) 175 OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_BLOCK_CHECK); 176 177 if (pe->pe_relstep != HAL_PHYERR_PARAM_NOVAL) { 178 val = OS_REG_READ(ah, AR_PHY_RADAR_1); 179 val &= ~AR_PHY_RADAR_1_RELSTEP_THRESH; 180 val |= SM(pe->pe_relstep, AR_PHY_RADAR_1_RELSTEP_THRESH); 181 OS_REG_WRITE(ah, AR_PHY_RADAR_1, val); 182 } 183 if (pe->pe_relpwr != HAL_PHYERR_PARAM_NOVAL) { 184 val = OS_REG_READ(ah, AR_PHY_RADAR_1); 185 val &= ~AR_PHY_RADAR_1_RELPWR_THRESH; 186 val |= SM(pe->pe_relpwr, AR_PHY_RADAR_1_RELPWR_THRESH); 187 OS_REG_WRITE(ah, AR_PHY_RADAR_1, val); 188 } 189 190 if (pe->pe_en_relstep_check == 1) 191 OS_REG_SET_BIT(ah, AR_PHY_RADAR_1, 192 AR_PHY_RADAR_1_RELSTEP_CHECK); 193 else if (pe->pe_en_relstep_check == 0) 194 OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1, 195 AR_PHY_RADAR_1_RELSTEP_CHECK); 196 197 if (pe->pe_enrelpwr == 1) 198 OS_REG_SET_BIT(ah, AR_PHY_RADAR_1, 199 AR_PHY_RADAR_1_RELPWR_ENA); 200 else if (pe->pe_enrelpwr == 0) 201 OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1, 202 AR_PHY_RADAR_1_RELPWR_ENA); 203 204 if (pe->pe_maxlen != HAL_PHYERR_PARAM_NOVAL) { 205 val = OS_REG_READ(ah, AR_PHY_RADAR_1); 206 val &= ~AR_PHY_RADAR_1_MAXLEN; 207 val |= SM(pe->pe_maxlen, AR_PHY_RADAR_1_MAXLEN); 208 OS_REG_WRITE(ah, AR_PHY_RADAR_1, val); 209 } 210 211 /* 212 * Enable HT/40 if the upper layer asks; 213 * it should check the channel is HT/40 and HAL_CAP_EXT_CHAN_DFS 214 * is available. 215 */ 216 if (pe->pe_extchannel == 1) 217 OS_REG_SET_BIT(ah, AR_PHY_RADAR_EXT, AR_PHY_RADAR_EXT_ENA); 218 else if (pe->pe_extchannel == 0) 219 OS_REG_CLR_BIT(ah, AR_PHY_RADAR_EXT, AR_PHY_RADAR_EXT_ENA); 220 } 221 222 /* 223 * Extract the radar event information from the given phy error. 224 * 225 * Returns AH_TRUE if the phy error was actually a phy error, 226 * AH_FALSE if the phy error wasn't a phy error. 227 */ 228 229 /* Flags for pulse_bw_info */ 230 #define PRI_CH_RADAR_FOUND 0x01 231 #define EXT_CH_RADAR_FOUND 0x02 232 #define EXT_CH_RADAR_EARLY_FOUND 0x04 233 234 HAL_BOOL 235 ar5416ProcessRadarEvent(struct ath_hal *ah, struct ath_rx_status *rxs, 236 uint64_t fulltsf, const char *buf, HAL_DFS_EVENT *event) 237 { 238 HAL_BOOL doDfsExtCh; 239 HAL_BOOL doDfsEnhanced; 240 HAL_BOOL doDfsCombinedRssi; 241 242 uint8_t rssi = 0, ext_rssi = 0; 243 uint8_t pulse_bw_info = 0, pulse_length_ext = 0, pulse_length_pri = 0; 244 uint32_t dur = 0; 245 int pri_found = 1, ext_found = 0; 246 int early_ext = 0; 247 int is_dc = 0; 248 uint16_t datalen; /* length from the RX status field */ 249 250 /* Check whether the given phy error is a radar event */ 251 if ((rxs->rs_phyerr != HAL_PHYERR_RADAR) && 252 (rxs->rs_phyerr != HAL_PHYERR_FALSE_RADAR_EXT)) { 253 return AH_FALSE; 254 } 255 256 /* Grab copies of the capabilities; just to make the code clearer */ 257 doDfsExtCh = AH_PRIVATE(ah)->ah_caps.halExtChanDfsSupport; 258 doDfsEnhanced = AH_PRIVATE(ah)->ah_caps.halEnhancedDfsSupport; 259 doDfsCombinedRssi = AH_PRIVATE(ah)->ah_caps.halUseCombinedRadarRssi; 260 261 datalen = rxs->rs_datalen; 262 263 /* If hardware supports it, use combined RSSI, else use chain 0 RSSI */ 264 if (doDfsCombinedRssi) 265 rssi = (uint8_t) rxs->rs_rssi; 266 else 267 rssi = (uint8_t) rxs->rs_rssi_ctl[0]; 268 269 /* Set this; but only use it if doDfsExtCh is set */ 270 ext_rssi = (uint8_t) rxs->rs_rssi_ext[0]; 271 272 /* Cap it at 0 if the RSSI is a negative number */ 273 if (rssi & 0x80) 274 rssi = 0; 275 276 if (ext_rssi & 0x80) 277 ext_rssi = 0; 278 279 /* 280 * Fetch the relevant data from the frame 281 */ 282 if (doDfsExtCh) { 283 if (datalen < 3) 284 return AH_FALSE; 285 286 /* Last three bytes of the frame are of interest */ 287 pulse_length_pri = *(buf + datalen - 3); 288 pulse_length_ext = *(buf + datalen - 2); 289 pulse_bw_info = *(buf + datalen - 1); 290 HALDEBUG(ah, HAL_DEBUG_DFS, "%s: rssi=%d, ext_rssi=%d, pulse_length_pri=%d," 291 " pulse_length_ext=%d, pulse_bw_info=%x\n", 292 __func__, rssi, ext_rssi, pulse_length_pri, pulse_length_ext, 293 pulse_bw_info); 294 } else { 295 /* The pulse width is byte 0 of the data */ 296 if (datalen >= 1) 297 dur = ((uint8_t) buf[0]) & 0xff; 298 else 299 dur = 0; 300 301 if (dur == 0 && rssi == 0) { 302 HALDEBUG(ah, HAL_DEBUG_DFS, "%s: dur and rssi are 0\n", __func__); 303 return AH_FALSE; 304 } 305 306 HALDEBUG(ah, HAL_DEBUG_DFS, "%s: rssi=%d, dur=%d\n", __func__, rssi, dur); 307 308 /* Single-channel only */ 309 pri_found = 1; 310 ext_found = 0; 311 } 312 313 /* 314 * If doing extended channel data, pulse_bw_info must 315 * have one of the flags set. 316 */ 317 if (doDfsExtCh && pulse_bw_info == 0x0) 318 return AH_FALSE; 319 320 /* 321 * If the extended channel data is available, calculate 322 * which to pay attention to. 323 */ 324 if (doDfsExtCh) { 325 /* If pulse is on DC, take the larger duration of the two */ 326 if ((pulse_bw_info & EXT_CH_RADAR_FOUND) && 327 (pulse_bw_info & PRI_CH_RADAR_FOUND)) { 328 is_dc = 1; 329 if (pulse_length_ext > pulse_length_pri) { 330 dur = pulse_length_ext; 331 pri_found = 0; 332 ext_found = 1; 333 } else { 334 dur = pulse_length_pri; 335 pri_found = 1; 336 ext_found = 0; 337 } 338 } else if (pulse_bw_info & EXT_CH_RADAR_EARLY_FOUND) { 339 dur = pulse_length_ext; 340 pri_found = 0; 341 ext_found = 1; 342 early_ext = 1; 343 } else if (pulse_bw_info & PRI_CH_RADAR_FOUND) { 344 dur = pulse_length_pri; 345 pri_found = 1; 346 ext_found = 0; 347 } else if (pulse_bw_info & EXT_CH_RADAR_FOUND) { 348 dur = pulse_length_ext; 349 pri_found = 0; 350 ext_found = 1; 351 } 352 353 } 354 355 /* 356 * For enhanced DFS (Merlin and later), pulse_bw_info has 357 * implications for selecting the correct RSSI value. 358 */ 359 if (doDfsEnhanced) { 360 switch (pulse_bw_info & 0x03) { 361 case 0: 362 /* No radar? */ 363 rssi = 0; 364 break; 365 case PRI_CH_RADAR_FOUND: 366 /* Radar in primary channel */ 367 /* Cannot use ctrl channel RSSI if ext channel is stronger */ 368 if (ext_rssi >= (rssi + 3)) { 369 rssi = 0; 370 } 371 break; 372 case EXT_CH_RADAR_FOUND: 373 /* Radar in extended channel */ 374 /* Cannot use ext channel RSSI if ctrl channel is stronger */ 375 if (rssi >= (ext_rssi + 12)) { 376 rssi = 0; 377 } else { 378 rssi = ext_rssi; 379 } 380 break; 381 case (PRI_CH_RADAR_FOUND | EXT_CH_RADAR_FOUND): 382 /* When both are present, use stronger one */ 383 if (rssi < ext_rssi) 384 rssi = ext_rssi; 385 break; 386 } 387 } 388 389 /* 390 * If not doing enhanced DFS, choose the ext channel if 391 * it is stronger than the main channel 392 */ 393 if (doDfsExtCh && !doDfsEnhanced) { 394 if ((ext_rssi > rssi) && (ext_rssi < 128)) 395 rssi = ext_rssi; 396 } 397 398 /* 399 * XXX what happens if the above code decides the RSSI 400 * XXX wasn't valid, an sets it to 0? 401 */ 402 403 /* 404 * Fill out dfs_event structure. 405 */ 406 event->re_full_ts = fulltsf; 407 event->re_ts = rxs->rs_tstamp; 408 event->re_rssi = rssi; 409 event->re_dur = dur; 410 411 event->re_flags = 0; 412 if (pri_found) 413 event->re_flags |= HAL_DFS_EVENT_PRICH; 414 if (ext_found) 415 event->re_flags |= HAL_DFS_EVENT_EXTCH; 416 if (early_ext) 417 event->re_flags |= HAL_DFS_EVENT_EXTEARLY; 418 if (is_dc) 419 event->re_flags |= HAL_DFS_EVENT_ISDC; 420 421 return AH_TRUE; 422 } 423 424 /* 425 * Return whether fast-clock is currently enabled for this 426 * channel. 427 */ 428 HAL_BOOL 429 ar5416IsFastClockEnabled(struct ath_hal *ah) 430 { 431 struct ath_hal_private *ahp = AH_PRIVATE(ah); 432 433 return IS_5GHZ_FAST_CLOCK_EN(ah, ahp->ah_curchan); 434 } 435