xref: /freebsd/sys/dev/ath/if_ath_lna_div.c (revision 216ca2346fff3a53770769146cf8a59a3f8c7b95)
1*216ca234SAdrian Chadd /*-
2*216ca234SAdrian Chadd  * Copyright (c) 2013 Adrian Chadd <adrian@FreeBSD.org>
3*216ca234SAdrian Chadd  * All rights reserved.
4*216ca234SAdrian Chadd  *
5*216ca234SAdrian Chadd  * Redistribution and use in source and binary forms, with or without
6*216ca234SAdrian Chadd  * modification, are permitted provided that the following conditions
7*216ca234SAdrian Chadd  * are met:
8*216ca234SAdrian Chadd  * 1. Redistributions of source code must retain the above copyright
9*216ca234SAdrian Chadd  *    notice, this list of conditions and the following disclaimer,
10*216ca234SAdrian Chadd  *    without modification.
11*216ca234SAdrian Chadd  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12*216ca234SAdrian Chadd  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13*216ca234SAdrian Chadd  *    redistribution must be conditioned upon including a substantially
14*216ca234SAdrian Chadd  *    similar Disclaimer requirement for further binary redistribution.
15*216ca234SAdrian Chadd  *
16*216ca234SAdrian Chadd  * NO WARRANTY
17*216ca234SAdrian Chadd  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18*216ca234SAdrian Chadd  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19*216ca234SAdrian Chadd  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
20*216ca234SAdrian Chadd  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21*216ca234SAdrian Chadd  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
22*216ca234SAdrian Chadd  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23*216ca234SAdrian Chadd  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24*216ca234SAdrian Chadd  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25*216ca234SAdrian Chadd  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26*216ca234SAdrian Chadd  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27*216ca234SAdrian Chadd  * THE POSSIBILITY OF SUCH DAMAGES.
28*216ca234SAdrian Chadd  *
29*216ca234SAdrian Chadd  * $FreeBSD$
30*216ca234SAdrian Chadd  */
31*216ca234SAdrian Chadd #include <sys/cdefs.h>
32*216ca234SAdrian Chadd __FBSDID("$FreeBSD$");
33*216ca234SAdrian Chadd 
34*216ca234SAdrian Chadd /*
35*216ca234SAdrian Chadd  * This module handles LNA diversity for those chips which implement LNA
36*216ca234SAdrian Chadd  * mixing (AR9285/AR9485.)
37*216ca234SAdrian Chadd  */
38*216ca234SAdrian Chadd #include "opt_ath.h"
39*216ca234SAdrian Chadd #include "opt_inet.h"
40*216ca234SAdrian Chadd #include "opt_wlan.h"
41*216ca234SAdrian Chadd 
42*216ca234SAdrian Chadd #include <sys/param.h>
43*216ca234SAdrian Chadd #include <sys/systm.h>
44*216ca234SAdrian Chadd #include <sys/sysctl.h>
45*216ca234SAdrian Chadd #include <sys/kernel.h>
46*216ca234SAdrian Chadd #include <sys/lock.h>
47*216ca234SAdrian Chadd #include <sys/mutex.h>
48*216ca234SAdrian Chadd #include <sys/errno.h>
49*216ca234SAdrian Chadd 
50*216ca234SAdrian Chadd #include <machine/bus.h>
51*216ca234SAdrian Chadd #include <machine/resource.h>
52*216ca234SAdrian Chadd #include <sys/bus.h>
53*216ca234SAdrian Chadd 
54*216ca234SAdrian Chadd #include <sys/socket.h>
55*216ca234SAdrian Chadd 
56*216ca234SAdrian Chadd #include <net/if.h>
57*216ca234SAdrian Chadd #include <net/if_media.h>
58*216ca234SAdrian Chadd #include <net/if_arp.h>
59*216ca234SAdrian Chadd #include <net/ethernet.h>		/* XXX for ether_sprintf */
60*216ca234SAdrian Chadd 
61*216ca234SAdrian Chadd #include <net80211/ieee80211_var.h>
62*216ca234SAdrian Chadd 
63*216ca234SAdrian Chadd #include <net/bpf.h>
64*216ca234SAdrian Chadd 
65*216ca234SAdrian Chadd #ifdef INET
66*216ca234SAdrian Chadd #include <netinet/in.h>
67*216ca234SAdrian Chadd #include <netinet/if_ether.h>
68*216ca234SAdrian Chadd #endif
69*216ca234SAdrian Chadd 
70*216ca234SAdrian Chadd #include <dev/ath/if_athvar.h>
71*216ca234SAdrian Chadd #include <dev/ath/if_ath_debug.h>
72*216ca234SAdrian Chadd #include <dev/ath/if_ath_lna_div.h>
73*216ca234SAdrian Chadd 
74*216ca234SAdrian Chadd /* Linux compability macros */
75*216ca234SAdrian Chadd /*
76*216ca234SAdrian Chadd  * XXX these don't handle rounding, underflow, overflow, wrapping!
77*216ca234SAdrian Chadd  */
78*216ca234SAdrian Chadd #define	msecs_to_jiffies(a)		( (a) * hz / 1000 )
79*216ca234SAdrian Chadd 
80*216ca234SAdrian Chadd /*
81*216ca234SAdrian Chadd  * Methods which are required
82*216ca234SAdrian Chadd  */
83*216ca234SAdrian Chadd 
84*216ca234SAdrian Chadd /*
85*216ca234SAdrian Chadd  * Attach the LNA diversity to the given interface
86*216ca234SAdrian Chadd  */
87*216ca234SAdrian Chadd int
88*216ca234SAdrian Chadd ath_lna_div_attach(struct ath_softc *sc)
89*216ca234SAdrian Chadd {
90*216ca234SAdrian Chadd 	struct if_ath_ant_comb_state *ss;
91*216ca234SAdrian Chadd 
92*216ca234SAdrian Chadd 	/* Only do this if diversity is enabled */
93*216ca234SAdrian Chadd 	if (! ath_hal_hasdivantcomb(sc->sc_ah))
94*216ca234SAdrian Chadd 		return (0);
95*216ca234SAdrian Chadd 
96*216ca234SAdrian Chadd 	ss = malloc(sizeof(struct if_ath_ant_comb_state),
97*216ca234SAdrian Chadd 	    M_TEMP, M_WAITOK | M_ZERO);
98*216ca234SAdrian Chadd 	if (ss == NULL) {
99*216ca234SAdrian Chadd 		device_printf(sc->sc_dev, "%s: failed to allocate\n",
100*216ca234SAdrian Chadd 		    __func__);
101*216ca234SAdrian Chadd 		/* Don't fail at this point */
102*216ca234SAdrian Chadd 		return (0);
103*216ca234SAdrian Chadd 	}
104*216ca234SAdrian Chadd 
105*216ca234SAdrian Chadd 	/* Let's flip this on */
106*216ca234SAdrian Chadd 	sc->sc_lna_div = ss;
107*216ca234SAdrian Chadd 	sc->sc_dolnadiv = 1;
108*216ca234SAdrian Chadd 
109*216ca234SAdrian Chadd 	return (0);
110*216ca234SAdrian Chadd }
111*216ca234SAdrian Chadd 
112*216ca234SAdrian Chadd /*
113*216ca234SAdrian Chadd  * Detach the LNA diversity state from the given interface
114*216ca234SAdrian Chadd  */
115*216ca234SAdrian Chadd int
116*216ca234SAdrian Chadd ath_lna_div_detach(struct ath_softc *sc)
117*216ca234SAdrian Chadd {
118*216ca234SAdrian Chadd 	if (sc->sc_lna_div != NULL) {
119*216ca234SAdrian Chadd 		free(sc->sc_lna_div, M_TEMP);
120*216ca234SAdrian Chadd 		sc->sc_lna_div = NULL;
121*216ca234SAdrian Chadd 	}
122*216ca234SAdrian Chadd 	sc->sc_dolnadiv = 0;
123*216ca234SAdrian Chadd 	return (0);
124*216ca234SAdrian Chadd }
125*216ca234SAdrian Chadd 
126*216ca234SAdrian Chadd /*
127*216ca234SAdrian Chadd  * Enable LNA diversity on the current channel if it's required.
128*216ca234SAdrian Chadd  */
129*216ca234SAdrian Chadd int
130*216ca234SAdrian Chadd ath_lna_div_enable(struct ath_softc *sc, const struct ieee80211_channel *chan)
131*216ca234SAdrian Chadd {
132*216ca234SAdrian Chadd 
133*216ca234SAdrian Chadd 	return (0);
134*216ca234SAdrian Chadd }
135*216ca234SAdrian Chadd 
136*216ca234SAdrian Chadd /*
137*216ca234SAdrian Chadd  * Handle ioctl requests from the diagnostic interface.
138*216ca234SAdrian Chadd  *
139*216ca234SAdrian Chadd  * The initial part of this code resembles ath_ioctl_diag();
140*216ca234SAdrian Chadd  * it's likely a good idea to reduce duplication between
141*216ca234SAdrian Chadd  * these two routines.
142*216ca234SAdrian Chadd  */
143*216ca234SAdrian Chadd int
144*216ca234SAdrian Chadd ath_lna_div_ioctl(struct ath_softc *sc, struct ath_diag *ad)
145*216ca234SAdrian Chadd {
146*216ca234SAdrian Chadd 	unsigned int id = ad->ad_id & ATH_DIAG_ID;
147*216ca234SAdrian Chadd 	void *indata = NULL;
148*216ca234SAdrian Chadd 	void *outdata = NULL;
149*216ca234SAdrian Chadd 	u_int32_t insize = ad->ad_in_size;
150*216ca234SAdrian Chadd 	u_int32_t outsize = ad->ad_out_size;
151*216ca234SAdrian Chadd 	int error = 0;
152*216ca234SAdrian Chadd //	int val;
153*216ca234SAdrian Chadd 
154*216ca234SAdrian Chadd 	if (ad->ad_id & ATH_DIAG_IN) {
155*216ca234SAdrian Chadd 		/*
156*216ca234SAdrian Chadd 		 * Copy in data.
157*216ca234SAdrian Chadd 		 */
158*216ca234SAdrian Chadd 		indata = malloc(insize, M_TEMP, M_NOWAIT);
159*216ca234SAdrian Chadd 		if (indata == NULL) {
160*216ca234SAdrian Chadd 			error = ENOMEM;
161*216ca234SAdrian Chadd 			goto bad;
162*216ca234SAdrian Chadd 		}
163*216ca234SAdrian Chadd 		error = copyin(ad->ad_in_data, indata, insize);
164*216ca234SAdrian Chadd 		if (error)
165*216ca234SAdrian Chadd 			goto bad;
166*216ca234SAdrian Chadd 	}
167*216ca234SAdrian Chadd 	if (ad->ad_id & ATH_DIAG_DYN) {
168*216ca234SAdrian Chadd 		/*
169*216ca234SAdrian Chadd 		 * Allocate a buffer for the results (otherwise the HAL
170*216ca234SAdrian Chadd 		 * returns a pointer to a buffer where we can read the
171*216ca234SAdrian Chadd 		 * results).  Note that we depend on the HAL leaving this
172*216ca234SAdrian Chadd 		 * pointer for us to use below in reclaiming the buffer;
173*216ca234SAdrian Chadd 		 * may want to be more defensive.
174*216ca234SAdrian Chadd 		 */
175*216ca234SAdrian Chadd 		outdata = malloc(outsize, M_TEMP, M_NOWAIT);
176*216ca234SAdrian Chadd 		if (outdata == NULL) {
177*216ca234SAdrian Chadd 			error = ENOMEM;
178*216ca234SAdrian Chadd 			goto bad;
179*216ca234SAdrian Chadd 		}
180*216ca234SAdrian Chadd 	}
181*216ca234SAdrian Chadd 	switch (id) {
182*216ca234SAdrian Chadd 		default:
183*216ca234SAdrian Chadd 			error = EINVAL;
184*216ca234SAdrian Chadd 	}
185*216ca234SAdrian Chadd 	if (outsize < ad->ad_out_size)
186*216ca234SAdrian Chadd 		ad->ad_out_size = outsize;
187*216ca234SAdrian Chadd 	if (outdata && copyout(outdata, ad->ad_out_data, ad->ad_out_size))
188*216ca234SAdrian Chadd 		error = EFAULT;
189*216ca234SAdrian Chadd bad:
190*216ca234SAdrian Chadd 	if ((ad->ad_id & ATH_DIAG_IN) && indata != NULL)
191*216ca234SAdrian Chadd 		free(indata, M_TEMP);
192*216ca234SAdrian Chadd 	if ((ad->ad_id & ATH_DIAG_DYN) && outdata != NULL)
193*216ca234SAdrian Chadd 		free(outdata, M_TEMP);
194*216ca234SAdrian Chadd 	return (error);
195*216ca234SAdrian Chadd }
196*216ca234SAdrian Chadd 
197*216ca234SAdrian Chadd static HAL_BOOL
198*216ca234SAdrian Chadd ath_is_alt_ant_ratio_better(int alt_ratio, int maxdelta, int mindelta,
199*216ca234SAdrian Chadd     int main_rssi_avg, int alt_rssi_avg, int pkt_count)
200*216ca234SAdrian Chadd {
201*216ca234SAdrian Chadd 	return (((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
202*216ca234SAdrian Chadd 		(alt_rssi_avg > main_rssi_avg + maxdelta)) ||
203*216ca234SAdrian Chadd 		(alt_rssi_avg > main_rssi_avg + mindelta)) && (pkt_count > 50);
204*216ca234SAdrian Chadd }
205*216ca234SAdrian Chadd 
206*216ca234SAdrian Chadd static void
207*216ca234SAdrian Chadd ath_lnaconf_alt_good_scan(struct if_ath_ant_comb_state *antcomb,
208*216ca234SAdrian Chadd     HAL_ANT_COMB_CONFIG *ant_conf, int main_rssi_avg)
209*216ca234SAdrian Chadd {
210*216ca234SAdrian Chadd 	antcomb->quick_scan_cnt = 0;
211*216ca234SAdrian Chadd 
212*216ca234SAdrian Chadd 	if (ant_conf->main_lna_conf == HAL_ANT_DIV_COMB_LNA2)
213*216ca234SAdrian Chadd 		antcomb->rssi_lna2 = main_rssi_avg;
214*216ca234SAdrian Chadd 	else if (ant_conf->main_lna_conf == HAL_ANT_DIV_COMB_LNA1)
215*216ca234SAdrian Chadd 		antcomb->rssi_lna1 = main_rssi_avg;
216*216ca234SAdrian Chadd 
217*216ca234SAdrian Chadd 	switch ((ant_conf->main_lna_conf << 4) | ant_conf->alt_lna_conf) {
218*216ca234SAdrian Chadd 	case (0x10): /* LNA2 A-B */
219*216ca234SAdrian Chadd 		antcomb->main_conf = HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2;
220*216ca234SAdrian Chadd 		antcomb->first_quick_scan_conf =
221*216ca234SAdrian Chadd 			HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2;
222*216ca234SAdrian Chadd 		antcomb->second_quick_scan_conf = HAL_ANT_DIV_COMB_LNA1;
223*216ca234SAdrian Chadd 		break;
224*216ca234SAdrian Chadd 	case (0x20): /* LNA1 A-B */
225*216ca234SAdrian Chadd 		antcomb->main_conf = HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2;
226*216ca234SAdrian Chadd 		antcomb->first_quick_scan_conf =
227*216ca234SAdrian Chadd 			HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2;
228*216ca234SAdrian Chadd 		antcomb->second_quick_scan_conf = HAL_ANT_DIV_COMB_LNA2;
229*216ca234SAdrian Chadd 		break;
230*216ca234SAdrian Chadd 	case (0x21): /* LNA1 LNA2 */
231*216ca234SAdrian Chadd 		antcomb->main_conf = HAL_ANT_DIV_COMB_LNA2;
232*216ca234SAdrian Chadd 		antcomb->first_quick_scan_conf =
233*216ca234SAdrian Chadd 			HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2;
234*216ca234SAdrian Chadd 		antcomb->second_quick_scan_conf =
235*216ca234SAdrian Chadd 			HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2;
236*216ca234SAdrian Chadd 		break;
237*216ca234SAdrian Chadd 	case (0x12): /* LNA2 LNA1 */
238*216ca234SAdrian Chadd 		antcomb->main_conf = HAL_ANT_DIV_COMB_LNA1;
239*216ca234SAdrian Chadd 		antcomb->first_quick_scan_conf =
240*216ca234SAdrian Chadd 			HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2;
241*216ca234SAdrian Chadd 		antcomb->second_quick_scan_conf =
242*216ca234SAdrian Chadd 			HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2;
243*216ca234SAdrian Chadd 		break;
244*216ca234SAdrian Chadd 	case (0x13): /* LNA2 A+B */
245*216ca234SAdrian Chadd 		antcomb->main_conf = HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2;
246*216ca234SAdrian Chadd 		antcomb->first_quick_scan_conf =
247*216ca234SAdrian Chadd 			HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2;
248*216ca234SAdrian Chadd 		antcomb->second_quick_scan_conf = HAL_ANT_DIV_COMB_LNA1;
249*216ca234SAdrian Chadd 		break;
250*216ca234SAdrian Chadd 	case (0x23): /* LNA1 A+B */
251*216ca234SAdrian Chadd 		antcomb->main_conf = HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2;
252*216ca234SAdrian Chadd 		antcomb->first_quick_scan_conf =
253*216ca234SAdrian Chadd 			HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2;
254*216ca234SAdrian Chadd 		antcomb->second_quick_scan_conf = HAL_ANT_DIV_COMB_LNA2;
255*216ca234SAdrian Chadd 		break;
256*216ca234SAdrian Chadd 	default:
257*216ca234SAdrian Chadd 		break;
258*216ca234SAdrian Chadd 	}
259*216ca234SAdrian Chadd }
260*216ca234SAdrian Chadd 
261*216ca234SAdrian Chadd static void
262*216ca234SAdrian Chadd ath_select_ant_div_from_quick_scan(struct if_ath_ant_comb_state *antcomb,
263*216ca234SAdrian Chadd     HAL_ANT_COMB_CONFIG *div_ant_conf, int main_rssi_avg,
264*216ca234SAdrian Chadd     int alt_rssi_avg, int alt_ratio)
265*216ca234SAdrian Chadd {
266*216ca234SAdrian Chadd 	/* alt_good */
267*216ca234SAdrian Chadd 	switch (antcomb->quick_scan_cnt) {
268*216ca234SAdrian Chadd 	case 0:
269*216ca234SAdrian Chadd 		/* set alt to main, and alt to first conf */
270*216ca234SAdrian Chadd 		div_ant_conf->main_lna_conf = antcomb->main_conf;
271*216ca234SAdrian Chadd 		div_ant_conf->alt_lna_conf = antcomb->first_quick_scan_conf;
272*216ca234SAdrian Chadd 		break;
273*216ca234SAdrian Chadd 	case 1:
274*216ca234SAdrian Chadd 		/* set alt to main, and alt to first conf */
275*216ca234SAdrian Chadd 		div_ant_conf->main_lna_conf = antcomb->main_conf;
276*216ca234SAdrian Chadd 		div_ant_conf->alt_lna_conf = antcomb->second_quick_scan_conf;
277*216ca234SAdrian Chadd 		antcomb->rssi_first = main_rssi_avg;
278*216ca234SAdrian Chadd 		antcomb->rssi_second = alt_rssi_avg;
279*216ca234SAdrian Chadd 
280*216ca234SAdrian Chadd 		if (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA1) {
281*216ca234SAdrian Chadd 			/* main is LNA1 */
282*216ca234SAdrian Chadd 			if (ath_is_alt_ant_ratio_better(alt_ratio,
283*216ca234SAdrian Chadd 						ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
284*216ca234SAdrian Chadd 						ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
285*216ca234SAdrian Chadd 						main_rssi_avg, alt_rssi_avg,
286*216ca234SAdrian Chadd 						antcomb->total_pkt_count))
287*216ca234SAdrian Chadd 				antcomb->first_ratio = AH_TRUE;
288*216ca234SAdrian Chadd 			else
289*216ca234SAdrian Chadd 				antcomb->first_ratio = AH_FALSE;
290*216ca234SAdrian Chadd 		} else if (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA2) {
291*216ca234SAdrian Chadd 			if (ath_is_alt_ant_ratio_better(alt_ratio,
292*216ca234SAdrian Chadd 						ATH_ANT_DIV_COMB_LNA1_DELTA_MID,
293*216ca234SAdrian Chadd 						ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
294*216ca234SAdrian Chadd 						main_rssi_avg, alt_rssi_avg,
295*216ca234SAdrian Chadd 						antcomb->total_pkt_count))
296*216ca234SAdrian Chadd 				antcomb->first_ratio = AH_TRUE;
297*216ca234SAdrian Chadd 			else
298*216ca234SAdrian Chadd 				antcomb->first_ratio = AH_FALSE;
299*216ca234SAdrian Chadd 		} else {
300*216ca234SAdrian Chadd 			if ((((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
301*216ca234SAdrian Chadd 			    (alt_rssi_avg > main_rssi_avg +
302*216ca234SAdrian Chadd 			    ATH_ANT_DIV_COMB_LNA1_DELTA_HI)) ||
303*216ca234SAdrian Chadd 			    (alt_rssi_avg > main_rssi_avg)) &&
304*216ca234SAdrian Chadd 			    (antcomb->total_pkt_count > 50))
305*216ca234SAdrian Chadd 				antcomb->first_ratio = AH_TRUE;
306*216ca234SAdrian Chadd 			else
307*216ca234SAdrian Chadd 				antcomb->first_ratio = AH_FALSE;
308*216ca234SAdrian Chadd 		}
309*216ca234SAdrian Chadd 		break;
310*216ca234SAdrian Chadd 	case 2:
311*216ca234SAdrian Chadd 		antcomb->alt_good = AH_FALSE;
312*216ca234SAdrian Chadd 		antcomb->scan_not_start = AH_FALSE;
313*216ca234SAdrian Chadd 		antcomb->scan = AH_FALSE;
314*216ca234SAdrian Chadd 		antcomb->rssi_first = main_rssi_avg;
315*216ca234SAdrian Chadd 		antcomb->rssi_third = alt_rssi_avg;
316*216ca234SAdrian Chadd 
317*216ca234SAdrian Chadd 		if (antcomb->second_quick_scan_conf == HAL_ANT_DIV_COMB_LNA1)
318*216ca234SAdrian Chadd 			antcomb->rssi_lna1 = alt_rssi_avg;
319*216ca234SAdrian Chadd 		else if (antcomb->second_quick_scan_conf ==
320*216ca234SAdrian Chadd 			 HAL_ANT_DIV_COMB_LNA2)
321*216ca234SAdrian Chadd 			antcomb->rssi_lna2 = alt_rssi_avg;
322*216ca234SAdrian Chadd 		else if (antcomb->second_quick_scan_conf ==
323*216ca234SAdrian Chadd 			 HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2) {
324*216ca234SAdrian Chadd 			if (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA2)
325*216ca234SAdrian Chadd 				antcomb->rssi_lna2 = main_rssi_avg;
326*216ca234SAdrian Chadd 			else if (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA1)
327*216ca234SAdrian Chadd 				antcomb->rssi_lna1 = main_rssi_avg;
328*216ca234SAdrian Chadd 		}
329*216ca234SAdrian Chadd 
330*216ca234SAdrian Chadd 		if (antcomb->rssi_lna2 > antcomb->rssi_lna1 +
331*216ca234SAdrian Chadd 		    ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)
332*216ca234SAdrian Chadd 			div_ant_conf->main_lna_conf = HAL_ANT_DIV_COMB_LNA2;
333*216ca234SAdrian Chadd 		else
334*216ca234SAdrian Chadd 			div_ant_conf->main_lna_conf = HAL_ANT_DIV_COMB_LNA1;
335*216ca234SAdrian Chadd 
336*216ca234SAdrian Chadd 		if (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA1) {
337*216ca234SAdrian Chadd 			if (ath_is_alt_ant_ratio_better(alt_ratio,
338*216ca234SAdrian Chadd 						ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
339*216ca234SAdrian Chadd 						ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
340*216ca234SAdrian Chadd 						main_rssi_avg, alt_rssi_avg,
341*216ca234SAdrian Chadd 						antcomb->total_pkt_count))
342*216ca234SAdrian Chadd 				antcomb->second_ratio = AH_TRUE;
343*216ca234SAdrian Chadd 			else
344*216ca234SAdrian Chadd 				antcomb->second_ratio = AH_FALSE;
345*216ca234SAdrian Chadd 		} else if (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA2) {
346*216ca234SAdrian Chadd 			if (ath_is_alt_ant_ratio_better(alt_ratio,
347*216ca234SAdrian Chadd 						ATH_ANT_DIV_COMB_LNA1_DELTA_MID,
348*216ca234SAdrian Chadd 						ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
349*216ca234SAdrian Chadd 						main_rssi_avg, alt_rssi_avg,
350*216ca234SAdrian Chadd 						antcomb->total_pkt_count))
351*216ca234SAdrian Chadd 				antcomb->second_ratio = AH_TRUE;
352*216ca234SAdrian Chadd 			else
353*216ca234SAdrian Chadd 				antcomb->second_ratio = AH_FALSE;
354*216ca234SAdrian Chadd 		} else {
355*216ca234SAdrian Chadd 			if ((((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
356*216ca234SAdrian Chadd 			    (alt_rssi_avg > main_rssi_avg +
357*216ca234SAdrian Chadd 			    ATH_ANT_DIV_COMB_LNA1_DELTA_HI)) ||
358*216ca234SAdrian Chadd 			    (alt_rssi_avg > main_rssi_avg)) &&
359*216ca234SAdrian Chadd 			    (antcomb->total_pkt_count > 50))
360*216ca234SAdrian Chadd 				antcomb->second_ratio = AH_TRUE;
361*216ca234SAdrian Chadd 			else
362*216ca234SAdrian Chadd 				antcomb->second_ratio = AH_FALSE;
363*216ca234SAdrian Chadd 		}
364*216ca234SAdrian Chadd 
365*216ca234SAdrian Chadd 		/* set alt to the conf with maximun ratio */
366*216ca234SAdrian Chadd 		if (antcomb->first_ratio && antcomb->second_ratio) {
367*216ca234SAdrian Chadd 			if (antcomb->rssi_second > antcomb->rssi_third) {
368*216ca234SAdrian Chadd 				/* first alt*/
369*216ca234SAdrian Chadd 				if ((antcomb->first_quick_scan_conf ==
370*216ca234SAdrian Chadd 				    HAL_ANT_DIV_COMB_LNA1) ||
371*216ca234SAdrian Chadd 				    (antcomb->first_quick_scan_conf ==
372*216ca234SAdrian Chadd 				    HAL_ANT_DIV_COMB_LNA2))
373*216ca234SAdrian Chadd 					/* Set alt LNA1 or LNA2*/
374*216ca234SAdrian Chadd 					if (div_ant_conf->main_lna_conf ==
375*216ca234SAdrian Chadd 					    HAL_ANT_DIV_COMB_LNA2)
376*216ca234SAdrian Chadd 						div_ant_conf->alt_lna_conf =
377*216ca234SAdrian Chadd 							HAL_ANT_DIV_COMB_LNA1;
378*216ca234SAdrian Chadd 					else
379*216ca234SAdrian Chadd 						div_ant_conf->alt_lna_conf =
380*216ca234SAdrian Chadd 							HAL_ANT_DIV_COMB_LNA2;
381*216ca234SAdrian Chadd 				else
382*216ca234SAdrian Chadd 					/* Set alt to A+B or A-B */
383*216ca234SAdrian Chadd 					div_ant_conf->alt_lna_conf =
384*216ca234SAdrian Chadd 						antcomb->first_quick_scan_conf;
385*216ca234SAdrian Chadd 			} else if ((antcomb->second_quick_scan_conf ==
386*216ca234SAdrian Chadd 				   HAL_ANT_DIV_COMB_LNA1) ||
387*216ca234SAdrian Chadd 				   (antcomb->second_quick_scan_conf ==
388*216ca234SAdrian Chadd 				   HAL_ANT_DIV_COMB_LNA2)) {
389*216ca234SAdrian Chadd 				/* Set alt LNA1 or LNA2 */
390*216ca234SAdrian Chadd 				if (div_ant_conf->main_lna_conf ==
391*216ca234SAdrian Chadd 				    HAL_ANT_DIV_COMB_LNA2)
392*216ca234SAdrian Chadd 					div_ant_conf->alt_lna_conf =
393*216ca234SAdrian Chadd 						HAL_ANT_DIV_COMB_LNA1;
394*216ca234SAdrian Chadd 				else
395*216ca234SAdrian Chadd 					div_ant_conf->alt_lna_conf =
396*216ca234SAdrian Chadd 						HAL_ANT_DIV_COMB_LNA2;
397*216ca234SAdrian Chadd 			} else {
398*216ca234SAdrian Chadd 				/* Set alt to A+B or A-B */
399*216ca234SAdrian Chadd 				div_ant_conf->alt_lna_conf =
400*216ca234SAdrian Chadd 					antcomb->second_quick_scan_conf;
401*216ca234SAdrian Chadd 			}
402*216ca234SAdrian Chadd 		} else if (antcomb->first_ratio) {
403*216ca234SAdrian Chadd 			/* first alt */
404*216ca234SAdrian Chadd 			if ((antcomb->first_quick_scan_conf ==
405*216ca234SAdrian Chadd 			    HAL_ANT_DIV_COMB_LNA1) ||
406*216ca234SAdrian Chadd 			    (antcomb->first_quick_scan_conf ==
407*216ca234SAdrian Chadd 			    HAL_ANT_DIV_COMB_LNA2))
408*216ca234SAdrian Chadd 					/* Set alt LNA1 or LNA2 */
409*216ca234SAdrian Chadd 				if (div_ant_conf->main_lna_conf ==
410*216ca234SAdrian Chadd 				    HAL_ANT_DIV_COMB_LNA2)
411*216ca234SAdrian Chadd 					div_ant_conf->alt_lna_conf =
412*216ca234SAdrian Chadd 							HAL_ANT_DIV_COMB_LNA1;
413*216ca234SAdrian Chadd 				else
414*216ca234SAdrian Chadd 					div_ant_conf->alt_lna_conf =
415*216ca234SAdrian Chadd 							HAL_ANT_DIV_COMB_LNA2;
416*216ca234SAdrian Chadd 			else
417*216ca234SAdrian Chadd 				/* Set alt to A+B or A-B */
418*216ca234SAdrian Chadd 				div_ant_conf->alt_lna_conf =
419*216ca234SAdrian Chadd 						antcomb->first_quick_scan_conf;
420*216ca234SAdrian Chadd 		} else if (antcomb->second_ratio) {
421*216ca234SAdrian Chadd 				/* second alt */
422*216ca234SAdrian Chadd 			if ((antcomb->second_quick_scan_conf ==
423*216ca234SAdrian Chadd 			    HAL_ANT_DIV_COMB_LNA1) ||
424*216ca234SAdrian Chadd 			    (antcomb->second_quick_scan_conf ==
425*216ca234SAdrian Chadd 			    HAL_ANT_DIV_COMB_LNA2))
426*216ca234SAdrian Chadd 				/* Set alt LNA1 or LNA2 */
427*216ca234SAdrian Chadd 				if (div_ant_conf->main_lna_conf ==
428*216ca234SAdrian Chadd 				    HAL_ANT_DIV_COMB_LNA2)
429*216ca234SAdrian Chadd 					div_ant_conf->alt_lna_conf =
430*216ca234SAdrian Chadd 						HAL_ANT_DIV_COMB_LNA1;
431*216ca234SAdrian Chadd 				else
432*216ca234SAdrian Chadd 					div_ant_conf->alt_lna_conf =
433*216ca234SAdrian Chadd 						HAL_ANT_DIV_COMB_LNA2;
434*216ca234SAdrian Chadd 			else
435*216ca234SAdrian Chadd 				/* Set alt to A+B or A-B */
436*216ca234SAdrian Chadd 				div_ant_conf->alt_lna_conf =
437*216ca234SAdrian Chadd 						antcomb->second_quick_scan_conf;
438*216ca234SAdrian Chadd 		} else {
439*216ca234SAdrian Chadd 			/* main is largest */
440*216ca234SAdrian Chadd 			if ((antcomb->main_conf == HAL_ANT_DIV_COMB_LNA1) ||
441*216ca234SAdrian Chadd 			    (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA2))
442*216ca234SAdrian Chadd 				/* Set alt LNA1 or LNA2 */
443*216ca234SAdrian Chadd 				if (div_ant_conf->main_lna_conf ==
444*216ca234SAdrian Chadd 				    HAL_ANT_DIV_COMB_LNA2)
445*216ca234SAdrian Chadd 					div_ant_conf->alt_lna_conf =
446*216ca234SAdrian Chadd 							HAL_ANT_DIV_COMB_LNA1;
447*216ca234SAdrian Chadd 				else
448*216ca234SAdrian Chadd 					div_ant_conf->alt_lna_conf =
449*216ca234SAdrian Chadd 							HAL_ANT_DIV_COMB_LNA2;
450*216ca234SAdrian Chadd 			else
451*216ca234SAdrian Chadd 				/* Set alt to A+B or A-B */
452*216ca234SAdrian Chadd 				div_ant_conf->alt_lna_conf = antcomb->main_conf;
453*216ca234SAdrian Chadd 		}
454*216ca234SAdrian Chadd 		break;
455*216ca234SAdrian Chadd 	default:
456*216ca234SAdrian Chadd 		break;
457*216ca234SAdrian Chadd 	}
458*216ca234SAdrian Chadd }
459*216ca234SAdrian Chadd 
460*216ca234SAdrian Chadd static void
461*216ca234SAdrian Chadd ath_ant_div_conf_fast_divbias(HAL_ANT_COMB_CONFIG *ant_conf)
462*216ca234SAdrian Chadd {
463*216ca234SAdrian Chadd 	/* Adjust the fast_div_bias based on main and alt lna conf */
464*216ca234SAdrian Chadd 	switch ((ant_conf->main_lna_conf << 4) | ant_conf->alt_lna_conf) {
465*216ca234SAdrian Chadd 	case (0x01): /* A-B LNA2 */
466*216ca234SAdrian Chadd 		ant_conf->fast_div_bias = 0x3b;
467*216ca234SAdrian Chadd 		break;
468*216ca234SAdrian Chadd 	case (0x02): /* A-B LNA1 */
469*216ca234SAdrian Chadd 		ant_conf->fast_div_bias = 0x3d;
470*216ca234SAdrian Chadd 		break;
471*216ca234SAdrian Chadd 	case (0x03): /* A-B A+B */
472*216ca234SAdrian Chadd 		ant_conf->fast_div_bias = 0x1;
473*216ca234SAdrian Chadd 		break;
474*216ca234SAdrian Chadd 	case (0x10): /* LNA2 A-B */
475*216ca234SAdrian Chadd 		ant_conf->fast_div_bias = 0x7;
476*216ca234SAdrian Chadd 		break;
477*216ca234SAdrian Chadd 	case (0x12): /* LNA2 LNA1 */
478*216ca234SAdrian Chadd 		ant_conf->fast_div_bias = 0x2;
479*216ca234SAdrian Chadd 		break;
480*216ca234SAdrian Chadd 	case (0x13): /* LNA2 A+B */
481*216ca234SAdrian Chadd 		ant_conf->fast_div_bias = 0x7;
482*216ca234SAdrian Chadd 		break;
483*216ca234SAdrian Chadd 	case (0x20): /* LNA1 A-B */
484*216ca234SAdrian Chadd 		ant_conf->fast_div_bias = 0x6;
485*216ca234SAdrian Chadd 		break;
486*216ca234SAdrian Chadd 	case (0x21): /* LNA1 LNA2 */
487*216ca234SAdrian Chadd 		ant_conf->fast_div_bias = 0x0;
488*216ca234SAdrian Chadd 		break;
489*216ca234SAdrian Chadd 	case (0x23): /* LNA1 A+B */
490*216ca234SAdrian Chadd 		ant_conf->fast_div_bias = 0x6;
491*216ca234SAdrian Chadd 		break;
492*216ca234SAdrian Chadd 	case (0x30): /* A+B A-B */
493*216ca234SAdrian Chadd 		ant_conf->fast_div_bias = 0x1;
494*216ca234SAdrian Chadd 		break;
495*216ca234SAdrian Chadd 	case (0x31): /* A+B LNA2 */
496*216ca234SAdrian Chadd 		ant_conf->fast_div_bias = 0x3b;
497*216ca234SAdrian Chadd 		break;
498*216ca234SAdrian Chadd 	case (0x32): /* A+B LNA1 */
499*216ca234SAdrian Chadd 		ant_conf->fast_div_bias = 0x3d;
500*216ca234SAdrian Chadd 		break;
501*216ca234SAdrian Chadd 	default:
502*216ca234SAdrian Chadd 		break;
503*216ca234SAdrian Chadd 	}
504*216ca234SAdrian Chadd }
505*216ca234SAdrian Chadd 
506*216ca234SAdrian Chadd /* Antenna diversity and combining */
507*216ca234SAdrian Chadd void
508*216ca234SAdrian Chadd ath_lna_rx_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs,
509*216ca234SAdrian Chadd     unsigned long ticks, int hz)
510*216ca234SAdrian Chadd {
511*216ca234SAdrian Chadd 	HAL_ANT_COMB_CONFIG div_ant_conf;
512*216ca234SAdrian Chadd 	struct if_ath_ant_comb_state *antcomb = sc->sc_lna_div;
513*216ca234SAdrian Chadd 	int alt_ratio = 0, alt_rssi_avg = 0, main_rssi_avg = 0, curr_alt_set;
514*216ca234SAdrian Chadd 	int curr_main_set, curr_bias;
515*216ca234SAdrian Chadd 	int main_rssi = rs->rs_rssi_ctl[0];
516*216ca234SAdrian Chadd 	int alt_rssi = rs->rs_rssi_ctl[1];
517*216ca234SAdrian Chadd 	int rx_ant_conf, main_ant_conf, alt_ant_conf;
518*216ca234SAdrian Chadd 	HAL_BOOL short_scan = AH_FALSE;
519*216ca234SAdrian Chadd 
520*216ca234SAdrian Chadd 	rx_ant_conf = (rs->rs_rssi_ctl[2] >> 4) & ATH_ANT_RX_MASK;
521*216ca234SAdrian Chadd 	main_ant_conf = (rs->rs_rssi_ctl[2] >> 2) & ATH_ANT_RX_MASK;
522*216ca234SAdrian Chadd 	alt_ant_conf = (rs->rs_rssi_ctl[2] >> 0) & ATH_ANT_RX_MASK;
523*216ca234SAdrian Chadd 
524*216ca234SAdrian Chadd #if 0
525*216ca234SAdrian Chadd 	DPRINTF(sc, ATH_DEBUG_DIVERSITY,
526*216ca234SAdrian Chadd 	    "%s: RSSI %d/%d, conf %x/%x, rxconf %x, LNA: %d; ANT: %d; "
527*216ca234SAdrian Chadd 	    "FastDiv: %d\n",
528*216ca234SAdrian Chadd 	    __func__,
529*216ca234SAdrian Chadd 	    main_rssi,
530*216ca234SAdrian Chadd 	    alt_rssi,
531*216ca234SAdrian Chadd 	    main_ant_conf,
532*216ca234SAdrian Chadd 	    alt_ant_conf,
533*216ca234SAdrian Chadd 	    rx_ant_conf,
534*216ca234SAdrian Chadd 	    !!(rs->rs_rssi_ctl[2] & 0x80),
535*216ca234SAdrian Chadd 	    !!(rs->rs_rssi_ctl[2] & 0x40),
536*216ca234SAdrian Chadd 	    !!(rs->rs_rssi_ext[2] & 0x40));
537*216ca234SAdrian Chadd #endif
538*216ca234SAdrian Chadd 
539*216ca234SAdrian Chadd 	/*
540*216ca234SAdrian Chadd 	 * If LNA diversity combining isn't enabled, don't run this.
541*216ca234SAdrian Chadd 	 */
542*216ca234SAdrian Chadd 	if (! sc->sc_dolnadiv)
543*216ca234SAdrian Chadd 		return;
544*216ca234SAdrian Chadd 
545*216ca234SAdrian Chadd 	/*
546*216ca234SAdrian Chadd 	 * XXX this is ugly, but the HAL code attaches the
547*216ca234SAdrian Chadd 	 * LNA diversity to the TX antenna settings.
548*216ca234SAdrian Chadd 	 * I don't know why.
549*216ca234SAdrian Chadd 	 */
550*216ca234SAdrian Chadd 	if (sc->sc_txantenna != HAL_ANT_VARIABLE)
551*216ca234SAdrian Chadd 		return;
552*216ca234SAdrian Chadd 
553*216ca234SAdrian Chadd 	/* Record packet only when alt_rssi is positive */
554*216ca234SAdrian Chadd 	if (main_rssi > 0 && alt_rssi > 0) {
555*216ca234SAdrian Chadd 		antcomb->total_pkt_count++;
556*216ca234SAdrian Chadd 		antcomb->main_total_rssi += main_rssi;
557*216ca234SAdrian Chadd 		antcomb->alt_total_rssi  += alt_rssi;
558*216ca234SAdrian Chadd 		if (main_ant_conf == rx_ant_conf)
559*216ca234SAdrian Chadd 			antcomb->main_recv_cnt++;
560*216ca234SAdrian Chadd 		else
561*216ca234SAdrian Chadd 			antcomb->alt_recv_cnt++;
562*216ca234SAdrian Chadd 	}
563*216ca234SAdrian Chadd 
564*216ca234SAdrian Chadd 	/* Short scan check */
565*216ca234SAdrian Chadd 	if (antcomb->scan && antcomb->alt_good) {
566*216ca234SAdrian Chadd 		if (time_after(ticks, antcomb->scan_start_time +
567*216ca234SAdrian Chadd 		    msecs_to_jiffies(ATH_ANT_DIV_COMB_SHORT_SCAN_INTR)))
568*216ca234SAdrian Chadd 			short_scan = AH_TRUE;
569*216ca234SAdrian Chadd 		else
570*216ca234SAdrian Chadd 			if (antcomb->total_pkt_count ==
571*216ca234SAdrian Chadd 			    ATH_ANT_DIV_COMB_SHORT_SCAN_PKTCOUNT) {
572*216ca234SAdrian Chadd 				alt_ratio = ((antcomb->alt_recv_cnt * 100) /
573*216ca234SAdrian Chadd 					    antcomb->total_pkt_count);
574*216ca234SAdrian Chadd 				if (alt_ratio < ATH_ANT_DIV_COMB_ALT_ANT_RATIO)
575*216ca234SAdrian Chadd 					short_scan = AH_TRUE;
576*216ca234SAdrian Chadd 			}
577*216ca234SAdrian Chadd 	}
578*216ca234SAdrian Chadd 
579*216ca234SAdrian Chadd 	if (((antcomb->total_pkt_count < ATH_ANT_DIV_COMB_MAX_PKTCOUNT) ||
580*216ca234SAdrian Chadd 	    rs->rs_moreaggr) && !short_scan)
581*216ca234SAdrian Chadd 		return;
582*216ca234SAdrian Chadd 
583*216ca234SAdrian Chadd 	if (antcomb->total_pkt_count) {
584*216ca234SAdrian Chadd 		alt_ratio = ((antcomb->alt_recv_cnt * 100) /
585*216ca234SAdrian Chadd 			     antcomb->total_pkt_count);
586*216ca234SAdrian Chadd 		main_rssi_avg = (antcomb->main_total_rssi /
587*216ca234SAdrian Chadd 				 antcomb->total_pkt_count);
588*216ca234SAdrian Chadd 		alt_rssi_avg = (antcomb->alt_total_rssi /
589*216ca234SAdrian Chadd 				 antcomb->total_pkt_count);
590*216ca234SAdrian Chadd 	}
591*216ca234SAdrian Chadd 
592*216ca234SAdrian Chadd 	OS_MEMZERO(&div_ant_conf, sizeof(div_ant_conf));
593*216ca234SAdrian Chadd 
594*216ca234SAdrian Chadd 	ath_hal_div_comb_conf_get(sc->sc_ah, &div_ant_conf);
595*216ca234SAdrian Chadd 	curr_alt_set = div_ant_conf.alt_lna_conf;
596*216ca234SAdrian Chadd 	curr_main_set = div_ant_conf.main_lna_conf;
597*216ca234SAdrian Chadd 	curr_bias = div_ant_conf.fast_div_bias;
598*216ca234SAdrian Chadd 
599*216ca234SAdrian Chadd 	antcomb->count++;
600*216ca234SAdrian Chadd 
601*216ca234SAdrian Chadd 	if (antcomb->count == ATH_ANT_DIV_COMB_MAX_COUNT) {
602*216ca234SAdrian Chadd 		if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO) {
603*216ca234SAdrian Chadd 			ath_lnaconf_alt_good_scan(antcomb, &div_ant_conf,
604*216ca234SAdrian Chadd 						  main_rssi_avg);
605*216ca234SAdrian Chadd 			antcomb->alt_good = AH_TRUE;
606*216ca234SAdrian Chadd 		} else {
607*216ca234SAdrian Chadd 			antcomb->alt_good = AH_FALSE;
608*216ca234SAdrian Chadd 		}
609*216ca234SAdrian Chadd 
610*216ca234SAdrian Chadd 		antcomb->count = 0;
611*216ca234SAdrian Chadd 		antcomb->scan = AH_TRUE;
612*216ca234SAdrian Chadd 		antcomb->scan_not_start = AH_TRUE;
613*216ca234SAdrian Chadd 	}
614*216ca234SAdrian Chadd 
615*216ca234SAdrian Chadd 	if (!antcomb->scan) {
616*216ca234SAdrian Chadd 		if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO) {
617*216ca234SAdrian Chadd 			if (curr_alt_set == HAL_ANT_DIV_COMB_LNA2) {
618*216ca234SAdrian Chadd 				/* Switch main and alt LNA */
619*216ca234SAdrian Chadd 				div_ant_conf.main_lna_conf =
620*216ca234SAdrian Chadd 						HAL_ANT_DIV_COMB_LNA2;
621*216ca234SAdrian Chadd 				div_ant_conf.alt_lna_conf  =
622*216ca234SAdrian Chadd 						HAL_ANT_DIV_COMB_LNA1;
623*216ca234SAdrian Chadd 			} else if (curr_alt_set == HAL_ANT_DIV_COMB_LNA1) {
624*216ca234SAdrian Chadd 				div_ant_conf.main_lna_conf =
625*216ca234SAdrian Chadd 						HAL_ANT_DIV_COMB_LNA1;
626*216ca234SAdrian Chadd 				div_ant_conf.alt_lna_conf  =
627*216ca234SAdrian Chadd 						HAL_ANT_DIV_COMB_LNA2;
628*216ca234SAdrian Chadd 			}
629*216ca234SAdrian Chadd 
630*216ca234SAdrian Chadd 			goto div_comb_done;
631*216ca234SAdrian Chadd 		} else if ((curr_alt_set != HAL_ANT_DIV_COMB_LNA1) &&
632*216ca234SAdrian Chadd 			   (curr_alt_set != HAL_ANT_DIV_COMB_LNA2)) {
633*216ca234SAdrian Chadd 			/* Set alt to another LNA */
634*216ca234SAdrian Chadd 			if (curr_main_set == HAL_ANT_DIV_COMB_LNA2)
635*216ca234SAdrian Chadd 				div_ant_conf.alt_lna_conf =
636*216ca234SAdrian Chadd 						HAL_ANT_DIV_COMB_LNA1;
637*216ca234SAdrian Chadd 			else if (curr_main_set == HAL_ANT_DIV_COMB_LNA1)
638*216ca234SAdrian Chadd 				div_ant_conf.alt_lna_conf =
639*216ca234SAdrian Chadd 						HAL_ANT_DIV_COMB_LNA2;
640*216ca234SAdrian Chadd 
641*216ca234SAdrian Chadd 			goto div_comb_done;
642*216ca234SAdrian Chadd 		}
643*216ca234SAdrian Chadd 
644*216ca234SAdrian Chadd 		if ((alt_rssi_avg < (main_rssi_avg +
645*216ca234SAdrian Chadd 		    ATH_ANT_DIV_COMB_LNA1_LNA2_DELTA)))
646*216ca234SAdrian Chadd 			goto div_comb_done;
647*216ca234SAdrian Chadd 	}
648*216ca234SAdrian Chadd 
649*216ca234SAdrian Chadd 	if (!antcomb->scan_not_start) {
650*216ca234SAdrian Chadd 		switch (curr_alt_set) {
651*216ca234SAdrian Chadd 		case HAL_ANT_DIV_COMB_LNA2:
652*216ca234SAdrian Chadd 			antcomb->rssi_lna2 = alt_rssi_avg;
653*216ca234SAdrian Chadd 			antcomb->rssi_lna1 = main_rssi_avg;
654*216ca234SAdrian Chadd 			antcomb->scan = AH_TRUE;
655*216ca234SAdrian Chadd 			/* set to A+B */
656*216ca234SAdrian Chadd 			div_ant_conf.main_lna_conf =
657*216ca234SAdrian Chadd 				HAL_ANT_DIV_COMB_LNA1;
658*216ca234SAdrian Chadd 			div_ant_conf.alt_lna_conf  =
659*216ca234SAdrian Chadd 				HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2;
660*216ca234SAdrian Chadd 			break;
661*216ca234SAdrian Chadd 		case HAL_ANT_DIV_COMB_LNA1:
662*216ca234SAdrian Chadd 			antcomb->rssi_lna1 = alt_rssi_avg;
663*216ca234SAdrian Chadd 			antcomb->rssi_lna2 = main_rssi_avg;
664*216ca234SAdrian Chadd 			antcomb->scan = AH_TRUE;
665*216ca234SAdrian Chadd 			/* set to A+B */
666*216ca234SAdrian Chadd 			div_ant_conf.main_lna_conf = HAL_ANT_DIV_COMB_LNA2;
667*216ca234SAdrian Chadd 			div_ant_conf.alt_lna_conf  =
668*216ca234SAdrian Chadd 				HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2;
669*216ca234SAdrian Chadd 			break;
670*216ca234SAdrian Chadd 		case HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2:
671*216ca234SAdrian Chadd 			antcomb->rssi_add = alt_rssi_avg;
672*216ca234SAdrian Chadd 			antcomb->scan = AH_TRUE;
673*216ca234SAdrian Chadd 			/* set to A-B */
674*216ca234SAdrian Chadd 			div_ant_conf.alt_lna_conf =
675*216ca234SAdrian Chadd 				HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2;
676*216ca234SAdrian Chadd 			break;
677*216ca234SAdrian Chadd 		case HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2:
678*216ca234SAdrian Chadd 			antcomb->rssi_sub = alt_rssi_avg;
679*216ca234SAdrian Chadd 			antcomb->scan = AH_FALSE;
680*216ca234SAdrian Chadd 			if (antcomb->rssi_lna2 >
681*216ca234SAdrian Chadd 			    (antcomb->rssi_lna1 +
682*216ca234SAdrian Chadd 			    ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)) {
683*216ca234SAdrian Chadd 				/* use LNA2 as main LNA */
684*216ca234SAdrian Chadd 				if ((antcomb->rssi_add > antcomb->rssi_lna1) &&
685*216ca234SAdrian Chadd 				    (antcomb->rssi_add > antcomb->rssi_sub)) {
686*216ca234SAdrian Chadd 					/* set to A+B */
687*216ca234SAdrian Chadd 					div_ant_conf.main_lna_conf =
688*216ca234SAdrian Chadd 						HAL_ANT_DIV_COMB_LNA2;
689*216ca234SAdrian Chadd 					div_ant_conf.alt_lna_conf  =
690*216ca234SAdrian Chadd 						HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2;
691*216ca234SAdrian Chadd 				} else if (antcomb->rssi_sub >
692*216ca234SAdrian Chadd 					   antcomb->rssi_lna1) {
693*216ca234SAdrian Chadd 					/* set to A-B */
694*216ca234SAdrian Chadd 					div_ant_conf.main_lna_conf =
695*216ca234SAdrian Chadd 						HAL_ANT_DIV_COMB_LNA2;
696*216ca234SAdrian Chadd 					div_ant_conf.alt_lna_conf =
697*216ca234SAdrian Chadd 						HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2;
698*216ca234SAdrian Chadd 				} else {
699*216ca234SAdrian Chadd 					/* set to LNA1 */
700*216ca234SAdrian Chadd 					div_ant_conf.main_lna_conf =
701*216ca234SAdrian Chadd 						HAL_ANT_DIV_COMB_LNA2;
702*216ca234SAdrian Chadd 					div_ant_conf.alt_lna_conf =
703*216ca234SAdrian Chadd 						HAL_ANT_DIV_COMB_LNA1;
704*216ca234SAdrian Chadd 				}
705*216ca234SAdrian Chadd 			} else {
706*216ca234SAdrian Chadd 				/* use LNA1 as main LNA */
707*216ca234SAdrian Chadd 				if ((antcomb->rssi_add > antcomb->rssi_lna2) &&
708*216ca234SAdrian Chadd 				    (antcomb->rssi_add > antcomb->rssi_sub)) {
709*216ca234SAdrian Chadd 					/* set to A+B */
710*216ca234SAdrian Chadd 					div_ant_conf.main_lna_conf =
711*216ca234SAdrian Chadd 						HAL_ANT_DIV_COMB_LNA1;
712*216ca234SAdrian Chadd 					div_ant_conf.alt_lna_conf  =
713*216ca234SAdrian Chadd 						HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2;
714*216ca234SAdrian Chadd 				} else if (antcomb->rssi_sub >
715*216ca234SAdrian Chadd 					   antcomb->rssi_lna1) {
716*216ca234SAdrian Chadd 					/* set to A-B */
717*216ca234SAdrian Chadd 					div_ant_conf.main_lna_conf =
718*216ca234SAdrian Chadd 						HAL_ANT_DIV_COMB_LNA1;
719*216ca234SAdrian Chadd 					div_ant_conf.alt_lna_conf =
720*216ca234SAdrian Chadd 						HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2;
721*216ca234SAdrian Chadd 				} else {
722*216ca234SAdrian Chadd 					/* set to LNA2 */
723*216ca234SAdrian Chadd 					div_ant_conf.main_lna_conf =
724*216ca234SAdrian Chadd 						HAL_ANT_DIV_COMB_LNA1;
725*216ca234SAdrian Chadd 					div_ant_conf.alt_lna_conf =
726*216ca234SAdrian Chadd 						HAL_ANT_DIV_COMB_LNA2;
727*216ca234SAdrian Chadd 				}
728*216ca234SAdrian Chadd 			}
729*216ca234SAdrian Chadd 			break;
730*216ca234SAdrian Chadd 		default:
731*216ca234SAdrian Chadd 			break;
732*216ca234SAdrian Chadd 		}
733*216ca234SAdrian Chadd 	} else {
734*216ca234SAdrian Chadd 		if (!antcomb->alt_good) {
735*216ca234SAdrian Chadd 			antcomb->scan_not_start = AH_FALSE;
736*216ca234SAdrian Chadd 			/* Set alt to another LNA */
737*216ca234SAdrian Chadd 			if (curr_main_set == HAL_ANT_DIV_COMB_LNA2) {
738*216ca234SAdrian Chadd 				div_ant_conf.main_lna_conf =
739*216ca234SAdrian Chadd 						HAL_ANT_DIV_COMB_LNA2;
740*216ca234SAdrian Chadd 				div_ant_conf.alt_lna_conf =
741*216ca234SAdrian Chadd 						HAL_ANT_DIV_COMB_LNA1;
742*216ca234SAdrian Chadd 			} else if (curr_main_set == HAL_ANT_DIV_COMB_LNA1) {
743*216ca234SAdrian Chadd 				div_ant_conf.main_lna_conf =
744*216ca234SAdrian Chadd 						HAL_ANT_DIV_COMB_LNA1;
745*216ca234SAdrian Chadd 				div_ant_conf.alt_lna_conf =
746*216ca234SAdrian Chadd 						HAL_ANT_DIV_COMB_LNA2;
747*216ca234SAdrian Chadd 			}
748*216ca234SAdrian Chadd 			goto div_comb_done;
749*216ca234SAdrian Chadd 		}
750*216ca234SAdrian Chadd 	}
751*216ca234SAdrian Chadd 
752*216ca234SAdrian Chadd 	ath_select_ant_div_from_quick_scan(antcomb, &div_ant_conf,
753*216ca234SAdrian Chadd 					   main_rssi_avg, alt_rssi_avg,
754*216ca234SAdrian Chadd 					   alt_ratio);
755*216ca234SAdrian Chadd 
756*216ca234SAdrian Chadd 	antcomb->quick_scan_cnt++;
757*216ca234SAdrian Chadd 
758*216ca234SAdrian Chadd div_comb_done:
759*216ca234SAdrian Chadd 	ath_ant_div_conf_fast_divbias(&div_ant_conf);
760*216ca234SAdrian Chadd 
761*216ca234SAdrian Chadd 	ath_hal_div_comb_conf_set(sc->sc_ah, &div_ant_conf);
762*216ca234SAdrian Chadd 
763*216ca234SAdrian Chadd 	DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: total_pkt_count=%d\n",
764*216ca234SAdrian Chadd 	   __func__, antcomb->total_pkt_count);
765*216ca234SAdrian Chadd 
766*216ca234SAdrian Chadd 	DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: main_total_rssi=%d\n",
767*216ca234SAdrian Chadd 	   __func__, antcomb->main_total_rssi);
768*216ca234SAdrian Chadd 	DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: alt_total_rssi=%d\n",
769*216ca234SAdrian Chadd 	   __func__, antcomb->alt_total_rssi);
770*216ca234SAdrian Chadd 
771*216ca234SAdrian Chadd 	DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: main_rssi_avg=%d\n",
772*216ca234SAdrian Chadd 	   __func__, main_rssi_avg);
773*216ca234SAdrian Chadd 	DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: alt_alt_rssi_avg=%d\n",
774*216ca234SAdrian Chadd 	   __func__, alt_rssi_avg);
775*216ca234SAdrian Chadd 
776*216ca234SAdrian Chadd 	DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: main_recv_cnt=%d\n",
777*216ca234SAdrian Chadd 	   __func__, antcomb->main_recv_cnt);
778*216ca234SAdrian Chadd 	DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: alt_recv_cnt=%d\n",
779*216ca234SAdrian Chadd 	   __func__, antcomb->alt_recv_cnt);
780*216ca234SAdrian Chadd 
781*216ca234SAdrian Chadd //	if (curr_alt_set != div_ant_conf.alt_lna_conf)
782*216ca234SAdrian Chadd 		DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: lna_conf: %x -> %x\n",
783*216ca234SAdrian Chadd 		    __func__, curr_alt_set, div_ant_conf.alt_lna_conf);
784*216ca234SAdrian Chadd //	if (curr_main_set != div_ant_conf.main_lna_conf)
785*216ca234SAdrian Chadd 		DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: main_lna_conf: %x -> %x\n",
786*216ca234SAdrian Chadd 		    __func__, curr_main_set, div_ant_conf.main_lna_conf);
787*216ca234SAdrian Chadd //	if (curr_bias != div_ant_conf.fast_div_bias)
788*216ca234SAdrian Chadd 		DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: fast_div_bias: %x -> %x\n",
789*216ca234SAdrian Chadd 		    __func__, curr_bias, div_ant_conf.fast_div_bias);
790*216ca234SAdrian Chadd 
791*216ca234SAdrian Chadd 	antcomb->scan_start_time = ticks;
792*216ca234SAdrian Chadd 	antcomb->total_pkt_count = 0;
793*216ca234SAdrian Chadd 	antcomb->main_total_rssi = 0;
794*216ca234SAdrian Chadd 	antcomb->alt_total_rssi = 0;
795*216ca234SAdrian Chadd 	antcomb->main_recv_cnt = 0;
796*216ca234SAdrian Chadd 	antcomb->alt_recv_cnt = 0;
797*216ca234SAdrian Chadd }
798*216ca234SAdrian Chadd 
799