ah.c revision 189713
1178354Ssam/*
2178354Ssam * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
3178354Ssam * Copyright (c) 2002-2008 Atheros Communications, Inc.
4178354Ssam *
5178354Ssam * Permission to use, copy, modify, and/or distribute this software for any
6178354Ssam * purpose with or without fee is hereby granted, provided that the above
7178354Ssam * copyright notice and this permission notice appear in all copies.
8178354Ssam *
9178354Ssam * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10178354Ssam * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11178354Ssam * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12178354Ssam * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13178354Ssam * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14178354Ssam * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15178354Ssam * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16178354Ssam *
17178354Ssam * $FreeBSD: head/sys/dev/ath/ath_hal/ah.c 189713 2009-03-12 00:09:29Z sam $
18178354Ssam */
19178354Ssam#include "opt_ah.h"
20178354Ssam
21178354Ssam#include "ah.h"
22178354Ssam#include "ah_internal.h"
23178354Ssam#include "ah_devid.h"
24178354Ssam
25178354Ssam#include "ar5416/ar5416reg.h"		/* NB: includes ar5212reg.h */
26178354Ssam
27178354Ssam/* linker set of registered chips */
28178354SsamOS_SET_DECLARE(ah_chips, struct ath_hal_chip);
29178354Ssam
30178354Ssam/*
31178354Ssam * Check the set of registered chips to see if any recognize
32178354Ssam * the device as one they can support.
33178354Ssam */
34178354Ssamconst char*
35178354Ssamath_hal_probe(uint16_t vendorid, uint16_t devid)
36178354Ssam{
37178354Ssam	struct ath_hal_chip * const *pchip;
38178354Ssam
39178354Ssam	OS_SET_FOREACH(pchip, ah_chips) {
40178354Ssam		const char *name = (*pchip)->probe(vendorid, devid);
41178354Ssam		if (name != AH_NULL)
42178354Ssam			return name;
43178354Ssam	}
44178354Ssam	return AH_NULL;
45178354Ssam}
46178354Ssam
47178354Ssam/*
48178354Ssam * Attach detects device chip revisions, initializes the hwLayer
49178354Ssam * function list, reads EEPROM information,
50178354Ssam * selects reset vectors, and performs a short self test.
51178354Ssam * Any failures will return an error that should cause a hardware
52178354Ssam * disable.
53178354Ssam */
54178354Ssamstruct ath_hal*
55178354Ssamath_hal_attach(uint16_t devid, HAL_SOFTC sc,
56178354Ssam	HAL_BUS_TAG st, HAL_BUS_HANDLE sh, HAL_STATUS *error)
57178354Ssam{
58178354Ssam	struct ath_hal_chip * const *pchip;
59178354Ssam
60190391Ssam	OS_SET_FOREACH(pchip, ah_chips) {
61190391Ssam		struct ath_hal_chip *chip = *pchip;
62190391Ssam		struct ath_hal *ah;
63178354Ssam
64178354Ssam		/* XXX don't have vendorid, assume atheros one works */
65178354Ssam		if (chip->probe(ATHEROS_VENDOR_ID, devid) == AH_NULL)
66192468Ssam			continue;
67178354Ssam		ah = chip->attach(devid, sc, st, sh, error);
68192468Ssam		if (ah != AH_NULL) {
69178354Ssam			/* copy back private state to public area */
70178354Ssam			ah->ah_devid = AH_PRIVATE(ah)->ah_devid;
71178354Ssam			ah->ah_subvendorid = AH_PRIVATE(ah)->ah_subvendorid;
72178354Ssam			ah->ah_macVersion = AH_PRIVATE(ah)->ah_macVersion;
73178354Ssam			ah->ah_macRev = AH_PRIVATE(ah)->ah_macRev;
74178354Ssam			ah->ah_phyRev = AH_PRIVATE(ah)->ah_phyRev;
75178354Ssam			ah->ah_analog5GhzRev = AH_PRIVATE(ah)->ah_analog5GhzRev;
76178354Ssam			ah->ah_analog2GhzRev = AH_PRIVATE(ah)->ah_analog2GhzRev;
77178354Ssam			return ah;
78178354Ssam		}
79178354Ssam	}
80178354Ssam	return AH_NULL;
81178354Ssam}
82178354Ssam
83178354Ssamconst char *
84178354Ssamath_hal_mac_name(struct ath_hal *ah)
85178354Ssam{
86178354Ssam	switch (ah->ah_macVersion) {
87178354Ssam	case AR_SREV_VERSION_CRETE:
88178354Ssam	case AR_SREV_VERSION_MAUI_1:
89178354Ssam		return "5210";
90178354Ssam	case AR_SREV_VERSION_MAUI_2:
91178354Ssam	case AR_SREV_VERSION_OAHU:
92178354Ssam		return "5211";
93178354Ssam	case AR_SREV_VERSION_VENICE:
94178354Ssam		return "5212";
95178354Ssam	case AR_SREV_VERSION_GRIFFIN:
96178354Ssam		return "2413";
97178354Ssam	case AR_SREV_VERSION_CONDOR:
98178354Ssam		return "5424";
99178354Ssam	case AR_SREV_VERSION_EAGLE:
100195379Ssam		return "5413";
101195379Ssam	case AR_SREV_VERSION_COBRA:
102195379Ssam		return "2415";
103195379Ssam	case AR_SREV_2425:
104195379Ssam		return "2425";
105195379Ssam	case AR_SREV_2417:
106195379Ssam		return "2417";
107195379Ssam	case AR_XSREV_VERSION_OWL_PCI:
108195379Ssam		return "5416";
109195379Ssam	case AR_XSREV_VERSION_OWL_PCIE:
110195379Ssam		return "5418";
111195379Ssam	case AR_XSREV_VERSION_SOWL:
112195379Ssam		return "9160";
113195379Ssam	case AR_XSREV_VERSION_MERLIN:
114195379Ssam		return "9280";
115195379Ssam	case AR_XSREV_VERSION_KITE:
116195379Ssam		return "9285";
117195379Ssam	}
118195379Ssam	return "????";
119195379Ssam}
120195379Ssam
121195379Ssam/*
122178354Ssam * Return the mask of available modes based on the hardware capabilities.
123178354Ssam */
124178354Ssamu_int
125178354Ssamath_hal_getwirelessmodes(struct ath_hal*ah)
126178354Ssam{
127178354Ssam	return ath_hal_getWirelessModes(ah);
128178354Ssam}
129178354Ssam
130178354Ssam/* linker set of registered RF backends */
131178354SsamOS_SET_DECLARE(ah_rfs, struct ath_hal_rf);
132178354Ssam
133178354Ssam/*
134178354Ssam * Check the set of registered RF backends to see if
135178354Ssam * any recognize the device as one they can support.
136178354Ssam */
137178354Ssamstruct ath_hal_rf *
138178354Ssamath_hal_rfprobe(struct ath_hal *ah, HAL_STATUS *ecode)
139178354Ssam{
140178354Ssam	struct ath_hal_rf * const *prf;
141178354Ssam
142178354Ssam	OS_SET_FOREACH(prf, ah_rfs) {
143178354Ssam		struct ath_hal_rf *rf = *prf;
144178354Ssam		if (rf->probe(ah))
145178354Ssam			return rf;
146178354Ssam	}
147178354Ssam	*ecode = HAL_ENOTSUPP;
148178354Ssam	return AH_NULL;
149178354Ssam}
150178354Ssam
151178354Ssamconst char *
152178354Ssamath_hal_rf_name(struct ath_hal *ah)
153178354Ssam{
154178354Ssam	switch (ah->ah_analog5GhzRev & AR_RADIO_SREV_MAJOR) {
155178354Ssam	case 0:			/* 5210 */
156178354Ssam		return "5110";	/* NB: made up */
157178354Ssam	case AR_RAD5111_SREV_MAJOR:
158178354Ssam	case AR_RAD5111_SREV_PROD:
159178354Ssam		return "5111";
160178354Ssam	case AR_RAD2111_SREV_MAJOR:
161178354Ssam		return "2111";
162178354Ssam	case AR_RAD5112_SREV_MAJOR:
163178354Ssam	case AR_RAD5112_SREV_2_0:
164178354Ssam	case AR_RAD5112_SREV_2_1:
165178354Ssam		return "5112";
166178354Ssam	case AR_RAD2112_SREV_MAJOR:
167178354Ssam	case AR_RAD2112_SREV_2_0:
168178354Ssam	case AR_RAD2112_SREV_2_1:
169178354Ssam		return "2112";
170178354Ssam	case AR_RAD2413_SREV_MAJOR:
171178354Ssam		return "2413";
172178354Ssam	case AR_RAD5413_SREV_MAJOR:
173178354Ssam		return "5413";
174178354Ssam	case AR_RAD2316_SREV_MAJOR:
175178354Ssam		return "2316";
176178354Ssam	case AR_RAD2317_SREV_MAJOR:
177178354Ssam		return "2317";
178178354Ssam	case AR_RAD5424_SREV_MAJOR:
179178354Ssam		return "5424";
180178354Ssam
181178354Ssam	case AR_RAD5133_SREV_MAJOR:
182178354Ssam		return "5133";
183178354Ssam	case AR_RAD2133_SREV_MAJOR:
184178354Ssam		return "2133";
185178354Ssam	case AR_RAD5122_SREV_MAJOR:
186178354Ssam		return "5122";
187178354Ssam	case AR_RAD2122_SREV_MAJOR:
188178354Ssam		return "2122";
189178354Ssam	}
190178354Ssam	return "????";
191178354Ssam}
192178354Ssam
193178354Ssam/*
194178354Ssam * Poll the register looking for a specific value.
195178354Ssam */
196178354SsamHAL_BOOL
197178354Ssamath_hal_wait(struct ath_hal *ah, u_int reg, uint32_t mask, uint32_t val)
198178354Ssam{
199178354Ssam#define	AH_TIMEOUT	1000
200178354Ssam	int i;
201178354Ssam
202178354Ssam	for (i = 0; i < AH_TIMEOUT; i++) {
203178354Ssam		if ((OS_REG_READ(ah, reg) & mask) == val)
204178354Ssam			return AH_TRUE;
205178354Ssam		OS_DELAY(10);
206178354Ssam	}
207178354Ssam	HALDEBUG(ah, HAL_DEBUG_REGIO | HAL_DEBUG_PHYIO,
208178354Ssam	    "%s: timeout on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n",
209178354Ssam	    __func__, reg, OS_REG_READ(ah, reg), mask, val);
210178354Ssam	return AH_FALSE;
211178354Ssam#undef AH_TIMEOUT
212178354Ssam}
213178354Ssam
214178354Ssam/*
215178354Ssam * Reverse the bits starting at the low bit for a value of
216178354Ssam * bit_count in size
217178354Ssam */
218178354Ssamuint32_t
219178354Ssamath_hal_reverseBits(uint32_t val, uint32_t n)
220195379Ssam{
221178354Ssam	uint32_t retval;
222195379Ssam	int i;
223195379Ssam
224178354Ssam	for (i = 0, retval = 0; i < n; i++) {
225178354Ssam		retval = (retval << 1) | (val & 1);
226178354Ssam		val >>= 1;
227178354Ssam	}
228178354Ssam	return retval;
229178354Ssam}
230178354Ssam
231178354Ssam/*
232178354Ssam * Compute the time to transmit a frame of length frameLen bytes
233178354Ssam * using the specified rate, phy, and short preamble setting.
234178354Ssam */
235178354Ssamuint16_t
236178354Ssamath_hal_computetxtime(struct ath_hal *ah,
237178354Ssam	const HAL_RATE_TABLE *rates, uint32_t frameLen, uint16_t rateix,
238178354Ssam	HAL_BOOL shortPreamble)
239178354Ssam{
240178354Ssam	uint32_t bitsPerSymbol, numBits, numSymbols, phyTime, txTime;
241178354Ssam	uint32_t kbps;
242178354Ssam
243178354Ssam	kbps = rates->info[rateix].rateKbps;
244178354Ssam	/*
245178354Ssam	 * index can be invalid duting dynamic Turbo transitions.
246178354Ssam	 * XXX
247178354Ssam	 */
248178354Ssam	if (kbps == 0)
249178354Ssam		return 0;
250178354Ssam	switch (rates->info[rateix].phy) {
251178354Ssam	case IEEE80211_T_CCK:
252178354Ssam		phyTime		= CCK_PREAMBLE_BITS + CCK_PLCP_BITS;
253178354Ssam		if (shortPreamble && rates->info[rateix].shortPreamble)
254178354Ssam			phyTime >>= 1;
255178354Ssam		numBits		= frameLen << 3;
256178354Ssam		txTime		= CCK_SIFS_TIME + phyTime
257190672Ssam				+ ((numBits * 1000)/kbps);
258178354Ssam		break;
259243882Sglebius	case IEEE80211_T_OFDM:
260178354Ssam		bitsPerSymbol	= (kbps * OFDM_SYMBOL_TIME) / 1000;
261178354Ssam		HALASSERT(bitsPerSymbol != 0);
262178354Ssam
263178354Ssam		numBits		= OFDM_PLCP_BITS + (frameLen << 3);
264178354Ssam		numSymbols	= howmany(numBits, bitsPerSymbol);
265178354Ssam		txTime		= OFDM_SIFS_TIME
266178354Ssam				+ OFDM_PREAMBLE_TIME
267178354Ssam				+ (numSymbols * OFDM_SYMBOL_TIME);
268178354Ssam		break;
269178354Ssam	case IEEE80211_T_OFDM_HALF:
270178354Ssam		bitsPerSymbol	= (kbps * OFDM_HALF_SYMBOL_TIME) / 1000;
271178354Ssam		HALASSERT(bitsPerSymbol != 0);
272190672Ssam
273178354Ssam		numBits		= OFDM_HALF_PLCP_BITS + (frameLen << 3);
274178354Ssam		numSymbols	= howmany(numBits, bitsPerSymbol);
275178354Ssam		txTime		= OFDM_HALF_SIFS_TIME
276178354Ssam				+ OFDM_HALF_PREAMBLE_TIME
277178354Ssam				+ (numSymbols * OFDM_HALF_SYMBOL_TIME);
278178354Ssam		break;
279178354Ssam	case IEEE80211_T_OFDM_QUARTER:
280178354Ssam		bitsPerSymbol	= (kbps * OFDM_QUARTER_SYMBOL_TIME) / 1000;
281178354Ssam		HALASSERT(bitsPerSymbol != 0);
282178354Ssam
283178354Ssam		numBits		= OFDM_QUARTER_PLCP_BITS + (frameLen << 3);
284191542Ssam		numSymbols	= howmany(numBits, bitsPerSymbol);
285191542Ssam		txTime		= OFDM_QUARTER_SIFS_TIME
286191542Ssam				+ OFDM_QUARTER_PREAMBLE_TIME
287190672Ssam				+ (numSymbols * OFDM_QUARTER_SYMBOL_TIME);
288190672Ssam		break;
289190672Ssam	case IEEE80211_T_TURBO:
290190672Ssam		/* we still save OFDM rates in kbps - so double them */
291194461Srpaulo		bitsPerSymbol = ((kbps << 1) * TURBO_SYMBOL_TIME) / 1000;
292190672Ssam		HALASSERT(bitsPerSymbol != 0);
293190672Ssam
294190672Ssam		numBits		= TURBO_PLCP_BITS + (frameLen << 3);
295190672Ssam		numSymbols	= howmany(numBits, bitsPerSymbol);
296190672Ssam		txTime		= TURBO_SIFS_TIME
297178354Ssam				+ TURBO_PREAMBLE_TIME
298178354Ssam				+ (numSymbols * TURBO_SYMBOL_TIME);
299186658Ssam		break;
300178354Ssam	default:
301178354Ssam		HALDEBUG(ah, HAL_DEBUG_PHYIO,
302178354Ssam		    "%s: unknown phy %u (rate ix %u)\n",
303178354Ssam		    __func__, rates->info[rateix].phy, rateix);
304178354Ssam		txTime = 0;
305178354Ssam		break;
306178354Ssam	}
307178354Ssam	return txTime;
308178354Ssam}
309178354Ssam
310178354Ssamtypedef enum {
311178354Ssam	WIRELESS_MODE_11a   = 0,
312178354Ssam	WIRELESS_MODE_TURBO = 1,
313178354Ssam	WIRELESS_MODE_11b   = 2,
314178354Ssam	WIRELESS_MODE_11g   = 3,
315178354Ssam	WIRELESS_MODE_108g  = 4,
316178354Ssam
317178354Ssam	WIRELESS_MODE_MAX
318178354Ssam} WIRELESS_MODE;
319178354Ssam
320178354Ssamstatic WIRELESS_MODE
321195379Ssamath_hal_chan2wmode(struct ath_hal *ah, const struct ieee80211_channel *chan)
322195379Ssam{
323195379Ssam	if (IEEE80211_IS_CHAN_B(chan))
324195379Ssam		return WIRELESS_MODE_11b;
325195379Ssam	if (IEEE80211_IS_CHAN_G(chan))
326195379Ssam		return WIRELESS_MODE_11g;
327195379Ssam	if (IEEE80211_IS_CHAN_108G(chan))
328195379Ssam		return WIRELESS_MODE_108g;
329195379Ssam	if (IEEE80211_IS_CHAN_TURBO(chan))
330195379Ssam		return WIRELESS_MODE_TURBO;
331195379Ssam	return WIRELESS_MODE_11a;
332195379Ssam}
333178354Ssam
334178354Ssam/*
335178354Ssam * Convert between microseconds and core system clocks.
336178354Ssam */
337178354Ssam                                     /* 11a Turbo  11b  11g  108g */
338178354Ssamstatic const uint8_t CLOCK_RATE[]  = { 40,  80,   22,  44,   88  };
339178354Ssam
340178354Ssamu_int
341178354Ssamath_hal_mac_clks(struct ath_hal *ah, u_int usecs)
342178354Ssam{
343178354Ssam	const struct ieee80211_channel *c = AH_PRIVATE(ah)->ah_curchan;
344178354Ssam	u_int clks;
345178354Ssam
346178354Ssam	/* NB: ah_curchan may be null when called attach time */
347178354Ssam	if (c != AH_NULL) {
348178354Ssam		clks = usecs * CLOCK_RATE[ath_hal_chan2wmode(ah, c)];
349178354Ssam		if (IEEE80211_IS_CHAN_HT40(c))
350178354Ssam			clks <<= 1;
351178354Ssam	} else
352178354Ssam		clks = usecs * CLOCK_RATE[WIRELESS_MODE_11b];
353178354Ssam	return clks;
354178354Ssam}
355178354Ssam
356178354Ssamu_int
357178354Ssamath_hal_mac_usec(struct ath_hal *ah, u_int clks)
358178354Ssam{
359178354Ssam	const struct ieee80211_channel *c = AH_PRIVATE(ah)->ah_curchan;
360178354Ssam	u_int usec;
361178354Ssam
362178354Ssam	/* NB: ah_curchan may be null when called attach time */
363178354Ssam	if (c != AH_NULL) {
364178354Ssam		usec = clks / CLOCK_RATE[ath_hal_chan2wmode(ah, c)];
365178354Ssam		if (IEEE80211_IS_CHAN_HT40(c))
366178354Ssam			usec >>= 1;
367178354Ssam	} else
368178354Ssam		usec = clks / CLOCK_RATE[WIRELESS_MODE_11b];
369178354Ssam	return usec;
370178354Ssam}
371178354Ssam
372178354Ssam/*
373178354Ssam * Setup a h/w rate table's reverse lookup table and
374178354Ssam * fill in ack durations.  This routine is called for
375178354Ssam * each rate table returned through the ah_getRateTable
376178354Ssam * method.  The reverse lookup tables are assumed to be
377178354Ssam * initialized to zero (or at least the first entry).
378178354Ssam * We use this as a key that indicates whether or not
379178354Ssam * we've previously setup the reverse lookup table.
380178354Ssam *
381178354Ssam * XXX not reentrant, but shouldn't matter
382178354Ssam */
383178354Ssamvoid
384178354Ssamath_hal_setupratetable(struct ath_hal *ah, HAL_RATE_TABLE *rt)
385178354Ssam{
386178354Ssam#define	N(a)	(sizeof(a)/sizeof(a[0]))
387178354Ssam	int i;
388178354Ssam
389178354Ssam	if (rt->rateCodeToIndex[0] != 0)	/* already setup */
390178354Ssam		return;
391178354Ssam	for (i = 0; i < N(rt->rateCodeToIndex); i++)
392178354Ssam		rt->rateCodeToIndex[i] = (uint8_t) -1;
393178354Ssam	for (i = 0; i < rt->rateCount; i++) {
394178354Ssam		uint8_t code = rt->info[i].rateCode;
395178354Ssam		uint8_t cix = rt->info[i].controlRate;
396178354Ssam
397178354Ssam		HALASSERT(code < N(rt->rateCodeToIndex));
398178354Ssam		rt->rateCodeToIndex[code] = i;
399178354Ssam		HALASSERT((code | rt->info[i].shortPreamble) <
400178354Ssam		    N(rt->rateCodeToIndex));
401178354Ssam		rt->rateCodeToIndex[code | rt->info[i].shortPreamble] = i;
402178354Ssam		/*
403178354Ssam		 * XXX for 11g the control rate to use for 5.5 and 11 Mb/s
404178354Ssam		 *     depends on whether they are marked as basic rates;
405178354Ssam		 *     the static tables are setup with an 11b-compatible
406178354Ssam		 *     2Mb/s rate which will work but is suboptimal
407192468Ssam		 */
408178354Ssam		rt->info[i].lpAckDuration = ath_hal_computetxtime(ah, rt,
409178354Ssam			WLAN_CTRL_FRAME_SIZE, cix, AH_FALSE);
410178354Ssam		rt->info[i].spAckDuration = ath_hal_computetxtime(ah, rt,
411178354Ssam			WLAN_CTRL_FRAME_SIZE, cix, AH_TRUE);
412178354Ssam	}
413178354Ssam#undef N
414178354Ssam}
415178354Ssam
416203422SrpauloHAL_STATUS
417178354Ssamath_hal_getcapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type,
418178354Ssam	uint32_t capability, uint32_t *result)
419178354Ssam{
420183247Ssam	const HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps;
421178354Ssam
422178354Ssam	switch (type) {
423183247Ssam	case HAL_CAP_REG_DMN:		/* regulatory domain */
424183247Ssam		*result = AH_PRIVATE(ah)->ah_currentRD;
425183247Ssam		return HAL_OK;
426183247Ssam	case HAL_CAP_CIPHER:		/* cipher handled in hardware */
427183247Ssam	case HAL_CAP_TKIP_MIC:		/* handle TKIP MIC in hardware */
428178354Ssam		return HAL_ENOTSUPP;
429178354Ssam	case HAL_CAP_TKIP_SPLIT:	/* hardware TKIP uses split keys */
430178354Ssam		return HAL_ENOTSUPP;
431178354Ssam	case HAL_CAP_PHYCOUNTERS:	/* hardware PHY error counters */
432178354Ssam		return pCap->halHwPhyCounterSupport ? HAL_OK : HAL_ENXIO;
433178354Ssam	case HAL_CAP_WME_TKIPMIC:   /* hardware can do TKIP MIC when WMM is turned on */
434178354Ssam		return HAL_ENOTSUPP;
435178354Ssam	case HAL_CAP_DIVERSITY:		/* hardware supports fast diversity */
436178354Ssam		return HAL_ENOTSUPP;
437178354Ssam	case HAL_CAP_KEYCACHE_SIZE:	/* hardware key cache size */
438178354Ssam		*result =  pCap->halKeyCacheSize;
439178354Ssam		return HAL_OK;
440178354Ssam	case HAL_CAP_NUM_TXQUEUES:	/* number of hardware tx queues */
441178354Ssam		*result = pCap->halTotalQueues;
442178354Ssam		return HAL_OK;
443178354Ssam	case HAL_CAP_VEOL:		/* hardware supports virtual EOL */
444178354Ssam		return pCap->halVEOLSupport ? HAL_OK : HAL_ENOTSUPP;
445178354Ssam	case HAL_CAP_PSPOLL:		/* hardware PS-Poll support works */
446178354Ssam		return pCap->halPSPollBroken ? HAL_ENOTSUPP : HAL_OK;
447178354Ssam	case HAL_CAP_COMPRESSION:
448178354Ssam		return pCap->halCompressSupport ? HAL_OK : HAL_ENOTSUPP;
449178354Ssam	case HAL_CAP_BURST:
450178354Ssam		return pCap->halBurstSupport ? HAL_OK : HAL_ENOTSUPP;
451178354Ssam	case HAL_CAP_FASTFRAME:
452178354Ssam		return pCap->halFastFramesSupport ? HAL_OK : HAL_ENOTSUPP;
453178354Ssam	case HAL_CAP_DIAG:		/* hardware diagnostic support */
454178354Ssam		*result = AH_PRIVATE(ah)->ah_diagreg;
455178354Ssam		return HAL_OK;
456218958Sbschmidt	case HAL_CAP_TXPOW:		/* global tx power limit  */
457218958Sbschmidt		switch (capability) {
458218958Sbschmidt		case 0:			/* facility is supported */
459178354Ssam			return HAL_OK;
460178354Ssam		case 1:			/* current limit */
461178354Ssam			*result = AH_PRIVATE(ah)->ah_powerLimit;
462191547Ssam			return HAL_OK;
463191547Ssam		case 2:			/* current max tx power */
464178354Ssam			*result = AH_PRIVATE(ah)->ah_maxPowerLevel;
465178354Ssam			return HAL_OK;
466178354Ssam		case 3:			/* scale factor */
467178354Ssam			*result = AH_PRIVATE(ah)->ah_tpScale;
468178354Ssam			return HAL_OK;
469178354Ssam		}
470178354Ssam		return HAL_ENOTSUPP;
471178354Ssam	case HAL_CAP_BSSIDMASK:		/* hardware supports bssid mask */
472178354Ssam		return pCap->halBssIdMaskSupport ? HAL_OK : HAL_ENOTSUPP;
473178354Ssam	case HAL_CAP_MCAST_KEYSRCH:	/* multicast frame keycache search */
474178354Ssam		return pCap->halMcastKeySrchSupport ? HAL_OK : HAL_ENOTSUPP;
475178354Ssam	case HAL_CAP_TSF_ADJUST:	/* hardware has beacon tsf adjust */
476178354Ssam		return HAL_ENOTSUPP;
477178354Ssam	case HAL_CAP_RFSILENT:		/* rfsilent support  */
478178354Ssam		switch (capability) {
479178354Ssam		case 0:			/* facility is supported */
480178354Ssam			return pCap->halRfSilentSupport ? HAL_OK : HAL_ENOTSUPP;
481178354Ssam		case 1:			/* current setting */
482178354Ssam			return AH_PRIVATE(ah)->ah_rfkillEnabled ?
483178354Ssam				HAL_OK : HAL_ENOTSUPP;
484178354Ssam		case 2:			/* rfsilent config */
485178354Ssam			*result = AH_PRIVATE(ah)->ah_rfsilent;
486178354Ssam			return HAL_OK;
487178354Ssam		}
488178354Ssam		return HAL_ENOTSUPP;
489178354Ssam	case HAL_CAP_11D:
490192468Ssam		return HAL_OK;
491178354Ssam	case HAL_CAP_RXORN_FATAL:	/* HAL_INT_RXORN treated as fatal  */
492178354Ssam		return AH_PRIVATE(ah)->ah_rxornIsFatal ? HAL_OK : HAL_ENOTSUPP;
493178354Ssam	case HAL_CAP_HT:
494178354Ssam		return pCap->halHTSupport ? HAL_OK : HAL_ENOTSUPP;
495178354Ssam	case HAL_CAP_TX_CHAINMASK:	/* mask of TX chains supported */
496178354Ssam		*result = pCap->halTxChainMask;
497221418Sadrian		return HAL_OK;
498178354Ssam	case HAL_CAP_RX_CHAINMASK:	/* mask of RX chains supported */
499178354Ssam		*result = pCap->halRxChainMask;
500178354Ssam		return HAL_OK;
501178354Ssam	case HAL_CAP_RXTSTAMP_PREC:	/* rx desc tstamp precision (bits) */
502178354Ssam		*result = pCap->halTstampPrecision;
503178354Ssam		return HAL_OK;
504178354Ssam	default:
505178354Ssam		return HAL_EINVAL;
506178354Ssam	}
507178354Ssam}
508178354Ssam
509178354SsamHAL_BOOL
510178354Ssamath_hal_setcapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type,
511178354Ssam	uint32_t capability, uint32_t setting, HAL_STATUS *status)
512178354Ssam{
513178354Ssam
514178354Ssam	switch (type) {
515178354Ssam	case HAL_CAP_TXPOW:
516178354Ssam		switch (capability) {
517178354Ssam		case 3:
518178354Ssam			if (setting <= HAL_TP_SCALE_MIN) {
519178354Ssam				AH_PRIVATE(ah)->ah_tpScale = setting;
520178354Ssam				return AH_TRUE;
521178354Ssam			}
522178354Ssam			break;
523178354Ssam		}
524178354Ssam		break;
525178354Ssam	case HAL_CAP_RFSILENT:		/* rfsilent support  */
526178354Ssam		/*
527178354Ssam		 * NB: allow even if halRfSilentSupport is false
528178354Ssam		 *     in case the EEPROM is misprogrammed.
529178354Ssam		 */
530178354Ssam		switch (capability) {
531178354Ssam		case 1:			/* current setting */
532178354Ssam			AH_PRIVATE(ah)->ah_rfkillEnabled = (setting != 0);
533178354Ssam			return AH_TRUE;
534178354Ssam		case 2:			/* rfsilent config */
535178354Ssam			/* XXX better done per-chip for validation? */
536178354Ssam			AH_PRIVATE(ah)->ah_rfsilent = setting;
537178354Ssam			return AH_TRUE;
538178354Ssam		}
539178354Ssam		break;
540183247Ssam	case HAL_CAP_REG_DMN:		/* regulatory domain */
541183247Ssam		AH_PRIVATE(ah)->ah_currentRD = setting;
542178354Ssam		return AH_TRUE;
543178354Ssam	case HAL_CAP_RXORN_FATAL:	/* HAL_INT_RXORN treated as fatal  */
544178354Ssam		AH_PRIVATE(ah)->ah_rxornIsFatal = setting;
545183247Ssam		return AH_TRUE;
546178354Ssam	default:
547178354Ssam		break;
548178354Ssam	}
549178354Ssam	if (status)
550178354Ssam		*status = HAL_EINVAL;
551178354Ssam	return AH_FALSE;
552178354Ssam}
553178354Ssam
554178354Ssam/*
555178354Ssam * Common support for getDiagState method.
556178354Ssam */
557178354Ssam
558178354Ssamstatic u_int
559178354Ssamath_hal_getregdump(struct ath_hal *ah, const HAL_REGRANGE *regs,
560178354Ssam	void *dstbuf, int space)
561178354Ssam{
562178354Ssam	uint32_t *dp = dstbuf;
563178354Ssam	int i;
564178354Ssam
565178354Ssam	for (i = 0; space >= 2*sizeof(uint32_t); i++) {
566178354Ssam		u_int r = regs[i].start;
567178354Ssam		u_int e = regs[i].end;
568178354Ssam		*dp++ = (r<<16) | e;
569178354Ssam		space -= sizeof(uint32_t);
570178354Ssam		do {
571178354Ssam			*dp++ = OS_REG_READ(ah, r);
572178354Ssam			r += sizeof(uint32_t);
573178354Ssam			space -= sizeof(uint32_t);
574178354Ssam		} while (r <= e && space >= sizeof(uint32_t));
575178354Ssam	}
576178354Ssam	return (char *) dp - (char *) dstbuf;
577178354Ssam}
578178354Ssam
579178354Ssamstatic void
580178354Ssamath_hal_setregs(struct ath_hal *ah, const HAL_REGWRITE *regs, int space)
581178354Ssam{
582178354Ssam	while (space >= sizeof(HAL_REGWRITE)) {
583178354Ssam		OS_REG_WRITE(ah, regs->addr, regs->value);
584178354Ssam		regs++, space -= sizeof(HAL_REGWRITE);
585178354Ssam	}
586178354Ssam}
587178354Ssam
588178354SsamHAL_BOOL
589178354Ssamath_hal_getdiagstate(struct ath_hal *ah, int request,
590178354Ssam	const void *args, uint32_t argsize,
591178354Ssam	void **result, uint32_t *resultsize)
592178354Ssam{
593178354Ssam	switch (request) {
594178354Ssam	case HAL_DIAG_REVS:
595178354Ssam		*result = &AH_PRIVATE(ah)->ah_devid;
596178354Ssam		*resultsize = sizeof(HAL_REVS);
597178354Ssam		return AH_TRUE;
598178354Ssam	case HAL_DIAG_REGS:
599178354Ssam		*resultsize = ath_hal_getregdump(ah, args, *result,*resultsize);
600178354Ssam		return AH_TRUE;
601178354Ssam	case HAL_DIAG_SETREGS:
602178354Ssam		ath_hal_setregs(ah, args, argsize);
603178354Ssam		*resultsize = 0;
604178354Ssam		return AH_TRUE;
605178354Ssam	case HAL_DIAG_FATALERR:
606178354Ssam		*result = &AH_PRIVATE(ah)->ah_fatalState[0];
607178354Ssam		*resultsize = sizeof(AH_PRIVATE(ah)->ah_fatalState);
608178354Ssam		return AH_TRUE;
609178354Ssam	case HAL_DIAG_EEREAD:
610178354Ssam		if (argsize != sizeof(uint16_t))
611178354Ssam			return AH_FALSE;
612178354Ssam		if (!ath_hal_eepromRead(ah, *(const uint16_t *)args, *result))
613178354Ssam			return AH_FALSE;
614178354Ssam		*resultsize = sizeof(uint16_t);
615178354Ssam		return AH_TRUE;
616178354Ssam#ifdef AH_PRIVATE_DIAG
617178354Ssam	case HAL_DIAG_SETKEY: {
618192468Ssam		const HAL_DIAG_KEYVAL *dk;
619192468Ssam
620178354Ssam		if (argsize != sizeof(HAL_DIAG_KEYVAL))
621178354Ssam			return AH_FALSE;
622178354Ssam		dk = (const HAL_DIAG_KEYVAL *)args;
623178354Ssam		return ah->ah_setKeyCacheEntry(ah, dk->dk_keyix,
624178354Ssam			&dk->dk_keyval, dk->dk_mac, dk->dk_xor);
625178354Ssam	}
626178354Ssam	case HAL_DIAG_RESETKEY:
627178354Ssam		if (argsize != sizeof(uint16_t))
628178354Ssam			return AH_FALSE;
629178354Ssam		return ah->ah_resetKeyCacheEntry(ah, *(const uint16_t *)args);
630178354Ssam#ifdef AH_SUPPORT_WRITE_EEPROM
631178354Ssam	case HAL_DIAG_EEWRITE: {
632178354Ssam		const HAL_DIAG_EEVAL *ee;
633178354Ssam		if (argsize != sizeof(HAL_DIAG_EEVAL))
634178354Ssam			return AH_FALSE;
635178354Ssam		ee = (const HAL_DIAG_EEVAL *)args;
636178354Ssam		return ath_hal_eepromWrite(ah, ee->ee_off, ee->ee_data);
637178354Ssam	}
638178354Ssam#endif /* AH_SUPPORT_WRITE_EEPROM */
639178354Ssam#endif /* AH_PRIVATE_DIAG */
640178354Ssam	case HAL_DIAG_11NCOMPAT:
641178354Ssam		if (argsize == 0) {
642178354Ssam			*resultsize = sizeof(uint32_t);
643178354Ssam			*((uint32_t *)(*result)) =
644178354Ssam				AH_PRIVATE(ah)->ah_11nCompat;
645178354Ssam		} else if (argsize == sizeof(uint32_t)) {
646178354Ssam			AH_PRIVATE(ah)->ah_11nCompat = *(const uint32_t *)args;
647178354Ssam		} else
648178354Ssam			return AH_FALSE;
649178354Ssam		return AH_TRUE;
650178354Ssam	}
651178354Ssam	return AH_FALSE;
652178354Ssam}
653178354Ssam
654178354Ssam/*
655178354Ssam * Set the properties of the tx queue with the parameters
656178354Ssam * from qInfo.
657178354Ssam */
658178354SsamHAL_BOOL
659178354Ssamath_hal_setTxQProps(struct ath_hal *ah,
660178354Ssam	HAL_TX_QUEUE_INFO *qi, const HAL_TXQ_INFO *qInfo)
661178354Ssam{
662178354Ssam	uint32_t cw;
663178354Ssam
664178354Ssam	if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) {
665178354Ssam		HALDEBUG(ah, HAL_DEBUG_TXQUEUE,
666178354Ssam		    "%s: inactive queue\n", __func__);
667178354Ssam		return AH_FALSE;
668178354Ssam	}
669178354Ssam	/* XXX validate parameters */
670178354Ssam	qi->tqi_ver = qInfo->tqi_ver;
671178354Ssam	qi->tqi_subtype = qInfo->tqi_subtype;
672178354Ssam	qi->tqi_qflags = qInfo->tqi_qflags;
673178354Ssam	qi->tqi_priority = qInfo->tqi_priority;
674178354Ssam	if (qInfo->tqi_aifs != HAL_TXQ_USEDEFAULT)
675178354Ssam		qi->tqi_aifs = AH_MIN(qInfo->tqi_aifs, 255);
676178354Ssam	else
677178354Ssam		qi->tqi_aifs = INIT_AIFS;
678190391Ssam	if (qInfo->tqi_cwmin != HAL_TXQ_USEDEFAULT) {
679190391Ssam		cw = AH_MIN(qInfo->tqi_cwmin, 1024);
680190391Ssam		/* make sure that the CWmin is of the form (2^n - 1) */
681190391Ssam		qi->tqi_cwmin = 1;
682178354Ssam		while (qi->tqi_cwmin < cw)
683190391Ssam			qi->tqi_cwmin = (qi->tqi_cwmin << 1) | 1;
684178354Ssam	} else
685178354Ssam		qi->tqi_cwmin = qInfo->tqi_cwmin;
686178354Ssam	if (qInfo->tqi_cwmax != HAL_TXQ_USEDEFAULT) {
687178354Ssam		cw = AH_MIN(qInfo->tqi_cwmax, 1024);
688178354Ssam		/* make sure that the CWmax is of the form (2^n - 1) */
689178354Ssam		qi->tqi_cwmax = 1;
690178354Ssam		while (qi->tqi_cwmax < cw)
691178354Ssam			qi->tqi_cwmax = (qi->tqi_cwmax << 1) | 1;
692178354Ssam	} else
693178354Ssam		qi->tqi_cwmax = INIT_CWMAX;
694178354Ssam	/* Set retry limit values */
695178354Ssam	if (qInfo->tqi_shretry != 0)
696178354Ssam		qi->tqi_shretry = AH_MIN(qInfo->tqi_shretry, 15);
697178354Ssam	else
698178354Ssam		qi->tqi_shretry = INIT_SH_RETRY;
699178354Ssam	if (qInfo->tqi_lgretry != 0)
700178354Ssam		qi->tqi_lgretry = AH_MIN(qInfo->tqi_lgretry, 15);
701178354Ssam	else
702178354Ssam		qi->tqi_lgretry = INIT_LG_RETRY;
703178354Ssam	qi->tqi_cbrPeriod = qInfo->tqi_cbrPeriod;
704178354Ssam	qi->tqi_cbrOverflowLimit = qInfo->tqi_cbrOverflowLimit;
705178354Ssam	qi->tqi_burstTime = qInfo->tqi_burstTime;
706178354Ssam	qi->tqi_readyTime = qInfo->tqi_readyTime;
707178354Ssam
708178354Ssam	switch (qInfo->tqi_subtype) {
709178354Ssam	case HAL_WME_UPSD:
710178354Ssam		if (qi->tqi_type == HAL_TX_QUEUE_DATA)
711178354Ssam			qi->tqi_intFlags = HAL_TXQ_USE_LOCKOUT_BKOFF_DIS;
712178354Ssam		break;
713178354Ssam	default:
714178354Ssam		break;		/* NB: silence compiler */
715178354Ssam	}
716178354Ssam	return AH_TRUE;
717178354Ssam}
718192468Ssam
719192468SsamHAL_BOOL
720178354Ssamath_hal_getTxQProps(struct ath_hal *ah,
721178354Ssam	HAL_TXQ_INFO *qInfo, const HAL_TX_QUEUE_INFO *qi)
722178354Ssam{
723178354Ssam	if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) {
724178354Ssam		HALDEBUG(ah, HAL_DEBUG_TXQUEUE,
725192468Ssam		    "%s: inactive queue\n", __func__);
726178354Ssam		return AH_FALSE;
727178354Ssam	}
728178354Ssam
729178354Ssam	qInfo->tqi_qflags = qi->tqi_qflags;
730178354Ssam	qInfo->tqi_ver = qi->tqi_ver;
731178354Ssam	qInfo->tqi_subtype = qi->tqi_subtype;
732178354Ssam	qInfo->tqi_qflags = qi->tqi_qflags;
733178354Ssam	qInfo->tqi_priority = qi->tqi_priority;
734178354Ssam	qInfo->tqi_aifs = qi->tqi_aifs;
735178354Ssam	qInfo->tqi_cwmin = qi->tqi_cwmin;
736192765Ssam	qInfo->tqi_cwmax = qi->tqi_cwmax;
737192468Ssam	qInfo->tqi_shretry = qi->tqi_shretry;
738178354Ssam	qInfo->tqi_lgretry = qi->tqi_lgretry;
739178354Ssam	qInfo->tqi_cbrPeriod = qi->tqi_cbrPeriod;
740178354Ssam	qInfo->tqi_cbrOverflowLimit = qi->tqi_cbrOverflowLimit;
741178354Ssam	qInfo->tqi_burstTime = qi->tqi_burstTime;
742178354Ssam	qInfo->tqi_readyTime = qi->tqi_readyTime;
743178354Ssam	return AH_TRUE;
744178354Ssam}
745192468Ssam
746178354Ssam                                     /* 11a Turbo  11b  11g  108g */
747178354Ssamstatic const int16_t NOISE_FLOOR[] = { -96, -93,  -98, -96,  -93 };
748178354Ssam
749178354Ssam/*
750178354Ssam * Read the current channel noise floor and return.
751178354Ssam * If nf cal hasn't finished, channel noise floor should be 0
752178354Ssam * and we return a nominal value based on band and frequency.
753178354Ssam *
754178354Ssam * NB: This is a private routine used by per-chip code to
755178354Ssam *     implement the ah_getChanNoise method.
756218927Sbschmidt */
757218927Sbschmidtint16_t
758218958Sbschmidtath_hal_getChanNoise(struct ath_hal *ah, const struct ieee80211_channel *chan)
759218958Sbschmidt{
760218958Sbschmidt	HAL_CHANNEL_INTERNAL *ichan;
761218927Sbschmidt
762218958Sbschmidt	ichan = ath_hal_checkchannel(ah, chan);
763218958Sbschmidt	if (ichan == AH_NULL) {
764218927Sbschmidt		HALDEBUG(ah, HAL_DEBUG_NFCAL,
765218958Sbschmidt		    "%s: invalid channel %u/0x%x; no mapping\n",
766218958Sbschmidt		    __func__, chan->ic_freq, chan->ic_flags);
767218958Sbschmidt		return 0;
768218958Sbschmidt	}
769218927Sbschmidt	if (ichan->rawNoiseFloor == 0) {
770218927Sbschmidt		WIRELESS_MODE mode = ath_hal_chan2wmode(ah, chan);
771218927Sbschmidt
772218958Sbschmidt		HALASSERT(mode < WIRELESS_MODE_MAX);
773218958Sbschmidt		return NOISE_FLOOR[mode] + ath_hal_getNfAdjust(ah, ichan);
774218958Sbschmidt	} else
775218927Sbschmidt		return ichan->rawNoiseFloor + ichan->noiseFloorAdjust;
776218927Sbschmidt}
777218927Sbschmidt
778178354Ssam/*
779218927Sbschmidt * Process all valid raw noise floors into the dBm noise floor values.
780178354Ssam * Though our device has no reference for a dBm noise floor, we perform
781178354Ssam * a relative minimization of NF's based on the lowest NF found across a
782218927Sbschmidt * channel scan.
783218927Sbschmidt */
784218927Sbschmidtvoid
785218927Sbschmidtath_hal_process_noisefloor(struct ath_hal *ah)
786178354Ssam{
787218927Sbschmidt	HAL_CHANNEL_INTERNAL *c;
788218927Sbschmidt	int16_t correct2, correct5;
789218927Sbschmidt	int16_t lowest2, lowest5;
790218927Sbschmidt	int i;
791178354Ssam
792178354Ssam	/*
793218927Sbschmidt	 * Find the lowest 2GHz and 5GHz noise floor values after adjusting
794178354Ssam	 * for statistically recorded NF/channel deviation.
795178354Ssam	 */
796218927Sbschmidt	correct2 = lowest2 = 0;
797178354Ssam	correct5 = lowest5 = 0;
798178354Ssam	for (i = 0; i < AH_PRIVATE(ah)->ah_nchan; i++) {
799178354Ssam		WIRELESS_MODE mode;
800178354Ssam		int16_t nf;
801
802		c = &AH_PRIVATE(ah)->ah_channels[i];
803		if (c->rawNoiseFloor >= 0)
804			continue;
805		/* XXX can't identify proper mode */
806		mode = IS_CHAN_5GHZ(c) ? WIRELESS_MODE_11a : WIRELESS_MODE_11g;
807		nf = c->rawNoiseFloor + NOISE_FLOOR[mode] +
808			ath_hal_getNfAdjust(ah, c);
809		if (IS_CHAN_5GHZ(c)) {
810			if (nf < lowest5) {
811				lowest5 = nf;
812				correct5 = NOISE_FLOOR[mode] -
813				    (c->rawNoiseFloor + ath_hal_getNfAdjust(ah, c));
814			}
815		} else {
816			if (nf < lowest2) {
817				lowest2 = nf;
818				correct2 = NOISE_FLOOR[mode] -
819				    (c->rawNoiseFloor + ath_hal_getNfAdjust(ah, c));
820			}
821		}
822	}
823
824	/* Correct the channels to reach the expected NF value */
825	for (i = 0; i < AH_PRIVATE(ah)->ah_nchan; i++) {
826		c = &AH_PRIVATE(ah)->ah_channels[i];
827		if (c->rawNoiseFloor >= 0)
828			continue;
829		/* Apply correction factor */
830		c->noiseFloorAdjust = ath_hal_getNfAdjust(ah, c) +
831			(IS_CHAN_5GHZ(c) ? correct5 : correct2);
832		HALDEBUG(ah, HAL_DEBUG_NFCAL, "%u raw nf %d adjust %d\n",
833		    c->channel, c->rawNoiseFloor, c->noiseFloorAdjust);
834	}
835}
836
837/*
838 * INI support routines.
839 */
840
841int
842ath_hal_ini_write(struct ath_hal *ah, const HAL_INI_ARRAY *ia,
843	int col, int regWr)
844{
845	int r;
846
847	HALASSERT(col < ia->cols);
848	for (r = 0; r < ia->rows; r++) {
849		OS_REG_WRITE(ah, HAL_INI_VAL(ia, r, 0),
850		    HAL_INI_VAL(ia, r, col));
851		DMA_YIELD(regWr);
852	}
853	return regWr;
854}
855
856void
857ath_hal_ini_bank_setup(uint32_t data[], const HAL_INI_ARRAY *ia, int col)
858{
859	int r;
860
861	HALASSERT(col < ia->cols);
862	for (r = 0; r < ia->rows; r++)
863		data[r] = HAL_INI_VAL(ia, r, col);
864}
865
866int
867ath_hal_ini_bank_write(struct ath_hal *ah, const HAL_INI_ARRAY *ia,
868	const uint32_t data[], int regWr)
869{
870	int r;
871
872	for (r = 0; r < ia->rows; r++) {
873		OS_REG_WRITE(ah, HAL_INI_VAL(ia, r, 0), data[r]);
874		DMA_YIELD(regWr);
875	}
876	return regWr;
877}
878