ath9k: merge an aggregation related fix
[openwrt.git] / package / kernel / mac80211 / patches / 300-pending_work.patch
index 8b044d2..1da7941 100644 (file)
@@ -1,3 +1,82 @@
+commit 584d297fd29fb39c76af25ae74ff9d5fe74c8a14
+Author: Helmut Schaa <helmut.schaa@googlemail.com>
+Date:   Wed Mar 12 10:37:55 2014 +0100
+
+    ath9k: Fix sequence number assignment for non-data frames
+    
+    Since commit 558ff225de80ac95b132d3a115ddadcd64498b4f (ath9k: fix
+    ps-poll responses under a-mpdu sessions) non-data frames would have
+    gotten a sequence number from a TIDs sequence counter instead of
+    using the global sequence counter.
+    
+    This can lead to instable connections.
+    
+    To fix this only select the correct TID if we are processing a
+    data frame. Furthermore, prevent non-data frames to get a sequence
+    number from a TID sequence counter by adding a check to
+    ath_tx_setup_buffer.
+    
+    Cc: Felix Fietkau <nbd@openwrt.org>
+    Signed-off-by: Helmut Schaa <helmut.schaa@googlemail.com>
+
+commit 3a0f984b1cdcd6a9f8c441635ef3b05d58547f4e
+Author: Felix Fietkau <nbd@openwrt.org>
+Date:   Tue Mar 11 14:03:32 2014 +0100
+
+    ath9k_hw: set ANI firstep as absolute values instead of relative
+    
+    On older chips, the INI value differ in similar ways as cycpwr_thr1, so
+    convert it to absolute values as well.
+    
+    Since the ANI algorithm is different here compared to the old
+    implementation (fewer steps, controlled at a different point in time),
+    it makes sense to use values similar to what would be applied for newer
+    chips, just without relying on INI defaults.
+    
+    Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+
+commit 91d70d40400c569b49605b78fd7c43e9405694f4
+Author: Felix Fietkau <nbd@openwrt.org>
+Date:   Tue Mar 11 14:00:37 2014 +0100
+
+    ath9k_hw: set ANI cycpwr_thr1 as absolute values instead of relative
+    
+    The table was copied from the ANI implementation of AR9300. It assumes
+    that the INI values contain a baseline value that is usable as reference
+    from which to increase/decrease based on the noise immunity value.
+    
+    On older chips, the differences are bigger and especially AR5008/AR9001
+    are configured to much more sensitive values than what is useful.
+    
+    Improve ANI behavior by reverting to the absolute values used in the
+    previous implementation (expressed as a simple formula instead of the
+    old table).
+    
+    Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+
+commit c977493766310a825f406836636ffd66e1447783
+Author: Felix Fietkau <nbd@openwrt.org>
+Date:   Mon Mar 10 19:52:56 2014 +0100
+
+    ath9k_hw: remove ANI function restrictions for AP mode
+    
+    The primary purpose of this piece of code was to selectively disable
+    OFDM weak signal detection. The checks for this are elsewhere, and an
+    earlier commit relaxed the restrictions for older chips, which are more
+    sensitive to interference.
+    
+    Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+
+commit 8d804f1af11e4e058b1e8453327777d73a585cb8
+Author: Felix Fietkau <nbd@openwrt.org>
+Date:   Sun Mar 9 11:25:43 2014 +0100
+
+    ath9k: clean up and enhance ANI debugfs file
+    
+    Unify scnprintf calls and include the current OFDM/CCK immunity level.
+    
+    Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+
 commit 22e298b5a3a8a49e33805d4e351965123dede35b
 Author: Felix Fietkau <nbd@openwrt.org>
 Date:   Sun Mar 9 10:58:47 2014 +0100
@@ -3312,11 +3391,20 @@ Date:   Thu Jan 23 20:06:34 2014 +0100
                            ATH_CABQ_READY_TIME) / 100;
        ath_txq_update(sc, qnum, &qi);
  
