From: Felix Fietkau <nbd@openwrt.org>
Date: Thu, 18 Feb 2016 18:55:35 +0000 (+0000)
Subject: mac80211: update A-MSDU tx support to the latest version
X-Git-Url: http://git.cdn.openwrt.org/?a=commitdiff_plain;h=42fc062d473348221c30774013406219b8592b4c;p=openwrt%2Fstaging%2Fyousong.git

mac80211: update A-MSDU tx support to the latest version

Signed-off-by: Felix Fietkau <nbd@openwrt.org>

SVN-Revision: 48743
---

diff --git a/package/kernel/mac80211/patches/322-mac80211-add-A-MSDU-tx-support.patch b/package/kernel/mac80211/patches/322-mac80211-add-A-MSDU-tx-support.patch
index d55f772760..a88229a3a0 100644
--- a/package/kernel/mac80211/patches/322-mac80211-add-A-MSDU-tx-support.patch
+++ b/package/kernel/mac80211/patches/322-mac80211-add-A-MSDU-tx-support.patch
@@ -26,7 +26,23 @@ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
  };
  
  /*
-@@ -1961,6 +1963,12 @@ struct ieee80211_txq {
+@@ -1728,6 +1730,7 @@ struct ieee80211_sta_rates {
+  *		  size is min(max_amsdu_len, 7935) bytes.
+  *	Both additional HT limits must be enforced by the low level driver.
+  *	This is defined by the spec (IEEE 802.11-2012 section 8.3.2.2 NOTE 2).
++ * @max_rc_amsdu_len: Maximum A-MSDU size in bytes recommended by rate control.
+  * @txq: per-TID data TX queues (if driver uses the TXQ abstraction)
+  */
+ struct ieee80211_sta {
+@@ -1748,6 +1751,7 @@ struct ieee80211_sta {
+ 	bool mfp;
+ 	u8 max_amsdu_subframes;
+ 	u16 max_amsdu_len;
++	u16 max_rc_amsdu_len;
+ 
+ 	struct ieee80211_txq *txq[IEEE80211_NUM_TIDS];
+ 
+@@ -1961,6 +1965,12 @@ struct ieee80211_txq {
   *	order and does not need to manage its own reorder buffer or BA session
   *	timeout.
   *
@@ -39,7 +55,7 @@ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
   * @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays
   */
  enum ieee80211_hw_flags {
-@@ -1998,6 +2006,8 @@ enum ieee80211_hw_flags {
+@@ -1998,6 +2008,8 @@ enum ieee80211_hw_flags {
  	IEEE80211_HW_BEACON_TX_STATUS,
  	IEEE80211_HW_NEEDS_UNIQUE_STA_ADDR,
  	IEEE80211_HW_SUPPORTS_REORDERING_BUFFER,
@@ -48,7 +64,7 @@ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
  
  	/* keep last, obviously */
  	NUM_IEEE80211_HW_FLAGS
-@@ -2070,6 +2080,8 @@ enum ieee80211_hw_flags {
+@@ -2070,6 +2082,8 @@ enum ieee80211_hw_flags {
   *	size is smaller (an example is LinkSys WRT120N with FW v1.0.07
   *	build 002 Jun 18 2012).
   *
@@ -57,7 +73,7 @@ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
   * @offchannel_tx_hw_queue: HW queue ID to use for offchannel TX
   *	(if %IEEE80211_HW_QUEUE_CONTROL is set)
   *
-@@ -2124,6 +2136,7 @@ struct ieee80211_hw {
+@@ -2124,6 +2138,7 @@ struct ieee80211_hw {
  	u8 max_rate_tries;
  	u8 max_rx_aggregation_subframes;
  	u8 max_tx_aggregation_subframes;
@@ -120,7 +136,7 @@ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
  	return skb;
  }
  EXPORT_SYMBOL(ieee80211_tx_dequeue);
-@@ -2757,6 +2761,158 @@ void ieee80211_clear_fast_xmit(struct st
+@@ -2757,6 +2761,165 @@ void ieee80211_clear_fast_xmit(struct st
  		kfree_rcu(fast_tx, rcu_head);
  }
  
@@ -148,6 +164,9 @@ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
 +	void *data;
 +	u8 *qc;
 +
++	if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE)
++		return false;
++
 +	if (info->control.flags & IEEE80211_TX_CTRL_AMSDU)
 +		return true;
 +
@@ -193,7 +212,7 @@ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
 +	int subframe_len = skb->len - ETH_ALEN;
 +	u8 max_subframes = sta->sta.max_amsdu_subframes;
 +	int max_frags = local->hw.max_tx_fragments;
-+	int max_amsdu_len;
++	int max_amsdu_len = sta->sta.max_amsdu_len;
 +	__be16 len;
 +	void *data;
 +	bool ret = false;
@@ -209,6 +228,10 @@ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
 +	if (test_bit(IEEE80211_TXQ_NO_AMSDU, &txqi->flags))
 +		return false;
 +
++	if (sta->sta.max_rc_amsdu_len)
++		max_amsdu_len = min_t(int, max_amsdu_len,
++				      sta->sta.max_rc_amsdu_len);
++
 +	spin_lock_bh(&txqi->queue.lock);
 +
 +	head = skb_peek_tail(&txqi->queue);
@@ -279,7 +302,7 @@ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
  static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
  				struct net_device *dev, struct sta_info *sta,
  				struct ieee80211_fast_tx *fast_tx,
-@@ -2811,6 +2967,10 @@ static bool ieee80211_xmit_fast(struct i
+@@ -2811,6 +2974,10 @@ static bool ieee80211_xmit_fast(struct i
  
  	ieee80211_tx_stats(dev, skb->len + extra_head);
  
diff --git a/package/kernel/mac80211/patches/335-mac80211-minstrel_ht-set-A-MSDU-tx-limits-based-on-s.patch b/package/kernel/mac80211/patches/335-mac80211-minstrel_ht-set-A-MSDU-tx-limits-based-on-s.patch
new file mode 100644
index 0000000000..acaacf7cac
--- /dev/null
+++ b/package/kernel/mac80211/patches/335-mac80211-minstrel_ht-set-A-MSDU-tx-limits-based-on-s.patch
@@ -0,0 +1,61 @@
+From: Felix Fietkau <nbd@openwrt.org>
+Date: Thu, 18 Feb 2016 19:30:05 +0100
+Subject: [PATCH] mac80211: minstrel_ht: set A-MSDU tx limits based on selected
+ max_prob_rate
+
+Prevents excessive A-MSDU aggregation at low data rates or bad
+conditions.
+
+Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+---
+
+--- a/net/mac80211/rc80211_minstrel_ht.c
++++ b/net/mac80211/rc80211_minstrel_ht.c
+@@ -883,6 +883,39 @@ minstrel_ht_set_rate(struct minstrel_pri
+ 	ratetbl->rate[offset].flags = flags;
+ }
+ 
++static int
++minstrel_ht_get_max_amsdu_len(struct minstrel_ht_sta *mi)
++{
++	int group = mi->max_prob_rate / MCS_GROUP_RATES;
++	const struct mcs_group *g = &minstrel_mcs_groups[group];
++	int rate = mi->max_prob_rate % MCS_GROUP_RATES;
++
++	/* Disable A-MSDU if max_prob_rate is bad */
++	if (mi->groups[group].rates[rate].prob_ewma < MINSTREL_FRAC(50, 100))
++		return 1;
++
++	/* If the rate is slower than single-stream MCS1, make A-MSDU limit small */
++	if (g->duration[rate] > MCS_DURATION(1, 0, 52))
++		return 500;
++
++	/*
++	 * If the rate is slower than single-stream MCS4, limit A-MSDU to usual
++	 * data packet size
++	 */
++	if (g->duration[rate] > MCS_DURATION(1, 0, 104))
++		return 1500;
++
++	/*
++	 * If the rate is slower than single-stream MCS7, limit A-MSDU to twice
++	 * the usual data packet size
++	 */
++	if (g->duration[rate] > MCS_DURATION(1, 0, 260))
++		return 3000;
++
++	/* unlimited */
++	return 0;
++}
++
+ static void
+ minstrel_ht_update_rates(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
+ {
+@@ -907,6 +940,7 @@ minstrel_ht_update_rates(struct minstrel
+ 		minstrel_ht_set_rate(mp, mi, rates, i++, mi->max_prob_rate);
+ 	}
+ 
++	mi->sta->max_rc_amsdu_len = minstrel_ht_get_max_amsdu_len(mi);
+ 	rates->rate[i].idx = -1;
+ 	rate_control_set_rates(mp->hw, mi->sta, rates);
+ }