mac80211: add support for reporting tx status without attached skb
authorFelix Fietkau <nbd@openwrt.org>
Tue, 18 Nov 2014 22:20:45 +0000 (22:20 +0000)
committerFelix Fietkau <nbd@openwrt.org>
Tue, 18 Nov 2014 22:20:45 +0000 (22:20 +0000)
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
SVN-Revision: 43297

package/kernel/mac80211/patches/313-mac80211-minstrel_ht-add-a-small-optimization-to-min.patch [new file with mode: 0644]
package/kernel/mac80211/patches/314-mac80211-minstrel_ht-move-aggregation-check-to-.get_.patch [new file with mode: 0644]
package/kernel/mac80211/patches/315-mac80211-add-tx_status_noskb-to-rate_control_ops.patch [new file with mode: 0644]
package/kernel/mac80211/patches/316-mac80211-minstrel-switch-to-.tx_status_noskb.patch [new file with mode: 0644]
package/kernel/mac80211/patches/317-mac80211-minstrel_ht-switch-to-.tx_status_noskb.patch [new file with mode: 0644]
package/kernel/mac80211/patches/318-mac80211-add-ieee80211_tx_status_noskb.patch [new file with mode: 0644]

diff --git a/package/kernel/mac80211/patches/313-mac80211-minstrel_ht-add-a-small-optimization-to-min.patch b/package/kernel/mac80211/patches/313-mac80211-minstrel_ht-add-a-small-optimization-to-min.patch
new file mode 100644 (file)
index 0000000..ba2ce1e
--- /dev/null
@@ -0,0 +1,33 @@
+From: Felix Fietkau <nbd@openwrt.org>
+Date: Sat, 15 Nov 2014 22:13:38 +0100
+Subject: [PATCH] mac80211: minstrel_ht: add a small optimization to
+ minstrel_aggr_check
+
+Check the queue mapping earlier, skb->queue_mapping is more likely than
+skb->data to still be in d-cache.
+
+Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+---
+
+--- a/net/mac80211/rc80211_minstrel_ht.c
++++ b/net/mac80211/rc80211_minstrel_ht.c
+@@ -690,6 +690,9 @@ minstrel_aggr_check(struct ieee80211_sta
+       struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
+       u16 tid;
++      if (skb_get_queue_mapping(skb) == IEEE80211_AC_VO)
++              return;
++
+       if (unlikely(!ieee80211_is_data_qos(hdr->frame_control)))
+               return;
+@@ -700,9 +703,6 @@ minstrel_aggr_check(struct ieee80211_sta
+       if (likely(sta->ampdu_mlme.tid_tx[tid]))
+               return;
+-      if (skb_get_queue_mapping(skb) == IEEE80211_AC_VO)
+-              return;
+-
+       ieee80211_start_tx_ba_session(pubsta, tid, 5000);
+ }
diff --git a/package/kernel/mac80211/patches/314-mac80211-minstrel_ht-move-aggregation-check-to-.get_.patch b/package/kernel/mac80211/patches/314-mac80211-minstrel_ht-move-aggregation-check-to-.get_.patch
new file mode 100644 (file)
index 0000000..38e867f
--- /dev/null
@@ -0,0 +1,33 @@
+From: Felix Fietkau <nbd@openwrt.org>
+Date: Sat, 15 Nov 2014 22:16:36 +0100
+Subject: [PATCH] mac80211: minstrel_ht: move aggregation check to
+ .get_rate()
+
+Preparation for adding a no-skb tx status path
+
+Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+---
+
+--- a/net/mac80211/rc80211_minstrel_ht.c
++++ b/net/mac80211/rc80211_minstrel_ht.c
+@@ -782,9 +782,6 @@ minstrel_ht_tx_status(void *priv, struct
+       if (time_after(jiffies, mi->stats_update + (mp->update_interval / 2 * HZ) / 1000)) {
+               update = true;
+               minstrel_ht_update_stats(mp, mi);
+-              if (!(info->flags & IEEE80211_TX_CTL_AMPDU) &&
+-                  mi->max_prob_rate / MCS_GROUP_RATES != MINSTREL_CCK_GROUP)
+-                      minstrel_aggr_check(sta, skb);
+       }
+       if (update)
+@@ -1026,6 +1023,10 @@ minstrel_ht_get_rate(void *priv, struct 
+       if (!msp->is_ht)
+               return mac80211_minstrel.get_rate(priv, sta, &msp->legacy, txrc);
++      if (!(info->flags & IEEE80211_TX_CTL_AMPDU) &&
++              mi->max_prob_rate / MCS_GROUP_RATES != MINSTREL_CCK_GROUP)
++              minstrel_aggr_check(sta, txrc->skb);
++
+       info->flags |= mi->tx_flags;
+       minstrel_ht_check_cck_shortpreamble(mp, mi, txrc->short_preamble);
diff --git a/package/kernel/mac80211/patches/315-mac80211-add-tx_status_noskb-to-rate_control_ops.patch b/package/kernel/mac80211/patches/315-mac80211-add-tx_status_noskb-to-rate_control_ops.patch
new file mode 100644 (file)
index 0000000..8a93970
--- /dev/null
@@ -0,0 +1,43 @@
+From: Felix Fietkau <nbd@openwrt.org>
+Date: Sat, 15 Nov 2014 22:23:44 +0100
+Subject: [PATCH] mac80211: add tx_status_noskb to rate_control_ops
+
+This op works like .tx_status, except it does not need access to the
+skb. This will be used by drivers that cannot match tx status
+information to specific packets.
+
+Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+---
+
+--- a/include/net/mac80211.h
++++ b/include/net/mac80211.h
+@@ -4727,6 +4727,10 @@ struct rate_control_ops {
+       void (*free_sta)(void *priv, struct ieee80211_sta *sta,
+                        void *priv_sta);
++      void (*tx_status_noskb)(void *priv,
++                              struct ieee80211_supported_band *sband,
++                              struct ieee80211_sta *sta, void *priv_sta,
++                              struct ieee80211_tx_info *info);
+       void (*tx_status)(void *priv, struct ieee80211_supported_band *sband,
+                         struct ieee80211_sta *sta, void *priv_sta,
+                         struct sk_buff *skb);
+--- a/net/mac80211/rate.h
++++ b/net/mac80211/rate.h
+@@ -37,11 +37,15 @@ static inline void rate_control_tx_statu
+       struct rate_control_ref *ref = local->rate_ctrl;
+       struct ieee80211_sta *ista = &sta->sta;
+       void *priv_sta = sta->rate_ctrl_priv;
++      struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       if (!ref || !test_sta_flag(sta, WLAN_STA_RATE_CONTROL))
+               return;
+-      ref->ops->tx_status(ref->priv, sband, ista, priv_sta, skb);
++      if (ref->ops->tx_status)
++              ref->ops->tx_status(ref->priv, sband, ista, priv_sta, skb);
++      else
++              ref->ops->tx_status_noskb(ref->priv, sband, ista, priv_sta, info);
+ }
diff --git a/package/kernel/mac80211/patches/316-mac80211-minstrel-switch-to-.tx_status_noskb.patch b/package/kernel/mac80211/patches/316-mac80211-minstrel-switch-to-.tx_status_noskb.patch
new file mode 100644 (file)
index 0000000..b32e410
--- /dev/null
@@ -0,0 +1,31 @@
+From: Felix Fietkau <nbd@openwrt.org>
+Date: Sat, 15 Nov 2014 22:38:07 +0100
+Subject: [PATCH] mac80211: minstrel: switch to .tx_status_noskb
+
+Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+---
+
+--- a/net/mac80211/rc80211_minstrel.c
++++ b/net/mac80211/rc80211_minstrel.c
+@@ -223,11 +223,10 @@ minstrel_update_stats(struct minstrel_pr
+ static void
+ minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband,
+                  struct ieee80211_sta *sta, void *priv_sta,
+-                 struct sk_buff *skb)
++                 struct ieee80211_tx_info *info)
+ {
+       struct minstrel_priv *mp = priv;
+       struct minstrel_sta_info *mi = priv_sta;
+-      struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       struct ieee80211_tx_rate *ar = info->status.rates;
+       int i, ndx;
+       int success;
+@@ -674,7 +673,7 @@ static u32 minstrel_get_expected_through
+ const struct rate_control_ops mac80211_minstrel = {
+       .name = "minstrel",
+-      .tx_status = minstrel_tx_status,
++      .tx_status_noskb = minstrel_tx_status,
+       .get_rate = minstrel_get_rate,
+       .rate_init = minstrel_rate_init,
+       .alloc = minstrel_alloc,
diff --git a/package/kernel/mac80211/patches/317-mac80211-minstrel_ht-switch-to-.tx_status_noskb.patch b/package/kernel/mac80211/patches/317-mac80211-minstrel_ht-switch-to-.tx_status_noskb.patch
new file mode 100644 (file)
index 0000000..6900005
--- /dev/null
@@ -0,0 +1,41 @@
+From: Felix Fietkau <nbd@openwrt.org>
+Date: Sat, 15 Nov 2014 22:38:21 +0100
+Subject: [PATCH] mac80211: minstrel_ht: switch to .tx_status_noskb
+
+Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+---
+
+--- a/net/mac80211/rc80211_minstrel_ht.c
++++ b/net/mac80211/rc80211_minstrel_ht.c
+@@ -709,11 +709,10 @@ minstrel_aggr_check(struct ieee80211_sta
+ static void
+ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband,
+                       struct ieee80211_sta *sta, void *priv_sta,
+-                      struct sk_buff *skb)
++                      struct ieee80211_tx_info *info)
+ {
+       struct minstrel_ht_sta_priv *msp = priv_sta;
+       struct minstrel_ht_sta *mi = &msp->ht;
+-      struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       struct ieee80211_tx_rate *ar = info->status.rates;
+       struct minstrel_rate_stats *rate, *rate2;
+       struct minstrel_priv *mp = priv;
+@@ -721,7 +720,8 @@ minstrel_ht_tx_status(void *priv, struct
+       int i;
+       if (!msp->is_ht)
+-              return mac80211_minstrel.tx_status(priv, sband, sta, &msp->legacy, skb);
++              return mac80211_minstrel.tx_status_noskb(priv, sband, sta,
++                                                       &msp->legacy, info);
+       /* This packet was aggregated but doesn't carry status info */
+       if ((info->flags & IEEE80211_TX_CTL_AMPDU) &&
+@@ -1343,7 +1343,7 @@ static u32 minstrel_ht_get_expected_thro
+ static const struct rate_control_ops mac80211_minstrel_ht = {
+       .name = "minstrel_ht",
+-      .tx_status = minstrel_ht_tx_status,
++      .tx_status_noskb = minstrel_ht_tx_status,
+       .get_rate = minstrel_ht_get_rate,
+       .rate_init = minstrel_ht_rate_init,
+       .rate_update = minstrel_ht_rate_update,
diff --git a/package/kernel/mac80211/patches/318-mac80211-add-ieee80211_tx_status_noskb.patch b/package/kernel/mac80211/patches/318-mac80211-add-ieee80211_tx_status_noskb.patch
new file mode 100644 (file)
index 0000000..18d3905
--- /dev/null
@@ -0,0 +1,219 @@
+From: Felix Fietkau <nbd@openwrt.org>
+Date: Sat, 15 Nov 2014 23:50:27 +0100
+Subject: [PATCH] mac80211: add ieee80211_tx_status_noskb
+
+This can be used by drivers that cannot reliably map tx status
+information onto specific skbs.
+
+Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+---
+
+--- a/include/net/mac80211.h
++++ b/include/net/mac80211.h
+@@ -3517,6 +3517,28 @@ void ieee80211_tx_status(struct ieee8021
+                        struct sk_buff *skb);
+ /**
++ * ieee80211_tx_status_noskb - transmit status callback without skb
++ *
++ * This function can be used as a replacement for ieee80211_tx_status
++ * in drivers that cannot reliably map tx status information back to
++ * specific skbs.
++ *
++ * This function may not be called in IRQ context. Calls to this function
++ * for a single hardware must be synchronized against each other. Calls
++ * to this function, ieee80211_tx_status_ni() and ieee80211_tx_status_irqsafe()
++ * may not be mixed for a single hardware. Must not run concurrently with
++ * ieee80211_rx() or ieee80211_rx_ni().
++ *
++ * @hw: the hardware the frame was transmitted by
++ * @sta: the receiver station to which this packet is sent
++ *    (NULL for multicast packets)
++ * @info: tx status information
++ */
++void ieee80211_tx_status_noskb(struct ieee80211_hw *hw,
++                             struct ieee80211_sta *sta,
++                             struct ieee80211_tx_info *info);
++
++/**
+  * ieee80211_tx_status_ni - transmit status callback (in process context)
+  *
+  * Like ieee80211_tx_status() but can be called in process context.
+--- a/net/mac80211/rate.h
++++ b/net/mac80211/rate.h
+@@ -49,6 +49,23 @@ static inline void rate_control_tx_statu
+ }
++static inline void
++rate_control_tx_status_noskb(struct ieee80211_local *local,
++                           struct ieee80211_supported_band *sband,
++                           struct sta_info *sta,
++                           struct ieee80211_tx_info *info)
++{
++      struct rate_control_ref *ref = local->rate_ctrl;
++      struct ieee80211_sta *ista = &sta->sta;
++      void *priv_sta = sta->rate_ctrl_priv;
++
++      if (!ref || !test_sta_flag(sta, WLAN_STA_RATE_CONTROL))
++              return;
++
++      ref->ops->tx_status_noskb(ref->priv, sband, ista, priv_sta, info);
++}
++
++
+ static inline void rate_control_rate_init(struct sta_info *sta)
+ {
+       struct ieee80211_local *local = sta->sdata->local;
+--- a/net/mac80211/status.c
++++ b/net/mac80211/status.c
+@@ -541,10 +541,9 @@ static void ieee80211_tx_latency_end_msr
+ #define STA_LOST_TDLS_PKT_THRESHOLD   10
+ #define STA_LOST_TDLS_PKT_TIME                (10*HZ) /* 10secs since last ACK */
+-static void ieee80211_lost_packet(struct sta_info *sta, struct sk_buff *skb)
++static void ieee80211_lost_packet(struct sta_info *sta,
++                                struct ieee80211_tx_info *info)
+ {
+-      struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+-
+       /* This packet was aggregated but doesn't carry status info */
+       if ((info->flags & IEEE80211_TX_CTL_AMPDU) &&
+           !(info->flags & IEEE80211_TX_STAT_AMPDU))
+@@ -571,24 +570,13 @@ static void ieee80211_lost_packet(struct
+       sta->lost_packets = 0;
+ }
+-void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
++static int ieee80211_tx_get_rates(struct ieee80211_hw *hw,
++                                struct ieee80211_tx_info *info,
++                                int *retry_count)
+ {
+-      struct sk_buff *skb2;
+-      struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+-      struct ieee80211_local *local = hw_to_local(hw);
+-      struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+-      __le16 fc;
+-      struct ieee80211_supported_band *sband;
+-      struct ieee80211_sub_if_data *sdata;
+-      struct net_device *prev_dev = NULL;
+-      struct sta_info *sta, *tmp;
+-      int retry_count = -1, i;
+       int rates_idx = -1;
+-      bool send_to_cooked;
+-      bool acked;
+-      struct ieee80211_bar *bar;
+-      int rtap_len;
+-      int shift = 0;
++      int count = -1;
++      int i;
+       for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
+               if ((info->flags & IEEE80211_TX_CTL_AMPDU) &&
+@@ -606,12 +594,94 @@ void ieee80211_tx_status(struct ieee8021
+                       break;
+               }
+-              retry_count += info->status.rates[i].count;
++              count += info->status.rates[i].count;
+       }
+       rates_idx = i - 1;
+-      if (retry_count < 0)
+-              retry_count = 0;
++      if (count < 0)
++              count = 0;
++
++      *retry_count = count;
++      return rates_idx;
++}
++
++void ieee80211_tx_status_noskb(struct ieee80211_hw *hw,
++                             struct ieee80211_sta *pubsta,
++                             struct ieee80211_tx_info *info)
++{
++      struct ieee80211_local *local = hw_to_local(hw);
++      struct ieee80211_supported_band *sband;
++      int retry_count;
++      int rates_idx;
++      bool acked;
++
++      rates_idx = ieee80211_tx_get_rates(hw, info, &retry_count);
++
++      sband = hw->wiphy->bands[info->band];
++
++      acked = !!(info->flags & IEEE80211_TX_STAT_ACK);
++      if (pubsta) {
++              struct sta_info *sta;
++
++              sta = container_of(pubsta, struct sta_info, sta);
++
++              if (info->flags & IEEE80211_TX_STATUS_EOSP)
++                      clear_sta_flag(sta, WLAN_STA_SP);
++
++              if (!acked)
++                      sta->tx_retry_failed++;
++              sta->tx_retry_count += retry_count;
++
++              if (acked) {
++                      sta->last_rx = jiffies;
++
++                      if (sta->lost_packets)
++                              sta->lost_packets = 0;
++
++                      /* Track when last TDLS packet was ACKed */
++                      if (test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH))
++                              sta->last_tdls_pkt_time = jiffies;
++              } else {
++                      ieee80211_lost_packet(sta, info);
++              }
++
++              rate_control_tx_status_noskb(local, sband, sta, info);
++      }
++
++      if (acked) {
++                  local->dot11TransmittedFrameCount++;
++                  if (!pubsta)
++                          local->dot11MulticastTransmittedFrameCount++;
++                  if (retry_count > 0)
++                          local->dot11RetryCount++;
++                  if (retry_count > 1)
++                          local->dot11MultipleRetryCount++;
++      } else {
++              local->dot11FailedCount++;
++      }
++}
++EXPORT_SYMBOL(ieee80211_tx_status_noskb);
++
++void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
++{
++      struct sk_buff *skb2;
++      struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
++      struct ieee80211_local *local = hw_to_local(hw);
++      struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
++      __le16 fc;
++      struct ieee80211_supported_band *sband;
++      struct ieee80211_sub_if_data *sdata;
++      struct net_device *prev_dev = NULL;
++      struct sta_info *sta, *tmp;
++      int retry_count;
++      int rates_idx;
++      bool send_to_cooked;
++      bool acked;
++      struct ieee80211_bar *bar;
++      int rtap_len;
++      int shift = 0;
++
++      rates_idx = ieee80211_tx_get_rates(hw, info, &retry_count);
+       rcu_read_lock();
+@@ -716,7 +786,7 @@ void ieee80211_tx_status(struct ieee8021
+                               if (test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH))
+                                       sta->last_tdls_pkt_time = jiffies;
+                       } else {
+-                              ieee80211_lost_packet(sta, skb);
++                              ieee80211_lost_packet(sta, info);
+                       }
+               }