+@@ -2061,7 +2063,7 @@ static struct ath_buf *ath_tx_setup_buff
+       ATH_TXBUF_RESET(bf);
+-      if (tid) {
++      if (tid && ieee80211_is_data_present(hdr->frame_control)) {
+               fragno = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG;
+               seqno = tid->seq_next;
+               hdr->seq_ctrl = cpu_to_le16(tid->seq_next << IEEE80211_SEQ_SEQ_SHIFT);
 @@ -2184,14 +2186,15 @@ int ath_tx_start(struct ieee80211_hw *hw
                txq->stopped = true;
        }
  
-+      if (txctl->an)
++      if (txctl->an && ieee80211_is_data_present(hdr->frame_control))
 +              tid = ath_get_skb_tid(sc, txctl->an, skb);
 +
        if (info->flags & IEEE80211_TX_CTL_PS_RESPONSE) {
@@ -3577,7 +3665,79 @@ Date:   Thu Jan 23 20:06:34 2014 +0100
                schedule_delayed_work(&reg_timeout, msecs_to_jiffies(3142));
 --- a/drivers/net/wireless/ath/ath9k/debug.c
 +++ b/drivers/net/wireless/ath/ath9k/debug.c
-@@ -866,6 +866,12 @@ static ssize_t read_file_reset(struct fi
+@@ -138,43 +138,41 @@ static ssize_t read_file_ani(struct file
+       unsigned int len = 0, size = 1024;
+       ssize_t retval = 0;
+       char *buf;
++      int i;
++      struct {
++              const char *name;
++              unsigned int val;
++      } ani_info[] = {
++              { "ANI RESET", ah->stats.ast_ani_reset },
++              { "OFDM LEVEL", ah->ani.ofdmNoiseImmunityLevel },
++              { "CCK LEVEL", ah->ani.cckNoiseImmunityLevel },
++              { "SPUR UP", ah->stats.ast_ani_spurup },
++              { "SPUR DOWN", ah->stats.ast_ani_spurup },
++              { "OFDM WS-DET ON", ah->stats.ast_ani_ofdmon },
++              { "OFDM WS-DET OFF", ah->stats.ast_ani_ofdmoff },
++              { "MRC-CCK ON", ah->stats.ast_ani_ccklow },
++              { "MRC-CCK OFF", ah->stats.ast_ani_cckhigh },
++              { "FIR-STEP UP", ah->stats.ast_ani_stepup },
++              { "FIR-STEP DOWN", ah->stats.ast_ani_stepdown },
++              { "INV LISTENTIME", ah->stats.ast_ani_lneg_or_lzero },
++              { "OFDM ERRORS", ah->stats.ast_ani_ofdmerrs },
++              { "CCK ERRORS", ah->stats.ast_ani_cckerrs },
++      };
+       buf = kzalloc(size, GFP_KERNEL);
+       if (buf == NULL)
+               return -ENOMEM;
+-      if (common->disable_ani) {
+-              len += scnprintf(buf + len, size - len, "%s: %s\n",
+-                               "ANI", "DISABLED");
++      len += scnprintf(buf + len, size - len, "%15s: %s\n", "ANI",
++                       common->disable_ani ? "DISABLED" : "ENABLED");
++
++      if (common->disable_ani)
+               goto exit;
+-      }
+-      len += scnprintf(buf + len, size - len, "%15s: %s\n",
+-                       "ANI", "ENABLED");
+-      len += scnprintf(buf + len, size - len, "%15s: %u\n",
+-                       "ANI RESET", ah->stats.ast_ani_reset);
+-      len += scnprintf(buf + len, size - len, "%15s: %u\n",
+-                       "SPUR UP", ah->stats.ast_ani_spurup);
+-      len += scnprintf(buf + len, size - len, "%15s: %u\n",
+-                       "SPUR DOWN", ah->stats.ast_ani_spurup);
+-      len += scnprintf(buf + len, size - len, "%15s: %u\n",
+-                       "OFDM WS-DET ON", ah->stats.ast_ani_ofdmon);
+-      len += scnprintf(buf + len, size - len, "%15s: %u\n",
+-                       "OFDM WS-DET OFF", ah->stats.ast_ani_ofdmoff);
+-      len += scnprintf(buf + len, size - len, "%15s: %u\n",
+-                       "MRC-CCK ON", ah->stats.ast_ani_ccklow);
+-      len += scnprintf(buf + len, size - len, "%15s: %u\n",
+-                       "MRC-CCK OFF", ah->stats.ast_ani_cckhigh);
+-      len += scnprintf(buf + len, size - len, "%15s: %u\n",
+-                       "FIR-STEP UP", ah->stats.ast_ani_stepup);
+-      len += scnprintf(buf + len, size - len, "%15s: %u\n",
+-                       "FIR-STEP DOWN", ah->stats.ast_ani_stepdown);
+-      len += scnprintf(buf + len, size - len, "%15s: %u\n",
+-                       "INV LISTENTIME", ah->stats.ast_ani_lneg_or_lzero);
+-      len += scnprintf(buf + len, size - len, "%15s: %u\n",
+-                       "OFDM ERRORS", ah->stats.ast_ani_ofdmerrs);
+-      len += scnprintf(buf + len, size - len, "%15s: %u\n",
+-                       "CCK ERRORS", ah->stats.ast_ani_cckerrs);
++      for (i = 0; i < ARRAY_SIZE(ani_info); i++)
++              len += scnprintf(buf + len, size - len, "%15s: %u\n",
++                               ani_info[i].name, ani_info[i].val);
++
+ exit:
+       if (len > size)
+               len = size;
+@@ -866,6 +864,12 @@ static ssize_t read_file_reset(struct fi
                         "%17s: %2d\n", "PLL RX Hang",
                         sc->debug.stats.reset[RESET_TYPE_PLL_HANG]);
        len += scnprintf(buf + len, sizeof(buf) - len,
@@ -3788,7 +3948,25 @@ Date:   Thu Jan 23 20:06:34 2014 +0100
  
        if (aniState->ofdmNoiseImmunityLevel >= ATH9K_ANI_OFDM_DEF_LEVEL) {
                ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH;
-@@ -483,10 +493,17 @@ void ath9k_hw_ani_init(struct ath_hw *ah
+@@ -308,17 +318,6 @@ void ath9k_ani_reset(struct ath_hw *ah, 
+       BUG_ON(aniState == NULL);
+       ah->stats.ast_ani_reset++;
+-      /* only allow a subset of functions in AP mode */
+-      if (ah->opmode == NL80211_IFTYPE_AP) {
+-              if (IS_CHAN_2GHZ(chan)) {
+-                      ah->ani_function = (ATH9K_ANI_SPUR_IMMUNITY_LEVEL |
+-                                          ATH9K_ANI_FIRSTEP_LEVEL);
+-                      if (AR_SREV_9300_20_OR_LATER(ah))
+-                              ah->ani_function |= ATH9K_ANI_MRC_CCK;
+-              } else
+-                      ah->ani_function = 0;
+-      }
+-
+       ofdm_nil = max_t(int, ATH9K_ANI_OFDM_DEF_LEVEL,
+                        aniState->ofdmNoiseImmunityLevel);
+       cck_nil = max_t(int, ATH9K_ANI_CCK_DEF_LEVEL,
+@@ -483,10 +482,17 @@ void ath9k_hw_ani_init(struct ath_hw *ah
  
        ath_dbg(common, ANI, "Initialize ANI\n");
  
@@ -3829,3 +4007,136 @@ Date:   Thu Jan 23 20:06:34 2014 +0100
  
  #define ATH9K_ANI_SPUR_IMMUNE_LVL         3
  #define ATH9K_ANI_FIRSTEP_LVL             2
+--- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c
++++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
+@@ -26,10 +26,6 @@ static const int firstep_table[] =
+ /* level:  0   1   2   3   4   5   6   7   8  */
+       { -4, -2,  0,  2,  4,  6,  8, 10, 12 }; /* lvl 0-8, default 2 */
+-static const int cycpwrThr1_table[] =
+-/* level:  0   1   2   3   4   5   6   7   8  */
+-      { -6, -4, -2,  0,  2,  4,  6,  8 };     /* lvl 0-7, default 3 */
+-
+ /*
+  * register values to turn OFDM weak signal detection OFF
+  */
+@@ -921,7 +917,7 @@ static bool ar5008_hw_ani_control_new(st
+       struct ath_common *common = ath9k_hw_common(ah);
+       struct ath9k_channel *chan = ah->curchan;
+       struct ar5416AniState *aniState = &ah->ani;
+-      s32 value, value2;
++      s32 value;
+       switch (cmd & ah->ani_function) {
+       case ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION:{
+@@ -1008,42 +1004,11 @@ static bool ar5008_hw_ani_control_new(st
+       case ATH9K_ANI_FIRSTEP_LEVEL:{
+               u32 level = param;
+-              if (level >= ARRAY_SIZE(firstep_table)) {
+-                      ath_dbg(common, ANI,
+-                              "ATH9K_ANI_FIRSTEP_LEVEL: level out of range (%u > %zu)\n",
+-                              level, ARRAY_SIZE(firstep_table));
+-                      return false;
+-              }
+-
+-              /*
+-               * make register setting relative to default
+-               * from INI file & cap value
+-               */
+-              value = firstep_table[level] -
+-                      firstep_table[ATH9K_ANI_FIRSTEP_LVL] +
+-                      aniState->iniDef.firstep;
+-              if (value < ATH9K_SIG_FIRSTEP_SETTING_MIN)
+-                      value = ATH9K_SIG_FIRSTEP_SETTING_MIN;
+-              if (value > ATH9K_SIG_FIRSTEP_SETTING_MAX)
+-                      value = ATH9K_SIG_FIRSTEP_SETTING_MAX;
++              value = level * 2;
+               REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
+-                            AR_PHY_FIND_SIG_FIRSTEP,
+-                            value);
+-              /*
+-               * we need to set first step low register too
+-               * make register setting relative to default
+-               * from INI file & cap value
+-               */
+-              value2 = firstep_table[level] -
+-                       firstep_table[ATH9K_ANI_FIRSTEP_LVL] +
+-                       aniState->iniDef.firstepLow;
+-              if (value2 < ATH9K_SIG_FIRSTEP_SETTING_MIN)
+-                      value2 = ATH9K_SIG_FIRSTEP_SETTING_MIN;
+-              if (value2 > ATH9K_SIG_FIRSTEP_SETTING_MAX)
+-                      value2 = ATH9K_SIG_FIRSTEP_SETTING_MAX;
+-
++                            AR_PHY_FIND_SIG_FIRSTEP, value);
+               REG_RMW_FIELD(ah, AR_PHY_FIND_SIG_LOW,
+-                            AR_PHY_FIND_SIG_FIRSTEP_LOW, value2);
++                            AR_PHY_FIND_SIG_FIRSTEP_LOW, value);
+               if (level != aniState->firstepLevel) {
+                       ath_dbg(common, ANI,
+@@ -1060,7 +1025,7 @@ static bool ar5008_hw_ani_control_new(st
+                               aniState->firstepLevel,
+                               level,
+                               ATH9K_ANI_FIRSTEP_LVL,
+-                              value2,
++                              value,
+                               aniState->iniDef.firstepLow);
+                       if (level > aniState->firstepLevel)
+                               ah->stats.ast_ani_stepup++;
+@@ -1073,41 +1038,13 @@ static bool ar5008_hw_ani_control_new(st
+       case ATH9K_ANI_SPUR_IMMUNITY_LEVEL:{
+               u32 level = param;
+-              if (level >= ARRAY_SIZE(cycpwrThr1_table)) {
+-                      ath_dbg(common, ANI,
+-                              "ATH9K_ANI_SPUR_IMMUNITY_LEVEL: level out of range (%u > %zu)\n",
+-                              level, ARRAY_SIZE(cycpwrThr1_table));
+-                      return false;
+-              }
+-              /*
+-               * make register setting relative to default
+-               * from INI file & cap value
+-               */
+-              value = cycpwrThr1_table[level] -
+-                      cycpwrThr1_table[ATH9K_ANI_SPUR_IMMUNE_LVL] +
+-                      aniState->iniDef.cycpwrThr1;
+-              if (value < ATH9K_SIG_SPUR_IMM_SETTING_MIN)
+-                      value = ATH9K_SIG_SPUR_IMM_SETTING_MIN;
+-              if (value > ATH9K_SIG_SPUR_IMM_SETTING_MAX)
+-                      value = ATH9K_SIG_SPUR_IMM_SETTING_MAX;
++              value = (level + 1) * 2;
+               REG_RMW_FIELD(ah, AR_PHY_TIMING5,
+-                            AR_PHY_TIMING5_CYCPWR_THR1,
+-                            value);
++                            AR_PHY_TIMING5_CYCPWR_THR1, value);
+-              /*
+-               * set AR_PHY_EXT_CCA for extension channel
+-               * make register setting relative to default
+-               * from INI file & cap value
+-               */
+-              value2 = cycpwrThr1_table[level] -
+-                       cycpwrThr1_table[ATH9K_ANI_SPUR_IMMUNE_LVL] +
+-                       aniState->iniDef.cycpwrThr1Ext;
+-              if (value2 < ATH9K_SIG_SPUR_IMM_SETTING_MIN)
+-                      value2 = ATH9K_SIG_SPUR_IMM_SETTING_MIN;
+-              if (value2 > ATH9K_SIG_SPUR_IMM_SETTING_MAX)
+-                      value2 = ATH9K_SIG_SPUR_IMM_SETTING_MAX;
+-              REG_RMW_FIELD(ah, AR_PHY_EXT_CCA,
+-                            AR_PHY_EXT_TIMING5_CYCPWR_THR1, value2);
++              if (IS_CHAN_HT40(ah->curchan))
++                      REG_RMW_FIELD(ah, AR_PHY_EXT_CCA,
++                                    AR_PHY_EXT_TIMING5_CYCPWR_THR1, value);
+               if (level != aniState->spurImmunityLevel) {
+                       ath_dbg(common, ANI,
+@@ -1124,7 +1061,7 @@ static bool ar5008_hw_ani_control_new(st
+                               aniState->spurImmunityLevel,
+                               level,
+                               ATH9K_ANI_SPUR_IMMUNE_LVL,
+-                              value2,
++                              value,
+                               aniState->iniDef.cycpwrThr1Ext);
+                       if (level > aniState->spurImmunityLevel)
+                               ah->stats.ast_ani_spurup++;