ah.c revision 218490
1193323Sed/*
2193323Sed * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
3193323Sed * Copyright (c) 2002-2008 Atheros Communications, Inc.
4193323Sed *
5193323Sed * Permission to use, copy, modify, and/or distribute this software for any
6193323Sed * purpose with or without fee is hereby granted, provided that the above
7193323Sed * copyright notice and this permission notice appear in all copies.
8193323Sed *
9193323Sed * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10193323Sed * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11193323Sed * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12193323Sed * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13193323Sed * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14193323Sed * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15193323Sed * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16193323Sed *
17193323Sed * $FreeBSD: head/sys/dev/ath/ath_hal/ah.c 218490 2011-02-09 16:37:29Z adrian $
18193323Sed */
19193323Sed#include "opt_ah.h"
20193323Sed
21193323Sed#include "ah.h"
22193323Sed#include "ah_internal.h"
23193323Sed#include "ah_devid.h"
24198090Srdivacky
25251662Sdim#include "ar5416/ar5416reg.h"		/* NB: includes ar5212reg.h */
26249423Sdim
27249423Sdim/* linker set of registered chips */
28193323SedOS_SET_DECLARE(ah_chips, struct ath_hal_chip);
29193323Sed
30193323Sed/*
31193323Sed * Check the set of registered chips to see if any recognize
32193323Sed * the device as one they can support.
33193323Sed */
34193323Sedconst char*
35212904Sdimath_hal_probe(uint16_t vendorid, uint16_t devid)
36193323Sed{
37193323Sed	struct ath_hal_chip * const *pchip;
38193323Sed
39193323Sed	OS_SET_FOREACH(pchip, ah_chips) {
40193323Sed		const char *name = (*pchip)->probe(vendorid, devid);
41193323Sed		if (name != AH_NULL)
42193323Sed			return name;
43193323Sed	}
44234353Sdim	return AH_NULL;
45243830Sdim}
46193323Sed
47193323Sed/*
48193323Sed * Attach detects device chip revisions, initializes the hwLayer
49193323Sed * function list, reads EEPROM information,
50193323Sed * selects reset vectors, and performs a short self test.
51193323Sed * Any failures will return an error that should cause a hardware
52243830Sdim * disable.
53193323Sed */
54193323Sedstruct ath_hal*
55193323Sedath_hal_attach(uint16_t devid, HAL_SOFTC sc,
56193323Sed	HAL_BUS_TAG st, HAL_BUS_HANDLE sh, uint16_t *eepromdata, HAL_STATUS *error)
57193323Sed{
58193323Sed	struct ath_hal_chip * const *pchip;
59193323Sed
60193323Sed	OS_SET_FOREACH(pchip, ah_chips) {
61226633Sdim		struct ath_hal_chip *chip = *pchip;
62226633Sdim		struct ath_hal *ah;
63226633Sdim
64226633Sdim		/* XXX don't have vendorid, assume atheros one works */
65226633Sdim		if (chip->probe(ATHEROS_VENDOR_ID, devid) == AH_NULL)
66226633Sdim			continue;
67226633Sdim		ah = chip->attach(devid, sc, st, sh, eepromdata, error);
68226633Sdim		if (ah != AH_NULL) {
69193323Sed			/* copy back private state to public area */
70226633Sdim			ah->ah_devid = AH_PRIVATE(ah)->ah_devid;
71221345Sdim			ah->ah_subvendorid = AH_PRIVATE(ah)->ah_subvendorid;
72221345Sdim			ah->ah_macVersion = AH_PRIVATE(ah)->ah_macVersion;
73221345Sdim			ah->ah_macRev = AH_PRIVATE(ah)->ah_macRev;
74221345Sdim			ah->ah_phyRev = AH_PRIVATE(ah)->ah_phyRev;
75221345Sdim			ah->ah_analog5GhzRev = AH_PRIVATE(ah)->ah_analog5GhzRev;
76221345Sdim			ah->ah_analog2GhzRev = AH_PRIVATE(ah)->ah_analog2GhzRev;
77193323Sed			return ah;
78193323Sed		}
79193323Sed	}
80193323Sed	return AH_NULL;
81193323Sed}
82193323Sed
83193323Sedconst char *
84198090Srdivackyath_hal_mac_name(struct ath_hal *ah)
85234353Sdim{
86234353Sdim	switch (ah->ah_macVersion) {
87234353Sdim	case AR_SREV_VERSION_CRETE:
88234353Sdim	case AR_SREV_VERSION_MAUI_1:
89193323Sed		return "5210";
90193323Sed	case AR_SREV_VERSION_MAUI_2:
91193323Sed	case AR_SREV_VERSION_OAHU:
92193323Sed		return "5211";
93193323Sed	case AR_SREV_VERSION_VENICE:
94193323Sed		return "5212";
95193323Sed	case AR_SREV_VERSION_GRIFFIN:
96193323Sed		return "2413";
97234353Sdim	case AR_SREV_VERSION_CONDOR:
98193323Sed		return "5424";
99193323Sed	case AR_SREV_VERSION_EAGLE:
100193323Sed		return "5413";
101234353Sdim	case AR_SREV_VERSION_COBRA:
102234353Sdim		return "2415";
103234353Sdim	case AR_SREV_2425:
104234353Sdim		return "2425";
105193323Sed	case AR_SREV_2417:
106193323Sed		return "2417";
107193323Sed	case AR_XSREV_VERSION_OWL_PCI:
108234353Sdim		return "5416";
109234353Sdim	case AR_XSREV_VERSION_OWL_PCIE:
110234353Sdim		return "5418";
111193323Sed	case AR_XSREV_VERSION_SOWL:
112193323Sed		return "9160";
113193323Sed	case AR_XSREV_VERSION_MERLIN:
114193323Sed		return "9280";
115193323Sed	case AR_XSREV_VERSION_KITE:
116193323Sed		return "9285";
117193323Sed	}
118193323Sed	return "????";
119193323Sed}
120193323Sed
121193323Sed/*
122193323Sed * Return the mask of available modes based on the hardware capabilities.
123193323Sed */
124193323Sedu_int
125193323Sedath_hal_getwirelessmodes(struct ath_hal*ah)
126193323Sed{
127193323Sed	return ath_hal_getWirelessModes(ah);
128193323Sed}
129234353Sdim
130234353Sdim/* linker set of registered RF backends */
131234353SdimOS_SET_DECLARE(ah_rfs, struct ath_hal_rf);
132234353Sdim
133193323Sed/*
134193323Sed * Check the set of registered RF backends to see if
135193323Sed * any recognize the device as one they can support.
136234353Sdim */
137234353Sdimstruct ath_hal_rf *
138234353Sdimath_hal_rfprobe(struct ath_hal *ah, HAL_STATUS *ecode)
139193323Sed{
140193323Sed	struct ath_hal_rf * const *prf;
141251662Sdim
142251662Sdim	OS_SET_FOREACH(prf, ah_rfs) {
143251662Sdim		struct ath_hal_rf *rf = *prf;
144251662Sdim		if (rf->probe(ah))
145251662Sdim			return rf;
146251662Sdim	}
147251662Sdim	*ecode = HAL_ENOTSUPP;
148251662Sdim	return AH_NULL;
149251662Sdim}
150251662Sdim
151251662Sdimconst char *
152251662Sdimath_hal_rf_name(struct ath_hal *ah)
153251662Sdim{
154251662Sdim	switch (ah->ah_analog5GhzRev & AR_RADIO_SREV_MAJOR) {
155193323Sed	case 0:			/* 5210 */
156251662Sdim		return "5110";	/* NB: made up */
157251662Sdim	case AR_RAD5111_SREV_MAJOR:
158193323Sed	case AR_RAD5111_SREV_PROD:
159193323Sed		return "5111";
160193323Sed	case AR_RAD2111_SREV_MAJOR:
161193323Sed		return "2111";
162193323Sed	case AR_RAD5112_SREV_MAJOR:
163193323Sed	case AR_RAD5112_SREV_2_0:
164193323Sed	case AR_RAD5112_SREV_2_1:
165193323Sed		return "5112";
166193323Sed	case AR_RAD2112_SREV_MAJOR:
167193323Sed	case AR_RAD2112_SREV_2_0:
168193323Sed	case AR_RAD2112_SREV_2_1:
169193323Sed		return "2112";
170198090Srdivacky	case AR_RAD2413_SREV_MAJOR:
171198090Srdivacky		return "2413";
172193323Sed	case AR_RAD5413_SREV_MAJOR:
173193323Sed		return "5413";
174193323Sed	case AR_RAD2316_SREV_MAJOR:
175193323Sed		return "2316";
176193323Sed	case AR_RAD2317_SREV_MAJOR:
177193323Sed		return "2317";
178193323Sed	case AR_RAD5424_SREV_MAJOR:
179193323Sed		return "5424";
180193323Sed
181234353Sdim	case AR_RAD5133_SREV_MAJOR:
182234353Sdim		return "5133";
183234353Sdim	case AR_RAD2133_SREV_MAJOR:
184234353Sdim		return "2133";
185234353Sdim	case AR_RAD5122_SREV_MAJOR:
186234353Sdim		return "5122";
187234353Sdim	case AR_RAD2122_SREV_MAJOR:
188234353Sdim		return "2122";
189234353Sdim	}
190193323Sed	return "????";
191193323Sed}
192193323Sed
193251662Sdim/*
194193323Sed * Poll the register looking for a specific value.
195251662Sdim */
196251662SdimHAL_BOOL
197251662Sdimath_hal_wait(struct ath_hal *ah, u_int reg, uint32_t mask, uint32_t val)
198251662Sdim{
199193323Sed#define	AH_TIMEOUT	1000
200198090Srdivacky	return ath_hal_waitfor(ah, reg, mask, val, AH_TIMEOUT);
201234353Sdim#undef AH_TIMEOUT
202193323Sed}
203193323Sed
204234353SdimHAL_BOOL
205193323Sedath_hal_waitfor(struct ath_hal *ah, u_int reg, uint32_t mask, uint32_t val, uint32_t timeout)
206193323Sed{
207193323Sed	int i;
208234353Sdim
209193323Sed	for (i = 0; i < timeout; i++) {
210193323Sed		if ((OS_REG_READ(ah, reg) & mask) == val)
211234353Sdim			return AH_TRUE;
212193323Sed		OS_DELAY(10);
213193323Sed	}
214234353Sdim	HALDEBUG(ah, HAL_DEBUG_REGIO | HAL_DEBUG_PHYIO,
215193323Sed	    "%s: timeout on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n",
216193323Sed	    __func__, reg, OS_REG_READ(ah, reg), mask, val);
217193323Sed	return AH_FALSE;
218193323Sed}
219193323Sed
220193323Sed/*
221193323Sed * Reverse the bits starting at the low bit for a value of
222193323Sed * bit_count in size
223193323Sed */
224193323Seduint32_t
225193323Sedath_hal_reverseBits(uint32_t val, uint32_t n)
226193323Sed{
227193323Sed	uint32_t retval;
228198090Srdivacky	int i;
229234353Sdim
230193323Sed	for (i = 0, retval = 0; i < n; i++) {
231234353Sdim		retval = (retval << 1) | (val & 1);
232234353Sdim		val >>= 1;
233234353Sdim	}
234234353Sdim	return retval;
235193323Sed}
236251662Sdim
237193323Sed/* 802.11n related timing definitions */
238239462Sdim
239234353Sdim#define	OFDM_PLCP_BITS	22
240239462Sdim#define	HT_L_STF	8
241239462Sdim#define	HT_L_LTF	8
242239462Sdim#define	HT_L_SIG	4
243251662Sdim#define	HT_SIG		8
244193323Sed#define	HT_STF		4
245193323Sed#define	HT_LTF(n)	((n) * 4)
246198090Srdivacky
247193323Sed#define	HT_RC_2_MCS(_rc)	((_rc) & 0xf)
248193323Sed#define	HT_RC_2_STREAMS(_rc)	((((_rc) & 0x78) >> 3) + 1)
249193323Sed#define	IS_HT_RATE(_rc)		( (_rc) & IEEE80211_RATE_MCS)
250193323Sed
251193323Sed/*
252193323Sed * Calculate the duration of a packet whether it is 11n or legacy.
253193323Sed */
254193323Seduint32_t
255193323Sedath_hal_pkt_txtime(struct ath_hal *ah, const HAL_RATE_TABLE *rates, uint32_t frameLen,
256193323Sed    uint16_t rateix, HAL_BOOL isht40, HAL_BOOL shortPreamble)
257193323Sed{
258193323Sed	uint8_t rc;
259193323Sed	int numStreams;
260193323Sed
261193323Sed	rc = rates->info[rateix].rateCode;
262221345Sdim
263221345Sdim	/* Legacy rate? Return the old way */
264198090Srdivacky	if (! IS_HT_RATE(rc))
265193323Sed		return ath_hal_computetxtime(ah, rates, frameLen, rateix, shortPreamble);
266198090Srdivacky
267193323Sed	/* 11n frame - extract out the number of spatial streams */
268198090Srdivacky	numStreams = HT_RC_2_STREAMS(rc);
269198090Srdivacky	KASSERT(numStreams == 1 || numStreams == 2, ("number of spatial streams needs to be 1 or 2: MCS rate 0x%x!", rateix));
270193323Sed
271193323Sed	return ath_computedur_ht(frameLen, rc, numStreams, isht40, shortPreamble);
272198090Srdivacky}
273193323Sed
274193323Sed/*
275193323Sed * Calculate the transmit duration of an 11n frame.
276193323Sed * This only works for MCS0->MCS15.
277193323Sed */
278193323Seduint32_t
279193323Sedath_computedur_ht(uint32_t frameLen, uint16_t rate, int streams, HAL_BOOL isht40,
280193323Sed    HAL_BOOL isShortGI)
281193323Sed{
282193323Sed	static const uint16_t ht20_bps[16] = {
283193323Sed	    26, 52, 78, 104, 156, 208, 234, 260,
284193323Sed	    52, 104, 156, 208, 312, 416, 468, 520
285204642Srdivacky	};
286193323Sed	static const uint16_t ht40_bps[16] = {
287193323Sed	    54, 108, 162, 216, 324, 432, 486, 540,
288193323Sed	    108, 216, 324, 432, 648, 864, 972, 1080,
289193323Sed	};
290193323Sed	uint32_t bitsPerSymbol, numBits, numSymbols, txTime;
291193323Sed
292204642Srdivacky	KASSERT(rate & IEEE80211_RATE_MCS, ("not mcs %d", rate));
293193323Sed	KASSERT((rate &~ IEEE80211_RATE_MCS) < 16, ("bad mcs 0x%x", rate));
294193323Sed
295193323Sed	if (isht40)
296193323Sed		bitsPerSymbol = ht40_bps[rate & 0xf];
297193323Sed	else
298193323Sed		bitsPerSymbol = ht20_bps[rate & 0xf];
299193323Sed	numBits = OFDM_PLCP_BITS + (frameLen << 3);
300193323Sed	numSymbols = howmany(numBits, bitsPerSymbol);
301193323Sed	if (isShortGI)
302193323Sed		txTime = ((numSymbols * 18) + 4) / 5;   /* 3.6us */
303193323Sed	else
304193323Sed		txTime = numSymbols * 4;                /* 4us */
305193323Sed	return txTime + HT_L_STF + HT_L_LTF +
306193323Sed	    HT_L_SIG + HT_SIG + HT_STF + HT_LTF(streams);
307193323Sed}
308193323Sed
309193323Sed/*
310193323Sed * Compute the time to transmit a frame of length frameLen bytes
311193323Sed * using the specified rate, phy, and short preamble setting.
312193323Sed */
313193323Seduint16_t
314193323Sedath_hal_computetxtime(struct ath_hal *ah,
315193323Sed	const HAL_RATE_TABLE *rates, uint32_t frameLen, uint16_t rateix,
316193323Sed	HAL_BOOL shortPreamble)
317193323Sed{
318193323Sed	uint32_t bitsPerSymbol, numBits, numSymbols, phyTime, txTime;
319193323Sed	uint32_t kbps;
320193323Sed
321193323Sed	kbps = rates->info[rateix].rateKbps;
322193323Sed	/*
323193323Sed	 * index can be invalid duting dynamic Turbo transitions.
324193323Sed	 * XXX
325193323Sed	 */
326193323Sed	if (kbps == 0)
327193323Sed		return 0;
328193323Sed	switch (rates->info[rateix].phy) {
329193323Sed	case IEEE80211_T_CCK:
330193323Sed		phyTime		= CCK_PREAMBLE_BITS + CCK_PLCP_BITS;
331193323Sed		if (shortPreamble && rates->info[rateix].shortPreamble)
332193323Sed			phyTime >>= 1;
333193323Sed		numBits		= frameLen << 3;
334193323Sed		txTime		= CCK_SIFS_TIME + phyTime
335251662Sdim				+ ((numBits * 1000)/kbps);
336251662Sdim		break;
337251662Sdim	case IEEE80211_T_OFDM:
338251662Sdim		bitsPerSymbol	= (kbps * OFDM_SYMBOL_TIME) / 1000;
339251662Sdim		HALASSERT(bitsPerSymbol != 0);
340193323Sed
341251662Sdim		numBits		= OFDM_PLCP_BITS + (frameLen << 3);
342251662Sdim		numSymbols	= howmany(numBits, bitsPerSymbol);
343251662Sdim		txTime		= OFDM_SIFS_TIME
344251662Sdim				+ OFDM_PREAMBLE_TIME
345251662Sdim				+ (numSymbols * OFDM_SYMBOL_TIME);
346193323Sed		break;
347221345Sdim	case IEEE80211_T_OFDM_HALF:
348221345Sdim		bitsPerSymbol	= (kbps * OFDM_HALF_SYMBOL_TIME) / 1000;
349221345Sdim		HALASSERT(bitsPerSymbol != 0);
350221345Sdim
351221345Sdim		numBits		= OFDM_HALF_PLCP_BITS + (frameLen << 3);
352221345Sdim		numSymbols	= howmany(numBits, bitsPerSymbol);
353263508Sdim		txTime		= OFDM_HALF_SIFS_TIME
354234353Sdim				+ OFDM_HALF_PREAMBLE_TIME
355234353Sdim				+ (numSymbols * OFDM_HALF_SYMBOL_TIME);
356221345Sdim		break;
357221345Sdim	case IEEE80211_T_OFDM_QUARTER:
358221345Sdim		bitsPerSymbol	= (kbps * OFDM_QUARTER_SYMBOL_TIME) / 1000;
359221345Sdim		HALASSERT(bitsPerSymbol != 0);
360221345Sdim
361221345Sdim		numBits		= OFDM_QUARTER_PLCP_BITS + (frameLen << 3);
362221345Sdim		numSymbols	= howmany(numBits, bitsPerSymbol);
363221345Sdim		txTime		= OFDM_QUARTER_SIFS_TIME
364221345Sdim				+ OFDM_QUARTER_PREAMBLE_TIME
365221345Sdim				+ (numSymbols * OFDM_QUARTER_SYMBOL_TIME);
366221345Sdim		break;
367221345Sdim	case IEEE80211_T_TURBO:
368221345Sdim		bitsPerSymbol	= (kbps * TURBO_SYMBOL_TIME) / 1000;
369234353Sdim		HALASSERT(bitsPerSymbol != 0);
370221345Sdim
371221345Sdim		numBits		= TURBO_PLCP_BITS + (frameLen << 3);
372221345Sdim		numSymbols	= howmany(numBits, bitsPerSymbol);
373221345Sdim		txTime		= TURBO_SIFS_TIME
374221345Sdim				+ TURBO_PREAMBLE_TIME
375221345Sdim				+ (numSymbols * TURBO_SYMBOL_TIME);
376221345Sdim		break;
377221345Sdim	default:
378221345Sdim		HALDEBUG(ah, HAL_DEBUG_PHYIO,
379221345Sdim		    "%s: unknown phy %u (rate ix %u)\n",
380221345Sdim		    __func__, rates->info[rateix].phy, rateix);
381221345Sdim		txTime = 0;
382221345Sdim		break;
383221345Sdim	}
384221345Sdim	return txTime;
385221345Sdim}
386221345Sdim
387221345Sdimtypedef enum {
388221345Sdim	WIRELESS_MODE_11a   = 0,
389221345Sdim	WIRELESS_MODE_TURBO = 1,
390221345Sdim	WIRELESS_MODE_11b   = 2,
391221345Sdim	WIRELESS_MODE_11g   = 3,
392221345Sdim	WIRELESS_MODE_108g  = 4,
393221345Sdim
394221345Sdim	WIRELESS_MODE_MAX
395221345Sdim} WIRELESS_MODE;
396221345Sdim
397221345Sdimstatic WIRELESS_MODE
398221345Sdimath_hal_chan2wmode(struct ath_hal *ah, const struct ieee80211_channel *chan)
399221345Sdim{
400221345Sdim	if (IEEE80211_IS_CHAN_B(chan))
401221345Sdim		return WIRELESS_MODE_11b;
402221345Sdim	if (IEEE80211_IS_CHAN_G(chan))
403221345Sdim		return WIRELESS_MODE_11g;
404221345Sdim	if (IEEE80211_IS_CHAN_108G(chan))
405221345Sdim		return WIRELESS_MODE_108g;
406221345Sdim	if (IEEE80211_IS_CHAN_TURBO(chan))
407221345Sdim		return WIRELESS_MODE_TURBO;
408221345Sdim	return WIRELESS_MODE_11a;
409221345Sdim}
410221345Sdim
411221345Sdim/*
412221345Sdim * Convert between microseconds and core system clocks.
413221345Sdim */
414221345Sdim                                     /* 11a Turbo  11b  11g  108g */
415221345Sdimstatic const uint8_t CLOCK_RATE[]  = { 40,  80,   22,  44,   88  };
416221345Sdim
417221345Sdimu_int
418221345Sdimath_hal_mac_clks(struct ath_hal *ah, u_int usecs)
419221345Sdim{
420221345Sdim	const struct ieee80211_channel *c = AH_PRIVATE(ah)->ah_curchan;
421221345Sdim	u_int clks;
422221345Sdim
423221345Sdim	/* NB: ah_curchan may be null when called attach time */
424221345Sdim	if (c != AH_NULL) {
425221345Sdim		clks = usecs * CLOCK_RATE[ath_hal_chan2wmode(ah, c)];
426221345Sdim		if (IEEE80211_IS_CHAN_HT40(c))
427221345Sdim			clks <<= 1;
428221345Sdim	} else
429221345Sdim		clks = usecs * CLOCK_RATE[WIRELESS_MODE_11b];
430221345Sdim	return clks;
431221345Sdim}
432221345Sdim
433221345Sdimu_int
434221345Sdimath_hal_mac_usec(struct ath_hal *ah, u_int clks)
435221345Sdim{
436221345Sdim	const struct ieee80211_channel *c = AH_PRIVATE(ah)->ah_curchan;
437221345Sdim	u_int usec;
438221345Sdim
439221345Sdim	/* NB: ah_curchan may be null when called attach time */
440221345Sdim	if (c != AH_NULL) {
441221345Sdim		usec = clks / CLOCK_RATE[ath_hal_chan2wmode(ah, c)];
442221345Sdim		if (IEEE80211_IS_CHAN_HT40(c))
443221345Sdim			usec >>= 1;
444221345Sdim	} else
445221345Sdim		usec = clks / CLOCK_RATE[WIRELESS_MODE_11b];
446234353Sdim	return usec;
447234353Sdim}
448221345Sdim
449221345Sdim/*
450221345Sdim * Setup a h/w rate table's reverse lookup table and
451221345Sdim * fill in ack durations.  This routine is called for
452221345Sdim * each rate table returned through the ah_getRateTable
453221345Sdim * method.  The reverse lookup tables are assumed to be
454221345Sdim * initialized to zero (or at least the first entry).
455221345Sdim * We use this as a key that indicates whether or not
456221345Sdim * we've previously setup the reverse lookup table.
457221345Sdim *
458221345Sdim * XXX not reentrant, but shouldn't matter
459221345Sdim */
460221345Sdimvoid
461221345Sdimath_hal_setupratetable(struct ath_hal *ah, HAL_RATE_TABLE *rt)
462221345Sdim{
463234353Sdim#define	N(a)	(sizeof(a)/sizeof(a[0]))
464234353Sdim	int i;
465221345Sdim
466221345Sdim	if (rt->rateCodeToIndex[0] != 0)	/* already setup */
467221345Sdim		return;
468193323Sed	for (i = 0; i < N(rt->rateCodeToIndex); i++)
469193323Sed		rt->rateCodeToIndex[i] = (uint8_t) -1;
470193323Sed	for (i = 0; i < rt->rateCount; i++) {
471193323Sed		uint8_t code = rt->info[i].rateCode;
472193323Sed		uint8_t cix = rt->info[i].controlRate;
473193323Sed
474193323Sed		HALASSERT(code < N(rt->rateCodeToIndex));
475193323Sed		rt->rateCodeToIndex[code] = i;
476193323Sed		HALASSERT((code | rt->info[i].shortPreamble) <
477193323Sed		    N(rt->rateCodeToIndex));
478193323Sed		rt->rateCodeToIndex[code | rt->info[i].shortPreamble] = i;
479193323Sed		/*
480193323Sed		 * XXX for 11g the control rate to use for 5.5 and 11 Mb/s
481193323Sed		 *     depends on whether they are marked as basic rates;
482193323Sed		 *     the static tables are setup with an 11b-compatible
483193323Sed		 *     2Mb/s rate which will work but is suboptimal
484193323Sed		 */
485193323Sed		rt->info[i].lpAckDuration = ath_hal_computetxtime(ah, rt,
486193323Sed			WLAN_CTRL_FRAME_SIZE, cix, AH_FALSE);
487193323Sed		rt->info[i].spAckDuration = ath_hal_computetxtime(ah, rt,
488193323Sed			WLAN_CTRL_FRAME_SIZE, cix, AH_TRUE);
489193323Sed	}
490193323Sed#undef N
491193323Sed}
492193323Sed
493193323SedHAL_STATUS
494193323Sedath_hal_getcapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type,
495193323Sed	uint32_t capability, uint32_t *result)
496193323Sed{
497193323Sed	const HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps;
498193323Sed
499193323Sed	switch (type) {
500193323Sed	case HAL_CAP_REG_DMN:		/* regulatory domain */
501193323Sed		*result = AH_PRIVATE(ah)->ah_currentRD;
502193323Sed		return HAL_OK;
503249423Sdim	case HAL_CAP_CIPHER:		/* cipher handled in hardware */
504193323Sed	case HAL_CAP_TKIP_MIC:		/* handle TKIP MIC in hardware */
505193323Sed		return HAL_ENOTSUPP;
506193323Sed	case HAL_CAP_TKIP_SPLIT:	/* hardware TKIP uses split keys */
507193323Sed		return HAL_ENOTSUPP;
508193323Sed	case HAL_CAP_PHYCOUNTERS:	/* hardware PHY error counters */
509193323Sed		return pCap->halHwPhyCounterSupport ? HAL_OK : HAL_ENXIO;
510193323Sed	case HAL_CAP_WME_TKIPMIC:   /* hardware can do TKIP MIC when WMM is turned on */
511193323Sed		return HAL_ENOTSUPP;
512193323Sed	case HAL_CAP_DIVERSITY:		/* hardware supports fast diversity */
513193323Sed		return HAL_ENOTSUPP;
514193323Sed	case HAL_CAP_KEYCACHE_SIZE:	/* hardware key cache size */
515193323Sed		*result =  pCap->halKeyCacheSize;
516193323Sed		return HAL_OK;
517193323Sed	case HAL_CAP_NUM_TXQUEUES:	/* number of hardware tx queues */
518193323Sed		*result = pCap->halTotalQueues;
519193323Sed		return HAL_OK;
520193323Sed	case HAL_CAP_VEOL:		/* hardware supports virtual EOL */
521193323Sed		return pCap->halVEOLSupport ? HAL_OK : HAL_ENOTSUPP;
522193323Sed	case HAL_CAP_PSPOLL:		/* hardware PS-Poll support works */
523193323Sed		return pCap->halPSPollBroken ? HAL_ENOTSUPP : HAL_OK;
524193323Sed	case HAL_CAP_COMPRESSION:
525193323Sed		return pCap->halCompressSupport ? HAL_OK : HAL_ENOTSUPP;
526193323Sed	case HAL_CAP_BURST:
527193323Sed		return pCap->halBurstSupport ? HAL_OK : HAL_ENOTSUPP;
528193323Sed	case HAL_CAP_FASTFRAME:
529193323Sed		return pCap->halFastFramesSupport ? HAL_OK : HAL_ENOTSUPP;
530193323Sed	case HAL_CAP_DIAG:		/* hardware diagnostic support */
531221345Sdim		*result = AH_PRIVATE(ah)->ah_diagreg;
532221345Sdim		return HAL_OK;
533221345Sdim	case HAL_CAP_TXPOW:		/* global tx power limit  */
534221345Sdim		switch (capability) {
535221345Sdim		case 0:			/* facility is supported */
536221345Sdim			return HAL_OK;
537221345Sdim		case 1:			/* current limit */
538221345Sdim			*result = AH_PRIVATE(ah)->ah_powerLimit;
539221345Sdim			return HAL_OK;
540221345Sdim		case 2:			/* current max tx power */
541193323Sed			*result = AH_PRIVATE(ah)->ah_maxPowerLevel;
542193323Sed			return HAL_OK;
543193323Sed		case 3:			/* scale factor */
544193323Sed			*result = AH_PRIVATE(ah)->ah_tpScale;
545193323Sed			return HAL_OK;
546193323Sed		}
547193323Sed		return HAL_ENOTSUPP;
548193323Sed	case HAL_CAP_BSSIDMASK:		/* hardware supports bssid mask */
549193323Sed		return pCap->halBssIdMaskSupport ? HAL_OK : HAL_ENOTSUPP;
550193323Sed	case HAL_CAP_MCAST_KEYSRCH:	/* multicast frame keycache search */
551193323Sed		return pCap->halMcastKeySrchSupport ? HAL_OK : HAL_ENOTSUPP;
552193323Sed	case HAL_CAP_TSF_ADJUST:	/* hardware has beacon tsf adjust */
553193323Sed		return HAL_ENOTSUPP;
554193323Sed	case HAL_CAP_RFSILENT:		/* rfsilent support  */
555193323Sed		switch (capability) {
556193323Sed		case 0:			/* facility is supported */
557221345Sdim			return pCap->halRfSilentSupport ? HAL_OK : HAL_ENOTSUPP;
558221345Sdim		case 1:			/* current setting */
559193323Sed			return AH_PRIVATE(ah)->ah_rfkillEnabled ?
560193323Sed				HAL_OK : HAL_ENOTSUPP;
561193323Sed		case 2:			/* rfsilent config */
562193323Sed			*result = AH_PRIVATE(ah)->ah_rfsilent;
563193323Sed			return HAL_OK;
564221345Sdim		}
565221345Sdim		return HAL_ENOTSUPP;
566221345Sdim	case HAL_CAP_11D:
567221345Sdim		return HAL_OK;
568221345Sdim	case HAL_CAP_RXORN_FATAL:	/* HAL_INT_RXORN treated as fatal  */
569221345Sdim		return AH_PRIVATE(ah)->ah_rxornIsFatal ? HAL_OK : HAL_ENOTSUPP;
570221345Sdim	case HAL_CAP_HT:
571221345Sdim		return pCap->halHTSupport ? HAL_OK : HAL_ENOTSUPP;
572221345Sdim	case HAL_CAP_TX_CHAINMASK:	/* mask of TX chains supported */
573221345Sdim		*result = pCap->halTxChainMask;
574221345Sdim		return HAL_OK;
575221345Sdim	case HAL_CAP_RX_CHAINMASK:	/* mask of RX chains supported */
576221345Sdim		*result = pCap->halRxChainMask;
577221345Sdim		return HAL_OK;
578221345Sdim	case HAL_CAP_RXTSTAMP_PREC:	/* rx desc tstamp precision (bits) */
579193323Sed		*result = pCap->halTstampPrecision;
580193323Sed		return HAL_OK;
581193323Sed	case HAL_CAP_INTRMASK:		/* mask of supported interrupts */
582193323Sed		*result = pCap->halIntrMask;
583193323Sed		return HAL_OK;
584193323Sed	case HAL_CAP_BSSIDMATCH:	/* hardware has disable bssid match */
585193323Sed		return pCap->halBssidMatchSupport ? HAL_OK : HAL_ENOTSUPP;
586198090Srdivacky	case HAL_CAP_STREAMS:		/* number of 11n spatial streams */
587193323Sed		switch (capability) {
588193323Sed		case 0:			/* TX */
589193323Sed			*result = pCap->halTxStreams;
590193323Sed			return HAL_OK;
591193323Sed		case 1:			/* RX */
592193323Sed			*result = pCap->halRxStreams;
593193323Sed			return HAL_OK;
594193323Sed		default:
595193323Sed			return HAL_ENOTSUPP;
596193323Sed		}
597193323Sed	case HAP_CAP_SPLIT_4KB_TRANS:	/* hardware handles descriptors straddling 4k page boundary */
598193323Sed		return pCap->hal4kbSplitTransSupport ? HAL_OK : HAL_ENOTSUPP;
599193323Sed	default:
600193323Sed		return HAL_EINVAL;
601193323Sed	}
602193323Sed}
603193323Sed
604193323SedHAL_BOOL
605193323Sedath_hal_setcapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type,
606193323Sed	uint32_t capability, uint32_t setting, HAL_STATUS *status)
607193323Sed{
608193323Sed
609193323Sed	switch (type) {
610193323Sed	case HAL_CAP_TXPOW:
611193323Sed		switch (capability) {
612193323Sed		case 3:
613193323Sed			if (setting <= HAL_TP_SCALE_MIN) {
614193323Sed				AH_PRIVATE(ah)->ah_tpScale = setting;
615193323Sed				return AH_TRUE;
616193323Sed			}
617193323Sed			break;
618193323Sed		}
619193323Sed		break;
620193323Sed	case HAL_CAP_RFSILENT:		/* rfsilent support  */
621193323Sed		/*
622193323Sed		 * NB: allow even if halRfSilentSupport is false
623193323Sed		 *     in case the EEPROM is misprogrammed.
624193323Sed		 */
625193323Sed		switch (capability) {
626204642Srdivacky		case 1:			/* current setting */
627193323Sed			AH_PRIVATE(ah)->ah_rfkillEnabled = (setting != 0);
628193323Sed			return AH_TRUE;
629193323Sed		case 2:			/* rfsilent config */
630193323Sed			/* XXX better done per-chip for validation? */
631193323Sed			AH_PRIVATE(ah)->ah_rfsilent = setting;
632221345Sdim			return AH_TRUE;
633212904Sdim		}
634212904Sdim		break;
635221345Sdim	case HAL_CAP_REG_DMN:		/* regulatory domain */
636221345Sdim		AH_PRIVATE(ah)->ah_currentRD = setting;
637212904Sdim		return AH_TRUE;
638212904Sdim	case HAL_CAP_RXORN_FATAL:	/* HAL_INT_RXORN treated as fatal  */
639193323Sed		AH_PRIVATE(ah)->ah_rxornIsFatal = setting;
640193323Sed		return AH_TRUE;
641193323Sed	default:
642193323Sed		break;
643193323Sed	}
644212904Sdim	if (status)
645193323Sed		*status = HAL_EINVAL;
646212904Sdim	return AH_FALSE;
647193323Sed}
648193323Sed
649221345Sdim/*
650221345Sdim * Common support for getDiagState method.
651221345Sdim */
652221345Sdim
653221345Sdimstatic u_int
654193323Sedath_hal_getregdump(struct ath_hal *ah, const HAL_REGRANGE *regs,
655198090Srdivacky	void *dstbuf, int space)
656198090Srdivacky{
657193323Sed	uint32_t *dp = dstbuf;
658193323Sed	int i;
659193323Sed
660193323Sed	for (i = 0; space >= 2*sizeof(uint32_t); i++) {
661193323Sed		u_int r = regs[i].start;
662249423Sdim		u_int e = regs[i].end;
663212904Sdim		*dp++ = (r<<16) | e;
664221345Sdim		space -= sizeof(uint32_t);
665193323Sed		do {
666193323Sed			*dp++ = OS_REG_READ(ah, r);
667193323Sed			r += sizeof(uint32_t);
668198090Srdivacky			space -= sizeof(uint32_t);
669193323Sed		} while (r <= e && space >= sizeof(uint32_t));
670193323Sed	}
671193323Sed	return (char *) dp - (char *) dstbuf;
672193323Sed}
673193323Sed
674193323Sedstatic void
675193323Sedath_hal_setregs(struct ath_hal *ah, const HAL_REGWRITE *regs, int space)
676212904Sdim{
677212904Sdim	while (space >= sizeof(HAL_REGWRITE)) {
678193323Sed		OS_REG_WRITE(ah, regs->addr, regs->value);
679193323Sed		regs++, space -= sizeof(HAL_REGWRITE);
680193323Sed	}
681193323Sed}
682193323Sed
683193323SedHAL_BOOL
684193323Sedath_hal_getdiagstate(struct ath_hal *ah, int request,
685193323Sed	const void *args, uint32_t argsize,
686193323Sed	void **result, uint32_t *resultsize)
687193323Sed{
688193323Sed	switch (request) {
689193323Sed	case HAL_DIAG_REVS:
690193323Sed		*result = &AH_PRIVATE(ah)->ah_devid;
691193323Sed		*resultsize = sizeof(HAL_REVS);
692193323Sed		return AH_TRUE;
693199481Srdivacky	case HAL_DIAG_REGS:
694199481Srdivacky		*resultsize = ath_hal_getregdump(ah, args, *result,*resultsize);
695193323Sed		return AH_TRUE;
696193323Sed	case HAL_DIAG_SETREGS:
697193323Sed		ath_hal_setregs(ah, args, argsize);
698193323Sed		*resultsize = 0;
699193323Sed		return AH_TRUE;
700193323Sed	case HAL_DIAG_FATALERR:
701198090Srdivacky		*result = &AH_PRIVATE(ah)->ah_fatalState[0];
702193323Sed		*resultsize = sizeof(AH_PRIVATE(ah)->ah_fatalState);
703193323Sed		return AH_TRUE;
704193323Sed	case HAL_DIAG_EEREAD:
705193323Sed		if (argsize != sizeof(uint16_t))
706193323Sed			return AH_FALSE;
707193323Sed		if (!ath_hal_eepromRead(ah, *(const uint16_t *)args, *result))
708193323Sed			return AH_FALSE;
709193323Sed		*resultsize = sizeof(uint16_t);
710193323Sed		return AH_TRUE;
711193323Sed#ifdef AH_PRIVATE_DIAG
712193323Sed	case HAL_DIAG_SETKEY: {
713221345Sdim		const HAL_DIAG_KEYVAL *dk;
714221345Sdim
715221345Sdim		if (argsize != sizeof(HAL_DIAG_KEYVAL))
716221345Sdim			return AH_FALSE;
717193323Sed		dk = (const HAL_DIAG_KEYVAL *)args;
718193323Sed		return ah->ah_setKeyCacheEntry(ah, dk->dk_keyix,
719193323Sed			&dk->dk_keyval, dk->dk_mac, dk->dk_xor);
720193323Sed	}
721193323Sed	case HAL_DIAG_RESETKEY:
722221345Sdim		if (argsize != sizeof(uint16_t))
723221345Sdim			return AH_FALSE;
724221345Sdim		return ah->ah_resetKeyCacheEntry(ah, *(const uint16_t *)args);
725221345Sdim#ifdef AH_SUPPORT_WRITE_EEPROM
726193323Sed	case HAL_DIAG_EEWRITE: {
727193323Sed		const HAL_DIAG_EEVAL *ee;
728193323Sed		if (argsize != sizeof(HAL_DIAG_EEVAL))
729193323Sed			return AH_FALSE;
730193323Sed		ee = (const HAL_DIAG_EEVAL *)args;
731193323Sed		return ath_hal_eepromWrite(ah, ee->ee_off, ee->ee_data);
732199481Srdivacky	}
733199481Srdivacky#endif /* AH_SUPPORT_WRITE_EEPROM */
734193323Sed#endif /* AH_PRIVATE_DIAG */
735221345Sdim	case HAL_DIAG_11NCOMPAT:
736193323Sed		if (argsize == 0) {
737193323Sed			*resultsize = sizeof(uint32_t);
738193323Sed			*((uint32_t *)(*result)) =
739193323Sed				AH_PRIVATE(ah)->ah_11nCompat;
740193323Sed		} else if (argsize == sizeof(uint32_t)) {
741193323Sed			AH_PRIVATE(ah)->ah_11nCompat = *(const uint32_t *)args;
742193323Sed		} else
743193323Sed			return AH_FALSE;
744193323Sed		return AH_TRUE;
745194612Sed	}
746193323Sed	return AH_FALSE;
747198090Srdivacky}
748193323Sed
749193323Sed/*
750193323Sed * Set the properties of the tx queue with the parameters
751193323Sed * from qInfo.
752193323Sed */
753193323SedHAL_BOOL
754193323Sedath_hal_setTxQProps(struct ath_hal *ah,
755193323Sed	HAL_TX_QUEUE_INFO *qi, const HAL_TXQ_INFO *qInfo)
756193323Sed{
757193323Sed	uint32_t cw;
758193323Sed
759193323Sed	if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) {
760193323Sed		HALDEBUG(ah, HAL_DEBUG_TXQUEUE,
761221345Sdim		    "%s: inactive queue\n", __func__);
762221345Sdim		return AH_FALSE;
763221345Sdim	}
764193323Sed	/* XXX validate parameters */
765193323Sed	qi->tqi_ver = qInfo->tqi_ver;
766193323Sed	qi->tqi_subtype = qInfo->tqi_subtype;
767193323Sed	qi->tqi_qflags = qInfo->tqi_qflags;
768193323Sed	qi->tqi_priority = qInfo->tqi_priority;
769193323Sed	if (qInfo->tqi_aifs != HAL_TXQ_USEDEFAULT)
770193323Sed		qi->tqi_aifs = AH_MIN(qInfo->tqi_aifs, 255);
771193323Sed	else
772193323Sed		qi->tqi_aifs = INIT_AIFS;
773193323Sed	if (qInfo->tqi_cwmin != HAL_TXQ_USEDEFAULT) {
774193323Sed		cw = AH_MIN(qInfo->tqi_cwmin, 1024);
775193323Sed		/* make sure that the CWmin is of the form (2^n - 1) */
776198090Srdivacky		qi->tqi_cwmin = 1;
777193323Sed		while (qi->tqi_cwmin < cw)
778193323Sed			qi->tqi_cwmin = (qi->tqi_cwmin << 1) | 1;
779193323Sed	} else
780193323Sed		qi->tqi_cwmin = qInfo->tqi_cwmin;
781193323Sed	if (qInfo->tqi_cwmax != HAL_TXQ_USEDEFAULT) {
782193323Sed		cw = AH_MIN(qInfo->tqi_cwmax, 1024);
783193323Sed		/* make sure that the CWmax is of the form (2^n - 1) */
784193323Sed		qi->tqi_cwmax = 1;
785221345Sdim		while (qi->tqi_cwmax < cw)
786221345Sdim			qi->tqi_cwmax = (qi->tqi_cwmax << 1) | 1;
787221345Sdim	} else
788193323Sed		qi->tqi_cwmax = INIT_CWMAX;
789193323Sed	/* Set retry limit values */
790193323Sed	if (qInfo->tqi_shretry != 0)
791193323Sed		qi->tqi_shretry = AH_MIN(qInfo->tqi_shretry, 15);
792193323Sed	else
793193323Sed		qi->tqi_shretry = INIT_SH_RETRY;
794193323Sed	if (qInfo->tqi_lgretry != 0)
795193323Sed		qi->tqi_lgretry = AH_MIN(qInfo->tqi_lgretry, 15);
796193323Sed	else
797193323Sed		qi->tqi_lgretry = INIT_LG_RETRY;
798193323Sed	qi->tqi_cbrPeriod = qInfo->tqi_cbrPeriod;
799193323Sed	qi->tqi_cbrOverflowLimit = qInfo->tqi_cbrOverflowLimit;
800193323Sed	qi->tqi_burstTime = qInfo->tqi_burstTime;
801198090Srdivacky	qi->tqi_readyTime = qInfo->tqi_readyTime;
802193323Sed
803193323Sed	switch (qInfo->tqi_subtype) {
804193323Sed	case HAL_WME_UPSD:
805193323Sed		if (qi->tqi_type == HAL_TX_QUEUE_DATA)
806221345Sdim			qi->tqi_intFlags = HAL_TXQ_USE_LOCKOUT_BKOFF_DIS;
807221345Sdim		break;
808221345Sdim	default:
809193323Sed		break;		/* NB: silence compiler */
810193323Sed	}
811193323Sed	return AH_TRUE;
812193323Sed}
813193323Sed
814193323SedHAL_BOOL
815193323Sedath_hal_getTxQProps(struct ath_hal *ah,
816193323Sed	HAL_TXQ_INFO *qInfo, const HAL_TX_QUEUE_INFO *qi)
817193323Sed{
818193323Sed	if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) {
819193323Sed		HALDEBUG(ah, HAL_DEBUG_TXQUEUE,
820193323Sed		    "%s: inactive queue\n", __func__);
821193323Sed		return AH_FALSE;
822193323Sed	}
823198090Srdivacky
824193323Sed	qInfo->tqi_qflags = qi->tqi_qflags;
825193323Sed	qInfo->tqi_ver = qi->tqi_ver;
826193323Sed	qInfo->tqi_subtype = qi->tqi_subtype;
827193323Sed	qInfo->tqi_qflags = qi->tqi_qflags;
828221345Sdim	qInfo->tqi_priority = qi->tqi_priority;
829221345Sdim	qInfo->tqi_aifs = qi->tqi_aifs;
830221345Sdim	qInfo->tqi_cwmin = qi->tqi_cwmin;
831193323Sed	qInfo->tqi_cwmax = qi->tqi_cwmax;
832193323Sed	qInfo->tqi_shretry = qi->tqi_shretry;
833193323Sed	qInfo->tqi_lgretry = qi->tqi_lgretry;
834193323Sed	qInfo->tqi_cbrPeriod = qi->tqi_cbrPeriod;
835193323Sed	qInfo->tqi_cbrOverflowLimit = qi->tqi_cbrOverflowLimit;
836193323Sed	qInfo->tqi_burstTime = qi->tqi_burstTime;
837193323Sed	qInfo->tqi_readyTime = qi->tqi_readyTime;
838226633Sdim	return AH_TRUE;
839226633Sdim}
840226633Sdim
841226633Sdim                                     /* 11a Turbo  11b  11g  108g */
842226633Sdimstatic const int16_t NOISE_FLOOR[] = { -96, -93,  -98, -96,  -93 };
843226633Sdim
844226633Sdim/*
845226633Sdim * Read the current channel noise floor and return.
846226633Sdim * If nf cal hasn't finished, channel noise floor should be 0
847226633Sdim * and we return a nominal value based on band and frequency.
848226633Sdim *
849226633Sdim * NB: This is a private routine used by per-chip code to
850226633Sdim *     implement the ah_getChanNoise method.
851226633Sdim */
852226633Sdimint16_t
853226633Sdimath_hal_getChanNoise(struct ath_hal *ah, const struct ieee80211_channel *chan)
854226633Sdim{
855226633Sdim	HAL_CHANNEL_INTERNAL *ichan;
856226633Sdim
857226633Sdim	ichan = ath_hal_checkchannel(ah, chan);
858226633Sdim	if (ichan == AH_NULL) {
859226633Sdim		HALDEBUG(ah, HAL_DEBUG_NFCAL,
860193323Sed		    "%s: invalid channel %u/0x%x; no mapping\n",
861193323Sed		    __func__, chan->ic_freq, chan->ic_flags);
862193323Sed		return 0;
863193323Sed	}
864193323Sed	if (ichan->rawNoiseFloor == 0) {
865193323Sed		WIRELESS_MODE mode = ath_hal_chan2wmode(ah, chan);
866198090Srdivacky
867193323Sed		HALASSERT(mode < WIRELESS_MODE_MAX);
868193323Sed		return NOISE_FLOOR[mode] + ath_hal_getNfAdjust(ah, ichan);
869193323Sed	} else
870193323Sed		return ichan->rawNoiseFloor + ichan->noiseFloorAdjust;
871221345Sdim}
872221345Sdim
873221345Sdim/*
874193323Sed * Process all valid raw noise floors into the dBm noise floor values.
875193323Sed * Though our device has no reference for a dBm noise floor, we perform
876193323Sed * a relative minimization of NF's based on the lowest NF found across a
877193323Sed * channel scan.
878193323Sed */
879193323Sedvoid
880193323Sedath_hal_process_noisefloor(struct ath_hal *ah)
881193323Sed{
882193323Sed	HAL_CHANNEL_INTERNAL *c;
883193323Sed	int16_t correct2, correct5;
884193323Sed	int16_t lowest2, lowest5;
885193323Sed	int i;
886193323Sed
887198090Srdivacky	/*
888193323Sed	 * Find the lowest 2GHz and 5GHz noise floor values after adjusting
889193323Sed	 * for statistically recorded NF/channel deviation.
890193323Sed	 */
891193323Sed	correct2 = lowest2 = 0;
892221345Sdim	correct5 = lowest5 = 0;
893221345Sdim	for (i = 0; i < AH_PRIVATE(ah)->ah_nchan; i++) {
894221345Sdim		WIRELESS_MODE mode;
895193323Sed		int16_t nf;
896193323Sed
897193323Sed		c = &AH_PRIVATE(ah)->ah_channels[i];
898193323Sed		if (c->rawNoiseFloor >= 0)
899193323Sed			continue;
900193323Sed		/* XXX can't identify proper mode */
901193323Sed		mode = IS_CHAN_5GHZ(c) ? WIRELESS_MODE_11a : WIRELESS_MODE_11g;
902193323Sed		nf = c->rawNoiseFloor + NOISE_FLOOR[mode] +
903193323Sed			ath_hal_getNfAdjust(ah, c);
904193323Sed		if (IS_CHAN_5GHZ(c)) {
905193323Sed			if (nf < lowest5) {
906193323Sed				lowest5 = nf;
907193323Sed				correct5 = NOISE_FLOOR[mode] -
908198113Srdivacky				    (c->rawNoiseFloor + ath_hal_getNfAdjust(ah, c));
909198090Srdivacky			}
910193323Sed		} else {
911193323Sed			if (nf < lowest2) {
912193323Sed				lowest2 = nf;
913193323Sed				correct2 = NOISE_FLOOR[mode] -
914193323Sed				    (c->rawNoiseFloor + ath_hal_getNfAdjust(ah, c));
915193323Sed			}
916221345Sdim		}
917221345Sdim	}
918221345Sdim
919193323Sed	/* Correct the channels to reach the expected NF value */
920193323Sed	for (i = 0; i < AH_PRIVATE(ah)->ah_nchan; i++) {
921193323Sed		c = &AH_PRIVATE(ah)->ah_channels[i];
922193323Sed		if (c->rawNoiseFloor >= 0)
923193323Sed			continue;
924193323Sed		/* Apply correction factor */
925193323Sed		c->noiseFloorAdjust = ath_hal_getNfAdjust(ah, c) +
926193323Sed			(IS_CHAN_5GHZ(c) ? correct5 : correct2);
927193323Sed		HALDEBUG(ah, HAL_DEBUG_NFCAL, "%u raw nf %d adjust %d\n",
928193323Sed		    c->channel, c->rawNoiseFloor, c->noiseFloorAdjust);
929193323Sed	}
930193323Sed}
931193323Sed
932198113Srdivacky/*
933193323Sed * INI support routines.
934193323Sed */
935193323Sed
936193323Sedint
937193323Sedath_hal_ini_write(struct ath_hal *ah, const HAL_INI_ARRAY *ia,
938193323Sed	int col, int regWr)
939193323Sed{
940221345Sdim	int r;
941221345Sdim
942221345Sdim	HALASSERT(col < ia->cols);
943193323Sed	for (r = 0; r < ia->rows; r++) {
944193323Sed		OS_REG_WRITE(ah, HAL_INI_VAL(ia, r, 0),
945193323Sed		    HAL_INI_VAL(ia, r, col));
946193323Sed
947193323Sed		/* Analog shift register delay seems needed for Merlin - PR kern/154220 */
948193323Sed		if (HAL_INI_VAL(ia, r, 0) >= 0x7800 && HAL_INI_VAL(ia, r, 0) < 0x78a0)
949221345Sdim			OS_DELAY(100);
950221345Sdim
951221345Sdim		DMA_YIELD(regWr);
952221345Sdim	}
953221345Sdim	return regWr;
954221345Sdim}
955221345Sdim
956221345Sdimvoid
957221345Sdimath_hal_ini_bank_setup(uint32_t data[], const HAL_INI_ARRAY *ia, int col)
958221345Sdim{
959221345Sdim	int r;
960221345Sdim
961221345Sdim	HALASSERT(col < ia->cols);
962221345Sdim	for (r = 0; r < ia->rows; r++)
963221345Sdim		data[r] = HAL_INI_VAL(ia, r, col);
964221345Sdim}
965221345Sdim
966221345Sdimint
967221345Sdimath_hal_ini_bank_write(struct ath_hal *ah, const HAL_INI_ARRAY *ia,
968221345Sdim	const uint32_t data[], int regWr)
969221345Sdim{
970221345Sdim	int r;
971221345Sdim
972221345Sdim	for (r = 0; r < ia->rows; r++) {
973221345Sdim		OS_REG_WRITE(ah, HAL_INI_VAL(ia, r, 0), data[r]);
974221345Sdim
975221345Sdim		/* Analog shift register delay seems needed for Merlin - PR kern/154220 */
976221345Sdim		/* XXX verify whether any analog radio bank writes will hit up this */
977221345Sdim		/* XXX since this is a merlin work-around; and merlin doesn't use radio banks */
978221345Sdim		if (HAL_INI_VAL(ia, r, 0) >= 0x7800 && HAL_INI_VAL(ia, r, 0) < 0x78a0)
979221345Sdim			OS_DELAY(100);
980221345Sdim		DMA_YIELD(regWr);
981221345Sdim	}
982221345Sdim	return regWr;
983221345Sdim}
984221345Sdim