Esempio n. 1
0
static void
dumpchannels(struct ath_hal *ah, int nc, HAL_CHANNEL *chans, int16_t *txpow)
{
	int i;

	for (i = 0; i < nc; i++) {
		HAL_CHANNEL *c = &chans[i];
		int type;

		printf("%s%u", sep, c->channel);
		if (IS_CHAN_TURBO(c))
			type = 'T';
		else if (IS_CHAN_A(c))
			type = 'A';
		else if (IS_CHAN_G(c))
			type = 'G';
		else
			type = 'B';
		if (dopassive && IS_CHAN_PASSIVE(c))
			type = tolower(type);
		printf("%c %d.%d", type, txpow[i]/2, (txpow[i]%2)*5);
		if ((n++ % 6) == 0)
			sep = "\n";
		else
			sep = " ";
	}
}
Esempio n. 2
0
/*
 * Determines and returns the new Tx rate index.
 */
A_UINT16
rcRateFind(struct ath_softc *sc, struct atheros_node *pSib,
           A_UINT32 frameLen,
           const RATE_TABLE *pRateTable,
           HAL_CHANNEL *curchan, int isretry)
{
#ifdef notyet
    WLAN_STA_CONFIG      *pConfig     = &pdevInfo->staConfig;
    VPORT_BSS            *pVportXrBss = GET_XR_BSS(pdevInfo);
    WLAN_DATA_MAC_HEADER *pHdr        = pDesc->pBufferVirtPtr.header;
#endif
    struct TxRateCtrl_s  *pRc;
    A_UINT32             dt;
    A_UINT32             bestThruput,thisThruput = 0;
    A_UINT32             nowMsec;
    A_UINT8              rate, nextRate, bestRate;
    A_RSSI               rssiLast, rssiReduce;
#if ATH_SUPERG_DYNTURBO
    A_UINT8              currentPrimeState = IS_CHAN_TURBO(curchan);
    /* 0 = regular; 1 = turbo */
    A_UINT8              primeInUse        = sc->sc_dturbo;
#else
    A_UINT8              primeInUse        = 0;
    A_UINT8              currentPrimeState = 0;
#endif
#ifdef notyet
    A_UINT8              xrRateAdaptation = FALSE;
#endif
    int               isChanTurbo      = FALSE;
    A_UINT8              maxIndex, minIndex;
    A_INT8               index;
    int               isProbing = FALSE;

    /* have the real rate control logic kick in */
    pRc = &pSib->txRateCtrl;

#if ATH_SUPERG_DYNTURBO
    /*
     * Reset primeInUse state, if we are currently using XR
     * rate tables or if we have any clients associated in XR mode
     */
#ifdef notyet
    if ((pRateTable == sc->sc_rates[WLAN_MODE_XR]) ||
            (isXrAp(sc) && (pVportXrBss->bss.numAssociatedClients > 0)))
    {
        currentPrimeState = 0;
        primeInUse = 0;
    }
#endif

    /* make sure that rateMax is correct when using TURBO_PRIME tables */
    if (currentPrimeState)
    {
        pRc->rateMax = pRateTable->rateCount - 1;
    } else
    {
        pRc->rateMax = pRateTable->rateCount - 1 - pRateTable->numTurboRates;
    }
#endif /* ATH_SUPERG_DYNTURBO */

    rssiLast   = median(pRc->rssiLast, pRc->rssiLastPrev, pRc->rssiLastPrev2);
    rssiReduce = 0;

    /*
     * Age (reduce) last ack rssi based on how old it is.
     * The bizarre numbers are so the delta is 160msec,
     * meaning we divide by 16.
     *   0msec   <= dt <= 25msec:   don't derate
     *   25msec  <= dt <= 185msec:  derate linearly from 0 to 10dB
     *   185msec <= dt:             derate by 10dB
     */
    nowMsec = A_MS_TICKGET();
    dt = nowMsec - pRc->rssiTime;

    if (dt >= 185) {
        rssiReduce = 10;
    } else if (dt >= 25) {
        rssiReduce = (A_UINT8)((dt - 25) >> 4);
    }
Esempio n. 3
0
/*
 * Sets the transmit power in the baseband for the given
 * operating channel and mode.
 */
static HAL_BOOL
setRateTable(struct ath_hal *ah, HAL_CHANNEL *chan, 
		   int16_t tpcScaleReduction, int16_t powerLimit,
                   int16_t *pMinPower, int16_t *pMaxPower)
{
	u_int16_t ratesArray[16];
	u_int16_t *rpow = ratesArray;
	u_int16_t twiceMaxRDPower, twiceMaxEdgePower, twiceMaxEdgePowerCck;
	int8_t twiceAntennaGain, twiceAntennaReduction;
	TRGT_POWER_INFO targetPowerOfdm, targetPowerCck;
	RD_EDGES_POWER *rep;
	int16_t scaledPower;
	u_int8_t cfgCtl;

	twiceMaxRDPower = ath_hal_getchannelpower(ah, chan) * 2;
	*pMaxPower = -MAX_RATE_POWER;
	*pMinPower = MAX_RATE_POWER;

	/* Get conformance test limit maximum for this channel */
	cfgCtl = ath_hal_getctl(ah, chan);
	rep = findEdgePower(ah, cfgCtl);
	if (rep != AH_NULL)
		twiceMaxEdgePower = ar5212GetMaxEdgePower(chan->channel, rep);
	else
		twiceMaxEdgePower = MAX_RATE_POWER;

	if (IS_CHAN_G(chan)) {
		/* Check for a CCK CTL for 11G CCK powers */
		cfgCtl = (cfgCtl & 0xFC) | 0x01;
		rep = findEdgePower(ah, cfgCtl);
		if (rep != AH_NULL)
			twiceMaxEdgePowerCck = ar5212GetMaxEdgePower(chan->channel, rep);
		else
			twiceMaxEdgePowerCck = MAX_RATE_POWER;
	} else {
		/* Set the 11B cck edge power to the one found before */
		twiceMaxEdgePowerCck = twiceMaxEdgePower;
	}

	/* Get Antenna Gain reduction */
	if (IS_CHAN_5GHZ(chan)) {
		twiceAntennaGain = antennaGainMax[0];
	} else {
		twiceAntennaGain = antennaGainMax[1];
	}
	twiceAntennaReduction =
		ath_hal_getantennareduction(ah, chan, twiceAntennaGain);

	if (IS_CHAN_OFDM(chan)) {
		/* Get final OFDM target powers */
		if (IS_CHAN_G(chan)) { 
			/* TODO - add Turbo 2.4 to this mode check */
			ar5212GetTargetPowers(ah, chan, trgtPwr_11g,
				numTargetPwr_11g, &targetPowerOfdm);
		} else {
			ar5212GetTargetPowers(ah, chan, trgtPwr_11a,
				numTargetPwr_11a, &targetPowerOfdm);
		}

		/* Get Maximum OFDM power */
		/* Minimum of target and edge powers */
		scaledPower = AH_MIN(twiceMaxEdgePower,
				twiceMaxRDPower - twiceAntennaReduction);

		/*
		 * If turbo is set, reduce power to keep power
		 * consumption under 2 Watts.  Note that we always do
		 * this unless specially configured.  Then we limit
		 * power only for non-AP operation.
		 */
		if (IS_CHAN_TURBO(chan)
#ifdef AH_ENABLE_AP_SUPPORT
		    && AH_PRIVATE(ah)->ah_opmode != HAL_M_HOSTAP
#endif
		) {
			/*
			 * If turbo is set, reduce power to keep power
			 * consumption under 2 Watts
			 */
			if (eeversion >= AR_EEPROM_VER3_1)
				scaledPower = AH_MIN(scaledPower,
					turbo2WMaxPower5);
			/*
			 * EEPROM version 4.0 added an additional
			 * constraint on 2.4GHz channels.
			 */
			if (eeversion >= AR_EEPROM_VER4_0 &&
			    IS_CHAN_2GHZ(chan))
				scaledPower = AH_MIN(scaledPower,
					turbo2WMaxPower2);
		}
		/* Reduce power by max regulatory domain allowed restrictions */
		scaledPower -= (tpcScaleReduction * 2);
		scaledPower = (scaledPower < 0) ? 0 : scaledPower;
		scaledPower = AH_MIN(scaledPower, powerLimit);

		scaledPower = AH_MIN(scaledPower, targetPowerOfdm.twicePwr6_24);

		/* Set OFDM rates 9, 12, 18, 24, 36, 48, 54, XR */
		rpow[0] = rpow[1] = rpow[2] = rpow[3] = rpow[4] = scaledPower;
		rpow[5] = AH_MIN(rpow[0], targetPowerOfdm.twicePwr36);
		rpow[6] = AH_MIN(rpow[0], targetPowerOfdm.twicePwr48);
		rpow[7] = AH_MIN(rpow[0], targetPowerOfdm.twicePwr54);

#ifdef notyet
		if (eeversion >= AR_EEPROM_VER4_0) {
			/* Setup XR target power from EEPROM */
			rpow[15] = AH_MIN(scaledPower, IS_CHAN_2GHZ(chan) ?
				xrTargetPower2 : xrTargetPower5);
		} else {
			/* XR uses 6mb power */
			rpow[15] = rpow[0];
		}
#else
		rpow[15] = rpow[0];
#endif

		*pMinPower = rpow[7];
		*pMaxPower = rpow[0];

#if 0
		ahp->ah_ofdmTxPower = rpow[0];
#endif

		HALDEBUG(ah, "%s: MaxRD: %d TurboMax: %d MaxCTL: %d "
			"TPC_Reduction %d\n",
			__func__,
			twiceMaxRDPower, turbo2WMaxPower5,
			twiceMaxEdgePower, tpcScaleReduction * 2);
	}

	if (IS_CHAN_CCK(chan) || IS_CHAN_G(chan)) {
		/* Get final CCK target powers */
		ar5212GetTargetPowers(ah, chan, trgtPwr_11b,
			numTargetPwr_11b, &targetPowerCck);

		/* Reduce power by max regulatory domain allowed restrictions */
		scaledPower = AH_MIN(twiceMaxEdgePowerCck,
			twiceMaxRDPower - twiceAntennaReduction);

		scaledPower -= (tpcScaleReduction * 2);
		scaledPower = (scaledPower < 0) ? 0 : scaledPower;
		scaledPower = AH_MIN(scaledPower, powerLimit);

		rpow[8] = (scaledPower < 1) ? 1 : scaledPower;

		/* Set CCK rates 2L, 2S, 5.5L, 5.5S, 11L, 11S */
		rpow[8]  = AH_MIN(scaledPower, targetPowerCck.twicePwr6_24);
		rpow[9]  = AH_MIN(scaledPower, targetPowerCck.twicePwr36);
		rpow[10] = rpow[9];
		rpow[11] = AH_MIN(scaledPower, targetPowerCck.twicePwr48);
		rpow[12] = rpow[11];
		rpow[13] = AH_MIN(scaledPower, targetPowerCck.twicePwr54);
		rpow[14] = rpow[13];

		/* Set min/max power based off OFDM values or initialization */
		if (rpow[13] < *pMinPower)
		    *pMinPower = rpow[13];
		if (rpow[9] > *pMaxPower)
		    *pMaxPower = rpow[9];

	}
#if 0
	ahp->ah_tx6PowerInHalfDbm = *pMaxPower;
#endif
	return AH_TRUE;
}
/*
 * Places the hardware into reset and then pulls it out of reset
 *
 * TODO: Only write the PLL if we're changing to or from CCK mode
 * 
 * WARNING: The order of the PLL and mode registers must be correct.
 */
HAL_BOOL
ar5312ChipReset(struct ath_hal *ah, HAL_CHANNEL *chan)
{

	OS_MARK(ah, AH_MARK_CHIPRESET, chan ? chan->channel : 0);

	/*
	 * Reset the HW 
	 */
	if (!ar5312SetResetReg(ah, AR_RC_MAC | AR_RC_BB)) {
		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: ar5312SetResetReg failed\n",
		    __func__);
		return AH_FALSE;
	}

	/* Bring out of sleep mode (AGAIN) */
	if (!ar5312SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) {
		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: ar5312SetPowerMode failed\n",
		    __func__);
		return AH_FALSE;
	}

	/* Clear warm reset register */
	if (!ar5312SetResetReg(ah, 0)) {
		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: ar5312SetResetReg failed\n",
		    __func__);
		return AH_FALSE;
	}

	/*
	 * Perform warm reset before the mode/PLL/turbo registers
	 * are changed in order to deactivate the radio.  Mode changes
	 * with an active radio can result in corrupted shifts to the
	 * radio device.
	 */

	/*
	 * Set CCK and Turbo modes correctly.
	 */
	if (chan != AH_NULL) {		/* NB: can be null during attach */
		uint32_t rfMode, phyPLL = 0, curPhyPLL, turbo;

		if (IS_RAD5112_ANY(ah)) {
			rfMode = AR_PHY_MODE_AR5112;
			if (!IS_5315(ah)) {
				if (IS_CHAN_CCK(chan) || IS_CHAN_G(chan)) {
					phyPLL = AR_PHY_PLL_CTL_44_5312;
				} else {
					if (IS_CHAN_HALF_RATE(chan)) {
						phyPLL = AR_PHY_PLL_CTL_40_5312_HALF;
					} else if (IS_CHAN_QUARTER_RATE(chan)) {
						phyPLL = AR_PHY_PLL_CTL_40_5312_QUARTER;
					} else {
						phyPLL = AR_PHY_PLL_CTL_40_5312;
					}
				}
			} else {
				if (IS_CHAN_CCK(chan) || IS_CHAN_G(chan))
					phyPLL = AR_PHY_PLL_CTL_44_5112;
				else
					phyPLL = AR_PHY_PLL_CTL_40_5112;
				if (IS_CHAN_HALF_RATE(chan))
					phyPLL |= AR_PHY_PLL_CTL_HALF;
				else if (IS_CHAN_QUARTER_RATE(chan))
					phyPLL |= AR_PHY_PLL_CTL_QUARTER;
			}
		} else {
			rfMode = AR_PHY_MODE_AR5111;
			if (IS_CHAN_CCK(chan) || IS_CHAN_G(chan))
				phyPLL = AR_PHY_PLL_CTL_44;
			else
				phyPLL = AR_PHY_PLL_CTL_40;
			if (IS_CHAN_HALF_RATE(chan))
				phyPLL = AR_PHY_PLL_CTL_HALF;
			else if (IS_CHAN_QUARTER_RATE(chan))
				phyPLL = AR_PHY_PLL_CTL_QUARTER;
		}
		if (IS_CHAN_OFDM(chan) && (IS_CHAN_CCK(chan) || 
					   IS_CHAN_G(chan)))
			rfMode |= AR_PHY_MODE_DYNAMIC;
		else if (IS_CHAN_OFDM(chan))
			rfMode |= AR_PHY_MODE_OFDM;
		else
			rfMode |= AR_PHY_MODE_CCK;
		if (IS_CHAN_5GHZ(chan))
			rfMode |= AR_PHY_MODE_RF5GHZ;
		else
			rfMode |= AR_PHY_MODE_RF2GHZ;
		turbo = IS_CHAN_TURBO(chan) ?
			(AR_PHY_FC_TURBO_MODE | AR_PHY_FC_TURBO_SHORT) : 0;
		curPhyPLL = OS_REG_READ(ah, AR_PHY_PLL_CTL);
		/*
		 * PLL, Mode, and Turbo values must be written in the correct
		 * order to ensure:
		 * - The PLL cannot be set to 44 unless the CCK or DYNAMIC
		 *   mode bit is set
		 * - Turbo cannot be set at the same time as CCK or DYNAMIC
		 */
		if (IS_CHAN_CCK(chan) || IS_CHAN_G(chan)) {
			OS_REG_WRITE(ah, AR_PHY_TURBO, turbo);
			OS_REG_WRITE(ah, AR_PHY_MODE, rfMode);
			if (curPhyPLL != phyPLL) {
				OS_REG_WRITE(ah,  AR_PHY_PLL_CTL,  phyPLL);
				/* Wait for the PLL to settle */
				OS_DELAY(PLL_SETTLE_DELAY);
			}
		} else {
			if (curPhyPLL != phyPLL) {
				OS_REG_WRITE(ah,  AR_PHY_PLL_CTL,  phyPLL);
				/* Wait for the PLL to settle */
				OS_DELAY(PLL_SETTLE_DELAY);
			}
			OS_REG_WRITE(ah, AR_PHY_TURBO, turbo);
			OS_REG_WRITE(ah, AR_PHY_MODE, rfMode);
		}
	}
	return AH_TRUE;
}
Esempio n. 5
0
/*
 * Return the next series 0 transmit rate and setup for a callback
 * to install the multi-rate transmit data if appropriate.  We cannot
 * install the multi-rate transmit data here because the caller is
 * going to initialize the tx descriptor and so would clobber whatever
 * we write. Note that we choose an arbitrary series 0 try count to
 * insure we get called back; this permits us to defer calculating
 * the actual number of tries until the callback at which time we
 * can just copy the pre-calculated series data.
 */
