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