ah.c revision 187831
1/*
2 * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
3 * Copyright (c) 2002-2008 Atheros Communications, Inc.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 *
17 * $FreeBSD: head/sys/dev/ath/ath_hal/ah.c 187831 2009-01-28 18:00:22Z sam $
18 */
19#include "opt_ah.h"
20
21#include "ah.h"
22#include "ah_internal.h"
23#include "ah_devid.h"
24
25/* linker set of registered chips */
26OS_SET_DECLARE(ah_chips, struct ath_hal_chip);
27
28/*
29 * Check the set of registered chips to see if any recognize
30 * the device as one they can support.
31 */
32const char*
33ath_hal_probe(uint16_t vendorid, uint16_t devid)
34{
35	struct ath_hal_chip * const *pchip;
36
37	OS_SET_FOREACH(pchip, ah_chips) {
38		const char *name = (*pchip)->probe(vendorid, devid);
39		if (name != AH_NULL)
40			return name;
41	}
42	return AH_NULL;
43}
44
45/*
46 * Attach detects device chip revisions, initializes the hwLayer
47 * function list, reads EEPROM information,
48 * selects reset vectors, and performs a short self test.
49 * Any failures will return an error that should cause a hardware
50 * disable.
51 */
52struct ath_hal*
53ath_hal_attach(uint16_t devid, HAL_SOFTC sc,
54	HAL_BUS_TAG st, HAL_BUS_HANDLE sh, HAL_STATUS *error)
55{
56	struct ath_hal_chip * const *pchip;
57
58	OS_SET_FOREACH(pchip, ah_chips) {
59		struct ath_hal_chip *chip = *pchip;
60		struct ath_hal *ah;
61
62		/* XXX don't have vendorid, assume atheros one works */
63		if (chip->probe(ATHEROS_VENDOR_ID, devid) == AH_NULL)
64			continue;
65		ah = chip->attach(devid, sc, st, sh, error);
66		if (ah != AH_NULL) {
67			/* copy back private state to public area */
68			ah->ah_devid = AH_PRIVATE(ah)->ah_devid;
69			ah->ah_subvendorid = AH_PRIVATE(ah)->ah_subvendorid;
70			ah->ah_macVersion = AH_PRIVATE(ah)->ah_macVersion;
71			ah->ah_macRev = AH_PRIVATE(ah)->ah_macRev;
72			ah->ah_phyRev = AH_PRIVATE(ah)->ah_phyRev;
73			ah->ah_analog5GhzRev = AH_PRIVATE(ah)->ah_analog5GhzRev;
74			ah->ah_analog2GhzRev = AH_PRIVATE(ah)->ah_analog2GhzRev;
75			return ah;
76		}
77	}
78	return AH_NULL;
79}
80
81/*
82 * Return the mask of available modes based on the hardware capabilities.
83 */
84u_int
85ath_hal_getwirelessmodes(struct ath_hal*ah)
86{
87	return ath_hal_getWirelessModes(ah);
88}
89
90/* linker set of registered RF backends */
91OS_SET_DECLARE(ah_rfs, struct ath_hal_rf);
92
93/*
94 * Check the set of registered RF backends to see if
95 * any recognize the device as one they can support.
96 */
97struct ath_hal_rf *
98ath_hal_rfprobe(struct ath_hal *ah, HAL_STATUS *ecode)
99{
100	struct ath_hal_rf * const *prf;
101
102	OS_SET_FOREACH(prf, ah_rfs) {
103		struct ath_hal_rf *rf = *prf;
104		if (rf->probe(ah))
105			return rf;
106	}
107	*ecode = HAL_ENOTSUPP;
108	return AH_NULL;
109}
110
111/*
112 * Poll the register looking for a specific value.
113 */
114HAL_BOOL
115ath_hal_wait(struct ath_hal *ah, u_int reg, uint32_t mask, uint32_t val)
116{
117#define	AH_TIMEOUT	1000
118	int i;
119
120	for (i = 0; i < AH_TIMEOUT; i++) {
121		if ((OS_REG_READ(ah, reg) & mask) == val)
122			return AH_TRUE;
123		OS_DELAY(10);
124	}
125	HALDEBUG(ah, HAL_DEBUG_REGIO | HAL_DEBUG_PHYIO,
126	    "%s: timeout on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n",
127	    __func__, reg, OS_REG_READ(ah, reg), mask, val);
128	return AH_FALSE;
129#undef AH_TIMEOUT
130}
131
132/*
133 * Reverse the bits starting at the low bit for a value of
134 * bit_count in size
135 */
136uint32_t
137ath_hal_reverseBits(uint32_t val, uint32_t n)
138{
139	uint32_t retval;
140	int i;
141
142	for (i = 0, retval = 0; i < n; i++) {
143		retval = (retval << 1) | (val & 1);
144		val >>= 1;
145	}
146	return retval;
147}
148
149/*
150 * Compute the time to transmit a frame of length frameLen bytes
151 * using the specified rate, phy, and short preamble setting.
152 */
153uint16_t
154ath_hal_computetxtime(struct ath_hal *ah,
155	const HAL_RATE_TABLE *rates, uint32_t frameLen, uint16_t rateix,
156	HAL_BOOL shortPreamble)
157{
158	uint32_t bitsPerSymbol, numBits, numSymbols, phyTime, txTime;
159	uint32_t kbps;
160
161	kbps = rates->info[rateix].rateKbps;
162	/*
163	 * index can be invalid duting dynamic Turbo transitions.
164	 * XXX
165	 */
166	if (kbps == 0)
167		return 0;
168	switch (rates->info[rateix].phy) {
169
170	case IEEE80211_T_CCK:
171#define CCK_SIFS_TIME        10
172#define CCK_PREAMBLE_BITS   144
173#define CCK_PLCP_BITS        48
174		phyTime		= CCK_PREAMBLE_BITS + CCK_PLCP_BITS;
175		if (shortPreamble && rates->info[rateix].shortPreamble)
176			phyTime >>= 1;
177		numBits		= frameLen << 3;
178		txTime		= CCK_SIFS_TIME + phyTime
179				+ ((numBits * 1000)/kbps);
180		break;
181#undef CCK_SIFS_TIME
182#undef CCK_PREAMBLE_BITS
183#undef CCK_PLCP_BITS
184
185	case IEEE80211_T_OFDM:
186#define OFDM_SIFS_TIME        16
187#define OFDM_PREAMBLE_TIME    20
188#define OFDM_PLCP_BITS        22
189#define OFDM_SYMBOL_TIME       4
190
191#define OFDM_SIFS_TIME_HALF	32
192#define OFDM_PREAMBLE_TIME_HALF	40
193#define OFDM_PLCP_BITS_HALF	22
194#define OFDM_SYMBOL_TIME_HALF	8
195
196#define OFDM_SIFS_TIME_QUARTER 		64
197#define OFDM_PREAMBLE_TIME_QUARTER	80
198#define OFDM_PLCP_BITS_QUARTER		22
199#define OFDM_SYMBOL_TIME_QUARTER	16
200
201		if (AH_PRIVATE(ah)->ah_curchan != AH_NULL &&
202		    IEEE80211_IS_CHAN_QUARTER(AH_PRIVATE(ah)->ah_curchan)) {
203			bitsPerSymbol	= (kbps * OFDM_SYMBOL_TIME_QUARTER) / 1000;
204			HALASSERT(bitsPerSymbol != 0);
205
206			numBits		= OFDM_PLCP_BITS + (frameLen << 3);
207			numSymbols	= howmany(numBits, bitsPerSymbol);
208			txTime		= OFDM_SIFS_TIME_QUARTER
209						+ OFDM_PREAMBLE_TIME_QUARTER
210					+ (numSymbols * OFDM_SYMBOL_TIME_QUARTER);
211		} else if (AH_PRIVATE(ah)->ah_curchan != AH_NULL &&
212		    IEEE80211_IS_CHAN_HALF(AH_PRIVATE(ah)->ah_curchan)) {
213			bitsPerSymbol	= (kbps * OFDM_SYMBOL_TIME_HALF) / 1000;
214			HALASSERT(bitsPerSymbol != 0);
215
216			numBits		= OFDM_PLCP_BITS + (frameLen << 3);
217			numSymbols	= howmany(numBits, bitsPerSymbol);
218			txTime		= OFDM_SIFS_TIME_HALF +
219						OFDM_PREAMBLE_TIME_HALF
220					+ (numSymbols * OFDM_SYMBOL_TIME_HALF);
221		} else { /* full rate channel */
222			bitsPerSymbol	= (kbps * OFDM_SYMBOL_TIME) / 1000;
223			HALASSERT(bitsPerSymbol != 0);
224
225			numBits		= OFDM_PLCP_BITS + (frameLen << 3);
226			numSymbols	= howmany(numBits, bitsPerSymbol);
227			txTime		= OFDM_SIFS_TIME + OFDM_PREAMBLE_TIME
228					+ (numSymbols * OFDM_SYMBOL_TIME);
229		}
230		break;
231
232#undef OFDM_SIFS_TIME
233#undef OFDM_PREAMBLE_TIME
234#undef OFDM_PLCP_BITS
235#undef OFDM_SYMBOL_TIME
236
237	case IEEE80211_T_TURBO:
238#define TURBO_SIFS_TIME         8
239#define TURBO_PREAMBLE_TIME    14
240#define TURBO_PLCP_BITS        22
241#define TURBO_SYMBOL_TIME       4
242		/* we still save OFDM rates in kbps - so double them */
243		bitsPerSymbol = ((kbps << 1) * TURBO_SYMBOL_TIME) / 1000;
244		HALASSERT(bitsPerSymbol != 0);
245
246		numBits       = TURBO_PLCP_BITS + (frameLen << 3);
247		numSymbols    = howmany(numBits, bitsPerSymbol);
248		txTime        = TURBO_SIFS_TIME + TURBO_PREAMBLE_TIME
249			      + (numSymbols * TURBO_SYMBOL_TIME);
250		break;
251#undef TURBO_SIFS_TIME
252#undef TURBO_PREAMBLE_TIME
253#undef TURBO_PLCP_BITS
254#undef TURBO_SYMBOL_TIME
255
256	default:
257		HALDEBUG(ah, HAL_DEBUG_PHYIO,
258		    "%s: unknown phy %u (rate ix %u)\n",
259		    __func__, rates->info[rateix].phy, rateix);
260		txTime = 0;
261		break;
262	}
263	return txTime;
264}
265
266typedef enum {
267	WIRELESS_MODE_11a   = 0,
268	WIRELESS_MODE_TURBO = 1,
269	WIRELESS_MODE_11b   = 2,
270	WIRELESS_MODE_11g   = 3,
271	WIRELESS_MODE_108g  = 4,
272
273	WIRELESS_MODE_MAX
274} WIRELESS_MODE;
275
276static WIRELESS_MODE
277ath_hal_chan2wmode(struct ath_hal *ah, const struct ieee80211_channel *chan)
278{
279	if (IEEE80211_IS_CHAN_B(chan))
280		return WIRELESS_MODE_11b;
281	if (IEEE80211_IS_CHAN_G(chan))
282		return WIRELESS_MODE_11g;
283	if (IEEE80211_IS_CHAN_108G(chan))
284		return WIRELESS_MODE_108g;
285	if (IEEE80211_IS_CHAN_TURBO(chan))
286		return WIRELESS_MODE_TURBO;
287	return WIRELESS_MODE_11a;
288}
289
290/*
291 * Convert between microseconds and core system clocks.
292 */
293                                     /* 11a Turbo  11b  11g  108g */
294static const uint8_t CLOCK_RATE[]  = { 40,  80,   22,  44,   88  };
295
296u_int
297ath_hal_mac_clks(struct ath_hal *ah, u_int usecs)
298{
299	const struct ieee80211_channel *c = AH_PRIVATE(ah)->ah_curchan;
300	u_int clks;
301
302	/* NB: ah_curchan may be null when called attach time */
303	if (c != AH_NULL) {
304		clks = usecs * CLOCK_RATE[ath_hal_chan2wmode(ah, c)];
305		if (IEEE80211_IS_CHAN_HT40(c))
306			clks <<= 1;
307		else if (IEEE80211_IS_CHAN_HALF(c))
308			clks >>= 1;
309		else if (IEEE80211_IS_CHAN_QUARTER(c))
310			clks >>= 2;
311	} else
312		clks = usecs * CLOCK_RATE[WIRELESS_MODE_11b];
313	return clks;
314}
315
316u_int
317ath_hal_mac_usec(struct ath_hal *ah, u_int clks)
318{
319	const struct ieee80211_channel *c = AH_PRIVATE(ah)->ah_curchan;
320	u_int usec;
321
322	/* NB: ah_curchan may be null when called attach time */
323	if (c != AH_NULL) {
324		usec = clks / CLOCK_RATE[ath_hal_chan2wmode(ah, c)];
325		if (IEEE80211_IS_CHAN_HT40(c))
326			usec >>= 1;
327		else if (IEEE80211_IS_CHAN_HALF(c))
328			usec <<= 1;
329		else if (IEEE80211_IS_CHAN_QUARTER(c))
330			usec <<= 2;
331	} else
332		usec = clks / CLOCK_RATE[WIRELESS_MODE_11b];
333	return usec;
334}
335
336/*
337 * Setup a h/w rate table's reverse lookup table and
338 * fill in ack durations.  This routine is called for
339 * each rate table returned through the ah_getRateTable
340 * method.  The reverse lookup tables are assumed to be
341 * initialized to zero (or at least the first entry).
342 * We use this as a key that indicates whether or not
343 * we've previously setup the reverse lookup table.
344 *
345 * XXX not reentrant, but shouldn't matter
346 */
347void
348ath_hal_setupratetable(struct ath_hal *ah, HAL_RATE_TABLE *rt)
349{
350#define	N(a)	(sizeof(a)/sizeof(a[0]))
351	int i;
352
353	if (rt->rateCodeToIndex[0] != 0)	/* already setup */
354		return;
355	for (i = 0; i < N(rt->rateCodeToIndex); i++)
356		rt->rateCodeToIndex[i] = (uint8_t) -1;
357	for (i = 0; i < rt->rateCount; i++) {
358		uint8_t code = rt->info[i].rateCode;
359		uint8_t cix = rt->info[i].controlRate;
360
361		HALASSERT(code < N(rt->rateCodeToIndex));
362		rt->rateCodeToIndex[code] = i;
363		HALASSERT((code | rt->info[i].shortPreamble) <
364		    N(rt->rateCodeToIndex));
365		rt->rateCodeToIndex[code | rt->info[i].shortPreamble] = i;
366		/*
367		 * XXX for 11g the control rate to use for 5.5 and 11 Mb/s
368		 *     depends on whether they are marked as basic rates;
369		 *     the static tables are setup with an 11b-compatible
370		 *     2Mb/s rate which will work but is suboptimal
371		 */
372		rt->info[i].lpAckDuration = ath_hal_computetxtime(ah, rt,
373			WLAN_CTRL_FRAME_SIZE, cix, AH_FALSE);
374		rt->info[i].spAckDuration = ath_hal_computetxtime(ah, rt,
375			WLAN_CTRL_FRAME_SIZE, cix, AH_TRUE);
376	}
377#undef N
378}
379
380HAL_STATUS
381ath_hal_getcapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type,
382	uint32_t capability, uint32_t *result)
383{
384	const HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps;
385
386	switch (type) {
387	case HAL_CAP_REG_DMN:		/* regulatory domain */
388		*result = AH_PRIVATE(ah)->ah_currentRD;
389		return HAL_OK;
390	case HAL_CAP_CIPHER:		/* cipher handled in hardware */
391	case HAL_CAP_TKIP_MIC:		/* handle TKIP MIC in hardware */
392		return HAL_ENOTSUPP;
393	case HAL_CAP_TKIP_SPLIT:	/* hardware TKIP uses split keys */
394		return HAL_ENOTSUPP;
395	case HAL_CAP_PHYCOUNTERS:	/* hardware PHY error counters */
396		return pCap->halHwPhyCounterSupport ? HAL_OK : HAL_ENXIO;
397	case HAL_CAP_WME_TKIPMIC:   /* hardware can do TKIP MIC when WMM is turned on */
398		return HAL_ENOTSUPP;
399	case HAL_CAP_DIVERSITY:		/* hardware supports fast diversity */
400		return HAL_ENOTSUPP;
401	case HAL_CAP_KEYCACHE_SIZE:	/* hardware key cache size */
402		*result =  pCap->halKeyCacheSize;
403		return HAL_OK;
404	case HAL_CAP_NUM_TXQUEUES:	/* number of hardware tx queues */
405		*result = pCap->halTotalQueues;
406		return HAL_OK;
407	case HAL_CAP_VEOL:		/* hardware supports virtual EOL */
408		return pCap->halVEOLSupport ? HAL_OK : HAL_ENOTSUPP;
409	case HAL_CAP_PSPOLL:		/* hardware PS-Poll support works */
410		return pCap->halPSPollBroken ? HAL_ENOTSUPP : HAL_OK;
411	case HAL_CAP_COMPRESSION:
412		return pCap->halCompressSupport ? HAL_OK : HAL_ENOTSUPP;
413	case HAL_CAP_BURST:
414		return pCap->halBurstSupport ? HAL_OK : HAL_ENOTSUPP;
415	case HAL_CAP_FASTFRAME:
416		return pCap->halFastFramesSupport ? HAL_OK : HAL_ENOTSUPP;
417	case HAL_CAP_DIAG:		/* hardware diagnostic support */
418		*result = AH_PRIVATE(ah)->ah_diagreg;
419		return HAL_OK;
420	case HAL_CAP_TXPOW:		/* global tx power limit  */
421		switch (capability) {
422		case 0:			/* facility is supported */
423			return HAL_OK;
424		case 1:			/* current limit */
425			*result = AH_PRIVATE(ah)->ah_powerLimit;
426			return HAL_OK;
427		case 2:			/* current max tx power */
428			*result = AH_PRIVATE(ah)->ah_maxPowerLevel;
429			return HAL_OK;
430		case 3:			/* scale factor */
431			*result = AH_PRIVATE(ah)->ah_tpScale;
432			return HAL_OK;
433		}
434		return HAL_ENOTSUPP;
435	case HAL_CAP_BSSIDMASK:		/* hardware supports bssid mask */
436		return pCap->halBssIdMaskSupport ? HAL_OK : HAL_ENOTSUPP;
437	case HAL_CAP_MCAST_KEYSRCH:	/* multicast frame keycache search */
438		return pCap->halMcastKeySrchSupport ? HAL_OK : HAL_ENOTSUPP;
439	case HAL_CAP_TSF_ADJUST:	/* hardware has beacon tsf adjust */
440		return HAL_ENOTSUPP;
441	case HAL_CAP_RFSILENT:		/* rfsilent support  */
442		switch (capability) {
443		case 0:			/* facility is supported */
444			return pCap->halRfSilentSupport ? HAL_OK : HAL_ENOTSUPP;
445		case 1:			/* current setting */
446			return AH_PRIVATE(ah)->ah_rfkillEnabled ?
447				HAL_OK : HAL_ENOTSUPP;
448		case 2:			/* rfsilent config */
449			*result = AH_PRIVATE(ah)->ah_rfsilent;
450			return HAL_OK;
451		}
452		return HAL_ENOTSUPP;
453	case HAL_CAP_11D:
454		return HAL_OK;
455	case HAL_CAP_RXORN_FATAL:	/* HAL_INT_RXORN treated as fatal  */
456		return AH_PRIVATE(ah)->ah_rxornIsFatal ? HAL_OK : HAL_ENOTSUPP;
457	case HAL_CAP_HT:
458		return pCap->halHTSupport ? HAL_OK : HAL_ENOTSUPP;
459	case HAL_CAP_TX_CHAINMASK:	/* mask of TX chains supported */
460		*result = pCap->halTxChainMask;
461		return HAL_OK;
462	case HAL_CAP_RX_CHAINMASK:	/* mask of RX chains supported */
463		*result = pCap->halRxChainMask;
464		return HAL_OK;
465	case HAL_CAP_RXTSTAMP_PREC:	/* rx desc tstamp precision (bits) */
466		*result = pCap->halTstampPrecision;
467		return HAL_OK;
468	default:
469		return HAL_EINVAL;
470	}
471}
472
473HAL_BOOL
474ath_hal_setcapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type,
475	uint32_t capability, uint32_t setting, HAL_STATUS *status)
476{
477
478	switch (type) {
479	case HAL_CAP_TXPOW:
480		switch (capability) {
481		case 3:
482			if (setting <= HAL_TP_SCALE_MIN) {
483				AH_PRIVATE(ah)->ah_tpScale = setting;
484				return AH_TRUE;
485			}
486			break;
487		}
488		break;
489	case HAL_CAP_RFSILENT:		/* rfsilent support  */
490		/*
491		 * NB: allow even if halRfSilentSupport is false
492		 *     in case the EEPROM is misprogrammed.
493		 */
494		switch (capability) {
495		case 1:			/* current setting */
496			AH_PRIVATE(ah)->ah_rfkillEnabled = (setting != 0);
497			return AH_TRUE;
498		case 2:			/* rfsilent config */
499			/* XXX better done per-chip for validation? */
500			AH_PRIVATE(ah)->ah_rfsilent = setting;
501			return AH_TRUE;
502		}
503		break;
504	case HAL_CAP_REG_DMN:		/* regulatory domain */
505		AH_PRIVATE(ah)->ah_currentRD = setting;
506		return AH_TRUE;
507	case HAL_CAP_RXORN_FATAL:	/* HAL_INT_RXORN treated as fatal  */
508		AH_PRIVATE(ah)->ah_rxornIsFatal = setting;
509		return AH_TRUE;
510	default:
511		break;
512	}
513	if (status)
514		*status = HAL_EINVAL;
515	return AH_FALSE;
516}
517
518/*
519 * Common support for getDiagState method.
520 */
521
522static u_int
523ath_hal_getregdump(struct ath_hal *ah, const HAL_REGRANGE *regs,
524	void *dstbuf, int space)
525{
526	uint32_t *dp = dstbuf;
527	int i;
528
529	for (i = 0; space >= 2*sizeof(uint32_t); i++) {
530		u_int r = regs[i].start;
531		u_int e = regs[i].end;
532		*dp++ = (r<<16) | e;
533		space -= sizeof(uint32_t);
534		do {
535			*dp++ = OS_REG_READ(ah, r);
536			r += sizeof(uint32_t);
537			space -= sizeof(uint32_t);
538		} while (r <= e && space >= sizeof(uint32_t));
539	}
540	return (char *) dp - (char *) dstbuf;
541}
542
543HAL_BOOL
544ath_hal_getdiagstate(struct ath_hal *ah, int request,
545	const void *args, uint32_t argsize,
546	void **result, uint32_t *resultsize)
547{
548	switch (request) {
549	case HAL_DIAG_REVS:
550		*result = &AH_PRIVATE(ah)->ah_devid;
551		*resultsize = sizeof(HAL_REVS);
552		return AH_TRUE;
553	case HAL_DIAG_REGS:
554		*resultsize = ath_hal_getregdump(ah, args, *result,*resultsize);
555		return AH_TRUE;
556	case HAL_DIAG_FATALERR:
557		*result = &AH_PRIVATE(ah)->ah_fatalState[0];
558		*resultsize = sizeof(AH_PRIVATE(ah)->ah_fatalState);
559		return AH_TRUE;
560	case HAL_DIAG_EEREAD:
561		if (argsize != sizeof(uint16_t))
562			return AH_FALSE;
563		if (!ath_hal_eepromRead(ah, *(const uint16_t *)args, *result))
564			return AH_FALSE;
565		*resultsize = sizeof(uint16_t);
566		return AH_TRUE;
567#ifdef AH_PRIVATE_DIAG
568	case HAL_DIAG_SETKEY: {
569		const HAL_DIAG_KEYVAL *dk;
570
571		if (argsize != sizeof(HAL_DIAG_KEYVAL))
572			return AH_FALSE;
573		dk = (const HAL_DIAG_KEYVAL *)args;
574		return ah->ah_setKeyCacheEntry(ah, dk->dk_keyix,
575			&dk->dk_keyval, dk->dk_mac, dk->dk_xor);
576	}
577	case HAL_DIAG_RESETKEY:
578		if (argsize != sizeof(uint16_t))
579			return AH_FALSE;
580		return ah->ah_resetKeyCacheEntry(ah, *(const uint16_t *)args);
581#ifdef AH_SUPPORT_WRITE_EEPROM
582	case HAL_DIAG_EEWRITE: {
583		const HAL_DIAG_EEVAL *ee;
584		if (argsize != sizeof(HAL_DIAG_EEVAL))
585			return AH_FALSE;
586		ee = (const HAL_DIAG_EEVAL *)args;
587		return ath_hal_eepromWrite(ah, ee->ee_off, ee->ee_data);
588	}
589#endif /* AH_SUPPORT_WRITE_EEPROM */
590#endif /* AH_PRIVATE_DIAG */
591	case HAL_DIAG_11NCOMPAT:
592		if (argsize == 0) {
593			*resultsize = sizeof(uint32_t);
594			*((uint32_t *)(*result)) =
595				AH_PRIVATE(ah)->ah_11nCompat;
596		} else if (argsize == sizeof(uint32_t)) {
597			AH_PRIVATE(ah)->ah_11nCompat = *(const uint32_t *)args;
598		} else
599			return AH_FALSE;
600		return AH_TRUE;
601	}
602	return AH_FALSE;
603}
604
605/*
606 * Set the properties of the tx queue with the parameters
607 * from qInfo.
608 */
609HAL_BOOL
610ath_hal_setTxQProps(struct ath_hal *ah,
611	HAL_TX_QUEUE_INFO *qi, const HAL_TXQ_INFO *qInfo)
612{
613	uint32_t cw;
614
615	if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) {
616		HALDEBUG(ah, HAL_DEBUG_TXQUEUE,
617		    "%s: inactive queue\n", __func__);
618		return AH_FALSE;
619	}
620	/* XXX validate parameters */
621	qi->tqi_ver = qInfo->tqi_ver;
622	qi->tqi_subtype = qInfo->tqi_subtype;
623	qi->tqi_qflags = qInfo->tqi_qflags;
624	qi->tqi_priority = qInfo->tqi_priority;
625	if (qInfo->tqi_aifs != HAL_TXQ_USEDEFAULT)
626		qi->tqi_aifs = AH_MIN(qInfo->tqi_aifs, 255);
627	else
628		qi->tqi_aifs = INIT_AIFS;
629	if (qInfo->tqi_cwmin != HAL_TXQ_USEDEFAULT) {
630		cw = AH_MIN(qInfo->tqi_cwmin, 1024);
631		/* make sure that the CWmin is of the form (2^n - 1) */
632		qi->tqi_cwmin = 1;
633		while (qi->tqi_cwmin < cw)
634			qi->tqi_cwmin = (qi->tqi_cwmin << 1) | 1;
635	} else
636		qi->tqi_cwmin = qInfo->tqi_cwmin;
637	if (qInfo->tqi_cwmax != HAL_TXQ_USEDEFAULT) {
638		cw = AH_MIN(qInfo->tqi_cwmax, 1024);
639		/* make sure that the CWmax is of the form (2^n - 1) */
640		qi->tqi_cwmax = 1;
641		while (qi->tqi_cwmax < cw)
642			qi->tqi_cwmax = (qi->tqi_cwmax << 1) | 1;
643	} else
644		qi->tqi_cwmax = INIT_CWMAX;
645	/* Set retry limit values */
646	if (qInfo->tqi_shretry != 0)
647		qi->tqi_shretry = AH_MIN(qInfo->tqi_shretry, 15);
648	else
649		qi->tqi_shretry = INIT_SH_RETRY;
650	if (qInfo->tqi_lgretry != 0)
651		qi->tqi_lgretry = AH_MIN(qInfo->tqi_lgretry, 15);
652	else
653		qi->tqi_lgretry = INIT_LG_RETRY;
654	qi->tqi_cbrPeriod = qInfo->tqi_cbrPeriod;
655	qi->tqi_cbrOverflowLimit = qInfo->tqi_cbrOverflowLimit;
656	qi->tqi_burstTime = qInfo->tqi_burstTime;
657	qi->tqi_readyTime = qInfo->tqi_readyTime;
658
659	switch (qInfo->tqi_subtype) {
660	case HAL_WME_UPSD:
661		if (qi->tqi_type == HAL_TX_QUEUE_DATA)
662			qi->tqi_intFlags = HAL_TXQ_USE_LOCKOUT_BKOFF_DIS;
663		break;
664	default:
665		break;		/* NB: silence compiler */
666	}
667	return AH_TRUE;
668}
669
670HAL_BOOL
671ath_hal_getTxQProps(struct ath_hal *ah,
672	HAL_TXQ_INFO *qInfo, const HAL_TX_QUEUE_INFO *qi)
673{
674	if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) {
675		HALDEBUG(ah, HAL_DEBUG_TXQUEUE,
676		    "%s: inactive queue\n", __func__);
677		return AH_FALSE;
678	}
679
680	qInfo->tqi_qflags = qi->tqi_qflags;
681	qInfo->tqi_ver = qi->tqi_ver;
682	qInfo->tqi_subtype = qi->tqi_subtype;
683	qInfo->tqi_qflags = qi->tqi_qflags;
684	qInfo->tqi_priority = qi->tqi_priority;
685	qInfo->tqi_aifs = qi->tqi_aifs;
686	qInfo->tqi_cwmin = qi->tqi_cwmin;
687	qInfo->tqi_cwmax = qi->tqi_cwmax;
688	qInfo->tqi_shretry = qi->tqi_shretry;
689	qInfo->tqi_lgretry = qi->tqi_lgretry;
690	qInfo->tqi_cbrPeriod = qi->tqi_cbrPeriod;
691	qInfo->tqi_cbrOverflowLimit = qi->tqi_cbrOverflowLimit;
692	qInfo->tqi_burstTime = qi->tqi_burstTime;
693	qInfo->tqi_readyTime = qi->tqi_readyTime;
694	return AH_TRUE;
695}
696
697                                     /* 11a Turbo  11b  11g  108g */
698static const int16_t NOISE_FLOOR[] = { -96, -93,  -98, -96,  -93 };
699
700/*
701 * Read the current channel noise floor and return.
702 * If nf cal hasn't finished, channel noise floor should be 0
703 * and we return a nominal value based on band and frequency.
704 *
705 * NB: This is a private routine used by per-chip code to
706 *     implement the ah_getChanNoise method.
707 */
708int16_t
709ath_hal_getChanNoise(struct ath_hal *ah, const struct ieee80211_channel *chan)
710{
711	HAL_CHANNEL_INTERNAL *ichan;
712
713	ichan = ath_hal_checkchannel(ah, chan);
714	if (ichan == AH_NULL) {
715		HALDEBUG(ah, HAL_DEBUG_NFCAL,
716		    "%s: invalid channel %u/0x%x; no mapping\n",
717		    __func__, chan->ic_freq, chan->ic_flags);
718		return 0;
719	}
720	if (ichan->rawNoiseFloor == 0) {
721		WIRELESS_MODE mode = ath_hal_chan2wmode(ah, chan);
722
723		HALASSERT(mode < WIRELESS_MODE_MAX);
724		return NOISE_FLOOR[mode] + ath_hal_getNfAdjust(ah, ichan);
725	} else
726		return ichan->rawNoiseFloor + ichan->noiseFloorAdjust;
727}
728
729/*
730 * Process all valid raw noise floors into the dBm noise floor values.
731 * Though our device has no reference for a dBm noise floor, we perform
732 * a relative minimization of NF's based on the lowest NF found across a
733 * channel scan.
734 */
735void
736ath_hal_process_noisefloor(struct ath_hal *ah)
737{
738	HAL_CHANNEL_INTERNAL *c;
739	int16_t correct2, correct5;
740	int16_t lowest2, lowest5;
741	int i;
742
743	/*
744	 * Find the lowest 2GHz and 5GHz noise floor values after adjusting
745	 * for statistically recorded NF/channel deviation.
746	 */
747	correct2 = lowest2 = 0;
748	correct5 = lowest5 = 0;
749	for (i = 0; i < AH_PRIVATE(ah)->ah_nchan; i++) {
750		WIRELESS_MODE mode;
751		int16_t nf;
752
753		c = &AH_PRIVATE(ah)->ah_channels[i];
754		if (c->rawNoiseFloor >= 0)
755			continue;
756		/* XXX can't identify proper mode */
757		mode = IS_CHAN_5GHZ(c) ? WIRELESS_MODE_11a : WIRELESS_MODE_11g;
758		nf = c->rawNoiseFloor + NOISE_FLOOR[mode] +
759			ath_hal_getNfAdjust(ah, c);
760		if (IS_CHAN_5GHZ(c)) {
761			if (nf < lowest5) {
762				lowest5 = nf;
763				correct5 = NOISE_FLOOR[mode] -
764				    (c->rawNoiseFloor + ath_hal_getNfAdjust(ah, c));
765			}
766		} else {
767			if (nf < lowest2) {
768				lowest2 = nf;
769				correct2 = NOISE_FLOOR[mode] -
770				    (c->rawNoiseFloor + ath_hal_getNfAdjust(ah, c));
771			}
772		}
773	}
774
775	/* Correct the channels to reach the expected NF value */
776	for (i = 0; i < AH_PRIVATE(ah)->ah_nchan; i++) {
777		c = &AH_PRIVATE(ah)->ah_channels[i];
778		if (c->rawNoiseFloor >= 0)
779			continue;
780		/* Apply correction factor */
781		c->noiseFloorAdjust = ath_hal_getNfAdjust(ah, c) +
782			(IS_CHAN_5GHZ(c) ? correct5 : correct2);
783		HALDEBUG(ah, HAL_DEBUG_NFCAL, "%u raw nf %d adjust %d\n",
784		    c->channel, c->rawNoiseFloor, c->noiseFloorAdjust);
785	}
786}
787
788/*
789 * INI support routines.
790 */
791
792int
793ath_hal_ini_write(struct ath_hal *ah, const HAL_INI_ARRAY *ia,
794	int col, int regWr)
795{
796	int r;
797
798	for (r = 0; r < ia->rows; r++) {
799		OS_REG_WRITE(ah, HAL_INI_VAL(ia, r, 0),
800		    HAL_INI_VAL(ia, r, col));
801		DMA_YIELD(regWr);
802	}
803	return regWr;
804}
805
806void
807ath_hal_ini_bank_setup(uint32_t data[], const HAL_INI_ARRAY *ia, int col)
808{
809	int r;
810
811	for (r = 0; r < ia->rows; r++)
812		data[r] = HAL_INI_VAL(ia, r, col);
813}
814
815int
816ath_hal_ini_bank_write(struct ath_hal *ah, const HAL_INI_ARRAY *ia,
817	const uint32_t data[], int regWr)
818{
819	int r;
820
821	for (r = 0; r < ia->rows; r++) {
822		OS_REG_WRITE(ah, HAL_INI_VAL(ia, r, 0), data[r]);
823		DMA_YIELD(regWr);
824	}
825	return regWr;
826}
827