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: releng/11.0/sys/dev/ath/if_ath_lna_div.c 298939 2016-05-02 19:56:48Z pfg $
30251655Sadrian */
31251655Sadrian#include <sys/cdefs.h>
32251655Sadrian__FBSDID("$FreeBSD: releng/11.0/sys/dev/ath/if_ath_lna_div.c 298939 2016-05-02 19:56:48Z pfg $");
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>
47257176Sglebius#include <sys/malloc.h>
48251655Sadrian#include <sys/mutex.h>
49251655Sadrian#include <sys/errno.h>
50251655Sadrian
51251655Sadrian#include <machine/bus.h>
52251655Sadrian#include <machine/resource.h>
53251655Sadrian#include <sys/bus.h>
54251655Sadrian
55251655Sadrian#include <sys/socket.h>
56251655Sadrian
57251655Sadrian#include <net/if.h>
58257176Sglebius#include <net/if_var.h>
59251655Sadrian#include <net/if_media.h>
60251655Sadrian#include <net/if_arp.h>
61251655Sadrian#include <net/ethernet.h>		/* XXX for ether_sprintf */
62251655Sadrian
63251655Sadrian#include <net80211/ieee80211_var.h>
64251655Sadrian
65251655Sadrian#include <net/bpf.h>
66251655Sadrian
67251655Sadrian#ifdef INET
68251655Sadrian#include <netinet/in.h>
69251655Sadrian#include <netinet/if_ether.h>
70251655Sadrian#endif
71251655Sadrian
72251655Sadrian#include <dev/ath/if_athvar.h>
73251655Sadrian#include <dev/ath/if_ath_debug.h>
74251655Sadrian#include <dev/ath/if_ath_lna_div.h>
75251655Sadrian
76298939Spfg/* Linux compatibility macros */
77251655Sadrian/*
78251655Sadrian * XXX these don't handle rounding, underflow, overflow, wrapping!
79251655Sadrian */
80251655Sadrian#define	msecs_to_jiffies(a)		( (a) * hz / 1000 )
81251655Sadrian
82251655Sadrian/*
83251655Sadrian * Methods which are required
84251655Sadrian */
85251655Sadrian
86251655Sadrian/*
87251655Sadrian * Attach the LNA diversity to the given interface
88251655Sadrian */
89251655Sadrianint
90251655Sadrianath_lna_div_attach(struct ath_softc *sc)
91251655Sadrian{
92251655Sadrian	struct if_ath_ant_comb_state *ss;
93251730Sadrian	HAL_ANT_COMB_CONFIG div_ant_conf;
94251655Sadrian
95251655Sadrian	/* Only do this if diversity is enabled */
96251655Sadrian	if (! ath_hal_hasdivantcomb(sc->sc_ah))
97251655Sadrian		return (0);
98251655Sadrian
99251655Sadrian	ss = malloc(sizeof(struct if_ath_ant_comb_state),
100251655Sadrian	    M_TEMP, M_WAITOK | M_ZERO);
101251655Sadrian	if (ss == NULL) {
102251655Sadrian		device_printf(sc->sc_dev, "%s: failed to allocate\n",
103251655Sadrian		    __func__);
104251655Sadrian		/* Don't fail at this point */
105251655Sadrian		return (0);
106251655Sadrian	}
107251655Sadrian
108251730Sadrian	/* Fetch the hardware configuration */
109251730Sadrian	OS_MEMZERO(&div_ant_conf, sizeof(div_ant_conf));
110251730Sadrian	ath_hal_div_comb_conf_get(sc->sc_ah, &div_ant_conf);
111251730Sadrian
112251730Sadrian	/* Figure out what the hardware specific bits should be */
113251730Sadrian	if ((div_ant_conf.antdiv_configgroup == HAL_ANTDIV_CONFIG_GROUP_1) ||
114251730Sadrian	    (div_ant_conf.antdiv_configgroup == HAL_ANTDIV_CONFIG_GROUP_2)) {
115251730Sadrian		ss->lna1_lna2_delta = -9;
116251730Sadrian	} else {
117251730Sadrian		ss->lna1_lna2_delta = -3;
118251730Sadrian	}
119251730Sadrian
120251655Sadrian	/* Let's flip this on */
121251655Sadrian	sc->sc_lna_div = ss;
122251655Sadrian	sc->sc_dolnadiv = 1;
123251655Sadrian
124251655Sadrian	return (0);
125251655Sadrian}
126251655Sadrian
127251655Sadrian/*
128251655Sadrian * Detach the LNA diversity state from the given interface
129251655Sadrian */
130251655Sadrianint
131251655Sadrianath_lna_div_detach(struct ath_softc *sc)
132251655Sadrian{
133251655Sadrian	if (sc->sc_lna_div != NULL) {
134251655Sadrian		free(sc->sc_lna_div, M_TEMP);
135251655Sadrian		sc->sc_lna_div = NULL;
136251655Sadrian	}
137251655Sadrian	sc->sc_dolnadiv = 0;
138251655Sadrian	return (0);
139251655Sadrian}
140251655Sadrian
141251655Sadrian/*
142251655Sadrian * Enable LNA diversity on the current channel if it's required.
143251655Sadrian */
144251655Sadrianint
145251655Sadrianath_lna_div_enable(struct ath_softc *sc, const struct ieee80211_channel *chan)
146251655Sadrian{
147251655Sadrian
148251655Sadrian	return (0);
149251655Sadrian}
150251655Sadrian
151251655Sadrian/*
152251655Sadrian * Handle ioctl requests from the diagnostic interface.
153251655Sadrian *
154251655Sadrian * The initial part of this code resembles ath_ioctl_diag();
155251655Sadrian * it's likely a good idea to reduce duplication between
156251655Sadrian * these two routines.
157251655Sadrian */
158251655Sadrianint
159251655Sadrianath_lna_div_ioctl(struct ath_softc *sc, struct ath_diag *ad)
160251655Sadrian{
161251655Sadrian	unsigned int id = ad->ad_id & ATH_DIAG_ID;
162251655Sadrian	void *indata = NULL;
163251655Sadrian	void *outdata = NULL;
164251655Sadrian	u_int32_t insize = ad->ad_in_size;
165251655Sadrian	u_int32_t outsize = ad->ad_out_size;
166251655Sadrian	int error = 0;
167251655Sadrian//	int val;
168251655Sadrian
169251655Sadrian	if (ad->ad_id & ATH_DIAG_IN) {
170251655Sadrian		/*
171251655Sadrian		 * Copy in data.
172251655Sadrian		 */
173251655Sadrian		indata = malloc(insize, M_TEMP, M_NOWAIT);
174251655Sadrian		if (indata == NULL) {
175251655Sadrian			error = ENOMEM;
176251655Sadrian			goto bad;
177251655Sadrian		}
178251655Sadrian		error = copyin(ad->ad_in_data, indata, insize);
179251655Sadrian		if (error)
180251655Sadrian			goto bad;
181251655Sadrian	}
182251655Sadrian	if (ad->ad_id & ATH_DIAG_DYN) {
183251655Sadrian		/*
184251655Sadrian		 * Allocate a buffer for the results (otherwise the HAL
185251655Sadrian		 * returns a pointer to a buffer where we can read the
186251655Sadrian		 * results).  Note that we depend on the HAL leaving this
187251655Sadrian		 * pointer for us to use below in reclaiming the buffer;
188251655Sadrian		 * may want to be more defensive.
189251655Sadrian		 */
190251655Sadrian		outdata = malloc(outsize, M_TEMP, M_NOWAIT);
191251655Sadrian		if (outdata == NULL) {
192251655Sadrian			error = ENOMEM;
193251655Sadrian			goto bad;
194251655Sadrian		}
195251655Sadrian	}
196251655Sadrian	switch (id) {
197251655Sadrian		default:
198251655Sadrian			error = EINVAL;
199251655Sadrian	}
200251655Sadrian	if (outsize < ad->ad_out_size)
201251655Sadrian		ad->ad_out_size = outsize;
202251655Sadrian	if (outdata && copyout(outdata, ad->ad_out_data, ad->ad_out_size))
203251655Sadrian		error = EFAULT;
204251655Sadrianbad:
205251655Sadrian	if ((ad->ad_id & ATH_DIAG_IN) && indata != NULL)
206251655Sadrian		free(indata, M_TEMP);
207251655Sadrian	if ((ad->ad_id & ATH_DIAG_DYN) && outdata != NULL)
208251655Sadrian		free(outdata, M_TEMP);
209251655Sadrian	return (error);
210251655Sadrian}
211251655Sadrian
212272292Sadrian/*
213272292Sadrian * XXX need to low_rssi_thresh config from ath9k, to support CUS198
214272292Sadrian * antenna diversity correctly.
215272292Sadrian */
216251655Sadrianstatic HAL_BOOL
217251655Sadrianath_is_alt_ant_ratio_better(int alt_ratio, int maxdelta, int mindelta,
218251655Sadrian    int main_rssi_avg, int alt_rssi_avg, int pkt_count)
219251655Sadrian{
220251655Sadrian	return (((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
221251655Sadrian		(alt_rssi_avg > main_rssi_avg + maxdelta)) ||
222251655Sadrian		(alt_rssi_avg > main_rssi_avg + mindelta)) && (pkt_count > 50);
223251655Sadrian}
224251655Sadrian
225251655Sadrianstatic void
226251655Sadrianath_lnaconf_alt_good_scan(struct if_ath_ant_comb_state *antcomb,
227251655Sadrian    HAL_ANT_COMB_CONFIG *ant_conf, int main_rssi_avg)
228251655Sadrian{
229251655Sadrian	antcomb->quick_scan_cnt = 0;
230251655Sadrian
231251655Sadrian	if (ant_conf->main_lna_conf == HAL_ANT_DIV_COMB_LNA2)
232251655Sadrian		antcomb->rssi_lna2 = main_rssi_avg;
233251655Sadrian	else if (ant_conf->main_lna_conf == HAL_ANT_DIV_COMB_LNA1)
234251655Sadrian		antcomb->rssi_lna1 = main_rssi_avg;
235251655Sadrian
236251655Sadrian	switch ((ant_conf->main_lna_conf << 4) | ant_conf->alt_lna_conf) {
237251655Sadrian	case (0x10): /* LNA2 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_LNA1;
242251655Sadrian		break;
243251655Sadrian	case (0x20): /* LNA1 A-B */
244251655Sadrian		antcomb->main_conf = HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2;
245251655Sadrian		antcomb->first_quick_scan_conf =
246251655Sadrian			HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2;
247251655Sadrian		antcomb->second_quick_scan_conf = HAL_ANT_DIV_COMB_LNA2;
248251655Sadrian		break;
249251655Sadrian	case (0x21): /* LNA1 LNA2 */
250251655Sadrian		antcomb->main_conf = HAL_ANT_DIV_COMB_LNA2;
251251655Sadrian		antcomb->first_quick_scan_conf =
252251655Sadrian			HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2;
253251655Sadrian		antcomb->second_quick_scan_conf =
254251655Sadrian			HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2;
255251655Sadrian		break;
256251655Sadrian	case (0x12): /* LNA2 LNA1 */
257251655Sadrian		antcomb->main_conf = HAL_ANT_DIV_COMB_LNA1;
258251655Sadrian		antcomb->first_quick_scan_conf =
259251655Sadrian			HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2;
260251655Sadrian		antcomb->second_quick_scan_conf =
261251655Sadrian			HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2;
262251655Sadrian		break;
263251655Sadrian	case (0x13): /* LNA2 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_LNA1;
268251655Sadrian		break;
269251655Sadrian	case (0x23): /* LNA1 A+B */
270251655Sadrian		antcomb->main_conf = HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2;
271251655Sadrian		antcomb->first_quick_scan_conf =
272251655Sadrian			HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2;
273251655Sadrian		antcomb->second_quick_scan_conf = HAL_ANT_DIV_COMB_LNA2;
274251655Sadrian		break;
275251655Sadrian	default:
276251655Sadrian		break;
277251655Sadrian	}
278251655Sadrian}
279251655Sadrian
280251655Sadrianstatic void
281251655Sadrianath_select_ant_div_from_quick_scan(struct if_ath_ant_comb_state *antcomb,
282251655Sadrian    HAL_ANT_COMB_CONFIG *div_ant_conf, int main_rssi_avg,
283251655Sadrian    int alt_rssi_avg, int alt_ratio)
284251655Sadrian{
285251655Sadrian	/* alt_good */
286251655Sadrian	switch (antcomb->quick_scan_cnt) {
287251655Sadrian	case 0:
288251655Sadrian		/* set alt to main, and alt to first conf */
289251655Sadrian		div_ant_conf->main_lna_conf = antcomb->main_conf;
290251655Sadrian		div_ant_conf->alt_lna_conf = antcomb->first_quick_scan_conf;
291251655Sadrian		break;
292251655Sadrian	case 1:
293251655Sadrian		/* set alt to main, and alt to first conf */
294251655Sadrian		div_ant_conf->main_lna_conf = antcomb->main_conf;
295251655Sadrian		div_ant_conf->alt_lna_conf = antcomb->second_quick_scan_conf;
296251655Sadrian		antcomb->rssi_first = main_rssi_avg;
297251655Sadrian		antcomb->rssi_second = alt_rssi_avg;
298251655Sadrian
299251655Sadrian		if (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA1) {
300251655Sadrian			/* main is LNA1 */
301251655Sadrian			if (ath_is_alt_ant_ratio_better(alt_ratio,
302251655Sadrian						ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
303251655Sadrian						ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
304251655Sadrian						main_rssi_avg, alt_rssi_avg,
305251655Sadrian						antcomb->total_pkt_count))
306251655Sadrian				antcomb->first_ratio = AH_TRUE;
307251655Sadrian			else
308251655Sadrian				antcomb->first_ratio = AH_FALSE;
309251655Sadrian		} else if (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA2) {
310251655Sadrian			if (ath_is_alt_ant_ratio_better(alt_ratio,
311251655Sadrian						ATH_ANT_DIV_COMB_LNA1_DELTA_MID,
312251655Sadrian						ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
313251655Sadrian						main_rssi_avg, alt_rssi_avg,
314251655Sadrian						antcomb->total_pkt_count))
315251655Sadrian				antcomb->first_ratio = AH_TRUE;
316251655Sadrian			else
317251655Sadrian				antcomb->first_ratio = AH_FALSE;
318251655Sadrian		} else {
319251655Sadrian			if ((((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
320251655Sadrian			    (alt_rssi_avg > main_rssi_avg +
321251655Sadrian			    ATH_ANT_DIV_COMB_LNA1_DELTA_HI)) ||
322251655Sadrian			    (alt_rssi_avg > main_rssi_avg)) &&
323251655Sadrian			    (antcomb->total_pkt_count > 50))
324251655Sadrian				antcomb->first_ratio = AH_TRUE;
325251655Sadrian			else
326251655Sadrian				antcomb->first_ratio = AH_FALSE;
327251655Sadrian		}
328251655Sadrian		break;
329251655Sadrian	case 2:
330251655Sadrian		antcomb->alt_good = AH_FALSE;
331251655Sadrian		antcomb->scan_not_start = AH_FALSE;
332251655Sadrian		antcomb->scan = AH_FALSE;
333251655Sadrian		antcomb->rssi_first = main_rssi_avg;
334251655Sadrian		antcomb->rssi_third = alt_rssi_avg;
335251655Sadrian
336251655Sadrian		if (antcomb->second_quick_scan_conf == HAL_ANT_DIV_COMB_LNA1)
337251655Sadrian			antcomb->rssi_lna1 = alt_rssi_avg;
338251655Sadrian		else if (antcomb->second_quick_scan_conf ==
339251655Sadrian			 HAL_ANT_DIV_COMB_LNA2)
340251655Sadrian			antcomb->rssi_lna2 = alt_rssi_avg;
341251655Sadrian		else if (antcomb->second_quick_scan_conf ==
342251655Sadrian			 HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2) {
343251655Sadrian			if (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA2)
344251655Sadrian				antcomb->rssi_lna2 = main_rssi_avg;
345251655Sadrian			else if (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA1)
346251655Sadrian				antcomb->rssi_lna1 = main_rssi_avg;
347251655Sadrian		}
348251655Sadrian
349251655Sadrian		if (antcomb->rssi_lna2 > antcomb->rssi_lna1 +
350251655Sadrian		    ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)
351251655Sadrian			div_ant_conf->main_lna_conf = HAL_ANT_DIV_COMB_LNA2;
352251655Sadrian		else
353251655Sadrian			div_ant_conf->main_lna_conf = HAL_ANT_DIV_COMB_LNA1;
354251655Sadrian
355251655Sadrian		if (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA1) {
356251655Sadrian			if (ath_is_alt_ant_ratio_better(alt_ratio,
357251655Sadrian						ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
358251655Sadrian						ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
359251655Sadrian						main_rssi_avg, alt_rssi_avg,
360251655Sadrian						antcomb->total_pkt_count))
361251655Sadrian				antcomb->second_ratio = AH_TRUE;
362251655Sadrian			else
363251655Sadrian				antcomb->second_ratio = AH_FALSE;
364251655Sadrian		} else if (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA2) {
365251655Sadrian			if (ath_is_alt_ant_ratio_better(alt_ratio,
366251655Sadrian						ATH_ANT_DIV_COMB_LNA1_DELTA_MID,
367251655Sadrian						ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
368251655Sadrian						main_rssi_avg, alt_rssi_avg,
369251655Sadrian						antcomb->total_pkt_count))
370251655Sadrian				antcomb->second_ratio = AH_TRUE;
371251655Sadrian			else
372251655Sadrian				antcomb->second_ratio = AH_FALSE;
373251655Sadrian		} else {
374251655Sadrian			if ((((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
375251655Sadrian			    (alt_rssi_avg > main_rssi_avg +
376251655Sadrian			    ATH_ANT_DIV_COMB_LNA1_DELTA_HI)) ||
377251655Sadrian			    (alt_rssi_avg > main_rssi_avg)) &&
378251655Sadrian			    (antcomb->total_pkt_count > 50))
379251655Sadrian				antcomb->second_ratio = AH_TRUE;
380251655Sadrian			else
381251655Sadrian				antcomb->second_ratio = AH_FALSE;
382251655Sadrian		}
383251655Sadrian
384251655Sadrian		/* set alt to the conf with maximun ratio */
385251655Sadrian		if (antcomb->first_ratio && antcomb->second_ratio) {
386251655Sadrian			if (antcomb->rssi_second > antcomb->rssi_third) {
387251655Sadrian				/* first alt*/
388251655Sadrian				if ((antcomb->first_quick_scan_conf ==
389251655Sadrian				    HAL_ANT_DIV_COMB_LNA1) ||
390251655Sadrian				    (antcomb->first_quick_scan_conf ==
391251655Sadrian				    HAL_ANT_DIV_COMB_LNA2))
392251655Sadrian					/* Set alt LNA1 or LNA2*/
393251655Sadrian					if (div_ant_conf->main_lna_conf ==
394251655Sadrian					    HAL_ANT_DIV_COMB_LNA2)
395251655Sadrian						div_ant_conf->alt_lna_conf =
396251655Sadrian							HAL_ANT_DIV_COMB_LNA1;
397251655Sadrian					else
398251655Sadrian						div_ant_conf->alt_lna_conf =
399251655Sadrian							HAL_ANT_DIV_COMB_LNA2;
400251655Sadrian				else
401251655Sadrian					/* Set alt to A+B or A-B */
402251655Sadrian					div_ant_conf->alt_lna_conf =
403251655Sadrian						antcomb->first_quick_scan_conf;
404251655Sadrian			} else if ((antcomb->second_quick_scan_conf ==
405251655Sadrian				   HAL_ANT_DIV_COMB_LNA1) ||
406251655Sadrian				   (antcomb->second_quick_scan_conf ==
407251655Sadrian				   HAL_ANT_DIV_COMB_LNA2)) {
408251655Sadrian				/* Set alt LNA1 or LNA2 */
409251655Sadrian				if (div_ant_conf->main_lna_conf ==
410251655Sadrian				    HAL_ANT_DIV_COMB_LNA2)
411251655Sadrian					div_ant_conf->alt_lna_conf =
412251655Sadrian						HAL_ANT_DIV_COMB_LNA1;
413251655Sadrian				else
414251655Sadrian					div_ant_conf->alt_lna_conf =
415251655Sadrian						HAL_ANT_DIV_COMB_LNA2;
416251655Sadrian			} else {
417251655Sadrian				/* Set alt to A+B or A-B */
418251655Sadrian				div_ant_conf->alt_lna_conf =
419251655Sadrian					antcomb->second_quick_scan_conf;
420251655Sadrian			}
421251655Sadrian		} else if (antcomb->first_ratio) {
422251655Sadrian			/* first alt */
423251655Sadrian			if ((antcomb->first_quick_scan_conf ==
424251655Sadrian			    HAL_ANT_DIV_COMB_LNA1) ||
425251655Sadrian			    (antcomb->first_quick_scan_conf ==
426251655Sadrian			    HAL_ANT_DIV_COMB_LNA2))
427251655Sadrian					/* Set alt LNA1 or LNA2 */
428251655Sadrian				if (div_ant_conf->main_lna_conf ==
429251655Sadrian				    HAL_ANT_DIV_COMB_LNA2)
430251655Sadrian					div_ant_conf->alt_lna_conf =
431251655Sadrian							HAL_ANT_DIV_COMB_LNA1;
432251655Sadrian				else
433251655Sadrian					div_ant_conf->alt_lna_conf =
434251655Sadrian							HAL_ANT_DIV_COMB_LNA2;
435251655Sadrian			else
436251655Sadrian				/* Set alt to A+B or A-B */
437251655Sadrian				div_ant_conf->alt_lna_conf =
438251655Sadrian						antcomb->first_quick_scan_conf;
439251655Sadrian		} else if (antcomb->second_ratio) {
440251655Sadrian				/* second alt */
441251655Sadrian			if ((antcomb->second_quick_scan_conf ==
442251655Sadrian			    HAL_ANT_DIV_COMB_LNA1) ||
443251655Sadrian			    (antcomb->second_quick_scan_conf ==
444251655Sadrian			    HAL_ANT_DIV_COMB_LNA2))
445251655Sadrian				/* Set alt LNA1 or LNA2 */
446251655Sadrian				if (div_ant_conf->main_lna_conf ==
447251655Sadrian				    HAL_ANT_DIV_COMB_LNA2)
448251655Sadrian					div_ant_conf->alt_lna_conf =
449251655Sadrian						HAL_ANT_DIV_COMB_LNA1;
450251655Sadrian				else
451251655Sadrian					div_ant_conf->alt_lna_conf =
452251655Sadrian						HAL_ANT_DIV_COMB_LNA2;
453251655Sadrian			else
454251655Sadrian				/* Set alt to A+B or A-B */
455251655Sadrian				div_ant_conf->alt_lna_conf =
456251655Sadrian						antcomb->second_quick_scan_conf;
457251655Sadrian		} else {
458251655Sadrian			/* main is largest */
459251655Sadrian			if ((antcomb->main_conf == HAL_ANT_DIV_COMB_LNA1) ||
460251655Sadrian			    (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA2))
461251655Sadrian				/* Set alt LNA1 or LNA2 */
462251655Sadrian				if (div_ant_conf->main_lna_conf ==
463251655Sadrian				    HAL_ANT_DIV_COMB_LNA2)
464251655Sadrian					div_ant_conf->alt_lna_conf =
465251655Sadrian							HAL_ANT_DIV_COMB_LNA1;
466251655Sadrian				else
467251655Sadrian					div_ant_conf->alt_lna_conf =
468251655Sadrian							HAL_ANT_DIV_COMB_LNA2;
469251655Sadrian			else
470251655Sadrian				/* Set alt to A+B or A-B */
471251655Sadrian				div_ant_conf->alt_lna_conf = antcomb->main_conf;
472251655Sadrian		}
473251655Sadrian		break;
474251655Sadrian	default:
475251655Sadrian		break;
476251655Sadrian	}
477251655Sadrian}
478251655Sadrian
479251655Sadrianstatic void
480251730Sadrianath_ant_adjust_fast_divbias(struct if_ath_ant_comb_state *antcomb,
481251730Sadrian    int alt_ratio, int alt_ant_ratio_th, u_int config_group,
482251730Sadrian    HAL_ANT_COMB_CONFIG *pdiv_ant_conf)
483251655Sadrian{
484251730Sadrian
485251730Sadrian	if (config_group == HAL_ANTDIV_CONFIG_GROUP_1) {
486251730Sadrian		switch ((pdiv_ant_conf->main_lna_conf << 4)
487251730Sadrian		    | pdiv_ant_conf->alt_lna_conf) {
488251730Sadrian		case (0x01): //A-B LNA2
489251730Sadrian			pdiv_ant_conf->fast_div_bias = 0x1;
490251730Sadrian			pdiv_ant_conf->main_gaintb   = 0;
491251730Sadrian			pdiv_ant_conf->alt_gaintb    = 0;
492251730Sadrian			break;
493251730Sadrian		case (0x02): //A-B LNA1
494251730Sadrian			pdiv_ant_conf->fast_div_bias = 0x1;
495251730Sadrian			pdiv_ant_conf->main_gaintb   = 0;
496251730Sadrian			pdiv_ant_conf->alt_gaintb    = 0;
497251730Sadrian			break;
498251730Sadrian		case (0x03): //A-B A+B
499251730Sadrian			pdiv_ant_conf->fast_div_bias = 0x1;
500251730Sadrian			pdiv_ant_conf->main_gaintb   = 0;
501251730Sadrian			pdiv_ant_conf->alt_gaintb    = 0;
502251730Sadrian			break;
503251730Sadrian		case (0x10): //LNA2 A-B
504251730Sadrian			if ((antcomb->scan == 0)
505251730Sadrian			    && (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) {
506251730Sadrian				pdiv_ant_conf->fast_div_bias = 0x3f;
507251730Sadrian			} else {
508251730Sadrian				pdiv_ant_conf->fast_div_bias = 0x1;
509251730Sadrian			}
510251730Sadrian			pdiv_ant_conf->main_gaintb   = 0;
511251730Sadrian			pdiv_ant_conf->alt_gaintb    = 0;
512251730Sadrian			break;
513251730Sadrian		case (0x12): //LNA2 LNA1
514251730Sadrian			pdiv_ant_conf->fast_div_bias = 0x1;
515251730Sadrian			pdiv_ant_conf->main_gaintb   = 0;
516251730Sadrian			pdiv_ant_conf->alt_gaintb    = 0;
517251730Sadrian			break;
518251730Sadrian			case (0x13): //LNA2 A+B
519251730Sadrian			if ((antcomb->scan == 0)
520251730Sadrian			    && (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) {
521251730Sadrian				pdiv_ant_conf->fast_div_bias = 0x3f;
522251730Sadrian			} else {
523251730Sadrian				pdiv_ant_conf->fast_div_bias = 0x1;
524251730Sadrian			}
525251730Sadrian			pdiv_ant_conf->main_gaintb   = 0;
526251730Sadrian			pdiv_ant_conf->alt_gaintb    = 0;
527251730Sadrian			break;
528251730Sadrian		case (0x20): //LNA1 A-B
529251730Sadrian			if ((antcomb->scan == 0)
530251730Sadrian			    && (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) {
531251730Sadrian				pdiv_ant_conf->fast_div_bias = 0x3f;
532251730Sadrian			} else {
533251730Sadrian				pdiv_ant_conf->fast_div_bias = 0x1;
534251730Sadrian			}
535251730Sadrian			pdiv_ant_conf->main_gaintb   = 0;
536251730Sadrian			pdiv_ant_conf->alt_gaintb    = 0;
537251730Sadrian			break;
538251730Sadrian		case (0x21): //LNA1 LNA2
539251730Sadrian			pdiv_ant_conf->fast_div_bias = 0x1;
540251730Sadrian			pdiv_ant_conf->main_gaintb   = 0;
541251730Sadrian			pdiv_ant_conf->alt_gaintb    = 0;
542251730Sadrian			break;
543251730Sadrian		case (0x23): //LNA1 A+B
544251730Sadrian			if ((antcomb->scan == 0)
545251730Sadrian			    && (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) {
546251730Sadrian				pdiv_ant_conf->fast_div_bias = 0x3f;
547251730Sadrian			} else {
548251730Sadrian				pdiv_ant_conf->fast_div_bias = 0x1;
549251730Sadrian			}
550251730Sadrian			pdiv_ant_conf->main_gaintb   = 0;
551251730Sadrian			pdiv_ant_conf->alt_gaintb    = 0;
552251730Sadrian			break;
553251730Sadrian		case (0x30): //A+B A-B
554251730Sadrian			pdiv_ant_conf->fast_div_bias = 0x1;
555251730Sadrian			pdiv_ant_conf->main_gaintb   = 0;
556251730Sadrian			pdiv_ant_conf->alt_gaintb    = 0;
557251730Sadrian			break;
558251730Sadrian		case (0x31): //A+B LNA2
559251730Sadrian			pdiv_ant_conf->fast_div_bias = 0x1;
560251730Sadrian			pdiv_ant_conf->main_gaintb   = 0;
561251730Sadrian			pdiv_ant_conf->alt_gaintb    = 0;
562251730Sadrian			break;
563251730Sadrian		case (0x32): //A+B LNA1
564251730Sadrian			pdiv_ant_conf->fast_div_bias = 0x1;
565251730Sadrian			pdiv_ant_conf->main_gaintb   = 0;
566251730Sadrian			pdiv_ant_conf->alt_gaintb    = 0;
567251730Sadrian			break;
568251730Sadrian		default:
569251730Sadrian			break;
570251730Sadrian		}
571251730Sadrian	} else if (config_group == HAL_ANTDIV_CONFIG_GROUP_2) {
572251730Sadrian		switch ((pdiv_ant_conf->main_lna_conf << 4)
573251730Sadrian		    | pdiv_ant_conf->alt_lna_conf) {
574251730Sadrian		case (0x01): //A-B LNA2
575251730Sadrian			pdiv_ant_conf->fast_div_bias = 0x1;
576251730Sadrian			pdiv_ant_conf->main_gaintb   = 0;
577251730Sadrian			pdiv_ant_conf->alt_gaintb    = 0;
578251730Sadrian			break;
579251730Sadrian		case (0x02): //A-B LNA1
580251730Sadrian			pdiv_ant_conf->fast_div_bias = 0x1;
581251730Sadrian			pdiv_ant_conf->main_gaintb   = 0;
582251730Sadrian			pdiv_ant_conf->alt_gaintb    = 0;
583251730Sadrian			break;
584251730Sadrian		case (0x03): //A-B A+B
585251730Sadrian			pdiv_ant_conf->fast_div_bias = 0x1;
586251730Sadrian			pdiv_ant_conf->main_gaintb   = 0;
587251730Sadrian			pdiv_ant_conf->alt_gaintb    = 0;
588251730Sadrian			break;
589251730Sadrian		case (0x10): //LNA2 A-B
590251730Sadrian			if ((antcomb->scan == 0)
591251730Sadrian			    && (alt_ratio > alt_ant_ratio_th)) {
592251730Sadrian				pdiv_ant_conf->fast_div_bias = 0x1;
593251730Sadrian			} else {
594251730Sadrian				pdiv_ant_conf->fast_div_bias = 0x2;
595251730Sadrian			}
596251730Sadrian			pdiv_ant_conf->main_gaintb   = 0;
597251730Sadrian			pdiv_ant_conf->alt_gaintb    = 0;
598251730Sadrian			break;
599251730Sadrian		case (0x12): //LNA2 LNA1
600251730Sadrian			pdiv_ant_conf->fast_div_bias = 0x1;
601251730Sadrian			pdiv_ant_conf->main_gaintb   = 0;
602251730Sadrian			pdiv_ant_conf->alt_gaintb    = 0;
603251730Sadrian			break;
604251730Sadrian		case (0x13): //LNA2 A+B
605251730Sadrian			if ((antcomb->scan == 0)
606251730Sadrian			    && (alt_ratio > alt_ant_ratio_th)) {
607251730Sadrian				pdiv_ant_conf->fast_div_bias = 0x1;
608251730Sadrian			} else {
609251730Sadrian				pdiv_ant_conf->fast_div_bias = 0x2;
610251730Sadrian			}
611251730Sadrian			pdiv_ant_conf->main_gaintb   = 0;
612251730Sadrian			pdiv_ant_conf->alt_gaintb    = 0;
613251730Sadrian			break;
614251730Sadrian		case (0x20): //LNA1 A-B
615251730Sadrian			if ((antcomb->scan == 0)
616251730Sadrian			    && (alt_ratio > alt_ant_ratio_th)) {
617251730Sadrian				pdiv_ant_conf->fast_div_bias = 0x1;
618251730Sadrian			} else {
619251730Sadrian				pdiv_ant_conf->fast_div_bias = 0x2;
620251730Sadrian			}
621251730Sadrian			pdiv_ant_conf->main_gaintb   = 0;
622251730Sadrian			pdiv_ant_conf->alt_gaintb    = 0;
623251730Sadrian			break;
624251730Sadrian		case (0x21): //LNA1 LNA2
625251730Sadrian			pdiv_ant_conf->fast_div_bias = 0x1;
626251730Sadrian			pdiv_ant_conf->main_gaintb   = 0;
627251730Sadrian			pdiv_ant_conf->alt_gaintb    = 0;
628251730Sadrian			break;
629251730Sadrian		case (0x23): //LNA1 A+B
630251730Sadrian			if ((antcomb->scan == 0)
631251730Sadrian			    && (alt_ratio > alt_ant_ratio_th)) {
632251730Sadrian				pdiv_ant_conf->fast_div_bias = 0x1;
633251730Sadrian			} else {
634251730Sadrian				pdiv_ant_conf->fast_div_bias = 0x2;
635251730Sadrian			}
636251730Sadrian			pdiv_ant_conf->main_gaintb   = 0;
637251730Sadrian			pdiv_ant_conf->alt_gaintb    = 0;
638251730Sadrian			break;
639251730Sadrian		case (0x30): //A+B A-B
640251730Sadrian			pdiv_ant_conf->fast_div_bias = 0x1;
641251730Sadrian			pdiv_ant_conf->main_gaintb   = 0;
642251730Sadrian			pdiv_ant_conf->alt_gaintb    = 0;
643251730Sadrian			break;
644251730Sadrian		case (0x31): //A+B LNA2
645251730Sadrian			pdiv_ant_conf->fast_div_bias = 0x1;
646251730Sadrian			pdiv_ant_conf->main_gaintb   = 0;
647251730Sadrian			pdiv_ant_conf->alt_gaintb    = 0;
648251730Sadrian			break;
649251730Sadrian		case (0x32): //A+B LNA1
650251730Sadrian			pdiv_ant_conf->fast_div_bias = 0x1;
651251730Sadrian			pdiv_ant_conf->main_gaintb   = 0;
652251730Sadrian			pdiv_ant_conf->alt_gaintb    = 0;
653251730Sadrian			break;
654251730Sadrian		default:
655251730Sadrian			break;
656251730Sadrian		}
657251730Sadrian	} else { /* DEFAULT_ANTDIV_CONFIG_GROUP */
658251730Sadrian		switch ((pdiv_ant_conf->main_lna_conf << 4) | pdiv_ant_conf->alt_lna_conf) {
659251730Sadrian		case (0x01): //A-B LNA2
660251730Sadrian			pdiv_ant_conf->fast_div_bias = 0x3b;
661251730Sadrian			break;
662251730Sadrian		case (0x02): //A-B LNA1
663251730Sadrian			pdiv_ant_conf->fast_div_bias = 0x3d;
664251730Sadrian			break;
665251730Sadrian		case (0x03): //A-B A+B
666251730Sadrian			pdiv_ant_conf->fast_div_bias = 0x1;
667251730Sadrian			break;
668251730Sadrian		case (0x10): //LNA2 A-B
669251730Sadrian			pdiv_ant_conf->fast_div_bias = 0x7;
670251730Sadrian			break;
671251730Sadrian		case (0x12): //LNA2 LNA1
672251730Sadrian			pdiv_ant_conf->fast_div_bias = 0x2;
673251730Sadrian			break;
674251730Sadrian		case (0x13): //LNA2 A+B
675251730Sadrian			pdiv_ant_conf->fast_div_bias = 0x7;
676251730Sadrian			break;
677251730Sadrian		case (0x20): //LNA1 A-B
678251730Sadrian			pdiv_ant_conf->fast_div_bias = 0x6;
679251730Sadrian			break;
680251730Sadrian		case (0x21): //LNA1 LNA2
681251730Sadrian			pdiv_ant_conf->fast_div_bias = 0x0;
682251730Sadrian			break;
683251730Sadrian		case (0x23): //LNA1 A+B
684251730Sadrian			pdiv_ant_conf->fast_div_bias = 0x6;
685251730Sadrian			break;
686251730Sadrian		case (0x30): //A+B A-B
687251730Sadrian			pdiv_ant_conf->fast_div_bias = 0x1;
688251730Sadrian			break;
689251730Sadrian		case (0x31): //A+B LNA2
690251730Sadrian			pdiv_ant_conf->fast_div_bias = 0x3b;
691251730Sadrian			break;
692251730Sadrian		case (0x32): //A+B LNA1
693251730Sadrian			pdiv_ant_conf->fast_div_bias = 0x3d;
694251730Sadrian			break;
695251730Sadrian		default:
696251730Sadrian			break;
697251730Sadrian		}
698251655Sadrian	}
699251655Sadrian}
700251655Sadrian
701251730Sadrian/*
702251730Sadrian * AR9485/AR933x TODO:
703251730Sadrian * + Select a ratio based on whether RSSI is low or not; but I need
704251730Sadrian *   to figure out what "low_rssi_th" is sourced from.
705251730Sadrian * + What's ath_ant_div_comb_alt_check() in the reference driver do?
706251730Sadrian * + .. and there's likely a bunch of other things to include in this.
707251730Sadrian */
708251730Sadrian
709251655Sadrian/* Antenna diversity and combining */
710251655Sadrianvoid
711251655Sadrianath_lna_rx_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs,
712251655Sadrian    unsigned long ticks, int hz)
713251655Sadrian{
714251655Sadrian	HAL_ANT_COMB_CONFIG div_ant_conf;
715251655Sadrian	struct if_ath_ant_comb_state *antcomb = sc->sc_lna_div;
716251655Sadrian	int alt_ratio = 0, alt_rssi_avg = 0, main_rssi_avg = 0, curr_alt_set;
717251655Sadrian	int curr_main_set, curr_bias;
718251655Sadrian	int main_rssi = rs->rs_rssi_ctl[0];
719251655Sadrian	int alt_rssi = rs->rs_rssi_ctl[1];
720251655Sadrian	int rx_ant_conf, main_ant_conf, alt_ant_conf;
721251655Sadrian	HAL_BOOL short_scan = AH_FALSE;
722251655Sadrian
723251655Sadrian	rx_ant_conf = (rs->rs_rssi_ctl[2] >> 4) & ATH_ANT_RX_MASK;
724251655Sadrian	main_ant_conf = (rs->rs_rssi_ctl[2] >> 2) & ATH_ANT_RX_MASK;
725251655Sadrian	alt_ant_conf = (rs->rs_rssi_ctl[2] >> 0) & ATH_ANT_RX_MASK;
726251655Sadrian
727251655Sadrian#if 0
728251655Sadrian	DPRINTF(sc, ATH_DEBUG_DIVERSITY,
729251655Sadrian	    "%s: RSSI %d/%d, conf %x/%x, rxconf %x, LNA: %d; ANT: %d; "
730251655Sadrian	    "FastDiv: %d\n",
731251655Sadrian	    __func__,
732251655Sadrian	    main_rssi,
733251655Sadrian	    alt_rssi,
734251655Sadrian	    main_ant_conf,
735251655Sadrian	    alt_ant_conf,
736251655Sadrian	    rx_ant_conf,
737251655Sadrian	    !!(rs->rs_rssi_ctl[2] & 0x80),
738251655Sadrian	    !!(rs->rs_rssi_ctl[2] & 0x40),
739251655Sadrian	    !!(rs->rs_rssi_ext[2] & 0x40));
740251655Sadrian#endif
741251655Sadrian
742251655Sadrian	/*
743251655Sadrian	 * If LNA diversity combining isn't enabled, don't run this.
744251655Sadrian	 */
745251655Sadrian	if (! sc->sc_dolnadiv)
746251655Sadrian		return;
747251655Sadrian
748251655Sadrian	/*
749251655Sadrian	 * XXX this is ugly, but the HAL code attaches the
750251655Sadrian	 * LNA diversity to the TX antenna settings.
751251655Sadrian	 * I don't know why.
752251655Sadrian	 */
753251655Sadrian	if (sc->sc_txantenna != HAL_ANT_VARIABLE)
754251655Sadrian		return;
755251655Sadrian
756251655Sadrian	/* Record packet only when alt_rssi is positive */
757251655Sadrian	if (main_rssi > 0 && alt_rssi > 0) {
758251655Sadrian		antcomb->total_pkt_count++;
759251655Sadrian		antcomb->main_total_rssi += main_rssi;
760251655Sadrian		antcomb->alt_total_rssi  += alt_rssi;
761251655Sadrian		if (main_ant_conf == rx_ant_conf)
762251655Sadrian			antcomb->main_recv_cnt++;
763251655Sadrian		else
764251655Sadrian			antcomb->alt_recv_cnt++;
765251655Sadrian	}
766251655Sadrian
767251655Sadrian	/* Short scan check */
768251655Sadrian	if (antcomb->scan && antcomb->alt_good) {
769297405Sadrian		if (ieee80211_time_after(ticks, antcomb->scan_start_time +
770251655Sadrian		    msecs_to_jiffies(ATH_ANT_DIV_COMB_SHORT_SCAN_INTR)))
771251655Sadrian			short_scan = AH_TRUE;
772251655Sadrian		else
773251655Sadrian			if (antcomb->total_pkt_count ==
774251655Sadrian			    ATH_ANT_DIV_COMB_SHORT_SCAN_PKTCOUNT) {
775251655Sadrian				alt_ratio = ((antcomb->alt_recv_cnt * 100) /
776251655Sadrian					    antcomb->total_pkt_count);
777251655Sadrian				if (alt_ratio < ATH_ANT_DIV_COMB_ALT_ANT_RATIO)
778251655Sadrian					short_scan = AH_TRUE;
779251655Sadrian			}
780251655Sadrian	}
781251655Sadrian
782251730Sadrian#if 0
783251730Sadrian	DPRINTF(sc, ATH_DEBUG_DIVERSITY,
784251730Sadrian	    "%s: total pkt=%d, aggr=%d, short_scan=%d\n",
785251730Sadrian	    __func__,
786251730Sadrian	    antcomb->total_pkt_count,
787251730Sadrian	    !! (rs->rs_moreaggr),
788251730Sadrian	    !! (short_scan));
789251730Sadrian#endif
790251730Sadrian
791251655Sadrian	if (((antcomb->total_pkt_count < ATH_ANT_DIV_COMB_MAX_PKTCOUNT) ||
792251655Sadrian	    rs->rs_moreaggr) && !short_scan)
793251655Sadrian		return;
794251655Sadrian
795251655Sadrian	if (antcomb->total_pkt_count) {
796251655Sadrian		alt_ratio = ((antcomb->alt_recv_cnt * 100) /
797251655Sadrian			     antcomb->total_pkt_count);
798251655Sadrian		main_rssi_avg = (antcomb->main_total_rssi /
799251655Sadrian				 antcomb->total_pkt_count);
800251655Sadrian		alt_rssi_avg = (antcomb->alt_total_rssi /
801251655Sadrian				 antcomb->total_pkt_count);
802251655Sadrian	}
803251655Sadrian
804251655Sadrian	OS_MEMZERO(&div_ant_conf, sizeof(div_ant_conf));
805251655Sadrian
806251655Sadrian	ath_hal_div_comb_conf_get(sc->sc_ah, &div_ant_conf);
807251655Sadrian	curr_alt_set = div_ant_conf.alt_lna_conf;
808251655Sadrian	curr_main_set = div_ant_conf.main_lna_conf;
809251655Sadrian	curr_bias = div_ant_conf.fast_div_bias;
810251655Sadrian
811251655Sadrian	antcomb->count++;
812251655Sadrian
813251655Sadrian	if (antcomb->count == ATH_ANT_DIV_COMB_MAX_COUNT) {
814251655Sadrian		if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO) {
815251655Sadrian			ath_lnaconf_alt_good_scan(antcomb, &div_ant_conf,
816251655Sadrian						  main_rssi_avg);
817251655Sadrian			antcomb->alt_good = AH_TRUE;
818251655Sadrian		} else {
819251655Sadrian			antcomb->alt_good = AH_FALSE;
820251655Sadrian		}
821251655Sadrian
822251655Sadrian		antcomb->count = 0;
823251655Sadrian		antcomb->scan = AH_TRUE;
824251655Sadrian		antcomb->scan_not_start = AH_TRUE;
825251655Sadrian	}
826251655Sadrian
827251655Sadrian	if (!antcomb->scan) {
828251655Sadrian		if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO) {
829251655Sadrian			if (curr_alt_set == HAL_ANT_DIV_COMB_LNA2) {
830251655Sadrian				/* Switch main and alt LNA */
831251655Sadrian				div_ant_conf.main_lna_conf =
832251655Sadrian						HAL_ANT_DIV_COMB_LNA2;
833251655Sadrian				div_ant_conf.alt_lna_conf  =
834251655Sadrian						HAL_ANT_DIV_COMB_LNA1;
835251655Sadrian			} else if (curr_alt_set == HAL_ANT_DIV_COMB_LNA1) {
836251655Sadrian				div_ant_conf.main_lna_conf =
837251655Sadrian						HAL_ANT_DIV_COMB_LNA1;
838251655Sadrian				div_ant_conf.alt_lna_conf  =
839251655Sadrian						HAL_ANT_DIV_COMB_LNA2;
840251655Sadrian			}
841251655Sadrian
842251655Sadrian			goto div_comb_done;
843251655Sadrian		} else if ((curr_alt_set != HAL_ANT_DIV_COMB_LNA1) &&
844251655Sadrian			   (curr_alt_set != HAL_ANT_DIV_COMB_LNA2)) {
845251655Sadrian			/* Set alt to another LNA */
846251655Sadrian			if (curr_main_set == HAL_ANT_DIV_COMB_LNA2)
847251655Sadrian				div_ant_conf.alt_lna_conf =
848251655Sadrian						HAL_ANT_DIV_COMB_LNA1;
849251655Sadrian			else if (curr_main_set == HAL_ANT_DIV_COMB_LNA1)
850251655Sadrian				div_ant_conf.alt_lna_conf =
851251655Sadrian						HAL_ANT_DIV_COMB_LNA2;
852251655Sadrian
853251655Sadrian			goto div_comb_done;
854251655Sadrian		}
855251655Sadrian
856251655Sadrian		if ((alt_rssi_avg < (main_rssi_avg +
857251730Sadrian		    antcomb->lna1_lna2_delta)))
858251655Sadrian			goto div_comb_done;
859251655Sadrian	}
860251655Sadrian
861251655Sadrian	if (!antcomb->scan_not_start) {
862251655Sadrian		switch (curr_alt_set) {
863251655Sadrian		case HAL_ANT_DIV_COMB_LNA2:
864251655Sadrian			antcomb->rssi_lna2 = alt_rssi_avg;
865251655Sadrian			antcomb->rssi_lna1 = main_rssi_avg;
866251655Sadrian			antcomb->scan = AH_TRUE;
867251655Sadrian			/* set to A+B */
868251655Sadrian			div_ant_conf.main_lna_conf =
869251655Sadrian				HAL_ANT_DIV_COMB_LNA1;
870251655Sadrian			div_ant_conf.alt_lna_conf  =
871251655Sadrian				HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2;
872251655Sadrian			break;
873251655Sadrian		case HAL_ANT_DIV_COMB_LNA1:
874251655Sadrian			antcomb->rssi_lna1 = alt_rssi_avg;
875251655Sadrian			antcomb->rssi_lna2 = main_rssi_avg;
876251655Sadrian			antcomb->scan = AH_TRUE;
877251655Sadrian			/* set to A+B */
878251655Sadrian			div_ant_conf.main_lna_conf = HAL_ANT_DIV_COMB_LNA2;
879251655Sadrian			div_ant_conf.alt_lna_conf  =
880251655Sadrian				HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2;
881251655Sadrian			break;
882251655Sadrian		case HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2:
883251655Sadrian			antcomb->rssi_add = alt_rssi_avg;
884251655Sadrian			antcomb->scan = AH_TRUE;
885251655Sadrian			/* set to A-B */
886251655Sadrian			div_ant_conf.alt_lna_conf =
887251655Sadrian				HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2;
888251655Sadrian			break;
889251655Sadrian		case HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2:
890251655Sadrian			antcomb->rssi_sub = alt_rssi_avg;
891251655Sadrian			antcomb->scan = AH_FALSE;
892251655Sadrian			if (antcomb->rssi_lna2 >
893251655Sadrian			    (antcomb->rssi_lna1 +
894251655Sadrian			    ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)) {
895251655Sadrian				/* use LNA2 as main LNA */
896251655Sadrian				if ((antcomb->rssi_add > antcomb->rssi_lna1) &&
897251655Sadrian				    (antcomb->rssi_add > antcomb->rssi_sub)) {
898251655Sadrian					/* set to A+B */
899251655Sadrian					div_ant_conf.main_lna_conf =
900251655Sadrian						HAL_ANT_DIV_COMB_LNA2;
901251655Sadrian					div_ant_conf.alt_lna_conf  =
902251655Sadrian						HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2;
903251655Sadrian				} else if (antcomb->rssi_sub >
904251655Sadrian					   antcomb->rssi_lna1) {
905251655Sadrian					/* set to A-B */
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_MINUS_LNA2;
910251655Sadrian				} else {
911251655Sadrian					/* set to LNA1 */
912251655Sadrian					div_ant_conf.main_lna_conf =
913251655Sadrian						HAL_ANT_DIV_COMB_LNA2;
914251655Sadrian					div_ant_conf.alt_lna_conf =
915251655Sadrian						HAL_ANT_DIV_COMB_LNA1;
916251655Sadrian				}
917251655Sadrian			} else {
918251655Sadrian				/* use LNA1 as main LNA */
919251655Sadrian				if ((antcomb->rssi_add > antcomb->rssi_lna2) &&
920251655Sadrian				    (antcomb->rssi_add > antcomb->rssi_sub)) {
921251655Sadrian					/* set to A+B */
922251655Sadrian					div_ant_conf.main_lna_conf =
923251655Sadrian						HAL_ANT_DIV_COMB_LNA1;
924251655Sadrian					div_ant_conf.alt_lna_conf  =
925251655Sadrian						HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2;
926251655Sadrian				} else if (antcomb->rssi_sub >
927251655Sadrian					   antcomb->rssi_lna1) {
928251655Sadrian					/* set to A-B */
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_LNA1_MINUS_LNA2;
933251655Sadrian				} else {
934251655Sadrian					/* set to LNA2 */
935251655Sadrian					div_ant_conf.main_lna_conf =
936251655Sadrian						HAL_ANT_DIV_COMB_LNA1;
937251655Sadrian					div_ant_conf.alt_lna_conf =
938251655Sadrian						HAL_ANT_DIV_COMB_LNA2;
939251655Sadrian				}
940251655Sadrian			}
941251655Sadrian			break;
942251655Sadrian		default:
943251655Sadrian			break;
944251655Sadrian		}
945251655Sadrian	} else {
946251655Sadrian		if (!antcomb->alt_good) {
947251655Sadrian			antcomb->scan_not_start = AH_FALSE;
948251655Sadrian			/* Set alt to another LNA */
949251655Sadrian			if (curr_main_set == HAL_ANT_DIV_COMB_LNA2) {
950251655Sadrian				div_ant_conf.main_lna_conf =
951251655Sadrian						HAL_ANT_DIV_COMB_LNA2;
952251655Sadrian				div_ant_conf.alt_lna_conf =
953251655Sadrian						HAL_ANT_DIV_COMB_LNA1;
954251655Sadrian			} else if (curr_main_set == HAL_ANT_DIV_COMB_LNA1) {
955251655Sadrian				div_ant_conf.main_lna_conf =
956251655Sadrian						HAL_ANT_DIV_COMB_LNA1;
957251655Sadrian				div_ant_conf.alt_lna_conf =
958251655Sadrian						HAL_ANT_DIV_COMB_LNA2;
959251655Sadrian			}
960251655Sadrian			goto div_comb_done;
961251655Sadrian		}
962251655Sadrian	}
963251655Sadrian
964251655Sadrian	ath_select_ant_div_from_quick_scan(antcomb, &div_ant_conf,
965251655Sadrian					   main_rssi_avg, alt_rssi_avg,
966251655Sadrian					   alt_ratio);
967251655Sadrian
968251655Sadrian	antcomb->quick_scan_cnt++;
969251655Sadrian
970251655Sadriandiv_comb_done:
971251730Sadrian#if 0
972251655Sadrian	ath_ant_div_conf_fast_divbias(&div_ant_conf);
973251730Sadrian#endif
974251655Sadrian
975251730Sadrian	ath_ant_adjust_fast_divbias(antcomb,
976251730Sadrian	    alt_ratio,
977251730Sadrian	    ATH_ANT_DIV_COMB_ALT_ANT_RATIO,
978251730Sadrian	    div_ant_conf.antdiv_configgroup,
979251730Sadrian	    &div_ant_conf);
980251730Sadrian
981251655Sadrian	ath_hal_div_comb_conf_set(sc->sc_ah, &div_ant_conf);
982251655Sadrian
983251655Sadrian	DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: total_pkt_count=%d\n",
984251655Sadrian	   __func__, antcomb->total_pkt_count);
985251655Sadrian
986251655Sadrian	DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: main_total_rssi=%d\n",
987251655Sadrian	   __func__, antcomb->main_total_rssi);
988251655Sadrian	DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: alt_total_rssi=%d\n",
989251655Sadrian	   __func__, antcomb->alt_total_rssi);
990251655Sadrian
991251655Sadrian	DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: main_rssi_avg=%d\n",
992251655Sadrian	   __func__, main_rssi_avg);
993251655Sadrian	DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: alt_alt_rssi_avg=%d\n",
994251655Sadrian	   __func__, alt_rssi_avg);
995251655Sadrian
996251655Sadrian	DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: main_recv_cnt=%d\n",
997251655Sadrian	   __func__, antcomb->main_recv_cnt);
998251655Sadrian	DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: alt_recv_cnt=%d\n",
999251655Sadrian	   __func__, antcomb->alt_recv_cnt);
1000251655Sadrian
1001251655Sadrian//	if (curr_alt_set != div_ant_conf.alt_lna_conf)
1002251655Sadrian		DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: lna_conf: %x -> %x\n",
1003251655Sadrian		    __func__, curr_alt_set, div_ant_conf.alt_lna_conf);
1004251655Sadrian//	if (curr_main_set != div_ant_conf.main_lna_conf)
1005251655Sadrian		DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: main_lna_conf: %x -> %x\n",
1006251655Sadrian		    __func__, curr_main_set, div_ant_conf.main_lna_conf);
1007251655Sadrian//	if (curr_bias != div_ant_conf.fast_div_bias)
1008251655Sadrian		DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: fast_div_bias: %x -> %x\n",
1009251655Sadrian		    __func__, curr_bias, div_ant_conf.fast_div_bias);
1010251655Sadrian
1011251655Sadrian	antcomb->scan_start_time = ticks;
1012251655Sadrian	antcomb->total_pkt_count = 0;
1013251655Sadrian	antcomb->main_total_rssi = 0;
1014251655Sadrian	antcomb->alt_total_rssi = 0;
1015251655Sadrian	antcomb->main_recv_cnt = 0;
1016251655Sadrian	antcomb->alt_recv_cnt = 0;
1017251655Sadrian}
1018251655Sadrian
1019