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