[openwrt/openwrt] mac80211: backport EHT 1024 MPDU TX aggregation

LEDE Commits lede-commits at lists.infradead.org
Fri Sep 19 04:14:06 PDT 2025


nbd pushed a commit to openwrt/openwrt.git, branch openwrt-24.10:
https://git.openwrt.org/efcdbe1087f54fc3ba9422ad476a2558c4e98ed6

commit efcdbe1087f54fc3ba9422ad476a2558c4e98ed6
Author: Oliver Sedlbauer <osedlbauer at tdt.de>
AuthorDate: Fri Sep 19 12:42:15 2025 +0200

    mac80211: backport EHT 1024 MPDU TX aggregation
    
    Backport support for 1024 MPDU TX aggregation in EHT from upstream
    kernel. Without this fix, TX performance on WiFi-7 links
    is severely limited, making the link practically unusable.
    
    Signed-off-by: Oliver Sedlbauer <osedlbauer at tdt.de>
---
 ...11-Support-EHT-1024-aggregation-size-in-T.patch | 321 +++++++++++++++++++++
 1 file changed, 321 insertions(+)

diff --git a/package/kernel/mac80211/patches/subsys/342-wifi-mac80211-Support-EHT-1024-aggregation-size-in-T.patch b/package/kernel/mac80211/patches/subsys/342-wifi-mac80211-Support-EHT-1024-aggregation-size-in-T.patch
new file mode 100644
index 0000000000..2771f5eac7
--- /dev/null
+++ b/package/kernel/mac80211/patches/subsys/342-wifi-mac80211-Support-EHT-1024-aggregation-size-in-T.patch
@@ -0,0 +1,321 @@
+From 406c5548c661df0bff6bb6ee79bf9d49faf23e31 Mon Sep 17 00:00:00 2001
+From: MeiChia Chiu <MeiChia.Chiu at mediatek.com>
+Date: Tue, 12 Nov 2024 16:38:46 +0800
+Subject: [PATCH] wifi: mac80211: Support EHT 1024 aggregation size in TX
+
+Support EHT 1024 aggregation size in TX
+
+The 1024 agg size for RX is supported but not for TX.
+This patch adds this support and refactors common parsing logics for
+addbaext in both process_addba_resp and process_addba_req into a
+function.
+
+Reviewed-by: Shayne Chen <shayne.chen at mediatek.com>
+Reviewed-by: Money Wang <money.wang at mediatek.com>
+Co-developed-by: Peter Chiu <chui-hao.chiu at mediatek.com>
+Signed-off-by: Peter Chiu <chui-hao.chiu at mediatek.com>
+Signed-off-by: MeiChia Chiu <MeiChia.Chiu at mediatek.com>
+Link: https://patch.msgid.link/20241112083846.32063-1-MeiChia.Chiu@mediatek.com
+[pass elems/len instead of mgmt/len/is_req]
+Signed-off-by: Johannes Berg <johannes.berg at intel.com>
+---
+ include/linux/ieee80211.h  |  2 +
+ net/mac80211/agg-rx.c      | 94 +++++++++++++++++++++++---------------
+ net/mac80211/agg-tx.c      | 31 +++++++++----
+ net/mac80211/ht.c          |  2 +-
+ net/mac80211/ieee80211_i.h |  9 +++-
+ 5 files changed, 90 insertions(+), 48 deletions(-)
+
+diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
+index 456bca45ff05..05dedc45505c 100644
+--- a/include/linux/ieee80211.h
++++ b/include/linux/ieee80211.h
+@@ -1445,6 +1445,8 @@ struct ieee80211_mgmt {
+ 					__le16 status;
+ 					__le16 capab;
+ 					__le16 timeout;
++					/* followed by BA Extension */
++					u8 variable[];
+ 				} __packed addba_resp;
+ 				struct{
+ 					u8 action_code;
+diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c
+index fe7eab4b681b..f3fbe5a4395e 100644
+--- a/net/mac80211/agg-rx.c
++++ b/net/mac80211/agg-rx.c
+@@ -170,28 +170,63 @@ static void sta_rx_agg_reorder_timer_expired(struct timer_list *t)
+ 	rcu_read_unlock();
+ }
+ 
+-static void ieee80211_add_addbaext(struct ieee80211_sub_if_data *sdata,
+-				   struct sk_buff *skb,
+-				   const struct ieee80211_addba_ext_ie *req,
+-				   u16 buf_size)
++void ieee80211_add_addbaext(struct sk_buff *skb,
++			    const u8 req_addba_ext_data,
++			    u16 buf_size)
+ {
+-	struct ieee80211_addba_ext_ie *resp;
++	struct ieee80211_addba_ext_ie *addba_ext;
+ 	u8 *pos;
+ 
+ 	pos = skb_put_zero(skb, 2 + sizeof(struct ieee80211_addba_ext_ie));
+ 	*pos++ = WLAN_EID_ADDBA_EXT;
+ 	*pos++ = sizeof(struct ieee80211_addba_ext_ie);
+-	resp = (struct ieee80211_addba_ext_ie *)pos;
+-	resp->data = req->data & IEEE80211_ADDBA_EXT_NO_FRAG;
++	addba_ext = (struct ieee80211_addba_ext_ie *)pos;
+ 
+-	resp->data |= u8_encode_bits(buf_size >> IEEE80211_ADDBA_EXT_BUF_SIZE_SHIFT,
+-				     IEEE80211_ADDBA_EXT_BUF_SIZE_MASK);
++	addba_ext->data = IEEE80211_ADDBA_EXT_NO_FRAG;
++	if (req_addba_ext_data)
++		addba_ext->data &= req_addba_ext_data;
++
++	addba_ext->data |=
++		u8_encode_bits(buf_size >> IEEE80211_ADDBA_EXT_BUF_SIZE_SHIFT,
++			       IEEE80211_ADDBA_EXT_BUF_SIZE_MASK);
++}
++
++u8 ieee80211_retrieve_addba_ext_data(struct sta_info *sta,
++				     const void *elem_data, ssize_t elem_len,
++				     u16 *buf_size)
++{
++	struct ieee802_11_elems *elems;
++	u8 buf_size_1k, data = 0;
++
++	if (!sta->sta.deflink.he_cap.has_he)
++		return 0;
++
++	if (elem_len <= 0)
++		return 0;
++
++	elems = ieee802_11_parse_elems(elem_data, elem_len, true, NULL);
++
++	if (elems && !elems->parse_error && elems->addba_ext_ie) {
++		data = elems->addba_ext_ie->data;
++
++		if (!sta->sta.deflink.eht_cap.has_eht || !buf_size)
++			goto free;
++
++		buf_size_1k = u8_get_bits(elems->addba_ext_ie->data,
++					  IEEE80211_ADDBA_EXT_BUF_SIZE_MASK);
++		*buf_size |= (u16)buf_size_1k <<
++			     IEEE80211_ADDBA_EXT_BUF_SIZE_SHIFT;
++	}
++free:
++	kfree(elems);
++
++	return data;
+ }
+ 
+ static void ieee80211_send_addba_resp(struct sta_info *sta, u8 *da, u16 tid,
+ 				      u8 dialog_token, u16 status, u16 policy,
+ 				      u16 buf_size, u16 timeout,
+-				      const struct ieee80211_addba_ext_ie *addbaext)
++				      const u8 req_addba_ext_data)
+ {
+ 	struct ieee80211_sub_if_data *sdata = sta->sdata;
+ 	struct ieee80211_local *local = sdata->local;
+@@ -223,8 +258,8 @@ static void ieee80211_send_addba_resp(struct sta_info *sta, u8 *da, u16 tid,
+ 	mgmt->u.action.u.addba_resp.timeout = cpu_to_le16(timeout);
+ 	mgmt->u.action.u.addba_resp.status = cpu_to_le16(status);
+ 
+-	if (sta->sta.deflink.he_cap.has_he && addbaext)
+-		ieee80211_add_addbaext(sdata, skb, addbaext, buf_size);
++	if (sta->sta.deflink.he_cap.has_he)
++		ieee80211_add_addbaext(skb, req_addba_ext_data, buf_size);
+ 
+ 	ieee80211_tx_skb(sdata, skb);
+ }
+@@ -233,7 +268,7 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta,
+ 				     u8 dialog_token, u16 timeout,
+ 				     u16 start_seq_num, u16 ba_policy, u16 tid,
+ 				     u16 buf_size, bool tx, bool auto_seq,
+-				     const struct ieee80211_addba_ext_ie *addbaext)
++				     const u8 addba_ext_data)
+ {
+ 	struct ieee80211_local *local = sta->sdata->local;
+ 	struct tid_ampdu_rx *tid_agg_rx;
+@@ -419,7 +454,7 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta,
+ 	if (tx)
+ 		ieee80211_send_addba_resp(sta, sta->sta.addr, tid,
+ 					  dialog_token, status, 1, buf_size,
+-					  timeout, addbaext);
++					  timeout, addba_ext_data);
+ }
+ 
+ void ieee80211_process_addba_request(struct ieee80211_local *local,
+@@ -428,9 +463,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
+ 				     size_t len)
+ {
+ 	u16 capab, tid, timeout, ba_policy, buf_size, start_seq_num;
+-	struct ieee802_11_elems *elems = NULL;
+-	u8 dialog_token;
+-	int ies_len;
++	u8 dialog_token, addba_ext_data;
+ 
+ 	/* extract session parameters from addba request frame */
+ 	dialog_token = mgmt->u.action.u.addba_req.dialog_token;
+@@ -443,28 +476,17 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
+ 	tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
+ 	buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6;
+ 
+-	ies_len = len - offsetof(struct ieee80211_mgmt,
+-				 u.action.u.addba_req.variable);
+-	if (ies_len) {
+-		elems = ieee802_11_parse_elems(mgmt->u.action.u.addba_req.variable,
+-					       ies_len, true, NULL);
+-		if (!elems || elems->parse_error)
+-			goto free;
+-	}
+-
+-	if (sta->sta.deflink.eht_cap.has_eht && elems && elems->addba_ext_ie) {
+-		u8 buf_size_1k = u8_get_bits(elems->addba_ext_ie->data,
+-					     IEEE80211_ADDBA_EXT_BUF_SIZE_MASK);
+-
+-		buf_size |= buf_size_1k << IEEE80211_ADDBA_EXT_BUF_SIZE_SHIFT;
+-	}
++	addba_ext_data =
++		ieee80211_retrieve_addba_ext_data(sta,
++						  mgmt->u.action.u.addba_req.variable,
++						  len -
++						  offsetof(typeof(*mgmt),
++							   u.action.u.addba_req.variable),
++						  &buf_size);
+ 
+ 	__ieee80211_start_rx_ba_session(sta, dialog_token, timeout,
+ 					start_seq_num, ba_policy, tid,
+-					buf_size, true, false,
+-					elems ? elems->addba_ext_ie : NULL);
+-free:
+-	kfree(elems);
++					buf_size, true, false, addba_ext_data);
+ }
+ 
+ void ieee80211_manage_rx_ba_offl(struct ieee80211_vif *vif,
+diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
+index 04cb45cfb310..61f2cac37728 100644
+--- a/net/mac80211/agg-tx.c
++++ b/net/mac80211/agg-tx.c
+@@ -58,23 +58,24 @@
+  * complete.
+  */
+ 
+-static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata,
+-					 const u8 *da, u16 tid,
++static void ieee80211_send_addba_request(struct sta_info *sta, u16 tid,
+ 					 u8 dialog_token, u16 start_seq_num,
+ 					 u16 agg_size, u16 timeout)
+ {
++	struct ieee80211_sub_if_data *sdata = sta->sdata;
+ 	struct ieee80211_local *local = sdata->local;
+ 	struct sk_buff *skb;
+ 	struct ieee80211_mgmt *mgmt;
+ 	u16 capab;
+ 
+-	skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom);
+-
++	skb = dev_alloc_skb(sizeof(*mgmt) +
++			    2 + sizeof(struct ieee80211_addba_ext_ie) +
++			    local->hw.extra_tx_headroom);
+ 	if (!skb)
+ 		return;
+ 
+ 	skb_reserve(skb, local->hw.extra_tx_headroom);
+-	mgmt = ieee80211_mgmt_ba(skb, da, sdata);
++	mgmt = ieee80211_mgmt_ba(skb, sta->sta.addr, sdata);
+ 
+ 	skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_req));
+ 
+@@ -93,6 +94,9 @@ static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata,
+ 	mgmt->u.action.u.addba_req.start_seq_num =
+ 					cpu_to_le16(start_seq_num << 4);
+ 
++	if (sta->sta.deflink.he_cap.has_he)
++		ieee80211_add_addbaext(skb, 0, agg_size);
++
+ 	ieee80211_tx_skb_tid(sdata, skb, tid, -1);
+ }
+ 
+@@ -460,8 +464,11 @@ static void ieee80211_send_addba_with_timeout(struct sta_info *sta,
+ 	sta->ampdu_mlme.addba_req_num[tid]++;
+ 	spin_unlock_bh(&sta->lock);
+ 
+-	if (sta->sta.deflink.he_cap.has_he) {
++	if (sta->sta.deflink.eht_cap.has_eht) {
+ 		buf_size = local->hw.max_tx_aggregation_subframes;
++	} else if (sta->sta.deflink.he_cap.has_he) {
++		buf_size = min_t(u16, local->hw.max_tx_aggregation_subframes,
++				 IEEE80211_MAX_AMPDU_BUF_HE);
+ 	} else {
+ 		/*
+ 		 * We really should use what the driver told us it will
+@@ -473,9 +480,8 @@ static void ieee80211_send_addba_with_timeout(struct sta_info *sta,
+ 	}
+ 
+ 	/* send AddBA request */
+-	ieee80211_send_addba_request(sdata, sta->sta.addr, tid,
+-				     tid_tx->dialog_token, tid_tx->ssn,
+-				     buf_size, tid_tx->timeout);
++	ieee80211_send_addba_request(sta, tid, tid_tx->dialog_token,
++				     tid_tx->ssn, buf_size, tid_tx->timeout);
+ 
+ 	WARN_ON(test_and_set_bit(HT_AGG_STATE_SENT_ADDBA, &tid_tx->state));
+ }
+@@ -970,6 +976,13 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
+ 	amsdu = capab & IEEE80211_ADDBA_PARAM_AMSDU_MASK;
+ 	tid = u16_get_bits(capab, IEEE80211_ADDBA_PARAM_TID_MASK);
+ 	buf_size = u16_get_bits(capab, IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK);
++
++	ieee80211_retrieve_addba_ext_data(sta,
++					  mgmt->u.action.u.addba_resp.variable,
++					  len - offsetof(typeof(*mgmt),
++							 u.action.u.addba_resp.variable),
++					  &buf_size);
++
+ 	buf_size = min(buf_size, local->hw.max_tx_aggregation_subframes);
+ 
+ 	txq = sta->sta.txq[tid];
+diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c
+index 1c2b7dd8976a..32390d8a9d75 100644
+--- a/net/mac80211/ht.c
++++ b/net/mac80211/ht.c
+@@ -379,7 +379,7 @@ void ieee80211_ba_session_work(struct wiphy *wiphy, struct wiphy_work *work)
+ 				       sta->ampdu_mlme.tid_rx_manage_offl))
+ 			__ieee80211_start_rx_ba_session(sta, 0, 0, 0, 1, tid,
+ 							IEEE80211_MAX_AMPDU_BUF_HT,
+-							false, true, NULL);
++							false, true, 0);
+ 
+ 		if (test_and_clear_bit(tid + IEEE80211_NUM_TIDS,
+ 				       sta->ampdu_mlme.tid_rx_manage_offl))
+diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
+index 7dcb46120abc..752297bcde76 100644
+--- a/net/mac80211/ieee80211_i.h
++++ b/net/mac80211/ieee80211_i.h
+@@ -2111,14 +2111,19 @@ int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata,
+ 			       const u8 *bssid, int link_id);
+ bool ieee80211_smps_is_restrictive(enum ieee80211_smps_mode smps_mode_old,
+ 				   enum ieee80211_smps_mode smps_mode_new);
+-
++void ieee80211_add_addbaext(struct sk_buff *skb,
++			    const u8 req_addba_ext_data,
++			    u16 buf_size);
++u8 ieee80211_retrieve_addba_ext_data(struct sta_info *sta,
++				     const void *elem_data, ssize_t elem_len,
++				     u16 *buf_size);
+ void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
+ 				    u16 initiator, u16 reason, bool stop);
+ void __ieee80211_start_rx_ba_session(struct sta_info *sta,
+ 				     u8 dialog_token, u16 timeout,
+ 				     u16 start_seq_num, u16 ba_policy, u16 tid,
+ 				     u16 buf_size, bool tx, bool auto_seq,
+-				     const struct ieee80211_addba_ext_ie *addbaext);
++				     const u8 addba_ext_data);
+ void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta,
+ 					 enum ieee80211_agg_stop_reason reason);
+ void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata,
+-- 
+2.39.5
+




More information about the lede-commits mailing list