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