Bladeren bron

mac80211: improve performance by deferring tx queue selection

Signed-off-by: Felix Fietkau <[email protected]>
Felix Fietkau 6 jaren geleden
bovenliggende
commit
1dd536f1fa

+ 183 - 0
package/kernel/mac80211/patches/subsys/360-mac80211-when-using-iTXQ-select-the-queue-in-ieee802.patch

@@ -0,0 +1,183 @@
+From: Felix Fietkau <[email protected]>
+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 <[email protected]>
+---
+
+--- 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,