summaryrefslogtreecommitdiffstats
path: root/sys/dev/ath
diff options
context:
space:
mode:
authoradrian <adrian@FreeBSD.org>2013-02-22 07:07:11 +0000
committeradrian <adrian@FreeBSD.org>2013-02-22 07:07:11 +0000
commit48730f45ab63e7928e7ccbcb9a5ef85115478c74 (patch)
treeb85623e450289edca86b8e4fb49bf87bd68e2374 /sys/dev/ath
parent8da5ddc4a58030c134944166ecf90768bc1e83f1 (diff)
downloadFreeBSD-src-48730f45ab63e7928e7ccbcb9a5ef85115478c74.zip
FreeBSD-src-48730f45ab63e7928e7ccbcb9a5ef85115478c74.tar.gz
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
Diffstat (limited to 'sys/dev/ath')
-rw-r--r--sys/dev/ath/ath_hal/ar5416/ar5416_xmit.c71
1 files changed, 70 insertions, 1 deletions
diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416_xmit.c b/sys/dev/ath/ath_hal/ar5416/ar5416_xmit.c
index 36f968f..945c766 100644
--- a/sys/dev/ath/ath_hal/ar5416/ar5416_xmit.c
+++ b/sys/dev/ath/ath_hal/ar5416/ar5416_xmit.c
@@ -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);
}
/*
OpenPOWER on IntegriCloud