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