2 * Copyright (c) 2013 Adrian Chadd <adrian@FreeBSD.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
31 #include <sys/cdefs.h>
34 * This module handles LNA diversity for those chips which implement LNA
35 * mixing (AR9285/AR9485.)
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/sysctl.h>
44 #include <sys/kernel.h>
46 #include <sys/malloc.h>
47 #include <sys/mutex.h>
48 #include <sys/errno.h>
50 #include <machine/bus.h>
51 #include <machine/resource.h>
54 #include <sys/socket.h>
57 #include <net/if_var.h>
58 #include <net/if_media.h>
59 #include <net/if_arp.h>
60 #include <net/ethernet.h> /* XXX for ether_sprintf */
62 #include <net80211/ieee80211_var.h>
67 #include <netinet/in.h>
68 #include <netinet/if_ether.h>
71 #include <dev/ath/if_athvar.h>
72 #include <dev/ath/if_ath_debug.h>
73 #include <dev/ath/if_ath_lna_div.h>
75 /* Linux compability macros */
77 * XXX these don't handle rounding, underflow, overflow, wrapping!
79 #define msecs_to_jiffies(a) ( (a) * hz / 1000 )
82 * Methods which are required
86 * Attach the LNA diversity to the given interface
89 ath_lna_div_attach(struct ath_softc *sc)
91 struct if_ath_ant_comb_state *ss;
92 HAL_ANT_COMB_CONFIG div_ant_conf;
94 /* Only do this if diversity is enabled */
95 if (! ath_hal_hasdivantcomb(sc->sc_ah))
98 ss = malloc(sizeof(struct if_ath_ant_comb_state),
99 M_TEMP, M_WAITOK | M_ZERO);
101 device_printf(sc->sc_dev, "%s: failed to allocate\n",
103 /* Don't fail at this point */
107 /* Fetch the hardware configuration */
108 OS_MEMZERO(&div_ant_conf, sizeof(div_ant_conf));
109 ath_hal_div_comb_conf_get(sc->sc_ah, &div_ant_conf);
111 /* Figure out what the hardware specific bits should be */
112 if ((div_ant_conf.antdiv_configgroup == HAL_ANTDIV_CONFIG_GROUP_1) ||
113 (div_ant_conf.antdiv_configgroup == HAL_ANTDIV_CONFIG_GROUP_2)) {
114 ss->lna1_lna2_delta = -9;
116 ss->lna1_lna2_delta = -3;
119 /* Let's flip this on */
127 * Detach the LNA diversity state from the given interface
130 ath_lna_div_detach(struct ath_softc *sc)
132 if (sc->sc_lna_div != NULL) {
133 free(sc->sc_lna_div, M_TEMP);
134 sc->sc_lna_div = NULL;
141 * Enable LNA diversity on the current channel if it's required.
144 ath_lna_div_enable(struct ath_softc *sc, const struct ieee80211_channel *chan)
151 * Handle ioctl requests from the diagnostic interface.
153 * The initial part of this code resembles ath_ioctl_diag();
154 * it's likely a good idea to reduce duplication between
155 * these two routines.
158 ath_lna_div_ioctl(struct ath_softc *sc, struct ath_diag *ad)
160 unsigned int id = ad->ad_id & ATH_DIAG_ID;
162 void *outdata = NULL;
163 u_int32_t insize = ad->ad_in_size;
164 u_int32_t outsize = ad->ad_out_size;
168 if (ad->ad_id & ATH_DIAG_IN) {
172 indata = malloc(insize, M_TEMP, M_NOWAIT);
173 if (indata == NULL) {
177 error = copyin(ad->ad_in_data, indata, insize);
181 if (ad->ad_id & ATH_DIAG_DYN) {
183 * Allocate a buffer for the results (otherwise the HAL
184 * returns a pointer to a buffer where we can read the
185 * results). Note that we depend on the HAL leaving this
186 * pointer for us to use below in reclaiming the buffer;
187 * may want to be more defensive.
189 outdata = malloc(outsize, M_TEMP, M_NOWAIT);
190 if (outdata == NULL) {
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))
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);
212 ath_is_alt_ant_ratio_better(int alt_ratio, int maxdelta, int mindelta,
213 int main_rssi_avg, int alt_rssi_avg, int pkt_count)
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);
221 ath_lnaconf_alt_good_scan(struct if_ath_ant_comb_state *antcomb,
222 HAL_ANT_COMB_CONFIG *ant_conf, int main_rssi_avg)
224 antcomb->quick_scan_cnt = 0;
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;
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;
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;
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;
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;
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;
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;
276 ath_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)
281 switch (antcomb->quick_scan_cnt) {
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;
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;
294 if (antcomb->main_conf == HAL_ANT_DIV_COMB_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;
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;
312 antcomb->first_ratio = AH_FALSE;
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;
321 antcomb->first_ratio = AH_FALSE;
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;
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;
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;
348 div_ant_conf->main_lna_conf = HAL_ANT_DIV_COMB_LNA1;
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;
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;
367 antcomb->second_ratio = AH_FALSE;
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;
376 antcomb->second_ratio = AH_FALSE;
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) {
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;
393 div_ant_conf->alt_lna_conf =
394 HAL_ANT_DIV_COMB_LNA2;
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;
409 div_ant_conf->alt_lna_conf =
410 HAL_ANT_DIV_COMB_LNA2;
412 /* Set alt to A+B or A-B */
413 div_ant_conf->alt_lna_conf =
414 antcomb->second_quick_scan_conf;
416 } else if (antcomb->first_ratio) {
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;
428 div_ant_conf->alt_lna_conf =
429 HAL_ANT_DIV_COMB_LNA2;
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) {
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;
446 div_ant_conf->alt_lna_conf =
447 HAL_ANT_DIV_COMB_LNA2;
449 /* Set alt to A+B or A-B */
450 div_ant_conf->alt_lna_conf =
451 antcomb->second_quick_scan_conf;
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;
462 div_ant_conf->alt_lna_conf =
463 HAL_ANT_DIV_COMB_LNA2;
465 /* Set alt to A+B or A-B */
466 div_ant_conf->alt_lna_conf = antcomb->main_conf;
475 ath_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)
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;
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;
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;
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;
503 pdiv_ant_conf->fast_div_bias = 0x1;
505 pdiv_ant_conf->main_gaintb = 0;
506 pdiv_ant_conf->alt_gaintb = 0;
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;
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;
518 pdiv_ant_conf->fast_div_bias = 0x1;
520 pdiv_ant_conf->main_gaintb = 0;
521 pdiv_ant_conf->alt_gaintb = 0;
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;
528 pdiv_ant_conf->fast_div_bias = 0x1;
530 pdiv_ant_conf->main_gaintb = 0;
531 pdiv_ant_conf->alt_gaintb = 0;
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;
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;
543 pdiv_ant_conf->fast_div_bias = 0x1;
545 pdiv_ant_conf->main_gaintb = 0;
546 pdiv_ant_conf->alt_gaintb = 0;
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;
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;
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;
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;
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;
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;
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;
589 pdiv_ant_conf->fast_div_bias = 0x2;
591 pdiv_ant_conf->main_gaintb = 0;
592 pdiv_ant_conf->alt_gaintb = 0;
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;
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;
604 pdiv_ant_conf->fast_div_bias = 0x2;
606 pdiv_ant_conf->main_gaintb = 0;
607 pdiv_ant_conf->alt_gaintb = 0;
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;
614 pdiv_ant_conf->fast_div_bias = 0x2;
616 pdiv_ant_conf->main_gaintb = 0;
617 pdiv_ant_conf->alt_gaintb = 0;
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;
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;
629 pdiv_ant_conf->fast_div_bias = 0x2;
631 pdiv_ant_conf->main_gaintb = 0;
632 pdiv_ant_conf->alt_gaintb = 0;
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;
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;
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;
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;
657 case (0x02): //A-B LNA1
658 pdiv_ant_conf->fast_div_bias = 0x3d;
660 case (0x03): //A-B A+B
661 pdiv_ant_conf->fast_div_bias = 0x1;
663 case (0x10): //LNA2 A-B
664 pdiv_ant_conf->fast_div_bias = 0x7;
666 case (0x12): //LNA2 LNA1
667 pdiv_ant_conf->fast_div_bias = 0x2;
669 case (0x13): //LNA2 A+B
670 pdiv_ant_conf->fast_div_bias = 0x7;
672 case (0x20): //LNA1 A-B
673 pdiv_ant_conf->fast_div_bias = 0x6;
675 case (0x21): //LNA1 LNA2
676 pdiv_ant_conf->fast_div_bias = 0x0;
678 case (0x23): //LNA1 A+B
679 pdiv_ant_conf->fast_div_bias = 0x6;
681 case (0x30): //A+B A-B
682 pdiv_ant_conf->fast_div_bias = 0x1;
684 case (0x31): //A+B LNA2
685 pdiv_ant_conf->fast_div_bias = 0x3b;
687 case (0x32): //A+B LNA1
688 pdiv_ant_conf->fast_div_bias = 0x3d;
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.
704 /* Antenna diversity and combining */
706 ath_lna_rx_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs,
707 unsigned long ticks, int hz)
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;
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;
723 DPRINTF(sc, ATH_DEBUG_DIVERSITY,
724 "%s: RSSI %d/%d, conf %x/%x, rxconf %x, LNA: %d; ANT: %d; "
732 !!(rs->rs_rssi_ctl[2] & 0x80),
733 !!(rs->rs_rssi_ctl[2] & 0x40),
734 !!(rs->rs_rssi_ext[2] & 0x40));
738 * If LNA diversity combining isn't enabled, don't run this.
740 if (! sc->sc_dolnadiv)
744 * XXX this is ugly, but the HAL code attaches the
745 * LNA diversity to the TX antenna settings.
748 if (sc->sc_txantenna != HAL_ANT_VARIABLE)
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++;
759 antcomb->alt_recv_cnt++;
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;
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;
778 DPRINTF(sc, ATH_DEBUG_DIVERSITY,
779 "%s: total pkt=%d, aggr=%d, short_scan=%d\n",
781 antcomb->total_pkt_count,
782 !! (rs->rs_moreaggr),
786 if (((antcomb->total_pkt_count < ATH_ANT_DIV_COMB_MAX_PKTCOUNT) ||
787 rs->rs_moreaggr) && !short_scan)
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);
799 OS_MEMZERO(&div_ant_conf, sizeof(div_ant_conf));
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;
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,
812 antcomb->alt_good = AH_TRUE;
814 antcomb->alt_good = AH_FALSE;
818 antcomb->scan = AH_TRUE;
819 antcomb->scan_not_start = AH_TRUE;
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;
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;
851 if ((alt_rssi_avg < (main_rssi_avg +
852 antcomb->lna1_lna2_delta)))
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;
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;
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;
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;
877 case HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2:
878 antcomb->rssi_add = alt_rssi_avg;
879 antcomb->scan = AH_TRUE;
881 div_ant_conf.alt_lna_conf =
882 HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2;
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)) {
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) {
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;
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;
913 /* use LNA1 as main LNA */
914 if ((antcomb->rssi_add > antcomb->rssi_lna2) &&
915 (antcomb->rssi_add > antcomb->rssi_sub)) {
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) {
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;
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;
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;
959 ath_select_ant_div_from_quick_scan(antcomb, &div_ant_conf,
960 main_rssi_avg, alt_rssi_avg,
963 antcomb->quick_scan_cnt++;
967 ath_ant_div_conf_fast_divbias(&div_ant_conf);
970 ath_ant_adjust_fast_divbias(antcomb,
972 ATH_ANT_DIV_COMB_ALT_ANT_RATIO,
973 div_ant_conf.antdiv_configgroup,
976 ath_hal_div_comb_conf_set(sc->sc_ah, &div_ant_conf);
978 DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: total_pkt_count=%d\n",
979 __func__, antcomb->total_pkt_count);
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);
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);
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);
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);
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;