diff options
Diffstat (limited to 'package/kernel/mac80211/patches/subsys')
63 files changed, 1312 insertions, 9646 deletions
diff --git a/package/kernel/mac80211/patches/subsys/001-wifi-mac80211-do-not-pass-ap_vlan-vif-pointer-to-dri.patch b/package/kernel/mac80211/patches/subsys/001-wifi-mac80211-do-not-pass-ap_vlan-vif-pointer-to-dri.patch new file mode 100644 index 00000000000..43724aee1ae --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/001-wifi-mac80211-do-not-pass-ap_vlan-vif-pointer-to-dri.patch @@ -0,0 +1,64 @@ +From ee0db868ee4d88493dfdc82f59e3b4e449ddddd5 Mon Sep 17 00:00:00 2001 +From: Oldřich Jedlička <oldium.pro@gmail.com> +Date: Sat, 4 Nov 2023 15:13:33 +0100 +Subject: wifi: mac80211: do not pass AP_VLAN vif pointer to drivers during + flush +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +[ Upstream commit 3e3a2b645c043f7e3e488d5011478cefb69bbe8b ] + +This fixes WARN_ONs when using AP_VLANs after station removal. The flush +call passed AP_VLAN vif to driver, but because these vifs are virtual and +not registered with drivers, we need to translate to the correct AP vif +first. + +Closes: https://github.com/openwrt/openwrt/issues/12420 +Fixes: 0b75a1b1e42e ("wifi: mac80211: flush queues on STA removal") +Fixes: d00800a289c9 ("wifi: mac80211: add flush_sta method") +Tested-by: Konstantin Demin <rockdrilla@gmail.com> +Tested-by: Koen Vandeputte <koen.vandeputte@citymesh.com> +Signed-off-by: Oldřich Jedlička <oldium.pro@gmail.com> +Link: https://lore.kernel.org/r/20231104141333.3710-1-oldium.pro@gmail.com +Signed-off-by: Johannes Berg <johannes.berg@intel.com> +Signed-off-by: Sasha Levin <sashal@kernel.org> +--- + net/mac80211/driver-ops.h | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +--- a/net/mac80211/driver-ops.h ++++ b/net/mac80211/driver-ops.h +@@ -23,7 +23,7 @@ + static inline struct ieee80211_sub_if_data * + get_bss_sdata(struct ieee80211_sub_if_data *sdata) + { +- if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) ++ if (sdata && sdata->vif.type == NL80211_IFTYPE_AP_VLAN) + sdata = container_of(sdata->bss, struct ieee80211_sub_if_data, + u.ap); + +@@ -638,10 +638,13 @@ static inline void drv_flush(struct ieee + struct ieee80211_sub_if_data *sdata, + u32 queues, bool drop) + { +- struct ieee80211_vif *vif = sdata ? &sdata->vif : NULL; ++ struct ieee80211_vif *vif; + + might_sleep(); + ++ sdata = get_bss_sdata(sdata); ++ vif = sdata ? &sdata->vif : NULL; ++ + if (sdata && !check_sdata_in_driver(sdata)) + return; + +@@ -657,6 +660,8 @@ static inline void drv_flush_sta(struct + { + might_sleep(); + ++ sdata = get_bss_sdata(sdata); ++ + if (sdata && !check_sdata_in_driver(sdata)) + return; + diff --git a/package/kernel/mac80211/patches/subsys/010-sync-nl80211_h.patch b/package/kernel/mac80211/patches/subsys/010-sync-nl80211_h.patch deleted file mode 100644 index e1f66ac1c34..00000000000 --- a/package/kernel/mac80211/patches/subsys/010-sync-nl80211_h.patch +++ /dev/null @@ -1,297 +0,0 @@ ---- a/include/uapi/linux/nl80211.h -+++ b/include/uapi/linux/nl80211.h -@@ -655,6 +655,9 @@ - * When a security association was established on an 802.1X network using - * fast transition, this event should be followed by an - * %NL80211_CMD_PORT_AUTHORIZED event. -+ * Following a %NL80211_CMD_ROAM event userspace can issue -+ * %NL80211_CMD_GET_SCAN in order to obtain the scan information for the -+ * new BSS the card/driver roamed to. - * @NL80211_CMD_DISCONNECT: drop a given connection; also used to notify - * userspace that a connection was dropped by the AP or due to other - * reasons, for this the %NL80211_ATTR_DISCONNECTED_BY_AP and -@@ -757,7 +760,8 @@ - * of any other interfaces, and other interfaces will again take - * precedence when they are used. - * -- * @NL80211_CMD_SET_WDS_PEER: Set the MAC address of the peer on a WDS interface. -+ * @NL80211_CMD_SET_WDS_PEER: Set the MAC address of the peer on a WDS interface -+ * (no longer supported). - * - * @NL80211_CMD_SET_MULTICAST_TO_UNICAST: Configure if this AP should perform - * multicast to unicast conversion. When enabled, all multicast packets -@@ -1177,6 +1181,10 @@ - * includes the contents of the frame. %NL80211_ATTR_ACK flag is included - * if the recipient acknowledged the frame. - * -+ * @NL80211_CMD_SET_SAR_SPECS: SAR power limitation configuration is -+ * passed using %NL80211_ATTR_SAR_SPEC. %NL80211_ATTR_WIPHY is used to -+ * specify the wiphy index to be applied to. -+ * - * @NL80211_CMD_MAX: highest used command number - * @__NL80211_CMD_AFTER_LAST: internal use - */ -@@ -1407,6 +1415,8 @@ enum nl80211_commands { - - NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS, - -+ NL80211_CMD_SET_SAR_SPECS, -+ - /* add new commands above here */ - - /* used to define NL80211_CMD_MAX below */ -@@ -1750,8 +1760,9 @@ enum nl80211_commands { - * specify just a single bitrate, which is to be used for the beacon. - * The driver must also specify support for this with the extended - * features NL80211_EXT_FEATURE_BEACON_RATE_LEGACY, -- * NL80211_EXT_FEATURE_BEACON_RATE_HT and -- * NL80211_EXT_FEATURE_BEACON_RATE_VHT. -+ * NL80211_EXT_FEATURE_BEACON_RATE_HT, -+ * NL80211_EXT_FEATURE_BEACON_RATE_VHT and -+ * NL80211_EXT_FEATURE_BEACON_RATE_HE. - * - * @NL80211_ATTR_FRAME_MATCH: A binary attribute which typically must contain - * at least one byte, currently used with @NL80211_CMD_REGISTER_FRAME. -@@ -1955,8 +1966,15 @@ enum nl80211_commands { - * @NL80211_ATTR_PROBE_RESP: Probe Response template data. Contains the entire - * probe-response frame. The DA field in the 802.11 header is zero-ed out, - * to be filled by the FW. -- * @NL80211_ATTR_DISABLE_HT: Force HT capable interfaces to disable -- * this feature. Currently, only supported in mac80211 drivers. -+ * @NL80211_ATTR_DISABLE_HT: Force HT capable interfaces to disable -+ * this feature during association. This is a flag attribute. -+ * Currently only supported in mac80211 drivers. -+ * @NL80211_ATTR_DISABLE_VHT: Force VHT capable interfaces to disable -+ * this feature during association. This is a flag attribute. -+ * Currently only supported in mac80211 drivers. -+ * @NL80211_ATTR_DISABLE_HE: Force HE capable interfaces to disable -+ * this feature during association. This is a flag attribute. -+ * Currently only supported in mac80211 drivers. - * @NL80211_ATTR_HT_CAPABILITY_MASK: Specify which bits of the - * ATTR_HT_CAPABILITY to which attention should be paid. - * Currently, only mac80211 NICs support this feature. -@@ -2077,7 +2095,8 @@ enum nl80211_commands { - * until the channel switch event. - * @NL80211_ATTR_CH_SWITCH_BLOCK_TX: flag attribute specifying that transmission - * must be blocked on the current channel (before the channel switch -- * operation). -+ * operation). Also included in the channel switch started event if quiet -+ * was requested by the AP. - * @NL80211_ATTR_CSA_IES: Nested set of attributes containing the IE information - * for the time while performing a channel switch. - * @NL80211_ATTR_CNTDWN_OFFS_BEACON: An array of offsets (u16) to the channel -@@ -2527,6 +2546,20 @@ enum nl80211_commands { - * override mask. Used with NL80211_ATTR_S1G_CAPABILITY in - * NL80211_CMD_ASSOCIATE or NL80211_CMD_CONNECT. - * -+ * @NL80211_ATTR_SAE_PWE: Indicates the mechanism(s) allowed for SAE PWE -+ * derivation in WPA3-Personal networks which are using SAE authentication. -+ * This is a u8 attribute that encapsulates one of the values from -+ * &enum nl80211_sae_pwe_mechanism. -+ * -+ * @NL80211_ATTR_SAR_SPEC: SAR power limitation specification when -+ * used with %NL80211_CMD_SET_SAR_SPECS. The message contains fields -+ * of %nl80211_sar_attrs which specifies the sar type and related -+ * sar specs. Sar specs contains array of %nl80211_sar_specs_attrs. -+ * -+ * @NL80211_ATTR_RECONNECT_REQUESTED: flag attribute, used with deauth and -+ * disassoc events to indicate that an immediate reconnect to the AP -+ * is desired. -+ * - * @NUM_NL80211_ATTR: total number of nl80211_attrs available - * @NL80211_ATTR_MAX: highest attribute number currently defined - * @__NL80211_ATTR_AFTER_LAST: internal use -@@ -3016,6 +3049,14 @@ enum nl80211_attrs { - NL80211_ATTR_S1G_CAPABILITY, - NL80211_ATTR_S1G_CAPABILITY_MASK, - -+ NL80211_ATTR_SAE_PWE, -+ -+ NL80211_ATTR_RECONNECT_REQUESTED, -+ -+ NL80211_ATTR_SAR_SPEC, -+ -+ NL80211_ATTR_DISABLE_HE, -+ - /* add attributes here, update the policy in nl80211.c */ - - __NL80211_ATTR_AFTER_LAST, -@@ -5896,6 +5937,19 @@ enum nl80211_feature_flags { - * @NL80211_EXT_FEATURE_UNSOL_BCAST_PROBE_RESP: Driver/device supports - * unsolicited broadcast probe response transmission - * -+ * @NL80211_EXT_FEATURE_BEACON_RATE_HE: Driver supports beacon rate -+ * configuration (AP/mesh) with HE rates. -+ * -+ * @NL80211_EXT_FEATURE_SECURE_LTF: Device supports secure LTF measurement -+ * exchange protocol. -+ * -+ * @NL80211_EXT_FEATURE_SECURE_RTT: Device supports secure RTT measurement -+ * exchange protocol. -+ * -+ * @NL80211_EXT_FEATURE_PROT_RANGE_NEGO_AND_MEASURE: Device supports management -+ * frame protection for all management frames exchanged during the -+ * negotiation and range measurement procedure. -+ * - * @NUM_NL80211_EXT_FEATURES: number of extended features. - * @MAX_NL80211_EXT_FEATURES: highest extended feature index. - */ -@@ -5956,6 +6010,10 @@ enum nl80211_ext_feature_index { - NL80211_EXT_FEATURE_SAE_OFFLOAD_AP, - NL80211_EXT_FEATURE_FILS_DISCOVERY, - NL80211_EXT_FEATURE_UNSOL_BCAST_PROBE_RESP, -+ NL80211_EXT_FEATURE_BEACON_RATE_HE, -+ NL80211_EXT_FEATURE_SECURE_LTF, -+ NL80211_EXT_FEATURE_SECURE_RTT, -+ NL80211_EXT_FEATURE_PROT_RANGE_NEGO_AND_MEASURE, - - /* add new features before the definition below */ - NUM_NL80211_EXT_FEATURES, -@@ -6253,11 +6311,13 @@ struct nl80211_vendor_cmd_info { - * @NL80211_TDLS_PEER_HT: TDLS peer is HT capable. - * @NL80211_TDLS_PEER_VHT: TDLS peer is VHT capable. - * @NL80211_TDLS_PEER_WMM: TDLS peer is WMM capable. -+ * @NL80211_TDLS_PEER_HE: TDLS peer is HE capable. - */ - enum nl80211_tdls_peer_capability { - NL80211_TDLS_PEER_HT = 1<<0, - NL80211_TDLS_PEER_VHT = 1<<1, - NL80211_TDLS_PEER_WMM = 1<<2, -+ NL80211_TDLS_PEER_HE = 1<<3, - }; - - /** -@@ -6849,6 +6909,9 @@ enum nl80211_peer_measurement_ftm_capa { - * if neither %NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED nor - * %NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED is set, EDCA based - * ranging will be used. -+ * @NL80211_PMSR_FTM_REQ_ATTR_LMR_FEEDBACK: negotiate for LMR feedback. Only -+ * valid if either %NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED or -+ * %NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED is set. - * - * @NUM_NL80211_PMSR_FTM_REQ_ATTR: internal - * @NL80211_PMSR_FTM_REQ_ATTR_MAX: highest attribute number -@@ -6867,6 +6930,7 @@ enum nl80211_peer_measurement_ftm_req { - NL80211_PMSR_FTM_REQ_ATTR_REQUEST_CIVICLOC, - NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED, - NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED, -+ NL80211_PMSR_FTM_REQ_ATTR_LMR_FEEDBACK, - - /* keep last */ - NUM_NL80211_PMSR_FTM_REQ_ATTR, -@@ -7124,4 +7188,115 @@ enum nl80211_unsol_bcast_probe_resp_attr - NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_MAX = - __NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_LAST - 1 - }; -+ -+/** -+ * enum nl80211_sae_pwe_mechanism - The mechanism(s) allowed for SAE PWE -+ * derivation. Applicable only when WPA3-Personal SAE authentication is -+ * used. -+ * -+ * @NL80211_SAE_PWE_UNSPECIFIED: not specified, used internally to indicate that -+ * attribute is not present from userspace. -+ * @NL80211_SAE_PWE_HUNT_AND_PECK: hunting-and-pecking loop only -+ * @NL80211_SAE_PWE_HASH_TO_ELEMENT: hash-to-element only -+ * @NL80211_SAE_PWE_BOTH: both hunting-and-pecking loop and hash-to-element -+ * can be used. -+ */ -+enum nl80211_sae_pwe_mechanism { -+ NL80211_SAE_PWE_UNSPECIFIED, -+ NL80211_SAE_PWE_HUNT_AND_PECK, -+ NL80211_SAE_PWE_HASH_TO_ELEMENT, -+ NL80211_SAE_PWE_BOTH, -+}; -+ -+/** -+ * enum nl80211_sar_type - type of SAR specs -+ * -+ * @NL80211_SAR_TYPE_POWER: power limitation specified in 0.25dBm unit -+ * -+ */ -+enum nl80211_sar_type { -+ NL80211_SAR_TYPE_POWER, -+ -+ /* add new type here */ -+ -+ /* Keep last */ -+ NUM_NL80211_SAR_TYPE, -+}; -+ -+/** -+ * enum nl80211_sar_attrs - Attributes for SAR spec -+ * -+ * @NL80211_SAR_ATTR_TYPE: the SAR type as defined in &enum nl80211_sar_type. -+ * -+ * @NL80211_SAR_ATTR_SPECS: Nested array of SAR power -+ * limit specifications. Each specification contains a set -+ * of %nl80211_sar_specs_attrs. -+ * -+ * For SET operation, it contains array of %NL80211_SAR_ATTR_SPECS_POWER -+ * and %NL80211_SAR_ATTR_SPECS_RANGE_INDEX. -+ * -+ * For sar_capa dump, it contains array of -+ * %NL80211_SAR_ATTR_SPECS_START_FREQ -+ * and %NL80211_SAR_ATTR_SPECS_END_FREQ. -+ * -+ * @__NL80211_SAR_ATTR_LAST: Internal -+ * @NL80211_SAR_ATTR_MAX: highest sar attribute -+ * -+ * These attributes are used with %NL80211_CMD_SET_SAR_SPEC -+ */ -+enum nl80211_sar_attrs { -+ __NL80211_SAR_ATTR_INVALID, -+ -+ NL80211_SAR_ATTR_TYPE, -+ NL80211_SAR_ATTR_SPECS, -+ -+ __NL80211_SAR_ATTR_LAST, -+ NL80211_SAR_ATTR_MAX = __NL80211_SAR_ATTR_LAST - 1, -+}; -+ -+/** -+ * enum nl80211_sar_specs_attrs - Attributes for SAR power limit specs -+ * -+ * @NL80211_SAR_ATTR_SPECS_POWER: Required (s32)value to specify the actual -+ * power limit value in units of 0.25 dBm if type is -+ * NL80211_SAR_TYPE_POWER. (i.e., a value of 44 represents 11 dBm). -+ * 0 means userspace doesn't have SAR limitation on this associated range. -+ * -+ * @NL80211_SAR_ATTR_SPECS_RANGE_INDEX: Required (u32) value to specify the -+ * index of exported freq range table and the associated power limitation -+ * is applied to this range. -+ * -+ * Userspace isn't required to set all the ranges advertised by WLAN driver, -+ * and userspace can skip some certain ranges. These skipped ranges don't -+ * have SAR limitations, and they are same as setting the -+ * %NL80211_SAR_ATTR_SPECS_POWER to any unreasonable high value because any -+ * value higher than regulatory allowed value just means SAR power -+ * limitation is removed, but it's required to set at least one range. -+ * It's not allowed to set duplicated range in one SET operation. -+ * -+ * Every SET operation overwrites previous SET operation. -+ * -+ * @NL80211_SAR_ATTR_SPECS_START_FREQ: Required (u32) value to specify the start -+ * frequency of this range edge when registering SAR capability to wiphy. -+ * It's not a channel center frequency. The unit is kHz. -+ * -+ * @NL80211_SAR_ATTR_SPECS_END_FREQ: Required (u32) value to specify the end -+ * frequency of this range edge when registering SAR capability to wiphy. -+ * It's not a channel center frequency. The unit is kHz. -+ * -+ * @__NL80211_SAR_ATTR_SPECS_LAST: Internal -+ * @NL80211_SAR_ATTR_SPECS_MAX: highest sar specs attribute -+ */ -+enum nl80211_sar_specs_attrs { -+ __NL80211_SAR_ATTR_SPECS_INVALID, -+ -+ NL80211_SAR_ATTR_SPECS_POWER, -+ NL80211_SAR_ATTR_SPECS_RANGE_INDEX, -+ NL80211_SAR_ATTR_SPECS_START_FREQ, -+ NL80211_SAR_ATTR_SPECS_END_FREQ, -+ -+ __NL80211_SAR_ATTR_SPECS_LAST, -+ NL80211_SAR_ATTR_SPECS_MAX = __NL80211_SAR_ATTR_SPECS_LAST - 1, -+}; -+ - #endif /* __LINUX_NL80211_H */ diff --git a/package/kernel/mac80211/patches/subsys/110-mac80211_keep_keys_on_stop_ap.patch b/package/kernel/mac80211/patches/subsys/110-mac80211_keep_keys_on_stop_ap.patch index 665231a040e..e3349dabd0b 100644 --- a/package/kernel/mac80211/patches/subsys/110-mac80211_keep_keys_on_stop_ap.patch +++ b/package/kernel/mac80211/patches/subsys/110-mac80211_keep_keys_on_stop_ap.patch @@ -1,12 +1,19 @@ -Used for AP+STA support in OpenWrt - preserve AP mode keys across STA reconnects +From: Felix Fietkau <nbd@nbd.name> +Date: Mon, 27 Oct 2014 00:00:00 +0100 +Subject: [PATCH] mac80211: preseve AP mode keys across STA reconnect + +Used for AP+STA support in OpenWrt - preserve AP mode keys across STA reconnect +--- + net/mac80211/cfg.c | 1 - + 1 file changed, 1 deletion(-) --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c -@@ -1288,7 +1288,6 @@ static int ieee80211_stop_ap(struct wiph - sdata->vif.bss_conf.ftmr_params = NULL; +@@ -1632,7 +1632,6 @@ static int ieee80211_stop_ap(struct wiph + link_conf->bssid_indicator = 0; __sta_info_flush(sdata, true); - ieee80211_free_keys(sdata, true); - sdata->vif.bss_conf.enable_beacon = false; + link_conf->enable_beacon = false; sdata->beacon_rate_set = false; diff --git a/package/kernel/mac80211/patches/subsys/120-cfg80211_allow_perm_addr_change.patch b/package/kernel/mac80211/patches/subsys/120-cfg80211_allow_perm_addr_change.patch index 172e5b04fdf..f315ae5ca2b 100644 --- a/package/kernel/mac80211/patches/subsys/120-cfg80211_allow_perm_addr_change.patch +++ b/package/kernel/mac80211/patches/subsys/120-cfg80211_allow_perm_addr_change.patch @@ -1,6 +1,15 @@ +From: Felix Fietkau <nbd@nbd.name> +Date: Thu, 11 Dec 2014 00:00:00 +0100 +Subject: [PATCH] cfg80211: add support for changing the device mac address via + sysfs + +--- + net/wireless/sysfs.c | 27 ++++++++++++++++++++++----- + 1 file changed, 22 insertions(+), 5 deletions(-) + --- a/net/wireless/sysfs.c +++ b/net/wireless/sysfs.c -@@ -23,18 +23,35 @@ static inline struct cfg80211_registered +@@ -24,18 +24,35 @@ static inline struct cfg80211_registered return container_of(dev, struct cfg80211_registered_device, wiphy.dev); } diff --git a/package/kernel/mac80211/patches/subsys/130-disable_auto_vif.patch b/package/kernel/mac80211/patches/subsys/130-disable_auto_vif.patch new file mode 100644 index 00000000000..9d8f781ac41 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/130-disable_auto_vif.patch @@ -0,0 +1,27 @@ +--- a/net/mac80211/main.c ++++ b/net/mac80211/main.c +@@ -1396,24 +1396,6 @@ int ieee80211_register_hw(struct ieee802 + debugfs_hw_add(local); + rate_control_add_debugfs(local); + +- rtnl_lock(); +- wiphy_lock(hw->wiphy); +- +- /* add one default STA interface if supported */ +- if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_STATION) && +- !ieee80211_hw_check(hw, NO_AUTO_VIF)) { +- struct vif_params params = {0}; +- +- result = ieee80211_if_add(local, "wlan%d", NET_NAME_ENUM, NULL, +- NL80211_IFTYPE_STATION, ¶ms); +- if (result) +- wiphy_warn(local->hw.wiphy, +- "Failed to add default virtual iface\n"); +- } +- +- wiphy_unlock(hw->wiphy); +- rtnl_unlock(); +- + #ifdef CONFIG_INET + local->ifa_notifier.notifier_call = ieee80211_ifa_changed; + result = register_inetaddr_notifier(&local->ifa_notifier); diff --git a/package/kernel/mac80211/patches/subsys/150-disable_addr_notifier.patch b/package/kernel/mac80211/patches/subsys/150-disable_addr_notifier.patch deleted file mode 100644 index 8d086625e44..00000000000 --- a/package/kernel/mac80211/patches/subsys/150-disable_addr_notifier.patch +++ /dev/null @@ -1,67 +0,0 @@ ---- a/net/mac80211/main.c -+++ b/net/mac80211/main.c -@@ -321,7 +321,7 @@ void ieee80211_restart_hw(struct ieee802 - } - EXPORT_SYMBOL(ieee80211_restart_hw); - --#ifdef CONFIG_INET -+#ifdef __disabled__CONFIG_INET - static int ieee80211_ifa_changed(struct notifier_block *nb, - unsigned long data, void *arg) - { -@@ -380,7 +380,7 @@ static int ieee80211_ifa_changed(struct - } - #endif - --#if IS_ENABLED(CONFIG_IPV6) -+#if IS_ENABLED(__disabled__CONFIG_IPV6) - static int ieee80211_ifa6_changed(struct notifier_block *nb, - unsigned long data, void *arg) - { -@@ -1315,14 +1315,14 @@ int ieee80211_register_hw(struct ieee802 - - rtnl_unlock(); - --#ifdef CONFIG_INET -+#ifdef __disabled__CONFIG_INET - local->ifa_notifier.notifier_call = ieee80211_ifa_changed; - result = register_inetaddr_notifier(&local->ifa_notifier); - if (result) - goto fail_ifa; - #endif - --#if IS_ENABLED(CONFIG_IPV6) -+#if IS_ENABLED(__disabled__CONFIG_IPV6) - local->ifa6_notifier.notifier_call = ieee80211_ifa6_changed; - result = register_inet6addr_notifier(&local->ifa6_notifier); - if (result) -@@ -1331,13 +1331,13 @@ int ieee80211_register_hw(struct ieee802 - - return 0; - --#if IS_ENABLED(CONFIG_IPV6) -+#if IS_ENABLED(__disabled__CONFIG_IPV6) - fail_ifa6: --#ifdef CONFIG_INET -+#ifdef __disabled__CONFIG_INET - unregister_inetaddr_notifier(&local->ifa_notifier); - #endif - #endif --#if defined(CONFIG_INET) || defined(CONFIG_IPV6) -+#if defined(__disabled__CONFIG_INET) || defined(__disabled__CONFIG_IPV6) - fail_ifa: - #endif - wiphy_unregister(local->hw.wiphy); -@@ -1365,10 +1365,10 @@ void ieee80211_unregister_hw(struct ieee - tasklet_kill(&local->tx_pending_tasklet); - tasklet_kill(&local->tasklet); - --#ifdef CONFIG_INET -+#ifdef __disabled__CONFIG_INET - unregister_inetaddr_notifier(&local->ifa_notifier); - #endif --#if IS_ENABLED(CONFIG_IPV6) -+#if IS_ENABLED(__disabled__CONFIG_IPV6) - unregister_inet6addr_notifier(&local->ifa6_notifier); - #endif - diff --git a/package/kernel/mac80211/patches/subsys/210-ap_scan.patch b/package/kernel/mac80211/patches/subsys/210-ap_scan.patch index ee49942459d..25b844a21b2 100644 --- a/package/kernel/mac80211/patches/subsys/210-ap_scan.patch +++ b/package/kernel/mac80211/patches/subsys/210-ap_scan.patch @@ -1,11 +1,19 @@ +From: Felix Fietkau <nbd@nbd.name> +Date: Wed, 3 Oct 2012 00:00:00 +0200 +Subject: [PATCH] mac80211: allow scans in access point mode (for site survey) + +--- + net/mac80211/cfg.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c -@@ -2444,7 +2444,7 @@ static int ieee80211_scan(struct wiphy * - * the frames sent while scanning on other channel will be - * lost) +@@ -2843,6 +2843,8 @@ static int ieee80211_scan(struct wiphy * */ -- if (sdata->u.ap.beacon && -+ if (0 && sdata->u.ap.beacon && - (!(wiphy->features & NL80211_FEATURE_AP_SCAN) || - !(req->flags & NL80211_SCAN_FLAG_AP))) - return -EOPNOTSUPP; + fallthrough; + case NL80211_IFTYPE_AP: ++ /* skip check */ ++ break; + /* + * If the scan has been forced (and the driver supports + * forcing), don't care about being beaconing already. diff --git a/package/kernel/mac80211/patches/subsys/300-cfg80211-support-immediate-reconnect-request-hint.patch b/package/kernel/mac80211/patches/subsys/300-cfg80211-support-immediate-reconnect-request-hint.patch deleted file mode 100644 index 8fe8723cfe3..00000000000 --- a/package/kernel/mac80211/patches/subsys/300-cfg80211-support-immediate-reconnect-request-hint.patch +++ /dev/null @@ -1,279 +0,0 @@ -From: Johannes Berg <johannes.berg@intel.com> -Date: Sun, 6 Dec 2020 14:54:42 +0200 -Subject: [PATCH] cfg80211: support immediate reconnect request hint - -There are cases where it's necessary to disconnect, but an -immediate reconnection is desired. Support a hint to userspace -that this is the case, by including a new attribute in the -deauth or disassoc event. - -Signed-off-by: Luca Coelho <luciano.coelho@intel.com> -Link: https://lore.kernel.org/r/iwlwifi.20201206145305.58d33941fb9d.I0e7168c205c7949529c8e3b86f3c9b12c01a7017@changeid -Signed-off-by: Johannes Berg <johannes.berg@intel.com> ---- - ---- a/include/net/cfg80211.h -+++ b/include/net/cfg80211.h -@@ -6410,13 +6410,15 @@ void cfg80211_abandon_assoc(struct net_d - * @dev: network device - * @buf: 802.11 frame (header + body) - * @len: length of the frame data -+ * @reconnect: immediate reconnect is desired (include the nl80211 attribute) - * - * This function is called whenever deauthentication has been processed in - * station mode. This includes both received deauthentication frames and - * locally generated ones. This function may sleep. The caller must hold the - * corresponding wdev's mutex. - */ --void cfg80211_tx_mlme_mgmt(struct net_device *dev, const u8 *buf, size_t len); -+void cfg80211_tx_mlme_mgmt(struct net_device *dev, const u8 *buf, size_t len, -+ bool reconnect); - - /** - * cfg80211_rx_unprot_mlme_mgmt - notification of unprotected mlme mgmt frame ---- a/net/mac80211/mlme.c -+++ b/net/mac80211/mlme.c -@@ -2734,7 +2734,7 @@ static void ieee80211_report_disconnect( - }; - - if (tx) -- cfg80211_tx_mlme_mgmt(sdata->dev, buf, len); -+ cfg80211_tx_mlme_mgmt(sdata->dev, buf, len, false); - else - cfg80211_rx_mlme_mgmt(sdata->dev, buf, len); - -@@ -4724,7 +4724,8 @@ void ieee80211_mgd_quiesce(struct ieee80 - if (ifmgd->auth_data) - ieee80211_destroy_auth_data(sdata, false); - cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf, -- IEEE80211_DEAUTH_FRAME_LEN); -+ IEEE80211_DEAUTH_FRAME_LEN, -+ false); - } - - /* This is a bit of a hack - we should find a better and more generic ---- a/net/wireless/mlme.c -+++ b/net/wireless/mlme.c -@@ -4,7 +4,7 @@ - * - * Copyright (c) 2009, Jouni Malinen <j@w1.fi> - * Copyright (c) 2015 Intel Deutschland GmbH -- * Copyright (C) 2019 Intel Corporation -+ * Copyright (C) 2019-2020 Intel Corporation - */ - - #include <linux/kernel.h> -@@ -81,7 +81,8 @@ static void cfg80211_process_auth(struct - } - - static void cfg80211_process_deauth(struct wireless_dev *wdev, -- const u8 *buf, size_t len) -+ const u8 *buf, size_t len, -+ bool reconnect) - { - struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); - struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; -@@ -89,7 +90,7 @@ static void cfg80211_process_deauth(stru - u16 reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); - bool from_ap = !ether_addr_equal(mgmt->sa, wdev->netdev->dev_addr); - -- nl80211_send_deauth(rdev, wdev->netdev, buf, len, GFP_KERNEL); -+ nl80211_send_deauth(rdev, wdev->netdev, buf, len, reconnect, GFP_KERNEL); - - if (!wdev->current_bss || - !ether_addr_equal(wdev->current_bss->pub.bssid, bssid)) -@@ -100,7 +101,8 @@ static void cfg80211_process_deauth(stru - } - - static void cfg80211_process_disassoc(struct wireless_dev *wdev, -- const u8 *buf, size_t len) -+ const u8 *buf, size_t len, -+ bool reconnect) - { - struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); - struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; -@@ -108,7 +110,8 @@ static void cfg80211_process_disassoc(st - u16 reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); - bool from_ap = !ether_addr_equal(mgmt->sa, wdev->netdev->dev_addr); - -- nl80211_send_disassoc(rdev, wdev->netdev, buf, len, GFP_KERNEL); -+ nl80211_send_disassoc(rdev, wdev->netdev, buf, len, reconnect, -+ GFP_KERNEL); - - if (WARN_ON(!wdev->current_bss || - !ether_addr_equal(wdev->current_bss->pub.bssid, bssid))) -@@ -133,9 +136,9 @@ void cfg80211_rx_mlme_mgmt(struct net_de - if (ieee80211_is_auth(mgmt->frame_control)) - cfg80211_process_auth(wdev, buf, len); - else if (ieee80211_is_deauth(mgmt->frame_control)) -- cfg80211_process_deauth(wdev, buf, len); -+ cfg80211_process_deauth(wdev, buf, len, false); - else if (ieee80211_is_disassoc(mgmt->frame_control)) -- cfg80211_process_disassoc(wdev, buf, len); -+ cfg80211_process_disassoc(wdev, buf, len, false); - } - EXPORT_SYMBOL(cfg80211_rx_mlme_mgmt); - -@@ -180,22 +183,23 @@ void cfg80211_abandon_assoc(struct net_d - } - EXPORT_SYMBOL(cfg80211_abandon_assoc); - --void cfg80211_tx_mlme_mgmt(struct net_device *dev, const u8 *buf, size_t len) -+void cfg80211_tx_mlme_mgmt(struct net_device *dev, const u8 *buf, size_t len, -+ bool reconnect) - { - struct wireless_dev *wdev = dev->ieee80211_ptr; - struct ieee80211_mgmt *mgmt = (void *)buf; - - ASSERT_WDEV_LOCK(wdev); - -- trace_cfg80211_tx_mlme_mgmt(dev, buf, len); -+ trace_cfg80211_tx_mlme_mgmt(dev, buf, len, reconnect); - - if (WARN_ON(len < 2)) - return; - - if (ieee80211_is_deauth(mgmt->frame_control)) -- cfg80211_process_deauth(wdev, buf, len); -+ cfg80211_process_deauth(wdev, buf, len, reconnect); - else -- cfg80211_process_disassoc(wdev, buf, len); -+ cfg80211_process_disassoc(wdev, buf, len, reconnect); - } - EXPORT_SYMBOL(cfg80211_tx_mlme_mgmt); - ---- a/net/wireless/nl80211.c -+++ b/net/wireless/nl80211.c -@@ -736,6 +736,7 @@ static const struct nla_policy nl80211_p - NLA_POLICY_EXACT_LEN(IEEE80211_S1G_CAPABILITY_LEN), - [NL80211_ATTR_S1G_CAPABILITY_MASK] = - NLA_POLICY_EXACT_LEN(IEEE80211_S1G_CAPABILITY_LEN), -+ [NL80211_ATTR_RECONNECT_REQUESTED] = { .type = NLA_REJECT }, - }; - - /* policy for the key attributes */ -@@ -15903,7 +15904,7 @@ static void nl80211_send_mlme_event(stru - const u8 *buf, size_t len, - enum nl80211_commands cmd, gfp_t gfp, - int uapsd_queues, const u8 *req_ies, -- size_t req_ies_len) -+ size_t req_ies_len, bool reconnect) - { - struct sk_buff *msg; - void *hdr; -@@ -15925,6 +15926,9 @@ static void nl80211_send_mlme_event(stru - nla_put(msg, NL80211_ATTR_REQ_IE, req_ies_len, req_ies))) - goto nla_put_failure; - -+ if (reconnect && nla_put_flag(msg, NL80211_ATTR_RECONNECT_REQUESTED)) -+ goto nla_put_failure; -+ - if (uapsd_queues >= 0) { - struct nlattr *nla_wmm = - nla_nest_start_noflag(msg, NL80211_ATTR_STA_WME); -@@ -15953,7 +15957,8 @@ void nl80211_send_rx_auth(struct cfg8021 - size_t len, gfp_t gfp) - { - nl80211_send_mlme_event(rdev, netdev, buf, len, -- NL80211_CMD_AUTHENTICATE, gfp, -1, NULL, 0); -+ NL80211_CMD_AUTHENTICATE, gfp, -1, NULL, 0, -+ false); - } - - void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev, -@@ -15963,23 +15968,25 @@ void nl80211_send_rx_assoc(struct cfg802 - { - nl80211_send_mlme_event(rdev, netdev, buf, len, - NL80211_CMD_ASSOCIATE, gfp, uapsd_queues, -- req_ies, req_ies_len); -+ req_ies, req_ies_len, false); - } - - void nl80211_send_deauth(struct cfg80211_registered_device *rdev, - struct net_device *netdev, const u8 *buf, -- size_t len, gfp_t gfp) -+ size_t len, bool reconnect, gfp_t gfp) - { - nl80211_send_mlme_event(rdev, netdev, buf, len, -- NL80211_CMD_DEAUTHENTICATE, gfp, -1, NULL, 0); -+ NL80211_CMD_DEAUTHENTICATE, gfp, -1, NULL, 0, -+ reconnect); - } - - void nl80211_send_disassoc(struct cfg80211_registered_device *rdev, - struct net_device *netdev, const u8 *buf, -- size_t len, gfp_t gfp) -+ size_t len, bool reconnect, gfp_t gfp) - { - nl80211_send_mlme_event(rdev, netdev, buf, len, -- NL80211_CMD_DISASSOCIATE, gfp, -1, NULL, 0); -+ NL80211_CMD_DISASSOCIATE, gfp, -1, NULL, 0, -+ reconnect); - } - - void cfg80211_rx_unprot_mlme_mgmt(struct net_device *dev, const u8 *buf, -@@ -16010,7 +16017,7 @@ void cfg80211_rx_unprot_mlme_mgmt(struct - - trace_cfg80211_rx_unprot_mlme_mgmt(dev, buf, len); - nl80211_send_mlme_event(rdev, dev, buf, len, cmd, GFP_ATOMIC, -1, -- NULL, 0); -+ NULL, 0, false); - } - EXPORT_SYMBOL(cfg80211_rx_unprot_mlme_mgmt); - ---- a/net/wireless/nl80211.h -+++ b/net/wireless/nl80211.h -@@ -1,7 +1,7 @@ - /* SPDX-License-Identifier: GPL-2.0 */ - /* - * Portions of this file -- * Copyright (C) 2018 Intel Corporation -+ * Copyright (C) 2018, 2020 Intel Corporation - */ - #ifndef __NET_WIRELESS_NL80211_H - #define __NET_WIRELESS_NL80211_H -@@ -69,10 +69,12 @@ void nl80211_send_rx_assoc(struct cfg802 - const u8 *req_ies, size_t req_ies_len); - void nl80211_send_deauth(struct cfg80211_registered_device *rdev, - struct net_device *netdev, -- const u8 *buf, size_t len, gfp_t gfp); -+ const u8 *buf, size_t len, -+ bool reconnect, gfp_t gfp); - void nl80211_send_disassoc(struct cfg80211_registered_device *rdev, - struct net_device *netdev, -- const u8 *buf, size_t len, gfp_t gfp); -+ const u8 *buf, size_t len, -+ bool reconnect, gfp_t gfp); - void nl80211_send_auth_timeout(struct cfg80211_registered_device *rdev, - struct net_device *netdev, - const u8 *addr, gfp_t gfp); ---- a/net/wireless/trace.h -+++ b/net/wireless/trace.h -@@ -2684,19 +2684,23 @@ DEFINE_EVENT(netdev_frame_event, cfg8021 - ); - - TRACE_EVENT(cfg80211_tx_mlme_mgmt, -- TP_PROTO(struct net_device *netdev, const u8 *buf, int len), -- TP_ARGS(netdev, buf, len), -+ TP_PROTO(struct net_device *netdev, const u8 *buf, int len, -+ bool reconnect), -+ TP_ARGS(netdev, buf, len, reconnect), - TP_STRUCT__entry( - NETDEV_ENTRY - __dynamic_array(u8, frame, len) -+ __field(int, reconnect) - ), - TP_fast_assign( - NETDEV_ASSIGN; - memcpy(__get_dynamic_array(frame), buf, len); -+ __entry->reconnect = reconnect; - ), -- TP_printk(NETDEV_PR_FMT ", ftype:0x%.2x", -+ TP_printk(NETDEV_PR_FMT ", ftype:0x%.2x reconnect:%d", - NETDEV_PR_ARG, -- le16_to_cpup((__le16 *)__get_dynamic_array(frame))) -+ le16_to_cpup((__le16 *)__get_dynamic_array(frame)), -+ __entry->reconnect) - ); - - DECLARE_EVENT_CLASS(netdev_mac_evt, diff --git a/package/kernel/mac80211/patches/subsys/304-mac80211-sta-randomize-BA-session-dialog-token-alloc.patch b/package/kernel/mac80211/patches/subsys/301-mac80211-sta-randomize-BA-session-dialog-token-alloc.patch index d09d70725e5..ffa5c17e487 100644 --- a/package/kernel/mac80211/patches/subsys/304-mac80211-sta-randomize-BA-session-dialog-token-alloc.patch +++ b/package/kernel/mac80211/patches/subsys/301-mac80211-sta-randomize-BA-session-dialog-token-alloc.patch @@ -28,7 +28,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com> --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c -@@ -357,6 +357,7 @@ struct sta_info *sta_info_alloc(struct i +@@ -558,6 +558,7 @@ __sta_info_alloc(struct ieee80211_sub_if INIT_WORK(&sta->drv_deliver_wk, sta_deliver_ps_frames); INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work); mutex_init(&sta->ampdu_mlme.mtx); diff --git a/package/kernel/mac80211/patches/subsys/301-mac80211-support-driver-based-disconnect-with-reconn.patch b/package/kernel/mac80211/patches/subsys/301-mac80211-support-driver-based-disconnect-with-reconn.patch deleted file mode 100644 index 31621ebf116..00000000000 --- a/package/kernel/mac80211/patches/subsys/301-mac80211-support-driver-based-disconnect-with-reconn.patch +++ /dev/null @@ -1,271 +0,0 @@ -From: Johannes Berg <johannes.berg@intel.com> -Date: Sun, 6 Dec 2020 14:54:43 +0200 -Subject: [PATCH] mac80211: support driver-based disconnect with reconnect hint - -Support the driver indicating that a disconnection needs -to be performed, and pass through the reconnect hint in -this case. - -Signed-off-by: Johannes Berg <johannes.berg@intel.com> -Signed-off-by: Luca Coelho <luciano.coelho@intel.com> -Link: https://lore.kernel.org/r/iwlwifi.20201206145305.5c8dab7a22a0.I58459fdf6968b16c90cab9c574f0f04ca22b0c79@changeid -Signed-off-by: Johannes Berg <johannes.berg@intel.com> ---- - ---- a/include/net/mac80211.h -+++ b/include/net/mac80211.h -@@ -5885,6 +5885,17 @@ void ieee80211_beacon_loss(struct ieee80 - void ieee80211_connection_loss(struct ieee80211_vif *vif); - - /** -+ * ieee80211_disconnect - request disconnection -+ * -+ * @vif: &struct ieee80211_vif pointer from the add_interface callback. -+ * @reconnect: immediate reconnect is desired -+ * -+ * Request disconnection from the current network and, if enabled, send a -+ * hint to the higher layers that immediate reconnect is desired. -+ */ -+void ieee80211_disconnect(struct ieee80211_vif *vif, bool reconnect); -+ -+/** - * ieee80211_resume_disconnect - disconnect from AP after resume - * - * @vif: &struct ieee80211_vif pointer from the add_interface callback. ---- a/net/mac80211/ieee80211_i.h -+++ b/net/mac80211/ieee80211_i.h -@@ -450,7 +450,9 @@ struct ieee80211_if_managed { - unsigned long probe_timeout; - int probe_send_count; - bool nullfunc_failed; -- bool connection_loss; -+ u8 connection_loss:1, -+ driver_disconnect:1, -+ reconnect:1; - - struct cfg80211_bss *associated; - struct ieee80211_mgd_auth_data *auth_data; ---- a/net/mac80211/mlme.c -+++ b/net/mac80211/mlme.c -@@ -2725,7 +2725,7 @@ EXPORT_SYMBOL(ieee80211_ap_probereq_get) - - static void ieee80211_report_disconnect(struct ieee80211_sub_if_data *sdata, - const u8 *buf, size_t len, bool tx, -- u16 reason) -+ u16 reason, bool reconnect) - { - struct ieee80211_event event = { - .type = MLME_EVENT, -@@ -2734,7 +2734,7 @@ static void ieee80211_report_disconnect( - }; - - if (tx) -- cfg80211_tx_mlme_mgmt(sdata->dev, buf, len, false); -+ cfg80211_tx_mlme_mgmt(sdata->dev, buf, len, reconnect); - else - cfg80211_rx_mlme_mgmt(sdata->dev, buf, len); - -@@ -2756,13 +2756,18 @@ static void __ieee80211_disconnect(struc - - tx = !sdata->csa_block_tx; - -- /* AP is probably out of range (or not reachable for another reason) so -- * remove the bss struct for that AP. -- */ -- cfg80211_unlink_bss(local->hw.wiphy, ifmgd->associated); -+ if (!ifmgd->driver_disconnect) { -+ /* -+ * AP is probably out of range (or not reachable for another -+ * reason) so remove the bss struct for that AP. -+ */ -+ cfg80211_unlink_bss(local->hw.wiphy, ifmgd->associated); -+ } - - ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, -- WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, -+ ifmgd->driver_disconnect ? -+ WLAN_REASON_DEAUTH_LEAVING : -+ WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, - tx, frame_buf); - mutex_lock(&local->mtx); - sdata->vif.csa_active = false; -@@ -2775,7 +2780,9 @@ static void __ieee80211_disconnect(struc - mutex_unlock(&local->mtx); - - ieee80211_report_disconnect(sdata, frame_buf, sizeof(frame_buf), tx, -- WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY); -+ WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, -+ ifmgd->reconnect); -+ ifmgd->reconnect = false; - - sdata_unlock(sdata); - } -@@ -2794,6 +2801,13 @@ static void ieee80211_beacon_connection_ - sdata_info(sdata, "Connection to AP %pM lost\n", - ifmgd->bssid); - __ieee80211_disconnect(sdata); -+ ifmgd->connection_loss = false; -+ } else if (ifmgd->driver_disconnect) { -+ sdata_info(sdata, -+ "Driver requested disconnection from AP %pM\n", -+ ifmgd->bssid); -+ __ieee80211_disconnect(sdata); -+ ifmgd->driver_disconnect = false; - } else { - ieee80211_mgd_probe_ap(sdata, true); - } -@@ -2832,6 +2846,21 @@ void ieee80211_connection_loss(struct ie - } - EXPORT_SYMBOL(ieee80211_connection_loss); - -+void ieee80211_disconnect(struct ieee80211_vif *vif, bool reconnect) -+{ -+ struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); -+ struct ieee80211_hw *hw = &sdata->local->hw; -+ -+ trace_api_disconnect(sdata, reconnect); -+ -+ if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION)) -+ return; -+ -+ sdata->u.mgd.driver_disconnect = true; -+ sdata->u.mgd.reconnect = reconnect; -+ ieee80211_queue_work(hw, &sdata->u.mgd.beacon_connection_loss_work); -+} -+EXPORT_SYMBOL(ieee80211_disconnect); - - static void ieee80211_destroy_auth_data(struct ieee80211_sub_if_data *sdata, - bool assoc) -@@ -3135,7 +3164,7 @@ static void ieee80211_rx_mgmt_deauth(str - ieee80211_set_disassoc(sdata, 0, 0, false, NULL); - - ieee80211_report_disconnect(sdata, (u8 *)mgmt, len, false, -- reason_code); -+ reason_code, false); - return; - } - -@@ -3184,7 +3213,8 @@ static void ieee80211_rx_mgmt_disassoc(s - - ieee80211_set_disassoc(sdata, 0, 0, false, NULL); - -- ieee80211_report_disconnect(sdata, (u8 *)mgmt, len, false, reason_code); -+ ieee80211_report_disconnect(sdata, (u8 *)mgmt, len, false, reason_code, -+ false); - } - - static void ieee80211_get_rates(struct ieee80211_supported_band *sband, -@@ -4204,7 +4234,8 @@ static void ieee80211_rx_mgmt_beacon(str - true, deauth_buf); - ieee80211_report_disconnect(sdata, deauth_buf, - sizeof(deauth_buf), true, -- WLAN_REASON_DEAUTH_LEAVING); -+ WLAN_REASON_DEAUTH_LEAVING, -+ false); - return; - } - -@@ -4349,7 +4380,7 @@ static void ieee80211_sta_connection_los - tx, frame_buf); - - ieee80211_report_disconnect(sdata, frame_buf, sizeof(frame_buf), true, -- reason); -+ reason, false); - } - - static int ieee80211_auth(struct ieee80211_sub_if_data *sdata) -@@ -5439,7 +5470,8 @@ int ieee80211_mgd_auth(struct ieee80211_ - - ieee80211_report_disconnect(sdata, frame_buf, - sizeof(frame_buf), true, -- WLAN_REASON_UNSPECIFIED); -+ WLAN_REASON_UNSPECIFIED, -+ false); - } - - sdata_info(sdata, "authenticate with %pM\n", req->bss->bssid); -@@ -5511,7 +5543,8 @@ int ieee80211_mgd_assoc(struct ieee80211 - - ieee80211_report_disconnect(sdata, frame_buf, - sizeof(frame_buf), true, -- WLAN_REASON_UNSPECIFIED); -+ WLAN_REASON_UNSPECIFIED, -+ false); - } - - if (ifmgd->auth_data && !ifmgd->auth_data->done) { -@@ -5810,7 +5843,7 @@ int ieee80211_mgd_deauth(struct ieee8021 - ieee80211_destroy_auth_data(sdata, false); - ieee80211_report_disconnect(sdata, frame_buf, - sizeof(frame_buf), true, -- req->reason_code); -+ req->reason_code, false); - - return 0; - } -@@ -5830,7 +5863,7 @@ int ieee80211_mgd_deauth(struct ieee8021 - ieee80211_destroy_assoc_data(sdata, false, true); - ieee80211_report_disconnect(sdata, frame_buf, - sizeof(frame_buf), true, -- req->reason_code); -+ req->reason_code, false); - return 0; - } - -@@ -5845,7 +5878,7 @@ int ieee80211_mgd_deauth(struct ieee8021 - req->reason_code, tx, frame_buf); - ieee80211_report_disconnect(sdata, frame_buf, - sizeof(frame_buf), true, -- req->reason_code); -+ req->reason_code, false); - return 0; - } - -@@ -5878,7 +5911,7 @@ int ieee80211_mgd_disassoc(struct ieee80 - frame_buf); - - ieee80211_report_disconnect(sdata, frame_buf, sizeof(frame_buf), true, -- req->reason_code); -+ req->reason_code, false); - - return 0; - } ---- a/net/mac80211/trace.h -+++ b/net/mac80211/trace.h -@@ -2,7 +2,7 @@ - /* - * Portions of this file - * Copyright(c) 2016-2017 Intel Deutschland GmbH --* Copyright (C) 2018 - 2019 Intel Corporation -+* Copyright (C) 2018 - 2020 Intel Corporation - */ - - #if !defined(__MAC80211_DRIVER_TRACE) || defined(TRACE_HEADER_MULTI_READ) -@@ -2086,6 +2086,27 @@ TRACE_EVENT(api_connection_loss, - ) - ); - -+TRACE_EVENT(api_disconnect, -+ TP_PROTO(struct ieee80211_sub_if_data *sdata, bool reconnect), -+ -+ TP_ARGS(sdata, reconnect), -+ -+ TP_STRUCT__entry( -+ VIF_ENTRY -+ __field(int, reconnect) -+ ), -+ -+ TP_fast_assign( -+ VIF_ASSIGN; -+ __entry->reconnect = reconnect; -+ ), -+ -+ TP_printk( -+ VIF_PR_FMT " reconnect:%d", -+ VIF_PR_ARG, __entry->reconnect -+ ) -+); -+ - TRACE_EVENT(api_cqm_rssi_notify, - TP_PROTO(struct ieee80211_sub_if_data *sdata, - enum nl80211_cqm_rssi_threshold_event rssi_event, diff --git a/package/kernel/mac80211/patches/subsys/302-cfg80211-Add-support-to-configure-SAE-PWE-value-to-d.patch b/package/kernel/mac80211/patches/subsys/302-cfg80211-Add-support-to-configure-SAE-PWE-value-to-d.patch deleted file mode 100644 index acfdae0f5b0..00000000000 --- a/package/kernel/mac80211/patches/subsys/302-cfg80211-Add-support-to-configure-SAE-PWE-value-to-d.patch +++ /dev/null @@ -1,74 +0,0 @@ -From: Rohan Dutta <drohan@codeaurora.org> -Date: Tue, 27 Oct 2020 12:09:10 +0200 -Subject: [PATCH] cfg80211: Add support to configure SAE PWE value to drivers - -Add support to configure SAE PWE preference from userspace to drivers in -both AP and STA modes. This is needed for cases where the driver takes -care of Authentication frame processing (SME in the driver) so that -correct enforcement of the acceptable PWE derivation mechanism can be -performed. - -The userspace applications can pass the sae_pwe value using the -NL80211_ATTR_SAE_PWE attribute in the NL80211_CMD_CONNECT and -NL80211_CMD_START_AP commands to the driver. This allows selection -between the hunting-and-pecking loop and hash-to-element options for PWE -derivation. For backwards compatibility, this new attribute is optional -and if not included, the driver is notified of the value being -unspecified. - -Signed-off-by: Rohan Dutta <drohan@codeaurora.org> -Signed-off-by: Jouni Malinen <jouni@codeaurora.org> -Link: https://lore.kernel.org/r/20201027100910.22283-1-jouni@codeaurora.org -Signed-off-by: Johannes Berg <johannes.berg@intel.com> ---- - ---- a/include/net/cfg80211.h -+++ b/include/net/cfg80211.h -@@ -1009,6 +1009,14 @@ struct survey_info { - * @sae_pwd: password for SAE authentication (for devices supporting SAE - * offload) - * @sae_pwd_len: length of SAE password (for devices supporting SAE offload) -+ * @sae_pwe: The mechanisms allowed for SAE PWE derivation -+ * NL80211_SAE_PWE_UNSPECIFIED: Not-specified, used to indicate userspace -+ * did not specify any preference. The driver should follow its -+ * internal policy in such a scenario. -+ * NL80211_SAE_PWE_HUNT_AND_PECK: Allow hunting-and-pecking loop only -+ * NL80211_SAE_PWE_HASH_TO_ELEMENT: Allow hash-to-element only -+ * NL80211_SAE_PWE_BOTH: Allow either hunting-and-pecking loop -+ * or hash-to-element - */ - struct cfg80211_crypto_settings { - u32 wpa_versions; -@@ -1027,6 +1035,7 @@ struct cfg80211_crypto_settings { - const u8 *psk; - const u8 *sae_pwd; - u8 sae_pwd_len; -+ enum nl80211_sae_pwe_mechanism sae_pwe; - }; - - /** ---- a/net/wireless/nl80211.c -+++ b/net/wireless/nl80211.c -@@ -736,6 +736,9 @@ static const struct nla_policy nl80211_p - NLA_POLICY_EXACT_LEN(IEEE80211_S1G_CAPABILITY_LEN), - [NL80211_ATTR_S1G_CAPABILITY_MASK] = - NLA_POLICY_EXACT_LEN(IEEE80211_S1G_CAPABILITY_LEN), -+ [NL80211_ATTR_SAE_PWE] = -+ NLA_POLICY_RANGE(NLA_U8, NL80211_SAE_PWE_HUNT_AND_PECK, -+ NL80211_SAE_PWE_BOTH), - [NL80211_ATTR_RECONNECT_REQUESTED] = { .type = NLA_REJECT }, - }; - -@@ -9764,6 +9767,12 @@ static int nl80211_crypto_settings(struc - nla_len(info->attrs[NL80211_ATTR_SAE_PASSWORD]); - } - -+ if (info->attrs[NL80211_ATTR_SAE_PWE]) -+ settings->sae_pwe = -+ nla_get_u8(info->attrs[NL80211_ATTR_SAE_PWE]); -+ else -+ settings->sae_pwe = NL80211_SAE_PWE_UNSPECIFIED; -+ - return 0; - } - diff --git a/package/kernel/mac80211/patches/subsys/353-mac80211-minstrel_ht-fix-MINSTREL_FRAC-macro.patch b/package/kernel/mac80211/patches/subsys/302-mac80211-minstrel_ht-fix-MINSTREL_FRAC-macro.patch index 0d475b73297..0d475b73297 100644 --- a/package/kernel/mac80211/patches/subsys/353-mac80211-minstrel_ht-fix-MINSTREL_FRAC-macro.patch +++ b/package/kernel/mac80211/patches/subsys/302-mac80211-minstrel_ht-fix-MINSTREL_FRAC-macro.patch diff --git a/package/kernel/mac80211/patches/subsys/354-mac80211-minstrel_ht-reduce-fluctuations-in-rate-pro.patch b/package/kernel/mac80211/patches/subsys/303-mac80211-minstrel_ht-reduce-fluctuations-in-rate-pro.patch index 16bcbc2ef91..f26477e8112 100644 --- a/package/kernel/mac80211/patches/subsys/354-mac80211-minstrel_ht-reduce-fluctuations-in-rate-pro.patch +++ b/package/kernel/mac80211/patches/subsys/303-mac80211-minstrel_ht-reduce-fluctuations-in-rate-pro.patch @@ -18,7 +18,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name> --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c -@@ -700,7 +700,8 @@ minstrel_ht_calc_rate_stats(struct minst +@@ -769,7 +769,8 @@ minstrel_ht_calc_rate_stats(struct minst unsigned int cur_prob; if (unlikely(mrs->attempts > 0)) { diff --git a/package/kernel/mac80211/patches/subsys/355-mac80211-minstrel_ht-rework-rate-downgrade-code-and-.patch b/package/kernel/mac80211/patches/subsys/304-mac80211-minstrel_ht-rework-rate-downgrade-code-and-.patch index aec2e077812..9b3cc3a664a 100644 --- a/package/kernel/mac80211/patches/subsys/355-mac80211-minstrel_ht-rework-rate-downgrade-code-and-.patch +++ b/package/kernel/mac80211/patches/subsys/304-mac80211-minstrel_ht-rework-rate-downgrade-code-and-.patch @@ -18,7 +18,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name> --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c -@@ -511,6 +511,14 @@ minstrel_ht_set_best_prob_rate(struct mi +@@ -580,6 +580,14 @@ minstrel_ht_set_best_prob_rate(struct mi int cur_tp_avg, cur_group, cur_idx; int max_gpr_group, max_gpr_idx; int max_gpr_tp_avg, max_gpr_prob; @@ -33,7 +33,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name> cur_group = MI_RATE_GROUP(index); cur_idx = MI_RATE_IDX(index); -@@ -532,11 +540,6 @@ minstrel_ht_set_best_prob_rate(struct mi +@@ -601,11 +609,6 @@ minstrel_ht_set_best_prob_rate(struct mi !minstrel_ht_is_legacy_group(max_tp_group)) return; @@ -45,7 +45,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name> max_gpr_group = MI_RATE_GROUP(mg->max_group_prob_rate); max_gpr_idx = MI_RATE_IDX(mg->max_group_prob_rate); max_gpr_prob = mi->groups[max_gpr_group].rates[max_gpr_idx].prob_avg; -@@ -594,40 +597,6 @@ minstrel_ht_assign_best_tp_rates(struct +@@ -663,40 +666,6 @@ minstrel_ht_assign_best_tp_rates(struct } @@ -60,7 +60,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name> - int tmp_max_streams, group, tmp_idx, tmp_prob; - int tmp_tp = 0; - -- if (!mi->sta->ht_cap.ht_supported) +- if (!mi->sta->deflink.ht_cap.ht_supported) - return; - - group = MI_RATE_GROUP(mi->max_tp_rate[0]); @@ -86,7 +86,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name> static u16 __minstrel_ht_get_sample_rate(struct minstrel_ht_sta *mi, enum minstrel_sample_type type) -@@ -1111,8 +1080,6 @@ minstrel_ht_update_stats(struct minstrel +@@ -1176,8 +1145,6 @@ minstrel_ht_update_stats(struct minstrel mi->max_prob_rate = tmp_max_prob_rate; @@ -95,7 +95,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name> minstrel_ht_refill_sample_rates(mi); #ifdef CPTCFG_MAC80211_DEBUGFS -@@ -1157,7 +1124,7 @@ minstrel_ht_txstat_valid(struct minstrel +@@ -1256,7 +1223,7 @@ minstrel_ht_ri_txstat_valid(struct minst } static void @@ -104,7 +104,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name> { int group, orig_group; -@@ -1172,11 +1139,7 @@ minstrel_downgrade_rate(struct minstrel_ +@@ -1271,11 +1238,7 @@ minstrel_downgrade_rate(struct minstrel_ minstrel_mcs_groups[orig_group].streams) continue; @@ -117,7 +117,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name> } } -@@ -1210,7 +1173,7 @@ minstrel_ht_tx_status(void *priv, struct +@@ -1286,7 +1249,7 @@ minstrel_ht_tx_status(void *priv, struct struct ieee80211_tx_info *info = st->info; struct minstrel_ht_sta *mi = priv_sta; struct ieee80211_tx_rate *ar = info->status.rates; @@ -126,7 +126,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name> struct minstrel_priv *mp = priv; u32 update_interval = mp->update_interval; bool last, update = false; -@@ -1256,18 +1219,13 @@ minstrel_ht_tx_status(void *priv, struct +@@ -1354,18 +1317,13 @@ minstrel_ht_tx_status(void *priv, struct /* * check for sudden death of spatial multiplexing, * downgrade to a lower number of streams if necessary. diff --git a/package/kernel/mac80211/patches/subsys/305-mac80211-increase-quantum-for-airtime-scheduler.patch b/package/kernel/mac80211/patches/subsys/305-mac80211-increase-quantum-for-airtime-scheduler.patch new file mode 100644 index 00000000000..a27925e64ee --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/305-mac80211-increase-quantum-for-airtime-scheduler.patch @@ -0,0 +1,53 @@ +From: Felix Fietkau <nbd@nbd.name> +Date: Sun, 26 Jun 2022 11:43:25 +0200 +Subject: [PATCH] mac80211: increase quantum for airtime scheduler + +Given the typical AQL budget and queue length, a quantum of 256 with the +default station weight often requires iterating over all queues frequently, +until one of them becomes eligible. +Improve performance by using 8 times station weight as scheduler quantum + +Signed-off-by: Felix Fietkau <nbd@nbd.name> +--- + +--- a/net/mac80211/ieee80211_i.h ++++ b/net/mac80211/ieee80211_i.h +@@ -92,6 +92,8 @@ extern const u8 ieee80211_ac_to_qos_mask + */ + #define AIRTIME_ACTIVE_DURATION (HZ / 10) + ++#define AIRTIME_QUANTUM_SHIFT 3 ++ + struct ieee80211_bss { + u32 device_ts_beacon, device_ts_presp; + +--- a/net/mac80211/tx.c ++++ b/net/mac80211/tx.c +@@ -4059,7 +4059,7 @@ struct ieee80211_txq *ieee80211_next_txq + + if (deficit < 0) + sta->airtime[txqi->txq.ac].deficit += +- sta->airtime_weight; ++ sta->airtime_weight << AIRTIME_QUANTUM_SHIFT; + + if (deficit < 0 || !aql_check) { + list_move_tail(&txqi->schedule_order, +@@ -4202,7 +4202,8 @@ bool ieee80211_txq_may_transmit(struct i + } + sta = container_of(iter->txq.sta, struct sta_info, sta); + if (ieee80211_sta_deficit(sta, ac) < 0) +- sta->airtime[ac].deficit += sta->airtime_weight; ++ sta->airtime[ac].deficit += sta->airtime_weight << ++ AIRTIME_QUANTUM_SHIFT; + list_move_tail(&iter->schedule_order, &local->active_txqs[ac]); + } + +@@ -4210,7 +4211,7 @@ bool ieee80211_txq_may_transmit(struct i + if (sta->airtime[ac].deficit >= 0) + goto out; + +- sta->airtime[ac].deficit += sta->airtime_weight; ++ sta->airtime[ac].deficit += sta->airtime_weight << AIRTIME_QUANTUM_SHIFT; + list_move_tail(&txqi->schedule_order, &local->active_txqs[ac]); + spin_unlock_bh(&local->active_txq_lock[ac]); + diff --git a/package/kernel/mac80211/patches/subsys/310-mac80211-split-mesh-fast-tx-cache-into-local-proxied.patch b/package/kernel/mac80211/patches/subsys/310-mac80211-split-mesh-fast-tx-cache-into-local-proxied.patch new file mode 100644 index 00000000000..f362751e0a3 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/310-mac80211-split-mesh-fast-tx-cache-into-local-proxied.patch @@ -0,0 +1,219 @@ +From: Felix Fietkau <nbd@nbd.name> +Date: Fri, 30 Jun 2023 13:11:51 +0200 +Subject: [PATCH] mac80211: split mesh fast tx cache into + local/proxied/forwarded + +Depending on the origin of the packets (and their SA), 802.11 + mesh headers +could be filled in differently. In order to properly deal with that, add a +new field to the lookup key, indicating the type (local, proxied or +forwarded). This can fix spurious packet drop issues that depend on the order +in which nodes/hosts communicate with each other. + +Signed-off-by: Felix Fietkau <nbd@nbd.name> +--- + +--- a/net/mac80211/mesh.c ++++ b/net/mac80211/mesh.c +@@ -765,6 +765,9 @@ bool ieee80211_mesh_xmit_fast(struct iee + struct sk_buff *skb, u32 ctrl_flags) + { + struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; ++ struct ieee80211_mesh_fast_tx_key key = { ++ .type = MESH_FAST_TX_TYPE_LOCAL ++ }; + struct ieee80211_mesh_fast_tx *entry; + struct ieee80211s_hdr *meshhdr; + u8 sa[ETH_ALEN] __aligned(2); +@@ -800,7 +803,10 @@ bool ieee80211_mesh_xmit_fast(struct iee + return false; + } + +- entry = mesh_fast_tx_get(sdata, skb->data); ++ ether_addr_copy(key.addr, skb->data); ++ if (!ether_addr_equal(skb->data + ETH_ALEN, sdata->vif.addr)) ++ key.type = MESH_FAST_TX_TYPE_PROXIED; ++ entry = mesh_fast_tx_get(sdata, &key); + if (!entry) + return false; + +--- a/net/mac80211/mesh.h ++++ b/net/mac80211/mesh.h +@@ -134,9 +134,33 @@ struct mesh_path { + #define MESH_FAST_TX_CACHE_TIMEOUT 8000 /* msecs */ + + /** ++ * enum ieee80211_mesh_fast_tx_type - cached mesh fast tx entry type ++ * ++ * @MESH_FAST_TX_TYPE_LOCAL: tx from the local vif address as SA ++ * @MESH_FAST_TX_TYPE_PROXIED: local tx with a different SA (e.g. bridged) ++ * @MESH_FAST_TX_TYPE_FORWARDED: forwarded from a different mesh point ++ */ ++enum ieee80211_mesh_fast_tx_type { ++ MESH_FAST_TX_TYPE_LOCAL, ++ MESH_FAST_TX_TYPE_PROXIED, ++ MESH_FAST_TX_TYPE_FORWARDED, ++}; ++ ++/** ++ * struct ieee80211_mesh_fast_tx_key - cached mesh fast tx entry key ++ * ++ * @addr: The Ethernet DA for this entry ++ * @type: cache entry type ++ */ ++struct ieee80211_mesh_fast_tx_key { ++ u8 addr[ETH_ALEN] __aligned(2); ++ enum ieee80211_mesh_fast_tx_type type; ++}; ++ ++/** + * struct ieee80211_mesh_fast_tx - cached mesh fast tx entry + * @rhash: rhashtable pointer +- * @addr_key: The Ethernet DA which is the key for this entry ++ * @key: the lookup key for this cache entry + * @fast_tx: base fast_tx data + * @hdr: cached mesh and rfc1042 headers + * @hdrlen: length of mesh + rfc1042 +@@ -147,7 +171,7 @@ struct mesh_path { + */ + struct ieee80211_mesh_fast_tx { + struct rhash_head rhash; +- u8 addr_key[ETH_ALEN] __aligned(2); ++ struct ieee80211_mesh_fast_tx_key key; + + struct ieee80211_fast_tx fast_tx; + u8 hdr[sizeof(struct ieee80211s_hdr) + sizeof(rfc1042_header)]; +@@ -334,7 +358,8 @@ void mesh_path_tx_root_frame(struct ieee + + bool mesh_action_is_path_sel(struct ieee80211_mgmt *mgmt); + struct ieee80211_mesh_fast_tx * +-mesh_fast_tx_get(struct ieee80211_sub_if_data *sdata, const u8 *addr); ++mesh_fast_tx_get(struct ieee80211_sub_if_data *sdata, ++ struct ieee80211_mesh_fast_tx_key *key); + bool ieee80211_mesh_xmit_fast(struct ieee80211_sub_if_data *sdata, + struct sk_buff *skb, u32 ctrl_flags); + void mesh_fast_tx_cache(struct ieee80211_sub_if_data *sdata, +--- a/net/mac80211/mesh_pathtbl.c ++++ b/net/mac80211/mesh_pathtbl.c +@@ -36,8 +36,8 @@ static const struct rhashtable_params me + static const struct rhashtable_params fast_tx_rht_params = { + .nelem_hint = 10, + .automatic_shrinking = true, +- .key_len = ETH_ALEN, +- .key_offset = offsetof(struct ieee80211_mesh_fast_tx, addr_key), ++ .key_len = sizeof(struct ieee80211_mesh_fast_tx_key), ++ .key_offset = offsetof(struct ieee80211_mesh_fast_tx, key), + .head_offset = offsetof(struct ieee80211_mesh_fast_tx, rhash), + .hashfn = mesh_table_hash, + }; +@@ -426,20 +426,21 @@ static void mesh_fast_tx_entry_free(stru + } + + struct ieee80211_mesh_fast_tx * +-mesh_fast_tx_get(struct ieee80211_sub_if_data *sdata, const u8 *addr) ++mesh_fast_tx_get(struct ieee80211_sub_if_data *sdata, ++ struct ieee80211_mesh_fast_tx_key *key) + { + struct ieee80211_mesh_fast_tx *entry; + struct mesh_tx_cache *cache; + + cache = &sdata->u.mesh.tx_cache; +- entry = rhashtable_lookup(&cache->rht, addr, fast_tx_rht_params); ++ entry = rhashtable_lookup(&cache->rht, key, fast_tx_rht_params); + if (!entry) + return NULL; + + if (!(entry->mpath->flags & MESH_PATH_ACTIVE) || + mpath_expired(entry->mpath)) { + spin_lock_bh(&cache->walk_lock); +- entry = rhashtable_lookup(&cache->rht, addr, fast_tx_rht_params); ++ entry = rhashtable_lookup(&cache->rht, key, fast_tx_rht_params); + if (entry) + mesh_fast_tx_entry_free(cache, entry); + spin_unlock_bh(&cache->walk_lock); +@@ -484,18 +485,24 @@ void mesh_fast_tx_cache(struct ieee80211 + if (!sta) + return; + ++ build.key.type = MESH_FAST_TX_TYPE_LOCAL; + if ((meshhdr->flags & MESH_FLAGS_AE) == MESH_FLAGS_AE_A5_A6) { + /* This is required to keep the mppath alive */ + mppath = mpp_path_lookup(sdata, meshhdr->eaddr1); + if (!mppath) + return; + build.mppath = mppath; ++ if (!ether_addr_equal(meshhdr->eaddr2, sdata->vif.addr)) ++ build.key.type = MESH_FAST_TX_TYPE_PROXIED; + } else if (ieee80211_has_a4(hdr->frame_control)) { + mppath = mpath; + } else { + return; + } + ++ if (!ether_addr_equal(hdr->addr4, sdata->vif.addr)) ++ build.key.type = MESH_FAST_TX_TYPE_FORWARDED; ++ + /* rate limit, in case fast xmit can't be enabled */ + if (mppath->fast_tx_check == jiffies) + return; +@@ -542,7 +549,7 @@ void mesh_fast_tx_cache(struct ieee80211 + } + } + +- memcpy(build.addr_key, mppath->dst, ETH_ALEN); ++ memcpy(build.key.addr, mppath->dst, ETH_ALEN); + build.timestamp = jiffies; + build.fast_tx.band = info->band; + build.fast_tx.da_offs = offsetof(struct ieee80211_hdr, addr3); +@@ -644,13 +651,19 @@ void mesh_fast_tx_flush_addr(struct ieee + const u8 *addr) + { + struct mesh_tx_cache *cache = &sdata->u.mesh.tx_cache; ++ struct ieee80211_mesh_fast_tx_key key = {}; + struct ieee80211_mesh_fast_tx *entry; ++ int i; + ++ ether_addr_copy(key.addr, addr); + cache = &sdata->u.mesh.tx_cache; + spin_lock_bh(&cache->walk_lock); +- entry = rhashtable_lookup(&cache->rht, addr, fast_tx_rht_params); +- if (entry) +- mesh_fast_tx_entry_free(cache, entry); ++ for (i = MESH_FAST_TX_TYPE_LOCAL; i < MESH_FAST_TX_TYPE_FORWARDED; i++) { ++ key.type = i; ++ entry = rhashtable_lookup(&cache->rht, &key, fast_tx_rht_params); ++ if (entry) ++ mesh_fast_tx_entry_free(cache, entry); ++ } + spin_unlock_bh(&cache->walk_lock); + } + +--- a/net/mac80211/rx.c ++++ b/net/mac80211/rx.c +@@ -2727,7 +2727,10 @@ ieee80211_rx_mesh_fast_forward(struct ie + struct sk_buff *skb, int hdrlen) + { + struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; +- struct ieee80211_mesh_fast_tx *entry = NULL; ++ struct ieee80211_mesh_fast_tx_key key = { ++ .type = MESH_FAST_TX_TYPE_FORWARDED ++ }; ++ struct ieee80211_mesh_fast_tx *entry; + struct ieee80211s_hdr *mesh_hdr; + struct tid_ampdu_tx *tid_tx; + struct sta_info *sta; +@@ -2736,9 +2739,13 @@ ieee80211_rx_mesh_fast_forward(struct ie + + mesh_hdr = (struct ieee80211s_hdr *)(skb->data + sizeof(eth)); + if ((mesh_hdr->flags & MESH_FLAGS_AE) == MESH_FLAGS_AE_A5_A6) +- entry = mesh_fast_tx_get(sdata, mesh_hdr->eaddr1); ++ ether_addr_copy(key.addr, mesh_hdr->eaddr1); + else if (!(mesh_hdr->flags & MESH_FLAGS_AE)) +- entry = mesh_fast_tx_get(sdata, skb->data); ++ ether_addr_copy(key.addr, skb->data); ++ else ++ return false; ++ ++ entry = mesh_fast_tx_get(sdata, &key); + if (!entry) + return false; + diff --git a/package/kernel/mac80211/patches/subsys/310-net-fq_impl-bulk-free-packets-from-a-flow-on-overmem.patch b/package/kernel/mac80211/patches/subsys/310-net-fq_impl-bulk-free-packets-from-a-flow-on-overmem.patch deleted file mode 100644 index 05a888006e2..00000000000 --- a/package/kernel/mac80211/patches/subsys/310-net-fq_impl-bulk-free-packets-from-a-flow-on-overmem.patch +++ /dev/null @@ -1,95 +0,0 @@ -From: Felix Fietkau <nbd@nbd.name> -Date: Wed, 25 Nov 2020 18:03:46 +0100 -Subject: [PATCH] net/fq_impl: bulk-free packets from a flow on overmemory - -This is similar to what sch_fq_codel does. It also amortizes the worst -case cost of a follow-up patch that changes the selection of the biggest -flow for dropping packets - -Signed-off-by: Felix Fietkau <nbd@nbd.name> ---- - ---- a/include/net/fq_impl.h -+++ b/include/net/fq_impl.h -@@ -11,17 +11,25 @@ - - /* functions that are embedded into includer */ - -+ -+static void -+__fq_adjust_removal(struct fq *fq, struct fq_flow *flow, unsigned int packets, -+ unsigned int bytes, unsigned int truesize) -+{ -+ struct fq_tin *tin = flow->tin; -+ -+ tin->backlog_bytes -= bytes; -+ tin->backlog_packets -= packets; -+ flow->backlog -= bytes; -+ fq->backlog -= packets; -+ fq->memory_usage -= truesize; -+} -+ - static void fq_adjust_removal(struct fq *fq, - struct fq_flow *flow, - struct sk_buff *skb) - { -- struct fq_tin *tin = flow->tin; -- -- tin->backlog_bytes -= skb->len; -- tin->backlog_packets--; -- flow->backlog -= skb->len; -- fq->backlog--; -- fq->memory_usage -= skb->truesize; -+ __fq_adjust_removal(fq, flow, 1, skb->len, skb->truesize); - } - - static void fq_rejigger_backlog(struct fq *fq, struct fq_flow *flow) -@@ -59,6 +67,34 @@ static struct sk_buff *fq_flow_dequeue(s - return skb; - } - -+static int fq_flow_drop(struct fq *fq, struct fq_flow *flow, -+ fq_skb_free_t free_func) -+{ -+ unsigned int packets = 0, bytes = 0, truesize = 0; -+ struct fq_tin *tin = flow->tin; -+ struct sk_buff *skb; -+ int pending; -+ -+ lockdep_assert_held(&fq->lock); -+ -+ pending = min_t(int, 32, skb_queue_len(&flow->queue) / 2); -+ do { -+ skb = __skb_dequeue(&flow->queue); -+ if (!skb) -+ break; -+ -+ packets++; -+ bytes += skb->len; -+ truesize += skb->truesize; -+ free_func(fq, tin, flow, skb); -+ } while (packets < pending); -+ -+ __fq_adjust_removal(fq, flow, packets, bytes, truesize); -+ fq_rejigger_backlog(fq, flow); -+ -+ return packets; -+} -+ - static struct sk_buff *fq_tin_dequeue(struct fq *fq, - struct fq_tin *tin, - fq_tin_dequeue_t dequeue_func) -@@ -190,12 +226,9 @@ static void fq_tin_enqueue(struct fq *fq - if (!flow) - return; - -- skb = fq_flow_dequeue(fq, flow); -- if (!skb) -+ if (!fq_flow_drop(fq, flow, free_func)) - return; - -- free_func(fq, flow->tin, flow, skb); -- - flow->tin->overlimit++; - fq->overlimit++; - if (oom) { diff --git a/package/kernel/mac80211/patches/subsys/311-mac80211-fix-mesh-id-corruption-on-32-bit-systems.patch b/package/kernel/mac80211/patches/subsys/311-mac80211-fix-mesh-id-corruption-on-32-bit-systems.patch new file mode 100644 index 00000000000..c0c774a89d5 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/311-mac80211-fix-mesh-id-corruption-on-32-bit-systems.patch @@ -0,0 +1,62 @@ +From: Felix Fietkau <nbd@nbd.name> +Date: Tue, 12 Sep 2023 15:09:27 +0200 +Subject: [PATCH] mac80211: fix mesh id corruption on 32 bit systems +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Since the changed field size was increased to u64, mesh_bss_info_changed +pulls invalid bits from the first 3 bytes of the mesh id, clears them, and +passes them on to ieee80211_link_info_change_notify, because +ifmsh->mbss_changed was not updated to match its size. +Fix this by turning into ifmsh->mbss_changed into an unsigned long array with +64 bit size. + +Fixes: 15ddba5f4311 ("wifi: mac80211: consistently use u64 for BSS changes") +Reported-by: Thomas Hühn <thomas.huehn@hs-nordhausen.de> +Signed-off-by: Felix Fietkau <nbd@nbd.name> +--- + +--- a/net/mac80211/ieee80211_i.h ++++ b/net/mac80211/ieee80211_i.h +@@ -678,7 +678,7 @@ struct ieee80211_if_mesh { + struct timer_list mesh_path_root_timer; + + unsigned long wrkq_flags; +- unsigned long mbss_changed; ++ unsigned long mbss_changed[64 / BITS_PER_LONG]; + + bool userspace_handles_dfs; + +--- a/net/mac80211/mesh.c ++++ b/net/mac80211/mesh.c +@@ -1181,7 +1181,7 @@ void ieee80211_mbss_info_change_notify(s + + /* if we race with running work, worst case this work becomes a noop */ + for_each_set_bit(bit, &bits, sizeof(changed) * BITS_PER_BYTE) +- set_bit(bit, &ifmsh->mbss_changed); ++ set_bit(bit, ifmsh->mbss_changed); + set_bit(MESH_WORK_MBSS_CHANGED, &ifmsh->wrkq_flags); + wiphy_work_queue(sdata->local->hw.wiphy, &sdata->work); + } +@@ -1263,7 +1263,7 @@ void ieee80211_stop_mesh(struct ieee8021 + + /* clear any mesh work (for next join) we may have accrued */ + ifmsh->wrkq_flags = 0; +- ifmsh->mbss_changed = 0; ++ memset(ifmsh->mbss_changed, 0, sizeof(ifmsh->mbss_changed)); + + local->fif_other_bss--; + atomic_dec(&local->iff_allmultis); +@@ -1730,9 +1730,9 @@ static void mesh_bss_info_changed(struct + u32 bit; + u64 changed = 0; + +- for_each_set_bit(bit, &ifmsh->mbss_changed, ++ for_each_set_bit(bit, ifmsh->mbss_changed, + sizeof(changed) * BITS_PER_BYTE) { +- clear_bit(bit, &ifmsh->mbss_changed); ++ clear_bit(bit, ifmsh->mbss_changed); + changed |= BIT(bit); + } + diff --git a/package/kernel/mac80211/patches/subsys/311-net-fq_impl-drop-get_default_func-move-default-flow-.patch b/package/kernel/mac80211/patches/subsys/311-net-fq_impl-drop-get_default_func-move-default-flow-.patch deleted file mode 100644 index 33dbb5eb905..00000000000 --- a/package/kernel/mac80211/patches/subsys/311-net-fq_impl-drop-get_default_func-move-default-flow-.patch +++ /dev/null @@ -1,144 +0,0 @@ -From: Felix Fietkau <nbd@nbd.name> -Date: Wed, 25 Nov 2020 18:09:10 +0100 -Subject: [PATCH] net/fq_impl: drop get_default_func, move default flow to - fq_tin - -Simplifies the code and prepares for a rework of scanning for flows on -overmemory drop. - -Signed-off-by: Felix Fietkau <nbd@nbd.name> ---- - ---- a/include/net/fq.h -+++ b/include/net/fq.h -@@ -47,6 +47,7 @@ struct fq_flow { - struct fq_tin { - struct list_head new_flows; - struct list_head old_flows; -+ struct fq_flow default_flow; - u32 backlog_bytes; - u32 backlog_packets; - u32 overlimit; ---- a/include/net/fq_impl.h -+++ b/include/net/fq_impl.h -@@ -151,8 +151,7 @@ static u32 fq_flow_idx(struct fq *fq, st - - static struct fq_flow *fq_flow_classify(struct fq *fq, - struct fq_tin *tin, u32 idx, -- struct sk_buff *skb, -- fq_flow_get_default_t get_default_func) -+ struct sk_buff *skb) - { - struct fq_flow *flow; - -@@ -160,7 +159,7 @@ static struct fq_flow *fq_flow_classify( - - flow = &fq->flows[idx]; - if (flow->tin && flow->tin != tin) { -- flow = get_default_func(fq, tin, idx, skb); -+ flow = &tin->default_flow; - tin->collisions++; - fq->collisions++; - } -@@ -192,15 +191,14 @@ static void fq_recalc_backlog(struct fq - static void fq_tin_enqueue(struct fq *fq, - struct fq_tin *tin, u32 idx, - struct sk_buff *skb, -- fq_skb_free_t free_func, -- fq_flow_get_default_t get_default_func) -+ fq_skb_free_t free_func) - { - struct fq_flow *flow; - bool oom; - - lockdep_assert_held(&fq->lock); - -- flow = fq_flow_classify(fq, tin, idx, skb, get_default_func); -+ flow = fq_flow_classify(fq, tin, idx, skb); - - flow->tin = tin; - flow->backlog += skb->len; -@@ -331,6 +329,7 @@ static void fq_tin_init(struct fq_tin *t - { - INIT_LIST_HEAD(&tin->new_flows); - INIT_LIST_HEAD(&tin->old_flows); -+ fq_flow_init(&tin->default_flow); - } - - static int fq_init(struct fq *fq, int flows_cnt) ---- a/net/mac80211/ieee80211_i.h -+++ b/net/mac80211/ieee80211_i.h -@@ -846,7 +846,6 @@ enum txq_info_flags { - */ - struct txq_info { - struct fq_tin tin; -- struct fq_flow def_flow; - struct codel_vars def_cvars; - struct codel_stats cstats; - struct sk_buff_head frags; ---- a/net/mac80211/tx.c -+++ b/net/mac80211/tx.c -@@ -1322,7 +1322,7 @@ static struct sk_buff *codel_dequeue_fun - fq = &local->fq; - - if (cvars == &txqi->def_cvars) -- flow = &txqi->def_flow; -+ flow = &txqi->tin.default_flow; - else - flow = &fq->flows[cvars - local->cvars]; - -@@ -1365,7 +1365,7 @@ static struct sk_buff *fq_tin_dequeue_fu - cparams = &local->cparams; - } - -- if (flow == &txqi->def_flow) -+ if (flow == &tin->default_flow) - cvars = &txqi->def_cvars; - else - cvars = &local->cvars[flow - fq->flows]; -@@ -1392,17 +1392,6 @@ static void fq_skb_free_func(struct fq * - ieee80211_free_txskb(&local->hw, skb); - } - --static struct fq_flow *fq_flow_get_default_func(struct fq *fq, -- struct fq_tin *tin, -- int idx, -- struct sk_buff *skb) --{ -- struct txq_info *txqi; -- -- txqi = container_of(tin, struct txq_info, tin); -- return &txqi->def_flow; --} -- - static void ieee80211_txq_enqueue(struct ieee80211_local *local, - struct txq_info *txqi, - struct sk_buff *skb) -@@ -1415,8 +1404,7 @@ static void ieee80211_txq_enqueue(struct - - spin_lock_bh(&fq->lock); - fq_tin_enqueue(fq, tin, flow_idx, skb, -- fq_skb_free_func, -- fq_flow_get_default_func); -+ fq_skb_free_func); - spin_unlock_bh(&fq->lock); - } - -@@ -1459,7 +1447,6 @@ void ieee80211_txq_init(struct ieee80211 - struct txq_info *txqi, int tid) - { - fq_tin_init(&txqi->tin); -- fq_flow_init(&txqi->def_flow); - codel_vars_init(&txqi->def_cvars); - codel_stats_init(&txqi->cstats); - __skb_queue_head_init(&txqi->frags); -@@ -3310,8 +3297,7 @@ static bool ieee80211_amsdu_aggregate(st - */ - - tin = &txqi->tin; -- flow = fq_flow_classify(fq, tin, flow_idx, skb, -- fq_flow_get_default_func); -+ flow = fq_flow_classify(fq, tin, flow_idx, skb); - head = skb_peek_tail(&flow->queue); - if (!head || skb_is_gso(head)) - goto out; diff --git a/package/kernel/mac80211/patches/subsys/312-net-fq_impl-do-not-maintain-a-backlog-sorted-list-of.patch b/package/kernel/mac80211/patches/subsys/312-net-fq_impl-do-not-maintain-a-backlog-sorted-list-of.patch deleted file mode 100644 index 08e5cbb5b90..00000000000 --- a/package/kernel/mac80211/patches/subsys/312-net-fq_impl-do-not-maintain-a-backlog-sorted-list-of.patch +++ /dev/null @@ -1,317 +0,0 @@ -From: Felix Fietkau <nbd@nbd.name> -Date: Wed, 25 Nov 2020 18:10:34 +0100 -Subject: [PATCH] net/fq_impl: do not maintain a backlog-sorted list of - flows - -A sorted flow list is only needed to drop packets in the biggest flow when -hitting the overmemory condition. -By scanning flows only when needed, we can avoid paying the cost of -maintaining the list under normal conditions -In order to avoid scanning lots of empty flows and touching too many cold -cache lines, a bitmap of flows with backlog is maintained - -Signed-off-by: Felix Fietkau <nbd@nbd.name> ---- - ---- a/include/net/fq.h -+++ b/include/net/fq.h -@@ -19,8 +19,6 @@ struct fq_tin; - * @flowchain: can be linked to fq_tin's new_flows or old_flows. Used for DRR++ - * (deficit round robin) based round robin queuing similar to the one - * found in net/sched/sch_fq_codel.c -- * @backlogchain: can be linked to other fq_flow and fq. Used to keep track of -- * fat flows and efficient head-dropping if packet limit is reached - * @queue: sk_buff queue to hold packets - * @backlog: number of bytes pending in the queue. The number of packets can be - * found in @queue.qlen -@@ -29,7 +27,6 @@ struct fq_tin; - struct fq_flow { - struct fq_tin *tin; - struct list_head flowchain; -- struct list_head backlogchain; - struct sk_buff_head queue; - u32 backlog; - int deficit; -@@ -47,6 +44,7 @@ struct fq_flow { - struct fq_tin { - struct list_head new_flows; - struct list_head old_flows; -+ struct list_head tin_list; - struct fq_flow default_flow; - u32 backlog_bytes; - u32 backlog_packets; -@@ -60,14 +58,14 @@ struct fq_tin { - /** - * struct fq - main container for fair queuing purposes - * -- * @backlogs: linked to fq_flows. Used to maintain fat flows for efficient -- * head-dropping when @backlog reaches @limit - * @limit: max number of packets that can be queued across all flows - * @backlog: number of packets queued across all flows - */ - struct fq { - struct fq_flow *flows; -- struct list_head backlogs; -+ unsigned long *flows_bitmap; -+ -+ struct list_head tin_backlog; - spinlock_t lock; - u32 flows_cnt; - u32 limit; ---- a/include/net/fq_impl.h -+++ b/include/net/fq_impl.h -@@ -17,12 +17,24 @@ __fq_adjust_removal(struct fq *fq, struc - unsigned int bytes, unsigned int truesize) - { - struct fq_tin *tin = flow->tin; -+ int idx; - - tin->backlog_bytes -= bytes; - tin->backlog_packets -= packets; - flow->backlog -= bytes; - fq->backlog -= packets; - fq->memory_usage -= truesize; -+ -+ if (flow->backlog) -+ return; -+ -+ if (flow == &tin->default_flow) { -+ list_del_init(&tin->tin_list); -+ return; -+ } -+ -+ idx = flow - fq->flows; -+ __clear_bit(idx, fq->flows_bitmap); - } - - static void fq_adjust_removal(struct fq *fq, -@@ -32,24 +44,6 @@ static void fq_adjust_removal(struct fq - __fq_adjust_removal(fq, flow, 1, skb->len, skb->truesize); - } - --static void fq_rejigger_backlog(struct fq *fq, struct fq_flow *flow) --{ -- struct fq_flow *i; -- -- if (flow->backlog == 0) { -- list_del_init(&flow->backlogchain); -- } else { -- i = flow; -- -- list_for_each_entry_continue(i, &fq->backlogs, backlogchain) -- if (i->backlog < flow->backlog) -- break; -- -- list_move_tail(&flow->backlogchain, -- &i->backlogchain); -- } --} -- - static struct sk_buff *fq_flow_dequeue(struct fq *fq, - struct fq_flow *flow) - { -@@ -62,7 +56,6 @@ static struct sk_buff *fq_flow_dequeue(s - return NULL; - - fq_adjust_removal(fq, flow, skb); -- fq_rejigger_backlog(fq, flow); - - return skb; - } -@@ -90,7 +83,6 @@ static int fq_flow_drop(struct fq *fq, s - } while (packets < pending); - - __fq_adjust_removal(fq, flow, packets, bytes, truesize); -- fq_rejigger_backlog(fq, flow); - - return packets; - } -@@ -170,22 +162,36 @@ static struct fq_flow *fq_flow_classify( - return flow; - } - --static void fq_recalc_backlog(struct fq *fq, -- struct fq_tin *tin, -- struct fq_flow *flow) --{ -- struct fq_flow *i; -- -- if (list_empty(&flow->backlogchain)) -- list_add_tail(&flow->backlogchain, &fq->backlogs); -- -- i = flow; -- list_for_each_entry_continue_reverse(i, &fq->backlogs, -- backlogchain) -- if (i->backlog > flow->backlog) -- break; -+static struct fq_flow *fq_find_fattest_flow(struct fq *fq) -+{ -+ struct fq_tin *tin; -+ struct fq_flow *flow = NULL; -+ u32 len = 0; -+ int i; -+ -+ for_each_set_bit(i, fq->flows_bitmap, fq->flows_cnt) { -+ struct fq_flow *cur = &fq->flows[i]; -+ unsigned int cur_len; -+ -+ cur_len = cur->backlog; -+ if (cur_len <= len) -+ continue; -+ -+ flow = cur; -+ len = cur_len; -+ } - -- list_move(&flow->backlogchain, &i->backlogchain); -+ list_for_each_entry(tin, &fq->tin_backlog, tin_list) { -+ unsigned int cur_len = tin->default_flow.backlog; -+ -+ if (cur_len <= len) -+ continue; -+ -+ flow = &tin->default_flow; -+ len = cur_len; -+ } -+ -+ return flow; - } - - static void fq_tin_enqueue(struct fq *fq, -@@ -200,6 +206,13 @@ static void fq_tin_enqueue(struct fq *fq - - flow = fq_flow_classify(fq, tin, idx, skb); - -+ if (!flow->backlog) { -+ if (flow != &tin->default_flow) -+ __set_bit(idx, fq->flows_bitmap); -+ else if (list_empty(&tin->tin_list)) -+ list_add(&tin->tin_list, &fq->tin_backlog); -+ } -+ - flow->tin = tin; - flow->backlog += skb->len; - tin->backlog_bytes += skb->len; -@@ -207,8 +220,6 @@ static void fq_tin_enqueue(struct fq *fq - fq->memory_usage += skb->truesize; - fq->backlog++; - -- fq_recalc_backlog(fq, tin, flow); -- - if (list_empty(&flow->flowchain)) { - flow->deficit = fq->quantum; - list_add_tail(&flow->flowchain, -@@ -218,9 +229,7 @@ static void fq_tin_enqueue(struct fq *fq - __skb_queue_tail(&flow->queue, skb); - oom = (fq->memory_usage > fq->memory_limit); - while (fq->backlog > fq->limit || oom) { -- flow = list_first_entry_or_null(&fq->backlogs, -- struct fq_flow, -- backlogchain); -+ flow = fq_find_fattest_flow(fq); - if (!flow) - return; - -@@ -255,8 +264,6 @@ static void fq_flow_filter(struct fq *fq - fq_adjust_removal(fq, flow, skb); - free_func(fq, tin, flow, skb); - } -- -- fq_rejigger_backlog(fq, flow); - } - - static void fq_tin_filter(struct fq *fq, -@@ -279,16 +286,18 @@ static void fq_flow_reset(struct fq *fq, - struct fq_flow *flow, - fq_skb_free_t free_func) - { -+ struct fq_tin *tin = flow->tin; - struct sk_buff *skb; - - while ((skb = fq_flow_dequeue(fq, flow))) -- free_func(fq, flow->tin, flow, skb); -+ free_func(fq, tin, flow, skb); - -- if (!list_empty(&flow->flowchain)) -+ if (!list_empty(&flow->flowchain)) { - list_del_init(&flow->flowchain); -- -- if (!list_empty(&flow->backlogchain)) -- list_del_init(&flow->backlogchain); -+ if (list_empty(&tin->new_flows) && -+ list_empty(&tin->old_flows)) -+ list_del_init(&tin->tin_list); -+ } - - flow->tin = NULL; - -@@ -314,6 +323,7 @@ static void fq_tin_reset(struct fq *fq, - fq_flow_reset(fq, flow, free_func); - } - -+ WARN_ON_ONCE(!list_empty(&tin->tin_list)); - WARN_ON_ONCE(tin->backlog_bytes); - WARN_ON_ONCE(tin->backlog_packets); - } -@@ -321,7 +331,6 @@ static void fq_tin_reset(struct fq *fq, - static void fq_flow_init(struct fq_flow *flow) - { - INIT_LIST_HEAD(&flow->flowchain); -- INIT_LIST_HEAD(&flow->backlogchain); - __skb_queue_head_init(&flow->queue); - } - -@@ -329,6 +338,7 @@ static void fq_tin_init(struct fq_tin *t - { - INIT_LIST_HEAD(&tin->new_flows); - INIT_LIST_HEAD(&tin->old_flows); -+ INIT_LIST_HEAD(&tin->tin_list); - fq_flow_init(&tin->default_flow); - } - -@@ -337,8 +347,8 @@ static int fq_init(struct fq *fq, int fl - int i; - - memset(fq, 0, sizeof(fq[0])); -- INIT_LIST_HEAD(&fq->backlogs); - spin_lock_init(&fq->lock); -+ INIT_LIST_HEAD(&fq->tin_backlog); - fq->flows_cnt = max_t(u32, flows_cnt, 1); - fq->quantum = 300; - fq->limit = 8192; -@@ -348,6 +358,14 @@ static int fq_init(struct fq *fq, int fl - if (!fq->flows) - return -ENOMEM; - -+ fq->flows_bitmap = kcalloc(BITS_TO_LONGS(fq->flows_cnt), sizeof(long), -+ GFP_KERNEL); -+ if (!fq->flows_bitmap) { -+ kvfree(fq->flows); -+ fq->flows = NULL; -+ return -ENOMEM; -+ } -+ - for (i = 0; i < fq->flows_cnt; i++) - fq_flow_init(&fq->flows[i]); - -@@ -364,6 +382,9 @@ static void fq_reset(struct fq *fq, - - kvfree(fq->flows); - fq->flows = NULL; -+ -+ kfree(fq->flows_bitmap); -+ fq->flows_bitmap = NULL; - } - - #endif ---- a/net/mac80211/tx.c -+++ b/net/mac80211/tx.c -@@ -3364,8 +3364,6 @@ out_recalc: - if (head->len != orig_len) { - flow->backlog += head->len - orig_len; - tin->backlog_bytes += head->len - orig_len; -- -- fq_recalc_backlog(fq, tin, flow); - } - out: - spin_unlock_bh(&fq->lock); diff --git a/package/kernel/mac80211/patches/subsys/312-wifi-cfg80211-annotate-iftype_data-pointer-with-spar.patch b/package/kernel/mac80211/patches/subsys/312-wifi-cfg80211-annotate-iftype_data-pointer-with-spar.patch new file mode 100644 index 00000000000..18420a80cf9 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/312-wifi-cfg80211-annotate-iftype_data-pointer-with-spar.patch @@ -0,0 +1,467 @@ +From: Johannes Berg <johannes.berg@intel.com> +Date: Mon, 28 Aug 2023 09:54:39 +0200 +Subject: [PATCH] wifi: cfg80211: annotate iftype_data pointer with sparse + +There were are a number of cases in mac80211 and iwlwifi (at +least) that used the sband->iftype_data pointer directly, +instead of using the accessors to find the right array entry +to use. + +Make sparse warn when such a thing is done. + +To not have a lot of casts, add two helper functions/macros + + - ieee80211_set_sband_iftype_data() + - for_each_sband_iftype_data() + +Signed-off-by: Johannes Berg <johannes.berg@intel.com> +--- + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -5893,8 +5893,9 @@ static void ath11k_mac_setup_he_cap(stru + ar->mac.iftype[NL80211_BAND_2GHZ], + NL80211_BAND_2GHZ); + band = &ar->mac.sbands[NL80211_BAND_2GHZ]; +- band->iftype_data = ar->mac.iftype[NL80211_BAND_2GHZ]; +- band->n_iftype_data = count; ++ _ieee80211_set_sband_iftype_data(band, ++ ar->mac.iftype[NL80211_BAND_2GHZ], ++ count); + } + + if (cap->supported_bands & WMI_HOST_WLAN_5G_CAP) { +@@ -5902,8 +5903,9 @@ static void ath11k_mac_setup_he_cap(stru + ar->mac.iftype[NL80211_BAND_5GHZ], + NL80211_BAND_5GHZ); + band = &ar->mac.sbands[NL80211_BAND_5GHZ]; +- band->iftype_data = ar->mac.iftype[NL80211_BAND_5GHZ]; +- band->n_iftype_data = count; ++ _ieee80211_set_sband_iftype_data(band, ++ ar->mac.iftype[NL80211_BAND_5GHZ], ++ count); + } + + if (cap->supported_bands & WMI_HOST_WLAN_5G_CAP && +@@ -5912,8 +5914,9 @@ static void ath11k_mac_setup_he_cap(stru + ar->mac.iftype[NL80211_BAND_6GHZ], + NL80211_BAND_6GHZ); + band = &ar->mac.sbands[NL80211_BAND_6GHZ]; +- band->iftype_data = ar->mac.iftype[NL80211_BAND_6GHZ]; +- band->n_iftype_data = count; ++ _ieee80211_set_sband_iftype_data(band, ++ ar->mac.iftype[NL80211_BAND_6GHZ], ++ count); + } + } + +--- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c ++++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +@@ -1075,8 +1075,8 @@ static void iwl_init_he_hw_capab(struct + + memcpy(iftype_data, iwl_he_eht_capa, sizeof(iwl_he_eht_capa)); + +- sband->iftype_data = iftype_data; +- sband->n_iftype_data = ARRAY_SIZE(iwl_he_eht_capa); ++ _ieee80211_set_sband_iftype_data(sband, iftype_data, ++ ARRAY_SIZE(iwl_he_eht_capa)); + + for (i = 0; i < sband->n_iftype_data; i++) + iwl_nvm_fixup_sband_iftd(trans, data, sband, &iftype_data[i], +--- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c +@@ -1119,8 +1119,7 @@ void mt7915_set_stream_he_caps(struct mt + n = mt7915_init_he_caps(phy, NL80211_BAND_2GHZ, data); + + band = &phy->mt76->sband_2g.sband; +- band->iftype_data = data; +- band->n_iftype_data = n; ++ _ieee80211_set_sband_iftype_data(band, data, n); + } + + if (phy->mt76->cap.has_5ghz) { +@@ -1128,8 +1127,7 @@ void mt7915_set_stream_he_caps(struct mt + n = mt7915_init_he_caps(phy, NL80211_BAND_5GHZ, data); + + band = &phy->mt76->sband_5g.sband; +- band->iftype_data = data; +- band->n_iftype_data = n; ++ _ieee80211_set_sband_iftype_data(band, data, n); + } + + if (phy->mt76->cap.has_6ghz) { +@@ -1137,8 +1135,7 @@ void mt7915_set_stream_he_caps(struct mt + n = mt7915_init_he_caps(phy, NL80211_BAND_6GHZ, data); + + band = &phy->mt76->sband_6g.sband; +- band->iftype_data = data; +- band->n_iftype_data = n; ++ _ieee80211_set_sband_iftype_data(band, data, n); + } + } + +--- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c +@@ -196,8 +196,7 @@ void mt7921_set_stream_he_caps(struct mt + n = mt7921_init_he_caps(phy, NL80211_BAND_2GHZ, data); + + band = &phy->mt76->sband_2g.sband; +- band->iftype_data = data; +- band->n_iftype_data = n; ++ _ieee80211_set_sband_iftype_data(band, data, n); + } + + if (phy->mt76->cap.has_5ghz) { +@@ -205,16 +204,14 @@ void mt7921_set_stream_he_caps(struct mt + n = mt7921_init_he_caps(phy, NL80211_BAND_5GHZ, data); + + band = &phy->mt76->sband_5g.sband; +- band->iftype_data = data; +- band->n_iftype_data = n; ++ _ieee80211_set_sband_iftype_data(band, data, n); + + if (phy->mt76->cap.has_6ghz) { + data = phy->iftype[NL80211_BAND_6GHZ]; + n = mt7921_init_he_caps(phy, NL80211_BAND_6GHZ, data); + + band = &phy->mt76->sband_6g.sband; +- band->iftype_data = data; +- band->n_iftype_data = n; ++ _ieee80211_set_sband_iftype_data(band, data, n); + } + } + } +--- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c +@@ -823,8 +823,7 @@ __mt7996_set_stream_he_eht_caps(struct m + n++; + } + +- sband->iftype_data = data; +- sband->n_iftype_data = n; ++ _ieee80211_set_sband_iftype_data(sband, data, n); + } + + void mt7996_set_stream_he_eht_caps(struct mt7996_phy *phy) +--- a/drivers/net/wireless/quantenna/qtnfmac/commands.c ++++ b/drivers/net/wireless/quantenna/qtnfmac/commands.c +@@ -1335,7 +1335,7 @@ static int qtnf_cmd_band_fill_iftype(con + return -EINVAL; + } + +- kfree(band->iftype_data); ++ kfree((__force void *)band->iftype_data); + band->iftype_data = NULL; + band->n_iftype_data = tlv->n_iftype_data; + if (band->n_iftype_data == 0) +@@ -1347,7 +1347,8 @@ static int qtnf_cmd_band_fill_iftype(con + band->n_iftype_data = 0; + return -ENOMEM; + } +- band->iftype_data = iftype_data; ++ ++ _ieee80211_set_sband_iftype_data(band, iftype_data, tlv->n_iftype_data); + + for (i = 0; i < band->n_iftype_data; i++) + qtnf_cmd_conv_iftype(iftype_data++, &tlv->iftype_data[i]); +--- a/drivers/net/wireless/quantenna/qtnfmac/core.c ++++ b/drivers/net/wireless/quantenna/qtnfmac/core.c +@@ -549,7 +549,7 @@ static void qtnf_core_mac_detach(struct + if (!wiphy->bands[band]) + continue; + +- kfree(wiphy->bands[band]->iftype_data); ++ kfree((__force void *)wiphy->bands[band]->iftype_data); + wiphy->bands[band]->n_iftype_data = 0; + + kfree(wiphy->bands[band]->channels); +--- a/drivers/net/wireless/realtek/rtw89/core.c ++++ b/drivers/net/wireless/realtek/rtw89/core.c +@@ -3328,8 +3328,7 @@ static void rtw89_init_he_cap(struct rtw + idx++; + } + +- sband->iftype_data = iftype_data; +- sband->n_iftype_data = idx; ++ _ieee80211_set_sband_iftype_data(sband, iftype_data, idx); + } + + static int rtw89_core_set_supported_band(struct rtw89_dev *rtwdev) +@@ -3374,11 +3373,11 @@ err: + hw->wiphy->bands[NL80211_BAND_5GHZ] = NULL; + hw->wiphy->bands[NL80211_BAND_6GHZ] = NULL; + if (sband_2ghz) +- kfree(sband_2ghz->iftype_data); ++ kfree((__force void *)sband_2ghz->iftype_data); + if (sband_5ghz) +- kfree(sband_5ghz->iftype_data); ++ kfree((__force void *)sband_5ghz->iftype_data); + if (sband_6ghz) +- kfree(sband_6ghz->iftype_data); ++ kfree((__force void *)sband_6ghz->iftype_data); + kfree(sband_2ghz); + kfree(sband_5ghz); + kfree(sband_6ghz); +@@ -3390,11 +3389,11 @@ static void rtw89_core_clr_supported_ban + struct ieee80211_hw *hw = rtwdev->hw; + + if (hw->wiphy->bands[NL80211_BAND_2GHZ]) +- kfree(hw->wiphy->bands[NL80211_BAND_2GHZ]->iftype_data); ++ kfree((__force void *)hw->wiphy->bands[NL80211_BAND_2GHZ]->iftype_data); + if (hw->wiphy->bands[NL80211_BAND_5GHZ]) +- kfree(hw->wiphy->bands[NL80211_BAND_5GHZ]->iftype_data); ++ kfree((__force void *)hw->wiphy->bands[NL80211_BAND_5GHZ]->iftype_data); + if (hw->wiphy->bands[NL80211_BAND_6GHZ]) +- kfree(hw->wiphy->bands[NL80211_BAND_6GHZ]->iftype_data); ++ kfree((__force void *)hw->wiphy->bands[NL80211_BAND_6GHZ]->iftype_data); + kfree(hw->wiphy->bands[NL80211_BAND_2GHZ]); + kfree(hw->wiphy->bands[NL80211_BAND_5GHZ]); + kfree(hw->wiphy->bands[NL80211_BAND_6GHZ]); +--- a/drivers/net/wireless/realtek/rtw89/regd.c ++++ b/drivers/net/wireless/realtek/rtw89/regd.c +@@ -376,7 +376,7 @@ bottom: + return; + + wiphy->bands[NL80211_BAND_6GHZ] = NULL; +- kfree(sband->iftype_data); ++ kfree((__force void *)sband->iftype_data); + kfree(sband); + } + +--- a/drivers/net/wireless/virtual/mac80211_hwsim.c ++++ b/drivers/net/wireless/virtual/mac80211_hwsim.c +@@ -4900,25 +4900,19 @@ static const struct ieee80211_sband_ifty + + static void mac80211_hwsim_sband_capab(struct ieee80211_supported_band *sband) + { +- u16 n_iftype_data; +- +- if (sband->band == NL80211_BAND_2GHZ) { +- n_iftype_data = ARRAY_SIZE(sband_capa_2ghz); +- sband->iftype_data = +- (struct ieee80211_sband_iftype_data *)sband_capa_2ghz; +- } else if (sband->band == NL80211_BAND_5GHZ) { +- n_iftype_data = ARRAY_SIZE(sband_capa_5ghz); +- sband->iftype_data = +- (struct ieee80211_sband_iftype_data *)sband_capa_5ghz; +- } else if (sband->band == NL80211_BAND_6GHZ) { +- n_iftype_data = ARRAY_SIZE(sband_capa_6ghz); +- sband->iftype_data = +- (struct ieee80211_sband_iftype_data *)sband_capa_6ghz; +- } else { +- return; ++ switch (sband->band) { ++ case NL80211_BAND_2GHZ: ++ ieee80211_set_sband_iftype_data(sband, sband_capa_2ghz); ++ break; ++ case NL80211_BAND_5GHZ: ++ ieee80211_set_sband_iftype_data(sband, sband_capa_5ghz); ++ break; ++ case NL80211_BAND_6GHZ: ++ ieee80211_set_sband_iftype_data(sband, sband_capa_6ghz); ++ break; ++ default: ++ break; + } +- +- sband->n_iftype_data = n_iftype_data; + } + + #ifdef CPTCFG_MAC80211_MESH +--- a/include/net/cfg80211.h ++++ b/include/net/cfg80211.h +@@ -415,6 +415,19 @@ struct ieee80211_sta_eht_cap { + u8 eht_ppe_thres[IEEE80211_EHT_PPE_THRES_MAX_LEN]; + }; + ++/* sparse defines __CHECKER__; see Documentation/dev-tools/sparse.rst */ ++#ifdef __CHECKER__ ++/* ++ * This is used to mark the sband->iftype_data pointer which is supposed ++ * to be an array with special access semantics (per iftype), but a lot ++ * of code got it wrong in the past, so with this marking sparse will be ++ * noisy when the pointer is used directly. ++ */ ++# define __iftd __attribute__((noderef, address_space(__iftype_data))) ++#else ++# define __iftd ++#endif /* __CHECKER__ */ ++ + /** + * struct ieee80211_sband_iftype_data - sband data per interface type + * +@@ -548,10 +561,48 @@ struct ieee80211_supported_band { + struct ieee80211_sta_s1g_cap s1g_cap; + struct ieee80211_edmg edmg_cap; + u16 n_iftype_data; +- const struct ieee80211_sband_iftype_data *iftype_data; ++ const struct ieee80211_sband_iftype_data __iftd *iftype_data; + }; + + /** ++ * _ieee80211_set_sband_iftype_data - set sband iftype data array ++ * @sband: the sband to initialize ++ * @iftd: the iftype data array pointer ++ * @n_iftd: the length of the iftype data array ++ * ++ * Set the sband iftype data array; use this where the length cannot ++ * be derived from the ARRAY_SIZE() of the argument, but prefer ++ * ieee80211_set_sband_iftype_data() where it can be used. ++ */ ++static inline void ++_ieee80211_set_sband_iftype_data(struct ieee80211_supported_band *sband, ++ const struct ieee80211_sband_iftype_data *iftd, ++ u16 n_iftd) ++{ ++ sband->iftype_data = (const void __iftd __force *)iftd; ++ sband->n_iftype_data = n_iftd; ++} ++ ++/** ++ * ieee80211_set_sband_iftype_data - set sband iftype data array ++ * @sband: the sband to initialize ++ * @iftd: the iftype data array ++ */ ++#define ieee80211_set_sband_iftype_data(sband, iftd) \ ++ _ieee80211_set_sband_iftype_data(sband, iftd, ARRAY_SIZE(iftd)) ++ ++/** ++ * for_each_sband_iftype_data - iterate sband iftype data entries ++ * @sband: the sband whose iftype_data array to iterate ++ * @i: iterator counter ++ * @iftd: iftype data pointer to set ++ */ ++#define for_each_sband_iftype_data(sband, i, iftd) \ ++ for (i = 0, iftd = (const void __force *)&(sband)->iftype_data[i]; \ ++ i < (sband)->n_iftype_data; \ ++ i++, iftd = (const void __force *)&(sband)->iftype_data[i]) ++ ++/** + * ieee80211_get_sband_iftype_data - return sband data for a given iftype + * @sband: the sband to search for the STA on + * @iftype: enum nl80211_iftype +@@ -562,6 +613,7 @@ static inline const struct ieee80211_sba + ieee80211_get_sband_iftype_data(const struct ieee80211_supported_band *sband, + u8 iftype) + { ++ const struct ieee80211_sband_iftype_data *data; + int i; + + if (WARN_ON(iftype >= NL80211_IFTYPE_MAX)) +@@ -570,10 +622,7 @@ ieee80211_get_sband_iftype_data(const st + if (iftype == NL80211_IFTYPE_AP_VLAN) + iftype = NL80211_IFTYPE_AP; + +- for (i = 0; i < sband->n_iftype_data; i++) { +- const struct ieee80211_sband_iftype_data *data = +- &sband->iftype_data[i]; +- ++ for_each_sband_iftype_data(sband, i, data) { + if (data->types_mask & BIT(iftype)) + return data; + } +--- a/net/mac80211/main.c ++++ b/net/mac80211/main.c +@@ -1055,6 +1055,7 @@ int ieee80211_register_hw(struct ieee802 + supp_he = false; + supp_eht = false; + for (band = 0; band < NUM_NL80211_BANDS; band++) { ++ const struct ieee80211_sband_iftype_data *iftd; + struct ieee80211_supported_band *sband; + + sband = local->hw.wiphy->bands[band]; +@@ -1101,11 +1102,7 @@ int ieee80211_register_hw(struct ieee802 + supp_ht = supp_ht || sband->ht_cap.ht_supported; + supp_vht = supp_vht || sband->vht_cap.vht_supported; + +- for (i = 0; i < sband->n_iftype_data; i++) { +- const struct ieee80211_sband_iftype_data *iftd; +- +- iftd = &sband->iftype_data[i]; +- ++ for_each_sband_iftype_data(sband, i, iftd) { + supp_he = supp_he || iftd->he_cap.has_he; + supp_eht = supp_eht || iftd->eht_cap.has_eht; + } +--- a/net/wireless/chan.c ++++ b/net/wireless/chan.c +@@ -6,7 +6,7 @@ + * + * Copyright 2009 Johannes Berg <johannes@sipsolutions.net> + * Copyright 2013-2014 Intel Mobile Communications GmbH +- * Copyright 2018-2022 Intel Corporation ++ * Copyright 2018-2023 Intel Corporation + */ + + #include <linux/export.h> +@@ -1162,8 +1162,7 @@ bool cfg80211_chandef_usable(struct wiph + if (!sband) + return false; + +- for (i = 0; i < sband->n_iftype_data; i++) { +- iftd = &sband->iftype_data[i]; ++ for_each_sband_iftype_data(sband, i, iftd) { + if (!iftd->eht_cap.has_eht) + continue; + +--- a/net/wireless/core.c ++++ b/net/wireless/core.c +@@ -5,7 +5,7 @@ + * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net> + * Copyright 2013-2014 Intel Mobile Communications GmbH + * Copyright 2015-2017 Intel Deutschland GmbH +- * Copyright (C) 2018-2022 Intel Corporation ++ * Copyright (C) 2018-2023 Intel Corporation + */ + + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +@@ -817,6 +817,7 @@ int wiphy_register(struct wiphy *wiphy) + + /* sanity check supported bands/channels */ + for (band = 0; band < NUM_NL80211_BANDS; band++) { ++ const struct ieee80211_sband_iftype_data *iftd; + u16 types = 0; + bool have_he = false; + +@@ -873,14 +874,11 @@ int wiphy_register(struct wiphy *wiphy) + return -EINVAL; + } + +- for (i = 0; i < sband->n_iftype_data; i++) { +- const struct ieee80211_sband_iftype_data *iftd; ++ for_each_sband_iftype_data(sband, i, iftd) { + bool has_ap, has_non_ap; + u32 ap_bits = BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_P2P_GO); + +- iftd = &sband->iftype_data[i]; +- + if (WARN_ON(!iftd->types_mask)) + return -EINVAL; + if (WARN_ON(types & iftd->types_mask)) +--- a/net/wireless/nl80211.c ++++ b/net/wireless/nl80211.c +@@ -1906,20 +1906,20 @@ static int nl80211_send_band_rateinfo(st + struct nlattr *nl_iftype_data = + nla_nest_start_noflag(msg, + NL80211_BAND_ATTR_IFTYPE_DATA); ++ const struct ieee80211_sband_iftype_data *iftd; + int err; + + if (!nl_iftype_data) + return -ENOBUFS; + +- for (i = 0; i < sband->n_iftype_data; i++) { ++ for_each_sband_iftype_data(sband, i, iftd) { + struct nlattr *iftdata; + + iftdata = nla_nest_start_noflag(msg, i + 1); + if (!iftdata) + return -ENOBUFS; + +- err = nl80211_send_iftype_data(msg, sband, +- &sband->iftype_data[i]); ++ err = nl80211_send_iftype_data(msg, sband, iftd); + if (err) + return err; + diff --git a/package/kernel/mac80211/patches/subsys/313-wifi-cfg80211-export-DFS-CAC-time-and-usable-state-h.patch b/package/kernel/mac80211/patches/subsys/313-wifi-cfg80211-export-DFS-CAC-time-and-usable-state-h.patch new file mode 100644 index 00000000000..78ec030e18b --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/313-wifi-cfg80211-export-DFS-CAC-time-and-usable-state-h.patch @@ -0,0 +1,111 @@ +From 30ca8b0c4d6c9fb1d76e5894b1e8bf7c6a12224d Mon Sep 17 00:00:00 2001 +From: Aditya Kumar Singh <quic_adisi@quicinc.com> +Date: Tue, 12 Sep 2023 10:48:55 +0530 +Subject: [PATCH] wifi: cfg80211: export DFS CAC time and usable state helper + functions + +cfg80211 has cfg80211_chandef_dfs_usable() function to know whether +at least one channel in the chandef is in usable state or not. Also, +cfg80211_chandef_dfs_cac_time() function is there which tells the CAC +time required for the given chandef. + +Make these two functions visible to drivers by exporting their symbol +to global list of kernel symbols. + +Lower level drivers can make use of these two functions to be aware +if CAC is required on the given chandef and for how long. For example +drivers which maintains the CAC state internally can make use of these. + +Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com> +Reviewed-by: Jeff Johnson <quic_jjohnson@quicinc.com> +Link: https://lore.kernel.org/r/20230912051857.2284-2-quic_adisi@quicinc.com +Signed-off-by: Johannes Berg <johannes.berg@intel.com> +--- + include/net/cfg80211.h | 24 ++++++++++++++++++++++++ + net/wireless/chan.c | 2 ++ + net/wireless/core.h | 17 ----------------- + 3 files changed, 26 insertions(+), 17 deletions(-) + +--- a/include/net/cfg80211.h ++++ b/include/net/cfg80211.h +@@ -1008,6 +1008,30 @@ int cfg80211_chandef_dfs_required(struct + enum nl80211_iftype iftype); + + /** ++ * cfg80211_chandef_dfs_usable - checks if chandef is DFS usable and we ++ * can/need start CAC on such channel ++ * @wiphy: the wiphy to validate against ++ * @chandef: the channel definition to check ++ * ++ * Return: true if all channels available and at least ++ * one channel requires CAC (NL80211_DFS_USABLE) ++ */ ++bool cfg80211_chandef_dfs_usable(struct wiphy *wiphy, ++ const struct cfg80211_chan_def *chandef); ++ ++/** ++ * cfg80211_chandef_dfs_cac_time - get the DFS CAC time (in ms) for given ++ * channel definition ++ * @wiphy: the wiphy to validate against ++ * @chandef: the channel definition to check ++ * ++ * Returns: DFS CAC time (in ms) which applies for this channel definition ++ */ ++unsigned int ++cfg80211_chandef_dfs_cac_time(struct wiphy *wiphy, ++ const struct cfg80211_chan_def *chandef); ++ ++/** + * nl80211_send_chandef - sends the channel definition. + * @msg: the msg to send channel definition + * @chandef: the channel definition to check +--- a/net/wireless/chan.c ++++ b/net/wireless/chan.c +@@ -666,6 +666,7 @@ bool cfg80211_chandef_dfs_usable(struct + + return (r1 + r2 > 0); + } ++EXPORT_SYMBOL(cfg80211_chandef_dfs_usable); + + /* + * Checks if center frequency of chan falls with in the bandwidth +@@ -965,6 +966,7 @@ cfg80211_chandef_dfs_cac_time(struct wip + + return max(t1, t2); + } ++EXPORT_SYMBOL(cfg80211_chandef_dfs_cac_time); + + static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy, + u32 center_freq, u32 bandwidth, +--- a/net/wireless/core.h ++++ b/net/wireless/core.h +@@ -469,29 +469,12 @@ int cfg80211_scan(struct cfg80211_regist + + extern struct work_struct cfg80211_disconnect_work; + +-/** +- * cfg80211_chandef_dfs_usable - checks if chandef is DFS usable +- * @wiphy: the wiphy to validate against +- * @chandef: the channel definition to check +- * +- * Checks if chandef is usable and we can/need start CAC on such channel. +- * +- * Return: true if all channels available and at least +- * one channel requires CAC (NL80211_DFS_USABLE) +- */ +-bool cfg80211_chandef_dfs_usable(struct wiphy *wiphy, +- const struct cfg80211_chan_def *chandef); +- + void cfg80211_set_dfs_state(struct wiphy *wiphy, + const struct cfg80211_chan_def *chandef, + enum nl80211_dfs_state dfs_state); + + void cfg80211_dfs_channels_update_work(struct work_struct *work); + +-unsigned int +-cfg80211_chandef_dfs_cac_time(struct wiphy *wiphy, +- const struct cfg80211_chan_def *chandef); +- + void cfg80211_sched_dfs_chan_update(struct cfg80211_registered_device *rdev); + + int diff --git a/package/kernel/mac80211/patches/subsys/314-wifi-mac80211-fix-race-condition-on-enabling-fast-xm.patch b/package/kernel/mac80211/patches/subsys/314-wifi-mac80211-fix-race-condition-on-enabling-fast-xm.patch new file mode 100644 index 00000000000..191eb67e8ea --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/314-wifi-mac80211-fix-race-condition-on-enabling-fast-xm.patch @@ -0,0 +1,34 @@ +From: Felix Fietkau <nbd@nbd.name> +Date: Wed, 3 Jan 2024 15:10:18 +0100 +Subject: [PATCH] wifi: mac80211: fix race condition on enabling fast-xmit + +fast-xmit must only be enabled after the sta has been uploaded to the driver, +otherwise it could end up passing the not-yet-uploaded sta via drv_tx calls +to the driver, leading to potential crashes because of uninitialized drv_priv +data. +Add a missing sta->uploaded check and re-check fast xmit after inserting a sta. + +Signed-off-by: Felix Fietkau <nbd@nbd.name> +--- + +--- a/net/mac80211/sta_info.c ++++ b/net/mac80211/sta_info.c +@@ -911,6 +911,7 @@ static int sta_info_insert_finish(struct + + if (ieee80211_vif_is_mesh(&sdata->vif)) + mesh_accept_plinks_update(sdata); ++ ieee80211_check_fast_xmit(sta); + + return 0; + out_remove: +--- a/net/mac80211/tx.c ++++ b/net/mac80211/tx.c +@@ -3033,7 +3033,7 @@ void ieee80211_check_fast_xmit(struct st + sdata->vif.type == NL80211_IFTYPE_STATION) + goto out; + +- if (!test_sta_flag(sta, WLAN_STA_AUTHORIZED)) ++ if (!test_sta_flag(sta, WLAN_STA_AUTHORIZED) || !sta->uploaded) + goto out; + + if (test_sta_flag(sta, WLAN_STA_PS_STA) || diff --git a/package/kernel/mac80211/patches/subsys/315-mac80211-add-rx-decapsulation-offload-support.patch b/package/kernel/mac80211/patches/subsys/315-mac80211-add-rx-decapsulation-offload-support.patch deleted file mode 100644 index b8bb2930f58..00000000000 --- a/package/kernel/mac80211/patches/subsys/315-mac80211-add-rx-decapsulation-offload-support.patch +++ /dev/null @@ -1,570 +0,0 @@ -From: Felix Fietkau <nbd@nbd.name> -Date: Wed, 16 Dec 2020 21:34:03 +0100 -Subject: [PATCH] mac80211: add rx decapsulation offload support - -This allows drivers to pass 802.3 frames to mac80211, with some restrictions: - -- the skb must be passed with a valid sta -- fast-rx needs to be active for the sta -- monitor mode needs to be disabled - -mac80211 will tell the driver when it is safe to enable rx decap offload for -a particular station. - -In order to implement support, a driver must: - -- call ieee80211_hw_set(hw, SUPPORTS_RX_DECAP_OFFLOAD) -- implement ops->sta_set_decap_offload -- mark 802.3 frames with RX_FLAG_8023 - -If it doesn't want to enable offload for some vif types, it can mask out -IEEE80211_OFFLOAD_DECAP_ENABLED in vif->offload_flags from within the -.add_interface or .update_vif_offload driver ops - -Signed-off-by: Felix Fietkau <nbd@nbd.name> ---- - ---- a/include/net/mac80211.h -+++ b/include/net/mac80211.h -@@ -1297,6 +1297,8 @@ ieee80211_tx_info_clear_status(struct ie - * the "0-length PSDU" field included there. The value for it is - * in &struct ieee80211_rx_status. Note that if this value isn't - * known the frame shouldn't be reported. -+ * @RX_FLAG_8023: the frame has an 802.3 header (decap offload performed by -+ * hardware or driver) - */ - enum mac80211_rx_flags { - RX_FLAG_MMIC_ERROR = BIT(0), -@@ -1329,6 +1331,7 @@ enum mac80211_rx_flags { - RX_FLAG_RADIOTAP_HE_MU = BIT(27), - RX_FLAG_RADIOTAP_LSIG = BIT(28), - RX_FLAG_NO_PSDU = BIT(29), -+ RX_FLAG_8023 = BIT(30), - }; - - /** -@@ -1650,11 +1653,15 @@ enum ieee80211_vif_flags { - * The driver supports sending frames passed as 802.3 frames by mac80211. - * It must also support sending 802.11 packets for the same interface. - * @IEEE80211_OFFLOAD_ENCAP_4ADDR: support 4-address mode encapsulation offload -+ * @IEEE80211_OFFLOAD_DECAP_ENABLED: rx encapsulation offload is enabled -+ * The driver supports passing received 802.11 frames as 802.3 frames to -+ * mac80211. - */ - - enum ieee80211_offload_flags { - IEEE80211_OFFLOAD_ENCAP_ENABLED = BIT(0), - IEEE80211_OFFLOAD_ENCAP_4ADDR = BIT(1), -+ IEEE80211_OFFLOAD_DECAP_ENABLED = BIT(2), - }; - - /** -@@ -2390,6 +2397,9 @@ struct ieee80211_txq { - * @IEEE80211_HW_SUPPORTS_TX_ENCAP_OFFLOAD: Hardware supports tx encapsulation - * offload - * -+ * @IEEE80211_HW_SUPPORTS_RX_DECAP_OFFLOAD: Hardware supports rx decapsulation -+ * offload -+ * - * @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays - */ - enum ieee80211_hw_flags { -@@ -2443,6 +2453,7 @@ enum ieee80211_hw_flags { - IEEE80211_HW_SUPPORTS_ONLY_HE_MULTI_BSSID, - IEEE80211_HW_AMPDU_KEYBORDER_SUPPORT, - IEEE80211_HW_SUPPORTS_TX_ENCAP_OFFLOAD, -+ IEEE80211_HW_SUPPORTS_RX_DECAP_OFFLOAD, - - /* keep last, obviously */ - NUM_IEEE80211_HW_FLAGS -@@ -4196,6 +4207,9 @@ struct ieee80211_ops { - struct ieee80211_vif *vif); - void (*sta_set_4addr)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, bool enabled); -+ void (*sta_set_decap_offload)(struct ieee80211_hw *hw, -+ struct ieee80211_vif *vif, -+ struct ieee80211_sta *sta, bool enabled); - }; - - /** ---- a/net/mac80211/debugfs.c -+++ b/net/mac80211/debugfs.c -@@ -405,6 +405,7 @@ static const char *hw_flag_names[] = { - FLAG(SUPPORTS_ONLY_HE_MULTI_BSSID), - FLAG(AMPDU_KEYBORDER_SUPPORT), - FLAG(SUPPORTS_TX_ENCAP_OFFLOAD), -+ FLAG(SUPPORTS_RX_DECAP_OFFLOAD), - #undef FLAG - }; - ---- a/net/mac80211/debugfs_sta.c -+++ b/net/mac80211/debugfs_sta.c -@@ -79,6 +79,7 @@ static const char * const sta_flag_names - FLAG(MPSP_RECIPIENT), - FLAG(PS_DELIVER), - FLAG(USES_ENCRYPTION), -+ FLAG(DECAP_OFFLOAD), - #undef FLAG - }; - ---- a/net/mac80211/driver-ops.h -+++ b/net/mac80211/driver-ops.h -@@ -1413,4 +1413,20 @@ static inline void drv_sta_set_4addr(str - trace_drv_return_void(local); - } - -+static inline void drv_sta_set_decap_offload(struct ieee80211_local *local, -+ struct ieee80211_sub_if_data *sdata, -+ struct ieee80211_sta *sta, -+ bool enabled) -+{ -+ sdata = get_bss_sdata(sdata); -+ if (!check_sdata_in_driver(sdata)) -+ return; -+ -+ trace_drv_sta_set_decap_offload(local, sdata, sta, enabled); -+ if (local->ops->sta_set_decap_offload) -+ local->ops->sta_set_decap_offload(&local->hw, &sdata->vif, sta, -+ enabled); -+ trace_drv_return_void(local); -+} -+ - #endif /* __MAC80211_DRIVER_OPS */ ---- a/net/mac80211/iface.c -+++ b/net/mac80211/iface.c -@@ -835,7 +835,7 @@ static const struct net_device_ops ieee8 - - }; - --static bool ieee80211_iftype_supports_encap_offload(enum nl80211_iftype iftype) -+static bool ieee80211_iftype_supports_hdr_offload(enum nl80211_iftype iftype) - { - switch (iftype) { - /* P2P GO and client are mapped to AP/STATION types */ -@@ -855,7 +855,7 @@ static bool ieee80211_set_sdata_offload_ - flags = sdata->vif.offload_flags; - - if (ieee80211_hw_check(&local->hw, SUPPORTS_TX_ENCAP_OFFLOAD) && -- ieee80211_iftype_supports_encap_offload(sdata->vif.type)) { -+ ieee80211_iftype_supports_hdr_offload(sdata->vif.type)) { - flags |= IEEE80211_OFFLOAD_ENCAP_ENABLED; - - if (!ieee80211_hw_check(&local->hw, SUPPORTS_TX_FRAG) && -@@ -868,10 +868,21 @@ static bool ieee80211_set_sdata_offload_ - flags &= ~IEEE80211_OFFLOAD_ENCAP_ENABLED; - } - -+ if (ieee80211_hw_check(&local->hw, SUPPORTS_RX_DECAP_OFFLOAD) && -+ ieee80211_iftype_supports_hdr_offload(sdata->vif.type)) { -+ flags |= IEEE80211_OFFLOAD_DECAP_ENABLED; -+ -+ if (local->monitors) -+ flags &= ~IEEE80211_OFFLOAD_DECAP_ENABLED; -+ } else { -+ flags &= ~IEEE80211_OFFLOAD_DECAP_ENABLED; -+ } -+ - if (sdata->vif.offload_flags == flags) - return false; - - sdata->vif.offload_flags = flags; -+ ieee80211_check_fast_rx_iface(sdata); - return true; - } - -@@ -889,7 +900,7 @@ static void ieee80211_set_vif_encap_ops( - } - - if (!ieee80211_hw_check(&local->hw, SUPPORTS_TX_ENCAP_OFFLOAD) || -- !ieee80211_iftype_supports_encap_offload(bss->vif.type)) -+ !ieee80211_iftype_supports_hdr_offload(bss->vif.type)) - return; - - enabled = bss->vif.offload_flags & IEEE80211_OFFLOAD_ENCAP_ENABLED; ---- a/net/mac80211/rx.c -+++ b/net/mac80211/rx.c -@@ -4198,7 +4198,9 @@ void ieee80211_check_fast_rx(struct sta_ - .vif_type = sdata->vif.type, - .control_port_protocol = sdata->control_port_protocol, - }, *old, *new = NULL; -+ bool set_offload = false; - bool assign = false; -+ bool offload; - - /* use sparse to check that we don't return without updating */ - __acquire(check_fast_rx); -@@ -4311,6 +4313,17 @@ void ieee80211_check_fast_rx(struct sta_ - if (assign) - new = kmemdup(&fastrx, sizeof(fastrx), GFP_KERNEL); - -+ offload = assign && -+ (sdata->vif.offload_flags & IEEE80211_OFFLOAD_DECAP_ENABLED); -+ -+ if (offload) -+ set_offload = !test_and_set_sta_flag(sta, WLAN_STA_DECAP_OFFLOAD); -+ else -+ set_offload = test_and_clear_sta_flag(sta, WLAN_STA_DECAP_OFFLOAD); -+ -+ if (set_offload) -+ drv_sta_set_decap_offload(local, sdata, &sta->sta, assign); -+ - spin_lock_bh(&sta->lock); - old = rcu_dereference_protected(sta->fast_rx, true); - rcu_assign_pointer(sta->fast_rx, new); -@@ -4357,6 +4370,108 @@ void ieee80211_check_fast_rx_iface(struc - mutex_unlock(&local->sta_mtx); - } - -+static void ieee80211_rx_8023(struct ieee80211_rx_data *rx, -+ struct ieee80211_fast_rx *fast_rx, -+ int orig_len) -+{ -+ struct ieee80211_sta_rx_stats *stats; -+ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); -+ struct sta_info *sta = rx->sta; -+ struct sk_buff *skb = rx->skb; -+ void *sa = skb->data + ETH_ALEN; -+ void *da = skb->data; -+ -+ stats = &sta->rx_stats; -+ if (fast_rx->uses_rss) -+ stats = this_cpu_ptr(sta->pcpu_rx_stats); -+ -+ /* statistics part of ieee80211_rx_h_sta_process() */ -+ if (!(status->flag & RX_FLAG_NO_SIGNAL_VAL)) { -+ stats->last_signal = status->signal; -+ if (!fast_rx->uses_rss) -+ ewma_signal_add(&sta->rx_stats_avg.signal, -+ -status->signal); -+ } -+ -+ if (status->chains) { -+ int i; -+ -+ stats->chains = status->chains; -+ for (i = 0; i < ARRAY_SIZE(status->chain_signal); i++) { -+ int signal = status->chain_signal[i]; -+ -+ if (!(status->chains & BIT(i))) -+ continue; -+ -+ stats->chain_signal_last[i] = signal; -+ if (!fast_rx->uses_rss) -+ ewma_signal_add(&sta->rx_stats_avg.chain_signal[i], -+ -signal); -+ } -+ } -+ /* end of statistics */ -+ -+ stats->last_rx = jiffies; -+ stats->last_rate = sta_stats_encode_rate(status); -+ -+ stats->fragments++; -+ stats->packets++; -+ -+ skb->dev = fast_rx->dev; -+ -+ ieee80211_rx_stats(fast_rx->dev, skb->len); -+ -+ /* The seqno index has the same property as needed -+ * for the rx_msdu field, i.e. it is IEEE80211_NUM_TIDS -+ * for non-QoS-data frames. Here we know it's a data -+ * frame, so count MSDUs. -+ */ -+ u64_stats_update_begin(&stats->syncp); -+ stats->msdu[rx->seqno_idx]++; -+ stats->bytes += orig_len; -+ u64_stats_update_end(&stats->syncp); -+ -+ if (fast_rx->internal_forward) { -+ struct sk_buff *xmit_skb = NULL; -+ if (is_multicast_ether_addr(da)) { -+ xmit_skb = skb_copy(skb, GFP_ATOMIC); -+ } else if (!ether_addr_equal(da, sa) && -+ sta_info_get(rx->sdata, da)) { -+ xmit_skb = skb; -+ skb = NULL; -+ } -+ -+ if (xmit_skb) { -+ /* -+ * Send to wireless media and increase priority by 256 -+ * to keep the received priority instead of -+ * reclassifying the frame (see cfg80211_classify8021d). -+ */ -+ xmit_skb->priority += 256; -+ xmit_skb->protocol = htons(ETH_P_802_3); -+ skb_reset_network_header(xmit_skb); -+ skb_reset_mac_header(xmit_skb); -+ dev_queue_xmit(xmit_skb); -+ } -+ -+ if (!skb) -+ return; -+ } -+ -+ /* deliver to local stack */ -+ skb->protocol = eth_type_trans(skb, fast_rx->dev); -+ memset(skb->cb, 0, sizeof(skb->cb)); -+ if (rx->list) -+#if LINUX_VERSION_IS_GEQ(4,19,0) -+ list_add_tail(&skb->list, rx->list); -+#else -+ __skb_queue_tail(rx->list, skb); -+#endif -+ else -+ netif_receive_skb(skb); -+ -+} -+ - static bool ieee80211_invoke_fast_rx(struct ieee80211_rx_data *rx, - struct ieee80211_fast_rx *fast_rx) - { -@@ -4377,9 +4492,6 @@ static bool ieee80211_invoke_fast_rx(str - } addrs __aligned(2); - struct ieee80211_sta_rx_stats *stats = &sta->rx_stats; - -- if (fast_rx->uses_rss) -- stats = this_cpu_ptr(sta->pcpu_rx_stats); -- - /* for parallel-rx, we need to have DUP_VALIDATED, otherwise we write - * to a common data structure; drivers can implement that per queue - * but we don't have that information in mac80211 -@@ -4453,32 +4565,6 @@ static bool ieee80211_invoke_fast_rx(str - pskb_trim(skb, skb->len - fast_rx->icv_len)) - goto drop; - -- /* statistics part of ieee80211_rx_h_sta_process() */ -- if (!(status->flag & RX_FLAG_NO_SIGNAL_VAL)) { -- stats->last_signal = status->signal; -- if (!fast_rx->uses_rss) -- ewma_signal_add(&sta->rx_stats_avg.signal, -- -status->signal); -- } -- -- if (status->chains) { -- int i; -- -- stats->chains = status->chains; -- for (i = 0; i < ARRAY_SIZE(status->chain_signal); i++) { -- int signal = status->chain_signal[i]; -- -- if (!(status->chains & BIT(i))) -- continue; -- -- stats->chain_signal_last[i] = signal; -- if (!fast_rx->uses_rss) -- ewma_signal_add(&sta->rx_stats_avg.chain_signal[i], -- -signal); -- } -- } -- /* end of statistics */ -- - if (rx->key && !ieee80211_has_protected(hdr->frame_control)) - goto drop; - -@@ -4490,12 +4576,6 @@ static bool ieee80211_invoke_fast_rx(str - return true; - } - -- stats->last_rx = jiffies; -- stats->last_rate = sta_stats_encode_rate(status); -- -- stats->fragments++; -- stats->packets++; -- - /* do the header conversion - first grab the addresses */ - ether_addr_copy(addrs.da, skb->data + fast_rx->da_offs); - ether_addr_copy(addrs.sa, skb->data + fast_rx->sa_offs); -@@ -4504,62 +4584,14 @@ static bool ieee80211_invoke_fast_rx(str - /* push the addresses in front */ - memcpy(skb_push(skb, sizeof(addrs)), &addrs, sizeof(addrs)); - -- skb->dev = fast_rx->dev; -- -- ieee80211_rx_stats(fast_rx->dev, skb->len); -- -- /* The seqno index has the same property as needed -- * for the rx_msdu field, i.e. it is IEEE80211_NUM_TIDS -- * for non-QoS-data frames. Here we know it's a data -- * frame, so count MSDUs. -- */ -- u64_stats_update_begin(&stats->syncp); -- stats->msdu[rx->seqno_idx]++; -- stats->bytes += orig_len; -- u64_stats_update_end(&stats->syncp); -- -- if (fast_rx->internal_forward) { -- struct sk_buff *xmit_skb = NULL; -- if (is_multicast_ether_addr(addrs.da)) { -- xmit_skb = skb_copy(skb, GFP_ATOMIC); -- } else if (!ether_addr_equal(addrs.da, addrs.sa) && -- sta_info_get(rx->sdata, addrs.da)) { -- xmit_skb = skb; -- skb = NULL; -- } -- -- if (xmit_skb) { -- /* -- * Send to wireless media and increase priority by 256 -- * to keep the received priority instead of -- * reclassifying the frame (see cfg80211_classify8021d). -- */ -- xmit_skb->priority += 256; -- xmit_skb->protocol = htons(ETH_P_802_3); -- skb_reset_network_header(xmit_skb); -- skb_reset_mac_header(xmit_skb); -- dev_queue_xmit(xmit_skb); -- } -- -- if (!skb) -- return true; -- } -- -- /* deliver to local stack */ -- skb->protocol = eth_type_trans(skb, fast_rx->dev); -- memset(skb->cb, 0, sizeof(skb->cb)); -- if (rx->list) --#if LINUX_VERSION_IS_GEQ(4,19,0) -- list_add_tail(&skb->list, rx->list); --#else -- __skb_queue_tail(rx->list, skb); --#endif -- else -- netif_receive_skb(skb); -+ ieee80211_rx_8023(rx, fast_rx, orig_len); - - return true; - drop: - dev_kfree_skb(skb); -+ if (fast_rx->uses_rss) -+ stats = this_cpu_ptr(sta->pcpu_rx_stats); -+ - stats->dropped++; - return true; - } -@@ -4613,6 +4645,47 @@ static bool ieee80211_prepare_and_rx_han - return true; - } - -+static void __ieee80211_rx_handle_8023(struct ieee80211_hw *hw, -+ struct ieee80211_sta *pubsta, -+ struct sk_buff *skb, -+#if LINUX_VERSION_IS_GEQ(4,19,0) -+ struct list_head *list) -+#else -+ struct sk_buff_head *list) -+#endif -+{ -+ struct ieee80211_local *local = hw_to_local(hw); -+ struct ieee80211_fast_rx *fast_rx; -+ struct ieee80211_rx_data rx; -+ -+ memset(&rx, 0, sizeof(rx)); -+ rx.skb = skb; -+ rx.local = local; -+ rx.list = list; -+ -+ I802_DEBUG_INC(local->dot11ReceivedFragmentCount); -+ -+ /* drop frame if too short for header */ -+ if (skb->len < sizeof(struct ethhdr)) -+ goto drop; -+ -+ if (!pubsta) -+ goto drop; -+ -+ rx.sta = container_of(pubsta, struct sta_info, sta); -+ rx.sdata = rx.sta->sdata; -+ -+ fast_rx = rcu_dereference(rx.sta->fast_rx); -+ if (!fast_rx) -+ goto drop; -+ -+ ieee80211_rx_8023(&rx, fast_rx, skb->len); -+ return; -+ -+drop: -+ dev_kfree_skb(skb); -+} -+ - /* - * This is the actual Rx frames handler. as it belongs to Rx path it must - * be called with rcu_read_lock protection. -@@ -4850,15 +4923,20 @@ void ieee80211_rx_list(struct ieee80211_ - * if it was previously present. - * Also, frames with less than 16 bytes are dropped. - */ -- skb = ieee80211_rx_monitor(local, skb, rate); -- if (!skb) -- return; -+ if (!(status->flag & RX_FLAG_8023)) { -+ skb = ieee80211_rx_monitor(local, skb, rate); -+ if (!skb) -+ return; -+ } - - ieee80211_tpt_led_trig_rx(local, - ((struct ieee80211_hdr *)skb->data)->frame_control, - skb->len); - -- __ieee80211_rx_handle_packet(hw, pubsta, skb, list); -+ if (status->flag & RX_FLAG_8023) -+ __ieee80211_rx_handle_8023(hw, pubsta, skb, list); -+ else -+ __ieee80211_rx_handle_packet(hw, pubsta, skb, list); - - return; - drop: ---- a/net/mac80211/sta_info.h -+++ b/net/mac80211/sta_info.h -@@ -71,6 +71,7 @@ - * until pending frames are delivered - * @WLAN_STA_USES_ENCRYPTION: This station was configured for encryption, - * so drop all packets without a key later. -+ * @WLAN_STA_DECAP_OFFLOAD: This station uses rx decap offload - * - * @NUM_WLAN_STA_FLAGS: number of defined flags - */ -@@ -102,6 +103,7 @@ enum ieee80211_sta_info_flags { - WLAN_STA_MPSP_RECIPIENT, - WLAN_STA_PS_DELIVER, - WLAN_STA_USES_ENCRYPTION, -+ WLAN_STA_DECAP_OFFLOAD, - - NUM_WLAN_STA_FLAGS, - }; ---- a/net/mac80211/trace.h -+++ b/net/mac80211/trace.h -@@ -2761,7 +2761,7 @@ DEFINE_EVENT(local_sdata_addr_evt, drv_u - TP_ARGS(local, sdata) - ); - --TRACE_EVENT(drv_sta_set_4addr, -+DECLARE_EVENT_CLASS(sta_flag_evt, - TP_PROTO(struct ieee80211_local *local, - struct ieee80211_sub_if_data *sdata, - struct ieee80211_sta *sta, bool enabled), -@@ -2788,6 +2788,22 @@ TRACE_EVENT(drv_sta_set_4addr, - ) - ); - -+DEFINE_EVENT(sta_flag_evt, drv_sta_set_4addr, -+ TP_PROTO(struct ieee80211_local *local, -+ struct ieee80211_sub_if_data *sdata, -+ struct ieee80211_sta *sta, bool enabled), -+ -+ TP_ARGS(local, sdata, sta, enabled) -+); -+ -+DEFINE_EVENT(sta_flag_evt, drv_sta_set_decap_offload, -+ TP_PROTO(struct ieee80211_local *local, -+ struct ieee80211_sub_if_data *sdata, -+ struct ieee80211_sta *sta, bool enabled), -+ -+ TP_ARGS(local, sdata, sta, enabled) -+); -+ - #endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */ - - #undef TRACE_INCLUDE_PATH diff --git a/package/kernel/mac80211/patches/subsys/316-mac80211-enable-QoS-support-for-nl80211-ctrl-port.patch b/package/kernel/mac80211/patches/subsys/316-mac80211-enable-QoS-support-for-nl80211-ctrl-port.patch deleted file mode 100644 index 4be011ffec0..00000000000 --- a/package/kernel/mac80211/patches/subsys/316-mac80211-enable-QoS-support-for-nl80211-ctrl-port.patch +++ /dev/null @@ -1,116 +0,0 @@ -From: Markus Theil <markus.theil@tu-ilmenau.de> -Date: Sat, 6 Feb 2021 12:51:12 +0100 -Subject: [PATCH] mac80211: enable QoS support for nl80211 ctrl port - -This patch unifies sending control port frames -over nl80211 and AF_PACKET sockets a little more. - -Before this patch, EAPOL frames got QoS prioritization -only when using AF_PACKET sockets. - -__ieee80211_select_queue only selects a QoS-enabled queue -for control port frames, when the control port protocol -is set correctly on the skb. For the AF_PACKET path this -works, but the nl80211 path used ETH_P_802_3. - -Another check for injected frames in wme.c then prevented -the QoS TID to be copied in the frame. - -In order to fix this, get rid of the frame injection marking -for nl80211 ctrl port and set the correct ethernet protocol. - -Please note: -An erlier version of this path tried to prevent -frame aggregation for control port frames in order to speed up -the initial connection setup a little. This seemed to cause -issues on my older Intel dvm-based hardware, and was therefore -removed again. Future commits which try to reintroduce this -have to check carefully how hw behaves with aggregated and -non-aggregated traffic for the same TID. -My NIC: Intel(R) Centrino(R) Ultimate-N 6300 AGN, REV=0x74 - -Reported-by: kernel test robot <lkp@intel.com> -Signed-off-by: Markus Theil <markus.theil@tu-ilmenau.de> -Link: https://lore.kernel.org/r/20210206115112.567881-1-markus.theil@tu-ilmenau.de -Signed-off-by: Johannes Berg <johannes.berg@intel.com> ---- - ---- a/net/mac80211/status.c -+++ b/net/mac80211/status.c -@@ -628,16 +628,12 @@ static void ieee80211_report_ack_skb(str - u64 cookie = IEEE80211_SKB_CB(skb)->ack.cookie; - struct ieee80211_sub_if_data *sdata; - struct ieee80211_hdr *hdr = (void *)skb->data; -- __be16 ethertype = 0; -- -- if (skb->len >= ETH_HLEN && skb->protocol == cpu_to_be16(ETH_P_802_3)) -- skb_copy_bits(skb, 2 * ETH_ALEN, ðertype, ETH_TLEN); - - rcu_read_lock(); - sdata = ieee80211_sdata_from_skb(local, skb); - if (sdata) { -- if (ethertype == sdata->control_port_protocol || -- ethertype == cpu_to_be16(ETH_P_PREAUTH)) -+ if (skb->protocol == sdata->control_port_protocol || -+ skb->protocol == cpu_to_be16(ETH_P_PREAUTH)) - cfg80211_control_port_tx_status(&sdata->wdev, - cookie, - skb->data, ---- a/net/mac80211/tx.c -+++ b/net/mac80211/tx.c -@@ -1195,9 +1195,7 @@ ieee80211_tx_prepare(struct ieee80211_su - tx->sta = rcu_dereference(sdata->u.vlan.sta); - if (!tx->sta && sdata->wdev.use_4addr) - return TX_DROP; -- } else if (info->flags & (IEEE80211_TX_INTFL_NL80211_FRAME_TX | -- IEEE80211_TX_CTL_INJECTED) || -- tx->sdata->control_port_protocol == tx->skb->protocol) { -+ } else if (tx->sdata->control_port_protocol == tx->skb->protocol) { - tx->sta = sta_info_get_bss(sdata, hdr->addr1); - } - if (!tx->sta && !is_multicast_ether_addr(hdr->addr1)) -@@ -5421,6 +5419,7 @@ int ieee80211_tx_control_port(struct wip - { - 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 *skb; - struct ethhdr *ehdr; - u32 ctrl_flags = 0; -@@ -5443,8 +5442,7 @@ int ieee80211_tx_control_port(struct wip - if (cookie) - ctrl_flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; - -- flags |= IEEE80211_TX_INTFL_NL80211_FRAME_TX | -- IEEE80211_TX_CTL_INJECTED; -+ flags |= IEEE80211_TX_INTFL_NL80211_FRAME_TX; - - skb = dev_alloc_skb(local->hw.extra_tx_headroom + - sizeof(struct ethhdr) + len); -@@ -5461,10 +5459,25 @@ int ieee80211_tx_control_port(struct wip - ehdr->h_proto = proto; - - skb->dev = dev; -- skb->protocol = htons(ETH_P_802_3); -+ skb->protocol = proto; - skb_reset_network_header(skb); - skb_reset_mac_header(skb); - -+ /* update QoS header to prioritize control port frames if possible, -+ * priorization also happens for control port frames send over -+ * AF_PACKET -+ */ -+ rcu_read_lock(); -+ -+ if (ieee80211_lookup_ra_sta(sdata, skb, &sta) == 0 && !IS_ERR(sta)) { -+ u16 queue = __ieee80211_select_queue(sdata, sta, skb); -+ -+ skb_set_queue_mapping(skb, queue); -+ skb_get_hash(skb); -+ } -+ -+ rcu_read_unlock(); -+ - /* mutex lock is only needed for incrementing the cookie counter */ - mutex_lock(&local->mtx); - diff --git a/package/kernel/mac80211/patches/subsys/320-cfg80211-allow-grace-period-for-DFS-available-after-.patch b/package/kernel/mac80211/patches/subsys/320-cfg80211-allow-grace-period-for-DFS-available-after-.patch new file mode 100644 index 00000000000..28e2144f7f5 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/320-cfg80211-allow-grace-period-for-DFS-available-after-.patch @@ -0,0 +1,149 @@ +From: Felix Fietkau <nbd@nbd.name> +Date: Thu, 14 Sep 2023 13:17:16 +0200 +Subject: [PATCH] cfg80211: allow grace period for DFS available after beacon + shutdown + +Fixes reconfiguring an AP on a DFS channel in non-ETSI regdomain + +Fixes: b35a51c7dd25 ("cfg80211: Make pre-CAC results valid only for ETSI domain") +Signed-off-by: Felix Fietkau <nbd@nbd.name> +--- + +--- a/include/net/cfg80211.h ++++ b/include/net/cfg80211.h +@@ -175,6 +175,8 @@ enum ieee80211_channel_flags { + * @dfs_state: current state of this channel. Only relevant if radar is required + * on this channel. + * @dfs_state_entered: timestamp (jiffies) when the dfs state was entered. ++ * @dfs_state_last_available: timestamp (jiffies) of the last time when the ++ * channel was available. + * @dfs_cac_ms: DFS CAC time in milliseconds, this is valid for DFS channels. + */ + struct ieee80211_channel { +@@ -191,6 +193,7 @@ struct ieee80211_channel { + int orig_mag, orig_mpwr; + enum nl80211_dfs_state dfs_state; + unsigned long dfs_state_entered; ++ unsigned long dfs_state_last_available; + unsigned int dfs_cac_ms; + }; + +--- a/net/wireless/ap.c ++++ b/net/wireless/ap.c +@@ -30,6 +30,9 @@ static int ___cfg80211_stop_ap(struct cf + if (!wdev->links[link_id].ap.beacon_interval) + return -ENOENT; + ++ cfg80211_update_last_available(wdev->wiphy, ++ &wdev->links[link_id].ap.chandef); ++ + err = rdev_stop_ap(rdev, dev, link_id); + if (!err) { + wdev->conn_owner_nlportid = 0; +@@ -41,9 +44,6 @@ static int ___cfg80211_stop_ap(struct cf + if (notify) + nl80211_send_ap_stopped(wdev, link_id); + +- /* Should we apply the grace period during beaconing interface +- * shutdown also? +- */ + cfg80211_sched_dfs_chan_update(rdev); + } + +--- a/net/wireless/chan.c ++++ b/net/wireless/chan.c +@@ -461,6 +461,8 @@ static void cfg80211_set_chans_dfs_state + + c->dfs_state = dfs_state; + c->dfs_state_entered = jiffies; ++ if (dfs_state == NL80211_DFS_AVAILABLE) ++ c->dfs_state_last_available = jiffies; + } + } + +@@ -874,6 +876,49 @@ static bool cfg80211_get_chans_dfs_avail + return true; + } + ++static void ++__cfg80211_update_last_available(struct wiphy *wiphy, ++ u32 center_freq, ++ u32 bandwidth) ++{ ++ struct ieee80211_channel *c; ++ u32 freq, start_freq, end_freq; ++ ++ start_freq = cfg80211_get_start_freq(center_freq, bandwidth); ++ end_freq = cfg80211_get_end_freq(center_freq, bandwidth); ++ ++ /* ++ * Check entire range of channels for the bandwidth. ++ * If any channel in between is disabled or has not ++ * had gone through CAC return false ++ */ ++ for (freq = start_freq; freq <= end_freq; freq += MHZ_TO_KHZ(20)) { ++ c = ieee80211_get_channel_khz(wiphy, freq); ++ if (!c) ++ return; ++ ++ c->dfs_state_last_available = jiffies; ++ } ++} ++ ++void cfg80211_update_last_available(struct wiphy *wiphy, ++ const struct cfg80211_chan_def *chandef) ++{ ++ int width; ++ ++ width = cfg80211_chandef_get_width(chandef); ++ if (width < 0) ++ return; ++ ++ __cfg80211_update_last_available(wiphy, MHZ_TO_KHZ(chandef->center_freq1), ++ width); ++ if (chandef->width != NL80211_CHAN_WIDTH_80P80) ++ return; ++ ++ __cfg80211_update_last_available(wiphy, MHZ_TO_KHZ(chandef->center_freq2), ++ width); ++} ++ + static bool cfg80211_chandef_dfs_available(struct wiphy *wiphy, + const struct cfg80211_chan_def *chandef) + { +--- a/net/wireless/core.h ++++ b/net/wireless/core.h +@@ -474,6 +474,8 @@ void cfg80211_set_dfs_state(struct wiphy + enum nl80211_dfs_state dfs_state); + + void cfg80211_dfs_channels_update_work(struct work_struct *work); ++void cfg80211_update_last_available(struct wiphy *wiphy, ++ const struct cfg80211_chan_def *chandef); + + void cfg80211_sched_dfs_chan_update(struct cfg80211_registered_device *rdev); + +--- a/net/wireless/mlme.c ++++ b/net/wireless/mlme.c +@@ -915,6 +915,8 @@ void cfg80211_dfs_channels_update_work(s + if (c->dfs_state == NL80211_DFS_UNAVAILABLE) { + time_dfs_update = IEEE80211_DFS_MIN_NOP_TIME_MS; + radar_event = NL80211_RADAR_NOP_FINISHED; ++ timeout = c->dfs_state_entered + ++ msecs_to_jiffies(time_dfs_update); + } else { + if (regulatory_pre_cac_allowed(wiphy) || + cfg80211_any_wiphy_oper_chan(wiphy, c)) +@@ -922,11 +924,10 @@ void cfg80211_dfs_channels_update_work(s + + time_dfs_update = REG_PRE_CAC_EXPIRY_GRACE_MS; + radar_event = NL80211_RADAR_PRE_CAC_EXPIRED; ++ timeout = c->dfs_state_last_available + ++ msecs_to_jiffies(time_dfs_update); + } + +- timeout = c->dfs_state_entered + +- msecs_to_jiffies(time_dfs_update); +- + if (time_after_eq(jiffies, timeout)) { + c->dfs_state = NL80211_DFS_USABLE; + c->dfs_state_entered = jiffies; diff --git a/package/kernel/mac80211/patches/subsys/320-mac80211_hwsim-add-6GHz-channels.patch b/package/kernel/mac80211/patches/subsys/320-mac80211_hwsim-add-6GHz-channels.patch deleted file mode 100644 index a7c09f00bc4..00000000000 --- a/package/kernel/mac80211/patches/subsys/320-mac80211_hwsim-add-6GHz-channels.patch +++ /dev/null @@ -1,123 +0,0 @@ -From: Ramon Fontes <ramonreisfontes@gmail.com> -Date: Sun, 27 Dec 2020 00:11:55 -0300 -Subject: [PATCH] mac80211_hwsim: add 6GHz channels - -Advertise 6GHz channels to mac80211. - -Signed-off-by: Ramon Fontes <ramonreisfontes@gmail.com> -Link: https://lore.kernel.org/r/20201227031155.81161-1-ramonreisfontes@gmail.com -[reword commit message] -Signed-off-by: Johannes Berg <johannes.berg@intel.com> ---- - ---- a/drivers/net/wireless/mac80211_hwsim.c -+++ b/drivers/net/wireless/mac80211_hwsim.c -@@ -311,6 +311,12 @@ static struct net_device *hwsim_mon; /* - .hw_value = (_freq), \ - } - -+#define CHAN6G(_freq) { \ -+ .band = NL80211_BAND_6GHZ, \ -+ .center_freq = (_freq), \ -+ .hw_value = (_freq), \ -+} -+ - static const struct ieee80211_channel hwsim_channels_2ghz[] = { - CHAN2G(2412), /* Channel 1 */ - CHAN2G(2417), /* Channel 2 */ -@@ -377,6 +383,68 @@ static const struct ieee80211_channel hw - CHAN5G(5925), /* Channel 185 */ - }; - -+static const struct ieee80211_channel hwsim_channels_6ghz[] = { -+ CHAN6G(5955), /* Channel 1 */ -+ CHAN6G(5975), /* Channel 5 */ -+ CHAN6G(5995), /* Channel 9 */ -+ CHAN6G(6015), /* Channel 13 */ -+ CHAN6G(6035), /* Channel 17 */ -+ CHAN6G(6055), /* Channel 21 */ -+ CHAN6G(6075), /* Channel 25 */ -+ CHAN6G(6095), /* Channel 29 */ -+ CHAN6G(6115), /* Channel 33 */ -+ CHAN6G(6135), /* Channel 37 */ -+ CHAN6G(6155), /* Channel 41 */ -+ CHAN6G(6175), /* Channel 45 */ -+ CHAN6G(6195), /* Channel 49 */ -+ CHAN6G(6215), /* Channel 53 */ -+ CHAN6G(6235), /* Channel 57 */ -+ CHAN6G(6255), /* Channel 61 */ -+ CHAN6G(6275), /* Channel 65 */ -+ CHAN6G(6295), /* Channel 69 */ -+ CHAN6G(6315), /* Channel 73 */ -+ CHAN6G(6335), /* Channel 77 */ -+ CHAN6G(6355), /* Channel 81 */ -+ CHAN6G(6375), /* Channel 85 */ -+ CHAN6G(6395), /* Channel 89 */ -+ CHAN6G(6415), /* Channel 93 */ -+ CHAN6G(6435), /* Channel 97 */ -+ CHAN6G(6455), /* Channel 181 */ -+ CHAN6G(6475), /* Channel 105 */ -+ CHAN6G(6495), /* Channel 109 */ -+ CHAN6G(6515), /* Channel 113 */ -+ CHAN6G(6535), /* Channel 117 */ -+ CHAN6G(6555), /* Channel 121 */ -+ CHAN6G(6575), /* Channel 125 */ -+ CHAN6G(6595), /* Channel 129 */ -+ CHAN6G(6615), /* Channel 133 */ -+ CHAN6G(6635), /* Channel 137 */ -+ CHAN6G(6655), /* Channel 141 */ -+ CHAN6G(6675), /* Channel 145 */ -+ CHAN6G(6695), /* Channel 149 */ -+ CHAN6G(6715), /* Channel 153 */ -+ CHAN6G(6735), /* Channel 157 */ -+ CHAN6G(6755), /* Channel 161 */ -+ CHAN6G(6775), /* Channel 165 */ -+ CHAN6G(6795), /* Channel 169 */ -+ CHAN6G(6815), /* Channel 173 */ -+ CHAN6G(6835), /* Channel 177 */ -+ CHAN6G(6855), /* Channel 181 */ -+ CHAN6G(6875), /* Channel 185 */ -+ CHAN6G(6895), /* Channel 189 */ -+ CHAN6G(6915), /* Channel 193 */ -+ CHAN6G(6935), /* Channel 197 */ -+ CHAN6G(6955), /* Channel 201 */ -+ CHAN6G(6975), /* Channel 205 */ -+ CHAN6G(6995), /* Channel 209 */ -+ CHAN6G(7015), /* Channel 213 */ -+ CHAN6G(7035), /* Channel 217 */ -+ CHAN6G(7055), /* Channel 221 */ -+ CHAN6G(7075), /* Channel 225 */ -+ CHAN6G(7095), /* Channel 229 */ -+ CHAN6G(7115), /* Channel 233 */ -+}; -+ - #define NUM_S1G_CHANS_US 51 - static struct ieee80211_channel hwsim_channels_s1g[NUM_S1G_CHANS_US]; - -@@ -548,6 +616,7 @@ struct mac80211_hwsim_data { - struct ieee80211_supported_band bands[NUM_NL80211_BANDS]; - struct ieee80211_channel channels_2ghz[ARRAY_SIZE(hwsim_channels_2ghz)]; - struct ieee80211_channel channels_5ghz[ARRAY_SIZE(hwsim_channels_5ghz)]; -+ struct ieee80211_channel channels_6ghz[ARRAY_SIZE(hwsim_channels_6ghz)]; - struct ieee80211_channel channels_s1g[ARRAY_SIZE(hwsim_channels_s1g)]; - struct ieee80211_rate rates[ARRAY_SIZE(hwsim_rates)]; - struct ieee80211_iface_combination if_combination; -@@ -578,7 +647,8 @@ struct mac80211_hwsim_data { - struct ieee80211_channel *channel; - unsigned long next_start, start, end; - } survey_data[ARRAY_SIZE(hwsim_channels_2ghz) + -- ARRAY_SIZE(hwsim_channels_5ghz)]; -+ ARRAY_SIZE(hwsim_channels_5ghz) + -+ ARRAY_SIZE(hwsim_channels_6ghz)]; - - struct ieee80211_channel *channel; - u64 beacon_int /* beacon interval in us */; -@@ -3149,6 +3219,8 @@ static int mac80211_hwsim_new_radio(stru - sizeof(hwsim_channels_2ghz)); - memcpy(data->channels_5ghz, hwsim_channels_5ghz, - sizeof(hwsim_channels_5ghz)); -+ memcpy(data->channels_6ghz, hwsim_channels_6ghz, -+ sizeof(hwsim_channels_6ghz)); - memcpy(data->channels_s1g, hwsim_channels_s1g, - sizeof(hwsim_channels_s1g)); - memcpy(data->rates, hwsim_rates, sizeof(hwsim_rates)); diff --git a/package/kernel/mac80211/patches/subsys/321-mac80211_hwsim-make-6-GHz-channels-usable.patch b/package/kernel/mac80211/patches/subsys/321-mac80211_hwsim-make-6-GHz-channels-usable.patch deleted file mode 100644 index 4bac10eefe7..00000000000 --- a/package/kernel/mac80211/patches/subsys/321-mac80211_hwsim-make-6-GHz-channels-usable.patch +++ /dev/null @@ -1,74 +0,0 @@ -From: Felix Fietkau <nbd@nbd.name> -Date: Mon, 24 May 2021 11:46:09 +0200 -Subject: [PATCH] mac80211_hwsim: make 6 GHz channels usable - -The previous commit that claimed to add 6 GHz channels didn't actually make -them usable, since the 6 GHz band was not registered with mac80211. - -Fixes: 28881922abd7 ("mac80211_hwsim: add 6GHz channels") -Signed-off-by: Felix Fietkau <nbd@nbd.name> ---- - ---- a/drivers/net/wireless/mac80211_hwsim.c -+++ b/drivers/net/wireless/mac80211_hwsim.c -@@ -2968,15 +2968,19 @@ static void mac80211_hwsim_he_capab(stru - { - u16 n_iftype_data; - -- if (sband->band == NL80211_BAND_2GHZ) { -+ switch (sband->band) { -+ case NL80211_BAND_2GHZ: - n_iftype_data = ARRAY_SIZE(he_capa_2ghz); - sband->iftype_data = - (struct ieee80211_sband_iftype_data *)he_capa_2ghz; -- } else if (sband->band == NL80211_BAND_5GHZ) { -+ break; -+ case NL80211_BAND_5GHZ: -+ case NL80211_BAND_6GHZ: - n_iftype_data = ARRAY_SIZE(he_capa_5ghz); - sband->iftype_data = - (struct ieee80211_sband_iftype_data *)he_capa_5ghz; -- } else { -+ break; -+ default: - return; - } - -@@ -3265,6 +3269,12 @@ static int mac80211_hwsim_new_radio(stru - sband->vht_cap.vht_mcs.tx_mcs_map = - sband->vht_cap.vht_mcs.rx_mcs_map; - break; -+ case NL80211_BAND_6GHZ: -+ sband->channels = data->channels_6ghz; -+ sband->n_channels = ARRAY_SIZE(hwsim_channels_6ghz); -+ sband->bitrates = data->rates + 4; -+ sband->n_bitrates = ARRAY_SIZE(hwsim_rates) - 4; -+ break; - case NL80211_BAND_S1GHZ: - memcpy(&sband->s1g_cap, &hwsim_s1g_cap, - sizeof(sband->s1g_cap)); -@@ -3275,6 +3285,13 @@ static int mac80211_hwsim_new_radio(stru - continue; - } - -+ mac80211_hwsim_he_capab(sband); -+ -+ hw->wiphy->bands[band] = sband; -+ -+ if (band == NL80211_BAND_6GHZ) -+ continue; -+ - sband->ht_cap.ht_supported = true; - sband->ht_cap.cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | - IEEE80211_HT_CAP_GRN_FLD | -@@ -3288,10 +3305,6 @@ static int mac80211_hwsim_new_radio(stru - sband->ht_cap.mcs.rx_mask[0] = 0xff; - sband->ht_cap.mcs.rx_mask[1] = 0xff; - sband->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; -- -- mac80211_hwsim_he_capab(sband); -- -- hw->wiphy->bands[band] = sband; - } - - /* By default all radios belong to the first group */ diff --git a/package/kernel/mac80211/patches/subsys/337-mac80211-minstrel_ht-clean-up-CCK-code.patch b/package/kernel/mac80211/patches/subsys/337-mac80211-minstrel_ht-clean-up-CCK-code.patch deleted file mode 100644 index f667d2c94e5..00000000000 --- a/package/kernel/mac80211/patches/subsys/337-mac80211-minstrel_ht-clean-up-CCK-code.patch +++ /dev/null @@ -1,166 +0,0 @@ -From: Felix Fietkau <nbd@nbd.name> -Date: Fri, 25 Dec 2020 16:22:52 +0100 -Subject: [PATCH] mac80211: minstrel_ht: clean up CCK code - -- move ack overhead out of rate duration table -- remove cck_supported, cck_supported_short - -Preparation for adding OFDM legacy rates support - -Signed-off-by: Felix Fietkau <nbd@nbd.name> ---- - ---- a/net/mac80211/rc80211_minstrel_ht.c -+++ b/net/mac80211/rc80211_minstrel_ht.c -@@ -136,20 +136,16 @@ - __VHT_GROUP(_streams, _sgi, _bw, \ - VHT_GROUP_SHIFT(_streams, _sgi, _bw)) - --#define CCK_DURATION(_bitrate, _short, _len) \ -+#define CCK_DURATION(_bitrate, _short) \ - (1000 * (10 /* SIFS */ + \ - (_short ? 72 + 24 : 144 + 48) + \ -- (8 * (_len + 4) * 10) / (_bitrate))) -- --#define CCK_ACK_DURATION(_bitrate, _short) \ -- (CCK_DURATION((_bitrate > 10 ? 20 : 10), false, 60) + \ -- CCK_DURATION(_bitrate, _short, AVG_PKT_SIZE)) -+ (8 * (AVG_PKT_SIZE + 4) * 10) / (_bitrate))) - - #define CCK_DURATION_LIST(_short, _s) \ -- CCK_ACK_DURATION(10, _short) >> _s, \ -- CCK_ACK_DURATION(20, _short) >> _s, \ -- CCK_ACK_DURATION(55, _short) >> _s, \ -- CCK_ACK_DURATION(110, _short) >> _s -+ CCK_DURATION(10, _short) >> _s, \ -+ CCK_DURATION(20, _short) >> _s, \ -+ CCK_DURATION(55, _short) >> _s, \ -+ CCK_DURATION(110, _short) >> _s - - #define __CCK_GROUP(_s) \ - [MINSTREL_CCK_GROUP] = { \ -@@ -163,7 +159,7 @@ - } - - #define CCK_GROUP_SHIFT \ -- GROUP_SHIFT(CCK_ACK_DURATION(10, false)) -+ GROUP_SHIFT(CCK_DURATION(10, false)) - - #define CCK_GROUP __CCK_GROUP(CCK_GROUP_SHIFT) - -@@ -349,15 +345,19 @@ int - minstrel_ht_get_tp_avg(struct minstrel_ht_sta *mi, int group, int rate, - int prob_avg) - { -- unsigned int nsecs = 0; -+ unsigned int nsecs = 0, overhead = mi->overhead; -+ unsigned int ampdu_len = 1; - - /* do not account throughput if sucess prob is below 10% */ - if (prob_avg < MINSTREL_FRAC(10, 100)) - return 0; - -- if (group != MINSTREL_CCK_GROUP) -- nsecs = 1000 * mi->overhead / minstrel_ht_avg_ampdu_len(mi); -+ if (group == MINSTREL_CCK_GROUP) -+ overhead = mi->overhead_legacy; -+ else -+ ampdu_len = minstrel_ht_avg_ampdu_len(mi); - -+ nsecs = 1000 * overhead / ampdu_len; - nsecs += minstrel_mcs_groups[group].duration[rate] << - minstrel_mcs_groups[group].shift; - -@@ -1031,7 +1031,10 @@ minstrel_calc_retransmit(struct minstrel - ctime += (t_slot * cw) >> 1; - cw = min((cw << 1) | 1, mp->cw_max); - -- if (index / MCS_GROUP_RATES != MINSTREL_CCK_GROUP) { -+ if (index / MCS_GROUP_RATES == MINSTREL_CCK_GROUP) { -+ overhead = mi->overhead_legacy; -+ overhead_rtscts = mi->overhead_legacy_rtscts; -+ } else { - overhead = mi->overhead; - overhead_rtscts = mi->overhead_rtscts; - } -@@ -1369,18 +1372,14 @@ minstrel_ht_update_cck(struct minstrel_p - if (!ieee80211_hw_check(mp->hw, SUPPORTS_HT_CCK_RATES)) - return; - -- mi->cck_supported = 0; -- mi->cck_supported_short = 0; - for (i = 0; i < 4; i++) { - if (!rate_supported(sta, sband->band, mp->cck_rates[i])) - continue; - -- mi->cck_supported |= BIT(i); -+ mi->supported[MINSTREL_CCK_GROUP] |= BIT(i); - if (sband->bitrates[i].flags & IEEE80211_RATE_SHORT_PREAMBLE) -- mi->cck_supported_short |= BIT(i); -+ mi->supported[MINSTREL_CCK_GROUP] |= BIT(i + 4); - } -- -- mi->supported[MINSTREL_CCK_GROUP] = mi->cck_supported; - } - - static void -@@ -1394,12 +1393,13 @@ minstrel_ht_update_caps(void *priv, stru - struct ieee80211_mcs_info *mcs = &sta->ht_cap.mcs; - u16 ht_cap = sta->ht_cap.cap; - struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap; -+ const struct ieee80211_rate *ctl_rate; -+ bool ldpc, erp; - int use_vht; - int n_supported = 0; - int ack_dur; - int stbc; - int i; -- bool ldpc; - - /* fall back to the old minstrel for legacy stations */ - if (!sta->ht_cap.ht_supported) -@@ -1423,6 +1423,14 @@ minstrel_ht_update_caps(void *priv, stru - mi->overhead += ack_dur; - mi->overhead_rtscts = mi->overhead + 2 * ack_dur; - -+ ctl_rate = &sband->bitrates[rate_lowest_index(sband, sta)]; -+ erp = ctl_rate->flags & IEEE80211_RATE_ERP_G; -+ ack_dur = ieee80211_frame_duration(sband->band, 10, -+ ctl_rate->bitrate, erp, 1, -+ ieee80211_chandef_get_shift(chandef)); -+ mi->overhead_legacy = ack_dur; -+ mi->overhead_legacy_rtscts = mi->overhead_legacy + 2 * ack_dur; -+ - mi->avg_ampdu_len = MINSTREL_FRAC(1, 1); - - /* When using MRR, sample more on the first attempt, without delay */ -@@ -1523,8 +1531,6 @@ minstrel_ht_update_caps(void *priv, stru - if (!n_supported) - goto use_legacy; - -- mi->supported[MINSTREL_CCK_GROUP] |= mi->cck_supported_short << 4; -- - /* create an initial rate table with the lowest supported rates */ - minstrel_ht_update_stats(mp, mi, true); - minstrel_ht_update_rates(mp, mi); ---- a/net/mac80211/rc80211_minstrel_ht.h -+++ b/net/mac80211/rc80211_minstrel_ht.h -@@ -77,6 +77,8 @@ struct minstrel_ht_sta { - /* overhead time in usec for each frame */ - unsigned int overhead; - unsigned int overhead_rtscts; -+ unsigned int overhead_legacy; -+ unsigned int overhead_legacy_rtscts; - - unsigned int total_packets_last; - unsigned int total_packets_cur; -@@ -97,9 +99,6 @@ struct minstrel_ht_sta { - /* current MCS group to be sampled */ - u8 sample_group; - -- u8 cck_supported; -- u8 cck_supported_short; -- - /* Bitfield of supported MCS rates of all groups */ - u16 supported[MINSTREL_GROUPS_NB]; - diff --git a/package/kernel/mac80211/patches/subsys/338-mac80211-minstrel_ht-add-support-for-OFDM-rates-on-n.patch b/package/kernel/mac80211/patches/subsys/338-mac80211-minstrel_ht-add-support-for-OFDM-rates-on-n.patch deleted file mode 100644 index abefde7109c..00000000000 --- a/package/kernel/mac80211/patches/subsys/338-mac80211-minstrel_ht-add-support-for-OFDM-rates-on-n.patch +++ /dev/null @@ -1,762 +0,0 @@ -From: Felix Fietkau <nbd@nbd.name> -Date: Sat, 26 Dec 2020 13:56:42 +0100 -Subject: [PATCH] mac80211: minstrel_ht: add support for OFDM rates on - non-HT clients - -The legacy minstrel code is essentially unmaintained and receives only very -little testing. In order to bring the significant algorithm improvements from -minstrel_ht to legacy clients, this patch adds support for OFDM rates to -minstrel_ht and removes the fallback to the legacy codepath. -This also makes it work much better on hardware with rate selection constraints, -e.g. mt76. - -Signed-off-by: Felix Fietkau <nbd@nbd.name> ---- - ---- a/net/mac80211/rc80211_minstrel.h -+++ b/net/mac80211/rc80211_minstrel.h -@@ -152,6 +152,7 @@ struct minstrel_priv { - unsigned int lookaround_rate_mrr; - - u8 cck_rates[4]; -+ u8 ofdm_rates[NUM_NL80211_BANDS][8]; - - #ifdef CPTCFG_MAC80211_DEBUGFS - /* ---- a/net/mac80211/rc80211_minstrel_ht.c -+++ b/net/mac80211/rc80211_minstrel_ht.c -@@ -163,6 +163,38 @@ - - #define CCK_GROUP __CCK_GROUP(CCK_GROUP_SHIFT) - -+#define OFDM_DURATION(_bitrate) \ -+ (1000 * (16 /* SIFS + signal ext */ + \ -+ 16 /* T_PREAMBLE */ + \ -+ 4 /* T_SIGNAL */ + \ -+ 4 * (((16 + 80 * (AVG_PKT_SIZE + 4) + 6) / \ -+ ((_bitrate) * 4))))) -+ -+#define OFDM_DURATION_LIST(_s) \ -+ OFDM_DURATION(60) >> _s, \ -+ OFDM_DURATION(90) >> _s, \ -+ OFDM_DURATION(120) >> _s, \ -+ OFDM_DURATION(180) >> _s, \ -+ OFDM_DURATION(240) >> _s, \ -+ OFDM_DURATION(360) >> _s, \ -+ OFDM_DURATION(480) >> _s, \ -+ OFDM_DURATION(540) >> _s -+ -+#define __OFDM_GROUP(_s) \ -+ [MINSTREL_OFDM_GROUP] = { \ -+ .streams = 1, \ -+ .flags = 0, \ -+ .shift = _s, \ -+ .duration = { \ -+ OFDM_DURATION_LIST(_s), \ -+ } \ -+ } -+ -+#define OFDM_GROUP_SHIFT \ -+ GROUP_SHIFT(OFDM_DURATION(60)) -+ -+#define OFDM_GROUP __OFDM_GROUP(OFDM_GROUP_SHIFT) -+ - - static bool minstrel_vht_only = true; - module_param(minstrel_vht_only, bool, 0644); -@@ -199,6 +231,7 @@ const struct mcs_group minstrel_mcs_grou - MCS_GROUP(4, 1, BW_40), - - CCK_GROUP, -+ OFDM_GROUP, - - VHT_GROUP(1, 0, BW_20), - VHT_GROUP(2, 0, BW_20), -@@ -231,6 +264,8 @@ const struct mcs_group minstrel_mcs_grou - VHT_GROUP(4, 1, BW_80), - }; - -+const s16 minstrel_cck_bitrates[4] = { 10, 20, 55, 110 }; -+const s16 minstrel_ofdm_bitrates[8] = { 60, 90, 120, 180, 240, 360, 480, 540 }; - static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES] __read_mostly; - - static void -@@ -275,6 +310,13 @@ minstrel_get_valid_vht_rates(int bw, int - return 0x3ff & ~mask; - } - -+static bool -+minstrel_ht_is_legacy_group(int group) -+{ -+ return group == MINSTREL_CCK_GROUP || -+ group == MINSTREL_OFDM_GROUP; -+} -+ - /* - * Look up an MCS group index based on mac80211 rate information - */ -@@ -304,21 +346,34 @@ minstrel_ht_get_stats(struct minstrel_pr - if (rate->flags & IEEE80211_TX_RC_MCS) { - group = minstrel_ht_get_group_idx(rate); - idx = rate->idx % 8; -- } else if (rate->flags & IEEE80211_TX_RC_VHT_MCS) { -+ goto out; -+ } -+ -+ if (rate->flags & IEEE80211_TX_RC_VHT_MCS) { - group = minstrel_vht_get_group_idx(rate); - idx = ieee80211_rate_get_vht_mcs(rate); -- } else { -- group = MINSTREL_CCK_GROUP; -+ goto out; -+ } - -- for (idx = 0; idx < ARRAY_SIZE(mp->cck_rates); idx++) -- if (rate->idx == mp->cck_rates[idx]) -- break; -+ group = MINSTREL_CCK_GROUP; -+ for (idx = 0; idx < ARRAY_SIZE(mp->cck_rates); idx++) { -+ if (rate->idx != mp->cck_rates[idx]) -+ continue; - - /* short preamble */ - if ((mi->supported[group] & BIT(idx + 4)) && - (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)) -- idx += 4; -+ idx += 4; -+ goto out; - } -+ -+ group = MINSTREL_OFDM_GROUP; -+ for (idx = 0; idx < ARRAY_SIZE(mp->ofdm_rates[0]); idx++) -+ if (rate->idx == mp->ofdm_rates[mi->band][idx]) -+ goto out; -+ -+ idx = 0; -+out: - return &mi->groups[group].rates[idx]; - } - -@@ -352,7 +407,7 @@ minstrel_ht_get_tp_avg(struct minstrel_h - if (prob_avg < MINSTREL_FRAC(10, 100)) - return 0; - -- if (group == MINSTREL_CCK_GROUP) -+ if (minstrel_ht_is_legacy_group(group)) - overhead = mi->overhead_legacy; - else - ampdu_len = minstrel_ht_avg_ampdu_len(mi); -@@ -439,8 +494,8 @@ minstrel_ht_set_best_prob_rate(struct mi - /* if max_tp_rate[0] is from MCS_GROUP max_prob_rate get selected from - * MCS_GROUP as well as CCK_GROUP rates do not allow aggregation */ - max_tp_group = mi->max_tp_rate[0] / MCS_GROUP_RATES; -- if((index / MCS_GROUP_RATES == MINSTREL_CCK_GROUP) && -- (max_tp_group != MINSTREL_CCK_GROUP)) -+ if (minstrel_ht_is_legacy_group(index / MCS_GROUP_RATES) && -+ !minstrel_ht_is_legacy_group(max_tp_group)) - return; - - max_gpr_group = mg->max_group_prob_rate / MCS_GROUP_RATES; -@@ -476,13 +531,13 @@ minstrel_ht_set_best_prob_rate(struct mi - static void - minstrel_ht_assign_best_tp_rates(struct minstrel_ht_sta *mi, - u16 tmp_mcs_tp_rate[MAX_THR_RATES], -- u16 tmp_cck_tp_rate[MAX_THR_RATES]) -+ u16 tmp_legacy_tp_rate[MAX_THR_RATES]) - { - unsigned int tmp_group, tmp_idx, tmp_cck_tp, tmp_mcs_tp, tmp_prob; - int i; - -- tmp_group = tmp_cck_tp_rate[0] / MCS_GROUP_RATES; -- tmp_idx = tmp_cck_tp_rate[0] % MCS_GROUP_RATES; -+ tmp_group = tmp_legacy_tp_rate[0] / MCS_GROUP_RATES; -+ tmp_idx = tmp_legacy_tp_rate[0] % MCS_GROUP_RATES; - tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_avg; - tmp_cck_tp = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx, tmp_prob); - -@@ -493,7 +548,7 @@ minstrel_ht_assign_best_tp_rates(struct - - if (tmp_cck_tp > tmp_mcs_tp) { - for(i = 0; i < MAX_THR_RATES; i++) { -- minstrel_ht_sort_best_tp_rates(mi, tmp_cck_tp_rate[i], -+ minstrel_ht_sort_best_tp_rates(mi, tmp_legacy_tp_rate[i], - tmp_mcs_tp_rate); - } - } -@@ -511,6 +566,9 @@ minstrel_ht_prob_rate_reduce_streams(str - int tmp_max_streams, group, tmp_idx, tmp_prob; - int tmp_tp = 0; - -+ if (!mi->sta->ht_cap.ht_supported) -+ return; -+ - tmp_max_streams = minstrel_mcs_groups[mi->max_tp_rate[0] / - MCS_GROUP_RATES].streams; - for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) { -@@ -675,7 +733,8 @@ minstrel_ht_update_stats(struct minstrel - struct minstrel_rate_stats *mrs; - int group, i, j, cur_prob; - u16 tmp_mcs_tp_rate[MAX_THR_RATES], tmp_group_tp_rate[MAX_THR_RATES]; -- u16 tmp_cck_tp_rate[MAX_THR_RATES], index; -+ u16 tmp_legacy_tp_rate[MAX_THR_RATES], index; -+ bool ht_supported = mi->sta->ht_cap.ht_supported; - - mi->sample_mode = MINSTREL_SAMPLE_IDLE; - -@@ -704,21 +763,29 @@ minstrel_ht_update_stats(struct minstrel - mi->sample_count = 0; - - memset(tmp_mcs_tp_rate, 0, sizeof(tmp_mcs_tp_rate)); -- memset(tmp_cck_tp_rate, 0, sizeof(tmp_cck_tp_rate)); -+ memset(tmp_legacy_tp_rate, 0, sizeof(tmp_legacy_tp_rate)); - if (mi->supported[MINSTREL_CCK_GROUP]) -- for (j = 0; j < ARRAY_SIZE(tmp_cck_tp_rate); j++) -- tmp_cck_tp_rate[j] = MINSTREL_CCK_GROUP * MCS_GROUP_RATES; -+ for (j = 0; j < ARRAY_SIZE(tmp_legacy_tp_rate); j++) -+ tmp_legacy_tp_rate[j] = MINSTREL_CCK_GROUP * MCS_GROUP_RATES; -+ else if (mi->supported[MINSTREL_OFDM_GROUP]) -+ for (j = 0; j < ARRAY_SIZE(tmp_legacy_tp_rate); j++) -+ tmp_legacy_tp_rate[j] = MINSTREL_OFDM_GROUP * MCS_GROUP_RATES; - - if (mi->supported[MINSTREL_VHT_GROUP_0]) - index = MINSTREL_VHT_GROUP_0 * MCS_GROUP_RATES; -- else -+ else if (ht_supported) - index = MINSTREL_HT_GROUP_0 * MCS_GROUP_RATES; -+ else if (mi->supported[MINSTREL_CCK_GROUP]) -+ index = MINSTREL_CCK_GROUP * MCS_GROUP_RATES; -+ else -+ index = MINSTREL_OFDM_GROUP * MCS_GROUP_RATES; - - for (j = 0; j < ARRAY_SIZE(tmp_mcs_tp_rate); j++) - tmp_mcs_tp_rate[j] = index; - - /* Find best rate sets within all MCS groups*/ - for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) { -+ u16 *tp_rate = tmp_mcs_tp_rate; - - mg = &mi->groups[group]; - if (!mi->supported[group]) -@@ -730,6 +797,9 @@ minstrel_ht_update_stats(struct minstrel - for(j = 0; j < MAX_THR_RATES; j++) - tmp_group_tp_rate[j] = MCS_GROUP_RATES * group; - -+ if (group == MINSTREL_CCK_GROUP && ht_supported) -+ tp_rate = tmp_legacy_tp_rate; -+ - for (i = 0; i < MCS_GROUP_RATES; i++) { - if (!(mi->supported[group] & BIT(i))) - continue; -@@ -745,13 +815,7 @@ minstrel_ht_update_stats(struct minstrel - continue; - - /* Find max throughput rate set */ -- if (group != MINSTREL_CCK_GROUP) { -- minstrel_ht_sort_best_tp_rates(mi, index, -- tmp_mcs_tp_rate); -- } else if (group == MINSTREL_CCK_GROUP) { -- minstrel_ht_sort_best_tp_rates(mi, index, -- tmp_cck_tp_rate); -- } -+ minstrel_ht_sort_best_tp_rates(mi, index, tp_rate); - - /* Find max throughput rate set within a group */ - minstrel_ht_sort_best_tp_rates(mi, index, -@@ -766,7 +830,8 @@ minstrel_ht_update_stats(struct minstrel - } - - /* Assign new rate set per sta */ -- minstrel_ht_assign_best_tp_rates(mi, tmp_mcs_tp_rate, tmp_cck_tp_rate); -+ minstrel_ht_assign_best_tp_rates(mi, tmp_mcs_tp_rate, -+ tmp_legacy_tp_rate); - memcpy(mi->max_tp_rate, tmp_mcs_tp_rate, sizeof(mi->max_tp_rate)); - - /* Try to increase robustness of max_prob_rate*/ -@@ -795,8 +860,11 @@ minstrel_ht_update_stats(struct minstrel - } - - static bool --minstrel_ht_txstat_valid(struct minstrel_priv *mp, struct ieee80211_tx_rate *rate) -+minstrel_ht_txstat_valid(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, -+ struct ieee80211_tx_rate *rate) - { -+ int i; -+ - if (rate->idx < 0) - return false; - -@@ -807,10 +875,15 @@ minstrel_ht_txstat_valid(struct minstrel - rate->flags & IEEE80211_TX_RC_VHT_MCS) - return true; - -- return rate->idx == mp->cck_rates[0] || -- rate->idx == mp->cck_rates[1] || -- rate->idx == mp->cck_rates[2] || -- rate->idx == mp->cck_rates[3]; -+ for (i = 0; i < ARRAY_SIZE(mp->cck_rates); i++) -+ if (rate->idx == mp->cck_rates[i]) -+ return true; -+ -+ for (i = 0; i < ARRAY_SIZE(mp->ofdm_rates[0]); i++) -+ if (rate->idx == mp->ofdm_rates[mi->band][i]) -+ return true; -+ -+ return false; - } - - static void -@@ -897,11 +970,6 @@ minstrel_ht_tx_status(void *priv, struct - bool sample_status = false; - int i; - -- if (!msp->is_ht) -- return mac80211_minstrel.tx_status_ext(priv, sband, -- &msp->legacy, st); -- -- - /* This packet was aggregated but doesn't carry status info */ - if ((info->flags & IEEE80211_TX_CTL_AMPDU) && - !(info->flags & IEEE80211_TX_STAT_AMPDU)) -@@ -930,10 +998,10 @@ minstrel_ht_tx_status(void *priv, struct - if (mi->sample_mode != MINSTREL_SAMPLE_IDLE) - rate_sample = minstrel_get_ratestats(mi, mi->sample_rate); - -- last = !minstrel_ht_txstat_valid(mp, &ar[0]); -+ last = !minstrel_ht_txstat_valid(mp, mi, &ar[0]); - for (i = 0; !last; i++) { - last = (i == IEEE80211_TX_MAX_RATES - 1) || -- !minstrel_ht_txstat_valid(mp, &ar[i + 1]); -+ !minstrel_ht_txstat_valid(mp, mi, &ar[i + 1]); - - rate = minstrel_ht_get_stats(mp, mi, &ar[i]); - if (rate == rate_sample) -@@ -1031,7 +1099,7 @@ minstrel_calc_retransmit(struct minstrel - ctime += (t_slot * cw) >> 1; - cw = min((cw << 1) | 1, mp->cw_max); - -- if (index / MCS_GROUP_RATES == MINSTREL_CCK_GROUP) { -+ if (minstrel_ht_is_legacy_group(index / MCS_GROUP_RATES)) { - overhead = mi->overhead_legacy; - overhead_rtscts = mi->overhead_legacy_rtscts; - } else { -@@ -1064,7 +1132,8 @@ static void - minstrel_ht_set_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, - struct ieee80211_sta_rates *ratetbl, int offset, int index) - { -- const struct mcs_group *group = &minstrel_mcs_groups[index / MCS_GROUP_RATES]; -+ int group_idx = index / MCS_GROUP_RATES; -+ const struct mcs_group *group = &minstrel_mcs_groups[group_idx]; - struct minstrel_rate_stats *mrs; - u8 idx; - u16 flags = group->flags; -@@ -1083,13 +1152,17 @@ minstrel_ht_set_rate(struct minstrel_pri - ratetbl->rate[offset].count_rts = mrs->retry_count_rtscts; - } - -- if (index / MCS_GROUP_RATES == MINSTREL_CCK_GROUP) -+ index %= MCS_GROUP_RATES; -+ if (group_idx == MINSTREL_CCK_GROUP) - idx = mp->cck_rates[index % ARRAY_SIZE(mp->cck_rates)]; -+ else if (group_idx == MINSTREL_OFDM_GROUP) -+ idx = mp->ofdm_rates[mi->band][index % -+ ARRAY_SIZE(mp->ofdm_rates[0])]; - else if (flags & IEEE80211_TX_RC_VHT_MCS) - idx = ((group->streams - 1) << 4) | -- ((index % MCS_GROUP_RATES) & 0xF); -+ (index & 0xF); - else -- idx = index % MCS_GROUP_RATES + (group->streams - 1) * 8; -+ idx = index + (group->streams - 1) * 8; - - /* enable RTS/CTS if needed: - * - if station is in dynamic SMPS (and streams > 1) -@@ -1304,11 +1377,8 @@ minstrel_ht_get_rate(void *priv, struct - struct minstrel_priv *mp = priv; - int sample_idx; - -- if (!msp->is_ht) -- return mac80211_minstrel.get_rate(priv, sta, &msp->legacy, txrc); -- - if (!(info->flags & IEEE80211_TX_CTL_AMPDU) && -- mi->max_prob_rate / MCS_GROUP_RATES != MINSTREL_CCK_GROUP) -+ !minstrel_ht_is_legacy_group(mi->max_prob_rate / MCS_GROUP_RATES)) - minstrel_aggr_check(sta, txrc->skb); - - info->flags |= mi->tx_flags; -@@ -1349,6 +1419,9 @@ minstrel_ht_get_rate(void *priv, struct - if (sample_group == &minstrel_mcs_groups[MINSTREL_CCK_GROUP]) { - int idx = sample_idx % ARRAY_SIZE(mp->cck_rates); - rate->idx = mp->cck_rates[idx]; -+ } else if (sample_group == &minstrel_mcs_groups[MINSTREL_OFDM_GROUP]) { -+ int idx = sample_idx % ARRAY_SIZE(mp->ofdm_rates[0]); -+ rate->idx = mp->ofdm_rates[mi->band][idx]; - } else if (sample_group->flags & IEEE80211_TX_RC_VHT_MCS) { - ieee80211_rate_set_vht(rate, sample_idx % MCS_GROUP_RATES, - sample_group->streams); -@@ -1369,11 +1442,13 @@ minstrel_ht_update_cck(struct minstrel_p - if (sband->band != NL80211_BAND_2GHZ) - return; - -- if (!ieee80211_hw_check(mp->hw, SUPPORTS_HT_CCK_RATES)) -+ if (sta->ht_cap.ht_supported && -+ !ieee80211_hw_check(mp->hw, SUPPORTS_HT_CCK_RATES)) - return; - - for (i = 0; i < 4; i++) { -- if (!rate_supported(sta, sband->band, mp->cck_rates[i])) -+ if (mp->cck_rates[i] == 0xff || -+ !rate_supported(sta, sband->band, mp->cck_rates[i])) - continue; - - mi->supported[MINSTREL_CCK_GROUP] |= BIT(i); -@@ -1383,9 +1458,30 @@ minstrel_ht_update_cck(struct minstrel_p - } - - static void -+minstrel_ht_update_ofdm(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, -+ struct ieee80211_supported_band *sband, -+ struct ieee80211_sta *sta) -+{ -+ const u8 *rates; -+ int i; -+ -+ if (sta->ht_cap.ht_supported) -+ return; -+ -+ rates = mp->ofdm_rates[sband->band]; -+ for (i = 0; i < ARRAY_SIZE(mp->ofdm_rates[0]); i++) { -+ if (rates[i] == 0xff || -+ !rate_supported(sta, sband->band, rates[i])) -+ continue; -+ -+ mi->supported[MINSTREL_OFDM_GROUP] |= BIT(i); -+ } -+} -+ -+static void - minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, - struct cfg80211_chan_def *chandef, -- struct ieee80211_sta *sta, void *priv_sta) -+ struct ieee80211_sta *sta, void *priv_sta) - { - struct minstrel_priv *mp = priv; - struct minstrel_ht_sta_priv *msp = priv_sta; -@@ -1401,10 +1497,6 @@ minstrel_ht_update_caps(void *priv, stru - int stbc; - int i; - -- /* fall back to the old minstrel for legacy stations */ -- if (!sta->ht_cap.ht_supported) -- goto use_legacy; -- - BUILD_BUG_ON(ARRAY_SIZE(minstrel_mcs_groups) != MINSTREL_GROUPS_NB); - - if (vht_cap->vht_supported) -@@ -1412,10 +1504,10 @@ minstrel_ht_update_caps(void *priv, stru - else - use_vht = 0; - -- msp->is_ht = true; - memset(mi, 0, sizeof(*mi)); - - mi->sta = sta; -+ mi->band = sband->band; - mi->last_stats_update = jiffies; - - ack_dur = ieee80211_frame_duration(sband->band, 10, 60, 1, 1, 0); -@@ -1464,10 +1556,8 @@ minstrel_ht_update_caps(void *priv, stru - int bw, nss; - - mi->supported[i] = 0; -- if (i == MINSTREL_CCK_GROUP) { -- minstrel_ht_update_cck(mp, mi, sband, sta); -+ if (minstrel_ht_is_legacy_group(i)) - continue; -- } - - if (gflags & IEEE80211_TX_RC_SHORT_GI) { - if (gflags & IEEE80211_TX_RC_40_MHZ_WIDTH) { -@@ -1528,22 +1618,12 @@ minstrel_ht_update_caps(void *priv, stru - n_supported++; - } - -- if (!n_supported) -- goto use_legacy; -+ minstrel_ht_update_cck(mp, mi, sband, sta); -+ minstrel_ht_update_ofdm(mp, mi, sband, sta); - - /* create an initial rate table with the lowest supported rates */ - minstrel_ht_update_stats(mp, mi, true); - minstrel_ht_update_rates(mp, mi); -- -- return; -- --use_legacy: -- msp->is_ht = false; -- memset(&msp->legacy, 0, sizeof(msp->legacy)); -- msp->legacy.r = msp->ratelist; -- msp->legacy.sample_table = msp->sample_table; -- return mac80211_minstrel.rate_init(priv, sband, chandef, sta, -- &msp->legacy); - } - - static void -@@ -1611,40 +1691,70 @@ minstrel_ht_free_sta(void *priv, struct - } - - static void --minstrel_ht_init_cck_rates(struct minstrel_priv *mp) -+minstrel_ht_fill_rate_array(u8 *dest, struct ieee80211_supported_band *sband, -+ const s16 *bitrates, int n_rates, u32 rate_flags) - { -- static const int bitrates[4] = { 10, 20, 55, 110 }; -- struct ieee80211_supported_band *sband; -- u32 rate_flags = ieee80211_chandef_rate_flags(&mp->hw->conf.chandef); - int i, j; - -- sband = mp->hw->wiphy->bands[NL80211_BAND_2GHZ]; -- if (!sband) -- return; -- - for (i = 0; i < sband->n_bitrates; i++) { - struct ieee80211_rate *rate = &sband->bitrates[i]; - -- if (rate->flags & IEEE80211_RATE_ERP_G) -- continue; -- - if ((rate_flags & sband->bitrates[i].flags) != rate_flags) - continue; - -- for (j = 0; j < ARRAY_SIZE(bitrates); j++) { -+ for (j = 0; j < n_rates; j++) { - if (rate->bitrate != bitrates[j]) - continue; - -- mp->cck_rates[j] = i; -+ dest[j] = i; - break; - } - } - } - -+static void -+minstrel_ht_init_cck_rates(struct minstrel_priv *mp) -+{ -+ static const s16 bitrates[4] = { 10, 20, 55, 110 }; -+ struct ieee80211_supported_band *sband; -+ u32 rate_flags = ieee80211_chandef_rate_flags(&mp->hw->conf.chandef); -+ -+ memset(mp->cck_rates, 0xff, sizeof(mp->cck_rates)); -+ sband = mp->hw->wiphy->bands[NL80211_BAND_2GHZ]; -+ if (!sband) -+ return; -+ -+ BUILD_BUG_ON(ARRAY_SIZE(mp->cck_rates) != ARRAY_SIZE(bitrates)); -+ minstrel_ht_fill_rate_array(mp->cck_rates, sband, -+ minstrel_cck_bitrates, -+ ARRAY_SIZE(minstrel_cck_bitrates), -+ rate_flags); -+} -+ -+static void -+minstrel_ht_init_ofdm_rates(struct minstrel_priv *mp, enum nl80211_band band) -+{ -+ static const s16 bitrates[8] = { 60, 90, 120, 180, 240, 360, 480, 540 }; -+ struct ieee80211_supported_band *sband; -+ u32 rate_flags = ieee80211_chandef_rate_flags(&mp->hw->conf.chandef); -+ -+ memset(mp->ofdm_rates[band], 0xff, sizeof(mp->ofdm_rates[band])); -+ sband = mp->hw->wiphy->bands[band]; -+ if (!sband) -+ return; -+ -+ BUILD_BUG_ON(ARRAY_SIZE(mp->ofdm_rates[band]) != ARRAY_SIZE(bitrates)); -+ minstrel_ht_fill_rate_array(mp->ofdm_rates[band], sband, -+ minstrel_ofdm_bitrates, -+ ARRAY_SIZE(minstrel_ofdm_bitrates), -+ rate_flags); -+} -+ - static void * - minstrel_ht_alloc(struct ieee80211_hw *hw) - { - struct minstrel_priv *mp; -+ int i; - - mp = kzalloc(sizeof(struct minstrel_priv), GFP_ATOMIC); - if (!mp) -@@ -1681,6 +1791,8 @@ minstrel_ht_alloc(struct ieee80211_hw *h - mp->new_avg = true; - - minstrel_ht_init_cck_rates(mp); -+ for (i = 0; i < ARRAY_SIZE(mp->hw->wiphy->bands); i++) -+ minstrel_ht_init_ofdm_rates(mp, i); - - return mp; - } -@@ -1713,9 +1825,6 @@ static u32 minstrel_ht_get_expected_thro - struct minstrel_ht_sta *mi = &msp->ht; - int i, j, prob, tp_avg; - -- if (!msp->is_ht) -- return mac80211_minstrel.get_expected_throughput(priv_sta); -- - i = mi->max_tp_rate[0] / MCS_GROUP_RATES; - j = mi->max_tp_rate[0] % MCS_GROUP_RATES; - prob = mi->groups[i].rates[j].prob_avg; ---- a/net/mac80211/rc80211_minstrel_ht.h -+++ b/net/mac80211/rc80211_minstrel_ht.h -@@ -18,14 +18,15 @@ - MINSTREL_HT_STREAM_GROUPS) - #define MINSTREL_VHT_GROUPS_NB (MINSTREL_MAX_STREAMS * \ - MINSTREL_VHT_STREAM_GROUPS) --#define MINSTREL_CCK_GROUPS_NB 1 -+#define MINSTREL_LEGACY_GROUPS_NB 2 - #define MINSTREL_GROUPS_NB (MINSTREL_HT_GROUPS_NB + \ - MINSTREL_VHT_GROUPS_NB + \ -- MINSTREL_CCK_GROUPS_NB) -+ MINSTREL_LEGACY_GROUPS_NB) - - #define MINSTREL_HT_GROUP_0 0 - #define MINSTREL_CCK_GROUP (MINSTREL_HT_GROUP_0 + MINSTREL_HT_GROUPS_NB) --#define MINSTREL_VHT_GROUP_0 (MINSTREL_CCK_GROUP + 1) -+#define MINSTREL_OFDM_GROUP (MINSTREL_CCK_GROUP + 1) -+#define MINSTREL_VHT_GROUP_0 (MINSTREL_OFDM_GROUP + 1) - - #define MCS_GROUP_RATES 10 - -@@ -37,6 +38,8 @@ struct mcs_group { - u16 duration[MCS_GROUP_RATES]; - }; - -+extern const s16 minstrel_cck_bitrates[4]; -+extern const s16 minstrel_ofdm_bitrates[8]; - extern const struct mcs_group minstrel_mcs_groups[]; - - struct minstrel_mcs_group_data { -@@ -99,6 +102,8 @@ struct minstrel_ht_sta { - /* current MCS group to be sampled */ - u8 sample_group; - -+ u8 band; -+ - /* Bitfield of supported MCS rates of all groups */ - u16 supported[MINSTREL_GROUPS_NB]; - -@@ -107,13 +112,9 @@ struct minstrel_ht_sta { - }; - - struct minstrel_ht_sta_priv { -- union { -- struct minstrel_ht_sta ht; -- struct minstrel_sta_info legacy; -- }; -+ struct minstrel_ht_sta ht; - void *ratelist; - void *sample_table; -- bool is_ht; - }; - - void minstrel_ht_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir); ---- a/net/mac80211/rc80211_minstrel_ht_debugfs.c -+++ b/net/mac80211/rc80211_minstrel_ht_debugfs.c -@@ -52,7 +52,6 @@ minstrel_ht_stats_dump(struct minstrel_h - - for (j = 0; j < MCS_GROUP_RATES; j++) { - struct minstrel_rate_stats *mrs = &mi->groups[i].rates[j]; -- static const int bitrates[4] = { 10, 20, 55, 110 }; - int idx = i * MCS_GROUP_RATES + j; - unsigned int duration; - -@@ -67,6 +66,9 @@ minstrel_ht_stats_dump(struct minstrel_h - p += sprintf(p, "VHT%c0 ", htmode); - p += sprintf(p, "%cGI ", gimode); - p += sprintf(p, "%d ", mg->streams); -+ } else if (i == MINSTREL_OFDM_GROUP) { -+ p += sprintf(p, "OFDM "); -+ p += sprintf(p, "1 "); - } else { - p += sprintf(p, "CCK "); - p += sprintf(p, "%cP ", j < 4 ? 'L' : 'S'); -@@ -84,7 +86,12 @@ minstrel_ht_stats_dump(struct minstrel_h - } else if (gflags & IEEE80211_TX_RC_VHT_MCS) { - p += sprintf(p, " MCS%-1u/%1u", j, mg->streams); - } else { -- int r = bitrates[j % 4]; -+ int r; -+ -+ if (i == MINSTREL_OFDM_GROUP) -+ r = minstrel_ofdm_bitrates[j % 8]; -+ else -+ r = minstrel_cck_bitrates[j % 4]; - - p += sprintf(p, " %2u.%1uM", r / 10, r % 10); - } -@@ -124,16 +131,8 @@ minstrel_ht_stats_open(struct inode *ino - struct minstrel_ht_sta *mi = &msp->ht; - struct minstrel_debugfs_info *ms; - unsigned int i; -- int ret; - char *p; - -- if (!msp->is_ht) { -- inode->i_private = &msp->legacy; -- ret = minstrel_stats_open(inode, file); -- inode->i_private = msp; -- return ret; -- } -- - ms = kmalloc(32768, GFP_KERNEL); - if (!ms) - return -ENOMEM; -@@ -199,7 +198,6 @@ minstrel_ht_stats_csv_dump(struct minstr - - for (j = 0; j < MCS_GROUP_RATES; j++) { - struct minstrel_rate_stats *mrs = &mi->groups[i].rates[j]; -- static const int bitrates[4] = { 10, 20, 55, 110 }; - int idx = i * MCS_GROUP_RATES + j; - unsigned int duration; - -@@ -214,6 +212,8 @@ minstrel_ht_stats_csv_dump(struct minstr - p += sprintf(p, "VHT%c0,", htmode); - p += sprintf(p, "%cGI,", gimode); - p += sprintf(p, "%d,", mg->streams); -+ } else if (i == MINSTREL_OFDM_GROUP) { -+ p += sprintf(p, "OFDM,,1,"); - } else { - p += sprintf(p, "CCK,"); - p += sprintf(p, "%cP,", j < 4 ? 'L' : 'S'); -@@ -231,7 +231,13 @@ minstrel_ht_stats_csv_dump(struct minstr - } else if (gflags & IEEE80211_TX_RC_VHT_MCS) { - p += sprintf(p, ",MCS%-1u/%1u,", j, mg->streams); - } else { -- int r = bitrates[j % 4]; -+ int r; -+ -+ if (i == MINSTREL_OFDM_GROUP) -+ r = minstrel_ofdm_bitrates[j % 8]; -+ else -+ r = minstrel_cck_bitrates[j % 4]; -+ - p += sprintf(p, ",%2u.%1uM,", r / 10, r % 10); - } - -@@ -274,18 +280,9 @@ minstrel_ht_stats_csv_open(struct inode - struct minstrel_ht_sta *mi = &msp->ht; - struct minstrel_debugfs_info *ms; - unsigned int i; -- int ret; - char *p; - -- if (!msp->is_ht) { -- inode->i_private = &msp->legacy; -- ret = minstrel_stats_csv_open(inode, file); -- inode->i_private = msp; -- return ret; -- } -- - ms = kmalloc(32768, GFP_KERNEL); -- - if (!ms) - return -ENOMEM; - diff --git a/package/kernel/mac80211/patches/subsys/339-mac80211-remove-legacy-minstrel-rate-control.patch b/package/kernel/mac80211/patches/subsys/339-mac80211-remove-legacy-minstrel-rate-control.patch deleted file mode 100644 index 1cab2eb1947..00000000000 --- a/package/kernel/mac80211/patches/subsys/339-mac80211-remove-legacy-minstrel-rate-control.patch +++ /dev/null @@ -1,1328 +0,0 @@ -From: Felix Fietkau <nbd@nbd.name> -Date: Sat, 26 Dec 2020 14:23:47 +0100 -Subject: [PATCH] mac80211: remove legacy minstrel rate control - -Now that minstrel_ht supports legacy rates, it is no longer needed - -Signed-off-by: Felix Fietkau <nbd@nbd.name> ---- - delete mode 100644 net/mac80211/rc80211_minstrel.c - delete mode 100644 net/mac80211/rc80211_minstrel.h - delete mode 100644 net/mac80211/rc80211_minstrel_debugfs.c - ---- a/net/mac80211/Makefile -+++ b/net/mac80211/Makefile -@@ -56,11 +56,9 @@ mac80211-$(CONFIG_PM) += pm.o - CFLAGS_trace.o := -I$(src) - - rc80211_minstrel-y := \ -- rc80211_minstrel.o \ - rc80211_minstrel_ht.o - - rc80211_minstrel-$(CPTCFG_MAC80211_DEBUGFS) += \ -- rc80211_minstrel_debugfs.o \ - rc80211_minstrel_ht_debugfs.o - - mac80211-$(CPTCFG_MAC80211_RC_MINSTREL) += $(rc80211_minstrel-y) ---- a/net/mac80211/rc80211_minstrel.c -+++ /dev/null -@@ -1,574 +0,0 @@ --/* -- * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org> -- * -- * This program is free software; you can redistribute it and/or modify -- * it under the terms of the GNU General Public License version 2 as -- * published by the Free Software Foundation. -- * -- * Based on minstrel.c: -- * Copyright (C) 2005-2007 Derek Smithies <derek@indranet.co.nz> -- * Sponsored by Indranet Technologies Ltd -- * -- * Based on sample.c: -- * Copyright (c) 2005 John Bicket -- * All rights reserved. -- * -- * Redistribution and use in source and binary forms, with or without -- * modification, are permitted provided that the following conditions -- * are met: -- * 1. Redistributions of source code must retain the above copyright -- * notice, this list of conditions and the following disclaimer, -- * without modification. -- * 2. Redistributions in binary form must reproduce at minimum a disclaimer -- * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any -- * redistribution must be conditioned upon including a substantially -- * similar Disclaimer requirement for further binary redistribution. -- * 3. Neither the names of the above-listed copyright holders nor the names -- * of any contributors may be used to endorse or promote products derived -- * from this software without specific prior written permission. -- * -- * Alternatively, this software may be distributed under the terms of the -- * GNU General Public License ("GPL") version 2 as published by the Free -- * Software Foundation. -- * -- * NO WARRANTY -- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -- * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY -- * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -- * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, -- * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER -- * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -- * THE POSSIBILITY OF SUCH DAMAGES. -- */ --#include <linux/netdevice.h> --#include <linux/types.h> --#include <linux/skbuff.h> --#include <linux/debugfs.h> --#include <linux/random.h> --#include <linux/ieee80211.h> --#include <linux/slab.h> --#include <net/mac80211.h> --#include "rate.h" --#include "rc80211_minstrel.h" -- --#define SAMPLE_TBL(_mi, _idx, _col) \ -- _mi->sample_table[(_idx * SAMPLE_COLUMNS) + _col] -- --/* convert mac80211 rate index to local array index */ --static inline int --rix_to_ndx(struct minstrel_sta_info *mi, int rix) --{ -- int i = rix; -- for (i = rix; i >= 0; i--) -- if (mi->r[i].rix == rix) -- break; -- return i; --} -- --/* return current EMWA throughput */ --int minstrel_get_tp_avg(struct minstrel_rate *mr, int prob_avg) --{ -- int usecs; -- -- usecs = mr->perfect_tx_time; -- if (!usecs) -- usecs = 1000000; -- -- /* reset thr. below 10% success */ -- if (mr->stats.prob_avg < MINSTREL_FRAC(10, 100)) -- return 0; -- -- if (prob_avg > MINSTREL_FRAC(90, 100)) -- return MINSTREL_TRUNC(100000 * (MINSTREL_FRAC(90, 100) / usecs)); -- else -- return MINSTREL_TRUNC(100000 * (prob_avg / usecs)); --} -- --/* find & sort topmost throughput rates */ --static inline void --minstrel_sort_best_tp_rates(struct minstrel_sta_info *mi, int i, u8 *tp_list) --{ -- int j; -- struct minstrel_rate_stats *tmp_mrs; -- struct minstrel_rate_stats *cur_mrs = &mi->r[i].stats; -- -- for (j = MAX_THR_RATES; j > 0; --j) { -- tmp_mrs = &mi->r[tp_list[j - 1]].stats; -- if (minstrel_get_tp_avg(&mi->r[i], cur_mrs->prob_avg) <= -- minstrel_get_tp_avg(&mi->r[tp_list[j - 1]], tmp_mrs->prob_avg)) -- break; -- } -- -- if (j < MAX_THR_RATES - 1) -- memmove(&tp_list[j + 1], &tp_list[j], MAX_THR_RATES - (j + 1)); -- if (j < MAX_THR_RATES) -- tp_list[j] = i; --} -- --static void --minstrel_set_rate(struct minstrel_sta_info *mi, struct ieee80211_sta_rates *ratetbl, -- int offset, int idx) --{ -- struct minstrel_rate *r = &mi->r[idx]; -- -- ratetbl->rate[offset].idx = r->rix; -- ratetbl->rate[offset].count = r->adjusted_retry_count; -- ratetbl->rate[offset].count_cts = r->retry_count_cts; -- ratetbl->rate[offset].count_rts = r->stats.retry_count_rtscts; --} -- --static void --minstrel_update_rates(struct minstrel_priv *mp, struct minstrel_sta_info *mi) --{ -- struct ieee80211_sta_rates *ratetbl; -- int i = 0; -- -- ratetbl = kzalloc(sizeof(*ratetbl), GFP_ATOMIC); -- if (!ratetbl) -- return; -- -- /* Start with max_tp_rate */ -- minstrel_set_rate(mi, ratetbl, i++, mi->max_tp_rate[0]); -- -- if (mp->hw->max_rates >= 3) { -- /* At least 3 tx rates supported, use max_tp_rate2 next */ -- minstrel_set_rate(mi, ratetbl, i++, mi->max_tp_rate[1]); -- } -- -- if (mp->hw->max_rates >= 2) { -- /* At least 2 tx rates supported, use max_prob_rate next */ -- minstrel_set_rate(mi, ratetbl, i++, mi->max_prob_rate); -- } -- -- /* Use lowest rate last */ -- ratetbl->rate[i].idx = mi->lowest_rix; -- ratetbl->rate[i].count = mp->max_retry; -- ratetbl->rate[i].count_cts = mp->max_retry; -- ratetbl->rate[i].count_rts = mp->max_retry; -- -- rate_control_set_rates(mp->hw, mi->sta, ratetbl); --} -- --/* --* Recalculate statistics and counters of a given rate --*/ --void --minstrel_calc_rate_stats(struct minstrel_priv *mp, -- struct minstrel_rate_stats *mrs) --{ -- unsigned int cur_prob; -- -- if (unlikely(mrs->attempts > 0)) { -- mrs->sample_skipped = 0; -- cur_prob = MINSTREL_FRAC(mrs->success, mrs->attempts); -- if (mp->new_avg) { -- minstrel_filter_avg_add(&mrs->prob_avg, -- &mrs->prob_avg_1, cur_prob); -- } else if (unlikely(!mrs->att_hist)) { -- mrs->prob_avg = cur_prob; -- } else { -- /*update exponential weighted moving avarage */ -- mrs->prob_avg = minstrel_ewma(mrs->prob_avg, -- cur_prob, -- EWMA_LEVEL); -- } -- mrs->att_hist += mrs->attempts; -- mrs->succ_hist += mrs->success; -- } else { -- mrs->sample_skipped++; -- } -- -- mrs->last_success = mrs->success; -- mrs->last_attempts = mrs->attempts; -- mrs->success = 0; -- mrs->attempts = 0; --} -- --static void --minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi) --{ -- u8 tmp_tp_rate[MAX_THR_RATES]; -- u8 tmp_prob_rate = 0; -- int i, tmp_cur_tp, tmp_prob_tp; -- -- for (i = 0; i < MAX_THR_RATES; i++) -- tmp_tp_rate[i] = 0; -- -- for (i = 0; i < mi->n_rates; i++) { -- struct minstrel_rate *mr = &mi->r[i]; -- struct minstrel_rate_stats *mrs = &mi->r[i].stats; -- struct minstrel_rate_stats *tmp_mrs = &mi->r[tmp_prob_rate].stats; -- -- /* Update statistics of success probability per rate */ -- minstrel_calc_rate_stats(mp, mrs); -- -- /* Sample less often below the 10% chance of success. -- * Sample less often above the 95% chance of success. */ -- if (mrs->prob_avg > MINSTREL_FRAC(95, 100) || -- mrs->prob_avg < MINSTREL_FRAC(10, 100)) { -- mr->adjusted_retry_count = mrs->retry_count >> 1; -- if (mr->adjusted_retry_count > 2) -- mr->adjusted_retry_count = 2; -- mr->sample_limit = 4; -- } else { -- mr->sample_limit = -1; -- mr->adjusted_retry_count = mrs->retry_count; -- } -- if (!mr->adjusted_retry_count) -- mr->adjusted_retry_count = 2; -- -- minstrel_sort_best_tp_rates(mi, i, tmp_tp_rate); -- -- /* To determine the most robust rate (max_prob_rate) used at -- * 3rd mmr stage we distinct between two cases: -- * (1) if any success probabilitiy >= 95%, out of those rates -- * choose the maximum throughput rate as max_prob_rate -- * (2) if all success probabilities < 95%, the rate with -- * highest success probability is chosen as max_prob_rate */ -- if (mrs->prob_avg >= MINSTREL_FRAC(95, 100)) { -- tmp_cur_tp = minstrel_get_tp_avg(mr, mrs->prob_avg); -- tmp_prob_tp = minstrel_get_tp_avg(&mi->r[tmp_prob_rate], -- tmp_mrs->prob_avg); -- if (tmp_cur_tp >= tmp_prob_tp) -- tmp_prob_rate = i; -- } else { -- if (mrs->prob_avg >= tmp_mrs->prob_avg) -- tmp_prob_rate = i; -- } -- } -- -- /* Assign the new rate set */ -- memcpy(mi->max_tp_rate, tmp_tp_rate, sizeof(mi->max_tp_rate)); -- mi->max_prob_rate = tmp_prob_rate; -- --#ifdef CPTCFG_MAC80211_DEBUGFS -- /* use fixed index if set */ -- if (mp->fixed_rate_idx != -1) { -- mi->max_tp_rate[0] = mp->fixed_rate_idx; -- mi->max_tp_rate[1] = mp->fixed_rate_idx; -- mi->max_prob_rate = mp->fixed_rate_idx; -- } --#endif -- -- /* Reset update timer */ -- mi->last_stats_update = jiffies; -- -- minstrel_update_rates(mp, mi); --} -- --static void --minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband, -- void *priv_sta, struct ieee80211_tx_status *st) --{ -- struct ieee80211_tx_info *info = st->info; -- struct minstrel_priv *mp = priv; -- struct minstrel_sta_info *mi = priv_sta; -- struct ieee80211_tx_rate *ar = info->status.rates; -- int i, ndx; -- int success; -- -- success = !!(info->flags & IEEE80211_TX_STAT_ACK); -- -- for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { -- if (ar[i].idx < 0 || !ar[i].count) -- break; -- -- ndx = rix_to_ndx(mi, ar[i].idx); -- if (ndx < 0) -- continue; -- -- mi->r[ndx].stats.attempts += ar[i].count; -- -- if ((i != IEEE80211_TX_MAX_RATES - 1) && (ar[i + 1].idx < 0)) -- mi->r[ndx].stats.success += success; -- } -- -- if (time_after(jiffies, mi->last_stats_update + -- mp->update_interval / (mp->new_avg ? 2 : 1))) -- minstrel_update_stats(mp, mi); --} -- -- --static inline unsigned int --minstrel_get_retry_count(struct minstrel_rate *mr, -- struct ieee80211_tx_info *info) --{ -- u8 retry = mr->adjusted_retry_count; -- -- if (info->control.use_rts) -- retry = max_t(u8, 2, min(mr->stats.retry_count_rtscts, retry)); -- else if (info->control.use_cts_prot) -- retry = max_t(u8, 2, min(mr->retry_count_cts, retry)); -- return retry; --} -- -- --static int --minstrel_get_next_sample(struct minstrel_sta_info *mi) --{ -- unsigned int sample_ndx; -- sample_ndx = SAMPLE_TBL(mi, mi->sample_row, mi->sample_column); -- mi->sample_row++; -- if ((int) mi->sample_row >= mi->n_rates) { -- mi->sample_row = 0; -- mi->sample_column++; -- if (mi->sample_column >= SAMPLE_COLUMNS) -- mi->sample_column = 0; -- } -- return sample_ndx; --} -- --static void --minstrel_get_rate(void *priv, struct ieee80211_sta *sta, -- void *priv_sta, struct ieee80211_tx_rate_control *txrc) --{ -- struct sk_buff *skb = txrc->skb; -- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); -- struct minstrel_sta_info *mi = priv_sta; -- struct minstrel_priv *mp = priv; -- struct ieee80211_tx_rate *rate = &info->control.rates[0]; -- struct minstrel_rate *msr, *mr; -- unsigned int ndx; -- bool mrr_capable; -- bool prev_sample; -- int delta; -- int sampling_ratio; -- -- /* check multi-rate-retry capabilities & adjust lookaround_rate */ -- mrr_capable = mp->has_mrr && -- !txrc->rts && -- !txrc->bss_conf->use_cts_prot; -- if (mrr_capable) -- sampling_ratio = mp->lookaround_rate_mrr; -- else -- sampling_ratio = mp->lookaround_rate; -- -- /* increase sum packet counter */ -- mi->total_packets++; -- --#ifdef CPTCFG_MAC80211_DEBUGFS -- if (mp->fixed_rate_idx != -1) -- return; --#endif -- -- /* Don't use EAPOL frames for sampling on non-mrr hw */ -- if (mp->hw->max_rates == 1 && -- (info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO)) -- return; -- -- delta = (mi->total_packets * sampling_ratio / 100) - -- mi->sample_packets; -- -- /* delta < 0: no sampling required */ -- prev_sample = mi->prev_sample; -- mi->prev_sample = false; -- if (delta < 0 || (!mrr_capable && prev_sample)) -- return; -- -- if (mi->total_packets >= 10000) { -- mi->sample_packets = 0; -- mi->total_packets = 0; -- } else if (delta > mi->n_rates * 2) { -- /* With multi-rate retry, not every planned sample -- * attempt actually gets used, due to the way the retry -- * chain is set up - [max_tp,sample,prob,lowest] for -- * sample_rate < max_tp. -- * -- * If there's too much sampling backlog and the link -- * starts getting worse, minstrel would start bursting -- * out lots of sampling frames, which would result -- * in a large throughput loss. */ -- mi->sample_packets += (delta - mi->n_rates * 2); -- } -- -- /* get next random rate sample */ -- ndx = minstrel_get_next_sample(mi); -- msr = &mi->r[ndx]; -- mr = &mi->r[mi->max_tp_rate[0]]; -- -- /* Decide if direct ( 1st mrr stage) or indirect (2nd mrr stage) -- * rate sampling method should be used. -- * Respect such rates that are not sampled for 20 interations. -- */ -- if (msr->perfect_tx_time < mr->perfect_tx_time || -- msr->stats.sample_skipped >= 20) { -- if (!msr->sample_limit) -- return; -- -- mi->sample_packets++; -- if (msr->sample_limit > 0) -- msr->sample_limit--; -- } -- -- /* If we're not using MRR and the sampling rate already -- * has a probability of >95%, we shouldn't be attempting -- * to use it, as this only wastes precious airtime */ -- if (!mrr_capable && -- (mi->r[ndx].stats.prob_avg > MINSTREL_FRAC(95, 100))) -- return; -- -- mi->prev_sample = true; -- -- rate->idx = mi->r[ndx].rix; -- rate->count = minstrel_get_retry_count(&mi->r[ndx], info); -- info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE; --} -- -- --static void --calc_rate_durations(enum nl80211_band band, -- struct minstrel_rate *d, -- struct ieee80211_rate *rate, -- struct cfg80211_chan_def *chandef) --{ -- int erp = !!(rate->flags & IEEE80211_RATE_ERP_G); -- int shift = ieee80211_chandef_get_shift(chandef); -- -- d->perfect_tx_time = ieee80211_frame_duration(band, 1200, -- DIV_ROUND_UP(rate->bitrate, 1 << shift), erp, 1, -- shift); -- d->ack_time = ieee80211_frame_duration(band, 10, -- DIV_ROUND_UP(rate->bitrate, 1 << shift), erp, 1, -- shift); --} -- --static void --init_sample_table(struct minstrel_sta_info *mi) --{ -- unsigned int i, col, new_idx; -- u8 rnd[8]; -- -- mi->sample_column = 0; -- mi->sample_row = 0; -- memset(mi->sample_table, 0xff, SAMPLE_COLUMNS * mi->n_rates); -- -- for (col = 0; col < SAMPLE_COLUMNS; col++) { -- prandom_bytes(rnd, sizeof(rnd)); -- for (i = 0; i < mi->n_rates; i++) { -- new_idx = (i + rnd[i & 7]) % mi->n_rates; -- while (SAMPLE_TBL(mi, new_idx, col) != 0xff) -- new_idx = (new_idx + 1) % mi->n_rates; -- -- SAMPLE_TBL(mi, new_idx, col) = i; -- } -- } --} -- --static void --minstrel_rate_init(void *priv, struct ieee80211_supported_band *sband, -- struct cfg80211_chan_def *chandef, -- struct ieee80211_sta *sta, void *priv_sta) --{ -- struct minstrel_sta_info *mi = priv_sta; -- struct minstrel_priv *mp = priv; -- struct ieee80211_rate *ctl_rate; -- unsigned int i, n = 0; -- unsigned int t_slot = 9; /* FIXME: get real slot time */ -- u32 rate_flags; -- -- mi->sta = sta; -- mi->lowest_rix = rate_lowest_index(sband, sta); -- ctl_rate = &sband->bitrates[mi->lowest_rix]; -- mi->sp_ack_dur = ieee80211_frame_duration(sband->band, 10, -- ctl_rate->bitrate, -- !!(ctl_rate->flags & IEEE80211_RATE_ERP_G), 1, -- ieee80211_chandef_get_shift(chandef)); -- -- rate_flags = ieee80211_chandef_rate_flags(&mp->hw->conf.chandef); -- memset(mi->max_tp_rate, 0, sizeof(mi->max_tp_rate)); -- mi->max_prob_rate = 0; -- -- for (i = 0; i < sband->n_bitrates; i++) { -- struct minstrel_rate *mr = &mi->r[n]; -- struct minstrel_rate_stats *mrs = &mi->r[n].stats; -- unsigned int tx_time = 0, tx_time_cts = 0, tx_time_rtscts = 0; -- unsigned int tx_time_single; -- unsigned int cw = mp->cw_min; -- int shift; -- -- if (!rate_supported(sta, sband->band, i)) -- continue; -- if ((rate_flags & sband->bitrates[i].flags) != rate_flags) -- continue; -- -- n++; -- memset(mr, 0, sizeof(*mr)); -- memset(mrs, 0, sizeof(*mrs)); -- -- mr->rix = i; -- shift = ieee80211_chandef_get_shift(chandef); -- mr->bitrate = DIV_ROUND_UP(sband->bitrates[i].bitrate, -- (1 << shift) * 5); -- calc_rate_durations(sband->band, mr, &sband->bitrates[i], -- chandef); -- -- /* calculate maximum number of retransmissions before -- * fallback (based on maximum segment size) */ -- mr->sample_limit = -1; -- mrs->retry_count = 1; -- mr->retry_count_cts = 1; -- mrs->retry_count_rtscts = 1; -- tx_time = mr->perfect_tx_time + mi->sp_ack_dur; -- do { -- /* add one retransmission */ -- tx_time_single = mr->ack_time + mr->perfect_tx_time; -- -- /* contention window */ -- tx_time_single += (t_slot * cw) >> 1; -- cw = min((cw << 1) | 1, mp->cw_max); -- -- tx_time += tx_time_single; -- tx_time_cts += tx_time_single + mi->sp_ack_dur; -- tx_time_rtscts += tx_time_single + 2 * mi->sp_ack_dur; -- if ((tx_time_cts < mp->segment_size) && -- (mr->retry_count_cts < mp->max_retry)) -- mr->retry_count_cts++; -- if ((tx_time_rtscts < mp->segment_size) && -- (mrs->retry_count_rtscts < mp->max_retry)) -- mrs->retry_count_rtscts++; -- } while ((tx_time < mp->segment_size) && -- (++mr->stats.retry_count < mp->max_retry)); -- mr->adjusted_retry_count = mrs->retry_count; -- if (!(sband->bitrates[i].flags & IEEE80211_RATE_ERP_G)) -- mr->retry_count_cts = mrs->retry_count; -- } -- -- for (i = n; i < sband->n_bitrates; i++) { -- struct minstrel_rate *mr = &mi->r[i]; -- mr->rix = -1; -- } -- -- mi->n_rates = n; -- mi->last_stats_update = jiffies; -- -- init_sample_table(mi); -- minstrel_update_rates(mp, mi); --} -- --static u32 minstrel_get_expected_throughput(void *priv_sta) --{ -- struct minstrel_sta_info *mi = priv_sta; -- struct minstrel_rate_stats *tmp_mrs; -- int idx = mi->max_tp_rate[0]; -- int tmp_cur_tp; -- -- /* convert pkt per sec in kbps (1200 is the average pkt size used for -- * computing cur_tp -- */ -- tmp_mrs = &mi->r[idx].stats; -- tmp_cur_tp = minstrel_get_tp_avg(&mi->r[idx], tmp_mrs->prob_avg) * 10; -- tmp_cur_tp = tmp_cur_tp * 1200 * 8 / 1024; -- -- return tmp_cur_tp; --} -- --const struct rate_control_ops mac80211_minstrel = { -- .tx_status_ext = minstrel_tx_status, -- .get_rate = minstrel_get_rate, -- .rate_init = minstrel_rate_init, -- .get_expected_throughput = minstrel_get_expected_throughput, --}; ---- a/net/mac80211/rc80211_minstrel.h -+++ /dev/null -@@ -1,185 +0,0 @@ --/* SPDX-License-Identifier: GPL-2.0-only */ --/* -- * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org> -- */ -- --#ifndef __RC_MINSTREL_H --#define __RC_MINSTREL_H -- --#define EWMA_LEVEL 96 /* ewma weighting factor [/EWMA_DIV] */ --#define EWMA_DIV 128 --#define SAMPLE_COLUMNS 10 /* number of columns in sample table */ -- --/* scaled fraction values */ --#define MINSTREL_SCALE 12 --#define MINSTREL_FRAC(val, div) (((val) << MINSTREL_SCALE) / div) --#define MINSTREL_TRUNC(val) ((val) >> MINSTREL_SCALE) -- --/* number of highest throughput rates to consider*/ --#define MAX_THR_RATES 4 -- --/* -- * Coefficients for moving average with noise filter (period=16), -- * scaled by 10 bits -- * -- * a1 = exp(-pi * sqrt(2) / period) -- * coeff2 = 2 * a1 * cos(sqrt(2) * 2 * pi / period) -- * coeff3 = -sqr(a1) -- * coeff1 = 1 - coeff2 - coeff3 -- */ --#define MINSTREL_AVG_COEFF1 (MINSTREL_FRAC(1, 1) - \ -- MINSTREL_AVG_COEFF2 - \ -- MINSTREL_AVG_COEFF3) --#define MINSTREL_AVG_COEFF2 0x00001499 --#define MINSTREL_AVG_COEFF3 -0x0000092e -- --/* -- * Perform EWMA (Exponentially Weighted Moving Average) calculation -- */ --static inline int --minstrel_ewma(int old, int new, int weight) --{ -- int diff, incr; -- -- diff = new - old; -- incr = (EWMA_DIV - weight) * diff / EWMA_DIV; -- -- return old + incr; --} -- --static inline int minstrel_filter_avg_add(u16 *prev_1, u16 *prev_2, s32 in) --{ -- s32 out_1 = *prev_1; -- s32 out_2 = *prev_2; -- s32 val; -- -- if (!in) -- in += 1; -- -- if (!out_1) { -- val = out_1 = in; -- goto out; -- } -- -- val = MINSTREL_AVG_COEFF1 * in; -- val += MINSTREL_AVG_COEFF2 * out_1; -- val += MINSTREL_AVG_COEFF3 * out_2; -- val >>= MINSTREL_SCALE; -- -- if (val > 1 << MINSTREL_SCALE) -- val = 1 << MINSTREL_SCALE; -- if (val < 0) -- val = 1; -- --out: -- *prev_2 = out_1; -- *prev_1 = val; -- -- return val; --} -- --struct minstrel_rate_stats { -- /* current / last sampling period attempts/success counters */ -- u16 attempts, last_attempts; -- u16 success, last_success; -- -- /* total attempts/success counters */ -- u32 att_hist, succ_hist; -- -- /* prob_avg - moving average of prob */ -- u16 prob_avg; -- u16 prob_avg_1; -- -- /* maximum retry counts */ -- u8 retry_count; -- u8 retry_count_rtscts; -- -- u8 sample_skipped; -- bool retry_updated; --}; -- --struct minstrel_rate { -- int bitrate; -- -- s8 rix; -- u8 retry_count_cts; -- u8 adjusted_retry_count; -- -- unsigned int perfect_tx_time; -- unsigned int ack_time; -- -- int sample_limit; -- -- struct minstrel_rate_stats stats; --}; -- --struct minstrel_sta_info { -- struct ieee80211_sta *sta; -- -- unsigned long last_stats_update; -- unsigned int sp_ack_dur; -- unsigned int rate_avg; -- -- unsigned int lowest_rix; -- -- u8 max_tp_rate[MAX_THR_RATES]; -- u8 max_prob_rate; -- unsigned int total_packets; -- unsigned int sample_packets; -- -- unsigned int sample_row; -- unsigned int sample_column; -- -- int n_rates; -- struct minstrel_rate *r; -- bool prev_sample; -- -- /* sampling table */ -- u8 *sample_table; --}; -- --struct minstrel_priv { -- struct ieee80211_hw *hw; -- bool has_mrr; -- bool new_avg; -- u32 sample_switch; -- unsigned int cw_min; -- unsigned int cw_max; -- unsigned int max_retry; -- unsigned int segment_size; -- unsigned int update_interval; -- unsigned int lookaround_rate; -- unsigned int lookaround_rate_mrr; -- -- u8 cck_rates[4]; -- u8 ofdm_rates[NUM_NL80211_BANDS][8]; -- --#ifdef CPTCFG_MAC80211_DEBUGFS -- /* -- * enable fixed rate processing per RC -- * - write static index to debugfs:ieee80211/phyX/rc/fixed_rate_idx -- * - write -1 to enable RC processing again -- * - setting will be applied on next update -- */ -- u32 fixed_rate_idx; --#endif --}; -- --struct minstrel_debugfs_info { -- size_t len; -- char buf[]; --}; -- --extern const struct rate_control_ops mac80211_minstrel; --void minstrel_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir); -- --/* Recalculate success probabilities and counters for a given rate using EWMA */ --void minstrel_calc_rate_stats(struct minstrel_priv *mp, -- struct minstrel_rate_stats *mrs); --int minstrel_get_tp_avg(struct minstrel_rate *mr, int prob_avg); -- --/* debugfs */ --int minstrel_stats_open(struct inode *inode, struct file *file); --int minstrel_stats_csv_open(struct inode *inode, struct file *file); -- --#endif ---- a/net/mac80211/rc80211_minstrel_debugfs.c -+++ /dev/null -@@ -1,172 +0,0 @@ --/* -- * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org> -- * -- * This program is free software; you can redistribute it and/or modify -- * it under the terms of the GNU General Public License version 2 as -- * published by the Free Software Foundation. -- * -- * Based on minstrel.c: -- * Copyright (C) 2005-2007 Derek Smithies <derek@indranet.co.nz> -- * Sponsored by Indranet Technologies Ltd -- * -- * Based on sample.c: -- * Copyright (c) 2005 John Bicket -- * All rights reserved. -- * -- * Redistribution and use in source and binary forms, with or without -- * modification, are permitted provided that the following conditions -- * are met: -- * 1. Redistributions of source code must retain the above copyright -- * notice, this list of conditions and the following disclaimer, -- * without modification. -- * 2. Redistributions in binary form must reproduce at minimum a disclaimer -- * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any -- * redistribution must be conditioned upon including a substantially -- * similar Disclaimer requirement for further binary redistribution. -- * 3. Neither the names of the above-listed copyright holders nor the names -- * of any contributors may be used to endorse or promote products derived -- * from this software without specific prior written permission. -- * -- * Alternatively, this software may be distributed under the terms of the -- * GNU General Public License ("GPL") version 2 as published by the Free -- * Software Foundation. -- * -- * NO WARRANTY -- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -- * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY -- * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -- * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, -- * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER -- * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -- * THE POSSIBILITY OF SUCH DAMAGES. -- */ --#include <linux/netdevice.h> --#include <linux/types.h> --#include <linux/skbuff.h> --#include <linux/debugfs.h> --#include <linux/ieee80211.h> --#include <linux/slab.h> --#include <linux/export.h> --#include <net/mac80211.h> --#include "rc80211_minstrel.h" -- --int --minstrel_stats_open(struct inode *inode, struct file *file) --{ -- struct minstrel_sta_info *mi = inode->i_private; -- struct minstrel_debugfs_info *ms; -- unsigned int i, tp_max, tp_avg, eprob; -- char *p; -- -- ms = kmalloc(2048, GFP_KERNEL); -- if (!ms) -- return -ENOMEM; -- -- file->private_data = ms; -- p = ms->buf; -- p += sprintf(p, "\n"); -- p += sprintf(p, -- "best __________rate_________ ____statistics___ ____last_____ ______sum-of________\n"); -- p += sprintf(p, -- "rate [name idx airtime max_tp] [avg(tp) avg(prob)] [retry|suc|att] [#success | #attempts]\n"); -- -- for (i = 0; i < mi->n_rates; i++) { -- struct minstrel_rate *mr = &mi->r[i]; -- struct minstrel_rate_stats *mrs = &mi->r[i].stats; -- -- *(p++) = (i == mi->max_tp_rate[0]) ? 'A' : ' '; -- *(p++) = (i == mi->max_tp_rate[1]) ? 'B' : ' '; -- *(p++) = (i == mi->max_tp_rate[2]) ? 'C' : ' '; -- *(p++) = (i == mi->max_tp_rate[3]) ? 'D' : ' '; -- *(p++) = (i == mi->max_prob_rate) ? 'P' : ' '; -- -- p += sprintf(p, " %3u%s ", mr->bitrate / 2, -- (mr->bitrate & 1 ? ".5" : " ")); -- p += sprintf(p, "%3u ", i); -- p += sprintf(p, "%6u ", mr->perfect_tx_time); -- -- tp_max = minstrel_get_tp_avg(mr, MINSTREL_FRAC(100,100)); -- tp_avg = minstrel_get_tp_avg(mr, mrs->prob_avg); -- eprob = MINSTREL_TRUNC(mrs->prob_avg * 1000); -- -- p += sprintf(p, "%4u.%1u %4u.%1u %3u.%1u" -- " %3u %3u %-3u " -- "%9llu %-9llu\n", -- tp_max / 10, tp_max % 10, -- tp_avg / 10, tp_avg % 10, -- eprob / 10, eprob % 10, -- mrs->retry_count, -- mrs->last_success, -- mrs->last_attempts, -- (unsigned long long)mrs->succ_hist, -- (unsigned long long)mrs->att_hist); -- } -- p += sprintf(p, "\nTotal packet count:: ideal %d " -- "lookaround %d\n\n", -- mi->total_packets - mi->sample_packets, -- mi->sample_packets); -- ms->len = p - ms->buf; -- -- WARN_ON(ms->len + sizeof(*ms) > 2048); -- -- return 0; --} -- --int --minstrel_stats_csv_open(struct inode *inode, struct file *file) --{ -- struct minstrel_sta_info *mi = inode->i_private; -- struct minstrel_debugfs_info *ms; -- unsigned int i, tp_max, tp_avg, eprob; -- char *p; -- -- ms = kmalloc(2048, GFP_KERNEL); -- if (!ms) -- return -ENOMEM; -- -- file->private_data = ms; -- p = ms->buf; -- -- for (i = 0; i < mi->n_rates; i++) { -- struct minstrel_rate *mr = &mi->r[i]; -- struct minstrel_rate_stats *mrs = &mi->r[i].stats; -- -- p += sprintf(p, "%s" ,((i == mi->max_tp_rate[0]) ? "A" : "")); -- p += sprintf(p, "%s" ,((i == mi->max_tp_rate[1]) ? "B" : "")); -- p += sprintf(p, "%s" ,((i == mi->max_tp_rate[2]) ? "C" : "")); -- p += sprintf(p, "%s" ,((i == mi->max_tp_rate[3]) ? "D" : "")); -- p += sprintf(p, "%s" ,((i == mi->max_prob_rate) ? "P" : "")); -- -- p += sprintf(p, ",%u%s", mr->bitrate / 2, -- (mr->bitrate & 1 ? ".5," : ",")); -- p += sprintf(p, "%u,", i); -- p += sprintf(p, "%u,",mr->perfect_tx_time); -- -- tp_max = minstrel_get_tp_avg(mr, MINSTREL_FRAC(100,100)); -- tp_avg = minstrel_get_tp_avg(mr, mrs->prob_avg); -- eprob = MINSTREL_TRUNC(mrs->prob_avg * 1000); -- -- p += sprintf(p, "%u.%u,%u.%u,%u.%u,%u,%u,%u," -- "%llu,%llu,%d,%d\n", -- tp_max / 10, tp_max % 10, -- tp_avg / 10, tp_avg % 10, -- eprob / 10, eprob % 10, -- mrs->retry_count, -- mrs->last_success, -- mrs->last_attempts, -- (unsigned long long)mrs->succ_hist, -- (unsigned long long)mrs->att_hist, -- mi->total_packets - mi->sample_packets, -- mi->sample_packets); -- -- } -- ms->len = p - ms->buf; -- -- WARN_ON(ms->len + sizeof(*ms) > 2048); -- -- return 0; --} ---- a/net/mac80211/rc80211_minstrel_ht.c -+++ b/net/mac80211/rc80211_minstrel_ht.c -@@ -13,7 +13,6 @@ - #include <net/mac80211.h> - #include "rate.h" - #include "sta_info.h" --#include "rc80211_minstrel.h" - #include "rc80211_minstrel_ht.h" - - #define AVG_AMPDU_SIZE 16 -@@ -716,6 +715,83 @@ out: - mi->sample_mode = MINSTREL_SAMPLE_ACTIVE; - } - -+static inline int -+minstrel_ewma(int old, int new, int weight) -+{ -+ int diff, incr; -+ -+ diff = new - old; -+ incr = (EWMA_DIV - weight) * diff / EWMA_DIV; -+ -+ return old + incr; -+} -+ -+static inline int minstrel_filter_avg_add(u16 *prev_1, u16 *prev_2, s32 in) -+{ -+ s32 out_1 = *prev_1; -+ s32 out_2 = *prev_2; -+ s32 val; -+ -+ if (!in) -+ in += 1; -+ -+ if (!out_1) { -+ val = out_1 = in; -+ goto out; -+ } -+ -+ val = MINSTREL_AVG_COEFF1 * in; -+ val += MINSTREL_AVG_COEFF2 * out_1; -+ val += MINSTREL_AVG_COEFF3 * out_2; -+ val >>= MINSTREL_SCALE; -+ -+ if (val > 1 << MINSTREL_SCALE) -+ val = 1 << MINSTREL_SCALE; -+ if (val < 0) -+ val = 1; -+ -+out: -+ *prev_2 = out_1; -+ *prev_1 = val; -+ -+ return val; -+} -+ -+/* -+* Recalculate statistics and counters of a given rate -+*/ -+static void -+minstrel_ht_calc_rate_stats(struct minstrel_priv *mp, -+ struct minstrel_rate_stats *mrs) -+{ -+ unsigned int cur_prob; -+ -+ if (unlikely(mrs->attempts > 0)) { -+ mrs->sample_skipped = 0; -+ cur_prob = MINSTREL_FRAC(mrs->success, mrs->attempts); -+ if (mp->new_avg) { -+ minstrel_filter_avg_add(&mrs->prob_avg, -+ &mrs->prob_avg_1, cur_prob); -+ } else if (unlikely(!mrs->att_hist)) { -+ mrs->prob_avg = cur_prob; -+ } else { -+ /*update exponential weighted moving avarage */ -+ mrs->prob_avg = minstrel_ewma(mrs->prob_avg, -+ cur_prob, -+ EWMA_LEVEL); -+ } -+ mrs->att_hist += mrs->attempts; -+ mrs->succ_hist += mrs->success; -+ } else { -+ mrs->sample_skipped++; -+ } -+ -+ mrs->last_success = mrs->success; -+ mrs->last_attempts = mrs->attempts; -+ mrs->success = 0; -+ mrs->attempts = 0; -+} -+ - /* - * Update rate statistics and select new primary rates - * -@@ -808,7 +884,7 @@ minstrel_ht_update_stats(struct minstrel - - mrs = &mg->rates[i]; - mrs->retry_updated = false; -- minstrel_calc_rate_stats(mp, mrs); -+ minstrel_ht_calc_rate_stats(mp, mrs); - cur_prob = mrs->prob_avg; - - if (minstrel_ht_get_tp_avg(mi, group, i, cur_prob) == 0) -@@ -960,8 +1036,7 @@ minstrel_ht_tx_status(void *priv, struct - void *priv_sta, struct ieee80211_tx_status *st) - { - struct ieee80211_tx_info *info = st->info; -- struct minstrel_ht_sta_priv *msp = priv_sta; -- struct minstrel_ht_sta *mi = &msp->ht; -+ struct minstrel_ht_sta *mi = priv_sta; - struct ieee80211_tx_rate *ar = info->status.rates; - struct minstrel_rate_stats *rate, *rate2, *rate_sample = NULL; - struct minstrel_priv *mp = priv; -@@ -1372,8 +1447,7 @@ minstrel_ht_get_rate(void *priv, struct - const struct mcs_group *sample_group; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txrc->skb); - struct ieee80211_tx_rate *rate = &info->status.rates[0]; -- struct minstrel_ht_sta_priv *msp = priv_sta; -- struct minstrel_ht_sta *mi = &msp->ht; -+ struct minstrel_ht_sta *mi = priv_sta; - struct minstrel_priv *mp = priv; - int sample_idx; - -@@ -1484,8 +1558,7 @@ minstrel_ht_update_caps(void *priv, stru - struct ieee80211_sta *sta, void *priv_sta) - { - struct minstrel_priv *mp = priv; -- struct minstrel_ht_sta_priv *msp = priv_sta; -- struct minstrel_ht_sta *mi = &msp->ht; -+ struct minstrel_ht_sta *mi = priv_sta; - struct ieee80211_mcs_info *mcs = &sta->ht_cap.mcs; - u16 ht_cap = sta->ht_cap.cap; - struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap; -@@ -1647,7 +1720,7 @@ static void * - minstrel_ht_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp) - { - struct ieee80211_supported_band *sband; -- struct minstrel_ht_sta_priv *msp; -+ struct minstrel_ht_sta *mi; - struct minstrel_priv *mp = priv; - struct ieee80211_hw *hw = mp->hw; - int max_rates = 0; -@@ -1659,35 +1732,13 @@ minstrel_ht_alloc_sta(void *priv, struct - max_rates = sband->n_bitrates; - } - -- msp = kzalloc(sizeof(*msp), gfp); -- if (!msp) -- return NULL; -- -- msp->ratelist = kcalloc(max_rates, sizeof(struct minstrel_rate), gfp); -- if (!msp->ratelist) -- goto error; -- -- msp->sample_table = kmalloc_array(max_rates, SAMPLE_COLUMNS, gfp); -- if (!msp->sample_table) -- goto error1; -- -- return msp; -- --error1: -- kfree(msp->ratelist); --error: -- kfree(msp); -- return NULL; -+ return kzalloc(sizeof(*mi), gfp); - } - - static void - minstrel_ht_free_sta(void *priv, struct ieee80211_sta *sta, void *priv_sta) - { -- struct minstrel_ht_sta_priv *msp = priv_sta; -- -- kfree(msp->sample_table); -- kfree(msp->ratelist); -- kfree(msp); -+ kfree(priv_sta); - } - - static void -@@ -1768,12 +1819,6 @@ minstrel_ht_alloc(struct ieee80211_hw *h - mp->cw_min = 15; - mp->cw_max = 1023; - -- /* number of packets (in %) to use for sampling other rates -- * sample less often for non-mrr packets, because the overhead -- * is much higher than with mrr */ -- mp->lookaround_rate = 5; -- mp->lookaround_rate_mrr = 10; -- - /* maximum time that the hw is allowed to stay in one MRR segment */ - mp->segment_size = 6000; - -@@ -1821,8 +1866,7 @@ minstrel_ht_free(void *priv) - - static u32 minstrel_ht_get_expected_throughput(void *priv_sta) - { -- struct minstrel_ht_sta_priv *msp = priv_sta; -- struct minstrel_ht_sta *mi = &msp->ht; -+ struct minstrel_ht_sta *mi = priv_sta; - int i, j, prob, tp_avg; - - i = mi->max_tp_rate[0] / MCS_GROUP_RATES; ---- a/net/mac80211/rc80211_minstrel_ht.h -+++ b/net/mac80211/rc80211_minstrel_ht.h -@@ -6,6 +6,33 @@ - #ifndef __RC_MINSTREL_HT_H - #define __RC_MINSTREL_HT_H - -+/* number of highest throughput rates to consider*/ -+#define MAX_THR_RATES 4 -+#define SAMPLE_COLUMNS 10 /* number of columns in sample table */ -+ -+/* scaled fraction values */ -+#define MINSTREL_SCALE 12 -+#define MINSTREL_FRAC(val, div) (((val) << MINSTREL_SCALE) / div) -+#define MINSTREL_TRUNC(val) ((val) >> MINSTREL_SCALE) -+ -+#define EWMA_LEVEL 96 /* ewma weighting factor [/EWMA_DIV] */ -+#define EWMA_DIV 128 -+ -+/* -+ * Coefficients for moving average with noise filter (period=16), -+ * scaled by 10 bits -+ * -+ * a1 = exp(-pi * sqrt(2) / period) -+ * coeff2 = 2 * a1 * cos(sqrt(2) * 2 * pi / period) -+ * coeff3 = -sqr(a1) -+ * coeff1 = 1 - coeff2 - coeff3 -+ */ -+#define MINSTREL_AVG_COEFF1 (MINSTREL_FRAC(1, 1) - \ -+ MINSTREL_AVG_COEFF2 - \ -+ MINSTREL_AVG_COEFF3) -+#define MINSTREL_AVG_COEFF2 0x00001499 -+#define MINSTREL_AVG_COEFF3 -0x0000092e -+ - /* - * The number of streams can be changed to 2 to reduce code - * size and memory footprint. -@@ -30,6 +57,32 @@ - - #define MCS_GROUP_RATES 10 - -+struct minstrel_priv { -+ struct ieee80211_hw *hw; -+ bool has_mrr; -+ bool new_avg; -+ u32 sample_switch; -+ unsigned int cw_min; -+ unsigned int cw_max; -+ unsigned int max_retry; -+ unsigned int segment_size; -+ unsigned int update_interval; -+ -+ u8 cck_rates[4]; -+ u8 ofdm_rates[NUM_NL80211_BANDS][8]; -+ -+#ifdef CPTCFG_MAC80211_DEBUGFS -+ /* -+ * enable fixed rate processing per RC -+ * - write static index to debugfs:ieee80211/phyX/rc/fixed_rate_idx -+ * - write -1 to enable RC processing again -+ * - setting will be applied on next update -+ */ -+ u32 fixed_rate_idx; -+#endif -+}; -+ -+ - struct mcs_group { - u16 flags; - u8 streams; -@@ -42,6 +95,26 @@ extern const s16 minstrel_cck_bitrates[4 - extern const s16 minstrel_ofdm_bitrates[8]; - extern const struct mcs_group minstrel_mcs_groups[]; - -+struct minstrel_rate_stats { -+ /* current / last sampling period attempts/success counters */ -+ u16 attempts, last_attempts; -+ u16 success, last_success; -+ -+ /* total attempts/success counters */ -+ u32 att_hist, succ_hist; -+ -+ /* prob_avg - moving average of prob */ -+ u16 prob_avg; -+ u16 prob_avg_1; -+ -+ /* maximum retry counts */ -+ u8 retry_count; -+ u8 retry_count_rtscts; -+ -+ u8 sample_skipped; -+ bool retry_updated; -+}; -+ - struct minstrel_mcs_group_data { - u8 index; - u8 column; -@@ -111,12 +184,6 @@ struct minstrel_ht_sta { - struct minstrel_mcs_group_data groups[MINSTREL_GROUPS_NB]; - }; - --struct minstrel_ht_sta_priv { -- struct minstrel_ht_sta ht; -- void *ratelist; -- void *sample_table; --}; -- - void minstrel_ht_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir); - int minstrel_ht_get_tp_avg(struct minstrel_ht_sta *mi, int group, int rate, - int prob_avg); ---- a/net/mac80211/rc80211_minstrel_ht_debugfs.c -+++ b/net/mac80211/rc80211_minstrel_ht_debugfs.c -@@ -9,9 +9,13 @@ - #include <linux/ieee80211.h> - #include <linux/export.h> - #include <net/mac80211.h> --#include "rc80211_minstrel.h" - #include "rc80211_minstrel_ht.h" - -+struct minstrel_debugfs_info { -+ size_t len; -+ char buf[]; -+}; -+ - static ssize_t - minstrel_stats_read(struct file *file, char __user *buf, size_t len, loff_t *ppos) - { -@@ -127,8 +131,7 @@ minstrel_ht_stats_dump(struct minstrel_h - static int - minstrel_ht_stats_open(struct inode *inode, struct file *file) - { -- struct minstrel_ht_sta_priv *msp = inode->i_private; -- struct minstrel_ht_sta *mi = &msp->ht; -+ struct minstrel_ht_sta *mi = inode->i_private; - struct minstrel_debugfs_info *ms; - unsigned int i; - char *p; -@@ -276,8 +279,7 @@ minstrel_ht_stats_csv_dump(struct minstr - static int - minstrel_ht_stats_csv_open(struct inode *inode, struct file *file) - { -- struct minstrel_ht_sta_priv *msp = inode->i_private; -- struct minstrel_ht_sta *mi = &msp->ht; -+ struct minstrel_ht_sta *mi = inode->i_private; - struct minstrel_debugfs_info *ms; - unsigned int i; - char *p; -@@ -313,10 +315,8 @@ static const struct file_operations mins - void - minstrel_ht_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir) - { -- struct minstrel_ht_sta_priv *msp = priv_sta; -- -- debugfs_create_file("rc_stats", 0444, dir, msp, -+ debugfs_create_file("rc_stats", 0444, dir, priv_sta, - &minstrel_ht_stat_fops); -- debugfs_create_file("rc_stats_csv", 0444, dir, msp, -+ debugfs_create_file("rc_stats_csv", 0444, dir, priv_sta, - &minstrel_ht_stat_csv_fops); - } diff --git a/package/kernel/mac80211/patches/subsys/340-mac80211-minstrel_ht-remove-old-ewma-based-rate-aver.patch b/package/kernel/mac80211/patches/subsys/340-mac80211-minstrel_ht-remove-old-ewma-based-rate-aver.patch deleted file mode 100644 index 9b6a614aa83..00000000000 --- a/package/kernel/mac80211/patches/subsys/340-mac80211-minstrel_ht-remove-old-ewma-based-rate-aver.patch +++ /dev/null @@ -1,96 +0,0 @@ -From: Felix Fietkau <nbd@nbd.name> -Date: Sat, 26 Dec 2020 14:34:30 +0100 -Subject: [PATCH] mac80211: minstrel_ht: remove old ewma based rate average - code - -The new noise filter has been the default for a while now with no reported -downside and significant improvement compared to the old code. - -Signed-off-by: Felix Fietkau <nbd@nbd.name> ---- - ---- a/net/mac80211/rc80211_minstrel_ht.c -+++ b/net/mac80211/rc80211_minstrel_ht.c -@@ -769,17 +769,8 @@ minstrel_ht_calc_rate_stats(struct minst - if (unlikely(mrs->attempts > 0)) { - mrs->sample_skipped = 0; - cur_prob = MINSTREL_FRAC(mrs->success, mrs->attempts); -- if (mp->new_avg) { -- minstrel_filter_avg_add(&mrs->prob_avg, -- &mrs->prob_avg_1, cur_prob); -- } else if (unlikely(!mrs->att_hist)) { -- mrs->prob_avg = cur_prob; -- } else { -- /*update exponential weighted moving avarage */ -- mrs->prob_avg = minstrel_ewma(mrs->prob_avg, -- cur_prob, -- EWMA_LEVEL); -- } -+ minstrel_filter_avg_add(&mrs->prob_avg, -+ &mrs->prob_avg_1, cur_prob); - mrs->att_hist += mrs->attempts; - mrs->succ_hist += mrs->success; - } else { -@@ -913,10 +904,8 @@ minstrel_ht_update_stats(struct minstrel - /* Try to increase robustness of max_prob_rate*/ - minstrel_ht_prob_rate_reduce_streams(mi); - -- /* try to sample all available rates during each interval */ -- mi->sample_count *= 8; -- if (mp->new_avg) -- mi->sample_count /= 2; -+ /* try to sample half of all available rates during each interval */ -+ mi->sample_count *= 4; - - if (sample) - minstrel_ht_rate_sample_switch(mp, mi); -@@ -1040,7 +1029,7 @@ minstrel_ht_tx_status(void *priv, struct - struct ieee80211_tx_rate *ar = info->status.rates; - struct minstrel_rate_stats *rate, *rate2, *rate_sample = NULL; - struct minstrel_priv *mp = priv; -- u32 update_interval = mp->update_interval / 2; -+ u32 update_interval = mp->update_interval; - bool last, update = false; - bool sample_status = false; - int i; -@@ -1090,9 +1079,8 @@ minstrel_ht_tx_status(void *priv, struct - - switch (mi->sample_mode) { - case MINSTREL_SAMPLE_IDLE: -- if (mp->new_avg && -- (mp->hw->max_rates > 1 || -- mi->total_packets_cur < SAMPLE_SWITCH_THR)) -+ if (mp->hw->max_rates > 1 || -+ mi->total_packets_cur < SAMPLE_SWITCH_THR) - update_interval /= 2; - break; - -@@ -1832,8 +1820,7 @@ minstrel_ht_alloc(struct ieee80211_hw *h - mp->has_mrr = true; - - mp->hw = hw; -- mp->update_interval = HZ / 10; -- mp->new_avg = true; -+ mp->update_interval = HZ / 20; - - minstrel_ht_init_cck_rates(mp); - for (i = 0; i < ARRAY_SIZE(mp->hw->wiphy->bands); i++) -@@ -1853,8 +1840,6 @@ static void minstrel_ht_add_debugfs(stru - &mp->fixed_rate_idx); - debugfs_create_u32("sample_switch", S_IRUGO | S_IWUSR, debugfsdir, - &mp->sample_switch); -- debugfs_create_bool("new_avg", S_IRUGO | S_IWUSR, debugfsdir, -- &mp->new_avg); - } - #endif - ---- a/net/mac80211/rc80211_minstrel_ht.h -+++ b/net/mac80211/rc80211_minstrel_ht.h -@@ -60,7 +60,6 @@ - struct minstrel_priv { - struct ieee80211_hw *hw; - bool has_mrr; -- bool new_avg; - u32 sample_switch; - unsigned int cw_min; - unsigned int cw_max; diff --git a/package/kernel/mac80211/patches/subsys/341-mac80211-minstrel_ht-improve-ampdu-length-estimation.patch b/package/kernel/mac80211/patches/subsys/341-mac80211-minstrel_ht-improve-ampdu-length-estimation.patch deleted file mode 100644 index a8e6e899544..00000000000 --- a/package/kernel/mac80211/patches/subsys/341-mac80211-minstrel_ht-improve-ampdu-length-estimation.patch +++ /dev/null @@ -1,67 +0,0 @@ -From: Felix Fietkau <nbd@nbd.name> -Date: Sat, 26 Dec 2020 19:08:19 +0100 -Subject: [PATCH] mac80211: minstrel_ht: improve ampdu length estimation - -If the driver does not report A-MPDU length, estimate it based on the rate. - -Signed-off-by: Felix Fietkau <nbd@nbd.name> ---- - ---- a/net/mac80211/rc80211_minstrel_ht.c -+++ b/net/mac80211/rc80211_minstrel_ht.c -@@ -382,13 +382,37 @@ minstrel_get_ratestats(struct minstrel_h - return &mi->groups[index / MCS_GROUP_RATES].rates[index % MCS_GROUP_RATES]; - } - -+static inline int -+minstrel_get_duration(int index) -+{ -+ const struct mcs_group *group = &minstrel_mcs_groups[index / MCS_GROUP_RATES]; -+ unsigned int duration = group->duration[index % MCS_GROUP_RATES]; -+ return duration << group->shift; -+} -+ - static unsigned int - minstrel_ht_avg_ampdu_len(struct minstrel_ht_sta *mi) - { -- if (!mi->avg_ampdu_len) -- return AVG_AMPDU_SIZE; -+ int duration; -+ -+ if (mi->avg_ampdu_len) -+ return MINSTREL_TRUNC(mi->avg_ampdu_len); -+ -+ if (minstrel_ht_is_legacy_group(mi->max_tp_rate[0] / MCS_GROUP_RATES)) -+ return 1; -+ -+ duration = minstrel_get_duration(mi->max_tp_rate[0]); - -- return MINSTREL_TRUNC(mi->avg_ampdu_len); -+ if (duration > 400 * 1000) -+ return 2; -+ -+ if (duration > 250 * 1000) -+ return 4; -+ -+ if (duration > 150 * 1000) -+ return 8; -+ -+ return 16; - } - - /* -@@ -588,14 +612,6 @@ minstrel_ht_prob_rate_reduce_streams(str - } - } - --static inline int --minstrel_get_duration(int index) --{ -- const struct mcs_group *group = &minstrel_mcs_groups[index / MCS_GROUP_RATES]; -- unsigned int duration = group->duration[index % MCS_GROUP_RATES]; -- return duration << group->shift; --} -- - static bool - minstrel_ht_probe_group(struct minstrel_ht_sta *mi, const struct mcs_group *tp_group, - int tp_idx, const struct mcs_group *group) diff --git a/package/kernel/mac80211/patches/subsys/342-mac80211-minstrel_ht-improve-sample-rate-selection.patch b/package/kernel/mac80211/patches/subsys/342-mac80211-minstrel_ht-improve-sample-rate-selection.patch deleted file mode 100644 index e0845252354..00000000000 --- a/package/kernel/mac80211/patches/subsys/342-mac80211-minstrel_ht-improve-sample-rate-selection.patch +++ /dev/null @@ -1,31 +0,0 @@ -From: Felix Fietkau <nbd@nbd.name> -Date: Sat, 26 Dec 2020 19:12:22 +0100 -Subject: [PATCH] mac80211: minstrel_ht: improve sample rate selection - -Always allow sampling of rates faster than the primary max throughput rate. -When the second max_tp_rate is higher than the first one, sample attempts were -previously skipped, potentially causing rate control to get stuck at a slightly -lower rate - -Signed-off-by: Felix Fietkau <nbd@nbd.name> ---- - ---- a/net/mac80211/rc80211_minstrel_ht.c -+++ b/net/mac80211/rc80211_minstrel_ht.c -@@ -1379,13 +1379,13 @@ minstrel_get_sample_rate(struct minstrel - mrs = &mg->rates[sample_idx]; - sample_idx += sample_group * MCS_GROUP_RATES; - -- /* Set tp_rate1, tp_rate2 to the highest / second highest max_tp_rate */ -+ tp_rate1 = mi->max_tp_rate[0]; -+ -+ /* Set tp_rate2 to the second highest max_tp_rate */ - if (minstrel_get_duration(mi->max_tp_rate[0]) > - minstrel_get_duration(mi->max_tp_rate[1])) { -- tp_rate1 = mi->max_tp_rate[1]; - tp_rate2 = mi->max_tp_rate[0]; - } else { -- tp_rate1 = mi->max_tp_rate[0]; - tp_rate2 = mi->max_tp_rate[1]; - } - diff --git a/package/kernel/mac80211/patches/subsys/343-mac80211-minstrel_ht-fix-max-probability-rate-select.patch b/package/kernel/mac80211/patches/subsys/343-mac80211-minstrel_ht-fix-max-probability-rate-select.patch deleted file mode 100644 index 0dbfa9d4fb4..00000000000 --- a/package/kernel/mac80211/patches/subsys/343-mac80211-minstrel_ht-fix-max-probability-rate-select.patch +++ /dev/null @@ -1,124 +0,0 @@ -From: Felix Fietkau <nbd@nbd.name> -Date: Sat, 26 Dec 2020 19:09:08 +0100 -Subject: [PATCH] mac80211: minstrel_ht: fix max probability rate selection - -- do not select rates faster than the max throughput rate if probability is lower -- reset previous rate before sorting again - -This ensures that the max prob rate gets set to a more reliable rate - -Signed-off-by: Felix Fietkau <nbd@nbd.name> ---- - ---- a/net/mac80211/rc80211_minstrel_ht.c -+++ b/net/mac80211/rc80211_minstrel_ht.c -@@ -495,12 +495,13 @@ minstrel_ht_sort_best_tp_rates(struct mi - * Find and set the topmost probability rate per sta and per group - */ - static void --minstrel_ht_set_best_prob_rate(struct minstrel_ht_sta *mi, u16 index) -+minstrel_ht_set_best_prob_rate(struct minstrel_ht_sta *mi, u16 *dest, u16 index) - { - struct minstrel_mcs_group_data *mg; - struct minstrel_rate_stats *mrs; - int tmp_group, tmp_idx, tmp_tp_avg, tmp_prob; -- int max_tp_group, cur_tp_avg, cur_group, cur_idx; -+ int max_tp_group, max_tp_idx, max_tp_prob; -+ int cur_tp_avg, cur_group, cur_idx; - int max_gpr_group, max_gpr_idx; - int max_gpr_tp_avg, max_gpr_prob; - -@@ -509,18 +510,26 @@ minstrel_ht_set_best_prob_rate(struct mi - mg = &mi->groups[index / MCS_GROUP_RATES]; - mrs = &mg->rates[index % MCS_GROUP_RATES]; - -- tmp_group = mi->max_prob_rate / MCS_GROUP_RATES; -- tmp_idx = mi->max_prob_rate % MCS_GROUP_RATES; -+ tmp_group = *dest / MCS_GROUP_RATES; -+ tmp_idx = *dest % MCS_GROUP_RATES; - tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_avg; - tmp_tp_avg = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx, tmp_prob); - - /* if max_tp_rate[0] is from MCS_GROUP max_prob_rate get selected from - * MCS_GROUP as well as CCK_GROUP rates do not allow aggregation */ - max_tp_group = mi->max_tp_rate[0] / MCS_GROUP_RATES; -+ max_tp_idx = mi->max_tp_rate[0] % MCS_GROUP_RATES; -+ max_tp_prob = mi->groups[max_tp_group].rates[max_tp_idx].prob_avg; -+ - if (minstrel_ht_is_legacy_group(index / MCS_GROUP_RATES) && - !minstrel_ht_is_legacy_group(max_tp_group)) - return; - -+ /* skip rates faster than max tp rate with lower prob */ -+ if (minstrel_get_duration(mi->max_tp_rate[0]) > minstrel_get_duration(index) && -+ mrs->prob_avg < max_tp_prob) -+ return; -+ - max_gpr_group = mg->max_group_prob_rate / MCS_GROUP_RATES; - max_gpr_idx = mg->max_group_prob_rate % MCS_GROUP_RATES; - max_gpr_prob = mi->groups[max_gpr_group].rates[max_gpr_idx].prob_avg; -@@ -538,7 +547,7 @@ minstrel_ht_set_best_prob_rate(struct mi - mg->max_group_prob_rate = index; - } else { - if (mrs->prob_avg > tmp_prob) -- mi->max_prob_rate = index; -+ *dest = index; - if (mrs->prob_avg > max_gpr_prob) - mg->max_group_prob_rate = index; - } -@@ -816,7 +825,8 @@ minstrel_ht_update_stats(struct minstrel - struct minstrel_rate_stats *mrs; - int group, i, j, cur_prob; - u16 tmp_mcs_tp_rate[MAX_THR_RATES], tmp_group_tp_rate[MAX_THR_RATES]; -- u16 tmp_legacy_tp_rate[MAX_THR_RATES], index; -+ u16 tmp_legacy_tp_rate[MAX_THR_RATES], tmp_max_prob_rate; -+ u16 index; - bool ht_supported = mi->sta->ht_cap.ht_supported; - - mi->sample_mode = MINSTREL_SAMPLE_IDLE; -@@ -863,6 +873,7 @@ minstrel_ht_update_stats(struct minstrel - else - index = MINSTREL_OFDM_GROUP * MCS_GROUP_RATES; - -+ tmp_max_prob_rate = index; - for (j = 0; j < ARRAY_SIZE(tmp_mcs_tp_rate); j++) - tmp_mcs_tp_rate[j] = index; - -@@ -903,9 +914,6 @@ minstrel_ht_update_stats(struct minstrel - /* Find max throughput rate set within a group */ - minstrel_ht_sort_best_tp_rates(mi, index, - tmp_group_tp_rate); -- -- /* Find max probability rate per group and global */ -- minstrel_ht_set_best_prob_rate(mi, index); - } - - memcpy(mg->max_group_tp_rate, tmp_group_tp_rate, -@@ -917,6 +925,27 @@ minstrel_ht_update_stats(struct minstrel - tmp_legacy_tp_rate); - memcpy(mi->max_tp_rate, tmp_mcs_tp_rate, sizeof(mi->max_tp_rate)); - -+ for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) { -+ if (!mi->supported[group]) -+ continue; -+ -+ mg = &mi->groups[group]; -+ mg->max_group_prob_rate = MCS_GROUP_RATES * group; -+ -+ for (i = 0; i < MCS_GROUP_RATES; i++) { -+ if (!(mi->supported[group] & BIT(i))) -+ continue; -+ -+ index = MCS_GROUP_RATES * group + i; -+ -+ /* Find max probability rate per group and global */ -+ minstrel_ht_set_best_prob_rate(mi, &tmp_max_prob_rate, -+ index); -+ } -+ } -+ -+ mi->max_prob_rate = tmp_max_prob_rate; -+ - /* Try to increase robustness of max_prob_rate*/ - minstrel_ht_prob_rate_reduce_streams(mi); - diff --git a/package/kernel/mac80211/patches/subsys/344-mac80211-minstrel_ht-increase-stats-update-interval.patch b/package/kernel/mac80211/patches/subsys/344-mac80211-minstrel_ht-increase-stats-update-interval.patch deleted file mode 100644 index 9972a9414e2..00000000000 --- a/package/kernel/mac80211/patches/subsys/344-mac80211-minstrel_ht-increase-stats-update-interval.patch +++ /dev/null @@ -1,20 +0,0 @@ -From: Felix Fietkau <nbd@nbd.name> -Date: Sat, 26 Dec 2020 19:14:58 +0100 -Subject: [PATCH] mac80211: minstrel_ht: increase stats update interval - -The shorter interval was leading to too many frames being used for probing - -Signed-off-by: Felix Fietkau <nbd@nbd.name> ---- - ---- a/net/mac80211/rc80211_minstrel_ht.c -+++ b/net/mac80211/rc80211_minstrel_ht.c -@@ -1865,7 +1865,7 @@ minstrel_ht_alloc(struct ieee80211_hw *h - mp->has_mrr = true; - - mp->hw = hw; -- mp->update_interval = HZ / 20; -+ mp->update_interval = HZ / 10; - - minstrel_ht_init_cck_rates(mp); - for (i = 0; i < ARRAY_SIZE(mp->hw->wiphy->bands); i++) diff --git a/package/kernel/mac80211/patches/subsys/345-mac80211-minstrel_ht-fix-rounding-error-in-throughpu.patch b/package/kernel/mac80211/patches/subsys/345-mac80211-minstrel_ht-fix-rounding-error-in-throughpu.patch deleted file mode 100644 index 1df5dec0394..00000000000 --- a/package/kernel/mac80211/patches/subsys/345-mac80211-minstrel_ht-fix-rounding-error-in-throughpu.patch +++ /dev/null @@ -1,34 +0,0 @@ -From: Felix Fietkau <nbd@nbd.name> -Date: Fri, 15 Jan 2021 12:15:06 +0100 -Subject: [PATCH] mac80211: minstrel_ht: fix rounding error in throughput - calculation - -On lower data rates, the throughput calculation has a significant rounding -error, causing rates like 48M and 54M OFDM to share the same throughput -value with >= 90% success probablity. - -This is because the result of the division (prob_avg * 1000) / nsecs -is really small (8 in this example). - -Improve accuracy by moving over some zeroes, making better use of the full -range of u32 before the division. - -Signed-off-by: Felix Fietkau <nbd@nbd.name> ---- - ---- a/net/mac80211/rc80211_minstrel_ht.c -+++ b/net/mac80211/rc80211_minstrel_ht.c -@@ -445,10 +445,9 @@ minstrel_ht_get_tp_avg(struct minstrel_h - * (prob is scaled - see MINSTREL_FRAC above) - */ - if (prob_avg > MINSTREL_FRAC(90, 100)) -- return MINSTREL_TRUNC(100000 * ((MINSTREL_FRAC(90, 100) * 1000) -- / nsecs)); -- else -- return MINSTREL_TRUNC(100000 * ((prob_avg * 1000) / nsecs)); -+ prob_avg = MINSTREL_FRAC(90, 100); -+ -+ return MINSTREL_TRUNC(100 * ((prob_avg * 1000000) / nsecs)); - } - - /* diff --git a/package/kernel/mac80211/patches/subsys/346-mac80211-minstrel_ht-use-bitfields-to-encode-rate-in.patch b/package/kernel/mac80211/patches/subsys/346-mac80211-minstrel_ht-use-bitfields-to-encode-rate-in.patch deleted file mode 100644 index 6aa6f0ed934..00000000000 --- a/package/kernel/mac80211/patches/subsys/346-mac80211-minstrel_ht-use-bitfields-to-encode-rate-in.patch +++ /dev/null @@ -1,412 +0,0 @@ -From: Felix Fietkau <nbd@nbd.name> -Date: Thu, 21 Jan 2021 18:29:30 +0100 -Subject: [PATCH] mac80211: minstrel_ht: use bitfields to encode rate - indexes - -Get rid of a lot of divisions and modulo operations -Reduces code size and improves performance - -Signed-off-by: Felix Fietkau <nbd@nbd.name> ---- - ---- a/net/mac80211/rc80211_minstrel_ht.c -+++ b/net/mac80211/rc80211_minstrel_ht.c -@@ -379,14 +379,14 @@ out: - static inline struct minstrel_rate_stats * - minstrel_get_ratestats(struct minstrel_ht_sta *mi, int index) - { -- return &mi->groups[index / MCS_GROUP_RATES].rates[index % MCS_GROUP_RATES]; -+ return &mi->groups[MI_RATE_GROUP(index)].rates[MI_RATE_IDX(index)]; - } - --static inline int --minstrel_get_duration(int index) -+static inline int minstrel_get_duration(int index) - { -- const struct mcs_group *group = &minstrel_mcs_groups[index / MCS_GROUP_RATES]; -- unsigned int duration = group->duration[index % MCS_GROUP_RATES]; -+ const struct mcs_group *group = &minstrel_mcs_groups[MI_RATE_GROUP(index)]; -+ unsigned int duration = group->duration[MI_RATE_IDX(index)]; -+ - return duration << group->shift; - } - -@@ -398,7 +398,7 @@ minstrel_ht_avg_ampdu_len(struct minstre - if (mi->avg_ampdu_len) - return MINSTREL_TRUNC(mi->avg_ampdu_len); - -- if (minstrel_ht_is_legacy_group(mi->max_tp_rate[0] / MCS_GROUP_RATES)) -+ if (minstrel_ht_is_legacy_group(MI_RATE_GROUP(mi->max_tp_rate[0]))) - return 1; - - duration = minstrel_get_duration(mi->max_tp_rate[0]); -@@ -465,14 +465,14 @@ minstrel_ht_sort_best_tp_rates(struct mi - int tmp_group, tmp_idx, tmp_tp_avg, tmp_prob; - int j = MAX_THR_RATES; - -- cur_group = index / MCS_GROUP_RATES; -- cur_idx = index % MCS_GROUP_RATES; -+ cur_group = MI_RATE_GROUP(index); -+ cur_idx = MI_RATE_IDX(index); - cur_prob = mi->groups[cur_group].rates[cur_idx].prob_avg; - cur_tp_avg = minstrel_ht_get_tp_avg(mi, cur_group, cur_idx, cur_prob); - - do { -- tmp_group = tp_list[j - 1] / MCS_GROUP_RATES; -- tmp_idx = tp_list[j - 1] % MCS_GROUP_RATES; -+ tmp_group = MI_RATE_GROUP(tp_list[j - 1]); -+ tmp_idx = MI_RATE_IDX(tp_list[j - 1]); - tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_avg; - tmp_tp_avg = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx, - tmp_prob); -@@ -504,23 +504,23 @@ minstrel_ht_set_best_prob_rate(struct mi - int max_gpr_group, max_gpr_idx; - int max_gpr_tp_avg, max_gpr_prob; - -- cur_group = index / MCS_GROUP_RATES; -- cur_idx = index % MCS_GROUP_RATES; -- mg = &mi->groups[index / MCS_GROUP_RATES]; -- mrs = &mg->rates[index % MCS_GROUP_RATES]; -+ cur_group = MI_RATE_GROUP(index); -+ cur_idx = MI_RATE_IDX(index); -+ mg = &mi->groups[cur_group]; -+ mrs = &mg->rates[cur_idx]; - -- tmp_group = *dest / MCS_GROUP_RATES; -- tmp_idx = *dest % MCS_GROUP_RATES; -+ tmp_group = MI_RATE_GROUP(*dest); -+ tmp_idx = MI_RATE_IDX(*dest); - tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_avg; - tmp_tp_avg = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx, tmp_prob); - - /* if max_tp_rate[0] is from MCS_GROUP max_prob_rate get selected from - * MCS_GROUP as well as CCK_GROUP rates do not allow aggregation */ -- max_tp_group = mi->max_tp_rate[0] / MCS_GROUP_RATES; -- max_tp_idx = mi->max_tp_rate[0] % MCS_GROUP_RATES; -+ max_tp_group = MI_RATE_GROUP(mi->max_tp_rate[0]); -+ max_tp_idx = MI_RATE_IDX(mi->max_tp_rate[0]); - max_tp_prob = mi->groups[max_tp_group].rates[max_tp_idx].prob_avg; - -- if (minstrel_ht_is_legacy_group(index / MCS_GROUP_RATES) && -+ if (minstrel_ht_is_legacy_group(MI_RATE_GROUP(index)) && - !minstrel_ht_is_legacy_group(max_tp_group)) - return; - -@@ -529,8 +529,8 @@ minstrel_ht_set_best_prob_rate(struct mi - mrs->prob_avg < max_tp_prob) - return; - -- max_gpr_group = mg->max_group_prob_rate / MCS_GROUP_RATES; -- max_gpr_idx = mg->max_group_prob_rate % MCS_GROUP_RATES; -+ max_gpr_group = MI_RATE_GROUP(mg->max_group_prob_rate); -+ max_gpr_idx = MI_RATE_IDX(mg->max_group_prob_rate); - max_gpr_prob = mi->groups[max_gpr_group].rates[max_gpr_idx].prob_avg; - - if (mrs->prob_avg > MINSTREL_FRAC(75, 100)) { -@@ -567,13 +567,13 @@ minstrel_ht_assign_best_tp_rates(struct - unsigned int tmp_group, tmp_idx, tmp_cck_tp, tmp_mcs_tp, tmp_prob; - int i; - -- tmp_group = tmp_legacy_tp_rate[0] / MCS_GROUP_RATES; -- tmp_idx = tmp_legacy_tp_rate[0] % MCS_GROUP_RATES; -+ tmp_group = MI_RATE_GROUP(tmp_legacy_tp_rate[0]); -+ tmp_idx = MI_RATE_IDX(tmp_legacy_tp_rate[0]); - tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_avg; - tmp_cck_tp = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx, tmp_prob); - -- tmp_group = tmp_mcs_tp_rate[0] / MCS_GROUP_RATES; -- tmp_idx = tmp_mcs_tp_rate[0] % MCS_GROUP_RATES; -+ tmp_group = MI_RATE_GROUP(tmp_mcs_tp_rate[0]); -+ tmp_idx = MI_RATE_IDX(tmp_mcs_tp_rate[0]); - tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_avg; - tmp_mcs_tp = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx, tmp_prob); - -@@ -600,14 +600,14 @@ minstrel_ht_prob_rate_reduce_streams(str - if (!mi->sta->ht_cap.ht_supported) - return; - -- tmp_max_streams = minstrel_mcs_groups[mi->max_tp_rate[0] / -- MCS_GROUP_RATES].streams; -+ group = MI_RATE_GROUP(mi->max_tp_rate[0]); -+ tmp_max_streams = minstrel_mcs_groups[group].streams; - for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) { - mg = &mi->groups[group]; - if (!mi->supported[group] || group == MINSTREL_CCK_GROUP) - continue; - -- tmp_idx = mg->max_group_prob_rate % MCS_GROUP_RATES; -+ tmp_idx = MI_RATE_IDX(mg->max_group_prob_rate); - tmp_prob = mi->groups[group].rates[tmp_idx].prob_avg; - - if (tmp_tp < minstrel_ht_get_tp_avg(mi, group, tmp_idx, tmp_prob) && -@@ -644,8 +644,8 @@ minstrel_ht_find_probe_rates(struct mins - int i, g, max_dur; - int tp_idx; - -- tp_group = &minstrel_mcs_groups[mi->max_tp_rate[0] / MCS_GROUP_RATES]; -- tp_idx = mi->max_tp_rate[0] % MCS_GROUP_RATES; -+ tp_group = &minstrel_mcs_groups[MI_RATE_GROUP(mi->max_tp_rate[0])]; -+ tp_idx = MI_RATE_IDX(mi->max_tp_rate[0]); - - max_dur = minstrel_get_duration(mi->max_tp_rate[0]); - if (faster_rate) -@@ -670,7 +670,7 @@ minstrel_ht_find_probe_rates(struct mins - if ((group->duration[i] << group->shift) > max_dur) - continue; - -- idx = g * MCS_GROUP_RATES + i; -+ idx = MI_RATE(g, i); - if (idx == mi->max_tp_rate[0]) - continue; - -@@ -712,10 +712,10 @@ minstrel_ht_rate_sample_switch(struct mi - - /* If no suitable rate was found, try to pick the next one in the group */ - if (!n_rates) { -- int g_idx = mi->max_tp_rate[0] / MCS_GROUP_RATES; -+ int g_idx = MI_RATE_GROUP(mi->max_tp_rate[0]); - u16 supported = mi->supported[g_idx]; - -- supported >>= mi->max_tp_rate[0] % MCS_GROUP_RATES; -+ supported >>= MI_RATE_IDX(mi->max_tp_rate[0]); - for (i = 0; supported; supported >>= 1, i++) { - if (!(supported & 1)) - continue; -@@ -854,24 +854,27 @@ minstrel_ht_update_stats(struct minstrel - mi->sample_slow = 0; - mi->sample_count = 0; - -- memset(tmp_mcs_tp_rate, 0, sizeof(tmp_mcs_tp_rate)); -- memset(tmp_legacy_tp_rate, 0, sizeof(tmp_legacy_tp_rate)); - if (mi->supported[MINSTREL_CCK_GROUP]) -- for (j = 0; j < ARRAY_SIZE(tmp_legacy_tp_rate); j++) -- tmp_legacy_tp_rate[j] = MINSTREL_CCK_GROUP * MCS_GROUP_RATES; -+ group = MINSTREL_CCK_GROUP; - else if (mi->supported[MINSTREL_OFDM_GROUP]) -- for (j = 0; j < ARRAY_SIZE(tmp_legacy_tp_rate); j++) -- tmp_legacy_tp_rate[j] = MINSTREL_OFDM_GROUP * MCS_GROUP_RATES; -+ group = MINSTREL_OFDM_GROUP; -+ else -+ group = 0; -+ -+ index = MI_RATE(group, 0); -+ for (j = 0; j < ARRAY_SIZE(tmp_legacy_tp_rate); j++) -+ tmp_legacy_tp_rate[j] = index; - - if (mi->supported[MINSTREL_VHT_GROUP_0]) -- index = MINSTREL_VHT_GROUP_0 * MCS_GROUP_RATES; -+ group = MINSTREL_VHT_GROUP_0; - else if (ht_supported) -- index = MINSTREL_HT_GROUP_0 * MCS_GROUP_RATES; -+ group = MINSTREL_HT_GROUP_0; - else if (mi->supported[MINSTREL_CCK_GROUP]) -- index = MINSTREL_CCK_GROUP * MCS_GROUP_RATES; -+ group = MINSTREL_CCK_GROUP; - else -- index = MINSTREL_OFDM_GROUP * MCS_GROUP_RATES; -+ group = MINSTREL_OFDM_GROUP; - -+ index = MI_RATE(group, 0); - tmp_max_prob_rate = index; - for (j = 0; j < ARRAY_SIZE(tmp_mcs_tp_rate); j++) - tmp_mcs_tp_rate[j] = index; -@@ -888,7 +891,7 @@ minstrel_ht_update_stats(struct minstrel - - /* (re)Initialize group rate indexes */ - for(j = 0; j < MAX_THR_RATES; j++) -- tmp_group_tp_rate[j] = MCS_GROUP_RATES * group; -+ tmp_group_tp_rate[j] = MI_RATE(group, 0); - - if (group == MINSTREL_CCK_GROUP && ht_supported) - tp_rate = tmp_legacy_tp_rate; -@@ -897,7 +900,7 @@ minstrel_ht_update_stats(struct minstrel - if (!(mi->supported[group] & BIT(i))) - continue; - -- index = MCS_GROUP_RATES * group + i; -+ index = MI_RATE(group, i); - - mrs = &mg->rates[i]; - mrs->retry_updated = false; -@@ -929,13 +932,13 @@ minstrel_ht_update_stats(struct minstrel - continue; - - mg = &mi->groups[group]; -- mg->max_group_prob_rate = MCS_GROUP_RATES * group; -+ mg->max_group_prob_rate = MI_RATE(group, 0); - - for (i = 0; i < MCS_GROUP_RATES; i++) { - if (!(mi->supported[group] & BIT(i))) - continue; - -- index = MCS_GROUP_RATES * group + i; -+ index = MI_RATE(group, i); - - /* Find max probability rate per group and global */ - minstrel_ht_set_best_prob_rate(mi, &tmp_max_prob_rate, -@@ -1022,7 +1025,7 @@ minstrel_downgrade_rate(struct minstrel_ - { - int group, orig_group; - -- orig_group = group = *idx / MCS_GROUP_RATES; -+ orig_group = group = MI_RATE_GROUP(*idx); - while (group > 0) { - group--; - -@@ -1206,7 +1209,7 @@ minstrel_calc_retransmit(struct minstrel - ctime += (t_slot * cw) >> 1; - cw = min((cw << 1) | 1, mp->cw_max); - -- if (minstrel_ht_is_legacy_group(index / MCS_GROUP_RATES)) { -+ if (minstrel_ht_is_legacy_group(MI_RATE_GROUP(index))) { - overhead = mi->overhead_legacy; - overhead_rtscts = mi->overhead_legacy_rtscts; - } else { -@@ -1239,7 +1242,7 @@ static void - minstrel_ht_set_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, - struct ieee80211_sta_rates *ratetbl, int offset, int index) - { -- int group_idx = index / MCS_GROUP_RATES; -+ int group_idx = MI_RATE_GROUP(index); - const struct mcs_group *group = &minstrel_mcs_groups[group_idx]; - struct minstrel_rate_stats *mrs; - u8 idx; -@@ -1259,7 +1262,7 @@ minstrel_ht_set_rate(struct minstrel_pri - ratetbl->rate[offset].count_rts = mrs->retry_count_rtscts; - } - -- index %= MCS_GROUP_RATES; -+ index = MI_RATE_IDX(index); - if (group_idx == MINSTREL_CCK_GROUP) - idx = mp->cck_rates[index % ARRAY_SIZE(mp->cck_rates)]; - else if (group_idx == MINSTREL_OFDM_GROUP) -@@ -1289,17 +1292,17 @@ minstrel_ht_set_rate(struct minstrel_pri - static inline int - minstrel_ht_get_prob_avg(struct minstrel_ht_sta *mi, int rate) - { -- int group = rate / MCS_GROUP_RATES; -- rate %= MCS_GROUP_RATES; -+ int group = MI_RATE_GROUP(rate); -+ rate = MI_RATE_IDX(rate); - return mi->groups[group].rates[rate].prob_avg; - } - - static int - minstrel_ht_get_max_amsdu_len(struct minstrel_ht_sta *mi) - { -- int group = mi->max_prob_rate / MCS_GROUP_RATES; -+ int group = MI_RATE_GROUP(mi->max_prob_rate); - const struct mcs_group *g = &minstrel_mcs_groups[group]; -- int rate = mi->max_prob_rate % MCS_GROUP_RATES; -+ int rate = MI_RATE_IDX(mi->max_prob_rate); - unsigned int duration; - - /* Disable A-MSDU if max_prob_rate is bad */ -@@ -1405,7 +1408,7 @@ minstrel_get_sample_rate(struct minstrel - return -1; - - mrs = &mg->rates[sample_idx]; -- sample_idx += sample_group * MCS_GROUP_RATES; -+ sample_idx += MI_RATE(sample_group, 0); - - tp_rate1 = mi->max_tp_rate[0]; - -@@ -1455,8 +1458,7 @@ minstrel_get_sample_rate(struct minstrel - * if the link is working perfectly. - */ - -- cur_max_tp_streams = minstrel_mcs_groups[tp_rate1 / -- MCS_GROUP_RATES].streams; -+ cur_max_tp_streams = minstrel_mcs_groups[MI_RATE_GROUP(tp_rate1)].streams; - if (sample_dur >= minstrel_get_duration(tp_rate2) && - (cur_max_tp_streams - 1 < - minstrel_mcs_groups[sample_group].streams || -@@ -1484,7 +1486,7 @@ minstrel_ht_get_rate(void *priv, struct - int sample_idx; - - if (!(info->flags & IEEE80211_TX_CTL_AMPDU) && -- !minstrel_ht_is_legacy_group(mi->max_prob_rate / MCS_GROUP_RATES)) -+ !minstrel_ht_is_legacy_group(MI_RATE_GROUP(mi->max_prob_rate))) - minstrel_aggr_check(sta, txrc->skb); - - info->flags |= mi->tx_flags; -@@ -1512,8 +1514,8 @@ minstrel_ht_get_rate(void *priv, struct - if (sample_idx < 0) - return; - -- sample_group = &minstrel_mcs_groups[sample_idx / MCS_GROUP_RATES]; -- sample_idx %= MCS_GROUP_RATES; -+ sample_group = &minstrel_mcs_groups[MI_RATE_GROUP(sample_idx)]; -+ sample_idx = MI_RATE_IDX(sample_idx); - - if (sample_group == &minstrel_mcs_groups[MINSTREL_CCK_GROUP] && - (sample_idx >= 4) != txrc->short_preamble) -@@ -1529,7 +1531,7 @@ minstrel_ht_get_rate(void *priv, struct - int idx = sample_idx % ARRAY_SIZE(mp->ofdm_rates[0]); - rate->idx = mp->ofdm_rates[mi->band][idx]; - } else if (sample_group->flags & IEEE80211_TX_RC_VHT_MCS) { -- ieee80211_rate_set_vht(rate, sample_idx % MCS_GROUP_RATES, -+ ieee80211_rate_set_vht(rate, MI_RATE_IDX(sample_idx), - sample_group->streams); - } else { - rate->idx = sample_idx + (sample_group->streams - 1) * 8; -@@ -1898,8 +1900,8 @@ static u32 minstrel_ht_get_expected_thro - struct minstrel_ht_sta *mi = priv_sta; - int i, j, prob, tp_avg; - -- i = mi->max_tp_rate[0] / MCS_GROUP_RATES; -- j = mi->max_tp_rate[0] % MCS_GROUP_RATES; -+ i = MI_RATE_GROUP(mi->max_tp_rate[0]); -+ j = MI_RATE_IDX(mi->max_tp_rate[0]); - prob = mi->groups[i].rates[j].prob_avg; - - /* convert tp_avg from pkt per second in kbps */ ---- a/net/mac80211/rc80211_minstrel_ht.h -+++ b/net/mac80211/rc80211_minstrel_ht.h -@@ -6,6 +6,8 @@ - #ifndef __RC_MINSTREL_HT_H - #define __RC_MINSTREL_HT_H - -+#include <linux/bitfield.h> -+ - /* number of highest throughput rates to consider*/ - #define MAX_THR_RATES 4 - #define SAMPLE_COLUMNS 10 /* number of columns in sample table */ -@@ -57,6 +59,17 @@ - - #define MCS_GROUP_RATES 10 - -+#define MI_RATE_IDX_MASK GENMASK(3, 0) -+#define MI_RATE_GROUP_MASK GENMASK(15, 4) -+ -+#define MI_RATE(_group, _idx) \ -+ (FIELD_PREP(MI_RATE_GROUP_MASK, _group) | \ -+ FIELD_PREP(MI_RATE_IDX_MASK, _idx)) -+ -+#define MI_RATE_IDX(_rate) FIELD_GET(MI_RATE_IDX_MASK, _rate) -+#define MI_RATE_GROUP(_rate) FIELD_GET(MI_RATE_GROUP_MASK, _rate) -+ -+ - struct minstrel_priv { - struct ieee80211_hw *hw; - bool has_mrr; ---- a/net/mac80211/rc80211_minstrel_ht_debugfs.c -+++ b/net/mac80211/rc80211_minstrel_ht_debugfs.c -@@ -56,7 +56,7 @@ minstrel_ht_stats_dump(struct minstrel_h - - for (j = 0; j < MCS_GROUP_RATES; j++) { - struct minstrel_rate_stats *mrs = &mi->groups[i].rates[j]; -- int idx = i * MCS_GROUP_RATES + j; -+ int idx = MI_RATE(i, j); - unsigned int duration; - - if (!(mi->supported[i] & BIT(j))) -@@ -201,7 +201,7 @@ minstrel_ht_stats_csv_dump(struct minstr - - for (j = 0; j < MCS_GROUP_RATES; j++) { - struct minstrel_rate_stats *mrs = &mi->groups[i].rates[j]; -- int idx = i * MCS_GROUP_RATES + j; -+ int idx = MI_RATE(i, j); - unsigned int duration; - - if (!(mi->supported[i] & BIT(j))) diff --git a/package/kernel/mac80211/patches/subsys/347-mac80211-minstrel_ht-update-total-packets-counter-in.patch b/package/kernel/mac80211/patches/subsys/347-mac80211-minstrel_ht-update-total-packets-counter-in.patch deleted file mode 100644 index dce8104934f..00000000000 --- a/package/kernel/mac80211/patches/subsys/347-mac80211-minstrel_ht-update-total-packets-counter-in.patch +++ /dev/null @@ -1,54 +0,0 @@ -From: Felix Fietkau <nbd@nbd.name> -Date: Fri, 22 Jan 2021 18:21:13 +0100 -Subject: [PATCH] mac80211: minstrel_ht: update total packets counter in tx - status path - -Keep the update in one place and prepare for further rework - -Signed-off-by: Felix Fietkau <nbd@nbd.name> ---- - ---- a/net/mac80211/rc80211_minstrel_ht.c -+++ b/net/mac80211/rc80211_minstrel_ht.c -@@ -1092,6 +1092,16 @@ minstrel_ht_tx_status(void *priv, struct - info->status.ampdu_len = 1; - } - -+ /* wraparound */ -+ if (mi->total_packets >= ~0 - info->status.ampdu_len) { -+ mi->total_packets = 0; -+ mi->sample_packets = 0; -+ } -+ -+ mi->total_packets += info->status.ampdu_len; -+ if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) -+ mi->sample_packets += info->status.ampdu_len; -+ - mi->ampdu_packets++; - mi->ampdu_len += info->status.ampdu_len; - -@@ -1103,9 +1113,6 @@ minstrel_ht_tx_status(void *priv, struct - mi->sample_count--; - } - -- if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) -- mi->sample_packets += info->status.ampdu_len; -- - if (mi->sample_mode != MINSTREL_SAMPLE_IDLE) - rate_sample = minstrel_get_ratestats(mi, mi->sample_rate); - -@@ -1503,14 +1510,6 @@ minstrel_ht_get_rate(void *priv, struct - else - sample_idx = minstrel_get_sample_rate(mp, mi); - -- mi->total_packets++; -- -- /* wraparound */ -- if (mi->total_packets == ~0) { -- mi->total_packets = 0; -- mi->sample_packets = 0; -- } -- - if (sample_idx < 0) - return; - diff --git a/package/kernel/mac80211/patches/subsys/348-mac80211-minstrel_ht-reduce-the-need-to-sample-slowe.patch b/package/kernel/mac80211/patches/subsys/348-mac80211-minstrel_ht-reduce-the-need-to-sample-slowe.patch deleted file mode 100644 index dc6f11e4b94..00000000000 --- a/package/kernel/mac80211/patches/subsys/348-mac80211-minstrel_ht-reduce-the-need-to-sample-slowe.patch +++ /dev/null @@ -1,102 +0,0 @@ -From: Felix Fietkau <nbd@nbd.name> -Date: Fri, 22 Jan 2021 19:24:59 +0100 -Subject: [PATCH] mac80211: minstrel_ht: reduce the need to sample slower - rates - -In order to more gracefully be able to fall back to lower rates without too -much throughput fluctuations, initialize all untested rates below tested ones -to the maximum probabilty of higher rates. -Usually this leads to untested lower rates getting initialized with a -probability value of 100%, making them better candidates for fallback without -having to rely on random probing - -Signed-off-by: Felix Fietkau <nbd@nbd.name> ---- - ---- a/net/mac80211/rc80211_minstrel_ht.c -+++ b/net/mac80211/rc80211_minstrel_ht.c -@@ -791,14 +791,11 @@ minstrel_ht_calc_rate_stats(struct minst - unsigned int cur_prob; - - if (unlikely(mrs->attempts > 0)) { -- mrs->sample_skipped = 0; - cur_prob = MINSTREL_FRAC(mrs->success, mrs->attempts); - minstrel_filter_avg_add(&mrs->prob_avg, - &mrs->prob_avg_1, cur_prob); - mrs->att_hist += mrs->attempts; - mrs->succ_hist += mrs->success; -- } else { -- mrs->sample_skipped++; - } - - mrs->last_success = mrs->success; -@@ -851,7 +848,6 @@ minstrel_ht_update_stats(struct minstrel - mi->ampdu_packets = 0; - } - -- mi->sample_slow = 0; - mi->sample_count = 0; - - if (mi->supported[MINSTREL_CCK_GROUP]) -@@ -882,6 +878,7 @@ minstrel_ht_update_stats(struct minstrel - /* Find best rate sets within all MCS groups*/ - for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) { - u16 *tp_rate = tmp_mcs_tp_rate; -+ u16 last_prob = 0; - - mg = &mi->groups[group]; - if (!mi->supported[group]) -@@ -896,7 +893,7 @@ minstrel_ht_update_stats(struct minstrel - if (group == MINSTREL_CCK_GROUP && ht_supported) - tp_rate = tmp_legacy_tp_rate; - -- for (i = 0; i < MCS_GROUP_RATES; i++) { -+ for (i = MCS_GROUP_RATES - 1; i >= 0; i--) { - if (!(mi->supported[group] & BIT(i))) - continue; - -@@ -905,6 +902,11 @@ minstrel_ht_update_stats(struct minstrel - mrs = &mg->rates[i]; - mrs->retry_updated = false; - minstrel_ht_calc_rate_stats(mp, mrs); -+ -+ if (mrs->att_hist) -+ last_prob = max(last_prob, mrs->prob_avg); -+ else -+ mrs->prob_avg = max(last_prob, mrs->prob_avg); - cur_prob = mrs->prob_avg; - - if (minstrel_ht_get_tp_avg(mi, group, i, cur_prob) == 0) -@@ -1469,13 +1471,9 @@ minstrel_get_sample_rate(struct minstrel - if (sample_dur >= minstrel_get_duration(tp_rate2) && - (cur_max_tp_streams - 1 < - minstrel_mcs_groups[sample_group].streams || -- sample_dur >= minstrel_get_duration(mi->max_prob_rate))) { -- if (mrs->sample_skipped < 20) -+ sample_dur >= minstrel_get_duration(mi->max_prob_rate))) - return -1; - -- if (mi->sample_slow++ > 2) -- return -1; -- } - mi->sample_tries--; - - return sample_idx; ---- a/net/mac80211/rc80211_minstrel_ht.h -+++ b/net/mac80211/rc80211_minstrel_ht.h -@@ -123,7 +123,6 @@ struct minstrel_rate_stats { - u8 retry_count; - u8 retry_count_rtscts; - -- u8 sample_skipped; - bool retry_updated; - }; - -@@ -179,7 +178,6 @@ struct minstrel_ht_sta { - u8 sample_wait; - u8 sample_tries; - u8 sample_count; -- u8 sample_slow; - - enum minstrel_sample_mode sample_mode; - u16 sample_rate; diff --git a/package/kernel/mac80211/patches/subsys/349-mac80211-minstrel_ht-significantly-redesign-the-rate.patch b/package/kernel/mac80211/patches/subsys/349-mac80211-minstrel_ht-significantly-redesign-the-rate.patch deleted file mode 100644 index 09f6fd22144..00000000000 --- a/package/kernel/mac80211/patches/subsys/349-mac80211-minstrel_ht-significantly-redesign-the-rate.patch +++ /dev/null @@ -1,767 +0,0 @@ -From: Felix Fietkau <nbd@nbd.name> -Date: Fri, 22 Jan 2021 23:57:50 +0100 -Subject: [PATCH] mac80211: minstrel_ht: significantly redesign the rate - probing strategy - -The biggest flaw in current minstrel_ht is the fact that it needs way too -many probing packets to be able to quickly find the best rate. -Depending on the wifi hardware and operating mode, this can significantly -reduce throughput when not operating at the highest available data rate. - -In order to be able to significantly reduce the amount of rate sampling, -we need a much smarter selection of probing rates. - -The new approach introduced by this patch maintains a limited set of -available rates to be tested during a statistics window. - -They are split into distinct categories: -- MINSTREL_SAMPLE_TYPE_INC - incremental rate upgrade: - Pick the next rate group and find the first rate that is faster than - the current max. throughput rate -- MINSTREL_SAMPLE_TYPE_JUMP - random testing of higher rates: - Pick a random rate from the next group that is faster than the current - max throughput rate. This allows faster adaptation when the link changes - significantly -- MINSTREL_SAMPLE_TYPE_SLOW - test a rate between max_prob, max_tp2 and - max_tp in order to reduce the gap between them - -In order to prioritize sampling, every 6 attempts are split into 3x INC, -2x JUMP, 1x SLOW. - -Available rates are checked and refilled on every stats window update. - -With this approach, we finally get a very small delta in throughput when -comparing setting the optimal data rate as a fixed rate vs normal rate -control operation. - -Signed-off-by: Felix Fietkau <nbd@nbd.name> ---- - ---- a/net/mac80211/rc80211_minstrel_ht.c -+++ b/net/mac80211/rc80211_minstrel_ht.c -@@ -266,6 +266,14 @@ const struct mcs_group minstrel_mcs_grou - const s16 minstrel_cck_bitrates[4] = { 10, 20, 55, 110 }; - const s16 minstrel_ofdm_bitrates[8] = { 60, 90, 120, 180, 240, 360, 480, 540 }; - static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES] __read_mostly; -+static const u8 minstrel_sample_seq[] = { -+ MINSTREL_SAMPLE_TYPE_INC, -+ MINSTREL_SAMPLE_TYPE_JUMP, -+ MINSTREL_SAMPLE_TYPE_INC, -+ MINSTREL_SAMPLE_TYPE_JUMP, -+ MINSTREL_SAMPLE_TYPE_INC, -+ MINSTREL_SAMPLE_TYPE_SLOW, -+}; - - static void - minstrel_ht_update_rates(struct minstrel_priv *mp, struct minstrel_ht_sta *mi); -@@ -620,77 +628,31 @@ minstrel_ht_prob_rate_reduce_streams(str - } - } - --static bool --minstrel_ht_probe_group(struct minstrel_ht_sta *mi, const struct mcs_group *tp_group, -- int tp_idx, const struct mcs_group *group) --{ -- if (group->bw < tp_group->bw) -- return false; -- -- if (group->streams == tp_group->streams) -- return true; -- -- if (tp_idx < 4 && group->streams == tp_group->streams - 1) -- return true; -- -- return group->streams == tp_group->streams + 1; --} -- --static void --minstrel_ht_find_probe_rates(struct minstrel_ht_sta *mi, u16 *rates, int *n_rates, -- bool faster_rate) -+static u16 -+__minstrel_ht_get_sample_rate(struct minstrel_ht_sta *mi, -+ enum minstrel_sample_type type) - { -- const struct mcs_group *group, *tp_group; -- int i, g, max_dur; -- int tp_idx; -- -- tp_group = &minstrel_mcs_groups[MI_RATE_GROUP(mi->max_tp_rate[0])]; -- tp_idx = MI_RATE_IDX(mi->max_tp_rate[0]); -- -- max_dur = minstrel_get_duration(mi->max_tp_rate[0]); -- if (faster_rate) -- max_dur -= max_dur / 16; -- -- for (g = 0; g < MINSTREL_GROUPS_NB; g++) { -- u16 supported = mi->supported[g]; -- -- if (!supported) -- continue; -+ u16 *rates = mi->sample[type].sample_rates; -+ u16 cur; -+ int i; - -- group = &minstrel_mcs_groups[g]; -- if (!minstrel_ht_probe_group(mi, tp_group, tp_idx, group)) -+ for (i = 0; i < MINSTREL_SAMPLE_RATES; i++) { -+ if (!rates[i]) - continue; - -- for (i = 0; supported; supported >>= 1, i++) { -- int idx; -- -- if (!(supported & 1)) -- continue; -- -- if ((group->duration[i] << group->shift) > max_dur) -- continue; -- -- idx = MI_RATE(g, i); -- if (idx == mi->max_tp_rate[0]) -- continue; -- -- rates[(*n_rates)++] = idx; -- break; -- } -+ cur = rates[i]; -+ rates[i] = 0; -+ return cur; - } -+ -+ return 0; - } - - static void - minstrel_ht_rate_sample_switch(struct minstrel_priv *mp, - struct minstrel_ht_sta *mi) - { -- struct minstrel_rate_stats *mrs; -- u16 rates[MINSTREL_GROUPS_NB]; -- int n_rates = 0; -- int probe_rate = 0; -- bool faster_rate; -- int i; -- u8 random; -+ u16 rate; - - /* - * Use rate switching instead of probing packets for devices with -@@ -699,43 +661,11 @@ minstrel_ht_rate_sample_switch(struct mi - if (mp->hw->max_rates > 1) - return; - -- /* -- * If the current EWMA prob is >75%, look for a rate that's 6.25% -- * faster than the max tp rate. -- * If that fails, look again for a rate that is at least as fast -- */ -- mrs = minstrel_get_ratestats(mi, mi->max_tp_rate[0]); -- faster_rate = mrs->prob_avg > MINSTREL_FRAC(75, 100); -- minstrel_ht_find_probe_rates(mi, rates, &n_rates, faster_rate); -- if (!n_rates && faster_rate) -- minstrel_ht_find_probe_rates(mi, rates, &n_rates, false); -- -- /* If no suitable rate was found, try to pick the next one in the group */ -- if (!n_rates) { -- int g_idx = MI_RATE_GROUP(mi->max_tp_rate[0]); -- u16 supported = mi->supported[g_idx]; -- -- supported >>= MI_RATE_IDX(mi->max_tp_rate[0]); -- for (i = 0; supported; supported >>= 1, i++) { -- if (!(supported & 1)) -- continue; -- -- probe_rate = mi->max_tp_rate[0] + i; -- goto out; -- } -- -+ rate = __minstrel_ht_get_sample_rate(mi, MINSTREL_SAMPLE_TYPE_INC); -+ if (!rate) - return; -- } -- -- i = 0; -- if (n_rates > 1) { -- random = prandom_u32(); -- i = random % n_rates; -- } -- probe_rate = rates[i]; - --out: -- mi->sample_rate = probe_rate; -+ mi->sample_rate = rate; - mi->sample_mode = MINSTREL_SAMPLE_ACTIVE; - } - -@@ -804,6 +734,274 @@ minstrel_ht_calc_rate_stats(struct minst - mrs->attempts = 0; - } - -+static bool -+minstrel_ht_find_sample_rate(struct minstrel_ht_sta *mi, int type, int idx) -+{ -+ int i; -+ -+ for (i = 0; i < MINSTREL_SAMPLE_RATES; i++) { -+ u16 cur = mi->sample[type].sample_rates[i]; -+ -+ if (cur == idx) -+ return true; -+ -+ if (!cur) -+ break; -+ } -+ -+ return false; -+} -+ -+static int -+minstrel_ht_move_sample_rates(struct minstrel_ht_sta *mi, int type, -+ u32 fast_rate_dur, u32 slow_rate_dur) -+{ -+ u16 *rates = mi->sample[type].sample_rates; -+ int i, j; -+ -+ for (i = 0, j = 0; i < MINSTREL_SAMPLE_RATES; i++) { -+ u32 duration; -+ bool valid = false; -+ u16 cur; -+ -+ cur = rates[i]; -+ if (!cur) -+ continue; -+ -+ duration = minstrel_get_duration(cur); -+ switch (type) { -+ case MINSTREL_SAMPLE_TYPE_SLOW: -+ valid = duration > fast_rate_dur && -+ duration < slow_rate_dur; -+ break; -+ case MINSTREL_SAMPLE_TYPE_INC: -+ case MINSTREL_SAMPLE_TYPE_JUMP: -+ valid = duration < fast_rate_dur; -+ break; -+ default: -+ valid = false; -+ break; -+ } -+ -+ if (!valid) { -+ rates[i] = 0; -+ continue; -+ } -+ -+ if (i == j) -+ continue; -+ -+ rates[j++] = cur; -+ rates[i] = 0; -+ } -+ -+ return j; -+} -+ -+static int -+minstrel_ht_group_min_rate_offset(struct minstrel_ht_sta *mi, int group, -+ u32 max_duration) -+{ -+ u16 supported = mi->supported[group]; -+ int i; -+ -+ for (i = 0; i < MCS_GROUP_RATES && supported; i++, supported >>= 1) { -+ if (!(supported & BIT(0))) -+ continue; -+ -+ if (minstrel_get_duration(MI_RATE(group, i)) >= max_duration) -+ continue; -+ -+ return i; -+ } -+ -+ return -1; -+} -+ -+/* -+ * Incremental update rates: -+ * Flip through groups and pick the first group rate that is faster than the -+ * highest currently selected rate -+ */ -+static u16 -+minstrel_ht_next_inc_rate(struct minstrel_ht_sta *mi, u32 fast_rate_dur) -+{ -+ struct minstrel_mcs_group_data *mg; -+ u8 type = MINSTREL_SAMPLE_TYPE_INC; -+ int i, index = 0; -+ u8 group; -+ -+ group = mi->sample[type].sample_group; -+ for (i = 0; i < ARRAY_SIZE(minstrel_mcs_groups); i++) { -+ group = (group + 1) % ARRAY_SIZE(minstrel_mcs_groups); -+ mg = &mi->groups[group]; -+ -+ index = minstrel_ht_group_min_rate_offset(mi, group, -+ fast_rate_dur); -+ if (index < 0) -+ continue; -+ -+ index = MI_RATE(group, index & 0xf); -+ if (!minstrel_ht_find_sample_rate(mi, type, index)) -+ goto out; -+ } -+ index = 0; -+ -+out: -+ mi->sample[type].sample_group = group; -+ -+ return index; -+} -+ -+static int -+minstrel_ht_next_group_sample_rate(struct minstrel_ht_sta *mi, int group, -+ u16 supported, int offset) -+{ -+ struct minstrel_mcs_group_data *mg = &mi->groups[group]; -+ u16 idx; -+ int i; -+ -+ for (i = 0; i < MCS_GROUP_RATES; i++) { -+ idx = sample_table[mg->column][mg->index]; -+ if (++mg->index >= MCS_GROUP_RATES) { -+ mg->index = 0; -+ if (++mg->column >= ARRAY_SIZE(sample_table)) -+ mg->column = 0; -+ } -+ -+ if (idx < offset) -+ continue; -+ -+ if (!(supported & BIT(idx))) -+ continue; -+ -+ return MI_RATE(group, idx); -+ } -+ -+ return -1; -+} -+ -+/* -+ * Jump rates: -+ * Sample random rates, use those that are faster than the highest -+ * currently selected rate. Rates between the fastest and the slowest -+ * get sorted into the slow sample bucket, but only if it has room -+ */ -+static u16 -+minstrel_ht_next_jump_rate(struct minstrel_ht_sta *mi, u32 fast_rate_dur, -+ u32 slow_rate_dur, int *slow_rate_ofs) -+{ -+ struct minstrel_mcs_group_data *mg; -+ struct minstrel_rate_stats *mrs; -+ u32 max_duration = slow_rate_dur; -+ int i, index, offset; -+ u16 *slow_rates; -+ u16 supported; -+ u32 duration; -+ u8 group; -+ -+ if (*slow_rate_ofs >= MINSTREL_SAMPLE_RATES) -+ max_duration = fast_rate_dur; -+ -+ slow_rates = mi->sample[MINSTREL_SAMPLE_TYPE_SLOW].sample_rates; -+ group = mi->sample[MINSTREL_SAMPLE_TYPE_JUMP].sample_group; -+ for (i = 0; i < ARRAY_SIZE(minstrel_mcs_groups); i++) { -+ u8 type; -+ -+ group = (group + 1) % ARRAY_SIZE(minstrel_mcs_groups); -+ mg = &mi->groups[group]; -+ -+ supported = mi->supported[group]; -+ if (!supported) -+ continue; -+ -+ offset = minstrel_ht_group_min_rate_offset(mi, group, -+ max_duration); -+ if (offset < 0) -+ continue; -+ -+ index = minstrel_ht_next_group_sample_rate(mi, group, supported, -+ offset); -+ if (index < 0) -+ continue; -+ -+ duration = minstrel_get_duration(index); -+ if (duration < fast_rate_dur) -+ type = MINSTREL_SAMPLE_TYPE_JUMP; -+ else -+ type = MINSTREL_SAMPLE_TYPE_SLOW; -+ -+ if (minstrel_ht_find_sample_rate(mi, type, index)) -+ continue; -+ -+ if (type == MINSTREL_SAMPLE_TYPE_JUMP) -+ goto found; -+ -+ if (*slow_rate_ofs >= MINSTREL_SAMPLE_RATES) -+ continue; -+ -+ if (duration >= slow_rate_dur) -+ continue; -+ -+ /* skip slow rates with high success probability */ -+ mrs = minstrel_get_ratestats(mi, index); -+ if (mrs->prob_avg > MINSTREL_FRAC(95, 100)) -+ continue; -+ -+ slow_rates[(*slow_rate_ofs)++] = index; -+ if (*slow_rate_ofs >= MINSTREL_SAMPLE_RATES) -+ max_duration = fast_rate_dur; -+ } -+ index = 0; -+ -+found: -+ mi->sample[MINSTREL_SAMPLE_TYPE_JUMP].sample_group = group; -+ -+ return index; -+} -+ -+static void -+minstrel_ht_refill_sample_rates(struct minstrel_ht_sta *mi) -+{ -+ u32 prob_dur = minstrel_get_duration(mi->max_prob_rate); -+ u32 tp_dur = minstrel_get_duration(mi->max_tp_rate[0]); -+ u32 tp2_dur = minstrel_get_duration(mi->max_tp_rate[1]); -+ u32 fast_rate_dur = min(min(tp_dur, tp2_dur), prob_dur); -+ u32 slow_rate_dur = max(max(tp_dur, tp2_dur), prob_dur); -+ u16 *rates; -+ int i, j; -+ -+ rates = mi->sample[MINSTREL_SAMPLE_TYPE_INC].sample_rates; -+ i = minstrel_ht_move_sample_rates(mi, MINSTREL_SAMPLE_TYPE_INC, -+ fast_rate_dur, slow_rate_dur); -+ while (i < MINSTREL_SAMPLE_RATES) { -+ rates[i] = minstrel_ht_next_inc_rate(mi, tp_dur); -+ if (!rates[i]) -+ break; -+ -+ i++; -+ } -+ -+ rates = mi->sample[MINSTREL_SAMPLE_TYPE_JUMP].sample_rates; -+ i = minstrel_ht_move_sample_rates(mi, MINSTREL_SAMPLE_TYPE_JUMP, -+ fast_rate_dur, slow_rate_dur); -+ j = minstrel_ht_move_sample_rates(mi, MINSTREL_SAMPLE_TYPE_SLOW, -+ fast_rate_dur, slow_rate_dur); -+ while (i < MINSTREL_SAMPLE_RATES) { -+ rates[i] = minstrel_ht_next_jump_rate(mi, fast_rate_dur, -+ slow_rate_dur, &j); -+ if (!rates[i]) -+ break; -+ -+ i++; -+ } -+ -+ for (i = 0; i < ARRAY_SIZE(mi->sample); i++) -+ memcpy(mi->sample[i].cur_sample_rates, mi->sample[i].sample_rates, -+ sizeof(mi->sample[i].cur_sample_rates)); -+} -+ -+ - /* - * Update rate statistics and select new primary rates - * -@@ -848,8 +1046,6 @@ minstrel_ht_update_stats(struct minstrel - mi->ampdu_packets = 0; - } - -- mi->sample_count = 0; -- - if (mi->supported[MINSTREL_CCK_GROUP]) - group = MINSTREL_CCK_GROUP; - else if (mi->supported[MINSTREL_OFDM_GROUP]) -@@ -884,8 +1080,6 @@ minstrel_ht_update_stats(struct minstrel - if (!mi->supported[group]) - continue; - -- mi->sample_count++; -- - /* (re)Initialize group rate indexes */ - for(j = 0; j < MAX_THR_RATES; j++) - tmp_group_tp_rate[j] = MI_RATE(group, 0); -@@ -952,9 +1146,7 @@ minstrel_ht_update_stats(struct minstrel - - /* Try to increase robustness of max_prob_rate*/ - minstrel_ht_prob_rate_reduce_streams(mi); -- -- /* try to sample half of all available rates during each interval */ -- mi->sample_count *= 4; -+ minstrel_ht_refill_sample_rates(mi); - - if (sample) - minstrel_ht_rate_sample_switch(mp, mi); -@@ -971,6 +1163,7 @@ minstrel_ht_update_stats(struct minstrel - - /* Reset update timer */ - mi->last_stats_update = jiffies; -+ mi->sample_time = jiffies; - } - - static bool -@@ -1001,28 +1194,6 @@ minstrel_ht_txstat_valid(struct minstrel - } - - static void --minstrel_set_next_sample_idx(struct minstrel_ht_sta *mi) --{ -- struct minstrel_mcs_group_data *mg; -- -- for (;;) { -- mi->sample_group++; -- mi->sample_group %= ARRAY_SIZE(minstrel_mcs_groups); -- mg = &mi->groups[mi->sample_group]; -- -- if (!mi->supported[mi->sample_group]) -- continue; -- -- if (++mg->index >= MCS_GROUP_RATES) { -- mg->index = 0; -- if (++mg->column >= ARRAY_SIZE(sample_table)) -- mg->column = 0; -- } -- break; -- } --} -- --static void - minstrel_downgrade_rate(struct minstrel_ht_sta *mi, u16 *idx, bool primary) - { - int group, orig_group; -@@ -1107,14 +1278,6 @@ minstrel_ht_tx_status(void *priv, struct - mi->ampdu_packets++; - mi->ampdu_len += info->status.ampdu_len; - -- if (!mi->sample_wait && !mi->sample_tries && mi->sample_count > 0) { -- int avg_ampdu_len = minstrel_ht_avg_ampdu_len(mi); -- -- mi->sample_wait = 16 + 2 * avg_ampdu_len; -- mi->sample_tries = 1; -- mi->sample_count--; -- } -- - if (mi->sample_mode != MINSTREL_SAMPLE_IDLE) - rate_sample = minstrel_get_ratestats(mi, mi->sample_rate); - -@@ -1386,97 +1549,20 @@ minstrel_ht_update_rates(struct minstrel - rate_control_set_rates(mp->hw, mi->sta, rates); - } - --static int --minstrel_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) -+static u16 -+minstrel_ht_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) - { -- struct minstrel_rate_stats *mrs; -- struct minstrel_mcs_group_data *mg; -- unsigned int sample_dur, sample_group, cur_max_tp_streams; -- int tp_rate1, tp_rate2; -- int sample_idx = 0; -- -- if (mp->hw->max_rates == 1 && mp->sample_switch && -- (mi->total_packets_cur >= SAMPLE_SWITCH_THR || -- mp->sample_switch == 1)) -- return -1; -- -- if (mi->sample_wait > 0) { -- mi->sample_wait--; -- return -1; -- } -- -- if (!mi->sample_tries) -- return -1; -- -- sample_group = mi->sample_group; -- mg = &mi->groups[sample_group]; -- sample_idx = sample_table[mg->column][mg->index]; -- minstrel_set_next_sample_idx(mi); -- -- if (!(mi->supported[sample_group] & BIT(sample_idx))) -- return -1; -+ u8 seq; - -- mrs = &mg->rates[sample_idx]; -- sample_idx += MI_RATE(sample_group, 0); -- -- tp_rate1 = mi->max_tp_rate[0]; -- -- /* Set tp_rate2 to the second highest max_tp_rate */ -- if (minstrel_get_duration(mi->max_tp_rate[0]) > -- minstrel_get_duration(mi->max_tp_rate[1])) { -- tp_rate2 = mi->max_tp_rate[0]; -+ if (mp->hw->max_rates > 1) { -+ seq = mi->sample_seq; -+ mi->sample_seq = (seq + 1) % ARRAY_SIZE(minstrel_sample_seq); -+ seq = minstrel_sample_seq[seq]; - } else { -- tp_rate2 = mi->max_tp_rate[1]; -+ seq = MINSTREL_SAMPLE_TYPE_INC; - } - -- /* -- * Sampling might add some overhead (RTS, no aggregation) -- * to the frame. Hence, don't use sampling for the highest currently -- * used highest throughput or probability rate. -- */ -- if (sample_idx == mi->max_tp_rate[0] || sample_idx == mi->max_prob_rate) -- return -1; -- -- /* -- * Do not sample if the probability is already higher than 95%, -- * or if the rate is 3 times slower than the current max probability -- * rate, to avoid wasting airtime. -- */ -- sample_dur = minstrel_get_duration(sample_idx); -- if (mrs->prob_avg > MINSTREL_FRAC(95, 100) || -- minstrel_get_duration(mi->max_prob_rate) * 3 < sample_dur) -- return -1; -- -- -- /* -- * For devices with no configurable multi-rate retry, skip sampling -- * below the per-group max throughput rate, and only use one sampling -- * attempt per rate -- */ -- if (mp->hw->max_rates == 1 && -- (minstrel_get_duration(mg->max_group_tp_rate[0]) < sample_dur || -- mrs->attempts)) -- return -1; -- -- /* Skip already sampled slow rates */ -- if (sample_dur >= minstrel_get_duration(tp_rate1) && mrs->attempts) -- return -1; -- -- /* -- * Make sure that lower rates get sampled only occasionally, -- * if the link is working perfectly. -- */ -- -- cur_max_tp_streams = minstrel_mcs_groups[MI_RATE_GROUP(tp_rate1)].streams; -- if (sample_dur >= minstrel_get_duration(tp_rate2) && -- (cur_max_tp_streams - 1 < -- minstrel_mcs_groups[sample_group].streams || -- sample_dur >= minstrel_get_duration(mi->max_prob_rate))) -- return -1; -- -- mi->sample_tries--; -- -- return sample_idx; -+ return __minstrel_ht_get_sample_rate(mi, seq); - } - - static void -@@ -1488,7 +1574,7 @@ minstrel_ht_get_rate(void *priv, struct - struct ieee80211_tx_rate *rate = &info->status.rates[0]; - struct minstrel_ht_sta *mi = priv_sta; - struct minstrel_priv *mp = priv; -- int sample_idx; -+ u16 sample_idx; - - if (!(info->flags & IEEE80211_TX_CTL_AMPDU) && - !minstrel_ht_is_legacy_group(MI_RATE_GROUP(mi->max_prob_rate))) -@@ -1504,11 +1590,19 @@ minstrel_ht_get_rate(void *priv, struct - /* Don't use EAPOL frames for sampling on non-mrr hw */ - if (mp->hw->max_rates == 1 && - (info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO)) -- sample_idx = -1; -- else -- sample_idx = minstrel_get_sample_rate(mp, mi); -+ return; -+ -+ if (mp->hw->max_rates == 1 && mp->sample_switch && -+ (mi->total_packets_cur >= SAMPLE_SWITCH_THR || -+ mp->sample_switch == 1)) -+ return; -+ -+ if (time_is_before_jiffies(mi->sample_time)) -+ return; - -- if (sample_idx < 0) -+ mi->sample_time = jiffies + MINSTREL_SAMPLE_INTERVAL; -+ sample_idx = minstrel_ht_get_sample_rate(mp, mi); -+ if (!sample_idx) - return; - - sample_group = &minstrel_mcs_groups[MI_RATE_GROUP(sample_idx)]; -@@ -1629,16 +1723,6 @@ minstrel_ht_update_caps(void *priv, stru - - mi->avg_ampdu_len = MINSTREL_FRAC(1, 1); - -- /* When using MRR, sample more on the first attempt, without delay */ -- if (mp->has_mrr) { -- mi->sample_count = 16; -- mi->sample_wait = 0; -- } else { -- mi->sample_count = 8; -- mi->sample_wait = 8; -- } -- mi->sample_tries = 4; -- - if (!use_vht) { - stbc = (ht_cap & IEEE80211_HT_CAP_RX_STBC) >> - IEEE80211_HT_CAP_RX_STBC_SHIFT; ---- a/net/mac80211/rc80211_minstrel_ht.h -+++ b/net/mac80211/rc80211_minstrel_ht.h -@@ -69,6 +69,8 @@ - #define MI_RATE_IDX(_rate) FIELD_GET(MI_RATE_IDX_MASK, _rate) - #define MI_RATE_GROUP(_rate) FIELD_GET(MI_RATE_GROUP_MASK, _rate) - -+#define MINSTREL_SAMPLE_RATES 5 /* rates per sample type */ -+#define MINSTREL_SAMPLE_INTERVAL (HZ / 50) - - struct minstrel_priv { - struct ieee80211_hw *hw; -@@ -126,6 +128,13 @@ struct minstrel_rate_stats { - bool retry_updated; - }; - -+enum minstrel_sample_type { -+ MINSTREL_SAMPLE_TYPE_INC, -+ MINSTREL_SAMPLE_TYPE_JUMP, -+ MINSTREL_SAMPLE_TYPE_SLOW, -+ __MINSTREL_SAMPLE_TYPE_MAX -+}; -+ - struct minstrel_mcs_group_data { - u8 index; - u8 column; -@@ -144,6 +153,12 @@ enum minstrel_sample_mode { - MINSTREL_SAMPLE_PENDING, - }; - -+struct minstrel_sample_category { -+ u8 sample_group; -+ u16 sample_rates[MINSTREL_SAMPLE_RATES]; -+ u16 cur_sample_rates[MINSTREL_SAMPLE_RATES]; -+}; -+ - struct minstrel_ht_sta { - struct ieee80211_sta *sta; - -@@ -175,16 +190,14 @@ struct minstrel_ht_sta { - /* tx flags to add for frames for this sta */ - u32 tx_flags; - -- u8 sample_wait; -- u8 sample_tries; -- u8 sample_count; -+ unsigned long sample_time; -+ struct minstrel_sample_category sample[__MINSTREL_SAMPLE_TYPE_MAX]; -+ -+ u8 sample_seq; - - enum minstrel_sample_mode sample_mode; - u16 sample_rate; - -- /* current MCS group to be sampled */ -- u8 sample_group; -- - u8 band; - - /* Bitfield of supported MCS rates of all groups */ diff --git a/package/kernel/mac80211/patches/subsys/350-mac80211-minstrel_ht-show-sampling-rates-in-debugfs.patch b/package/kernel/mac80211/patches/subsys/350-mac80211-minstrel_ht-show-sampling-rates-in-debugfs.patch deleted file mode 100644 index 041ba31a378..00000000000 --- a/package/kernel/mac80211/patches/subsys/350-mac80211-minstrel_ht-show-sampling-rates-in-debugfs.patch +++ /dev/null @@ -1,58 +0,0 @@ -From: Felix Fietkau <nbd@nbd.name> -Date: Sat, 23 Jan 2021 00:10:34 +0100 -Subject: [PATCH] mac80211: minstrel_ht: show sampling rates in debugfs - -This makes it easier to see what rates are going to be tested next - -Signed-off-by: Felix Fietkau <nbd@nbd.name> ---- - ---- a/net/mac80211/rc80211_minstrel_ht_debugfs.c -+++ b/net/mac80211/rc80211_minstrel_ht_debugfs.c -@@ -32,6 +32,18 @@ minstrel_stats_release(struct inode *ino - return 0; - } - -+static bool -+minstrel_ht_is_sample_rate(struct minstrel_ht_sta *mi, int idx) -+{ -+ int type, i; -+ -+ for (type = 0; type < ARRAY_SIZE(mi->sample); type++) -+ for (i = 0; i < MINSTREL_SAMPLE_RATES; i++) -+ if (mi->sample[type].cur_sample_rates[i] == idx) -+ return true; -+ return false; -+} -+ - static char * - minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p) - { -@@ -84,6 +96,7 @@ minstrel_ht_stats_dump(struct minstrel_h - *(p++) = (idx == mi->max_tp_rate[2]) ? 'C' : ' '; - *(p++) = (idx == mi->max_tp_rate[3]) ? 'D' : ' '; - *(p++) = (idx == mi->max_prob_rate) ? 'P' : ' '; -+ *(p++) = minstrel_ht_is_sample_rate(mi, idx) ? 'S' : ' '; - - if (gflags & IEEE80211_TX_RC_MCS) { - p += sprintf(p, " MCS%-2u", (mg->streams - 1) * 8 + j); -@@ -145,9 +158,9 @@ minstrel_ht_stats_open(struct inode *ino - - p += sprintf(p, "\n"); - p += sprintf(p, -- " best ____________rate__________ ____statistics___ _____last____ ______sum-of________\n"); -+ " best ____________rate__________ ____statistics___ _____last____ ______sum-of________\n"); - p += sprintf(p, -- "mode guard # rate [name idx airtime max_tp] [avg(tp) avg(prob)] [retry|suc|att] [#success | #attempts]\n"); -+ "mode guard # rate [name idx airtime max_tp] [avg(tp) avg(prob)] [retry|suc|att] [#success | #attempts]\n"); - - p = minstrel_ht_stats_dump(mi, MINSTREL_CCK_GROUP, p); - for (i = 0; i < MINSTREL_CCK_GROUP; i++) -@@ -228,6 +241,7 @@ minstrel_ht_stats_csv_dump(struct minstr - p += sprintf(p, "%s" ,((idx == mi->max_tp_rate[2]) ? "C" : "")); - p += sprintf(p, "%s" ,((idx == mi->max_tp_rate[3]) ? "D" : "")); - p += sprintf(p, "%s" ,((idx == mi->max_prob_rate) ? "P" : "")); -+ p += sprintf(p, "%s", (minstrel_ht_is_sample_rate(mi, idx) ? "S" : "")); - - if (gflags & IEEE80211_TX_RC_MCS) { - p += sprintf(p, ",MCS%-2u,", (mg->streams - 1) * 8 + j); diff --git a/package/kernel/mac80211/patches/subsys/351-mac80211-minstrel_ht-remove-sample-rate-switching-co.patch b/package/kernel/mac80211/patches/subsys/351-mac80211-minstrel_ht-remove-sample-rate-switching-co.patch deleted file mode 100644 index 8170ff85f8a..00000000000 --- a/package/kernel/mac80211/patches/subsys/351-mac80211-minstrel_ht-remove-sample-rate-switching-co.patch +++ /dev/null @@ -1,279 +0,0 @@ -From: Felix Fietkau <nbd@nbd.name> -Date: Sat, 23 Jan 2021 07:18:26 +0100 -Subject: [PATCH] mac80211: minstrel_ht: remove sample rate switching code for - constrained devices - -This was added to mitigate the effects of too much sampling on devices that -use a static global fallback table instead of configurable multi-rate retry. -Now that the sampling algorithm is improved, this code path no longer performs -any better than the standard probing on affected devices. - -Signed-off-by: Felix Fietkau <nbd@nbd.name> ---- - ---- a/net/mac80211/rc80211_minstrel_ht.c -+++ b/net/mac80211/rc80211_minstrel_ht.c -@@ -648,27 +648,6 @@ __minstrel_ht_get_sample_rate(struct min - return 0; - } - --static void --minstrel_ht_rate_sample_switch(struct minstrel_priv *mp, -- struct minstrel_ht_sta *mi) --{ -- u16 rate; -- -- /* -- * Use rate switching instead of probing packets for devices with -- * little control over retry fallback behavior -- */ -- if (mp->hw->max_rates > 1) -- return; -- -- rate = __minstrel_ht_get_sample_rate(mi, MINSTREL_SAMPLE_TYPE_INC); -- if (!rate) -- return; -- -- mi->sample_rate = rate; -- mi->sample_mode = MINSTREL_SAMPLE_ACTIVE; --} -- - static inline int - minstrel_ewma(int old, int new, int weight) - { -@@ -1012,8 +991,7 @@ minstrel_ht_refill_sample_rates(struct m - * higher throughput rates, even if the probablity is a bit lower - */ - static void --minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, -- bool sample) -+minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) - { - struct minstrel_mcs_group_data *mg; - struct minstrel_rate_stats *mrs; -@@ -1023,18 +1001,6 @@ minstrel_ht_update_stats(struct minstrel - u16 index; - bool ht_supported = mi->sta->ht_cap.ht_supported; - -- mi->sample_mode = MINSTREL_SAMPLE_IDLE; -- -- if (sample) { -- mi->total_packets_cur = mi->total_packets - -- mi->total_packets_last; -- mi->total_packets_last = mi->total_packets; -- } -- if (!mp->sample_switch) -- sample = false; -- if (mi->total_packets_cur < SAMPLE_SWITCH_THR && mp->sample_switch != 1) -- sample = false; -- - if (mi->ampdu_packets > 0) { - if (!ieee80211_hw_check(mp->hw, TX_STATUS_NO_AMPDU_LEN)) - mi->avg_ampdu_len = minstrel_ewma(mi->avg_ampdu_len, -@@ -1148,16 +1114,12 @@ minstrel_ht_update_stats(struct minstrel - minstrel_ht_prob_rate_reduce_streams(mi); - minstrel_ht_refill_sample_rates(mi); - -- if (sample) -- minstrel_ht_rate_sample_switch(mp, mi); -- - #ifdef CPTCFG_MAC80211_DEBUGFS - /* use fixed index if set */ - if (mp->fixed_rate_idx != -1) { - for (i = 0; i < 4; i++) - mi->max_tp_rate[i] = mp->fixed_rate_idx; - mi->max_prob_rate = mp->fixed_rate_idx; -- mi->sample_mode = MINSTREL_SAMPLE_IDLE; - } - #endif - -@@ -1247,11 +1209,10 @@ minstrel_ht_tx_status(void *priv, struct - struct ieee80211_tx_info *info = st->info; - struct minstrel_ht_sta *mi = priv_sta; - struct ieee80211_tx_rate *ar = info->status.rates; -- struct minstrel_rate_stats *rate, *rate2, *rate_sample = NULL; -+ struct minstrel_rate_stats *rate, *rate2; - struct minstrel_priv *mp = priv; - u32 update_interval = mp->update_interval; - bool last, update = false; -- bool sample_status = false; - int i; - - /* This packet was aggregated but doesn't carry status info */ -@@ -1278,49 +1239,18 @@ minstrel_ht_tx_status(void *priv, struct - mi->ampdu_packets++; - mi->ampdu_len += info->status.ampdu_len; - -- if (mi->sample_mode != MINSTREL_SAMPLE_IDLE) -- rate_sample = minstrel_get_ratestats(mi, mi->sample_rate); -- - last = !minstrel_ht_txstat_valid(mp, mi, &ar[0]); - for (i = 0; !last; i++) { - last = (i == IEEE80211_TX_MAX_RATES - 1) || - !minstrel_ht_txstat_valid(mp, mi, &ar[i + 1]); - - rate = minstrel_ht_get_stats(mp, mi, &ar[i]); -- if (rate == rate_sample) -- sample_status = true; -- - if (last) - rate->success += info->status.ampdu_ack_len; - - rate->attempts += ar[i].count * info->status.ampdu_len; - } - -- switch (mi->sample_mode) { -- case MINSTREL_SAMPLE_IDLE: -- if (mp->hw->max_rates > 1 || -- mi->total_packets_cur < SAMPLE_SWITCH_THR) -- update_interval /= 2; -- break; -- -- case MINSTREL_SAMPLE_ACTIVE: -- if (!sample_status) -- break; -- -- mi->sample_mode = MINSTREL_SAMPLE_PENDING; -- update = true; -- break; -- -- case MINSTREL_SAMPLE_PENDING: -- if (sample_status) -- break; -- -- update = true; -- minstrel_ht_update_stats(mp, mi, false); -- break; -- } -- -- - if (mp->hw->max_rates > 1) { - /* - * check for sudden death of spatial multiplexing, -@@ -1343,7 +1273,7 @@ minstrel_ht_tx_status(void *priv, struct - - if (time_after(jiffies, mi->last_stats_update + update_interval)) { - update = true; -- minstrel_ht_update_stats(mp, mi, true); -+ minstrel_ht_update_stats(mp, mi); - } - - if (update) -@@ -1522,18 +1452,14 @@ static void - minstrel_ht_update_rates(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) - { - struct ieee80211_sta_rates *rates; -- u16 first_rate = mi->max_tp_rate[0]; - int i = 0; - -- if (mi->sample_mode == MINSTREL_SAMPLE_ACTIVE) -- first_rate = mi->sample_rate; -- - rates = kzalloc(sizeof(*rates), GFP_ATOMIC); - if (!rates) - return; - - /* Start with max_tp_rate[0] */ -- minstrel_ht_set_rate(mp, mi, rates, i++, first_rate); -+ minstrel_ht_set_rate(mp, mi, rates, i++, mi->max_tp_rate[0]); - - if (mp->hw->max_rates >= 3) { - /* At least 3 tx rates supported, use max_tp_rate[1] next */ -@@ -1592,11 +1518,6 @@ minstrel_ht_get_rate(void *priv, struct - (info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO)) - return; - -- if (mp->hw->max_rates == 1 && mp->sample_switch && -- (mi->total_packets_cur >= SAMPLE_SWITCH_THR || -- mp->sample_switch == 1)) -- return; -- - if (time_is_before_jiffies(mi->sample_time)) - return; - -@@ -1810,7 +1731,7 @@ minstrel_ht_update_caps(void *priv, stru - minstrel_ht_update_ofdm(mp, mi, sband, sta); - - /* create an initial rate table with the lowest supported rates */ -- minstrel_ht_update_stats(mp, mi, true); -+ minstrel_ht_update_stats(mp, mi); - minstrel_ht_update_rates(mp, mi); - } - -@@ -1926,8 +1847,6 @@ minstrel_ht_alloc(struct ieee80211_hw *h - if (!mp) - return NULL; - -- mp->sample_switch = -1; -- - /* contention window settings - * Just an approximation. Using the per-queue values would complicate - * the calculations and is probably unnecessary */ -@@ -1947,7 +1866,7 @@ minstrel_ht_alloc(struct ieee80211_hw *h - mp->has_mrr = true; - - mp->hw = hw; -- mp->update_interval = HZ / 10; -+ mp->update_interval = HZ / 20; - - minstrel_ht_init_cck_rates(mp); - for (i = 0; i < ARRAY_SIZE(mp->hw->wiphy->bands); i++) -@@ -1965,8 +1884,6 @@ static void minstrel_ht_add_debugfs(stru - mp->fixed_rate_idx = (u32) -1; - debugfs_create_u32("fixed_rate_idx", S_IRUGO | S_IWUGO, debugfsdir, - &mp->fixed_rate_idx); -- debugfs_create_u32("sample_switch", S_IRUGO | S_IWUSR, debugfsdir, -- &mp->sample_switch); - } - #endif - ---- a/net/mac80211/rc80211_minstrel_ht.h -+++ b/net/mac80211/rc80211_minstrel_ht.h -@@ -75,7 +75,6 @@ - struct minstrel_priv { - struct ieee80211_hw *hw; - bool has_mrr; -- u32 sample_switch; - unsigned int cw_min; - unsigned int cw_max; - unsigned int max_retry; -@@ -147,12 +146,6 @@ struct minstrel_mcs_group_data { - struct minstrel_rate_stats rates[MCS_GROUP_RATES]; - }; - --enum minstrel_sample_mode { -- MINSTREL_SAMPLE_IDLE, -- MINSTREL_SAMPLE_ACTIVE, -- MINSTREL_SAMPLE_PENDING, --}; -- - struct minstrel_sample_category { - u8 sample_group; - u16 sample_rates[MINSTREL_SAMPLE_RATES]; -@@ -182,23 +175,19 @@ struct minstrel_ht_sta { - unsigned int overhead_legacy; - unsigned int overhead_legacy_rtscts; - -- unsigned int total_packets_last; -- unsigned int total_packets_cur; - unsigned int total_packets; - unsigned int sample_packets; - - /* tx flags to add for frames for this sta */ - u32 tx_flags; - -- unsigned long sample_time; -- struct minstrel_sample_category sample[__MINSTREL_SAMPLE_TYPE_MAX]; -+ u8 band; - - u8 sample_seq; -- -- enum minstrel_sample_mode sample_mode; - u16 sample_rate; - -- u8 band; -+ unsigned long sample_time; -+ struct minstrel_sample_category sample[__MINSTREL_SAMPLE_TYPE_MAX]; - - /* Bitfield of supported MCS rates of all groups */ - u16 supported[MINSTREL_GROUPS_NB]; diff --git a/package/kernel/mac80211/patches/subsys/352-mac80211-minstrel_ht-fix-regression-in-the-max_prob_.patch b/package/kernel/mac80211/patches/subsys/352-mac80211-minstrel_ht-fix-regression-in-the-max_prob_.patch deleted file mode 100644 index a366a921d4f..00000000000 --- a/package/kernel/mac80211/patches/subsys/352-mac80211-minstrel_ht-fix-regression-in-the-max_prob_.patch +++ /dev/null @@ -1,23 +0,0 @@ -From: Felix Fietkau <nbd@nbd.name> -Date: Tue, 26 Jan 2021 16:40:52 +0100 -Subject: [PATCH] mac80211: minstrel_ht: fix regression in the max_prob_rate - fix - -Since mi->max_prob_rate is overwritten after the loop that calls -minstrel_ht_set_best_prob_rate, the new best rate needs to be written to *dest - -Fixes: a7fca4e4037f ("mac80211: minstrel_ht: fix max probability rate selection") -Signed-off-by: Felix Fietkau <nbd@nbd.name> ---- - ---- a/net/mac80211/rc80211_minstrel_ht.c -+++ b/net/mac80211/rc80211_minstrel_ht.c -@@ -545,7 +545,7 @@ minstrel_ht_set_best_prob_rate(struct mi - cur_tp_avg = minstrel_ht_get_tp_avg(mi, cur_group, cur_idx, - mrs->prob_avg); - if (cur_tp_avg > tmp_tp_avg) -- mi->max_prob_rate = index; -+ *dest = index; - - max_gpr_tp_avg = minstrel_ht_get_tp_avg(mi, max_gpr_group, - max_gpr_idx, diff --git a/package/kernel/mac80211/patches/subsys/371-mac80211-don-t-apply-flow-control-on-management-fram.patch b/package/kernel/mac80211/patches/subsys/371-mac80211-don-t-apply-flow-control-on-management-fram.patch deleted file mode 100644 index 8d094a3632e..00000000000 --- a/package/kernel/mac80211/patches/subsys/371-mac80211-don-t-apply-flow-control-on-management-fram.patch +++ /dev/null @@ -1,60 +0,0 @@ -From: Johannes Berg <johannes.berg@intel.com> -Date: Fri, 19 Mar 2021 23:28:01 +0100 -Subject: [PATCH] mac80211: don't apply flow control on management frames - -In some cases (depending on the driver, but it's true e.g. for -iwlwifi) we're using an internal TXQ for management packets, -mostly to simplify the code and to have a place to queue them. -However, it appears that in certain cases we can confuse the -code and management frames are dropped, which is certainly not -what we want. - -Short-circuit the processing of management frames. To keep the -impact minimal, only put them on the frags queue and check the -tid == management only for doing that and to skip the airtime -fairness checks, if applicable. - -Signed-off-by: Johannes Berg <johannes.berg@intel.com> ---- - ---- a/net/mac80211/tx.c -+++ b/net/mac80211/tx.c -@@ -5,7 +5,7 @@ - * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> - * Copyright 2007 Johannes Berg <johannes@sipsolutions.net> - * Copyright 2013-2014 Intel Mobile Communications GmbH -- * Copyright (C) 2018-2020 Intel Corporation -+ * Copyright (C) 2018-2021 Intel Corporation - * - * Transmit and frame generation functions. - */ -@@ -1401,8 +1401,17 @@ static void ieee80211_txq_enqueue(struct - ieee80211_set_skb_enqueue_time(skb); - - spin_lock_bh(&fq->lock); -- fq_tin_enqueue(fq, tin, flow_idx, skb, -- fq_skb_free_func); -+ /* -+ * For management frames, don't really apply codel etc., -+ * we don't want to apply any shaping or anything we just -+ * want to simplify the driver API by having them on the -+ * txqi. -+ */ -+ if (unlikely(txqi->txq.tid == IEEE80211_NUM_TIDS)) -+ __skb_queue_tail(&txqi->frags, skb); -+ else -+ fq_tin_enqueue(fq, tin, flow_idx, skb, -+ fq_skb_free_func); - spin_unlock_bh(&fq->lock); - } - -@@ -3844,6 +3853,9 @@ bool ieee80211_txq_airtime_check(struct - if (!txq->sta) - return true; - -+ if (unlikely(txq->tid == IEEE80211_NUM_TIDS)) -+ return true; -+ - sta = container_of(txq->sta, struct sta_info, sta); - if (atomic_read(&sta->airtime[txq->ac].aql_tx_pending) < - sta->airtime[txq->ac].aql_limit_low) diff --git a/package/kernel/mac80211/patches/subsys/372-mac80211-set-sk_pacing_shift-for-802.3-txpath.patch b/package/kernel/mac80211/patches/subsys/372-mac80211-set-sk_pacing_shift-for-802.3-txpath.patch deleted file mode 100644 index 5bc1469a3f1..00000000000 --- a/package/kernel/mac80211/patches/subsys/372-mac80211-set-sk_pacing_shift-for-802.3-txpath.patch +++ /dev/null @@ -1,21 +0,0 @@ -From: Lorenzo Bianconi <lorenzo@kernel.org> -Date: Mon, 8 Mar 2021 23:01:49 +0100 -Subject: [PATCH] mac80211: set sk_pacing_shift for 802.3 txpath - -Similar to 802.11 txpath, set socket sk_pacing_shift for 802.3 tx path. - -Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org> ---- - ---- a/net/mac80211/tx.c -+++ b/net/mac80211/tx.c -@@ -4171,6 +4171,9 @@ static bool ieee80211_tx_8023(struct iee - unsigned long flags; - int q = info->hw_queue; - -+ if (sta) -+ sk_pacing_shift_update(skb->sk, local->hw.tx_sk_pacing_shift); -+ - if (ieee80211_queue_skb(local, sdata, sta, skb)) - return true; - diff --git a/package/kernel/mac80211/patches/subsys/373-mac80211-support-Rx-timestamp-calculation-for-all-pr.patch b/package/kernel/mac80211/patches/subsys/373-mac80211-support-Rx-timestamp-calculation-for-all-pr.patch deleted file mode 100644 index 117fb35fcf1..00000000000 --- a/package/kernel/mac80211/patches/subsys/373-mac80211-support-Rx-timestamp-calculation-for-all-pr.patch +++ /dev/null @@ -1,134 +0,0 @@ -From: Avraham Stern <avraham.stern@intel.com> -Date: Sun, 6 Dec 2020 14:54:45 +0200 -Subject: [PATCH] mac80211: support Rx timestamp calculation for all preamble - types - -Add support for calculating the Rx timestamp for HE frames. -Since now all frame types are supported, allow setting the Rx -timestamp regardless of the frame type. - -Signed-off-by: Avraham Stern <avraham.stern@intel.com> -Signed-off-by: Luca Coelho <luciano.coelho@intel.com> -Link: https://lore.kernel.org/r/iwlwifi.20201206145305.4786559af475.Ia54486bb0a12e5351f9d5c60ef6fcda7c9e7141c@changeid -Signed-off-by: Johannes Berg <johannes.berg@intel.com> ---- - ---- a/net/mac80211/ieee80211_i.h -+++ b/net/mac80211/ieee80211_i.h -@@ -1587,13 +1587,8 @@ ieee80211_have_rx_timestamp(struct ieee8 - { - WARN_ON_ONCE(status->flag & RX_FLAG_MACTIME_START && - status->flag & RX_FLAG_MACTIME_END); -- if (status->flag & (RX_FLAG_MACTIME_START | RX_FLAG_MACTIME_END)) -- return true; -- /* can't handle non-legacy preamble yet */ -- if (status->flag & RX_FLAG_MACTIME_PLCP_START && -- status->encoding == RX_ENC_LEGACY) -- return true; -- return false; -+ return !!(status->flag & (RX_FLAG_MACTIME_START | RX_FLAG_MACTIME_END | -+ RX_FLAG_MACTIME_PLCP_START)); - } - - void ieee80211_vif_inc_num_mcast(struct ieee80211_sub_if_data *sdata); ---- a/net/mac80211/util.c -+++ b/net/mac80211/util.c -@@ -3665,6 +3665,7 @@ u64 ieee80211_calculate_rx_timestamp(str - u64 ts = status->mactime; - struct rate_info ri; - u16 rate; -+ u8 n_ltf; - - if (WARN_ON(!ieee80211_have_rx_timestamp(status))) - return 0; -@@ -3675,11 +3676,58 @@ u64 ieee80211_calculate_rx_timestamp(str - - /* Fill cfg80211 rate info */ - switch (status->encoding) { -+ case RX_ENC_HE: -+ ri.flags |= RATE_INFO_FLAGS_HE_MCS; -+ ri.mcs = status->rate_idx; -+ ri.nss = status->nss; -+ ri.he_ru_alloc = status->he_ru; -+ if (status->enc_flags & RX_ENC_FLAG_SHORT_GI) -+ ri.flags |= RATE_INFO_FLAGS_SHORT_GI; -+ -+ /* -+ * See P802.11ax_D6.0, section 27.3.4 for -+ * VHT PPDU format. -+ */ -+ if (status->flag & RX_FLAG_MACTIME_PLCP_START) { -+ mpdu_offset += 2; -+ ts += 36; -+ -+ /* -+ * TODO: -+ * For HE MU PPDU, add the HE-SIG-B. -+ * For HE ER PPDU, add 8us for the HE-SIG-A. -+ * For HE TB PPDU, add 4us for the HE-STF. -+ * Add the HE-LTF durations - variable. -+ */ -+ } -+ -+ break; - case RX_ENC_HT: - ri.mcs = status->rate_idx; - ri.flags |= RATE_INFO_FLAGS_MCS; - if (status->enc_flags & RX_ENC_FLAG_SHORT_GI) - ri.flags |= RATE_INFO_FLAGS_SHORT_GI; -+ -+ /* -+ * See P802.11REVmd_D3.0, section 19.3.2 for -+ * HT PPDU format. -+ */ -+ if (status->flag & RX_FLAG_MACTIME_PLCP_START) { -+ mpdu_offset += 2; -+ if (status->enc_flags & RX_ENC_FLAG_HT_GF) -+ ts += 24; -+ else -+ ts += 32; -+ -+ /* -+ * Add Data HT-LTFs per streams -+ * TODO: add Extension HT-LTFs, 4us per LTF -+ */ -+ n_ltf = ((ri.mcs >> 3) & 3) + 1; -+ n_ltf = n_ltf == 3 ? 4 : n_ltf; -+ ts += n_ltf * 4; -+ } -+ - break; - case RX_ENC_VHT: - ri.flags |= RATE_INFO_FLAGS_VHT_MCS; -@@ -3687,6 +3735,23 @@ u64 ieee80211_calculate_rx_timestamp(str - ri.nss = status->nss; - if (status->enc_flags & RX_ENC_FLAG_SHORT_GI) - ri.flags |= RATE_INFO_FLAGS_SHORT_GI; -+ -+ /* -+ * See P802.11REVmd_D3.0, section 21.3.2 for -+ * VHT PPDU format. -+ */ -+ if (status->flag & RX_FLAG_MACTIME_PLCP_START) { -+ mpdu_offset += 2; -+ ts += 36; -+ -+ /* -+ * Add VHT-LTFs per streams -+ */ -+ n_ltf = (ri.nss != 1) && (ri.nss % 2) ? -+ ri.nss + 1 : ri.nss; -+ ts += 4 * n_ltf; -+ } -+ - break; - default: - WARN_ON(1); -@@ -3710,7 +3775,6 @@ u64 ieee80211_calculate_rx_timestamp(str - ri.legacy = DIV_ROUND_UP(bitrate, (1 << shift)); - - if (status->flag & RX_FLAG_MACTIME_PLCP_START) { -- /* TODO: handle HT/VHT preambles */ - if (status->band == NL80211_BAND_5GHZ) { - ts += 20 << shift; - mpdu_offset += 2; diff --git a/package/kernel/mac80211/patches/subsys/374-mac80211-move-A-MPDU-session-check-from-minstrel_ht-.patch b/package/kernel/mac80211/patches/subsys/374-mac80211-move-A-MPDU-session-check-from-minstrel_ht-.patch deleted file mode 100644 index 031f8e16360..00000000000 --- a/package/kernel/mac80211/patches/subsys/374-mac80211-move-A-MPDU-session-check-from-minstrel_ht-.patch +++ /dev/null @@ -1,126 +0,0 @@ -From: Felix Fietkau <nbd@nbd.name> -Date: Thu, 17 Jun 2021 17:56:54 +0200 -Subject: [PATCH] mac80211: move A-MPDU session check from minstrel_ht to - mac80211 - -This avoids calling back into tx handlers from within the rate control module. -Preparation for deferring rate control until tx dequeue - -Signed-off-by: Felix Fietkau <nbd@nbd.name> ---- - ---- a/include/net/mac80211.h -+++ b/include/net/mac80211.h -@@ -6160,6 +6160,11 @@ enum rate_control_capabilities { - * otherwise the NSS difference doesn't bother us. - */ - RATE_CTRL_CAPA_VHT_EXT_NSS_BW = BIT(0), -+ /** -+ * @RATE_CTRL_CAPA_AMPDU_TRIGGER: -+ * mac80211 should start A-MPDU sessions on tx -+ */ -+ RATE_CTRL_CAPA_AMPDU_TRIGGER = BIT(1), - }; - - struct rate_control_ops { ---- a/net/mac80211/rc80211_minstrel_ht.c -+++ b/net/mac80211/rc80211_minstrel_ht.c -@@ -1153,29 +1153,6 @@ minstrel_downgrade_prob_rate(struct mins - } - - static void --minstrel_aggr_check(struct ieee80211_sta *pubsta, struct sk_buff *skb) --{ -- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; -- struct sta_info *sta = container_of(pubsta, struct sta_info, sta); -- u16 tid; -- -- if (skb_get_queue_mapping(skb) == IEEE80211_AC_VO) -- return; -- -- if (unlikely(!ieee80211_is_data_qos(hdr->frame_control))) -- return; -- -- if (unlikely(skb->protocol == cpu_to_be16(ETH_P_PAE))) -- return; -- -- tid = ieee80211_get_tid(hdr); -- if (likely(sta->ampdu_mlme.tid_tx[tid])) -- return; -- -- ieee80211_start_tx_ba_session(pubsta, tid, 0); --} -- --static void - minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband, - void *priv_sta, struct ieee80211_tx_status *st) - { -@@ -1477,10 +1454,6 @@ minstrel_ht_get_rate(void *priv, struct - struct minstrel_priv *mp = priv; - u16 sample_idx; - -- if (!(info->flags & IEEE80211_TX_CTL_AMPDU) && -- !minstrel_ht_is_legacy_group(MI_RATE_GROUP(mi->max_prob_rate))) -- minstrel_aggr_check(sta, txrc->skb); -- - info->flags |= mi->tx_flags; - - #ifdef CPTCFG_MAC80211_DEBUGFS -@@ -1894,6 +1867,7 @@ static u32 minstrel_ht_get_expected_thro - - static const struct rate_control_ops mac80211_minstrel_ht = { - .name = "minstrel_ht", -+ .capa = RATE_CTRL_CAPA_AMPDU_TRIGGER, - .tx_status_ext = minstrel_ht_tx_status, - .get_rate = minstrel_ht_get_rate, - .rate_init = minstrel_ht_rate_init, ---- a/net/mac80211/tx.c -+++ b/net/mac80211/tx.c -@@ -3931,6 +3931,29 @@ void ieee80211_txq_schedule_start(struct - } - EXPORT_SYMBOL(ieee80211_txq_schedule_start); - -+static void -+ieee80211_aggr_check(struct ieee80211_sub_if_data *sdata, -+ struct sta_info *sta, -+ struct sk_buff *skb) -+{ -+ struct rate_control_ref *ref = sdata->local->rate_ctrl; -+ u16 tid; -+ -+ if (!ref || !(ref->ops->capa & RATE_CTRL_CAPA_AMPDU_TRIGGER)) -+ return; -+ -+ if (!sta || !sta->sta.ht_cap.ht_supported || -+ !sta->sta.wme || skb_get_queue_mapping(skb) == IEEE80211_AC_VO || -+ skb->protocol == sdata->control_port_protocol) -+ return; -+ -+ tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK; -+ if (likely(sta->ampdu_mlme.tid_tx[tid])) -+ return; -+ -+ ieee80211_start_tx_ba_session(&sta->sta, tid, 0); -+} -+ - void __ieee80211_subif_start_xmit(struct sk_buff *skb, - struct net_device *dev, - u32 info_flags, -@@ -3961,6 +3984,8 @@ void __ieee80211_subif_start_xmit(struct - skb_get_hash(skb); - } - -+ ieee80211_aggr_check(sdata, sta, skb); -+ - if (sta) { - struct ieee80211_fast_tx *fast_tx; - -@@ -4224,6 +4249,8 @@ static void ieee80211_8023_xmit(struct i - - memset(info, 0, sizeof(*info)); - -+ ieee80211_aggr_check(sdata, sta, skb); -+ - tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK; - tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[tid]); - if (tid_tx) { diff --git a/package/kernel/mac80211/patches/subsys/375-mac80211-call-ieee80211_tx_h_rate_ctrl-when-dequeue.patch b/package/kernel/mac80211/patches/subsys/375-mac80211-call-ieee80211_tx_h_rate_ctrl-when-dequeue.patch deleted file mode 100644 index cf84fca68a3..00000000000 --- a/package/kernel/mac80211/patches/subsys/375-mac80211-call-ieee80211_tx_h_rate_ctrl-when-dequeue.patch +++ /dev/null @@ -1,114 +0,0 @@ -From: Ryder Lee <ryder.lee@mediatek.com> -Date: Fri, 28 May 2021 14:05:41 +0800 -Subject: [PATCH] mac80211: call ieee80211_tx_h_rate_ctrl() when dequeue - -Make ieee80211_tx_h_rate_ctrl() get called on dequeue to improve -performance since it reduces the turnaround time for rate control. - -Signed-off-by: Ryder Lee <ryder.lee@mediatek.com> ---- - ---- a/net/mac80211/tx.c -+++ b/net/mac80211/tx.c -@@ -1778,8 +1778,6 @@ static int invoke_tx_handlers_early(stru - CALL_TXH(ieee80211_tx_h_ps_buf); - CALL_TXH(ieee80211_tx_h_check_control_port_protocol); - CALL_TXH(ieee80211_tx_h_select_key); -- if (!ieee80211_hw_check(&tx->local->hw, HAS_RATE_CONTROL)) -- CALL_TXH(ieee80211_tx_h_rate_ctrl); - - txh_done: - if (unlikely(res == TX_DROP)) { -@@ -1812,6 +1810,9 @@ static int invoke_tx_handlers_late(struc - goto txh_done; - } - -+ if (!ieee80211_hw_check(&tx->local->hw, HAS_RATE_CONTROL)) -+ CALL_TXH(ieee80211_tx_h_rate_ctrl); -+ - CALL_TXH(ieee80211_tx_h_michael_mic_add); - CALL_TXH(ieee80211_tx_h_sequence); - CALL_TXH(ieee80211_tx_h_fragment); -@@ -3382,15 +3383,21 @@ out: - * Can be called while the sta lock is held. Anything that can cause packets to - * be generated will cause deadlock! - */ --static void ieee80211_xmit_fast_finish(struct ieee80211_sub_if_data *sdata, -- struct sta_info *sta, u8 pn_offs, -- struct ieee80211_key *key, -- struct sk_buff *skb) -+static ieee80211_tx_result -+ieee80211_xmit_fast_finish(struct ieee80211_sub_if_data *sdata, -+ struct sta_info *sta, u8 pn_offs, -+ struct ieee80211_key *key, -+ struct ieee80211_tx_data *tx) - { -+ struct sk_buff *skb = tx->skb; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ieee80211_hdr *hdr = (void *)skb->data; - u8 tid = IEEE80211_NUM_TIDS; - -+ if (!ieee80211_hw_check(&tx->local->hw, HAS_RATE_CONTROL) && -+ ieee80211_tx_h_rate_ctrl(tx) != TX_CONTINUE) -+ return TX_DROP; -+ - if (key) - info->control.hw_key = &key->conf; - -@@ -3439,6 +3446,8 @@ static void ieee80211_xmit_fast_finish(s - break; - } - } -+ -+ return TX_CONTINUE; - } - - static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata, -@@ -3542,24 +3551,17 @@ static bool ieee80211_xmit_fast(struct i - tx.sta = sta; - tx.key = fast_tx->key; - -- if (!ieee80211_hw_check(&local->hw, HAS_RATE_CONTROL)) { -- tx.skb = skb; -- r = ieee80211_tx_h_rate_ctrl(&tx); -- skb = tx.skb; -- tx.skb = NULL; -- -- if (r != TX_CONTINUE) { -- if (r != TX_QUEUED) -- kfree_skb(skb); -- return true; -- } -- } -- - if (ieee80211_queue_skb(local, sdata, sta, skb)) - return true; - -- ieee80211_xmit_fast_finish(sdata, sta, fast_tx->pn_offs, -- fast_tx->key, skb); -+ tx.skb = skb; -+ r = ieee80211_xmit_fast_finish(sdata, sta, fast_tx->pn_offs, -+ fast_tx->key, &tx); -+ tx.skb = NULL; -+ if (r == TX_DROP) { -+ kfree_skb(skb); -+ return true; -+ } - - if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) - sdata = container_of(sdata->bss, -@@ -3670,8 +3672,12 @@ begin: - (tx.key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) - pn_offs = ieee80211_hdrlen(hdr->frame_control); - -- ieee80211_xmit_fast_finish(sta->sdata, sta, pn_offs, -- tx.key, skb); -+ r = ieee80211_xmit_fast_finish(sta->sdata, sta, pn_offs, -+ tx.key, &tx); -+ if (r != TX_CONTINUE) { -+ ieee80211_free_txskb(&local->hw, skb); -+ goto begin; -+ } - } else { - if (invoke_tx_handlers_late(&tx)) - goto begin; diff --git a/package/kernel/mac80211/patches/subsys/376-mac80211-add-rate-control-support-for-encap-offload.patch b/package/kernel/mac80211/patches/subsys/376-mac80211-add-rate-control-support-for-encap-offload.patch deleted file mode 100644 index 43a4a1334df..00000000000 --- a/package/kernel/mac80211/patches/subsys/376-mac80211-add-rate-control-support-for-encap-offload.patch +++ /dev/null @@ -1,119 +0,0 @@ -From: Ryder Lee <ryder.lee@mediatek.com> -Date: Fri, 28 May 2021 14:05:43 +0800 -Subject: [PATCH] mac80211: add rate control support for encap offload - -The software rate control cannot deal with encap offload, so fix it. - -Signed-off-by: Ryder Lee <ryder.lee@mediatek.com> ---- - ---- a/net/mac80211/ieee80211_i.h -+++ b/net/mac80211/ieee80211_i.h -@@ -2024,6 +2024,15 @@ static inline void ieee80211_tx_skb(stru - ieee80211_tx_skb_tid(sdata, skb, 7); - } - -+static inline bool ieee80211_is_tx_data(struct sk_buff *skb) -+{ -+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; -+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); -+ -+ return info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP || -+ ieee80211_is_data(hdr->frame_control); -+} -+ - u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, - struct ieee802_11_elems *elems, - u64 filter, u32 crc, u8 *transmitter_bssid, ---- a/net/mac80211/rate.c -+++ b/net/mac80211/rate.c -@@ -297,15 +297,11 @@ void ieee80211_check_rate_mask(struct ie - static bool rc_no_data_or_no_ack_use_min(struct ieee80211_tx_rate_control *txrc) - { - struct sk_buff *skb = txrc->skb; -- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); -- __le16 fc; -- -- fc = hdr->frame_control; - - return (info->flags & (IEEE80211_TX_CTL_NO_ACK | - IEEE80211_TX_CTL_USE_MINRATE)) || -- !ieee80211_is_data(fc); -+ !ieee80211_is_tx_data(skb); - } - - static void rc_send_low_basicrate(struct ieee80211_tx_rate *rate, -@@ -870,7 +866,6 @@ void ieee80211_get_tx_rates(struct ieee8 - int max_rates) - { - struct ieee80211_sub_if_data *sdata; -- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ieee80211_supported_band *sband; - -@@ -882,7 +877,7 @@ void ieee80211_get_tx_rates(struct ieee8 - sdata = vif_to_sdata(vif); - sband = sdata->local->hw.wiphy->bands[info->band]; - -- if (ieee80211_is_data(hdr->frame_control)) -+ if (ieee80211_is_tx_data(skb)) - rate_control_apply_mask(sdata, sta, sband, dest, max_rates); - - if (dest[0].idx < 0) ---- a/net/mac80211/tx.c -+++ b/net/mac80211/tx.c -@@ -679,6 +679,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee8021 - u32 len; - struct ieee80211_tx_rate_control txrc; - struct ieee80211_sta_rates *ratetbl = NULL; -+ bool encap = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP; - bool assoc = false; - - memset(&txrc, 0, sizeof(txrc)); -@@ -720,7 +721,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee8021 - * just wants a probe response. - */ - if (tx->sdata->vif.bss_conf.use_short_preamble && -- (ieee80211_is_data(hdr->frame_control) || -+ (ieee80211_is_tx_data(tx->skb) || - (tx->sta && test_sta_flag(tx->sta, WLAN_STA_SHORT_PREAMBLE)))) - txrc.short_preamble = true; - -@@ -742,7 +743,8 @@ ieee80211_tx_h_rate_ctrl(struct ieee8021 - "%s: Dropped data frame as no usable bitrate found while " - "scanning and associated. Target station: " - "%pM on %d GHz band\n", -- tx->sdata->name, hdr->addr1, -+ tx->sdata->name, -+ encap ? ((struct ethhdr *)hdr)->h_dest : hdr->addr1, - info->band ? 5 : 2)) - return TX_DROP; - -@@ -776,7 +778,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee8021 - - if (txrc.reported_rate.idx < 0) { - txrc.reported_rate = tx->rate; -- if (tx->sta && ieee80211_is_data(hdr->frame_control)) -+ if (tx->sta && ieee80211_is_tx_data(tx->skb)) - tx->sta->tx_stats.last_rate = txrc.reported_rate; - } else if (tx->sta) - tx->sta->tx_stats.last_rate = txrc.reported_rate; -@@ -3660,8 +3662,16 @@ begin: - else - info->flags &= ~IEEE80211_TX_CTL_AMPDU; - -- if (info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) -+ if (info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) { -+ if (!ieee80211_hw_check(&local->hw, HAS_RATE_CONTROL)) { -+ r = ieee80211_tx_h_rate_ctrl(&tx); -+ if (r != TX_CONTINUE) { -+ ieee80211_free_txskb(&local->hw, skb); -+ goto begin; -+ } -+ } - goto encap_out; -+ } - - if (info->control.flags & IEEE80211_TX_CTRL_FAST_XMIT) { - struct sta_info *sta = container_of(txq->sta, struct sta_info, diff --git a/package/kernel/mac80211/patches/subsys/377-mac80211-minstrel_ht-fix-sample-time-check.patch b/package/kernel/mac80211/patches/subsys/377-mac80211-minstrel_ht-fix-sample-time-check.patch deleted file mode 100644 index d4b327c69c9..00000000000 --- a/package/kernel/mac80211/patches/subsys/377-mac80211-minstrel_ht-fix-sample-time-check.patch +++ /dev/null @@ -1,23 +0,0 @@ -From: Felix Fietkau <nbd@nbd.name> -Date: Thu, 17 Jun 2021 12:05:54 +0200 -Subject: [PATCH] mac80211: minstrel_ht: fix sample time check - -We need to skip sampling if the next sample time is after jiffies, not before. -This patch fixes an issue where in some cases only very little sampling (or none -at all) is performed, leading to really bad data rates - -Fixes: 80d55154b2f8 ("mac80211: minstrel_ht: significantly redesign the rate probing strategy") -Signed-off-by: Felix Fietkau <nbd@nbd.name> ---- - ---- a/net/mac80211/rc80211_minstrel_ht.c -+++ b/net/mac80211/rc80211_minstrel_ht.c -@@ -1466,7 +1466,7 @@ minstrel_ht_get_rate(void *priv, struct - (info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO)) - return; - -- if (time_is_before_jiffies(mi->sample_time)) -+ if (time_is_after_jiffies(mi->sample_time)) - return; - - mi->sample_time = jiffies + MINSTREL_SAMPLE_INTERVAL; diff --git a/package/kernel/mac80211/patches/subsys/378-mac80211-remove-iwlwifi-specific-workaround-that-bro.patch b/package/kernel/mac80211/patches/subsys/378-mac80211-remove-iwlwifi-specific-workaround-that-bro.patch deleted file mode 100644 index a5ad377e6fb..00000000000 --- a/package/kernel/mac80211/patches/subsys/378-mac80211-remove-iwlwifi-specific-workaround-that-bro.patch +++ /dev/null @@ -1,51 +0,0 @@ -From: Felix Fietkau <nbd@nbd.name> -Date: Sat, 19 Jun 2021 12:10:14 +0200 -Subject: [PATCH] mac80211: remove iwlwifi specific workaround that broke sta - NDP tx - -Sending nulldata packets is important for sw AP link probing and detecting -4-address mode links. The checks that dropped these packets were apparently -added to work around an iwlwifi firmware bug with multi-TID aggregation. - -Fixes: 41cbb0f5a295 ("mac80211: add support for HE") -Cc: stable@vger.kernel.org -Signed-off-by: Felix Fietkau <nbd@nbd.name> ---- - ---- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c -+++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c -@@ -1085,6 +1085,9 @@ static int iwl_mvm_tx_mpdu(struct iwl_mv - if (WARN_ON_ONCE(mvmsta->sta_id == IWL_MVM_INVALID_STA)) - return -1; - -+ if (unlikely(ieee80211_is_any_nullfunc(fc)) && sta->he_cap.has_he) -+ return -1; -+ - if (unlikely(ieee80211_is_probe_resp(fc))) - iwl_mvm_probe_resp_set_noa(mvm, skb); - ---- a/net/mac80211/mlme.c -+++ b/net/mac80211/mlme.c -@@ -1094,11 +1094,6 @@ void ieee80211_send_nullfunc(struct ieee - struct ieee80211_hdr_3addr *nullfunc; - struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - -- /* Don't send NDPs when STA is connected HE */ -- if (sdata->vif.type == NL80211_IFTYPE_STATION && -- !(ifmgd->flags & IEEE80211_STA_DISABLE_HE)) -- return; -- - skb = ieee80211_nullfunc_get(&local->hw, &sdata->vif, - !ieee80211_hw_check(&local->hw, DOESNT_SUPPORT_QOS_NDP)); - if (!skb) -@@ -1130,10 +1125,6 @@ static void ieee80211_send_4addr_nullfun - if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION)) - return; - -- /* Don't send NDPs when connected HE */ -- if (!(sdata->u.mgd.flags & IEEE80211_STA_DISABLE_HE)) -- return; -- - skb = dev_alloc_skb(local->hw.extra_tx_headroom + 30); - if (!skb) - return; diff --git a/package/kernel/mac80211/patches/subsys/379-mac80211-fix-starting-aggregation-sessions-on-mesh-i.patch b/package/kernel/mac80211/patches/subsys/379-mac80211-fix-starting-aggregation-sessions-on-mesh-i.patch deleted file mode 100644 index 2ad083f1507..00000000000 --- a/package/kernel/mac80211/patches/subsys/379-mac80211-fix-starting-aggregation-sessions-on-mesh-i.patch +++ /dev/null @@ -1,112 +0,0 @@ -From: Felix Fietkau <nbd@nbd.name> -Date: Tue, 29 Jun 2021 13:25:09 +0200 -Subject: [PATCH] mac80211: fix starting aggregation sessions on mesh - interfaces - -The logic for starting aggregation sessions was recently moved from minstrel_ht -to mac80211, into the subif tx handler just after the sta lookup. -Unfortunately this didn't work for mesh interfaces, since the sta lookup is -deferred until a much later point in time on those. -Fix this by also calling the aggregation check right after the deferred sta -lookup. - -Fixes: 08a46c642001 ("mac80211: move A-MPDU session check from minstrel_ht to mac80211") -Signed-off-by: Felix Fietkau <nbd@nbd.name> ---- - ---- a/net/mac80211/tx.c -+++ b/net/mac80211/tx.c -@@ -1159,6 +1159,29 @@ static bool ieee80211_tx_prep_agg(struct - return queued; - } - -+static void -+ieee80211_aggr_check(struct ieee80211_sub_if_data *sdata, -+ struct sta_info *sta, -+ struct sk_buff *skb) -+{ -+ struct rate_control_ref *ref = sdata->local->rate_ctrl; -+ u16 tid; -+ -+ if (!ref || !(ref->ops->capa & RATE_CTRL_CAPA_AMPDU_TRIGGER)) -+ return; -+ -+ if (!sta || !sta->sta.ht_cap.ht_supported || -+ !sta->sta.wme || skb_get_queue_mapping(skb) == IEEE80211_AC_VO || -+ skb->protocol == sdata->control_port_protocol) -+ return; -+ -+ tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK; -+ if (likely(sta->ampdu_mlme.tid_tx[tid])) -+ return; -+ -+ ieee80211_start_tx_ba_session(&sta->sta, tid, 0); -+} -+ - /* - * initialises @tx - * pass %NULL for the station if unknown, a valid pointer if known -@@ -1172,6 +1195,7 @@ ieee80211_tx_prepare(struct ieee80211_su - struct ieee80211_local *local = sdata->local; - struct ieee80211_hdr *hdr; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); -+ bool aggr_check = false; - int tid; - - memset(tx, 0, sizeof(*tx)); -@@ -1200,8 +1224,10 @@ ieee80211_tx_prepare(struct ieee80211_su - } else if (tx->sdata->control_port_protocol == tx->skb->protocol) { - tx->sta = sta_info_get_bss(sdata, hdr->addr1); - } -- if (!tx->sta && !is_multicast_ether_addr(hdr->addr1)) -+ if (!tx->sta && !is_multicast_ether_addr(hdr->addr1)) { - tx->sta = sta_info_get(sdata, hdr->addr1); -+ aggr_check = true; -+ } - } - - if (tx->sta && ieee80211_is_data_qos(hdr->frame_control) && -@@ -1211,8 +1237,12 @@ ieee80211_tx_prepare(struct ieee80211_su - struct tid_ampdu_tx *tid_tx; - - tid = ieee80211_get_tid(hdr); -- - tid_tx = rcu_dereference(tx->sta->ampdu_mlme.tid_tx[tid]); -+ if (!tid_tx && aggr_check) { -+ ieee80211_aggr_check(sdata, tx->sta, skb); -+ tid_tx = rcu_dereference(tx->sta->ampdu_mlme.tid_tx[tid]); -+ } -+ - if (tid_tx) { - bool queued; - -@@ -3947,29 +3977,6 @@ void ieee80211_txq_schedule_start(struct - } - EXPORT_SYMBOL(ieee80211_txq_schedule_start); - --static void --ieee80211_aggr_check(struct ieee80211_sub_if_data *sdata, -- struct sta_info *sta, -- struct sk_buff *skb) --{ -- struct rate_control_ref *ref = sdata->local->rate_ctrl; -- u16 tid; -- -- if (!ref || !(ref->ops->capa & RATE_CTRL_CAPA_AMPDU_TRIGGER)) -- return; -- -- if (!sta || !sta->sta.ht_cap.ht_supported || -- !sta->sta.wme || skb_get_queue_mapping(skb) == IEEE80211_AC_VO || -- skb->protocol == sdata->control_port_protocol) -- return; -- -- tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK; -- if (likely(sta->ampdu_mlme.tid_tx[tid])) -- return; -- -- ieee80211_start_tx_ba_session(&sta->sta, tid, 0); --} -- - void __ieee80211_subif_start_xmit(struct sk_buff *skb, - struct net_device *dev, - u32 info_flags, diff --git a/package/kernel/mac80211/patches/subsys/380-mac80211-introduce-aql_enable-node-in-debugfs.patch b/package/kernel/mac80211/patches/subsys/380-mac80211-introduce-aql_enable-node-in-debugfs.patch deleted file mode 100644 index b21b671c10a..00000000000 --- a/package/kernel/mac80211/patches/subsys/380-mac80211-introduce-aql_enable-node-in-debugfs.patch +++ /dev/null @@ -1,111 +0,0 @@ -From: Lorenzo Bianconi <lorenzo@kernel.org> -Date: Sat, 9 Jan 2021 18:57:51 +0100 -Subject: [PATCH] mac80211: introduce aql_enable node in debugfs - -Introduce aql_enable node in debugfs in order to enable/disable aql. -This is useful for debugging purpose. - -Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org> -Link: https://lore.kernel.org/r/e7a934d5d84e4796c4f97ea5de4e66c824296b07.1610214851.git.lorenzo@kernel.org -Signed-off-by: Johannes Berg <johannes.berg@intel.com> ---- - ---- a/net/mac80211/debugfs.c -+++ b/net/mac80211/debugfs.c -@@ -281,6 +281,56 @@ static const struct file_operations aql_ - .llseek = default_llseek, - }; - -+static ssize_t aql_enable_read(struct file *file, char __user *user_buf, -+ size_t count, loff_t *ppos) -+{ -+ char buf[3]; -+ int len; -+ -+ len = scnprintf(buf, sizeof(buf), "%d\n", -+ !static_key_false(&aql_disable.key)); -+ -+ return simple_read_from_buffer(user_buf, count, ppos, buf, len); -+} -+ -+static ssize_t aql_enable_write(struct file *file, const char __user *user_buf, -+ size_t count, loff_t *ppos) -+{ -+ bool aql_disabled = static_key_false(&aql_disable.key); -+ char buf[3]; -+ size_t len; -+ -+ if (count > sizeof(buf)) -+ return -EINVAL; -+ -+ if (copy_from_user(buf, user_buf, count)) -+ return -EFAULT; -+ -+ buf[sizeof(buf) - 1] = '\0'; -+ len = strlen(buf); -+ if (len > 0 && buf[len - 1] == '\n') -+ buf[len - 1] = 0; -+ -+ if (buf[0] == '0' && buf[1] == '\0') { -+ if (!aql_disabled) -+ static_branch_inc(&aql_disable); -+ } else if (buf[0] == '1' && buf[1] == '\0') { -+ if (aql_disabled) -+ static_branch_dec(&aql_disable); -+ } else { -+ return -EINVAL; -+ } -+ -+ return count; -+} -+ -+static const struct file_operations aql_enable_ops = { -+ .write = aql_enable_write, -+ .read = aql_enable_read, -+ .open = simple_open, -+ .llseek = default_llseek, -+}; -+ - static ssize_t force_tx_status_read(struct file *file, - char __user *user_buf, - size_t count, -@@ -569,6 +619,7 @@ void debugfs_hw_add(struct ieee80211_loc - DEBUGFS_ADD(power); - DEBUGFS_ADD(hw_conf); - DEBUGFS_ADD_MODE(force_tx_status, 0600); -+ DEBUGFS_ADD_MODE(aql_enable, 0600); - - if (local->ops->wake_tx_queue) - DEBUGFS_ADD_MODE(aqm, 0600); ---- a/net/mac80211/ieee80211_i.h -+++ b/net/mac80211/ieee80211_i.h -@@ -1140,6 +1140,8 @@ enum mac80211_scan_state { - SCAN_ABORT, - }; - -+DECLARE_STATIC_KEY_FALSE(aql_disable); -+ - struct ieee80211_local { - /* embed the driver visible part. - * don't cast (use the static inlines below), but we keep ---- a/net/mac80211/tx.c -+++ b/net/mac80211/tx.c -@@ -3887,6 +3887,8 @@ void __ieee80211_schedule_txq(struct iee - } - EXPORT_SYMBOL(__ieee80211_schedule_txq); - -+DEFINE_STATIC_KEY_FALSE(aql_disable); -+ - bool ieee80211_txq_airtime_check(struct ieee80211_hw *hw, - struct ieee80211_txq *txq) - { -@@ -3896,6 +3898,9 @@ bool ieee80211_txq_airtime_check(struct - if (!wiphy_ext_feature_isset(local->hw.wiphy, NL80211_EXT_FEATURE_AQL)) - return true; - -+ if (static_branch_unlikely(&aql_disable)) -+ return true; -+ - if (!txq->sta) - return true; - diff --git a/package/kernel/mac80211/patches/subsys/381-mac80211-rearrange-struct-txq_info-for-fewer-holes.patch b/package/kernel/mac80211/patches/subsys/381-mac80211-rearrange-struct-txq_info-for-fewer-holes.patch deleted file mode 100644 index 708ad6f4601..00000000000 --- a/package/kernel/mac80211/patches/subsys/381-mac80211-rearrange-struct-txq_info-for-fewer-holes.patch +++ /dev/null @@ -1,39 +0,0 @@ -From: Johannes Berg <johannes.berg@intel.com> -Date: Fri, 18 Jun 2021 13:41:44 +0300 -Subject: [PATCH] mac80211: rearrange struct txq_info for fewer holes - -We can slightly decrease the size of struct txq_info by -rearranging some fields for fewer holes, so do that. - -Signed-off-by: Johannes Berg <johannes.berg@intel.com> -Signed-off-by: Luca Coelho <luciano.coelho@intel.com> -Link: https://lore.kernel.org/r/iwlwifi.20210618133832.1bf019a1fe2e.Ib54622b8d6dc1a9a7dc484e573c073119450538b@changeid -Signed-off-by: Johannes Berg <johannes.berg@intel.com> ---- - ---- a/net/mac80211/ieee80211_i.h -+++ b/net/mac80211/ieee80211_i.h -@@ -5,7 +5,7 @@ - * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> - * Copyright 2007-2010 Johannes Berg <johannes@sipsolutions.net> - * Copyright 2013-2015 Intel Mobile Communications GmbH -- * Copyright (C) 2018-2020 Intel Corporation -+ * Copyright (C) 2018-2021 Intel Corporation - */ - - #ifndef IEEE80211_I_H -@@ -848,9 +848,12 @@ struct txq_info { - struct fq_tin tin; - struct codel_vars def_cvars; - struct codel_stats cstats; -- struct sk_buff_head frags; -- struct list_head schedule_order; -+ - u16 schedule_round; -+ struct list_head schedule_order; -+ -+ struct sk_buff_head frags; -+ - unsigned long flags; - - /* keep last! */ diff --git a/package/kernel/mac80211/patches/subsys/382-mac80211-Switch-to-a-virtual-time-based-airtime-sche.patch b/package/kernel/mac80211/patches/subsys/382-mac80211-Switch-to-a-virtual-time-based-airtime-sche.patch deleted file mode 100644 index ba78f7a1428..00000000000 --- a/package/kernel/mac80211/patches/subsys/382-mac80211-Switch-to-a-virtual-time-based-airtime-sche.patch +++ /dev/null @@ -1,1277 +0,0 @@ -From: =?UTF-8?q?Toke=20H=C3=B8iland-J=C3=B8rgensen?= <toke@redhat.com> -Date: Wed, 23 Jun 2021 15:47:55 +0200 -Subject: [PATCH] mac80211: Switch to a virtual time-based airtime scheduler -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This switches the airtime scheduler in mac80211 to use a virtual -time-based scheduler instead of the round-robin scheduler used before. -This has a couple of advantages: - -- No need to sync up the round-robin scheduler in firmware/hardware with - the round-robin airtime scheduler. - -- If several stations are eligible for transmission we can schedule both - of them; no need to hard-block the scheduling rotation until the head - of the queue has used up its quantum. - -- The check of whether a station is eligible for transmission becomes - simpler (in ieee80211_txq_may_transmit()). - -The drawback is that scheduling becomes slightly more expensive, as we -need to maintain an rbtree of TXQs sorted by virtual time. This means -that ieee80211_register_airtime() becomes O(logN) in the number of -currently scheduled TXQs because it can change the order of the -scheduled stations. We mitigate this overhead by only resorting when a -station changes position in the tree, and hopefully N rarely grows too -big (it's only TXQs currently backlogged, not all associated stations), -so it shouldn't be too big of an issue. - -To prevent divisions in the fast path, we maintain both station sums and -pre-computed reciprocals of the sums. This turns the fast-path operation -into a multiplication, with divisions only happening as the number of -active stations change (to re-compute the current sum of all active -station weights). To prevent this re-computation of the reciprocal from -happening too frequently, we use a time-based notion of station -activity, instead of updating the weight every time a station gets -scheduled or de-scheduled. As queues can oscillate between empty and -occupied quite frequently, this can significantly cut down on the number -of re-computations. It also has the added benefit of making the station -airtime calculation independent on whether the queue happened to have -drained at the time an airtime value was accounted. - -Co-developed-by: Yibo Zhao <yiboz@codeaurora.org> -Signed-off-by: Yibo Zhao <yiboz@codeaurora.org> -Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com> -Link: https://lore.kernel.org/r/20210623134755.235545-1-toke@redhat.com -Signed-off-by: Johannes Berg <johannes.berg@intel.com> ---- - ---- a/include/net/mac80211.h -+++ b/include/net/mac80211.h -@@ -6552,9 +6552,6 @@ static inline void ieee80211_txq_schedul - { - } - --void __ieee80211_schedule_txq(struct ieee80211_hw *hw, -- struct ieee80211_txq *txq, bool force); -- - /** - * ieee80211_schedule_txq - schedule a TXQ for transmission - * -@@ -6567,11 +6564,7 @@ void __ieee80211_schedule_txq(struct iee - * The driver may call this function if it has buffered packets for - * this TXQ internally. - */ --static inline void --ieee80211_schedule_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq) --{ -- __ieee80211_schedule_txq(hw, txq, true); --} -+void ieee80211_schedule_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq); - - /** - * ieee80211_return_txq - return a TXQ previously acquired by ieee80211_next_txq() -@@ -6583,12 +6576,8 @@ ieee80211_schedule_txq(struct ieee80211_ - * The driver may set force=true if it has buffered packets for this TXQ - * internally. - */ --static inline void --ieee80211_return_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq, -- bool force) --{ -- __ieee80211_schedule_txq(hw, txq, force); --} -+void ieee80211_return_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq, -+ bool force); - - /** - * ieee80211_txq_may_transmit - check whether TXQ is allowed to transmit ---- a/net/mac80211/cfg.c -+++ b/net/mac80211/cfg.c -@@ -1442,6 +1442,38 @@ static void sta_apply_mesh_params(struct - #endif - } - -+static void sta_apply_airtime_params(struct ieee80211_local *local, -+ struct sta_info *sta, -+ struct station_parameters *params) -+{ -+ u8 ac; -+ -+ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { -+ struct airtime_sched_info *air_sched = &local->airtime[ac]; -+ struct airtime_info *air_info = &sta->airtime[ac]; -+ struct txq_info *txqi; -+ u8 tid; -+ -+ spin_lock_bh(&air_sched->lock); -+ for (tid = 0; tid < IEEE80211_NUM_TIDS + 1; tid++) { -+ if (air_info->weight == params->airtime_weight || -+ !sta->sta.txq[tid] || -+ ac != ieee80211_ac_from_tid(tid)) -+ continue; -+ -+ airtime_weight_set(air_info, params->airtime_weight); -+ -+ txqi = to_txq_info(sta->sta.txq[tid]); -+ if (RB_EMPTY_NODE(&txqi->schedule_order)) -+ continue; -+ -+ ieee80211_update_airtime_weight(local, air_sched, -+ 0, true); -+ } -+ spin_unlock_bh(&air_sched->lock); -+ } -+} -+ - static int sta_apply_parameters(struct ieee80211_local *local, - struct sta_info *sta, - struct station_parameters *params) -@@ -1629,7 +1661,8 @@ static int sta_apply_parameters(struct i - sta_apply_mesh_params(local, sta, params); - - if (params->airtime_weight) -- sta->airtime_weight = params->airtime_weight; -+ sta_apply_airtime_params(local, sta, params); -+ - - /* set the STA state after all sta info from usermode has been set */ - if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) || ---- a/net/mac80211/debugfs.c -+++ b/net/mac80211/debugfs.c -@@ -216,14 +216,14 @@ static ssize_t aql_txq_limit_read(struct - "VI %u %u\n" - "BE %u %u\n" - "BK %u %u\n", -- local->aql_txq_limit_low[IEEE80211_AC_VO], -- local->aql_txq_limit_high[IEEE80211_AC_VO], -- local->aql_txq_limit_low[IEEE80211_AC_VI], -- local->aql_txq_limit_high[IEEE80211_AC_VI], -- local->aql_txq_limit_low[IEEE80211_AC_BE], -- local->aql_txq_limit_high[IEEE80211_AC_BE], -- local->aql_txq_limit_low[IEEE80211_AC_BK], -- local->aql_txq_limit_high[IEEE80211_AC_BK]); -+ local->airtime[IEEE80211_AC_VO].aql_txq_limit_low, -+ local->airtime[IEEE80211_AC_VO].aql_txq_limit_high, -+ local->airtime[IEEE80211_AC_VI].aql_txq_limit_low, -+ local->airtime[IEEE80211_AC_VI].aql_txq_limit_high, -+ local->airtime[IEEE80211_AC_BE].aql_txq_limit_low, -+ local->airtime[IEEE80211_AC_BE].aql_txq_limit_high, -+ local->airtime[IEEE80211_AC_BK].aql_txq_limit_low, -+ local->airtime[IEEE80211_AC_BK].aql_txq_limit_high); - return simple_read_from_buffer(user_buf, count, ppos, - buf, len); - } -@@ -255,11 +255,11 @@ static ssize_t aql_txq_limit_write(struc - if (ac >= IEEE80211_NUM_ACS) - return -EINVAL; - -- q_limit_low_old = local->aql_txq_limit_low[ac]; -- q_limit_high_old = local->aql_txq_limit_high[ac]; -+ q_limit_low_old = local->airtime[ac].aql_txq_limit_low; -+ q_limit_high_old = local->airtime[ac].aql_txq_limit_high; - -- local->aql_txq_limit_low[ac] = q_limit_low; -- local->aql_txq_limit_high[ac] = q_limit_high; -+ local->airtime[ac].aql_txq_limit_low = q_limit_low; -+ local->airtime[ac].aql_txq_limit_high = q_limit_high; - - mutex_lock(&local->sta_mtx); - list_for_each_entry(sta, &local->sta_list, list) { -@@ -382,6 +382,46 @@ static const struct file_operations forc - .llseek = default_llseek, - }; - -+static ssize_t airtime_read(struct file *file, -+ char __user *user_buf, -+ size_t count, -+ loff_t *ppos) -+{ -+ struct ieee80211_local *local = file->private_data; -+ char buf[200]; -+ u64 v_t[IEEE80211_NUM_ACS]; -+ u64 wt[IEEE80211_NUM_ACS]; -+ int len = 0, ac; -+ -+ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { -+ spin_lock_bh(&local->airtime[ac].lock); -+ v_t[ac] = local->airtime[ac].v_t; -+ wt[ac] = local->airtime[ac].weight_sum; -+ spin_unlock_bh(&local->airtime[ac].lock); -+ } -+ len = scnprintf(buf, sizeof(buf), -+ "\tVO VI BE BK\n" -+ "Virt-t\t%-10llu %-10llu %-10llu %-10llu\n" -+ "Weight\t%-10llu %-10llu %-10llu %-10llu\n", -+ v_t[0], -+ v_t[1], -+ v_t[2], -+ v_t[3], -+ wt[0], -+ wt[1], -+ wt[2], -+ wt[3]); -+ -+ return simple_read_from_buffer(user_buf, count, ppos, -+ buf, len); -+} -+ -+static const struct file_operations airtime_ops = { -+ .read = airtime_read, -+ .open = simple_open, -+ .llseek = default_llseek, -+}; -+ - #ifdef CONFIG_PM - static ssize_t reset_write(struct file *file, const char __user *user_buf, - size_t count, loff_t *ppos) -@@ -624,7 +664,11 @@ void debugfs_hw_add(struct ieee80211_loc - if (local->ops->wake_tx_queue) - DEBUGFS_ADD_MODE(aqm, 0600); - -- DEBUGFS_ADD_MODE(airtime_flags, 0600); -+ if (wiphy_ext_feature_isset(local->hw.wiphy, -+ NL80211_EXT_FEATURE_AIRTIME_FAIRNESS)) { -+ DEBUGFS_ADD_MODE(airtime, 0600); -+ DEBUGFS_ADD_MODE(airtime_flags, 0600); -+ } - - DEBUGFS_ADD(aql_txq_limit); - debugfs_create_u32("aql_threshold", 0600, ---- a/net/mac80211/debugfs_netdev.c -+++ b/net/mac80211/debugfs_netdev.c -@@ -513,6 +513,34 @@ static ssize_t ieee80211_if_fmt_aqm( - } - IEEE80211_IF_FILE_R(aqm); - -+static ssize_t ieee80211_if_fmt_airtime( -+ const struct ieee80211_sub_if_data *sdata, char *buf, int buflen) -+{ -+ struct ieee80211_local *local = sdata->local; -+ struct ieee80211_txq *txq = sdata->vif.txq; -+ struct airtime_info *air_info; -+ int len; -+ -+ if (!txq) -+ return 0; -+ -+ spin_lock_bh(&local->airtime[txq->ac].lock); -+ air_info = to_airtime_info(txq); -+ len = scnprintf(buf, -+ buflen, -+ "RX: %llu us\nTX: %llu us\nWeight: %u\n" -+ "Virt-T: %lld us\n", -+ air_info->rx_airtime, -+ air_info->tx_airtime, -+ air_info->weight, -+ air_info->v_t); -+ spin_unlock_bh(&local->airtime[txq->ac].lock); -+ -+ return len; -+} -+ -+IEEE80211_IF_FILE_R(airtime); -+ - IEEE80211_IF_FILE(multicast_to_unicast, u.ap.multicast_to_unicast, HEX); - - /* IBSS attributes */ -@@ -661,8 +689,10 @@ static void add_common_files(struct ieee - - if (sdata->local->ops->wake_tx_queue && - sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE && -- sdata->vif.type != NL80211_IFTYPE_NAN) -+ sdata->vif.type != NL80211_IFTYPE_NAN) { - DEBUGFS_ADD(aqm); -+ DEBUGFS_ADD(airtime); -+ } - } - - static void add_sta_files(struct ieee80211_sub_if_data *sdata) ---- a/net/mac80211/debugfs_sta.c -+++ b/net/mac80211/debugfs_sta.c -@@ -202,7 +202,7 @@ static ssize_t sta_airtime_read(struct f - size_t bufsz = 400; - char *buf = kzalloc(bufsz, GFP_KERNEL), *p = buf; - u64 rx_airtime = 0, tx_airtime = 0; -- s64 deficit[IEEE80211_NUM_ACS]; -+ u64 v_t[IEEE80211_NUM_ACS]; - ssize_t rv; - int ac; - -@@ -210,18 +210,18 @@ static ssize_t sta_airtime_read(struct f - return -ENOMEM; - - for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { -- spin_lock_bh(&local->active_txq_lock[ac]); -+ spin_lock_bh(&local->airtime[ac].lock); - rx_airtime += sta->airtime[ac].rx_airtime; - tx_airtime += sta->airtime[ac].tx_airtime; -- deficit[ac] = sta->airtime[ac].deficit; -- spin_unlock_bh(&local->active_txq_lock[ac]); -+ v_t[ac] = sta->airtime[ac].v_t; -+ spin_unlock_bh(&local->airtime[ac].lock); - } - - p += scnprintf(p, bufsz + buf - p, - "RX: %llu us\nTX: %llu us\nWeight: %u\n" -- "Deficit: VO: %lld us VI: %lld us BE: %lld us BK: %lld us\n", -- rx_airtime, tx_airtime, sta->airtime_weight, -- deficit[0], deficit[1], deficit[2], deficit[3]); -+ "Virt-T: VO: %lld us VI: %lld us BE: %lld us BK: %lld us\n", -+ rx_airtime, tx_airtime, sta->airtime[0].weight, -+ v_t[0], v_t[1], v_t[2], v_t[3]); - - rv = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf); - kfree(buf); -@@ -236,11 +236,11 @@ static ssize_t sta_airtime_write(struct - int ac; - - for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { -- spin_lock_bh(&local->active_txq_lock[ac]); -+ spin_lock_bh(&local->airtime[ac].lock); - sta->airtime[ac].rx_airtime = 0; - sta->airtime[ac].tx_airtime = 0; -- sta->airtime[ac].deficit = sta->airtime_weight; -- spin_unlock_bh(&local->active_txq_lock[ac]); -+ sta->airtime[ac].v_t = 0; -+ spin_unlock_bh(&local->airtime[ac].lock); - } - - return count; -@@ -263,10 +263,10 @@ static ssize_t sta_aql_read(struct file - return -ENOMEM; - - for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { -- spin_lock_bh(&local->active_txq_lock[ac]); -+ spin_lock_bh(&local->airtime[ac].lock); - q_limit_l[ac] = sta->airtime[ac].aql_limit_low; - q_limit_h[ac] = sta->airtime[ac].aql_limit_high; -- spin_unlock_bh(&local->active_txq_lock[ac]); -+ spin_unlock_bh(&local->airtime[ac].lock); - q_depth[ac] = atomic_read(&sta->airtime[ac].aql_tx_pending); - } - ---- a/net/mac80211/ieee80211_i.h -+++ b/net/mac80211/ieee80211_i.h -@@ -840,20 +840,16 @@ enum txq_info_flags { - * @def_flow: used as a fallback flow when a packet destined to @tin hashes to - * a fq_flow which is already owned by a different tin - * @def_cvars: codel vars for @def_flow -- * @frags: used to keep fragments created after dequeue - * @schedule_order: used with ieee80211_local->active_txqs -- * @schedule_round: counter to prevent infinite loops on TXQ scheduling -+ * @frags: used to keep fragments created after dequeue - */ - struct txq_info { - struct fq_tin tin; - struct codel_vars def_cvars; - struct codel_stats cstats; -- -- u16 schedule_round; -- struct list_head schedule_order; -+ struct rb_node schedule_order; - - struct sk_buff_head frags; -- - unsigned long flags; - - /* keep last! */ -@@ -930,6 +926,8 @@ struct ieee80211_sub_if_data { - struct ieee80211_tx_queue_params tx_conf[IEEE80211_NUM_ACS]; - struct mac80211_qos_map __rcu *qos_map; - -+ struct airtime_info airtime[IEEE80211_NUM_ACS]; -+ - struct work_struct csa_finalize_work; - bool csa_block_tx; /* write-protected by sdata_lock and local->mtx */ - struct cfg80211_chan_def csa_chandef; -@@ -1143,6 +1141,44 @@ enum mac80211_scan_state { - SCAN_ABORT, - }; - -+/** -+ * struct airtime_sched_info - state used for airtime scheduling and AQL -+ * -+ * @lock: spinlock that protects all the fields in this struct -+ * @active_txqs: rbtree of currently backlogged queues, sorted by virtual time -+ * @schedule_pos: the current position maintained while a driver walks the tree -+ * with ieee80211_next_txq() -+ * @active_list: list of struct airtime_info structs that were active within -+ * the last AIRTIME_ACTIVE_DURATION (100 ms), used to compute -+ * weight_sum -+ * @last_weight_update: used for rate limiting walking active_list -+ * @last_schedule_time: tracks the last time a transmission was scheduled; used -+ * for catching up v_t if no stations are eligible for -+ * transmission. -+ * @v_t: global virtual time; queues with v_t < this are eligible for -+ * transmission -+ * @weight_sum: total sum of all active stations used for dividing airtime -+ * @weight_sum_reciprocal: reciprocal of weight_sum (to avoid divisions in fast -+ * path - see comment above -+ * IEEE80211_RECIPROCAL_DIVISOR_64) -+ * @aql_txq_limit_low: AQL limit when total outstanding airtime -+ * is < IEEE80211_AQL_THRESHOLD -+ * @aql_txq_limit_high: AQL limit when total outstanding airtime -+ * is > IEEE80211_AQL_THRESHOLD -+ */ -+struct airtime_sched_info { -+ spinlock_t lock; -+ struct rb_root_cached active_txqs; -+ struct rb_node *schedule_pos; -+ struct list_head active_list; -+ u64 last_weight_update; -+ u64 last_schedule_activity; -+ u64 v_t; -+ u64 weight_sum; -+ u64 weight_sum_reciprocal; -+ u32 aql_txq_limit_low; -+ u32 aql_txq_limit_high; -+}; - DECLARE_STATIC_KEY_FALSE(aql_disable); - - struct ieee80211_local { -@@ -1156,13 +1192,8 @@ struct ieee80211_local { - struct codel_params cparams; - - /* protects active_txqs and txqi->schedule_order */ -- spinlock_t active_txq_lock[IEEE80211_NUM_ACS]; -- struct list_head active_txqs[IEEE80211_NUM_ACS]; -- u16 schedule_round[IEEE80211_NUM_ACS]; -- -+ struct airtime_sched_info airtime[IEEE80211_NUM_ACS]; - u16 airtime_flags; -- u32 aql_txq_limit_low[IEEE80211_NUM_ACS]; -- u32 aql_txq_limit_high[IEEE80211_NUM_ACS]; - u32 aql_threshold; - atomic_t aql_total_pending_airtime; - -@@ -1581,6 +1612,125 @@ static inline bool txq_has_queue(struct - return !(skb_queue_empty(&txqi->frags) && !txqi->tin.backlog_packets); - } - -+static inline struct airtime_info *to_airtime_info(struct ieee80211_txq *txq) -+{ -+ struct ieee80211_sub_if_data *sdata; -+ struct sta_info *sta; -+ -+ if (txq->sta) { -+ sta = container_of(txq->sta, struct sta_info, sta); -+ return &sta->airtime[txq->ac]; -+ } -+ -+ sdata = vif_to_sdata(txq->vif); -+ return &sdata->airtime[txq->ac]; -+} -+ -+/* To avoid divisions in the fast path, we keep pre-computed reciprocals for -+ * airtime weight calculations. There are two different weights to keep track -+ * of: The per-station weight and the sum of weights per phy. -+ * -+ * For the per-station weights (kept in airtime_info below), we use 32-bit -+ * reciprocals with a devisor of 2^19. This lets us keep the multiplications and -+ * divisions for the station weights as 32-bit operations at the cost of a bit -+ * of rounding error for high weights; but the choice of divisor keeps rounding -+ * errors <10% for weights <2^15, assuming no more than 8ms of airtime is -+ * reported at a time. -+ * -+ * For the per-phy sum of weights the values can get higher, so we use 64-bit -+ * operations for those with a 32-bit divisor, which should avoid any -+ * significant rounding errors. -+ */ -+#define IEEE80211_RECIPROCAL_DIVISOR_64 0x100000000ULL -+#define IEEE80211_RECIPROCAL_SHIFT_64 32 -+#define IEEE80211_RECIPROCAL_DIVISOR_32 0x80000U -+#define IEEE80211_RECIPROCAL_SHIFT_32 19 -+ -+static inline void airtime_weight_set(struct airtime_info *air_info, u16 weight) -+{ -+ if (air_info->weight == weight) -+ return; -+ -+ air_info->weight = weight; -+ if (weight) { -+ air_info->weight_reciprocal = -+ IEEE80211_RECIPROCAL_DIVISOR_32 / weight; -+ } else { -+ air_info->weight_reciprocal = 0; -+ } -+} -+ -+static inline void airtime_weight_sum_set(struct airtime_sched_info *air_sched, -+ int weight_sum) -+{ -+ if (air_sched->weight_sum == weight_sum) -+ return; -+ -+ air_sched->weight_sum = weight_sum; -+ if (air_sched->weight_sum) { -+ air_sched->weight_sum_reciprocal = IEEE80211_RECIPROCAL_DIVISOR_64; -+ do_div(air_sched->weight_sum_reciprocal, air_sched->weight_sum); -+ } else { -+ air_sched->weight_sum_reciprocal = 0; -+ } -+} -+ -+/* A problem when trying to enforce airtime fairness is that we want to divide -+ * the airtime between the currently *active* stations. However, basing this on -+ * the instantaneous queue state of stations doesn't work, as queues tend to -+ * oscillate very quickly between empty and occupied, leading to the scheduler -+ * thinking only a single station is active when deciding whether to allow -+ * transmission (and thus not throttling correctly). -+ * -+ * To fix this we use a timer-based notion of activity: a station is considered -+ * active if it has been scheduled within the last 100 ms; we keep a separate -+ * list of all the stations considered active in this manner, and lazily update -+ * the total weight of active stations from this list (filtering the stations in -+ * the list by their 'last active' time). -+ * -+ * We add one additional safeguard to guard against stations that manage to get -+ * scheduled every 100 ms but don't transmit a lot of data, and thus don't use -+ * up any airtime. Such stations would be able to get priority for an extended -+ * period of time if they do start transmitting at full capacity again, and so -+ * we add an explicit maximum for how far behind a station is allowed to fall in -+ * the virtual airtime domain. This limit is set to a relatively high value of -+ * 20 ms because the main mechanism for catching up idle stations is the active -+ * state as described above; i.e., the hard limit should only be hit in -+ * pathological cases. -+ */ -+#define AIRTIME_ACTIVE_DURATION (100 * NSEC_PER_MSEC) -+#define AIRTIME_MAX_BEHIND 20000 /* 20 ms */ -+ -+static inline bool airtime_is_active(struct airtime_info *air_info, u64 now) -+{ -+ return air_info->last_scheduled >= now - AIRTIME_ACTIVE_DURATION; -+} -+ -+static inline void airtime_set_active(struct airtime_sched_info *air_sched, -+ struct airtime_info *air_info, u64 now) -+{ -+ air_info->last_scheduled = now; -+ air_sched->last_schedule_activity = now; -+ list_move_tail(&air_info->list, &air_sched->active_list); -+} -+ -+static inline bool airtime_catchup_v_t(struct airtime_sched_info *air_sched, -+ u64 v_t, u64 now) -+{ -+ air_sched->v_t = v_t; -+ return true; -+} -+ -+static inline void init_airtime_info(struct airtime_info *air_info, -+ struct airtime_sched_info *air_sched) -+{ -+ atomic_set(&air_info->aql_tx_pending, 0); -+ air_info->aql_limit_low = air_sched->aql_txq_limit_low; -+ air_info->aql_limit_high = air_sched->aql_txq_limit_high; -+ airtime_weight_set(air_info, IEEE80211_DEFAULT_AIRTIME_WEIGHT); -+ INIT_LIST_HEAD(&air_info->list); -+} -+ - static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr) - { - return ether_addr_equal(raddr, addr) || -@@ -1821,6 +1971,14 @@ int ieee80211_tx_control_port(struct wip - u64 *cookie); - int ieee80211_probe_mesh_link(struct wiphy *wiphy, struct net_device *dev, - const u8 *buf, size_t len); -+void ieee80211_resort_txq(struct ieee80211_hw *hw, -+ struct ieee80211_txq *txq); -+void ieee80211_unschedule_txq(struct ieee80211_hw *hw, -+ struct ieee80211_txq *txq, -+ bool purge); -+void ieee80211_update_airtime_weight(struct ieee80211_local *local, -+ struct airtime_sched_info *air_sched, -+ u64 now, bool force); - - /* HT */ - void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, ---- a/net/mac80211/iface.c -+++ b/net/mac80211/iface.c -@@ -2067,6 +2067,9 @@ int ieee80211_if_add(struct ieee80211_lo - } - } - -+ for (i = 0; i < IEEE80211_NUM_ACS; i++) -+ init_airtime_info(&sdata->airtime[i], &local->airtime[i]); -+ - ieee80211_set_default_queues(sdata); - - sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL; ---- a/net/mac80211/main.c -+++ b/net/mac80211/main.c -@@ -693,10 +693,13 @@ struct ieee80211_hw *ieee80211_alloc_hw_ - spin_lock_init(&local->queue_stop_reason_lock); - - for (i = 0; i < IEEE80211_NUM_ACS; i++) { -- INIT_LIST_HEAD(&local->active_txqs[i]); -- spin_lock_init(&local->active_txq_lock[i]); -- local->aql_txq_limit_low[i] = IEEE80211_DEFAULT_AQL_TXQ_LIMIT_L; -- local->aql_txq_limit_high[i] = -+ struct airtime_sched_info *air_sched = &local->airtime[i]; -+ -+ air_sched->active_txqs = RB_ROOT_CACHED; -+ INIT_LIST_HEAD(&air_sched->active_list); -+ spin_lock_init(&air_sched->lock); -+ air_sched->aql_txq_limit_low = IEEE80211_DEFAULT_AQL_TXQ_LIMIT_L; -+ air_sched->aql_txq_limit_high = - IEEE80211_DEFAULT_AQL_TXQ_LIMIT_H; - } - ---- a/net/mac80211/rx.c -+++ b/net/mac80211/rx.c -@@ -1573,12 +1573,8 @@ static void sta_ps_start(struct sta_info - - for (tid = 0; tid < IEEE80211_NUM_TIDS; tid++) { - struct ieee80211_txq *txq = sta->sta.txq[tid]; -- struct txq_info *txqi = to_txq_info(txq); - -- spin_lock(&local->active_txq_lock[txq->ac]); -- if (!list_empty(&txqi->schedule_order)) -- list_del_init(&txqi->schedule_order); -- spin_unlock(&local->active_txq_lock[txq->ac]); -+ ieee80211_unschedule_txq(&local->hw, txq, false); - - if (txq_has_queue(txq)) - set_bit(tid, &sta->txq_buffered_tids); ---- a/net/mac80211/sta_info.c -+++ b/net/mac80211/sta_info.c -@@ -426,15 +426,11 @@ struct sta_info *sta_info_alloc(struct i - if (sta_prepare_rate_control(local, sta, gfp)) - goto free_txq; - -- sta->airtime_weight = IEEE80211_DEFAULT_AIRTIME_WEIGHT; - - for (i = 0; i < IEEE80211_NUM_ACS; i++) { - skb_queue_head_init(&sta->ps_tx_buf[i]); - skb_queue_head_init(&sta->tx_filtered[i]); -- sta->airtime[i].deficit = sta->airtime_weight; -- atomic_set(&sta->airtime[i].aql_tx_pending, 0); -- sta->airtime[i].aql_limit_low = local->aql_txq_limit_low[i]; -- sta->airtime[i].aql_limit_high = local->aql_txq_limit_high[i]; -+ init_airtime_info(&sta->airtime[i], &local->airtime[i]); - } - - for (i = 0; i < IEEE80211_NUM_TIDS; i++) -@@ -1898,24 +1894,59 @@ void ieee80211_sta_set_buffered(struct i - } - EXPORT_SYMBOL(ieee80211_sta_set_buffered); - --void ieee80211_sta_register_airtime(struct ieee80211_sta *pubsta, u8 tid, -- u32 tx_airtime, u32 rx_airtime) -+void ieee80211_register_airtime(struct ieee80211_txq *txq, -+ u32 tx_airtime, u32 rx_airtime) - { -- struct sta_info *sta = container_of(pubsta, struct sta_info, sta); -- struct ieee80211_local *local = sta->sdata->local; -- u8 ac = ieee80211_ac_from_tid(tid); -+ struct ieee80211_sub_if_data *sdata = vif_to_sdata(txq->vif); -+ struct ieee80211_local *local = sdata->local; -+ u64 weight_sum, weight_sum_reciprocal; -+ struct airtime_sched_info *air_sched; -+ struct airtime_info *air_info; - u32 airtime = 0; - -- if (sta->local->airtime_flags & AIRTIME_USE_TX) -+ air_sched = &local->airtime[txq->ac]; -+ air_info = to_airtime_info(txq); -+ -+ if (local->airtime_flags & AIRTIME_USE_TX) - airtime += tx_airtime; -- if (sta->local->airtime_flags & AIRTIME_USE_RX) -+ if (local->airtime_flags & AIRTIME_USE_RX) - airtime += rx_airtime; - -- spin_lock_bh(&local->active_txq_lock[ac]); -- sta->airtime[ac].tx_airtime += tx_airtime; -- sta->airtime[ac].rx_airtime += rx_airtime; -- sta->airtime[ac].deficit -= airtime; -- spin_unlock_bh(&local->active_txq_lock[ac]); -+ /* Weights scale so the unit weight is 256 */ -+ airtime <<= 8; -+ -+ spin_lock_bh(&air_sched->lock); -+ -+ air_info->tx_airtime += tx_airtime; -+ air_info->rx_airtime += rx_airtime; -+ -+ if (air_sched->weight_sum) { -+ weight_sum = air_sched->weight_sum; -+ weight_sum_reciprocal = air_sched->weight_sum_reciprocal; -+ } else { -+ weight_sum = air_info->weight; -+ weight_sum_reciprocal = air_info->weight_reciprocal; -+ } -+ -+ /* Round the calculation of global vt */ -+ air_sched->v_t += (u64)((airtime + (weight_sum >> 1)) * -+ weight_sum_reciprocal) >> IEEE80211_RECIPROCAL_SHIFT_64; -+ air_info->v_t += (u32)((airtime + (air_info->weight >> 1)) * -+ air_info->weight_reciprocal) >> IEEE80211_RECIPROCAL_SHIFT_32; -+ ieee80211_resort_txq(&local->hw, txq); -+ -+ spin_unlock_bh(&air_sched->lock); -+} -+ -+void ieee80211_sta_register_airtime(struct ieee80211_sta *pubsta, u8 tid, -+ u32 tx_airtime, u32 rx_airtime) -+{ -+ struct ieee80211_txq *txq = pubsta->txq[tid]; -+ -+ if (!txq) -+ return; -+ -+ ieee80211_register_airtime(txq, tx_airtime, rx_airtime); - } - EXPORT_SYMBOL(ieee80211_sta_register_airtime); - -@@ -2364,7 +2395,7 @@ void sta_set_sinfo(struct sta_info *sta, - } - - if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_AIRTIME_WEIGHT))) { -- sinfo->airtime_weight = sta->airtime_weight; -+ sinfo->airtime_weight = sta->airtime[0].weight; - sinfo->filled |= BIT_ULL(NL80211_STA_INFO_AIRTIME_WEIGHT); - } - ---- a/net/mac80211/sta_info.h -+++ b/net/mac80211/sta_info.h -@@ -135,18 +135,25 @@ enum ieee80211_agg_stop_reason { - #define AIRTIME_USE_TX BIT(0) - #define AIRTIME_USE_RX BIT(1) - -+ - struct airtime_info { - u64 rx_airtime; - u64 tx_airtime; -- s64 deficit; -+ u64 v_t; -+ u64 last_scheduled; -+ struct list_head list; - atomic_t aql_tx_pending; /* Estimated airtime for frames pending */ - u32 aql_limit_low; - u32 aql_limit_high; -+ u32 weight_reciprocal; -+ u16 weight; - }; - - void ieee80211_sta_update_pending_airtime(struct ieee80211_local *local, - struct sta_info *sta, u8 ac, - u16 tx_airtime, bool tx_completed); -+void ieee80211_register_airtime(struct ieee80211_txq *txq, -+ u32 tx_airtime, u32 rx_airtime); - - struct sta_info; - -@@ -515,7 +522,6 @@ struct ieee80211_fragment_cache { - * @tid_seq: per-TID sequence numbers for sending to this STA - * @airtime: per-AC struct airtime_info describing airtime statistics for this - * station -- * @airtime_weight: station weight for airtime fairness calculation purposes - * @ampdu_mlme: A-MPDU state machine state - * @mesh: mesh STA information - * @debugfs_dir: debug filesystem directory dentry -@@ -646,7 +652,6 @@ struct sta_info { - u16 tid_seq[IEEE80211_QOS_CTL_TID_MASK + 1]; - - struct airtime_info airtime[IEEE80211_NUM_ACS]; -- u16 airtime_weight; - - /* - * Aggregation information, locked with lock. ---- a/net/mac80211/status.c -+++ b/net/mac80211/status.c -@@ -972,6 +972,25 @@ static void __ieee80211_tx_status(struct - if (!(info->flags & IEEE80211_TX_CTL_INJECTED) && acked) - ieee80211_frame_acked(sta, skb); - -+ } else if (wiphy_ext_feature_isset(local->hw.wiphy, -+ NL80211_EXT_FEATURE_AIRTIME_FAIRNESS)) { -+ struct ieee80211_sub_if_data *sdata; -+ struct ieee80211_txq *txq; -+ u32 airtime; -+ -+ /* Account airtime to multicast queue */ -+ sdata = ieee80211_sdata_from_skb(local, skb); -+ -+ if (sdata && (txq = sdata->vif.txq)) { -+ airtime = info->status.tx_time ?: -+ ieee80211_calc_expected_tx_airtime(hw, -+ &sdata->vif, -+ NULL, -+ skb->len, -+ false); -+ -+ ieee80211_register_airtime(txq, airtime, 0); -+ } - } - - /* SNMP counters ---- a/net/mac80211/tx.c -+++ b/net/mac80211/tx.c -@@ -18,6 +18,7 @@ - #include <linux/bitmap.h> - #include <linux/rcupdate.h> - #include <linux/export.h> -+#include <linux/timekeeping.h> - #include <net/net_namespace.h> - #include <net/ieee80211_radiotap.h> - #include <net/cfg80211.h> -@@ -1489,7 +1490,7 @@ void ieee80211_txq_init(struct ieee80211 - codel_vars_init(&txqi->def_cvars); - codel_stats_init(&txqi->cstats); - __skb_queue_head_init(&txqi->frags); -- INIT_LIST_HEAD(&txqi->schedule_order); -+ RB_CLEAR_NODE(&txqi->schedule_order); - - txqi->txq.vif = &sdata->vif; - -@@ -1533,9 +1534,7 @@ void ieee80211_txq_purge(struct ieee8021 - ieee80211_purge_tx_queue(&local->hw, &txqi->frags); - spin_unlock_bh(&fq->lock); - -- spin_lock_bh(&local->active_txq_lock[txqi->txq.ac]); -- list_del_init(&txqi->schedule_order); -- spin_unlock_bh(&local->active_txq_lock[txqi->txq.ac]); -+ ieee80211_unschedule_txq(&local->hw, &txqi->txq, true); - } - - void ieee80211_txq_set_params(struct ieee80211_local *local) -@@ -3797,102 +3796,259 @@ EXPORT_SYMBOL(ieee80211_tx_dequeue); - struct ieee80211_txq *ieee80211_next_txq(struct ieee80211_hw *hw, u8 ac) - { - struct ieee80211_local *local = hw_to_local(hw); -+ struct airtime_sched_info *air_sched; -+ u64 now = ktime_get_boottime_ns(); - struct ieee80211_txq *ret = NULL; -- struct txq_info *txqi = NULL, *head = NULL; -- bool found_eligible_txq = false; -+ struct airtime_info *air_info; -+ struct txq_info *txqi = NULL; -+ struct rb_node *node; -+ bool first = false; - -- spin_lock_bh(&local->active_txq_lock[ac]); -+ air_sched = &local->airtime[ac]; -+ spin_lock_bh(&air_sched->lock); - -- begin: -- txqi = list_first_entry_or_null(&local->active_txqs[ac], -- struct txq_info, -- schedule_order); -- if (!txqi) -+ node = air_sched->schedule_pos; -+ -+begin: -+ if (!node) { -+ node = rb_first_cached(&air_sched->active_txqs); -+ first = true; -+ } else { -+ node = rb_next(node); -+ } -+ -+ if (!node) - goto out; - -- if (txqi == head) { -- if (!found_eligible_txq) -- goto out; -- else -- found_eligible_txq = false; -+ txqi = container_of(node, struct txq_info, schedule_order); -+ air_info = to_airtime_info(&txqi->txq); -+ -+ if (air_info->v_t > air_sched->v_t && -+ (!first || !airtime_catchup_v_t(air_sched, air_info->v_t, now))) -+ goto out; -+ -+ if (!ieee80211_txq_airtime_check(hw, &txqi->txq)) { -+ first = false; -+ goto begin; - } - -- if (!head) -- head = txqi; -+ air_sched->schedule_pos = node; -+ air_sched->last_schedule_activity = now; -+ ret = &txqi->txq; -+out: -+ spin_unlock_bh(&air_sched->lock); -+ return ret; -+} -+EXPORT_SYMBOL(ieee80211_next_txq); - -- if (txqi->txq.sta) { -- struct sta_info *sta = container_of(txqi->txq.sta, -- struct sta_info, sta); -- bool aql_check = ieee80211_txq_airtime_check(hw, &txqi->txq); -- s64 deficit = sta->airtime[txqi->txq.ac].deficit; -+static void __ieee80211_insert_txq(struct rb_root_cached *root, -+ struct txq_info *txqi) -+{ -+ struct rb_node **new = &root->rb_root.rb_node; -+ struct airtime_info *old_air, *new_air; -+ struct rb_node *parent = NULL; -+ struct txq_info *__txqi; -+ bool leftmost = true; -+ -+ while (*new) { -+ parent = *new; -+ __txqi = rb_entry(parent, struct txq_info, schedule_order); -+ old_air = to_airtime_info(&__txqi->txq); -+ new_air = to_airtime_info(&txqi->txq); - -- if (aql_check) -- found_eligible_txq = true; -+ if (new_air->v_t <= old_air->v_t) { -+ new = &parent->rb_left; -+ } else { -+ new = &parent->rb_right; -+ leftmost = false; -+ } -+ } - -- if (deficit < 0) -- sta->airtime[txqi->txq.ac].deficit += -- sta->airtime_weight; -- -- if (deficit < 0 || !aql_check) { -- list_move_tail(&txqi->schedule_order, -- &local->active_txqs[txqi->txq.ac]); -- goto begin; -+ rb_link_node(&txqi->schedule_order, parent, new); -+ rb_insert_color_cached(&txqi->schedule_order, root, leftmost); -+} -+ -+void ieee80211_resort_txq(struct ieee80211_hw *hw, -+ struct ieee80211_txq *txq) -+{ -+ struct airtime_info *air_info = to_airtime_info(txq); -+ struct ieee80211_local *local = hw_to_local(hw); -+ struct txq_info *txqi = to_txq_info(txq); -+ struct airtime_sched_info *air_sched; -+ -+ air_sched = &local->airtime[txq->ac]; -+ -+ lockdep_assert_held(&air_sched->lock); -+ -+ if (!RB_EMPTY_NODE(&txqi->schedule_order)) { -+ struct airtime_info *a_prev = NULL, *a_next = NULL; -+ struct txq_info *t_prev, *t_next; -+ struct rb_node *n_prev, *n_next; -+ -+ /* Erasing a node can cause an expensive rebalancing operation, -+ * so we check the previous and next nodes first and only remove -+ * and re-insert if the current node is not already in the -+ * correct position. -+ */ -+ if ((n_prev = rb_prev(&txqi->schedule_order)) != NULL) { -+ t_prev = container_of(n_prev, struct txq_info, -+ schedule_order); -+ a_prev = to_airtime_info(&t_prev->txq); -+ } -+ -+ if ((n_next = rb_next(&txqi->schedule_order)) != NULL) { -+ t_next = container_of(n_next, struct txq_info, -+ schedule_order); -+ a_next = to_airtime_info(&t_next->txq); - } -+ -+ if ((!a_prev || a_prev->v_t <= air_info->v_t) && -+ (!a_next || a_next->v_t > air_info->v_t)) -+ return; -+ -+ if (air_sched->schedule_pos == &txqi->schedule_order) -+ air_sched->schedule_pos = n_prev; -+ -+ rb_erase_cached(&txqi->schedule_order, -+ &air_sched->active_txqs); -+ RB_CLEAR_NODE(&txqi->schedule_order); -+ __ieee80211_insert_txq(&air_sched->active_txqs, txqi); - } -+} -+ -+void ieee80211_update_airtime_weight(struct ieee80211_local *local, -+ struct airtime_sched_info *air_sched, -+ u64 now, bool force) -+{ -+ struct airtime_info *air_info, *tmp; -+ u64 weight_sum = 0; -+ -+ if (unlikely(!now)) -+ now = ktime_get_boottime_ns(); -+ -+ lockdep_assert_held(&air_sched->lock); -+ -+ if (!force && (air_sched->last_weight_update < -+ now - AIRTIME_ACTIVE_DURATION)) -+ return; -+ -+ list_for_each_entry_safe(air_info, tmp, -+ &air_sched->active_list, list) { -+ if (airtime_is_active(air_info, now)) -+ weight_sum += air_info->weight; -+ else -+ list_del_init(&air_info->list); -+ } -+ airtime_weight_sum_set(air_sched, weight_sum); -+ air_sched->last_weight_update = now; -+} - -+void ieee80211_schedule_txq(struct ieee80211_hw *hw, -+ struct ieee80211_txq *txq) -+ __acquires(txq_lock) __releases(txq_lock) -+{ -+ struct ieee80211_local *local = hw_to_local(hw); -+ struct txq_info *txqi = to_txq_info(txq); -+ struct airtime_sched_info *air_sched; -+ u64 now = ktime_get_boottime_ns(); -+ struct airtime_info *air_info; -+ u8 ac = txq->ac; -+ bool was_active; - -- if (txqi->schedule_round == local->schedule_round[ac]) -+ air_sched = &local->airtime[ac]; -+ air_info = to_airtime_info(txq); -+ -+ spin_lock_bh(&air_sched->lock); -+ was_active = airtime_is_active(air_info, now); -+ airtime_set_active(air_sched, air_info, now); -+ -+ if (!RB_EMPTY_NODE(&txqi->schedule_order)) - goto out; - -- list_del_init(&txqi->schedule_order); -- txqi->schedule_round = local->schedule_round[ac]; -- ret = &txqi->txq; -+ /* If the station has been inactive for a while, catch up its v_t so it -+ * doesn't get indefinite priority; see comment above the definition of -+ * AIRTIME_MAX_BEHIND. -+ */ -+ if ((!was_active && air_info->v_t < air_sched->v_t) || -+ air_info->v_t < air_sched->v_t - AIRTIME_MAX_BEHIND) -+ air_info->v_t = air_sched->v_t; -+ -+ ieee80211_update_airtime_weight(local, air_sched, now, !was_active); -+ __ieee80211_insert_txq(&air_sched->active_txqs, txqi); - - out: -- spin_unlock_bh(&local->active_txq_lock[ac]); -- return ret; -+ spin_unlock_bh(&air_sched->lock); - } --EXPORT_SYMBOL(ieee80211_next_txq); -+EXPORT_SYMBOL(ieee80211_schedule_txq); - --void __ieee80211_schedule_txq(struct ieee80211_hw *hw, -- struct ieee80211_txq *txq, -- bool force) -+static void __ieee80211_unschedule_txq(struct ieee80211_hw *hw, -+ struct ieee80211_txq *txq, -+ bool purge) - { - struct ieee80211_local *local = hw_to_local(hw); - struct txq_info *txqi = to_txq_info(txq); -+ struct airtime_sched_info *air_sched; -+ struct airtime_info *air_info; - -- spin_lock_bh(&local->active_txq_lock[txq->ac]); -+ air_sched = &local->airtime[txq->ac]; -+ air_info = to_airtime_info(&txqi->txq); - -- if (list_empty(&txqi->schedule_order) && -- (force || !skb_queue_empty(&txqi->frags) || -- txqi->tin.backlog_packets)) { -- /* If airtime accounting is active, always enqueue STAs at the -- * head of the list to ensure that they only get moved to the -- * back by the airtime DRR scheduler once they have a negative -- * deficit. A station that already has a negative deficit will -- * get immediately moved to the back of the list on the next -- * call to ieee80211_next_txq(). -- */ -- if (txqi->txq.sta && local->airtime_flags && -- wiphy_ext_feature_isset(local->hw.wiphy, -- NL80211_EXT_FEATURE_AIRTIME_FAIRNESS)) -- list_add(&txqi->schedule_order, -- &local->active_txqs[txq->ac]); -- else -- list_add_tail(&txqi->schedule_order, -- &local->active_txqs[txq->ac]); -+ lockdep_assert_held(&air_sched->lock); -+ -+ if (purge) { -+ list_del_init(&air_info->list); -+ ieee80211_update_airtime_weight(local, air_sched, 0, true); - } - -- spin_unlock_bh(&local->active_txq_lock[txq->ac]); -+ if (RB_EMPTY_NODE(&txqi->schedule_order)) -+ return; -+ -+ if (air_sched->schedule_pos == &txqi->schedule_order) -+ air_sched->schedule_pos = rb_prev(&txqi->schedule_order); -+ -+ if (!purge) -+ airtime_set_active(air_sched, air_info, -+ ktime_get_boottime_ns()); -+ -+ rb_erase_cached(&txqi->schedule_order, -+ &air_sched->active_txqs); -+ RB_CLEAR_NODE(&txqi->schedule_order); -+} -+ -+void ieee80211_unschedule_txq(struct ieee80211_hw *hw, -+ struct ieee80211_txq *txq, -+ bool purge) -+ __acquires(txq_lock) __releases(txq_lock) -+{ -+ struct ieee80211_local *local = hw_to_local(hw); -+ -+ spin_lock_bh(&local->airtime[txq->ac].lock); -+ __ieee80211_unschedule_txq(hw, txq, purge); -+ spin_unlock_bh(&local->airtime[txq->ac].lock); -+} -+ -+void ieee80211_return_txq(struct ieee80211_hw *hw, -+ struct ieee80211_txq *txq, bool force) -+{ -+ struct ieee80211_local *local = hw_to_local(hw); -+ struct txq_info *txqi = to_txq_info(txq); -+ -+ spin_lock_bh(&local->airtime[txq->ac].lock); -+ -+ if (!RB_EMPTY_NODE(&txqi->schedule_order) && !force && -+ !txq_has_queue(txq)) -+ __ieee80211_unschedule_txq(hw, txq, false); -+ -+ spin_unlock_bh(&local->airtime[txq->ac].lock); - } --EXPORT_SYMBOL(__ieee80211_schedule_txq); -+EXPORT_SYMBOL(ieee80211_return_txq); - - DEFINE_STATIC_KEY_FALSE(aql_disable); - - bool ieee80211_txq_airtime_check(struct ieee80211_hw *hw, - struct ieee80211_txq *txq) - { -- struct sta_info *sta; -+ struct airtime_info *air_info = to_airtime_info(txq); - struct ieee80211_local *local = hw_to_local(hw); - - if (!wiphy_ext_feature_isset(local->hw.wiphy, NL80211_EXT_FEATURE_AQL)) -@@ -3907,15 +4063,12 @@ bool ieee80211_txq_airtime_check(struct - if (unlikely(txq->tid == IEEE80211_NUM_TIDS)) - return true; - -- sta = container_of(txq->sta, struct sta_info, sta); -- if (atomic_read(&sta->airtime[txq->ac].aql_tx_pending) < -- sta->airtime[txq->ac].aql_limit_low) -+ if (atomic_read(&air_info->aql_tx_pending) < air_info->aql_limit_low) - return true; - - if (atomic_read(&local->aql_total_pending_airtime) < - local->aql_threshold && -- atomic_read(&sta->airtime[txq->ac].aql_tx_pending) < -- sta->airtime[txq->ac].aql_limit_high) -+ atomic_read(&air_info->aql_tx_pending) < air_info->aql_limit_high) - return true; - - return false; -@@ -3925,60 +4078,59 @@ EXPORT_SYMBOL(ieee80211_txq_airtime_chec - bool ieee80211_txq_may_transmit(struct ieee80211_hw *hw, - struct ieee80211_txq *txq) - { -+ struct txq_info *first_txqi = NULL, *txqi = to_txq_info(txq); - struct ieee80211_local *local = hw_to_local(hw); -- struct txq_info *iter, *tmp, *txqi = to_txq_info(txq); -- struct sta_info *sta; -- u8 ac = txq->ac; -+ struct airtime_sched_info *air_sched; -+ struct airtime_info *air_info; -+ struct rb_node *node = NULL; -+ bool ret = false; -+ u64 now; - -- spin_lock_bh(&local->active_txq_lock[ac]); - -- if (!txqi->txq.sta) -- goto out; -+ if (!ieee80211_txq_airtime_check(hw, txq)) -+ return false; -+ -+ air_sched = &local->airtime[txq->ac]; -+ spin_lock_bh(&air_sched->lock); - -- if (list_empty(&txqi->schedule_order)) -+ if (RB_EMPTY_NODE(&txqi->schedule_order)) - goto out; - -- list_for_each_entry_safe(iter, tmp, &local->active_txqs[ac], -- schedule_order) { -- if (iter == txqi) -- break; -+ now = ktime_get_boottime_ns(); - -- if (!iter->txq.sta) { -- list_move_tail(&iter->schedule_order, -- &local->active_txqs[ac]); -- continue; -- } -- sta = container_of(iter->txq.sta, struct sta_info, sta); -- if (sta->airtime[ac].deficit < 0) -- sta->airtime[ac].deficit += sta->airtime_weight; -- list_move_tail(&iter->schedule_order, &local->active_txqs[ac]); -+ /* Like in ieee80211_next_txq(), make sure the first station in the -+ * scheduling order is eligible for transmission to avoid starvation. -+ */ -+ node = rb_first_cached(&air_sched->active_txqs); -+ if (node) { -+ first_txqi = container_of(node, struct txq_info, -+ schedule_order); -+ air_info = to_airtime_info(&first_txqi->txq); -+ -+ if (air_sched->v_t < air_info->v_t) -+ airtime_catchup_v_t(air_sched, air_info->v_t, now); - } - -- sta = container_of(txqi->txq.sta, struct sta_info, sta); -- if (sta->airtime[ac].deficit >= 0) -- goto out; -- -- sta->airtime[ac].deficit += sta->airtime_weight; -- list_move_tail(&txqi->schedule_order, &local->active_txqs[ac]); -- spin_unlock_bh(&local->active_txq_lock[ac]); -+ air_info = to_airtime_info(&txqi->txq); -+ if (air_info->v_t <= air_sched->v_t) { -+ air_sched->last_schedule_activity = now; -+ ret = true; -+ } - -- return false; - out: -- if (!list_empty(&txqi->schedule_order)) -- list_del_init(&txqi->schedule_order); -- spin_unlock_bh(&local->active_txq_lock[ac]); -- -- return true; -+ spin_unlock_bh(&air_sched->lock); -+ return ret; - } - EXPORT_SYMBOL(ieee80211_txq_may_transmit); - - void ieee80211_txq_schedule_start(struct ieee80211_hw *hw, u8 ac) - { - struct ieee80211_local *local = hw_to_local(hw); -+ struct airtime_sched_info *air_sched = &local->airtime[ac]; - -- spin_lock_bh(&local->active_txq_lock[ac]); -- local->schedule_round[ac]++; -- spin_unlock_bh(&local->active_txq_lock[ac]); -+ spin_lock_bh(&air_sched->lock); -+ air_sched->schedule_pos = NULL; -+ spin_unlock_bh(&air_sched->lock); - } - EXPORT_SYMBOL(ieee80211_txq_schedule_start); - diff --git a/package/kernel/mac80211/patches/subsys/383-mac80211-fix-enabling-4-address-mode-on-a-sta-vif-af.patch b/package/kernel/mac80211/patches/subsys/383-mac80211-fix-enabling-4-address-mode-on-a-sta-vif-af.patch deleted file mode 100644 index 5a82f00c9e7..00000000000 --- a/package/kernel/mac80211/patches/subsys/383-mac80211-fix-enabling-4-address-mode-on-a-sta-vif-af.patch +++ /dev/null @@ -1,72 +0,0 @@ -From: Felix Fietkau <nbd@nbd.name> -Date: Fri, 2 Jul 2021 06:57:53 +0200 -Subject: [PATCH] mac80211: fix enabling 4-address mode on a sta vif after - assoc - -Notify the driver about the 4-address mode change and also send a nulldata -packet to the AP to notify it about the change - -Fixes: 1ff4e8f2dec8 ("mac80211: notify the driver when a sta uses 4-address mode") -Signed-off-by: Felix Fietkau <nbd@nbd.name> ---- - ---- a/net/mac80211/cfg.c -+++ b/net/mac80211/cfg.c -@@ -152,6 +152,8 @@ static int ieee80211_change_iface(struct - struct vif_params *params) - { - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); -+ struct ieee80211_local *local = sdata->local; -+ struct sta_info *sta; - int ret; - - ret = ieee80211_if_change_type(sdata, type); -@@ -162,7 +164,24 @@ static int ieee80211_change_iface(struct - RCU_INIT_POINTER(sdata->u.vlan.sta, NULL); - ieee80211_check_fast_rx_iface(sdata); - } else if (type == NL80211_IFTYPE_STATION && params->use_4addr >= 0) { -+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; -+ -+ if (params->use_4addr == ifmgd->use_4addr) -+ return 0; -+ - sdata->u.mgd.use_4addr = params->use_4addr; -+ if (!ifmgd->associated) -+ return 0; -+ -+ mutex_lock(&local->sta_mtx); -+ sta = sta_info_get(sdata, ifmgd->bssid); -+ if (sta) -+ drv_sta_set_4addr(local, sdata, &sta->sta, -+ params->use_4addr); -+ mutex_unlock(&local->sta_mtx); -+ -+ if (params->use_4addr) -+ ieee80211_send_4addr_nullfunc(local, sdata); - } - - if (sdata->vif.type == NL80211_IFTYPE_MONITOR) { ---- a/net/mac80211/ieee80211_i.h -+++ b/net/mac80211/ieee80211_i.h -@@ -2224,6 +2224,8 @@ void ieee80211_dynamic_ps_timer(struct t - void ieee80211_send_nullfunc(struct ieee80211_local *local, - struct ieee80211_sub_if_data *sdata, - bool powersave); -+void ieee80211_send_4addr_nullfunc(struct ieee80211_local *local, -+ struct ieee80211_sub_if_data *sdata); - void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata, - struct ieee80211_hdr *hdr, bool ack, u16 tx_time); - ---- a/net/mac80211/mlme.c -+++ b/net/mac80211/mlme.c -@@ -1115,8 +1115,8 @@ void ieee80211_send_nullfunc(struct ieee - ieee80211_tx_skb(sdata, skb); - } - --static void ieee80211_send_4addr_nullfunc(struct ieee80211_local *local, -- struct ieee80211_sub_if_data *sdata) -+void ieee80211_send_4addr_nullfunc(struct ieee80211_local *local, -+ struct ieee80211_sub_if_data *sdata) - { - struct sk_buff *skb; - struct ieee80211_hdr *nullfunc; diff --git a/package/kernel/mac80211/patches/subsys/384-nl80211-add-common-API-to-configure-SAR-power-limita.patch b/package/kernel/mac80211/patches/subsys/384-nl80211-add-common-API-to-configure-SAR-power-limita.patch deleted file mode 100644 index 0c9ae3595d8..00000000000 --- a/package/kernel/mac80211/patches/subsys/384-nl80211-add-common-API-to-configure-SAR-power-limita.patch +++ /dev/null @@ -1,398 +0,0 @@ -From: Carl Huang <cjhuang@codeaurora.org> -Date: Thu, 3 Dec 2020 05:37:26 -0500 -Subject: [PATCH] nl80211: add common API to configure SAR power limitations - -NL80211_CMD_SET_SAR_SPECS is added to configure SAR from -user space. NL80211_ATTR_SAR_SPEC is used to pass the SAR -power specification when used with NL80211_CMD_SET_SAR_SPECS. - -Wireless driver needs to register SAR type, supported frequency -ranges to wiphy, so user space can query it. The index in -frequency range is used to specify which sub band the power -limitation applies to. The SAR type is for compatibility, so later -other SAR mechanism can be implemented without breaking the user -space SAR applications. - -Normal process is user space queries the SAR capability, and -gets the index of supported frequency ranges and associates the -power limitation with this index and sends to kernel. - -Here is an example of message send to kernel: -8c 00 00 00 08 00 01 00 00 00 00 00 38 00 2b 81 -08 00 01 00 00 00 00 00 2c 00 02 80 14 00 00 80 -08 00 02 00 00 00 00 00 08 00 01 00 38 00 00 00 -14 00 01 80 08 00 02 00 01 00 00 00 08 00 01 00 -48 00 00 00 - -NL80211_CMD_SET_SAR_SPECS: 0x8c -NL80211_ATTR_WIPHY: 0x01(phy idx is 0) -NL80211_ATTR_SAR_SPEC: 0x812b (NLA_NESTED) -NL80211_SAR_ATTR_TYPE: 0x00 (NL80211_SAR_TYPE_POWER) -NL80211_SAR_ATTR_SPECS: 0x8002 (NLA_NESTED) -freq range 0 power: 0x38 in 0.25dbm unit (14dbm) -freq range 1 power: 0x48 in 0.25dbm unit (18dbm) - -Signed-off-by: Carl Huang <cjhuang@codeaurora.org> -Reviewed-by: Brian Norris <briannorris@chromium.org> -Reviewed-by: Abhishek Kumar <kuabhs@chromium.org> -Link: https://lore.kernel.org/r/20201203103728.3034-2-cjhuang@codeaurora.org -[minor edits, NLA parse cleanups] -Signed-off-by: Johannes Berg <johannes.berg@intel.com> ---- - ---- a/include/net/cfg80211.h -+++ b/include/net/cfg80211.h -@@ -1737,6 +1737,54 @@ struct station_info { - u8 connected_to_as; - }; - -+/** -+ * struct cfg80211_sar_sub_specs - sub specs limit -+ * @power: power limitation in 0.25dbm -+ * @freq_range_index: index the power limitation applies to -+ */ -+struct cfg80211_sar_sub_specs { -+ s32 power; -+ u32 freq_range_index; -+}; -+ -+/** -+ * struct cfg80211_sar_specs - sar limit specs -+ * @type: it's set with power in 0.25dbm or other types -+ * @num_sub_specs: number of sar sub specs -+ * @sub_specs: memory to hold the sar sub specs -+ */ -+struct cfg80211_sar_specs { -+ enum nl80211_sar_type type; -+ u32 num_sub_specs; -+ struct cfg80211_sar_sub_specs sub_specs[]; -+}; -+ -+ -+/** -+ * @struct cfg80211_sar_chan_ranges - sar frequency ranges -+ * @start_freq: start range edge frequency -+ * @end_freq: end range edge frequency -+ */ -+struct cfg80211_sar_freq_ranges { -+ u32 start_freq; -+ u32 end_freq; -+}; -+ -+/** -+ * struct cfg80211_sar_capa - sar limit capability -+ * @type: it's set via power in 0.25dbm or other types -+ * @num_freq_ranges: number of frequency ranges -+ * @freq_ranges: memory to hold the freq ranges. -+ * -+ * Note: WLAN driver may append new ranges or split an existing -+ * range to small ones and then append them. -+ */ -+struct cfg80211_sar_capa { -+ enum nl80211_sar_type type; -+ u32 num_freq_ranges; -+ const struct cfg80211_sar_freq_ranges *freq_ranges; -+}; -+ - #if IS_ENABLED(CPTCFG_CFG80211) - /** - * cfg80211_get_station - retrieve information about a given station -@@ -4259,6 +4307,8 @@ struct cfg80211_ops { - struct cfg80211_tid_config *tid_conf); - int (*reset_tid_config)(struct wiphy *wiphy, struct net_device *dev, - const u8 *peer, u8 tids); -+ int (*set_sar_specs)(struct wiphy *wiphy, -+ struct cfg80211_sar_specs *sar); - }; - - /* -@@ -5030,6 +5080,8 @@ struct wiphy { - - u8 max_data_retry_count; - -+ const struct cfg80211_sar_capa *sar_capa; -+ - char priv[] __aligned(NETDEV_ALIGN); - }; - ---- a/net/wireless/nl80211.c -+++ b/net/wireless/nl80211.c -@@ -405,6 +405,18 @@ nl80211_unsol_bcast_probe_resp_policy[NL - .len = IEEE80211_MAX_DATA_LEN } - }; - -+static const struct nla_policy -+sar_specs_policy[NL80211_SAR_ATTR_SPECS_MAX + 1] = { -+ [NL80211_SAR_ATTR_SPECS_POWER] = { .type = NLA_S32 }, -+ [NL80211_SAR_ATTR_SPECS_RANGE_INDEX] = {.type = NLA_U32 }, -+}; -+ -+static const struct nla_policy -+sar_policy[NL80211_SAR_ATTR_MAX + 1] = { -+ [NL80211_SAR_ATTR_TYPE] = NLA_POLICY_MAX(NLA_U32, NUM_NL80211_SAR_TYPE), -+ [NL80211_SAR_ATTR_SPECS] = NLA_POLICY_NESTED_ARRAY(sar_specs_policy), -+}; -+ - static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { - [0] = { .strict_start_type = NL80211_ATTR_HE_OBSS_PD }, - [NL80211_ATTR_WIPHY] = { .type = NLA_U32 }, -@@ -739,6 +751,7 @@ static const struct nla_policy nl80211_p - [NL80211_ATTR_SAE_PWE] = - NLA_POLICY_RANGE(NLA_U8, NL80211_SAE_PWE_HUNT_AND_PECK, - NL80211_SAE_PWE_BOTH), -+ [NL80211_ATTR_SAR_SPEC] = NLA_POLICY_NESTED(sar_policy), - [NL80211_ATTR_RECONNECT_REQUESTED] = { .type = NLA_REJECT }, - }; - -@@ -2117,6 +2130,56 @@ fail: - return -ENOBUFS; - } - -+static int -+nl80211_put_sar_specs(struct cfg80211_registered_device *rdev, -+ struct sk_buff *msg) -+{ -+ struct nlattr *sar_capa, *specs, *sub_freq_range; -+ u8 num_freq_ranges; -+ int i; -+ -+ if (!rdev->wiphy.sar_capa) -+ return 0; -+ -+ num_freq_ranges = rdev->wiphy.sar_capa->num_freq_ranges; -+ -+ sar_capa = nla_nest_start(msg, NL80211_ATTR_SAR_SPEC); -+ if (!sar_capa) -+ return -ENOSPC; -+ -+ if (nla_put_u32(msg, NL80211_SAR_ATTR_TYPE, rdev->wiphy.sar_capa->type)) -+ goto fail; -+ -+ specs = nla_nest_start(msg, NL80211_SAR_ATTR_SPECS); -+ if (!specs) -+ goto fail; -+ -+ /* report supported freq_ranges */ -+ for (i = 0; i < num_freq_ranges; i++) { -+ sub_freq_range = nla_nest_start(msg, i + 1); -+ if (!sub_freq_range) -+ goto fail; -+ -+ if (nla_put_u32(msg, NL80211_SAR_ATTR_SPECS_START_FREQ, -+ rdev->wiphy.sar_capa->freq_ranges[i].start_freq)) -+ goto fail; -+ -+ if (nla_put_u32(msg, NL80211_SAR_ATTR_SPECS_END_FREQ, -+ rdev->wiphy.sar_capa->freq_ranges[i].end_freq)) -+ goto fail; -+ -+ nla_nest_end(msg, sub_freq_range); -+ } -+ -+ nla_nest_end(msg, specs); -+ nla_nest_end(msg, sar_capa); -+ -+ return 0; -+fail: -+ nla_nest_cancel(msg, sar_capa); -+ return -ENOBUFS; -+} -+ - struct nl80211_dump_wiphy_state { - s64 filter_wiphy; - long start; -@@ -2366,6 +2429,8 @@ static int nl80211_send_wiphy(struct cfg - CMD(set_multicast_to_unicast, SET_MULTICAST_TO_UNICAST); - CMD(update_connect_params, UPDATE_CONNECT_PARAMS); - CMD(update_ft_ies, UPDATE_FT_IES); -+ if (rdev->wiphy.sar_capa) -+ CMD(set_sar_specs, SET_SAR_SPECS); - } - #undef CMD - -@@ -2691,6 +2756,11 @@ static int nl80211_send_wiphy(struct cfg - - if (nl80211_put_tid_config_support(rdev, msg)) - goto nla_put_failure; -+ state->split_start++; -+ break; -+ case 16: -+ if (nl80211_put_sar_specs(rdev, msg)) -+ goto nla_put_failure; - - /* done */ - state->split_start = 0; -@@ -14713,6 +14783,111 @@ static void nl80211_post_doit(__genl_con - } - } - -+static int nl80211_set_sar_sub_specs(struct cfg80211_registered_device *rdev, -+ struct cfg80211_sar_specs *sar_specs, -+ struct nlattr *spec[], int index) -+{ -+ u32 range_index, i; -+ -+ if (!sar_specs || !spec) -+ return -EINVAL; -+ -+ if (!spec[NL80211_SAR_ATTR_SPECS_POWER] || -+ !spec[NL80211_SAR_ATTR_SPECS_RANGE_INDEX]) -+ return -EINVAL; -+ -+ range_index = nla_get_u32(spec[NL80211_SAR_ATTR_SPECS_RANGE_INDEX]); -+ -+ /* check if range_index exceeds num_freq_ranges */ -+ if (range_index >= rdev->wiphy.sar_capa->num_freq_ranges) -+ return -EINVAL; -+ -+ /* check if range_index duplicates */ -+ for (i = 0; i < index; i++) { -+ if (sar_specs->sub_specs[i].freq_range_index == range_index) -+ return -EINVAL; -+ } -+ -+ sar_specs->sub_specs[index].power = -+ nla_get_s32(spec[NL80211_SAR_ATTR_SPECS_POWER]); -+ -+ sar_specs->sub_specs[index].freq_range_index = range_index; -+ -+ return 0; -+} -+ -+static int nl80211_set_sar_specs(struct sk_buff *skb, struct genl_info *info) -+{ -+ struct cfg80211_registered_device *rdev = info->user_ptr[0]; -+ struct nlattr *spec[NL80211_SAR_ATTR_SPECS_MAX + 1]; -+ struct nlattr *tb[NL80211_SAR_ATTR_MAX + 1]; -+ struct cfg80211_sar_specs *sar_spec; -+ enum nl80211_sar_type type; -+ struct nlattr *spec_list; -+ u32 specs; -+ int rem, err; -+ -+ if (!rdev->wiphy.sar_capa || !rdev->ops->set_sar_specs) -+ return -EOPNOTSUPP; -+ -+ if (!info->attrs[NL80211_ATTR_SAR_SPEC]) -+ return -EINVAL; -+ -+ nla_parse_nested(tb, NL80211_SAR_ATTR_MAX, -+ info->attrs[NL80211_ATTR_SAR_SPEC], -+ NULL, NULL); -+ -+ if (!tb[NL80211_SAR_ATTR_TYPE] || !tb[NL80211_SAR_ATTR_SPECS]) -+ return -EINVAL; -+ -+ type = nla_get_u32(tb[NL80211_SAR_ATTR_TYPE]); -+ if (type != rdev->wiphy.sar_capa->type) -+ return -EINVAL; -+ -+ specs = 0; -+ nla_for_each_nested(spec_list, tb[NL80211_SAR_ATTR_SPECS], rem) -+ specs++; -+ -+ if (specs > rdev->wiphy.sar_capa->num_freq_ranges) -+ return -EINVAL; -+ -+ sar_spec = kzalloc(sizeof(*sar_spec) + -+ specs * sizeof(struct cfg80211_sar_sub_specs), -+ GFP_KERNEL); -+ if (!sar_spec) -+ return -ENOMEM; -+ -+ sar_spec->type = type; -+ specs = 0; -+ nla_for_each_nested(spec_list, tb[NL80211_SAR_ATTR_SPECS], rem) { -+ nla_parse_nested(spec, NL80211_SAR_ATTR_SPECS_MAX, -+ spec_list, NULL, NULL); -+ -+ switch (type) { -+ case NL80211_SAR_TYPE_POWER: -+ if (nl80211_set_sar_sub_specs(rdev, sar_spec, -+ spec, specs)) { -+ err = -EINVAL; -+ goto error; -+ } -+ break; -+ default: -+ err = -EINVAL; -+ goto error; -+ } -+ specs++; -+ } -+ -+ sar_spec->num_sub_specs = specs; -+ -+ rdev->cur_cmd_info = info; -+ err = rdev_set_sar_specs(rdev, sar_spec); -+ rdev->cur_cmd_info = NULL; -+error: -+ kfree(sar_spec); -+ return err; -+} -+ - static __genl_const struct genl_ops nl80211_ops[] = { - { - .cmd = NL80211_CMD_GET_WIPHY, -@@ -15576,6 +15751,14 @@ static const struct genl_small_ops nl802 - .internal_flags = NL80211_FLAG_NEED_NETDEV | - NL80211_FLAG_NEED_RTNL, - }, -+ { -+ .cmd = NL80211_CMD_SET_SAR_SPECS, -+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, -+ .doit = nl80211_set_sar_specs, -+ .flags = GENL_UNS_ADMIN_PERM, -+ .internal_flags = NL80211_FLAG_NEED_WIPHY | -+ NL80211_FLAG_NEED_RTNL, -+ }, - }; - - static struct genl_family nl80211_fam __genl_ro_after_init = { ---- a/net/wireless/rdev-ops.h -+++ b/net/wireless/rdev-ops.h -@@ -1356,4 +1356,16 @@ static inline int rdev_reset_tid_config( - return ret; - } - -+static inline int rdev_set_sar_specs(struct cfg80211_registered_device *rdev, -+ struct cfg80211_sar_specs *sar) -+{ -+ int ret; -+ -+ trace_rdev_set_sar_specs(&rdev->wiphy, sar); -+ ret = rdev->ops->set_sar_specs(&rdev->wiphy, sar); -+ trace_rdev_return_int(&rdev->wiphy, ret); -+ -+ return ret; -+} -+ - #endif /* __CFG80211_RDEV_OPS */ ---- a/net/wireless/trace.h -+++ b/net/wireless/trace.h -@@ -3551,6 +3551,25 @@ TRACE_EVENT(rdev_reset_tid_config, - TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", peer: " MAC_PR_FMT ", tids: 0x%x", - WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer), __entry->tids) - ); -+ -+TRACE_EVENT(rdev_set_sar_specs, -+ TP_PROTO(struct wiphy *wiphy, struct cfg80211_sar_specs *sar), -+ TP_ARGS(wiphy, sar), -+ TP_STRUCT__entry( -+ WIPHY_ENTRY -+ __field(u16, type) -+ __field(u16, num) -+ ), -+ TP_fast_assign( -+ WIPHY_ASSIGN; -+ __entry->type = sar->type; -+ __entry->num = sar->num_sub_specs; -+ -+ ), -+ TP_printk(WIPHY_PR_FMT ", Set type:%d, num_specs:%d", -+ WIPHY_PR_ARG, __entry->type, __entry->num) -+); -+ - #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */ - - #undef TRACE_INCLUDE_PATH diff --git a/package/kernel/mac80211/patches/subsys/385-mac80211-add-ieee80211_set_sar_specs.patch b/package/kernel/mac80211/patches/subsys/385-mac80211-add-ieee80211_set_sar_specs.patch deleted file mode 100644 index c351bc812a2..00000000000 --- a/package/kernel/mac80211/patches/subsys/385-mac80211-add-ieee80211_set_sar_specs.patch +++ /dev/null @@ -1,51 +0,0 @@ -From: Carl Huang <cjhuang@codeaurora.org> -Date: Thu, 3 Dec 2020 05:37:27 -0500 -Subject: [PATCH] mac80211: add ieee80211_set_sar_specs - -This change registers ieee80211_set_sar_specs to -mac80211_config_ops, so cfg80211 can call it. - -Signed-off-by: Carl Huang <cjhuang@codeaurora.org> -Reviewed-by: Brian Norris <briannorris@chromium.org> -Reviewed-by: Abhishek Kumar <kuabhs@chromium.org> -Link: https://lore.kernel.org/r/20201203103728.3034-3-cjhuang@codeaurora.org -Signed-off-by: Johannes Berg <johannes.berg@intel.com> ---- - ---- a/include/net/mac80211.h -+++ b/include/net/mac80211.h -@@ -4207,6 +4207,8 @@ struct ieee80211_ops { - struct ieee80211_vif *vif); - void (*sta_set_4addr)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, bool enabled); -+ int (*set_sar_specs)(struct ieee80211_hw *hw, -+ const struct cfg80211_sar_specs *sar); - void (*sta_set_decap_offload)(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, bool enabled); ---- a/net/mac80211/cfg.c -+++ b/net/mac80211/cfg.c -@@ -4136,6 +4136,17 @@ static int ieee80211_reset_tid_config(st - return ret; - } - -+static int ieee80211_set_sar_specs(struct wiphy *wiphy, -+ struct cfg80211_sar_specs *sar) -+{ -+ struct ieee80211_local *local = wiphy_priv(wiphy); -+ -+ if (!local->ops->set_sar_specs) -+ return -EOPNOTSUPP; -+ -+ return local->ops->set_sar_specs(&local->hw, sar); -+} -+ - const struct cfg80211_ops mac80211_config_ops = { - .add_virtual_intf = ieee80211_add_iface, - .del_virtual_intf = ieee80211_del_iface, -@@ -4239,4 +4250,5 @@ const struct cfg80211_ops mac80211_confi - .probe_mesh_link = ieee80211_probe_mesh_link, - .set_tid_config = ieee80211_set_tid_config, - .reset_tid_config = ieee80211_reset_tid_config, -+ .set_sar_specs = ieee80211_set_sar_specs, - }; diff --git a/package/kernel/mac80211/patches/subsys/400-allow-ibss-mixed.patch b/package/kernel/mac80211/patches/subsys/400-allow-ibss-mixed.patch index f9c4caa51c8..ad24dfda5a7 100644 --- a/package/kernel/mac80211/patches/subsys/400-allow-ibss-mixed.patch +++ b/package/kernel/mac80211/patches/subsys/400-allow-ibss-mixed.patch @@ -1,11 +1,22 @@ -ath10k-ct starting with version 5.2 allows the combination of -NL80211_IFTYPE_ADHOC and beacon_int_min_gcd in ath10k_10x_ct_if_comb -which triggers this warning. Ben told me that this is not a big problem +From: Hauke Mehrtens <hauke@hauke-m.de> +Date: Mon, 24 Feb 2020 00:00:00 +0100 +Subject: [PATCH] mac80211: Allow IBSS mode and different beacon intervals + +ath10k-ct supports the combination to select IBSS (ADHOC) mode and +different beacon intervals together. mac80211 does not like this +combination, but Ben says this is ok, so remove this check. + +ath10k-ct starting with version 5.2 allows the combination of +NL80211_IFTYPE_ADHOC and beacon_int_min_gcd in ath10k_10x_ct_if_comb +which triggers this warning. Ben told me that this is not a big problem and we should ignore this. +--- + net/wireless/core.c | 15 --------------- + 1 file changed, 15 deletions(-) --- a/net/wireless/core.c +++ b/net/wireless/core.c -@@ -614,21 +614,6 @@ static int wiphy_verify_combinations(str +@@ -649,21 +649,6 @@ static int wiphy_verify_combinations(str c->limits[j].max > 1)) return -EINVAL; diff --git a/package/kernel/mac80211/patches/subsys/500-mac80211_configure_antenna_gain.patch b/package/kernel/mac80211/patches/subsys/500-mac80211_configure_antenna_gain.patch deleted file mode 100644 index b2ee61a6dc9..00000000000 --- a/package/kernel/mac80211/patches/subsys/500-mac80211_configure_antenna_gain.patch +++ /dev/null @@ -1,160 +0,0 @@ ---- a/include/net/cfg80211.h -+++ b/include/net/cfg80211.h -@@ -3793,6 +3793,7 @@ struct mgmt_frame_regs { - * (as advertised by the nl80211 feature flag.) - * @get_tx_power: store the current TX power into the dbm variable; - * return 0 if successful -+ * @set_antenna_gain: set antenna gain to reduce maximum tx power if necessary - * - * @set_wds_peer: set the WDS peer for a WDS interface - * -@@ -4115,6 +4116,7 @@ struct cfg80211_ops { - enum nl80211_tx_power_setting type, int mbm); - int (*get_tx_power)(struct wiphy *wiphy, struct wireless_dev *wdev, - int *dbm); -+ int (*set_antenna_gain)(struct wiphy *wiphy, int dbi); - - int (*set_wds_peer)(struct wiphy *wiphy, struct net_device *dev, - const u8 *addr); ---- a/include/net/mac80211.h -+++ b/include/net/mac80211.h -@@ -1561,6 +1561,7 @@ enum ieee80211_smps_mode { - * - * @power_level: requested transmit power (in dBm), backward compatibility - * value only that is set to the minimum of all interfaces -+ * @max_antenna_gain: maximum antenna gain adjusted by user config (in dBi) - * - * @chandef: the channel definition to tune to - * @radar_enabled: whether radar detection is enabled -@@ -1581,6 +1582,7 @@ enum ieee80211_smps_mode { - struct ieee80211_conf { - u32 flags; - int power_level, dynamic_ps_timeout; -+ int max_antenna_gain; - - u16 listen_interval; - u8 ps_dtim_period; ---- a/include/uapi/linux/nl80211.h -+++ b/include/uapi/linux/nl80211.h -@@ -2560,6 +2560,9 @@ enum nl80211_commands { - * disassoc events to indicate that an immediate reconnect to the AP - * is desired. - * -+ * @NL80211_ATTR_WIPHY_ANTENNA_GAIN: Configured antenna gain. Used to reduce -+ * transmit power to stay within regulatory limits. u32, dBi. -+ * - * @NUM_NL80211_ATTR: total number of nl80211_attrs available - * @NL80211_ATTR_MAX: highest attribute number currently defined - * @__NL80211_ATTR_AFTER_LAST: internal use -@@ -3057,6 +3060,8 @@ enum nl80211_attrs { - - NL80211_ATTR_DISABLE_HE, - -+ NL80211_ATTR_WIPHY_ANTENNA_GAIN, -+ - /* add attributes here, update the policy in nl80211.c */ - - __NL80211_ATTR_AFTER_LAST, ---- a/net/mac80211/cfg.c -+++ b/net/mac80211/cfg.c -@@ -2761,6 +2761,19 @@ static int ieee80211_get_tx_power(struct - return 0; - } - -+static int ieee80211_set_antenna_gain(struct wiphy *wiphy, int dbi) -+{ -+ struct ieee80211_local *local = wiphy_priv(wiphy); -+ -+ if (dbi < 0) -+ return -EINVAL; -+ -+ local->user_antenna_gain = dbi; -+ ieee80211_hw_config(local, 0); -+ -+ return 0; -+} -+ - static int ieee80211_set_wds_peer(struct wiphy *wiphy, struct net_device *dev, - const u8 *addr) - { -@@ -4202,6 +4215,7 @@ const struct cfg80211_ops mac80211_confi - .set_wiphy_params = ieee80211_set_wiphy_params, - .set_tx_power = ieee80211_set_tx_power, - .get_tx_power = ieee80211_get_tx_power, -+ .set_antenna_gain = ieee80211_set_antenna_gain, - .set_wds_peer = ieee80211_set_wds_peer, - .rfkill_poll = ieee80211_rfkill_poll, - CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd) ---- a/net/mac80211/ieee80211_i.h -+++ b/net/mac80211/ieee80211_i.h -@@ -1426,6 +1426,7 @@ struct ieee80211_local { - int dynamic_ps_forced_timeout; - - int user_power_level; /* in dBm, for all interfaces */ -+ int user_antenna_gain; /* in dBi */ - - enum ieee80211_smps_mode smps_mode; - ---- a/net/mac80211/main.c -+++ b/net/mac80211/main.c -@@ -96,7 +96,7 @@ static u32 ieee80211_hw_conf_chan(struct - struct ieee80211_sub_if_data *sdata; - struct cfg80211_chan_def chandef = {}; - u32 changed = 0; -- int power; -+ int power, max_power; - u32 offchannel_flag; - - offchannel_flag = local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL; -@@ -157,6 +157,12 @@ static u32 ieee80211_hw_conf_chan(struct - } - rcu_read_unlock(); - -+ max_power = chandef.chan->max_reg_power; -+ if (local->user_antenna_gain > 0) { -+ max_power -= local->user_antenna_gain; -+ power = min(power, max_power); -+ } -+ - if (local->hw.conf.power_level != power) { - changed |= IEEE80211_CONF_CHANGE_POWER; - local->hw.conf.power_level = power; -@@ -665,6 +671,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_ - IEEE80211_RADIOTAP_MCS_HAVE_BW; - local->hw.radiotap_vht_details = IEEE80211_RADIOTAP_VHT_KNOWN_GI | - IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH; -+ local->user_antenna_gain = 0; - local->hw.uapsd_queues = IEEE80211_DEFAULT_UAPSD_QUEUES; - local->hw.uapsd_max_sp_len = IEEE80211_DEFAULT_MAX_SP_LEN; - local->hw.max_mtu = IEEE80211_MAX_DATA_LEN; ---- a/net/wireless/nl80211.c -+++ b/net/wireless/nl80211.c -@@ -753,6 +753,7 @@ static const struct nla_policy nl80211_p - NL80211_SAE_PWE_BOTH), - [NL80211_ATTR_SAR_SPEC] = NLA_POLICY_NESTED(sar_policy), - [NL80211_ATTR_RECONNECT_REQUESTED] = { .type = NLA_REJECT }, -+ [NL80211_ATTR_WIPHY_ANTENNA_GAIN] = { .type = NLA_U32 }, - }; - - /* policy for the key attributes */ -@@ -3318,6 +3319,20 @@ static int nl80211_set_wiphy(struct sk_b - if (result) - return result; - } -+ -+ if (info->attrs[NL80211_ATTR_WIPHY_ANTENNA_GAIN]) { -+ int idx, dbi = 0; -+ -+ if (!rdev->ops->set_antenna_gain) -+ return -EOPNOTSUPP; -+ -+ idx = NL80211_ATTR_WIPHY_ANTENNA_GAIN; -+ dbi = nla_get_u32(info->attrs[idx]); -+ -+ result = rdev->ops->set_antenna_gain(&rdev->wiphy, dbi); -+ if (result) -+ return result; -+ } - - if (info->attrs[NL80211_ATTR_WIPHY_ANTENNA_TX] && - info->attrs[NL80211_ATTR_WIPHY_ANTENNA_RX]) { diff --git a/package/kernel/mac80211/patches/subsys/780-avoid-crashing-missing-band.patch b/package/kernel/mac80211/patches/subsys/780-avoid-crashing-missing-band.patch new file mode 100644 index 00000000000..4bbd7860436 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/780-avoid-crashing-missing-band.patch @@ -0,0 +1,34 @@ +From: David Bauer <mail@david-bauer.net> +Date: Thu, 30 Nov 2023 07:32:52 +0100 +Subject: [PATCH] mac80211: avoid crashing on invalid band info + +Frequent crashes have been observed on MT7916 based platforms. While the +root of these crashes are currently unknown, they happen when decoding +rate information of connected STAs in AP mode. The rate-information is +associated with a band which is not available on the PHY. + +Check for this condition in order to avoid crashing the whole system. +This patch should be removed once the roout cause has been found and +fixed. + +Link: https://github.com/freifunk-gluon/gluon/issues/2980 + +Signed-off-by: David Bauer <mail@david-bauer.net> +--- + +--- a/net/mac80211/sta_info.c ++++ b/net/mac80211/sta_info.c +@@ -2423,6 +2423,13 @@ static void sta_stats_decode_rate(struct + + sband = local->hw.wiphy->bands[band]; + ++ if (!sband) { ++ wiphy_warn(local->hw.wiphy, ++ "Invalid band %d\n", ++ band); ++ break; ++ } ++ + if (WARN_ON_ONCE(!sband->bitrates)) + break; + diff --git a/package/kernel/mac80211/patches/subsys/782-net-next-1-of-net-pass-the-dst-buffer-to-of_get_mac_address.patch b/package/kernel/mac80211/patches/subsys/782-net-next-1-of-net-pass-the-dst-buffer-to-of_get_mac_address.patch new file mode 100644 index 00000000000..26af6a2fb98 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/782-net-next-1-of-net-pass-the-dst-buffer-to-of_get_mac_address.patch @@ -0,0 +1,29 @@ +--- a/backport-include/linux/of_net.h ++++ /dev/null +@@ -1,26 +0,0 @@ +-#ifndef _BP_OF_NET_H +-#define _BP_OF_NET_H +-#include_next <linux/of_net.h> +-#include <linux/version.h> +-#include <linux/etherdevice.h> +- +-/* The behavior of of_get_mac_address() changed in kernel 5.2, it now +- * returns an error code and not NULL in case of an error. +- */ +-#if LINUX_VERSION_IS_LESS(5,13,0) +-static inline int backport_of_get_mac_address(struct device_node *np, u8 *mac_out) +-{ +- const void *mac = of_get_mac_address(np); +- +- if (!mac) +- return -ENODEV; +- if (IS_ERR(mac)) +- return PTR_ERR(mac); +- ether_addr_copy(mac_out, mac); +- +- return 0; +-} +-#define of_get_mac_address LINUX_BACKPORT(of_get_mac_address) +-#endif /* < 5.2 */ +- +-#endif /* _BP_OF_NET_H */ |
