1 /*- 2 * Copyright (c) 2013 Adrian Chadd <adrian@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer, 10 * without modification. 11 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12 * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 13 * redistribution must be conditioned upon including a substantially 14 * similar Disclaimer requirement for further binary redistribution. 15 * 16 * NO WARRANTY 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 20 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 21 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 22 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 25 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 * THE POSSIBILITY OF SUCH DAMAGES. 28 * 29 * $FreeBSD$ 30 */ 31 #include <sys/cdefs.h> 32 __FBSDID("$FreeBSD$"); 33 34 /* 35 * This module handles LNA diversity for those chips which implement LNA 36 * mixing (AR9285/AR9485.) 37 */ 38 #include "opt_ath.h" 39 #include "opt_inet.h" 40 #include "opt_wlan.h" 41 42 #include <sys/param.h> 43 #include <sys/systm.h> 44 #include <sys/sysctl.h> 45 #include <sys/kernel.h> 46 #include <sys/lock.h> 47 #include <sys/malloc.h> 48 #include <sys/mutex.h> 49 #include <sys/errno.h> 50 51 #include <machine/bus.h> 52 #include <machine/resource.h> 53 #include <sys/bus.h> 54 55 #include <sys/socket.h> 56 57 #include <net/if.h> 58 #include <net/if_var.h> 59 #include <net/if_media.h> 60 #include <net/if_arp.h> 61 #include <net/ethernet.h> /* XXX for ether_sprintf */ 62 63 #include <net80211/ieee80211_var.h> 64 65 #include <net/bpf.h> 66 67 #ifdef INET 68 #include <netinet/in.h> 69 #include <netinet/if_ether.h> 70 #endif 71 72 #include <dev/ath/if_athvar.h> 73 #include <dev/ath/if_ath_debug.h> 74 #include <dev/ath/if_ath_lna_div.h> 75 76 /* Linux compability macros */ 77 /* 78 * XXX these don't handle rounding, underflow, overflow, wrapping! 79 */ 80 #define msecs_to_jiffies(a) ( (a) * hz / 1000 ) 81 82 /* 83 * Methods which are required 84 */ 85 86 /* 87 * Attach the LNA diversity to the given interface 88 */ 89 int 90 ath_lna_div_attach(struct ath_softc *sc) 91 { 92 struct if_ath_ant_comb_state *ss; 93 HAL_ANT_COMB_CONFIG div_ant_conf; 94 95 /* Only do this if diversity is enabled */ 96 if (! ath_hal_hasdivantcomb(sc->sc_ah)) 97 return (0); 98 99 ss = malloc(sizeof(struct if_ath_ant_comb_state), 100 M_TEMP, M_WAITOK | M_ZERO); 101 if (ss == NULL) { 102 device_printf(sc->sc_dev, "%s: failed to allocate\n", 103 __func__); 104 /* Don't fail at this point */ 105 return (0); 106 } 107 108 /* Fetch the hardware configuration */ 109 OS_MEMZERO(&div_ant_conf, sizeof(div_ant_conf)); 110 ath_hal_div_comb_conf_get(sc->sc_ah, &div_ant_conf); 111 112 /* Figure out what the hardware specific bits should be */ 113 if ((div_ant_conf.antdiv_configgroup == HAL_ANTDIV_CONFIG_GROUP_1) || 114 (div_ant_conf.antdiv_configgroup == HAL_ANTDIV_CONFIG_GROUP_2)) { 115 ss->lna1_lna2_delta = -9; 116 } else { 117 ss->lna1_lna2_delta = -3; 118 } 119 120 /* Let's flip this on */ 121 sc->sc_lna_div = ss; 122 sc->sc_dolnadiv = 1; 123 124 return (0); 125 } 126 127 /* 128 * Detach the LNA diversity state from the given interface 129 */ 130 int 131 ath_lna_div_detach(struct ath_softc *sc) 132 { 133 if (sc->sc_lna_div != NULL) { 134 free(sc->sc_lna_div, M_TEMP); 135 sc->sc_lna_div = NULL; 136 } 137 sc->sc_dolnadiv = 0; 138 return (0); 139 } 140 141 /* 142 * Enable LNA diversity on the current channel if it's required. 143 */ 144 int 145 ath_lna_div_enable(struct ath_softc *sc, const struct ieee80211_channel *chan) 146 { 147 148 return (0); 149 } 150 151 /* 152 * Handle ioctl requests from the diagnostic interface. 153 * 154 * The initial part of this code resembles ath_ioctl_diag(); 155 * it's likely a good idea to reduce duplication between 156 * these two routines. 157 */ 158 int 159 ath_lna_div_ioctl(struct ath_softc *sc, struct ath_diag *ad) 160 { 161 unsigned int id = ad->ad_id & ATH_DIAG_ID; 162 void *indata = NULL; 163 void *outdata = NULL; 164 u_int32_t insize = ad->ad_in_size; 165 u_int32_t outsize = ad->ad_out_size; 166 int error = 0; 167 // int val; 168 169 if (ad->ad_id & ATH_DIAG_IN) { 170 /* 171 * Copy in data. 172 */ 173 indata = malloc(insize, M_TEMP, M_NOWAIT); 174 if (indata == NULL) { 175 error = ENOMEM; 176 goto bad; 177 } 178 error = copyin(ad->ad_in_data, indata, insize); 179 if (error) 180 goto bad; 181 } 182 if (ad->ad_id & ATH_DIAG_DYN) { 183 /* 184 * Allocate a buffer for the results (otherwise the HAL 185 * returns a pointer to a buffer where we can read the 186 * results). Note that we depend on the HAL leaving this 187 * pointer for us to use below in reclaiming the buffer; 188 * may want to be more defensive. 189 */ 190 outdata = malloc(outsize, M_TEMP, M_NOWAIT); 191 if (outdata == NULL) { 192 error = ENOMEM; 193 goto bad; 194 } 195 } 196 switch (id) { 197 default: 198 error = EINVAL; 199 } 200 if (outsize < ad->ad_out_size) 201 ad->ad_out_size = outsize; 202 if (outdata && copyout(outdata, ad->ad_out_data, ad->ad_out_size)) 203 error = EFAULT; 204 bad: 205 if ((ad->ad_id & ATH_DIAG_IN) && indata != NULL) 206 free(indata, M_TEMP); 207 if ((ad->ad_id & ATH_DIAG_DYN) && outdata != NULL) 208 free(outdata, M_TEMP); 209 return (error); 210 } 211 212 static HAL_BOOL 213 ath_is_alt_ant_ratio_better(int alt_ratio, int maxdelta, int mindelta, 214 int main_rssi_avg, int alt_rssi_avg, int pkt_count) 215 { 216 return (((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) && 217 (alt_rssi_avg > main_rssi_avg + maxdelta)) || 218 (alt_rssi_avg > main_rssi_avg + mindelta)) && (pkt_count > 50); 219 } 220 221 static void 222 ath_lnaconf_alt_good_scan(struct if_ath_ant_comb_state *antcomb, 223 HAL_ANT_COMB_CONFIG *ant_conf, int main_rssi_avg) 224 { 225 antcomb->quick_scan_cnt = 0; 226 227 if (ant_conf->main_lna_conf == HAL_ANT_DIV_COMB_LNA2) 228 antcomb->rssi_lna2 = main_rssi_avg; 229 else if (ant_conf->main_lna_conf == HAL_ANT_DIV_COMB_LNA1) 230 antcomb->rssi_lna1 = main_rssi_avg; 231 232 switch ((ant_conf->main_lna_conf << 4) | ant_conf->alt_lna_conf) { 233 case (0x10): /* LNA2 A-B */ 234 antcomb->main_conf = HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2; 235 antcomb->first_quick_scan_conf = 236 HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2; 237 antcomb->second_quick_scan_conf = HAL_ANT_DIV_COMB_LNA1; 238 break; 239 case (0x20): /* LNA1 A-B */ 240 antcomb->main_conf = HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2; 241 antcomb->first_quick_scan_conf = 242 HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2; 243 antcomb->second_quick_scan_conf = HAL_ANT_DIV_COMB_LNA2; 244 break; 245 case (0x21): /* LNA1 LNA2 */ 246 antcomb->main_conf = HAL_ANT_DIV_COMB_LNA2; 247 antcomb->first_quick_scan_conf = 248 HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2; 249 antcomb->second_quick_scan_conf = 250 HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2; 251 break; 252 case (0x12): /* LNA2 LNA1 */ 253 antcomb->main_conf = HAL_ANT_DIV_COMB_LNA1; 254 antcomb->first_quick_scan_conf = 255 HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2; 256 antcomb->second_quick_scan_conf = 257 HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2; 258 break; 259 case (0x13): /* LNA2 A+B */ 260 antcomb->main_conf = HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2; 261 antcomb->first_quick_scan_conf = 262 HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2; 263 antcomb->second_quick_scan_conf = HAL_ANT_DIV_COMB_LNA1; 264 break; 265 case (0x23): /* LNA1 A+B */ 266 antcomb->main_conf = HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2; 267 antcomb->first_quick_scan_conf = 268 HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2; 269 antcomb->second_quick_scan_conf = HAL_ANT_DIV_COMB_LNA2; 270 break; 271 default: 272 break; 273 } 274 } 275 276 static void 277 ath_select_ant_div_from_quick_scan(struct if_ath_ant_comb_state *antcomb, 278 HAL_ANT_COMB_CONFIG *div_ant_conf, int main_rssi_avg, 279 int alt_rssi_avg, int alt_ratio) 280 { 281 /* alt_good */ 282 switch (antcomb->quick_scan_cnt) { 283 case 0: 284 /* set alt to main, and alt to first conf */ 285 div_ant_conf->main_lna_conf = antcomb->main_conf; 286 div_ant_conf->alt_lna_conf = antcomb->first_quick_scan_conf; 287 break; 288 case 1: 289 /* set alt to main, and alt to first conf */ 290 div_ant_conf->main_lna_conf = antcomb->main_conf; 291 div_ant_conf->alt_lna_conf = antcomb->second_quick_scan_conf; 292 antcomb->rssi_first = main_rssi_avg; 293 antcomb->rssi_second = alt_rssi_avg; 294 295 if (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA1) { 296 /* main is LNA1 */ 297 if (ath_is_alt_ant_ratio_better(alt_ratio, 298 ATH_ANT_DIV_COMB_LNA1_DELTA_HI, 299 ATH_ANT_DIV_COMB_LNA1_DELTA_LOW, 300 main_rssi_avg, alt_rssi_avg, 301 antcomb->total_pkt_count)) 302 antcomb->first_ratio = AH_TRUE; 303 else 304 antcomb->first_ratio = AH_FALSE; 305 } else if (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA2) { 306 if (ath_is_alt_ant_ratio_better(alt_ratio, 307 ATH_ANT_DIV_COMB_LNA1_DELTA_MID, 308 ATH_ANT_DIV_COMB_LNA1_DELTA_LOW, 309 main_rssi_avg, alt_rssi_avg, 310 antcomb->total_pkt_count)) 311 antcomb->first_ratio = AH_TRUE; 312 else 313 antcomb->first_ratio = AH_FALSE; 314 } else { 315 if ((((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) && 316 (alt_rssi_avg > main_rssi_avg + 317 ATH_ANT_DIV_COMB_LNA1_DELTA_HI)) || 318 (alt_rssi_avg > main_rssi_avg)) && 319 (antcomb->total_pkt_count > 50)) 320 antcomb->first_ratio = AH_TRUE; 321 else 322 antcomb->first_ratio = AH_FALSE; 323 } 324 break; 325 case 2: 326 antcomb->alt_good = AH_FALSE; 327 antcomb->scan_not_start = AH_FALSE; 328 antcomb->scan = AH_FALSE; 329 antcomb->rssi_first = main_rssi_avg; 330 antcomb->rssi_third = alt_rssi_avg; 331 332 if (antcomb->second_quick_scan_conf == HAL_ANT_DIV_COMB_LNA1) 333 antcomb->rssi_lna1 = alt_rssi_avg; 334 else if (antcomb->second_quick_scan_conf == 335 HAL_ANT_DIV_COMB_LNA2) 336 antcomb->rssi_lna2 = alt_rssi_avg; 337 else if (antcomb->second_quick_scan_conf == 338 HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2) { 339 if (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA2) 340 antcomb->rssi_lna2 = main_rssi_avg; 341 else if (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA1) 342 antcomb->rssi_lna1 = main_rssi_avg; 343 } 344 345 if (antcomb->rssi_lna2 > antcomb->rssi_lna1 + 346 ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA) 347 div_ant_conf->main_lna_conf = HAL_ANT_DIV_COMB_LNA2; 348 else 349 div_ant_conf->main_lna_conf = HAL_ANT_DIV_COMB_LNA1; 350 351 if (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA1) { 352 if (ath_is_alt_ant_ratio_better(alt_ratio, 353 ATH_ANT_DIV_COMB_LNA1_DELTA_HI, 354 ATH_ANT_DIV_COMB_LNA1_DELTA_LOW, 355 main_rssi_avg, alt_rssi_avg, 356 antcomb->total_pkt_count)) 357 antcomb->second_ratio = AH_TRUE; 358 else 359 antcomb->second_ratio = AH_FALSE; 360 } else if (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA2) { 361 if (ath_is_alt_ant_ratio_better(alt_ratio, 362 ATH_ANT_DIV_COMB_LNA1_DELTA_MID, 363 ATH_ANT_DIV_COMB_LNA1_DELTA_LOW, 364 main_rssi_avg, alt_rssi_avg, 365 antcomb->total_pkt_count)) 366 antcomb->second_ratio = AH_TRUE; 367 else 368 antcomb->second_ratio = AH_FALSE; 369 } else { 370 if ((((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) && 371 (alt_rssi_avg > main_rssi_avg + 372 ATH_ANT_DIV_COMB_LNA1_DELTA_HI)) || 373 (alt_rssi_avg > main_rssi_avg)) && 374 (antcomb->total_pkt_count > 50)) 375 antcomb->second_ratio = AH_TRUE; 376 else 377 antcomb->second_ratio = AH_FALSE; 378 } 379 380 /* set alt to the conf with maximun ratio */ 381 if (antcomb->first_ratio && antcomb->second_ratio) { 382 if (antcomb->rssi_second > antcomb->rssi_third) { 383 /* first alt*/ 384 if ((antcomb->first_quick_scan_conf == 385 HAL_ANT_DIV_COMB_LNA1) || 386 (antcomb->first_quick_scan_conf == 387 HAL_ANT_DIV_COMB_LNA2)) 388 /* Set alt LNA1 or LNA2*/ 389 if (div_ant_conf->main_lna_conf == 390 HAL_ANT_DIV_COMB_LNA2) 391 div_ant_conf->alt_lna_conf = 392 HAL_ANT_DIV_COMB_LNA1; 393 else 394 div_ant_conf->alt_lna_conf = 395 HAL_ANT_DIV_COMB_LNA2; 396 else 397 /* Set alt to A+B or A-B */ 398 div_ant_conf->alt_lna_conf = 399 antcomb->first_quick_scan_conf; 400 } else if ((antcomb->second_quick_scan_conf == 401 HAL_ANT_DIV_COMB_LNA1) || 402 (antcomb->second_quick_scan_conf == 403 HAL_ANT_DIV_COMB_LNA2)) { 404 /* Set alt LNA1 or LNA2 */ 405 if (div_ant_conf->main_lna_conf == 406 HAL_ANT_DIV_COMB_LNA2) 407 div_ant_conf->alt_lna_conf = 408 HAL_ANT_DIV_COMB_LNA1; 409 else 410 div_ant_conf->alt_lna_conf = 411 HAL_ANT_DIV_COMB_LNA2; 412 } else { 413 /* Set alt to A+B or A-B */ 414 div_ant_conf->alt_lna_conf = 415 antcomb->second_quick_scan_conf; 416 } 417 } else if (antcomb->first_ratio) { 418 /* first alt */ 419 if ((antcomb->first_quick_scan_conf == 420 HAL_ANT_DIV_COMB_LNA1) || 421 (antcomb->first_quick_scan_conf == 422 HAL_ANT_DIV_COMB_LNA2)) 423 /* Set alt LNA1 or LNA2 */ 424 if (div_ant_conf->main_lna_conf == 425 HAL_ANT_DIV_COMB_LNA2) 426 div_ant_conf->alt_lna_conf = 427 HAL_ANT_DIV_COMB_LNA1; 428 else 429 div_ant_conf->alt_lna_conf = 430 HAL_ANT_DIV_COMB_LNA2; 431 else 432 /* Set alt to A+B or A-B */ 433 div_ant_conf->alt_lna_conf = 434 antcomb->first_quick_scan_conf; 435 } else if (antcomb->second_ratio) { 436 /* second alt */ 437 if ((antcomb->second_quick_scan_conf == 438 HAL_ANT_DIV_COMB_LNA1) || 439 (antcomb->second_quick_scan_conf == 440 HAL_ANT_DIV_COMB_LNA2)) 441 /* Set alt LNA1 or LNA2 */ 442 if (div_ant_conf->main_lna_conf == 443 HAL_ANT_DIV_COMB_LNA2) 444 div_ant_conf->alt_lna_conf = 445 HAL_ANT_DIV_COMB_LNA1; 446 else 447 div_ant_conf->alt_lna_conf = 448 HAL_ANT_DIV_COMB_LNA2; 449 else 450 /* Set alt to A+B or A-B */ 451 div_ant_conf->alt_lna_conf = 452 antcomb->second_quick_scan_conf; 453 } else { 454 /* main is largest */ 455 if ((antcomb->main_conf == HAL_ANT_DIV_COMB_LNA1) || 456 (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA2)) 457 /* Set alt LNA1 or LNA2 */ 458 if (div_ant_conf->main_lna_conf == 459 HAL_ANT_DIV_COMB_LNA2) 460 div_ant_conf->alt_lna_conf = 461 HAL_ANT_DIV_COMB_LNA1; 462 else 463 div_ant_conf->alt_lna_conf = 464 HAL_ANT_DIV_COMB_LNA2; 465 else 466 /* Set alt to A+B or A-B */ 467 div_ant_conf->alt_lna_conf = antcomb->main_conf; 468 } 469 break; 470 default: 471 break; 472 } 473 } 474 475 static void 476 ath_ant_adjust_fast_divbias(struct if_ath_ant_comb_state *antcomb, 477 int alt_ratio, int alt_ant_ratio_th, u_int config_group, 478 HAL_ANT_COMB_CONFIG *pdiv_ant_conf) 479 { 480 481 if (config_group == HAL_ANTDIV_CONFIG_GROUP_1) { 482 switch ((pdiv_ant_conf->main_lna_conf << 4) 483 | pdiv_ant_conf->alt_lna_conf) { 484 case (0x01): //A-B LNA2 485 pdiv_ant_conf->fast_div_bias = 0x1; 486 pdiv_ant_conf->main_gaintb = 0; 487 pdiv_ant_conf->alt_gaintb = 0; 488 break; 489 case (0x02): //A-B LNA1 490 pdiv_ant_conf->fast_div_bias = 0x1; 491 pdiv_ant_conf->main_gaintb = 0; 492 pdiv_ant_conf->alt_gaintb = 0; 493 break; 494 case (0x03): //A-B A+B 495 pdiv_ant_conf->fast_div_bias = 0x1; 496 pdiv_ant_conf->main_gaintb = 0; 497 pdiv_ant_conf->alt_gaintb = 0; 498 break; 499 case (0x10): //LNA2 A-B 500 if ((antcomb->scan == 0) 501 && (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) { 502 pdiv_ant_conf->fast_div_bias = 0x3f; 503 } else { 504 pdiv_ant_conf->fast_div_bias = 0x1; 505 } 506 pdiv_ant_conf->main_gaintb = 0; 507 pdiv_ant_conf->alt_gaintb = 0; 508 break; 509 case (0x12): //LNA2 LNA1 510 pdiv_ant_conf->fast_div_bias = 0x1; 511 pdiv_ant_conf->main_gaintb = 0; 512 pdiv_ant_conf->alt_gaintb = 0; 513 break; 514 case (0x13): //LNA2 A+B 515 if ((antcomb->scan == 0) 516 && (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) { 517 pdiv_ant_conf->fast_div_bias = 0x3f; 518 } else { 519 pdiv_ant_conf->fast_div_bias = 0x1; 520 } 521 pdiv_ant_conf->main_gaintb = 0; 522 pdiv_ant_conf->alt_gaintb = 0; 523 break; 524 case (0x20): //LNA1 A-B 525 if ((antcomb->scan == 0) 526 && (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) { 527 pdiv_ant_conf->fast_div_bias = 0x3f; 528 } else { 529 pdiv_ant_conf->fast_div_bias = 0x1; 530 } 531 pdiv_ant_conf->main_gaintb = 0; 532 pdiv_ant_conf->alt_gaintb = 0; 533 break; 534 case (0x21): //LNA1 LNA2 535 pdiv_ant_conf->fast_div_bias = 0x1; 536 pdiv_ant_conf->main_gaintb = 0; 537 pdiv_ant_conf->alt_gaintb = 0; 538 break; 539 case (0x23): //LNA1 A+B 540 if ((antcomb->scan == 0) 541 && (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) { 542 pdiv_ant_conf->fast_div_bias = 0x3f; 543 } else { 544 pdiv_ant_conf->fast_div_bias = 0x1; 545 } 546 pdiv_ant_conf->main_gaintb = 0; 547 pdiv_ant_conf->alt_gaintb = 0; 548 break; 549 case (0x30): //A+B A-B 550 pdiv_ant_conf->fast_div_bias = 0x1; 551 pdiv_ant_conf->main_gaintb = 0; 552 pdiv_ant_conf->alt_gaintb = 0; 553 break; 554 case (0x31): //A+B LNA2 555 pdiv_ant_conf->fast_div_bias = 0x1; 556 pdiv_ant_conf->main_gaintb = 0; 557 pdiv_ant_conf->alt_gaintb = 0; 558 break; 559 case (0x32): //A+B LNA1 560 pdiv_ant_conf->fast_div_bias = 0x1; 561 pdiv_ant_conf->main_gaintb = 0; 562 pdiv_ant_conf->alt_gaintb = 0; 563 break; 564 default: 565 break; 566 } 567 } else if (config_group == HAL_ANTDIV_CONFIG_GROUP_2) { 568 switch ((pdiv_ant_conf->main_lna_conf << 4) 569 | pdiv_ant_conf->alt_lna_conf) { 570 case (0x01): //A-B LNA2 571 pdiv_ant_conf->fast_div_bias = 0x1; 572 pdiv_ant_conf->main_gaintb = 0; 573 pdiv_ant_conf->alt_gaintb = 0; 574 break; 575 case (0x02): //A-B LNA1 576 pdiv_ant_conf->fast_div_bias = 0x1; 577 pdiv_ant_conf->main_gaintb = 0; 578 pdiv_ant_conf->alt_gaintb = 0; 579 break; 580 case (0x03): //A-B A+B 581 pdiv_ant_conf->fast_div_bias = 0x1; 582 pdiv_ant_conf->main_gaintb = 0; 583 pdiv_ant_conf->alt_gaintb = 0; 584 break; 585 case (0x10): //LNA2 A-B 586 if ((antcomb->scan == 0) 587 && (alt_ratio > alt_ant_ratio_th)) { 588 pdiv_ant_conf->fast_div_bias = 0x1; 589 } else { 590 pdiv_ant_conf->fast_div_bias = 0x2; 591 } 592 pdiv_ant_conf->main_gaintb = 0; 593 pdiv_ant_conf->alt_gaintb = 0; 594 break; 595 case (0x12): //LNA2 LNA1 596 pdiv_ant_conf->fast_div_bias = 0x1; 597 pdiv_ant_conf->main_gaintb = 0; 598 pdiv_ant_conf->alt_gaintb = 0; 599 break; 600 case (0x13): //LNA2 A+B 601 if ((antcomb->scan == 0) 602 && (alt_ratio > alt_ant_ratio_th)) { 603 pdiv_ant_conf->fast_div_bias = 0x1; 604 } else { 605 pdiv_ant_conf->fast_div_bias = 0x2; 606 } 607 pdiv_ant_conf->main_gaintb = 0; 608 pdiv_ant_conf->alt_gaintb = 0; 609 break; 610 case (0x20): //LNA1 A-B 611 if ((antcomb->scan == 0) 612 && (alt_ratio > alt_ant_ratio_th)) { 613 pdiv_ant_conf->fast_div_bias = 0x1; 614 } else { 615 pdiv_ant_conf->fast_div_bias = 0x2; 616 } 617 pdiv_ant_conf->main_gaintb = 0; 618 pdiv_ant_conf->alt_gaintb = 0; 619 break; 620 case (0x21): //LNA1 LNA2 621 pdiv_ant_conf->fast_div_bias = 0x1; 622 pdiv_ant_conf->main_gaintb = 0; 623 pdiv_ant_conf->alt_gaintb = 0; 624 break; 625 case (0x23): //LNA1 A+B 626 if ((antcomb->scan == 0) 627 && (alt_ratio > alt_ant_ratio_th)) { 628 pdiv_ant_conf->fast_div_bias = 0x1; 629 } else { 630 pdiv_ant_conf->fast_div_bias = 0x2; 631 } 632 pdiv_ant_conf->main_gaintb = 0; 633 pdiv_ant_conf->alt_gaintb = 0; 634 break; 635 case (0x30): //A+B A-B 636 pdiv_ant_conf->fast_div_bias = 0x1; 637 pdiv_ant_conf->main_gaintb = 0; 638 pdiv_ant_conf->alt_gaintb = 0; 639 break; 640 case (0x31): //A+B LNA2 641 pdiv_ant_conf->fast_div_bias = 0x1; 642 pdiv_ant_conf->main_gaintb = 0; 643 pdiv_ant_conf->alt_gaintb = 0; 644 break; 645 case (0x32): //A+B LNA1 646 pdiv_ant_conf->fast_div_bias = 0x1; 647 pdiv_ant_conf->main_gaintb = 0; 648 pdiv_ant_conf->alt_gaintb = 0; 649 break; 650 default: 651 break; 652 } 653 } else { /* DEFAULT_ANTDIV_CONFIG_GROUP */ 654 switch ((pdiv_ant_conf->main_lna_conf << 4) | pdiv_ant_conf->alt_lna_conf) { 655 case (0x01): //A-B LNA2 656 pdiv_ant_conf->fast_div_bias = 0x3b; 657 break; 658 case (0x02): //A-B LNA1 659 pdiv_ant_conf->fast_div_bias = 0x3d; 660 break; 661 case (0x03): //A-B A+B 662 pdiv_ant_conf->fast_div_bias = 0x1; 663 break; 664 case (0x10): //LNA2 A-B 665 pdiv_ant_conf->fast_div_bias = 0x7; 666 break; 667 case (0x12): //LNA2 LNA1 668 pdiv_ant_conf->fast_div_bias = 0x2; 669 break; 670 case (0x13): //LNA2 A+B 671 pdiv_ant_conf->fast_div_bias = 0x7; 672 break; 673 case (0x20): //LNA1 A-B 674 pdiv_ant_conf->fast_div_bias = 0x6; 675 break; 676 case (0x21): //LNA1 LNA2 677 pdiv_ant_conf->fast_div_bias = 0x0; 678 break; 679 case (0x23): //LNA1 A+B 680 pdiv_ant_conf->fast_div_bias = 0x6; 681 break; 682 case (0x30): //A+B A-B 683 pdiv_ant_conf->fast_div_bias = 0x1; 684 break; 685 case (0x31): //A+B LNA2 686 pdiv_ant_conf->fast_div_bias = 0x3b; 687 break; 688 case (0x32): //A+B LNA1 689 pdiv_ant_conf->fast_div_bias = 0x3d; 690 break; 691 default: 692 break; 693 } 694 } 695 } 696 697 /* 698 * AR9485/AR933x TODO: 699 * + Select a ratio based on whether RSSI is low or not; but I need 700 * to figure out what "low_rssi_th" is sourced from. 701 * + What's ath_ant_div_comb_alt_check() in the reference driver do? 702 * + .. and there's likely a bunch of other things to include in this. 703 */ 704 705 /* Antenna diversity and combining */ 706 void 707 ath_lna_rx_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs, 708 unsigned long ticks, int hz) 709 { 710 HAL_ANT_COMB_CONFIG div_ant_conf; 711 struct if_ath_ant_comb_state *antcomb = sc->sc_lna_div; 712 int alt_ratio = 0, alt_rssi_avg = 0, main_rssi_avg = 0, curr_alt_set; 713 int curr_main_set, curr_bias; 714 int main_rssi = rs->rs_rssi_ctl[0]; 715 int alt_rssi = rs->rs_rssi_ctl[1]; 716 int rx_ant_conf, main_ant_conf, alt_ant_conf; 717 HAL_BOOL short_scan = AH_FALSE; 718 719 rx_ant_conf = (rs->rs_rssi_ctl[2] >> 4) & ATH_ANT_RX_MASK; 720 main_ant_conf = (rs->rs_rssi_ctl[2] >> 2) & ATH_ANT_RX_MASK; 721 alt_ant_conf = (rs->rs_rssi_ctl[2] >> 0) & ATH_ANT_RX_MASK; 722 723 #if 0 724 DPRINTF(sc, ATH_DEBUG_DIVERSITY, 725 "%s: RSSI %d/%d, conf %x/%x, rxconf %x, LNA: %d; ANT: %d; " 726 "FastDiv: %d\n", 727 __func__, 728 main_rssi, 729 alt_rssi, 730 main_ant_conf, 731 alt_ant_conf, 732 rx_ant_conf, 733 !!(rs->rs_rssi_ctl[2] & 0x80), 734 !!(rs->rs_rssi_ctl[2] & 0x40), 735 !!(rs->rs_rssi_ext[2] & 0x40)); 736 #endif 737 738 /* 739 * If LNA diversity combining isn't enabled, don't run this. 740 */ 741 if (! sc->sc_dolnadiv) 742 return; 743 744 /* 745 * XXX this is ugly, but the HAL code attaches the 746 * LNA diversity to the TX antenna settings. 747 * I don't know why. 748 */ 749 if (sc->sc_txantenna != HAL_ANT_VARIABLE) 750 return; 751 752 /* Record packet only when alt_rssi is positive */ 753 if (main_rssi > 0 && alt_rssi > 0) { 754 antcomb->total_pkt_count++; 755 antcomb->main_total_rssi += main_rssi; 756 antcomb->alt_total_rssi += alt_rssi; 757 if (main_ant_conf == rx_ant_conf) 758 antcomb->main_recv_cnt++; 759 else 760 antcomb->alt_recv_cnt++; 761 } 762 763 /* Short scan check */ 764 if (antcomb->scan && antcomb->alt_good) { 765 if (time_after(ticks, antcomb->scan_start_time + 766 msecs_to_jiffies(ATH_ANT_DIV_COMB_SHORT_SCAN_INTR))) 767 short_scan = AH_TRUE; 768 else 769 if (antcomb->total_pkt_count == 770 ATH_ANT_DIV_COMB_SHORT_SCAN_PKTCOUNT) { 771 alt_ratio = ((antcomb->alt_recv_cnt * 100) / 772 antcomb->total_pkt_count); 773 if (alt_ratio < ATH_ANT_DIV_COMB_ALT_ANT_RATIO) 774 short_scan = AH_TRUE; 775 } 776 } 777 778 #if 0 779 DPRINTF(sc, ATH_DEBUG_DIVERSITY, 780 "%s: total pkt=%d, aggr=%d, short_scan=%d\n", 781 __func__, 782 antcomb->total_pkt_count, 783 !! (rs->rs_moreaggr), 784 !! (short_scan)); 785 #endif 786 787 if (((antcomb->total_pkt_count < ATH_ANT_DIV_COMB_MAX_PKTCOUNT) || 788 rs->rs_moreaggr) && !short_scan) 789 return; 790 791 if (antcomb->total_pkt_count) { 792 alt_ratio = ((antcomb->alt_recv_cnt * 100) / 793 antcomb->total_pkt_count); 794 main_rssi_avg = (antcomb->main_total_rssi / 795 antcomb->total_pkt_count); 796 alt_rssi_avg = (antcomb->alt_total_rssi / 797 antcomb->total_pkt_count); 798 } 799 800 OS_MEMZERO(&div_ant_conf, sizeof(div_ant_conf)); 801 802 ath_hal_div_comb_conf_get(sc->sc_ah, &div_ant_conf); 803 curr_alt_set = div_ant_conf.alt_lna_conf; 804 curr_main_set = div_ant_conf.main_lna_conf; 805 curr_bias = div_ant_conf.fast_div_bias; 806 807 antcomb->count++; 808 809 if (antcomb->count == ATH_ANT_DIV_COMB_MAX_COUNT) { 810 if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO) { 811 ath_lnaconf_alt_good_scan(antcomb, &div_ant_conf, 812 main_rssi_avg); 813 antcomb->alt_good = AH_TRUE; 814 } else { 815 antcomb->alt_good = AH_FALSE; 816 } 817 818 antcomb->count = 0; 819 antcomb->scan = AH_TRUE; 820 antcomb->scan_not_start = AH_TRUE; 821 } 822 823 if (!antcomb->scan) { 824 if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO) { 825 if (curr_alt_set == HAL_ANT_DIV_COMB_LNA2) { 826 /* Switch main and alt LNA */ 827 div_ant_conf.main_lna_conf = 828 HAL_ANT_DIV_COMB_LNA2; 829 div_ant_conf.alt_lna_conf = 830 HAL_ANT_DIV_COMB_LNA1; 831 } else if (curr_alt_set == HAL_ANT_DIV_COMB_LNA1) { 832 div_ant_conf.main_lna_conf = 833 HAL_ANT_DIV_COMB_LNA1; 834 div_ant_conf.alt_lna_conf = 835 HAL_ANT_DIV_COMB_LNA2; 836 } 837 838 goto div_comb_done; 839 } else if ((curr_alt_set != HAL_ANT_DIV_COMB_LNA1) && 840 (curr_alt_set != HAL_ANT_DIV_COMB_LNA2)) { 841 /* Set alt to another LNA */ 842 if (curr_main_set == HAL_ANT_DIV_COMB_LNA2) 843 div_ant_conf.alt_lna_conf = 844 HAL_ANT_DIV_COMB_LNA1; 845 else if (curr_main_set == HAL_ANT_DIV_COMB_LNA1) 846 div_ant_conf.alt_lna_conf = 847 HAL_ANT_DIV_COMB_LNA2; 848 849 goto div_comb_done; 850 } 851 852 if ((alt_rssi_avg < (main_rssi_avg + 853 antcomb->lna1_lna2_delta))) 854 goto div_comb_done; 855 } 856 857 if (!antcomb->scan_not_start) { 858 switch (curr_alt_set) { 859 case HAL_ANT_DIV_COMB_LNA2: 860 antcomb->rssi_lna2 = alt_rssi_avg; 861 antcomb->rssi_lna1 = main_rssi_avg; 862 antcomb->scan = AH_TRUE; 863 /* set to A+B */ 864 div_ant_conf.main_lna_conf = 865 HAL_ANT_DIV_COMB_LNA1; 866 div_ant_conf.alt_lna_conf = 867 HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2; 868 break; 869 case HAL_ANT_DIV_COMB_LNA1: 870 antcomb->rssi_lna1 = alt_rssi_avg; 871 antcomb->rssi_lna2 = main_rssi_avg; 872 antcomb->scan = AH_TRUE; 873 /* set to A+B */ 874 div_ant_conf.main_lna_conf = HAL_ANT_DIV_COMB_LNA2; 875 div_ant_conf.alt_lna_conf = 876 HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2; 877 break; 878 case HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2: 879 antcomb->rssi_add = alt_rssi_avg; 880 antcomb->scan = AH_TRUE; 881 /* set to A-B */ 882 div_ant_conf.alt_lna_conf = 883 HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2; 884 break; 885 case HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2: 886 antcomb->rssi_sub = alt_rssi_avg; 887 antcomb->scan = AH_FALSE; 888 if (antcomb->rssi_lna2 > 889 (antcomb->rssi_lna1 + 890 ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)) { 891 /* use LNA2 as main LNA */ 892 if ((antcomb->rssi_add > antcomb->rssi_lna1) && 893 (antcomb->rssi_add > antcomb->rssi_sub)) { 894 /* set to A+B */ 895 div_ant_conf.main_lna_conf = 896 HAL_ANT_DIV_COMB_LNA2; 897 div_ant_conf.alt_lna_conf = 898 HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2; 899 } else if (antcomb->rssi_sub > 900 antcomb->rssi_lna1) { 901 /* set to A-B */ 902 div_ant_conf.main_lna_conf = 903 HAL_ANT_DIV_COMB_LNA2; 904 div_ant_conf.alt_lna_conf = 905 HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2; 906 } else { 907 /* set to LNA1 */ 908 div_ant_conf.main_lna_conf = 909 HAL_ANT_DIV_COMB_LNA2; 910 div_ant_conf.alt_lna_conf = 911 HAL_ANT_DIV_COMB_LNA1; 912 } 913 } else { 914 /* use LNA1 as main LNA */ 915 if ((antcomb->rssi_add > antcomb->rssi_lna2) && 916 (antcomb->rssi_add > antcomb->rssi_sub)) { 917 /* set to A+B */ 918 div_ant_conf.main_lna_conf = 919 HAL_ANT_DIV_COMB_LNA1; 920 div_ant_conf.alt_lna_conf = 921 HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2; 922 } else if (antcomb->rssi_sub > 923 antcomb->rssi_lna1) { 924 /* set to A-B */ 925 div_ant_conf.main_lna_conf = 926 HAL_ANT_DIV_COMB_LNA1; 927 div_ant_conf.alt_lna_conf = 928 HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2; 929 } else { 930 /* set to LNA2 */ 931 div_ant_conf.main_lna_conf = 932 HAL_ANT_DIV_COMB_LNA1; 933 div_ant_conf.alt_lna_conf = 934 HAL_ANT_DIV_COMB_LNA2; 935 } 936 } 937 break; 938 default: 939 break; 940 } 941 } else { 942 if (!antcomb->alt_good) { 943 antcomb->scan_not_start = AH_FALSE; 944 /* Set alt to another LNA */ 945 if (curr_main_set == HAL_ANT_DIV_COMB_LNA2) { 946 div_ant_conf.main_lna_conf = 947 HAL_ANT_DIV_COMB_LNA2; 948 div_ant_conf.alt_lna_conf = 949 HAL_ANT_DIV_COMB_LNA1; 950 } else if (curr_main_set == HAL_ANT_DIV_COMB_LNA1) { 951 div_ant_conf.main_lna_conf = 952 HAL_ANT_DIV_COMB_LNA1; 953 div_ant_conf.alt_lna_conf = 954 HAL_ANT_DIV_COMB_LNA2; 955 } 956 goto div_comb_done; 957 } 958 } 959 960 ath_select_ant_div_from_quick_scan(antcomb, &div_ant_conf, 961 main_rssi_avg, alt_rssi_avg, 962 alt_ratio); 963 964 antcomb->quick_scan_cnt++; 965 966 div_comb_done: 967 #if 0 968 ath_ant_div_conf_fast_divbias(&div_ant_conf); 969 #endif 970 971 ath_ant_adjust_fast_divbias(antcomb, 972 alt_ratio, 973 ATH_ANT_DIV_COMB_ALT_ANT_RATIO, 974 div_ant_conf.antdiv_configgroup, 975 &div_ant_conf); 976 977 ath_hal_div_comb_conf_set(sc->sc_ah, &div_ant_conf); 978 979 DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: total_pkt_count=%d\n", 980 __func__, antcomb->total_pkt_count); 981 982 DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: main_total_rssi=%d\n", 983 __func__, antcomb->main_total_rssi); 984 DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: alt_total_rssi=%d\n", 985 __func__, antcomb->alt_total_rssi); 986 987 DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: main_rssi_avg=%d\n", 988 __func__, main_rssi_avg); 989 DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: alt_alt_rssi_avg=%d\n", 990 __func__, alt_rssi_avg); 991 992 DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: main_recv_cnt=%d\n", 993 __func__, antcomb->main_recv_cnt); 994 DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: alt_recv_cnt=%d\n", 995 __func__, antcomb->alt_recv_cnt); 996 997 // if (curr_alt_set != div_ant_conf.alt_lna_conf) 998 DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: lna_conf: %x -> %x\n", 999 __func__, curr_alt_set, div_ant_conf.alt_lna_conf); 1000 // if (curr_main_set != div_ant_conf.main_lna_conf) 1001 DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: main_lna_conf: %x -> %x\n", 1002 __func__, curr_main_set, div_ant_conf.main_lna_conf); 1003 // if (curr_bias != div_ant_conf.fast_div_bias) 1004 DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: fast_div_bias: %x -> %x\n", 1005 __func__, curr_bias, div_ant_conf.fast_div_bias); 1006 1007 antcomb->scan_start_time = ticks; 1008 antcomb->total_pkt_count = 0; 1009 antcomb->main_total_rssi = 0; 1010 antcomb->alt_total_rssi = 0; 1011 antcomb->main_recv_cnt = 0; 1012 antcomb->alt_recv_cnt = 0; 1013 } 1014 1015