--- /dev/null
+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,