void
ath_rate_findrate(struct ath_softc *sc, struct ath_node *an,
                  int shortPreamble, u_int32_t frameLen, int numTries,
                  unsigned int rcflag, u_int8_t ac, struct ath_rc_series rcs[],
                  int *isProbe, int isretry,u_int32_t bf_flags)
{
    struct atheros_node *oan = an->an_rc_node;
    struct atheros_softc *asc = oan->asc;
    struct atheros_vap *avap = oan->avp;
    struct ath_vap *avp = oan->avp->athdev_vap;
    const RATE_TABLE *pRateTable = avap->rateTable;
    u_int8_t *retrySched;
    int       i;
    u_int8_t fixedratecode;
    u_int32_t old_av_fixed_rateset;
    u_int32_t old_av_fixed_retryset;

    ASSERT(rcs != NULL);

    if (sc->sc_ah->ah_magic == 0x19641014 ||
        sc->sc_ah->ah_magic == 0x19741014)
    {
#ifdef ATH_SUPPORT_TxBF     // set calibration and sounding indicator
#define MS(_v, _f)  (((_v) & _f) >> _f##_S)
        sc->sc_txbfsounding = 0;
        oan->txbf_sounding = 0;
        sc->sc_txbfcalibrating = 0;
        if ((MS(bf_flags,HAL_TXDESC_TXBF_SOUND)==HAL_TXDESC_STAG_SOUND)
            ||(MS(bf_flags,HAL_TXDESC_TXBF_SOUND)== HAL_TXDESC_SOUND)){
            sc->sc_txbfsounding = 1;
            oan->txbf_sounding = 1;
        }            
        if (bf_flags & HAL_TXDESC_CAL) {
            sc->sc_txbfcalibrating = 1;
        }
#endif
        /* store the previous values */
        old_av_fixed_rateset = avp->av_config.av_fixed_rateset;
        old_av_fixed_retryset = avp->av_config.av_fixed_retryset;

        /* If fixed node rate is enabled, we fixed the link rate */
        if (an->an_fixedrate_enable) {
            fixedratecode = an->an_fixedratecode;
            avp->av_config.av_fixed_rateset = 0;
            for (i=0; i<4; i++) {
                avp->av_config.av_fixed_rateset <<= 8;
                avp->av_config.av_fixed_rateset |= fixedratecode; 
            }
            avp->av_config.av_fixed_retryset = 0x03030303;
        }

            ath_rate_findrate_11n(sc, an, frameLen, numTries, 4,
                                  rcflag, ac, rcs, isProbe, isretry);

        /* restore the previous values */
        avp->av_config.av_fixed_rateset = old_av_fixed_rateset;
        avp->av_config.av_fixed_retryset = old_av_fixed_retryset;
            return;
    }

    if (asc->fixedrix == IEEE80211_FIXED_RATE_NONE) {
        rcs[0].rix = rcRateFind(sc, oan, frameLen, pRateTable, &sc->sc_curchan, isretry);
	/* multi-rate support implied */
        rcs[0].tries = ATH_TXMAXTRY-1;	/* anything != ATH_TXMAXTRY */
    } else {
        rcs[0].rix = asc->fixedrix;
        rcs[0].tries = ATH_TXMAXTRY;
    }

    /* If fixed node rate is enabled, we fixed the link rate */
    if (an->an_fixedrate_enable) {
        rcs[0].rix = an->an_fixedrix;
        rcs[0].tries = ATH_TXMAXTRY;
    }

    ASSERT(rcs[0].rix != (u_int8_t)-1);
    /* get the corresponding index for the choosen rate in txRateCtrl */
    for (i = 0; oan->txRateCtrl.validRateIndex[i] != rcs[0].rix 
       && i < oan->txRateCtrl.maxValidRate ; i++);

    ASSERT(asc->fixedrix != IEEE80211_FIXED_RATE_NONE || i != oan->txRateCtrl.maxValidRate);

    if (rcs[0].tries != ATH_TXMAXTRY) {

        /* NB: only called for data frames */
        if (oan->txRateCtrl.probeRate) {
            retrySched = shortPreamble ?
                (u_int8_t *)&(oan->txRateCtrl.validRateSeries[i][24]) :
                (u_int8_t *)&(oan->txRateCtrl.validRateSeries[i][16]);
        } else {
            retrySched = shortPreamble ?
                (u_int8_t *)&(oan->txRateCtrl.validRateSeries[i][8]) :
                (u_int8_t *)&(oan->txRateCtrl.validRateSeries[i][0]);
        }
#ifdef ATH_SUPPORT_UAPSD_RATE_CONTROL
        if (oan->uapsd) {
            retrySched = shortPreamble ?
                (u_int8_t *)&(oan->txRateCtrl.validRateSeries[i][40]) :
                (u_int8_t *)&(oan->txRateCtrl.validRateSeries[i][32]);
        }
#endif /* ATH_SUPPORT_UAPSD_RATE_CONTROL */
        /* Update rate seies based on retry schedule */
        rcs[0].tries = retrySched[0];
        rcs[1].tries = retrySched[1];
        rcs[2].tries = retrySched[2];
        rcs[3].tries = retrySched[3];
        
        if (!IS_CHAN_TURBO(&sc->sc_curchan))
            ASSERT(rcs[0].rix == pRateTable->rateCodeToIndex[retrySched[4]]);

        /* 
         * Retry scheduler assumes that all the rates below max rate in the
         * intersection rate table are present and so it takes the next possible
         * lower rates for the retries, which is not correct. So check them
         * before filling the retry rates.
         */
        rcs[1].rix = pRateTable->rateCodeToIndex[retrySched[5]];
        rcs[2].rix = pRateTable->rateCodeToIndex[retrySched[6]];
        rcs[3].rix = pRateTable->rateCodeToIndex[retrySched[7]];

        if (sc->sc_curchan.privFlags & CHANNEL_4MS_LIMIT) {
            u_int32_t  prevrix = rcs[0].rix;

            for (i=1; i<4; i++) {
                if (rcs[i].tries) {
                    if (pRateTable->info[rcs[i].rix].max4msFrameLen < frameLen) {
                        rcs[i].rix = prevrix;
                    } else {
                        prevrix = rcs[i].rix;
                    }
                } else {
                    /* Retries are 0 from here */
                    break;
                }
            }
        }

    }

    if (sc->sc_ieee_ops->update_txrate) {
        sc->sc_ieee_ops->update_txrate(an->an_node, oan->rixMap[rcs[0].rix]);
    }
    
#if ATH_SUPERG_DYNTURBO
    /* XXX map from merged table to split for driver */
    if (IS_CHAN_TURBO(&sc->sc_curchan) && rcs[0].rix >=
        (pRateTable->rateCount - pRateTable->numTurboRates))
    {
        u_int32_t numCCKRates = 5;
        u_int32_t i;

         rcs[0].rix -= (pRateTable->rateCount-pRateTable->numTurboRates);
         if (IS_CHAN_2GHZ(&sc->sc_curchan)) {
            for (i=1;i<=3;i++) { /*Mapping for retry rates from merged table to split table*/
                 if (rcs[i].rix >= numCCKRates) {
                     rcs[i].rix -= numCCKRates;
                 } else { /* For 6Mbps Turbo rate */
                     rcs[i].rix -= numCCKRates-1;
                 }                                
            }
        }

    }
#endif
    if (oan->txRateCtrl.consecRtsFailCount > MAX_CONSEC_RTS_FAILED_FRAMES) {
        rcs[0].flags |= ATH_RC_RTSCTS_FLAG;
        rcs[1].rix = rcs[2].rix = rcs[3].rix = 0;
        rcs[1].tries = rcs[2].tries = rcs[3].tries = 0;
    }
}
Esempio n. 6
0
HAL_BOOL
ar5210ResetTxQueue(struct ath_hal *ah, u_int q)
{
	struct ath_hal_5210 *ahp = AH5210(ah);
	HAL_CHANNEL_INTERNAL *chan = AH_PRIVATE(ah)->ah_curchan;
	HAL_TX_QUEUE_INFO *qi;
	uint32_t cwMin;

	if (q >= HAL_NUM_TX_QUEUES) {
		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n",
		    __func__, q);
		return AH_FALSE;
	}
	qi = &ahp->ah_txq[q];
	if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) {
		HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: inactive queue %u\n",
		    __func__, q);
		return AH_FALSE;
	}

	/*
	 * Ignore any non-data queue(s).
	 */
	if (qi->tqi_type != HAL_TX_QUEUE_DATA)
		return AH_TRUE;

	/* Set turbo mode / base mode parameters on or off */
	if (IS_CHAN_TURBO(chan)) {
		OS_REG_WRITE(ah, AR_SLOT_TIME, INIT_SLOT_TIME_TURBO);
		OS_REG_WRITE(ah, AR_TIME_OUT, INIT_ACK_CTS_TIMEOUT_TURBO);
		OS_REG_WRITE(ah, AR_USEC, INIT_TRANSMIT_LATENCY_TURBO);
		OS_REG_WRITE(ah, AR_IFS0, 
			((INIT_SIFS_TURBO + qi->tqi_aifs * INIT_SLOT_TIME_TURBO)
				<< AR_IFS0_DIFS_S)
			| INIT_SIFS_TURBO);
		OS_REG_WRITE(ah, AR_IFS1, INIT_PROTO_TIME_CNTRL_TURBO);
		OS_REG_WRITE(ah, AR_PHY(17),
			(OS_REG_READ(ah, AR_PHY(17)) & ~0x7F) | 0x38);
		OS_REG_WRITE(ah, AR_PHY_FRCTL,
			AR_PHY_SERVICE_ERR | AR_PHY_TXURN_ERR |
			AR_PHY_ILLLEN_ERR | AR_PHY_ILLRATE_ERR |
			AR_PHY_PARITY_ERR | AR_PHY_TIMING_ERR |
			0x2020 |
			AR_PHY_TURBO_MODE | AR_PHY_TURBO_SHORT);
	} else {
		OS_REG_WRITE(ah, AR_SLOT_TIME, INIT_SLOT_TIME);
		OS_REG_WRITE(ah, AR_TIME_OUT, INIT_ACK_CTS_TIMEOUT);
		OS_REG_WRITE(ah, AR_USEC, INIT_TRANSMIT_LATENCY);
		OS_REG_WRITE(ah, AR_IFS0, 
			((INIT_SIFS + qi->tqi_aifs * INIT_SLOT_TIME)
				<< AR_IFS0_DIFS_S)
			| INIT_SIFS);
		OS_REG_WRITE(ah, AR_IFS1, INIT_PROTO_TIME_CNTRL);
		OS_REG_WRITE(ah, AR_PHY(17),
			(OS_REG_READ(ah, AR_PHY(17)) & ~0x7F) | 0x1C);
		OS_REG_WRITE(ah, AR_PHY_FRCTL,
			AR_PHY_SERVICE_ERR | AR_PHY_TXURN_ERR |
			AR_PHY_ILLLEN_ERR | AR_PHY_ILLRATE_ERR |
			AR_PHY_PARITY_ERR | AR_PHY_TIMING_ERR | 0x1020);
	}

	if (qi->tqi_cwmin == HAL_TXQ_USEDEFAULT)
		cwMin = INIT_CWMIN;
	else
		cwMin = qi->tqi_cwmin;

	/* Set cwmin and retry limit values */
	OS_REG_WRITE(ah, AR_RETRY_LMT, 
		  (cwMin << AR_RETRY_LMT_CW_MIN_S)
		 | SM(INIT_SLG_RETRY, AR_RETRY_LMT_SLG_RETRY)
		 | SM(INIT_SSH_RETRY, AR_RETRY_LMT_SSH_RETRY)
		 | SM(qi->tqi_lgretry, AR_RETRY_LMT_LG_RETRY)
		 | SM(qi->tqi_shretry, AR_RETRY_LMT_SH_RETRY)
	);

	if (qi->tqi_qflags & HAL_TXQ_TXOKINT_ENABLE)
		ahp->ah_txOkInterruptMask |= 1 << q;
	else
		ahp->ah_txOkInterruptMask &= ~(1 << q);
	if (qi->tqi_qflags & HAL_TXQ_TXERRINT_ENABLE)
		ahp->ah_txErrInterruptMask |= 1 << q;
	else
		ahp->ah_txErrInterruptMask &= ~(1 << q);
	if (qi->tqi_qflags & HAL_TXQ_TXDESCINT_ENABLE)
		ahp->ah_txDescInterruptMask |= 1 << q;
	else
		ahp->ah_txDescInterruptMask &= ~(1 << q);
	if (qi->tqi_qflags & HAL_TXQ_TXEOLINT_ENABLE)
		ahp->ah_txEolInterruptMask |= 1 << q;
	else
		ahp->ah_txEolInterruptMask &= ~(1 << q);
	if (qi->tqi_qflags & HAL_TXQ_TXURNINT_ENABLE)
		ahp->ah_txUrnInterruptMask |= 1 << q;
	else
		ahp->ah_txUrnInterruptMask &= ~(1 << q);

	return AH_TRUE;
}