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