xref: /freebsd/sys/dev/ath/ath_hal/ar5416/ar5416_xmit.c (revision 95ee2897e98f5d444f26ed2334cc7c439f9c16c6)
1*6e778a7eSPedro F. Giffuni /*-
2*6e778a7eSPedro F. Giffuni  * SPDX-License-Identifier: ISC
3*6e778a7eSPedro F. Giffuni  *
459efa8b5SSam Leffler  * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
514779705SSam Leffler  * Copyright (c) 2002-2008 Atheros Communications, Inc.
614779705SSam Leffler  *
714779705SSam Leffler  * Permission to use, copy, modify, and/or distribute this software for any
814779705SSam Leffler  * purpose with or without fee is hereby granted, provided that the above
914779705SSam Leffler  * copyright notice and this permission notice appear in all copies.
1014779705SSam Leffler  *
1114779705SSam Leffler  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1214779705SSam Leffler  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1314779705SSam Leffler  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1414779705SSam Leffler  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1514779705SSam Leffler  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1614779705SSam Leffler  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1714779705SSam Leffler  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1814779705SSam Leffler  */
1914779705SSam Leffler #include "opt_ah.h"
2014779705SSam Leffler 
2114779705SSam Leffler #include "ah.h"
2214779705SSam Leffler #include "ah_desc.h"
2314779705SSam Leffler #include "ah_internal.h"
2414779705SSam Leffler 
2514779705SSam Leffler #include "ar5416/ar5416.h"
2614779705SSam Leffler #include "ar5416/ar5416reg.h"
2714779705SSam Leffler #include "ar5416/ar5416phy.h"
2814779705SSam Leffler #include "ar5416/ar5416desc.h"
2914779705SSam Leffler 
3014779705SSam Leffler /*
3114779705SSam Leffler  * Stop transmit on the specified queue
3214779705SSam Leffler  */
3314779705SSam Leffler HAL_BOOL
ar5416StopTxDma(struct ath_hal * ah,u_int q)3414779705SSam Leffler ar5416StopTxDma(struct ath_hal *ah, u_int q)
3514779705SSam Leffler {
3614779705SSam Leffler #define	STOP_DMA_TIMEOUT	4000	/* us */
3714779705SSam Leffler #define	STOP_DMA_ITER		100	/* us */
3814779705SSam Leffler 	u_int i;
3914779705SSam Leffler 
4014779705SSam Leffler 	HALASSERT(q < AH_PRIVATE(ah)->ah_caps.halTotalQueues);
4114779705SSam Leffler 
4214779705SSam Leffler 	HALASSERT(AH5212(ah)->ah_txq[q].tqi_type != HAL_TX_QUEUE_INACTIVE);
4314779705SSam Leffler 
4414779705SSam Leffler 	OS_REG_WRITE(ah, AR_Q_TXD, 1 << q);
4514779705SSam Leffler 	for (i = STOP_DMA_TIMEOUT/STOP_DMA_ITER; i != 0; i--) {
4614779705SSam Leffler 		if (ar5212NumTxPending(ah, q) == 0)
4714779705SSam Leffler 			break;
4814779705SSam Leffler 		OS_DELAY(STOP_DMA_ITER);
4914779705SSam Leffler 	}
5014779705SSam Leffler #ifdef AH_DEBUG
5114779705SSam Leffler 	if (i == 0) {
5214779705SSam Leffler 		HALDEBUG(ah, HAL_DEBUG_ANY,
5314779705SSam Leffler 		    "%s: queue %u DMA did not stop in 400 msec\n", __func__, q);
5414779705SSam Leffler 		HALDEBUG(ah, HAL_DEBUG_ANY,
5514779705SSam Leffler 		    "%s: QSTS 0x%x Q_TXE 0x%x Q_TXD 0x%x Q_CBR 0x%x\n", __func__,
5614779705SSam Leffler 		    OS_REG_READ(ah, AR_QSTS(q)), OS_REG_READ(ah, AR_Q_TXE),
5714779705SSam Leffler 		    OS_REG_READ(ah, AR_Q_TXD), OS_REG_READ(ah, AR_QCBRCFG(q)));
5814779705SSam Leffler 		HALDEBUG(ah, HAL_DEBUG_ANY,
5914779705SSam Leffler 		    "%s: Q_MISC 0x%x Q_RDYTIMECFG 0x%x Q_RDYTIMESHDN 0x%x\n",
6014779705SSam Leffler 		    __func__, OS_REG_READ(ah, AR_QMISC(q)),
6114779705SSam Leffler 		    OS_REG_READ(ah, AR_QRDYTIMECFG(q)),
6214779705SSam Leffler 		    OS_REG_READ(ah, AR_Q_RDYTIMESHDN));
6314779705SSam Leffler 	}
6414779705SSam Leffler #endif /* AH_DEBUG */
6514779705SSam Leffler 
6614779705SSam Leffler 	/* ar5416 and up can kill packets at the PCU level */
6714779705SSam Leffler 	if (ar5212NumTxPending(ah, q)) {
6814779705SSam Leffler 		uint32_t j;
6914779705SSam Leffler 
7014779705SSam Leffler 		HALDEBUG(ah, HAL_DEBUG_TXQUEUE,
7114779705SSam Leffler 		    "%s: Num of pending TX Frames %d on Q %d\n",
7214779705SSam Leffler 		    __func__, ar5212NumTxPending(ah, q), q);
7314779705SSam Leffler 
7414779705SSam Leffler 		/* Kill last PCU Tx Frame */
7514779705SSam Leffler 		/* TODO - save off and restore current values of Q1/Q2? */
7614779705SSam Leffler 		for (j = 0; j < 2; j++) {
7714779705SSam Leffler 			uint32_t tsfLow = OS_REG_READ(ah, AR_TSF_L32);
7814779705SSam Leffler 			OS_REG_WRITE(ah, AR_QUIET2,
7914779705SSam Leffler 			    SM(10, AR_QUIET2_QUIET_DUR));
8014779705SSam Leffler 			OS_REG_WRITE(ah, AR_QUIET_PERIOD, 100);
8114779705SSam Leffler 			OS_REG_WRITE(ah, AR_NEXT_QUIET, tsfLow >> 10);
8214779705SSam Leffler 			OS_REG_SET_BIT(ah, AR_TIMER_MODE, AR_TIMER_MODE_QUIET);
8314779705SSam Leffler 
8414779705SSam Leffler 			if ((OS_REG_READ(ah, AR_TSF_L32)>>10) == (tsfLow>>10))
8514779705SSam Leffler 				break;
8614779705SSam Leffler 
8714779705SSam Leffler 			HALDEBUG(ah, HAL_DEBUG_ANY,
8814779705SSam Leffler 			    "%s: TSF moved while trying to set quiet time "
8914779705SSam Leffler 			    "TSF: 0x%08x\n", __func__, tsfLow);
9014779705SSam Leffler 			HALASSERT(j < 1); /* TSF shouldn't count twice or reg access is taking forever */
9114779705SSam Leffler 		}
9214779705SSam Leffler 
9314779705SSam Leffler 		OS_REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_CHAN_IDLE);
9414779705SSam Leffler 
9514779705SSam Leffler 		/* Allow the quiet mechanism to do its work */
9614779705SSam Leffler 		OS_DELAY(200);
9714779705SSam Leffler 		OS_REG_CLR_BIT(ah, AR_TIMER_MODE, AR_TIMER_MODE_QUIET);
9814779705SSam Leffler 
9914779705SSam Leffler 		/* Verify the transmit q is empty */
10014779705SSam Leffler 		for (i = STOP_DMA_TIMEOUT/STOP_DMA_ITER; i != 0; i--) {
10114779705SSam Leffler 			if (ar5212NumTxPending(ah, q) == 0)
10214779705SSam Leffler 				break;
10314779705SSam Leffler 			OS_DELAY(STOP_DMA_ITER);
10414779705SSam Leffler 		}
10514779705SSam Leffler 		if (i == 0) {
10614779705SSam Leffler 			HALDEBUG(ah, HAL_DEBUG_ANY,
10714779705SSam Leffler 			    "%s: Failed to stop Tx DMA in %d msec after killing"
10814779705SSam Leffler 			    " last frame\n", __func__, STOP_DMA_TIMEOUT / 1000);
10914779705SSam Leffler 		}
11014779705SSam Leffler 		OS_REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_CHAN_IDLE);
11114779705SSam Leffler 	}
11214779705SSam Leffler 
11314779705SSam Leffler 	OS_REG_WRITE(ah, AR_Q_TXD, 0);
11414779705SSam Leffler 	return (i != 0);
11514779705SSam Leffler #undef STOP_DMA_ITER
11614779705SSam Leffler #undef STOP_DMA_TIMEOUT
11714779705SSam Leffler }
11814779705SSam Leffler 
11914779705SSam Leffler #define VALID_KEY_TYPES \
12014779705SSam Leffler         ((1 << HAL_KEY_TYPE_CLEAR) | (1 << HAL_KEY_TYPE_WEP)|\
12114779705SSam Leffler          (1 << HAL_KEY_TYPE_AES)   | (1 << HAL_KEY_TYPE_TKIP))
12214779705SSam Leffler #define isValidKeyType(_t)      ((1 << (_t)) & VALID_KEY_TYPES)
12314779705SSam Leffler 
12414779705SSam Leffler #define set11nTries(_series, _index) \
12514779705SSam Leffler         (SM((_series)[_index].Tries, AR_XmitDataTries##_index))
12614779705SSam Leffler 
12714779705SSam Leffler #define set11nRate(_series, _index) \
12814779705SSam Leffler         (SM((_series)[_index].Rate, AR_XmitRate##_index))
12914779705SSam Leffler 
13014779705SSam Leffler #define set11nPktDurRTSCTS(_series, _index) \
13114779705SSam Leffler         (SM((_series)[_index].PktDuration, AR_PacketDur##_index) |\
13214779705SSam Leffler          ((_series)[_index].RateFlags & HAL_RATESERIES_RTS_CTS   ?\
13314779705SSam Leffler          AR_RTSCTSQual##_index : 0))
13414779705SSam Leffler 
13514779705SSam Leffler #define set11nRateFlags(_series, _index) \
13614779705SSam Leffler         ((_series)[_index].RateFlags & HAL_RATESERIES_2040 ? AR_2040_##_index : 0) \
13714779705SSam Leffler         |((_series)[_index].RateFlags & HAL_RATESERIES_HALFGI ? AR_GI##_index : 0) \
138ea750884SAdrian Chadd         |((_series)[_index].RateFlags & HAL_RATESERIES_STBC ? AR_STBC##_index : 0) \
13914779705SSam Leffler         |SM((_series)[_index].ChSel, AR_ChainSel##_index)
14014779705SSam Leffler 
14114779705SSam Leffler /*
14214779705SSam Leffler  * Descriptor Access Functions
14314779705SSam Leffler  */
14414779705SSam Leffler 
14514779705SSam Leffler #define VALID_PKT_TYPES \
14614779705SSam Leffler         ((1<<HAL_PKT_TYPE_NORMAL)|(1<<HAL_PKT_TYPE_ATIM)|\
14714779705SSam Leffler          (1<<HAL_PKT_TYPE_PSPOLL)|(1<<HAL_PKT_TYPE_PROBE_RESP)|\
14814779705SSam Leffler          (1<<HAL_PKT_TYPE_BEACON)|(1<<HAL_PKT_TYPE_AMPDU))
14914779705SSam Leffler #define isValidPktType(_t)      ((1<<(_t)) & VALID_PKT_TYPES)
15014779705SSam Leffler #define VALID_TX_RATES \
15114779705SSam Leffler         ((1<<0x0b)|(1<<0x0f)|(1<<0x0a)|(1<<0x0e)|(1<<0x09)|(1<<0x0d)|\
15214779705SSam Leffler          (1<<0x08)|(1<<0x0c)|(1<<0x1b)|(1<<0x1a)|(1<<0x1e)|(1<<0x19)|\
153be96a6d3SAdrian Chadd 	 (1<<0x1d)|(1<<0x18)|(1<<0x1c)|(1<<0x01)|(1<<0x02)|(1<<0x03)|\
154be96a6d3SAdrian Chadd 	 (1<<0x04)|(1<<0x05)|(1<<0x06)|(1<<0x07)|(1<<0x00))
155be96a6d3SAdrian Chadd /* NB: accept HT rates */
156be96a6d3SAdrian Chadd #define	isValidTxRate(_r)	((1<<((_r) & 0x7f)) & VALID_TX_RATES)
15714779705SSam Leffler 
15891046e9cSAdrian Chadd static inline int
ar5416RateToRateTable(struct ath_hal * ah,uint8_t rate,HAL_BOOL is_ht40)15991046e9cSAdrian Chadd ar5416RateToRateTable(struct ath_hal *ah, uint8_t rate, HAL_BOOL is_ht40)
16091046e9cSAdrian Chadd {
16191046e9cSAdrian Chadd 
16291046e9cSAdrian Chadd 	/*
16391046e9cSAdrian Chadd 	 * Handle the non-MCS rates
16491046e9cSAdrian Chadd 	 */
16591046e9cSAdrian Chadd 	switch (rate) {
16691046e9cSAdrian Chadd 	case /*   1 Mb */ 0x1b:
16791046e9cSAdrian Chadd 	case /*   1 MbS*/ 0x1b | 0x4:
16891046e9cSAdrian Chadd 		return (AH5416(ah)->ah_ratesArray[rate1l]);
16991046e9cSAdrian Chadd 	case /*   2 Mb */ 0x1a:
17091046e9cSAdrian Chadd 		return (AH5416(ah)->ah_ratesArray[rate2l]);
17191046e9cSAdrian Chadd 	case /*   2 MbS*/ 0x1a | 0x4:
17291046e9cSAdrian Chadd 		return (AH5416(ah)->ah_ratesArray[rate2s]);
17391046e9cSAdrian Chadd 	case /* 5.5 Mb */ 0x19:
17491046e9cSAdrian Chadd 		return (AH5416(ah)->ah_ratesArray[rate5_5l]);
17591046e9cSAdrian Chadd 	case /* 5.5 MbS*/ 0x19 | 0x4:
17691046e9cSAdrian Chadd 		return (AH5416(ah)->ah_ratesArray[rate5_5s]);
17791046e9cSAdrian Chadd 	case /*  11 Mb */ 0x18:
17891046e9cSAdrian Chadd 		return (AH5416(ah)->ah_ratesArray[rate11l]);
17991046e9cSAdrian Chadd 	case /*  11 MbS*/ 0x18 | 0x4:
18091046e9cSAdrian Chadd 		return (AH5416(ah)->ah_ratesArray[rate11s]);
18191046e9cSAdrian Chadd 	}
18291046e9cSAdrian Chadd 
18391046e9cSAdrian Chadd 	/* OFDM rates */
18491046e9cSAdrian Chadd 	switch (rate) {
18591046e9cSAdrian Chadd 	case /*   6 Mb */ 0x0b:
18691046e9cSAdrian Chadd 		return (AH5416(ah)->ah_ratesArray[rate6mb]);
18791046e9cSAdrian Chadd 	case /*   9 Mb */ 0x0f:
18891046e9cSAdrian Chadd 		return (AH5416(ah)->ah_ratesArray[rate9mb]);
18991046e9cSAdrian Chadd 	case /*  12 Mb */ 0x0a:
19091046e9cSAdrian Chadd 		return (AH5416(ah)->ah_ratesArray[rate12mb]);
19191046e9cSAdrian Chadd 	case /*  18 Mb */ 0x0e:
19291046e9cSAdrian Chadd 		return (AH5416(ah)->ah_ratesArray[rate18mb]);
19391046e9cSAdrian Chadd 	case /*  24 Mb */ 0x09:
19491046e9cSAdrian Chadd 		return (AH5416(ah)->ah_ratesArray[rate24mb]);
19591046e9cSAdrian Chadd 	case /*  36 Mb */ 0x0d:
19691046e9cSAdrian Chadd 		return (AH5416(ah)->ah_ratesArray[rate36mb]);
19791046e9cSAdrian Chadd 	case /*  48 Mb */ 0x08:
19891046e9cSAdrian Chadd 		return (AH5416(ah)->ah_ratesArray[rate48mb]);
19991046e9cSAdrian Chadd 	case /*  54 Mb */ 0x0c:
20091046e9cSAdrian Chadd 		return (AH5416(ah)->ah_ratesArray[rate54mb]);
20191046e9cSAdrian Chadd 	}
20291046e9cSAdrian Chadd 
20391046e9cSAdrian Chadd 	/*
20491046e9cSAdrian Chadd 	 * Handle HT20/HT40 - we only have to do MCS0-7;
20591046e9cSAdrian Chadd 	 * there's no stream differences.
20691046e9cSAdrian Chadd 	 */
20791046e9cSAdrian Chadd 	if ((rate & 0x80) && is_ht40) {
20891046e9cSAdrian Chadd 		return (AH5416(ah)->ah_ratesArray[rateHt40_0 + (rate & 0x7)]);
20991046e9cSAdrian Chadd 	} else if (rate & 0x80) {
21091046e9cSAdrian Chadd 		return (AH5416(ah)->ah_ratesArray[rateHt20_0 + (rate & 0x7)]);
21191046e9cSAdrian Chadd 	}
21291046e9cSAdrian Chadd 
21391046e9cSAdrian Chadd 	/* XXX default (eg XR, bad bad person!) */
21491046e9cSAdrian Chadd 	return (AH5416(ah)->ah_ratesArray[rate6mb]);
21591046e9cSAdrian Chadd }
21691046e9cSAdrian Chadd 
21791046e9cSAdrian Chadd /*
21891046e9cSAdrian Chadd  * Return the TX power to be used for the given rate/chains/TX power.
21991046e9cSAdrian Chadd  *
22091046e9cSAdrian Chadd  * There are a bunch of tweaks to make to a given TX power based on
22191046e9cSAdrian Chadd  * the current configuration, so...
22291046e9cSAdrian Chadd  */
22391046e9cSAdrian Chadd static uint16_t
ar5416GetTxRatePower(struct ath_hal * ah,uint8_t rate,uint8_t tx_chainmask,uint16_t txPower,HAL_BOOL is_ht40)22491046e9cSAdrian Chadd ar5416GetTxRatePower(struct ath_hal *ah, uint8_t rate, uint8_t tx_chainmask,
22591046e9cSAdrian Chadd     uint16_t txPower, HAL_BOOL is_ht40)
22691046e9cSAdrian Chadd {
22791046e9cSAdrian Chadd 	int n_txpower, max_txpower;
22891046e9cSAdrian Chadd 	const int cck_ofdm_delta = 2;
22991046e9cSAdrian Chadd #define	EEP_MINOR(_ah) \
23091046e9cSAdrian Chadd 	(AH_PRIVATE(_ah)->ah_eeversion & AR5416_EEP_VER_MINOR_MASK)
23191046e9cSAdrian Chadd #define	IS_EEP_MINOR_V2(_ah)	(EEP_MINOR(_ah) >= AR5416_EEP_MINOR_VER_2)
23291046e9cSAdrian Chadd 
23391046e9cSAdrian Chadd 	/* Take a copy ; we may underflow and thus need to clamp things */
23491046e9cSAdrian Chadd 	n_txpower = txPower;
23591046e9cSAdrian Chadd 
23691046e9cSAdrian Chadd 	/* HT40? Need to adjust the TX power by this */
23791046e9cSAdrian Chadd 	if (is_ht40)
23891046e9cSAdrian Chadd 		n_txpower += AH5416(ah)->ah_ht40PowerIncForPdadc;
23991046e9cSAdrian Chadd 
24091046e9cSAdrian Chadd 	/*
24191046e9cSAdrian Chadd 	 * Merlin? Offset the target TX power offset - it defaults to
24291046e9cSAdrian Chadd 	 * starting at -5.0dBm, but that can change!
24391046e9cSAdrian Chadd 	 *
24491046e9cSAdrian Chadd 	 * Kiwi/Kite? Always -5.0dBm offset.
24591046e9cSAdrian Chadd 	 */
24691046e9cSAdrian Chadd 	if (AR_SREV_KIWI_10_OR_LATER(ah)) {
24791046e9cSAdrian Chadd 		n_txpower -= (AR5416_PWR_TABLE_OFFSET_DB * 2);
24891046e9cSAdrian Chadd 	} else if (AR_SREV_MERLIN_20_OR_LATER(ah)) {
24991046e9cSAdrian Chadd 		int8_t pwr_table_offset = 0;
25091046e9cSAdrian Chadd 		/* This is in dBm, convert to 1/2 dBm */
25191046e9cSAdrian Chadd 		(void) ath_hal_eepromGet(ah, AR_EEP_PWR_TABLE_OFFSET,
25291046e9cSAdrian Chadd 		    &pwr_table_offset);
25391046e9cSAdrian Chadd 		n_txpower -= (pwr_table_offset * 2);
25491046e9cSAdrian Chadd 	}
25591046e9cSAdrian Chadd 
25691046e9cSAdrian Chadd 	/*
25791046e9cSAdrian Chadd 	 * If Open-loop TX power control is used, the CCK rates need
25891046e9cSAdrian Chadd 	 * to be offset by that.
25991046e9cSAdrian Chadd 	 *
26091046e9cSAdrian Chadd 	 * Rates: 2S, 2L, 1S, 1L, 5.5S, 5.5L
26191046e9cSAdrian Chadd 	 *
26291046e9cSAdrian Chadd 	 * XXX Odd, we don't have a PHY table entry for long preamble
26391046e9cSAdrian Chadd 	 * 1mbit CCK?
26491046e9cSAdrian Chadd 	 */
26591046e9cSAdrian Chadd 	if (AR_SREV_MERLIN_20_OR_LATER(ah) &&
26691046e9cSAdrian Chadd 	    ath_hal_eepromGetFlag(ah, AR_EEP_OL_PWRCTRL)) {
26791046e9cSAdrian Chadd 		if (rate == 0x19 || rate == 0x1a || rate == 0x1b ||
26891046e9cSAdrian Chadd 		    rate == (0x19 | 0x04) || rate == (0x1a | 0x04) ||
26991046e9cSAdrian Chadd 		    rate == (0x1b | 0x04)) {
27091046e9cSAdrian Chadd 			n_txpower -= cck_ofdm_delta;
27191046e9cSAdrian Chadd 		}
27291046e9cSAdrian Chadd 	}
27391046e9cSAdrian Chadd 
27491046e9cSAdrian Chadd 	/*
27591046e9cSAdrian Chadd 	 * We're now offset by the same amount that the static maximum
27691046e9cSAdrian Chadd 	 * PHY power tables are.  So, clamp the value based on that rate.
27791046e9cSAdrian Chadd 	 */
27891046e9cSAdrian Chadd 	max_txpower = ar5416RateToRateTable(ah, rate, is_ht40);
27991046e9cSAdrian Chadd #if 0
28091046e9cSAdrian Chadd 	ath_hal_printf(ah, "%s: n_txpower = %d, max_txpower = %d, "
28191046e9cSAdrian Chadd 	    "rate = 0x%x , is_ht40 = %d\n",
28291046e9cSAdrian Chadd 	    __func__,
28391046e9cSAdrian Chadd 	    n_txpower,
28491046e9cSAdrian Chadd 	    max_txpower,
28591046e9cSAdrian Chadd 	    rate,
28691046e9cSAdrian Chadd 	    is_ht40);
28791046e9cSAdrian Chadd #endif
28891046e9cSAdrian Chadd 	n_txpower = MIN(max_txpower, n_txpower);
28991046e9cSAdrian Chadd 
29091046e9cSAdrian Chadd 	/*
29191046e9cSAdrian Chadd 	 * We don't have to offset the TX power for two or three
29291046e9cSAdrian Chadd 	 * chain operation here - it's done by the AR_PHY_POWER_TX_SUB
29391046e9cSAdrian Chadd 	 * register setting via the EEPROM.
29491046e9cSAdrian Chadd 	 *
29591046e9cSAdrian Chadd 	 * So for vendors that programmed the maximum target power assuming
29691046e9cSAdrian Chadd 	 * that 2/3 chains are always on, things will just plain work.
29791046e9cSAdrian Chadd 	 * (They won't reach that target power if only one chain is on, but
29891046e9cSAdrian Chadd 	 * that's a different problem.)
29991046e9cSAdrian Chadd 	 */
30091046e9cSAdrian Chadd 
30191046e9cSAdrian Chadd 	/* Over/underflow? Adjust */
30291046e9cSAdrian Chadd 	if (n_txpower < 0)
30391046e9cSAdrian Chadd 		n_txpower = 0;
30491046e9cSAdrian Chadd 	else if (n_txpower > 63)
30591046e9cSAdrian Chadd 		n_txpower = 63;
30691046e9cSAdrian Chadd 
30791046e9cSAdrian Chadd 	/*
30891046e9cSAdrian Chadd 	 * For some odd reason the AR9160 with txpower=0 results in a
30991046e9cSAdrian Chadd 	 * much higher (max?) TX power.  So, if it's a chipset before
31091046e9cSAdrian Chadd 	 * AR9220/AR9280, just clamp the minimum value at 1.
31191046e9cSAdrian Chadd 	 */
31291046e9cSAdrian Chadd 	if ((! AR_SREV_MERLIN_10_OR_LATER(ah)) && (n_txpower == 0))
31391046e9cSAdrian Chadd 		n_txpower = 1;
31491046e9cSAdrian Chadd 
31591046e9cSAdrian Chadd 	return (n_txpower);
31691046e9cSAdrian Chadd #undef	EEP_MINOR
31791046e9cSAdrian Chadd #undef	IS_EEP_MINOR_V2
31891046e9cSAdrian Chadd }
31991046e9cSAdrian Chadd 
32014779705SSam Leffler HAL_BOOL
ar5416SetupTxDesc(struct ath_hal * ah,struct ath_desc * ds,u_int pktLen,u_int hdrLen,HAL_PKT_TYPE type,u_int txPower,u_int txRate0,u_int txTries0,u_int keyIx,u_int antMode,u_int flags,u_int rtsctsRate,u_int rtsctsDuration,u_int compicvLen,u_int compivLen,u_int comp)32114779705SSam Leffler ar5416SetupTxDesc(struct ath_hal *ah, struct ath_desc *ds,
32214779705SSam Leffler 	u_int pktLen,
32314779705SSam Leffler 	u_int hdrLen,
32414779705SSam Leffler 	HAL_PKT_TYPE type,
32514779705SSam Leffler 	u_int txPower,
32614779705SSam Leffler 	u_int txRate0, u_int txTries0,
32714779705SSam Leffler 	u_int keyIx,
32814779705SSam Leffler 	u_int antMode,
32914779705SSam Leffler 	u_int flags,
33014779705SSam Leffler 	u_int rtsctsRate,
33114779705SSam Leffler 	u_int rtsctsDuration,
33214779705SSam Leffler 	u_int compicvLen,
33314779705SSam Leffler 	u_int compivLen,
33414779705SSam Leffler 	u_int comp)
33514779705SSam Leffler {
33614779705SSam Leffler #define	RTSCTS	(HAL_TXDESC_RTSENA|HAL_TXDESC_CTSENA)
33714779705SSam Leffler 	struct ar5416_desc *ads = AR5416DESC(ds);
33814779705SSam Leffler 	struct ath_hal_5416 *ahp = AH5416(ah);
33914779705SSam Leffler 
34014779705SSam Leffler 	(void) hdrLen;
34114779705SSam Leffler 
34214779705SSam Leffler 	HALASSERT(txTries0 != 0);
34314779705SSam Leffler 	HALASSERT(isValidPktType(type));
34414779705SSam Leffler 	HALASSERT(isValidTxRate(txRate0));
34514779705SSam Leffler 	HALASSERT((flags & RTSCTS) != RTSCTS);
34614779705SSam Leffler 	/* XXX validate antMode */
34714779705SSam Leffler 
34814779705SSam Leffler         txPower = (txPower + AH5212(ah)->ah_txPowerIndexOffset);
34914779705SSam Leffler         if (txPower > 63)
35014779705SSam Leffler 		txPower = 63;
35114779705SSam Leffler 
35291046e9cSAdrian Chadd 	/*
35391046e9cSAdrian Chadd 	 * XXX For now, just assume that this isn't a HT40 frame.
354c3d41e2eSAdrian Chadd 	 * It'll get over-ridden by the multi-rate TX power setup.
35591046e9cSAdrian Chadd 	 */
35691046e9cSAdrian Chadd 	if (AH5212(ah)->ah_tpcEnabled) {
35791046e9cSAdrian Chadd 		txPower = ar5416GetTxRatePower(ah, txRate0,
35891046e9cSAdrian Chadd 		    ahp->ah_tx_chainmask,
35991046e9cSAdrian Chadd 		    txPower,
36091046e9cSAdrian Chadd 		    AH_FALSE);
36191046e9cSAdrian Chadd 	}
36291046e9cSAdrian Chadd 
36314779705SSam Leffler 	ads->ds_ctl0 = (pktLen & AR_FrameLen)
36414779705SSam Leffler 		     | (txPower << AR_XmitPower_S)
36514779705SSam Leffler 		     | (flags & HAL_TXDESC_VEOL ? AR_VEOL : 0)
36614779705SSam Leffler 		     | (flags & HAL_TXDESC_CLRDMASK ? AR_ClrDestMask : 0)
36714779705SSam Leffler 		     | (flags & HAL_TXDESC_INTREQ ? AR_TxIntrReq : 0)
36814779705SSam Leffler 		     ;
36914779705SSam Leffler 	ads->ds_ctl1 = (type << AR_FrameType_S)
37014779705SSam Leffler 		     | (flags & HAL_TXDESC_NOACK ? AR_NoAck : 0)
371c3d41e2eSAdrian Chadd 		     | (flags & HAL_TXDESC_HWTS ? AR_InsertTS : 0)
37214779705SSam Leffler                      ;
37314779705SSam Leffler 	ads->ds_ctl2 = SM(txTries0, AR_XmitDataTries0)
37414779705SSam Leffler 		     | (flags & HAL_TXDESC_DURENA ? AR_DurUpdateEn : 0)
37514779705SSam Leffler 		     ;
37614779705SSam Leffler 	ads->ds_ctl3 = (txRate0 << AR_XmitRate0_S)
37714779705SSam Leffler 		     ;
37814779705SSam Leffler 	ads->ds_ctl4 = 0;
37914779705SSam Leffler 	ads->ds_ctl5 = 0;
38014779705SSam Leffler 	ads->ds_ctl6 = 0;
38114779705SSam Leffler 	ads->ds_ctl7 = SM(ahp->ah_tx_chainmask, AR_ChainSel0)
38214779705SSam Leffler 		     | SM(ahp->ah_tx_chainmask, AR_ChainSel1)
38314779705SSam Leffler 		     | SM(ahp->ah_tx_chainmask, AR_ChainSel2)
38414779705SSam Leffler 		     | SM(ahp->ah_tx_chainmask, AR_ChainSel3)
38514779705SSam Leffler 		     ;
386634be0a9SAdrian Chadd 	ads->ds_ctl8 = SM(0, AR_AntCtl0);
387634be0a9SAdrian Chadd 	ads->ds_ctl9 = SM(0, AR_AntCtl1) | SM(txPower, AR_XmitPower1);
388634be0a9SAdrian Chadd 	ads->ds_ctl10 = SM(0, AR_AntCtl2) | SM(txPower, AR_XmitPower2);
389634be0a9SAdrian Chadd 	ads->ds_ctl11 = SM(0, AR_AntCtl3) | SM(txPower, AR_XmitPower3);
390634be0a9SAdrian Chadd 
39114779705SSam Leffler 	if (keyIx != HAL_TXKEYIX_INVALID) {
39214779705SSam Leffler 		/* XXX validate key index */
39314779705SSam Leffler 		ads->ds_ctl1 |= SM(keyIx, AR_DestIdx);
39414779705SSam Leffler 		ads->ds_ctl0 |= AR_DestIdxValid;
39514779705SSam Leffler 		ads->ds_ctl6 |= SM(ahp->ah_keytype[keyIx], AR_EncrType);
39614779705SSam Leffler 	}
39714779705SSam Leffler 	if (flags & RTSCTS) {
39814779705SSam Leffler 		if (!isValidTxRate(rtsctsRate)) {
39914779705SSam Leffler 			HALDEBUG(ah, HAL_DEBUG_ANY,
40014779705SSam Leffler 			    "%s: invalid rts/cts rate 0x%x\n",
40114779705SSam Leffler 			    __func__, rtsctsRate);
40214779705SSam Leffler 			return AH_FALSE;
40314779705SSam Leffler 		}
40414779705SSam Leffler 		/* XXX validate rtsctsDuration */
40514779705SSam Leffler 		ads->ds_ctl0 |= (flags & HAL_TXDESC_CTSENA ? AR_CTSEnable : 0)
40614779705SSam Leffler 			     | (flags & HAL_TXDESC_RTSENA ? AR_RTSEnable : 0)
40714779705SSam Leffler 			     ;
40814779705SSam Leffler 		ads->ds_ctl7 |= (rtsctsRate << AR_RTSCTSRate_S);
40914779705SSam Leffler 	}
4106468b2baSAdrian Chadd 
411634be0a9SAdrian Chadd 	/*
412634be0a9SAdrian Chadd 	 * Set the TX antenna to 0 for Kite
413634be0a9SAdrian Chadd 	 * To preserve existing behaviour, also set the TPC bits to 0;
414634be0a9SAdrian Chadd 	 * when TPC is enabled these should be filled in appropriately.
41591046e9cSAdrian Chadd 	 *
41691046e9cSAdrian Chadd 	 * XXX TODO: when doing TPC, set the TX power up appropriately?
417634be0a9SAdrian Chadd 	 */
4186468b2baSAdrian Chadd 	if (AR_SREV_KITE(ah)) {
419634be0a9SAdrian Chadd 		ads->ds_ctl8 = SM(0, AR_AntCtl0);
420634be0a9SAdrian Chadd 		ads->ds_ctl9 = SM(0, AR_AntCtl1) | SM(0, AR_XmitPower1);
421634be0a9SAdrian Chadd 		ads->ds_ctl10 = SM(0, AR_AntCtl2) | SM(0, AR_XmitPower2);
422634be0a9SAdrian Chadd 		ads->ds_ctl11 = SM(0, AR_AntCtl3) | SM(0, AR_XmitPower3);
4236468b2baSAdrian Chadd 	}
42414779705SSam Leffler 	return AH_TRUE;
42514779705SSam Leffler #undef RTSCTS
42614779705SSam Leffler }
42714779705SSam Leffler 
42814779705SSam Leffler HAL_BOOL
ar5416SetupXTxDesc(struct ath_hal * ah,struct ath_desc * ds,u_int txRate1,u_int txTries1,u_int txRate2,u_int txTries2,u_int txRate3,u_int txTries3)42914779705SSam Leffler ar5416SetupXTxDesc(struct ath_hal *ah, struct ath_desc *ds,
43014779705SSam Leffler 	u_int txRate1, u_int txTries1,
43114779705SSam Leffler 	u_int txRate2, u_int txTries2,
43214779705SSam Leffler 	u_int txRate3, u_int txTries3)
43314779705SSam Leffler {
43414779705SSam Leffler 	struct ar5416_desc *ads = AR5416DESC(ds);
43514779705SSam Leffler 
43614779705SSam Leffler 	if (txTries1) {
43714779705SSam Leffler 		HALASSERT(isValidTxRate(txRate1));
43814779705SSam Leffler 		ads->ds_ctl2 |= SM(txTries1, AR_XmitDataTries1);
43914779705SSam Leffler 		ads->ds_ctl3 |= (txRate1 << AR_XmitRate1_S);
44014779705SSam Leffler 	}
44114779705SSam Leffler 	if (txTries2) {
44214779705SSam Leffler 		HALASSERT(isValidTxRate(txRate2));
44314779705SSam Leffler 		ads->ds_ctl2 |= SM(txTries2, AR_XmitDataTries2);
44414779705SSam Leffler 		ads->ds_ctl3 |= (txRate2 << AR_XmitRate2_S);
44514779705SSam Leffler 	}
44614779705SSam Leffler 	if (txTries3) {
44714779705SSam Leffler 		HALASSERT(isValidTxRate(txRate3));
44814779705SSam Leffler 		ads->ds_ctl2 |= SM(txTries3, AR_XmitDataTries3);
44914779705SSam Leffler 		ads->ds_ctl3 |= (txRate3 << AR_XmitRate3_S);
45014779705SSam Leffler 	}
45114779705SSam Leffler 	return AH_TRUE;
45214779705SSam Leffler }
45314779705SSam Leffler 
454c3d41e2eSAdrian Chadd /*
455c3d41e2eSAdrian Chadd  * XXX TODO: Figure out if AR_InsertTS is required on all sub-frames
456c3d41e2eSAdrian Chadd  * of a TX descriptor.
457c3d41e2eSAdrian Chadd  */
45814779705SSam Leffler HAL_BOOL
ar5416FillTxDesc(struct ath_hal * ah,struct ath_desc * ds,HAL_DMA_ADDR * bufAddrList,uint32_t * segLenList,u_int descId,u_int qcuId,HAL_BOOL firstSeg,HAL_BOOL lastSeg,const struct ath_desc * ds0)45914779705SSam Leffler ar5416FillTxDesc(struct ath_hal *ah, struct ath_desc *ds,
46046634305SAdrian Chadd 	HAL_DMA_ADDR *bufAddrList, uint32_t *segLenList, u_int descId,
46146634305SAdrian Chadd 	u_int qcuId, HAL_BOOL firstSeg, HAL_BOOL lastSeg,
46214779705SSam Leffler 	const struct ath_desc *ds0)
46314779705SSam Leffler {
46414779705SSam Leffler 	struct ar5416_desc *ads = AR5416DESC(ds);
46546634305SAdrian Chadd 	uint32_t segLen = segLenList[0];
46614779705SSam Leffler 
46714779705SSam Leffler 	HALASSERT((segLen &~ AR_BufLen) == 0);
46814779705SSam Leffler 
46946634305SAdrian Chadd 	ds->ds_data = bufAddrList[0];
47046634305SAdrian Chadd 
47114779705SSam Leffler 	if (firstSeg) {
47214779705SSam Leffler 		/*
47314779705SSam Leffler 		 * First descriptor, don't clobber xmit control data
47414779705SSam Leffler 		 * setup by ar5212SetupTxDesc.
47514779705SSam Leffler 		 */
47614779705SSam Leffler 		ads->ds_ctl1 |= segLen | (lastSeg ? 0 : AR_TxMore);
47714779705SSam Leffler 	} else if (lastSeg) {		/* !firstSeg && lastSeg */
47814779705SSam Leffler 		/*
47914779705SSam Leffler 		 * Last descriptor in a multi-descriptor frame,
48014779705SSam Leffler 		 * copy the multi-rate transmit parameters from
48114779705SSam Leffler 		 * the first frame for processing on completion.
48214779705SSam Leffler 		 */
48314779705SSam Leffler 		ads->ds_ctl1 = segLen;
48414779705SSam Leffler #ifdef AH_NEED_DESC_SWAP
4856897698aSAdrian Chadd 		ads->ds_ctl0 = __bswap32(AR5416DESC_CONST(ds0)->ds_ctl0)
4866897698aSAdrian Chadd 		    & AR_TxIntrReq;
48714779705SSam Leffler 		ads->ds_ctl2 = __bswap32(AR5416DESC_CONST(ds0)->ds_ctl2);
48814779705SSam Leffler 		ads->ds_ctl3 = __bswap32(AR5416DESC_CONST(ds0)->ds_ctl3);
489650da230SAdrian Chadd 		/* ctl6 - we only need encrtype; the rest are blank */
490650da230SAdrian Chadd 		ads->ds_ctl6 = __bswap32(AR5416DESC_CONST(ds0)->ds_ctl6 & AR_EncrType);
49114779705SSam Leffler #else
4926897698aSAdrian Chadd 		ads->ds_ctl0 = AR5416DESC_CONST(ds0)->ds_ctl0 & AR_TxIntrReq;
49314779705SSam Leffler 		ads->ds_ctl2 = AR5416DESC_CONST(ds0)->ds_ctl2;
49414779705SSam Leffler 		ads->ds_ctl3 = AR5416DESC_CONST(ds0)->ds_ctl3;
495650da230SAdrian Chadd 		/* ctl6 - we only need encrtype; the rest are blank */
496650da230SAdrian Chadd 		ads->ds_ctl6 = AR5416DESC_CONST(ds0)->ds_ctl6 & AR_EncrType;
49714779705SSam Leffler #endif
49814779705SSam Leffler 	} else {			/* !firstSeg && !lastSeg */
49914779705SSam Leffler 		/*
50014779705SSam Leffler 		 * Intermediate descriptor in a multi-descriptor frame.
50114779705SSam Leffler 		 */
5026897698aSAdrian Chadd #ifdef AH_NEED_DESC_SWAP
5036897698aSAdrian Chadd 		ads->ds_ctl0 = __bswap32(AR5416DESC_CONST(ds0)->ds_ctl0)
5046897698aSAdrian Chadd 		    & AR_TxIntrReq;
505650da230SAdrian Chadd 		ads->ds_ctl6 = __bswap32(AR5416DESC_CONST(ds0)->ds_ctl6 & AR_EncrType);
5066897698aSAdrian Chadd #else
5076897698aSAdrian Chadd 		ads->ds_ctl0 = AR5416DESC_CONST(ds0)->ds_ctl0 & AR_TxIntrReq;
508650da230SAdrian Chadd 		ads->ds_ctl6 = AR5416DESC_CONST(ds0)->ds_ctl6 & AR_EncrType;
5096897698aSAdrian Chadd #endif
51014779705SSam Leffler 		ads->ds_ctl1 = segLen | AR_TxMore;
51114779705SSam Leffler 		ads->ds_ctl2 = 0;
51214779705SSam Leffler 		ads->ds_ctl3 = 0;
51314779705SSam Leffler 	}
51414779705SSam Leffler 	/* XXX only on last descriptor? */
51514779705SSam Leffler 	OS_MEMZERO(ads->u.tx.status, sizeof(ads->u.tx.status));
51614779705SSam Leffler 	return AH_TRUE;
51714779705SSam Leffler }
51814779705SSam Leffler 
5196897698aSAdrian Chadd /*
5206897698aSAdrian Chadd  * NB: cipher is no longer used, it's calculated.
5216897698aSAdrian Chadd  */
52214779705SSam Leffler HAL_BOOL
ar5416ChainTxDesc(struct ath_hal * ah,struct ath_desc * ds,HAL_DMA_ADDR * bufAddrList,uint32_t * segLenList,u_int pktLen,u_int hdrLen,HAL_PKT_TYPE type,u_int keyIx,HAL_CIPHER cipher,uint8_t delims,HAL_BOOL firstSeg,HAL_BOOL lastSeg,HAL_BOOL lastAggr)52314779705SSam Leffler ar5416ChainTxDesc(struct ath_hal *ah, struct ath_desc *ds,
524fffbec86SAdrian Chadd 	HAL_DMA_ADDR *bufAddrList,
525fffbec86SAdrian Chadd 	uint32_t *segLenList,
52614779705SSam Leffler 	u_int pktLen,
52714779705SSam Leffler 	u_int hdrLen,
52814779705SSam Leffler 	HAL_PKT_TYPE type,
52914779705SSam Leffler 	u_int keyIx,
53014779705SSam Leffler 	HAL_CIPHER cipher,
53114779705SSam Leffler 	uint8_t delims,
53214779705SSam Leffler 	HAL_BOOL firstSeg,
53333d34032SAdrian Chadd 	HAL_BOOL lastSeg,
53433d34032SAdrian Chadd 	HAL_BOOL lastAggr)
53514779705SSam Leffler {
53614779705SSam Leffler 	struct ar5416_desc *ads = AR5416DESC(ds);
53714779705SSam Leffler 	uint32_t *ds_txstatus = AR5416_DS_TXSTATUS(ah,ads);
53894b61069SAdrian Chadd 	struct ath_hal_5416 *ahp = AH5416(ah);
539fffbec86SAdrian Chadd 	u_int segLen = segLenList[0];
54014779705SSam Leffler 
54114779705SSam Leffler 	int isaggr = 0;
54233d34032SAdrian Chadd 	uint32_t last_aggr = 0;
54314779705SSam Leffler 
54414779705SSam Leffler 	(void) hdrLen;
54514779705SSam Leffler 	(void) ah;
54614779705SSam Leffler 
54714779705SSam Leffler 	HALASSERT((segLen &~ AR_BufLen) == 0);
548fffbec86SAdrian Chadd 	ds->ds_data = bufAddrList[0];
54914779705SSam Leffler 
55014779705SSam Leffler 	HALASSERT(isValidPktType(type));
55114779705SSam Leffler 	if (type == HAL_PKT_TYPE_AMPDU) {
55214779705SSam Leffler 		type = HAL_PKT_TYPE_NORMAL;
55314779705SSam Leffler 		isaggr = 1;
55433d34032SAdrian Chadd 		if (lastAggr == AH_FALSE)
55533d34032SAdrian Chadd 			last_aggr = AR_MoreAggr;
55614779705SSam Leffler 	}
55714779705SSam Leffler 
5586897698aSAdrian Chadd 	/*
5596897698aSAdrian Chadd 	 * Since this function is called before any of the other
5606897698aSAdrian Chadd 	 * descriptor setup functions (at least in this particular
5616897698aSAdrian Chadd 	 * 802.11n aggregation implementation), always bzero() the
5626897698aSAdrian Chadd 	 * descriptor. Previously this would be done for all but
5636897698aSAdrian Chadd 	 * the first segment.
5646897698aSAdrian Chadd 	 * XXX TODO: figure out why; perhaps I'm using this slightly
5656897698aSAdrian Chadd 	 * XXX incorrectly.
5666897698aSAdrian Chadd 	 */
56794b61069SAdrian Chadd 	OS_MEMZERO(ds->ds_hw, AR5416_DESC_TX_CTL_SZ);
56814779705SSam Leffler 
5696897698aSAdrian Chadd 	/*
5706897698aSAdrian Chadd 	 * Note: VEOL should only be for the last descriptor in the chain.
5716897698aSAdrian Chadd 	 */
57214779705SSam Leffler 	ads->ds_ctl0 = (pktLen & AR_FrameLen);
57333d34032SAdrian Chadd 
57433d34032SAdrian Chadd 	/*
57533d34032SAdrian Chadd 	 * For aggregates:
57633d34032SAdrian Chadd 	 * + IsAggr must be set for all descriptors of all subframes of
57733d34032SAdrian Chadd 	 *   the aggregate
57833d34032SAdrian Chadd 	 * + MoreAggr must be set for all descriptors of all subframes
57933d34032SAdrian Chadd 	 *   of the aggregate EXCEPT the last subframe;
58033d34032SAdrian Chadd 	 * + MoreAggr must be _CLEAR_ for all descrpitors of the last
58133d34032SAdrian Chadd 	 *   subframe of the aggregate.
58233d34032SAdrian Chadd 	 */
58314779705SSam Leffler 	ads->ds_ctl1 = (type << AR_FrameType_S)
58433d34032SAdrian Chadd 			| (isaggr ? (AR_IsAggr | last_aggr) : 0);
58533d34032SAdrian Chadd 
58614779705SSam Leffler 	ads->ds_ctl2 = 0;
58714779705SSam Leffler 	ads->ds_ctl3 = 0;
58814779705SSam Leffler 	if (keyIx != HAL_TXKEYIX_INVALID) {
58914779705SSam Leffler 		/* XXX validate key index */
59014779705SSam Leffler 		ads->ds_ctl1 |= SM(keyIx, AR_DestIdx);
59114779705SSam Leffler 		ads->ds_ctl0 |= AR_DestIdxValid;
59214779705SSam Leffler 	}
59314779705SSam Leffler 
5946897698aSAdrian Chadd 	ads->ds_ctl6 |= SM(ahp->ah_keytype[keyIx], AR_EncrType);
59514779705SSam Leffler 	if (isaggr) {
59614779705SSam Leffler 		ads->ds_ctl6 |= SM(delims, AR_PadDelim);
59714779705SSam Leffler 	}
59814779705SSam Leffler 
59914779705SSam Leffler 	if (firstSeg) {
60014779705SSam Leffler 		ads->ds_ctl1 |= segLen | (lastSeg ? 0 : AR_TxMore);
60114779705SSam Leffler 	} else if (lastSeg) {           /* !firstSeg && lastSeg */
60214779705SSam Leffler 		ads->ds_ctl0 = 0;
60314779705SSam Leffler 		ads->ds_ctl1 |= segLen;
60414779705SSam Leffler 	} else {                        /* !firstSeg && !lastSeg */
60514779705SSam Leffler 		/*
60614779705SSam Leffler 		 * Intermediate descriptor in a multi-descriptor frame.
60714779705SSam Leffler 		 */
60814779705SSam Leffler 		ads->ds_ctl0 = 0;
60914779705SSam Leffler 		ads->ds_ctl1 |= segLen | AR_TxMore;
61014779705SSam Leffler 	}
61114779705SSam Leffler 	ds_txstatus[0] = ds_txstatus[1] = 0;
61214779705SSam Leffler 	ds_txstatus[9] &= ~AR_TxDone;
61314779705SSam Leffler 
61414779705SSam Leffler 	return AH_TRUE;
61514779705SSam Leffler }
61614779705SSam Leffler 
61714779705SSam Leffler HAL_BOOL
ar5416SetupFirstTxDesc(struct ath_hal * ah,struct ath_desc * ds,u_int aggrLen,u_int flags,u_int txPower,u_int txRate0,u_int txTries0,u_int antMode,u_int rtsctsRate,u_int rtsctsDuration)61814779705SSam Leffler ar5416SetupFirstTxDesc(struct ath_hal *ah, struct ath_desc *ds,
61914779705SSam Leffler 	u_int aggrLen, u_int flags, u_int txPower,
62014779705SSam Leffler 	u_int txRate0, u_int txTries0, u_int antMode,
62114779705SSam Leffler 	u_int rtsctsRate, u_int rtsctsDuration)
62214779705SSam Leffler {
62314779705SSam Leffler #define RTSCTS  (HAL_TXDESC_RTSENA|HAL_TXDESC_CTSENA)
62414779705SSam Leffler 	struct ar5416_desc *ads = AR5416DESC(ds);
62514779705SSam Leffler 	struct ath_hal_5212 *ahp = AH5212(ah);
62614779705SSam Leffler 
62714779705SSam Leffler 	HALASSERT(txTries0 != 0);
62814779705SSam Leffler 	HALASSERT(isValidTxRate(txRate0));
62914779705SSam Leffler 	HALASSERT((flags & RTSCTS) != RTSCTS);
63014779705SSam Leffler 	/* XXX validate antMode */
63114779705SSam Leffler 
63214779705SSam Leffler 	txPower = (txPower + ahp->ah_txPowerIndexOffset );
63314779705SSam Leffler 	if(txPower > 63)  txPower=63;
63414779705SSam Leffler 
63514779705SSam Leffler 	ads->ds_ctl0 |= (txPower << AR_XmitPower_S)
63614779705SSam Leffler 		| (flags & HAL_TXDESC_VEOL ? AR_VEOL : 0)
63714779705SSam Leffler 		| (flags & HAL_TXDESC_CLRDMASK ? AR_ClrDestMask : 0)
63814779705SSam Leffler 		| (flags & HAL_TXDESC_INTREQ ? AR_TxIntrReq : 0);
63914779705SSam Leffler 	ads->ds_ctl1 |= (flags & HAL_TXDESC_NOACK ? AR_NoAck : 0);
64014779705SSam Leffler 	ads->ds_ctl2 |= SM(txTries0, AR_XmitDataTries0);
64114779705SSam Leffler 	ads->ds_ctl3 |= (txRate0 << AR_XmitRate0_S);
64214779705SSam Leffler 	ads->ds_ctl7 = SM(AH5416(ah)->ah_tx_chainmask, AR_ChainSel0)
64314779705SSam Leffler 		| SM(AH5416(ah)->ah_tx_chainmask, AR_ChainSel1)
64414779705SSam Leffler 		| SM(AH5416(ah)->ah_tx_chainmask, AR_ChainSel2)
64514779705SSam Leffler 		| SM(AH5416(ah)->ah_tx_chainmask, AR_ChainSel3);
64614779705SSam Leffler 
64714779705SSam Leffler 	/* NB: no V1 WAR */
648634be0a9SAdrian Chadd 	ads->ds_ctl8 = SM(0, AR_AntCtl0);
649634be0a9SAdrian Chadd 	ads->ds_ctl9 = SM(0, AR_AntCtl1) | SM(txPower, AR_XmitPower1);
650634be0a9SAdrian Chadd 	ads->ds_ctl10 = SM(0, AR_AntCtl2) | SM(txPower, AR_XmitPower2);
651634be0a9SAdrian Chadd 	ads->ds_ctl11 = SM(0, AR_AntCtl3) | SM(txPower, AR_XmitPower3);
65214779705SSam Leffler 
65314779705SSam Leffler 	ads->ds_ctl6 &= ~(0xffff);
65414779705SSam Leffler 	ads->ds_ctl6 |= SM(aggrLen, AR_AggrLen);
65514779705SSam Leffler 
65614779705SSam Leffler 	if (flags & RTSCTS) {
65714779705SSam Leffler 		/* XXX validate rtsctsDuration */
65814779705SSam Leffler 		ads->ds_ctl0 |= (flags & HAL_TXDESC_CTSENA ? AR_CTSEnable : 0)
65914779705SSam Leffler 			| (flags & HAL_TXDESC_RTSENA ? AR_RTSEnable : 0);
66014779705SSam Leffler 	}
66114779705SSam Leffler 
662634be0a9SAdrian Chadd 	/*
663634be0a9SAdrian Chadd 	 * Set the TX antenna to 0 for Kite
664634be0a9SAdrian Chadd 	 * To preserve existing behaviour, also set the TPC bits to 0;
665634be0a9SAdrian Chadd 	 * when TPC is enabled these should be filled in appropriately.
666634be0a9SAdrian Chadd 	 */
6676468b2baSAdrian Chadd 	if (AR_SREV_KITE(ah)) {
668634be0a9SAdrian Chadd 		ads->ds_ctl8 = SM(0, AR_AntCtl0);
669634be0a9SAdrian Chadd 		ads->ds_ctl9 = SM(0, AR_AntCtl1) | SM(0, AR_XmitPower1);
670634be0a9SAdrian Chadd 		ads->ds_ctl10 = SM(0, AR_AntCtl2) | SM(0, AR_XmitPower2);
671634be0a9SAdrian Chadd 		ads->ds_ctl11 = SM(0, AR_AntCtl3) | SM(0, AR_XmitPower3);
6726468b2baSAdrian Chadd 	}
6736468b2baSAdrian Chadd 
67414779705SSam Leffler 	return AH_TRUE;
67514779705SSam Leffler #undef RTSCTS
67614779705SSam Leffler }
67714779705SSam Leffler 
67814779705SSam Leffler HAL_BOOL
ar5416SetupLastTxDesc(struct ath_hal * ah,struct ath_desc * ds,const struct ath_desc * ds0)67914779705SSam Leffler ar5416SetupLastTxDesc(struct ath_hal *ah, struct ath_desc *ds,
68014779705SSam Leffler 		const struct ath_desc *ds0)
68114779705SSam Leffler {
68214779705SSam Leffler 	struct ar5416_desc *ads = AR5416DESC(ds);
68314779705SSam Leffler 
68414779705SSam Leffler 	ads->ds_ctl1 &= ~AR_MoreAggr;
68514779705SSam Leffler 	ads->ds_ctl6 &= ~AR_PadDelim;
68614779705SSam Leffler 
68714779705SSam Leffler 	/* hack to copy rate info to last desc for later processing */
68814779705SSam Leffler #ifdef AH_NEED_DESC_SWAP
68914779705SSam Leffler 	ads->ds_ctl2 = __bswap32(AR5416DESC_CONST(ds0)->ds_ctl2);
69014779705SSam Leffler 	ads->ds_ctl3 = __bswap32(AR5416DESC_CONST(ds0)->ds_ctl3);
69114779705SSam Leffler #else
69214779705SSam Leffler 	ads->ds_ctl2 = AR5416DESC_CONST(ds0)->ds_ctl2;
69314779705SSam Leffler 	ads->ds_ctl3 = AR5416DESC_CONST(ds0)->ds_ctl3;
69414779705SSam Leffler #endif
69514779705SSam Leffler 	return AH_TRUE;
69614779705SSam Leffler }
69714779705SSam Leffler 
69814779705SSam Leffler #ifdef AH_NEED_DESC_SWAP
69914779705SSam Leffler /* Swap transmit descriptor */
70014779705SSam Leffler static __inline void
ar5416SwapTxDesc(struct ath_desc * ds)70114779705SSam Leffler ar5416SwapTxDesc(struct ath_desc *ds)
70214779705SSam Leffler {
70314779705SSam Leffler 	ds->ds_data = __bswap32(ds->ds_data);
70414779705SSam Leffler 	ds->ds_ctl0 = __bswap32(ds->ds_ctl0);
70514779705SSam Leffler 	ds->ds_ctl1 = __bswap32(ds->ds_ctl1);
70614779705SSam Leffler 	ds->ds_hw[0] = __bswap32(ds->ds_hw[0]);
70714779705SSam Leffler 	ds->ds_hw[1] = __bswap32(ds->ds_hw[1]);
70814779705SSam Leffler 	ds->ds_hw[2] = __bswap32(ds->ds_hw[2]);
70914779705SSam Leffler 	ds->ds_hw[3] = __bswap32(ds->ds_hw[3]);
71014779705SSam Leffler }
71114779705SSam Leffler #endif
71214779705SSam Leffler 
71314779705SSam Leffler /*
71414779705SSam Leffler  * Processing of HW TX descriptor.
71514779705SSam Leffler  */
71614779705SSam Leffler HAL_STATUS
ar5416ProcTxDesc(struct ath_hal * ah,struct ath_desc * ds,struct ath_tx_status * ts)71714779705SSam Leffler ar5416ProcTxDesc(struct ath_hal *ah,
71814779705SSam Leffler 	struct ath_desc *ds, struct ath_tx_status *ts)
71914779705SSam Leffler {
72014779705SSam Leffler 	struct ar5416_desc *ads = AR5416DESC(ds);
72114779705SSam Leffler 	uint32_t *ds_txstatus = AR5416_DS_TXSTATUS(ah,ads);
72214779705SSam Leffler 
72314779705SSam Leffler #ifdef AH_NEED_DESC_SWAP
72414779705SSam Leffler 	if ((ds_txstatus[9] & __bswap32(AR_TxDone)) == 0)
72514779705SSam Leffler 		return HAL_EINPROGRESS;
72614779705SSam Leffler 	ar5416SwapTxDesc(ds);
72714779705SSam Leffler #else
72814779705SSam Leffler 	if ((ds_txstatus[9] & AR_TxDone) == 0)
72914779705SSam Leffler 		return HAL_EINPROGRESS;
73014779705SSam Leffler #endif
73114779705SSam Leffler 
73214779705SSam Leffler 	/* Update software copies of the HW status */
73314779705SSam Leffler 	ts->ts_seqnum = MS(ds_txstatus[9], AR_SeqNum);
73414779705SSam Leffler 	ts->ts_tstamp = AR_SendTimestamp(ds_txstatus);
7355916ef68SAdrian Chadd 	ts->ts_tid = MS(ds_txstatus[9], AR_TxTid);
73614779705SSam Leffler 
73714779705SSam Leffler 	ts->ts_status = 0;
73814779705SSam Leffler 	if (ds_txstatus[1] & AR_ExcessiveRetries)
73914779705SSam Leffler 		ts->ts_status |= HAL_TXERR_XRETRY;
74014779705SSam Leffler 	if (ds_txstatus[1] & AR_Filtered)
74114779705SSam Leffler 		ts->ts_status |= HAL_TXERR_FILT;
74214779705SSam Leffler 	if (ds_txstatus[1] & AR_FIFOUnderrun)
74314779705SSam Leffler 		ts->ts_status |= HAL_TXERR_FIFO;
74414779705SSam Leffler 	if (ds_txstatus[9] & AR_TxOpExceeded)
74514779705SSam Leffler 		ts->ts_status |= HAL_TXERR_XTXOP;
74614779705SSam Leffler 	if (ds_txstatus[1] & AR_TxTimerExpired)
74714779705SSam Leffler 		ts->ts_status |= HAL_TXERR_TIMER_EXPIRED;
74814779705SSam Leffler 
74914779705SSam Leffler 	ts->ts_flags  = 0;
75014779705SSam Leffler 	if (ds_txstatus[0] & AR_TxBaStatus) {
75114779705SSam Leffler 		ts->ts_flags |= HAL_TX_BA;
75214779705SSam Leffler 		ts->ts_ba_low = AR_BaBitmapLow(ds_txstatus);
75314779705SSam Leffler 		ts->ts_ba_high = AR_BaBitmapHigh(ds_txstatus);
75414779705SSam Leffler 	}
75514779705SSam Leffler 	if (ds->ds_ctl1 & AR_IsAggr)
75614779705SSam Leffler 		ts->ts_flags |= HAL_TX_AGGR;
75714779705SSam Leffler 	if (ds_txstatus[1] & AR_DescCfgErr)
75814779705SSam Leffler 		ts->ts_flags |= HAL_TX_DESC_CFG_ERR;
75914779705SSam Leffler 	if (ds_txstatus[1] & AR_TxDataUnderrun)
76014779705SSam Leffler 		ts->ts_flags |= HAL_TX_DATA_UNDERRUN;
76114779705SSam Leffler 	if (ds_txstatus[1] & AR_TxDelimUnderrun)
76214779705SSam Leffler 		ts->ts_flags |= HAL_TX_DELIM_UNDERRUN;
76314779705SSam Leffler 
76414779705SSam Leffler 	/*
76514779705SSam Leffler 	 * Extract the transmit rate used and mark the rate as
76614779705SSam Leffler 	 * ``alternate'' if it wasn't the series 0 rate.
76714779705SSam Leffler 	 */
76814779705SSam Leffler 	ts->ts_finaltsi =  MS(ds_txstatus[9], AR_FinalTxIdx);
76914779705SSam Leffler 	switch (ts->ts_finaltsi) {
77014779705SSam Leffler 	case 0:
77114779705SSam Leffler 		ts->ts_rate = MS(ads->ds_ctl3, AR_XmitRate0);
77214779705SSam Leffler 		break;
77314779705SSam Leffler 	case 1:
774f6cbf16aSSam Leffler 		ts->ts_rate = MS(ads->ds_ctl3, AR_XmitRate1);
77514779705SSam Leffler 		break;
77614779705SSam Leffler 	case 2:
777f6cbf16aSSam Leffler 		ts->ts_rate = MS(ads->ds_ctl3, AR_XmitRate2);
77814779705SSam Leffler 		break;
77914779705SSam Leffler 	case 3:
780f6cbf16aSSam Leffler 		ts->ts_rate = MS(ads->ds_ctl3, AR_XmitRate3);
78114779705SSam Leffler 		break;
78214779705SSam Leffler 	}
78314779705SSam Leffler 
78414779705SSam Leffler 	ts->ts_rssi = MS(ds_txstatus[5], AR_TxRSSICombined);
78514779705SSam Leffler 	ts->ts_rssi_ctl[0] = MS(ds_txstatus[0], AR_TxRSSIAnt00);
78614779705SSam Leffler 	ts->ts_rssi_ctl[1] = MS(ds_txstatus[0], AR_TxRSSIAnt01);
78714779705SSam Leffler 	ts->ts_rssi_ctl[2] = MS(ds_txstatus[0], AR_TxRSSIAnt02);
78814779705SSam Leffler 	ts->ts_rssi_ext[0] = MS(ds_txstatus[5], AR_TxRSSIAnt10);
78914779705SSam Leffler 	ts->ts_rssi_ext[1] = MS(ds_txstatus[5], AR_TxRSSIAnt11);
79014779705SSam Leffler 	ts->ts_rssi_ext[2] = MS(ds_txstatus[5], AR_TxRSSIAnt12);
79114779705SSam Leffler 	ts->ts_evm0 = AR_TxEVM0(ds_txstatus);
79214779705SSam Leffler 	ts->ts_evm1 = AR_TxEVM1(ds_txstatus);
79314779705SSam Leffler 	ts->ts_evm2 = AR_TxEVM2(ds_txstatus);
79414779705SSam Leffler 
79514779705SSam Leffler 	ts->ts_shortretry = MS(ds_txstatus[1], AR_RTSFailCnt);
79614779705SSam Leffler 	ts->ts_longretry = MS(ds_txstatus[1], AR_DataFailCnt);
79714779705SSam Leffler 	/*
79814779705SSam Leffler 	 * The retry count has the number of un-acked tries for the
79914779705SSam Leffler 	 * final series used.  When doing multi-rate retry we must
80014779705SSam Leffler 	 * fixup the retry count by adding in the try counts for
80114779705SSam Leffler 	 * each series that was fully-processed.  Beware that this
80214779705SSam Leffler 	 * takes values from the try counts in the final descriptor.
80314779705SSam Leffler 	 * These are not required by the hardware.  We assume they
80414779705SSam Leffler 	 * are placed there by the driver as otherwise we have no
80514779705SSam Leffler 	 * access and the driver can't do the calculation because it
80614779705SSam Leffler 	 * doesn't know the descriptor format.
80714779705SSam Leffler 	 */
80814779705SSam Leffler 	switch (ts->ts_finaltsi) {
80914779705SSam Leffler 	case 3: ts->ts_longretry += MS(ads->ds_ctl2, AR_XmitDataTries2);
81014779705SSam Leffler 	case 2: ts->ts_longretry += MS(ads->ds_ctl2, AR_XmitDataTries1);
81114779705SSam Leffler 	case 1: ts->ts_longretry += MS(ads->ds_ctl2, AR_XmitDataTries0);
81214779705SSam Leffler 	}
81314779705SSam Leffler 
81414779705SSam Leffler 	/*
815f6b6084bSPedro F. Giffuni 	 * These fields are not used. Zero these to preserve compatibility
81614779705SSam Leffler 	 * with existing drivers.
81714779705SSam Leffler 	 */
81814779705SSam Leffler 	ts->ts_virtcol = MS(ads->ds_ctl1, AR_VirtRetryCnt);
81914779705SSam Leffler 	ts->ts_antenna = 0; /* We don't switch antennas on Owl*/
82014779705SSam Leffler 
82114779705SSam Leffler 	/* handle tx trigger level changes internally */
82214779705SSam Leffler 	if ((ts->ts_status & HAL_TXERR_FIFO) ||
823256796dbSRui Paulo 	    (ts->ts_flags & (HAL_TX_DATA_UNDERRUN | HAL_TX_DELIM_UNDERRUN)))
82414779705SSam Leffler 		ar5212UpdateTxTrigLevel(ah, AH_TRUE);
82514779705SSam Leffler 
82614779705SSam Leffler 	return HAL_OK;
82714779705SSam Leffler }
82814779705SSam Leffler 
82914779705SSam Leffler HAL_BOOL
ar5416SetGlobalTxTimeout(struct ath_hal * ah,u_int tu)83014779705SSam Leffler ar5416SetGlobalTxTimeout(struct ath_hal *ah, u_int tu)
83114779705SSam Leffler {
83214779705SSam Leffler 	struct ath_hal_5416 *ahp = AH5416(ah);
83314779705SSam Leffler 
83414779705SSam Leffler 	if (tu > 0xFFFF) {
83514779705SSam Leffler 		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad global tx timeout %u\n",
83614779705SSam Leffler 		    __func__, tu);
83714779705SSam Leffler 		/* restore default handling */
83814779705SSam Leffler 		ahp->ah_globaltxtimeout = (u_int) -1;
83914779705SSam Leffler 		return AH_FALSE;
84014779705SSam Leffler 	}
84114779705SSam Leffler 	OS_REG_RMW_FIELD(ah, AR_GTXTO, AR_GTXTO_TIMEOUT_LIMIT, tu);
84214779705SSam Leffler 	ahp->ah_globaltxtimeout = tu;
84314779705SSam Leffler 	return AH_TRUE;
84414779705SSam Leffler }
84514779705SSam Leffler 
84614779705SSam Leffler u_int
ar5416GetGlobalTxTimeout(struct ath_hal * ah)84714779705SSam Leffler ar5416GetGlobalTxTimeout(struct ath_hal *ah)
84814779705SSam Leffler {
84914779705SSam Leffler 	return MS(OS_REG_READ(ah, AR_GTXTO), AR_GTXTO_TIMEOUT_LIMIT);
85014779705SSam Leffler }
85114779705SSam Leffler 
852ffdc8f48SAdrian Chadd #define	HT_RC_2_MCS(_rc)	((_rc) & 0x0f)
853ffdc8f48SAdrian Chadd static const u_int8_t baDurationDelta[] = {
854ffdc8f48SAdrian Chadd 	24,	//  0: BPSK
855ffdc8f48SAdrian Chadd 	12,	//  1: QPSK 1/2
856ffdc8f48SAdrian Chadd 	12,	//  2: QPSK 3/4
857ffdc8f48SAdrian Chadd 	4,	//  3: 16-QAM 1/2
858ffdc8f48SAdrian Chadd 	4,	//  4: 16-QAM 3/4
859ffdc8f48SAdrian Chadd 	4,	//  5: 64-QAM 2/3
860ffdc8f48SAdrian Chadd 	4,	//  6: 64-QAM 3/4
861ffdc8f48SAdrian Chadd 	4,	//  7: 64-QAM 5/6
862ffdc8f48SAdrian Chadd 	24,	//  8: BPSK
863ffdc8f48SAdrian Chadd 	12,	//  9: QPSK 1/2
864ffdc8f48SAdrian Chadd 	12,	// 10: QPSK 3/4
865ffdc8f48SAdrian Chadd 	4,	// 11: 16-QAM 1/2
866ffdc8f48SAdrian Chadd 	4,	// 12: 16-QAM 3/4
867ffdc8f48SAdrian Chadd 	4,	// 13: 64-QAM 2/3
868ffdc8f48SAdrian Chadd 	4,	// 14: 64-QAM 3/4
869ffdc8f48SAdrian Chadd 	4,	// 15: 64-QAM 5/6
870ffdc8f48SAdrian Chadd };
871ffdc8f48SAdrian Chadd 
87214779705SSam Leffler void
ar5416Set11nRateScenario(struct ath_hal * ah,struct ath_desc * ds,u_int durUpdateEn,u_int rtsctsRate,HAL_11N_RATE_SERIES series[],u_int nseries,u_int flags)87314779705SSam Leffler ar5416Set11nRateScenario(struct ath_hal *ah, struct ath_desc *ds,
87414779705SSam Leffler         u_int durUpdateEn, u_int rtsctsRate,
8757c913deaSAdrian Chadd 	HAL_11N_RATE_SERIES series[], u_int nseries, u_int flags)
87614779705SSam Leffler {
87714779705SSam Leffler 	struct ar5416_desc *ads = AR5416DESC(ds);
8787c913deaSAdrian Chadd 	uint32_t ds_ctl0;
87914779705SSam Leffler 
88014779705SSam Leffler 	HALASSERT(nseries == 4);
88114779705SSam Leffler 	(void)nseries;
88214779705SSam Leffler 
8837c913deaSAdrian Chadd 	/*
8847c913deaSAdrian Chadd 	 * Only one of RTS and CTS enable must be set.
8857c913deaSAdrian Chadd 	 * If a frame has both set, just do RTS protection -
8867c913deaSAdrian Chadd 	 * that's enough to satisfy legacy protection.
8877c913deaSAdrian Chadd 	 */
8887c913deaSAdrian Chadd 	if (flags & (HAL_TXDESC_RTSENA | HAL_TXDESC_CTSENA)) {
8897c913deaSAdrian Chadd 		ds_ctl0 = ads->ds_ctl0;
8907c913deaSAdrian Chadd 
8917c913deaSAdrian Chadd 		if (flags & HAL_TXDESC_RTSENA) {
8927c913deaSAdrian Chadd 			ds_ctl0 &= ~AR_CTSEnable;
8937c913deaSAdrian Chadd 			ds_ctl0 |= AR_RTSEnable;
8947c913deaSAdrian Chadd 		} else {
8957c913deaSAdrian Chadd 			ds_ctl0 &= ~AR_RTSEnable;
8967c913deaSAdrian Chadd 			ds_ctl0 |= AR_CTSEnable;
8977c913deaSAdrian Chadd 		}
8987c913deaSAdrian Chadd 
8997c913deaSAdrian Chadd 		ads->ds_ctl0 = ds_ctl0;
9007c913deaSAdrian Chadd 	} else {
9017c913deaSAdrian Chadd 		ads->ds_ctl0 =
9027c913deaSAdrian Chadd 		    (ads->ds_ctl0 & ~(AR_RTSEnable | AR_CTSEnable));
9037c913deaSAdrian Chadd 	}
9047c913deaSAdrian Chadd 
90514779705SSam Leffler 	ads->ds_ctl2 = set11nTries(series, 0)
90614779705SSam Leffler 		     | set11nTries(series, 1)
90714779705SSam Leffler 		     | set11nTries(series, 2)
90814779705SSam Leffler 		     | set11nTries(series, 3)
90914779705SSam Leffler 		     | (durUpdateEn ? AR_DurUpdateEn : 0);
91014779705SSam Leffler 
91114779705SSam Leffler 	ads->ds_ctl3 = set11nRate(series, 0)
91214779705SSam Leffler 		     | set11nRate(series, 1)
91314779705SSam Leffler 		     | set11nRate(series, 2)
91414779705SSam Leffler 		     | set11nRate(series, 3);
91514779705SSam Leffler 
91614779705SSam Leffler 	ads->ds_ctl4 = set11nPktDurRTSCTS(series, 0)
91714779705SSam Leffler 		     | set11nPktDurRTSCTS(series, 1);
91814779705SSam Leffler 
91914779705SSam Leffler 	ads->ds_ctl5 = set11nPktDurRTSCTS(series, 2)
92014779705SSam Leffler 		     | set11nPktDurRTSCTS(series, 3);
92114779705SSam Leffler 
92214779705SSam Leffler 	ads->ds_ctl7 = set11nRateFlags(series, 0)
92314779705SSam Leffler 		     | set11nRateFlags(series, 1)
92414779705SSam Leffler 		     | set11nRateFlags(series, 2)
92514779705SSam Leffler 		     | set11nRateFlags(series, 3)
92614779705SSam Leffler 		     | SM(rtsctsRate, AR_RTSCTSRate);
92791046e9cSAdrian Chadd 
92891046e9cSAdrian Chadd 	/*
92991046e9cSAdrian Chadd 	 * Doing per-packet TPC - update the TX power for the first
93091046e9cSAdrian Chadd 	 * field; program in the other series.
93191046e9cSAdrian Chadd 	 */
93291046e9cSAdrian Chadd 	if (AH5212(ah)->ah_tpcEnabled) {
93391046e9cSAdrian Chadd 		uint32_t ds_ctl0;
93491046e9cSAdrian Chadd 		uint16_t txPower;
93591046e9cSAdrian Chadd 
93691046e9cSAdrian Chadd 		/* Modify the tx power field for rate 0 */
93791046e9cSAdrian Chadd 		txPower = ar5416GetTxRatePower(ah, series[0].Rate,
93891046e9cSAdrian Chadd 		    series[0].ChSel,
93991046e9cSAdrian Chadd 		    series[0].tx_power_cap,
94091046e9cSAdrian Chadd 		    !! (series[0].RateFlags & HAL_RATESERIES_2040));
94191046e9cSAdrian Chadd 		ds_ctl0 = ads->ds_ctl0 & ~AR_XmitPower;
94291046e9cSAdrian Chadd 		ds_ctl0 |= (txPower << AR_XmitPower_S);
94391046e9cSAdrian Chadd 		ads->ds_ctl0 = ds_ctl0;
94491046e9cSAdrian Chadd 
94591046e9cSAdrian Chadd 		/*
94691046e9cSAdrian Chadd 		 * Override the whole descriptor field for each TX power.
94791046e9cSAdrian Chadd 		 *
94891046e9cSAdrian Chadd 		 * This will need changing if we ever support antenna control
94991046e9cSAdrian Chadd 		 * programming.
95091046e9cSAdrian Chadd 		 */
95191046e9cSAdrian Chadd 		txPower = ar5416GetTxRatePower(ah, series[1].Rate,
95291046e9cSAdrian Chadd 		    series[1].ChSel,
95391046e9cSAdrian Chadd 		    series[1].tx_power_cap,
95491046e9cSAdrian Chadd 		    !! (series[1].RateFlags & HAL_RATESERIES_2040));
95591046e9cSAdrian Chadd 		ads->ds_ctl9 = SM(0, AR_AntCtl1) | SM(txPower, AR_XmitPower1);
95691046e9cSAdrian Chadd 
95791046e9cSAdrian Chadd 		txPower = ar5416GetTxRatePower(ah, series[2].Rate,
95891046e9cSAdrian Chadd 		    series[2].ChSel,
95991046e9cSAdrian Chadd 		    series[2].tx_power_cap,
96091046e9cSAdrian Chadd 		    !! (series[2].RateFlags & HAL_RATESERIES_2040));
96191046e9cSAdrian Chadd 		ads->ds_ctl10 = SM(0, AR_AntCtl2) | SM(txPower, AR_XmitPower2);
96291046e9cSAdrian Chadd 
96391046e9cSAdrian Chadd 		txPower = ar5416GetTxRatePower(ah, series[3].Rate,
96491046e9cSAdrian Chadd 		    series[3].ChSel,
96591046e9cSAdrian Chadd 		    series[3].tx_power_cap,
96691046e9cSAdrian Chadd 		    !! (series[3].RateFlags & HAL_RATESERIES_2040));
96791046e9cSAdrian Chadd 		ads->ds_ctl11 = SM(0, AR_AntCtl3) | SM(txPower, AR_XmitPower3);
96891046e9cSAdrian Chadd 	}
96914779705SSam Leffler }
97014779705SSam Leffler 
971ffdc8f48SAdrian Chadd /*
972ffdc8f48SAdrian Chadd  * Note: this should be called before calling ar5416SetBurstDuration()
973ffdc8f48SAdrian Chadd  * (if it is indeed called) in order to ensure that the burst duration
974ffdc8f48SAdrian Chadd  * is correctly updated with the BA delta workaround.
975ffdc8f48SAdrian Chadd  */
97614779705SSam Leffler void
ar5416Set11nAggrFirst(struct ath_hal * ah,struct ath_desc * ds,u_int aggrLen,u_int numDelims)977f74b406dSAdrian Chadd ar5416Set11nAggrFirst(struct ath_hal *ah, struct ath_desc *ds, u_int aggrLen,
978f74b406dSAdrian Chadd     u_int numDelims)
9795916ef68SAdrian Chadd {
9805916ef68SAdrian Chadd 	struct ar5416_desc *ads = AR5416DESC(ds);
981ffdc8f48SAdrian Chadd 	uint32_t flags;
982ffdc8f48SAdrian Chadd 	uint32_t burstDur;
983ffdc8f48SAdrian Chadd 	uint8_t rate;
9845916ef68SAdrian Chadd 
9855916ef68SAdrian Chadd 	ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr);
9865916ef68SAdrian Chadd 
9875916ef68SAdrian Chadd 	ads->ds_ctl6 &= ~(AR_AggrLen | AR_PadDelim);
98826463136SAdrian Chadd 	ads->ds_ctl6 |= SM(aggrLen, AR_AggrLen);
989f74b406dSAdrian Chadd 	ads->ds_ctl6 |= SM(numDelims, AR_PadDelim);
990ffdc8f48SAdrian Chadd 
991ffdc8f48SAdrian Chadd 	if (! AR_SREV_MERLIN_10_OR_LATER(ah)) {
992ffdc8f48SAdrian Chadd 		/*
993ffdc8f48SAdrian Chadd 		 * XXX It'd be nice if I were passed in the rate scenario
994ffdc8f48SAdrian Chadd 		 * at this point..
995ffdc8f48SAdrian Chadd 		 */
996ffdc8f48SAdrian Chadd 		rate = MS(ads->ds_ctl3, AR_XmitRate0);
997ffdc8f48SAdrian Chadd 		flags = ads->ds_ctl0 & (AR_CTSEnable | AR_RTSEnable);
998ffdc8f48SAdrian Chadd 		/*
999ffdc8f48SAdrian Chadd 		 * WAR - MAC assumes normal ACK time instead of
1000ffdc8f48SAdrian Chadd 		 * block ACK while computing packet duration.
1001ffdc8f48SAdrian Chadd 		 * Add this delta to the burst duration in the descriptor.
1002ffdc8f48SAdrian Chadd 		 */
1003ffdc8f48SAdrian Chadd 		if (flags && (ads->ds_ctl1 & AR_IsAggr)) {
1004ffdc8f48SAdrian Chadd 			burstDur = baDurationDelta[HT_RC_2_MCS(rate)];
1005ffdc8f48SAdrian Chadd 			ads->ds_ctl2 &= ~(AR_BurstDur);
1006ffdc8f48SAdrian Chadd 			ads->ds_ctl2 |= SM(burstDur, AR_BurstDur);
1007ffdc8f48SAdrian Chadd 		}
1008ffdc8f48SAdrian Chadd 	}
10095916ef68SAdrian Chadd }
10105916ef68SAdrian Chadd 
10115916ef68SAdrian Chadd void
ar5416Set11nAggrMiddle(struct ath_hal * ah,struct ath_desc * ds,u_int numDelims)101214779705SSam Leffler ar5416Set11nAggrMiddle(struct ath_hal *ah, struct ath_desc *ds, u_int numDelims)
101314779705SSam Leffler {
101414779705SSam Leffler 	struct ar5416_desc *ads = AR5416DESC(ds);
101514779705SSam Leffler 	uint32_t *ds_txstatus = AR5416_DS_TXSTATUS(ah,ads);
101614779705SSam Leffler 
101714779705SSam Leffler 	ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr);
101814779705SSam Leffler 
101914779705SSam Leffler 	ads->ds_ctl6 &= ~AR_PadDelim;
102014779705SSam Leffler 	ads->ds_ctl6 |= SM(numDelims, AR_PadDelim);
102114779705SSam Leffler 	ads->ds_ctl6 &= ~AR_AggrLen;
102214779705SSam Leffler 
102314779705SSam Leffler 	/*
102414779705SSam Leffler 	 * Clear the TxDone status here, may need to change
102514779705SSam Leffler 	 * func name to reflect this
102614779705SSam Leffler 	 */
102714779705SSam Leffler 	ds_txstatus[9] &= ~AR_TxDone;
102814779705SSam Leffler }
102914779705SSam Leffler 
103014779705SSam Leffler void
ar5416Set11nAggrLast(struct ath_hal * ah,struct ath_desc * ds)10315916ef68SAdrian Chadd ar5416Set11nAggrLast(struct ath_hal *ah, struct ath_desc *ds)
10325916ef68SAdrian Chadd {
10335916ef68SAdrian Chadd 	struct ar5416_desc *ads = AR5416DESC(ds);
10345916ef68SAdrian Chadd 
10355916ef68SAdrian Chadd 	ads->ds_ctl1 |= AR_IsAggr;
10365916ef68SAdrian Chadd 	ads->ds_ctl1 &= ~AR_MoreAggr;
10375916ef68SAdrian Chadd 	ads->ds_ctl6 &= ~AR_PadDelim;
10385916ef68SAdrian Chadd }
10395916ef68SAdrian Chadd 
10405916ef68SAdrian Chadd void
ar5416Clr11nAggr(struct ath_hal * ah,struct ath_desc * ds)104114779705SSam Leffler ar5416Clr11nAggr(struct ath_hal *ah, struct ath_desc *ds)
104214779705SSam Leffler {
104314779705SSam Leffler 	struct ar5416_desc *ads = AR5416DESC(ds);
104414779705SSam Leffler 
104514779705SSam Leffler 	ads->ds_ctl1 &= (~AR_IsAggr & ~AR_MoreAggr);
104614779705SSam Leffler 	ads->ds_ctl6 &= ~AR_PadDelim;
104714779705SSam Leffler 	ads->ds_ctl6 &= ~AR_AggrLen;
104814779705SSam Leffler }
104914779705SSam Leffler 
1050bdb9fa5cSAdrian Chadd void
ar5416Set11nVirtualMoreFrag(struct ath_hal * ah,struct ath_desc * ds,u_int vmf)1051bdb9fa5cSAdrian Chadd ar5416Set11nVirtualMoreFrag(struct ath_hal *ah, struct ath_desc *ds,
1052bdb9fa5cSAdrian Chadd     u_int vmf)
1053bdb9fa5cSAdrian Chadd {
1054bdb9fa5cSAdrian Chadd 	struct ar5416_desc *ads = AR5416DESC(ds);
1055bdb9fa5cSAdrian Chadd 	if (vmf)
1056bdb9fa5cSAdrian Chadd 		ads->ds_ctl0 |= AR_VirtMoreFrag;
1057bdb9fa5cSAdrian Chadd 	else
1058bdb9fa5cSAdrian Chadd 		ads->ds_ctl0 &= ~AR_VirtMoreFrag;
1059bdb9fa5cSAdrian Chadd }
1060bdb9fa5cSAdrian Chadd 
1061ffdc8f48SAdrian Chadd /*
1062ffdc8f48SAdrian Chadd  * Program the burst duration, with the included BA delta if it's
1063ffdc8f48SAdrian Chadd  * applicable.
1064ffdc8f48SAdrian Chadd  */
106514779705SSam Leffler void
ar5416Set11nBurstDuration(struct ath_hal * ah,struct ath_desc * ds,u_int burstDuration)106614779705SSam Leffler ar5416Set11nBurstDuration(struct ath_hal *ah, struct ath_desc *ds,
106714779705SSam Leffler                                                   u_int burstDuration)
106814779705SSam Leffler {
106914779705SSam Leffler 	struct ar5416_desc *ads = AR5416DESC(ds);
1070ffdc8f48SAdrian Chadd 	uint32_t burstDur = 0;
1071ffdc8f48SAdrian Chadd 	uint8_t rate;
1072ffdc8f48SAdrian Chadd 
1073ffdc8f48SAdrian Chadd 	if (! AR_SREV_MERLIN_10_OR_LATER(ah)) {
1074ffdc8f48SAdrian Chadd 		/*
1075ffdc8f48SAdrian Chadd 		 * XXX It'd be nice if I were passed in the rate scenario
1076ffdc8f48SAdrian Chadd 		 * at this point..
1077ffdc8f48SAdrian Chadd 		 */
1078ffdc8f48SAdrian Chadd 		rate = MS(ads->ds_ctl3, AR_XmitDataTries0);
1079ffdc8f48SAdrian Chadd 		/*
1080ffdc8f48SAdrian Chadd 		 * WAR - MAC assumes normal ACK time instead of
1081ffdc8f48SAdrian Chadd 		 * block ACK while computing packet duration.
1082ffdc8f48SAdrian Chadd 		 * Add this delta to the burst duration in the descriptor.
1083ffdc8f48SAdrian Chadd 		 */
1084ffdc8f48SAdrian Chadd 		if (ads->ds_ctl1 & AR_IsAggr) {
1085ffdc8f48SAdrian Chadd 			burstDur = baDurationDelta[HT_RC_2_MCS(rate)];
1086ffdc8f48SAdrian Chadd 		}
1087ffdc8f48SAdrian Chadd 	}
108814779705SSam Leffler 
108914779705SSam Leffler 	ads->ds_ctl2 &= ~AR_BurstDur;
1090ffdc8f48SAdrian Chadd 	ads->ds_ctl2 |= SM(burstDur + burstDuration, AR_BurstDur);
109114779705SSam Leffler }
10929ea46744SAdrian Chadd 
10939ea46744SAdrian Chadd /*
10949ea46744SAdrian Chadd  * Retrieve the rate table from the given TX completion descriptor
10959ea46744SAdrian Chadd  */
10969ea46744SAdrian Chadd HAL_BOOL
ar5416GetTxCompletionRates(struct ath_hal * ah,const struct ath_desc * ds0,int * rates,int * tries)10979ea46744SAdrian Chadd ar5416GetTxCompletionRates(struct ath_hal *ah, const struct ath_desc *ds0, int *rates, int *tries)
10989ea46744SAdrian Chadd {
10999ea46744SAdrian Chadd 	const struct ar5416_desc *ads = AR5416DESC_CONST(ds0);
11009ea46744SAdrian Chadd 
11019ea46744SAdrian Chadd 	rates[0] = MS(ads->ds_ctl3, AR_XmitRate0);
11029ea46744SAdrian Chadd 	rates[1] = MS(ads->ds_ctl3, AR_XmitRate1);
11039ea46744SAdrian Chadd 	rates[2] = MS(ads->ds_ctl3, AR_XmitRate2);
11049ea46744SAdrian Chadd 	rates[3] = MS(ads->ds_ctl3, AR_XmitRate3);
11059ea46744SAdrian Chadd 
11069ea46744SAdrian Chadd 	tries[0] = MS(ads->ds_ctl2, AR_XmitDataTries0);
11079ea46744SAdrian Chadd 	tries[1] = MS(ads->ds_ctl2, AR_XmitDataTries1);
11089ea46744SAdrian Chadd 	tries[2] = MS(ads->ds_ctl2, AR_XmitDataTries2);
11099ea46744SAdrian Chadd 	tries[3] = MS(ads->ds_ctl2, AR_XmitDataTries3);
11109ea46744SAdrian Chadd 
11119ea46744SAdrian Chadd 	return AH_TRUE;
11129ea46744SAdrian Chadd }
11139ea46744SAdrian Chadd 
11144bc2f08fSAdrian Chadd /*
11154bc2f08fSAdrian Chadd  * TX queue management routines - AR5416 and later chipsets
11164bc2f08fSAdrian Chadd  */
11174bc2f08fSAdrian Chadd 
11184bc2f08fSAdrian Chadd /*
11194bc2f08fSAdrian Chadd  * Allocate and initialize a tx DCU/QCU combination.
11204bc2f08fSAdrian Chadd  */
11214bc2f08fSAdrian Chadd int
ar5416SetupTxQueue(struct ath_hal * ah,HAL_TX_QUEUE type,const HAL_TXQ_INFO * qInfo)11224bc2f08fSAdrian Chadd ar5416SetupTxQueue(struct ath_hal *ah, HAL_TX_QUEUE type,
11234bc2f08fSAdrian Chadd 	const HAL_TXQ_INFO *qInfo)
11244bc2f08fSAdrian Chadd {
11254bc2f08fSAdrian Chadd 	struct ath_hal_5212 *ahp = AH5212(ah);
11264bc2f08fSAdrian Chadd 	HAL_TX_QUEUE_INFO *qi;
11274bc2f08fSAdrian Chadd 	HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps;
11284bc2f08fSAdrian Chadd 	int q, defqflags;
11294bc2f08fSAdrian Chadd 
11304bc2f08fSAdrian Chadd 	/* by default enable OK+ERR+DESC+URN interrupts */
11314bc2f08fSAdrian Chadd 	defqflags = HAL_TXQ_TXOKINT_ENABLE
11324bc2f08fSAdrian Chadd 		  | HAL_TXQ_TXERRINT_ENABLE
11334bc2f08fSAdrian Chadd 		  | HAL_TXQ_TXDESCINT_ENABLE
11344bc2f08fSAdrian Chadd 		  | HAL_TXQ_TXURNINT_ENABLE;
11354bc2f08fSAdrian Chadd 	/* XXX move queue assignment to driver */
11364bc2f08fSAdrian Chadd 	switch (type) {
11374bc2f08fSAdrian Chadd 	case HAL_TX_QUEUE_BEACON:
11384bc2f08fSAdrian Chadd 		q = pCap->halTotalQueues-1;	/* highest priority */
11394bc2f08fSAdrian Chadd 		defqflags |= HAL_TXQ_DBA_GATED
11404bc2f08fSAdrian Chadd 		       | HAL_TXQ_CBR_DIS_QEMPTY
11414bc2f08fSAdrian Chadd 		       | HAL_TXQ_ARB_LOCKOUT_GLOBAL
11424bc2f08fSAdrian Chadd 		       | HAL_TXQ_BACKOFF_DISABLE;
11434bc2f08fSAdrian Chadd 		break;
11444bc2f08fSAdrian Chadd 	case HAL_TX_QUEUE_CAB:
11454bc2f08fSAdrian Chadd 		q = pCap->halTotalQueues-2;	/* next highest priority */
11464bc2f08fSAdrian Chadd 		defqflags |= HAL_TXQ_DBA_GATED
11474bc2f08fSAdrian Chadd 		       | HAL_TXQ_CBR_DIS_QEMPTY
11484bc2f08fSAdrian Chadd 		       | HAL_TXQ_CBR_DIS_BEMPTY
11494bc2f08fSAdrian Chadd 		       | HAL_TXQ_ARB_LOCKOUT_GLOBAL
11504bc2f08fSAdrian Chadd 		       | HAL_TXQ_BACKOFF_DISABLE;
11514bc2f08fSAdrian Chadd 		break;
1152dca968a2SAdrian Chadd 	case HAL_TX_QUEUE_PSPOLL:
1153dca968a2SAdrian Chadd 		q = 1;				/* lowest priority */
1154dca968a2SAdrian Chadd 		defqflags |= HAL_TXQ_DBA_GATED
1155dca968a2SAdrian Chadd 		       | HAL_TXQ_CBR_DIS_QEMPTY
1156dca968a2SAdrian Chadd 		       | HAL_TXQ_CBR_DIS_BEMPTY
1157dca968a2SAdrian Chadd 		       | HAL_TXQ_ARB_LOCKOUT_GLOBAL
1158dca968a2SAdrian Chadd 		       | HAL_TXQ_BACKOFF_DISABLE;
1159dca968a2SAdrian Chadd 		break;
11604bc2f08fSAdrian Chadd 	case HAL_TX_QUEUE_UAPSD:
11614bc2f08fSAdrian Chadd 		q = pCap->halTotalQueues-3;	/* nextest highest priority */
11624bc2f08fSAdrian Chadd 		if (ahp->ah_txq[q].tqi_type != HAL_TX_QUEUE_INACTIVE) {
11634bc2f08fSAdrian Chadd 			HALDEBUG(ah, HAL_DEBUG_ANY,
11644bc2f08fSAdrian Chadd 			    "%s: no available UAPSD tx queue\n", __func__);
11654bc2f08fSAdrian Chadd 			return -1;
11664bc2f08fSAdrian Chadd 		}
11674bc2f08fSAdrian Chadd 		break;
11684bc2f08fSAdrian Chadd 	case HAL_TX_QUEUE_DATA:
11694bc2f08fSAdrian Chadd 		for (q = 0; q < pCap->halTotalQueues; q++)
11704bc2f08fSAdrian Chadd 			if (ahp->ah_txq[q].tqi_type == HAL_TX_QUEUE_INACTIVE)
11714bc2f08fSAdrian Chadd 				break;
11724bc2f08fSAdrian Chadd 		if (q == pCap->halTotalQueues) {
11734bc2f08fSAdrian Chadd 			HALDEBUG(ah, HAL_DEBUG_ANY,
11744bc2f08fSAdrian Chadd 			    "%s: no available tx queue\n", __func__);
11754bc2f08fSAdrian Chadd 			return -1;
11764bc2f08fSAdrian Chadd 		}
11774bc2f08fSAdrian Chadd 		break;
11784bc2f08fSAdrian Chadd 	default:
11794bc2f08fSAdrian Chadd 		HALDEBUG(ah, HAL_DEBUG_ANY,
11804bc2f08fSAdrian Chadd 		    "%s: bad tx queue type %u\n", __func__, type);
11814bc2f08fSAdrian Chadd 		return -1;
11824bc2f08fSAdrian Chadd 	}
11834bc2f08fSAdrian Chadd 
11844bc2f08fSAdrian Chadd 	HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: queue %u\n", __func__, q);
11854bc2f08fSAdrian Chadd 
11864bc2f08fSAdrian Chadd 	qi = &ahp->ah_txq[q];
11874bc2f08fSAdrian Chadd 	if (qi->tqi_type != HAL_TX_QUEUE_INACTIVE) {
11884bc2f08fSAdrian Chadd 		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: tx queue %u already active\n",
11894bc2f08fSAdrian Chadd 		    __func__, q);
11904bc2f08fSAdrian Chadd 		return -1;
11914bc2f08fSAdrian Chadd 	}
11924bc2f08fSAdrian Chadd 	OS_MEMZERO(qi, sizeof(HAL_TX_QUEUE_INFO));
11934bc2f08fSAdrian Chadd 	qi->tqi_type = type;
11944bc2f08fSAdrian Chadd 	if (qInfo == AH_NULL) {
11954bc2f08fSAdrian Chadd 		qi->tqi_qflags = defqflags;
11964bc2f08fSAdrian Chadd 		qi->tqi_aifs = INIT_AIFS;
11974bc2f08fSAdrian Chadd 		qi->tqi_cwmin = HAL_TXQ_USEDEFAULT;	/* NB: do at reset */
11984bc2f08fSAdrian Chadd 		qi->tqi_cwmax = INIT_CWMAX;
11994bc2f08fSAdrian Chadd 		qi->tqi_shretry = INIT_SH_RETRY;
12004bc2f08fSAdrian Chadd 		qi->tqi_lgretry = INIT_LG_RETRY;
12014bc2f08fSAdrian Chadd 		qi->tqi_physCompBuf = 0;
12024bc2f08fSAdrian Chadd 	} else {
12034bc2f08fSAdrian Chadd 		qi->tqi_physCompBuf = qInfo->tqi_compBuf;
12044bc2f08fSAdrian Chadd 		(void) ar5212SetTxQueueProps(ah, q, qInfo);
12054bc2f08fSAdrian Chadd 	}
12064bc2f08fSAdrian Chadd 	/* NB: must be followed by ar5212ResetTxQueue */
12074bc2f08fSAdrian Chadd 	return q;
12084bc2f08fSAdrian Chadd }
12094bc2f08fSAdrian Chadd 
12104bc2f08fSAdrian Chadd /*
12114bc2f08fSAdrian Chadd  * Update the h/w interrupt registers to reflect a tx q's configuration.
12124bc2f08fSAdrian Chadd  */
12134bc2f08fSAdrian Chadd static void
setTxQInterrupts(struct ath_hal * ah,HAL_TX_QUEUE_INFO * qi)12144bc2f08fSAdrian Chadd setTxQInterrupts(struct ath_hal *ah, HAL_TX_QUEUE_INFO *qi)
12154bc2f08fSAdrian Chadd {
12164bc2f08fSAdrian Chadd 	struct ath_hal_5212 *ahp = AH5212(ah);
12174bc2f08fSAdrian Chadd 
12184bc2f08fSAdrian Chadd 	HALDEBUG(ah, HAL_DEBUG_TXQUEUE,
12194bc2f08fSAdrian Chadd 	    "%s: tx ok 0x%x err 0x%x desc 0x%x eol 0x%x urn 0x%x\n", __func__,
12204bc2f08fSAdrian Chadd 	    ahp->ah_txOkInterruptMask, ahp->ah_txErrInterruptMask,
12214bc2f08fSAdrian Chadd 	    ahp->ah_txDescInterruptMask, ahp->ah_txEolInterruptMask,
12224bc2f08fSAdrian Chadd 	    ahp->ah_txUrnInterruptMask);
12234bc2f08fSAdrian Chadd 
12244bc2f08fSAdrian Chadd 	OS_REG_WRITE(ah, AR_IMR_S0,
12254bc2f08fSAdrian Chadd 		  SM(ahp->ah_txOkInterruptMask, AR_IMR_S0_QCU_TXOK)
12264bc2f08fSAdrian Chadd 		| SM(ahp->ah_txDescInterruptMask, AR_IMR_S0_QCU_TXDESC)
12274bc2f08fSAdrian Chadd 	);
12284bc2f08fSAdrian Chadd 	OS_REG_WRITE(ah, AR_IMR_S1,
12294bc2f08fSAdrian Chadd 		  SM(ahp->ah_txErrInterruptMask, AR_IMR_S1_QCU_TXERR)
12304bc2f08fSAdrian Chadd 		| SM(ahp->ah_txEolInterruptMask, AR_IMR_S1_QCU_TXEOL)
12314bc2f08fSAdrian Chadd 	);
12324bc2f08fSAdrian Chadd 	OS_REG_RMW_FIELD(ah, AR_IMR_S2,
12334bc2f08fSAdrian Chadd 		AR_IMR_S2_QCU_TXURN, ahp->ah_txUrnInterruptMask);
12344bc2f08fSAdrian Chadd }
12354bc2f08fSAdrian Chadd 
12364bc2f08fSAdrian Chadd /*
12374bc2f08fSAdrian Chadd  * Set the retry, aifs, cwmin/max, readyTime regs for specified queue
12384bc2f08fSAdrian Chadd  * Assumes:
12394bc2f08fSAdrian Chadd  *  phwChannel has been set to point to the current channel
12404bc2f08fSAdrian Chadd  */
1241353d2977SAdrian Chadd #define	TU_TO_USEC(_tu)		((_tu) << 10)
12424bc2f08fSAdrian Chadd HAL_BOOL
ar5416ResetTxQueue(struct ath_hal * ah,u_int q)12434bc2f08fSAdrian Chadd ar5416ResetTxQueue(struct ath_hal *ah, u_int q)
12444bc2f08fSAdrian Chadd {
12454bc2f08fSAdrian Chadd 	struct ath_hal_5212 *ahp = AH5212(ah);
12464bc2f08fSAdrian Chadd 	HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps;
12474bc2f08fSAdrian Chadd 	const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan;
12484bc2f08fSAdrian Chadd 	HAL_TX_QUEUE_INFO *qi;
1249353d2977SAdrian Chadd 	uint32_t cwMin, chanCwMin, qmisc, dmisc;
12504bc2f08fSAdrian Chadd 
12514bc2f08fSAdrian Chadd 	if (q >= pCap->halTotalQueues) {
12524bc2f08fSAdrian Chadd 		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n",
12534bc2f08fSAdrian Chadd 		    __func__, q);
12544bc2f08fSAdrian Chadd 		return AH_FALSE;
12554bc2f08fSAdrian Chadd 	}
12564bc2f08fSAdrian Chadd 	qi = &ahp->ah_txq[q];
12574bc2f08fSAdrian Chadd 	if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) {
12584bc2f08fSAdrian Chadd 		HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: inactive queue %u\n",
12594bc2f08fSAdrian Chadd 		    __func__, q);
12604bc2f08fSAdrian Chadd 		return AH_TRUE;		/* XXX??? */
12614bc2f08fSAdrian Chadd 	}
12624bc2f08fSAdrian Chadd 
12634bc2f08fSAdrian Chadd 	HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: reset queue %u\n", __func__, q);
12644bc2f08fSAdrian Chadd 
12654bc2f08fSAdrian Chadd 	if (qi->tqi_cwmin == HAL_TXQ_USEDEFAULT) {
12664bc2f08fSAdrian Chadd 		/*
12674bc2f08fSAdrian Chadd 		 * Select cwmin according to channel type.
12684bc2f08fSAdrian Chadd 		 * NB: chan can be NULL during attach
12694bc2f08fSAdrian Chadd 		 */
12704bc2f08fSAdrian Chadd 		if (chan && IEEE80211_IS_CHAN_B(chan))
12714bc2f08fSAdrian Chadd 			chanCwMin = INIT_CWMIN_11B;
12724bc2f08fSAdrian Chadd 		else
12734bc2f08fSAdrian Chadd 			chanCwMin = INIT_CWMIN;
12744bc2f08fSAdrian Chadd 		/* make sure that the CWmin is of the form (2^n - 1) */
12754bc2f08fSAdrian Chadd 		for (cwMin = 1; cwMin < chanCwMin; cwMin = (cwMin << 1) | 1)
12764bc2f08fSAdrian Chadd 			;
12774bc2f08fSAdrian Chadd 	} else
12784bc2f08fSAdrian Chadd 		cwMin = qi->tqi_cwmin;
12794bc2f08fSAdrian Chadd 
12804bc2f08fSAdrian Chadd 	/* set cwMin/Max and AIFS values */
12814bc2f08fSAdrian Chadd 	OS_REG_WRITE(ah, AR_DLCL_IFS(q),
12824bc2f08fSAdrian Chadd 		  SM(cwMin, AR_D_LCL_IFS_CWMIN)
12834bc2f08fSAdrian Chadd 		| SM(qi->tqi_cwmax, AR_D_LCL_IFS_CWMAX)
12844bc2f08fSAdrian Chadd 		| SM(qi->tqi_aifs, AR_D_LCL_IFS_AIFS));
12854bc2f08fSAdrian Chadd 
12864bc2f08fSAdrian Chadd 	/* Set retry limit values */
12874bc2f08fSAdrian Chadd 	OS_REG_WRITE(ah, AR_DRETRY_LIMIT(q),
12884bc2f08fSAdrian Chadd 		   SM(INIT_SSH_RETRY, AR_D_RETRY_LIMIT_STA_SH)
12894bc2f08fSAdrian Chadd 		 | SM(INIT_SLG_RETRY, AR_D_RETRY_LIMIT_STA_LG)
12904bc2f08fSAdrian Chadd 		 | SM(qi->tqi_lgretry, AR_D_RETRY_LIMIT_FR_LG)
12914bc2f08fSAdrian Chadd 		 | SM(qi->tqi_shretry, AR_D_RETRY_LIMIT_FR_SH)
12924bc2f08fSAdrian Chadd 	);
12934bc2f08fSAdrian Chadd 
12944bc2f08fSAdrian Chadd 	/* NB: always enable early termination on the QCU */
12954bc2f08fSAdrian Chadd 	qmisc = AR_Q_MISC_DCU_EARLY_TERM_REQ
12964bc2f08fSAdrian Chadd 	      | SM(AR_Q_MISC_FSP_ASAP, AR_Q_MISC_FSP);
12974bc2f08fSAdrian Chadd 
12984bc2f08fSAdrian Chadd 	/* NB: always enable DCU to wait for next fragment from QCU */
12994bc2f08fSAdrian Chadd 	dmisc = AR_D_MISC_FRAG_WAIT_EN;
13004bc2f08fSAdrian Chadd 
1301dca968a2SAdrian Chadd 	/* Enable exponential backoff window */
1302dca968a2SAdrian Chadd 	dmisc |= AR_D_MISC_BKOFF_PERSISTENCE;
1303dca968a2SAdrian Chadd 
1304d27f0179SAdrian Chadd 	/*
1305d27f0179SAdrian Chadd 	 * The chip reset default is to use a DCU backoff threshold of 0x2.
1306d27f0179SAdrian Chadd 	 * Restore this when programming the DCU MISC register.
1307d27f0179SAdrian Chadd 	 */
1308d27f0179SAdrian Chadd 	dmisc |= 0x2;
1309d27f0179SAdrian Chadd 
13104bc2f08fSAdrian Chadd 	/* multiqueue support */
13114bc2f08fSAdrian Chadd 	if (qi->tqi_cbrPeriod) {
13124bc2f08fSAdrian Chadd 		OS_REG_WRITE(ah, AR_QCBRCFG(q),
13134bc2f08fSAdrian Chadd 			  SM(qi->tqi_cbrPeriod,AR_Q_CBRCFG_CBR_INTERVAL)
13144bc2f08fSAdrian Chadd 			| SM(qi->tqi_cbrOverflowLimit, AR_Q_CBRCFG_CBR_OVF_THRESH));
13154bc2f08fSAdrian Chadd 		qmisc = (qmisc &~ AR_Q_MISC_FSP) | AR_Q_MISC_FSP_CBR;
13164bc2f08fSAdrian Chadd 		if (qi->tqi_cbrOverflowLimit)
13174bc2f08fSAdrian Chadd 			qmisc |= AR_Q_MISC_CBR_EXP_CNTR_LIMIT;
13184bc2f08fSAdrian Chadd 	}
1319353d2977SAdrian Chadd 
1320353d2977SAdrian Chadd 	if (qi->tqi_readyTime && (qi->tqi_type != HAL_TX_QUEUE_CAB)) {
13214bc2f08fSAdrian Chadd 		OS_REG_WRITE(ah, AR_QRDYTIMECFG(q),
13224bc2f08fSAdrian Chadd 			  SM(qi->tqi_readyTime, AR_Q_RDYTIMECFG_INT)
13234bc2f08fSAdrian Chadd 			| AR_Q_RDYTIMECFG_ENA);
13244bc2f08fSAdrian Chadd 	}
13254bc2f08fSAdrian Chadd 
13264bc2f08fSAdrian Chadd 	OS_REG_WRITE(ah, AR_DCHNTIME(q),
13274bc2f08fSAdrian Chadd 		  SM(qi->tqi_burstTime, AR_D_CHNTIME_DUR)
13284bc2f08fSAdrian Chadd 		| (qi->tqi_burstTime ? AR_D_CHNTIME_EN : 0));
13294bc2f08fSAdrian Chadd 
13304bc2f08fSAdrian Chadd 	if (qi->tqi_readyTime &&
13314bc2f08fSAdrian Chadd 	    (qi->tqi_qflags & HAL_TXQ_RDYTIME_EXP_POLICY_ENABLE))
13324bc2f08fSAdrian Chadd 		qmisc |= AR_Q_MISC_RDYTIME_EXP_POLICY;
13334bc2f08fSAdrian Chadd 	if (qi->tqi_qflags & HAL_TXQ_DBA_GATED)
13344bc2f08fSAdrian Chadd 		qmisc = (qmisc &~ AR_Q_MISC_FSP) | AR_Q_MISC_FSP_DBA_GATED;
13354bc2f08fSAdrian Chadd 	if (MS(qmisc, AR_Q_MISC_FSP) != AR_Q_MISC_FSP_ASAP) {
13364bc2f08fSAdrian Chadd 		/*
13374bc2f08fSAdrian Chadd 		 * These are meangingful only when not scheduled asap.
13384bc2f08fSAdrian Chadd 		 */
13394bc2f08fSAdrian Chadd 		if (qi->tqi_qflags & HAL_TXQ_CBR_DIS_BEMPTY)
13404bc2f08fSAdrian Chadd 			qmisc |= AR_Q_MISC_CBR_INCR_DIS0;
13414bc2f08fSAdrian Chadd 		else
13424bc2f08fSAdrian Chadd 			qmisc &= ~AR_Q_MISC_CBR_INCR_DIS0;
13434bc2f08fSAdrian Chadd 		if (qi->tqi_qflags & HAL_TXQ_CBR_DIS_QEMPTY)
13444bc2f08fSAdrian Chadd 			qmisc |= AR_Q_MISC_CBR_INCR_DIS1;
13454bc2f08fSAdrian Chadd 		else
13464bc2f08fSAdrian Chadd 			qmisc &= ~AR_Q_MISC_CBR_INCR_DIS1;
13474bc2f08fSAdrian Chadd 	}
13484bc2f08fSAdrian Chadd 
13494bc2f08fSAdrian Chadd 	if (qi->tqi_qflags & HAL_TXQ_BACKOFF_DISABLE)
13504bc2f08fSAdrian Chadd 		dmisc |= AR_D_MISC_POST_FR_BKOFF_DIS;
13514bc2f08fSAdrian Chadd 	if (qi->tqi_qflags & HAL_TXQ_FRAG_BURST_BACKOFF_ENABLE)
13524bc2f08fSAdrian Chadd 		dmisc |= AR_D_MISC_FRAG_BKOFF_EN;
13534bc2f08fSAdrian Chadd 	if (qi->tqi_qflags & HAL_TXQ_ARB_LOCKOUT_GLOBAL)
13544bc2f08fSAdrian Chadd 		dmisc |= SM(AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL,
13554bc2f08fSAdrian Chadd 			    AR_D_MISC_ARB_LOCKOUT_CNTRL);
13564bc2f08fSAdrian Chadd 	else if (qi->tqi_qflags & HAL_TXQ_ARB_LOCKOUT_INTRA)
13574bc2f08fSAdrian Chadd 		dmisc |= SM(AR_D_MISC_ARB_LOCKOUT_CNTRL_INTRA_FR,
13584bc2f08fSAdrian Chadd 			    AR_D_MISC_ARB_LOCKOUT_CNTRL);
13594bc2f08fSAdrian Chadd 	if (qi->tqi_qflags & HAL_TXQ_IGNORE_VIRTCOL)
13604bc2f08fSAdrian Chadd 		dmisc |= SM(AR_D_MISC_VIR_COL_HANDLING_IGNORE,
13614bc2f08fSAdrian Chadd 			    AR_D_MISC_VIR_COL_HANDLING);
13624bc2f08fSAdrian Chadd 	if (qi->tqi_qflags & HAL_TXQ_SEQNUM_INC_DIS)
13634bc2f08fSAdrian Chadd 		dmisc |= AR_D_MISC_SEQ_NUM_INCR_DIS;
13644bc2f08fSAdrian Chadd 
13654bc2f08fSAdrian Chadd 	/*
13664bc2f08fSAdrian Chadd 	 * Fillin type-dependent bits.  Most of this can be
13674bc2f08fSAdrian Chadd 	 * removed by specifying the queue parameters in the
13684bc2f08fSAdrian Chadd 	 * driver; it's here for backwards compatibility.
13694bc2f08fSAdrian Chadd 	 */
13704bc2f08fSAdrian Chadd 	switch (qi->tqi_type) {
13714bc2f08fSAdrian Chadd 	case HAL_TX_QUEUE_BEACON:		/* beacon frames */
13724bc2f08fSAdrian Chadd 		qmisc |= AR_Q_MISC_FSP_DBA_GATED
13734bc2f08fSAdrian Chadd 		      |  AR_Q_MISC_BEACON_USE
13744bc2f08fSAdrian Chadd 		      |  AR_Q_MISC_CBR_INCR_DIS1;
13754bc2f08fSAdrian Chadd 
13764bc2f08fSAdrian Chadd 		dmisc |= SM(AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL,
13774bc2f08fSAdrian Chadd 			    AR_D_MISC_ARB_LOCKOUT_CNTRL)
13784bc2f08fSAdrian Chadd 		      |  AR_D_MISC_BEACON_USE
13794bc2f08fSAdrian Chadd 		      |  AR_D_MISC_POST_FR_BKOFF_DIS;
13804bc2f08fSAdrian Chadd 		break;
13814bc2f08fSAdrian Chadd 	case HAL_TX_QUEUE_CAB:			/* CAB  frames */
13824bc2f08fSAdrian Chadd 		/*
13834bc2f08fSAdrian Chadd 		 * No longer Enable AR_Q_MISC_RDYTIME_EXP_POLICY,
13844bc2f08fSAdrian Chadd 		 * There is an issue with the CAB Queue
13854bc2f08fSAdrian Chadd 		 * not properly refreshing the Tx descriptor if
13864bc2f08fSAdrian Chadd 		 * the TXE clear setting is used.
13874bc2f08fSAdrian Chadd 		 */
13884bc2f08fSAdrian Chadd 		qmisc |= AR_Q_MISC_FSP_DBA_GATED
13894bc2f08fSAdrian Chadd 		      |  AR_Q_MISC_CBR_INCR_DIS1
13904bc2f08fSAdrian Chadd 		      |  AR_Q_MISC_CBR_INCR_DIS0;
1391353d2977SAdrian Chadd 		HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: CAB: tqi_readyTime = %d\n",
1392353d2977SAdrian Chadd 		    __func__, qi->tqi_readyTime);
1393353d2977SAdrian Chadd 		if (qi->tqi_readyTime) {
1394353d2977SAdrian Chadd 			HALDEBUG(ah, HAL_DEBUG_TXQUEUE,
1395353d2977SAdrian Chadd 			    "%s: using tqi_readyTime\n", __func__);
1396353d2977SAdrian Chadd 			OS_REG_WRITE(ah, AR_QRDYTIMECFG(q),
1397353d2977SAdrian Chadd 			    SM(qi->tqi_readyTime, AR_Q_RDYTIMECFG_INT) |
1398353d2977SAdrian Chadd 			    AR_Q_RDYTIMECFG_ENA);
1399353d2977SAdrian Chadd 		} else {
1400353d2977SAdrian Chadd 			int value;
14014bc2f08fSAdrian Chadd 			/*
14024bc2f08fSAdrian Chadd 			 * NB: don't set default ready time if driver
14034bc2f08fSAdrian Chadd 			 * has explicitly specified something.  This is
14044bc2f08fSAdrian Chadd 			 * here solely for backwards compatibility.
14054bc2f08fSAdrian Chadd 			 */
1406353d2977SAdrian Chadd 			/*
1407353d2977SAdrian Chadd 			 * XXX for now, hard-code a CAB interval of 70%
1408353d2977SAdrian Chadd 			 * XXX of the total beacon interval.
1409353d2977SAdrian Chadd 			 *
1410353d2977SAdrian Chadd 			 * XXX This keeps Merlin and later based MACs
1411353d2977SAdrian Chadd 			 * XXX quite a bit happier (stops stuck beacons,
1412353d2977SAdrian Chadd 			 * XXX which I gather is because of such a long
1413353d2977SAdrian Chadd 			 * XXX cabq time.)
1414353d2977SAdrian Chadd 			 */
141549ddabc4SAdrian Chadd 			value = (ahp->ah_beaconInterval * 50 / 100)
141649ddabc4SAdrian Chadd 				- ah->ah_config.ah_additional_swba_backoff
141749ddabc4SAdrian Chadd 				- ah->ah_config.ah_sw_beacon_response_time
141849ddabc4SAdrian Chadd 				+ ah->ah_config.ah_dma_beacon_response_time;
1419353d2977SAdrian Chadd 			/*
1420353d2977SAdrian Chadd 			 * XXX Ensure it isn't too low - nothing lower
1421353d2977SAdrian Chadd 			 * XXX than 10 TU
1422353d2977SAdrian Chadd 			 */
1423353d2977SAdrian Chadd 			if (value < 10)
1424353d2977SAdrian Chadd 				value = 10;
1425353d2977SAdrian Chadd 			HALDEBUG(ah, HAL_DEBUG_TXQUEUE,
1426353d2977SAdrian Chadd 			    "%s: defaulting to rdytime = %d uS\n",
1427353d2977SAdrian Chadd 			    __func__, value);
1428353d2977SAdrian Chadd 			OS_REG_WRITE(ah, AR_QRDYTIMECFG(q),
1429353d2977SAdrian Chadd 			    SM(TU_TO_USEC(value), AR_Q_RDYTIMECFG_INT) |
1430353d2977SAdrian Chadd 			    AR_Q_RDYTIMECFG_ENA);
14314bc2f08fSAdrian Chadd 		}
14324bc2f08fSAdrian Chadd 		dmisc |= SM(AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL,
14334bc2f08fSAdrian Chadd 			    AR_D_MISC_ARB_LOCKOUT_CNTRL);
14344bc2f08fSAdrian Chadd 		break;
1435dca968a2SAdrian Chadd 	case HAL_TX_QUEUE_PSPOLL:
1436dca968a2SAdrian Chadd 		qmisc |= AR_Q_MISC_CBR_INCR_DIS1;
1437dca968a2SAdrian Chadd 		break;
1438dca968a2SAdrian Chadd 	case HAL_TX_QUEUE_UAPSD:
1439dca968a2SAdrian Chadd 		dmisc |= AR_D_MISC_POST_FR_BKOFF_DIS;
1440dca968a2SAdrian Chadd 		break;
14414bc2f08fSAdrian Chadd 	default:			/* NB: silence compiler */
14424bc2f08fSAdrian Chadd 		break;
14434bc2f08fSAdrian Chadd 	}
14444bc2f08fSAdrian Chadd 
14454bc2f08fSAdrian Chadd 	OS_REG_WRITE(ah, AR_QMISC(q), qmisc);
14464bc2f08fSAdrian Chadd 	OS_REG_WRITE(ah, AR_DMISC(q), dmisc);
14474bc2f08fSAdrian Chadd 
14484bc2f08fSAdrian Chadd 	/* Setup compression scratchpad buffer */
14494bc2f08fSAdrian Chadd 	/*
14504bc2f08fSAdrian Chadd 	 * XXX: calling this asynchronously to queue operation can
14514bc2f08fSAdrian Chadd 	 *      cause unexpected behavior!!!
14524bc2f08fSAdrian Chadd 	 */
14534bc2f08fSAdrian Chadd 	if (qi->tqi_physCompBuf) {
14544bc2f08fSAdrian Chadd 		HALASSERT(qi->tqi_type == HAL_TX_QUEUE_DATA ||
14554bc2f08fSAdrian Chadd 			  qi->tqi_type == HAL_TX_QUEUE_UAPSD);
14564bc2f08fSAdrian Chadd 		OS_REG_WRITE(ah, AR_Q_CBBS, (80 + 2*q));
14574bc2f08fSAdrian Chadd 		OS_REG_WRITE(ah, AR_Q_CBBA, qi->tqi_physCompBuf);
14584bc2f08fSAdrian Chadd 		OS_REG_WRITE(ah, AR_Q_CBC,  HAL_COMP_BUF_MAX_SIZE/1024);
14594bc2f08fSAdrian Chadd 		OS_REG_WRITE(ah, AR_Q0_MISC + 4*q,
14604bc2f08fSAdrian Chadd 			     OS_REG_READ(ah, AR_Q0_MISC + 4*q)
14614bc2f08fSAdrian Chadd 			     | AR_Q_MISC_QCU_COMP_EN);
14624bc2f08fSAdrian Chadd 	}
14634bc2f08fSAdrian Chadd 
14644bc2f08fSAdrian Chadd 	/*
14654bc2f08fSAdrian Chadd 	 * Always update the secondary interrupt mask registers - this
14664bc2f08fSAdrian Chadd 	 * could be a new queue getting enabled in a running system or
14674bc2f08fSAdrian Chadd 	 * hw getting re-initialized during a reset!
14684bc2f08fSAdrian Chadd 	 *
14694bc2f08fSAdrian Chadd 	 * Since we don't differentiate between tx interrupts corresponding
14704bc2f08fSAdrian Chadd 	 * to individual queues - secondary tx mask regs are always unmasked;
14714bc2f08fSAdrian Chadd 	 * tx interrupts are enabled/disabled for all queues collectively
14724bc2f08fSAdrian Chadd 	 * using the primary mask reg
14734bc2f08fSAdrian Chadd 	 */
14744bc2f08fSAdrian Chadd 	if (qi->tqi_qflags & HAL_TXQ_TXOKINT_ENABLE)
14754bc2f08fSAdrian Chadd 		ahp->ah_txOkInterruptMask |= 1 << q;
14764bc2f08fSAdrian Chadd 	else
14774bc2f08fSAdrian Chadd 		ahp->ah_txOkInterruptMask &= ~(1 << q);
14784bc2f08fSAdrian Chadd 	if (qi->tqi_qflags & HAL_TXQ_TXERRINT_ENABLE)
14794bc2f08fSAdrian Chadd 		ahp->ah_txErrInterruptMask |= 1 << q;
14804bc2f08fSAdrian Chadd 	else
14814bc2f08fSAdrian Chadd 		ahp->ah_txErrInterruptMask &= ~(1 << q);
14824bc2f08fSAdrian Chadd 	if (qi->tqi_qflags & HAL_TXQ_TXDESCINT_ENABLE)
14834bc2f08fSAdrian Chadd 		ahp->ah_txDescInterruptMask |= 1 << q;
14844bc2f08fSAdrian Chadd 	else
14854bc2f08fSAdrian Chadd 		ahp->ah_txDescInterruptMask &= ~(1 << q);
14864bc2f08fSAdrian Chadd 	if (qi->tqi_qflags & HAL_TXQ_TXEOLINT_ENABLE)
14874bc2f08fSAdrian Chadd 		ahp->ah_txEolInterruptMask |= 1 << q;
14884bc2f08fSAdrian Chadd 	else
14894bc2f08fSAdrian Chadd 		ahp->ah_txEolInterruptMask &= ~(1 << q);
14904bc2f08fSAdrian Chadd 	if (qi->tqi_qflags & HAL_TXQ_TXURNINT_ENABLE)
14914bc2f08fSAdrian Chadd 		ahp->ah_txUrnInterruptMask |= 1 << q;
14924bc2f08fSAdrian Chadd 	else
14934bc2f08fSAdrian Chadd 		ahp->ah_txUrnInterruptMask &= ~(1 << q);
14944bc2f08fSAdrian Chadd 	setTxQInterrupts(ah, qi);
14954bc2f08fSAdrian Chadd 
14964bc2f08fSAdrian Chadd 	return AH_TRUE;
14974bc2f08fSAdrian Chadd }
1498353d2977SAdrian Chadd #undef	TU_TO_USEC
1499