mac80211: Update to version 5.12.19-1

The removed patches were applied upstream.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
This commit is contained in:
Hauke Mehrtens 2021-10-09 16:25:30 +02:00
parent e185080c87
commit b96c2569ac
86 changed files with 249 additions and 6099 deletions

View File

@ -10,10 +10,10 @@ include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=mac80211
PKG_VERSION:=5.11.22-1
PKG_VERSION:=5.12.19-1
PKG_RELEASE:=1
PKG_SOURCE_URL:=@KERNEL/linux/kernel/projects/backports/stable/v5.11.22/
PKG_HASH:=35c23dd182711a3a6f671a673c2e0ace2ffdd25bbd1fb917e428d04924141299
PKG_SOURCE_URL:=@KERNEL/linux/kernel/projects/backports/stable/v5.12.19/
PKG_HASH:=4233002bcf26237783cd517d93c27807e534234cef64def7e550c5f06b779d18
PKG_SOURCE:=backports-$(PKG_VERSION).tar.xz
PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/backports-$(PKG_VERSION)

View File

@ -14,7 +14,7 @@
CFLAGS_trace.o := -I$(src)
--- a/drivers/net/wireless/ath/ath.h
+++ b/drivers/net/wireless/ath/ath.h
@@ -316,14 +316,7 @@ void _ath_dbg(struct ath_common *common,
@@ -317,14 +317,7 @@ void _ath_dbg(struct ath_common *common,
#endif /* CPTCFG_ATH_DEBUG */
/** Returns string describing opmode, or NULL if unknown mode. */

View File

@ -1,6 +1,6 @@
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -3269,6 +3269,8 @@ void regulatory_hint_country_ie(struct w
@@ -3292,6 +3292,8 @@ void regulatory_hint_country_ie(struct w
enum environment_cap env = ENVIRON_ANY;
struct regulatory_request *request = NULL, *lr;
@ -9,7 +9,7 @@
/* IE len must be evenly divisible by 2 */
if (country_ie_len & 0x01)
return;
@@ -3520,6 +3522,7 @@ static bool is_wiphy_all_set_reg_flag(en
@@ -3543,6 +3545,7 @@ static bool is_wiphy_all_set_reg_flag(en
void regulatory_hint_disconnect(void)
{

View File

@ -14,7 +14,7 @@ Signed-off-by: Sven Eckelmann <sven@open-mesh.com>
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -3329,6 +3329,16 @@ int ath10k_core_register(struct ath10k *
@@ -3345,6 +3345,16 @@ int ath10k_core_register(struct ath10k *
queue_work(ar->workqueue, &ar->register_work);

View File

@ -1,37 +0,0 @@
From: Linus Lüssing <ll@simonwunderlich.de>
Date: Wed, 5 Feb 2020 20:10:43 +0100
Subject: ath10k: increase rx buffer size to 2048
Before, only frames with a maximum size of 1528 bytes could be
transmitted between two 802.11s nodes.
For batman-adv for instance, which adds its own header to each frame,
we typically need an MTU of at least 1532 bytes to be able to transmit
without fragmentation.
This patch now increases the maxmimum frame size from 1528 to 1656
bytes.
Tested with two ath10k devices in 802.11s mode, as well as with
batman-adv on top of 802.11s with forwarding disabled.
Fix originally found and developed by Ben Greear.
Link: https://github.com/greearb/ath10k-ct/issues/89
Link: https://github.com/greearb/ath10k-ct/commit/9e5ab25027e0971fa24ccf93373324c08c4e992d
Cc: Ben Greear <greearb@candelatech.com>
Signed-off-by: Linus Lüssing <ll@simonwunderlich.de>
Forwarded: https://patchwork.kernel.org/patch/11367055/
--- a/drivers/net/wireless/ath/ath10k/htt.h
+++ b/drivers/net/wireless/ath/ath10k/htt.h
@@ -2241,7 +2241,7 @@ struct htt_rx_chan_info {
* Should be: sizeof(struct htt_host_rx_desc) + max rx MSDU size,
* rounded up to a cache line size.
*/
-#define HTT_RX_BUF_SIZE 1920
+#define HTT_RX_BUF_SIZE 2048
#define HTT_RX_MSDU_SIZE (HTT_RX_BUF_SIZE - (int)sizeof(struct htt_rx_desc))
/* Refill a bunch of RX buffers for each refill round so that FW/HW can handle

View File

@ -1,6 +1,6 @@
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -9708,6 +9708,21 @@ static int ath10k_mac_init_rd(struct ath
@@ -9818,6 +9818,21 @@ static int ath10k_mac_init_rd(struct ath
return 0;
}
@ -22,7 +22,7 @@
int ath10k_mac_register(struct ath10k *ar)
{
static const u32 cipher_suites[] = {
@@ -10057,6 +10072,12 @@ int ath10k_mac_register(struct ath10k *a
@@ -10170,6 +10185,12 @@ int ath10k_mac_register(struct ath10k *a
ar->hw->weight_multiplier = ATH10K_AIRTIME_WEIGHT_MULTIPLIER;

View File

@ -140,7 +140,7 @@ v13:
.patch_load_addr = QCA988X_HW_2_0_PATCH_LOAD_ADDR,
.uart_pin = 7,
.cc_wraparound_type = ATH10K_HW_CC_WRAP_SHIFTED_ALL,
@@ -130,6 +132,7 @@ static const struct ath10k_hw_params ath
@@ -132,6 +134,7 @@ static const struct ath10k_hw_params ath
.dev_id = QCA9887_1_0_DEVICE_ID,
.bus = ATH10K_BUS_PCI,
.name = "qca9887 hw1.0",
@ -148,7 +148,7 @@ v13:
.patch_load_addr = QCA9887_HW_1_0_PATCH_LOAD_ADDR,
.uart_pin = 7,
.cc_wraparound_type = ATH10K_HW_CC_WRAP_SHIFTED_ALL,
@@ -335,6 +338,7 @@ static const struct ath10k_hw_params ath
@@ -343,6 +346,7 @@ static const struct ath10k_hw_params ath
.dev_id = QCA99X0_2_0_DEVICE_ID,
.bus = ATH10K_BUS_PCI,
.name = "qca99x0 hw2.0",
@ -156,7 +156,7 @@ v13:
.patch_load_addr = QCA99X0_HW_2_0_PATCH_LOAD_ADDR,
.uart_pin = 7,
.otp_exe_param = 0x00000700,
@@ -375,6 +379,7 @@ static const struct ath10k_hw_params ath
@@ -384,6 +388,7 @@ static const struct ath10k_hw_params ath
.dev_id = QCA9984_1_0_DEVICE_ID,
.bus = ATH10K_BUS_PCI,
.name = "qca9984/qca9994 hw1.0",
@ -164,7 +164,7 @@ v13:
.patch_load_addr = QCA9984_HW_1_0_PATCH_LOAD_ADDR,
.uart_pin = 7,
.cc_wraparound_type = ATH10K_HW_CC_WRAP_SHIFTED_EACH,
@@ -422,6 +427,7 @@ static const struct ath10k_hw_params ath
@@ -432,6 +437,7 @@ static const struct ath10k_hw_params ath
.dev_id = QCA9888_2_0_DEVICE_ID,
.bus = ATH10K_BUS_PCI,
.name = "qca9888 hw2.0",
@ -172,7 +172,7 @@ v13:
.patch_load_addr = QCA9888_HW_2_0_PATCH_LOAD_ADDR,
.uart_pin = 7,
.cc_wraparound_type = ATH10K_HW_CC_WRAP_SHIFTED_EACH,
@@ -3044,6 +3050,10 @@ int ath10k_core_start(struct ath10k *ar,
@@ -3060,6 +3066,10 @@ int ath10k_core_start(struct ath10k *ar,
goto err_hif_stop;
}
@ -183,7 +183,7 @@ v13:
return 0;
err_hif_stop:
@@ -3302,9 +3312,18 @@ static void ath10k_core_register_work(st
@@ -3318,9 +3328,18 @@ static void ath10k_core_register_work(st
goto err_spectral_destroy;
}
@ -202,7 +202,7 @@ v13:
err_spectral_destroy:
ath10k_spectral_destroy(ar);
err_debug_destroy:
@@ -3350,6 +3369,8 @@ void ath10k_core_unregister(struct ath10
@@ -3366,6 +3385,8 @@ void ath10k_core_unregister(struct ath10
if (!test_bit(ATH10K_FLAG_CORE_REGISTERED, &ar->dev_flags))
return;
@ -221,7 +221,7 @@ v13:
#include "htt.h"
#include "htc.h"
@@ -1251,6 +1252,13 @@ struct ath10k {
@@ -1250,6 +1251,13 @@ struct ath10k {
} testmode;
struct {

View File

@ -16,9 +16,9 @@ Signed-off-by: Mathias Kresin <dev@kresin.me>
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -1304,6 +1304,10 @@ struct ath10k {
bool coex_support;
int coex_gpio_pin;
@@ -1306,6 +1306,10 @@ struct ath10k {
s32 tx_power_2g_limit;
s32 tx_power_5g_limit;
+#ifdef CPTCFG_MAC80211_LEDS
+ const char *led_default_trigger;
@ -42,7 +42,7 @@ Signed-off-by: Mathias Kresin <dev@kresin.me>
if (ret)
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -10074,7 +10074,7 @@ int ath10k_mac_register(struct ath10k *a
@@ -10187,7 +10187,7 @@ int ath10k_mac_register(struct ath10k *a
ar->hw->weight_multiplier = ATH10K_AIRTIME_WEIGHT_MULTIPLIER;
#ifdef CPTCFG_MAC80211_LEDS

View File

@ -20,7 +20,7 @@ Forwarded: https://patchwork.kernel.org/patch/10986723/
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -1038,7 +1038,7 @@ static int ath10k_monitor_vdev_start(str
@@ -1049,7 +1049,7 @@ static int ath10k_monitor_vdev_start(str
arg.channel.min_power = 0;
arg.channel.max_power = channel->max_power * 2;
arg.channel.max_reg_power = channel->max_reg_power * 2;
@ -29,7 +29,7 @@ Forwarded: https://patchwork.kernel.org/patch/10986723/
reinit_completion(&ar->vdev_setup_done);
reinit_completion(&ar->vdev_delete_done);
@@ -1484,7 +1484,7 @@ static int ath10k_vdev_start_restart(str
@@ -1495,7 +1495,7 @@ static int ath10k_vdev_start_restart(str
arg.channel.min_power = 0;
arg.channel.max_power = chandef->chan->max_power * 2;
arg.channel.max_reg_power = chandef->chan->max_reg_power * 2;
@ -38,7 +38,7 @@ Forwarded: https://patchwork.kernel.org/patch/10986723/
if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
arg.ssid = arvif->u.ap.ssid;
@@ -3255,7 +3255,7 @@ static int ath10k_update_channel_list(st
@@ -3423,7 +3423,7 @@ static int ath10k_update_channel_list(st
ch->min_power = 0;
ch->max_power = channel->max_power * 2;
ch->max_reg_power = channel->max_reg_power * 2;

View File

@ -28,7 +28,7 @@ Forwarded: no
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -1006,6 +1006,40 @@ static inline int ath10k_vdev_setup_sync
@@ -1017,6 +1017,40 @@ static inline int ath10k_vdev_setup_sync
return ar->last_wmi_vdev_start_status;
}
@ -69,7 +69,7 @@ Forwarded: no
static int ath10k_monitor_vdev_start(struct ath10k *ar, int vdev_id)
{
struct cfg80211_chan_def *chandef = NULL;
@@ -1038,7 +1072,8 @@ static int ath10k_monitor_vdev_start(str
@@ -1049,7 +1083,8 @@ static int ath10k_monitor_vdev_start(str
arg.channel.min_power = 0;
arg.channel.max_power = channel->max_power * 2;
arg.channel.max_reg_power = channel->max_reg_power * 2;
@ -79,7 +79,7 @@ Forwarded: no
reinit_completion(&ar->vdev_setup_done);
reinit_completion(&ar->vdev_delete_done);
@@ -1484,7 +1519,8 @@ static int ath10k_vdev_start_restart(str
@@ -1495,7 +1530,8 @@ static int ath10k_vdev_start_restart(str
arg.channel.min_power = 0;
arg.channel.max_power = chandef->chan->max_power * 2;
arg.channel.max_reg_power = chandef->chan->max_reg_power * 2;
@ -89,7 +89,7 @@ Forwarded: no
if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
arg.ssid = arvif->u.ap.ssid;
@@ -3255,7 +3291,8 @@ static int ath10k_update_channel_list(st
@@ -3423,7 +3459,8 @@ static int ath10k_update_channel_list(st
ch->min_power = 0;
ch->max_power = channel->max_power * 2;
ch->max_reg_power = channel->max_reg_power * 2;

View File

@ -26,7 +26,7 @@ Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
#include <linux/property.h>
#include <linux/dmi.h>
#include <linux/ctype.h>
@@ -3220,6 +3221,8 @@ static int ath10k_core_probe_fw(struct a
@@ -3236,6 +3237,8 @@ static int ath10k_core_probe_fw(struct a
device_get_mac_address(ar->dev, ar->mac_addr, sizeof(ar->mac_addr));

View File

@ -18,7 +18,7 @@
goto end;
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -1964,7 +1964,7 @@ ath5k_beacon_send(struct ath5k_hw *ah)
@@ -1963,7 +1963,7 @@ ath5k_beacon_send(struct ath5k_hw *ah)
}
if ((ah->opmode == NL80211_IFTYPE_AP && ah->num_ap_vifs +
@ -27,7 +27,7 @@
ah->opmode == NL80211_IFTYPE_MESH_POINT) {
u64 tsf = ath5k_hw_get_tsf64(ah);
u32 tsftu = TSF_TO_TU(tsf);
@@ -2050,7 +2050,7 @@ ath5k_beacon_update_timers(struct ath5k_
@@ -2049,7 +2049,7 @@ ath5k_beacon_update_timers(struct ath5k_
intval = ah->bintval & AR5K_BEACON_PERIOD;
if (ah->opmode == NL80211_IFTYPE_AP && ah->num_ap_vifs
@ -36,7 +36,7 @@
intval /= ATH_BCBUF; /* staggered multi-bss beacons */
if (intval < 15)
ATH5K_WARN(ah, "intval %u is too low, min 15\n",
@@ -2516,6 +2516,7 @@ static const struct ieee80211_iface_limi
@@ -2515,6 +2515,7 @@ static const struct ieee80211_iface_limi
BIT(NL80211_IFTYPE_MESH_POINT) |
#endif
BIT(NL80211_IFTYPE_AP) },

View File

@ -130,7 +130,7 @@ drivers/net/wireless/ath/ath5k/debug.c | 86 ++++++++++++++++++++++++++++++++
/* Antenna Control */
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -466,6 +466,9 @@ ath5k_chan_set(struct ath5k_hw *ah, stru
@@ -465,6 +465,9 @@ ath5k_chan_set(struct ath5k_hw *ah, stru
return -EINVAL;
}

View File

@ -9,7 +9,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -1435,8 +1435,12 @@ static bool ath9k_hw_set_reset(struct at
@@ -1434,8 +1434,12 @@ static bool ath9k_hw_set_reset(struct at
if (!AR_SREV_9100(ah))
REG_WRITE(ah, AR_RC, 0);

View File

@ -10,7 +10,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -1312,39 +1312,56 @@ void ath9k_hw_get_delta_slope_vals(struc
@@ -1311,39 +1311,56 @@ void ath9k_hw_get_delta_slope_vals(struc
*coef_exponent = coef_exp - 16;
}
@ -94,7 +94,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
return true;
}
@@ -1397,24 +1414,24 @@ static bool ath9k_hw_set_reset(struct at
@@ -1396,24 +1413,24 @@ static bool ath9k_hw_set_reset(struct at
rst_flags |= AR_RTC_RC_MAC_COLD;
}

View File

@ -8,7 +8,7 @@ This reverts commit 71f5137bf010c6faffab50c0ec15374c59c4a411.
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -2976,7 +2976,8 @@ void ath9k_hw_apply_txpower(struct ath_h
@@ -2975,7 +2975,8 @@ void ath9k_hw_apply_txpower(struct ath_h
{
struct ath_regulatory *reg = ath9k_hw_regulatory(ah);
struct ieee80211_channel *channel;
@ -18,7 +18,7 @@ This reverts commit 71f5137bf010c6faffab50c0ec15374c59c4a411.
u16 ctl = NO_CTL;
if (!chan)
@@ -2988,9 +2989,14 @@ void ath9k_hw_apply_txpower(struct ath_h
@@ -2987,9 +2988,14 @@ void ath9k_hw_apply_txpower(struct ath_h
channel = chan->chan;
chan_pwr = min_t(int, channel->max_power * 2, MAX_COMBINED_POWER);
new_pwr = min_t(int, chan_pwr, reg->power_limit);

View File

@ -11,7 +11,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -2995,6 +2995,10 @@ void ath9k_hw_apply_txpower(struct ath_h
@@ -2994,6 +2994,10 @@ void ath9k_hw_apply_txpower(struct ath_h
if (ant_gain > max_gain)
ant_reduction = ant_gain - max_gain;

View File

@ -1,6 +1,6 @@
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -48,7 +48,7 @@ int ath9k_modparam_nohwcrypt;
@@ -47,7 +47,7 @@ int ath9k_modparam_nohwcrypt;
module_param_named(nohwcrypt, ath9k_modparam_nohwcrypt, int, 0444);
MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption");

View File

@ -1,6 +1,6 @@
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -827,6 +827,7 @@ static const struct ieee80211_iface_limi
@@ -826,6 +826,7 @@ static const struct ieee80211_iface_limi
BIT(NL80211_IFTYPE_AP) },
{ .max = 1, .types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
BIT(NL80211_IFTYPE_P2P_GO) },

View File

@ -14,7 +14,7 @@ Signed-off-by: David Bauer <mail@david-bauer.net>
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -908,6 +908,7 @@ static void ath9k_set_hw_capab(struct at
@@ -907,6 +907,7 @@ static void ath9k_set_hw_capab(struct at
ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING);
ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS);
@ -22,7 +22,7 @@ Signed-off-by: David Bauer <mail@david-bauer.net>
if (ath9k_ps_enable)
ieee80211_hw_set(hw, SUPPORTS_PS);
@@ -920,9 +921,6 @@ static void ath9k_set_hw_capab(struct at
@@ -919,9 +920,6 @@ static void ath9k_set_hw_capab(struct at
IEEE80211_RADIOTAP_MCS_HAVE_STBC;
}

View File

@ -1,6 +1,6 @@
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -1121,25 +1121,25 @@ static int __init ath9k_init(void)
@@ -1120,25 +1120,25 @@ static int __init ath9k_init(void)
{
int error;

View File

@ -1,6 +1,6 @@
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -403,13 +403,8 @@ static void ath9k_hw_init_config(struct
@@ -402,13 +402,8 @@ static void ath9k_hw_init_config(struct
ah->config.rx_intr_mitigation = true;

View File

@ -1,6 +1,6 @@
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -663,6 +663,7 @@ int ath9k_hw_init(struct ath_hw *ah)
@@ -662,6 +662,7 @@ int ath9k_hw_init(struct ath_hw *ah)
/* These are all the AR5008/AR9001/AR9002/AR9003 hardware family of chipsets */
switch (ah->hw_version.devid) {

View File

@ -181,7 +181,7 @@
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -1033,7 +1033,7 @@ int ath9k_init_device(u16 devid, struct
@@ -1032,7 +1032,7 @@ int ath9k_init_device(u16 devid, struct
#ifdef CPTCFG_MAC80211_LEDS
/* must be initialized before ieee80211_register_hw */

View File

@ -84,7 +84,7 @@
bool reset_power_on;
bool htc_reset_init;
@@ -1076,6 +1084,7 @@ void ath9k_hw_check_nav(struct ath_hw *a
@@ -1077,6 +1085,7 @@ void ath9k_hw_check_nav(struct ath_hw *a
bool ath9k_hw_check_alive(struct ath_hw *ah);
bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode);
@ -94,7 +94,7 @@
struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah,
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -1883,6 +1883,20 @@ u32 ath9k_hw_get_tsf_offset(struct times
@@ -1882,6 +1882,20 @@ u32 ath9k_hw_get_tsf_offset(struct times
}
EXPORT_SYMBOL(ath9k_hw_get_tsf_offset);
@ -115,7 +115,7 @@
int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
struct ath9k_hw_cal_data *caldata, bool fastcc)
{
@@ -2091,6 +2105,7 @@ int ath9k_hw_reset(struct ath_hw *ah, st
@@ -2090,6 +2104,7 @@ int ath9k_hw_reset(struct ath_hw *ah, st
ar9003_hw_disable_phy_restart(ah);
ath9k_hw_apply_gpio_override(ah);
@ -125,7 +125,7 @@
REG_SET_BIT(ah, AR_BTCOEX_WL_LNADIV, AR_BTCOEX_WL_LNADIV_FORCE_ON);
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -531,6 +531,11 @@ irqreturn_t ath_isr(int irq, void *dev)
@@ -536,6 +536,11 @@ irqreturn_t ath_isr(int irq, void *dev)
if (test_bit(ATH_OP_HW_RESET, &common->op_flags))
return IRQ_HANDLED;

View File

@ -55,7 +55,7 @@
ops->spectral_scan_config = ar9003_hw_spectral_scan_config;
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -815,7 +815,8 @@ static void ath9k_init_txpower_limits(st
@@ -814,7 +814,8 @@ static void ath9k_init_txpower_limits(st
if (ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ)
ath9k_init_band_txpower(sc, NL80211_BAND_5GHZ);
@ -65,7 +65,7 @@
}
static const struct ieee80211_iface_limit if_limits[] = {
@@ -993,6 +994,18 @@ static void ath9k_set_hw_capab(struct at
@@ -992,6 +993,18 @@ static void ath9k_set_hw_capab(struct at
wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CAN_REPLACE_PTK0);
}
@ -84,7 +84,7 @@
int ath9k_init_device(u16 devid, struct ath_softc *sc,
const struct ath_bus_ops *bus_ops)
{
@@ -1038,6 +1051,8 @@ int ath9k_init_device(u16 devid, struct
@@ -1037,6 +1050,8 @@ int ath9k_init_device(u16 devid, struct
ARRAY_SIZE(ath9k_tpt_blink));
#endif

View File

@ -1,6 +1,6 @@
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -248,6 +248,19 @@ void ath9k_hw_get_channel_centers(struct
@@ -247,6 +247,19 @@ void ath9k_hw_get_channel_centers(struct
centers->synth_center + (extoff * HT40_CHANNEL_CENTER_SHIFT);
}
@ -20,7 +20,7 @@
/******************/
/* Chip Revisions */
/******************/
@@ -1455,6 +1468,9 @@ static bool ath9k_hw_set_reset(struct at
@@ -1454,6 +1467,9 @@ static bool ath9k_hw_set_reset(struct at
udelay(50);
}
@ -30,7 +30,7 @@
return true;
}
@@ -1554,6 +1570,9 @@ static bool ath9k_hw_chip_reset(struct a
@@ -1553,6 +1569,9 @@ static bool ath9k_hw_chip_reset(struct a
ar9003_hw_internal_regulator_apply(ah);
ath9k_hw_init_pll(ah, chan);
@ -40,7 +40,7 @@
return true;
}
@@ -1861,8 +1880,14 @@ static int ath9k_hw_do_fastcc(struct ath
@@ -1860,8 +1879,14 @@ static int ath9k_hw_do_fastcc(struct ath
if (AR_SREV_9271(ah))
ar9002_hw_load_ani_reg(ah, chan);
@ -55,7 +55,7 @@
return -EINVAL;
}
@@ -2116,6 +2141,9 @@ int ath9k_hw_reset(struct ath_hw *ah, st
@@ -2115,6 +2140,9 @@ int ath9k_hw_reset(struct ath_hw *ah, st
ath9k_hw_set_radar_params(ah);
}

View File

@ -1,6 +1,6 @@
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -626,6 +626,12 @@ static int ath9k_of_init(struct ath_soft
@@ -625,6 +625,12 @@ static int ath9k_of_init(struct ath_soft
ath_dbg(common, CONFIG, "parsing configuration from OF node\n");

View File

@ -339,7 +339,7 @@
static void ath9k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
u32 queues, bool drop);
@@ -652,6 +653,7 @@ void ath_reset_work(struct work_struct *
@@ -657,6 +658,7 @@ void ath_reset_work(struct work_struct *
static int ath9k_start(struct ieee80211_hw *hw)
{
struct ath_softc *sc = hw->priv;
@ -347,7 +347,7 @@
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
struct ieee80211_channel *curchan = sc->cur_chan->chandef.chan;
@@ -730,6 +732,11 @@ static int ath9k_start(struct ieee80211_
@@ -735,6 +737,11 @@ static int ath9k_start(struct ieee80211_
AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
}

View File

@ -1,6 +1,6 @@
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -651,6 +651,12 @@ static int ath9k_of_init(struct ath_soft
@@ -650,6 +650,12 @@ static int ath9k_of_init(struct ath_soft
return 0;
}
@ -13,7 +13,7 @@
static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
const struct ath_bus_ops *bus_ops)
{
@@ -754,6 +760,9 @@ static int ath9k_init_softc(u16 devid, s
@@ -753,6 +759,9 @@ static int ath9k_init_softc(u16 devid, s
if (ret)
goto err_hw;

View File

@ -13,7 +13,7 @@ Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
@@ -431,6 +431,7 @@ struct brcmf_fw {
@@ -429,6 +429,7 @@ struct brcmf_fw {
struct brcmf_fw_request *req;
u32 curpos;
void (*done)(struct device *dev, int err, struct brcmf_fw_request *req);
@ -21,7 +21,7 @@ Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
};
static void brcmf_fw_request_done(const struct firmware *fw, void *ctx);
@@ -638,6 +639,8 @@ static void brcmf_fw_request_done(const
@@ -636,6 +637,8 @@ static void brcmf_fw_request_done(const
fwctx->req = NULL;
}
fwctx->done(fwctx->dev, ret, fwctx->req);
@ -30,7 +30,7 @@ Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
kfree(fwctx);
}
@@ -662,6 +665,8 @@ int brcmf_fw_get_firmwares(struct device
@@ -660,6 +663,8 @@ int brcmf_fw_get_firmwares(struct device
{
struct brcmf_fw_item *first = &req->items[0];
struct brcmf_fw *fwctx;
@ -39,7 +39,7 @@ Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
int ret;
brcmf_dbg(TRACE, "enter: dev=%s\n", dev_name(dev));
@@ -678,6 +683,9 @@ int brcmf_fw_get_firmwares(struct device
@@ -676,6 +681,9 @@ int brcmf_fw_get_firmwares(struct device
fwctx->dev = dev;
fwctx->req = req;
fwctx->done = fw_cb;
@ -49,7 +49,7 @@ Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
ret = request_firmware_nowait(THIS_MODULE, true, first->path,
fwctx->dev, GFP_KERNEL, fwctx,
@@ -685,6 +693,12 @@ int brcmf_fw_get_firmwares(struct device
@@ -683,6 +691,12 @@ int brcmf_fw_get_firmwares(struct device
if (ret < 0)
brcmf_fw_request_done(NULL, fwctx);

View File

@ -14,7 +14,7 @@ Signed-off-by: Phil Elwell <phil@raspberrypi.org>
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -2958,6 +2958,10 @@ brcmf_cfg80211_set_power_mgmt(struct wip
@@ -2961,6 +2961,10 @@ brcmf_cfg80211_set_power_mgmt(struct wip
* preference in cfg struct to apply this to
* FW later while initializing the dongle
*/

View File

@ -1,6 +1,6 @@
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -2910,6 +2910,63 @@ done:
@@ -2913,6 +2913,63 @@ done:
}
static int
@ -64,7 +64,7 @@
brcmf_cfg80211_dump_station(struct wiphy *wiphy, struct net_device *ndev,
int idx, u8 *mac, struct station_info *sinfo)
{
@@ -3005,6 +3062,7 @@ static s32 brcmf_inform_single_bss(struc
@@ -3008,6 +3065,7 @@ static s32 brcmf_inform_single_bss(struc
struct brcmu_chan ch;
u16 channel;
u32 freq;
@ -72,7 +72,7 @@
u16 notify_capability;
u16 notify_interval;
u8 *notify_ie;
@@ -3029,6 +3087,17 @@ static s32 brcmf_inform_single_bss(struc
@@ -3032,6 +3090,17 @@ static s32 brcmf_inform_single_bss(struc
band = NL80211_BAND_5GHZ;
freq = ieee80211_channel_to_frequency(channel, band);
@ -90,7 +90,7 @@
bss_data.chan = ieee80211_get_channel(wiphy, freq);
bss_data.scan_width = NL80211_BSS_CHAN_WIDTH_20;
bss_data.boottime_ns = ktime_to_ns(ktime_get_boottime());
@@ -5515,6 +5584,7 @@ static struct cfg80211_ops brcmf_cfg8021
@@ -5560,6 +5629,7 @@ static struct cfg80211_ops brcmf_cfg8021
.leave_ibss = brcmf_cfg80211_leave_ibss,
.get_station = brcmf_cfg80211_get_station,
.dump_station = brcmf_cfg80211_dump_station,

View File

@ -1,6 +1,6 @@
--- a/net/wireless/Kconfig
+++ b/net/wireless/Kconfig
@@ -187,7 +187,7 @@ config CFG80211_WEXT_EXPORT
@@ -188,7 +188,7 @@ config CFG80211_WEXT_EXPORT
endif # CFG80211
config LIB80211
@ -9,7 +9,7 @@
depends on m
default n
help
@@ -197,19 +197,19 @@ config LIB80211
@@ -198,19 +198,19 @@ config LIB80211
Drivers should select this themselves if needed.
config LIB80211_CRYPT_WEP

View File

@ -1,6 +1,6 @@
--- a/local-symbols
+++ b/local-symbols
@@ -429,43 +429,6 @@ USB_VL600=
@@ -431,43 +431,6 @@ USB_VL600=
USB_NET_CH9200=
USB_NET_AQC111=
USB_RTL8153_ECM=
@ -192,7 +192,7 @@
select BRCMUTIL
--- a/Kconfig.local
+++ b/Kconfig.local
@@ -1291,117 +1291,6 @@ config BACKPORTED_USB_NET_AQC111
@@ -1297,117 +1297,6 @@ config BACKPORTED_USB_NET_AQC111
config BACKPORTED_USB_RTL8153_ECM
tristate
default USB_RTL8153_ECM

View File

@ -1,6 +1,6 @@
--- a/drivers/net/wireless/marvell/mwl8k.c
+++ b/drivers/net/wireless/marvell/mwl8k.c
@@ -5700,6 +5700,7 @@ MODULE_FIRMWARE("mwl8k/fmimage_8366.fw")
@@ -5699,6 +5699,7 @@ MODULE_FIRMWARE("mwl8k/fmimage_8366.fw")
MODULE_FIRMWARE(MWL8K_8366_AP_FW(MWL8K_8366_AP_FW_API));
static const struct pci_device_id mwl8k_pci_id_table[] = {

View File

@ -1,6 +1,6 @@
--- a/drivers/net/wireless/marvell/mwl8k.c
+++ b/drivers/net/wireless/marvell/mwl8k.c
@@ -6286,6 +6286,8 @@ static int mwl8k_probe(struct pci_dev *p
@@ -6285,6 +6285,8 @@ static int mwl8k_probe(struct pci_dev *p
priv->running_bsses = 0;
@ -9,7 +9,7 @@
return rc;
err_stop_firmware:
@@ -6319,8 +6321,6 @@ static void mwl8k_remove(struct pci_dev
@@ -6318,8 +6320,6 @@ static void mwl8k_remove(struct pci_dev
return;
priv = hw->priv;

View File

@ -1,6 +1,6 @@
--- a/local-symbols
+++ b/local-symbols
@@ -323,6 +323,7 @@ RT2X00_LIB_FIRMWARE=
@@ -325,6 +325,7 @@ RT2X00_LIB_FIRMWARE=
RT2X00_LIB_CRYPTO=
RT2X00_LIB_LEDS=
RT2X00_LIB_DEBUGFS=

View File

@ -89,7 +89,7 @@ Tested-by: Maciej S. Szmigiero <mail@maciej.szmigiero.name>
#endif
--- a/drivers/net/wireless/realtek/rtlwifi/usb.c
+++ b/drivers/net/wireless/realtek/rtlwifi/usb.c
@@ -806,6 +806,7 @@ static void rtl_usb_stop(struct ieee8021
@@ -805,6 +805,7 @@ static void rtl_usb_stop(struct ieee8021
tasklet_kill(&rtlusb->rx_work_tasklet);
cancel_work_sync(&rtlpriv->works.lps_change_work);
@ -97,7 +97,7 @@ Tested-by: Maciej S. Szmigiero <mail@maciej.szmigiero.name>
flush_workqueue(rtlpriv->works.rtl_wq);
@@ -1032,6 +1033,8 @@ int rtl_usb_probe(struct usb_interface *
@@ -1031,6 +1032,8 @@ int rtl_usb_probe(struct usb_interface *
rtl_fill_h2c_cmd_work_callback);
INIT_WORK(&rtlpriv->works.lps_change_work,
rtl_lps_change_work_callback);

View File

@ -10,34 +10,7 @@
* @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
@@ -1963,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.
@@ -3045,6 +3055,8 @@ enum nl80211_attrs {
NL80211_ATTR_SAR_SPEC,
+ NL80211_ATTR_DISABLE_HE,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -5928,6 +5940,16 @@ enum nl80211_feature_flags {
@@ -5937,6 +5940,16 @@ enum nl80211_feature_flags {
* @NL80211_EXT_FEATURE_BEACON_RATE_HE: Driver supports beacon rate
* configuration (AP/mesh) with HE rates.
*
@ -54,7 +27,7 @@
* @NUM_NL80211_EXT_FEATURES: number of extended features.
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
*/
@@ -5989,6 +6011,9 @@ enum nl80211_ext_feature_index {
@@ -5998,6 +6011,9 @@ enum nl80211_ext_feature_index {
NL80211_EXT_FEATURE_FILS_DISCOVERY,
NL80211_EXT_FEATURE_UNSOL_BCAST_PROBE_RESP,
NL80211_EXT_FEATURE_BEACON_RATE_HE,
@ -64,7 +37,7 @@
/* add new features before the definition below */
NUM_NL80211_EXT_FEATURES,
@@ -6286,11 +6311,13 @@ struct nl80211_vendor_cmd_info {
@@ -6295,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.
@ -78,7 +51,7 @@
};
/**
@@ -6882,6 +6909,9 @@ enum nl80211_peer_measurement_ftm_capa {
@@ -6891,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.
@ -88,7 +61,7 @@
*
* @NUM_NL80211_PMSR_FTM_REQ_ATTR: internal
* @NL80211_PMSR_FTM_REQ_ATTR_MAX: highest attribute number
@@ -6900,6 +6930,7 @@ enum nl80211_peer_measurement_ftm_req {
@@ -6909,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,

View File

@ -1,6 +1,6 @@
--- 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);
}

View File

@ -1,6 +1,6 @@
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -321,7 +321,7 @@ void ieee80211_restart_hw(struct ieee802
@@ -328,7 +328,7 @@ void ieee80211_restart_hw(struct ieee802
}
EXPORT_SYMBOL(ieee80211_restart_hw);
@ -9,7 +9,7 @@
static int ieee80211_ifa_changed(struct notifier_block *nb,
unsigned long data, void *arg)
{
@@ -380,7 +380,7 @@ static int ieee80211_ifa_changed(struct
@@ -387,7 +387,7 @@ static int ieee80211_ifa_changed(struct
}
#endif
@ -18,8 +18,8 @@
static int ieee80211_ifa6_changed(struct notifier_block *nb,
unsigned long data, void *arg)
{
@@ -1301,14 +1301,14 @@ int ieee80211_register_hw(struct ieee802
@@ -1310,14 +1310,14 @@ int ieee80211_register_hw(struct ieee802
wiphy_unlock(hw->wiphy);
rtnl_unlock();
-#ifdef CONFIG_INET
@ -35,7 +35,7 @@
local->ifa6_notifier.notifier_call = ieee80211_ifa6_changed;
result = register_inet6addr_notifier(&local->ifa6_notifier);
if (result)
@@ -1317,13 +1317,13 @@ int ieee80211_register_hw(struct ieee802
@@ -1326,13 +1326,13 @@ int ieee80211_register_hw(struct ieee802
return 0;
@ -52,7 +52,7 @@
fail_ifa:
#endif
wiphy_unregister(local->hw.wiphy);
@@ -1351,10 +1351,10 @@ void ieee80211_unregister_hw(struct ieee
@@ -1360,10 +1360,10 @@ void ieee80211_unregister_hw(struct ieee
tasklet_kill(&local->tx_pending_tasklet);
tasklet_kill(&local->tasklet);

View File

@ -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) {

View File

@ -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
@@ -852,7 +852,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
@@ -1309,7 +1309,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];
@@ -1352,7 +1352,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];
@@ -1379,17 +1379,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)
@@ -1402,8 +1391,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);
}
@@ -1446,7 +1434,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);
@@ -3281,8 +3268,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;

View File

@ -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
@@ -3335,8 +3335,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);

View File

@ -1,565 +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
@@ -1300,6 +1300,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),
@@ -1332,6 +1334,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),
};
/**
@@ -1653,11 +1656,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),
};
/**
@@ -2393,6 +2400,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 {
@@ -2446,6 +2456,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
@@ -4202,6 +4213,9 @@ struct ieee80211_ops {
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/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
@@ -815,7 +815,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 */
@@ -835,7 +835,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) &&
@@ -848,10 +848,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;
}
@@ -869,7 +880,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
@@ -4099,7 +4099,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);
@@ -4212,6 +4214,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);
@@ -4258,6 +4271,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;
+
+ dev_sw_netstats_rx_add(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)
{
@@ -4278,9 +4393,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
@@ -4354,32 +4466,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;
@@ -4391,12 +4477,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);
@@ -4405,62 +4485,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;
-
- dev_sw_netstats_rx_add(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;
}
@@ -4514,6 +4546,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.
@@ -4753,13 +4826,17 @@ 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 (!(status->flag & RX_FLAG_8023))
+ skb = ieee80211_rx_monitor(local, skb, rate);
if (skb) {
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);
}
kcov_remote_stop();
--- 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

View File

@ -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, &ethertype, 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
@@ -1182,9 +1182,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))
@@ -5393,6 +5391,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;
@@ -5415,8 +5414,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);
@@ -5433,10 +5431,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);

View File

@ -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));

View File

@ -11,7 +11,7 @@ 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
@@ -2990,15 +2990,19 @@ static void mac80211_hwsim_he_capab(stru
{
u16 n_iftype_data;
@ -34,7 +34,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
return;
}
@@ -3265,6 +3269,12 @@ static int mac80211_hwsim_new_radio(stru
@@ -3288,6 +3292,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;
@ -47,7 +47,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
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
@@ -3298,6 +3308,13 @@ static int mac80211_hwsim_new_radio(stru
continue;
}
@ -61,7 +61,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
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
@@ -3311,10 +3328,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;

View File

@ -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];

View File

@ -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;

View File

@ -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;

View File

@ -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)

View File

@ -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];
}

View File

@ -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);

View File

@ -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++)

View File

@ -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));
}
/*

View File

@ -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)))

View File

@ -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;

View File

@ -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;

View File

@ -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 */

View File

@ -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);

View File

@ -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];

View File

@ -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,

View File

@ -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
@@ -1109,8 +1078,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
@@ -1155,7 +1122,7 @@ minstrel_ht_txstat_valid(struct minstrel
}
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_
@@ -1170,11 +1137,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
@@ -1208,7 +1171,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
@@ -1254,18 +1217,13 @@ minstrel_ht_tx_status(void *priv, struct
/*
* check for sudden death of spatial multiplexing,
* downgrade to a lower number of streams if necessary.

View File

@ -48,7 +48,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
spin_unlock_bh(&fq->lock);
}
@@ -3815,6 +3824,9 @@ bool ieee80211_txq_airtime_check(struct
@@ -3853,6 +3862,9 @@ bool ieee80211_txq_airtime_check(struct
if (!txq->sta)
return true;

View File

@ -9,7 +9,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -4142,6 +4142,9 @@ static bool ieee80211_tx_8023(struct iee
@@ -4180,6 +4180,9 @@ static bool ieee80211_tx_8023(struct iee
unsigned long flags;
int q = info->hw_queue;

View File

@ -11,7 +11,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -6186,6 +6186,11 @@ enum rate_control_capabilities {
@@ -6188,6 +6188,11 @@ enum rate_control_capabilities {
* otherwise the NSS difference doesn't bother us.
*/
RATE_CTRL_CAPA_VHT_EXT_NSS_BW = BIT(0),
@ -25,7 +25,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
struct rate_control_ops {
--- a/net/mac80211/rc80211_minstrel_ht.c
+++ b/net/mac80211/rc80211_minstrel_ht.c
@@ -1144,29 +1144,6 @@ minstrel_downgrade_prob_rate(struct mins
@@ -1142,29 +1142,6 @@ minstrel_downgrade_prob_rate(struct mins
}
static void
@ -55,7 +55,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband,
void *priv_sta, struct ieee80211_tx_status *st)
{
@@ -1461,10 +1438,6 @@ minstrel_ht_get_rate(void *priv, struct
@@ -1459,10 +1436,6 @@ minstrel_ht_get_rate(void *priv, struct
struct minstrel_priv *mp = priv;
u16 sample_idx;
@ -66,7 +66,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
info->flags |= mi->tx_flags;
#ifdef CPTCFG_MAC80211_DEBUGFS
@@ -1870,6 +1843,7 @@ static u32 minstrel_ht_get_expected_thro
@@ -1868,6 +1841,7 @@ static u32 minstrel_ht_get_expected_thro
static const struct rate_control_ops mac80211_minstrel_ht = {
.name = "minstrel_ht",
@ -76,7 +76,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
.rate_init = minstrel_ht_rate_init,
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -3902,6 +3902,29 @@ void ieee80211_txq_schedule_start(struct
@@ -3940,6 +3940,29 @@ void ieee80211_txq_schedule_start(struct
}
EXPORT_SYMBOL(ieee80211_txq_schedule_start);
@ -106,7 +106,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
void __ieee80211_subif_start_xmit(struct sk_buff *skb,
struct net_device *dev,
u32 info_flags,
@@ -3932,6 +3955,8 @@ void __ieee80211_subif_start_xmit(struct
@@ -3970,6 +3993,8 @@ void __ieee80211_subif_start_xmit(struct
skb_get_hash(skb);
}
@ -115,7 +115,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
if (sta) {
struct ieee80211_fast_tx *fast_tx;
@@ -4195,6 +4220,8 @@ static void ieee80211_8023_xmit(struct i
@@ -4233,6 +4258,8 @@ static void ieee80211_8023_xmit(struct i
memset(info, 0, sizeof(*info));

View File

@ -29,7 +29,7 @@ Signed-off-by: Ryder Lee <ryder.lee@mediatek.com>
CALL_TXH(ieee80211_tx_h_michael_mic_add);
CALL_TXH(ieee80211_tx_h_sequence);
CALL_TXH(ieee80211_tx_h_fragment);
@@ -3353,15 +3354,21 @@ out:
@@ -3386,15 +3387,21 @@ out:
* Can be called while the sta lock is held. Anything that can cause packets to
* be generated will cause deadlock!
*/
@ -55,7 +55,7 @@ Signed-off-by: Ryder Lee <ryder.lee@mediatek.com>
if (key)
info->control.hw_key = &key->conf;
@@ -3410,6 +3417,8 @@ static void ieee80211_xmit_fast_finish(s
@@ -3443,6 +3450,8 @@ static void ieee80211_xmit_fast_finish(s
break;
}
}
@ -64,7 +64,7 @@ Signed-off-by: Ryder Lee <ryder.lee@mediatek.com>
}
static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
@@ -3513,24 +3522,17 @@ static bool ieee80211_xmit_fast(struct i
@@ -3546,24 +3555,17 @@ static bool ieee80211_xmit_fast(struct i
tx.sta = sta;
tx.key = fast_tx->key;
@ -97,7 +97,7 @@ Signed-off-by: Ryder Lee <ryder.lee@mediatek.com>
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
sdata = container_of(sdata->bss,
@@ -3641,8 +3643,12 @@ begin:
@@ -3674,8 +3676,12 @@ begin:
(tx.key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV))
pn_offs = ieee80211_hdrlen(hdr->frame_control);

View File

@ -81,7 +81,7 @@ Signed-off-by: Ryder Lee <ryder.lee@mediatek.com>
tx->sta->tx_stats.last_rate = txrc.reported_rate;
} else if (tx->sta)
tx->sta->tx_stats.last_rate = txrc.reported_rate;
@@ -3631,8 +3633,16 @@ begin:
@@ -3664,8 +3666,16 @@ begin:
else
info->flags &= ~IEEE80211_TX_CTL_AMPDU;
@ -101,7 +101,7 @@ Signed-off-by: Ryder Lee <ryder.lee@mediatek.com>
struct sta_info *sta = container_of(txq->sta, struct sta_info,
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -6754,4 +6754,22 @@ struct sk_buff *ieee80211_get_fils_disco
@@ -6761,4 +6761,22 @@ struct sk_buff *ieee80211_get_fils_disco
struct sk_buff *
ieee80211_get_unsol_bcast_probe_resp_tmpl(struct ieee80211_hw *hw,
struct ieee80211_vif *vif);

View File

@ -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
@@ -1450,7 +1450,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;

View File

@ -80,7 +80,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
if (tid_tx) {
bool queued;
@@ -3918,29 +3948,6 @@ void ieee80211_txq_schedule_start(struct
@@ -3956,29 +3986,6 @@ void ieee80211_txq_schedule_start(struct
}
EXPORT_SYMBOL(ieee80211_txq_schedule_start);

View File

@ -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
@@ -1147,6 +1147,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
@@ -3858,6 +3858,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)
{
@@ -3867,6 +3869,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;

View File

@ -22,7 +22,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
*/
#ifndef IEEE80211_I_H
@@ -854,9 +854,12 @@ struct txq_info {
@@ -843,9 +843,12 @@ struct txq_info {
struct fq_tin tin;
struct codel_vars def_cvars;
struct codel_stats cstats;

View File

@ -50,7 +50,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -6578,9 +6578,6 @@ static inline void ieee80211_txq_schedul
@@ -6585,9 +6585,6 @@ static inline void ieee80211_txq_schedul
{
}
@ -60,7 +60,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
/**
* ieee80211_schedule_txq - schedule a TXQ for transmission
*
@@ -6593,11 +6590,7 @@ void __ieee80211_schedule_txq(struct iee
@@ -6600,11 +6597,7 @@ void __ieee80211_schedule_txq(struct iee
* The driver may call this function if it has buffered packets for
* this TXQ internally.
*/
@ -73,7 +73,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
/**
* ieee80211_return_txq - return a TXQ previously acquired by ieee80211_next_txq()
@@ -6609,12 +6602,8 @@ ieee80211_schedule_txq(struct ieee80211_
@@ -6616,12 +6609,8 @@ ieee80211_schedule_txq(struct ieee80211_
* The driver may set force=true if it has buffered packets for this TXQ
* internally.
*/
@ -227,7 +227,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
#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
@@ -631,7 +671,11 @@ void debugfs_hw_add(struct ieee80211_loc
if (local->ops->wake_tx_queue)
DEBUGFS_ADD_MODE(aqm, 0600);
@ -355,7 +355,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -846,20 +846,16 @@ enum txq_info_flags {
@@ -835,20 +835,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
@ -378,7 +378,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
unsigned long flags;
/* keep last! */
@@ -938,6 +934,8 @@ struct ieee80211_sub_if_data {
@@ -925,6 +921,8 @@ struct ieee80211_sub_if_data {
struct ieee80211_tx_queue_params tx_conf[IEEE80211_NUM_ACS];
struct mac80211_qos_map __rcu *qos_map;
@ -387,7 +387,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
struct work_struct csa_finalize_work;
bool csa_block_tx; /* write-protected by sdata_lock and local->mtx */
struct cfg80211_chan_def csa_chandef;
@@ -1150,6 +1148,44 @@ enum mac80211_scan_state {
@@ -1137,6 +1135,44 @@ enum mac80211_scan_state {
SCAN_ABORT,
};
@ -432,7 +432,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
DECLARE_STATIC_KEY_FALSE(aql_disable);
struct ieee80211_local {
@@ -1163,13 +1199,8 @@ struct ieee80211_local {
@@ -1150,13 +1186,8 @@ struct ieee80211_local {
struct codel_params cparams;
/* protects active_txqs and txqi->schedule_order */
@ -447,7 +447,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
u32 aql_threshold;
atomic_t aql_total_pending_airtime;
@@ -1587,6 +1618,125 @@ static inline bool txq_has_queue(struct
@@ -1574,6 +1605,125 @@ static inline bool txq_has_queue(struct
return !(skb_queue_empty(&txqi->frags) && !txqi->tin.backlog_packets);
}
@ -573,7 +573,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr)
{
return ether_addr_equal(raddr, addr) ||
@@ -1827,6 +1977,14 @@ int ieee80211_tx_control_port(struct wip
@@ -1814,6 +1964,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);
@ -590,7 +590,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata,
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -2013,6 +2013,9 @@ int ieee80211_if_add(struct ieee80211_lo
@@ -2018,6 +2018,9 @@ int ieee80211_if_add(struct ieee80211_lo
}
}
@ -602,7 +602,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL;
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -691,10 +691,13 @@ struct ieee80211_hw *ieee80211_alloc_hw_
@@ -698,10 +698,13 @@ struct ieee80211_hw *ieee80211_alloc_hw_
spin_lock_init(&local->queue_stop_reason_lock);
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
@ -638,7 +638,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
set_bit(tid, &sta->txq_buffered_tids);
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -424,15 +424,11 @@ struct sta_info *sta_info_alloc(struct i
@@ -426,15 +426,11 @@ struct sta_info *sta_info_alloc(struct i
if (sta_prepare_rate_control(local, sta, gfp))
goto free_txq;
@ -655,7 +655,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
}
for (i = 0; i < IEEE80211_NUM_TIDS; i++)
@@ -1894,24 +1890,59 @@ void ieee80211_sta_set_buffered(struct i
@@ -1893,24 +1889,59 @@ void ieee80211_sta_set_buffered(struct i
}
EXPORT_SYMBOL(ieee80211_sta_set_buffered);
@ -727,7 +727,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
}
EXPORT_SYMBOL(ieee80211_sta_register_airtime);
@@ -2360,7 +2391,7 @@ void sta_set_sinfo(struct sta_info *sta,
@@ -2354,7 +2385,7 @@ void sta_set_sinfo(struct sta_info *sta,
}
if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_AIRTIME_WEIGHT))) {
@ -765,7 +765,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
struct sta_info;
@@ -487,7 +494,6 @@ struct ieee80211_sta_rx_stats {
@@ -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
@ -773,7 +773,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
* @ampdu_mlme: A-MPDU state machine state
* @mesh: mesh STA information
* @debugfs_dir: debug filesystem directory dentry
@@ -617,7 +623,6 @@ struct sta_info {
@@ -646,7 +652,6 @@ struct sta_info {
u16 tid_seq[IEEE80211_QOS_CTL_TID_MASK + 1];
struct airtime_info airtime[IEEE80211_NUM_ACS];
@ -839,7 +839,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
}
void ieee80211_txq_set_params(struct ieee80211_local *local)
@@ -3768,102 +3767,259 @@ EXPORT_SYMBOL(ieee80211_tx_dequeue);
@@ -3801,102 +3800,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);
@ -999,7 +999,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+{
+ struct airtime_info *air_info, *tmp;
+ u64 weight_sum = 0;
+
+ if (unlikely(!now))
+ now = ktime_get_boottime_ns();
+
@ -1008,8 +1008,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+ if (!force && (air_sched->last_weight_update <
+ now - AIRTIME_ACTIVE_DURATION))
+ return;
- if (txqi->schedule_round == local->schedule_round[ac])
+
+ list_for_each_entry_safe(air_info, tmp,
+ &air_sched->active_list, list) {
+ if (airtime_is_active(air_info, now))
@ -1020,7 +1019,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+ 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)
@ -1032,7 +1031,8 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+ 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);
+
@ -1161,7 +1161,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
struct ieee80211_local *local = hw_to_local(hw);
if (!wiphy_ext_feature_isset(local->hw.wiphy, NL80211_EXT_FEATURE_AQL))
@@ -3878,15 +4034,12 @@ bool ieee80211_txq_airtime_check(struct
@@ -3911,15 +4067,12 @@ bool ieee80211_txq_airtime_check(struct
if (unlikely(txq->tid == IEEE80211_NUM_TIDS))
return true;
@ -1179,7 +1179,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
return true;
return false;
@@ -3896,60 +4049,59 @@ EXPORT_SYMBOL(ieee80211_txq_airtime_chec
@@ -3929,60 +4082,59 @@ EXPORT_SYMBOL(ieee80211_txq_airtime_chec
bool ieee80211_txq_may_transmit(struct ieee80211_hw *hw,
struct ieee80211_txq *txq)
{
@ -1200,11 +1200,11 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
- goto out;
+ if (!ieee80211_txq_airtime_check(hw, txq))
+ return false;
- if (list_empty(&txqi->schedule_order))
+
+ 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;
@ -1223,7 +1223,6 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
- 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.
+ */
@ -1232,14 +1231,15 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+ 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;
+ if (air_sched->v_t < air_info->v_t)
+ airtime_catchup_v_t(air_sched, air_info->v_t, now);
+ }
-
- 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]);

View File

@ -14,7 +14,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -3280,6 +3280,9 @@ static bool ieee80211_amsdu_aggregate(st
@@ -3313,6 +3313,9 @@ static bool ieee80211_amsdu_aggregate(st
if (!ieee80211_hw_check(&local->hw, TX_AMSDU))
return false;

View File

@ -51,7 +51,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
* struct iface_combination_params - input parameters for interface combinations
*
* Used to pass interface combination parameters
@@ -3975,6 +3996,8 @@ struct mgmt_frame_regs {
@@ -3983,6 +4004,8 @@ struct mgmt_frame_regs {
* given TIDs. This callback may sleep.
*
* @set_sar_specs: Update the SAR (TX power) settings.
@ -60,7 +60,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
*/
struct cfg80211_ops {
int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@@ -4302,6 +4325,9 @@ struct cfg80211_ops {
@@ -4310,6 +4333,9 @@ struct cfg80211_ops {
const u8 *peer, u8 tids);
int (*set_sar_specs)(struct wiphy *wiphy,
struct cfg80211_sar_specs *sar);
@ -70,7 +70,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
};
/*
@@ -8089,4 +8115,70 @@ void cfg80211_update_owe_info_event(stru
@@ -8193,4 +8219,70 @@ void cfg80211_update_owe_info_event(stru
*/
void cfg80211_bss_flush(struct wiphy *wiphy);
@ -230,10 +230,10 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
NUM_NL80211_EXT_FEATURES,
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -753,6 +753,10 @@ static const struct nla_policy nl80211_p
NL80211_SAE_PWE_BOTH),
@@ -774,6 +774,10 @@ static const struct nla_policy nl80211_p
[NL80211_ATTR_RECONNECT_REQUESTED] = { .type = NLA_REJECT },
[NL80211_ATTR_SAR_SPEC] = NLA_POLICY_NESTED(sar_policy),
[NL80211_ATTR_DISABLE_HE] = { .type = NLA_FLAG },
+ [NL80211_ATTR_OBSS_COLOR_BITMAP] = { .type = NLA_U64 },
+ [NL80211_ATTR_COLOR_CHANGE_COUNT] = { .type = NLA_U8 },
+ [NL80211_ATTR_COLOR_CHANGE_COLOR] = { .type = NLA_U8 },
@ -241,7 +241,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
};
/* policy for the key attributes */
@@ -14659,6 +14663,106 @@ bad_tid_conf:
@@ -14813,6 +14817,106 @@ bad_tid_conf:
return ret;
}
@ -348,7 +348,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
#define NL80211_FLAG_NEED_WIPHY 0x01
#define NL80211_FLAG_NEED_NETDEV 0x02
#define NL80211_FLAG_NEED_RTNL 0x04
@@ -15730,6 +15834,14 @@ static const struct genl_small_ops nl802
@@ -15813,6 +15917,14 @@ static const struct genl_small_ops nl802
.internal_flags = NL80211_FLAG_NEED_WIPHY |
NL80211_FLAG_NEED_RTNL,
},
@ -363,7 +363,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
};
static struct genl_family nl80211_fam __genl_ro_after_init = {
@@ -17361,6 +17473,51 @@ void cfg80211_ch_switch_started_notify(s
@@ -17444,6 +17556,51 @@ void cfg80211_ch_switch_started_notify(s
}
EXPORT_SYMBOL(cfg80211_ch_switch_started_notify);

View File

@ -40,7 +40,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
/* must be last */
u8 drv_priv[] __aligned(sizeof(void *));
};
@@ -4986,6 +4993,16 @@ void ieee80211_csa_finish(struct ieee802
@@ -4988,6 +4995,16 @@ void ieee80211_csa_finish(struct ieee802
bool ieee80211_beacon_cntdwn_is_complete(struct ieee80211_vif *vif);
/**
@ -57,7 +57,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
* ieee80211_proberesp_get - retrieve a Probe Response template
* @hw: pointer obtained from ieee80211_alloc_hw().
* @vif: &struct ieee80211_vif pointer from the add_interface callback.
@@ -6745,6 +6762,18 @@ ieee80211_get_unsol_bcast_probe_resp_tmp
@@ -6752,6 +6769,18 @@ ieee80211_get_unsol_bcast_probe_resp_tmp
struct ieee80211_vif *vif);
/**
@ -411,7 +411,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
};
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -259,6 +259,12 @@ struct ieee80211_csa_settings {
@@ -248,6 +248,12 @@ struct ieee80211_csa_settings {
u8 count;
};
@ -424,7 +424,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
struct beacon_data {
u8 *head, *tail;
int head_len, tail_len;
@@ -940,6 +946,8 @@ struct ieee80211_sub_if_data {
@@ -927,6 +933,8 @@ struct ieee80211_sub_if_data {
bool csa_block_tx; /* write-protected by sdata_lock and local->mtx */
struct cfg80211_chan_def csa_chandef;
@ -433,7 +433,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
struct list_head assigned_chanctx_list; /* protected by chanctx_mtx */
struct list_head reserved_chanctx_list; /* protected by chanctx_mtx */
@@ -1906,6 +1914,9 @@ void ieee80211_csa_finalize_work(struct
@@ -1893,6 +1901,9 @@ void ieee80211_csa_finalize_work(struct
int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_csa_settings *params);
@ -445,7 +445,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
NETIF_F_HW_CSUM | NETIF_F_SG | \
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -458,6 +458,7 @@ static void ieee80211_do_stop(struct iee
@@ -461,6 +461,7 @@ static void ieee80211_do_stop(struct iee
sdata_unlock(sdata);
cancel_work_sync(&sdata->csa_finalize_work);
@ -453,7 +453,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
cancel_delayed_work_sync(&sdata->dfs_cac_timer_work);
@@ -1569,6 +1570,7 @@ static void ieee80211_setup_sdata(struct
@@ -1572,6 +1573,7 @@ static void ieee80211_setup_sdata(struct
INIT_WORK(&sdata->work, ieee80211_iface_work);
INIT_WORK(&sdata->recalc_smps, ieee80211_recalc_smps_work);
INIT_WORK(&sdata->csa_finalize_work, ieee80211_csa_finalize_work);
@ -463,7 +463,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -4740,11 +4740,11 @@ static int ieee80211_beacon_add_tim(stru
@@ -4773,11 +4773,11 @@ static int ieee80211_beacon_add_tim(stru
static void ieee80211_set_beacon_cntdwn(struct ieee80211_sub_if_data *sdata,
struct beacon_data *beacon)
{
@ -477,7 +477,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
switch (sdata->vif.type) {
case NL80211_IFTYPE_AP:
@@ -4764,21 +4764,27 @@ static void ieee80211_set_beacon_cntdwn(
@@ -4797,21 +4797,27 @@ static void ieee80211_set_beacon_cntdwn(
}
rcu_read_lock();
@ -514,7 +514,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
}
rcu_read_unlock();
}
@@ -4988,6 +4994,7 @@ __ieee80211_beacon_get(struct ieee80211_
@@ -5021,6 +5027,7 @@ __ieee80211_beacon_get(struct ieee80211_
if (offs) {
offs->tim_offset = beacon->head_len;
offs->tim_length = skb->len - beacon->head_len;

View File

@ -27,7 +27,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -4223,6 +4223,11 @@ struct ieee80211_ops {
@@ -4225,6 +4225,11 @@ struct ieee80211_ops {
void (*sta_set_decap_offload)(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta, bool enabled);
@ -84,7 +84,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
#endif /* __MAC80211_DRIVER_OPS */
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -962,6 +962,7 @@ struct ieee80211_sub_if_data {
@@ -949,6 +949,7 @@ struct ieee80211_sub_if_data {
struct work_struct work;
struct sk_buff_head skb_queue;
@ -92,7 +92,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
u8 needed_rx_chains;
enum ieee80211_smps_mode smps_mode;
@@ -2099,6 +2100,11 @@ ieee80211_he_op_ie_to_bss_conf(struct ie
@@ -2086,6 +2087,11 @@ ieee80211_he_op_ie_to_bss_conf(struct ie
/* S1G */
void ieee80211_s1g_sta_rate_init(struct sta_info *sta);
@ -106,7 +106,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata,
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -555,6 +555,7 @@ static void ieee80211_do_stop(struct iee
@@ -551,6 +551,7 @@ static void ieee80211_do_stop(struct iee
*/
ieee80211_free_keys(sdata, true);
skb_queue_purge(&sdata->skb_queue);
@ -114,7 +114,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
}
spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
@@ -1029,6 +1030,7 @@ int ieee80211_add_virtual_monitor(struct
@@ -1032,6 +1033,7 @@ int ieee80211_add_virtual_monitor(struct
}
skb_queue_head_init(&sdata->skb_queue);
@ -122,7 +122,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
INIT_WORK(&sdata->work, ieee80211_iface_work);
return 0;
@@ -1370,6 +1372,24 @@ static void ieee80211_if_setup_no_queue(
@@ -1373,6 +1375,24 @@ static void ieee80211_if_setup_no_queue(
dev->priv_flags |= IFF_NO_QUEUE;
}
@ -147,7 +147,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
static void ieee80211_iface_work(struct work_struct *work)
{
struct ieee80211_sub_if_data *sdata =
@@ -1448,6 +1468,16 @@ static void ieee80211_iface_work(struct
@@ -1451,6 +1471,16 @@ static void ieee80211_iface_work(struct
WARN_ON(1);
break;
}
@ -164,7 +164,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
} else if (ieee80211_is_ext(mgmt->frame_control)) {
if (sdata->vif.type == NL80211_IFTYPE_STATION)
ieee80211_sta_rx_queued_ext(sdata, skb);
@@ -1504,6 +1534,12 @@ static void ieee80211_iface_work(struct
@@ -1507,6 +1537,12 @@ static void ieee80211_iface_work(struct
kcov_remote_stop();
}
@ -177,7 +177,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
/* then other type-dependent work */
switch (sdata->vif.type) {
case NL80211_IFTYPE_STATION:
@@ -1567,6 +1603,7 @@ static void ieee80211_setup_sdata(struct
@@ -1570,6 +1606,7 @@ static void ieee80211_setup_sdata(struct
}
skb_queue_head_init(&sdata->skb_queue);
@ -187,7 +187,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
INIT_WORK(&sdata->csa_finalize_work, ieee80211_csa_finalize_work);
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -3116,6 +3116,68 @@ ieee80211_rx_h_mgmt_check(struct ieee802
@@ -3197,6 +3197,68 @@ ieee80211_rx_h_mgmt_check(struct ieee802
return RX_CONTINUE;
}
@ -256,7 +256,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
static ieee80211_rx_result debug_noinline
ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
{
@@ -3395,6 +3457,17 @@ ieee80211_rx_h_action(struct ieee80211_r
@@ -3476,6 +3538,17 @@ ieee80211_rx_h_action(struct ieee80211_r
!mesh_path_sel_is_hwmp(sdata))
break;
goto queue;

View File

@ -12,7 +12,7 @@ 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
@@ -3656,7 +3656,7 @@ ath11k_mac_filter_he_cap_mesh(struct iee
@@ -3813,7 +3813,7 @@ ath11k_mac_filter_he_cap_mesh(struct iee
IEEE80211_HE_MAC_CAP4_BQR;
he_cap_elem->mac_cap_info[4] &= ~m;
@ -21,7 +21,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
IEEE80211_HE_MAC_CAP5_UL_2x996_TONE_RU |
IEEE80211_HE_MAC_CAP5_PUNCTURED_SOUNDING |
IEEE80211_HE_MAC_CAP5_HT_VHT_TRIG_FRAME_RX;
@@ -3666,7 +3666,7 @@ ath11k_mac_filter_he_cap_mesh(struct iee
@@ -3823,7 +3823,7 @@ ath11k_mac_filter_he_cap_mesh(struct iee
IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO;
he_cap_elem->phy_cap_info[2] &= ~m;
@ -30,7 +30,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_MASK |
IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_MASK;
he_cap_elem->phy_cap_info[3] &= ~m;
@@ -3678,13 +3678,13 @@ ath11k_mac_filter_he_cap_mesh(struct iee
@@ -3835,13 +3835,13 @@ ath11k_mac_filter_he_cap_mesh(struct iee
he_cap_elem->phy_cap_info[5] &= ~m;
m = IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_75_MU |
@ -49,7 +49,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
he_cap_elem->phy_cap_info[7] &= ~m;
--- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c
@@ -423,8 +423,8 @@ mt7915_set_stream_he_txbf_caps(struct ie
@@ -424,8 +424,8 @@ mt7915_set_stream_he_txbf_caps(struct ie
IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_MASK;
elem->phy_cap_info[5] &= ~c;
@ -60,7 +60,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
elem->phy_cap_info[6] &= ~c;
elem->phy_cap_info[7] &= ~IEEE80211_HE_PHY_CAP7_MAX_NC_MASK;
@@ -461,8 +461,8 @@ mt7915_set_stream_he_txbf_caps(struct ie
@@ -465,8 +465,8 @@ mt7915_set_stream_he_txbf_caps(struct ie
c = (nss - 1) | (max_t(int, le16_to_cpu(mcs->tx_mcs_160), 1) << 3);
elem->phy_cap_info[5] |= c;
@ -69,13 +69,38 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+ c = IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMING_FB |
+ IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMING_PARTIAL_BW_FB;
elem->phy_cap_info[6] |= c;
}
/* the maximum cap is 4 x 3, (Nr, Nc) = (3, 2) */
@@ -589,7 +589,7 @@ mt7915_init_he_caps(struct mt7915_phy *p
IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE |
IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT;
he_cap_elem->phy_cap_info[7] |=
- IEEE80211_HE_PHY_CAP7_POWER_BOOST_FACTOR_AR |
+ IEEE80211_HE_PHY_CAP7_POWER_BOOST_FACTOR_SUPP |
IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI;
he_cap_elem->phy_cap_info[8] |=
IEEE80211_HE_PHY_CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G |
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
@@ -1840,9 +1840,9 @@ mt7915_mcu_sta_bfer_he(struct ieee80211_
bf->tx_mode = MT_PHY_TYPE_HE_SU;
mt7915_mcu_sta_sounding_rate(bf);
- bf->trigger_su = HE_PHY(CAP6_TRIG_SU_BEAMFORMER_FB,
+ bf->trigger_su = HE_PHY(CAP6_TRIG_SU_BEAMFORMING_FB,
pe->phy_cap_info[6]);
- bf->trigger_mu = HE_PHY(CAP6_TRIG_MU_BEAMFORMER_FB,
+ bf->trigger_mu = HE_PHY(CAP6_TRIG_MU_BEAMFORMING_PARTIAL_BW_FB,
pe->phy_cap_info[6]);
bfer_nr = HE_PHY(CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK,
ve->phy_cap_info[5]);
--- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c
@@ -107,7 +107,7 @@ mt7921_init_he_caps(struct mt7921_phy *p
IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE |
IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT;
he_cap_elem->phy_cap_info[7] |=
- IEEE80211_HE_PHY_CAP7_POWER_BOOST_FACTOR_AR |
+ IEEE80211_HE_PHY_CAP7_POWER_BOOST_FACTOR_SUPP |
IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI;
he_cap_elem->phy_cap_info[8] |=
@ -185,8 +210,14 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
PFLAG_RANGE(PHY, 7, MAX_NC, 0, 1, 1, "MAX-NC-%d");
--- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
@@ -587,7 +587,7 @@ static const struct ieee80211_sband_ifty
@@ -583,11 +583,11 @@ static const struct ieee80211_sband_ifty
IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_2 |
IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_2,
.phy_cap_info[6] =
- IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMER_FB |
- IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMER_FB |
+ IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMING_FB |
+ IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMING_PARTIAL_BW_FB |
IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT,
.phy_cap_info[7] =
- IEEE80211_HE_PHY_CAP7_POWER_BOOST_FACTOR_AR |

View File

@ -11,7 +11,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
--- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
@@ -554,7 +554,7 @@ static const struct ieee80211_sband_ifty
@@ -552,7 +552,7 @@ static const struct ieee80211_sband_ifty
IEEE80211_HE_MAC_CAP3_OMI_CONTROL |
IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_VHT_2,
.mac_cap_info[4] =
@ -42,7 +42,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
he_cap_elem->phy_cap_info[0] =
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
@@ -1325,7 +1325,7 @@ mt7915_mcu_sta_he_tlv(struct sk_buff *sk
@@ -1343,7 +1343,7 @@ mt7915_mcu_sta_he_tlv(struct sk_buff *sk
if (elem->mac_cap_info[3] & IEEE80211_HE_MAC_CAP3_OMI_CONTROL)
cap |= STA_REC_HE_CAP_OM;
@ -75,7 +75,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -2796,7 +2796,7 @@ static const struct ieee80211_sband_ifty
@@ -2818,7 +2818,7 @@ static const struct ieee80211_sband_ifty
.mac_cap_info[3] =
IEEE80211_HE_MAC_CAP3_OMI_CONTROL |
IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_VHT_2,
@ -84,7 +84,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
.phy_cap_info[1] =
IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK |
IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A |
@@ -2840,7 +2840,7 @@ static const struct ieee80211_sband_ifty
@@ -2862,7 +2862,7 @@ static const struct ieee80211_sband_ifty
.mac_cap_info[3] =
IEEE80211_HE_MAC_CAP3_OMI_CONTROL |
IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_VHT_2,
@ -93,7 +93,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
.phy_cap_info[1] =
IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK |
IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A |
@@ -2886,7 +2886,7 @@ static const struct ieee80211_sband_ifty
@@ -2908,7 +2908,7 @@ static const struct ieee80211_sband_ifty
.mac_cap_info[3] =
IEEE80211_HE_MAC_CAP3_OMI_CONTROL |
IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_VHT_2,
@ -102,7 +102,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
.phy_cap_info[0] =
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G |
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G |
@@ -2934,7 +2934,7 @@ static const struct ieee80211_sband_ifty
@@ -2956,7 +2956,7 @@ static const struct ieee80211_sband_ifty
.mac_cap_info[3] =
IEEE80211_HE_MAC_CAP3_OMI_CONTROL |
IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_VHT_2,

View File

@ -27,7 +27,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
if (sta->vht_cap.vht_supported)
--- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
@@ -552,7 +552,7 @@ static const struct ieee80211_sband_ifty
@@ -550,7 +550,7 @@ static const struct ieee80211_sband_ifty
IEEE80211_HE_MAC_CAP2_32BIT_BA_BITMAP,
.mac_cap_info[3] =
IEEE80211_HE_MAC_CAP3_OMI_CONTROL |
@ -47,7 +47,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
.mac_cap_info[5] =
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -2795,7 +2795,7 @@ static const struct ieee80211_sband_ifty
@@ -2817,7 +2817,7 @@ static const struct ieee80211_sband_ifty
IEEE80211_HE_MAC_CAP2_ACK_EN,
.mac_cap_info[3] =
IEEE80211_HE_MAC_CAP3_OMI_CONTROL |
@ -56,7 +56,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
.mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU,
.phy_cap_info[1] =
IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK |
@@ -2839,7 +2839,7 @@ static const struct ieee80211_sband_ifty
@@ -2861,7 +2861,7 @@ static const struct ieee80211_sband_ifty
IEEE80211_HE_MAC_CAP2_ACK_EN,
.mac_cap_info[3] =
IEEE80211_HE_MAC_CAP3_OMI_CONTROL |
@ -65,7 +65,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
.mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU,
.phy_cap_info[1] =
IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK |
@@ -2885,7 +2885,7 @@ static const struct ieee80211_sband_ifty
@@ -2907,7 +2907,7 @@ static const struct ieee80211_sband_ifty
IEEE80211_HE_MAC_CAP2_ACK_EN,
.mac_cap_info[3] =
IEEE80211_HE_MAC_CAP3_OMI_CONTROL |
@ -74,7 +74,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
.mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU,
.phy_cap_info[0] =
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G |
@@ -2933,7 +2933,7 @@ static const struct ieee80211_sband_ifty
@@ -2955,7 +2955,7 @@ static const struct ieee80211_sband_ifty
IEEE80211_HE_MAC_CAP2_ACK_EN,
.mac_cap_info[3] =
IEEE80211_HE_MAC_CAP3_OMI_CONTROL |

View File

@ -5,7 +5,7 @@ and we should ignore this.
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -614,21 +614,6 @@ static int wiphy_verify_combinations(str
@@ -637,21 +637,6 @@ static int wiphy_verify_combinations(str
c->limits[j].max > 1))
return -EINVAL;

View File

@ -1,6 +1,6 @@
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -3810,6 +3810,7 @@ struct mgmt_frame_regs {
@@ -3818,6 +3818,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
@ -8,7 +8,7 @@
*
* @rfkill_poll: polls the hw rfkill line, use cfg80211 reporting
* functions to adjust rfkill hw state
@@ -4134,6 +4135,7 @@ struct cfg80211_ops {
@@ -4142,6 +4143,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);
@ -87,7 +87,7 @@
CFG80211_TESTMODE_DUMP(ieee80211_testmode_dump)
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1441,6 +1441,7 @@ struct ieee80211_local {
@@ -1428,6 +1428,7 @@ struct ieee80211_local {
int dynamic_ps_forced_timeout;
int user_power_level; /* in dBm, for all interfaces */
@ -119,7 +119,7 @@
if (local->hw.conf.power_level != power) {
changed |= IEEE80211_CONF_CHANGE_POWER;
local->hw.conf.power_level = power;
@@ -663,6 +669,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_
@@ -670,6 +676,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;
@ -129,7 +129,7 @@
local->hw.max_mtu = IEEE80211_MAX_DATA_LEN;
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -757,6 +757,7 @@ static const struct nla_policy nl80211_p
@@ -778,6 +778,7 @@ static const struct nla_policy nl80211_p
[NL80211_ATTR_COLOR_CHANGE_COUNT] = { .type = NLA_U8 },
[NL80211_ATTR_COLOR_CHANGE_COLOR] = { .type = NLA_U8 },
[NL80211_ATTR_COLOR_CHANGE_ELEMS] = NLA_POLICY_NESTED(nl80211_policy),
@ -137,11 +137,10 @@
};
/* policy for the key attributes */
@@ -3296,6 +3297,20 @@ static int nl80211_set_wiphy(struct sk_b
if (result)
return result;
@@ -3315,6 +3316,20 @@ static int nl80211_set_wiphy(struct sk_b
goto out;
}
+
+ if (info->attrs[NL80211_ATTR_WIPHY_ANTENNA_GAIN]) {
+ int idx, dbi = 0;
+
@ -155,6 +154,7 @@
+ if (result)
+ return result;
+ }
if (info->attrs[NL80211_ATTR_WIPHY_ANTENNA_TX] &&
info->attrs[NL80211_ATTR_WIPHY_ANTENNA_RX]) {
+
if (info->attrs[NL80211_ATTR_WIPHY_TX_POWER_SETTING]) {
struct wireless_dev *txp_wdev = wdev;
enum nl80211_tx_power_setting type;

View File

@ -182,7 +182,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -618,7 +618,6 @@ static int ath9k_of_init(struct ath_soft
@@ -617,7 +617,6 @@ static int ath9k_of_init(struct ath_soft
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
enum ath_bus_type bus_type = common->bus_ops->ath_bus_type;
@ -190,7 +190,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
char eeprom_name[100];
int ret;
@@ -641,9 +640,7 @@ static int ath9k_of_init(struct ath_soft
@@ -640,9 +639,7 @@ static int ath9k_of_init(struct ath_soft
ah->ah_flags |= AH_NO_EEP_SWAP;
}