Author: adrian Date: Fri Feb 22 07:07:11 2013 New Revision: 247145 URL: http://svnweb.freebsd.org/changeset/base/247145
Log: Add a workaround for AR5416, AR9130 and AR9160 chipsets - work around an incorrectly calculated RTS duration value when transmitting aggregates. These earlier 802.11n NICs incorrectly used the ACK duration time when calculating what to put in the RTS of an aggregate frame. Instead it should have used the block-ack time. The result is that other stations may not reserve enough time and start transmitting _over_ the top of the in-progress blockack field. Tsk. This workaround is to popuate the burst duration field with the delta between the ACK duration the hardware is using and the required duration for the block-ack. The result is that the RTS field should now contain the correct duration for the subsequent block-ack. This doesn't apply for AR9280 and later NICs. Obtained from: Qualcomm Atheros Modified: head/sys/dev/ath/ath_hal/ar5416/ar5416_xmit.c Modified: head/sys/dev/ath/ath_hal/ar5416/ar5416_xmit.c ============================================================================== --- head/sys/dev/ath/ath_hal/ar5416/ar5416_xmit.c Fri Feb 22 00:46:32 2013 (r247144) +++ head/sys/dev/ath/ath_hal/ar5416/ar5416_xmit.c Fri Feb 22 07:07:11 2013 (r247145) @@ -669,6 +669,26 @@ ar5416GetGlobalTxTimeout(struct ath_hal return MS(OS_REG_READ(ah, AR_GTXTO), AR_GTXTO_TIMEOUT_LIMIT); } +#define HT_RC_2_MCS(_rc) ((_rc) & 0x0f) +static const u_int8_t baDurationDelta[] = { + 24, // 0: BPSK + 12, // 1: QPSK 1/2 + 12, // 2: QPSK 3/4 + 4, // 3: 16-QAM 1/2 + 4, // 4: 16-QAM 3/4 + 4, // 5: 64-QAM 2/3 + 4, // 6: 64-QAM 3/4 + 4, // 7: 64-QAM 5/6 + 24, // 8: BPSK + 12, // 9: QPSK 1/2 + 12, // 10: QPSK 3/4 + 4, // 11: 16-QAM 1/2 + 4, // 12: 16-QAM 3/4 + 4, // 13: 64-QAM 2/3 + 4, // 14: 64-QAM 3/4 + 4, // 15: 64-QAM 5/6 +}; + void ar5416Set11nRateScenario(struct ath_hal *ah, struct ath_desc *ds, u_int durUpdateEn, u_int rtsctsRate, @@ -740,17 +760,44 @@ ar5416Set11nRateScenario(struct ath_hal | SM(rtsctsRate, AR_RTSCTSRate); } +/* + * Note: this should be called before calling ar5416SetBurstDuration() + * (if it is indeed called) in order to ensure that the burst duration + * is correctly updated with the BA delta workaround. + */ void ar5416Set11nAggrFirst(struct ath_hal *ah, struct ath_desc *ds, u_int aggrLen, u_int numDelims) { struct ar5416_desc *ads = AR5416DESC(ds); + uint32_t flags; + uint32_t burstDur; + uint8_t rate; ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr); ads->ds_ctl6 &= ~(AR_AggrLen | AR_PadDelim); ads->ds_ctl6 |= SM(aggrLen, AR_AggrLen); ads->ds_ctl6 |= SM(numDelims, AR_PadDelim); + + if (! AR_SREV_MERLIN_10_OR_LATER(ah)) { + /* + * XXX It'd be nice if I were passed in the rate scenario + * at this point.. + */ + rate = MS(ads->ds_ctl3, AR_XmitRate0); + flags = ads->ds_ctl0 & (AR_CTSEnable | AR_RTSEnable); + /* + * WAR - MAC assumes normal ACK time instead of + * block ACK while computing packet duration. + * Add this delta to the burst duration in the descriptor. + */ + if (flags && (ads->ds_ctl1 & AR_IsAggr)) { + burstDur = baDurationDelta[HT_RC_2_MCS(rate)]; + ads->ds_ctl2 &= ~(AR_BurstDur); + ads->ds_ctl2 |= SM(burstDur, AR_BurstDur); + } + } } void @@ -792,14 +839,36 @@ ar5416Clr11nAggr(struct ath_hal *ah, str ads->ds_ctl6 &= ~AR_AggrLen; } +/* + * Program the burst duration, with the included BA delta if it's + * applicable. + */ void ar5416Set11nBurstDuration(struct ath_hal *ah, struct ath_desc *ds, u_int burstDuration) { struct ar5416_desc *ads = AR5416DESC(ds); + uint32_t burstDur = 0; + uint8_t rate; + + if (! AR_SREV_MERLIN_10_OR_LATER(ah)) { + /* + * XXX It'd be nice if I were passed in the rate scenario + * at this point.. + */ + rate = MS(ads->ds_ctl3, AR_XmitDataTries0); + /* + * WAR - MAC assumes normal ACK time instead of + * block ACK while computing packet duration. + * Add this delta to the burst duration in the descriptor. + */ + if (ads->ds_ctl1 & AR_IsAggr) { + burstDur = baDurationDelta[HT_RC_2_MCS(rate)]; + } + } ads->ds_ctl2 &= ~AR_BurstDur; - ads->ds_ctl2 |= SM(burstDuration, AR_BurstDur); + ads->ds_ctl2 |= SM(burstDur + burstDuration, AR_BurstDur); } /* _______________________________________________ svn-src-all@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/svn-src-all To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"