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