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
This commit is contained in:
Adrian Chadd 2013-02-22 07:07:11 +00:00
parent 0ab13648f5
commit ffdc8f48dd

View File

@ -669,6 +669,26 @@ ar5416GetGlobalTxTimeout(struct ath_hal *ah)
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 *ah, struct ath_desc *ds,
| 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, struct ath_desc *ds)
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);
}
/*