ah.c revision 222157
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 222157 2011-05-21 09:23:18Z adrian $
18 */
19#include "opt_ah.h"
20
21#include "ah.h"
22#include "ah_internal.h"
23#include "ah_devid.h"
24#include "ah_eeprom.h"			/* for 5ghz fast clock flag */
25
26#include "ar5416/ar5416reg.h"		/* NB: includes ar5212reg.h */
27
28/* linker set of registered chips */
29OS_SET_DECLARE(ah_chips, struct ath_hal_chip);
30
31/*
32 * Check the set of registered chips to see if any recognize
33 * the device as one they can support.
34 */
35const char*
36ath_hal_probe(uint16_t vendorid, uint16_t devid)
37{
38	struct ath_hal_chip * const *pchip;
39
40	OS_SET_FOREACH(pchip, ah_chips) {
41		const char *name = (*pchip)->probe(vendorid, devid);
42		if (name != AH_NULL)
43			return name;
44	}
45	return AH_NULL;
46}
47
48/*
49 * Attach detects device chip revisions, initializes the hwLayer
50 * function list, reads EEPROM information,
51 * selects reset vectors, and performs a short self test.
52 * Any failures will return an error that should cause a hardware
53 * disable.
54 */
55struct ath_hal*
56ath_hal_attach(uint16_t devid, HAL_SOFTC sc,
57	HAL_BUS_TAG st, HAL_BUS_HANDLE sh, uint16_t *eepromdata, HAL_STATUS *error)
58{
59	struct ath_hal_chip * const *pchip;
60
61	OS_SET_FOREACH(pchip, ah_chips) {
62		struct ath_hal_chip *chip = *pchip;
63		struct ath_hal *ah;
64
65		/* XXX don't have vendorid, assume atheros one works */
66		if (chip->probe(ATHEROS_VENDOR_ID, devid) == AH_NULL)
67			continue;
68		ah = chip->attach(devid, sc, st, sh, eepromdata, error);
69		if (ah != AH_NULL) {
70			/* copy back private state to public area */
71			ah->ah_devid = AH_PRIVATE(ah)->ah_devid;
72			ah->ah_subvendorid = AH_PRIVATE(ah)->ah_subvendorid;
73			ah->ah_macVersion = AH_PRIVATE(ah)->ah_macVersion;
74			ah->ah_macRev = AH_PRIVATE(ah)->ah_macRev;
75			ah->ah_phyRev = AH_PRIVATE(ah)->ah_phyRev;
76			ah->ah_analog5GhzRev = AH_PRIVATE(ah)->ah_analog5GhzRev;
77			ah->ah_analog2GhzRev = AH_PRIVATE(ah)->ah_analog2GhzRev;
78			return ah;
79		}
80	}
81	return AH_NULL;
82}
83
84const char *
85ath_hal_mac_name(struct ath_hal *ah)
86{
87	switch (ah->ah_macVersion) {
88	case AR_SREV_VERSION_CRETE:
89	case AR_SREV_VERSION_MAUI_1:
90		return "5210";
91	case AR_SREV_VERSION_MAUI_2:
92	case AR_SREV_VERSION_OAHU:
93		return "5211";
94	case AR_SREV_VERSION_VENICE:
95		return "5212";
96	case AR_SREV_VERSION_GRIFFIN:
97		return "2413";
98	case AR_SREV_VERSION_CONDOR:
99		return "5424";
100	case AR_SREV_VERSION_EAGLE:
101		return "5413";
102	case AR_SREV_VERSION_COBRA:
103		return "2415";
104	case AR_SREV_2425:
105		return "2425";
106	case AR_SREV_2417:
107		return "2417";
108	case AR_XSREV_VERSION_OWL_PCI:
109		return "5416";
110	case AR_XSREV_VERSION_OWL_PCIE:
111		return "5418";
112	case AR_XSREV_VERSION_HOWL:
113		return "9130";
114	case AR_XSREV_VERSION_SOWL:
115		return "9160";
116	case AR_XSREV_VERSION_MERLIN:
117		return "9280";
118	case AR_XSREV_VERSION_KITE:
119		return "9285";
120	}
121	return "????";
122}
123
124/*
125 * Return the mask of available modes based on the hardware capabilities.
126 */
127u_int
128ath_hal_getwirelessmodes(struct ath_hal*ah)
129{
130	return ath_hal_getWirelessModes(ah);
131}
132
133/* linker set of registered RF backends */
134OS_SET_DECLARE(ah_rfs, struct ath_hal_rf);
135
136/*
137 * Check the set of registered RF backends to see if
138 * any recognize the device as one they can support.
139 */
140struct ath_hal_rf *
141ath_hal_rfprobe(struct ath_hal *ah, HAL_STATUS *ecode)
142{
143	struct ath_hal_rf * const *prf;
144
145	OS_SET_FOREACH(prf, ah_rfs) {
146		struct ath_hal_rf *rf = *prf;
147		if (rf->probe(ah))
148			return rf;
149	}
150	*ecode = HAL_ENOTSUPP;
151	return AH_NULL;
152}
153
154const char *
155ath_hal_rf_name(struct ath_hal *ah)
156{
157	switch (ah->ah_analog5GhzRev & AR_RADIO_SREV_MAJOR) {
158	case 0:			/* 5210 */
159		return "5110";	/* NB: made up */
160	case AR_RAD5111_SREV_MAJOR:
161	case AR_RAD5111_SREV_PROD:
162		return "5111";
163	case AR_RAD2111_SREV_MAJOR:
164		return "2111";
165	case AR_RAD5112_SREV_MAJOR:
166	case AR_RAD5112_SREV_2_0:
167	case AR_RAD5112_SREV_2_1:
168		return "5112";
169	case AR_RAD2112_SREV_MAJOR:
170	case AR_RAD2112_SREV_2_0:
171	case AR_RAD2112_SREV_2_1:
172		return "2112";
173	case AR_RAD2413_SREV_MAJOR:
174		return "2413";
175	case AR_RAD5413_SREV_MAJOR:
176		return "5413";
177	case AR_RAD2316_SREV_MAJOR:
178		return "2316";
179	case AR_RAD2317_SREV_MAJOR:
180		return "2317";
181	case AR_RAD5424_SREV_MAJOR:
182		return "5424";
183
184	case AR_RAD5133_SREV_MAJOR:
185		return "5133";
186	case AR_RAD2133_SREV_MAJOR:
187		return "2133";
188	case AR_RAD5122_SREV_MAJOR:
189		return "5122";
190	case AR_RAD2122_SREV_MAJOR:
191		return "2122";
192	}
193	return "????";
194}
195
196/*
197 * Poll the register looking for a specific value.
198 */
199HAL_BOOL
200ath_hal_wait(struct ath_hal *ah, u_int reg, uint32_t mask, uint32_t val)
201{
202#define	AH_TIMEOUT	1000
203	return ath_hal_waitfor(ah, reg, mask, val, AH_TIMEOUT);
204#undef AH_TIMEOUT
205}
206
207HAL_BOOL
208ath_hal_waitfor(struct ath_hal *ah, u_int reg, uint32_t mask, uint32_t val, uint32_t timeout)
209{
210	int i;
211
212	for (i = 0; i < timeout; i++) {
213		if ((OS_REG_READ(ah, reg) & mask) == val)
214			return AH_TRUE;
215		OS_DELAY(10);
216	}
217	HALDEBUG(ah, HAL_DEBUG_REGIO | HAL_DEBUG_PHYIO,
218	    "%s: timeout on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n",
219	    __func__, reg, OS_REG_READ(ah, reg), mask, val);
220	return AH_FALSE;
221}
222
223/*
224 * Reverse the bits starting at the low bit for a value of
225 * bit_count in size
226 */
227uint32_t
228ath_hal_reverseBits(uint32_t val, uint32_t n)
229{
230	uint32_t retval;
231	int i;
232
233	for (i = 0, retval = 0; i < n; i++) {
234		retval = (retval << 1) | (val & 1);
235		val >>= 1;
236	}
237	return retval;
238}
239
240/* 802.11n related timing definitions */
241
242#define	OFDM_PLCP_BITS	22
243#define	HT_L_STF	8
244#define	HT_L_LTF	8
245#define	HT_L_SIG	4
246#define	HT_SIG		8
247#define	HT_STF		4
248#define	HT_LTF(n)	((n) * 4)
249
250#define	HT_RC_2_MCS(_rc)	((_rc) & 0xf)
251#define	HT_RC_2_STREAMS(_rc)	((((_rc) & 0x78) >> 3) + 1)
252#define	IS_HT_RATE(_rc)		( (_rc) & IEEE80211_RATE_MCS)
253
254/*
255 * Calculate the duration of a packet whether it is 11n or legacy.
256 */
257uint32_t
258ath_hal_pkt_txtime(struct ath_hal *ah, const HAL_RATE_TABLE *rates, uint32_t frameLen,
259    uint16_t rateix, HAL_BOOL isht40, HAL_BOOL shortPreamble)
260{
261	uint8_t rc;
262	int numStreams;
263
264	rc = rates->info[rateix].rateCode;
265
266	/* Legacy rate? Return the old way */
267	if (! IS_HT_RATE(rc))
268		return ath_hal_computetxtime(ah, rates, frameLen, rateix, shortPreamble);
269
270	/* 11n frame - extract out the number of spatial streams */
271	numStreams = HT_RC_2_STREAMS(rc);
272	KASSERT(numStreams == 1 || numStreams == 2, ("number of spatial streams needs to be 1 or 2: MCS rate 0x%x!", rateix));
273
274	return ath_computedur_ht(frameLen, rc, numStreams, isht40, shortPreamble);
275}
276
277/*
278 * Calculate the transmit duration of an 11n frame.
279 * This only works for MCS0->MCS15.
280 */
281uint32_t
282ath_computedur_ht(uint32_t frameLen, uint16_t rate, int streams, HAL_BOOL isht40,
283    HAL_BOOL isShortGI)
284{
285	static const uint16_t ht20_bps[16] = {
286	    26, 52, 78, 104, 156, 208, 234, 260,
287	    52, 104, 156, 208, 312, 416, 468, 520
288	};
289	static const uint16_t ht40_bps[16] = {
290	    54, 108, 162, 216, 324, 432, 486, 540,
291	    108, 216, 324, 432, 648, 864, 972, 1080,
292	};
293	uint32_t bitsPerSymbol, numBits, numSymbols, txTime;
294
295	KASSERT(rate & IEEE80211_RATE_MCS, ("not mcs %d", rate));
296	KASSERT((rate &~ IEEE80211_RATE_MCS) < 16, ("bad mcs 0x%x", rate));
297
298	if (isht40)
299		bitsPerSymbol = ht40_bps[rate & 0xf];
300	else
301		bitsPerSymbol = ht20_bps[rate & 0xf];
302	numBits = OFDM_PLCP_BITS + (frameLen << 3);
303	numSymbols = howmany(numBits, bitsPerSymbol);
304	if (isShortGI)
305		txTime = ((numSymbols * 18) + 4) / 5;   /* 3.6us */
306	else
307		txTime = numSymbols * 4;                /* 4us */
308	return txTime + HT_L_STF + HT_L_LTF +
309	    HT_L_SIG + HT_SIG + HT_STF + HT_LTF(streams);
310}
311
312/*
313 * Compute the time to transmit a frame of length frameLen bytes
314 * using the specified rate, phy, and short preamble setting.
315 */
316uint16_t
317ath_hal_computetxtime(struct ath_hal *ah,
318	const HAL_RATE_TABLE *rates, uint32_t frameLen, uint16_t rateix,
319	HAL_BOOL shortPreamble)
320{
321	uint32_t bitsPerSymbol, numBits, numSymbols, phyTime, txTime;
322	uint32_t kbps;
323
324	/* Warn if this function is called for 11n rates; it should not be! */
325	if (IS_HT_RATE(rates->info[rateix].rateCode))
326		ath_hal_printf(ah, "%s: MCS rate? (index %d; hwrate 0x%x)\n",
327		    __func__, rateix, rates->info[rateix].rateCode);
328
329	kbps = rates->info[rateix].rateKbps;
330	/*
331	 * index can be invalid duting dynamic Turbo transitions.
332	 * XXX
333	 */
334	if (kbps == 0)
335		return 0;
336	switch (rates->info[rateix].phy) {
337	case IEEE80211_T_CCK:
338		phyTime		= CCK_PREAMBLE_BITS + CCK_PLCP_BITS;
339		if (shortPreamble && rates->info[rateix].shortPreamble)
340			phyTime >>= 1;
341		numBits		= frameLen << 3;
342		txTime		= CCK_SIFS_TIME + phyTime
343				+ ((numBits * 1000)/kbps);
344		break;
345	case IEEE80211_T_OFDM:
346		bitsPerSymbol	= (kbps * OFDM_SYMBOL_TIME) / 1000;
347		HALASSERT(bitsPerSymbol != 0);
348
349		numBits		= OFDM_PLCP_BITS + (frameLen << 3);
350		numSymbols	= howmany(numBits, bitsPerSymbol);
351		txTime		= OFDM_SIFS_TIME
352				+ OFDM_PREAMBLE_TIME
353				+ (numSymbols * OFDM_SYMBOL_TIME);
354		break;
355	case IEEE80211_T_OFDM_HALF:
356		bitsPerSymbol	= (kbps * OFDM_HALF_SYMBOL_TIME) / 1000;
357		HALASSERT(bitsPerSymbol != 0);
358
359		numBits		= OFDM_HALF_PLCP_BITS + (frameLen << 3);
360		numSymbols	= howmany(numBits, bitsPerSymbol);
361		txTime		= OFDM_HALF_SIFS_TIME
362				+ OFDM_HALF_PREAMBLE_TIME
363				+ (numSymbols * OFDM_HALF_SYMBOL_TIME);
364		break;
365	case IEEE80211_T_OFDM_QUARTER:
366		bitsPerSymbol	= (kbps * OFDM_QUARTER_SYMBOL_TIME) / 1000;
367		HALASSERT(bitsPerSymbol != 0);
368
369		numBits		= OFDM_QUARTER_PLCP_BITS + (frameLen << 3);
370		numSymbols	= howmany(numBits, bitsPerSymbol);
371		txTime		= OFDM_QUARTER_SIFS_TIME
372				+ OFDM_QUARTER_PREAMBLE_TIME
373				+ (numSymbols * OFDM_QUARTER_SYMBOL_TIME);
374		break;
375	case IEEE80211_T_TURBO:
376		bitsPerSymbol	= (kbps * TURBO_SYMBOL_TIME) / 1000;
377		HALASSERT(bitsPerSymbol != 0);
378
379		numBits		= TURBO_PLCP_BITS + (frameLen << 3);
380		numSymbols	= howmany(numBits, bitsPerSymbol);
381		txTime		= TURBO_SIFS_TIME
382				+ TURBO_PREAMBLE_TIME
383				+ (numSymbols * TURBO_SYMBOL_TIME);
384		break;
385	default:
386		HALDEBUG(ah, HAL_DEBUG_PHYIO,
387		    "%s: unknown phy %u (rate ix %u)\n",
388		    __func__, rates->info[rateix].phy, rateix);
389		txTime = 0;
390		break;
391	}
392	return txTime;
393}
394
395typedef enum {
396	WIRELESS_MODE_11a   = 0,
397	WIRELESS_MODE_TURBO = 1,
398	WIRELESS_MODE_11b   = 2,
399	WIRELESS_MODE_11g   = 3,
400	WIRELESS_MODE_108g  = 4,
401
402	WIRELESS_MODE_MAX
403} WIRELESS_MODE;
404
405static WIRELESS_MODE
406ath_hal_chan2wmode(struct ath_hal *ah, const struct ieee80211_channel *chan)
407{
408	if (IEEE80211_IS_CHAN_B(chan))
409		return WIRELESS_MODE_11b;
410	if (IEEE80211_IS_CHAN_G(chan))
411		return WIRELESS_MODE_11g;
412	if (IEEE80211_IS_CHAN_108G(chan))
413		return WIRELESS_MODE_108g;
414	if (IEEE80211_IS_CHAN_TURBO(chan))
415		return WIRELESS_MODE_TURBO;
416	return WIRELESS_MODE_11a;
417}
418
419/*
420 * Convert between microseconds and core system clocks.
421 */
422                                     /* 11a Turbo  11b  11g  108g */
423static const uint8_t CLOCK_RATE[]  = { 40,  80,   22,  44,   88  };
424
425#define	CLOCK_FAST_RATE_5GHZ_OFDM	44
426
427u_int
428ath_hal_mac_clks(struct ath_hal *ah, u_int usecs)
429{
430	const struct ieee80211_channel *c = AH_PRIVATE(ah)->ah_curchan;
431	u_int clks;
432
433	/* NB: ah_curchan may be null when called attach time */
434	/* XXX merlin and later specific workaround - 5ghz fast clock is 44 */
435	if (c != AH_NULL && IS_5GHZ_FAST_CLOCK_EN(ah, c)) {
436		clks = usecs * CLOCK_FAST_RATE_5GHZ_OFDM;
437		if (IEEE80211_IS_CHAN_HT40(c))
438			clks <<= 1;
439	} else if (c != AH_NULL) {
440		clks = usecs * CLOCK_RATE[ath_hal_chan2wmode(ah, c)];
441		if (IEEE80211_IS_CHAN_HT40(c))
442			clks <<= 1;
443	} else
444		clks = usecs * CLOCK_RATE[WIRELESS_MODE_11b];
445	return clks;
446}
447
448u_int
449ath_hal_mac_usec(struct ath_hal *ah, u_int clks)
450{
451	const struct ieee80211_channel *c = AH_PRIVATE(ah)->ah_curchan;
452	u_int usec;
453
454	/* NB: ah_curchan may be null when called attach time */
455	/* XXX merlin and later specific workaround - 5ghz fast clock is 44 */
456	if (c != AH_NULL && IS_5GHZ_FAST_CLOCK_EN(ah, c)) {
457		usec = clks / CLOCK_FAST_RATE_5GHZ_OFDM;
458		if (IEEE80211_IS_CHAN_HT40(c))
459			usec >>= 1;
460	} else if (c != AH_NULL) {
461		usec = clks / CLOCK_RATE[ath_hal_chan2wmode(ah, c)];
462		if (IEEE80211_IS_CHAN_HT40(c))
463			usec >>= 1;
464	} else
465		usec = clks / CLOCK_RATE[WIRELESS_MODE_11b];
466	return usec;
467}
468
469/*
470 * Setup a h/w rate table's reverse lookup table and
471 * fill in ack durations.  This routine is called for
472 * each rate table returned through the ah_getRateTable
473 * method.  The reverse lookup tables are assumed to be
474 * initialized to zero (or at least the first entry).
475 * We use this as a key that indicates whether or not
476 * we've previously setup the reverse lookup table.
477 *
478 * XXX not reentrant, but shouldn't matter
479 */
480void
481ath_hal_setupratetable(struct ath_hal *ah, HAL_RATE_TABLE *rt)
482{
483#define	N(a)	(sizeof(a)/sizeof(a[0]))
484	int i;
485
486	if (rt->rateCodeToIndex[0] != 0)	/* already setup */
487		return;
488	for (i = 0; i < N(rt->rateCodeToIndex); i++)
489		rt->rateCodeToIndex[i] = (uint8_t) -1;
490	for (i = 0; i < rt->rateCount; i++) {
491		uint8_t code = rt->info[i].rateCode;
492		uint8_t cix = rt->info[i].controlRate;
493
494		HALASSERT(code < N(rt->rateCodeToIndex));
495		rt->rateCodeToIndex[code] = i;
496		HALASSERT((code | rt->info[i].shortPreamble) <
497		    N(rt->rateCodeToIndex));
498		rt->rateCodeToIndex[code | rt->info[i].shortPreamble] = i;
499		/*
500		 * XXX for 11g the control rate to use for 5.5 and 11 Mb/s
501		 *     depends on whether they are marked as basic rates;
502		 *     the static tables are setup with an 11b-compatible
503		 *     2Mb/s rate which will work but is suboptimal
504		 */
505		rt->info[i].lpAckDuration = ath_hal_computetxtime(ah, rt,
506			WLAN_CTRL_FRAME_SIZE, cix, AH_FALSE);
507		rt->info[i].spAckDuration = ath_hal_computetxtime(ah, rt,
508			WLAN_CTRL_FRAME_SIZE, cix, AH_TRUE);
509	}
510#undef N
511}
512
513HAL_STATUS
514ath_hal_getcapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type,
515	uint32_t capability, uint32_t *result)
516{
517	const HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps;
518
519	switch (type) {
520	case HAL_CAP_REG_DMN:		/* regulatory domain */
521		*result = AH_PRIVATE(ah)->ah_currentRD;
522		return HAL_OK;
523	case HAL_CAP_CIPHER:		/* cipher handled in hardware */
524	case HAL_CAP_TKIP_MIC:		/* handle TKIP MIC in hardware */
525		return HAL_ENOTSUPP;
526	case HAL_CAP_TKIP_SPLIT:	/* hardware TKIP uses split keys */
527		return HAL_ENOTSUPP;
528	case HAL_CAP_PHYCOUNTERS:	/* hardware PHY error counters */
529		return pCap->halHwPhyCounterSupport ? HAL_OK : HAL_ENXIO;
530	case HAL_CAP_WME_TKIPMIC:   /* hardware can do TKIP MIC when WMM is turned on */
531		return HAL_ENOTSUPP;
532	case HAL_CAP_DIVERSITY:		/* hardware supports fast diversity */
533		return HAL_ENOTSUPP;
534	case HAL_CAP_KEYCACHE_SIZE:	/* hardware key cache size */
535		*result =  pCap->halKeyCacheSize;
536		return HAL_OK;
537	case HAL_CAP_NUM_TXQUEUES:	/* number of hardware tx queues */
538		*result = pCap->halTotalQueues;
539		return HAL_OK;
540	case HAL_CAP_VEOL:		/* hardware supports virtual EOL */
541		return pCap->halVEOLSupport ? HAL_OK : HAL_ENOTSUPP;
542	case HAL_CAP_PSPOLL:		/* hardware PS-Poll support works */
543		return pCap->halPSPollBroken ? HAL_ENOTSUPP : HAL_OK;
544	case HAL_CAP_COMPRESSION:
545		return pCap->halCompressSupport ? HAL_OK : HAL_ENOTSUPP;
546	case HAL_CAP_BURST:
547		return pCap->halBurstSupport ? HAL_OK : HAL_ENOTSUPP;
548	case HAL_CAP_FASTFRAME:
549		return pCap->halFastFramesSupport ? HAL_OK : HAL_ENOTSUPP;
550	case HAL_CAP_DIAG:		/* hardware diagnostic support */
551		*result = AH_PRIVATE(ah)->ah_diagreg;
552		return HAL_OK;
553	case HAL_CAP_TXPOW:		/* global tx power limit  */
554		switch (capability) {
555		case 0:			/* facility is supported */
556			return HAL_OK;
557		case 1:			/* current limit */
558			*result = AH_PRIVATE(ah)->ah_powerLimit;
559			return HAL_OK;
560		case 2:			/* current max tx power */
561			*result = AH_PRIVATE(ah)->ah_maxPowerLevel;
562			return HAL_OK;
563		case 3:			/* scale factor */
564			*result = AH_PRIVATE(ah)->ah_tpScale;
565			return HAL_OK;
566		}
567		return HAL_ENOTSUPP;
568	case HAL_CAP_BSSIDMASK:		/* hardware supports bssid mask */
569		return pCap->halBssIdMaskSupport ? HAL_OK : HAL_ENOTSUPP;
570	case HAL_CAP_MCAST_KEYSRCH:	/* multicast frame keycache search */
571		return pCap->halMcastKeySrchSupport ? HAL_OK : HAL_ENOTSUPP;
572	case HAL_CAP_TSF_ADJUST:	/* hardware has beacon tsf adjust */
573		return HAL_ENOTSUPP;
574	case HAL_CAP_RFSILENT:		/* rfsilent support  */
575		switch (capability) {
576		case 0:			/* facility is supported */
577			return pCap->halRfSilentSupport ? HAL_OK : HAL_ENOTSUPP;
578		case 1:			/* current setting */
579			return AH_PRIVATE(ah)->ah_rfkillEnabled ?
580				HAL_OK : HAL_ENOTSUPP;
581		case 2:			/* rfsilent config */
582			*result = AH_PRIVATE(ah)->ah_rfsilent;
583			return HAL_OK;
584		}
585		return HAL_ENOTSUPP;
586	case HAL_CAP_11D:
587		return HAL_OK;
588
589	case HAL_CAP_HT:
590		return pCap->halHTSupport ? HAL_OK : HAL_ENOTSUPP;
591	case HAL_CAP_GTXTO:
592		return pCap->halGTTSupport ? HAL_OK : HAL_ENOTSUPP;
593	case HAL_CAP_FAST_CC:
594		return pCap->halFastCCSupport ? HAL_OK : HAL_ENOTSUPP;
595	case HAL_CAP_TX_CHAINMASK:	/* mask of TX chains supported */
596		*result = pCap->halTxChainMask;
597		return HAL_OK;
598	case HAL_CAP_RX_CHAINMASK:	/* mask of RX chains supported */
599		*result = pCap->halRxChainMask;
600		return HAL_OK;
601	case HAL_CAP_NUM_GPIO_PINS:
602		*result = pCap->halNumGpioPins;
603		return HAL_OK;
604	case HAL_CAP_CST:
605		return pCap->halCSTSupport ? HAL_OK : HAL_ENOTSUPP;
606	case HAL_CAP_RTS_AGGR_LIMIT:
607		*result = pCap->halRtsAggrLimit;
608		return HAL_OK;
609	case HAL_CAP_4ADDR_AGGR:
610		return pCap->hal4AddrAggrSupport ? HAL_OK : HAL_ENOTSUPP;
611	case HAL_CAP_AUTO_SLEEP:
612		return pCap->halAutoSleepSupport ? HAL_OK : HAL_ENOTSUPP;
613	case HAL_CAP_MBSSID_AGGR_SUPPORT:
614		return pCap->halMbssidAggrSupport ? HAL_OK : HAL_ENOTSUPP;
615	case HAL_CAP_SPLIT_4KB_TRANS:	/* hardware handles descriptors straddling 4k page boundary */
616		return pCap->hal4kbSplitTransSupport ? HAL_OK : HAL_ENOTSUPP;
617	case HAL_CAP_REG_FLAG:
618		*result = AH_PRIVATE(ah)->ah_currentRDext;
619		return HAL_OK;
620	case HAL_CAP_BT_COEX:
621		return pCap->halBtCoexSupport ? HAL_OK : HAL_ENOTSUPP;
622	case HAL_CAP_HT20_SGI:
623		return pCap->halHTSGI20Support ? HAL_OK : HAL_ENOTSUPP;
624	case HAL_CAP_RXTSTAMP_PREC:	/* rx desc tstamp precision (bits) */
625		*result = pCap->halTstampPrecision;
626		return HAL_OK;
627
628	/* FreeBSD-specific entries for now */
629	case HAL_CAP_RXORN_FATAL:	/* HAL_INT_RXORN treated as fatal  */
630		return AH_PRIVATE(ah)->ah_rxornIsFatal ? HAL_OK : HAL_ENOTSUPP;
631	case HAL_CAP_INTRMASK:		/* mask of supported interrupts */
632		*result = pCap->halIntrMask;
633		return HAL_OK;
634	case HAL_CAP_BSSIDMATCH:	/* hardware has disable bssid match */
635		return pCap->halBssidMatchSupport ? HAL_OK : HAL_ENOTSUPP;
636	case HAL_CAP_STREAMS:		/* number of 11n spatial streams */
637		switch (capability) {
638		case 0:			/* TX */
639			*result = pCap->halTxStreams;
640			return HAL_OK;
641		case 1:			/* RX */
642			*result = pCap->halRxStreams;
643			return HAL_OK;
644		default:
645			return HAL_ENOTSUPP;
646		}
647	case HAL_CAP_RXDESC_SELFLINK:	/* hardware supports self-linked final RX descriptors correctly */
648		return pCap->halHasRxSelfLinkedTail ? HAL_OK : HAL_ENOTSUPP;
649	default:
650		return HAL_EINVAL;
651	}
652}
653
654HAL_BOOL
655ath_hal_setcapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type,
656	uint32_t capability, uint32_t setting, HAL_STATUS *status)
657{
658
659	switch (type) {
660	case HAL_CAP_TXPOW:
661		switch (capability) {
662		case 3:
663			if (setting <= HAL_TP_SCALE_MIN) {
664				AH_PRIVATE(ah)->ah_tpScale = setting;
665				return AH_TRUE;
666			}
667			break;
668		}
669		break;
670	case HAL_CAP_RFSILENT:		/* rfsilent support  */
671		/*
672		 * NB: allow even if halRfSilentSupport is false
673		 *     in case the EEPROM is misprogrammed.
674		 */
675		switch (capability) {
676		case 1:			/* current setting */
677			AH_PRIVATE(ah)->ah_rfkillEnabled = (setting != 0);
678			return AH_TRUE;
679		case 2:			/* rfsilent config */
680			/* XXX better done per-chip for validation? */
681			AH_PRIVATE(ah)->ah_rfsilent = setting;
682			return AH_TRUE;
683		}
684		break;
685	case HAL_CAP_REG_DMN:		/* regulatory domain */
686		AH_PRIVATE(ah)->ah_currentRD = setting;
687		return AH_TRUE;
688	case HAL_CAP_RXORN_FATAL:	/* HAL_INT_RXORN treated as fatal  */
689		AH_PRIVATE(ah)->ah_rxornIsFatal = setting;
690		return AH_TRUE;
691	default:
692		break;
693	}
694	if (status)
695		*status = HAL_EINVAL;
696	return AH_FALSE;
697}
698
699/*
700 * Common support for getDiagState method.
701 */
702
703static u_int
704ath_hal_getregdump(struct ath_hal *ah, const HAL_REGRANGE *regs,
705	void *dstbuf, int space)
706{
707	uint32_t *dp = dstbuf;
708	int i;
709
710	for (i = 0; space >= 2*sizeof(uint32_t); i++) {
711		u_int r = regs[i].start;
712		u_int e = regs[i].end;
713		*dp++ = (r<<16) | e;
714		space -= sizeof(uint32_t);
715		do {
716			*dp++ = OS_REG_READ(ah, r);
717			r += sizeof(uint32_t);
718			space -= sizeof(uint32_t);
719		} while (r <= e && space >= sizeof(uint32_t));
720	}
721	return (char *) dp - (char *) dstbuf;
722}
723
724static void
725ath_hal_setregs(struct ath_hal *ah, const HAL_REGWRITE *regs, int space)
726{
727	while (space >= sizeof(HAL_REGWRITE)) {
728		OS_REG_WRITE(ah, regs->addr, regs->value);
729		regs++, space -= sizeof(HAL_REGWRITE);
730	}
731}
732
733HAL_BOOL
734ath_hal_getdiagstate(struct ath_hal *ah, int request,
735	const void *args, uint32_t argsize,
736	void **result, uint32_t *resultsize)
737{
738	switch (request) {
739	case HAL_DIAG_REVS:
740		*result = &AH_PRIVATE(ah)->ah_devid;
741		*resultsize = sizeof(HAL_REVS);
742		return AH_TRUE;
743	case HAL_DIAG_REGS:
744		*resultsize = ath_hal_getregdump(ah, args, *result,*resultsize);
745		return AH_TRUE;
746	case HAL_DIAG_SETREGS:
747		ath_hal_setregs(ah, args, argsize);
748		*resultsize = 0;
749		return AH_TRUE;
750	case HAL_DIAG_FATALERR:
751		*result = &AH_PRIVATE(ah)->ah_fatalState[0];
752		*resultsize = sizeof(AH_PRIVATE(ah)->ah_fatalState);
753		return AH_TRUE;
754	case HAL_DIAG_EEREAD:
755		if (argsize != sizeof(uint16_t))
756			return AH_FALSE;
757		if (!ath_hal_eepromRead(ah, *(const uint16_t *)args, *result))
758			return AH_FALSE;
759		*resultsize = sizeof(uint16_t);
760		return AH_TRUE;
761#ifdef AH_PRIVATE_DIAG
762	case HAL_DIAG_SETKEY: {
763		const HAL_DIAG_KEYVAL *dk;
764
765		if (argsize != sizeof(HAL_DIAG_KEYVAL))
766			return AH_FALSE;
767		dk = (const HAL_DIAG_KEYVAL *)args;
768		return ah->ah_setKeyCacheEntry(ah, dk->dk_keyix,
769			&dk->dk_keyval, dk->dk_mac, dk->dk_xor);
770	}
771	case HAL_DIAG_RESETKEY:
772		if (argsize != sizeof(uint16_t))
773			return AH_FALSE;
774		return ah->ah_resetKeyCacheEntry(ah, *(const uint16_t *)args);
775#ifdef AH_SUPPORT_WRITE_EEPROM
776	case HAL_DIAG_EEWRITE: {
777		const HAL_DIAG_EEVAL *ee;
778		if (argsize != sizeof(HAL_DIAG_EEVAL))
779			return AH_FALSE;
780		ee = (const HAL_DIAG_EEVAL *)args;
781		return ath_hal_eepromWrite(ah, ee->ee_off, ee->ee_data);
782	}
783#endif /* AH_SUPPORT_WRITE_EEPROM */
784#endif /* AH_PRIVATE_DIAG */
785	case HAL_DIAG_11NCOMPAT:
786		if (argsize == 0) {
787			*resultsize = sizeof(uint32_t);
788			*((uint32_t *)(*result)) =
789				AH_PRIVATE(ah)->ah_11nCompat;
790		} else if (argsize == sizeof(uint32_t)) {
791			AH_PRIVATE(ah)->ah_11nCompat = *(const uint32_t *)args;
792		} else
793			return AH_FALSE;
794		return AH_TRUE;
795	}
796	return AH_FALSE;
797}
798
799/*
800 * Set the properties of the tx queue with the parameters
801 * from qInfo.
802 */
803HAL_BOOL
804ath_hal_setTxQProps(struct ath_hal *ah,
805	HAL_TX_QUEUE_INFO *qi, const HAL_TXQ_INFO *qInfo)
806{
807	uint32_t cw;
808
809	if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) {
810		HALDEBUG(ah, HAL_DEBUG_TXQUEUE,
811		    "%s: inactive queue\n", __func__);
812		return AH_FALSE;
813	}
814	/* XXX validate parameters */
815	qi->tqi_ver = qInfo->tqi_ver;
816	qi->tqi_subtype = qInfo->tqi_subtype;
817	qi->tqi_qflags = qInfo->tqi_qflags;
818	qi->tqi_priority = qInfo->tqi_priority;
819	if (qInfo->tqi_aifs != HAL_TXQ_USEDEFAULT)
820		qi->tqi_aifs = AH_MIN(qInfo->tqi_aifs, 255);
821	else
822		qi->tqi_aifs = INIT_AIFS;
823	if (qInfo->tqi_cwmin != HAL_TXQ_USEDEFAULT) {
824		cw = AH_MIN(qInfo->tqi_cwmin, 1024);
825		/* make sure that the CWmin is of the form (2^n - 1) */
826		qi->tqi_cwmin = 1;
827		while (qi->tqi_cwmin < cw)
828			qi->tqi_cwmin = (qi->tqi_cwmin << 1) | 1;
829	} else
830		qi->tqi_cwmin = qInfo->tqi_cwmin;
831	if (qInfo->tqi_cwmax != HAL_TXQ_USEDEFAULT) {
832		cw = AH_MIN(qInfo->tqi_cwmax, 1024);
833		/* make sure that the CWmax is of the form (2^n - 1) */
834		qi->tqi_cwmax = 1;
835		while (qi->tqi_cwmax < cw)
836			qi->tqi_cwmax = (qi->tqi_cwmax << 1) | 1;
837	} else
838		qi->tqi_cwmax = INIT_CWMAX;
839	/* Set retry limit values */
840	if (qInfo->tqi_shretry != 0)
841		qi->tqi_shretry = AH_MIN(qInfo->tqi_shretry, 15);
842	else
843		qi->tqi_shretry = INIT_SH_RETRY;
844	if (qInfo->tqi_lgretry != 0)
845		qi->tqi_lgretry = AH_MIN(qInfo->tqi_lgretry, 15);
846	else
847		qi->tqi_lgretry = INIT_LG_RETRY;
848	qi->tqi_cbrPeriod = qInfo->tqi_cbrPeriod;
849	qi->tqi_cbrOverflowLimit = qInfo->tqi_cbrOverflowLimit;
850	qi->tqi_burstTime = qInfo->tqi_burstTime;
851	qi->tqi_readyTime = qInfo->tqi_readyTime;
852
853	switch (qInfo->tqi_subtype) {
854	case HAL_WME_UPSD:
855		if (qi->tqi_type == HAL_TX_QUEUE_DATA)
856			qi->tqi_intFlags = HAL_TXQ_USE_LOCKOUT_BKOFF_DIS;
857		break;
858	default:
859		break;		/* NB: silence compiler */
860	}
861	return AH_TRUE;
862}
863
864HAL_BOOL
865ath_hal_getTxQProps(struct ath_hal *ah,
866	HAL_TXQ_INFO *qInfo, const HAL_TX_QUEUE_INFO *qi)
867{
868	if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) {
869		HALDEBUG(ah, HAL_DEBUG_TXQUEUE,
870		    "%s: inactive queue\n", __func__);
871		return AH_FALSE;
872	}
873
874	qInfo->tqi_qflags = qi->tqi_qflags;
875	qInfo->tqi_ver = qi->tqi_ver;
876	qInfo->tqi_subtype = qi->tqi_subtype;
877	qInfo->tqi_qflags = qi->tqi_qflags;
878	qInfo->tqi_priority = qi->tqi_priority;
879	qInfo->tqi_aifs = qi->tqi_aifs;
880	qInfo->tqi_cwmin = qi->tqi_cwmin;
881	qInfo->tqi_cwmax = qi->tqi_cwmax;
882	qInfo->tqi_shretry = qi->tqi_shretry;
883	qInfo->tqi_lgretry = qi->tqi_lgretry;
884	qInfo->tqi_cbrPeriod = qi->tqi_cbrPeriod;
885	qInfo->tqi_cbrOverflowLimit = qi->tqi_cbrOverflowLimit;
886	qInfo->tqi_burstTime = qi->tqi_burstTime;
887	qInfo->tqi_readyTime = qi->tqi_readyTime;
888	return AH_TRUE;
889}
890
891                                     /* 11a Turbo  11b  11g  108g */
892static const int16_t NOISE_FLOOR[] = { -96, -93,  -98, -96,  -93 };
893
894/*
895 * Read the current channel noise floor and return.
896 * If nf cal hasn't finished, channel noise floor should be 0
897 * and we return a nominal value based on band and frequency.
898 *
899 * NB: This is a private routine used by per-chip code to
900 *     implement the ah_getChanNoise method.
901 */
902int16_t
903ath_hal_getChanNoise(struct ath_hal *ah, const struct ieee80211_channel *chan)
904{
905	HAL_CHANNEL_INTERNAL *ichan;
906
907	ichan = ath_hal_checkchannel(ah, chan);
908	if (ichan == AH_NULL) {
909		HALDEBUG(ah, HAL_DEBUG_NFCAL,
910		    "%s: invalid channel %u/0x%x; no mapping\n",
911		    __func__, chan->ic_freq, chan->ic_flags);
912		return 0;
913	}
914	if (ichan->rawNoiseFloor == 0) {
915		WIRELESS_MODE mode = ath_hal_chan2wmode(ah, chan);
916
917		HALASSERT(mode < WIRELESS_MODE_MAX);
918		return NOISE_FLOOR[mode] + ath_hal_getNfAdjust(ah, ichan);
919	} else
920		return ichan->rawNoiseFloor + ichan->noiseFloorAdjust;
921}
922
923/*
924 * Fetch the current setup of ctl/ext noise floor values.
925 *
926 * If the CHANNEL_MIMO_NF_VALID flag isn't set, the array is simply
927 * populated with values from NOISE_FLOOR[] + ath_hal_getNfAdjust().
928 *
929 * The caller must supply ctl/ext NF arrays which are at least
930 * AH_MIMO_MAX_CHAINS entries long.
931 */
932int
933ath_hal_get_mimo_chan_noise(struct ath_hal *ah,
934    const struct ieee80211_channel *chan, int16_t *nf_ctl,
935    int16_t *nf_ext)
936{
937#ifdef	AH_SUPPORT_AR5416
938	HAL_CHANNEL_INTERNAL *ichan;
939	int i;
940
941	ichan = ath_hal_checkchannel(ah, chan);
942	if (ichan == AH_NULL) {
943		HALDEBUG(ah, HAL_DEBUG_NFCAL,
944		    "%s: invalid channel %u/0x%x; no mapping\n",
945		    __func__, chan->ic_freq, chan->ic_flags);
946		for (i = 0; i < AH_MIMO_MAX_CHAINS; i++) {
947			nf_ctl[i] = nf_ext[i] = 0;
948		}
949		return 0;
950	}
951
952	/* Return 0 if there's no valid MIMO values (yet) */
953	if (! (ichan->privFlags & CHANNEL_MIMO_NF_VALID)) {
954		for (i = 0; i < AH_MIMO_MAX_CHAINS; i++) {
955			nf_ctl[i] = nf_ext[i] = 0;
956		}
957		return 0;
958	}
959	if (ichan->rawNoiseFloor == 0) {
960		WIRELESS_MODE mode = ath_hal_chan2wmode(ah, chan);
961		HALASSERT(mode < WIRELESS_MODE_MAX);
962		/*
963		 * See the comment below - this could cause issues for
964		 * stations which have a very low RSSI, below the
965		 * 'normalised' NF values in NOISE_FLOOR[].
966		 */
967		for (i = 0; i < AH_MIMO_MAX_CHAINS; i++) {
968			nf_ctl[i] = nf_ext[i] = NOISE_FLOOR[mode] +
969			    ath_hal_getNfAdjust(ah, ichan);
970		}
971		return 1;
972	} else {
973		/*
974		 * The value returned here from a MIMO radio is presumed to be
975		 * "good enough" as a NF calculation. As RSSI values are calculated
976		 * against this, an adjusted NF may be higher than the RSSI value
977		 * returned from a vary weak station, resulting in an obscenely
978		 * high signal strength calculation being returned.
979		 *
980		 * This should be re-evaluated at a later date, along with any
981		 * signal strength calculations which are made. Quite likely the
982		 * RSSI values will need to be adjusted to ensure the calculations
983		 * don't "wrap" when RSSI is less than the "adjusted" NF value.
984		 * ("Adjust" here is via ichan->noiseFloorAdjust.)
985		 */
986		for (i = 0; i < AH_MIMO_MAX_CHAINS; i++) {
987			nf_ctl[i] = ichan->noiseFloorCtl[i] + ath_hal_getNfAdjust(ah, ichan);
988			nf_ext[i] = ichan->noiseFloorExt[i] + ath_hal_getNfAdjust(ah, ichan);
989		}
990		return 1;
991	}
992#else
993	return 0;
994#endif	/* AH_SUPPORT_AR5416 */
995}
996
997/*
998 * Process all valid raw noise floors into the dBm noise floor values.
999 * Though our device has no reference for a dBm noise floor, we perform
1000 * a relative minimization of NF's based on the lowest NF found across a
1001 * channel scan.
1002 */
1003void
1004ath_hal_process_noisefloor(struct ath_hal *ah)
1005{
1006	HAL_CHANNEL_INTERNAL *c;
1007	int16_t correct2, correct5;
1008	int16_t lowest2, lowest5;
1009	int i;
1010
1011	/*
1012	 * Find the lowest 2GHz and 5GHz noise floor values after adjusting
1013	 * for statistically recorded NF/channel deviation.
1014	 */
1015	correct2 = lowest2 = 0;
1016	correct5 = lowest5 = 0;
1017	for (i = 0; i < AH_PRIVATE(ah)->ah_nchan; i++) {
1018		WIRELESS_MODE mode;
1019		int16_t nf;
1020
1021		c = &AH_PRIVATE(ah)->ah_channels[i];
1022		if (c->rawNoiseFloor >= 0)
1023			continue;
1024		/* XXX can't identify proper mode */
1025		mode = IS_CHAN_5GHZ(c) ? WIRELESS_MODE_11a : WIRELESS_MODE_11g;
1026		nf = c->rawNoiseFloor + NOISE_FLOOR[mode] +
1027			ath_hal_getNfAdjust(ah, c);
1028		if (IS_CHAN_5GHZ(c)) {
1029			if (nf < lowest5) {
1030				lowest5 = nf;
1031				correct5 = NOISE_FLOOR[mode] -
1032				    (c->rawNoiseFloor + ath_hal_getNfAdjust(ah, c));
1033			}
1034		} else {
1035			if (nf < lowest2) {
1036				lowest2 = nf;
1037				correct2 = NOISE_FLOOR[mode] -
1038				    (c->rawNoiseFloor + ath_hal_getNfAdjust(ah, c));
1039			}
1040		}
1041	}
1042
1043	/* Correct the channels to reach the expected NF value */
1044	for (i = 0; i < AH_PRIVATE(ah)->ah_nchan; i++) {
1045		c = &AH_PRIVATE(ah)->ah_channels[i];
1046		if (c->rawNoiseFloor >= 0)
1047			continue;
1048		/* Apply correction factor */
1049		c->noiseFloorAdjust = ath_hal_getNfAdjust(ah, c) +
1050			(IS_CHAN_5GHZ(c) ? correct5 : correct2);
1051		HALDEBUG(ah, HAL_DEBUG_NFCAL, "%u raw nf %d adjust %d\n",
1052		    c->channel, c->rawNoiseFloor, c->noiseFloorAdjust);
1053	}
1054}
1055
1056/*
1057 * INI support routines.
1058 */
1059
1060int
1061ath_hal_ini_write(struct ath_hal *ah, const HAL_INI_ARRAY *ia,
1062	int col, int regWr)
1063{
1064	int r;
1065
1066	HALASSERT(col < ia->cols);
1067	for (r = 0; r < ia->rows; r++) {
1068		OS_REG_WRITE(ah, HAL_INI_VAL(ia, r, 0),
1069		    HAL_INI_VAL(ia, r, col));
1070
1071		/* Analog shift register delay seems needed for Merlin - PR kern/154220 */
1072		if (HAL_INI_VAL(ia, r, 0) >= 0x7800 && HAL_INI_VAL(ia, r, 0) < 0x7900)
1073			OS_DELAY(100);
1074
1075		DMA_YIELD(regWr);
1076	}
1077	return regWr;
1078}
1079
1080void
1081ath_hal_ini_bank_setup(uint32_t data[], const HAL_INI_ARRAY *ia, int col)
1082{
1083	int r;
1084
1085	HALASSERT(col < ia->cols);
1086	for (r = 0; r < ia->rows; r++)
1087		data[r] = HAL_INI_VAL(ia, r, col);
1088}
1089
1090int
1091ath_hal_ini_bank_write(struct ath_hal *ah, const HAL_INI_ARRAY *ia,
1092	const uint32_t data[], int regWr)
1093{
1094	int r;
1095
1096	for (r = 0; r < ia->rows; r++) {
1097		OS_REG_WRITE(ah, HAL_INI_VAL(ia, r, 0), data[r]);
1098		DMA_YIELD(regWr);
1099	}
1100	return regWr;
1101}
1102
1103/*
1104 * These are EEPROM board related routines which should likely live in
1105 * a helper library of some sort.
1106 */
1107
1108/**************************************************************
1109 * ath_ee_getLowerUppderIndex
1110 *
1111 * Return indices surrounding the value in sorted integer lists.
1112 * Requirement: the input list must be monotonically increasing
1113 *     and populated up to the list size
1114 * Returns: match is set if an index in the array matches exactly
1115 *     or a the target is before or after the range of the array.
1116 */
1117HAL_BOOL
1118ath_ee_getLowerUpperIndex(uint8_t target, uint8_t *pList, uint16_t listSize,
1119                   uint16_t *indexL, uint16_t *indexR)
1120{
1121    uint16_t i;
1122
1123    /*
1124     * Check first and last elements for beyond ordered array cases.
1125     */
1126    if (target <= pList[0]) {
1127        *indexL = *indexR = 0;
1128        return AH_TRUE;
1129    }
1130    if (target >= pList[listSize-1]) {
1131        *indexL = *indexR = (uint16_t)(listSize - 1);
1132        return AH_TRUE;
1133    }
1134
1135    /* look for value being near or between 2 values in list */
1136    for (i = 0; i < listSize - 1; i++) {
1137        /*
1138         * If value is close to the current value of the list
1139         * then target is not between values, it is one of the values
1140         */
1141        if (pList[i] == target) {
1142            *indexL = *indexR = i;
1143            return AH_TRUE;
1144        }
1145        /*
1146         * Look for value being between current value and next value
1147         * if so return these 2 values
1148         */
1149        if (target < pList[i + 1]) {
1150            *indexL = i;
1151            *indexR = (uint16_t)(i + 1);
1152            return AH_FALSE;
1153        }
1154    }
1155    HALASSERT(0);
1156    *indexL = *indexR = 0;
1157    return AH_FALSE;
1158}
1159
1160/**************************************************************
1161 * ath_ee_FillVpdTable
1162 *
1163 * Fill the Vpdlist for indices Pmax-Pmin
1164 * Note: pwrMin, pwrMax and Vpdlist are all in dBm * 4
1165 */
1166HAL_BOOL
1167ath_ee_FillVpdTable(uint8_t pwrMin, uint8_t pwrMax, uint8_t *pPwrList,
1168                   uint8_t *pVpdList, uint16_t numIntercepts, uint8_t *pRetVpdList)
1169{
1170    uint16_t  i, k;
1171    uint8_t   currPwr = pwrMin;
1172    uint16_t  idxL, idxR;
1173
1174    HALASSERT(pwrMax > pwrMin);
1175    for (i = 0; i <= (pwrMax - pwrMin) / 2; i++) {
1176        ath_ee_getLowerUpperIndex(currPwr, pPwrList, numIntercepts,
1177                           &(idxL), &(idxR));
1178        if (idxR < 1)
1179            idxR = 1;           /* extrapolate below */
1180        if (idxL == numIntercepts - 1)
1181            idxL = (uint16_t)(numIntercepts - 2);   /* extrapolate above */
1182        if (pPwrList[idxL] == pPwrList[idxR])
1183            k = pVpdList[idxL];
1184        else
1185            k = (uint16_t)( ((currPwr - pPwrList[idxL]) * pVpdList[idxR] + (pPwrList[idxR] - currPwr) * pVpdList[idxL]) /
1186                  (pPwrList[idxR] - pPwrList[idxL]) );
1187        HALASSERT(k < 256);
1188        pRetVpdList[i] = (uint8_t)k;
1189        currPwr += 2;               /* half dB steps */
1190    }
1191
1192    return AH_TRUE;
1193}
1194
1195/**************************************************************************
1196 * ath_ee_interpolate
1197 *
1198 * Returns signed interpolated or the scaled up interpolated value
1199 */
1200int16_t
1201ath_ee_interpolate(uint16_t target, uint16_t srcLeft, uint16_t srcRight,
1202            int16_t targetLeft, int16_t targetRight)
1203{
1204    int16_t rv;
1205
1206    if (srcRight == srcLeft) {
1207        rv = targetLeft;
1208    } else {
1209        rv = (int16_t)( ((target - srcLeft) * targetRight +
1210              (srcRight - target) * targetLeft) / (srcRight - srcLeft) );
1211    }
1212    return rv;
1213}
1214