ath9k_hw: Fix low throughput issue with AR93xx
authorSenthil Balasubramanian <senthilkumar@atheros.com>
Wed, 10 Nov 2010 13:03:16 +0000 (05:03 -0800)
committerJohn W. Linville <linville@tuxdriver.com>
Tue, 16 Nov 2010 21:37:07 +0000 (16:37 -0500)
TX underruns were noticed when RTS/CTS preceded aggregates.
This issue was noticed in ar93xx family of chipsets only.
The workaround involves padding the RTS or CTS length up
to the min packet length of 256 bytes required by the
hardware by adding delimiters to the fist descriptor of
the aggregate.

Signed-off-by: Senthil Balasubramanian <senthilkumar@atheros.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/ath/ath9k/ar9003_mac.c
drivers/net/wireless/ath/ath9k/hw.c
drivers/net/wireless/ath/ath9k/hw.h
drivers/net/wireless/ath/ath9k/reg.h

index 10c812e353a63b0294dab5669ab3888536eff0be..f5896aa3000580255ad14377d7ade91cd7c6fac4 100644 (file)
@@ -410,12 +410,36 @@ static void ar9003_hw_set11n_ratescenario(struct ath_hw *ah, void *ds,
 static void ar9003_hw_set11n_aggr_first(struct ath_hw *ah, void *ds,
                                        u32 aggrLen)
 {
+#define FIRST_DESC_NDELIMS 60
        struct ar9003_txc *ads = (struct ar9003_txc *) ds;
 
        ads->ctl12 |= (AR_IsAggr | AR_MoreAggr);
 
-       ads->ctl17 &= ~AR_AggrLen;
-       ads->ctl17 |= SM(aggrLen, AR_AggrLen);
+       if (ah->ent_mode & AR_ENT_OTP_MPSD) {
+               u32 ctl17, ndelim;
+               /*
+                * Add delimiter when using RTS/CTS with aggregation
+                * and non enterprise AR9003 card
+                */
+               ctl17 = ads->ctl17;
+               ndelim = MS(ctl17, AR_PadDelim);
+
+               if (ndelim < FIRST_DESC_NDELIMS) {
+                       aggrLen += (FIRST_DESC_NDELIMS - ndelim) * 4;
+                       ndelim = FIRST_DESC_NDELIMS;
+               }
+
+               ctl17 &= ~AR_AggrLen;
+               ctl17 |= SM(aggrLen, AR_AggrLen);
+
+               ctl17 &= ~AR_PadDelim;
+               ctl17 |= SM(ndelim, AR_PadDelim);
+
+               ads->ctl17 = ctl17;
+       } else {
+               ads->ctl17 &= ~AR_AggrLen;
+               ads->ctl17 |= SM(aggrLen, AR_AggrLen);
+       }
 }
 
 static void ar9003_hw_set11n_aggr_middle(struct ath_hw *ah, void *ds,
index e75d8e8cf4d2ddcf505bfdec8cc06ed4037372b2..75e23632b968659053291b947c3f49c9a0c14e7d 100644 (file)
@@ -1952,6 +1952,9 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
        if (AR_SREV_9300_20_OR_LATER(ah))
                pCap->hw_caps |= ATH9K_HW_CAP_RAC_SUPPORTED;
 
+       if (AR_SREV_9300_20_OR_LATER(ah))
+               ah->ent_mode = REG_READ(ah, AR_ENT_OTP);
+
        if (AR_SREV_9287_11_OR_LATER(ah) || AR_SREV_9271(ah))
                pCap->hw_caps |= ATH9K_HW_CAP_SGI_20;
 
index f821a28bcda3febf568eebaf177c39f547e74b99..15f51c8943a1f11b9b5358d053c1d5c4e8dc9ebe 100644 (file)
@@ -803,6 +803,9 @@ struct ath_hw {
         * this register when in sleep states.
         */
        u32 WARegVal;
+
+       /* Enterprise mode cap */
+       u32 ent_mode;
 };
 
 static inline struct ath_common *ath9k_hw_common(struct ath_hw *ah)
index ac6a13e2735241beb01e87223809891f3fd276ec..60826b82f4a2e9e6c51bf15ae886deb8642a5ee9 100644 (file)
@@ -1067,6 +1067,7 @@ enum {
 #define AR_INTR_PRIO_ASYNC_ENABLE 0x40d4
 #define AR_ENT_OTP               0x40d8
 #define AR_ENT_OTP_CHAIN2_DISABLE               0x00020000
+#define AR_ENT_OTP_MPSD                0x00800000
 
 #define AR_RTC_9300_PLL_DIV          0x000003ff
 #define AR_RTC_9300_PLL_DIV_S        0