xref: /dflybsd-src/sys/dev/netif/ath/ath_hal/ah.c (revision dc24979338a9c26cf9963899768e21a9c95d30f2)
1572ff6f6SMatthew Dillon /*
2572ff6f6SMatthew Dillon  * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
3572ff6f6SMatthew Dillon  * Copyright (c) 2002-2008 Atheros Communications, Inc.
4572ff6f6SMatthew Dillon  *
5572ff6f6SMatthew Dillon  * Permission to use, copy, modify, and/or distribute this software for any
6572ff6f6SMatthew Dillon  * purpose with or without fee is hereby granted, provided that the above
7572ff6f6SMatthew Dillon  * copyright notice and this permission notice appear in all copies.
8572ff6f6SMatthew Dillon  *
9572ff6f6SMatthew Dillon  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10572ff6f6SMatthew Dillon  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11572ff6f6SMatthew Dillon  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12572ff6f6SMatthew Dillon  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13572ff6f6SMatthew Dillon  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14572ff6f6SMatthew Dillon  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15572ff6f6SMatthew Dillon  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16572ff6f6SMatthew Dillon  *
17572ff6f6SMatthew Dillon  * $FreeBSD$
18572ff6f6SMatthew Dillon  */
19572ff6f6SMatthew Dillon #include "opt_ah.h"
20572ff6f6SMatthew Dillon 
21572ff6f6SMatthew Dillon #include "ah.h"
22572ff6f6SMatthew Dillon #include "ah_internal.h"
23572ff6f6SMatthew Dillon #include "ah_devid.h"
24572ff6f6SMatthew Dillon #include "ah_eeprom.h"			/* for 5ghz fast clock flag */
25572ff6f6SMatthew Dillon 
26572ff6f6SMatthew Dillon #include "ar5416/ar5416reg.h"		/* NB: includes ar5212reg.h */
27572ff6f6SMatthew Dillon #include "ar9003/ar9300_devid.h"
28572ff6f6SMatthew Dillon 
29572ff6f6SMatthew Dillon /* linker set of registered chips */
30572ff6f6SMatthew Dillon OS_SET_DECLARE(ah_chips, struct ath_hal_chip);
31572ff6f6SMatthew Dillon 
32572ff6f6SMatthew Dillon /*
33572ff6f6SMatthew Dillon  * Check the set of registered chips to see if any recognize
34572ff6f6SMatthew Dillon  * the device as one they can support.
35572ff6f6SMatthew Dillon  */
36572ff6f6SMatthew Dillon const char*
ath_hal_probe(uint16_t vendorid,uint16_t devid)37572ff6f6SMatthew Dillon ath_hal_probe(uint16_t vendorid, uint16_t devid)
38572ff6f6SMatthew Dillon {
39572ff6f6SMatthew Dillon 	struct ath_hal_chip * const *pchip;
40572ff6f6SMatthew Dillon 
41572ff6f6SMatthew Dillon 	OS_SET_FOREACH(pchip, ah_chips) {
42572ff6f6SMatthew Dillon 		const char *name = (*pchip)->probe(vendorid, devid);
43572ff6f6SMatthew Dillon 		if (name != AH_NULL)
44572ff6f6SMatthew Dillon 			return name;
45572ff6f6SMatthew Dillon 	}
46572ff6f6SMatthew Dillon 	return AH_NULL;
47572ff6f6SMatthew Dillon }
48572ff6f6SMatthew Dillon 
49572ff6f6SMatthew Dillon /*
50572ff6f6SMatthew Dillon  * Attach detects device chip revisions, initializes the hwLayer
51572ff6f6SMatthew Dillon  * function list, reads EEPROM information,
52572ff6f6SMatthew Dillon  * selects reset vectors, and performs a short self test.
53572ff6f6SMatthew Dillon  * Any failures will return an error that should cause a hardware
54572ff6f6SMatthew Dillon  * disable.
55572ff6f6SMatthew Dillon  */
56572ff6f6SMatthew Dillon struct ath_hal*
ath_hal_attach(uint16_t devid,HAL_SOFTC sc,HAL_BUS_TAG st,HAL_BUS_HANDLE sh,uint16_t * eepromdata,HAL_OPS_CONFIG * ah_config,HAL_STATUS * error)57572ff6f6SMatthew Dillon ath_hal_attach(uint16_t devid, HAL_SOFTC sc,
58848b370cSMatthew Dillon 	HAL_BUS_TAG st, HAL_BUS_HANDLE sh, uint16_t *eepromdata,
59848b370cSMatthew Dillon 	HAL_OPS_CONFIG *ah_config,
60848b370cSMatthew Dillon 	HAL_STATUS *error)
61572ff6f6SMatthew Dillon {
62572ff6f6SMatthew Dillon 	struct ath_hal_chip * const *pchip;
63572ff6f6SMatthew Dillon 
64572ff6f6SMatthew Dillon 	OS_SET_FOREACH(pchip, ah_chips) {
65572ff6f6SMatthew Dillon 		struct ath_hal_chip *chip = *pchip;
66572ff6f6SMatthew Dillon 		struct ath_hal *ah;
67572ff6f6SMatthew Dillon 
68572ff6f6SMatthew Dillon 		/* XXX don't have vendorid, assume atheros one works */
69572ff6f6SMatthew Dillon 		if (chip->probe(ATHEROS_VENDOR_ID, devid) == AH_NULL)
70572ff6f6SMatthew Dillon 			continue;
71848b370cSMatthew Dillon 		ah = chip->attach(devid, sc, st, sh, eepromdata, ah_config,
72848b370cSMatthew Dillon 		    error);
73572ff6f6SMatthew Dillon 		if (ah != AH_NULL) {
74572ff6f6SMatthew Dillon 			/* copy back private state to public area */
75572ff6f6SMatthew Dillon 			ah->ah_devid = AH_PRIVATE(ah)->ah_devid;
76572ff6f6SMatthew Dillon 			ah->ah_subvendorid = AH_PRIVATE(ah)->ah_subvendorid;
77572ff6f6SMatthew Dillon 			ah->ah_macVersion = AH_PRIVATE(ah)->ah_macVersion;
78572ff6f6SMatthew Dillon 			ah->ah_macRev = AH_PRIVATE(ah)->ah_macRev;
79572ff6f6SMatthew Dillon 			ah->ah_phyRev = AH_PRIVATE(ah)->ah_phyRev;
80572ff6f6SMatthew Dillon 			ah->ah_analog5GhzRev = AH_PRIVATE(ah)->ah_analog5GhzRev;
81572ff6f6SMatthew Dillon 			ah->ah_analog2GhzRev = AH_PRIVATE(ah)->ah_analog2GhzRev;
82572ff6f6SMatthew Dillon 			return ah;
83572ff6f6SMatthew Dillon 		}
84572ff6f6SMatthew Dillon 	}
85572ff6f6SMatthew Dillon 	return AH_NULL;
86572ff6f6SMatthew Dillon }
87572ff6f6SMatthew Dillon 
88572ff6f6SMatthew Dillon const char *
ath_hal_mac_name(struct ath_hal * ah)89572ff6f6SMatthew Dillon ath_hal_mac_name(struct ath_hal *ah)
90572ff6f6SMatthew Dillon {
91572ff6f6SMatthew Dillon 	switch (ah->ah_macVersion) {
92572ff6f6SMatthew Dillon 	case AR_SREV_VERSION_CRETE:
93572ff6f6SMatthew Dillon 	case AR_SREV_VERSION_MAUI_1:
94*b14ca477SMatthew Dillon 		return "AR5210";
95572ff6f6SMatthew Dillon 	case AR_SREV_VERSION_MAUI_2:
96572ff6f6SMatthew Dillon 	case AR_SREV_VERSION_OAHU:
97*b14ca477SMatthew Dillon 		return "AR5211";
98572ff6f6SMatthew Dillon 	case AR_SREV_VERSION_VENICE:
99*b14ca477SMatthew Dillon 		return "AR5212";
100572ff6f6SMatthew Dillon 	case AR_SREV_VERSION_GRIFFIN:
101*b14ca477SMatthew Dillon 		return "AR2413";
102572ff6f6SMatthew Dillon 	case AR_SREV_VERSION_CONDOR:
103*b14ca477SMatthew Dillon 		return "AR5424";
104572ff6f6SMatthew Dillon 	case AR_SREV_VERSION_EAGLE:
105*b14ca477SMatthew Dillon 		return "AR5413";
106572ff6f6SMatthew Dillon 	case AR_SREV_VERSION_COBRA:
107*b14ca477SMatthew Dillon 		return "AR2415";
108572ff6f6SMatthew Dillon 	case AR_SREV_2425:	/* Swan */
109*b14ca477SMatthew Dillon 		return "AR2425";
110572ff6f6SMatthew Dillon 	case AR_SREV_2417:	/* Nala */
111*b14ca477SMatthew Dillon 		return "AR2417";
112572ff6f6SMatthew Dillon 	case AR_XSREV_VERSION_OWL_PCI:
113*b14ca477SMatthew Dillon 		return "AR5416";
114572ff6f6SMatthew Dillon 	case AR_XSREV_VERSION_OWL_PCIE:
115*b14ca477SMatthew Dillon 		return "AR5418";
116572ff6f6SMatthew Dillon 	case AR_XSREV_VERSION_HOWL:
117*b14ca477SMatthew Dillon 		return "AR9130";
118572ff6f6SMatthew Dillon 	case AR_XSREV_VERSION_SOWL:
119*b14ca477SMatthew Dillon 		return "AR9160";
120572ff6f6SMatthew Dillon 	case AR_XSREV_VERSION_MERLIN:
121572ff6f6SMatthew Dillon 		if (AH_PRIVATE(ah)->ah_ispcie)
122*b14ca477SMatthew Dillon 			return "AR9280";
123*b14ca477SMatthew Dillon 		return "AR9220";
124572ff6f6SMatthew Dillon 	case AR_XSREV_VERSION_KITE:
125*b14ca477SMatthew Dillon 		return "AR9285";
126572ff6f6SMatthew Dillon 	case AR_XSREV_VERSION_KIWI:
127572ff6f6SMatthew Dillon 		if (AH_PRIVATE(ah)->ah_ispcie)
128*b14ca477SMatthew Dillon 			return "AR9287";
129*b14ca477SMatthew Dillon 		return "AR9227";
130572ff6f6SMatthew Dillon 	case AR_SREV_VERSION_AR9380:
131572ff6f6SMatthew Dillon 		if (ah->ah_macRev >= AR_SREV_REVISION_AR9580_10)
132*b14ca477SMatthew Dillon 			return "AR9580";
133*b14ca477SMatthew Dillon 		return "AR9380";
134572ff6f6SMatthew Dillon 	case AR_SREV_VERSION_AR9460:
135*b14ca477SMatthew Dillon 		return "AR9460";
136572ff6f6SMatthew Dillon 	case AR_SREV_VERSION_AR9330:
137*b14ca477SMatthew Dillon 		return "AR9330";
138572ff6f6SMatthew Dillon 	case AR_SREV_VERSION_AR9340:
139*b14ca477SMatthew Dillon 		return "AR9340";
140572ff6f6SMatthew Dillon 	case AR_SREV_VERSION_QCA9550:
141*b14ca477SMatthew Dillon 		return "QCA9550";
142572ff6f6SMatthew Dillon 	case AR_SREV_VERSION_AR9485:
143*b14ca477SMatthew Dillon 		return "AR9485";
144572ff6f6SMatthew Dillon 	case AR_SREV_VERSION_QCA9565:
145*b14ca477SMatthew Dillon 		return "QCA9565";
146*b14ca477SMatthew Dillon 	case AR_SREV_VERSION_QCA9530:
147*b14ca477SMatthew Dillon 		return "QCA9530";
148572ff6f6SMatthew Dillon 	}
149572ff6f6SMatthew Dillon 	return "????";
150572ff6f6SMatthew Dillon }
151572ff6f6SMatthew Dillon 
152572ff6f6SMatthew Dillon /*
153572ff6f6SMatthew Dillon  * Return the mask of available modes based on the hardware capabilities.
154572ff6f6SMatthew Dillon  */
155572ff6f6SMatthew Dillon u_int
ath_hal_getwirelessmodes(struct ath_hal * ah)156572ff6f6SMatthew Dillon ath_hal_getwirelessmodes(struct ath_hal*ah)
157572ff6f6SMatthew Dillon {
158572ff6f6SMatthew Dillon 	return ath_hal_getWirelessModes(ah);
159572ff6f6SMatthew Dillon }
160572ff6f6SMatthew Dillon 
161572ff6f6SMatthew Dillon /* linker set of registered RF backends */
162572ff6f6SMatthew Dillon OS_SET_DECLARE(ah_rfs, struct ath_hal_rf);
163572ff6f6SMatthew Dillon 
164572ff6f6SMatthew Dillon /*
165572ff6f6SMatthew Dillon  * Check the set of registered RF backends to see if
166572ff6f6SMatthew Dillon  * any recognize the device as one they can support.
167572ff6f6SMatthew Dillon  */
168572ff6f6SMatthew Dillon struct ath_hal_rf *
ath_hal_rfprobe(struct ath_hal * ah,HAL_STATUS * ecode)169572ff6f6SMatthew Dillon ath_hal_rfprobe(struct ath_hal *ah, HAL_STATUS *ecode)
170572ff6f6SMatthew Dillon {
171572ff6f6SMatthew Dillon 	struct ath_hal_rf * const *prf;
172572ff6f6SMatthew Dillon 
173572ff6f6SMatthew Dillon 	OS_SET_FOREACH(prf, ah_rfs) {
174572ff6f6SMatthew Dillon 		struct ath_hal_rf *rf = *prf;
175572ff6f6SMatthew Dillon 		if (rf->probe(ah))
176572ff6f6SMatthew Dillon 			return rf;
177572ff6f6SMatthew Dillon 	}
178572ff6f6SMatthew Dillon 	*ecode = HAL_ENOTSUPP;
179572ff6f6SMatthew Dillon 	return AH_NULL;
180572ff6f6SMatthew Dillon }
181572ff6f6SMatthew Dillon 
182572ff6f6SMatthew Dillon const char *
ath_hal_rf_name(struct ath_hal * ah)183572ff6f6SMatthew Dillon ath_hal_rf_name(struct ath_hal *ah)
184572ff6f6SMatthew Dillon {
185572ff6f6SMatthew Dillon 	switch (ah->ah_analog5GhzRev & AR_RADIO_SREV_MAJOR) {
186572ff6f6SMatthew Dillon 	case 0:			/* 5210 */
187572ff6f6SMatthew Dillon 		return "5110";	/* NB: made up */
188572ff6f6SMatthew Dillon 	case AR_RAD5111_SREV_MAJOR:
189572ff6f6SMatthew Dillon 	case AR_RAD5111_SREV_PROD:
190572ff6f6SMatthew Dillon 		return "5111";
191572ff6f6SMatthew Dillon 	case AR_RAD2111_SREV_MAJOR:
192572ff6f6SMatthew Dillon 		return "2111";
193572ff6f6SMatthew Dillon 	case AR_RAD5112_SREV_MAJOR:
194572ff6f6SMatthew Dillon 	case AR_RAD5112_SREV_2_0:
195572ff6f6SMatthew Dillon 	case AR_RAD5112_SREV_2_1:
196572ff6f6SMatthew Dillon 		return "5112";
197572ff6f6SMatthew Dillon 	case AR_RAD2112_SREV_MAJOR:
198572ff6f6SMatthew Dillon 	case AR_RAD2112_SREV_2_0:
199572ff6f6SMatthew Dillon 	case AR_RAD2112_SREV_2_1:
200572ff6f6SMatthew Dillon 		return "2112";
201572ff6f6SMatthew Dillon 	case AR_RAD2413_SREV_MAJOR:
202572ff6f6SMatthew Dillon 		return "2413";
203572ff6f6SMatthew Dillon 	case AR_RAD5413_SREV_MAJOR:
204572ff6f6SMatthew Dillon 		return "5413";
205572ff6f6SMatthew Dillon 	case AR_RAD2316_SREV_MAJOR:
206572ff6f6SMatthew Dillon 		return "2316";
207572ff6f6SMatthew Dillon 	case AR_RAD2317_SREV_MAJOR:
208572ff6f6SMatthew Dillon 		return "2317";
209572ff6f6SMatthew Dillon 	case AR_RAD5424_SREV_MAJOR:
210572ff6f6SMatthew Dillon 		return "5424";
211572ff6f6SMatthew Dillon 
212572ff6f6SMatthew Dillon 	case AR_RAD5133_SREV_MAJOR:
213572ff6f6SMatthew Dillon 		return "5133";
214572ff6f6SMatthew Dillon 	case AR_RAD2133_SREV_MAJOR:
215572ff6f6SMatthew Dillon 		return "2133";
216572ff6f6SMatthew Dillon 	case AR_RAD5122_SREV_MAJOR:
217572ff6f6SMatthew Dillon 		return "5122";
218572ff6f6SMatthew Dillon 	case AR_RAD2122_SREV_MAJOR:
219572ff6f6SMatthew Dillon 		return "2122";
220572ff6f6SMatthew Dillon 	}
221572ff6f6SMatthew Dillon 	return "????";
222572ff6f6SMatthew Dillon }
223572ff6f6SMatthew Dillon 
224572ff6f6SMatthew Dillon /*
225572ff6f6SMatthew Dillon  * Poll the register looking for a specific value.
226572ff6f6SMatthew Dillon  */
227572ff6f6SMatthew Dillon HAL_BOOL
ath_hal_wait(struct ath_hal * ah,u_int reg,uint32_t mask,uint32_t val)228572ff6f6SMatthew Dillon ath_hal_wait(struct ath_hal *ah, u_int reg, uint32_t mask, uint32_t val)
229572ff6f6SMatthew Dillon {
230572ff6f6SMatthew Dillon #define	AH_TIMEOUT	1000
231572ff6f6SMatthew Dillon 	return ath_hal_waitfor(ah, reg, mask, val, AH_TIMEOUT);
232572ff6f6SMatthew Dillon #undef AH_TIMEOUT
233572ff6f6SMatthew Dillon }
234572ff6f6SMatthew Dillon 
235572ff6f6SMatthew Dillon HAL_BOOL
ath_hal_waitfor(struct ath_hal * ah,u_int reg,uint32_t mask,uint32_t val,uint32_t timeout)236572ff6f6SMatthew Dillon ath_hal_waitfor(struct ath_hal *ah, u_int reg, uint32_t mask, uint32_t val, uint32_t timeout)
237572ff6f6SMatthew Dillon {
238572ff6f6SMatthew Dillon 	int i;
239572ff6f6SMatthew Dillon 
240572ff6f6SMatthew Dillon 	for (i = 0; i < timeout; i++) {
241572ff6f6SMatthew Dillon 		if ((OS_REG_READ(ah, reg) & mask) == val)
242572ff6f6SMatthew Dillon 			return AH_TRUE;
243572ff6f6SMatthew Dillon 		OS_DELAY(10);
244572ff6f6SMatthew Dillon 	}
245572ff6f6SMatthew Dillon 	HALDEBUG(ah, HAL_DEBUG_REGIO | HAL_DEBUG_PHYIO,
246572ff6f6SMatthew Dillon 	    "%s: timeout on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n",
247572ff6f6SMatthew Dillon 	    __func__, reg, OS_REG_READ(ah, reg), mask, val);
248572ff6f6SMatthew Dillon 	return AH_FALSE;
249572ff6f6SMatthew Dillon }
250572ff6f6SMatthew Dillon 
251572ff6f6SMatthew Dillon /*
252572ff6f6SMatthew Dillon  * Reverse the bits starting at the low bit for a value of
253572ff6f6SMatthew Dillon  * bit_count in size
254572ff6f6SMatthew Dillon  */
255572ff6f6SMatthew Dillon uint32_t
ath_hal_reverseBits(uint32_t val,uint32_t n)256572ff6f6SMatthew Dillon ath_hal_reverseBits(uint32_t val, uint32_t n)
257572ff6f6SMatthew Dillon {
258572ff6f6SMatthew Dillon 	uint32_t retval;
259572ff6f6SMatthew Dillon 	int i;
260572ff6f6SMatthew Dillon 
261572ff6f6SMatthew Dillon 	for (i = 0, retval = 0; i < n; i++) {
262572ff6f6SMatthew Dillon 		retval = (retval << 1) | (val & 1);
263572ff6f6SMatthew Dillon 		val >>= 1;
264572ff6f6SMatthew Dillon 	}
265572ff6f6SMatthew Dillon 	return retval;
266572ff6f6SMatthew Dillon }
267572ff6f6SMatthew Dillon 
268572ff6f6SMatthew Dillon /* 802.11n related timing definitions */
269572ff6f6SMatthew Dillon 
270572ff6f6SMatthew Dillon #define	OFDM_PLCP_BITS	22
271572ff6f6SMatthew Dillon #define	HT_L_STF	8
272572ff6f6SMatthew Dillon #define	HT_L_LTF	8
273572ff6f6SMatthew Dillon #define	HT_L_SIG	4
274572ff6f6SMatthew Dillon #define	HT_SIG		8
275572ff6f6SMatthew Dillon #define	HT_STF		4
276572ff6f6SMatthew Dillon #define	HT_LTF(n)	((n) * 4)
277572ff6f6SMatthew Dillon 
278572ff6f6SMatthew Dillon #define	HT_RC_2_MCS(_rc)	((_rc) & 0xf)
279572ff6f6SMatthew Dillon #define	HT_RC_2_STREAMS(_rc)	((((_rc) & 0x78) >> 3) + 1)
280572ff6f6SMatthew Dillon #define	IS_HT_RATE(_rc)		( (_rc) & IEEE80211_RATE_MCS)
281572ff6f6SMatthew Dillon 
282572ff6f6SMatthew Dillon /*
283572ff6f6SMatthew Dillon  * Calculate the duration of a packet whether it is 11n or legacy.
284572ff6f6SMatthew Dillon  */
285572ff6f6SMatthew Dillon uint32_t
ath_hal_pkt_txtime(struct ath_hal * ah,const HAL_RATE_TABLE * rates,uint32_t frameLen,uint16_t rateix,HAL_BOOL isht40,HAL_BOOL shortPreamble)286572ff6f6SMatthew Dillon ath_hal_pkt_txtime(struct ath_hal *ah, const HAL_RATE_TABLE *rates, uint32_t frameLen,
287572ff6f6SMatthew Dillon     uint16_t rateix, HAL_BOOL isht40, HAL_BOOL shortPreamble)
288572ff6f6SMatthew Dillon {
289572ff6f6SMatthew Dillon 	uint8_t rc;
290572ff6f6SMatthew Dillon 	int numStreams;
291572ff6f6SMatthew Dillon 
292572ff6f6SMatthew Dillon 	rc = rates->info[rateix].rateCode;
293572ff6f6SMatthew Dillon 
294572ff6f6SMatthew Dillon 	/* Legacy rate? Return the old way */
295572ff6f6SMatthew Dillon 	if (! IS_HT_RATE(rc))
296572ff6f6SMatthew Dillon 		return ath_hal_computetxtime(ah, rates, frameLen, rateix, shortPreamble);
297572ff6f6SMatthew Dillon 
298572ff6f6SMatthew Dillon 	/* 11n frame - extract out the number of spatial streams */
299572ff6f6SMatthew Dillon 	numStreams = HT_RC_2_STREAMS(rc);
300572ff6f6SMatthew Dillon 	KASSERT(numStreams > 0 && numStreams <= 4,
301572ff6f6SMatthew Dillon 	    ("number of spatial streams needs to be 1..3: MCS rate 0x%x!",
302572ff6f6SMatthew Dillon 	    rateix));
303572ff6f6SMatthew Dillon 
304572ff6f6SMatthew Dillon 	return ath_computedur_ht(frameLen, rc, numStreams, isht40, shortPreamble);
305572ff6f6SMatthew Dillon }
306572ff6f6SMatthew Dillon 
307572ff6f6SMatthew Dillon static const uint16_t ht20_bps[32] = {
308572ff6f6SMatthew Dillon     26, 52, 78, 104, 156, 208, 234, 260,
309572ff6f6SMatthew Dillon     52, 104, 156, 208, 312, 416, 468, 520,
310572ff6f6SMatthew Dillon     78, 156, 234, 312, 468, 624, 702, 780,
311572ff6f6SMatthew Dillon     104, 208, 312, 416, 624, 832, 936, 1040
312572ff6f6SMatthew Dillon };
313572ff6f6SMatthew Dillon static const uint16_t ht40_bps[32] = {
314572ff6f6SMatthew Dillon     54, 108, 162, 216, 324, 432, 486, 540,
315572ff6f6SMatthew Dillon     108, 216, 324, 432, 648, 864, 972, 1080,
316572ff6f6SMatthew Dillon     162, 324, 486, 648, 972, 1296, 1458, 1620,
317572ff6f6SMatthew Dillon     216, 432, 648, 864, 1296, 1728, 1944, 2160
318572ff6f6SMatthew Dillon };
319572ff6f6SMatthew Dillon 
320572ff6f6SMatthew Dillon /*
321572ff6f6SMatthew Dillon  * Calculate the transmit duration of an 11n frame.
322572ff6f6SMatthew Dillon  */
323572ff6f6SMatthew Dillon uint32_t
ath_computedur_ht(uint32_t frameLen,uint16_t rate,int streams,HAL_BOOL isht40,HAL_BOOL isShortGI)324572ff6f6SMatthew Dillon ath_computedur_ht(uint32_t frameLen, uint16_t rate, int streams,
325572ff6f6SMatthew Dillon     HAL_BOOL isht40, HAL_BOOL isShortGI)
326572ff6f6SMatthew Dillon {
327572ff6f6SMatthew Dillon 	uint32_t bitsPerSymbol, numBits, numSymbols, txTime;
328572ff6f6SMatthew Dillon 
329572ff6f6SMatthew Dillon 	KASSERT(rate & IEEE80211_RATE_MCS, ("not mcs %d", rate));
330572ff6f6SMatthew Dillon 	KASSERT((rate &~ IEEE80211_RATE_MCS) < 31, ("bad mcs 0x%x", rate));
331572ff6f6SMatthew Dillon 
332572ff6f6SMatthew Dillon 	if (isht40)
333572ff6f6SMatthew Dillon 		bitsPerSymbol = ht40_bps[rate & 0x1f];
334572ff6f6SMatthew Dillon 	else
335572ff6f6SMatthew Dillon 		bitsPerSymbol = ht20_bps[rate & 0x1f];
336572ff6f6SMatthew Dillon 	numBits = OFDM_PLCP_BITS + (frameLen << 3);
337572ff6f6SMatthew Dillon 	numSymbols = howmany(numBits, bitsPerSymbol);
338572ff6f6SMatthew Dillon 	if (isShortGI)
339572ff6f6SMatthew Dillon 		txTime = ((numSymbols * 18) + 4) / 5;   /* 3.6us */
340572ff6f6SMatthew Dillon 	else
341572ff6f6SMatthew Dillon 		txTime = numSymbols * 4;                /* 4us */
342572ff6f6SMatthew Dillon 	return txTime + HT_L_STF + HT_L_LTF +
343572ff6f6SMatthew Dillon 	    HT_L_SIG + HT_SIG + HT_STF + HT_LTF(streams);
344572ff6f6SMatthew Dillon }
345572ff6f6SMatthew Dillon 
346572ff6f6SMatthew Dillon /*
347572ff6f6SMatthew Dillon  * Compute the time to transmit a frame of length frameLen bytes
348572ff6f6SMatthew Dillon  * using the specified rate, phy, and short preamble setting.
349572ff6f6SMatthew Dillon  */
350572ff6f6SMatthew Dillon uint16_t
ath_hal_computetxtime(struct ath_hal * ah,const HAL_RATE_TABLE * rates,uint32_t frameLen,uint16_t rateix,HAL_BOOL shortPreamble)351572ff6f6SMatthew Dillon ath_hal_computetxtime(struct ath_hal *ah,
352572ff6f6SMatthew Dillon 	const HAL_RATE_TABLE *rates, uint32_t frameLen, uint16_t rateix,
353572ff6f6SMatthew Dillon 	HAL_BOOL shortPreamble)
354572ff6f6SMatthew Dillon {
355572ff6f6SMatthew Dillon 	uint32_t bitsPerSymbol, numBits, numSymbols, phyTime, txTime;
356572ff6f6SMatthew Dillon 	uint32_t kbps;
357572ff6f6SMatthew Dillon 
358572ff6f6SMatthew Dillon 	/* Warn if this function is called for 11n rates; it should not be! */
359572ff6f6SMatthew Dillon 	if (IS_HT_RATE(rates->info[rateix].rateCode))
360572ff6f6SMatthew Dillon 		ath_hal_printf(ah, "%s: MCS rate? (index %d; hwrate 0x%x)\n",
361572ff6f6SMatthew Dillon 		    __func__, rateix, rates->info[rateix].rateCode);
362572ff6f6SMatthew Dillon 
363572ff6f6SMatthew Dillon 	kbps = rates->info[rateix].rateKbps;
364572ff6f6SMatthew Dillon 	/*
365*b14ca477SMatthew Dillon 	 * index can be invalid during dynamic Turbo transitions.
366572ff6f6SMatthew Dillon 	 * XXX
367572ff6f6SMatthew Dillon 	 */
368572ff6f6SMatthew Dillon 	if (kbps == 0)
369572ff6f6SMatthew Dillon 		return 0;
370572ff6f6SMatthew Dillon 	switch (rates->info[rateix].phy) {
371572ff6f6SMatthew Dillon 	case IEEE80211_T_CCK:
372572ff6f6SMatthew Dillon 		phyTime		= CCK_PREAMBLE_BITS + CCK_PLCP_BITS;
373572ff6f6SMatthew Dillon 		if (shortPreamble && rates->info[rateix].shortPreamble)
374572ff6f6SMatthew Dillon 			phyTime >>= 1;
375572ff6f6SMatthew Dillon 		numBits		= frameLen << 3;
376572ff6f6SMatthew Dillon 		txTime		= CCK_SIFS_TIME + phyTime
377572ff6f6SMatthew Dillon 				+ ((numBits * 1000)/kbps);
378572ff6f6SMatthew Dillon 		break;
379572ff6f6SMatthew Dillon 	case IEEE80211_T_OFDM:
380572ff6f6SMatthew Dillon 		bitsPerSymbol	= (kbps * OFDM_SYMBOL_TIME) / 1000;
381572ff6f6SMatthew Dillon 		HALASSERT(bitsPerSymbol != 0);
382572ff6f6SMatthew Dillon 
383572ff6f6SMatthew Dillon 		numBits		= OFDM_PLCP_BITS + (frameLen << 3);
384572ff6f6SMatthew Dillon 		numSymbols	= howmany(numBits, bitsPerSymbol);
385572ff6f6SMatthew Dillon 		txTime		= OFDM_SIFS_TIME
386572ff6f6SMatthew Dillon 				+ OFDM_PREAMBLE_TIME
387572ff6f6SMatthew Dillon 				+ (numSymbols * OFDM_SYMBOL_TIME);
388572ff6f6SMatthew Dillon 		break;
389572ff6f6SMatthew Dillon 	case IEEE80211_T_OFDM_HALF:
390572ff6f6SMatthew Dillon 		bitsPerSymbol	= (kbps * OFDM_HALF_SYMBOL_TIME) / 1000;
391572ff6f6SMatthew Dillon 		HALASSERT(bitsPerSymbol != 0);
392572ff6f6SMatthew Dillon 
393572ff6f6SMatthew Dillon 		numBits		= OFDM_HALF_PLCP_BITS + (frameLen << 3);
394572ff6f6SMatthew Dillon 		numSymbols	= howmany(numBits, bitsPerSymbol);
395572ff6f6SMatthew Dillon 		txTime		= OFDM_HALF_SIFS_TIME
396572ff6f6SMatthew Dillon 				+ OFDM_HALF_PREAMBLE_TIME
397572ff6f6SMatthew Dillon 				+ (numSymbols * OFDM_HALF_SYMBOL_TIME);
398572ff6f6SMatthew Dillon 		break;
399572ff6f6SMatthew Dillon 	case IEEE80211_T_OFDM_QUARTER:
400572ff6f6SMatthew Dillon 		bitsPerSymbol	= (kbps * OFDM_QUARTER_SYMBOL_TIME) / 1000;
401572ff6f6SMatthew Dillon 		HALASSERT(bitsPerSymbol != 0);
402572ff6f6SMatthew Dillon 
403572ff6f6SMatthew Dillon 		numBits		= OFDM_QUARTER_PLCP_BITS + (frameLen << 3);
404572ff6f6SMatthew Dillon 		numSymbols	= howmany(numBits, bitsPerSymbol);
405572ff6f6SMatthew Dillon 		txTime		= OFDM_QUARTER_SIFS_TIME
406572ff6f6SMatthew Dillon 				+ OFDM_QUARTER_PREAMBLE_TIME
407572ff6f6SMatthew Dillon 				+ (numSymbols * OFDM_QUARTER_SYMBOL_TIME);
408572ff6f6SMatthew Dillon 		break;
409572ff6f6SMatthew Dillon 	case IEEE80211_T_TURBO:
410572ff6f6SMatthew Dillon 		bitsPerSymbol	= (kbps * TURBO_SYMBOL_TIME) / 1000;
411572ff6f6SMatthew Dillon 		HALASSERT(bitsPerSymbol != 0);
412572ff6f6SMatthew Dillon 
413572ff6f6SMatthew Dillon 		numBits		= TURBO_PLCP_BITS + (frameLen << 3);
414572ff6f6SMatthew Dillon 		numSymbols	= howmany(numBits, bitsPerSymbol);
415572ff6f6SMatthew Dillon 		txTime		= TURBO_SIFS_TIME
416572ff6f6SMatthew Dillon 				+ TURBO_PREAMBLE_TIME
417572ff6f6SMatthew Dillon 				+ (numSymbols * TURBO_SYMBOL_TIME);
418572ff6f6SMatthew Dillon 		break;
419572ff6f6SMatthew Dillon 	default:
420572ff6f6SMatthew Dillon 		HALDEBUG(ah, HAL_DEBUG_PHYIO,
421572ff6f6SMatthew Dillon 		    "%s: unknown phy %u (rate ix %u)\n",
422572ff6f6SMatthew Dillon 		    __func__, rates->info[rateix].phy, rateix);
423572ff6f6SMatthew Dillon 		txTime = 0;
424572ff6f6SMatthew Dillon 		break;
425572ff6f6SMatthew Dillon 	}
426572ff6f6SMatthew Dillon 	return txTime;
427572ff6f6SMatthew Dillon }
428572ff6f6SMatthew Dillon 
429572ff6f6SMatthew Dillon int
ath_hal_get_curmode(struct ath_hal * ah,const struct ieee80211_channel * chan)430572ff6f6SMatthew Dillon ath_hal_get_curmode(struct ath_hal *ah, const struct ieee80211_channel *chan)
431572ff6f6SMatthew Dillon {
432572ff6f6SMatthew Dillon 	/*
433572ff6f6SMatthew Dillon 	 * Pick a default mode at bootup. A channel change is inevitable.
434572ff6f6SMatthew Dillon 	 */
435572ff6f6SMatthew Dillon 	if (!chan)
436572ff6f6SMatthew Dillon 		return HAL_MODE_11NG_HT20;
437572ff6f6SMatthew Dillon 
438572ff6f6SMatthew Dillon 	if (IEEE80211_IS_CHAN_TURBO(chan))
439572ff6f6SMatthew Dillon 		return HAL_MODE_TURBO;
440572ff6f6SMatthew Dillon 
441572ff6f6SMatthew Dillon 	/* check for NA_HT before plain A, since IS_CHAN_A includes NA_HT */
442572ff6f6SMatthew Dillon 	if (IEEE80211_IS_CHAN_5GHZ(chan) && IEEE80211_IS_CHAN_HT20(chan))
443572ff6f6SMatthew Dillon 		return HAL_MODE_11NA_HT20;
444572ff6f6SMatthew Dillon 	if (IEEE80211_IS_CHAN_5GHZ(chan) && IEEE80211_IS_CHAN_HT40U(chan))
445572ff6f6SMatthew Dillon 		return HAL_MODE_11NA_HT40PLUS;
446572ff6f6SMatthew Dillon 	if (IEEE80211_IS_CHAN_5GHZ(chan) && IEEE80211_IS_CHAN_HT40D(chan))
447572ff6f6SMatthew Dillon 		return HAL_MODE_11NA_HT40MINUS;
448572ff6f6SMatthew Dillon 	if (IEEE80211_IS_CHAN_A(chan))
449572ff6f6SMatthew Dillon 		return HAL_MODE_11A;
450572ff6f6SMatthew Dillon 
451572ff6f6SMatthew Dillon 	/* check for NG_HT before plain G, since IS_CHAN_G includes NG_HT */
452572ff6f6SMatthew Dillon 	if (IEEE80211_IS_CHAN_2GHZ(chan) && IEEE80211_IS_CHAN_HT20(chan))
453572ff6f6SMatthew Dillon 		return HAL_MODE_11NG_HT20;
454572ff6f6SMatthew Dillon 	if (IEEE80211_IS_CHAN_2GHZ(chan) && IEEE80211_IS_CHAN_HT40U(chan))
455572ff6f6SMatthew Dillon 		return HAL_MODE_11NG_HT40PLUS;
456572ff6f6SMatthew Dillon 	if (IEEE80211_IS_CHAN_2GHZ(chan) && IEEE80211_IS_CHAN_HT40D(chan))
457572ff6f6SMatthew Dillon 		return HAL_MODE_11NG_HT40MINUS;
458572ff6f6SMatthew Dillon 
459572ff6f6SMatthew Dillon 	/*
460572ff6f6SMatthew Dillon 	 * XXX For FreeBSD, will this work correctly given the DYN
461572ff6f6SMatthew Dillon 	 * chan mode (OFDM+CCK dynamic) ? We have pure-G versions DYN-BG..
462572ff6f6SMatthew Dillon 	 */
463572ff6f6SMatthew Dillon 	if (IEEE80211_IS_CHAN_G(chan))
464572ff6f6SMatthew Dillon 		return HAL_MODE_11G;
465572ff6f6SMatthew Dillon 	if (IEEE80211_IS_CHAN_B(chan))
466572ff6f6SMatthew Dillon 		return HAL_MODE_11B;
467572ff6f6SMatthew Dillon 
468572ff6f6SMatthew Dillon 	HALASSERT(0);
469572ff6f6SMatthew Dillon 	return HAL_MODE_11NG_HT20;
470572ff6f6SMatthew Dillon }
471572ff6f6SMatthew Dillon 
472572ff6f6SMatthew Dillon 
473572ff6f6SMatthew Dillon typedef enum {
474572ff6f6SMatthew Dillon 	WIRELESS_MODE_11a   = 0,
475572ff6f6SMatthew Dillon 	WIRELESS_MODE_TURBO = 1,
476572ff6f6SMatthew Dillon 	WIRELESS_MODE_11b   = 2,
477572ff6f6SMatthew Dillon 	WIRELESS_MODE_11g   = 3,
478572ff6f6SMatthew Dillon 	WIRELESS_MODE_108g  = 4,
479572ff6f6SMatthew Dillon 
480572ff6f6SMatthew Dillon 	WIRELESS_MODE_MAX
481572ff6f6SMatthew Dillon } WIRELESS_MODE;
482572ff6f6SMatthew Dillon 
483572ff6f6SMatthew Dillon static WIRELESS_MODE
ath_hal_chan2wmode(struct ath_hal * ah,const struct ieee80211_channel * chan)484572ff6f6SMatthew Dillon ath_hal_chan2wmode(struct ath_hal *ah, const struct ieee80211_channel *chan)
485572ff6f6SMatthew Dillon {
486572ff6f6SMatthew Dillon 	if (IEEE80211_IS_CHAN_B(chan))
487572ff6f6SMatthew Dillon 		return WIRELESS_MODE_11b;
488572ff6f6SMatthew Dillon 	if (IEEE80211_IS_CHAN_G(chan))
489572ff6f6SMatthew Dillon 		return WIRELESS_MODE_11g;
490572ff6f6SMatthew Dillon 	if (IEEE80211_IS_CHAN_108G(chan))
491572ff6f6SMatthew Dillon 		return WIRELESS_MODE_108g;
492572ff6f6SMatthew Dillon 	if (IEEE80211_IS_CHAN_TURBO(chan))
493572ff6f6SMatthew Dillon 		return WIRELESS_MODE_TURBO;
494572ff6f6SMatthew Dillon 	return WIRELESS_MODE_11a;
495572ff6f6SMatthew Dillon }
496572ff6f6SMatthew Dillon 
497572ff6f6SMatthew Dillon /*
498572ff6f6SMatthew Dillon  * Convert between microseconds and core system clocks.
499572ff6f6SMatthew Dillon  */
500572ff6f6SMatthew Dillon                                      /* 11a Turbo  11b  11g  108g */
501572ff6f6SMatthew Dillon static const uint8_t CLOCK_RATE[]  = { 40,  80,   22,  44,   88  };
502572ff6f6SMatthew Dillon 
503572ff6f6SMatthew Dillon #define	CLOCK_FAST_RATE_5GHZ_OFDM	44
504572ff6f6SMatthew Dillon 
505572ff6f6SMatthew Dillon u_int
ath_hal_mac_clks(struct ath_hal * ah,u_int usecs)506572ff6f6SMatthew Dillon ath_hal_mac_clks(struct ath_hal *ah, u_int usecs)
507572ff6f6SMatthew Dillon {
508572ff6f6SMatthew Dillon 	const struct ieee80211_channel *c = AH_PRIVATE(ah)->ah_curchan;
509572ff6f6SMatthew Dillon 	u_int clks;
510572ff6f6SMatthew Dillon 
511572ff6f6SMatthew Dillon 	/* NB: ah_curchan may be null when called attach time */
512572ff6f6SMatthew Dillon 	/* XXX merlin and later specific workaround - 5ghz fast clock is 44 */
513572ff6f6SMatthew Dillon 	if (c != AH_NULL && IS_5GHZ_FAST_CLOCK_EN(ah, c)) {
514572ff6f6SMatthew Dillon 		clks = usecs * CLOCK_FAST_RATE_5GHZ_OFDM;
515572ff6f6SMatthew Dillon 		if (IEEE80211_IS_CHAN_HT40(c))
516572ff6f6SMatthew Dillon 			clks <<= 1;
517572ff6f6SMatthew Dillon 	} else if (c != AH_NULL) {
518572ff6f6SMatthew Dillon 		clks = usecs * CLOCK_RATE[ath_hal_chan2wmode(ah, c)];
519572ff6f6SMatthew Dillon 		if (IEEE80211_IS_CHAN_HT40(c))
520572ff6f6SMatthew Dillon 			clks <<= 1;
521572ff6f6SMatthew Dillon 	} else
522572ff6f6SMatthew Dillon 		clks = usecs * CLOCK_RATE[WIRELESS_MODE_11b];
523572ff6f6SMatthew Dillon 
524572ff6f6SMatthew Dillon 	/* Compensate for half/quarter rate */
525572ff6f6SMatthew Dillon 	if (c != AH_NULL && IEEE80211_IS_CHAN_HALF(c))
526572ff6f6SMatthew Dillon 		clks = clks / 2;
527572ff6f6SMatthew Dillon 	else if (c != AH_NULL && IEEE80211_IS_CHAN_QUARTER(c))
528572ff6f6SMatthew Dillon 		clks = clks / 4;
529572ff6f6SMatthew Dillon 
530572ff6f6SMatthew Dillon 	return clks;
531572ff6f6SMatthew Dillon }
532572ff6f6SMatthew Dillon 
533572ff6f6SMatthew Dillon u_int
ath_hal_mac_usec(struct ath_hal * ah,u_int clks)534572ff6f6SMatthew Dillon ath_hal_mac_usec(struct ath_hal *ah, u_int clks)
535572ff6f6SMatthew Dillon {
536572ff6f6SMatthew Dillon 	const struct ieee80211_channel *c = AH_PRIVATE(ah)->ah_curchan;
537572ff6f6SMatthew Dillon 	u_int usec;
538572ff6f6SMatthew Dillon 
539572ff6f6SMatthew Dillon 	/* NB: ah_curchan may be null when called attach time */
540572ff6f6SMatthew Dillon 	/* XXX merlin and later specific workaround - 5ghz fast clock is 44 */
541572ff6f6SMatthew Dillon 	if (c != AH_NULL && IS_5GHZ_FAST_CLOCK_EN(ah, c)) {
542572ff6f6SMatthew Dillon 		usec = clks / CLOCK_FAST_RATE_5GHZ_OFDM;
543572ff6f6SMatthew Dillon 		if (IEEE80211_IS_CHAN_HT40(c))
544572ff6f6SMatthew Dillon 			usec >>= 1;
545572ff6f6SMatthew Dillon 	} else if (c != AH_NULL) {
546572ff6f6SMatthew Dillon 		usec = clks / CLOCK_RATE[ath_hal_chan2wmode(ah, c)];
547572ff6f6SMatthew Dillon 		if (IEEE80211_IS_CHAN_HT40(c))
548572ff6f6SMatthew Dillon 			usec >>= 1;
549572ff6f6SMatthew Dillon 	} else
550572ff6f6SMatthew Dillon 		usec = clks / CLOCK_RATE[WIRELESS_MODE_11b];
551572ff6f6SMatthew Dillon 	return usec;
552572ff6f6SMatthew Dillon }
553572ff6f6SMatthew Dillon 
554572ff6f6SMatthew Dillon /*
555572ff6f6SMatthew Dillon  * Setup a h/w rate table's reverse lookup table and
556572ff6f6SMatthew Dillon  * fill in ack durations.  This routine is called for
557572ff6f6SMatthew Dillon  * each rate table returned through the ah_getRateTable
558572ff6f6SMatthew Dillon  * method.  The reverse lookup tables are assumed to be
559572ff6f6SMatthew Dillon  * initialized to zero (or at least the first entry).
560572ff6f6SMatthew Dillon  * We use this as a key that indicates whether or not
561572ff6f6SMatthew Dillon  * we've previously setup the reverse lookup table.
562572ff6f6SMatthew Dillon  *
563572ff6f6SMatthew Dillon  * XXX not reentrant, but shouldn't matter
564572ff6f6SMatthew Dillon  */
565572ff6f6SMatthew Dillon void
ath_hal_setupratetable(struct ath_hal * ah,HAL_RATE_TABLE * rt)566572ff6f6SMatthew Dillon ath_hal_setupratetable(struct ath_hal *ah, HAL_RATE_TABLE *rt)
567572ff6f6SMatthew Dillon {
568572ff6f6SMatthew Dillon #define	N(a)	(sizeof(a)/sizeof(a[0]))
569572ff6f6SMatthew Dillon 	int i;
570572ff6f6SMatthew Dillon 
571572ff6f6SMatthew Dillon 	if (rt->rateCodeToIndex[0] != 0)	/* already setup */
572572ff6f6SMatthew Dillon 		return;
573572ff6f6SMatthew Dillon 	for (i = 0; i < N(rt->rateCodeToIndex); i++)
574572ff6f6SMatthew Dillon 		rt->rateCodeToIndex[i] = (uint8_t) -1;
575572ff6f6SMatthew Dillon 	for (i = 0; i < rt->rateCount; i++) {
576572ff6f6SMatthew Dillon 		uint8_t code = rt->info[i].rateCode;
577572ff6f6SMatthew Dillon 		uint8_t cix = rt->info[i].controlRate;
578572ff6f6SMatthew Dillon 
579572ff6f6SMatthew Dillon 		HALASSERT(code < N(rt->rateCodeToIndex));
580572ff6f6SMatthew Dillon 		rt->rateCodeToIndex[code] = i;
581572ff6f6SMatthew Dillon 		HALASSERT((code | rt->info[i].shortPreamble) <
582572ff6f6SMatthew Dillon 		    N(rt->rateCodeToIndex));
583572ff6f6SMatthew Dillon 		rt->rateCodeToIndex[code | rt->info[i].shortPreamble] = i;
584572ff6f6SMatthew Dillon 		/*
585572ff6f6SMatthew Dillon 		 * XXX for 11g the control rate to use for 5.5 and 11 Mb/s
586572ff6f6SMatthew Dillon 		 *     depends on whether they are marked as basic rates;
587572ff6f6SMatthew Dillon 		 *     the static tables are setup with an 11b-compatible
588572ff6f6SMatthew Dillon 		 *     2Mb/s rate which will work but is suboptimal
589572ff6f6SMatthew Dillon 		 */
590572ff6f6SMatthew Dillon 		rt->info[i].lpAckDuration = ath_hal_computetxtime(ah, rt,
591572ff6f6SMatthew Dillon 			WLAN_CTRL_FRAME_SIZE, cix, AH_FALSE);
592572ff6f6SMatthew Dillon 		rt->info[i].spAckDuration = ath_hal_computetxtime(ah, rt,
593572ff6f6SMatthew Dillon 			WLAN_CTRL_FRAME_SIZE, cix, AH_TRUE);
594572ff6f6SMatthew Dillon 	}
595572ff6f6SMatthew Dillon #undef N
596572ff6f6SMatthew Dillon }
597572ff6f6SMatthew Dillon 
598572ff6f6SMatthew Dillon HAL_STATUS
ath_hal_getcapability(struct ath_hal * ah,HAL_CAPABILITY_TYPE type,uint32_t capability,uint32_t * result)599572ff6f6SMatthew Dillon ath_hal_getcapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type,
600572ff6f6SMatthew Dillon 	uint32_t capability, uint32_t *result)
601572ff6f6SMatthew Dillon {
602572ff6f6SMatthew Dillon 	const HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps;
603572ff6f6SMatthew Dillon 
604572ff6f6SMatthew Dillon 	switch (type) {
605572ff6f6SMatthew Dillon 	case HAL_CAP_REG_DMN:		/* regulatory domain */
606572ff6f6SMatthew Dillon 		*result = AH_PRIVATE(ah)->ah_currentRD;
607572ff6f6SMatthew Dillon 		return HAL_OK;
608572ff6f6SMatthew Dillon 	case HAL_CAP_DFS_DMN:		/* DFS Domain */
609572ff6f6SMatthew Dillon 		*result = AH_PRIVATE(ah)->ah_dfsDomain;
610572ff6f6SMatthew Dillon 		return HAL_OK;
611572ff6f6SMatthew Dillon 	case HAL_CAP_CIPHER:		/* cipher handled in hardware */
612572ff6f6SMatthew Dillon 	case HAL_CAP_TKIP_MIC:		/* handle TKIP MIC in hardware */
613572ff6f6SMatthew Dillon 		return HAL_ENOTSUPP;
614572ff6f6SMatthew Dillon 	case HAL_CAP_TKIP_SPLIT:	/* hardware TKIP uses split keys */
615572ff6f6SMatthew Dillon 		return HAL_ENOTSUPP;
616572ff6f6SMatthew Dillon 	case HAL_CAP_PHYCOUNTERS:	/* hardware PHY error counters */
617572ff6f6SMatthew Dillon 		return pCap->halHwPhyCounterSupport ? HAL_OK : HAL_ENXIO;
618572ff6f6SMatthew Dillon 	case HAL_CAP_WME_TKIPMIC:   /* hardware can do TKIP MIC when WMM is turned on */
619572ff6f6SMatthew Dillon 		return HAL_ENOTSUPP;
620572ff6f6SMatthew Dillon 	case HAL_CAP_DIVERSITY:		/* hardware supports fast diversity */
621572ff6f6SMatthew Dillon 		return HAL_ENOTSUPP;
622572ff6f6SMatthew Dillon 	case HAL_CAP_KEYCACHE_SIZE:	/* hardware key cache size */
623572ff6f6SMatthew Dillon 		*result =  pCap->halKeyCacheSize;
624572ff6f6SMatthew Dillon 		return HAL_OK;
625572ff6f6SMatthew Dillon 	case HAL_CAP_NUM_TXQUEUES:	/* number of hardware tx queues */
626572ff6f6SMatthew Dillon 		*result = pCap->halTotalQueues;
627572ff6f6SMatthew Dillon 		return HAL_OK;
628572ff6f6SMatthew Dillon 	case HAL_CAP_VEOL:		/* hardware supports virtual EOL */
629572ff6f6SMatthew Dillon 		return pCap->halVEOLSupport ? HAL_OK : HAL_ENOTSUPP;
630572ff6f6SMatthew Dillon 	case HAL_CAP_PSPOLL:		/* hardware PS-Poll support works */
631572ff6f6SMatthew Dillon 		return pCap->halPSPollBroken ? HAL_ENOTSUPP : HAL_OK;
632572ff6f6SMatthew Dillon 	case HAL_CAP_COMPRESSION:
633572ff6f6SMatthew Dillon 		return pCap->halCompressSupport ? HAL_OK : HAL_ENOTSUPP;
634572ff6f6SMatthew Dillon 	case HAL_CAP_BURST:
635572ff6f6SMatthew Dillon 		return pCap->halBurstSupport ? HAL_OK : HAL_ENOTSUPP;
636572ff6f6SMatthew Dillon 	case HAL_CAP_FASTFRAME:
637572ff6f6SMatthew Dillon 		return pCap->halFastFramesSupport ? HAL_OK : HAL_ENOTSUPP;
638572ff6f6SMatthew Dillon 	case HAL_CAP_DIAG:		/* hardware diagnostic support */
639572ff6f6SMatthew Dillon 		*result = AH_PRIVATE(ah)->ah_diagreg;
640572ff6f6SMatthew Dillon 		return HAL_OK;
641572ff6f6SMatthew Dillon 	case HAL_CAP_TXPOW:		/* global tx power limit  */
642572ff6f6SMatthew Dillon 		switch (capability) {
643572ff6f6SMatthew Dillon 		case 0:			/* facility is supported */
644572ff6f6SMatthew Dillon 			return HAL_OK;
645572ff6f6SMatthew Dillon 		case 1:			/* current limit */
646572ff6f6SMatthew Dillon 			*result = AH_PRIVATE(ah)->ah_powerLimit;
647572ff6f6SMatthew Dillon 			return HAL_OK;
648572ff6f6SMatthew Dillon 		case 2:			/* current max tx power */
649572ff6f6SMatthew Dillon 			*result = AH_PRIVATE(ah)->ah_maxPowerLevel;
650572ff6f6SMatthew Dillon 			return HAL_OK;
651572ff6f6SMatthew Dillon 		case 3:			/* scale factor */
652572ff6f6SMatthew Dillon 			*result = AH_PRIVATE(ah)->ah_tpScale;
653572ff6f6SMatthew Dillon 			return HAL_OK;
654572ff6f6SMatthew Dillon 		}
655572ff6f6SMatthew Dillon 		return HAL_ENOTSUPP;
656572ff6f6SMatthew Dillon 	case HAL_CAP_BSSIDMASK:		/* hardware supports bssid mask */
657572ff6f6SMatthew Dillon 		return pCap->halBssIdMaskSupport ? HAL_OK : HAL_ENOTSUPP;
658572ff6f6SMatthew Dillon 	case HAL_CAP_MCAST_KEYSRCH:	/* multicast frame keycache search */
659572ff6f6SMatthew Dillon 		return pCap->halMcastKeySrchSupport ? HAL_OK : HAL_ENOTSUPP;
660572ff6f6SMatthew Dillon 	case HAL_CAP_TSF_ADJUST:	/* hardware has beacon tsf adjust */
661572ff6f6SMatthew Dillon 		return HAL_ENOTSUPP;
662572ff6f6SMatthew Dillon 	case HAL_CAP_RFSILENT:		/* rfsilent support  */
663572ff6f6SMatthew Dillon 		switch (capability) {
664572ff6f6SMatthew Dillon 		case 0:			/* facility is supported */
665572ff6f6SMatthew Dillon 			return pCap->halRfSilentSupport ? HAL_OK : HAL_ENOTSUPP;
666572ff6f6SMatthew Dillon 		case 1:			/* current setting */
667572ff6f6SMatthew Dillon 			return AH_PRIVATE(ah)->ah_rfkillEnabled ?
668572ff6f6SMatthew Dillon 				HAL_OK : HAL_ENOTSUPP;
669572ff6f6SMatthew Dillon 		case 2:			/* rfsilent config */
670572ff6f6SMatthew Dillon 			*result = AH_PRIVATE(ah)->ah_rfsilent;
671572ff6f6SMatthew Dillon 			return HAL_OK;
672572ff6f6SMatthew Dillon 		}
673572ff6f6SMatthew Dillon 		return HAL_ENOTSUPP;
674572ff6f6SMatthew Dillon 	case HAL_CAP_11D:
675572ff6f6SMatthew Dillon 		return HAL_OK;
676572ff6f6SMatthew Dillon 
677572ff6f6SMatthew Dillon 	case HAL_CAP_HT:
678572ff6f6SMatthew Dillon 		return pCap->halHTSupport ? HAL_OK : HAL_ENOTSUPP;
679572ff6f6SMatthew Dillon 	case HAL_CAP_GTXTO:
680572ff6f6SMatthew Dillon 		return pCap->halGTTSupport ? HAL_OK : HAL_ENOTSUPP;
681572ff6f6SMatthew Dillon 	case HAL_CAP_FAST_CC:
682572ff6f6SMatthew Dillon 		return pCap->halFastCCSupport ? HAL_OK : HAL_ENOTSUPP;
683572ff6f6SMatthew Dillon 	case HAL_CAP_TX_CHAINMASK:	/* mask of TX chains supported */
684572ff6f6SMatthew Dillon 		*result = pCap->halTxChainMask;
685572ff6f6SMatthew Dillon 		return HAL_OK;
686572ff6f6SMatthew Dillon 	case HAL_CAP_RX_CHAINMASK:	/* mask of RX chains supported */
687572ff6f6SMatthew Dillon 		*result = pCap->halRxChainMask;
688572ff6f6SMatthew Dillon 		return HAL_OK;
689572ff6f6SMatthew Dillon 	case HAL_CAP_NUM_GPIO_PINS:
690572ff6f6SMatthew Dillon 		*result = pCap->halNumGpioPins;
691572ff6f6SMatthew Dillon 		return HAL_OK;
692572ff6f6SMatthew Dillon 	case HAL_CAP_CST:
693572ff6f6SMatthew Dillon 		return pCap->halCSTSupport ? HAL_OK : HAL_ENOTSUPP;
694572ff6f6SMatthew Dillon 	case HAL_CAP_RTS_AGGR_LIMIT:
695572ff6f6SMatthew Dillon 		*result = pCap->halRtsAggrLimit;
696572ff6f6SMatthew Dillon 		return HAL_OK;
697572ff6f6SMatthew Dillon 	case HAL_CAP_4ADDR_AGGR:
698572ff6f6SMatthew Dillon 		return pCap->hal4AddrAggrSupport ? HAL_OK : HAL_ENOTSUPP;
699572ff6f6SMatthew Dillon 	case HAL_CAP_EXT_CHAN_DFS:
700572ff6f6SMatthew Dillon 		return pCap->halExtChanDfsSupport ? HAL_OK : HAL_ENOTSUPP;
701572ff6f6SMatthew Dillon 	case HAL_CAP_RX_STBC:
702572ff6f6SMatthew Dillon 		return pCap->halRxStbcSupport ? HAL_OK : HAL_ENOTSUPP;
703572ff6f6SMatthew Dillon 	case HAL_CAP_TX_STBC:
704572ff6f6SMatthew Dillon 		return pCap->halTxStbcSupport ? HAL_OK : HAL_ENOTSUPP;
705572ff6f6SMatthew Dillon 	case HAL_CAP_COMBINED_RADAR_RSSI:
706572ff6f6SMatthew Dillon 		return pCap->halUseCombinedRadarRssi ? HAL_OK : HAL_ENOTSUPP;
707572ff6f6SMatthew Dillon 	case HAL_CAP_AUTO_SLEEP:
708572ff6f6SMatthew Dillon 		return pCap->halAutoSleepSupport ? HAL_OK : HAL_ENOTSUPP;
709572ff6f6SMatthew Dillon 	case HAL_CAP_MBSSID_AGGR_SUPPORT:
710572ff6f6SMatthew Dillon 		return pCap->halMbssidAggrSupport ? HAL_OK : HAL_ENOTSUPP;
711572ff6f6SMatthew Dillon 	case HAL_CAP_SPLIT_4KB_TRANS:	/* hardware handles descriptors straddling 4k page boundary */
712572ff6f6SMatthew Dillon 		return pCap->hal4kbSplitTransSupport ? HAL_OK : HAL_ENOTSUPP;
713572ff6f6SMatthew Dillon 	case HAL_CAP_REG_FLAG:
714572ff6f6SMatthew Dillon 		*result = AH_PRIVATE(ah)->ah_currentRDext;
715572ff6f6SMatthew Dillon 		return HAL_OK;
716572ff6f6SMatthew Dillon 	case HAL_CAP_ENHANCED_DMA_SUPPORT:
717572ff6f6SMatthew Dillon 		return pCap->halEnhancedDmaSupport ? HAL_OK : HAL_ENOTSUPP;
718572ff6f6SMatthew Dillon 	case HAL_CAP_NUM_TXMAPS:
719572ff6f6SMatthew Dillon 		*result = pCap->halNumTxMaps;
720572ff6f6SMatthew Dillon 		return HAL_OK;
721572ff6f6SMatthew Dillon 	case HAL_CAP_TXDESCLEN:
722572ff6f6SMatthew Dillon 		*result = pCap->halTxDescLen;
723572ff6f6SMatthew Dillon 		return HAL_OK;
724572ff6f6SMatthew Dillon 	case HAL_CAP_TXSTATUSLEN:
725572ff6f6SMatthew Dillon 		*result = pCap->halTxStatusLen;
726572ff6f6SMatthew Dillon 		return HAL_OK;
727572ff6f6SMatthew Dillon 	case HAL_CAP_RXSTATUSLEN:
728572ff6f6SMatthew Dillon 		*result = pCap->halRxStatusLen;
729572ff6f6SMatthew Dillon 		return HAL_OK;
730572ff6f6SMatthew Dillon 	case HAL_CAP_RXFIFODEPTH:
731572ff6f6SMatthew Dillon 		switch (capability) {
732572ff6f6SMatthew Dillon 		case HAL_RX_QUEUE_HP:
733572ff6f6SMatthew Dillon 			*result = pCap->halRxHpFifoDepth;
734572ff6f6SMatthew Dillon 			return HAL_OK;
735572ff6f6SMatthew Dillon 		case HAL_RX_QUEUE_LP:
736572ff6f6SMatthew Dillon 			*result = pCap->halRxLpFifoDepth;
737572ff6f6SMatthew Dillon 			return HAL_OK;
738572ff6f6SMatthew Dillon 		default:
739572ff6f6SMatthew Dillon 			return HAL_ENOTSUPP;
740572ff6f6SMatthew Dillon 	}
741572ff6f6SMatthew Dillon 	case HAL_CAP_RXBUFSIZE:
742572ff6f6SMatthew Dillon 	case HAL_CAP_NUM_MR_RETRIES:
743572ff6f6SMatthew Dillon 		*result = pCap->halNumMRRetries;
744572ff6f6SMatthew Dillon 		return HAL_OK;
745572ff6f6SMatthew Dillon 	case HAL_CAP_BT_COEX:
746572ff6f6SMatthew Dillon 		return pCap->halBtCoexSupport ? HAL_OK : HAL_ENOTSUPP;
747572ff6f6SMatthew Dillon 	case HAL_CAP_SPECTRAL_SCAN:
748572ff6f6SMatthew Dillon 		return pCap->halSpectralScanSupport ? HAL_OK : HAL_ENOTSUPP;
749572ff6f6SMatthew Dillon 	case HAL_CAP_HT20_SGI:
750572ff6f6SMatthew Dillon 		return pCap->halHTSGI20Support ? HAL_OK : HAL_ENOTSUPP;
751572ff6f6SMatthew Dillon 	case HAL_CAP_RXTSTAMP_PREC:	/* rx desc tstamp precision (bits) */
752572ff6f6SMatthew Dillon 		*result = pCap->halTstampPrecision;
753572ff6f6SMatthew Dillon 		return HAL_OK;
754572ff6f6SMatthew Dillon 	case HAL_CAP_ANT_DIV_COMB:	/* AR9285/AR9485 LNA diversity */
755572ff6f6SMatthew Dillon 		return pCap->halAntDivCombSupport ? HAL_OK  : HAL_ENOTSUPP;
756572ff6f6SMatthew Dillon 
757572ff6f6SMatthew Dillon 	case HAL_CAP_ENHANCED_DFS_SUPPORT:
758572ff6f6SMatthew Dillon 		return pCap->halEnhancedDfsSupport ? HAL_OK : HAL_ENOTSUPP;
759572ff6f6SMatthew Dillon 
760572ff6f6SMatthew Dillon 	/* FreeBSD-specific entries for now */
761572ff6f6SMatthew Dillon 	case HAL_CAP_RXORN_FATAL:	/* HAL_INT_RXORN treated as fatal  */
762572ff6f6SMatthew Dillon 		return AH_PRIVATE(ah)->ah_rxornIsFatal ? HAL_OK : HAL_ENOTSUPP;
763572ff6f6SMatthew Dillon 	case HAL_CAP_INTRMASK:		/* mask of supported interrupts */
764572ff6f6SMatthew Dillon 		*result = pCap->halIntrMask;
765572ff6f6SMatthew Dillon 		return HAL_OK;
766572ff6f6SMatthew Dillon 	case HAL_CAP_BSSIDMATCH:	/* hardware has disable bssid match */
767572ff6f6SMatthew Dillon 		return pCap->halBssidMatchSupport ? HAL_OK : HAL_ENOTSUPP;
768572ff6f6SMatthew Dillon 	case HAL_CAP_STREAMS:		/* number of 11n spatial streams */
769572ff6f6SMatthew Dillon 		switch (capability) {
770572ff6f6SMatthew Dillon 		case 0:			/* TX */
771572ff6f6SMatthew Dillon 			*result = pCap->halTxStreams;
772572ff6f6SMatthew Dillon 			return HAL_OK;
773572ff6f6SMatthew Dillon 		case 1:			/* RX */
774572ff6f6SMatthew Dillon 			*result = pCap->halRxStreams;
775572ff6f6SMatthew Dillon 			return HAL_OK;
776572ff6f6SMatthew Dillon 		default:
777572ff6f6SMatthew Dillon 			return HAL_ENOTSUPP;
778572ff6f6SMatthew Dillon 		}
779572ff6f6SMatthew Dillon 	case HAL_CAP_RXDESC_SELFLINK:	/* hardware supports self-linked final RX descriptors correctly */
780572ff6f6SMatthew Dillon 		return pCap->halHasRxSelfLinkedTail ? HAL_OK : HAL_ENOTSUPP;
781572ff6f6SMatthew Dillon 	case HAL_CAP_LONG_RXDESC_TSF:		/* 32 bit TSF in RX descriptor? */
782572ff6f6SMatthew Dillon 		return pCap->halHasLongRxDescTsf ? HAL_OK : HAL_ENOTSUPP;
783572ff6f6SMatthew Dillon 	case HAL_CAP_BB_READ_WAR:		/* Baseband read WAR */
784572ff6f6SMatthew Dillon 		return pCap->halHasBBReadWar? HAL_OK : HAL_ENOTSUPP;
785572ff6f6SMatthew Dillon 	case HAL_CAP_SERIALISE_WAR:		/* PCI register serialisation */
786572ff6f6SMatthew Dillon 		return pCap->halSerialiseRegWar ? HAL_OK : HAL_ENOTSUPP;
787572ff6f6SMatthew Dillon 	case HAL_CAP_MFP:			/* Management frame protection setting */
788572ff6f6SMatthew Dillon 		*result = pCap->halMfpSupport;
789572ff6f6SMatthew Dillon 		return HAL_OK;
790572ff6f6SMatthew Dillon 	case HAL_CAP_RX_LNA_MIXING:	/* Hardware uses an RX LNA mixer to map 2 antennas to a 1 stream receiver */
791572ff6f6SMatthew Dillon 		return pCap->halRxUsingLnaMixing ? HAL_OK : HAL_ENOTSUPP;
792d98a0bcfSMatthew Dillon 	case HAL_CAP_DO_MYBEACON:	/* Hardware supports filtering my-beacons */
793d98a0bcfSMatthew Dillon 		return pCap->halRxDoMyBeacon ? HAL_OK : HAL_ENOTSUPP;
794572ff6f6SMatthew Dillon 	default:
795572ff6f6SMatthew Dillon 		return HAL_EINVAL;
796572ff6f6SMatthew Dillon 	}
797572ff6f6SMatthew Dillon }
798572ff6f6SMatthew Dillon 
799572ff6f6SMatthew Dillon HAL_BOOL
ath_hal_setcapability(struct ath_hal * ah,HAL_CAPABILITY_TYPE type,uint32_t capability,uint32_t setting,HAL_STATUS * status)800572ff6f6SMatthew Dillon ath_hal_setcapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type,
801572ff6f6SMatthew Dillon 	uint32_t capability, uint32_t setting, HAL_STATUS *status)
802572ff6f6SMatthew Dillon {
803572ff6f6SMatthew Dillon 
804572ff6f6SMatthew Dillon 	switch (type) {
805572ff6f6SMatthew Dillon 	case HAL_CAP_TXPOW:
806572ff6f6SMatthew Dillon 		switch (capability) {
807572ff6f6SMatthew Dillon 		case 3:
808572ff6f6SMatthew Dillon 			if (setting <= HAL_TP_SCALE_MIN) {
809572ff6f6SMatthew Dillon 				AH_PRIVATE(ah)->ah_tpScale = setting;
810572ff6f6SMatthew Dillon 				return AH_TRUE;
811572ff6f6SMatthew Dillon 			}
812572ff6f6SMatthew Dillon 			break;
813572ff6f6SMatthew Dillon 		}
814572ff6f6SMatthew Dillon 		break;
815572ff6f6SMatthew Dillon 	case HAL_CAP_RFSILENT:		/* rfsilent support  */
816572ff6f6SMatthew Dillon 		/*
817572ff6f6SMatthew Dillon 		 * NB: allow even if halRfSilentSupport is false
818572ff6f6SMatthew Dillon 		 *     in case the EEPROM is misprogrammed.
819572ff6f6SMatthew Dillon 		 */
820572ff6f6SMatthew Dillon 		switch (capability) {
821572ff6f6SMatthew Dillon 		case 1:			/* current setting */
822572ff6f6SMatthew Dillon 			AH_PRIVATE(ah)->ah_rfkillEnabled = (setting != 0);
823572ff6f6SMatthew Dillon 			return AH_TRUE;
824572ff6f6SMatthew Dillon 		case 2:			/* rfsilent config */
825572ff6f6SMatthew Dillon 			/* XXX better done per-chip for validation? */
826572ff6f6SMatthew Dillon 			AH_PRIVATE(ah)->ah_rfsilent = setting;
827572ff6f6SMatthew Dillon 			return AH_TRUE;
828572ff6f6SMatthew Dillon 		}
829572ff6f6SMatthew Dillon 		break;
830572ff6f6SMatthew Dillon 	case HAL_CAP_REG_DMN:		/* regulatory domain */
831572ff6f6SMatthew Dillon 		AH_PRIVATE(ah)->ah_currentRD = setting;
832572ff6f6SMatthew Dillon 		return AH_TRUE;
833572ff6f6SMatthew Dillon 	case HAL_CAP_RXORN_FATAL:	/* HAL_INT_RXORN treated as fatal  */
834572ff6f6SMatthew Dillon 		AH_PRIVATE(ah)->ah_rxornIsFatal = setting;
835572ff6f6SMatthew Dillon 		return AH_TRUE;
836572ff6f6SMatthew Dillon 	default:
837572ff6f6SMatthew Dillon 		break;
838572ff6f6SMatthew Dillon 	}
839572ff6f6SMatthew Dillon 	if (status)
840572ff6f6SMatthew Dillon 		*status = HAL_EINVAL;
841572ff6f6SMatthew Dillon 	return AH_FALSE;
842572ff6f6SMatthew Dillon }
843572ff6f6SMatthew Dillon 
844572ff6f6SMatthew Dillon /*
845572ff6f6SMatthew Dillon  * Common support for getDiagState method.
846572ff6f6SMatthew Dillon  */
847572ff6f6SMatthew Dillon 
848572ff6f6SMatthew Dillon static u_int
ath_hal_getregdump(struct ath_hal * ah,const HAL_REGRANGE * regs,void * dstbuf,int space)849572ff6f6SMatthew Dillon ath_hal_getregdump(struct ath_hal *ah, const HAL_REGRANGE *regs,
850572ff6f6SMatthew Dillon 	void *dstbuf, int space)
851572ff6f6SMatthew Dillon {
852572ff6f6SMatthew Dillon 	uint32_t *dp = dstbuf;
853572ff6f6SMatthew Dillon 	int i;
854572ff6f6SMatthew Dillon 
855572ff6f6SMatthew Dillon 	for (i = 0; space >= 2*sizeof(uint32_t); i++) {
856848b370cSMatthew Dillon 		uint32_t r = regs[i].start;
857848b370cSMatthew Dillon 		uint32_t e = regs[i].end;
858848b370cSMatthew Dillon 		*dp++ = r;
859848b370cSMatthew Dillon 		*dp++ = e;
860848b370cSMatthew Dillon 		space -= 2*sizeof(uint32_t);
861572ff6f6SMatthew Dillon 		do {
862572ff6f6SMatthew Dillon 			*dp++ = OS_REG_READ(ah, r);
863572ff6f6SMatthew Dillon 			r += sizeof(uint32_t);
864572ff6f6SMatthew Dillon 			space -= sizeof(uint32_t);
865572ff6f6SMatthew Dillon 		} while (r <= e && space >= sizeof(uint32_t));
866572ff6f6SMatthew Dillon 	}
867572ff6f6SMatthew Dillon 	return (char *) dp - (char *) dstbuf;
868572ff6f6SMatthew Dillon }
869572ff6f6SMatthew Dillon 
870572ff6f6SMatthew Dillon static void
ath_hal_setregs(struct ath_hal * ah,const HAL_REGWRITE * regs,int space)871572ff6f6SMatthew Dillon ath_hal_setregs(struct ath_hal *ah, const HAL_REGWRITE *regs, int space)
872572ff6f6SMatthew Dillon {
873572ff6f6SMatthew Dillon 	while (space >= sizeof(HAL_REGWRITE)) {
874572ff6f6SMatthew Dillon 		OS_REG_WRITE(ah, regs->addr, regs->value);
875572ff6f6SMatthew Dillon 		regs++, space -= sizeof(HAL_REGWRITE);
876572ff6f6SMatthew Dillon 	}
877572ff6f6SMatthew Dillon }
878572ff6f6SMatthew Dillon 
879572ff6f6SMatthew Dillon HAL_BOOL
ath_hal_getdiagstate(struct ath_hal * ah,int request,const void * args,uint32_t argsize,void ** result,uint32_t * resultsize)880572ff6f6SMatthew Dillon ath_hal_getdiagstate(struct ath_hal *ah, int request,
881572ff6f6SMatthew Dillon 	const void *args, uint32_t argsize,
882572ff6f6SMatthew Dillon 	void **result, uint32_t *resultsize)
883572ff6f6SMatthew Dillon {
884*b14ca477SMatthew Dillon 
885572ff6f6SMatthew Dillon 	switch (request) {
886572ff6f6SMatthew Dillon 	case HAL_DIAG_REVS:
887572ff6f6SMatthew Dillon 		*result = &AH_PRIVATE(ah)->ah_devid;
888572ff6f6SMatthew Dillon 		*resultsize = sizeof(HAL_REVS);
889572ff6f6SMatthew Dillon 		return AH_TRUE;
890572ff6f6SMatthew Dillon 	case HAL_DIAG_REGS:
891572ff6f6SMatthew Dillon 		*resultsize = ath_hal_getregdump(ah, args, *result,*resultsize);
892572ff6f6SMatthew Dillon 		return AH_TRUE;
893572ff6f6SMatthew Dillon 	case HAL_DIAG_SETREGS:
894572ff6f6SMatthew Dillon 		ath_hal_setregs(ah, args, argsize);
895572ff6f6SMatthew Dillon 		*resultsize = 0;
896572ff6f6SMatthew Dillon 		return AH_TRUE;
897572ff6f6SMatthew Dillon 	case HAL_DIAG_FATALERR:
898572ff6f6SMatthew Dillon 		*result = &AH_PRIVATE(ah)->ah_fatalState[0];
899572ff6f6SMatthew Dillon 		*resultsize = sizeof(AH_PRIVATE(ah)->ah_fatalState);
900572ff6f6SMatthew Dillon 		return AH_TRUE;
901572ff6f6SMatthew Dillon 	case HAL_DIAG_EEREAD:
902572ff6f6SMatthew Dillon 		if (argsize != sizeof(uint16_t))
903572ff6f6SMatthew Dillon 			return AH_FALSE;
904572ff6f6SMatthew Dillon 		if (!ath_hal_eepromRead(ah, *(const uint16_t *)args, *result))
905572ff6f6SMatthew Dillon 			return AH_FALSE;
906572ff6f6SMatthew Dillon 		*resultsize = sizeof(uint16_t);
907572ff6f6SMatthew Dillon 		return AH_TRUE;
908572ff6f6SMatthew Dillon #ifdef AH_PRIVATE_DIAG
909572ff6f6SMatthew Dillon 	case HAL_DIAG_SETKEY: {
910572ff6f6SMatthew Dillon 		const HAL_DIAG_KEYVAL *dk;
911572ff6f6SMatthew Dillon 
912572ff6f6SMatthew Dillon 		if (argsize != sizeof(HAL_DIAG_KEYVAL))
913572ff6f6SMatthew Dillon 			return AH_FALSE;
914572ff6f6SMatthew Dillon 		dk = (const HAL_DIAG_KEYVAL *)args;
915572ff6f6SMatthew Dillon 		return ah->ah_setKeyCacheEntry(ah, dk->dk_keyix,
916572ff6f6SMatthew Dillon 			&dk->dk_keyval, dk->dk_mac, dk->dk_xor);
917572ff6f6SMatthew Dillon 	}
918572ff6f6SMatthew Dillon 	case HAL_DIAG_RESETKEY:
919572ff6f6SMatthew Dillon 		if (argsize != sizeof(uint16_t))
920572ff6f6SMatthew Dillon 			return AH_FALSE;
921572ff6f6SMatthew Dillon 		return ah->ah_resetKeyCacheEntry(ah, *(const uint16_t *)args);
922572ff6f6SMatthew Dillon #ifdef AH_SUPPORT_WRITE_EEPROM
923572ff6f6SMatthew Dillon 	case HAL_DIAG_EEWRITE: {
924572ff6f6SMatthew Dillon 		const HAL_DIAG_EEVAL *ee;
925572ff6f6SMatthew Dillon 		if (argsize != sizeof(HAL_DIAG_EEVAL))
926572ff6f6SMatthew Dillon 			return AH_FALSE;
927572ff6f6SMatthew Dillon 		ee = (const HAL_DIAG_EEVAL *)args;
928572ff6f6SMatthew Dillon 		return ath_hal_eepromWrite(ah, ee->ee_off, ee->ee_data);
929572ff6f6SMatthew Dillon 	}
930572ff6f6SMatthew Dillon #endif /* AH_SUPPORT_WRITE_EEPROM */
931572ff6f6SMatthew Dillon #endif /* AH_PRIVATE_DIAG */
932572ff6f6SMatthew Dillon 	case HAL_DIAG_11NCOMPAT:
933572ff6f6SMatthew Dillon 		if (argsize == 0) {
934572ff6f6SMatthew Dillon 			*resultsize = sizeof(uint32_t);
935572ff6f6SMatthew Dillon 			*((uint32_t *)(*result)) =
936572ff6f6SMatthew Dillon 				AH_PRIVATE(ah)->ah_11nCompat;
937572ff6f6SMatthew Dillon 		} else if (argsize == sizeof(uint32_t)) {
938572ff6f6SMatthew Dillon 			AH_PRIVATE(ah)->ah_11nCompat = *(const uint32_t *)args;
939572ff6f6SMatthew Dillon 		} else
940572ff6f6SMatthew Dillon 			return AH_FALSE;
941572ff6f6SMatthew Dillon 		return AH_TRUE;
942572ff6f6SMatthew Dillon 	}
943572ff6f6SMatthew Dillon 	return AH_FALSE;
944572ff6f6SMatthew Dillon }
945572ff6f6SMatthew Dillon 
946572ff6f6SMatthew Dillon /*
947572ff6f6SMatthew Dillon  * Set the properties of the tx queue with the parameters
948572ff6f6SMatthew Dillon  * from qInfo.
949572ff6f6SMatthew Dillon  */
950572ff6f6SMatthew Dillon HAL_BOOL
ath_hal_setTxQProps(struct ath_hal * ah,HAL_TX_QUEUE_INFO * qi,const HAL_TXQ_INFO * qInfo)951572ff6f6SMatthew Dillon ath_hal_setTxQProps(struct ath_hal *ah,
952572ff6f6SMatthew Dillon 	HAL_TX_QUEUE_INFO *qi, const HAL_TXQ_INFO *qInfo)
953572ff6f6SMatthew Dillon {
954572ff6f6SMatthew Dillon 	uint32_t cw;
955572ff6f6SMatthew Dillon 
956572ff6f6SMatthew Dillon 	if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) {
957572ff6f6SMatthew Dillon 		HALDEBUG(ah, HAL_DEBUG_TXQUEUE,
958572ff6f6SMatthew Dillon 		    "%s: inactive queue\n", __func__);
959572ff6f6SMatthew Dillon 		return AH_FALSE;
960572ff6f6SMatthew Dillon 	}
961572ff6f6SMatthew Dillon 	/* XXX validate parameters */
962572ff6f6SMatthew Dillon 	qi->tqi_ver = qInfo->tqi_ver;
963572ff6f6SMatthew Dillon 	qi->tqi_subtype = qInfo->tqi_subtype;
964572ff6f6SMatthew Dillon 	qi->tqi_qflags = qInfo->tqi_qflags;
965572ff6f6SMatthew Dillon 	qi->tqi_priority = qInfo->tqi_priority;
966572ff6f6SMatthew Dillon 	if (qInfo->tqi_aifs != HAL_TXQ_USEDEFAULT)
967572ff6f6SMatthew Dillon 		qi->tqi_aifs = AH_MIN(qInfo->tqi_aifs, 255);
968572ff6f6SMatthew Dillon 	else
969572ff6f6SMatthew Dillon 		qi->tqi_aifs = INIT_AIFS;
970572ff6f6SMatthew Dillon 	if (qInfo->tqi_cwmin != HAL_TXQ_USEDEFAULT) {
971572ff6f6SMatthew Dillon 		cw = AH_MIN(qInfo->tqi_cwmin, 1024);
972572ff6f6SMatthew Dillon 		/* make sure that the CWmin is of the form (2^n - 1) */
973572ff6f6SMatthew Dillon 		qi->tqi_cwmin = 1;
974572ff6f6SMatthew Dillon 		while (qi->tqi_cwmin < cw)
975572ff6f6SMatthew Dillon 			qi->tqi_cwmin = (qi->tqi_cwmin << 1) | 1;
976572ff6f6SMatthew Dillon 	} else
977572ff6f6SMatthew Dillon 		qi->tqi_cwmin = qInfo->tqi_cwmin;
978572ff6f6SMatthew Dillon 	if (qInfo->tqi_cwmax != HAL_TXQ_USEDEFAULT) {
979572ff6f6SMatthew Dillon 		cw = AH_MIN(qInfo->tqi_cwmax, 1024);
980572ff6f6SMatthew Dillon 		/* make sure that the CWmax is of the form (2^n - 1) */
981572ff6f6SMatthew Dillon 		qi->tqi_cwmax = 1;
982572ff6f6SMatthew Dillon 		while (qi->tqi_cwmax < cw)
983572ff6f6SMatthew Dillon 			qi->tqi_cwmax = (qi->tqi_cwmax << 1) | 1;
984572ff6f6SMatthew Dillon 	} else
985572ff6f6SMatthew Dillon 		qi->tqi_cwmax = INIT_CWMAX;
986572ff6f6SMatthew Dillon 	/* Set retry limit values */
987572ff6f6SMatthew Dillon 	if (qInfo->tqi_shretry != 0)
988572ff6f6SMatthew Dillon 		qi->tqi_shretry = AH_MIN(qInfo->tqi_shretry, 15);
989572ff6f6SMatthew Dillon 	else
990572ff6f6SMatthew Dillon 		qi->tqi_shretry = INIT_SH_RETRY;
991572ff6f6SMatthew Dillon 	if (qInfo->tqi_lgretry != 0)
992572ff6f6SMatthew Dillon 		qi->tqi_lgretry = AH_MIN(qInfo->tqi_lgretry, 15);
993572ff6f6SMatthew Dillon 	else
994572ff6f6SMatthew Dillon 		qi->tqi_lgretry = INIT_LG_RETRY;
995572ff6f6SMatthew Dillon 	qi->tqi_cbrPeriod = qInfo->tqi_cbrPeriod;
996572ff6f6SMatthew Dillon 	qi->tqi_cbrOverflowLimit = qInfo->tqi_cbrOverflowLimit;
997572ff6f6SMatthew Dillon 	qi->tqi_burstTime = qInfo->tqi_burstTime;
998572ff6f6SMatthew Dillon 	qi->tqi_readyTime = qInfo->tqi_readyTime;
999572ff6f6SMatthew Dillon 
1000572ff6f6SMatthew Dillon 	switch (qInfo->tqi_subtype) {
1001572ff6f6SMatthew Dillon 	case HAL_WME_UPSD:
1002572ff6f6SMatthew Dillon 		if (qi->tqi_type == HAL_TX_QUEUE_DATA)
1003572ff6f6SMatthew Dillon 			qi->tqi_intFlags = HAL_TXQ_USE_LOCKOUT_BKOFF_DIS;
1004572ff6f6SMatthew Dillon 		break;
1005572ff6f6SMatthew Dillon 	default:
1006572ff6f6SMatthew Dillon 		break;		/* NB: silence compiler */
1007572ff6f6SMatthew Dillon 	}
1008572ff6f6SMatthew Dillon 	return AH_TRUE;
1009572ff6f6SMatthew Dillon }
1010572ff6f6SMatthew Dillon 
1011572ff6f6SMatthew Dillon HAL_BOOL
ath_hal_getTxQProps(struct ath_hal * ah,HAL_TXQ_INFO * qInfo,const HAL_TX_QUEUE_INFO * qi)1012572ff6f6SMatthew Dillon ath_hal_getTxQProps(struct ath_hal *ah,
1013572ff6f6SMatthew Dillon 	HAL_TXQ_INFO *qInfo, const HAL_TX_QUEUE_INFO *qi)
1014572ff6f6SMatthew Dillon {
1015572ff6f6SMatthew Dillon 	if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) {
1016572ff6f6SMatthew Dillon 		HALDEBUG(ah, HAL_DEBUG_TXQUEUE,
1017572ff6f6SMatthew Dillon 		    "%s: inactive queue\n", __func__);
1018572ff6f6SMatthew Dillon 		return AH_FALSE;
1019572ff6f6SMatthew Dillon 	}
1020572ff6f6SMatthew Dillon 
1021572ff6f6SMatthew Dillon 	qInfo->tqi_qflags = qi->tqi_qflags;
1022572ff6f6SMatthew Dillon 	qInfo->tqi_ver = qi->tqi_ver;
1023572ff6f6SMatthew Dillon 	qInfo->tqi_subtype = qi->tqi_subtype;
1024572ff6f6SMatthew Dillon 	qInfo->tqi_qflags = qi->tqi_qflags;
1025572ff6f6SMatthew Dillon 	qInfo->tqi_priority = qi->tqi_priority;
1026572ff6f6SMatthew Dillon 	qInfo->tqi_aifs = qi->tqi_aifs;
1027572ff6f6SMatthew Dillon 	qInfo->tqi_cwmin = qi->tqi_cwmin;
1028572ff6f6SMatthew Dillon 	qInfo->tqi_cwmax = qi->tqi_cwmax;
1029572ff6f6SMatthew Dillon 	qInfo->tqi_shretry = qi->tqi_shretry;
1030572ff6f6SMatthew Dillon 	qInfo->tqi_lgretry = qi->tqi_lgretry;
1031572ff6f6SMatthew Dillon 	qInfo->tqi_cbrPeriod = qi->tqi_cbrPeriod;
1032572ff6f6SMatthew Dillon 	qInfo->tqi_cbrOverflowLimit = qi->tqi_cbrOverflowLimit;
1033572ff6f6SMatthew Dillon 	qInfo->tqi_burstTime = qi->tqi_burstTime;
1034572ff6f6SMatthew Dillon 	qInfo->tqi_readyTime = qi->tqi_readyTime;
1035572ff6f6SMatthew Dillon 	return AH_TRUE;
1036572ff6f6SMatthew Dillon }
1037572ff6f6SMatthew Dillon 
1038572ff6f6SMatthew Dillon                                      /* 11a Turbo  11b  11g  108g */
1039572ff6f6SMatthew Dillon static const int16_t NOISE_FLOOR[] = { -96, -93,  -98, -96,  -93 };
1040572ff6f6SMatthew Dillon 
1041572ff6f6SMatthew Dillon /*
1042572ff6f6SMatthew Dillon  * Read the current channel noise floor and return.
1043572ff6f6SMatthew Dillon  * If nf cal hasn't finished, channel noise floor should be 0
1044572ff6f6SMatthew Dillon  * and we return a nominal value based on band and frequency.
1045572ff6f6SMatthew Dillon  *
1046572ff6f6SMatthew Dillon  * NB: This is a private routine used by per-chip code to
1047572ff6f6SMatthew Dillon  *     implement the ah_getChanNoise method.
1048572ff6f6SMatthew Dillon  */
1049572ff6f6SMatthew Dillon int16_t
ath_hal_getChanNoise(struct ath_hal * ah,const struct ieee80211_channel * chan)1050572ff6f6SMatthew Dillon ath_hal_getChanNoise(struct ath_hal *ah, const struct ieee80211_channel *chan)
1051572ff6f6SMatthew Dillon {
1052572ff6f6SMatthew Dillon 	HAL_CHANNEL_INTERNAL *ichan;
1053572ff6f6SMatthew Dillon 
1054572ff6f6SMatthew Dillon 	ichan = ath_hal_checkchannel(ah, chan);
1055572ff6f6SMatthew Dillon 	if (ichan == AH_NULL) {
1056572ff6f6SMatthew Dillon 		HALDEBUG(ah, HAL_DEBUG_NFCAL,
1057572ff6f6SMatthew Dillon 		    "%s: invalid channel %u/0x%x; no mapping\n",
1058572ff6f6SMatthew Dillon 		    __func__, chan->ic_freq, chan->ic_flags);
1059572ff6f6SMatthew Dillon 		return 0;
1060572ff6f6SMatthew Dillon 	}
1061572ff6f6SMatthew Dillon 	if (ichan->rawNoiseFloor == 0) {
1062572ff6f6SMatthew Dillon 		WIRELESS_MODE mode = ath_hal_chan2wmode(ah, chan);
1063572ff6f6SMatthew Dillon 
1064572ff6f6SMatthew Dillon 		HALASSERT(mode < WIRELESS_MODE_MAX);
1065572ff6f6SMatthew Dillon 		return NOISE_FLOOR[mode] + ath_hal_getNfAdjust(ah, ichan);
1066572ff6f6SMatthew Dillon 	} else
1067572ff6f6SMatthew Dillon 		return ichan->rawNoiseFloor + ichan->noiseFloorAdjust;
1068572ff6f6SMatthew Dillon }
1069572ff6f6SMatthew Dillon 
1070572ff6f6SMatthew Dillon /*
1071572ff6f6SMatthew Dillon  * Fetch the current setup of ctl/ext noise floor values.
1072572ff6f6SMatthew Dillon  *
1073572ff6f6SMatthew Dillon  * If the CHANNEL_MIMO_NF_VALID flag isn't set, the array is simply
1074572ff6f6SMatthew Dillon  * populated with values from NOISE_FLOOR[] + ath_hal_getNfAdjust().
1075572ff6f6SMatthew Dillon  *
1076572ff6f6SMatthew Dillon  * The caller must supply ctl/ext NF arrays which are at least
1077572ff6f6SMatthew Dillon  * AH_MAX_CHAINS entries long.
1078572ff6f6SMatthew Dillon  */
1079572ff6f6SMatthew Dillon int
ath_hal_get_mimo_chan_noise(struct ath_hal * ah,const struct ieee80211_channel * chan,int16_t * nf_ctl,int16_t * nf_ext)1080572ff6f6SMatthew Dillon ath_hal_get_mimo_chan_noise(struct ath_hal *ah,
1081572ff6f6SMatthew Dillon     const struct ieee80211_channel *chan, int16_t *nf_ctl,
1082572ff6f6SMatthew Dillon     int16_t *nf_ext)
1083572ff6f6SMatthew Dillon {
1084572ff6f6SMatthew Dillon #ifdef	AH_SUPPORT_AR5416
1085572ff6f6SMatthew Dillon 	HAL_CHANNEL_INTERNAL *ichan;
1086572ff6f6SMatthew Dillon 	int i;
1087572ff6f6SMatthew Dillon 
1088572ff6f6SMatthew Dillon 	ichan = ath_hal_checkchannel(ah, chan);
1089572ff6f6SMatthew Dillon 	if (ichan == AH_NULL) {
1090572ff6f6SMatthew Dillon 		HALDEBUG(ah, HAL_DEBUG_NFCAL,
1091572ff6f6SMatthew Dillon 		    "%s: invalid channel %u/0x%x; no mapping\n",
1092572ff6f6SMatthew Dillon 		    __func__, chan->ic_freq, chan->ic_flags);
1093572ff6f6SMatthew Dillon 		for (i = 0; i < AH_MAX_CHAINS; i++) {
1094572ff6f6SMatthew Dillon 			nf_ctl[i] = nf_ext[i] = 0;
1095572ff6f6SMatthew Dillon 		}
1096572ff6f6SMatthew Dillon 		return 0;
1097572ff6f6SMatthew Dillon 	}
1098572ff6f6SMatthew Dillon 
1099572ff6f6SMatthew Dillon 	/* Return 0 if there's no valid MIMO values (yet) */
1100572ff6f6SMatthew Dillon 	if (! (ichan->privFlags & CHANNEL_MIMO_NF_VALID)) {
1101572ff6f6SMatthew Dillon 		for (i = 0; i < AH_MAX_CHAINS; i++) {
1102572ff6f6SMatthew Dillon 			nf_ctl[i] = nf_ext[i] = 0;
1103572ff6f6SMatthew Dillon 		}
1104572ff6f6SMatthew Dillon 		return 0;
1105572ff6f6SMatthew Dillon 	}
1106572ff6f6SMatthew Dillon 	if (ichan->rawNoiseFloor == 0) {
1107572ff6f6SMatthew Dillon 		WIRELESS_MODE mode = ath_hal_chan2wmode(ah, chan);
1108572ff6f6SMatthew Dillon 		HALASSERT(mode < WIRELESS_MODE_MAX);
1109572ff6f6SMatthew Dillon 		/*
1110572ff6f6SMatthew Dillon 		 * See the comment below - this could cause issues for
1111572ff6f6SMatthew Dillon 		 * stations which have a very low RSSI, below the
1112572ff6f6SMatthew Dillon 		 * 'normalised' NF values in NOISE_FLOOR[].
1113572ff6f6SMatthew Dillon 		 */
1114572ff6f6SMatthew Dillon 		for (i = 0; i < AH_MAX_CHAINS; i++) {
1115572ff6f6SMatthew Dillon 			nf_ctl[i] = nf_ext[i] = NOISE_FLOOR[mode] +
1116572ff6f6SMatthew Dillon 			    ath_hal_getNfAdjust(ah, ichan);
1117572ff6f6SMatthew Dillon 		}
1118572ff6f6SMatthew Dillon 		return 1;
1119572ff6f6SMatthew Dillon 	} else {
1120572ff6f6SMatthew Dillon 		/*
1121572ff6f6SMatthew Dillon 		 * The value returned here from a MIMO radio is presumed to be
1122572ff6f6SMatthew Dillon 		 * "good enough" as a NF calculation. As RSSI values are calculated
1123572ff6f6SMatthew Dillon 		 * against this, an adjusted NF may be higher than the RSSI value
1124572ff6f6SMatthew Dillon 		 * returned from a vary weak station, resulting in an obscenely
1125572ff6f6SMatthew Dillon 		 * high signal strength calculation being returned.
1126572ff6f6SMatthew Dillon 		 *
1127572ff6f6SMatthew Dillon 		 * This should be re-evaluated at a later date, along with any
1128572ff6f6SMatthew Dillon 		 * signal strength calculations which are made. Quite likely the
1129572ff6f6SMatthew Dillon 		 * RSSI values will need to be adjusted to ensure the calculations
1130572ff6f6SMatthew Dillon 		 * don't "wrap" when RSSI is less than the "adjusted" NF value.
1131572ff6f6SMatthew Dillon 		 * ("Adjust" here is via ichan->noiseFloorAdjust.)
1132572ff6f6SMatthew Dillon 		 */
1133572ff6f6SMatthew Dillon 		for (i = 0; i < AH_MAX_CHAINS; i++) {
1134572ff6f6SMatthew Dillon 			nf_ctl[i] = ichan->noiseFloorCtl[i] + ath_hal_getNfAdjust(ah, ichan);
1135572ff6f6SMatthew Dillon 			nf_ext[i] = ichan->noiseFloorExt[i] + ath_hal_getNfAdjust(ah, ichan);
1136572ff6f6SMatthew Dillon 		}
1137572ff6f6SMatthew Dillon 		return 1;
1138572ff6f6SMatthew Dillon 	}
1139572ff6f6SMatthew Dillon #else
1140572ff6f6SMatthew Dillon 	return 0;
1141572ff6f6SMatthew Dillon #endif	/* AH_SUPPORT_AR5416 */
1142572ff6f6SMatthew Dillon }
1143572ff6f6SMatthew Dillon 
1144572ff6f6SMatthew Dillon /*
1145572ff6f6SMatthew Dillon  * Process all valid raw noise floors into the dBm noise floor values.
1146572ff6f6SMatthew Dillon  * Though our device has no reference for a dBm noise floor, we perform
1147572ff6f6SMatthew Dillon  * a relative minimization of NF's based on the lowest NF found across a
1148572ff6f6SMatthew Dillon  * channel scan.
1149572ff6f6SMatthew Dillon  */
1150572ff6f6SMatthew Dillon void
ath_hal_process_noisefloor(struct ath_hal * ah)1151572ff6f6SMatthew Dillon ath_hal_process_noisefloor(struct ath_hal *ah)
1152572ff6f6SMatthew Dillon {
1153572ff6f6SMatthew Dillon 	HAL_CHANNEL_INTERNAL *c;
1154572ff6f6SMatthew Dillon 	int16_t correct2, correct5;
1155572ff6f6SMatthew Dillon 	int16_t lowest2, lowest5;
1156572ff6f6SMatthew Dillon 	int i;
1157572ff6f6SMatthew Dillon 
1158572ff6f6SMatthew Dillon 	/*
1159572ff6f6SMatthew Dillon 	 * Find the lowest 2GHz and 5GHz noise floor values after adjusting
1160572ff6f6SMatthew Dillon 	 * for statistically recorded NF/channel deviation.
1161572ff6f6SMatthew Dillon 	 */
1162572ff6f6SMatthew Dillon 	correct2 = lowest2 = 0;
1163572ff6f6SMatthew Dillon 	correct5 = lowest5 = 0;
1164572ff6f6SMatthew Dillon 	for (i = 0; i < AH_PRIVATE(ah)->ah_nchan; i++) {
1165572ff6f6SMatthew Dillon 		WIRELESS_MODE mode;
1166572ff6f6SMatthew Dillon 		int16_t nf;
1167572ff6f6SMatthew Dillon 
1168572ff6f6SMatthew Dillon 		c = &AH_PRIVATE(ah)->ah_channels[i];
1169572ff6f6SMatthew Dillon 		if (c->rawNoiseFloor >= 0)
1170572ff6f6SMatthew Dillon 			continue;
1171572ff6f6SMatthew Dillon 		/* XXX can't identify proper mode */
1172572ff6f6SMatthew Dillon 		mode = IS_CHAN_5GHZ(c) ? WIRELESS_MODE_11a : WIRELESS_MODE_11g;
1173572ff6f6SMatthew Dillon 		nf = c->rawNoiseFloor + NOISE_FLOOR[mode] +
1174572ff6f6SMatthew Dillon 			ath_hal_getNfAdjust(ah, c);
1175572ff6f6SMatthew Dillon 		if (IS_CHAN_5GHZ(c)) {
1176572ff6f6SMatthew Dillon 			if (nf < lowest5) {
1177572ff6f6SMatthew Dillon 				lowest5 = nf;
1178572ff6f6SMatthew Dillon 				correct5 = NOISE_FLOOR[mode] -
1179572ff6f6SMatthew Dillon 				    (c->rawNoiseFloor + ath_hal_getNfAdjust(ah, c));
1180572ff6f6SMatthew Dillon 			}
1181572ff6f6SMatthew Dillon 		} else {
1182572ff6f6SMatthew Dillon 			if (nf < lowest2) {
1183572ff6f6SMatthew Dillon 				lowest2 = nf;
1184572ff6f6SMatthew Dillon 				correct2 = NOISE_FLOOR[mode] -
1185572ff6f6SMatthew Dillon 				    (c->rawNoiseFloor + ath_hal_getNfAdjust(ah, c));
1186572ff6f6SMatthew Dillon 			}
1187572ff6f6SMatthew Dillon 		}
1188572ff6f6SMatthew Dillon 	}
1189572ff6f6SMatthew Dillon 
1190572ff6f6SMatthew Dillon 	/* Correct the channels to reach the expected NF value */
1191572ff6f6SMatthew Dillon 	for (i = 0; i < AH_PRIVATE(ah)->ah_nchan; i++) {
1192572ff6f6SMatthew Dillon 		c = &AH_PRIVATE(ah)->ah_channels[i];
1193572ff6f6SMatthew Dillon 		if (c->rawNoiseFloor >= 0)
1194572ff6f6SMatthew Dillon 			continue;
1195572ff6f6SMatthew Dillon 		/* Apply correction factor */
1196572ff6f6SMatthew Dillon 		c->noiseFloorAdjust = ath_hal_getNfAdjust(ah, c) +
1197572ff6f6SMatthew Dillon 			(IS_CHAN_5GHZ(c) ? correct5 : correct2);
1198572ff6f6SMatthew Dillon 		HALDEBUG(ah, HAL_DEBUG_NFCAL, "%u raw nf %d adjust %d\n",
1199572ff6f6SMatthew Dillon 		    c->channel, c->rawNoiseFloor, c->noiseFloorAdjust);
1200572ff6f6SMatthew Dillon 	}
1201572ff6f6SMatthew Dillon }
1202572ff6f6SMatthew Dillon 
1203572ff6f6SMatthew Dillon /*
1204572ff6f6SMatthew Dillon  * INI support routines.
1205572ff6f6SMatthew Dillon  */
1206572ff6f6SMatthew Dillon 
1207572ff6f6SMatthew Dillon int
ath_hal_ini_write(struct ath_hal * ah,const HAL_INI_ARRAY * ia,int col,int regWr)1208572ff6f6SMatthew Dillon ath_hal_ini_write(struct ath_hal *ah, const HAL_INI_ARRAY *ia,
1209572ff6f6SMatthew Dillon 	int col, int regWr)
1210572ff6f6SMatthew Dillon {
1211572ff6f6SMatthew Dillon 	int r;
1212572ff6f6SMatthew Dillon 
1213572ff6f6SMatthew Dillon 	HALASSERT(col < ia->cols);
1214572ff6f6SMatthew Dillon 	for (r = 0; r < ia->rows; r++) {
1215572ff6f6SMatthew Dillon 		OS_REG_WRITE(ah, HAL_INI_VAL(ia, r, 0),
1216572ff6f6SMatthew Dillon 		    HAL_INI_VAL(ia, r, col));
1217572ff6f6SMatthew Dillon 
1218572ff6f6SMatthew Dillon 		/* Analog shift register delay seems needed for Merlin - PR kern/154220 */
1219572ff6f6SMatthew Dillon 		if (HAL_INI_VAL(ia, r, 0) >= 0x7800 && HAL_INI_VAL(ia, r, 0) < 0x7900)
1220572ff6f6SMatthew Dillon 			OS_DELAY(100);
1221572ff6f6SMatthew Dillon 
1222572ff6f6SMatthew Dillon 		DMA_YIELD(regWr);
1223572ff6f6SMatthew Dillon 	}
1224572ff6f6SMatthew Dillon 	return regWr;
1225572ff6f6SMatthew Dillon }
1226572ff6f6SMatthew Dillon 
1227572ff6f6SMatthew Dillon void
ath_hal_ini_bank_setup(uint32_t data[],const HAL_INI_ARRAY * ia,int col)1228572ff6f6SMatthew Dillon ath_hal_ini_bank_setup(uint32_t data[], const HAL_INI_ARRAY *ia, int col)
1229572ff6f6SMatthew Dillon {
1230572ff6f6SMatthew Dillon 	int r;
1231572ff6f6SMatthew Dillon 
1232572ff6f6SMatthew Dillon 	HALASSERT(col < ia->cols);
1233572ff6f6SMatthew Dillon 	for (r = 0; r < ia->rows; r++)
1234572ff6f6SMatthew Dillon 		data[r] = HAL_INI_VAL(ia, r, col);
1235572ff6f6SMatthew Dillon }
1236572ff6f6SMatthew Dillon 
1237572ff6f6SMatthew Dillon int
ath_hal_ini_bank_write(struct ath_hal * ah,const HAL_INI_ARRAY * ia,const uint32_t data[],int regWr)1238572ff6f6SMatthew Dillon ath_hal_ini_bank_write(struct ath_hal *ah, const HAL_INI_ARRAY *ia,
1239572ff6f6SMatthew Dillon 	const uint32_t data[], int regWr)
1240572ff6f6SMatthew Dillon {
1241572ff6f6SMatthew Dillon 	int r;
1242572ff6f6SMatthew Dillon 
1243572ff6f6SMatthew Dillon 	for (r = 0; r < ia->rows; r++) {
1244572ff6f6SMatthew Dillon 		OS_REG_WRITE(ah, HAL_INI_VAL(ia, r, 0), data[r]);
1245572ff6f6SMatthew Dillon 		DMA_YIELD(regWr);
1246572ff6f6SMatthew Dillon 	}
1247572ff6f6SMatthew Dillon 	return regWr;
1248572ff6f6SMatthew Dillon }
1249572ff6f6SMatthew Dillon 
1250572ff6f6SMatthew Dillon /*
1251572ff6f6SMatthew Dillon  * These are EEPROM board related routines which should likely live in
1252572ff6f6SMatthew Dillon  * a helper library of some sort.
1253572ff6f6SMatthew Dillon  */
1254572ff6f6SMatthew Dillon 
1255572ff6f6SMatthew Dillon /**************************************************************
1256572ff6f6SMatthew Dillon  * ath_ee_getLowerUppderIndex
1257572ff6f6SMatthew Dillon  *
1258572ff6f6SMatthew Dillon  * Return indices surrounding the value in sorted integer lists.
1259572ff6f6SMatthew Dillon  * Requirement: the input list must be monotonically increasing
1260572ff6f6SMatthew Dillon  *     and populated up to the list size
1261572ff6f6SMatthew Dillon  * Returns: match is set if an index in the array matches exactly
1262572ff6f6SMatthew Dillon  *     or a the target is before or after the range of the array.
1263572ff6f6SMatthew Dillon  */
1264572ff6f6SMatthew Dillon HAL_BOOL
ath_ee_getLowerUpperIndex(uint8_t target,uint8_t * pList,uint16_t listSize,uint16_t * indexL,uint16_t * indexR)1265572ff6f6SMatthew Dillon ath_ee_getLowerUpperIndex(uint8_t target, uint8_t *pList, uint16_t listSize,
1266572ff6f6SMatthew Dillon                    uint16_t *indexL, uint16_t *indexR)
1267572ff6f6SMatthew Dillon {
1268572ff6f6SMatthew Dillon     uint16_t i;
1269572ff6f6SMatthew Dillon 
1270572ff6f6SMatthew Dillon     /*
1271572ff6f6SMatthew Dillon      * Check first and last elements for beyond ordered array cases.
1272572ff6f6SMatthew Dillon      */
1273572ff6f6SMatthew Dillon     if (target <= pList[0]) {
1274572ff6f6SMatthew Dillon         *indexL = *indexR = 0;
1275572ff6f6SMatthew Dillon         return AH_TRUE;
1276572ff6f6SMatthew Dillon     }
1277572ff6f6SMatthew Dillon     if (target >= pList[listSize-1]) {
1278572ff6f6SMatthew Dillon         *indexL = *indexR = (uint16_t)(listSize - 1);
1279572ff6f6SMatthew Dillon         return AH_TRUE;
1280572ff6f6SMatthew Dillon     }
1281572ff6f6SMatthew Dillon 
1282572ff6f6SMatthew Dillon     /* look for value being near or between 2 values in list */
1283572ff6f6SMatthew Dillon     for (i = 0; i < listSize - 1; i++) {
1284572ff6f6SMatthew Dillon         /*
1285572ff6f6SMatthew Dillon          * If value is close to the current value of the list
1286572ff6f6SMatthew Dillon          * then target is not between values, it is one of the values
1287572ff6f6SMatthew Dillon          */
1288572ff6f6SMatthew Dillon         if (pList[i] == target) {
1289572ff6f6SMatthew Dillon             *indexL = *indexR = i;
1290572ff6f6SMatthew Dillon             return AH_TRUE;
1291572ff6f6SMatthew Dillon         }
1292572ff6f6SMatthew Dillon         /*
1293572ff6f6SMatthew Dillon          * Look for value being between current value and next value
1294572ff6f6SMatthew Dillon          * if so return these 2 values
1295572ff6f6SMatthew Dillon          */
1296572ff6f6SMatthew Dillon         if (target < pList[i + 1]) {
1297572ff6f6SMatthew Dillon             *indexL = i;
1298572ff6f6SMatthew Dillon             *indexR = (uint16_t)(i + 1);
1299572ff6f6SMatthew Dillon             return AH_FALSE;
1300572ff6f6SMatthew Dillon         }
1301572ff6f6SMatthew Dillon     }
1302572ff6f6SMatthew Dillon     HALASSERT(0);
1303572ff6f6SMatthew Dillon     *indexL = *indexR = 0;
1304572ff6f6SMatthew Dillon     return AH_FALSE;
1305572ff6f6SMatthew Dillon }
1306572ff6f6SMatthew Dillon 
1307572ff6f6SMatthew Dillon /**************************************************************
1308572ff6f6SMatthew Dillon  * ath_ee_FillVpdTable
1309572ff6f6SMatthew Dillon  *
1310572ff6f6SMatthew Dillon  * Fill the Vpdlist for indices Pmax-Pmin
1311572ff6f6SMatthew Dillon  * Note: pwrMin, pwrMax and Vpdlist are all in dBm * 4
1312572ff6f6SMatthew Dillon  */
1313572ff6f6SMatthew Dillon HAL_BOOL
ath_ee_FillVpdTable(uint8_t pwrMin,uint8_t pwrMax,uint8_t * pPwrList,uint8_t * pVpdList,uint16_t numIntercepts,uint8_t * pRetVpdList)1314572ff6f6SMatthew Dillon ath_ee_FillVpdTable(uint8_t pwrMin, uint8_t pwrMax, uint8_t *pPwrList,
1315572ff6f6SMatthew Dillon                    uint8_t *pVpdList, uint16_t numIntercepts, uint8_t *pRetVpdList)
1316572ff6f6SMatthew Dillon {
1317572ff6f6SMatthew Dillon     uint16_t  i, k;
1318572ff6f6SMatthew Dillon     uint8_t   currPwr = pwrMin;
1319572ff6f6SMatthew Dillon     uint16_t  idxL, idxR;
1320572ff6f6SMatthew Dillon 
1321572ff6f6SMatthew Dillon     HALASSERT(pwrMax > pwrMin);
1322572ff6f6SMatthew Dillon     for (i = 0; i <= (pwrMax - pwrMin) / 2; i++) {
1323572ff6f6SMatthew Dillon         ath_ee_getLowerUpperIndex(currPwr, pPwrList, numIntercepts,
1324572ff6f6SMatthew Dillon                            &(idxL), &(idxR));
1325572ff6f6SMatthew Dillon         if (idxR < 1)
1326572ff6f6SMatthew Dillon             idxR = 1;           /* extrapolate below */
1327572ff6f6SMatthew Dillon         if (idxL == numIntercepts - 1)
1328572ff6f6SMatthew Dillon             idxL = (uint16_t)(numIntercepts - 2);   /* extrapolate above */
1329572ff6f6SMatthew Dillon         if (pPwrList[idxL] == pPwrList[idxR])
1330572ff6f6SMatthew Dillon             k = pVpdList[idxL];
1331572ff6f6SMatthew Dillon         else
1332572ff6f6SMatthew Dillon             k = (uint16_t)( ((currPwr - pPwrList[idxL]) * pVpdList[idxR] + (pPwrList[idxR] - currPwr) * pVpdList[idxL]) /
1333572ff6f6SMatthew Dillon                   (pPwrList[idxR] - pPwrList[idxL]) );
1334572ff6f6SMatthew Dillon         HALASSERT(k < 256);
1335572ff6f6SMatthew Dillon         pRetVpdList[i] = (uint8_t)k;
1336572ff6f6SMatthew Dillon         currPwr += 2;               /* half dB steps */
1337572ff6f6SMatthew Dillon     }
1338572ff6f6SMatthew Dillon 
1339572ff6f6SMatthew Dillon     return AH_TRUE;
1340572ff6f6SMatthew Dillon }
1341572ff6f6SMatthew Dillon 
1342572ff6f6SMatthew Dillon /**************************************************************************
1343572ff6f6SMatthew Dillon  * ath_ee_interpolate
1344572ff6f6SMatthew Dillon  *
1345572ff6f6SMatthew Dillon  * Returns signed interpolated or the scaled up interpolated value
1346572ff6f6SMatthew Dillon  */
1347572ff6f6SMatthew Dillon int16_t
ath_ee_interpolate(uint16_t target,uint16_t srcLeft,uint16_t srcRight,int16_t targetLeft,int16_t targetRight)1348572ff6f6SMatthew Dillon ath_ee_interpolate(uint16_t target, uint16_t srcLeft, uint16_t srcRight,
1349572ff6f6SMatthew Dillon             int16_t targetLeft, int16_t targetRight)
1350572ff6f6SMatthew Dillon {
1351572ff6f6SMatthew Dillon     int16_t rv;
1352572ff6f6SMatthew Dillon 
1353572ff6f6SMatthew Dillon     if (srcRight == srcLeft) {
1354572ff6f6SMatthew Dillon         rv = targetLeft;
1355572ff6f6SMatthew Dillon     } else {
1356572ff6f6SMatthew Dillon         rv = (int16_t)( ((target - srcLeft) * targetRight +
1357572ff6f6SMatthew Dillon               (srcRight - target) * targetLeft) / (srcRight - srcLeft) );
1358572ff6f6SMatthew Dillon     }
1359572ff6f6SMatthew Dillon     return rv;
1360572ff6f6SMatthew Dillon }
1361572ff6f6SMatthew Dillon 
1362572ff6f6SMatthew Dillon /*
1363572ff6f6SMatthew Dillon  * Adjust the TSF.
1364572ff6f6SMatthew Dillon  */
1365572ff6f6SMatthew Dillon void
ath_hal_adjusttsf(struct ath_hal * ah,int32_t tsfdelta)1366572ff6f6SMatthew Dillon ath_hal_adjusttsf(struct ath_hal *ah, int32_t tsfdelta)
1367572ff6f6SMatthew Dillon {
1368572ff6f6SMatthew Dillon 	/* XXX handle wrap/overflow */
1369572ff6f6SMatthew Dillon 	OS_REG_WRITE(ah, AR_TSF_L32, OS_REG_READ(ah, AR_TSF_L32) + tsfdelta);
1370572ff6f6SMatthew Dillon }
1371572ff6f6SMatthew Dillon 
1372572ff6f6SMatthew Dillon /*
1373572ff6f6SMatthew Dillon  * Enable or disable CCA.
1374572ff6f6SMatthew Dillon  */
1375572ff6f6SMatthew Dillon void
ath_hal_setcca(struct ath_hal * ah,int ena)1376572ff6f6SMatthew Dillon ath_hal_setcca(struct ath_hal *ah, int ena)
1377572ff6f6SMatthew Dillon {
1378572ff6f6SMatthew Dillon 	/*
1379572ff6f6SMatthew Dillon 	 * NB: fill me in; this is not provided by default because disabling
1380572ff6f6SMatthew Dillon 	 *     CCA in most locales violates regulatory.
1381572ff6f6SMatthew Dillon 	 */
1382572ff6f6SMatthew Dillon }
1383572ff6f6SMatthew Dillon 
1384572ff6f6SMatthew Dillon /*
1385572ff6f6SMatthew Dillon  * Get CCA setting.
1386572ff6f6SMatthew Dillon  */
1387572ff6f6SMatthew Dillon int
ath_hal_getcca(struct ath_hal * ah)1388572ff6f6SMatthew Dillon ath_hal_getcca(struct ath_hal *ah)
1389572ff6f6SMatthew Dillon {
1390572ff6f6SMatthew Dillon 	u_int32_t diag;
1391572ff6f6SMatthew Dillon 	if (ath_hal_getcapability(ah, HAL_CAP_DIAG, 0, &diag) != HAL_OK)
1392572ff6f6SMatthew Dillon 		return 1;
1393572ff6f6SMatthew Dillon 	return ((diag & 0x500000) == 0);
1394572ff6f6SMatthew Dillon }
1395572ff6f6SMatthew Dillon 
1396572ff6f6SMatthew Dillon /*
1397572ff6f6SMatthew Dillon  * This routine is only needed when supporting EEPROM-in-RAM setups
1398572ff6f6SMatthew Dillon  * (eg embedded SoCs and on-board PCI/PCIe devices.)
1399572ff6f6SMatthew Dillon  */
1400572ff6f6SMatthew Dillon /* NB: This is in 16 bit words; not bytes */
1401572ff6f6SMatthew Dillon /* XXX This doesn't belong here!  */
1402572ff6f6SMatthew Dillon #define ATH_DATA_EEPROM_SIZE    2048
1403572ff6f6SMatthew Dillon 
1404572ff6f6SMatthew Dillon HAL_BOOL
ath_hal_EepromDataRead(struct ath_hal * ah,u_int off,uint16_t * data)1405572ff6f6SMatthew Dillon ath_hal_EepromDataRead(struct ath_hal *ah, u_int off, uint16_t *data)
1406572ff6f6SMatthew Dillon {
1407572ff6f6SMatthew Dillon 	if (ah->ah_eepromdata == AH_NULL) {
1408572ff6f6SMatthew Dillon 		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: no eeprom data!\n", __func__);
1409572ff6f6SMatthew Dillon 		return AH_FALSE;
1410572ff6f6SMatthew Dillon 	}
1411572ff6f6SMatthew Dillon 	if (off > ATH_DATA_EEPROM_SIZE) {
1412572ff6f6SMatthew Dillon 		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: offset %x > %x\n",
1413572ff6f6SMatthew Dillon 		    __func__, off, ATH_DATA_EEPROM_SIZE);
1414572ff6f6SMatthew Dillon 		return AH_FALSE;
1415572ff6f6SMatthew Dillon 	}
1416572ff6f6SMatthew Dillon 	(*data) = ah->ah_eepromdata[off];
1417572ff6f6SMatthew Dillon 	return AH_TRUE;
1418572ff6f6SMatthew Dillon }
1419572ff6f6SMatthew Dillon 
1420572ff6f6SMatthew Dillon /*
1421572ff6f6SMatthew Dillon  * Do a 2GHz specific MHz->IEEE based on the hardware
1422572ff6f6SMatthew Dillon  * frequency.
1423572ff6f6SMatthew Dillon  *
1424572ff6f6SMatthew Dillon  * This is the unmapped frequency which is programmed into the hardware.
1425572ff6f6SMatthew Dillon  */
1426572ff6f6SMatthew Dillon int
ath_hal_mhz2ieee_2ghz(struct ath_hal * ah,int freq)1427*b14ca477SMatthew Dillon ath_hal_mhz2ieee_2ghz(struct ath_hal *ah, int freq)
1428572ff6f6SMatthew Dillon {
1429572ff6f6SMatthew Dillon 
1430*b14ca477SMatthew Dillon 	if (freq == 2484)
1431572ff6f6SMatthew Dillon 		return 14;
1432*b14ca477SMatthew Dillon 	if (freq < 2484)
1433*b14ca477SMatthew Dillon 		return ((int) freq - 2407) / 5;
1434572ff6f6SMatthew Dillon 	else
1435*b14ca477SMatthew Dillon 		return 15 + ((freq - 2512) / 20);
1436*b14ca477SMatthew Dillon }
1437*b14ca477SMatthew Dillon 
1438*b14ca477SMatthew Dillon /*
1439*b14ca477SMatthew Dillon  * Clear the current survey data.
1440*b14ca477SMatthew Dillon  *
1441*b14ca477SMatthew Dillon  * This should be done during a channel change.
1442*b14ca477SMatthew Dillon  */
1443*b14ca477SMatthew Dillon void
ath_hal_survey_clear(struct ath_hal * ah)1444*b14ca477SMatthew Dillon ath_hal_survey_clear(struct ath_hal *ah)
1445*b14ca477SMatthew Dillon {
1446*b14ca477SMatthew Dillon 	OS_MEMZERO(&AH_PRIVATE(ah)->ah_chansurvey,
1447*b14ca477SMatthew Dillon 	    sizeof(AH_PRIVATE(ah)->ah_chansurvey));
1448*b14ca477SMatthew Dillon }
1449*b14ca477SMatthew Dillon 
1450*b14ca477SMatthew Dillon /*
1451*b14ca477SMatthew Dillon  * Add a sample to the channel survey.
1452*b14ca477SMatthew Dillon  */
1453*b14ca477SMatthew Dillon void
ath_hal_survey_add_sample(struct ath_hal * ah,HAL_SURVEY_SAMPLE * hs)1454*b14ca477SMatthew Dillon ath_hal_survey_add_sample(struct ath_hal *ah, HAL_SURVEY_SAMPLE *hs)
1455*b14ca477SMatthew Dillon {
1456*b14ca477SMatthew Dillon 	HAL_CHANNEL_SURVEY *cs;
1457*b14ca477SMatthew Dillon 
1458*b14ca477SMatthew Dillon 	cs = &AH_PRIVATE(ah)->ah_chansurvey;
1459*b14ca477SMatthew Dillon 
1460*b14ca477SMatthew Dillon 	OS_MEMCPY(&cs->samples[cs->cur_sample], hs, sizeof(*hs));
1461*b14ca477SMatthew Dillon 	cs->samples[cs->cur_sample].seq_num = cs->cur_seq;
1462*b14ca477SMatthew Dillon 	cs->cur_sample = (cs->cur_sample + 1) % CHANNEL_SURVEY_SAMPLE_COUNT;
1463*b14ca477SMatthew Dillon 	cs->cur_seq++;
1464572ff6f6SMatthew Dillon }
1465