1185377Ssam/*
2187831Ssam * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
3185377Ssam * Copyright (c) 2002-2008 Atheros Communications, Inc.
4185377Ssam *
5185377Ssam * Permission to use, copy, modify, and/or distribute this software for any
6185377Ssam * purpose with or without fee is hereby granted, provided that the above
7185377Ssam * copyright notice and this permission notice appear in all copies.
8185377Ssam *
9185377Ssam * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10185377Ssam * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11185377Ssam * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12185377Ssam * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13185377Ssam * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14185377Ssam * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15185377Ssam * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16185377Ssam *
17186018Ssam * $FreeBSD$
18185377Ssam */
19185377Ssam#include "opt_ah.h"
20185377Ssam
21185377Ssam#include "ah.h"
22185377Ssam#include "ah_internal.h"
23185377Ssam#include "ah_devid.h"
24220298Sadrian#include "ah_eeprom.h"			/* for 5ghz fast clock flag */
25185377Ssam
26188968Ssam#include "ar5416/ar5416reg.h"		/* NB: includes ar5212reg.h */
27239604Sadrian#include "ar9003/ar9300_devid.h"
28188968Ssam
29185406Ssam/* linker set of registered chips */
30185406SsamOS_SET_DECLARE(ah_chips, struct ath_hal_chip);
31185406Ssam
32185406Ssam/*
33185406Ssam * Check the set of registered chips to see if any recognize
34185406Ssam * the device as one they can support.
35185406Ssam */
36185406Ssamconst char*
37185406Ssamath_hal_probe(uint16_t vendorid, uint16_t devid)
38185377Ssam{
39186018Ssam	struct ath_hal_chip * const *pchip;
40185377Ssam
41185417Ssam	OS_SET_FOREACH(pchip, ah_chips) {
42185406Ssam		const char *name = (*pchip)->probe(vendorid, devid);
43185406Ssam		if (name != AH_NULL)
44185406Ssam			return name;
45185377Ssam	}
46185377Ssam	return AH_NULL;
47185377Ssam}
48185377Ssam
49185377Ssam/*
50185377Ssam * Attach detects device chip revisions, initializes the hwLayer
51185377Ssam * function list, reads EEPROM information,
52185377Ssam * selects reset vectors, and performs a short self test.
53185377Ssam * Any failures will return an error that should cause a hardware
54185377Ssam * disable.
55185377Ssam */
56185377Ssamstruct ath_hal*
57185377Ssamath_hal_attach(uint16_t devid, HAL_SOFTC sc,
58272292Sadrian	HAL_BUS_TAG st, HAL_BUS_HANDLE sh, uint16_t *eepromdata,
59272292Sadrian	HAL_OPS_CONFIG *ah_config,
60272292Sadrian	HAL_STATUS *error)
61185377Ssam{
62186018Ssam	struct ath_hal_chip * const *pchip;
63185377Ssam
64185417Ssam	OS_SET_FOREACH(pchip, ah_chips) {
65185406Ssam		struct ath_hal_chip *chip = *pchip;
66185406Ssam		struct ath_hal *ah;
67185406Ssam
68185406Ssam		/* XXX don't have vendorid, assume atheros one works */
69185406Ssam		if (chip->probe(ATHEROS_VENDOR_ID, devid) == AH_NULL)
70185406Ssam			continue;
71272292Sadrian		ah = chip->attach(devid, sc, st, sh, eepromdata, ah_config,
72272292Sadrian		    error);
73185406Ssam		if (ah != AH_NULL) {
74185406Ssam			/* copy back private state to public area */
75185406Ssam			ah->ah_devid = AH_PRIVATE(ah)->ah_devid;
76185406Ssam			ah->ah_subvendorid = AH_PRIVATE(ah)->ah_subvendorid;
77185406Ssam			ah->ah_macVersion = AH_PRIVATE(ah)->ah_macVersion;
78185406Ssam			ah->ah_macRev = AH_PRIVATE(ah)->ah_macRev;
79185406Ssam			ah->ah_phyRev = AH_PRIVATE(ah)->ah_phyRev;
80185406Ssam			ah->ah_analog5GhzRev = AH_PRIVATE(ah)->ah_analog5GhzRev;
81185406Ssam			ah->ah_analog2GhzRev = AH_PRIVATE(ah)->ah_analog2GhzRev;
82185406Ssam			return ah;
83185406Ssam		}
84185377Ssam	}
85185406Ssam	return AH_NULL;
86185406Ssam}
87185406Ssam
88188968Ssamconst char *
89188968Ssamath_hal_mac_name(struct ath_hal *ah)
90188968Ssam{
91188968Ssam	switch (ah->ah_macVersion) {
92188968Ssam	case AR_SREV_VERSION_CRETE:
93188968Ssam	case AR_SREV_VERSION_MAUI_1:
94296176Sadrian		return "AR5210";
95188968Ssam	case AR_SREV_VERSION_MAUI_2:
96188968Ssam	case AR_SREV_VERSION_OAHU:
97296176Sadrian		return "AR5211";
98188968Ssam	case AR_SREV_VERSION_VENICE:
99296176Sadrian		return "AR5212";
100188968Ssam	case AR_SREV_VERSION_GRIFFIN:
101296176Sadrian		return "AR2413";
102188968Ssam	case AR_SREV_VERSION_CONDOR:
103296176Sadrian		return "AR5424";
104188968Ssam	case AR_SREV_VERSION_EAGLE:
105296176Sadrian		return "AR5413";
106188968Ssam	case AR_SREV_VERSION_COBRA:
107296176Sadrian		return "AR2415";
108239603Sadrian	case AR_SREV_2425:	/* Swan */
109296176Sadrian		return "AR2425";
110239603Sadrian	case AR_SREV_2417:	/* Nala */
111296176Sadrian		return "AR2417";
112188968Ssam	case AR_XSREV_VERSION_OWL_PCI:
113296176Sadrian		return "AR5416";
114188968Ssam	case AR_XSREV_VERSION_OWL_PCIE:
115296176Sadrian		return "AR5418";
116221163Sadrian	case AR_XSREV_VERSION_HOWL:
117296176Sadrian		return "AR9130";
118188968Ssam	case AR_XSREV_VERSION_SOWL:
119296176Sadrian		return "AR9160";
120188968Ssam	case AR_XSREV_VERSION_MERLIN:
121227372Sadrian		if (AH_PRIVATE(ah)->ah_ispcie)
122296176Sadrian			return "AR9280";
123296176Sadrian		return "AR9220";
124188968Ssam	case AR_XSREV_VERSION_KITE:
125296176Sadrian		return "AR9285";
126222305Sadrian	case AR_XSREV_VERSION_KIWI:
127227372Sadrian		if (AH_PRIVATE(ah)->ah_ispcie)
128296176Sadrian			return "AR9287";
129296176Sadrian		return "AR9227";
130239604Sadrian	case AR_SREV_VERSION_AR9380:
131239604Sadrian		if (ah->ah_macRev >= AR_SREV_REVISION_AR9580_10)
132296176Sadrian			return "AR9580";
133296176Sadrian		return "AR9380";
134239604Sadrian	case AR_SREV_VERSION_AR9460:
135296176Sadrian		return "AR9460";
136239604Sadrian	case AR_SREV_VERSION_AR9330:
137296176Sadrian		return "AR9330";
138239604Sadrian	case AR_SREV_VERSION_AR9340:
139296176Sadrian		return "AR9340";
140239604Sadrian	case AR_SREV_VERSION_QCA9550:
141296176Sadrian		return "QCA9550";
142239604Sadrian	case AR_SREV_VERSION_AR9485:
143296176Sadrian		return "AR9485";
144250166Sadrian	case AR_SREV_VERSION_QCA9565:
145296176Sadrian		return "QCA9565";
146291418Sadrian	case AR_SREV_VERSION_QCA9530:
147296176Sadrian		return "QCA9530";
148188968Ssam	}
149188968Ssam	return "????";
150188968Ssam}
151188968Ssam
152187831Ssam/*
153187831Ssam * Return the mask of available modes based on the hardware capabilities.
154187831Ssam */
155187831Ssamu_int
156187831Ssamath_hal_getwirelessmodes(struct ath_hal*ah)
157187831Ssam{
158187831Ssam	return ath_hal_getWirelessModes(ah);
159187831Ssam}
160187831Ssam
161185406Ssam/* linker set of registered RF backends */
162185406SsamOS_SET_DECLARE(ah_rfs, struct ath_hal_rf);
163185406Ssam
164185406Ssam/*
165185406Ssam * Check the set of registered RF backends to see if
166185406Ssam * any recognize the device as one they can support.
167185406Ssam */
168185406Ssamstruct ath_hal_rf *
169185406Ssamath_hal_rfprobe(struct ath_hal *ah, HAL_STATUS *ecode)
170185406Ssam{
171186018Ssam	struct ath_hal_rf * const *prf;
172185406Ssam
173185417Ssam	OS_SET_FOREACH(prf, ah_rfs) {
174185406Ssam		struct ath_hal_rf *rf = *prf;
175185406Ssam		if (rf->probe(ah))
176185406Ssam			return rf;
177185377Ssam	}
178185406Ssam	*ecode = HAL_ENOTSUPP;
179185406Ssam	return AH_NULL;
180185377Ssam}
181185377Ssam
182188968Ssamconst char *
183188968Ssamath_hal_rf_name(struct ath_hal *ah)
184188968Ssam{
185188968Ssam	switch (ah->ah_analog5GhzRev & AR_RADIO_SREV_MAJOR) {
186188968Ssam	case 0:			/* 5210 */
187188968Ssam		return "5110";	/* NB: made up */
188188968Ssam	case AR_RAD5111_SREV_MAJOR:
189188968Ssam	case AR_RAD5111_SREV_PROD:
190188968Ssam		return "5111";
191188968Ssam	case AR_RAD2111_SREV_MAJOR:
192188968Ssam		return "2111";
193188968Ssam	case AR_RAD5112_SREV_MAJOR:
194188968Ssam	case AR_RAD5112_SREV_2_0:
195188968Ssam	case AR_RAD5112_SREV_2_1:
196188968Ssam		return "5112";
197188968Ssam	case AR_RAD2112_SREV_MAJOR:
198188968Ssam	case AR_RAD2112_SREV_2_0:
199188968Ssam	case AR_RAD2112_SREV_2_1:
200188968Ssam		return "2112";
201188968Ssam	case AR_RAD2413_SREV_MAJOR:
202188968Ssam		return "2413";
203188968Ssam	case AR_RAD5413_SREV_MAJOR:
204188968Ssam		return "5413";
205188968Ssam	case AR_RAD2316_SREV_MAJOR:
206188968Ssam		return "2316";
207188968Ssam	case AR_RAD2317_SREV_MAJOR:
208188968Ssam		return "2317";
209188968Ssam	case AR_RAD5424_SREV_MAJOR:
210188968Ssam		return "5424";
211188968Ssam
212188968Ssam	case AR_RAD5133_SREV_MAJOR:
213188968Ssam		return "5133";
214188968Ssam	case AR_RAD2133_SREV_MAJOR:
215188968Ssam		return "2133";
216188968Ssam	case AR_RAD5122_SREV_MAJOR:
217188968Ssam		return "5122";
218188968Ssam	case AR_RAD2122_SREV_MAJOR:
219188968Ssam		return "2122";
220188968Ssam	}
221188968Ssam	return "????";
222188968Ssam}
223188968Ssam
224185377Ssam/*
225185377Ssam * Poll the register looking for a specific value.
226185377Ssam */
227185377SsamHAL_BOOL
228185377Ssamath_hal_wait(struct ath_hal *ah, u_int reg, uint32_t mask, uint32_t val)
229185377Ssam{
230185377Ssam#define	AH_TIMEOUT	1000
231217622Sadrian	return ath_hal_waitfor(ah, reg, mask, val, AH_TIMEOUT);
232217622Sadrian#undef AH_TIMEOUT
233217622Sadrian}
234217622Sadrian
235217622SadrianHAL_BOOL
236217622Sadrianath_hal_waitfor(struct ath_hal *ah, u_int reg, uint32_t mask, uint32_t val, uint32_t timeout)
237217622Sadrian{
238185377Ssam	int i;
239185377Ssam
240217622Sadrian	for (i = 0; i < timeout; i++) {
241185377Ssam		if ((OS_REG_READ(ah, reg) & mask) == val)
242185377Ssam			return AH_TRUE;
243185377Ssam		OS_DELAY(10);
244185377Ssam	}
245185377Ssam	HALDEBUG(ah, HAL_DEBUG_REGIO | HAL_DEBUG_PHYIO,
246185377Ssam	    "%s: timeout on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n",
247185377Ssam	    __func__, reg, OS_REG_READ(ah, reg), mask, val);
248185377Ssam	return AH_FALSE;
249185377Ssam}
250185377Ssam
251185377Ssam/*
252185377Ssam * Reverse the bits starting at the low bit for a value of
253185377Ssam * bit_count in size
254185377Ssam */
255185377Ssamuint32_t
256185377Ssamath_hal_reverseBits(uint32_t val, uint32_t n)
257185377Ssam{
258185377Ssam	uint32_t retval;
259185377Ssam	int i;
260185377Ssam
261185377Ssam	for (i = 0, retval = 0; i < n; i++) {
262185377Ssam		retval = (retval << 1) | (val & 1);
263185377Ssam		val >>= 1;
264185377Ssam	}
265185377Ssam	return retval;
266185377Ssam}
267185377Ssam
268218011Sadrian/* 802.11n related timing definitions */
269218011Sadrian
270218011Sadrian#define	OFDM_PLCP_BITS	22
271218011Sadrian#define	HT_L_STF	8
272218011Sadrian#define	HT_L_LTF	8
273218011Sadrian#define	HT_L_SIG	4
274218011Sadrian#define	HT_SIG		8
275218011Sadrian#define	HT_STF		4
276218011Sadrian#define	HT_LTF(n)	((n) * 4)
277218011Sadrian
278218011Sadrian#define	HT_RC_2_MCS(_rc)	((_rc) & 0xf)
279218011Sadrian#define	HT_RC_2_STREAMS(_rc)	((((_rc) & 0x78) >> 3) + 1)
280218011Sadrian#define	IS_HT_RATE(_rc)		( (_rc) & IEEE80211_RATE_MCS)
281218011Sadrian
282185377Ssam/*
283218011Sadrian * Calculate the duration of a packet whether it is 11n or legacy.
284218011Sadrian */
285218011Sadrianuint32_t
286218011Sadrianath_hal_pkt_txtime(struct ath_hal *ah, const HAL_RATE_TABLE *rates, uint32_t frameLen,
287218011Sadrian    uint16_t rateix, HAL_BOOL isht40, HAL_BOOL shortPreamble)
288218011Sadrian{
289218011Sadrian	uint8_t rc;
290218011Sadrian	int numStreams;
291218011Sadrian
292218011Sadrian	rc = rates->info[rateix].rateCode;
293218011Sadrian
294218011Sadrian	/* Legacy rate? Return the old way */
295218011Sadrian	if (! IS_HT_RATE(rc))
296218011Sadrian		return ath_hal_computetxtime(ah, rates, frameLen, rateix, shortPreamble);
297218011Sadrian
298218011Sadrian	/* 11n frame - extract out the number of spatial streams */
299218011Sadrian	numStreams = HT_RC_2_STREAMS(rc);
300239287Sadrian	KASSERT(numStreams > 0 && numStreams <= 4,
301239287Sadrian	    ("number of spatial streams needs to be 1..3: MCS rate 0x%x!",
302239287Sadrian	    rateix));
303218011Sadrian
304218011Sadrian	return ath_computedur_ht(frameLen, rc, numStreams, isht40, shortPreamble);
305218011Sadrian}
306218011Sadrian
307239287Sadrianstatic const uint16_t ht20_bps[32] = {
308239287Sadrian    26, 52, 78, 104, 156, 208, 234, 260,
309239287Sadrian    52, 104, 156, 208, 312, 416, 468, 520,
310239287Sadrian    78, 156, 234, 312, 468, 624, 702, 780,
311239287Sadrian    104, 208, 312, 416, 624, 832, 936, 1040
312239287Sadrian};
313239287Sadrianstatic const uint16_t ht40_bps[32] = {
314239287Sadrian    54, 108, 162, 216, 324, 432, 486, 540,
315239287Sadrian    108, 216, 324, 432, 648, 864, 972, 1080,
316239287Sadrian    162, 324, 486, 648, 972, 1296, 1458, 1620,
317239287Sadrian    216, 432, 648, 864, 1296, 1728, 1944, 2160
318239287Sadrian};
319239287Sadrian
320218011Sadrian/*
321218011Sadrian * Calculate the transmit duration of an 11n frame.
322218011Sadrian */
323218011Sadrianuint32_t
324239287Sadrianath_computedur_ht(uint32_t frameLen, uint16_t rate, int streams,
325239287Sadrian    HAL_BOOL isht40, HAL_BOOL isShortGI)
326218011Sadrian{
327218011Sadrian	uint32_t bitsPerSymbol, numBits, numSymbols, txTime;
328218011Sadrian
329218011Sadrian	KASSERT(rate & IEEE80211_RATE_MCS, ("not mcs %d", rate));
330239287Sadrian	KASSERT((rate &~ IEEE80211_RATE_MCS) < 31, ("bad mcs 0x%x", rate));
331218011Sadrian
332218011Sadrian	if (isht40)
333250824Sadrian		bitsPerSymbol = ht40_bps[rate & 0x1f];
334218011Sadrian	else
335250824Sadrian		bitsPerSymbol = ht20_bps[rate & 0x1f];
336218011Sadrian	numBits = OFDM_PLCP_BITS + (frameLen << 3);
337218011Sadrian	numSymbols = howmany(numBits, bitsPerSymbol);
338218011Sadrian	if (isShortGI)
339218011Sadrian		txTime = ((numSymbols * 18) + 4) / 5;   /* 3.6us */
340218011Sadrian	else
341218011Sadrian		txTime = numSymbols * 4;                /* 4us */
342218011Sadrian	return txTime + HT_L_STF + HT_L_LTF +
343218011Sadrian	    HT_L_SIG + HT_SIG + HT_STF + HT_LTF(streams);
344218011Sadrian}
345218011Sadrian
346218011Sadrian/*
347185377Ssam * Compute the time to transmit a frame of length frameLen bytes
348185377Ssam * using the specified rate, phy, and short preamble setting.
349185377Ssam */
350185377Ssamuint16_t
351185377Ssamath_hal_computetxtime(struct ath_hal *ah,
352185377Ssam	const HAL_RATE_TABLE *rates, uint32_t frameLen, uint16_t rateix,
353185377Ssam	HAL_BOOL shortPreamble)
354185377Ssam{
355185377Ssam	uint32_t bitsPerSymbol, numBits, numSymbols, phyTime, txTime;
356185377Ssam	uint32_t kbps;
357185377Ssam
358218923Sadrian	/* Warn if this function is called for 11n rates; it should not be! */
359218923Sadrian	if (IS_HT_RATE(rates->info[rateix].rateCode))
360218923Sadrian		ath_hal_printf(ah, "%s: MCS rate? (index %d; hwrate 0x%x)\n",
361218923Sadrian		    __func__, rateix, rates->info[rateix].rateCode);
362218923Sadrian
363185377Ssam	kbps = rates->info[rateix].rateKbps;
364185377Ssam	/*
365298939Spfg	 * index can be invalid during dynamic Turbo transitions.
366187831Ssam	 * XXX
367185377Ssam	 */
368187831Ssam	if (kbps == 0)
369187831Ssam		return 0;
370185377Ssam	switch (rates->info[rateix].phy) {
371185377Ssam	case IEEE80211_T_CCK:
372185377Ssam		phyTime		= CCK_PREAMBLE_BITS + CCK_PLCP_BITS;
373185377Ssam		if (shortPreamble && rates->info[rateix].shortPreamble)
374185377Ssam			phyTime >>= 1;
375185377Ssam		numBits		= frameLen << 3;
376185377Ssam		txTime		= CCK_SIFS_TIME + phyTime
377185377Ssam				+ ((numBits * 1000)/kbps);
378185377Ssam		break;
379185377Ssam	case IEEE80211_T_OFDM:
380188773Ssam		bitsPerSymbol	= (kbps * OFDM_SYMBOL_TIME) / 1000;
381188773Ssam		HALASSERT(bitsPerSymbol != 0);
382185377Ssam
383188773Ssam		numBits		= OFDM_PLCP_BITS + (frameLen << 3);
384188773Ssam		numSymbols	= howmany(numBits, bitsPerSymbol);
385188773Ssam		txTime		= OFDM_SIFS_TIME
386188773Ssam				+ OFDM_PREAMBLE_TIME
387188773Ssam				+ (numSymbols * OFDM_SYMBOL_TIME);
388188773Ssam		break;
389188773Ssam	case IEEE80211_T_OFDM_HALF:
390188773Ssam		bitsPerSymbol	= (kbps * OFDM_HALF_SYMBOL_TIME) / 1000;
391188773Ssam		HALASSERT(bitsPerSymbol != 0);
392185377Ssam
393188773Ssam		numBits		= OFDM_HALF_PLCP_BITS + (frameLen << 3);
394188773Ssam		numSymbols	= howmany(numBits, bitsPerSymbol);
395188773Ssam		txTime		= OFDM_HALF_SIFS_TIME
396188773Ssam				+ OFDM_HALF_PREAMBLE_TIME
397188773Ssam				+ (numSymbols * OFDM_HALF_SYMBOL_TIME);
398188773Ssam		break;
399188773Ssam	case IEEE80211_T_OFDM_QUARTER:
400188773Ssam		bitsPerSymbol	= (kbps * OFDM_QUARTER_SYMBOL_TIME) / 1000;
401188773Ssam		HALASSERT(bitsPerSymbol != 0);
402185377Ssam
403188773Ssam		numBits		= OFDM_QUARTER_PLCP_BITS + (frameLen << 3);
404188773Ssam		numSymbols	= howmany(numBits, bitsPerSymbol);
405188773Ssam		txTime		= OFDM_QUARTER_SIFS_TIME
406188773Ssam				+ OFDM_QUARTER_PREAMBLE_TIME
407188773Ssam				+ (numSymbols * OFDM_QUARTER_SYMBOL_TIME);
408185377Ssam		break;
409185377Ssam	case IEEE80211_T_TURBO:
410191022Ssam		bitsPerSymbol	= (kbps * TURBO_SYMBOL_TIME) / 1000;
411185377Ssam		HALASSERT(bitsPerSymbol != 0);
412185377Ssam
413188773Ssam		numBits		= TURBO_PLCP_BITS + (frameLen << 3);
414188773Ssam		numSymbols	= howmany(numBits, bitsPerSymbol);
415188773Ssam		txTime		= TURBO_SIFS_TIME
416188773Ssam				+ TURBO_PREAMBLE_TIME
417188773Ssam				+ (numSymbols * TURBO_SYMBOL_TIME);
418185377Ssam		break;
419185377Ssam	default:
420185377Ssam		HALDEBUG(ah, HAL_DEBUG_PHYIO,
421185377Ssam		    "%s: unknown phy %u (rate ix %u)\n",
422185377Ssam		    __func__, rates->info[rateix].phy, rateix);
423185377Ssam		txTime = 0;
424185377Ssam		break;
425185377Ssam	}
426185377Ssam	return txTime;
427185377Ssam}
428185377Ssam
429239634Sadrianint
430239634Sadrianath_hal_get_curmode(struct ath_hal *ah, const struct ieee80211_channel *chan)
431239634Sadrian{
432239634Sadrian	/*
433239634Sadrian	 * Pick a default mode at bootup. A channel change is inevitable.
434239634Sadrian	 */
435239634Sadrian	if (!chan)
436239634Sadrian		return HAL_MODE_11NG_HT20;
437239634Sadrian
438239634Sadrian	if (IEEE80211_IS_CHAN_TURBO(chan))
439239634Sadrian		return HAL_MODE_TURBO;
440239634Sadrian
441239634Sadrian	/* check for NA_HT before plain A, since IS_CHAN_A includes NA_HT */
442239634Sadrian	if (IEEE80211_IS_CHAN_5GHZ(chan) && IEEE80211_IS_CHAN_HT20(chan))
443239634Sadrian		return HAL_MODE_11NA_HT20;
444239634Sadrian	if (IEEE80211_IS_CHAN_5GHZ(chan) && IEEE80211_IS_CHAN_HT40U(chan))
445239634Sadrian		return HAL_MODE_11NA_HT40PLUS;
446239634Sadrian	if (IEEE80211_IS_CHAN_5GHZ(chan) && IEEE80211_IS_CHAN_HT40D(chan))
447239634Sadrian		return HAL_MODE_11NA_HT40MINUS;
448239634Sadrian	if (IEEE80211_IS_CHAN_A(chan))
449239634Sadrian		return HAL_MODE_11A;
450239634Sadrian
451239634Sadrian	/* check for NG_HT before plain G, since IS_CHAN_G includes NG_HT */
452239634Sadrian	if (IEEE80211_IS_CHAN_2GHZ(chan) && IEEE80211_IS_CHAN_HT20(chan))
453239634Sadrian		return HAL_MODE_11NG_HT20;
454239634Sadrian	if (IEEE80211_IS_CHAN_2GHZ(chan) && IEEE80211_IS_CHAN_HT40U(chan))
455239634Sadrian		return HAL_MODE_11NG_HT40PLUS;
456239634Sadrian	if (IEEE80211_IS_CHAN_2GHZ(chan) && IEEE80211_IS_CHAN_HT40D(chan))
457239634Sadrian		return HAL_MODE_11NG_HT40MINUS;
458239634Sadrian
459239634Sadrian	/*
460239634Sadrian	 * XXX For FreeBSD, will this work correctly given the DYN
461239634Sadrian	 * chan mode (OFDM+CCK dynamic) ? We have pure-G versions DYN-BG..
462239634Sadrian	 */
463239634Sadrian	if (IEEE80211_IS_CHAN_G(chan))
464239634Sadrian		return HAL_MODE_11G;
465239634Sadrian	if (IEEE80211_IS_CHAN_B(chan))
466239634Sadrian		return HAL_MODE_11B;
467239634Sadrian
468239634Sadrian	HALASSERT(0);
469239634Sadrian	return HAL_MODE_11NG_HT20;
470239634Sadrian}
471239634Sadrian
472239634Sadrian
473185377Ssamtypedef enum {
474185377Ssam	WIRELESS_MODE_11a   = 0,
475185377Ssam	WIRELESS_MODE_TURBO = 1,
476185377Ssam	WIRELESS_MODE_11b   = 2,
477185377Ssam	WIRELESS_MODE_11g   = 3,
478185377Ssam	WIRELESS_MODE_108g  = 4,
479185377Ssam
480185377Ssam	WIRELESS_MODE_MAX
481185377Ssam} WIRELESS_MODE;
482185377Ssam
483185377Ssamstatic WIRELESS_MODE
484187831Ssamath_hal_chan2wmode(struct ath_hal *ah, const struct ieee80211_channel *chan)
485185377Ssam{
486187831Ssam	if (IEEE80211_IS_CHAN_B(chan))
487185377Ssam		return WIRELESS_MODE_11b;
488187831Ssam	if (IEEE80211_IS_CHAN_G(chan))
489185377Ssam		return WIRELESS_MODE_11g;
490187831Ssam	if (IEEE80211_IS_CHAN_108G(chan))
491185377Ssam		return WIRELESS_MODE_108g;
492187831Ssam	if (IEEE80211_IS_CHAN_TURBO(chan))
493185377Ssam		return WIRELESS_MODE_TURBO;
494185377Ssam	return WIRELESS_MODE_11a;
495185377Ssam}
496185377Ssam
497185377Ssam/*
498185377Ssam * Convert between microseconds and core system clocks.
499185377Ssam */
500185377Ssam                                     /* 11a Turbo  11b  11g  108g */
501185377Ssamstatic const uint8_t CLOCK_RATE[]  = { 40,  80,   22,  44,   88  };
502185377Ssam
503220298Sadrian#define	CLOCK_FAST_RATE_5GHZ_OFDM	44
504220298Sadrian
505185377Ssamu_int
506185377Ssamath_hal_mac_clks(struct ath_hal *ah, u_int usecs)
507185377Ssam{
508187831Ssam	const struct ieee80211_channel *c = AH_PRIVATE(ah)->ah_curchan;
509185377Ssam	u_int clks;
510185377Ssam
511185377Ssam	/* NB: ah_curchan may be null when called attach time */
512220298Sadrian	/* XXX merlin and later specific workaround - 5ghz fast clock is 44 */
513220298Sadrian	if (c != AH_NULL && IS_5GHZ_FAST_CLOCK_EN(ah, c)) {
514220298Sadrian		clks = usecs * CLOCK_FAST_RATE_5GHZ_OFDM;
515220298Sadrian		if (IEEE80211_IS_CHAN_HT40(c))
516220298Sadrian			clks <<= 1;
517220298Sadrian	} else if (c != AH_NULL) {
518185377Ssam		clks = usecs * CLOCK_RATE[ath_hal_chan2wmode(ah, c)];
519187831Ssam		if (IEEE80211_IS_CHAN_HT40(c))
520185377Ssam			clks <<= 1;
521185377Ssam	} else
522185377Ssam		clks = usecs * CLOCK_RATE[WIRELESS_MODE_11b];
523240444Sadrian
524240444Sadrian	/* Compensate for half/quarter rate */
525240444Sadrian	if (c != AH_NULL && IEEE80211_IS_CHAN_HALF(c))
526240444Sadrian		clks = clks / 2;
527240444Sadrian	else if (c != AH_NULL && IEEE80211_IS_CHAN_QUARTER(c))
528240444Sadrian		clks = clks / 4;
529240444Sadrian
530185377Ssam	return clks;
531185377Ssam}
532185377Ssam
533185377Ssamu_int
534185377Ssamath_hal_mac_usec(struct ath_hal *ah, u_int clks)
535185377Ssam{
536187831Ssam	const struct ieee80211_channel *c = AH_PRIVATE(ah)->ah_curchan;
537185377Ssam	u_int usec;
538185377Ssam
539185377Ssam	/* NB: ah_curchan may be null when called attach time */
540220298Sadrian	/* XXX merlin and later specific workaround - 5ghz fast clock is 44 */
541220298Sadrian	if (c != AH_NULL && IS_5GHZ_FAST_CLOCK_EN(ah, c)) {
542220298Sadrian		usec = clks / CLOCK_FAST_RATE_5GHZ_OFDM;
543220298Sadrian		if (IEEE80211_IS_CHAN_HT40(c))
544220298Sadrian			usec >>= 1;
545220298Sadrian	} else if (c != AH_NULL) {
546185377Ssam		usec = clks / CLOCK_RATE[ath_hal_chan2wmode(ah, c)];
547187831Ssam		if (IEEE80211_IS_CHAN_HT40(c))
548185377Ssam			usec >>= 1;
549185377Ssam	} else
550185377Ssam		usec = clks / CLOCK_RATE[WIRELESS_MODE_11b];
551185377Ssam	return usec;
552185377Ssam}
553185377Ssam
554185377Ssam/*
555185377Ssam * Setup a h/w rate table's reverse lookup table and
556185377Ssam * fill in ack durations.  This routine is called for
557185377Ssam * each rate table returned through the ah_getRateTable
558185377Ssam * method.  The reverse lookup tables are assumed to be
559185377Ssam * initialized to zero (or at least the first entry).
560185377Ssam * We use this as a key that indicates whether or not
561185377Ssam * we've previously setup the reverse lookup table.
562185377Ssam *
563185377Ssam * XXX not reentrant, but shouldn't matter
564185377Ssam */
565185377Ssamvoid
566185377Ssamath_hal_setupratetable(struct ath_hal *ah, HAL_RATE_TABLE *rt)
567185377Ssam{
568185377Ssam#define	N(a)	(sizeof(a)/sizeof(a[0]))
569185377Ssam	int i;
570185377Ssam
571185377Ssam	if (rt->rateCodeToIndex[0] != 0)	/* already setup */
572185377Ssam		return;
573185377Ssam	for (i = 0; i < N(rt->rateCodeToIndex); i++)
574185377Ssam		rt->rateCodeToIndex[i] = (uint8_t) -1;
575185377Ssam	for (i = 0; i < rt->rateCount; i++) {
576185377Ssam		uint8_t code = rt->info[i].rateCode;
577185377Ssam		uint8_t cix = rt->info[i].controlRate;
578185377Ssam
579185377Ssam		HALASSERT(code < N(rt->rateCodeToIndex));
580185377Ssam		rt->rateCodeToIndex[code] = i;
581185377Ssam		HALASSERT((code | rt->info[i].shortPreamble) <
582185377Ssam		    N(rt->rateCodeToIndex));
583185377Ssam		rt->rateCodeToIndex[code | rt->info[i].shortPreamble] = i;
584185377Ssam		/*
585185377Ssam		 * XXX for 11g the control rate to use for 5.5 and 11 Mb/s
586185377Ssam		 *     depends on whether they are marked as basic rates;
587185377Ssam		 *     the static tables are setup with an 11b-compatible
588185377Ssam		 *     2Mb/s rate which will work but is suboptimal
589185377Ssam		 */
590185377Ssam		rt->info[i].lpAckDuration = ath_hal_computetxtime(ah, rt,
591185377Ssam			WLAN_CTRL_FRAME_SIZE, cix, AH_FALSE);
592185377Ssam		rt->info[i].spAckDuration = ath_hal_computetxtime(ah, rt,
593185377Ssam			WLAN_CTRL_FRAME_SIZE, cix, AH_TRUE);
594185377Ssam	}
595185377Ssam#undef N
596185377Ssam}
597185377Ssam
598185377SsamHAL_STATUS
599185377Ssamath_hal_getcapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type,
600185377Ssam	uint32_t capability, uint32_t *result)
601185377Ssam{
602185377Ssam	const HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps;
603185377Ssam
604185377Ssam	switch (type) {
605185377Ssam	case HAL_CAP_REG_DMN:		/* regulatory domain */
606185377Ssam		*result = AH_PRIVATE(ah)->ah_currentRD;
607185377Ssam		return HAL_OK;
608224716Sadrian	case HAL_CAP_DFS_DMN:		/* DFS Domain */
609224716Sadrian		*result = AH_PRIVATE(ah)->ah_dfsDomain;
610224716Sadrian		return HAL_OK;
611185377Ssam	case HAL_CAP_CIPHER:		/* cipher handled in hardware */
612185377Ssam	case HAL_CAP_TKIP_MIC:		/* handle TKIP MIC in hardware */
613185377Ssam		return HAL_ENOTSUPP;
614185377Ssam	case HAL_CAP_TKIP_SPLIT:	/* hardware TKIP uses split keys */
615185377Ssam		return HAL_ENOTSUPP;
616185377Ssam	case HAL_CAP_PHYCOUNTERS:	/* hardware PHY error counters */
617185377Ssam		return pCap->halHwPhyCounterSupport ? HAL_OK : HAL_ENXIO;
618185377Ssam	case HAL_CAP_WME_TKIPMIC:   /* hardware can do TKIP MIC when WMM is turned on */
619185377Ssam		return HAL_ENOTSUPP;
620185377Ssam	case HAL_CAP_DIVERSITY:		/* hardware supports fast diversity */
621185377Ssam		return HAL_ENOTSUPP;
622185377Ssam	case HAL_CAP_KEYCACHE_SIZE:	/* hardware key cache size */
623185377Ssam		*result =  pCap->halKeyCacheSize;
624185377Ssam		return HAL_OK;
625185377Ssam	case HAL_CAP_NUM_TXQUEUES:	/* number of hardware tx queues */
626185377Ssam		*result = pCap->halTotalQueues;
627185377Ssam		return HAL_OK;
628185377Ssam	case HAL_CAP_VEOL:		/* hardware supports virtual EOL */
629185377Ssam		return pCap->halVEOLSupport ? HAL_OK : HAL_ENOTSUPP;
630185377Ssam	case HAL_CAP_PSPOLL:		/* hardware PS-Poll support works */
631185377Ssam		return pCap->halPSPollBroken ? HAL_ENOTSUPP : HAL_OK;
632185377Ssam	case HAL_CAP_COMPRESSION:
633185377Ssam		return pCap->halCompressSupport ? HAL_OK : HAL_ENOTSUPP;
634185377Ssam	case HAL_CAP_BURST:
635185377Ssam		return pCap->halBurstSupport ? HAL_OK : HAL_ENOTSUPP;
636185377Ssam	case HAL_CAP_FASTFRAME:
637185377Ssam		return pCap->halFastFramesSupport ? HAL_OK : HAL_ENOTSUPP;
638185377Ssam	case HAL_CAP_DIAG:		/* hardware diagnostic support */
639185377Ssam		*result = AH_PRIVATE(ah)->ah_diagreg;
640185377Ssam		return HAL_OK;
641185377Ssam	case HAL_CAP_TXPOW:		/* global tx power limit  */
642185377Ssam		switch (capability) {
643185377Ssam		case 0:			/* facility is supported */
644185377Ssam			return HAL_OK;
645185377Ssam		case 1:			/* current limit */
646185377Ssam			*result = AH_PRIVATE(ah)->ah_powerLimit;
647185377Ssam			return HAL_OK;
648185377Ssam		case 2:			/* current max tx power */
649185377Ssam			*result = AH_PRIVATE(ah)->ah_maxPowerLevel;
650185377Ssam			return HAL_OK;
651185377Ssam		case 3:			/* scale factor */
652185377Ssam			*result = AH_PRIVATE(ah)->ah_tpScale;
653185377Ssam			return HAL_OK;
654185377Ssam		}
655185377Ssam		return HAL_ENOTSUPP;
656185377Ssam	case HAL_CAP_BSSIDMASK:		/* hardware supports bssid mask */
657185377Ssam		return pCap->halBssIdMaskSupport ? HAL_OK : HAL_ENOTSUPP;
658185377Ssam	case HAL_CAP_MCAST_KEYSRCH:	/* multicast frame keycache search */
659185377Ssam		return pCap->halMcastKeySrchSupport ? HAL_OK : HAL_ENOTSUPP;
660185377Ssam	case HAL_CAP_TSF_ADJUST:	/* hardware has beacon tsf adjust */
661185377Ssam		return HAL_ENOTSUPP;
662185377Ssam	case HAL_CAP_RFSILENT:		/* rfsilent support  */
663185377Ssam		switch (capability) {
664185377Ssam		case 0:			/* facility is supported */
665185377Ssam			return pCap->halRfSilentSupport ? HAL_OK : HAL_ENOTSUPP;
666185377Ssam		case 1:			/* current setting */
667185377Ssam			return AH_PRIVATE(ah)->ah_rfkillEnabled ?
668185377Ssam				HAL_OK : HAL_ENOTSUPP;
669185377Ssam		case 2:			/* rfsilent config */
670185377Ssam			*result = AH_PRIVATE(ah)->ah_rfsilent;
671185377Ssam			return HAL_OK;
672185377Ssam		}
673185377Ssam		return HAL_ENOTSUPP;
674185377Ssam	case HAL_CAP_11D:
675185377Ssam		return HAL_OK;
676221603Sadrian
677185377Ssam	case HAL_CAP_HT:
678185377Ssam		return pCap->halHTSupport ? HAL_OK : HAL_ENOTSUPP;
679221603Sadrian	case HAL_CAP_GTXTO:
680221603Sadrian		return pCap->halGTTSupport ? HAL_OK : HAL_ENOTSUPP;
681221603Sadrian	case HAL_CAP_FAST_CC:
682221603Sadrian		return pCap->halFastCCSupport ? HAL_OK : HAL_ENOTSUPP;
683185377Ssam	case HAL_CAP_TX_CHAINMASK:	/* mask of TX chains supported */
684185377Ssam		*result = pCap->halTxChainMask;
685185377Ssam		return HAL_OK;
686185377Ssam	case HAL_CAP_RX_CHAINMASK:	/* mask of RX chains supported */
687185377Ssam		*result = pCap->halRxChainMask;
688185377Ssam		return HAL_OK;
689221603Sadrian	case HAL_CAP_NUM_GPIO_PINS:
690221603Sadrian		*result = pCap->halNumGpioPins;
691221603Sadrian		return HAL_OK;
692221603Sadrian	case HAL_CAP_CST:
693221603Sadrian		return pCap->halCSTSupport ? HAL_OK : HAL_ENOTSUPP;
694221603Sadrian	case HAL_CAP_RTS_AGGR_LIMIT:
695221603Sadrian		*result = pCap->halRtsAggrLimit;
696221603Sadrian		return HAL_OK;
697221603Sadrian	case HAL_CAP_4ADDR_AGGR:
698221603Sadrian		return pCap->hal4AddrAggrSupport ? HAL_OK : HAL_ENOTSUPP;
699222584Sadrian	case HAL_CAP_EXT_CHAN_DFS:
700222584Sadrian		return pCap->halExtChanDfsSupport ? HAL_OK : HAL_ENOTSUPP;
701247366Sadrian	case HAL_CAP_RX_STBC:
702247366Sadrian		return pCap->halRxStbcSupport ? HAL_OK : HAL_ENOTSUPP;
703247366Sadrian	case HAL_CAP_TX_STBC:
704247366Sadrian		return pCap->halTxStbcSupport ? HAL_OK : HAL_ENOTSUPP;
705238333Sadrian	case HAL_CAP_COMBINED_RADAR_RSSI:
706238333Sadrian		return pCap->halUseCombinedRadarRssi ? HAL_OK : HAL_ENOTSUPP;
707238333Sadrian	case HAL_CAP_AUTO_SLEEP:
708238333Sadrian		return pCap->halAutoSleepSupport ? HAL_OK : HAL_ENOTSUPP;
709238333Sadrian	case HAL_CAP_MBSSID_AGGR_SUPPORT:
710238333Sadrian		return pCap->halMbssidAggrSupport ? HAL_OK : HAL_ENOTSUPP;
711238333Sadrian	case HAL_CAP_SPLIT_4KB_TRANS:	/* hardware handles descriptors straddling 4k page boundary */
712238333Sadrian		return pCap->hal4kbSplitTransSupport ? HAL_OK : HAL_ENOTSUPP;
713238333Sadrian	case HAL_CAP_REG_FLAG:
714238333Sadrian		*result = AH_PRIVATE(ah)->ah_currentRDext;
715238333Sadrian		return HAL_OK;
716238333Sadrian	case HAL_CAP_ENHANCED_DMA_SUPPORT:
717238333Sadrian		return pCap->halEnhancedDmaSupport ? HAL_OK : HAL_ENOTSUPP;
718238280Sadrian	case HAL_CAP_NUM_TXMAPS:
719238280Sadrian		*result = pCap->halNumTxMaps;
720238280Sadrian		return HAL_OK;
721238280Sadrian	case HAL_CAP_TXDESCLEN:
722238280Sadrian		*result = pCap->halTxDescLen;
723238280Sadrian		return HAL_OK;
724238280Sadrian	case HAL_CAP_TXSTATUSLEN:
725238280Sadrian		*result = pCap->halTxStatusLen;
726238280Sadrian		return HAL_OK;
727238280Sadrian	case HAL_CAP_RXSTATUSLEN:
728238280Sadrian		*result = pCap->halRxStatusLen;
729238280Sadrian		return HAL_OK;
730238280Sadrian	case HAL_CAP_RXFIFODEPTH:
731238280Sadrian		switch (capability) {
732238280Sadrian		case HAL_RX_QUEUE_HP:
733238280Sadrian			*result = pCap->halRxHpFifoDepth;
734238280Sadrian			return HAL_OK;
735238280Sadrian		case HAL_RX_QUEUE_LP:
736238280Sadrian			*result = pCap->halRxLpFifoDepth;
737238280Sadrian			return HAL_OK;
738238280Sadrian		default:
739238280Sadrian			return HAL_ENOTSUPP;
740238280Sadrian	}
741238280Sadrian	case HAL_CAP_RXBUFSIZE:
742238280Sadrian	case HAL_CAP_NUM_MR_RETRIES:
743238858Sadrian		*result = pCap->halNumMRRetries;
744238858Sadrian		return HAL_OK;
745221603Sadrian	case HAL_CAP_BT_COEX:
746221603Sadrian		return pCap->halBtCoexSupport ? HAL_OK : HAL_ENOTSUPP;
747244854Sadrian	case HAL_CAP_SPECTRAL_SCAN:
748244854Sadrian		return pCap->halSpectralScanSupport ? HAL_OK : HAL_ENOTSUPP;
749221603Sadrian	case HAL_CAP_HT20_SGI:
750221603Sadrian		return pCap->halHTSGI20Support ? HAL_OK : HAL_ENOTSUPP;
751185377Ssam	case HAL_CAP_RXTSTAMP_PREC:	/* rx desc tstamp precision (bits) */
752185377Ssam		*result = pCap->halTstampPrecision;
753185377Ssam		return HAL_OK;
754251360Sadrian	case HAL_CAP_ANT_DIV_COMB:	/* AR9285/AR9485 LNA diversity */
755251360Sadrian		return pCap->halAntDivCombSupport ? HAL_OK  : HAL_ENOTSUPP;
756251360Sadrian
757222584Sadrian	case HAL_CAP_ENHANCED_DFS_SUPPORT:
758222584Sadrian		return pCap->halEnhancedDfsSupport ? HAL_OK : HAL_ENOTSUPP;
759221603Sadrian
760221603Sadrian	/* FreeBSD-specific entries for now */
761221603Sadrian	case HAL_CAP_RXORN_FATAL:	/* HAL_INT_RXORN treated as fatal  */
762221603Sadrian		return AH_PRIVATE(ah)->ah_rxornIsFatal ? HAL_OK : HAL_ENOTSUPP;
763192396Ssam	case HAL_CAP_INTRMASK:		/* mask of supported interrupts */
764192396Ssam		*result = pCap->halIntrMask;
765192396Ssam		return HAL_OK;
766195114Ssam	case HAL_CAP_BSSIDMATCH:	/* hardware has disable bssid match */
767195114Ssam		return pCap->halBssidMatchSupport ? HAL_OK : HAL_ENOTSUPP;
768218150Sadrian	case HAL_CAP_STREAMS:		/* number of 11n spatial streams */
769218150Sadrian		switch (capability) {
770218150Sadrian		case 0:			/* TX */
771218150Sadrian			*result = pCap->halTxStreams;
772218150Sadrian			return HAL_OK;
773218150Sadrian		case 1:			/* RX */
774218150Sadrian			*result = pCap->halRxStreams;
775218150Sadrian			return HAL_OK;
776218150Sadrian		default:
777218150Sadrian			return HAL_ENOTSUPP;
778218150Sadrian		}
779220324Sadrian	case HAL_CAP_RXDESC_SELFLINK:	/* hardware supports self-linked final RX descriptors correctly */
780220324Sadrian		return pCap->halHasRxSelfLinkedTail ? HAL_OK : HAL_ENOTSUPP;
781225444Sadrian	case HAL_CAP_LONG_RXDESC_TSF:		/* 32 bit TSF in RX descriptor? */
782225444Sadrian		return pCap->halHasLongRxDescTsf ? HAL_OK : HAL_ENOTSUPP;
783226488Sadrian	case HAL_CAP_BB_READ_WAR:		/* Baseband read WAR */
784226488Sadrian		return pCap->halHasBBReadWar? HAL_OK : HAL_ENOTSUPP;
785227410Sadrian	case HAL_CAP_SERIALISE_WAR:		/* PCI register serialisation */
786227410Sadrian		return pCap->halSerialiseRegWar ? HAL_OK : HAL_ENOTSUPP;
787239630Sadrian	case HAL_CAP_MFP:			/* Management frame protection setting */
788239630Sadrian		*result = pCap->halMfpSupport;
789239630Sadrian		return HAL_OK;
790251400Sadrian	case HAL_CAP_RX_LNA_MIXING:	/* Hardware uses an RX LNA mixer to map 2 antennas to a 1 stream receiver */
791251400Sadrian		return pCap->halRxUsingLnaMixing ? HAL_OK : HAL_ENOTSUPP;
792265032Sadrian	case HAL_CAP_DO_MYBEACON:	/* Hardware supports filtering my-beacons */
793265032Sadrian		return pCap->halRxDoMyBeacon ? HAL_OK : HAL_ENOTSUPP;
794185377Ssam	default:
795185377Ssam		return HAL_EINVAL;
796185377Ssam	}
797185377Ssam}
798185377Ssam
799185377SsamHAL_BOOL
800185377Ssamath_hal_setcapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type,
801185377Ssam	uint32_t capability, uint32_t setting, HAL_STATUS *status)
802185377Ssam{
803185377Ssam
804185377Ssam	switch (type) {
805185377Ssam	case HAL_CAP_TXPOW:
806185377Ssam		switch (capability) {
807185377Ssam		case 3:
808185377Ssam			if (setting <= HAL_TP_SCALE_MIN) {
809185377Ssam				AH_PRIVATE(ah)->ah_tpScale = setting;
810185377Ssam				return AH_TRUE;
811185377Ssam			}
812185377Ssam			break;
813185377Ssam		}
814185377Ssam		break;
815185377Ssam	case HAL_CAP_RFSILENT:		/* rfsilent support  */
816185377Ssam		/*
817185377Ssam		 * NB: allow even if halRfSilentSupport is false
818185377Ssam		 *     in case the EEPROM is misprogrammed.
819185377Ssam		 */
820185377Ssam		switch (capability) {
821185377Ssam		case 1:			/* current setting */
822185377Ssam			AH_PRIVATE(ah)->ah_rfkillEnabled = (setting != 0);
823185377Ssam			return AH_TRUE;
824185377Ssam		case 2:			/* rfsilent config */
825185377Ssam			/* XXX better done per-chip for validation? */
826185377Ssam			AH_PRIVATE(ah)->ah_rfsilent = setting;
827185377Ssam			return AH_TRUE;
828185377Ssam		}
829185377Ssam		break;
830185377Ssam	case HAL_CAP_REG_DMN:		/* regulatory domain */
831185377Ssam		AH_PRIVATE(ah)->ah_currentRD = setting;
832185377Ssam		return AH_TRUE;
833185377Ssam	case HAL_CAP_RXORN_FATAL:	/* HAL_INT_RXORN treated as fatal  */
834185377Ssam		AH_PRIVATE(ah)->ah_rxornIsFatal = setting;
835185377Ssam		return AH_TRUE;
836185377Ssam	default:
837185377Ssam		break;
838185377Ssam	}
839185377Ssam	if (status)
840185377Ssam		*status = HAL_EINVAL;
841185377Ssam	return AH_FALSE;
842185377Ssam}
843185377Ssam
844185377Ssam/*
845185377Ssam * Common support for getDiagState method.
846185377Ssam */
847185377Ssam
848185377Ssamstatic u_int
849185377Ssamath_hal_getregdump(struct ath_hal *ah, const HAL_REGRANGE *regs,
850185377Ssam	void *dstbuf, int space)
851185377Ssam{
852185377Ssam	uint32_t *dp = dstbuf;
853185377Ssam	int i;
854185377Ssam
855185377Ssam	for (i = 0; space >= 2*sizeof(uint32_t); i++) {
856269760Sadrian		uint32_t r = regs[i].start;
857269760Sadrian		uint32_t e = regs[i].end;
858269760Sadrian		*dp++ = r;
859269760Sadrian		*dp++ = e;
860269760Sadrian		space -= 2*sizeof(uint32_t);
861185377Ssam		do {
862185377Ssam			*dp++ = OS_REG_READ(ah, r);
863185377Ssam			r += sizeof(uint32_t);
864185377Ssam			space -= sizeof(uint32_t);
865185377Ssam		} while (r <= e && space >= sizeof(uint32_t));
866185377Ssam	}
867185377Ssam	return (char *) dp - (char *) dstbuf;
868185377Ssam}
869188771Ssam
870188771Ssamstatic void
871188771Ssamath_hal_setregs(struct ath_hal *ah, const HAL_REGWRITE *regs, int space)
872188771Ssam{
873188771Ssam	while (space >= sizeof(HAL_REGWRITE)) {
874188771Ssam		OS_REG_WRITE(ah, regs->addr, regs->value);
875188771Ssam		regs++, space -= sizeof(HAL_REGWRITE);
876188771Ssam	}
877188771Ssam}
878185377Ssam
879185377SsamHAL_BOOL
880185377Ssamath_hal_getdiagstate(struct ath_hal *ah, int request,
881185377Ssam	const void *args, uint32_t argsize,
882185377Ssam	void **result, uint32_t *resultsize)
883185377Ssam{
884280828Sadrian
885185377Ssam	switch (request) {
886185377Ssam	case HAL_DIAG_REVS:
887185377Ssam		*result = &AH_PRIVATE(ah)->ah_devid;
888185377Ssam		*resultsize = sizeof(HAL_REVS);
889185377Ssam		return AH_TRUE;
890185377Ssam	case HAL_DIAG_REGS:
891185377Ssam		*resultsize = ath_hal_getregdump(ah, args, *result,*resultsize);
892185377Ssam		return AH_TRUE;
893188771Ssam	case HAL_DIAG_SETREGS:
894188771Ssam		ath_hal_setregs(ah, args, argsize);
895188771Ssam		*resultsize = 0;
896188771Ssam		return AH_TRUE;
897185377Ssam	case HAL_DIAG_FATALERR:
898185377Ssam		*result = &AH_PRIVATE(ah)->ah_fatalState[0];
899185377Ssam		*resultsize = sizeof(AH_PRIVATE(ah)->ah_fatalState);
900185377Ssam		return AH_TRUE;
901185377Ssam	case HAL_DIAG_EEREAD:
902185377Ssam		if (argsize != sizeof(uint16_t))
903185377Ssam			return AH_FALSE;
904185377Ssam		if (!ath_hal_eepromRead(ah, *(const uint16_t *)args, *result))
905185377Ssam			return AH_FALSE;
906185377Ssam		*resultsize = sizeof(uint16_t);
907185377Ssam		return AH_TRUE;
908185377Ssam#ifdef AH_PRIVATE_DIAG
909185377Ssam	case HAL_DIAG_SETKEY: {
910185377Ssam		const HAL_DIAG_KEYVAL *dk;
911185377Ssam
912185377Ssam		if (argsize != sizeof(HAL_DIAG_KEYVAL))
913185377Ssam			return AH_FALSE;
914185377Ssam		dk = (const HAL_DIAG_KEYVAL *)args;
915185377Ssam		return ah->ah_setKeyCacheEntry(ah, dk->dk_keyix,
916185377Ssam			&dk->dk_keyval, dk->dk_mac, dk->dk_xor);
917185377Ssam	}
918185377Ssam	case HAL_DIAG_RESETKEY:
919185377Ssam		if (argsize != sizeof(uint16_t))
920185377Ssam			return AH_FALSE;
921185377Ssam		return ah->ah_resetKeyCacheEntry(ah, *(const uint16_t *)args);
922185380Ssam#ifdef AH_SUPPORT_WRITE_EEPROM
923185380Ssam	case HAL_DIAG_EEWRITE: {
924185380Ssam		const HAL_DIAG_EEVAL *ee;
925185380Ssam		if (argsize != sizeof(HAL_DIAG_EEVAL))
926185380Ssam			return AH_FALSE;
927185380Ssam		ee = (const HAL_DIAG_EEVAL *)args;
928185380Ssam		return ath_hal_eepromWrite(ah, ee->ee_off, ee->ee_data);
929185380Ssam	}
930185380Ssam#endif /* AH_SUPPORT_WRITE_EEPROM */
931185377Ssam#endif /* AH_PRIVATE_DIAG */
932185377Ssam	case HAL_DIAG_11NCOMPAT:
933185377Ssam		if (argsize == 0) {
934185377Ssam			*resultsize = sizeof(uint32_t);
935185377Ssam			*((uint32_t *)(*result)) =
936185377Ssam				AH_PRIVATE(ah)->ah_11nCompat;
937185377Ssam		} else if (argsize == sizeof(uint32_t)) {
938185377Ssam			AH_PRIVATE(ah)->ah_11nCompat = *(const uint32_t *)args;
939185377Ssam		} else
940185377Ssam			return AH_FALSE;
941185377Ssam		return AH_TRUE;
942280828Sadrian	case HAL_DIAG_CHANSURVEY:
943280828Sadrian		*result = &AH_PRIVATE(ah)->ah_chansurvey;
944280828Sadrian		*resultsize = sizeof(HAL_CHANNEL_SURVEY);
945280828Sadrian		return AH_TRUE;
946185377Ssam	}
947185377Ssam	return AH_FALSE;
948185377Ssam}
949185377Ssam
950185377Ssam/*
951185377Ssam * Set the properties of the tx queue with the parameters
952185377Ssam * from qInfo.
953185377Ssam */
954185377SsamHAL_BOOL
955185377Ssamath_hal_setTxQProps(struct ath_hal *ah,
956185377Ssam	HAL_TX_QUEUE_INFO *qi, const HAL_TXQ_INFO *qInfo)
957185377Ssam{
958185377Ssam	uint32_t cw;
959185377Ssam
960185377Ssam	if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) {
961185377Ssam		HALDEBUG(ah, HAL_DEBUG_TXQUEUE,
962185377Ssam		    "%s: inactive queue\n", __func__);
963185377Ssam		return AH_FALSE;
964185377Ssam	}
965185377Ssam	/* XXX validate parameters */
966185377Ssam	qi->tqi_ver = qInfo->tqi_ver;
967185377Ssam	qi->tqi_subtype = qInfo->tqi_subtype;
968185377Ssam	qi->tqi_qflags = qInfo->tqi_qflags;
969185377Ssam	qi->tqi_priority = qInfo->tqi_priority;
970185377Ssam	if (qInfo->tqi_aifs != HAL_TXQ_USEDEFAULT)
971185377Ssam		qi->tqi_aifs = AH_MIN(qInfo->tqi_aifs, 255);
972185377Ssam	else
973185377Ssam		qi->tqi_aifs = INIT_AIFS;
974185377Ssam	if (qInfo->tqi_cwmin != HAL_TXQ_USEDEFAULT) {
975185377Ssam		cw = AH_MIN(qInfo->tqi_cwmin, 1024);
976185377Ssam		/* make sure that the CWmin is of the form (2^n - 1) */
977185377Ssam		qi->tqi_cwmin = 1;
978185377Ssam		while (qi->tqi_cwmin < cw)
979185377Ssam			qi->tqi_cwmin = (qi->tqi_cwmin << 1) | 1;
980185377Ssam	} else
981185377Ssam		qi->tqi_cwmin = qInfo->tqi_cwmin;
982185377Ssam	if (qInfo->tqi_cwmax != HAL_TXQ_USEDEFAULT) {
983185377Ssam		cw = AH_MIN(qInfo->tqi_cwmax, 1024);
984185377Ssam		/* make sure that the CWmax is of the form (2^n - 1) */
985185377Ssam		qi->tqi_cwmax = 1;
986185377Ssam		while (qi->tqi_cwmax < cw)
987185377Ssam			qi->tqi_cwmax = (qi->tqi_cwmax << 1) | 1;
988185377Ssam	} else
989185377Ssam		qi->tqi_cwmax = INIT_CWMAX;
990185377Ssam	/* Set retry limit values */
991185377Ssam	if (qInfo->tqi_shretry != 0)
992185377Ssam		qi->tqi_shretry = AH_MIN(qInfo->tqi_shretry, 15);
993185377Ssam	else
994185377Ssam		qi->tqi_shretry = INIT_SH_RETRY;
995185377Ssam	if (qInfo->tqi_lgretry != 0)
996185377Ssam		qi->tqi_lgretry = AH_MIN(qInfo->tqi_lgretry, 15);
997185377Ssam	else
998185377Ssam		qi->tqi_lgretry = INIT_LG_RETRY;
999185377Ssam	qi->tqi_cbrPeriod = qInfo->tqi_cbrPeriod;
1000185377Ssam	qi->tqi_cbrOverflowLimit = qInfo->tqi_cbrOverflowLimit;
1001185377Ssam	qi->tqi_burstTime = qInfo->tqi_burstTime;
1002185377Ssam	qi->tqi_readyTime = qInfo->tqi_readyTime;
1003185377Ssam
1004185377Ssam	switch (qInfo->tqi_subtype) {
1005185377Ssam	case HAL_WME_UPSD:
1006185377Ssam		if (qi->tqi_type == HAL_TX_QUEUE_DATA)
1007185377Ssam			qi->tqi_intFlags = HAL_TXQ_USE_LOCKOUT_BKOFF_DIS;
1008185377Ssam		break;
1009185377Ssam	default:
1010185377Ssam		break;		/* NB: silence compiler */
1011185377Ssam	}
1012185377Ssam	return AH_TRUE;
1013185377Ssam}
1014185377Ssam
1015185377SsamHAL_BOOL
1016185377Ssamath_hal_getTxQProps(struct ath_hal *ah,
1017185377Ssam	HAL_TXQ_INFO *qInfo, const HAL_TX_QUEUE_INFO *qi)
1018185377Ssam{
1019185377Ssam	if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) {
1020185377Ssam		HALDEBUG(ah, HAL_DEBUG_TXQUEUE,
1021185377Ssam		    "%s: inactive queue\n", __func__);
1022185377Ssam		return AH_FALSE;
1023185377Ssam	}
1024185377Ssam
1025185377Ssam	qInfo->tqi_qflags = qi->tqi_qflags;
1026185377Ssam	qInfo->tqi_ver = qi->tqi_ver;
1027185377Ssam	qInfo->tqi_subtype = qi->tqi_subtype;
1028185377Ssam	qInfo->tqi_qflags = qi->tqi_qflags;
1029185377Ssam	qInfo->tqi_priority = qi->tqi_priority;
1030185377Ssam	qInfo->tqi_aifs = qi->tqi_aifs;
1031185377Ssam	qInfo->tqi_cwmin = qi->tqi_cwmin;
1032185377Ssam	qInfo->tqi_cwmax = qi->tqi_cwmax;
1033185377Ssam	qInfo->tqi_shretry = qi->tqi_shretry;
1034185377Ssam	qInfo->tqi_lgretry = qi->tqi_lgretry;
1035185377Ssam	qInfo->tqi_cbrPeriod = qi->tqi_cbrPeriod;
1036185377Ssam	qInfo->tqi_cbrOverflowLimit = qi->tqi_cbrOverflowLimit;
1037185377Ssam	qInfo->tqi_burstTime = qi->tqi_burstTime;
1038185377Ssam	qInfo->tqi_readyTime = qi->tqi_readyTime;
1039185377Ssam	return AH_TRUE;
1040185377Ssam}
1041185377Ssam
1042185377Ssam                                     /* 11a Turbo  11b  11g  108g */
1043185377Ssamstatic const int16_t NOISE_FLOOR[] = { -96, -93,  -98, -96,  -93 };
1044185377Ssam
1045185377Ssam/*
1046185377Ssam * Read the current channel noise floor and return.
1047185377Ssam * If nf cal hasn't finished, channel noise floor should be 0
1048185377Ssam * and we return a nominal value based on band and frequency.
1049185377Ssam *
1050185377Ssam * NB: This is a private routine used by per-chip code to
1051185377Ssam *     implement the ah_getChanNoise method.
1052185377Ssam */
1053185377Ssamint16_t
1054187831Ssamath_hal_getChanNoise(struct ath_hal *ah, const struct ieee80211_channel *chan)
1055185377Ssam{
1056185377Ssam	HAL_CHANNEL_INTERNAL *ichan;
1057185377Ssam
1058185377Ssam	ichan = ath_hal_checkchannel(ah, chan);
1059185377Ssam	if (ichan == AH_NULL) {
1060185377Ssam		HALDEBUG(ah, HAL_DEBUG_NFCAL,
1061185377Ssam		    "%s: invalid channel %u/0x%x; no mapping\n",
1062187831Ssam		    __func__, chan->ic_freq, chan->ic_flags);
1063185377Ssam		return 0;
1064185377Ssam	}
1065185377Ssam	if (ichan->rawNoiseFloor == 0) {
1066185377Ssam		WIRELESS_MODE mode = ath_hal_chan2wmode(ah, chan);
1067185377Ssam
1068185377Ssam		HALASSERT(mode < WIRELESS_MODE_MAX);
1069185377Ssam		return NOISE_FLOOR[mode] + ath_hal_getNfAdjust(ah, ichan);
1070185377Ssam	} else
1071185377Ssam		return ichan->rawNoiseFloor + ichan->noiseFloorAdjust;
1072185377Ssam}
1073185377Ssam
1074185377Ssam/*
1075220443Sadrian * Fetch the current setup of ctl/ext noise floor values.
1076220443Sadrian *
1077220443Sadrian * If the CHANNEL_MIMO_NF_VALID flag isn't set, the array is simply
1078220443Sadrian * populated with values from NOISE_FLOOR[] + ath_hal_getNfAdjust().
1079220443Sadrian *
1080220443Sadrian * The caller must supply ctl/ext NF arrays which are at least
1081240623Sadrian * AH_MAX_CHAINS entries long.
1082220443Sadrian */
1083220443Sadrianint
1084220443Sadrianath_hal_get_mimo_chan_noise(struct ath_hal *ah,
1085220444Sadrian    const struct ieee80211_channel *chan, int16_t *nf_ctl,
1086220444Sadrian    int16_t *nf_ext)
1087220443Sadrian{
1088221019Sadrian#ifdef	AH_SUPPORT_AR5416
1089220443Sadrian	HAL_CHANNEL_INTERNAL *ichan;
1090220443Sadrian	int i;
1091220443Sadrian
1092220443Sadrian	ichan = ath_hal_checkchannel(ah, chan);
1093220443Sadrian	if (ichan == AH_NULL) {
1094220443Sadrian		HALDEBUG(ah, HAL_DEBUG_NFCAL,
1095220443Sadrian		    "%s: invalid channel %u/0x%x; no mapping\n",
1096220443Sadrian		    __func__, chan->ic_freq, chan->ic_flags);
1097240623Sadrian		for (i = 0; i < AH_MAX_CHAINS; i++) {
1098220443Sadrian			nf_ctl[i] = nf_ext[i] = 0;
1099220443Sadrian		}
1100220443Sadrian		return 0;
1101220443Sadrian	}
1102220443Sadrian
1103220443Sadrian	/* Return 0 if there's no valid MIMO values (yet) */
1104220443Sadrian	if (! (ichan->privFlags & CHANNEL_MIMO_NF_VALID)) {
1105240623Sadrian		for (i = 0; i < AH_MAX_CHAINS; i++) {
1106220443Sadrian			nf_ctl[i] = nf_ext[i] = 0;
1107220443Sadrian		}
1108220443Sadrian		return 0;
1109220443Sadrian	}
1110220443Sadrian	if (ichan->rawNoiseFloor == 0) {
1111220443Sadrian		WIRELESS_MODE mode = ath_hal_chan2wmode(ah, chan);
1112220443Sadrian		HALASSERT(mode < WIRELESS_MODE_MAX);
1113220443Sadrian		/*
1114220443Sadrian		 * See the comment below - this could cause issues for
1115220443Sadrian		 * stations which have a very low RSSI, below the
1116220443Sadrian		 * 'normalised' NF values in NOISE_FLOOR[].
1117220443Sadrian		 */
1118240623Sadrian		for (i = 0; i < AH_MAX_CHAINS; i++) {
1119220443Sadrian			nf_ctl[i] = nf_ext[i] = NOISE_FLOOR[mode] +
1120220443Sadrian			    ath_hal_getNfAdjust(ah, ichan);
1121220443Sadrian		}
1122220443Sadrian		return 1;
1123220443Sadrian	} else {
1124220443Sadrian		/*
1125220443Sadrian		 * The value returned here from a MIMO radio is presumed to be
1126220443Sadrian		 * "good enough" as a NF calculation. As RSSI values are calculated
1127220443Sadrian		 * against this, an adjusted NF may be higher than the RSSI value
1128220443Sadrian		 * returned from a vary weak station, resulting in an obscenely
1129220443Sadrian		 * high signal strength calculation being returned.
1130220443Sadrian		 *
1131220443Sadrian		 * This should be re-evaluated at a later date, along with any
1132220443Sadrian		 * signal strength calculations which are made. Quite likely the
1133220443Sadrian		 * RSSI values will need to be adjusted to ensure the calculations
1134220443Sadrian		 * don't "wrap" when RSSI is less than the "adjusted" NF value.
1135220443Sadrian		 * ("Adjust" here is via ichan->noiseFloorAdjust.)
1136220443Sadrian		 */
1137240623Sadrian		for (i = 0; i < AH_MAX_CHAINS; i++) {
1138220443Sadrian			nf_ctl[i] = ichan->noiseFloorCtl[i] + ath_hal_getNfAdjust(ah, ichan);
1139220443Sadrian			nf_ext[i] = ichan->noiseFloorExt[i] + ath_hal_getNfAdjust(ah, ichan);
1140220443Sadrian		}
1141220443Sadrian		return 1;
1142220443Sadrian	}
1143221019Sadrian#else
1144221019Sadrian	return 0;
1145221019Sadrian#endif	/* AH_SUPPORT_AR5416 */
1146220443Sadrian}
1147220443Sadrian
1148220443Sadrian/*
1149185377Ssam * Process all valid raw noise floors into the dBm noise floor values.
1150185377Ssam * Though our device has no reference for a dBm noise floor, we perform
1151185377Ssam * a relative minimization of NF's based on the lowest NF found across a
1152185377Ssam * channel scan.
1153185377Ssam */
1154185377Ssamvoid
1155185377Ssamath_hal_process_noisefloor(struct ath_hal *ah)
1156185377Ssam{
1157185377Ssam	HAL_CHANNEL_INTERNAL *c;
1158185377Ssam	int16_t correct2, correct5;
1159185377Ssam	int16_t lowest2, lowest5;
1160185377Ssam	int i;
1161185377Ssam
1162185377Ssam	/*
1163185377Ssam	 * Find the lowest 2GHz and 5GHz noise floor values after adjusting
1164185377Ssam	 * for statistically recorded NF/channel deviation.
1165185377Ssam	 */
1166185377Ssam	correct2 = lowest2 = 0;
1167185377Ssam	correct5 = lowest5 = 0;
1168185377Ssam	for (i = 0; i < AH_PRIVATE(ah)->ah_nchan; i++) {
1169185377Ssam		WIRELESS_MODE mode;
1170185377Ssam		int16_t nf;
1171185377Ssam
1172185377Ssam		c = &AH_PRIVATE(ah)->ah_channels[i];
1173185377Ssam		if (c->rawNoiseFloor >= 0)
1174185377Ssam			continue;
1175187831Ssam		/* XXX can't identify proper mode */
1176187831Ssam		mode = IS_CHAN_5GHZ(c) ? WIRELESS_MODE_11a : WIRELESS_MODE_11g;
1177185377Ssam		nf = c->rawNoiseFloor + NOISE_FLOOR[mode] +
1178185377Ssam			ath_hal_getNfAdjust(ah, c);
1179185377Ssam		if (IS_CHAN_5GHZ(c)) {
1180185377Ssam			if (nf < lowest5) {
1181185377Ssam				lowest5 = nf;
1182185377Ssam				correct5 = NOISE_FLOOR[mode] -
1183185377Ssam				    (c->rawNoiseFloor + ath_hal_getNfAdjust(ah, c));
1184185377Ssam			}
1185185377Ssam		} else {
1186185377Ssam			if (nf < lowest2) {
1187185377Ssam				lowest2 = nf;
1188185377Ssam				correct2 = NOISE_FLOOR[mode] -
1189185377Ssam				    (c->rawNoiseFloor + ath_hal_getNfAdjust(ah, c));
1190185377Ssam			}
1191185377Ssam		}
1192185377Ssam	}
1193185377Ssam
1194185377Ssam	/* Correct the channels to reach the expected NF value */
1195185377Ssam	for (i = 0; i < AH_PRIVATE(ah)->ah_nchan; i++) {
1196185377Ssam		c = &AH_PRIVATE(ah)->ah_channels[i];
1197185377Ssam		if (c->rawNoiseFloor >= 0)
1198185377Ssam			continue;
1199185377Ssam		/* Apply correction factor */
1200185377Ssam		c->noiseFloorAdjust = ath_hal_getNfAdjust(ah, c) +
1201185377Ssam			(IS_CHAN_5GHZ(c) ? correct5 : correct2);
1202187831Ssam		HALDEBUG(ah, HAL_DEBUG_NFCAL, "%u raw nf %d adjust %d\n",
1203187831Ssam		    c->channel, c->rawNoiseFloor, c->noiseFloorAdjust);
1204185377Ssam	}
1205185377Ssam}
1206185377Ssam
1207185377Ssam/*
1208185377Ssam * INI support routines.
1209185377Ssam */
1210185377Ssam
1211185377Ssamint
1212185377Ssamath_hal_ini_write(struct ath_hal *ah, const HAL_INI_ARRAY *ia,
1213185377Ssam	int col, int regWr)
1214185377Ssam{
1215185377Ssam	int r;
1216185377Ssam
1217189713Ssam	HALASSERT(col < ia->cols);
1218185377Ssam	for (r = 0; r < ia->rows; r++) {
1219185377Ssam		OS_REG_WRITE(ah, HAL_INI_VAL(ia, r, 0),
1220185377Ssam		    HAL_INI_VAL(ia, r, col));
1221217921Sadrian
1222217921Sadrian		/* Analog shift register delay seems needed for Merlin - PR kern/154220 */
1223222157Sadrian		if (HAL_INI_VAL(ia, r, 0) >= 0x7800 && HAL_INI_VAL(ia, r, 0) < 0x7900)
1224217921Sadrian			OS_DELAY(100);
1225217921Sadrian
1226185377Ssam		DMA_YIELD(regWr);
1227185377Ssam	}
1228185377Ssam	return regWr;
1229185377Ssam}
1230185377Ssam
1231185377Ssamvoid
1232185377Ssamath_hal_ini_bank_setup(uint32_t data[], const HAL_INI_ARRAY *ia, int col)
1233185377Ssam{
1234185377Ssam	int r;
1235185377Ssam
1236189713Ssam	HALASSERT(col < ia->cols);
1237185377Ssam	for (r = 0; r < ia->rows; r++)
1238185377Ssam		data[r] = HAL_INI_VAL(ia, r, col);
1239185377Ssam}
1240185377Ssam
1241185377Ssamint
1242185377Ssamath_hal_ini_bank_write(struct ath_hal *ah, const HAL_INI_ARRAY *ia,
1243185377Ssam	const uint32_t data[], int regWr)
1244185377Ssam{
1245185377Ssam	int r;
1246185377Ssam
1247185377Ssam	for (r = 0; r < ia->rows; r++) {
1248185377Ssam		OS_REG_WRITE(ah, HAL_INI_VAL(ia, r, 0), data[r]);
1249185377Ssam		DMA_YIELD(regWr);
1250185377Ssam	}
1251185377Ssam	return regWr;
1252185377Ssam}
1253219586Sadrian
1254219586Sadrian/*
1255219586Sadrian * These are EEPROM board related routines which should likely live in
1256219586Sadrian * a helper library of some sort.
1257219586Sadrian */
1258219586Sadrian
1259219586Sadrian/**************************************************************
1260219586Sadrian * ath_ee_getLowerUppderIndex
1261219586Sadrian *
1262219586Sadrian * Return indices surrounding the value in sorted integer lists.
1263219586Sadrian * Requirement: the input list must be monotonically increasing
1264219586Sadrian *     and populated up to the list size
1265219586Sadrian * Returns: match is set if an index in the array matches exactly
1266219586Sadrian *     or a the target is before or after the range of the array.
1267219586Sadrian */
1268219586SadrianHAL_BOOL
1269219586Sadrianath_ee_getLowerUpperIndex(uint8_t target, uint8_t *pList, uint16_t listSize,
1270219586Sadrian                   uint16_t *indexL, uint16_t *indexR)
1271219586Sadrian{
1272219586Sadrian    uint16_t i;
1273219586Sadrian
1274219586Sadrian    /*
1275219586Sadrian     * Check first and last elements for beyond ordered array cases.
1276219586Sadrian     */
1277219586Sadrian    if (target <= pList[0]) {
1278219586Sadrian        *indexL = *indexR = 0;
1279219586Sadrian        return AH_TRUE;
1280219586Sadrian    }
1281219586Sadrian    if (target >= pList[listSize-1]) {
1282219586Sadrian        *indexL = *indexR = (uint16_t)(listSize - 1);
1283219586Sadrian        return AH_TRUE;
1284219586Sadrian    }
1285219586Sadrian
1286219586Sadrian    /* look for value being near or between 2 values in list */
1287219586Sadrian    for (i = 0; i < listSize - 1; i++) {
1288219586Sadrian        /*
1289219586Sadrian         * If value is close to the current value of the list
1290219586Sadrian         * then target is not between values, it is one of the values
1291219586Sadrian         */
1292219586Sadrian        if (pList[i] == target) {
1293219586Sadrian            *indexL = *indexR = i;
1294219586Sadrian            return AH_TRUE;
1295219586Sadrian        }
1296219586Sadrian        /*
1297219586Sadrian         * Look for value being between current value and next value
1298219586Sadrian         * if so return these 2 values
1299219586Sadrian         */
1300219586Sadrian        if (target < pList[i + 1]) {
1301219586Sadrian            *indexL = i;
1302219586Sadrian            *indexR = (uint16_t)(i + 1);
1303219586Sadrian            return AH_FALSE;
1304219586Sadrian        }
1305219586Sadrian    }
1306219586Sadrian    HALASSERT(0);
1307219586Sadrian    *indexL = *indexR = 0;
1308219586Sadrian    return AH_FALSE;
1309219586Sadrian}
1310219586Sadrian
1311219586Sadrian/**************************************************************
1312219586Sadrian * ath_ee_FillVpdTable
1313219586Sadrian *
1314219586Sadrian * Fill the Vpdlist for indices Pmax-Pmin
1315219586Sadrian * Note: pwrMin, pwrMax and Vpdlist are all in dBm * 4
1316219586Sadrian */
1317219586SadrianHAL_BOOL
1318219586Sadrianath_ee_FillVpdTable(uint8_t pwrMin, uint8_t pwrMax, uint8_t *pPwrList,
1319219586Sadrian                   uint8_t *pVpdList, uint16_t numIntercepts, uint8_t *pRetVpdList)
1320219586Sadrian{
1321219586Sadrian    uint16_t  i, k;
1322219586Sadrian    uint8_t   currPwr = pwrMin;
1323219586Sadrian    uint16_t  idxL, idxR;
1324219586Sadrian
1325219586Sadrian    HALASSERT(pwrMax > pwrMin);
1326219586Sadrian    for (i = 0; i <= (pwrMax - pwrMin) / 2; i++) {
1327219586Sadrian        ath_ee_getLowerUpperIndex(currPwr, pPwrList, numIntercepts,
1328219586Sadrian                           &(idxL), &(idxR));
1329219586Sadrian        if (idxR < 1)
1330219586Sadrian            idxR = 1;           /* extrapolate below */
1331219586Sadrian        if (idxL == numIntercepts - 1)
1332219586Sadrian            idxL = (uint16_t)(numIntercepts - 2);   /* extrapolate above */
1333219586Sadrian        if (pPwrList[idxL] == pPwrList[idxR])
1334219586Sadrian            k = pVpdList[idxL];
1335219586Sadrian        else
1336219586Sadrian            k = (uint16_t)( ((currPwr - pPwrList[idxL]) * pVpdList[idxR] + (pPwrList[idxR] - currPwr) * pVpdList[idxL]) /
1337219586Sadrian                  (pPwrList[idxR] - pPwrList[idxL]) );
1338219586Sadrian        HALASSERT(k < 256);
1339219586Sadrian        pRetVpdList[i] = (uint8_t)k;
1340219586Sadrian        currPwr += 2;               /* half dB steps */
1341219586Sadrian    }
1342219586Sadrian
1343219586Sadrian    return AH_TRUE;
1344219586Sadrian}
1345219586Sadrian
1346219586Sadrian/**************************************************************************
1347219586Sadrian * ath_ee_interpolate
1348219586Sadrian *
1349219586Sadrian * Returns signed interpolated or the scaled up interpolated value
1350219586Sadrian */
1351219586Sadrianint16_t
1352219586Sadrianath_ee_interpolate(uint16_t target, uint16_t srcLeft, uint16_t srcRight,
1353219586Sadrian            int16_t targetLeft, int16_t targetRight)
1354219586Sadrian{
1355219586Sadrian    int16_t rv;
1356219586Sadrian
1357219586Sadrian    if (srcRight == srcLeft) {
1358219586Sadrian        rv = targetLeft;
1359219586Sadrian    } else {
1360219586Sadrian        rv = (int16_t)( ((target - srcLeft) * targetRight +
1361219586Sadrian              (srcRight - target) * targetLeft) / (srcRight - srcLeft) );
1362219586Sadrian    }
1363219586Sadrian    return rv;
1364219586Sadrian}
1365225444Sadrian
1366225444Sadrian/*
1367225444Sadrian * Adjust the TSF.
1368225444Sadrian */
1369225444Sadrianvoid
1370225444Sadrianath_hal_adjusttsf(struct ath_hal *ah, int32_t tsfdelta)
1371225444Sadrian{
1372225444Sadrian	/* XXX handle wrap/overflow */
1373225444Sadrian	OS_REG_WRITE(ah, AR_TSF_L32, OS_REG_READ(ah, AR_TSF_L32) + tsfdelta);
1374225444Sadrian}
1375225444Sadrian
1376225444Sadrian/*
1377225444Sadrian * Enable or disable CCA.
1378225444Sadrian */
1379225444Sadrianvoid
1380225444Sadrianath_hal_setcca(struct ath_hal *ah, int ena)
1381225444Sadrian{
1382225444Sadrian	/*
1383225444Sadrian	 * NB: fill me in; this is not provided by default because disabling
1384225444Sadrian	 *     CCA in most locales violates regulatory.
1385225444Sadrian	 */
1386225444Sadrian}
1387225444Sadrian
1388225444Sadrian/*
1389225444Sadrian * Get CCA setting.
1390225444Sadrian */
1391225444Sadrianint
1392225444Sadrianath_hal_getcca(struct ath_hal *ah)
1393225444Sadrian{
1394225444Sadrian	u_int32_t diag;
1395225444Sadrian	if (ath_hal_getcapability(ah, HAL_CAP_DIAG, 0, &diag) != HAL_OK)
1396225444Sadrian		return 1;
1397225444Sadrian	return ((diag & 0x500000) == 0);
1398225444Sadrian}
1399230147Sadrian
1400230147Sadrian/*
1401230147Sadrian * This routine is only needed when supporting EEPROM-in-RAM setups
1402230147Sadrian * (eg embedded SoCs and on-board PCI/PCIe devices.)
1403230147Sadrian */
1404230147Sadrian/* NB: This is in 16 bit words; not bytes */
1405230147Sadrian/* XXX This doesn't belong here!  */
1406230147Sadrian#define ATH_DATA_EEPROM_SIZE    2048
1407230147Sadrian
1408230147SadrianHAL_BOOL
1409230147Sadrianath_hal_EepromDataRead(struct ath_hal *ah, u_int off, uint16_t *data)
1410230147Sadrian{
1411230147Sadrian	if (ah->ah_eepromdata == AH_NULL) {
1412230147Sadrian		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: no eeprom data!\n", __func__);
1413230147Sadrian		return AH_FALSE;
1414230147Sadrian	}
1415230147Sadrian	if (off > ATH_DATA_EEPROM_SIZE) {
1416230147Sadrian		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: offset %x > %x\n",
1417230147Sadrian		    __func__, off, ATH_DATA_EEPROM_SIZE);
1418230147Sadrian		return AH_FALSE;
1419230147Sadrian	}
1420230147Sadrian	(*data) = ah->ah_eepromdata[off];
1421230147Sadrian	return AH_TRUE;
1422230147Sadrian}
1423252236Sadrian
1424252236Sadrian/*
1425252236Sadrian * Do a 2GHz specific MHz->IEEE based on the hardware
1426252236Sadrian * frequency.
1427252236Sadrian *
1428252236Sadrian * This is the unmapped frequency which is programmed into the hardware.
1429252236Sadrian */
1430252236Sadrianint
1431291469Sadrianath_hal_mhz2ieee_2ghz(struct ath_hal *ah, int freq)
1432252236Sadrian{
1433252236Sadrian
1434291469Sadrian	if (freq == 2484)
1435252236Sadrian		return 14;
1436291469Sadrian	if (freq < 2484)
1437291469Sadrian		return ((int) freq - 2407) / 5;
1438252236Sadrian	else
1439291469Sadrian		return 15 + ((freq - 2512) / 20);
1440252236Sadrian}
1441280828Sadrian
1442280828Sadrian/*
1443280828Sadrian * Clear the current survey data.
1444280828Sadrian *
1445280828Sadrian * This should be done during a channel change.
1446280828Sadrian */
1447280828Sadrianvoid
1448280828Sadrianath_hal_survey_clear(struct ath_hal *ah)
1449280828Sadrian{
1450280828Sadrian
1451280828Sadrian	OS_MEMZERO(&AH_PRIVATE(ah)->ah_chansurvey,
1452280828Sadrian	    sizeof(AH_PRIVATE(ah)->ah_chansurvey));
1453280828Sadrian}
1454280828Sadrian
1455280828Sadrian/*
1456280828Sadrian * Add a sample to the channel survey.
1457280828Sadrian */
1458280828Sadrianvoid
1459280828Sadrianath_hal_survey_add_sample(struct ath_hal *ah, HAL_SURVEY_SAMPLE *hs)
1460280828Sadrian{
1461280828Sadrian	HAL_CHANNEL_SURVEY *cs;
1462280828Sadrian
1463280828Sadrian	cs = &AH_PRIVATE(ah)->ah_chansurvey;
1464280828Sadrian
1465280828Sadrian	OS_MEMCPY(&cs->samples[cs->cur_sample], hs, sizeof(*hs));
1466280828Sadrian	cs->samples[cs->cur_sample].seq_num = cs->cur_seq;
1467280828Sadrian	cs->cur_sample = (cs->cur_sample + 1) % CHANNEL_SURVEY_SAMPLE_COUNT;
1468280828Sadrian	cs->cur_seq++;
1469280828Sadrian}
1470