svn commit: r247145 - head/sys/dev/ath/ath_hal/ar5416

Adrian Chadd adrian at FreeBSD.org
Fri Feb 22 07:07:12 UTC 2013


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);
 }
 
 /*


More information about the svn-src-head mailing list