diff --git a/patches/0001-patches-mac80211-estimate-expected-throughput-if-not.patch b/patches/0001-patches-mac80211-estimate-expected-throughput-if-not.patch new file mode 100644 index 00000000..f2b50699 --- /dev/null +++ b/patches/0001-patches-mac80211-estimate-expected-throughput-if-not.patch @@ -0,0 +1,233 @@ +From 83b458f476fdd55ed06e4db50051f17ea4b3f2ba Mon Sep 17 00:00:00 2001 +From: Grische +Date: Thu, 7 Aug 2025 21:53:48 +0200 +Subject: [PATCH] patches: mac80211: estimate expected throughput if not + provided by driver/rc + +--- + ...oughput-if-not-provided-by-driver-rc.patch | 213 ++++++++++++++++++ + 1 file changed, 213 insertions(+) + create mode 100644 patches/openwrt/0010-mac80211-estimate-expected-throughput-if-not-provided-by-driver-rc.patch + +diff --git a/patches/openwrt/0010-mac80211-estimate-expected-throughput-if-not-provided-by-driver-rc.patch b/patches/openwrt/0010-mac80211-estimate-expected-throughput-if-not-provided-by-driver-rc.patch +new file mode 100644 +index 00000000..51188d06 +--- /dev/null ++++ b/patches/openwrt/0010-mac80211-estimate-expected-throughput-if-not-provided-by-driver-rc.patch +@@ -0,0 +1,213 @@ ++From: Felix Fietkau ++Date: Wed, 6 Aug 2025 11:09:57 +0200 ++Subject: mac80211: estimate expected throughput if not provided by driver/rc ++ ++Estimate the tx throughput based on the expected per-packet tx time. ++This is useful for mesh implementations that rely on expected throughput, ++e.g. 802.11s or batman-adv. ++ ++Signed-off-by: Felix Fietkau ++ ++diff --git a/package/kernel/mac80211/patches/subsys/360-mac80211-factor-out-part-of-ieee80211_calc_expected_.patch b/package/kernel/mac80211/patches/subsys/360-mac80211-factor-out-part-of-ieee80211_calc_expected_.patch ++new file mode 100644 ++index 0000000000000000000000000000000000000000..b5d5a72f87010f0d1d6bcb4ad65267c3f6725b57 ++--- /dev/null +++++ b/package/kernel/mac80211/patches/subsys/360-mac80211-factor-out-part-of-ieee80211_calc_expected_.patch ++@@ -0,0 +1,140 @@ +++From: Felix Fietkau +++Date: Wed, 6 Aug 2025 10:49:54 +0200 +++Subject: [PATCH] mac80211: factor out part of +++ ieee80211_calc_expected_tx_airtime +++ +++Create ieee80211_rate_expected_tx_airtime helper function, which returns +++the expected tx airtime for a given rate and packet length in units of +++1024 usec, for more accuracy. +++ +++Signed-off-by: Felix Fietkau +++--- +++ +++--- a/net/mac80211/airtime.c ++++++ b/net/mac80211/airtime.c +++@@ -685,7 +685,7 @@ static int ieee80211_fill_rx_status(stru +++ if (ieee80211_fill_rate_info(hw, stat, band, ri)) +++ return 0; +++ +++- if (!ieee80211_rate_valid(rate)) ++++ if (!rate || !ieee80211_rate_valid(rate)) +++ return -1; +++ +++ if (rate->flags & IEEE80211_TX_RC_160_MHZ_WIDTH) +++@@ -753,6 +753,53 @@ u32 ieee80211_calc_tx_airtime(struct iee +++ } +++ EXPORT_SYMBOL_GPL(ieee80211_calc_tx_airtime); +++ ++++u32 ieee80211_rate_expected_tx_airtime(struct ieee80211_hw *hw, ++++ struct ieee80211_tx_rate *tx_rate, ++++ struct rate_info *ri, ++++ enum nl80211_band band, ++++ bool ampdu, int len) ++++{ ++++ struct ieee80211_rx_status stat; ++++ u32 duration, overhead; ++++ u8 agg_shift; ++++ ++++ if (ieee80211_fill_rx_status(&stat, hw, tx_rate, ri, band, len)) ++++ return 0; ++++ ++++ if (stat.encoding == RX_ENC_LEGACY || !ampdu) ++++ return ieee80211_calc_rx_airtime(hw, &stat, len) * 1024; ++++ ++++ duration = ieee80211_get_rate_duration(hw, &stat, &overhead); ++++ ++++ /* ++++ * Assume that HT/VHT transmission on any AC except VO will ++++ * use aggregation. Since we don't have reliable reporting ++++ * of aggregation length, assume an average size based on the ++++ * tx rate. ++++ * This will not be very accurate, but much better than simply ++++ * assuming un-aggregated tx in all cases. ++++ */ ++++ if (duration > 400 * 1024) /* <= VHT20 MCS2 1S */ ++++ agg_shift = 1; ++++ else if (duration > 250 * 1024) /* <= VHT20 MCS3 1S or MCS1 2S */ ++++ agg_shift = 2; ++++ else if (duration > 150 * 1024) /* <= VHT20 MCS5 1S or MCS2 2S */ ++++ agg_shift = 3; ++++ else if (duration > 70 * 1024) /* <= VHT20 MCS5 2S */ ++++ agg_shift = 4; ++++ else if (stat.encoding != RX_ENC_HE || ++++ duration > 20 * 1024) /* <= HE40 MCS6 2S */ ++++ agg_shift = 5; ++++ else ++++ agg_shift = 6; ++++ ++++ duration *= len; ++++ duration /= AVG_PKT_SIZE; ++++ duration += (overhead * 1024 >> agg_shift); ++++ ++++ return duration; ++++} ++++ +++ u32 ieee80211_calc_expected_tx_airtime(struct ieee80211_hw *hw, +++ struct ieee80211_vif *vif, +++ struct ieee80211_sta *pubsta, +++@@ -775,45 +822,13 @@ u32 ieee80211_calc_expected_tx_airtime(s +++ if (pubsta) { +++ struct sta_info *sta = container_of(pubsta, struct sta_info, +++ sta); +++- struct ieee80211_rx_status stat; +++ struct ieee80211_tx_rate *tx_rate = &sta->deflink.tx_stats.last_rate; +++ struct rate_info *ri = &sta->deflink.tx_stats.last_rate_info; +++- u32 duration, overhead; +++- u8 agg_shift; +++- +++- if (ieee80211_fill_rx_status(&stat, hw, tx_rate, ri, band, len)) +++- return 0; +++- +++- if (stat.encoding == RX_ENC_LEGACY || !ampdu) +++- return ieee80211_calc_rx_airtime(hw, &stat, len); +++- +++- duration = ieee80211_get_rate_duration(hw, &stat, &overhead); +++- /* +++- * Assume that HT/VHT transmission on any AC except VO will +++- * use aggregation. Since we don't have reliable reporting +++- * of aggregation length, assume an average size based on the +++- * tx rate. +++- * This will not be very accurate, but much better than simply +++- * assuming un-aggregated tx in all cases. +++- */ +++- if (duration > 400 * 1024) /* <= VHT20 MCS2 1S */ +++- agg_shift = 1; +++- else if (duration > 250 * 1024) /* <= VHT20 MCS3 1S or MCS1 2S */ +++- agg_shift = 2; +++- else if (duration > 150 * 1024) /* <= VHT20 MCS5 1S or MCS2 2S */ +++- agg_shift = 3; +++- else if (duration > 70 * 1024) /* <= VHT20 MCS5 2S */ +++- agg_shift = 4; +++- else if (stat.encoding != RX_ENC_HE || +++- duration > 20 * 1024) /* <= HE40 MCS6 2S */ +++- agg_shift = 5; +++- else +++- agg_shift = 6; ++++ u32 duration; +++ +++- duration *= len; +++- duration /= AVG_PKT_SIZE; ++++ duration = ieee80211_rate_expected_tx_airtime(hw, tx_rate, ri, ++++ band, true, len); +++ duration /= 1024; +++- duration += (overhead >> agg_shift); +++ +++ return max_t(u32, duration, 4); +++ } +++--- a/net/mac80211/ieee80211_i.h ++++++ b/net/mac80211/ieee80211_i.h +++@@ -2756,6 +2756,11 @@ u8 *ieee80211_get_bssid(struct ieee80211 +++ +++ extern const struct ethtool_ops ieee80211_ethtool_ops; +++ ++++u32 ieee80211_rate_expected_tx_airtime(struct ieee80211_hw *hw, ++++ struct ieee80211_tx_rate *tx_rate, ++++ struct rate_info *ri, ++++ enum nl80211_band band, ++++ bool ampdu, int len); +++ u32 ieee80211_calc_expected_tx_airtime(struct ieee80211_hw *hw, +++ struct ieee80211_vif *vif, +++ struct ieee80211_sta *pubsta, ++diff --git a/package/kernel/mac80211/patches/subsys/361-mac80211-estimate-expected-throughput-if-not-provide.patch b/package/kernel/mac80211/patches/subsys/361-mac80211-estimate-expected-throughput-if-not-provide.patch ++new file mode 100644 ++index 0000000000000000000000000000000000000000..9bcaf86504170db5b5b77c1c40c96be1cbb5d701 ++--- /dev/null +++++ b/package/kernel/mac80211/patches/subsys/361-mac80211-estimate-expected-throughput-if-not-provide.patch ++@@ -0,0 +1,51 @@ +++From: Felix Fietkau +++Date: Wed, 6 Aug 2025 10:52:03 +0200 +++Subject: [PATCH] mac80211: estimate expected throughput if not provided by +++ driver/rc +++ +++Estimate the tx throughput based on the expected per-packet tx time. +++This is useful for mesh implementations that rely on expected throughput, +++e.g. 802.11s or batman-adv. +++ +++Signed-off-by: Felix Fietkau +++--- +++ +++--- a/net/mac80211/sta_info.c ++++++ b/net/mac80211/sta_info.c +++@@ -2621,6 +2621,27 @@ static inline u64 sta_get_stats_bytes(st +++ return value; +++ } +++ ++++static u32 sta_estimate_expected_throughput(struct sta_info *sta, ++++ struct station_info *sinfo) ++++{ ++++ struct ieee80211_sub_if_data *sdata = sta->sdata; ++++ struct ieee80211_local *local = sdata->local; ++++ struct rate_info *ri = &sinfo->txrate; ++++ struct ieee80211_hw *hw = &local->hw; ++++ struct ieee80211_chanctx_conf *conf; ++++ u32 duration; ++++ u8 band = 0; ++++ ++++ conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); ++++ if (conf) ++++ band = conf->def.chan->band; ++++ ++++ duration = ieee80211_rate_expected_tx_airtime(hw, NULL, ri, band, true, 1024); ++++ duration += duration >> 4; /* add assumed packet error rate of ~6% */ ++++ ++++ return ((1024 * USEC_PER_SEC) / duration) * 8; ++++} ++++ +++ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo, +++ bool tidstats) +++ { +++@@ -2865,6 +2886,8 @@ void sta_set_sinfo(struct sta_info *sta, +++ sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_TDLS_PEER); +++ +++ thr = sta_get_expected_throughput(sta); ++++ if (!thr && (sinfo->filled & BIT_ULL(NL80211_STA_INFO_TX_BITRATE))) ++++ thr = sta_estimate_expected_throughput(sta, sinfo); +++ +++ if (thr != 0) { +++ sinfo->filled |= BIT_ULL(NL80211_STA_INFO_EXPECTED_THROUGHPUT); +-- +2.43.0 +