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