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