ar5416_xmit.c revision 185406
1263508Sdim/*
2218885Sdim * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
3218885Sdim * Copyright (c) 2002-2008 Atheros Communications, Inc.
4218885Sdim *
5218885Sdim * Permission to use, copy, modify, and/or distribute this software for any
6218885Sdim * purpose with or without fee is hereby granted, provided that the above
7218885Sdim * copyright notice and this permission notice appear in all copies.
8218885Sdim *
9218885Sdim * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10263508Sdim * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11218885Sdim * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12218885Sdim * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13218885Sdim * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14218885Sdim * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15263508Sdim * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16263508Sdim *
17218885Sdim * $Id: ar5416_xmit.c,v 1.9 2008/11/27 22:30:08 sam Exp $
18218885Sdim */
19263508Sdim#include "opt_ah.h"
20218885Sdim
21263508Sdim#include "ah.h"
22263508Sdim#include "ah_desc.h"
23263508Sdim#include "ah_internal.h"
24263508Sdim
25218885Sdim#include "ar5416/ar5416.h"
26263508Sdim#include "ar5416/ar5416reg.h"
27218885Sdim#include "ar5416/ar5416phy.h"
28263508Sdim#include "ar5416/ar5416desc.h"
29263508Sdim
30263508Sdim/*
31263508Sdim * Stop transmit on the specified queue
32263508Sdim */
33218885SdimHAL_BOOL
34263508Sdimar5416StopTxDma(struct ath_hal *ah, u_int q)
35263508Sdim{
36263508Sdim#define	STOP_DMA_TIMEOUT	4000	/* us */
37218885Sdim#define	STOP_DMA_ITER		100	/* us */
38263508Sdim	u_int i;
39218885Sdim
40263508Sdim	HALASSERT(q < AH_PRIVATE(ah)->ah_caps.halTotalQueues);
41263508Sdim
42218885Sdim	HALASSERT(AH5212(ah)->ah_txq[q].tqi_type != HAL_TX_QUEUE_INACTIVE);
43263508Sdim
44263508Sdim	OS_REG_WRITE(ah, AR_Q_TXD, 1 << q);
45263508Sdim	for (i = STOP_DMA_TIMEOUT/STOP_DMA_ITER; i != 0; i--) {
46263508Sdim		if (ar5212NumTxPending(ah, q) == 0)
47263508Sdim			break;
48218885Sdim		OS_DELAY(STOP_DMA_ITER);
49263508Sdim	}
50263508Sdim#ifdef AH_DEBUG
51263508Sdim	if (i == 0) {
52218885Sdim		HALDEBUG(ah, HAL_DEBUG_ANY,
53263508Sdim		    "%s: queue %u DMA did not stop in 400 msec\n", __func__, q);
54263508Sdim		HALDEBUG(ah, HAL_DEBUG_ANY,
55263508Sdim		    "%s: QSTS 0x%x Q_TXE 0x%x Q_TXD 0x%x Q_CBR 0x%x\n", __func__,
56218885Sdim		    OS_REG_READ(ah, AR_QSTS(q)), OS_REG_READ(ah, AR_Q_TXE),
57263508Sdim		    OS_REG_READ(ah, AR_Q_TXD), OS_REG_READ(ah, AR_QCBRCFG(q)));
58263508Sdim		HALDEBUG(ah, HAL_DEBUG_ANY,
59218885Sdim		    "%s: Q_MISC 0x%x Q_RDYTIMECFG 0x%x Q_RDYTIMESHDN 0x%x\n",
60263508Sdim		    __func__, OS_REG_READ(ah, AR_QMISC(q)),
61263508Sdim		    OS_REG_READ(ah, AR_QRDYTIMECFG(q)),
62263508Sdim		    OS_REG_READ(ah, AR_Q_RDYTIMESHDN));
63263508Sdim	}
64218885Sdim#endif /* AH_DEBUG */
65263508Sdim
66263508Sdim	/* ar5416 and up can kill packets at the PCU level */
67263508Sdim	if (ar5212NumTxPending(ah, q)) {
68234353Sdim		uint32_t j;
69263508Sdim
70263508Sdim		HALDEBUG(ah, HAL_DEBUG_TXQUEUE,
71263508Sdim		    "%s: Num of pending TX Frames %d on Q %d\n",
72263508Sdim		    __func__, ar5212NumTxPending(ah, q), q);
73263508Sdim
74263508Sdim		/* Kill last PCU Tx Frame */
75218885Sdim		/* TODO - save off and restore current values of Q1/Q2? */
76263508Sdim		for (j = 0; j < 2; j++) {
77218885Sdim			uint32_t tsfLow = OS_REG_READ(ah, AR_TSF_L32);
78263508Sdim			OS_REG_WRITE(ah, AR_QUIET2,
79218885Sdim			    SM(10, AR_QUIET2_QUIET_DUR));
80263508Sdim			OS_REG_WRITE(ah, AR_QUIET_PERIOD, 100);
81263508Sdim			OS_REG_WRITE(ah, AR_NEXT_QUIET, tsfLow >> 10);
82263508Sdim			OS_REG_SET_BIT(ah, AR_TIMER_MODE, AR_TIMER_MODE_QUIET);
83263508Sdim
84263508Sdim			if ((OS_REG_READ(ah, AR_TSF_L32)>>10) == (tsfLow>>10))
85263508Sdim				break;
86263508Sdim
87263508Sdim			HALDEBUG(ah, HAL_DEBUG_ANY,
88263508Sdim			    "%s: TSF moved while trying to set quiet time "
89218885Sdim			    "TSF: 0x%08x\n", __func__, tsfLow);
90263508Sdim			HALASSERT(j < 1); /* TSF shouldn't count twice or reg access is taking forever */
91263508Sdim		}
92218885Sdim
93263508Sdim		OS_REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_CHAN_IDLE);
94263508Sdim
95263508Sdim		/* Allow the quiet mechanism to do its work */
96218885Sdim		OS_DELAY(200);
97263508Sdim		OS_REG_CLR_BIT(ah, AR_TIMER_MODE, AR_TIMER_MODE_QUIET);
98263508Sdim
99263508Sdim		/* Verify the transmit q is empty */
100263508Sdim		for (i = STOP_DMA_TIMEOUT/STOP_DMA_ITER; i != 0; i--) {
101263508Sdim			if (ar5212NumTxPending(ah, q) == 0)
102263508Sdim				break;
103263508Sdim			OS_DELAY(STOP_DMA_ITER);
104263508Sdim		}
105218885Sdim		if (i == 0) {
106263508Sdim			HALDEBUG(ah, HAL_DEBUG_ANY,
107218885Sdim			    "%s: Failed to stop Tx DMA in %d msec after killing"
108263508Sdim			    " last frame\n", __func__, STOP_DMA_TIMEOUT / 1000);
109263508Sdim		}
110263508Sdim		OS_REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_CHAN_IDLE);
111263508Sdim	}
112263508Sdim
113263508Sdim	OS_REG_WRITE(ah, AR_Q_TXD, 0);
114263508Sdim	return (i != 0);
115263508Sdim#undef STOP_DMA_ITER
116263508Sdim#undef STOP_DMA_TIMEOUT
117263508Sdim}
118263508Sdim
119263508Sdim#define VALID_KEY_TYPES \
120263508Sdim        ((1 << HAL_KEY_TYPE_CLEAR) | (1 << HAL_KEY_TYPE_WEP)|\
121263508Sdim         (1 << HAL_KEY_TYPE_AES)   | (1 << HAL_KEY_TYPE_TKIP))
122263508Sdim#define isValidKeyType(_t)      ((1 << (_t)) & VALID_KEY_TYPES)
123263508Sdim
124263508Sdim#define set11nTries(_series, _index) \
125263508Sdim        (SM((_series)[_index].Tries, AR_XmitDataTries##_index))
126263508Sdim
127263508Sdim#define set11nRate(_series, _index) \
128263508Sdim        (SM((_series)[_index].Rate, AR_XmitRate##_index))
129263508Sdim
130263508Sdim#define set11nPktDurRTSCTS(_series, _index) \
131263508Sdim        (SM((_series)[_index].PktDuration, AR_PacketDur##_index) |\
132218885Sdim         ((_series)[_index].RateFlags & HAL_RATESERIES_RTS_CTS   ?\
133263508Sdim         AR_RTSCTSQual##_index : 0))
134263508Sdim
135218885Sdim#define set11nRateFlags(_series, _index) \
136263508Sdim        ((_series)[_index].RateFlags & HAL_RATESERIES_2040 ? AR_2040_##_index : 0) \
137263508Sdim        |((_series)[_index].RateFlags & HAL_RATESERIES_HALFGI ? AR_GI##_index : 0) \
138263508Sdim        |SM((_series)[_index].ChSel, AR_ChainSel##_index)
139218885Sdim
140263508Sdim/*
141218885Sdim * Descriptor Access Functions
142263508Sdim */
143263508Sdim
144263508Sdim#define VALID_PKT_TYPES \
145263508Sdim        ((1<<HAL_PKT_TYPE_NORMAL)|(1<<HAL_PKT_TYPE_ATIM)|\
146263508Sdim         (1<<HAL_PKT_TYPE_PSPOLL)|(1<<HAL_PKT_TYPE_PROBE_RESP)|\
147263508Sdim         (1<<HAL_PKT_TYPE_BEACON)|(1<<HAL_PKT_TYPE_AMPDU))
148263508Sdim#define isValidPktType(_t)      ((1<<(_t)) & VALID_PKT_TYPES)
149263508Sdim#define VALID_TX_RATES \
150263508Sdim        ((1<<0x0b)|(1<<0x0f)|(1<<0x0a)|(1<<0x0e)|(1<<0x09)|(1<<0x0d)|\
151263508Sdim         (1<<0x08)|(1<<0x0c)|(1<<0x1b)|(1<<0x1a)|(1<<0x1e)|(1<<0x19)|\
152263508Sdim         (1<<0x1d)|(1<<0x18)|(1<<0x1c))
153263508Sdim#define isValidTxRate(_r)       ((1<<(_r)) & VALID_TX_RATES)
154263508Sdim
155263508SdimHAL_BOOL
156218885Sdimar5416SetupTxDesc(struct ath_hal *ah, struct ath_desc *ds,
157263508Sdim	u_int pktLen,
158263508Sdim	u_int hdrLen,
159218885Sdim	HAL_PKT_TYPE type,
160263508Sdim	u_int txPower,
161263508Sdim	u_int txRate0, u_int txTries0,
162263508Sdim	u_int keyIx,
163263508Sdim	u_int antMode,
164263508Sdim	u_int flags,
165263508Sdim	u_int rtsctsRate,
166263508Sdim	u_int rtsctsDuration,
167263508Sdim	u_int compicvLen,
168263508Sdim	u_int compivLen,
169263508Sdim	u_int comp)
170263508Sdim{
171263508Sdim#define	RTSCTS	(HAL_TXDESC_RTSENA|HAL_TXDESC_CTSENA)
172218885Sdim	struct ar5416_desc *ads = AR5416DESC(ds);
173218885Sdim	struct ath_hal_5416 *ahp = AH5416(ah);
174263508Sdim
175263508Sdim	(void) hdrLen;
176263508Sdim
177263508Sdim	HALASSERT(txTries0 != 0);
178263508Sdim	HALASSERT(isValidPktType(type));
179263508Sdim	HALASSERT(isValidTxRate(txRate0));
180263508Sdim	HALASSERT((flags & RTSCTS) != RTSCTS);
181263508Sdim	/* XXX validate antMode */
182263508Sdim
183218885Sdim        txPower = (txPower + AH5212(ah)->ah_txPowerIndexOffset);
184218885Sdim        if (txPower > 63)
185263508Sdim		txPower = 63;
186263508Sdim
187263508Sdim	ads->ds_ctl0 = (pktLen & AR_FrameLen)
188263508Sdim		     | (txPower << AR_XmitPower_S)
189263508Sdim		     | (flags & HAL_TXDESC_VEOL ? AR_VEOL : 0)
190263508Sdim		     | (flags & HAL_TXDESC_CLRDMASK ? AR_ClrDestMask : 0)
191263508Sdim		     | (flags & HAL_TXDESC_INTREQ ? AR_TxIntrReq : 0)
192263508Sdim		     ;
193218885Sdim	ads->ds_ctl1 = (type << AR_FrameType_S)
194263508Sdim		     | (flags & HAL_TXDESC_NOACK ? AR_NoAck : 0)
195263508Sdim                     ;
196263508Sdim	ads->ds_ctl2 = SM(txTries0, AR_XmitDataTries0)
197263508Sdim		     | (flags & HAL_TXDESC_DURENA ? AR_DurUpdateEn : 0)
198263508Sdim		     ;
199263508Sdim	ads->ds_ctl3 = (txRate0 << AR_XmitRate0_S)
200263508Sdim		     ;
201263508Sdim	ads->ds_ctl4 = 0;
202263508Sdim	ads->ds_ctl5 = 0;
203263508Sdim	ads->ds_ctl6 = 0;
204263508Sdim	ads->ds_ctl7 = SM(ahp->ah_tx_chainmask, AR_ChainSel0)
205263508Sdim		     | SM(ahp->ah_tx_chainmask, AR_ChainSel1)
206263508Sdim		     | SM(ahp->ah_tx_chainmask, AR_ChainSel2)
207263508Sdim		     | SM(ahp->ah_tx_chainmask, AR_ChainSel3)
208263508Sdim		     ;
209263508Sdim	ads->ds_ctl8 = 0;
210263508Sdim	ads->ds_ctl9 = (txPower << 24);		/* XXX? */
211263508Sdim	ads->ds_ctl10 = (txPower << 24);	/* XXX? */
212218885Sdim	ads->ds_ctl11 = (txPower << 24);	/* XXX? */
213218885Sdim	if (keyIx != HAL_TXKEYIX_INVALID) {
214263508Sdim		/* XXX validate key index */
215263508Sdim		ads->ds_ctl1 |= SM(keyIx, AR_DestIdx);
216263508Sdim		ads->ds_ctl0 |= AR_DestIdxValid;
217218885Sdim		ads->ds_ctl6 |= SM(ahp->ah_keytype[keyIx], AR_EncrType);
218263508Sdim	}
219263508Sdim	if (flags & RTSCTS) {
220263508Sdim		if (!isValidTxRate(rtsctsRate)) {
221218885Sdim			HALDEBUG(ah, HAL_DEBUG_ANY,
222263508Sdim			    "%s: invalid rts/cts rate 0x%x\n",
223263508Sdim			    __func__, rtsctsRate);
224263508Sdim			return AH_FALSE;
225218885Sdim		}
226263508Sdim		/* XXX validate rtsctsDuration */
227263508Sdim		ads->ds_ctl0 |= (flags & HAL_TXDESC_CTSENA ? AR_CTSEnable : 0)
228263508Sdim			     | (flags & HAL_TXDESC_RTSENA ? AR_RTSEnable : 0)
229263508Sdim			     ;
230218885Sdim		ads->ds_ctl2 |= SM(rtsctsDuration, AR_BurstDur);
231263508Sdim		ads->ds_ctl7 |= (rtsctsRate << AR_RTSCTSRate_S);
232263508Sdim	}
233263508Sdim	return AH_TRUE;
234218885Sdim#undef RTSCTS
235263508Sdim}
236263508Sdim
237263508SdimHAL_BOOL
238263508Sdimar5416SetupXTxDesc(struct ath_hal *ah, struct ath_desc *ds,
239218885Sdim	u_int txRate1, u_int txTries1,
240263508Sdim	u_int txRate2, u_int txTries2,
241218885Sdim	u_int txRate3, u_int txTries3)
242218885Sdim{
243263508Sdim	struct ar5416_desc *ads = AR5416DESC(ds);
244263508Sdim
245263508Sdim	if (txTries1) {
246263508Sdim		HALASSERT(isValidTxRate(txRate1));
247263508Sdim		ads->ds_ctl2 |= SM(txTries1, AR_XmitDataTries1);
248263508Sdim		ads->ds_ctl3 |= (txRate1 << AR_XmitRate1_S);
249263508Sdim	}
250218885Sdim	if (txTries2) {
251218885Sdim		HALASSERT(isValidTxRate(txRate2));
252263508Sdim		ads->ds_ctl2 |= SM(txTries2, AR_XmitDataTries2);
253263508Sdim		ads->ds_ctl3 |= (txRate2 << AR_XmitRate2_S);
254263508Sdim	}
255263508Sdim	if (txTries3) {
256218885Sdim		HALASSERT(isValidTxRate(txRate3));
257263508Sdim		ads->ds_ctl2 |= SM(txTries3, AR_XmitDataTries3);
258263508Sdim		ads->ds_ctl3 |= (txRate3 << AR_XmitRate3_S);
259263508Sdim	}
260218885Sdim	return AH_TRUE;
261218885Sdim}
262263508Sdim
263263508SdimHAL_BOOL
264263508Sdimar5416FillTxDesc(struct ath_hal *ah, struct ath_desc *ds,
265218885Sdim	u_int segLen, HAL_BOOL firstSeg, HAL_BOOL lastSeg,
266263508Sdim	const struct ath_desc *ds0)
267263508Sdim{
268263508Sdim	struct ar5416_desc *ads = AR5416DESC(ds);
269218885Sdim
270263508Sdim	HALASSERT((segLen &~ AR_BufLen) == 0);
271263508Sdim
272263508Sdim	if (firstSeg) {
273218885Sdim		/*
274263508Sdim		 * First descriptor, don't clobber xmit control data
275263508Sdim		 * setup by ar5212SetupTxDesc.
276263508Sdim		 */
277263508Sdim		ads->ds_ctl1 |= segLen | (lastSeg ? 0 : AR_TxMore);
278263508Sdim	} else if (lastSeg) {		/* !firstSeg && lastSeg */
279263508Sdim		/*
280263508Sdim		 * Last descriptor in a multi-descriptor frame,
281263508Sdim		 * copy the multi-rate transmit parameters from
282218885Sdim		 * the first frame for processing on completion.
283218885Sdim		 */
284263508Sdim		ads->ds_ctl0 = 0;
285263508Sdim		ads->ds_ctl1 = segLen;
286263508Sdim#ifdef AH_NEED_DESC_SWAP
287218885Sdim		ads->ds_ctl2 = __bswap32(AR5416DESC_CONST(ds0)->ds_ctl2);
288263508Sdim		ads->ds_ctl3 = __bswap32(AR5416DESC_CONST(ds0)->ds_ctl3);
289263508Sdim#else
290263508Sdim		ads->ds_ctl2 = AR5416DESC_CONST(ds0)->ds_ctl2;
291218885Sdim		ads->ds_ctl3 = AR5416DESC_CONST(ds0)->ds_ctl3;
292263508Sdim#endif
293263508Sdim	} else {			/* !firstSeg && !lastSeg */
294263508Sdim		/*
295263508Sdim		 * Intermediate descriptor in a multi-descriptor frame.
296263508Sdim		 */
297263508Sdim		ads->ds_ctl0 = 0;
298263508Sdim		ads->ds_ctl1 = segLen | AR_TxMore;
299263508Sdim		ads->ds_ctl2 = 0;
300218885Sdim		ads->ds_ctl3 = 0;
301263508Sdim	}
302218885Sdim	/* XXX only on last descriptor? */
303218885Sdim	OS_MEMZERO(ads->u.tx.status, sizeof(ads->u.tx.status));
304263508Sdim	return AH_TRUE;
305263508Sdim}
306263508Sdim
307263508Sdim#if 0
308263508Sdim
309263508SdimHAL_BOOL
310218885Sdimar5416ChainTxDesc(struct ath_hal *ah, struct ath_desc *ds,
311263508Sdim	u_int pktLen,
312263508Sdim	u_int hdrLen,
313263508Sdim	HAL_PKT_TYPE type,
314263508Sdim	u_int keyIx,
315263508Sdim	HAL_CIPHER cipher,
316218885Sdim	uint8_t delims,
317263508Sdim	u_int segLen,
318263508Sdim	HAL_BOOL firstSeg,
319218885Sdim	HAL_BOOL lastSeg)
320263508Sdim{
321218885Sdim	struct ar5416_desc *ads = AR5416DESC(ds);
322218885Sdim	uint32_t *ds_txstatus = AR5416_DS_TXSTATUS(ah,ads);
323263508Sdim
324263508Sdim	int isaggr = 0;
325263508Sdim
326263508Sdim	(void) hdrLen;
327218885Sdim	(void) ah;
328263508Sdim
329263508Sdim	HALASSERT((segLen &~ AR_BufLen) == 0);
330263508Sdim
331263508Sdim	HALASSERT(isValidPktType(type));
332263508Sdim	if (type == HAL_PKT_TYPE_AMPDU) {
333218885Sdim		type = HAL_PKT_TYPE_NORMAL;
334263508Sdim		isaggr = 1;
335263508Sdim	}
336263508Sdim
337263508Sdim	if (!firstSeg) {
338263508Sdim		ath_hal_memzero(ds->ds_hw, AR5416_DESC_TX_CTL_SZ);
339218885Sdim	}
340263508Sdim
341263508Sdim	ads->ds_ctl0 = (pktLen & AR_FrameLen);
342218885Sdim	ads->ds_ctl1 = (type << AR_FrameType_S)
343263508Sdim			| (isaggr ? (AR_IsAggr | AR_MoreAggr) : 0);
344218885Sdim	ads->ds_ctl2 = 0;
345218885Sdim	ads->ds_ctl3 = 0;
346263508Sdim	if (keyIx != HAL_TXKEYIX_INVALID) {
347263508Sdim		/* XXX validate key index */
348263508Sdim		ads->ds_ctl1 |= SM(keyIx, AR_DestIdx);
349218885Sdim		ads->ds_ctl0 |= AR_DestIdxValid;
350263508Sdim	}
351263508Sdim
352263508Sdim	ads->ds_ctl6 = SM(keyType[cipher], AR_EncrType);
353263508Sdim	if (isaggr) {
354263508Sdim		ads->ds_ctl6 |= SM(delims, AR_PadDelim);
355263508Sdim	}
356263508Sdim
357263508Sdim	if (firstSeg) {
358263508Sdim		ads->ds_ctl1 |= segLen | (lastSeg ? 0 : AR_TxMore);
359263508Sdim	} else if (lastSeg) {           /* !firstSeg && lastSeg */
360263508Sdim		ads->ds_ctl0 = 0;
361263508Sdim		ads->ds_ctl1 |= segLen;
362263508Sdim	} else {                        /* !firstSeg && !lastSeg */
363263508Sdim		/*
364263508Sdim		 * Intermediate descriptor in a multi-descriptor frame.
365263508Sdim		 */
366263508Sdim		ads->ds_ctl0 = 0;
367263508Sdim		ads->ds_ctl1 |= segLen | AR_TxMore;
368263508Sdim	}
369263508Sdim	ds_txstatus[0] = ds_txstatus[1] = 0;
370263508Sdim	ds_txstatus[9] &= ~AR_TxDone;
371263508Sdim
372263508Sdim	return AH_TRUE;
373263508Sdim}
374263508Sdim
375263508SdimHAL_BOOL
376263508Sdimar5416SetupFirstTxDesc(struct ath_hal *ah, struct ath_desc *ds,
377263508Sdim	u_int aggrLen, u_int flags, u_int txPower,
378263508Sdim	u_int txRate0, u_int txTries0, u_int antMode,
379263508Sdim	u_int rtsctsRate, u_int rtsctsDuration)
380263508Sdim{
381263508Sdim#define RTSCTS  (HAL_TXDESC_RTSENA|HAL_TXDESC_CTSENA)
382263508Sdim	struct ar5416_desc *ads = AR5416DESC(ds);
383263508Sdim	struct ath_hal_5212 *ahp = AH5212(ah);
384218885Sdim
385218885Sdim	HALASSERT(txTries0 != 0);
386263508Sdim	HALASSERT(isValidTxRate(txRate0));
387263508Sdim	HALASSERT((flags & RTSCTS) != RTSCTS);
388263508Sdim	/* XXX validate antMode */
389263508Sdim
390263508Sdim	txPower = (txPower + ahp->ah_txPowerIndexOffset );
391263508Sdim	if(txPower > 63)  txPower=63;
392263508Sdim
393263508Sdim	ads->ds_ctl0 |= (txPower << AR_XmitPower_S)
394263508Sdim		| (flags & HAL_TXDESC_VEOL ? AR_VEOL : 0)
395263508Sdim		| (flags & HAL_TXDESC_CLRDMASK ? AR_ClrDestMask : 0)
396263508Sdim		| (flags & HAL_TXDESC_INTREQ ? AR_TxIntrReq : 0);
397263508Sdim	ads->ds_ctl1 |= (flags & HAL_TXDESC_NOACK ? AR_NoAck : 0);
398263508Sdim	ads->ds_ctl2 |= SM(txTries0, AR_XmitDataTries0);
399263508Sdim	ads->ds_ctl3 |= (txRate0 << AR_XmitRate0_S);
400263508Sdim	ads->ds_ctl7 = SM(AH5416(ah)->ah_tx_chainmask, AR_ChainSel0)
401263508Sdim		| SM(AH5416(ah)->ah_tx_chainmask, AR_ChainSel1)
402263508Sdim		| SM(AH5416(ah)->ah_tx_chainmask, AR_ChainSel2)
403263508Sdim		| SM(AH5416(ah)->ah_tx_chainmask, AR_ChainSel3);
404263508Sdim
405263508Sdim	/* NB: no V1 WAR */
406263508Sdim	ads->ds_ctl8 = 0;
407263508Sdim	ads->ds_ctl9 = (txPower << 24);
408263508Sdim	ads->ds_ctl10 = (txPower << 24);
409263508Sdim	ads->ds_ctl11 = (txPower << 24);
410263508Sdim
411263508Sdim	ads->ds_ctl6 &= ~(0xffff);
412263508Sdim	ads->ds_ctl6 |= SM(aggrLen, AR_AggrLen);
413263508Sdim
414218885Sdim	if (flags & RTSCTS) {
415218885Sdim		/* XXX validate rtsctsDuration */
416263508Sdim		ads->ds_ctl0 |= (flags & HAL_TXDESC_CTSENA ? AR_CTSEnable : 0)
417263508Sdim			| (flags & HAL_TXDESC_RTSENA ? AR_RTSEnable : 0);
418263508Sdim		ads->ds_ctl2 |= SM(rtsctsDuration, AR_BurstDur);
419263508Sdim	}
420263508Sdim
421263508Sdim	return AH_TRUE;
422263508Sdim#undef RTSCTS
423263508Sdim}
424263508Sdim
425263508SdimHAL_BOOL
426263508Sdimar5416SetupLastTxDesc(struct ath_hal *ah, struct ath_desc *ds,
427263508Sdim		const struct ath_desc *ds0)
428263508Sdim{
429263508Sdim	struct ar5416_desc *ads = AR5416DESC(ds);
430263508Sdim
431263508Sdim	ads->ds_ctl1 &= ~AR_MoreAggr;
432263508Sdim	ads->ds_ctl6 &= ~AR_PadDelim;
433263508Sdim
434218885Sdim	/* hack to copy rate info to last desc for later processing */
435218885Sdim#ifdef AH_NEED_DESC_SWAP
436263508Sdim	ads->ds_ctl2 = __bswap32(AR5416DESC_CONST(ds0)->ds_ctl2);
437263508Sdim	ads->ds_ctl3 = __bswap32(AR5416DESC_CONST(ds0)->ds_ctl3);
438263508Sdim#else
439218885Sdim	ads->ds_ctl2 = AR5416DESC_CONST(ds0)->ds_ctl2;
440263508Sdim	ads->ds_ctl3 = AR5416DESC_CONST(ds0)->ds_ctl3;
441263508Sdim#endif
442263508Sdim
443218885Sdim	return AH_TRUE;
444263508Sdim}
445218885Sdim#endif /* 0 */
446263508Sdim
447263508Sdim#ifdef AH_NEED_DESC_SWAP
448263508Sdim/* Swap transmit descriptor */
449263508Sdimstatic __inline void
450263508Sdimar5416SwapTxDesc(struct ath_desc *ds)
451263508Sdim{
452263508Sdim	ds->ds_data = __bswap32(ds->ds_data);
453263508Sdim	ds->ds_ctl0 = __bswap32(ds->ds_ctl0);
454263508Sdim	ds->ds_ctl1 = __bswap32(ds->ds_ctl1);
455263508Sdim	ds->ds_hw[0] = __bswap32(ds->ds_hw[0]);
456218885Sdim	ds->ds_hw[1] = __bswap32(ds->ds_hw[1]);
457218885Sdim	ds->ds_hw[2] = __bswap32(ds->ds_hw[2]);
458263508Sdim	ds->ds_hw[3] = __bswap32(ds->ds_hw[3]);
459263508Sdim}
460263508Sdim#endif
461263508Sdim
462218885Sdim/*
463263508Sdim * Processing of HW TX descriptor.
464263508Sdim */
465218885SdimHAL_STATUS
466263508Sdimar5416ProcTxDesc(struct ath_hal *ah,
467263508Sdim	struct ath_desc *ds, struct ath_tx_status *ts)
468263508Sdim{
469218885Sdim	struct ar5416_desc *ads = AR5416DESC(ds);
470263508Sdim	uint32_t *ds_txstatus = AR5416_DS_TXSTATUS(ah,ads);
471263508Sdim
472263508Sdim#ifdef AH_NEED_DESC_SWAP
473218885Sdim	if ((ds_txstatus[9] & __bswap32(AR_TxDone)) == 0)
474263508Sdim		return HAL_EINPROGRESS;
475263508Sdim	ar5416SwapTxDesc(ds);
476218885Sdim#else
477263508Sdim	if ((ds_txstatus[9] & AR_TxDone) == 0)
478263508Sdim		return HAL_EINPROGRESS;
479218885Sdim#endif
480218885Sdim
481263508Sdim	/* Update software copies of the HW status */
482263508Sdim	ts->ts_seqnum = MS(ds_txstatus[9], AR_SeqNum);
483263508Sdim	ts->ts_tstamp = AR_SendTimestamp(ds_txstatus);
484263508Sdim
485263508Sdim	ts->ts_status = 0;
486263508Sdim	if (ds_txstatus[1] & AR_ExcessiveRetries)
487263508Sdim		ts->ts_status |= HAL_TXERR_XRETRY;
488263508Sdim	if (ds_txstatus[1] & AR_Filtered)
489263508Sdim		ts->ts_status |= HAL_TXERR_FILT;
490218885Sdim	if (ds_txstatus[1] & AR_FIFOUnderrun)
491218885Sdim		ts->ts_status |= HAL_TXERR_FIFO;
492263508Sdim	if (ds_txstatus[9] & AR_TxOpExceeded)
493263508Sdim		ts->ts_status |= HAL_TXERR_XTXOP;
494263508Sdim	if (ds_txstatus[1] & AR_TxTimerExpired)
495263508Sdim		ts->ts_status |= HAL_TXERR_TIMER_EXPIRED;
496263508Sdim
497263508Sdim	ts->ts_flags  = 0;
498263508Sdim	if (ds_txstatus[0] & AR_TxBaStatus) {
499218885Sdim		ts->ts_flags |= HAL_TX_BA;
500263508Sdim		ts->ts_ba_low = AR_BaBitmapLow(ds_txstatus);
501263508Sdim		ts->ts_ba_high = AR_BaBitmapHigh(ds_txstatus);
502263508Sdim	}
503263508Sdim	if (ds->ds_ctl1 & AR_IsAggr)
504263508Sdim		ts->ts_flags |= HAL_TX_AGGR;
505263508Sdim	if (ds_txstatus[1] & AR_DescCfgErr)
506263508Sdim		ts->ts_flags |= HAL_TX_DESC_CFG_ERR;
507218885Sdim	if (ds_txstatus[1] & AR_TxDataUnderrun)
508263508Sdim		ts->ts_flags |= HAL_TX_DATA_UNDERRUN;
509263508Sdim	if (ds_txstatus[1] & AR_TxDelimUnderrun)
510263508Sdim		ts->ts_flags |= HAL_TX_DELIM_UNDERRUN;
511263508Sdim
512263508Sdim	/*
513263508Sdim	 * Extract the transmit rate used and mark the rate as
514263508Sdim	 * ``alternate'' if it wasn't the series 0 rate.
515263508Sdim	 */
516218885Sdim	ts->ts_finaltsi =  MS(ds_txstatus[9], AR_FinalTxIdx);
517218885Sdim	switch (ts->ts_finaltsi) {
518218885Sdim	case 0:
519263508Sdim		ts->ts_rate = MS(ads->ds_ctl3, AR_XmitRate0);
520218885Sdim		break;
521218885Sdim	case 1:
522218885Sdim		ts->ts_rate = MS(ads->ds_ctl3, AR_XmitRate1) |
523263508Sdim			HAL_TXSTAT_ALTRATE;
524263508Sdim		break;
525263508Sdim	case 2:
526263508Sdim		ts->ts_rate = MS(ads->ds_ctl3, AR_XmitRate2) |
527263508Sdim			HAL_TXSTAT_ALTRATE;
528263508Sdim		break;
529263508Sdim	case 3:
530263508Sdim		ts->ts_rate = MS(ads->ds_ctl3, AR_XmitRate3) |
531263508Sdim			HAL_TXSTAT_ALTRATE;
532263508Sdim		break;
533263508Sdim	}
534263508Sdim
535263508Sdim	ts->ts_rssi = MS(ds_txstatus[5], AR_TxRSSICombined);
536218885Sdim	ts->ts_rssi_ctl[0] = MS(ds_txstatus[0], AR_TxRSSIAnt00);
537263508Sdim	ts->ts_rssi_ctl[1] = MS(ds_txstatus[0], AR_TxRSSIAnt01);
538263508Sdim	ts->ts_rssi_ctl[2] = MS(ds_txstatus[0], AR_TxRSSIAnt02);
539263508Sdim	ts->ts_rssi_ext[0] = MS(ds_txstatus[5], AR_TxRSSIAnt10);
540263508Sdim	ts->ts_rssi_ext[1] = MS(ds_txstatus[5], AR_TxRSSIAnt11);
541263508Sdim	ts->ts_rssi_ext[2] = MS(ds_txstatus[5], AR_TxRSSIAnt12);
542263508Sdim	ts->ts_evm0 = AR_TxEVM0(ds_txstatus);
543263508Sdim	ts->ts_evm1 = AR_TxEVM1(ds_txstatus);
544263508Sdim	ts->ts_evm2 = AR_TxEVM2(ds_txstatus);
545263508Sdim
546218885Sdim	ts->ts_shortretry = MS(ds_txstatus[1], AR_RTSFailCnt);
547263508Sdim	ts->ts_longretry = MS(ds_txstatus[1], AR_DataFailCnt);
548263508Sdim	/*
549263508Sdim	 * The retry count has the number of un-acked tries for the
550263508Sdim	 * final series used.  When doing multi-rate retry we must
551263508Sdim	 * fixup the retry count by adding in the try counts for
552263508Sdim	 * each series that was fully-processed.  Beware that this
553263508Sdim	 * takes values from the try counts in the final descriptor.
554263508Sdim	 * These are not required by the hardware.  We assume they
555263508Sdim	 * are placed there by the driver as otherwise we have no
556263508Sdim	 * access and the driver can't do the calculation because it
557263508Sdim	 * doesn't know the descriptor format.
558263508Sdim	 */
559263508Sdim	switch (ts->ts_finaltsi) {
560263508Sdim	case 3: ts->ts_longretry += MS(ads->ds_ctl2, AR_XmitDataTries2);
561218885Sdim	case 2: ts->ts_longretry += MS(ads->ds_ctl2, AR_XmitDataTries1);
562218885Sdim	case 1: ts->ts_longretry += MS(ads->ds_ctl2, AR_XmitDataTries0);
563263508Sdim	}
564263508Sdim
565263508Sdim	/*
566263508Sdim	 * These fields are not used. Zero these to preserve compatability
567263508Sdim	 * with existing drivers.
568263508Sdim	 */
569263508Sdim	ts->ts_virtcol = MS(ads->ds_ctl1, AR_VirtRetryCnt);
570218885Sdim	ts->ts_antenna = 0; /* We don't switch antennas on Owl*/
571263508Sdim
572263508Sdim	/* handle tx trigger level changes internally */
573263508Sdim	if ((ts->ts_status & HAL_TXERR_FIFO) ||
574218885Sdim	    (ts->ts_flags & (HAL_TX_DATA_UNDERRUN | HAL_TX_DELIM_UNDERRUN)))
575263508Sdim		ar5212UpdateTxTrigLevel(ah, AH_TRUE);
576263508Sdim
577263508Sdim	return HAL_OK;
578263508Sdim}
579263508Sdim
580263508Sdim#if 0
581263508SdimHAL_BOOL
582263508Sdimar5416SetGlobalTxTimeout(struct ath_hal *ah, u_int tu)
583218885Sdim{
584218885Sdim	struct ath_hal_5416 *ahp = AH5416(ah);
585263508Sdim
586263508Sdim	if (tu > 0xFFFF) {
587218885Sdim		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad global tx timeout %u\n",
588263508Sdim		    __func__, tu);
589263508Sdim		/* restore default handling */
590263508Sdim		ahp->ah_globaltxtimeout = (u_int) -1;
591263508Sdim		return AH_FALSE;
592263508Sdim	}
593263508Sdim	OS_REG_RMW_FIELD(ah, AR_GTXTO, AR_GTXTO_TIMEOUT_LIMIT, tu);
594263508Sdim	ahp->ah_globaltxtimeout = tu;
595263508Sdim	return AH_TRUE;
596263508Sdim}
597263508Sdim
598263508Sdimu_int
599263508Sdimar5416GetGlobalTxTimeout(struct ath_hal *ah)
600263508Sdim{
601263508Sdim	return MS(OS_REG_READ(ah, AR_GTXTO), AR_GTXTO_TIMEOUT_LIMIT);
602263508Sdim}
603263508Sdim
604218885Sdimvoid
605263508Sdimar5416Set11nRateScenario(struct ath_hal *ah, struct ath_desc *ds,
606263508Sdim        u_int durUpdateEn, u_int rtsctsRate,
607263508Sdim	HAL_11N_RATE_SERIES series[], u_int nseries)
608263508Sdim{
609263508Sdim	struct ar5416_desc *ads = AR5416DESC(ds);
610263508Sdim
611263508Sdim	HALASSERT(nseries == 4);
612263508Sdim	(void)nseries;
613263508Sdim
614218885Sdim
615218885Sdim	ads->ds_ctl2 = set11nTries(series, 0)
616263508Sdim		     | set11nTries(series, 1)
617263508Sdim		     | set11nTries(series, 2)
618263508Sdim		     | set11nTries(series, 3)
619263508Sdim		     | (durUpdateEn ? AR_DurUpdateEn : 0);
620263508Sdim
621263508Sdim	ads->ds_ctl3 = set11nRate(series, 0)
622263508Sdim		     | set11nRate(series, 1)
623263508Sdim		     | set11nRate(series, 2)
624263508Sdim		     | set11nRate(series, 3);
625263508Sdim
626263508Sdim	ads->ds_ctl4 = set11nPktDurRTSCTS(series, 0)
627263508Sdim		     | set11nPktDurRTSCTS(series, 1);
628263508Sdim
629263508Sdim	ads->ds_ctl5 = set11nPktDurRTSCTS(series, 2)
630263508Sdim		     | set11nPktDurRTSCTS(series, 3);
631263508Sdim
632263508Sdim	ads->ds_ctl7 = set11nRateFlags(series, 0)
633263508Sdim		     | set11nRateFlags(series, 1)
634263508Sdim		     | set11nRateFlags(series, 2)
635263508Sdim		     | set11nRateFlags(series, 3)
636263508Sdim		     | SM(rtsctsRate, AR_RTSCTSRate);
637263508Sdim
638263508Sdim	/*
639263508Sdim	 * Enable RTSCTS if any of the series is flagged for RTSCTS,
640263508Sdim	 * but only if CTS is not enabled.
641263508Sdim	 */
642263508Sdim	/*
643263508Sdim	 * FIXME : the entire RTS/CTS handling should be moved to this
644263508Sdim	 * function (by passing the global RTS/CTS flags to this function).
645263508Sdim	 * currently it is split between this function and the
646263508Sdim	 * setupFiirstDescriptor. with this current implementation there
647263508Sdim	 * is an implicit assumption that setupFirstDescriptor is called
648263508Sdim	 * before this function.
649263508Sdim	 */
650263508Sdim	if (((series[0].RateFlags & HAL_RATESERIES_RTS_CTS) ||
651263508Sdim	     (series[1].RateFlags & HAL_RATESERIES_RTS_CTS) ||
652263508Sdim	     (series[2].RateFlags & HAL_RATESERIES_RTS_CTS) ||
653263508Sdim	     (series[3].RateFlags & HAL_RATESERIES_RTS_CTS) )  &&
654263508Sdim	    (ads->ds_ctl0 & AR_CTSEnable) == 0) {
655263508Sdim		ads->ds_ctl0 |= AR_RTSEnable;
656263508Sdim		ads->ds_ctl0 &= ~AR_CTSEnable;
657263508Sdim	}
658263508Sdim}
659263508Sdim
660263508Sdimvoid
661263508Sdimar5416Set11nAggrMiddle(struct ath_hal *ah, struct ath_desc *ds, u_int numDelims)
662263508Sdim{
663263508Sdim	struct ar5416_desc *ads = AR5416DESC(ds);
664263508Sdim	uint32_t *ds_txstatus = AR5416_DS_TXSTATUS(ah,ads);
665263508Sdim
666263508Sdim	ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr);
667263508Sdim
668263508Sdim	ads->ds_ctl6 &= ~AR_PadDelim;
669218885Sdim	ads->ds_ctl6 |= SM(numDelims, AR_PadDelim);
670263508Sdim	ads->ds_ctl6 &= ~AR_AggrLen;
671263508Sdim
672263508Sdim	/*
673218885Sdim	 * Clear the TxDone status here, may need to change
674218885Sdim	 * func name to reflect this
675263508Sdim	 */
676263508Sdim	ds_txstatus[9] &= ~AR_TxDone;
677263508Sdim}
678263508Sdim
679263508Sdimvoid
680263508Sdimar5416Clr11nAggr(struct ath_hal *ah, struct ath_desc *ds)
681263508Sdim{
682263508Sdim	struct ar5416_desc *ads = AR5416DESC(ds);
683263508Sdim
684263508Sdim	ads->ds_ctl1 &= (~AR_IsAggr & ~AR_MoreAggr);
685218885Sdim	ads->ds_ctl6 &= ~AR_PadDelim;
686263508Sdim	ads->ds_ctl6 &= ~AR_AggrLen;
687263508Sdim}
688263508Sdim
689263508Sdimvoid
690263508Sdimar5416Set11nBurstDuration(struct ath_hal *ah, struct ath_desc *ds,
691263508Sdim                                                  u_int burstDuration)
692218885Sdim{
693218885Sdim	struct ar5416_desc *ads = AR5416DESC(ds);
694263508Sdim
695263508Sdim	ads->ds_ctl2 &= ~AR_BurstDur;
696263508Sdim	ads->ds_ctl2 |= SM(burstDuration, AR_BurstDur);
697263508Sdim}
698263508Sdim#endif
699263508Sdim