ah.c revision 220444
1185377Ssam/*
2187831Ssam * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
3185377Ssam * Copyright (c) 2002-2008 Atheros Communications, Inc.
4185377Ssam *
5185377Ssam * Permission to use, copy, modify, and/or distribute this software for any
6185377Ssam * purpose with or without fee is hereby granted, provided that the above
7185377Ssam * copyright notice and this permission notice appear in all copies.
8185377Ssam *
9185377Ssam * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10185377Ssam * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11185377Ssam * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12185377Ssam * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13185377Ssam * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14185377Ssam * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15185377Ssam * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16185377Ssam *
17186018Ssam * $FreeBSD: head/sys/dev/ath/ath_hal/ah.c 220444 2011-04-08 08:49:50Z adrian $
18185377Ssam */
19185377Ssam#include "opt_ah.h"
20185377Ssam
21185377Ssam#include "ah.h"
22185377Ssam#include "ah_internal.h"
23185377Ssam#include "ah_devid.h"
24220298Sadrian#include "ah_eeprom.h"			/* for 5ghz fast clock flag */
25185377Ssam
26188968Ssam#include "ar5416/ar5416reg.h"		/* NB: includes ar5212reg.h */
27188968Ssam
28185406Ssam/* linker set of registered chips */
29185406SsamOS_SET_DECLARE(ah_chips, struct ath_hal_chip);
30185406Ssam
31185406Ssam/*
32185406Ssam * Check the set of registered chips to see if any recognize
33185406Ssam * the device as one they can support.
34185406Ssam */
35185406Ssamconst char*
36185406Ssamath_hal_probe(uint16_t vendorid, uint16_t devid)
37185377Ssam{
38186018Ssam	struct ath_hal_chip * const *pchip;
39185377Ssam
40185417Ssam	OS_SET_FOREACH(pchip, ah_chips) {
41185406Ssam		const char *name = (*pchip)->probe(vendorid, devid);
42185406Ssam		if (name != AH_NULL)
43185406Ssam			return name;
44185377Ssam	}
45185377Ssam	return AH_NULL;
46185377Ssam}
47185377Ssam
48185377Ssam/*
49185377Ssam * Attach detects device chip revisions, initializes the hwLayer
50185377Ssam * function list, reads EEPROM information,
51185377Ssam * selects reset vectors, and performs a short self test.
52185377Ssam * Any failures will return an error that should cause a hardware
53185377Ssam * disable.
54185377Ssam */
55185377Ssamstruct ath_hal*
56185377Ssamath_hal_attach(uint16_t devid, HAL_SOFTC sc,
57217624Sadrian	HAL_BUS_TAG st, HAL_BUS_HANDLE sh, uint16_t *eepromdata, HAL_STATUS *error)
58185377Ssam{
59186018Ssam	struct ath_hal_chip * const *pchip;
60185377Ssam
61185417Ssam	OS_SET_FOREACH(pchip, ah_chips) {
62185406Ssam		struct ath_hal_chip *chip = *pchip;
63185406Ssam		struct ath_hal *ah;
64185406Ssam
65185406Ssam		/* XXX don't have vendorid, assume atheros one works */
66185406Ssam		if (chip->probe(ATHEROS_VENDOR_ID, devid) == AH_NULL)
67185406Ssam			continue;
68217624Sadrian		ah = chip->attach(devid, sc, st, sh, eepromdata, error);
69185406Ssam		if (ah != AH_NULL) {
70185406Ssam			/* copy back private state to public area */
71185406Ssam			ah->ah_devid = AH_PRIVATE(ah)->ah_devid;
72185406Ssam			ah->ah_subvendorid = AH_PRIVATE(ah)->ah_subvendorid;
73185406Ssam			ah->ah_macVersion = AH_PRIVATE(ah)->ah_macVersion;
74185406Ssam			ah->ah_macRev = AH_PRIVATE(ah)->ah_macRev;
75185406Ssam			ah->ah_phyRev = AH_PRIVATE(ah)->ah_phyRev;
76185406Ssam			ah->ah_analog5GhzRev = AH_PRIVATE(ah)->ah_analog5GhzRev;
77185406Ssam			ah->ah_analog2GhzRev = AH_PRIVATE(ah)->ah_analog2GhzRev;
78185406Ssam			return ah;
79185406Ssam		}
80185377Ssam	}
81185406Ssam	return AH_NULL;
82185406Ssam}
83185406Ssam
84188968Ssamconst char *
85188968Ssamath_hal_mac_name(struct ath_hal *ah)
86188968Ssam{
87188968Ssam	switch (ah->ah_macVersion) {
88188968Ssam	case AR_SREV_VERSION_CRETE:
89188968Ssam	case AR_SREV_VERSION_MAUI_1:
90188968Ssam		return "5210";
91188968Ssam	case AR_SREV_VERSION_MAUI_2:
92188968Ssam	case AR_SREV_VERSION_OAHU:
93188968Ssam		return "5211";
94188968Ssam	case AR_SREV_VERSION_VENICE:
95188968Ssam		return "5212";
96188968Ssam	case AR_SREV_VERSION_GRIFFIN:
97188968Ssam		return "2413";
98188968Ssam	case AR_SREV_VERSION_CONDOR:
99188968Ssam		return "5424";
100188968Ssam	case AR_SREV_VERSION_EAGLE:
101188968Ssam		return "5413";
102188968Ssam	case AR_SREV_VERSION_COBRA:
103188968Ssam		return "2415";
104188968Ssam	case AR_SREV_2425:
105188968Ssam		return "2425";
106188968Ssam	case AR_SREV_2417:
107188968Ssam		return "2417";
108188968Ssam	case AR_XSREV_VERSION_OWL_PCI:
109188968Ssam		return "5416";
110188968Ssam	case AR_XSREV_VERSION_OWL_PCIE:
111188968Ssam		return "5418";
112188968Ssam	case AR_XSREV_VERSION_SOWL:
113188968Ssam		return "9160";
114188968Ssam	case AR_XSREV_VERSION_MERLIN:
115188968Ssam		return "9280";
116188968Ssam	case AR_XSREV_VERSION_KITE:
117188968Ssam		return "9285";
118188968Ssam	}
119188968Ssam	return "????";
120188968Ssam}
121188968Ssam
122187831Ssam/*
123187831Ssam * Return the mask of available modes based on the hardware capabilities.
124187831Ssam */
125187831Ssamu_int
126187831Ssamath_hal_getwirelessmodes(struct ath_hal*ah)
127187831Ssam{
128187831Ssam	return ath_hal_getWirelessModes(ah);
129187831Ssam}
130187831Ssam
131185406Ssam/* linker set of registered RF backends */
132185406SsamOS_SET_DECLARE(ah_rfs, struct ath_hal_rf);
133185406Ssam
134185406Ssam/*
135185406Ssam * Check the set of registered RF backends to see if
136185406Ssam * any recognize the device as one they can support.
137185406Ssam */
138185406Ssamstruct ath_hal_rf *
139185406Ssamath_hal_rfprobe(struct ath_hal *ah, HAL_STATUS *ecode)
140185406Ssam{
141186018Ssam	struct ath_hal_rf * const *prf;
142185406Ssam
143185417Ssam	OS_SET_FOREACH(prf, ah_rfs) {
144185406Ssam		struct ath_hal_rf *rf = *prf;
145185406Ssam		if (rf->probe(ah))
146185406Ssam			return rf;
147185377Ssam	}
148185406Ssam	*ecode = HAL_ENOTSUPP;
149185406Ssam	return AH_NULL;
150185377Ssam}
151185377Ssam
152188968Ssamconst char *
153188968Ssamath_hal_rf_name(struct ath_hal *ah)
154188968Ssam{
155188968Ssam	switch (ah->ah_analog5GhzRev & AR_RADIO_SREV_MAJOR) {
156188968Ssam	case 0:			/* 5210 */
157188968Ssam		return "5110";	/* NB: made up */
158188968Ssam	case AR_RAD5111_SREV_MAJOR:
159188968Ssam	case AR_RAD5111_SREV_PROD:
160188968Ssam		return "5111";
161188968Ssam	case AR_RAD2111_SREV_MAJOR:
162188968Ssam		return "2111";
163188968Ssam	case AR_RAD5112_SREV_MAJOR:
164188968Ssam	case AR_RAD5112_SREV_2_0:
165188968Ssam	case AR_RAD5112_SREV_2_1:
166188968Ssam		return "5112";
167188968Ssam	case AR_RAD2112_SREV_MAJOR:
168188968Ssam	case AR_RAD2112_SREV_2_0:
169188968Ssam	case AR_RAD2112_SREV_2_1:
170188968Ssam		return "2112";
171188968Ssam	case AR_RAD2413_SREV_MAJOR:
172188968Ssam		return "2413";
173188968Ssam	case AR_RAD5413_SREV_MAJOR:
174188968Ssam		return "5413";
175188968Ssam	case AR_RAD2316_SREV_MAJOR:
176188968Ssam		return "2316";
177188968Ssam	case AR_RAD2317_SREV_MAJOR:
178188968Ssam		return "2317";
179188968Ssam	case AR_RAD5424_SREV_MAJOR:
180188968Ssam		return "5424";
181188968Ssam
182188968Ssam	case AR_RAD5133_SREV_MAJOR:
183188968Ssam		return "5133";
184188968Ssam	case AR_RAD2133_SREV_MAJOR:
185188968Ssam		return "2133";
186188968Ssam	case AR_RAD5122_SREV_MAJOR:
187188968Ssam		return "5122";
188188968Ssam	case AR_RAD2122_SREV_MAJOR:
189188968Ssam		return "2122";
190188968Ssam	}
191188968Ssam	return "????";
192188968Ssam}
193188968Ssam
194185377Ssam/*
195185377Ssam * Poll the register looking for a specific value.
196185377Ssam */
197185377SsamHAL_BOOL
198185377Ssamath_hal_wait(struct ath_hal *ah, u_int reg, uint32_t mask, uint32_t val)
199185377Ssam{
200185377Ssam#define	AH_TIMEOUT	1000
201217622Sadrian	return ath_hal_waitfor(ah, reg, mask, val, AH_TIMEOUT);
202217622Sadrian#undef AH_TIMEOUT
203217622Sadrian}
204217622Sadrian
205217622SadrianHAL_BOOL
206217622Sadrianath_hal_waitfor(struct ath_hal *ah, u_int reg, uint32_t mask, uint32_t val, uint32_t timeout)
207217622Sadrian{
208185377Ssam	int i;
209185377Ssam
210217622Sadrian	for (i = 0; i < timeout; i++) {
211185377Ssam		if ((OS_REG_READ(ah, reg) & mask) == val)
212185377Ssam			return AH_TRUE;
213185377Ssam		OS_DELAY(10);
214185377Ssam	}
215185377Ssam	HALDEBUG(ah, HAL_DEBUG_REGIO | HAL_DEBUG_PHYIO,
216185377Ssam	    "%s: timeout on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n",
217185377Ssam	    __func__, reg, OS_REG_READ(ah, reg), mask, val);
218185377Ssam	return AH_FALSE;
219185377Ssam}
220185377Ssam
221185377Ssam/*
222185377Ssam * Reverse the bits starting at the low bit for a value of
223185377Ssam * bit_count in size
224185377Ssam */
225185377Ssamuint32_t
226185377Ssamath_hal_reverseBits(uint32_t val, uint32_t n)
227185377Ssam{
228185377Ssam	uint32_t retval;
229185377Ssam	int i;
230185377Ssam
231185377Ssam	for (i = 0, retval = 0; i < n; i++) {
232185377Ssam		retval = (retval << 1) | (val & 1);
233185377Ssam		val >>= 1;
234185377Ssam	}
235185377Ssam	return retval;
236185377Ssam}
237185377Ssam
238218011Sadrian/* 802.11n related timing definitions */
239218011Sadrian
240218011Sadrian#define	OFDM_PLCP_BITS	22
241218011Sadrian#define	HT_L_STF	8
242218011Sadrian#define	HT_L_LTF	8
243218011Sadrian#define	HT_L_SIG	4
244218011Sadrian#define	HT_SIG		8
245218011Sadrian#define	HT_STF		4
246218011Sadrian#define	HT_LTF(n)	((n) * 4)
247218011Sadrian
248218011Sadrian#define	HT_RC_2_MCS(_rc)	((_rc) & 0xf)
249218011Sadrian#define	HT_RC_2_STREAMS(_rc)	((((_rc) & 0x78) >> 3) + 1)
250218011Sadrian#define	IS_HT_RATE(_rc)		( (_rc) & IEEE80211_RATE_MCS)
251218011Sadrian
252185377Ssam/*
253218011Sadrian * Calculate the duration of a packet whether it is 11n or legacy.
254218011Sadrian */
255218011Sadrianuint32_t
256218011Sadrianath_hal_pkt_txtime(struct ath_hal *ah, const HAL_RATE_TABLE *rates, uint32_t frameLen,
257218011Sadrian    uint16_t rateix, HAL_BOOL isht40, HAL_BOOL shortPreamble)
258218011Sadrian{
259218011Sadrian	uint8_t rc;
260218011Sadrian	int numStreams;
261218011Sadrian
262218011Sadrian	rc = rates->info[rateix].rateCode;
263218011Sadrian
264218011Sadrian	/* Legacy rate? Return the old way */
265218011Sadrian	if (! IS_HT_RATE(rc))
266218011Sadrian		return ath_hal_computetxtime(ah, rates, frameLen, rateix, shortPreamble);
267218011Sadrian
268218011Sadrian	/* 11n frame - extract out the number of spatial streams */
269218011Sadrian	numStreams = HT_RC_2_STREAMS(rc);
270218011Sadrian	KASSERT(numStreams == 1 || numStreams == 2, ("number of spatial streams needs to be 1 or 2: MCS rate 0x%x!", rateix));
271218011Sadrian
272218011Sadrian	return ath_computedur_ht(frameLen, rc, numStreams, isht40, shortPreamble);
273218011Sadrian}
274218011Sadrian
275218011Sadrian/*
276218011Sadrian * Calculate the transmit duration of an 11n frame.
277218011Sadrian * This only works for MCS0->MCS15.
278218011Sadrian */
279218011Sadrianuint32_t
280218011Sadrianath_computedur_ht(uint32_t frameLen, uint16_t rate, int streams, HAL_BOOL isht40,
281218011Sadrian    HAL_BOOL isShortGI)
282218011Sadrian{
283218011Sadrian	static const uint16_t ht20_bps[16] = {
284218011Sadrian	    26, 52, 78, 104, 156, 208, 234, 260,
285218011Sadrian	    52, 104, 156, 208, 312, 416, 468, 520
286218011Sadrian	};
287218011Sadrian	static const uint16_t ht40_bps[16] = {
288218011Sadrian	    54, 108, 162, 216, 324, 432, 486, 540,
289218011Sadrian	    108, 216, 324, 432, 648, 864, 972, 1080,
290218011Sadrian	};
291218011Sadrian	uint32_t bitsPerSymbol, numBits, numSymbols, txTime;
292218011Sadrian
293218011Sadrian	KASSERT(rate & IEEE80211_RATE_MCS, ("not mcs %d", rate));
294218011Sadrian	KASSERT((rate &~ IEEE80211_RATE_MCS) < 16, ("bad mcs 0x%x", rate));
295218011Sadrian
296218011Sadrian	if (isht40)
297218011Sadrian		bitsPerSymbol = ht40_bps[rate & 0xf];
298218011Sadrian	else
299218011Sadrian		bitsPerSymbol = ht20_bps[rate & 0xf];
300218011Sadrian	numBits = OFDM_PLCP_BITS + (frameLen << 3);
301218011Sadrian	numSymbols = howmany(numBits, bitsPerSymbol);
302218011Sadrian	if (isShortGI)
303218011Sadrian		txTime = ((numSymbols * 18) + 4) / 5;   /* 3.6us */
304218011Sadrian	else
305218011Sadrian		txTime = numSymbols * 4;                /* 4us */
306218011Sadrian	return txTime + HT_L_STF + HT_L_LTF +
307218011Sadrian	    HT_L_SIG + HT_SIG + HT_STF + HT_LTF(streams);
308218011Sadrian}
309218011Sadrian
310218011Sadrian/*
311185377Ssam * Compute the time to transmit a frame of length frameLen bytes
312185377Ssam * using the specified rate, phy, and short preamble setting.
313185377Ssam */
314185377Ssamuint16_t
315185377Ssamath_hal_computetxtime(struct ath_hal *ah,
316185377Ssam	const HAL_RATE_TABLE *rates, uint32_t frameLen, uint16_t rateix,
317185377Ssam	HAL_BOOL shortPreamble)
318185377Ssam{
319185377Ssam	uint32_t bitsPerSymbol, numBits, numSymbols, phyTime, txTime;
320185377Ssam	uint32_t kbps;
321185377Ssam
322218923Sadrian	/* Warn if this function is called for 11n rates; it should not be! */
323218923Sadrian	if (IS_HT_RATE(rates->info[rateix].rateCode))
324218923Sadrian		ath_hal_printf(ah, "%s: MCS rate? (index %d; hwrate 0x%x)\n",
325218923Sadrian		    __func__, rateix, rates->info[rateix].rateCode);
326218923Sadrian
327185377Ssam	kbps = rates->info[rateix].rateKbps;
328185377Ssam	/*
329185377Ssam	 * index can be invalid duting dynamic Turbo transitions.
330187831Ssam	 * XXX
331185377Ssam	 */
332187831Ssam	if (kbps == 0)
333187831Ssam		return 0;
334185377Ssam	switch (rates->info[rateix].phy) {
335185377Ssam	case IEEE80211_T_CCK:
336185377Ssam		phyTime		= CCK_PREAMBLE_BITS + CCK_PLCP_BITS;
337185377Ssam		if (shortPreamble && rates->info[rateix].shortPreamble)
338185377Ssam			phyTime >>= 1;
339185377Ssam		numBits		= frameLen << 3;
340185377Ssam		txTime		= CCK_SIFS_TIME + phyTime
341185377Ssam				+ ((numBits * 1000)/kbps);
342185377Ssam		break;
343185377Ssam	case IEEE80211_T_OFDM:
344188773Ssam		bitsPerSymbol	= (kbps * OFDM_SYMBOL_TIME) / 1000;
345188773Ssam		HALASSERT(bitsPerSymbol != 0);
346185377Ssam
347188773Ssam		numBits		= OFDM_PLCP_BITS + (frameLen << 3);
348188773Ssam		numSymbols	= howmany(numBits, bitsPerSymbol);
349188773Ssam		txTime		= OFDM_SIFS_TIME
350188773Ssam				+ OFDM_PREAMBLE_TIME
351188773Ssam				+ (numSymbols * OFDM_SYMBOL_TIME);
352188773Ssam		break;
353188773Ssam	case IEEE80211_T_OFDM_HALF:
354188773Ssam		bitsPerSymbol	= (kbps * OFDM_HALF_SYMBOL_TIME) / 1000;
355188773Ssam		HALASSERT(bitsPerSymbol != 0);
356185377Ssam
357188773Ssam		numBits		= OFDM_HALF_PLCP_BITS + (frameLen << 3);
358188773Ssam		numSymbols	= howmany(numBits, bitsPerSymbol);
359188773Ssam		txTime		= OFDM_HALF_SIFS_TIME
360188773Ssam				+ OFDM_HALF_PREAMBLE_TIME
361188773Ssam				+ (numSymbols * OFDM_HALF_SYMBOL_TIME);
362188773Ssam		break;
363188773Ssam	case IEEE80211_T_OFDM_QUARTER:
364188773Ssam		bitsPerSymbol	= (kbps * OFDM_QUARTER_SYMBOL_TIME) / 1000;
365188773Ssam		HALASSERT(bitsPerSymbol != 0);
366185377Ssam
367188773Ssam		numBits		= OFDM_QUARTER_PLCP_BITS + (frameLen << 3);
368188773Ssam		numSymbols	= howmany(numBits, bitsPerSymbol);
369188773Ssam		txTime		= OFDM_QUARTER_SIFS_TIME
370188773Ssam				+ OFDM_QUARTER_PREAMBLE_TIME
371188773Ssam				+ (numSymbols * OFDM_QUARTER_SYMBOL_TIME);
372185377Ssam		break;
373185377Ssam	case IEEE80211_T_TURBO:
374191022Ssam		bitsPerSymbol	= (kbps * TURBO_SYMBOL_TIME) / 1000;
375185377Ssam		HALASSERT(bitsPerSymbol != 0);
376185377Ssam
377188773Ssam		numBits		= TURBO_PLCP_BITS + (frameLen << 3);
378188773Ssam		numSymbols	= howmany(numBits, bitsPerSymbol);
379188773Ssam		txTime		= TURBO_SIFS_TIME
380188773Ssam				+ TURBO_PREAMBLE_TIME
381188773Ssam				+ (numSymbols * TURBO_SYMBOL_TIME);
382185377Ssam		break;
383185377Ssam	default:
384185377Ssam		HALDEBUG(ah, HAL_DEBUG_PHYIO,
385185377Ssam		    "%s: unknown phy %u (rate ix %u)\n",
386185377Ssam		    __func__, rates->info[rateix].phy, rateix);
387185377Ssam		txTime = 0;
388185377Ssam		break;
389185377Ssam	}
390185377Ssam	return txTime;
391185377Ssam}
392185377Ssam
393185377Ssamtypedef enum {
394185377Ssam	WIRELESS_MODE_11a   = 0,
395185377Ssam	WIRELESS_MODE_TURBO = 1,
396185377Ssam	WIRELESS_MODE_11b   = 2,
397185377Ssam	WIRELESS_MODE_11g   = 3,
398185377Ssam	WIRELESS_MODE_108g  = 4,
399185377Ssam
400185377Ssam	WIRELESS_MODE_MAX
401185377Ssam} WIRELESS_MODE;
402185377Ssam
403185377Ssamstatic WIRELESS_MODE
404187831Ssamath_hal_chan2wmode(struct ath_hal *ah, const struct ieee80211_channel *chan)
405185377Ssam{
406187831Ssam	if (IEEE80211_IS_CHAN_B(chan))
407185377Ssam		return WIRELESS_MODE_11b;
408187831Ssam	if (IEEE80211_IS_CHAN_G(chan))
409185377Ssam		return WIRELESS_MODE_11g;
410187831Ssam	if (IEEE80211_IS_CHAN_108G(chan))
411185377Ssam		return WIRELESS_MODE_108g;
412187831Ssam	if (IEEE80211_IS_CHAN_TURBO(chan))
413185377Ssam		return WIRELESS_MODE_TURBO;
414185377Ssam	return WIRELESS_MODE_11a;
415185377Ssam}
416185377Ssam
417185377Ssam/*
418185377Ssam * Convert between microseconds and core system clocks.
419185377Ssam */
420185377Ssam                                     /* 11a Turbo  11b  11g  108g */
421185377Ssamstatic const uint8_t CLOCK_RATE[]  = { 40,  80,   22,  44,   88  };
422185377Ssam
423220298Sadrian#define	CLOCK_FAST_RATE_5GHZ_OFDM	44
424220298Sadrian
425185377Ssamu_int
426185377Ssamath_hal_mac_clks(struct ath_hal *ah, u_int usecs)
427185377Ssam{
428187831Ssam	const struct ieee80211_channel *c = AH_PRIVATE(ah)->ah_curchan;
429185377Ssam	u_int clks;
430185377Ssam
431185377Ssam	/* NB: ah_curchan may be null when called attach time */
432220298Sadrian	/* XXX merlin and later specific workaround - 5ghz fast clock is 44 */
433220298Sadrian	if (c != AH_NULL && IS_5GHZ_FAST_CLOCK_EN(ah, c)) {
434220298Sadrian		clks = usecs * CLOCK_FAST_RATE_5GHZ_OFDM;
435220298Sadrian		if (IEEE80211_IS_CHAN_HT40(c))
436220298Sadrian			clks <<= 1;
437220298Sadrian	} else if (c != AH_NULL) {
438185377Ssam		clks = usecs * CLOCK_RATE[ath_hal_chan2wmode(ah, c)];
439187831Ssam		if (IEEE80211_IS_CHAN_HT40(c))
440185377Ssam			clks <<= 1;
441185377Ssam	} else
442185377Ssam		clks = usecs * CLOCK_RATE[WIRELESS_MODE_11b];
443185377Ssam	return clks;
444185377Ssam}
445185377Ssam
446185377Ssamu_int
447185377Ssamath_hal_mac_usec(struct ath_hal *ah, u_int clks)
448185377Ssam{
449187831Ssam	const struct ieee80211_channel *c = AH_PRIVATE(ah)->ah_curchan;
450185377Ssam	u_int usec;
451185377Ssam
452185377Ssam	/* NB: ah_curchan may be null when called attach time */
453220298Sadrian	/* XXX merlin and later specific workaround - 5ghz fast clock is 44 */
454220298Sadrian	if (c != AH_NULL && IS_5GHZ_FAST_CLOCK_EN(ah, c)) {
455220298Sadrian		usec = clks / CLOCK_FAST_RATE_5GHZ_OFDM;
456220298Sadrian		if (IEEE80211_IS_CHAN_HT40(c))
457220298Sadrian			usec >>= 1;
458220298Sadrian	} else if (c != AH_NULL) {
459185377Ssam		usec = clks / CLOCK_RATE[ath_hal_chan2wmode(ah, c)];
460187831Ssam		if (IEEE80211_IS_CHAN_HT40(c))
461185377Ssam			usec >>= 1;
462185377Ssam	} else
463185377Ssam		usec = clks / CLOCK_RATE[WIRELESS_MODE_11b];
464185377Ssam	return usec;
465185377Ssam}
466185377Ssam
467185377Ssam/*
468185377Ssam * Setup a h/w rate table's reverse lookup table and
469185377Ssam * fill in ack durations.  This routine is called for
470185377Ssam * each rate table returned through the ah_getRateTable
471185377Ssam * method.  The reverse lookup tables are assumed to be
472185377Ssam * initialized to zero (or at least the first entry).
473185377Ssam * We use this as a key that indicates whether or not
474185377Ssam * we've previously setup the reverse lookup table.
475185377Ssam *
476185377Ssam * XXX not reentrant, but shouldn't matter
477185377Ssam */
478185377Ssamvoid
479185377Ssamath_hal_setupratetable(struct ath_hal *ah, HAL_RATE_TABLE *rt)
480185377Ssam{
481185377Ssam#define	N(a)	(sizeof(a)/sizeof(a[0]))
482185377Ssam	int i;
483185377Ssam
484185377Ssam	if (rt->rateCodeToIndex[0] != 0)	/* already setup */
485185377Ssam		return;
486185377Ssam	for (i = 0; i < N(rt->rateCodeToIndex); i++)
487185377Ssam		rt->rateCodeToIndex[i] = (uint8_t) -1;
488185377Ssam	for (i = 0; i < rt->rateCount; i++) {
489185377Ssam		uint8_t code = rt->info[i].rateCode;
490185377Ssam		uint8_t cix = rt->info[i].controlRate;
491185377Ssam
492185377Ssam		HALASSERT(code < N(rt->rateCodeToIndex));
493185377Ssam		rt->rateCodeToIndex[code] = i;
494185377Ssam		HALASSERT((code | rt->info[i].shortPreamble) <
495185377Ssam		    N(rt->rateCodeToIndex));
496185377Ssam		rt->rateCodeToIndex[code | rt->info[i].shortPreamble] = i;
497185377Ssam		/*
498185377Ssam		 * XXX for 11g the control rate to use for 5.5 and 11 Mb/s
499185377Ssam		 *     depends on whether they are marked as basic rates;
500185377Ssam		 *     the static tables are setup with an 11b-compatible
501185377Ssam		 *     2Mb/s rate which will work but is suboptimal
502185377Ssam		 */
503185377Ssam		rt->info[i].lpAckDuration = ath_hal_computetxtime(ah, rt,
504185377Ssam			WLAN_CTRL_FRAME_SIZE, cix, AH_FALSE);
505185377Ssam		rt->info[i].spAckDuration = ath_hal_computetxtime(ah, rt,
506185377Ssam			WLAN_CTRL_FRAME_SIZE, cix, AH_TRUE);
507185377Ssam	}
508185377Ssam#undef N
509185377Ssam}
510185377Ssam
511185377SsamHAL_STATUS
512185377Ssamath_hal_getcapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type,
513185377Ssam	uint32_t capability, uint32_t *result)
514185377Ssam{
515185377Ssam	const HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps;
516185377Ssam
517185377Ssam	switch (type) {
518185377Ssam	case HAL_CAP_REG_DMN:		/* regulatory domain */
519185377Ssam		*result = AH_PRIVATE(ah)->ah_currentRD;
520185377Ssam		return HAL_OK;
521185377Ssam	case HAL_CAP_CIPHER:		/* cipher handled in hardware */
522185377Ssam	case HAL_CAP_TKIP_MIC:		/* handle TKIP MIC in hardware */
523185377Ssam		return HAL_ENOTSUPP;
524185377Ssam	case HAL_CAP_TKIP_SPLIT:	/* hardware TKIP uses split keys */
525185377Ssam		return HAL_ENOTSUPP;
526185377Ssam	case HAL_CAP_PHYCOUNTERS:	/* hardware PHY error counters */
527185377Ssam		return pCap->halHwPhyCounterSupport ? HAL_OK : HAL_ENXIO;
528185377Ssam	case HAL_CAP_WME_TKIPMIC:   /* hardware can do TKIP MIC when WMM is turned on */
529185377Ssam		return HAL_ENOTSUPP;
530185377Ssam	case HAL_CAP_DIVERSITY:		/* hardware supports fast diversity */
531185377Ssam		return HAL_ENOTSUPP;
532185377Ssam	case HAL_CAP_KEYCACHE_SIZE:	/* hardware key cache size */
533185377Ssam		*result =  pCap->halKeyCacheSize;
534185377Ssam		return HAL_OK;
535185377Ssam	case HAL_CAP_NUM_TXQUEUES:	/* number of hardware tx queues */
536185377Ssam		*result = pCap->halTotalQueues;
537185377Ssam		return HAL_OK;
538185377Ssam	case HAL_CAP_VEOL:		/* hardware supports virtual EOL */
539185377Ssam		return pCap->halVEOLSupport ? HAL_OK : HAL_ENOTSUPP;
540185377Ssam	case HAL_CAP_PSPOLL:		/* hardware PS-Poll support works */
541185377Ssam		return pCap->halPSPollBroken ? HAL_ENOTSUPP : HAL_OK;
542185377Ssam	case HAL_CAP_COMPRESSION:
543185377Ssam		return pCap->halCompressSupport ? HAL_OK : HAL_ENOTSUPP;
544185377Ssam	case HAL_CAP_BURST:
545185377Ssam		return pCap->halBurstSupport ? HAL_OK : HAL_ENOTSUPP;
546185377Ssam	case HAL_CAP_FASTFRAME:
547185377Ssam		return pCap->halFastFramesSupport ? HAL_OK : HAL_ENOTSUPP;
548185377Ssam	case HAL_CAP_DIAG:		/* hardware diagnostic support */
549185377Ssam		*result = AH_PRIVATE(ah)->ah_diagreg;
550185377Ssam		return HAL_OK;
551185377Ssam	case HAL_CAP_TXPOW:		/* global tx power limit  */
552185377Ssam		switch (capability) {
553185377Ssam		case 0:			/* facility is supported */
554185377Ssam			return HAL_OK;
555185377Ssam		case 1:			/* current limit */
556185377Ssam			*result = AH_PRIVATE(ah)->ah_powerLimit;
557185377Ssam			return HAL_OK;
558185377Ssam		case 2:			/* current max tx power */
559185377Ssam			*result = AH_PRIVATE(ah)->ah_maxPowerLevel;
560185377Ssam			return HAL_OK;
561185377Ssam		case 3:			/* scale factor */
562185377Ssam			*result = AH_PRIVATE(ah)->ah_tpScale;
563185377Ssam			return HAL_OK;
564185377Ssam		}
565185377Ssam		return HAL_ENOTSUPP;
566185377Ssam	case HAL_CAP_BSSIDMASK:		/* hardware supports bssid mask */
567185377Ssam		return pCap->halBssIdMaskSupport ? HAL_OK : HAL_ENOTSUPP;
568185377Ssam	case HAL_CAP_MCAST_KEYSRCH:	/* multicast frame keycache search */
569185377Ssam		return pCap->halMcastKeySrchSupport ? HAL_OK : HAL_ENOTSUPP;
570185377Ssam	case HAL_CAP_TSF_ADJUST:	/* hardware has beacon tsf adjust */
571185377Ssam		return HAL_ENOTSUPP;
572185377Ssam	case HAL_CAP_RFSILENT:		/* rfsilent support  */
573185377Ssam		switch (capability) {
574185377Ssam		case 0:			/* facility is supported */
575185377Ssam			return pCap->halRfSilentSupport ? HAL_OK : HAL_ENOTSUPP;
576185377Ssam		case 1:			/* current setting */
577185377Ssam			return AH_PRIVATE(ah)->ah_rfkillEnabled ?
578185377Ssam				HAL_OK : HAL_ENOTSUPP;
579185377Ssam		case 2:			/* rfsilent config */
580185377Ssam			*result = AH_PRIVATE(ah)->ah_rfsilent;
581185377Ssam			return HAL_OK;
582185377Ssam		}
583185377Ssam		return HAL_ENOTSUPP;
584185377Ssam	case HAL_CAP_11D:
585185377Ssam		return HAL_OK;
586185377Ssam	case HAL_CAP_RXORN_FATAL:	/* HAL_INT_RXORN treated as fatal  */
587185377Ssam		return AH_PRIVATE(ah)->ah_rxornIsFatal ? HAL_OK : HAL_ENOTSUPP;
588185377Ssam	case HAL_CAP_HT:
589185377Ssam		return pCap->halHTSupport ? HAL_OK : HAL_ENOTSUPP;
590185377Ssam	case HAL_CAP_TX_CHAINMASK:	/* mask of TX chains supported */
591185377Ssam		*result = pCap->halTxChainMask;
592185377Ssam		return HAL_OK;
593185377Ssam	case HAL_CAP_RX_CHAINMASK:	/* mask of RX chains supported */
594185377Ssam		*result = pCap->halRxChainMask;
595185377Ssam		return HAL_OK;
596185377Ssam	case HAL_CAP_RXTSTAMP_PREC:	/* rx desc tstamp precision (bits) */
597185377Ssam		*result = pCap->halTstampPrecision;
598185377Ssam		return HAL_OK;
599192396Ssam	case HAL_CAP_INTRMASK:		/* mask of supported interrupts */
600192396Ssam		*result = pCap->halIntrMask;
601192396Ssam		return HAL_OK;
602195114Ssam	case HAL_CAP_BSSIDMATCH:	/* hardware has disable bssid match */
603195114Ssam		return pCap->halBssidMatchSupport ? HAL_OK : HAL_ENOTSUPP;
604218150Sadrian	case HAL_CAP_STREAMS:		/* number of 11n spatial streams */
605218150Sadrian		switch (capability) {
606218150Sadrian		case 0:			/* TX */
607218150Sadrian			*result = pCap->halTxStreams;
608218150Sadrian			return HAL_OK;
609218150Sadrian		case 1:			/* RX */
610218150Sadrian			*result = pCap->halRxStreams;
611218150Sadrian			return HAL_OK;
612218150Sadrian		default:
613218150Sadrian			return HAL_ENOTSUPP;
614218150Sadrian		}
615220027Sadrian	case HAL_CAP_SPLIT_4KB_TRANS:	/* hardware handles descriptors straddling 4k page boundary */
616218490Sadrian		return pCap->hal4kbSplitTransSupport ? HAL_OK : HAL_ENOTSUPP;
617220027Sadrian	case HAL_CAP_HAS_PSPOLL:	/* hardware has ps-poll support */
618220027Sadrian		return pCap->halHasPsPollSupport ? HAL_OK : HAL_ENOTSUPP;
619220324Sadrian	case HAL_CAP_RXDESC_SELFLINK:	/* hardware supports self-linked final RX descriptors correctly */
620220324Sadrian		return pCap->halHasRxSelfLinkedTail ? HAL_OK : HAL_ENOTSUPP;
621185377Ssam	default:
622185377Ssam		return HAL_EINVAL;
623185377Ssam	}
624185377Ssam}
625185377Ssam
626185377SsamHAL_BOOL
627185377Ssamath_hal_setcapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type,
628185377Ssam	uint32_t capability, uint32_t setting, HAL_STATUS *status)
629185377Ssam{
630185377Ssam
631185377Ssam	switch (type) {
632185377Ssam	case HAL_CAP_TXPOW:
633185377Ssam		switch (capability) {
634185377Ssam		case 3:
635185377Ssam			if (setting <= HAL_TP_SCALE_MIN) {
636185377Ssam				AH_PRIVATE(ah)->ah_tpScale = setting;
637185377Ssam				return AH_TRUE;
638185377Ssam			}
639185377Ssam			break;
640185377Ssam		}
641185377Ssam		break;
642185377Ssam	case HAL_CAP_RFSILENT:		/* rfsilent support  */
643185377Ssam		/*
644185377Ssam		 * NB: allow even if halRfSilentSupport is false
645185377Ssam		 *     in case the EEPROM is misprogrammed.
646185377Ssam		 */
647185377Ssam		switch (capability) {
648185377Ssam		case 1:			/* current setting */
649185377Ssam			AH_PRIVATE(ah)->ah_rfkillEnabled = (setting != 0);
650185377Ssam			return AH_TRUE;
651185377Ssam		case 2:			/* rfsilent config */
652185377Ssam			/* XXX better done per-chip for validation? */
653185377Ssam			AH_PRIVATE(ah)->ah_rfsilent = setting;
654185377Ssam			return AH_TRUE;
655185377Ssam		}
656185377Ssam		break;
657185377Ssam	case HAL_CAP_REG_DMN:		/* regulatory domain */
658185377Ssam		AH_PRIVATE(ah)->ah_currentRD = setting;
659185377Ssam		return AH_TRUE;
660185377Ssam	case HAL_CAP_RXORN_FATAL:	/* HAL_INT_RXORN treated as fatal  */
661185377Ssam		AH_PRIVATE(ah)->ah_rxornIsFatal = setting;
662185377Ssam		return AH_TRUE;
663185377Ssam	default:
664185377Ssam		break;
665185377Ssam	}
666185377Ssam	if (status)
667185377Ssam		*status = HAL_EINVAL;
668185377Ssam	return AH_FALSE;
669185377Ssam}
670185377Ssam
671185377Ssam/*
672185377Ssam * Common support for getDiagState method.
673185377Ssam */
674185377Ssam
675185377Ssamstatic u_int
676185377Ssamath_hal_getregdump(struct ath_hal *ah, const HAL_REGRANGE *regs,
677185377Ssam	void *dstbuf, int space)
678185377Ssam{
679185377Ssam	uint32_t *dp = dstbuf;
680185377Ssam	int i;
681185377Ssam
682185377Ssam	for (i = 0; space >= 2*sizeof(uint32_t); i++) {
683185377Ssam		u_int r = regs[i].start;
684185377Ssam		u_int e = regs[i].end;
685185377Ssam		*dp++ = (r<<16) | e;
686185377Ssam		space -= sizeof(uint32_t);
687185377Ssam		do {
688185377Ssam			*dp++ = OS_REG_READ(ah, r);
689185377Ssam			r += sizeof(uint32_t);
690185377Ssam			space -= sizeof(uint32_t);
691185377Ssam		} while (r <= e && space >= sizeof(uint32_t));
692185377Ssam	}
693185377Ssam	return (char *) dp - (char *) dstbuf;
694185377Ssam}
695188771Ssam
696188771Ssamstatic void
697188771Ssamath_hal_setregs(struct ath_hal *ah, const HAL_REGWRITE *regs, int space)
698188771Ssam{
699188771Ssam	while (space >= sizeof(HAL_REGWRITE)) {
700188771Ssam		OS_REG_WRITE(ah, regs->addr, regs->value);
701188771Ssam		regs++, space -= sizeof(HAL_REGWRITE);
702188771Ssam	}
703188771Ssam}
704185377Ssam
705185377SsamHAL_BOOL
706185377Ssamath_hal_getdiagstate(struct ath_hal *ah, int request,
707185377Ssam	const void *args, uint32_t argsize,
708185377Ssam	void **result, uint32_t *resultsize)
709185377Ssam{
710185377Ssam	switch (request) {
711185377Ssam	case HAL_DIAG_REVS:
712185377Ssam		*result = &AH_PRIVATE(ah)->ah_devid;
713185377Ssam		*resultsize = sizeof(HAL_REVS);
714185377Ssam		return AH_TRUE;
715185377Ssam	case HAL_DIAG_REGS:
716185377Ssam		*resultsize = ath_hal_getregdump(ah, args, *result,*resultsize);
717185377Ssam		return AH_TRUE;
718188771Ssam	case HAL_DIAG_SETREGS:
719188771Ssam		ath_hal_setregs(ah, args, argsize);
720188771Ssam		*resultsize = 0;
721188771Ssam		return AH_TRUE;
722185377Ssam	case HAL_DIAG_FATALERR:
723185377Ssam		*result = &AH_PRIVATE(ah)->ah_fatalState[0];
724185377Ssam		*resultsize = sizeof(AH_PRIVATE(ah)->ah_fatalState);
725185377Ssam		return AH_TRUE;
726185377Ssam	case HAL_DIAG_EEREAD:
727185377Ssam		if (argsize != sizeof(uint16_t))
728185377Ssam			return AH_FALSE;
729185377Ssam		if (!ath_hal_eepromRead(ah, *(const uint16_t *)args, *result))
730185377Ssam			return AH_FALSE;
731185377Ssam		*resultsize = sizeof(uint16_t);
732185377Ssam		return AH_TRUE;
733185377Ssam#ifdef AH_PRIVATE_DIAG
734185377Ssam	case HAL_DIAG_SETKEY: {
735185377Ssam		const HAL_DIAG_KEYVAL *dk;
736185377Ssam
737185377Ssam		if (argsize != sizeof(HAL_DIAG_KEYVAL))
738185377Ssam			return AH_FALSE;
739185377Ssam		dk = (const HAL_DIAG_KEYVAL *)args;
740185377Ssam		return ah->ah_setKeyCacheEntry(ah, dk->dk_keyix,
741185377Ssam			&dk->dk_keyval, dk->dk_mac, dk->dk_xor);
742185377Ssam	}
743185377Ssam	case HAL_DIAG_RESETKEY:
744185377Ssam		if (argsize != sizeof(uint16_t))
745185377Ssam			return AH_FALSE;
746185377Ssam		return ah->ah_resetKeyCacheEntry(ah, *(const uint16_t *)args);
747185380Ssam#ifdef AH_SUPPORT_WRITE_EEPROM
748185380Ssam	case HAL_DIAG_EEWRITE: {
749185380Ssam		const HAL_DIAG_EEVAL *ee;
750185380Ssam		if (argsize != sizeof(HAL_DIAG_EEVAL))
751185380Ssam			return AH_FALSE;
752185380Ssam		ee = (const HAL_DIAG_EEVAL *)args;
753185380Ssam		return ath_hal_eepromWrite(ah, ee->ee_off, ee->ee_data);
754185380Ssam	}
755185380Ssam#endif /* AH_SUPPORT_WRITE_EEPROM */
756185377Ssam#endif /* AH_PRIVATE_DIAG */
757185377Ssam	case HAL_DIAG_11NCOMPAT:
758185377Ssam		if (argsize == 0) {
759185377Ssam			*resultsize = sizeof(uint32_t);
760185377Ssam			*((uint32_t *)(*result)) =
761185377Ssam				AH_PRIVATE(ah)->ah_11nCompat;
762185377Ssam		} else if (argsize == sizeof(uint32_t)) {
763185377Ssam			AH_PRIVATE(ah)->ah_11nCompat = *(const uint32_t *)args;
764185377Ssam		} else
765185377Ssam			return AH_FALSE;
766185377Ssam		return AH_TRUE;
767185377Ssam	}
768185377Ssam	return AH_FALSE;
769185377Ssam}
770185377Ssam
771185377Ssam/*
772185377Ssam * Set the properties of the tx queue with the parameters
773185377Ssam * from qInfo.
774185377Ssam */
775185377SsamHAL_BOOL
776185377Ssamath_hal_setTxQProps(struct ath_hal *ah,
777185377Ssam	HAL_TX_QUEUE_INFO *qi, const HAL_TXQ_INFO *qInfo)
778185377Ssam{
779185377Ssam	uint32_t cw;
780185377Ssam
781185377Ssam	if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) {
782185377Ssam		HALDEBUG(ah, HAL_DEBUG_TXQUEUE,
783185377Ssam		    "%s: inactive queue\n", __func__);
784185377Ssam		return AH_FALSE;
785185377Ssam	}
786185377Ssam	/* XXX validate parameters */
787185377Ssam	qi->tqi_ver = qInfo->tqi_ver;
788185377Ssam	qi->tqi_subtype = qInfo->tqi_subtype;
789185377Ssam	qi->tqi_qflags = qInfo->tqi_qflags;
790185377Ssam	qi->tqi_priority = qInfo->tqi_priority;
791185377Ssam	if (qInfo->tqi_aifs != HAL_TXQ_USEDEFAULT)
792185377Ssam		qi->tqi_aifs = AH_MIN(qInfo->tqi_aifs, 255);
793185377Ssam	else
794185377Ssam		qi->tqi_aifs = INIT_AIFS;
795185377Ssam	if (qInfo->tqi_cwmin != HAL_TXQ_USEDEFAULT) {
796185377Ssam		cw = AH_MIN(qInfo->tqi_cwmin, 1024);
797185377Ssam		/* make sure that the CWmin is of the form (2^n - 1) */
798185377Ssam		qi->tqi_cwmin = 1;
799185377Ssam		while (qi->tqi_cwmin < cw)
800185377Ssam			qi->tqi_cwmin = (qi->tqi_cwmin << 1) | 1;
801185377Ssam	} else
802185377Ssam		qi->tqi_cwmin = qInfo->tqi_cwmin;
803185377Ssam	if (qInfo->tqi_cwmax != HAL_TXQ_USEDEFAULT) {
804185377Ssam		cw = AH_MIN(qInfo->tqi_cwmax, 1024);
805185377Ssam		/* make sure that the CWmax is of the form (2^n - 1) */
806185377Ssam		qi->tqi_cwmax = 1;
807185377Ssam		while (qi->tqi_cwmax < cw)
808185377Ssam			qi->tqi_cwmax = (qi->tqi_cwmax << 1) | 1;
809185377Ssam	} else
810185377Ssam		qi->tqi_cwmax = INIT_CWMAX;
811185377Ssam	/* Set retry limit values */
812185377Ssam	if (qInfo->tqi_shretry != 0)
813185377Ssam		qi->tqi_shretry = AH_MIN(qInfo->tqi_shretry, 15);
814185377Ssam	else
815185377Ssam		qi->tqi_shretry = INIT_SH_RETRY;
816185377Ssam	if (qInfo->tqi_lgretry != 0)
817185377Ssam		qi->tqi_lgretry = AH_MIN(qInfo->tqi_lgretry, 15);
818185377Ssam	else
819185377Ssam		qi->tqi_lgretry = INIT_LG_RETRY;
820185377Ssam	qi->tqi_cbrPeriod = qInfo->tqi_cbrPeriod;
821185377Ssam	qi->tqi_cbrOverflowLimit = qInfo->tqi_cbrOverflowLimit;
822185377Ssam	qi->tqi_burstTime = qInfo->tqi_burstTime;
823185377Ssam	qi->tqi_readyTime = qInfo->tqi_readyTime;
824185377Ssam
825185377Ssam	switch (qInfo->tqi_subtype) {
826185377Ssam	case HAL_WME_UPSD:
827185377Ssam		if (qi->tqi_type == HAL_TX_QUEUE_DATA)
828185377Ssam			qi->tqi_intFlags = HAL_TXQ_USE_LOCKOUT_BKOFF_DIS;
829185377Ssam		break;
830185377Ssam	default:
831185377Ssam		break;		/* NB: silence compiler */
832185377Ssam	}
833185377Ssam	return AH_TRUE;
834185377Ssam}
835185377Ssam
836185377SsamHAL_BOOL
837185377Ssamath_hal_getTxQProps(struct ath_hal *ah,
838185377Ssam	HAL_TXQ_INFO *qInfo, const HAL_TX_QUEUE_INFO *qi)
839185377Ssam{
840185377Ssam	if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) {
841185377Ssam		HALDEBUG(ah, HAL_DEBUG_TXQUEUE,
842185377Ssam		    "%s: inactive queue\n", __func__);
843185377Ssam		return AH_FALSE;
844185377Ssam	}
845185377Ssam
846185377Ssam	qInfo->tqi_qflags = qi->tqi_qflags;
847185377Ssam	qInfo->tqi_ver = qi->tqi_ver;
848185377Ssam	qInfo->tqi_subtype = qi->tqi_subtype;
849185377Ssam	qInfo->tqi_qflags = qi->tqi_qflags;
850185377Ssam	qInfo->tqi_priority = qi->tqi_priority;
851185377Ssam	qInfo->tqi_aifs = qi->tqi_aifs;
852185377Ssam	qInfo->tqi_cwmin = qi->tqi_cwmin;
853185377Ssam	qInfo->tqi_cwmax = qi->tqi_cwmax;
854185377Ssam	qInfo->tqi_shretry = qi->tqi_shretry;
855185377Ssam	qInfo->tqi_lgretry = qi->tqi_lgretry;
856185377Ssam	qInfo->tqi_cbrPeriod = qi->tqi_cbrPeriod;
857185377Ssam	qInfo->tqi_cbrOverflowLimit = qi->tqi_cbrOverflowLimit;
858185377Ssam	qInfo->tqi_burstTime = qi->tqi_burstTime;
859185377Ssam	qInfo->tqi_readyTime = qi->tqi_readyTime;
860185377Ssam	return AH_TRUE;
861185377Ssam}
862185377Ssam
863185377Ssam                                     /* 11a Turbo  11b  11g  108g */
864185377Ssamstatic const int16_t NOISE_FLOOR[] = { -96, -93,  -98, -96,  -93 };
865185377Ssam
866185377Ssam/*
867185377Ssam * Read the current channel noise floor and return.
868185377Ssam * If nf cal hasn't finished, channel noise floor should be 0
869185377Ssam * and we return a nominal value based on band and frequency.
870185377Ssam *
871185377Ssam * NB: This is a private routine used by per-chip code to
872185377Ssam *     implement the ah_getChanNoise method.
873185377Ssam */
874185377Ssamint16_t
875187831Ssamath_hal_getChanNoise(struct ath_hal *ah, const struct ieee80211_channel *chan)
876185377Ssam{
877185377Ssam	HAL_CHANNEL_INTERNAL *ichan;
878185377Ssam
879185377Ssam	ichan = ath_hal_checkchannel(ah, chan);
880185377Ssam	if (ichan == AH_NULL) {
881185377Ssam		HALDEBUG(ah, HAL_DEBUG_NFCAL,
882185377Ssam		    "%s: invalid channel %u/0x%x; no mapping\n",
883187831Ssam		    __func__, chan->ic_freq, chan->ic_flags);
884185377Ssam		return 0;
885185377Ssam	}
886185377Ssam	if (ichan->rawNoiseFloor == 0) {
887185377Ssam		WIRELESS_MODE mode = ath_hal_chan2wmode(ah, chan);
888185377Ssam
889185377Ssam		HALASSERT(mode < WIRELESS_MODE_MAX);
890185377Ssam		return NOISE_FLOOR[mode] + ath_hal_getNfAdjust(ah, ichan);
891185377Ssam	} else
892185377Ssam		return ichan->rawNoiseFloor + ichan->noiseFloorAdjust;
893185377Ssam}
894185377Ssam
895185377Ssam/*
896220443Sadrian * Fetch the current setup of ctl/ext noise floor values.
897220443Sadrian *
898220443Sadrian * If the CHANNEL_MIMO_NF_VALID flag isn't set, the array is simply
899220443Sadrian * populated with values from NOISE_FLOOR[] + ath_hal_getNfAdjust().
900220443Sadrian *
901220443Sadrian * The caller must supply ctl/ext NF arrays which are at least
902220443Sadrian * AH_MIMO_MAX_CHAINS entries long.
903220443Sadrian */
904220443Sadrianint
905220443Sadrianath_hal_get_mimo_chan_noise(struct ath_hal *ah,
906220444Sadrian    const struct ieee80211_channel *chan, int16_t *nf_ctl,
907220444Sadrian    int16_t *nf_ext)
908220443Sadrian{
909220443Sadrian	HAL_CHANNEL_INTERNAL *ichan;
910220443Sadrian	int i;
911220443Sadrian
912220443Sadrian	ichan = ath_hal_checkchannel(ah, chan);
913220443Sadrian	if (ichan == AH_NULL) {
914220443Sadrian		HALDEBUG(ah, HAL_DEBUG_NFCAL,
915220443Sadrian		    "%s: invalid channel %u/0x%x; no mapping\n",
916220443Sadrian		    __func__, chan->ic_freq, chan->ic_flags);
917220443Sadrian		for (i = 0; i < AH_MIMO_MAX_CHAINS; i++) {
918220443Sadrian			nf_ctl[i] = nf_ext[i] = 0;
919220443Sadrian		}
920220443Sadrian		return 0;
921220443Sadrian	}
922220443Sadrian
923220443Sadrian	/* Return 0 if there's no valid MIMO values (yet) */
924220443Sadrian	if (! (ichan->privFlags & CHANNEL_MIMO_NF_VALID)) {
925220443Sadrian		for (i = 0; i < AH_MIMO_MAX_CHAINS; i++) {
926220443Sadrian			nf_ctl[i] = nf_ext[i] = 0;
927220443Sadrian		}
928220443Sadrian		return 0;
929220443Sadrian	}
930220443Sadrian	if (ichan->rawNoiseFloor == 0) {
931220443Sadrian		WIRELESS_MODE mode = ath_hal_chan2wmode(ah, chan);
932220443Sadrian		HALASSERT(mode < WIRELESS_MODE_MAX);
933220443Sadrian		/*
934220443Sadrian		 * See the comment below - this could cause issues for
935220443Sadrian		 * stations which have a very low RSSI, below the
936220443Sadrian		 * 'normalised' NF values in NOISE_FLOOR[].
937220443Sadrian		 */
938220443Sadrian		for (i = 0; i < AH_MIMO_MAX_CHAINS; i++) {
939220443Sadrian			nf_ctl[i] = nf_ext[i] = NOISE_FLOOR[mode] +
940220443Sadrian			    ath_hal_getNfAdjust(ah, ichan);
941220443Sadrian		}
942220443Sadrian		return 1;
943220443Sadrian	} else {
944220443Sadrian		/*
945220443Sadrian		 * The value returned here from a MIMO radio is presumed to be
946220443Sadrian		 * "good enough" as a NF calculation. As RSSI values are calculated
947220443Sadrian		 * against this, an adjusted NF may be higher than the RSSI value
948220443Sadrian		 * returned from a vary weak station, resulting in an obscenely
949220443Sadrian		 * high signal strength calculation being returned.
950220443Sadrian		 *
951220443Sadrian		 * This should be re-evaluated at a later date, along with any
952220443Sadrian		 * signal strength calculations which are made. Quite likely the
953220443Sadrian		 * RSSI values will need to be adjusted to ensure the calculations
954220443Sadrian		 * don't "wrap" when RSSI is less than the "adjusted" NF value.
955220443Sadrian		 * ("Adjust" here is via ichan->noiseFloorAdjust.)
956220443Sadrian		 */
957220443Sadrian		for (i = 0; i < AH_MIMO_MAX_CHAINS; i++) {
958220443Sadrian			nf_ctl[i] = ichan->noiseFloorCtl[i] + ath_hal_getNfAdjust(ah, ichan);
959220443Sadrian			nf_ext[i] = ichan->noiseFloorExt[i] + ath_hal_getNfAdjust(ah, ichan);
960220443Sadrian		}
961220443Sadrian		return 1;
962220443Sadrian	}
963220443Sadrian}
964220443Sadrian
965220443Sadrian/*
966185377Ssam * Process all valid raw noise floors into the dBm noise floor values.
967185377Ssam * Though our device has no reference for a dBm noise floor, we perform
968185377Ssam * a relative minimization of NF's based on the lowest NF found across a
969185377Ssam * channel scan.
970185377Ssam */
971185377Ssamvoid
972185377Ssamath_hal_process_noisefloor(struct ath_hal *ah)
973185377Ssam{
974185377Ssam	HAL_CHANNEL_INTERNAL *c;
975185377Ssam	int16_t correct2, correct5;
976185377Ssam	int16_t lowest2, lowest5;
977185377Ssam	int i;
978185377Ssam
979185377Ssam	/*
980185377Ssam	 * Find the lowest 2GHz and 5GHz noise floor values after adjusting
981185377Ssam	 * for statistically recorded NF/channel deviation.
982185377Ssam	 */
983185377Ssam	correct2 = lowest2 = 0;
984185377Ssam	correct5 = lowest5 = 0;
985185377Ssam	for (i = 0; i < AH_PRIVATE(ah)->ah_nchan; i++) {
986185377Ssam		WIRELESS_MODE mode;
987185377Ssam		int16_t nf;
988185377Ssam
989185377Ssam		c = &AH_PRIVATE(ah)->ah_channels[i];
990185377Ssam		if (c->rawNoiseFloor >= 0)
991185377Ssam			continue;
992187831Ssam		/* XXX can't identify proper mode */
993187831Ssam		mode = IS_CHAN_5GHZ(c) ? WIRELESS_MODE_11a : WIRELESS_MODE_11g;
994185377Ssam		nf = c->rawNoiseFloor + NOISE_FLOOR[mode] +
995185377Ssam			ath_hal_getNfAdjust(ah, c);
996185377Ssam		if (IS_CHAN_5GHZ(c)) {
997185377Ssam			if (nf < lowest5) {
998185377Ssam				lowest5 = nf;
999185377Ssam				correct5 = NOISE_FLOOR[mode] -
1000185377Ssam				    (c->rawNoiseFloor + ath_hal_getNfAdjust(ah, c));
1001185377Ssam			}
1002185377Ssam		} else {
1003185377Ssam			if (nf < lowest2) {
1004185377Ssam				lowest2 = nf;
1005185377Ssam				correct2 = NOISE_FLOOR[mode] -
1006185377Ssam				    (c->rawNoiseFloor + ath_hal_getNfAdjust(ah, c));
1007185377Ssam			}
1008185377Ssam		}
1009185377Ssam	}
1010185377Ssam
1011185377Ssam	/* Correct the channels to reach the expected NF value */
1012185377Ssam	for (i = 0; i < AH_PRIVATE(ah)->ah_nchan; i++) {
1013185377Ssam		c = &AH_PRIVATE(ah)->ah_channels[i];
1014185377Ssam		if (c->rawNoiseFloor >= 0)
1015185377Ssam			continue;
1016185377Ssam		/* Apply correction factor */
1017185377Ssam		c->noiseFloorAdjust = ath_hal_getNfAdjust(ah, c) +
1018185377Ssam			(IS_CHAN_5GHZ(c) ? correct5 : correct2);
1019187831Ssam		HALDEBUG(ah, HAL_DEBUG_NFCAL, "%u raw nf %d adjust %d\n",
1020187831Ssam		    c->channel, c->rawNoiseFloor, c->noiseFloorAdjust);
1021185377Ssam	}
1022185377Ssam}
1023185377Ssam
1024185377Ssam/*
1025185377Ssam * INI support routines.
1026185377Ssam */
1027185377Ssam
1028185377Ssamint
1029185377Ssamath_hal_ini_write(struct ath_hal *ah, const HAL_INI_ARRAY *ia,
1030185377Ssam	int col, int regWr)
1031185377Ssam{
1032185377Ssam	int r;
1033185377Ssam
1034189713Ssam	HALASSERT(col < ia->cols);
1035185377Ssam	for (r = 0; r < ia->rows; r++) {
1036185377Ssam		OS_REG_WRITE(ah, HAL_INI_VAL(ia, r, 0),
1037185377Ssam		    HAL_INI_VAL(ia, r, col));
1038217921Sadrian
1039217921Sadrian		/* Analog shift register delay seems needed for Merlin - PR kern/154220 */
1040217921Sadrian		if (HAL_INI_VAL(ia, r, 0) >= 0x7800 && HAL_INI_VAL(ia, r, 0) < 0x78a0)
1041217921Sadrian			OS_DELAY(100);
1042217921Sadrian
1043185377Ssam		DMA_YIELD(regWr);
1044185377Ssam	}
1045185377Ssam	return regWr;
1046185377Ssam}
1047185377Ssam
1048185377Ssamvoid
1049185377Ssamath_hal_ini_bank_setup(uint32_t data[], const HAL_INI_ARRAY *ia, int col)
1050185377Ssam{
1051185377Ssam	int r;
1052185377Ssam
1053189713Ssam	HALASSERT(col < ia->cols);
1054185377Ssam	for (r = 0; r < ia->rows; r++)
1055185377Ssam		data[r] = HAL_INI_VAL(ia, r, col);
1056185377Ssam}
1057185377Ssam
1058185377Ssamint
1059185377Ssamath_hal_ini_bank_write(struct ath_hal *ah, const HAL_INI_ARRAY *ia,
1060185377Ssam	const uint32_t data[], int regWr)
1061185377Ssam{
1062185377Ssam	int r;
1063185377Ssam
1064185377Ssam	for (r = 0; r < ia->rows; r++) {
1065185377Ssam		OS_REG_WRITE(ah, HAL_INI_VAL(ia, r, 0), data[r]);
1066185377Ssam		DMA_YIELD(regWr);
1067185377Ssam	}
1068185377Ssam	return regWr;
1069185377Ssam}
1070219586Sadrian
1071219586Sadrian/*
1072219586Sadrian * These are EEPROM board related routines which should likely live in
1073219586Sadrian * a helper library of some sort.
1074219586Sadrian */
1075219586Sadrian
1076219586Sadrian/**************************************************************
1077219586Sadrian * ath_ee_getLowerUppderIndex
1078219586Sadrian *
1079219586Sadrian * Return indices surrounding the value in sorted integer lists.
1080219586Sadrian * Requirement: the input list must be monotonically increasing
1081219586Sadrian *     and populated up to the list size
1082219586Sadrian * Returns: match is set if an index in the array matches exactly
1083219586Sadrian *     or a the target is before or after the range of the array.
1084219586Sadrian */
1085219586SadrianHAL_BOOL
1086219586Sadrianath_ee_getLowerUpperIndex(uint8_t target, uint8_t *pList, uint16_t listSize,
1087219586Sadrian                   uint16_t *indexL, uint16_t *indexR)
1088219586Sadrian{
1089219586Sadrian    uint16_t i;
1090219586Sadrian
1091219586Sadrian    /*
1092219586Sadrian     * Check first and last elements for beyond ordered array cases.
1093219586Sadrian     */
1094219586Sadrian    if (target <= pList[0]) {
1095219586Sadrian        *indexL = *indexR = 0;
1096219586Sadrian        return AH_TRUE;
1097219586Sadrian    }
1098219586Sadrian    if (target >= pList[listSize-1]) {
1099219586Sadrian        *indexL = *indexR = (uint16_t)(listSize - 1);
1100219586Sadrian        return AH_TRUE;
1101219586Sadrian    }
1102219586Sadrian
1103219586Sadrian    /* look for value being near or between 2 values in list */
1104219586Sadrian    for (i = 0; i < listSize - 1; i++) {
1105219586Sadrian        /*
1106219586Sadrian         * If value is close to the current value of the list
1107219586Sadrian         * then target is not between values, it is one of the values
1108219586Sadrian         */
1109219586Sadrian        if (pList[i] == target) {
1110219586Sadrian            *indexL = *indexR = i;
1111219586Sadrian            return AH_TRUE;
1112219586Sadrian        }
1113219586Sadrian        /*
1114219586Sadrian         * Look for value being between current value and next value
1115219586Sadrian         * if so return these 2 values
1116219586Sadrian         */
1117219586Sadrian        if (target < pList[i + 1]) {
1118219586Sadrian            *indexL = i;
1119219586Sadrian            *indexR = (uint16_t)(i + 1);
1120219586Sadrian            return AH_FALSE;
1121219586Sadrian        }
1122219586Sadrian    }
1123219586Sadrian    HALASSERT(0);
1124219586Sadrian    *indexL = *indexR = 0;
1125219586Sadrian    return AH_FALSE;
1126219586Sadrian}
1127219586Sadrian
1128219586Sadrian/**************************************************************
1129219586Sadrian * ath_ee_FillVpdTable
1130219586Sadrian *
1131219586Sadrian * Fill the Vpdlist for indices Pmax-Pmin
1132219586Sadrian * Note: pwrMin, pwrMax and Vpdlist are all in dBm * 4
1133219586Sadrian */
1134219586SadrianHAL_BOOL
1135219586Sadrianath_ee_FillVpdTable(uint8_t pwrMin, uint8_t pwrMax, uint8_t *pPwrList,
1136219586Sadrian                   uint8_t *pVpdList, uint16_t numIntercepts, uint8_t *pRetVpdList)
1137219586Sadrian{
1138219586Sadrian    uint16_t  i, k;
1139219586Sadrian    uint8_t   currPwr = pwrMin;
1140219586Sadrian    uint16_t  idxL, idxR;
1141219586Sadrian
1142219586Sadrian    HALASSERT(pwrMax > pwrMin);
1143219586Sadrian    for (i = 0; i <= (pwrMax - pwrMin) / 2; i++) {
1144219586Sadrian        ath_ee_getLowerUpperIndex(currPwr, pPwrList, numIntercepts,
1145219586Sadrian                           &(idxL), &(idxR));
1146219586Sadrian        if (idxR < 1)
1147219586Sadrian            idxR = 1;           /* extrapolate below */
1148219586Sadrian        if (idxL == numIntercepts - 1)
1149219586Sadrian            idxL = (uint16_t)(numIntercepts - 2);   /* extrapolate above */
1150219586Sadrian        if (pPwrList[idxL] == pPwrList[idxR])
1151219586Sadrian            k = pVpdList[idxL];
1152219586Sadrian        else
1153219586Sadrian            k = (uint16_t)( ((currPwr - pPwrList[idxL]) * pVpdList[idxR] + (pPwrList[idxR] - currPwr) * pVpdList[idxL]) /
1154219586Sadrian                  (pPwrList[idxR] - pPwrList[idxL]) );
1155219586Sadrian        HALASSERT(k < 256);
1156219586Sadrian        pRetVpdList[i] = (uint8_t)k;
1157219586Sadrian        currPwr += 2;               /* half dB steps */
1158219586Sadrian    }
1159219586Sadrian
1160219586Sadrian    return AH_TRUE;
1161219586Sadrian}
1162219586Sadrian
1163219586Sadrian/**************************************************************************
1164219586Sadrian * ath_ee_interpolate
1165219586Sadrian *
1166219586Sadrian * Returns signed interpolated or the scaled up interpolated value
1167219586Sadrian */
1168219586Sadrianint16_t
1169219586Sadrianath_ee_interpolate(uint16_t target, uint16_t srcLeft, uint16_t srcRight,
1170219586Sadrian            int16_t targetLeft, int16_t targetRight)
1171219586Sadrian{
1172219586Sadrian    int16_t rv;
1173219586Sadrian
1174219586Sadrian    if (srcRight == srcLeft) {
1175219586Sadrian        rv = targetLeft;
1176219586Sadrian    } else {
1177219586Sadrian        rv = (int16_t)( ((target - srcLeft) * targetRight +
1178219586Sadrian              (srcRight - target) * targetLeft) / (srcRight - srcLeft) );
1179219586Sadrian    }
1180219586Sadrian    return rv;
1181219586Sadrian}
1182