1251655Sadrian/*-
2251655Sadrian * Copyright (c) 2013 Adrian Chadd <adrian@FreeBSD.org>
3251655Sadrian * All rights reserved.
4251655Sadrian *
5251655Sadrian * Redistribution and use in source and binary forms, with or without
6251655Sadrian * modification, are permitted provided that the following conditions
7251655Sadrian * are met:
8251655Sadrian * 1. Redistributions of source code must retain the above copyright
9251655Sadrian *    notice, this list of conditions and the following disclaimer,
10251655Sadrian *    without modification.
11251655Sadrian * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12251655Sadrian *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13251655Sadrian *    redistribution must be conditioned upon including a substantially
14251655Sadrian *    similar Disclaimer requirement for further binary redistribution.
15251655Sadrian *
16251655Sadrian * NO WARRANTY
17251655Sadrian * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18251655Sadrian * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19251655Sadrian * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
20251655Sadrian * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21251655Sadrian * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
22251655Sadrian * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23251655Sadrian * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24251655Sadrian * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25251655Sadrian * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26251655Sadrian * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27251655Sadrian * THE POSSIBILITY OF SUCH DAMAGES.
28251655Sadrian *
29251655Sadrian * $FreeBSD$
30251655Sadrian */
31251655Sadrian#include <sys/cdefs.h>
32251655Sadrian__FBSDID("$FreeBSD$");
33251655Sadrian
34251655Sadrian/*
35251655Sadrian * This module handles LNA diversity for those chips which implement LNA
36251655Sadrian * mixing (AR9285/AR9485.)
37251655Sadrian */
38251655Sadrian#include "opt_ath.h"
39251655Sadrian#include "opt_inet.h"
40251655Sadrian#include "opt_wlan.h"
41251655Sadrian
42251655Sadrian#include <sys/param.h>
43251655Sadrian#include <sys/systm.h>
44251655Sadrian#include <sys/sysctl.h>
45251655Sadrian#include <sys/kernel.h>
46251655Sadrian#include <sys/lock.h>
47251655Sadrian#include <sys/mutex.h>
48251655Sadrian#include <sys/errno.h>
49251655Sadrian
50251655Sadrian#include <machine/bus.h>
51251655Sadrian#include <machine/resource.h>
52251655Sadrian#include <sys/bus.h>
53251655Sadrian
54251655Sadrian#include <sys/socket.h>
55251655Sadrian
56251655Sadrian#include <net/if.h>
57251655Sadrian#include <net/if_media.h>
58251655Sadrian#include <net/if_arp.h>
59251655Sadrian#include <net/ethernet.h>		/* XXX for ether_sprintf */
60251655Sadrian
61251655Sadrian#include <net80211/ieee80211_var.h>
62251655Sadrian
63251655Sadrian#include <net/bpf.h>
64251655Sadrian
65251655Sadrian#ifdef INET
66251655Sadrian#include <netinet/in.h>
67251655Sadrian#include <netinet/if_ether.h>
68251655Sadrian#endif
69251655Sadrian
70251655Sadrian#include <dev/ath/if_athvar.h>
71251655Sadrian#include <dev/ath/if_ath_debug.h>
72251655Sadrian#include <dev/ath/if_ath_lna_div.h>
73251655Sadrian
74251655Sadrian/* Linux compability macros */
75251655Sadrian/*
76251655Sadrian * XXX these don't handle rounding, underflow, overflow, wrapping!
77251655Sadrian */
78251655Sadrian#define	msecs_to_jiffies(a)		( (a) * hz / 1000 )
79251655Sadrian
80251655Sadrian/*
81251655Sadrian * Methods which are required
82251655Sadrian */
83251655Sadrian
84251655Sadrian/*
85251655Sadrian * Attach the LNA diversity to the given interface
86251655Sadrian */
87251655Sadrianint
88251655Sadrianath_lna_div_attach(struct ath_softc *sc)
89251655Sadrian{
90251655Sadrian	struct if_ath_ant_comb_state *ss;
91251730Sadrian	HAL_ANT_COMB_CONFIG div_ant_conf;
92251655Sadrian
93251655Sadrian	/* Only do this if diversity is enabled */
94251655Sadrian	if (! ath_hal_hasdivantcomb(sc->sc_ah))
95251655Sadrian		return (0);
96251655Sadrian
97251655Sadrian	ss = malloc(sizeof(struct if_ath_ant_comb_state),
98251655Sadrian	    M_TEMP, M_WAITOK | M_ZERO);
99251655Sadrian	if (ss == NULL) {
100251655Sadrian		device_printf(sc->sc_dev, "%s: failed to allocate\n",
101251655Sadrian		    __func__);
102251655Sadrian		/* Don't fail at this point */
103251655Sadrian		return (0);
104251655Sadrian	}
105251655Sadrian
106251730Sadrian	/* Fetch the hardware configuration */
107251730Sadrian	OS_MEMZERO(&div_ant_conf, sizeof(div_ant_conf));
108251730Sadrian	ath_hal_div_comb_conf_get(sc->sc_ah, &div_ant_conf);
109251730Sadrian
110251730Sadrian	/* Figure out what the hardware specific bits should be */
111251730Sadrian	if ((div_ant_conf.antdiv_configgroup == HAL_ANTDIV_CONFIG_GROUP_1) ||
112251730Sadrian	    (div_ant_conf.antdiv_configgroup == HAL_ANTDIV_CONFIG_GROUP_2)) {
113251730Sadrian		ss->lna1_lna2_delta = -9;
114251730Sadrian	} else {
115251730Sadrian		ss->lna1_lna2_delta = -3;
116251730Sadrian	}
117251730Sadrian
118251655Sadrian	/* Let's flip this on */
119251655Sadrian	sc->sc_lna_div = ss;
120251655Sadrian	sc->sc_dolnadiv = 1;
121251655Sadrian
122251655Sadrian	return (0);
123251655Sadrian}
124251655Sadrian
125251655Sadrian/*
126251655Sadrian * Detach the LNA diversity state from the given interface
127251655Sadrian */
128251655Sadrianint
129251655Sadrianath_lna_div_detach(struct ath_softc *sc)
130251655Sadrian{
131251655Sadrian	if (sc->sc_lna_div != NULL) {
132251655Sadrian		free(sc->sc_lna_div, M_TEMP);
133251655Sadrian		sc->sc_lna_div = NULL;
134251655Sadrian	}
135251655Sadrian	sc->sc_dolnadiv = 0;
136251655Sadrian	return (0);
137251655Sadrian}
138251655Sadrian
139251655Sadrian/*
140251655Sadrian * Enable LNA diversity on the current channel if it's required.
141251655Sadrian */
142251655Sadrianint
143251655Sadrianath_lna_div_enable(struct ath_softc *sc, const struct ieee80211_channel *chan)
144251655Sadrian{
145251655Sadrian
146251655Sadrian	return (0);
147251655Sadrian}
148251655Sadrian
149251655Sadrian/*
150251655Sadrian * Handle ioctl requests from the diagnostic interface.
151251655Sadrian *
152251655Sadrian * The initial part of this code resembles ath_ioctl_diag();
153251655Sadrian * it's likely a good idea to reduce duplication between
154251655Sadrian * these two routines.
155251655Sadrian */
156251655Sadrianint
157251655Sadrianath_lna_div_ioctl(struct ath_softc *sc, struct ath_diag *ad)
158251655Sadrian{
159251655Sadrian	unsigned int id = ad->ad_id & ATH_DIAG_ID;
160251655Sadrian	void *indata = NULL;
161251655Sadrian	void *outdata = NULL;
162251655Sadrian	u_int32_t insize = ad->ad_in_size;
163251655Sadrian	u_int32_t outsize = ad->ad_out_size;
164251655Sadrian	int error = 0;
165251655Sadrian//	int val;
166251655Sadrian
167251655Sadrian	if (ad->ad_id & ATH_DIAG_IN) {
168251655Sadrian		/*
169251655Sadrian		 * Copy in data.
170251655Sadrian		 */
171251655Sadrian		indata = malloc(insize, M_TEMP, M_NOWAIT);
172251655Sadrian		if (indata == NULL) {
173251655Sadrian			error = ENOMEM;
174251655Sadrian			goto bad;
175251655Sadrian		}
176251655Sadrian		error = copyin(ad->ad_in_data, indata, insize);
177251655Sadrian		if (error)
178251655Sadrian			goto bad;
179251655Sadrian	}
180251655Sadrian	if (ad->ad_id & ATH_DIAG_DYN) {
181251655Sadrian		/*
182251655Sadrian		 * Allocate a buffer for the results (otherwise the HAL
183251655Sadrian		 * returns a pointer to a buffer where we can read the
184251655Sadrian		 * results).  Note that we depend on the HAL leaving this
185251655Sadrian		 * pointer for us to use below in reclaiming the buffer;
186251655Sadrian		 * may want to be more defensive.
187251655Sadrian		 */
188251655Sadrian		outdata = malloc(outsize, M_TEMP, M_NOWAIT);
189251655Sadrian		if (outdata == NULL) {
190251655Sadrian			error = ENOMEM;
191251655Sadrian			goto bad;
192251655Sadrian		}
193251655Sadrian	}
194251655Sadrian	switch (id) {
195251655Sadrian		default:
196251655Sadrian			error = EINVAL;
197251655Sadrian	}
198251655Sadrian	if (outsize < ad->ad_out_size)
199251655Sadrian		ad->ad_out_size = outsize;
200251655Sadrian	if (outdata && copyout(outdata, ad->ad_out_data, ad->ad_out_size))
201251655Sadrian		error = EFAULT;
202251655Sadrianbad:
203251655Sadrian	if ((ad->ad_id & ATH_DIAG_IN) && indata != NULL)
204251655Sadrian		free(indata, M_TEMP);
205251655Sadrian	if ((ad->ad_id & ATH_DIAG_DYN) && outdata != NULL)
206251655Sadrian		free(outdata, M_TEMP);
207251655Sadrian	return (error);
208251655Sadrian}
209251655Sadrian
210251655Sadrianstatic HAL_BOOL
211251655Sadrianath_is_alt_ant_ratio_better(int alt_ratio, int maxdelta, int mindelta,
212251655Sadrian    int main_rssi_avg, int alt_rssi_avg, int pkt_count)
213251655Sadrian{
214251655Sadrian	return (((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
215251655Sadrian		(alt_rssi_avg > main_rssi_avg + maxdelta)) ||
216251655Sadrian		(alt_rssi_avg > main_rssi_avg + mindelta)) && (pkt_count > 50);
217251655Sadrian}
218251655Sadrian
219251655Sadrianstatic void
220251655Sadrianath_lnaconf_alt_good_scan(struct if_ath_ant_comb_state *antcomb,
221251655Sadrian    HAL_ANT_COMB_CONFIG *ant_conf, int main_rssi_avg)
222251655Sadrian{
223251655Sadrian	antcomb->quick_scan_cnt = 0;
224251655Sadrian
225251655Sadrian	if (ant_conf->main_lna_conf == HAL_ANT_DIV_COMB_LNA2)
226251655Sadrian		antcomb->rssi_lna2 = main_rssi_avg;
227251655Sadrian	else if (ant_conf->main_lna_conf == HAL_ANT_DIV_COMB_LNA1)
228251655Sadrian		antcomb->rssi_lna1 = main_rssi_avg;
229251655Sadrian
230251655Sadrian	switch ((ant_conf->main_lna_conf << 4) | ant_conf->alt_lna_conf) {
231251655Sadrian	case (0x10): /* LNA2 A-B */
232251655Sadrian		antcomb->main_conf = HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2;
233251655Sadrian		antcomb->first_quick_scan_conf =
234251655Sadrian			HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2;
235251655Sadrian		antcomb->second_quick_scan_conf = HAL_ANT_DIV_COMB_LNA1;
236251655Sadrian		break;
237251655Sadrian	case (0x20): /* LNA1 A-B */
238251655Sadrian		antcomb->main_conf = HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2;
239251655Sadrian		antcomb->first_quick_scan_conf =
240251655Sadrian			HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2;
241251655Sadrian		antcomb->second_quick_scan_conf = HAL_ANT_DIV_COMB_LNA2;
242251655Sadrian		break;
243251655Sadrian	case (0x21): /* LNA1 LNA2 */
244251655Sadrian		antcomb->main_conf = HAL_ANT_DIV_COMB_LNA2;
245251655Sadrian		antcomb->first_quick_scan_conf =
246251655Sadrian			HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2;
247251655Sadrian		antcomb->second_quick_scan_conf =
248251655Sadrian			HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2;
249251655Sadrian		break;
250251655Sadrian	case (0x12): /* LNA2 LNA1 */
251251655Sadrian		antcomb->main_conf = HAL_ANT_DIV_COMB_LNA1;
252251655Sadrian		antcomb->first_quick_scan_conf =
253251655Sadrian			HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2;
254251655Sadrian		antcomb->second_quick_scan_conf =
255251655Sadrian			HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2;
256251655Sadrian		break;
257251655Sadrian	case (0x13): /* LNA2 A+B */
258251655Sadrian		antcomb->main_conf = HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2;
259251655Sadrian		antcomb->first_quick_scan_conf =
260251655Sadrian			HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2;
261251655Sadrian		antcomb->second_quick_scan_conf = HAL_ANT_DIV_COMB_LNA1;
262251655Sadrian		break;
263251655Sadrian	case (0x23): /* LNA1 A+B */
264251655Sadrian		antcomb->main_conf = HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2;
265251655Sadrian		antcomb->first_quick_scan_conf =
266251655Sadrian			HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2;
267251655Sadrian		antcomb->second_quick_scan_conf = HAL_ANT_DIV_COMB_LNA2;
268251655Sadrian		break;
269251655Sadrian	default:
270251655Sadrian		break;
271251655Sadrian	}
272251655Sadrian}
273251655Sadrian
274251655Sadrianstatic void
275251655Sadrianath_select_ant_div_from_quick_scan(struct if_ath_ant_comb_state *antcomb,
276251655Sadrian    HAL_ANT_COMB_CONFIG *div_ant_conf, int main_rssi_avg,
277251655Sadrian    int alt_rssi_avg, int alt_ratio)
278251655Sadrian{
279251655Sadrian	/* alt_good */
280251655Sadrian	switch (antcomb->quick_scan_cnt) {
281251655Sadrian	case 0:
282251655Sadrian		/* set alt to main, and alt to first conf */
283251655Sadrian		div_ant_conf->main_lna_conf = antcomb->main_conf;
284251655Sadrian		div_ant_conf->alt_lna_conf = antcomb->first_quick_scan_conf;
285251655Sadrian		break;
286251655Sadrian	case 1:
287251655Sadrian		/* set alt to main, and alt to first conf */
288251655Sadrian		div_ant_conf->main_lna_conf = antcomb->main_conf;
289251655Sadrian		div_ant_conf->alt_lna_conf = antcomb->second_quick_scan_conf;
290251655Sadrian		antcomb->rssi_first = main_rssi_avg;
291251655Sadrian		antcomb->rssi_second = alt_rssi_avg;
292251655Sadrian
293251655Sadrian		if (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA1) {
294251655Sadrian			/* main is LNA1 */
295251655Sadrian			if (ath_is_alt_ant_ratio_better(alt_ratio,
296251655Sadrian						ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
297251655Sadrian						ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
298251655Sadrian						main_rssi_avg, alt_rssi_avg,
299251655Sadrian						antcomb->total_pkt_count))
300251655Sadrian				antcomb->first_ratio = AH_TRUE;
301251655Sadrian			else
302251655Sadrian				antcomb->first_ratio = AH_FALSE;
303251655Sadrian		} else if (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA2) {
304251655Sadrian			if (ath_is_alt_ant_ratio_better(alt_ratio,
305251655Sadrian						ATH_ANT_DIV_COMB_LNA1_DELTA_MID,
306251655Sadrian						ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
307251655Sadrian						main_rssi_avg, alt_rssi_avg,
308251655Sadrian						antcomb->total_pkt_count))
309251655Sadrian				antcomb->first_ratio = AH_TRUE;
310251655Sadrian			else
311251655Sadrian				antcomb->first_ratio = AH_FALSE;
312251655Sadrian		} else {
313251655Sadrian			if ((((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
314251655Sadrian			    (alt_rssi_avg > main_rssi_avg +
315251655Sadrian			    ATH_ANT_DIV_COMB_LNA1_DELTA_HI)) ||
316251655Sadrian			    (alt_rssi_avg > main_rssi_avg)) &&
317251655Sadrian			    (antcomb->total_pkt_count > 50))
318251655Sadrian				antcomb->first_ratio = AH_TRUE;
319251655Sadrian			else
320251655Sadrian				antcomb->first_ratio = AH_FALSE;
321251655Sadrian		}
322251655Sadrian		break;
323251655Sadrian	case 2:
324251655Sadrian		antcomb->alt_good = AH_FALSE;
325251655Sadrian		antcomb->scan_not_start = AH_FALSE;
326251655Sadrian		antcomb->scan = AH_FALSE;
327251655Sadrian		antcomb->rssi_first = main_rssi_avg;
328251655Sadrian		antcomb->rssi_third = alt_rssi_avg;
329251655Sadrian
330251655Sadrian		if (antcomb->second_quick_scan_conf == HAL_ANT_DIV_COMB_LNA1)
331251655Sadrian			antcomb->rssi_lna1 = alt_rssi_avg;
332251655Sadrian		else if (antcomb->second_quick_scan_conf ==
333251655Sadrian			 HAL_ANT_DIV_COMB_LNA2)
334251655Sadrian			antcomb->rssi_lna2 = alt_rssi_avg;
335251655Sadrian		else if (antcomb->second_quick_scan_conf ==
336251655Sadrian			 HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2) {
337251655Sadrian			if (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA2)
338251655Sadrian				antcomb->rssi_lna2 = main_rssi_avg;
339251655Sadrian			else if (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA1)
340251655Sadrian				antcomb->rssi_lna1 = main_rssi_avg;
341251655Sadrian		}
342251655Sadrian
343251655Sadrian		if (antcomb->rssi_lna2 > antcomb->rssi_lna1 +
344251655Sadrian		    ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)
345251655Sadrian			div_ant_conf->main_lna_conf = HAL_ANT_DIV_COMB_LNA2;
346251655Sadrian		else
347251655Sadrian			div_ant_conf->main_lna_conf = HAL_ANT_DIV_COMB_LNA1;
348251655Sadrian
349251655Sadrian		if (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA1) {
350251655Sadrian			if (ath_is_alt_ant_ratio_better(alt_ratio,
351251655Sadrian						ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
352251655Sadrian						ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
353251655Sadrian						main_rssi_avg, alt_rssi_avg,
354251655Sadrian						antcomb->total_pkt_count))
355251655Sadrian				antcomb->second_ratio = AH_TRUE;
356251655Sadrian			else
357251655Sadrian				antcomb->second_ratio = AH_FALSE;
358251655Sadrian		} else if (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA2) {
359251655Sadrian			if (ath_is_alt_ant_ratio_better(alt_ratio,
360251655Sadrian						ATH_ANT_DIV_COMB_LNA1_DELTA_MID,
361251655Sadrian						ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
362251655Sadrian						main_rssi_avg, alt_rssi_avg,
363251655Sadrian						antcomb->total_pkt_count))
364251655Sadrian				antcomb->second_ratio = AH_TRUE;
365251655Sadrian			else
366251655Sadrian				antcomb->second_ratio = AH_FALSE;
367251655Sadrian		} else {
368251655Sadrian			if ((((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
369251655Sadrian			    (alt_rssi_avg > main_rssi_avg +
370251655Sadrian			    ATH_ANT_DIV_COMB_LNA1_DELTA_HI)) ||
371251655Sadrian			    (alt_rssi_avg > main_rssi_avg)) &&
372251655Sadrian			    (antcomb->total_pkt_count > 50))
373251655Sadrian				antcomb->second_ratio = AH_TRUE;
374251655Sadrian			else
375251655Sadrian				antcomb->second_ratio = AH_FALSE;
376251655Sadrian		}
377251655Sadrian
378251655Sadrian		/* set alt to the conf with maximun ratio */
379251655Sadrian		if (antcomb->first_ratio && antcomb->second_ratio) {
380251655Sadrian			if (antcomb->rssi_second > antcomb->rssi_third) {
381251655Sadrian				/* first alt*/
382251655Sadrian				if ((antcomb->first_quick_scan_conf ==
383251655Sadrian				    HAL_ANT_DIV_COMB_LNA1) ||
384251655Sadrian				    (antcomb->first_quick_scan_conf ==
385251655Sadrian				    HAL_ANT_DIV_COMB_LNA2))
386251655Sadrian					/* Set alt LNA1 or LNA2*/
387251655Sadrian					if (div_ant_conf->main_lna_conf ==
388251655Sadrian					    HAL_ANT_DIV_COMB_LNA2)
389251655Sadrian						div_ant_conf->alt_lna_conf =
390251655Sadrian							HAL_ANT_DIV_COMB_LNA1;
391251655Sadrian					else
392251655Sadrian						div_ant_conf->alt_lna_conf =
393251655Sadrian							HAL_ANT_DIV_COMB_LNA2;
394251655Sadrian				else
395251655Sadrian					/* Set alt to A+B or A-B */
396251655Sadrian					div_ant_conf->alt_lna_conf =
397251655Sadrian						antcomb->first_quick_scan_conf;
398251655Sadrian			} else if ((antcomb->second_quick_scan_conf ==
399251655Sadrian				   HAL_ANT_DIV_COMB_LNA1) ||
400251655Sadrian				   (antcomb->second_quick_scan_conf ==
401251655Sadrian				   HAL_ANT_DIV_COMB_LNA2)) {
402251655Sadrian				/* Set alt LNA1 or LNA2 */
403251655Sadrian				if (div_ant_conf->main_lna_conf ==
404251655Sadrian				    HAL_ANT_DIV_COMB_LNA2)
405251655Sadrian					div_ant_conf->alt_lna_conf =
406251655Sadrian						HAL_ANT_DIV_COMB_LNA1;
407251655Sadrian				else
408251655Sadrian					div_ant_conf->alt_lna_conf =
409251655Sadrian						HAL_ANT_DIV_COMB_LNA2;
410251655Sadrian			} else {
411251655Sadrian				/* Set alt to A+B or A-B */
412251655Sadrian				div_ant_conf->alt_lna_conf =
413251655Sadrian					antcomb->second_quick_scan_conf;
414251655Sadrian			}
415251655Sadrian		} else if (antcomb->first_ratio) {
416251655Sadrian			/* first alt */
417251655Sadrian			if ((antcomb->first_quick_scan_conf ==
418251655Sadrian			    HAL_ANT_DIV_COMB_LNA1) ||
419251655Sadrian			    (antcomb->first_quick_scan_conf ==
420251655Sadrian			    HAL_ANT_DIV_COMB_LNA2))
421251655Sadrian					/* Set alt LNA1 or LNA2 */
422251655Sadrian				if (div_ant_conf->main_lna_conf ==
423251655Sadrian				    HAL_ANT_DIV_COMB_LNA2)
424251655Sadrian					div_ant_conf->alt_lna_conf =
425251655Sadrian							HAL_ANT_DIV_COMB_LNA1;
426251655Sadrian				else
427251655Sadrian					div_ant_conf->alt_lna_conf =
428251655Sadrian							HAL_ANT_DIV_COMB_LNA2;
429251655Sadrian			else
430251655Sadrian				/* Set alt to A+B or A-B */
431251655Sadrian				div_ant_conf->alt_lna_conf =
432251655Sadrian						antcomb->first_quick_scan_conf;
433251655Sadrian		} else if (antcomb->second_ratio) {
434251655Sadrian				/* second alt */
435251655Sadrian			if ((antcomb->second_quick_scan_conf ==
436251655Sadrian			    HAL_ANT_DIV_COMB_LNA1) ||
437251655Sadrian			    (antcomb->second_quick_scan_conf ==
438251655Sadrian			    HAL_ANT_DIV_COMB_LNA2))
439251655Sadrian				/* Set alt LNA1 or LNA2 */
440251655Sadrian				if (div_ant_conf->main_lna_conf ==
441251655Sadrian				    HAL_ANT_DIV_COMB_LNA2)
442251655Sadrian					div_ant_conf->alt_lna_conf =
443251655Sadrian						HAL_ANT_DIV_COMB_LNA1;
444251655Sadrian				else
445251655Sadrian					div_ant_conf->alt_lna_conf =
446251655Sadrian						HAL_ANT_DIV_COMB_LNA2;
447251655Sadrian			else
448251655Sadrian				/* Set alt to A+B or A-B */
449251655Sadrian				div_ant_conf->alt_lna_conf =
450251655Sadrian						antcomb->second_quick_scan_conf;
451251655Sadrian		} else {
452251655Sadrian			/* main is largest */
453251655Sadrian			if ((antcomb->main_conf == HAL_ANT_DIV_COMB_LNA1) ||
454251655Sadrian			    (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA2))
455251655Sadrian				/* Set alt LNA1 or LNA2 */
456251655Sadrian				if (div_ant_conf->main_lna_conf ==
457251655Sadrian				    HAL_ANT_DIV_COMB_LNA2)
458251655Sadrian					div_ant_conf->alt_lna_conf =
459251655Sadrian							HAL_ANT_DIV_COMB_LNA1;
460251655Sadrian				else
461251655Sadrian					div_ant_conf->alt_lna_conf =
462251655Sadrian							HAL_ANT_DIV_COMB_LNA2;
463251655Sadrian			else
464251655Sadrian				/* Set alt to A+B or A-B */
465251655Sadrian				div_ant_conf->alt_lna_conf = antcomb->main_conf;
466251655Sadrian		}
467251655Sadrian		break;
468251655Sadrian	default:
469251655Sadrian		break;
470251655Sadrian	}
471251655Sadrian}
472251655Sadrian
473251655Sadrianstatic void
474251730Sadrianath_ant_adjust_fast_divbias(struct if_ath_ant_comb_state *antcomb,
475251730Sadrian    int alt_ratio, int alt_ant_ratio_th, u_int config_group,
476251730Sadrian    HAL_ANT_COMB_CONFIG *pdiv_ant_conf)
477251655Sadrian{
478251730Sadrian
479251730Sadrian	if (config_group == HAL_ANTDIV_CONFIG_GROUP_1) {
480251730Sadrian		switch ((pdiv_ant_conf->main_lna_conf << 4)
481251730Sadrian		    | pdiv_ant_conf->alt_lna_conf) {
482251730Sadrian		case (0x01): //A-B LNA2
483251730Sadrian			pdiv_ant_conf->fast_div_bias = 0x1;
484251730Sadrian			pdiv_ant_conf->main_gaintb   = 0;
485251730Sadrian			pdiv_ant_conf->alt_gaintb    = 0;
486251730Sadrian			break;
487251730Sadrian		case (0x02): //A-B LNA1
488251730Sadrian			pdiv_ant_conf->fast_div_bias = 0x1;
489251730Sadrian			pdiv_ant_conf->main_gaintb   = 0;
490251730Sadrian			pdiv_ant_conf->alt_gaintb    = 0;
491251730Sadrian			break;
492251730Sadrian		case (0x03): //A-B A+B
493251730Sadrian			pdiv_ant_conf->fast_div_bias = 0x1;
494251730Sadrian			pdiv_ant_conf->main_gaintb   = 0;
495251730Sadrian			pdiv_ant_conf->alt_gaintb    = 0;
496251730Sadrian			break;
497251730Sadrian		case (0x10): //LNA2 A-B
498251730Sadrian			if ((antcomb->scan == 0)
499251730Sadrian			    && (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) {
500251730Sadrian				pdiv_ant_conf->fast_div_bias = 0x3f;
501251730Sadrian			} else {
502251730Sadrian				pdiv_ant_conf->fast_div_bias = 0x1;
503251730Sadrian			}
504251730Sadrian			pdiv_ant_conf->main_gaintb   = 0;
505251730Sadrian			pdiv_ant_conf->alt_gaintb    = 0;
506251730Sadrian			break;
507251730Sadrian		case (0x12): //LNA2 LNA1
508251730Sadrian			pdiv_ant_conf->fast_div_bias = 0x1;
509251730Sadrian			pdiv_ant_conf->main_gaintb   = 0;
510251730Sadrian			pdiv_ant_conf->alt_gaintb    = 0;
511251730Sadrian			break;
512251730Sadrian			case (0x13): //LNA2 A+B
513251730Sadrian			if ((antcomb->scan == 0)
514251730Sadrian			    && (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) {
515251730Sadrian				pdiv_ant_conf->fast_div_bias = 0x3f;
516251730Sadrian			} else {
517251730Sadrian				pdiv_ant_conf->fast_div_bias = 0x1;
518251730Sadrian			}
519251730Sadrian			pdiv_ant_conf->main_gaintb   = 0;
520251730Sadrian			pdiv_ant_conf->alt_gaintb    = 0;
521251730Sadrian			break;
522251730Sadrian		case (0x20): //LNA1 A-B
523251730Sadrian			if ((antcomb->scan == 0)
524251730Sadrian			    && (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) {
525251730Sadrian				pdiv_ant_conf->fast_div_bias = 0x3f;
526251730Sadrian			} else {
527251730Sadrian				pdiv_ant_conf->fast_div_bias = 0x1;
528251730Sadrian			}
529251730Sadrian			pdiv_ant_conf->main_gaintb   = 0;
530251730Sadrian			pdiv_ant_conf->alt_gaintb    = 0;
531251730Sadrian			break;
532251730Sadrian		case (0x21): //LNA1 LNA2
533251730Sadrian			pdiv_ant_conf->fast_div_bias = 0x1;
534251730Sadrian			pdiv_ant_conf->main_gaintb   = 0;
535251730Sadrian			pdiv_ant_conf->alt_gaintb    = 0;
536251730Sadrian			break;
537251730Sadrian		case (0x23): //LNA1 A+B
538251730Sadrian			if ((antcomb->scan == 0)
539251730Sadrian			    && (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) {
540251730Sadrian				pdiv_ant_conf->fast_div_bias = 0x3f;
541251730Sadrian			} else {
542251730Sadrian				pdiv_ant_conf->fast_div_bias = 0x1;
543251730Sadrian			}
544251730Sadrian			pdiv_ant_conf->main_gaintb   = 0;
545251730Sadrian			pdiv_ant_conf->alt_gaintb    = 0;
546251730Sadrian			break;
547251730Sadrian		case (0x30): //A+B A-B
548251730Sadrian			pdiv_ant_conf->fast_div_bias = 0x1;
549251730Sadrian			pdiv_ant_conf->main_gaintb   = 0;
550251730Sadrian			pdiv_ant_conf->alt_gaintb    = 0;
551251730Sadrian			break;
552251730Sadrian		case (0x31): //A+B LNA2
553251730Sadrian			pdiv_ant_conf->fast_div_bias = 0x1;
554251730Sadrian			pdiv_ant_conf->main_gaintb   = 0;
555251730Sadrian			pdiv_ant_conf->alt_gaintb    = 0;
556251730Sadrian			break;
557251730Sadrian		case (0x32): //A+B LNA1
558251730Sadrian			pdiv_ant_conf->fast_div_bias = 0x1;
559251730Sadrian			pdiv_ant_conf->main_gaintb   = 0;
560251730Sadrian			pdiv_ant_conf->alt_gaintb    = 0;
561251730Sadrian			break;
562251730Sadrian		default:
563251730Sadrian			break;
564251730Sadrian		}
565251730Sadrian	} else if (config_group == HAL_ANTDIV_CONFIG_GROUP_2) {
566251730Sadrian		switch ((pdiv_ant_conf->main_lna_conf << 4)
567251730Sadrian		    | pdiv_ant_conf->alt_lna_conf) {
568251730Sadrian		case (0x01): //A-B LNA2
569251730Sadrian			pdiv_ant_conf->fast_div_bias = 0x1;
570251730Sadrian			pdiv_ant_conf->main_gaintb   = 0;
571251730Sadrian			pdiv_ant_conf->alt_gaintb    = 0;
572251730Sadrian			break;
573251730Sadrian		case (0x02): //A-B LNA1
574251730Sadrian			pdiv_ant_conf->fast_div_bias = 0x1;
575251730Sadrian			pdiv_ant_conf->main_gaintb   = 0;
576251730Sadrian			pdiv_ant_conf->alt_gaintb    = 0;
577251730Sadrian			break;
578251730Sadrian		case (0x03): //A-B A+B
579251730Sadrian			pdiv_ant_conf->fast_div_bias = 0x1;
580251730Sadrian			pdiv_ant_conf->main_gaintb   = 0;
581251730Sadrian			pdiv_ant_conf->alt_gaintb    = 0;
582251730Sadrian			break;
583251730Sadrian		case (0x10): //LNA2 A-B
584251730Sadrian			if ((antcomb->scan == 0)
585251730Sadrian			    && (alt_ratio > alt_ant_ratio_th)) {
586251730Sadrian				pdiv_ant_conf->fast_div_bias = 0x1;
587251730Sadrian			} else {
588251730Sadrian				pdiv_ant_conf->fast_div_bias = 0x2;
589251730Sadrian			}
590251730Sadrian			pdiv_ant_conf->main_gaintb   = 0;
591251730Sadrian			pdiv_ant_conf->alt_gaintb    = 0;
592251730Sadrian			break;
593251730Sadrian		case (0x12): //LNA2 LNA1
594251730Sadrian			pdiv_ant_conf->fast_div_bias = 0x1;
595251730Sadrian			pdiv_ant_conf->main_gaintb   = 0;
596251730Sadrian			pdiv_ant_conf->alt_gaintb    = 0;
597251730Sadrian			break;
598251730Sadrian		case (0x13): //LNA2 A+B
599251730Sadrian			if ((antcomb->scan == 0)
600251730Sadrian			    && (alt_ratio > alt_ant_ratio_th)) {
601251730Sadrian				pdiv_ant_conf->fast_div_bias = 0x1;
602251730Sadrian			} else {
603251730Sadrian				pdiv_ant_conf->fast_div_bias = 0x2;
604251730Sadrian			}
605251730Sadrian			pdiv_ant_conf->main_gaintb   = 0;
606251730Sadrian			pdiv_ant_conf->alt_gaintb    = 0;
607251730Sadrian			break;
608251730Sadrian		case (0x20): //LNA1 A-B
609251730Sadrian			if ((antcomb->scan == 0)
610251730Sadrian			    && (alt_ratio > alt_ant_ratio_th)) {
611251730Sadrian				pdiv_ant_conf->fast_div_bias = 0x1;
612251730Sadrian			} else {
613251730Sadrian				pdiv_ant_conf->fast_div_bias = 0x2;
614251730Sadrian			}
615251730Sadrian			pdiv_ant_conf->main_gaintb   = 0;
616251730Sadrian			pdiv_ant_conf->alt_gaintb    = 0;
617251730Sadrian			break;
618251730Sadrian		case (0x21): //LNA1 LNA2
619251730Sadrian			pdiv_ant_conf->fast_div_bias = 0x1;
620251730Sadrian			pdiv_ant_conf->main_gaintb   = 0;
621251730Sadrian			pdiv_ant_conf->alt_gaintb    = 0;
622251730Sadrian			break;
623251730Sadrian		case (0x23): //LNA1 A+B
624251730Sadrian			if ((antcomb->scan == 0)
625251730Sadrian			    && (alt_ratio > alt_ant_ratio_th)) {
626251730Sadrian				pdiv_ant_conf->fast_div_bias = 0x1;
627251730Sadrian			} else {
628251730Sadrian				pdiv_ant_conf->fast_div_bias = 0x2;
629251730Sadrian			}
630251730Sadrian			pdiv_ant_conf->main_gaintb   = 0;
631251730Sadrian			pdiv_ant_conf->alt_gaintb    = 0;
632251730Sadrian			break;
633251730Sadrian		case (0x30): //A+B A-B
634251730Sadrian			pdiv_ant_conf->fast_div_bias = 0x1;
635251730Sadrian			pdiv_ant_conf->main_gaintb   = 0;
636251730Sadrian			pdiv_ant_conf->alt_gaintb    = 0;
637251730Sadrian			break;
638251730Sadrian		case (0x31): //A+B LNA2
639251730Sadrian			pdiv_ant_conf->fast_div_bias = 0x1;
640251730Sadrian			pdiv_ant_conf->main_gaintb   = 0;
641251730Sadrian			pdiv_ant_conf->alt_gaintb    = 0;
642251730Sadrian			break;
643251730Sadrian		case (0x32): //A+B LNA1
644251730Sadrian			pdiv_ant_conf->fast_div_bias = 0x1;
645251730Sadrian			pdiv_ant_conf->main_gaintb   = 0;
646251730Sadrian			pdiv_ant_conf->alt_gaintb    = 0;
647251730Sadrian			break;
648251730Sadrian		default:
649251730Sadrian			break;
650251730Sadrian		}
651251730Sadrian	} else { /* DEFAULT_ANTDIV_CONFIG_GROUP */
652251730Sadrian		switch ((pdiv_ant_conf->main_lna_conf << 4) | pdiv_ant_conf->alt_lna_conf) {
653251730Sadrian		case (0x01): //A-B LNA2
654251730Sadrian			pdiv_ant_conf->fast_div_bias = 0x3b;
655251730Sadrian			break;
656251730Sadrian		case (0x02): //A-B LNA1
657251730Sadrian			pdiv_ant_conf->fast_div_bias = 0x3d;
658251730Sadrian			break;
659251730Sadrian		case (0x03): //A-B A+B
660251730Sadrian			pdiv_ant_conf->fast_div_bias = 0x1;
661251730Sadrian			break;
662251730Sadrian		case (0x10): //LNA2 A-B
663251730Sadrian			pdiv_ant_conf->fast_div_bias = 0x7;
664251730Sadrian			break;
665251730Sadrian		case (0x12): //LNA2 LNA1
666251730Sadrian			pdiv_ant_conf->fast_div_bias = 0x2;
667251730Sadrian			break;
668251730Sadrian		case (0x13): //LNA2 A+B
669251730Sadrian			pdiv_ant_conf->fast_div_bias = 0x7;
670251730Sadrian			break;
671251730Sadrian		case (0x20): //LNA1 A-B
672251730Sadrian			pdiv_ant_conf->fast_div_bias = 0x6;
673251730Sadrian			break;
674251730Sadrian		case (0x21): //LNA1 LNA2
675251730Sadrian			pdiv_ant_conf->fast_div_bias = 0x0;
676251730Sadrian			break;
677251730Sadrian		case (0x23): //LNA1 A+B
678251730Sadrian			pdiv_ant_conf->fast_div_bias = 0x6;
679251730Sadrian			break;
680251730Sadrian		case (0x30): //A+B A-B
681251730Sadrian			pdiv_ant_conf->fast_div_bias = 0x1;
682251730Sadrian			break;
683251730Sadrian		case (0x31): //A+B LNA2
684251730Sadrian			pdiv_ant_conf->fast_div_bias = 0x3b;
685251730Sadrian			break;
686251730Sadrian		case (0x32): //A+B LNA1
687251730Sadrian			pdiv_ant_conf->fast_div_bias = 0x3d;
688251730Sadrian			break;
689251730Sadrian		default:
690251730Sadrian			break;
691251730Sadrian		}
692251655Sadrian	}
693251655Sadrian}
694251655Sadrian
695251730Sadrian/*
696251730Sadrian * AR9485/AR933x TODO:
697251730Sadrian * + Select a ratio based on whether RSSI is low or not; but I need
698251730Sadrian *   to figure out what "low_rssi_th" is sourced from.
699251730Sadrian * + What's ath_ant_div_comb_alt_check() in the reference driver do?
700251730Sadrian * + .. and there's likely a bunch of other things to include in this.
701251730Sadrian */
702251730Sadrian
703251655Sadrian/* Antenna diversity and combining */
704251655Sadrianvoid
705251655Sadrianath_lna_rx_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs,
706251655Sadrian    unsigned long ticks, int hz)
707251655Sadrian{
708251655Sadrian	HAL_ANT_COMB_CONFIG div_ant_conf;
709251655Sadrian	struct if_ath_ant_comb_state *antcomb = sc->sc_lna_div;
710251655Sadrian	int alt_ratio = 0, alt_rssi_avg = 0, main_rssi_avg = 0, curr_alt_set;
711251655Sadrian	int curr_main_set, curr_bias;
712251655Sadrian	int main_rssi = rs->rs_rssi_ctl[0];
713251655Sadrian	int alt_rssi = rs->rs_rssi_ctl[1];
714251655Sadrian	int rx_ant_conf, main_ant_conf, alt_ant_conf;
715251655Sadrian	HAL_BOOL short_scan = AH_FALSE;
716251655Sadrian
717251655Sadrian	rx_ant_conf = (rs->rs_rssi_ctl[2] >> 4) & ATH_ANT_RX_MASK;
718251655Sadrian	main_ant_conf = (rs->rs_rssi_ctl[2] >> 2) & ATH_ANT_RX_MASK;
719251655Sadrian	alt_ant_conf = (rs->rs_rssi_ctl[2] >> 0) & ATH_ANT_RX_MASK;
720251655Sadrian
721251655Sadrian#if 0
722251655Sadrian	DPRINTF(sc, ATH_DEBUG_DIVERSITY,
723251655Sadrian	    "%s: RSSI %d/%d, conf %x/%x, rxconf %x, LNA: %d; ANT: %d; "
724251655Sadrian	    "FastDiv: %d\n",
725251655Sadrian	    __func__,
726251655Sadrian	    main_rssi,
727251655Sadrian	    alt_rssi,
728251655Sadrian	    main_ant_conf,
729251655Sadrian	    alt_ant_conf,
730251655Sadrian	    rx_ant_conf,
731251655Sadrian	    !!(rs->rs_rssi_ctl[2] & 0x80),
732251655Sadrian	    !!(rs->rs_rssi_ctl[2] & 0x40),
733251655Sadrian	    !!(rs->rs_rssi_ext[2] & 0x40));
734251655Sadrian#endif
735251655Sadrian
736251655Sadrian	/*
737251655Sadrian	 * If LNA diversity combining isn't enabled, don't run this.
738251655Sadrian	 */
739251655Sadrian	if (! sc->sc_dolnadiv)
740251655Sadrian		return;
741251655Sadrian
742251655Sadrian	/*
743251655Sadrian	 * XXX this is ugly, but the HAL code attaches the
744251655Sadrian	 * LNA diversity to the TX antenna settings.
745251655Sadrian	 * I don't know why.
746251655Sadrian	 */
747251655Sadrian	if (sc->sc_txantenna != HAL_ANT_VARIABLE)
748251655Sadrian		return;
749251655Sadrian
750251655Sadrian	/* Record packet only when alt_rssi is positive */
751251655Sadrian	if (main_rssi > 0 && alt_rssi > 0) {
752251655Sadrian		antcomb->total_pkt_count++;
753251655Sadrian		antcomb->main_total_rssi += main_rssi;
754251655Sadrian		antcomb->alt_total_rssi  += alt_rssi;
755251655Sadrian		if (main_ant_conf == rx_ant_conf)
756251655Sadrian			antcomb->main_recv_cnt++;
757251655Sadrian		else
758251655Sadrian			antcomb->alt_recv_cnt++;
759251655Sadrian	}
760251655Sadrian
761251655Sadrian	/* Short scan check */
762251655Sadrian	if (antcomb->scan && antcomb->alt_good) {
763251655Sadrian		if (time_after(ticks, antcomb->scan_start_time +
764251655Sadrian		    msecs_to_jiffies(ATH_ANT_DIV_COMB_SHORT_SCAN_INTR)))
765251655Sadrian			short_scan = AH_TRUE;
766251655Sadrian		else
767251655Sadrian			if (antcomb->total_pkt_count ==
768251655Sadrian			    ATH_ANT_DIV_COMB_SHORT_SCAN_PKTCOUNT) {
769251655Sadrian				alt_ratio = ((antcomb->alt_recv_cnt * 100) /
770251655Sadrian					    antcomb->total_pkt_count);
771251655Sadrian				if (alt_ratio < ATH_ANT_DIV_COMB_ALT_ANT_RATIO)
772251655Sadrian					short_scan = AH_TRUE;
773251655Sadrian			}
774251655Sadrian	}
775251655Sadrian
776251730Sadrian#if 0
777251730Sadrian	DPRINTF(sc, ATH_DEBUG_DIVERSITY,
778251730Sadrian	    "%s: total pkt=%d, aggr=%d, short_scan=%d\n",
779251730Sadrian	    __func__,
780251730Sadrian	    antcomb->total_pkt_count,
781251730Sadrian	    !! (rs->rs_moreaggr),
782251730Sadrian	    !! (short_scan));
783251730Sadrian#endif
784251730Sadrian
785251655Sadrian	if (((antcomb->total_pkt_count < ATH_ANT_DIV_COMB_MAX_PKTCOUNT) ||
786251655Sadrian	    rs->rs_moreaggr) && !short_scan)
787251655Sadrian		return;
788251655Sadrian
789251655Sadrian	if (antcomb->total_pkt_count) {
790251655Sadrian		alt_ratio = ((antcomb->alt_recv_cnt * 100) /
791251655Sadrian			     antcomb->total_pkt_count);
792251655Sadrian		main_rssi_avg = (antcomb->main_total_rssi /
793251655Sadrian				 antcomb->total_pkt_count);
794251655Sadrian		alt_rssi_avg = (antcomb->alt_total_rssi /
795251655Sadrian				 antcomb->total_pkt_count);
796251655Sadrian	}
797251655Sadrian
798251655Sadrian	OS_MEMZERO(&div_ant_conf, sizeof(div_ant_conf));
799251655Sadrian
800251655Sadrian	ath_hal_div_comb_conf_get(sc->sc_ah, &div_ant_conf);
801251655Sadrian	curr_alt_set = div_ant_conf.alt_lna_conf;
802251655Sadrian	curr_main_set = div_ant_conf.main_lna_conf;
803251655Sadrian	curr_bias = div_ant_conf.fast_div_bias;
804251655Sadrian
805251655Sadrian	antcomb->count++;
806251655Sadrian
807251655Sadrian	if (antcomb->count == ATH_ANT_DIV_COMB_MAX_COUNT) {
808251655Sadrian		if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO) {
809251655Sadrian			ath_lnaconf_alt_good_scan(antcomb, &div_ant_conf,
810251655Sadrian						  main_rssi_avg);
811251655Sadrian			antcomb->alt_good = AH_TRUE;
812251655Sadrian		} else {
813251655Sadrian			antcomb->alt_good = AH_FALSE;
814251655Sadrian		}
815251655Sadrian
816251655Sadrian		antcomb->count = 0;
817251655Sadrian		antcomb->scan = AH_TRUE;
818251655Sadrian		antcomb->scan_not_start = AH_TRUE;
819251655Sadrian	}
820251655Sadrian
821251655Sadrian	if (!antcomb->scan) {
822251655Sadrian		if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO) {
823251655Sadrian			if (curr_alt_set == HAL_ANT_DIV_COMB_LNA2) {
824251655Sadrian				/* Switch main and alt LNA */
825251655Sadrian				div_ant_conf.main_lna_conf =
826251655Sadrian						HAL_ANT_DIV_COMB_LNA2;
827251655Sadrian				div_ant_conf.alt_lna_conf  =
828251655Sadrian						HAL_ANT_DIV_COMB_LNA1;
829251655Sadrian			} else if (curr_alt_set == HAL_ANT_DIV_COMB_LNA1) {
830251655Sadrian				div_ant_conf.main_lna_conf =
831251655Sadrian						HAL_ANT_DIV_COMB_LNA1;
832251655Sadrian				div_ant_conf.alt_lna_conf  =
833251655Sadrian						HAL_ANT_DIV_COMB_LNA2;
834251655Sadrian			}
835251655Sadrian
836251655Sadrian			goto div_comb_done;
837251655Sadrian		} else if ((curr_alt_set != HAL_ANT_DIV_COMB_LNA1) &&
838251655Sadrian			   (curr_alt_set != HAL_ANT_DIV_COMB_LNA2)) {
839251655Sadrian			/* Set alt to another LNA */
840251655Sadrian			if (curr_main_set == HAL_ANT_DIV_COMB_LNA2)
841251655Sadrian				div_ant_conf.alt_lna_conf =
842251655Sadrian						HAL_ANT_DIV_COMB_LNA1;
843251655Sadrian			else if (curr_main_set == HAL_ANT_DIV_COMB_LNA1)
844251655Sadrian				div_ant_conf.alt_lna_conf =
845251655Sadrian						HAL_ANT_DIV_COMB_LNA2;
846251655Sadrian
847251655Sadrian			goto div_comb_done;
848251655Sadrian		}
849251655Sadrian
850251655Sadrian		if ((alt_rssi_avg < (main_rssi_avg +
851251730Sadrian		    antcomb->lna1_lna2_delta)))
852251655Sadrian			goto div_comb_done;
853251655Sadrian	}
854251655Sadrian
855251655Sadrian	if (!antcomb->scan_not_start) {
856251655Sadrian		switch (curr_alt_set) {
857251655Sadrian		case HAL_ANT_DIV_COMB_LNA2:
858251655Sadrian			antcomb->rssi_lna2 = alt_rssi_avg;
859251655Sadrian			antcomb->rssi_lna1 = main_rssi_avg;
860251655Sadrian			antcomb->scan = AH_TRUE;
861251655Sadrian			/* set to A+B */
862251655Sadrian			div_ant_conf.main_lna_conf =
863251655Sadrian				HAL_ANT_DIV_COMB_LNA1;
864251655Sadrian			div_ant_conf.alt_lna_conf  =
865251655Sadrian				HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2;
866251655Sadrian			break;
867251655Sadrian		case HAL_ANT_DIV_COMB_LNA1:
868251655Sadrian			antcomb->rssi_lna1 = alt_rssi_avg;
869251655Sadrian			antcomb->rssi_lna2 = main_rssi_avg;
870251655Sadrian			antcomb->scan = AH_TRUE;
871251655Sadrian			/* set to A+B */
872251655Sadrian			div_ant_conf.main_lna_conf = HAL_ANT_DIV_COMB_LNA2;
873251655Sadrian			div_ant_conf.alt_lna_conf  =
874251655Sadrian				HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2;
875251655Sadrian			break;
876251655Sadrian		case HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2:
877251655Sadrian			antcomb->rssi_add = alt_rssi_avg;
878251655Sadrian			antcomb->scan = AH_TRUE;
879251655Sadrian			/* set to A-B */
880251655Sadrian			div_ant_conf.alt_lna_conf =
881251655Sadrian				HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2;
882251655Sadrian			break;
883251655Sadrian		case HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2:
884251655Sadrian			antcomb->rssi_sub = alt_rssi_avg;
885251655Sadrian			antcomb->scan = AH_FALSE;
886251655Sadrian			if (antcomb->rssi_lna2 >
887251655Sadrian			    (antcomb->rssi_lna1 +
888251655Sadrian			    ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)) {
889251655Sadrian				/* use LNA2 as main LNA */
890251655Sadrian				if ((antcomb->rssi_add > antcomb->rssi_lna1) &&
891251655Sadrian				    (antcomb->rssi_add > antcomb->rssi_sub)) {
892251655Sadrian					/* set to A+B */
893251655Sadrian					div_ant_conf.main_lna_conf =
894251655Sadrian						HAL_ANT_DIV_COMB_LNA2;
895251655Sadrian					div_ant_conf.alt_lna_conf  =
896251655Sadrian						HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2;
897251655Sadrian				} else if (antcomb->rssi_sub >
898251655Sadrian					   antcomb->rssi_lna1) {
899251655Sadrian					/* set to A-B */
900251655Sadrian					div_ant_conf.main_lna_conf =
901251655Sadrian						HAL_ANT_DIV_COMB_LNA2;
902251655Sadrian					div_ant_conf.alt_lna_conf =
903251655Sadrian						HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2;
904251655Sadrian				} else {
905251655Sadrian					/* set to LNA1 */
906251655Sadrian					div_ant_conf.main_lna_conf =
907251655Sadrian						HAL_ANT_DIV_COMB_LNA2;
908251655Sadrian					div_ant_conf.alt_lna_conf =
909251655Sadrian						HAL_ANT_DIV_COMB_LNA1;
910251655Sadrian				}
911251655Sadrian			} else {
912251655Sadrian				/* use LNA1 as main LNA */
913251655Sadrian				if ((antcomb->rssi_add > antcomb->rssi_lna2) &&
914251655Sadrian				    (antcomb->rssi_add > antcomb->rssi_sub)) {
915251655Sadrian					/* set to A+B */
916251655Sadrian					div_ant_conf.main_lna_conf =
917251655Sadrian						HAL_ANT_DIV_COMB_LNA1;
918251655Sadrian					div_ant_conf.alt_lna_conf  =
919251655Sadrian						HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2;
920251655Sadrian				} else if (antcomb->rssi_sub >
921251655Sadrian					   antcomb->rssi_lna1) {
922251655Sadrian					/* set to A-B */
923251655Sadrian					div_ant_conf.main_lna_conf =
924251655Sadrian						HAL_ANT_DIV_COMB_LNA1;
925251655Sadrian					div_ant_conf.alt_lna_conf =
926251655Sadrian						HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2;
927251655Sadrian				} else {
928251655Sadrian					/* set to LNA2 */
929251655Sadrian					div_ant_conf.main_lna_conf =
930251655Sadrian						HAL_ANT_DIV_COMB_LNA1;
931251655Sadrian					div_ant_conf.alt_lna_conf =
932251655Sadrian						HAL_ANT_DIV_COMB_LNA2;
933251655Sadrian				}
934251655Sadrian			}
935251655Sadrian			break;
936251655Sadrian		default:
937251655Sadrian			break;
938251655Sadrian		}
939251655Sadrian	} else {
940251655Sadrian		if (!antcomb->alt_good) {
941251655Sadrian			antcomb->scan_not_start = AH_FALSE;
942251655Sadrian			/* Set alt to another LNA */
943251655Sadrian			if (curr_main_set == HAL_ANT_DIV_COMB_LNA2) {
944251655Sadrian				div_ant_conf.main_lna_conf =
945251655Sadrian						HAL_ANT_DIV_COMB_LNA2;
946251655Sadrian				div_ant_conf.alt_lna_conf =
947251655Sadrian						HAL_ANT_DIV_COMB_LNA1;
948251655Sadrian			} else if (curr_main_set == HAL_ANT_DIV_COMB_LNA1) {
949251655Sadrian				div_ant_conf.main_lna_conf =
950251655Sadrian						HAL_ANT_DIV_COMB_LNA1;
951251655Sadrian				div_ant_conf.alt_lna_conf =
952251655Sadrian						HAL_ANT_DIV_COMB_LNA2;
953251655Sadrian			}
954251655Sadrian			goto div_comb_done;
955251655Sadrian		}
956251655Sadrian	}
957251655Sadrian
958251655Sadrian	ath_select_ant_div_from_quick_scan(antcomb, &div_ant_conf,
959251655Sadrian					   main_rssi_avg, alt_rssi_avg,
960251655Sadrian					   alt_ratio);
961251655Sadrian
962251655Sadrian	antcomb->quick_scan_cnt++;
963251655Sadrian
964251655Sadriandiv_comb_done:
965251730Sadrian#if 0
966251655Sadrian	ath_ant_div_conf_fast_divbias(&div_ant_conf);
967251730Sadrian#endif
968251655Sadrian
969251730Sadrian	ath_ant_adjust_fast_divbias(antcomb,
970251730Sadrian	    alt_ratio,
971251730Sadrian	    ATH_ANT_DIV_COMB_ALT_ANT_RATIO,
972251730Sadrian	    div_ant_conf.antdiv_configgroup,
973251730Sadrian	    &div_ant_conf);
974251730Sadrian
975251655Sadrian	ath_hal_div_comb_conf_set(sc->sc_ah, &div_ant_conf);
976251655Sadrian
977251655Sadrian	DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: total_pkt_count=%d\n",
978251655Sadrian	   __func__, antcomb->total_pkt_count);
979251655Sadrian
980251655Sadrian	DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: main_total_rssi=%d\n",
981251655Sadrian	   __func__, antcomb->main_total_rssi);
982251655Sadrian	DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: alt_total_rssi=%d\n",
983251655Sadrian	   __func__, antcomb->alt_total_rssi);
984251655Sadrian
985251655Sadrian	DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: main_rssi_avg=%d\n",
986251655Sadrian	   __func__, main_rssi_avg);
987251655Sadrian	DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: alt_alt_rssi_avg=%d\n",
988251655Sadrian	   __func__, alt_rssi_avg);
989251655Sadrian
990251655Sadrian	DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: main_recv_cnt=%d\n",
991251655Sadrian	   __func__, antcomb->main_recv_cnt);
992251655Sadrian	DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: alt_recv_cnt=%d\n",
993251655Sadrian	   __func__, antcomb->alt_recv_cnt);
994251655Sadrian
995251655Sadrian//	if (curr_alt_set != div_ant_conf.alt_lna_conf)
996251655Sadrian		DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: lna_conf: %x -> %x\n",
997251655Sadrian		    __func__, curr_alt_set, div_ant_conf.alt_lna_conf);
998251655Sadrian//	if (curr_main_set != div_ant_conf.main_lna_conf)
999251655Sadrian		DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: main_lna_conf: %x -> %x\n",
1000251655Sadrian		    __func__, curr_main_set, div_ant_conf.main_lna_conf);
1001251655Sadrian//	if (curr_bias != div_ant_conf.fast_div_bias)
1002251655Sadrian		DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: fast_div_bias: %x -> %x\n",
1003251655Sadrian		    __func__, curr_bias, div_ant_conf.fast_div_bias);
1004251655Sadrian
1005251655Sadrian	antcomb->scan_start_time = ticks;
1006251655Sadrian	antcomb->total_pkt_count = 0;
1007251655Sadrian	antcomb->main_total_rssi = 0;
1008251655Sadrian	antcomb->alt_total_rssi = 0;
1009251655Sadrian	antcomb->main_recv_cnt = 0;
1010251655Sadrian	antcomb->alt_recv_cnt = 0;
1011251655Sadrian}
1012251655Sadrian
1013