mac80211: improve performance by deferring tx queue selection
authorFelix Fietkau <nbd@nbd.name>
Sat, 23 Mar 2019 08:59:35 +0000 (09:59 +0100)
committerFelix Fietkau <nbd@nbd.name>
Wed, 3 Apr 2019 08:40:09 +0000 (10:40 +0200)
Signed-off-by: Felix Fietkau <nbd@nbd.name>
package/kernel/mac80211/patches/subsys/360-mac80211-when-using-iTXQ-select-the-queue-in-ieee802.patch [new file with mode: 0644]

diff --git a/package/kernel/mac80211/patches/subsys/360-mac80211-when-using-iTXQ-select-the-queue-in-ieee802.patch b/package/kernel/mac80211/patches/subsys/360-mac80211-when-using-iTXQ-select-the-queue-in-ieee802.patch
new file mode 100644 (file)
index 0000000..03d1150
--- /dev/null
@@ -0,0 +1,183 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Fri, 22 Mar 2019 18:06:03 +0100
+Subject: [PATCH] mac80211: when using iTXQ, select the queue in
+ ieee80211_subif_start_xmit
+
+When using iTXQ, the network stack does not need the real queue number, since
+mac80211 is using its internal queues anyway. In that case we can defer
+selecting the queue and remove a redundant station lookup in the tx path to save
+some CPU cycles.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/net/mac80211/tx.c
++++ b/net/mac80211/tx.c
+@@ -3753,6 +3753,7 @@ void __ieee80211_subif_start_xmit(struct
+                                 u32 info_flags)
+ {
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
++      struct ieee80211_local *local = sdata->local;
+       struct sta_info *sta;
+       struct sk_buff *next;
+@@ -3766,7 +3767,15 @@ void __ieee80211_subif_start_xmit(struct
+       if (ieee80211_lookup_ra_sta(sdata, skb, &sta))
+               goto out_free;
+-      if (!IS_ERR_OR_NULL(sta)) {
++      if (IS_ERR(sta))
++              sta = NULL;
++
++      if (local->ops->wake_tx_queue) {
++              u16 queue = __ieee80211_select_queue(sdata, sta, skb);
++              skb_set_queue_mapping(skb, queue);
++      }
++
++      if (sta) {
+               struct ieee80211_fast_tx *fast_tx;
+               /* We need a bit of data queued to build aggregates properly, so
+--- a/net/mac80211/wme.c
++++ b/net/mac80211/wme.c
+@@ -141,6 +141,42 @@ u16 ieee80211_select_queue_80211(struct
+       return ieee80211_downgrade_queue(sdata, NULL, skb);
+ }
++u16 __ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
++                           struct sta_info *sta, struct sk_buff *skb)
++{
++      struct mac80211_qos_map *qos_map;
++      bool qos;
++
++      /* all mesh/ocb stations are required to support WME */
++      if (sdata->vif.type == NL80211_IFTYPE_MESH_POINT ||
++          sdata->vif.type == NL80211_IFTYPE_OCB)
++              qos = true;
++      else if (sta)
++              qos = sta->sta.wme;
++      else
++              qos = false;
++
++      if (!qos) {
++              skb->priority = 0; /* required for correct WPA/11i MIC */
++              return IEEE80211_AC_BE;
++      }
++
++      if (skb->protocol == sdata->control_port_protocol) {
++              skb->priority = 7;
++              goto downgrade;
++      }
++
++      /* use the data classifier to determine what 802.1d tag the
++       * data frame has */
++      qos_map = rcu_dereference(sdata->qos_map);
++      skb->priority = cfg80211_classify8021d(skb, qos_map ?
++                                             &qos_map->qos_map : NULL);
++
++ downgrade:
++      return ieee80211_downgrade_queue(sdata, sta, skb);
++}
++
++
+ /* Indicate which queue to use. */
+ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
+                          struct sk_buff *skb)
+@@ -148,10 +184,12 @@ u16 ieee80211_select_queue(struct ieee80
+       struct ieee80211_local *local = sdata->local;
+       struct sta_info *sta = NULL;
+       const u8 *ra = NULL;
+-      bool qos = false;
+-      struct mac80211_qos_map *qos_map;
+       u16 ret;
++      /* when using iTXQ, we can do this later */
++      if (local->ops->wake_tx_queue)
++              return 0;
++
+       if (local->hw.queues < IEEE80211_NUM_ACS || skb->len < 6) {
+               skb->priority = 0; /* required for correct WPA/11i MIC */
+               return 0;
+@@ -161,10 +199,8 @@ u16 ieee80211_select_queue(struct ieee80
+       switch (sdata->vif.type) {
+       case NL80211_IFTYPE_AP_VLAN:
+               sta = rcu_dereference(sdata->u.vlan.sta);
+-              if (sta) {
+-                      qos = sta->sta.wme;
++              if (sta)
+                       break;
+-              }
+               /* fall through */
+       case NL80211_IFTYPE_AP:
+               ra = skb->data;
+@@ -172,56 +208,26 @@ u16 ieee80211_select_queue(struct ieee80
+       case NL80211_IFTYPE_WDS:
+               ra = sdata->u.wds.remote_addr;
+               break;
+-#ifdef CPTCFG_MAC80211_MESH
+-      case NL80211_IFTYPE_MESH_POINT:
+-              qos = true;
+-              break;
+-#endif
+       case NL80211_IFTYPE_STATION:
+               /* might be a TDLS station */
+               sta = sta_info_get(sdata, skb->data);
+               if (sta)
+-                      qos = sta->sta.wme;
++                      break;
+               ra = sdata->u.mgd.bssid;
+               break;
+       case NL80211_IFTYPE_ADHOC:
+               ra = skb->data;
+               break;
+-      case NL80211_IFTYPE_OCB:
+-              /* all stations are required to support WME */
+-              qos = true;
+-              break;
+       default:
+               break;
+       }
+-      if (!sta && ra && !is_multicast_ether_addr(ra)) {
++      if (!sta && ra && !is_multicast_ether_addr(ra))
+               sta = sta_info_get(sdata, ra);
+-              if (sta)
+-                      qos = sta->sta.wme;
+-      }
+-      if (!qos) {
+-              skb->priority = 0; /* required for correct WPA/11i MIC */
+-              ret = IEEE80211_AC_BE;
+-              goto out;
+-      }
+-
+-      if (skb->protocol == sdata->control_port_protocol) {
+-              skb->priority = 7;
+-              goto downgrade;
+-      }
+-
+-      /* use the data classifier to determine what 802.1d tag the
+-       * data frame has */
+-      qos_map = rcu_dereference(sdata->qos_map);
+-      skb->priority = cfg80211_classify8021d(skb, qos_map ?
+-                                             &qos_map->qos_map : NULL);
++      ret = __ieee80211_select_queue(sdata, sta, skb);
+- downgrade:
+-      ret = ieee80211_downgrade_queue(sdata, sta, skb);
+- out:
+       rcu_read_unlock();
+       return ret;
+ }
+--- a/net/mac80211/wme.h
++++ b/net/mac80211/wme.h
+@@ -16,6 +16,8 @@
+ u16 ieee80211_select_queue_80211(struct ieee80211_sub_if_data *sdata,
+                                struct sk_buff *skb,
+                                struct ieee80211_hdr *hdr);
++u16 __ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
++                           struct sta_info *sta, struct sk_buff *skb);
+ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
+                          struct sk_buff *skb);
+ void ieee80211_set_qos_hdr(struct ieee80211_sub_if_data *sdata,