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>
75 #include <dev/ath/if_ath_debug.h>
76 #include <dev/ath/if_ath_lna_div.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 */
91 int
92 ath_lna_div_attach(struct ath_softc *sc)
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 */
98 if (! ath_hal_hasdivantcomb(sc->sc_ah))
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) ||
116 (div_ant_conf.antdiv_configgroup == HAL_ANTDIV_CONFIG_GROUP_2)) {
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 */
132 int
133 ath_lna_div_detach(struct ath_softc *sc)
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 */
146 int
147 ath_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 */
160 int
161 ath_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;
207 bad:
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 */
219 static HAL_BOOL
220 ath_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
228 static void
229 ath_lnaconf_alt_good_scan(struct if_ath_ant_comb_state *antcomb,
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 */
241 antcomb->main_conf = HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2;
242 antcomb->first_quick_scan_conf =
243 HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2;
244 antcomb->second_quick_scan_conf = HAL_ANT_DIV_COMB_LNA1;
245 break;
246 case (0x20): /* LNA1 A-B */
247 antcomb->main_conf = HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2;
248 antcomb->first_quick_scan_conf =
249 HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2;
250 antcomb->second_quick_scan_conf = HAL_ANT_DIV_COMB_LNA2;
251 break;
252 case (0x21): /* LNA1 LNA2 */
253 antcomb->main_conf = HAL_ANT_DIV_COMB_LNA2;
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 (0x12): /* LNA2 LNA1 */
260 antcomb->main_conf = HAL_ANT_DIV_COMB_LNA1;
261 antcomb->first_quick_scan_conf =
262 HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2;
263 antcomb->second_quick_scan_conf =
264 HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2;
265 break;
266 case (0x13): /* LNA2 A+B */
267 antcomb->main_conf = HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2;
268 antcomb->first_quick_scan_conf =
269 HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2;
270 antcomb->second_quick_scan_conf = HAL_ANT_DIV_COMB_LNA1;
271 break;
272 case (0x23): /* LNA1 A+B */
273 antcomb->main_conf = HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2;
274 antcomb->first_quick_scan_conf =
275 HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2;
276 antcomb->second_quick_scan_conf = HAL_ANT_DIV_COMB_LNA2;
277 break;
278 default:
279 break;
280 }
281 }
282
283 static void
284 ath_select_ant_div_from_quick_scan(struct if_ath_ant_comb_state *antcomb,
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,
305 ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
306 ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
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,
314 ATH_ANT_DIV_COMB_LNA1_DELTA_MID,
315 ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
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 +
324 ATH_ANT_DIV_COMB_LNA1_DELTA_HI)) ||
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
339 if (antcomb->second_quick_scan_conf == HAL_ANT_DIV_COMB_LNA1)
340 antcomb->rssi_lna1 = alt_rssi_avg;
341 else if (antcomb->second_quick_scan_conf ==
342 HAL_ANT_DIV_COMB_LNA2)
343 antcomb->rssi_lna2 = alt_rssi_avg;
344 else if (antcomb->second_quick_scan_conf ==
345 HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2) {
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 +
353 ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)
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,
360 ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
361 ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
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,
369 ATH_ANT_DIV_COMB_LNA1_DELTA_MID,
370 ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
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 +
379 ATH_ANT_DIV_COMB_LNA1_DELTA_HI)) ||
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 ==
392 HAL_ANT_DIV_COMB_LNA1) ||
393 (antcomb->first_quick_scan_conf ==
394 HAL_ANT_DIV_COMB_LNA2))
395 /* Set alt LNA1 or LNA2*/
396 if (div_ant_conf->main_lna_conf ==
397 HAL_ANT_DIV_COMB_LNA2)
398 div_ant_conf->alt_lna_conf =
399 HAL_ANT_DIV_COMB_LNA1;
400 else
401 div_ant_conf->alt_lna_conf =
402 HAL_ANT_DIV_COMB_LNA2;
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 ==
408 HAL_ANT_DIV_COMB_LNA1) ||
409 (antcomb->second_quick_scan_conf ==
410 HAL_ANT_DIV_COMB_LNA2)) {
411 /* Set alt LNA1 or LNA2 */
412 if (div_ant_conf->main_lna_conf ==
413 HAL_ANT_DIV_COMB_LNA2)
414 div_ant_conf->alt_lna_conf =
415 HAL_ANT_DIV_COMB_LNA1;
416 else
417 div_ant_conf->alt_lna_conf =
418 HAL_ANT_DIV_COMB_LNA2;
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 ==
427 HAL_ANT_DIV_COMB_LNA1) ||
428 (antcomb->first_quick_scan_conf ==
429 HAL_ANT_DIV_COMB_LNA2))
430 /* Set alt LNA1 or LNA2 */
431 if (div_ant_conf->main_lna_conf ==
432 HAL_ANT_DIV_COMB_LNA2)
433 div_ant_conf->alt_lna_conf =
434 HAL_ANT_DIV_COMB_LNA1;
435 else
436 div_ant_conf->alt_lna_conf =
437 HAL_ANT_DIV_COMB_LNA2;
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 ==
445 HAL_ANT_DIV_COMB_LNA1) ||
446 (antcomb->second_quick_scan_conf ==
447 HAL_ANT_DIV_COMB_LNA2))
448 /* Set alt LNA1 or LNA2 */
449 if (div_ant_conf->main_lna_conf ==
450 HAL_ANT_DIV_COMB_LNA2)
451 div_ant_conf->alt_lna_conf =
452 HAL_ANT_DIV_COMB_LNA1;
453 else
454 div_ant_conf->alt_lna_conf =
455 HAL_ANT_DIV_COMB_LNA2;
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 ==
466 HAL_ANT_DIV_COMB_LNA2)
467 div_ant_conf->alt_lna_conf =
468 HAL_ANT_DIV_COMB_LNA1;
469 else
470 div_ant_conf->alt_lna_conf =
471 HAL_ANT_DIV_COMB_LNA2;
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
482 static void
483 ath_ant_adjust_fast_divbias(struct if_ath_ant_comb_state *antcomb,
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 */
713 void
714 ath_lna_rx_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs,
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 */
756 if (sc->sc_txantenna != HAL_ANT_VARIABLE)
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 +
773 msecs_to_jiffies(ATH_ANT_DIV_COMB_SHORT_SCAN_INTR)))
774 short_scan = AH_TRUE;
775 else
776 if (antcomb->total_pkt_count ==
777 ATH_ANT_DIV_COMB_SHORT_SCAN_PKTCOUNT) {
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
794 if (((antcomb->total_pkt_count < ATH_ANT_DIV_COMB_MAX_PKTCOUNT) ||
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 =
835 HAL_ANT_DIV_COMB_LNA2;
836 div_ant_conf.alt_lna_conf =
837 HAL_ANT_DIV_COMB_LNA1;
838 } else if (curr_alt_set == HAL_ANT_DIV_COMB_LNA1) {
839 div_ant_conf.main_lna_conf =
840 HAL_ANT_DIV_COMB_LNA1;
841 div_ant_conf.alt_lna_conf =
842 HAL_ANT_DIV_COMB_LNA2;
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 =
851 HAL_ANT_DIV_COMB_LNA1;
852 else if (curr_main_set == HAL_ANT_DIV_COMB_LNA1)
853 div_ant_conf.alt_lna_conf =
854 HAL_ANT_DIV_COMB_LNA2;
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) {
866 case HAL_ANT_DIV_COMB_LNA2:
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 =
872 HAL_ANT_DIV_COMB_LNA1;
873 div_ant_conf.alt_lna_conf =
874 HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2;
875 break;
876 case HAL_ANT_DIV_COMB_LNA1:
877 antcomb->rssi_lna1 = alt_rssi_avg;
878 antcomb->rssi_lna2 = main_rssi_avg;
879 antcomb->scan = AH_TRUE;
880 /* set to A+B */
881 div_ant_conf.main_lna_conf = HAL_ANT_DIV_COMB_LNA2;
882 div_ant_conf.alt_lna_conf =
883 HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2;
884 break;
885 case HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2:
886 antcomb->rssi_add = alt_rssi_avg;
887 antcomb->scan = AH_TRUE;
888 /* set to A-B */
889 div_ant_conf.alt_lna_conf =
890 HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2;
891 break;
892 case HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2:
893 antcomb->rssi_sub = alt_rssi_avg;
894 antcomb->scan = AH_FALSE;
895 if (antcomb->rssi_lna2 >
896 (antcomb->rssi_lna1 +
897 ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)) {
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 =
903 HAL_ANT_DIV_COMB_LNA2;
904 div_ant_conf.alt_lna_conf =
905 HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2;
906 } else if (antcomb->rssi_sub >
907 antcomb->rssi_lna1) {
908 /* set to A-B */
909 div_ant_conf.main_lna_conf =
910 HAL_ANT_DIV_COMB_LNA2;
911 div_ant_conf.alt_lna_conf =
912 HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2;
913 } else {
914 /* set to LNA1 */
915 div_ant_conf.main_lna_conf =
916 HAL_ANT_DIV_COMB_LNA2;
917 div_ant_conf.alt_lna_conf =
918 HAL_ANT_DIV_COMB_LNA1;
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 =
926 HAL_ANT_DIV_COMB_LNA1;
927 div_ant_conf.alt_lna_conf =
928 HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2;
929 } else if (antcomb->rssi_sub >
930 antcomb->rssi_lna1) {
931 /* set to A-B */
932 div_ant_conf.main_lna_conf =
933 HAL_ANT_DIV_COMB_LNA1;
934 div_ant_conf.alt_lna_conf =
935 HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2;
936 } else {
937 /* set to LNA2 */
938 div_ant_conf.main_lna_conf =
939 HAL_ANT_DIV_COMB_LNA1;
940 div_ant_conf.alt_lna_conf =
941 HAL_ANT_DIV_COMB_LNA2;
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 =
954 HAL_ANT_DIV_COMB_LNA2;
955 div_ant_conf.alt_lna_conf =
956 HAL_ANT_DIV_COMB_LNA1;
957 } else if (curr_main_set == HAL_ANT_DIV_COMB_LNA1) {
958 div_ant_conf.main_lna_conf =
959 HAL_ANT_DIV_COMB_LNA1;
960 div_ant_conf.alt_lna_conf =
961 HAL_ANT_DIV_COMB_LNA2;
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
973 div_comb_done:
974 #if 0
975 ath_ant_div_conf_fast_divbias(&div_ant_conf);
976 #endif
977
978 ath_ant_adjust_fast_divbias(antcomb,
979 alt_ratio,
980 ATH_ANT_DIV_COMB_ALT_ANT_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 }
Cache object: cfa3f3f83bb4985e7f1c0376cfde1240
|