This updates the mac80211 backport.
The removed patches are already integrated in the upstream version.
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
PKG_NAME:=mac80211
-PKG_VERSION:=5.4.36-1
+PKG_VERSION:=5.5.19-1
PKG_RELEASE:=1
-PKG_SOURCE_URL:=@KERNEL/linux/kernel/projects/backports/stable/v5.4.36/
-PKG_HASH:=5b39734986fba3b9c24c521d0499a2dc9cb17267bb58c02d9a520205add2d16b
+PKG_SOURCE_URL:=@KERNEL/linux/kernel/projects/backports/stable/v5.5.19/
+PKG_HASH:=9dd9153df6082eaa079144193a3fab79d200942e1a2a1a80e032c9667b7b92a6
PKG_SOURCE:=backports-$(PKG_VERSION).tar.xz
PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/backports-$(PKG_VERSION)
--- a/drivers/net/wireless/ath/ath9k/ath9k_pci_owl_loader.c
+++ b/drivers/net/wireless/ath/ath9k/ath9k_pci_owl_loader.c
-@@ -104,6 +104,7 @@ static void owl_fw_cb(const struct firmw
+@@ -103,6 +103,7 @@ static void owl_fw_cb(const struct firmw
{
struct pci_dev *pdev = (struct pci_dev *)context;
struct owl_ctx *ctx = (struct owl_ctx *)pci_get_drvdata(pdev);
struct pci_bus *bus;
complete(&ctx->eeprom_load);
-@@ -119,6 +120,16 @@ static void owl_fw_cb(const struct firmw
+@@ -118,6 +119,16 @@ static void owl_fw_cb(const struct firmw
goto release;
}
if (ath9k_pci_fixup(pdev, (const u16 *)fw->data, fw->size))
goto release;
-@@ -138,8 +149,14 @@ release:
+@@ -137,8 +148,14 @@ release:
static const char *owl_get_eeprom_name(struct pci_dev *pdev)
{
struct device *dev = &pdev->dev;
NL80211_RRF_NO_OFDM)
/* We allow IBSS on these on a case by case basis by regulatory domain */
--#define ATH9K_5GHZ_5150_5350 REG_RULE(5150-10, 5350+10, 80, 0, 30,\
-+#define ATH9K_5GHZ_5150_5350 REG_RULE(5150-10, 5240+10, 80, 0, 30, 0),\
+-#define ATH_5GHZ_5150_5350 REG_RULE(5150-10, 5350+10, 80, 0, 30,\
++#define ATH_5GHZ_5150_5350 REG_RULE(5150-10, 5240+10, 80, 0, 30, 0),\
+ REG_RULE(5260-10, 5350+10, 80, 0, 30,\
NL80211_RRF_NO_IR)
- #define ATH9K_5GHZ_5470_5850 REG_RULE(5470-10, 5850+10, 80, 0, 30,\
+ #define ATH_5GHZ_5470_5850 REG_RULE(5470-10, 5850+10, 80, 0, 30,\
NL80211_RRF_NO_IR)
@@ -62,57 +63,56 @@ static struct reg_dmn_pair_mapping *ath_
- #define ATH9K_5GHZ_NO_MIDBAND ATH9K_5GHZ_5150_5350, \
- ATH9K_5GHZ_5725_5850
+ #define ATH_5GHZ_NO_MIDBAND ATH_5GHZ_5150_5350, \
+ ATH_5GHZ_5725_5850
+#define REGD_RULES(...) \
+ .reg_rules = { __VA_ARGS__ }, \
.alpha2 = "99",
- .reg_rules = {
+ REGD_RULES(
- ATH9K_2GHZ_ALL,
- ATH9K_5GHZ_ALL,
+ ATH_2GHZ_ALL,
+ ATH_5GHZ_ALL,
- }
+ )
};
.alpha2 = "99",
- .reg_rules = {
+ REGD_RULES(
- ATH9K_2GHZ_CH01_11,
- ATH9K_2GHZ_CH12_13,
- ATH9K_5GHZ_NO_MIDBAND,
+ ATH_2GHZ_CH01_11,
+ ATH_2GHZ_CH12_13,
+ ATH_5GHZ_NO_MIDBAND,
- }
+ )
};
.alpha2 = "99",
- .reg_rules = {
+ REGD_RULES(
- ATH9K_2GHZ_CH01_11,
- ATH9K_5GHZ_NO_MIDBAND,
+ ATH_2GHZ_CH01_11,
+ ATH_5GHZ_NO_MIDBAND,
- }
+ )
};
.alpha2 = "99",
- .reg_rules = {
+ REGD_RULES(
- ATH9K_2GHZ_CH01_11,
- ATH9K_5GHZ_ALL,
+ ATH_2GHZ_CH01_11,
+ ATH_5GHZ_ALL,
- }
+ )
};
.alpha2 = "99",
- .reg_rules = {
+ REGD_RULES(
- ATH9K_2GHZ_CH01_11,
- ATH9K_2GHZ_CH12_13,
- ATH9K_5GHZ_ALL,
+ ATH_2GHZ_CH01_11,
+ ATH_2GHZ_CH12_13,
+ ATH_5GHZ_ALL,
- }
+ )
};
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
-@@ -3074,6 +3074,16 @@ int ath10k_core_register(struct ath10k *
+@@ -3105,6 +3105,16 @@ int ath10k_core_register(struct ath10k *
queue_work(ar->workqueue, &ar->register_work);
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
-@@ -8673,6 +8673,21 @@ static int ath10k_mac_init_rd(struct ath
+@@ -8761,6 +8761,21 @@ static int ath10k_mac_init_rd(struct ath
return 0;
}
int ath10k_mac_register(struct ath10k *ar)
{
static const u32 cipher_suites[] = {
-@@ -9000,6 +9015,12 @@ int ath10k_mac_register(struct ath10k *a
+@@ -9088,6 +9103,12 @@ int ath10k_mac_register(struct ath10k *a
ar->hw->weight_multiplier = ATH10K_AIRTIME_WEIGHT_MULTIPLIER;
3 files changed, 52 insertions(+), 23 deletions(-)
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
-@@ -2515,7 +2515,7 @@ static void ath10k_peer_assoc_h_vht(stru
+@@ -2516,7 +2516,7 @@ static void ath10k_peer_assoc_h_vht(stru
const u16 *vht_mcs_mask;
u8 ampdu_factor;
u8 max_nss, vht_mcs;
if (WARN_ON(ath10k_mac_vif_chan(vif, &def)))
return;
-@@ -2575,23 +2575,45 @@ static void ath10k_peer_assoc_h_vht(stru
+@@ -2576,23 +2576,45 @@ static void ath10k_peer_assoc_h_vht(stru
__le16_to_cpu(vht_cap->vht_mcs.tx_highest);
arg->peer_vht_rates.tx_mcs_set = ath10k_peer_assoc_h_vht_limit(
__le16_to_cpu(vht_cap->vht_mcs.tx_mcs_map), vht_mcs_mask);
}
static void ath10k_peer_assoc_h_qos(struct ath10k *ar,
-@@ -2743,9 +2765,9 @@ static int ath10k_peer_assoc_prepare(str
+@@ -2744,9 +2766,9 @@ static int ath10k_peer_assoc_prepare(str
ath10k_peer_assoc_h_crypto(ar, vif, sta, arg);
ath10k_peer_assoc_h_rates(ar, vif, sta, arg);
ath10k_peer_assoc_h_ht(ar, vif, sta, arg);
}
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
-@@ -7552,12 +7552,7 @@ ath10k_wmi_peer_assoc_fill_10_4(struct a
+@@ -7601,12 +7601,7 @@ ath10k_wmi_peer_assoc_fill_10_4(struct a
struct wmi_10_4_peer_assoc_complete_cmd *cmd = buf;
ath10k_wmi_peer_assoc_fill_10_2(ar, buf, arg);
static int
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
-@@ -6478,7 +6478,19 @@ struct wmi_10_2_peer_assoc_complete_cmd
+@@ -6501,7 +6501,19 @@ struct wmi_10_2_peer_assoc_complete_cmd
__le32 info0; /* WMI_PEER_ASSOC_INFO0_ */
} __packed;
2 files changed, 8 insertions(+), 10 deletions(-)
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
-@@ -4575,13 +4575,6 @@ static struct ieee80211_sta_vht_cap ath1
+@@ -4576,13 +4576,6 @@ static struct ieee80211_sta_vht_cap ath1
vht_cap.cap |= val;
}
if ((i < ar->num_rf_chains) && (ar->cfg_tx_chainmask & BIT(i)))
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
-@@ -1700,13 +1700,18 @@ void ath10k_wmi_put_wmi_channel(struct w
+@@ -1713,13 +1713,18 @@ void ath10k_wmi_put_wmi_channel(struct w
flags |= WMI_CHAN_FLAG_HT40_PLUS;
if (arg->chan_radar)
flags |= WMI_CHAN_FLAG_DFS;
WCN36XX=
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
-@@ -24,6 +24,7 @@
+@@ -25,6 +25,7 @@
#include "testmode.h"
#include "wmi-ops.h"
#include "coredump.h"
unsigned int ath10k_debug_mask;
EXPORT_SYMBOL(ath10k_debug_mask);
-@@ -60,6 +61,7 @@ static const struct ath10k_hw_params ath
+@@ -61,6 +62,7 @@ static const struct ath10k_hw_params ath
.dev_id = QCA988X_2_0_DEVICE_ID,
.bus = ATH10K_BUS_PCI,
.name = "qca988x hw2.0",
.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
+@@ -131,6 +133,7 @@ static const struct ath10k_hw_params ath
.dev_id = QCA9887_1_0_DEVICE_ID,
.bus = ATH10K_BUS_PCI,
.name = "qca9887 hw1.0",
.patch_load_addr = QCA9887_HW_1_0_PATCH_LOAD_ADDR,
.uart_pin = 7,
.cc_wraparound_type = ATH10K_HW_CC_WRAP_SHIFTED_ALL,
-@@ -337,6 +340,7 @@ static const struct ath10k_hw_params ath
+@@ -338,6 +341,7 @@ static const struct ath10k_hw_params ath
.dev_id = QCA99X0_2_0_DEVICE_ID,
.bus = ATH10K_BUS_PCI,
.name = "qca99x0 hw2.0",
.patch_load_addr = QCA99X0_HW_2_0_PATCH_LOAD_ADDR,
.uart_pin = 7,
.otp_exe_param = 0x00000700,
-@@ -378,6 +382,7 @@ static const struct ath10k_hw_params ath
+@@ -379,6 +383,7 @@ static const struct ath10k_hw_params ath
.dev_id = QCA9984_1_0_DEVICE_ID,
.bus = ATH10K_BUS_PCI,
.name = "qca9984/qca9994 hw1.0",
.patch_load_addr = QCA9984_HW_1_0_PATCH_LOAD_ADDR,
.uart_pin = 7,
.cc_wraparound_type = ATH10K_HW_CC_WRAP_SHIFTED_EACH,
-@@ -426,6 +431,7 @@ static const struct ath10k_hw_params ath
+@@ -427,6 +432,7 @@ static const struct ath10k_hw_params ath
.dev_id = QCA9888_2_0_DEVICE_ID,
.bus = ATH10K_BUS_PCI,
.name = "qca9888 hw2.0",
.patch_load_addr = QCA9888_HW_2_0_PATCH_LOAD_ADDR,
.uart_pin = 7,
.cc_wraparound_type = ATH10K_HW_CC_WRAP_SHIFTED_EACH,
-@@ -2791,6 +2797,10 @@ int ath10k_core_start(struct ath10k *ar,
+@@ -2822,6 +2828,10 @@ int ath10k_core_start(struct ath10k *ar,
goto err_hif_stop;
}
return 0;
err_hif_stop:
-@@ -3047,9 +3057,18 @@ static void ath10k_core_register_work(st
+@@ -3078,9 +3088,18 @@ static void ath10k_core_register_work(st
goto err_spectral_destroy;
}
err_spectral_destroy:
ath10k_spectral_destroy(ar);
err_debug_destroy:
-@@ -3095,6 +3114,8 @@ void ath10k_core_unregister(struct ath10
+@@ -3126,6 +3145,8 @@ void ath10k_core_unregister(struct ath10
if (!test_bit(ATH10K_FLAG_CORE_REGISTERED, &ar->dev_flags))
return;
#include "htt.h"
#include "htc.h"
-@@ -1170,6 +1171,13 @@ struct ath10k {
+@@ -1179,6 +1180,13 @@ struct ath10k {
} testmode;
struct {
u32 fw_warm_reset_counter;
--- a/drivers/net/wireless/ath/ath10k/hw.h
+++ b/drivers/net/wireless/ath/ath10k/hw.h
-@@ -514,6 +514,7 @@ struct ath10k_hw_params {
+@@ -517,6 +517,7 @@ struct ath10k_hw_params {
const char *name;
u32 patch_load_addr;
int uart_pin;
+#endif /* _LEDS_H_ */
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
-@@ -23,6 +23,7 @@
+@@ -24,6 +24,7 @@
#include "wmi-tlv.h"
#include "wmi-ops.h"
#include "wow.h"
{
--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
-@@ -4367,6 +4367,8 @@ static const struct wmi_ops wmi_tlv_ops
+@@ -4444,6 +4444,8 @@ static const struct wmi_ops wmi_tlv_ops
.gen_echo = ath10k_wmi_tlv_op_gen_echo,
.gen_vdev_spectral_conf = ath10k_wmi_tlv_op_gen_vdev_spectral_conf,
.gen_vdev_spectral_enable = ath10k_wmi_tlv_op_gen_vdev_spectral_enable,
static const struct wmi_peer_flags_map wmi_tlv_peer_flags_map = {
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
-@@ -7372,6 +7372,49 @@ ath10k_wmi_op_gen_peer_set_param(struct
+@@ -7421,6 +7421,49 @@ ath10k_wmi_op_gen_peer_set_param(struct
return skb;
}
static struct sk_buff *
ath10k_wmi_op_gen_set_psmode(struct ath10k *ar, u32 vdev_id,
enum wmi_sta_ps_mode psmode)
-@@ -9029,6 +9072,9 @@ static const struct wmi_ops wmi_ops = {
+@@ -9078,6 +9121,9 @@ static const struct wmi_ops wmi_ops = {
.fw_stats_fill = ath10k_wmi_main_op_fw_stats_fill,
.get_vdev_subtype = ath10k_wmi_op_get_vdev_subtype,
.gen_echo = ath10k_wmi_op_gen_echo,
/* .gen_bcn_tmpl not implemented */
/* .gen_prb_tmpl not implemented */
/* .gen_p2p_go_bcn_ie not implemented */
-@@ -9099,6 +9145,8 @@ static const struct wmi_ops wmi_10_1_ops
+@@ -9148,6 +9194,8 @@ static const struct wmi_ops wmi_10_1_ops
.fw_stats_fill = ath10k_wmi_10x_op_fw_stats_fill,
.get_vdev_subtype = ath10k_wmi_op_get_vdev_subtype,
.gen_echo = ath10k_wmi_op_gen_echo,
/* .gen_bcn_tmpl not implemented */
/* .gen_prb_tmpl not implemented */
/* .gen_p2p_go_bcn_ie not implemented */
-@@ -9171,6 +9219,8 @@ static const struct wmi_ops wmi_10_2_ops
+@@ -9220,6 +9268,8 @@ static const struct wmi_ops wmi_10_2_ops
.gen_delba_send = ath10k_wmi_op_gen_delba_send,
.fw_stats_fill = ath10k_wmi_10x_op_fw_stats_fill,
.get_vdev_subtype = ath10k_wmi_op_get_vdev_subtype,
/* .gen_pdev_enable_adaptive_cca not implemented */
};
-@@ -9242,6 +9292,8 @@ static const struct wmi_ops wmi_10_2_4_o
+@@ -9291,6 +9341,8 @@ static const struct wmi_ops wmi_10_2_4_o
ath10k_wmi_op_gen_pdev_enable_adaptive_cca,
.get_vdev_subtype = ath10k_wmi_10_2_4_op_get_vdev_subtype,
.gen_bb_timing = ath10k_wmi_10_2_4_op_gen_bb_timing,
/* .gen_bcn_tmpl not implemented */
/* .gen_prb_tmpl not implemented */
/* .gen_p2p_go_bcn_ie not implemented */
-@@ -9322,6 +9374,8 @@ static const struct wmi_ops wmi_10_4_ops
+@@ -9371,6 +9423,8 @@ static const struct wmi_ops wmi_10_4_ops
.gen_pdev_bss_chan_info_req = ath10k_wmi_10_2_op_gen_pdev_bss_chan_info,
.gen_echo = ath10k_wmi_op_gen_echo,
.gen_pdev_get_tpc_config = ath10k_wmi_10_2_4_op_gen_pdev_get_tpc_config,
int ath10k_wmi_attach(struct ath10k *ar)
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
-@@ -3005,6 +3005,41 @@ enum wmi_10_4_feature_mask {
+@@ -3007,6 +3007,41 @@ enum wmi_10_4_feature_mask {
};
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
-@@ -1219,6 +1219,10 @@ struct ath10k {
+@@ -1228,6 +1228,10 @@ struct ath10k {
struct ath10k_bus_params bus_param;
struct completion peer_delete_done;
if (ret)
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
-@@ -9032,7 +9032,7 @@ int ath10k_mac_register(struct ath10k *a
+@@ -9120,7 +9120,7 @@ int ath10k_mac_register(struct ath10k *a
ar->hw->weight_multiplier = ATH10K_AIRTIME_WEIGHT_MULTIPLIER;
#ifdef CPTCFG_MAC80211_LEDS
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
-@@ -1041,7 +1041,7 @@ static int ath10k_monitor_vdev_start(str
+@@ -1042,7 +1042,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;
reinit_completion(&ar->vdev_setup_done);
reinit_completion(&ar->vdev_delete_done);
-@@ -1487,7 +1487,7 @@ static int ath10k_vdev_start_restart(str
+@@ -1488,7 +1488,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;
if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
arg.ssid = arvif->u.ap.ssid;
-@@ -3168,7 +3168,7 @@ static int ath10k_update_channel_list(st
+@@ -3169,7 +3169,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;
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
-@@ -1009,6 +1009,40 @@ static inline int ath10k_vdev_setup_sync
+@@ -1010,6 +1010,40 @@ static inline int ath10k_vdev_setup_sync
return ar->last_wmi_vdev_start_status;
}
static int ath10k_monitor_vdev_start(struct ath10k *ar, int vdev_id)
{
struct cfg80211_chan_def *chandef = NULL;
-@@ -1041,7 +1075,8 @@ static int ath10k_monitor_vdev_start(str
+@@ -1042,7 +1076,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;
reinit_completion(&ar->vdev_setup_done);
reinit_completion(&ar->vdev_delete_done);
-@@ -1487,7 +1522,8 @@ static int ath10k_vdev_start_restart(str
+@@ -1488,7 +1523,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;
if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
arg.ssid = arvif->u.ap.ssid;
-@@ -3168,7 +3204,8 @@ static int ath10k_update_channel_list(st
+@@ -3169,7 +3205,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;
+++ /dev/null
-From 1524cbf3621576c639405e7aabeac415f9617c8d Mon Sep 17 00:00:00 2001
-From: Adrian Ratiu <adrian.ratiu@collabora.com>
-Date: Wed, 25 Sep 2019 16:44:57 +0300
-Subject: [PATCH] brcmfmac: don't WARN when there are no requests
-
-When n_reqs == 0 there is nothing to do so it doesn't make sense to
-search for requests and issue a warning because none is found.
-
-Signed-off-by: Martyn Welch <martyn.welch@collabora.com>
-Signed-off-by: Adrian Ratiu <adrian.ratiu@collabora.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
- drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c | 4 ++++
- 1 file changed, 4 insertions(+)
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c
-@@ -57,6 +57,10 @@ static int brcmf_pno_remove_request(stru
-
- mutex_lock(&pi->req_lock);
-
-+ /* Nothing to do if we have no requests */
-+ if (pi->n_reqs == 0)
-+ goto done;
-+
- /* find request */
- for (i = 0; i < pi->n_reqs; i++) {
- if (pi->reqs[i]->reqid == reqid)
+++ /dev/null
-From e0ae4bac22effbd644add326f658a3aeeb8d45ee Mon Sep 17 00:00:00 2001
-From: Adrian Ratiu <adrian.ratiu@collabora.com>
-Date: Wed, 25 Sep 2019 16:44:58 +0300
-Subject: [PATCH] brcmfmac: fix suspend/resume when power is cut off
-
-brcmfmac assumed the wifi device always remains powered on and thus
-hardcoded the MMC_PM_KEEP_POWER flag expecting the wifi device to
-remain on even during suspend/resume cycles.
-
-This is not always the case, some appliances cut power to everything
-connected via SDIO for efficiency reasons and this leads to wifi not
-being usable after coming out of suspend because the device was not
-correctly reinitialized.
-
-So we check for the keep_power capability and if it's not present then
-we remove the device and probe it again during resume to mirror what's
-happening in hardware and ensure correct reinitialization in the case
-when MMC_PM_KEEP_POWER is not supported.
-
-Suggested-by: Gustavo Padovan <gustavo.padovan@collabora.com>
-Signed-off-by: Adrian Ratiu <adrian.ratiu@collabora.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
- .../broadcom/brcm80211/brcmfmac/bcmsdh.c | 53 ++++++++++++++-----
- 1 file changed, 39 insertions(+), 14 deletions(-)
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
-@@ -1108,7 +1108,8 @@ static int brcmf_ops_sdio_suspend(struct
- struct sdio_func *func;
- struct brcmf_bus *bus_if;
- struct brcmf_sdio_dev *sdiodev;
-- mmc_pm_flag_t sdio_flags;
-+ mmc_pm_flag_t pm_caps, sdio_flags;
-+ int ret = 0;
-
- func = container_of(dev, struct sdio_func, dev);
- brcmf_dbg(SDIO, "Enter: F%d\n", func->num);
-@@ -1119,19 +1120,33 @@ static int brcmf_ops_sdio_suspend(struct
- bus_if = dev_get_drvdata(dev);
- sdiodev = bus_if->bus_priv.sdio;
-
-- brcmf_sdiod_freezer_on(sdiodev);
-- brcmf_sdio_wd_timer(sdiodev->bus, 0);
-+ pm_caps = sdio_get_host_pm_caps(func);
-
-- sdio_flags = MMC_PM_KEEP_POWER;
-- if (sdiodev->wowl_enabled) {
-- if (sdiodev->settings->bus.sdio.oob_irq_supported)
-- enable_irq_wake(sdiodev->settings->bus.sdio.oob_irq_nr);
-- else
-- sdio_flags |= MMC_PM_WAKE_SDIO_IRQ;
-+ if (pm_caps & MMC_PM_KEEP_POWER) {
-+ /* preserve card power during suspend */
-+ brcmf_sdiod_freezer_on(sdiodev);
-+ brcmf_sdio_wd_timer(sdiodev->bus, 0);
-+
-+ sdio_flags = MMC_PM_KEEP_POWER;
-+ if (sdiodev->wowl_enabled) {
-+ if (sdiodev->settings->bus.sdio.oob_irq_supported)
-+ enable_irq_wake(sdiodev->settings->bus.sdio.oob_irq_nr);
-+ else
-+ sdio_flags |= MMC_PM_WAKE_SDIO_IRQ;
-+ }
-+
-+ if (sdio_set_host_pm_flags(sdiodev->func1, sdio_flags))
-+ brcmf_err("Failed to set pm_flags %x\n", sdio_flags);
-+
-+ } else {
-+ /* power will be cut so remove device, probe again in resume */
-+ brcmf_sdiod_intr_unregister(sdiodev);
-+ ret = brcmf_sdiod_remove(sdiodev);
-+ if (ret)
-+ brcmf_err("Failed to remove device on suspend\n");
- }
-- if (sdio_set_host_pm_flags(sdiodev->func1, sdio_flags))
-- brcmf_err("Failed to set pm_flags %x\n", sdio_flags);
-- return 0;
-+
-+ return ret;
- }
-
- static int brcmf_ops_sdio_resume(struct device *dev)
-@@ -1139,13 +1154,23 @@ static int brcmf_ops_sdio_resume(struct
- struct brcmf_bus *bus_if = dev_get_drvdata(dev);
- struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
- struct sdio_func *func = container_of(dev, struct sdio_func, dev);
-+ mmc_pm_flag_t pm_caps = sdio_get_host_pm_caps(func);
-+ int ret = 0;
-
- brcmf_dbg(SDIO, "Enter: F%d\n", func->num);
- if (func->num != 2)
- return 0;
-
-- brcmf_sdiod_freezer_off(sdiodev);
-- return 0;
-+ if (!(pm_caps & MMC_PM_KEEP_POWER)) {
-+ /* bus was powered off and device removed, probe again */
-+ ret = brcmf_sdiod_probe(sdiodev);
-+ if (ret)
-+ brcmf_err("Failed to probe device on resume\n");
-+ } else {
-+ brcmf_sdiod_freezer_off(sdiodev);
-+ }
-+
-+ return ret;
- }
-
- static const struct dev_pm_ops brcmf_sdio_pm_ops = {
+++ /dev/null
-From 7af496b9eb0433bc4cb478c9a46f85509cdb5541 Mon Sep 17 00:00:00 2001
-From: zhengbin <zhengbin13@huawei.com>
-Date: Sat, 16 Nov 2019 15:22:47 +0800
-Subject: [PATCH] brcmfmac: remove set but not used variable
- 'mpnum','nsp','nmp'
-
-Fixes gcc '-Wunused-but-set-variable' warning:
-
-drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c: In function brcmf_chip_dmp_get_regaddr:
-drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c:790:5: warning: variable mpnum set but not used [-Wunused-but-set-variable]
-drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c: In function brcmf_chip_dmp_erom_scan:
-drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c:866:10: warning: variable nsp set but not used [-Wunused-but-set-variable]
-drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c: In function brcmf_chip_dmp_erom_scan:
-drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c:866:5: warning: variable nmp set but not used [-Wunused-but-set-variable]
-
-Reported-by: Hulk Robot <hulkci@huawei.com>
-Signed-off-by: zhengbin <zhengbin13@huawei.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
- drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c | 6 +-----
- 1 file changed, 1 insertion(+), 5 deletions(-)
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
-@@ -778,7 +778,6 @@ static int brcmf_chip_dmp_get_regaddr(st
- {
- u8 desc;
- u32 val, szdesc;
-- u8 mpnum = 0;
- u8 stype, sztype, wraptype;
-
- *regbase = 0;
-@@ -786,7 +785,6 @@ static int brcmf_chip_dmp_get_regaddr(st
-
- val = brcmf_chip_dmp_get_desc(ci, eromaddr, &desc);
- if (desc == DMP_DESC_MASTER_PORT) {
-- mpnum = (val & DMP_MASTER_PORT_NUM) >> DMP_MASTER_PORT_NUM_S;
- wraptype = DMP_SLAVE_TYPE_MWRAP;
- } else if (desc == DMP_DESC_ADDRESS) {
- /* revert erom address */
-@@ -854,7 +852,7 @@ int brcmf_chip_dmp_erom_scan(struct brcm
- u8 desc_type = 0;
- u32 val;
- u16 id;
-- u8 nmp, nsp, nmw, nsw, rev;
-+ u8 nmw, nsw, rev;
- u32 base, wrap;
- int err;
-
-@@ -880,8 +878,6 @@ int brcmf_chip_dmp_erom_scan(struct brcm
- return -EFAULT;
-
- /* only look at cores with master port(s) */
-- nmp = (val & DMP_COMP_NUM_MPORT) >> DMP_COMP_NUM_MPORT_S;
-- nsp = (val & DMP_COMP_NUM_SPORT) >> DMP_COMP_NUM_SPORT_S;
- nmw = (val & DMP_COMP_NUM_MWRAP) >> DMP_COMP_NUM_MWRAP_S;
- nsw = (val & DMP_COMP_NUM_SWRAP) >> DMP_COMP_NUM_SWRAP_S;
- rev = (val & DMP_COMP_REVISION) >> DMP_COMP_REVISION_S;
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
-@@ -5944,19 +5944,17 @@ static s32 brcmf_dongle_roam(struct brcm
+@@ -6012,19 +6012,17 @@ static s32 brcmf_dongle_roam(struct brcm
roamtrigger[1] = cpu_to_le32(BRCM_BAND_ALL);
err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_TRIGGER,
(void *)roamtrigger, sizeof(roamtrigger));
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
-@@ -6452,6 +6452,9 @@ brcmf_txrx_stypes[NUM_NL80211_IFTYPES] =
+@@ -6520,6 +6520,9 @@ brcmf_txrx_stypes[NUM_NL80211_IFTYPES] =
* #STA <= 1, #AP <= 1, channels = 1, 2 total
* #AP <= 4, matching BI, channels = 1, 4 total
*
* p2p, no mchan, and mbss:
*
* #STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 1, channels = 1, 3 total
-@@ -6463,6 +6466,10 @@ brcmf_txrx_stypes[NUM_NL80211_IFTYPES] =
+@@ -6531,6 +6534,10 @@ brcmf_txrx_stypes[NUM_NL80211_IFTYPES] =
* #STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 1, channels = 2, 3 total
* #STA <= 1, #P2P-DEV <= 1, #AP <= 1, #P2P-CL <= 1, channels = 1, 4 total
* #AP <= 4, matching BI, channels = 1, 4 total
*/
static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp)
{
-@@ -6470,13 +6477,14 @@ static int brcmf_setup_ifmodes(struct wi
+@@ -6538,13 +6545,14 @@ static int brcmf_setup_ifmodes(struct wi
struct ieee80211_iface_limit *c0_limits = NULL;
struct ieee80211_iface_limit *p2p_limits = NULL;
struct ieee80211_iface_limit *mbss_limits = NULL;
combo = kcalloc(n_combos, sizeof(*combo), GFP_KERNEL);
if (!combo)
goto err;
-@@ -6487,16 +6495,36 @@ static int brcmf_setup_ifmodes(struct wi
+@@ -6555,16 +6563,36 @@ static int brcmf_setup_ifmodes(struct wi
c = 0;
i = 0;
wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_CLIENT) |
BIT(NL80211_IFTYPE_P2P_GO) |
BIT(NL80211_IFTYPE_P2P_DEVICE);
-@@ -6505,16 +6533,26 @@ static int brcmf_setup_ifmodes(struct wi
+@@ -6573,16 +6601,26 @@ static int brcmf_setup_ifmodes(struct wi
c0_limits[i].max = 1;
c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
BIT(NL80211_IFTYPE_P2P_GO);
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
-@@ -5301,6 +5301,7 @@ struct brcmf_cfg80211_vif *brcmf_alloc_v
+@@ -5363,6 +5363,7 @@ struct brcmf_cfg80211_vif *brcmf_alloc_v
struct brcmf_cfg80211_vif *vif_walk;
struct brcmf_cfg80211_vif *vif;
bool mbss;
brcmf_dbg(TRACE, "allocating virtual interface (size=%zu)\n",
sizeof(*vif));
-@@ -5313,7 +5314,8 @@ struct brcmf_cfg80211_vif *brcmf_alloc_v
+@@ -5375,7 +5376,8 @@ struct brcmf_cfg80211_vif *brcmf_alloc_v
brcmf_init_prof(&vif->profile);
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
-@@ -6479,12 +6479,13 @@ static int brcmf_setup_ifmodes(struct wi
+@@ -6547,12 +6547,13 @@ static int brcmf_setup_ifmodes(struct wi
struct ieee80211_iface_limit *c0_limits = NULL;
struct ieee80211_iface_limit *p2p_limits = NULL;
struct ieee80211_iface_limit *mbss_limits = NULL;
n_combos = 1 + !!(p2p && !rsdb) + !!mbss;
combo = kcalloc(n_combos, sizeof(*combo), GFP_KERNEL);
-@@ -6494,6 +6495,10 @@ static int brcmf_setup_ifmodes(struct wi
+@@ -6562,6 +6563,10 @@ static int brcmf_setup_ifmodes(struct wi
wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_ADHOC) |
BIT(NL80211_IFTYPE_AP);
c = 0;
i = 0;
-@@ -6505,48 +6510,28 @@ static int brcmf_setup_ifmodes(struct wi
+@@ -6573,48 +6578,28 @@ static int brcmf_setup_ifmodes(struct wi
c0_limits = kcalloc(2, sizeof(*c0_limits), GFP_KERNEL);
if (!c0_limits)
goto err;
case NL80211_IFTYPE_AP:
return brcmf_cfg80211_del_ap_iface(wiphy, wdev);
case NL80211_IFTYPE_P2P_CLIENT:
-@@ -6479,9 +6558,10 @@ static int brcmf_setup_ifmodes(struct wi
+@@ -6547,9 +6626,10 @@ static int brcmf_setup_ifmodes(struct wi
struct ieee80211_iface_limit *c0_limits = NULL;
struct ieee80211_iface_limit *p2p_limits = NULL;
struct ieee80211_iface_limit *mbss_limits = NULL;
mbss = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS);
p2p = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_P2P);
rsdb = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_RSDB);
-@@ -6495,6 +6575,8 @@ static int brcmf_setup_ifmodes(struct wi
+@@ -6563,6 +6643,8 @@ static int brcmf_setup_ifmodes(struct wi
wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_ADHOC) |
BIT(NL80211_IFTYPE_AP);
if (p2p)
wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_CLIENT) |
BIT(NL80211_IFTYPE_P2P_GO) |
-@@ -6502,18 +6584,18 @@ static int brcmf_setup_ifmodes(struct wi
+@@ -6570,18 +6652,18 @@ static int brcmf_setup_ifmodes(struct wi
c = 0;
i = 0;
if (p2p) {
c0_limits[i].max = 1;
c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE);
-@@ -6562,14 +6644,20 @@ static int brcmf_setup_ifmodes(struct wi
+@@ -6630,14 +6712,20 @@ static int brcmf_setup_ifmodes(struct wi
if (mbss) {
c++;
i = 0;
{ BRCMF_FEAT_MONITOR, "monitor" },
+ { BRCMF_FEAT_MONITOR_FLAG, "rtap" },
{ BRCMF_FEAT_MONITOR_FMT_RADIOTAP, "rtap" },
- { BRCMF_FEAT_DOT11H, "802.11h" }
- };
+ { BRCMF_FEAT_DOT11H, "802.11h" },
+ { BRCMF_FEAT_SAE, "sae" },
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
@@ -23,6 +23,7 @@
* MONITOR_FMT_RADIOTAP: firmware provides monitor packets with radiotap header
* MONITOR_FMT_HW_RX_HDR: firmware provides monitor packets with hw/ucode header
* DOT11H: firmware supports 802.11h
-@@ -43,6 +44,7 @@
+@@ -44,6 +45,7 @@
BRCMF_FEAT_DEF(GSCAN) \
BRCMF_FEAT_DEF(FWSUP) \
BRCMF_FEAT_DEF(MONITOR) \
+ BRCMF_FEAT_DEF(MONITOR_FLAG) \
BRCMF_FEAT_DEF(MONITOR_FMT_RADIOTAP) \
BRCMF_FEAT_DEF(MONITOR_FMT_HW_RX_HDR) \
- BRCMF_FEAT_DEF(DOT11H)
+ BRCMF_FEAT_DEF(DOT11H) \
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.h
@@ -49,6 +49,8 @@
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
-@@ -2874,6 +2874,10 @@ brcmf_cfg80211_set_power_mgmt(struct wip
+@@ -2936,6 +2936,10 @@ brcmf_cfg80211_set_power_mgmt(struct wip
* preference in cfg struct to apply this to
* FW later while initializing the dongle
*/
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
-@@ -2826,6 +2826,63 @@ done:
+@@ -2888,6 +2888,63 @@ done:
}
static int
brcmf_cfg80211_dump_station(struct wiphy *wiphy, struct net_device *ndev,
int idx, u8 *mac, struct station_info *sinfo)
{
-@@ -2915,6 +2972,7 @@ static s32 brcmf_inform_single_bss(struc
+@@ -2977,6 +3034,7 @@ static s32 brcmf_inform_single_bss(struc
struct brcmu_chan ch;
u16 channel;
u32 freq;
u16 notify_capability;
u16 notify_interval;
u8 *notify_ie;
-@@ -2939,6 +2997,17 @@ static s32 brcmf_inform_single_bss(struc
+@@ -3001,6 +3059,17 @@ static s32 brcmf_inform_single_bss(struc
band = NL80211_BAND_5GHZ;
freq = ieee80211_channel_to_frequency(channel, band);
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());
-@@ -5356,6 +5425,7 @@ static struct cfg80211_ops brcmf_cfg8021
+@@ -5418,6 +5487,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,
--- a/drivers/net/wireless/intel/ipw2x00/ipw2200.c
+++ b/drivers/net/wireless/intel/ipw2x00/ipw2200.c
-@@ -11482,6 +11482,15 @@ static const struct attribute_group ipw_
+@@ -11479,6 +11479,15 @@ static const struct attribute_group ipw_
.attrs = ipw_sysfs_entries,
};
#ifdef CPTCFG_IPW2200_PROMISCUOUS
static int ipw_prom_open(struct net_device *dev)
{
-@@ -11530,15 +11539,6 @@ static netdev_tx_t ipw_prom_hard_start_x
+@@ -11527,15 +11536,6 @@ static netdev_tx_t ipw_prom_hard_start_x
return NETDEV_TX_OK;
}
--- a/net/wireless/Kconfig
+++ b/net/wireless/Kconfig
-@@ -186,7 +186,7 @@ config CFG80211_WEXT_EXPORT
+@@ -187,7 +187,7 @@ config CFG80211_WEXT_EXPORT
endif # CFG80211
config LIB80211
depends on m
default n
help
-@@ -196,18 +196,18 @@ config LIB80211
+@@ -197,18 +197,18 @@ config LIB80211
Drivers should select this themselves if needed.
config LIB80211_CRYPT_WEP
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
-@@ -4048,6 +4048,12 @@ out:
+@@ -4116,6 +4116,12 @@ out:
netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
struct net_device *dev)
{
static int ieee80211_ifa6_changed(struct notifier_block *nb,
unsigned long data, void *arg)
{
-@@ -1267,14 +1267,14 @@ int ieee80211_register_hw(struct ieee802
+@@ -1272,14 +1272,14 @@ int ieee80211_register_hw(struct ieee802
rtnl_unlock();
local->ifa6_notifier.notifier_call = ieee80211_ifa6_changed;
result = register_inet6addr_notifier(&local->ifa6_notifier);
if (result)
-@@ -1283,13 +1283,13 @@ int ieee80211_register_hw(struct ieee802
+@@ -1288,13 +1288,13 @@ int ieee80211_register_hw(struct ieee802
return 0;
fail_ifa:
#endif
wiphy_unregister(local->hw.wiphy);
-@@ -1317,10 +1317,10 @@ void ieee80211_unregister_hw(struct ieee
+@@ -1322,10 +1322,10 @@ void ieee80211_unregister_hw(struct ieee
tasklet_kill(&local->tx_pending_tasklet);
tasklet_kill(&local->tasklet);
--- /dev/null
+From 6cb5f3ea4654faf8c28b901266e960b1a4787b26 Mon Sep 17 00:00:00 2001
+From: Johannes Berg <johannes.berg@intel.com>
+Date: Thu, 23 Apr 2020 11:13:49 +0200
+Subject: [PATCH] mac80211: populate debugfs only after cfg80211 init
+
+When fixing the initialization race, we neglected to account for
+the fact that debugfs is initialized in wiphy_register(), and
+some debugfs things went missing (or rather were rerooted to the
+global debugfs root).
+
+Fix this by adding debugfs entries only after wiphy_register().
+This requires some changes in the rate control code since it
+currently adds debugfs at alloc time, which can no longer be
+done after the reordering.
+
+Reported-by: Jouni Malinen <j@w1.fi>
+Reported-by: kernel test robot <rong.a.chen@intel.com>
+Reported-by: Hauke Mehrtens <hauke@hauke-m.de>
+Reported-by: Felix Fietkau <nbd@nbd.name>
+Cc: stable@vger.kernel.org
+Fixes: 52e04b4ce5d0 ("mac80211: fix race in ieee80211_register_hw()")
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Acked-by: Sumit Garg <sumit.garg@linaro.org>
+Link: https://lore.kernel.org/r/20200423111344.0e00d3346f12.Iadc76a03a55093d94391fc672e996a458702875d@changeid
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+---
+ drivers/net/wireless/intel/iwlegacy/3945-rs.c | 2 +-
+ drivers/net/wireless/intel/iwlegacy/4965-rs.c | 2 +-
+ drivers/net/wireless/intel/iwlwifi/dvm/rs.c | 2 +-
+ drivers/net/wireless/intel/iwlwifi/mvm/rs.c | 2 +-
+ drivers/net/wireless/realtek/rtlwifi/rc.c | 2 +-
+ include/net/mac80211.h | 4 +++-
+ net/mac80211/main.c | 5 ++--
+ net/mac80211/rate.c | 15 ++++--------
+ net/mac80211/rate.h | 23 +++++++++++++++++++
+ net/mac80211/rc80211_minstrel_ht.c | 19 ++++++++++-----
+ 10 files changed, 51 insertions(+), 25 deletions(-)
+
+--- a/drivers/net/wireless/intel/iwlegacy/3945-rs.c
++++ b/drivers/net/wireless/intel/iwlegacy/3945-rs.c
+@@ -374,7 +374,7 @@ out:
+ }
+
+ static void *
+-il3945_rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
++il3945_rs_alloc(struct ieee80211_hw *hw)
+ {
+ return hw->priv;
+ }
+--- a/drivers/net/wireless/intel/iwlegacy/4965-rs.c
++++ b/drivers/net/wireless/intel/iwlegacy/4965-rs.c
+@@ -2474,7 +2474,7 @@ il4965_rs_fill_link_cmd(struct il_priv *
+ }
+
+ static void *
+-il4965_rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
++il4965_rs_alloc(struct ieee80211_hw *hw)
+ {
+ return hw->priv;
+ }
+--- a/drivers/net/wireless/intel/iwlwifi/dvm/rs.c
++++ b/drivers/net/wireless/intel/iwlwifi/dvm/rs.c
+@@ -3019,7 +3019,7 @@ static void rs_fill_link_cmd(struct iwl_
+ cpu_to_le16(priv->lib->bt_params->agg_time_limit);
+ }
+
+-static void *rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
++static void *rs_alloc(struct ieee80211_hw *hw)
+ {
+ return hw->priv;
+ }
+--- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c
++++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c
+@@ -3665,7 +3665,7 @@ static void rs_fill_lq_cmd(struct iwl_mv
+ cpu_to_le16(iwl_mvm_coex_agg_time_limit(mvm, sta));
+ }
+
+-static void *rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
++static void *rs_alloc(struct ieee80211_hw *hw)
+ {
+ return hw->priv;
+ }
+--- a/drivers/net/wireless/realtek/rtlwifi/rc.c
++++ b/drivers/net/wireless/realtek/rtlwifi/rc.c
+@@ -261,7 +261,7 @@ static void rtl_rate_update(void *ppriv,
+ {
+ }
+
+-static void *rtl_rate_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
++static void *rtl_rate_alloc(struct ieee80211_hw *hw)
+ {
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ return rtlpriv;
+--- a/include/net/mac80211.h
++++ b/include/net/mac80211.h
+@@ -5969,7 +5969,9 @@ enum rate_control_capabilities {
+ struct rate_control_ops {
+ unsigned long capa;
+ const char *name;
+- void *(*alloc)(struct ieee80211_hw *hw, struct dentry *debugfsdir);
++ void *(*alloc)(struct ieee80211_hw *hw);
++ void (*add_debugfs)(struct ieee80211_hw *hw, void *priv,
++ struct dentry *debugfsdir);
+ void (*free)(void *priv);
+
+ void *(*alloc_sta)(void *priv, struct ieee80211_sta *sta, gfp_t gfp);
+--- a/net/mac80211/main.c
++++ b/net/mac80211/main.c
+@@ -1163,8 +1163,6 @@ int ieee80211_register_hw(struct ieee802
+ local->tx_headroom = max_t(unsigned int , local->hw.extra_tx_headroom,
+ IEEE80211_TX_STATUS_HEADROOM);
+
+- debugfs_hw_add(local);
+-
+ /*
+ * if the driver doesn't specify a max listen interval we
+ * use 5 which should be a safe default
+@@ -1256,6 +1254,9 @@ int ieee80211_register_hw(struct ieee802
+ if (result < 0)
+ goto fail_wiphy_register;
+
++ debugfs_hw_add(local);
++ rate_control_add_debugfs(local);
++
+ rtnl_lock();
+
+ /* add one default STA interface if supported */
+--- a/net/mac80211/rate.c
++++ b/net/mac80211/rate.c
+@@ -214,17 +214,16 @@ static ssize_t rcname_read(struct file *
+ ref->ops->name, len);
+ }
+
+-static const struct file_operations rcname_ops = {
++const struct file_operations rcname_ops = {
+ .read = rcname_read,
+ .open = simple_open,
+ .llseek = default_llseek,
+ };
+ #endif
+
+-static struct rate_control_ref *rate_control_alloc(const char *name,
+- struct ieee80211_local *local)
++static struct rate_control_ref *
++rate_control_alloc(const char *name, struct ieee80211_local *local)
+ {
+- struct dentry *debugfsdir = NULL;
+ struct rate_control_ref *ref;
+
+ ref = kmalloc(sizeof(struct rate_control_ref), GFP_KERNEL);
+@@ -234,13 +233,7 @@ static struct rate_control_ref *rate_con
+ if (!ref->ops)
+ goto free;
+
+-#ifdef CPTCFG_MAC80211_DEBUGFS
+- debugfsdir = debugfs_create_dir("rc", local->hw.wiphy->debugfsdir);
+- local->debugfs.rcdir = debugfsdir;
+- debugfs_create_file("name", 0400, debugfsdir, ref, &rcname_ops);
+-#endif
+-
+- ref->priv = ref->ops->alloc(&local->hw, debugfsdir);
++ ref->priv = ref->ops->alloc(&local->hw);
+ if (!ref->priv)
+ goto free;
+ return ref;
+--- a/net/mac80211/rate.h
++++ b/net/mac80211/rate.h
+@@ -60,6 +60,29 @@ static inline void rate_control_add_sta_
+ #endif
+ }
+
++extern const struct file_operations rcname_ops;
++
++static inline void rate_control_add_debugfs(struct ieee80211_local *local)
++{
++#ifdef CPTCFG_MAC80211_DEBUGFS
++ struct dentry *debugfsdir;
++
++ if (!local->rate_ctrl)
++ return;
++
++ if (!local->rate_ctrl->ops->add_debugfs)
++ return;
++
++ debugfsdir = debugfs_create_dir("rc", local->hw.wiphy->debugfsdir);
++ local->debugfs.rcdir = debugfsdir;
++ debugfs_create_file("name", 0400, debugfsdir,
++ local->rate_ctrl, &rcname_ops);
++
++ local->rate_ctrl->ops->add_debugfs(&local->hw, local->rate_ctrl->priv,
++ debugfsdir);
++#endif
++}
++
+ void ieee80211_check_rate_mask(struct ieee80211_sub_if_data *sdata);
+
+ /* Get a reference to the rate control algorithm. If `name' is NULL, get the
+--- a/net/mac80211/rc80211_minstrel_ht.c
++++ b/net/mac80211/rc80211_minstrel_ht.c
+@@ -1635,7 +1635,7 @@ minstrel_ht_init_cck_rates(struct minstr
+ }
+
+ static void *
+-minstrel_ht_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
++minstrel_ht_alloc(struct ieee80211_hw *hw)
+ {
+ struct minstrel_priv *mp;
+
+@@ -1673,7 +1673,17 @@ minstrel_ht_alloc(struct ieee80211_hw *h
+ mp->update_interval = HZ / 10;
+ mp->new_avg = true;
+
++ minstrel_ht_init_cck_rates(mp);
++
++ return mp;
++}
++
+ #ifdef CPTCFG_MAC80211_DEBUGFS
++static void minstrel_ht_add_debugfs(struct ieee80211_hw *hw, void *priv,
++ struct dentry *debugfsdir)
++{
++ struct minstrel_priv *mp = priv;
++
+ mp->fixed_rate_idx = (u32) -1;
+ debugfs_create_u32("fixed_rate_idx", S_IRUGO | S_IWUGO, debugfsdir,
+ &mp->fixed_rate_idx);
+@@ -1681,12 +1691,8 @@ minstrel_ht_alloc(struct ieee80211_hw *h
+ &mp->sample_switch);
+ debugfs_create_bool("new_avg", S_IRUGO | S_IWUSR, debugfsdir,
+ &mp->new_avg);
+-#endif
+-
+- minstrel_ht_init_cck_rates(mp);
+-
+- return mp;
+ }
++#endif
+
+ static void
+ minstrel_ht_free(void *priv)
+@@ -1725,6 +1731,7 @@ static const struct rate_control_ops mac
+ .alloc = minstrel_ht_alloc,
+ .free = minstrel_ht_free,
+ #ifdef CPTCFG_MAC80211_DEBUGFS
++ .add_debugfs = minstrel_ht_add_debugfs,
+ .add_sta_debugfs = minstrel_ht_add_sta_debugfs,
+ #endif
+ .get_expected_throughput = minstrel_ht_get_expected_throughput,
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
-@@ -1782,6 +1782,9 @@ int ieee80211_tx_control_port(struct wip
+@@ -1786,6 +1786,9 @@ int ieee80211_tx_control_port(struct wip
const u8 *dest, __be16 proto, bool unencrypted);
int ieee80211_probe_mesh_link(struct wiphy *wiphy, struct net_device *dev,
const u8 *buf, size_t len);
void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata,
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
-@@ -815,6 +815,11 @@ void ieee80211_tx_monitor(struct ieee802
+@@ -829,6 +829,11 @@ void ieee80211_tx_monitor(struct ieee802
struct net_device *prev_dev = NULL;
int rtap_len;
if (WARN_ON_ONCE(skb_headroom(skb) < rtap_len)) {
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
-@@ -1943,37 +1943,53 @@ static bool ieee80211_tx(struct ieee8021
+@@ -1936,37 +1936,53 @@ static bool ieee80211_tx(struct ieee8021
}
/* device xmit handlers */
wiphy_debug(local->hw.wiphy,
"failed to reallocate TX buffer\n");
return -ENOMEM;
-@@ -1989,18 +2005,8 @@ void ieee80211_xmit(struct ieee80211_sub
+@@ -1982,18 +1998,8 @@ void ieee80211_xmit(struct ieee80211_sub
struct ieee80211_local *local = sdata->local;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *hdr;
ieee80211_free_txskb(&local->hw, skb);
return;
}
-@@ -2790,29 +2796,13 @@ static struct sk_buff *ieee80211_build_h
+@@ -2795,29 +2801,13 @@ static struct sk_buff *ieee80211_build_h
}
skb_pull(skb, skip_header_bytes);
}
if (encaps_data)
-@@ -3427,7 +3417,6 @@ static bool ieee80211_xmit_fast(struct i
+@@ -3432,7 +3422,6 @@ static bool ieee80211_xmit_fast(struct i
struct ieee80211_local *local = sdata->local;
u16 ethertype = (skb->data[12] << 8) | skb->data[13];
int extra_head = fast_tx->hdr_len - (ETH_HLEN - 2);
struct ethhdr eth;
struct ieee80211_tx_info *info;
struct ieee80211_hdr *hdr = (void *)fast_tx->hdr;
-@@ -3479,10 +3468,7 @@ static bool ieee80211_xmit_fast(struct i
+@@ -3484,10 +3473,7 @@ static bool ieee80211_xmit_fast(struct i
* as the may-encrypt argument for the resize to not account for
* more room than we already have in 'extra_head'
*/
+++ /dev/null
-From: Felix Fietkau <nbd@nbd.name>
-Date: Sat, 28 Sep 2019 15:44:06 +0200
-Subject: [PATCH] mac80211: minstrel: remove divisions in tx status path
-
-Use a slightly different threshold for downgrading spatial streams to
-make it easier to calculate without divisions.
-Slightly reduces CPU overhead.
-
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/net/mac80211/rc80211_minstrel.c
-+++ b/net/mac80211/rc80211_minstrel.c
-@@ -289,8 +289,7 @@ minstrel_tx_status(void *priv, struct ie
- if (mi->sample_deferred > 0)
- mi->sample_deferred--;
-
-- if (time_after(jiffies, mi->last_stats_update +
-- (mp->update_interval * HZ) / 1000))
-+ if (time_after(jiffies, mi->last_stats_update + mp->update_interval))
- minstrel_update_stats(mp, mi);
- }
-
---- a/net/mac80211/rc80211_minstrel_ht.c
-+++ b/net/mac80211/rc80211_minstrel_ht.c
-@@ -970,23 +970,21 @@ minstrel_ht_tx_status(void *priv, struct
- */
- rate = minstrel_get_ratestats(mi, mi->max_tp_rate[0]);
- if (rate->attempts > 30 &&
-- MINSTREL_FRAC(rate->success, rate->attempts) <
-- MINSTREL_FRAC(20, 100)) {
-+ rate->success < rate->attempts / 4) {
- minstrel_downgrade_rate(mi, &mi->max_tp_rate[0], true);
- update = true;
- }
-
- rate2 = minstrel_get_ratestats(mi, mi->max_tp_rate[1]);
- if (rate2->attempts > 30 &&
-- MINSTREL_FRAC(rate2->success, rate2->attempts) <
-- MINSTREL_FRAC(20, 100)) {
-+ rate2->success < rate2->attempts / 4) {
- minstrel_downgrade_rate(mi, &mi->max_tp_rate[1], false);
- update = true;
- }
- }
-
- if (time_after(jiffies, mi->last_stats_update +
-- (mp->update_interval / 2 * HZ) / 1000)) {
-+ mp->update_interval / 2)) {
- update = true;
- minstrel_ht_update_stats(mp, mi, true);
- }
-@@ -1666,7 +1664,7 @@ minstrel_ht_alloc(struct ieee80211_hw *h
- mp->has_mrr = true;
-
- mp->hw = hw;
-- mp->update_interval = 100;
-+ mp->update_interval = HZ / 10;
-
- minstrel_ht_init_cck_rates(mp);
-
+++ /dev/null
-From: Felix Fietkau <nbd@nbd.name>
-Date: Sat, 28 Sep 2019 15:46:06 +0200
-Subject: [PATCH] mac80211: minstrel_ht: replace rate stats ewma with a
- better moving average
-
-Rate success probability usually fluctuates a lot under normal conditions.
-With a simple EWMA, noise and fluctuation can be reduced by increasing the
-window length, but that comes at the cost of introducing lag on sudden
-changes.
-
-This change replaces the EWMA implementation with a moving average that's
-designed to significantly reduce lag while keeping a bigger window size
-by being better at filtering out noise.
-
-It is only slightly more expensive than the simple EWMA and still avoids
-divisions in its calculation.
-
-The algorithm is adapted from an implementation intended for a completely
-different field (stock market trading), where the tradeoff of lag vs
-noise filtering is equally important.
-
-The algorithm works in the same way as the "smoothing filter" from
-http://www.stockspotter.com/files/PredictiveIndicators.pdf adapted for
-fixed-point math with some constants, using only addition, bit shifts
-and multiplication
-
-To better make use of the filtering and bigger window size, the update
-interval is cut in half.
-
-For testing, the algorithm can be reverted to the older one via debugfs
-
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/net/mac80211/rc80211_minstrel.c
-+++ b/net/mac80211/rc80211_minstrel.c
-@@ -157,14 +157,18 @@ minstrel_update_rates(struct minstrel_pr
- * Recalculate statistics and counters of a given rate
- */
- void
--minstrel_calc_rate_stats(struct minstrel_rate_stats *mrs)
-+minstrel_calc_rate_stats(struct minstrel_priv *mp,
-+ struct minstrel_rate_stats *mrs)
- {
- unsigned int cur_prob;
-
- if (unlikely(mrs->attempts > 0)) {
- mrs->sample_skipped = 0;
- cur_prob = MINSTREL_FRAC(mrs->success, mrs->attempts);
-- if (unlikely(!mrs->att_hist)) {
-+ if (mp->new_avg) {
-+ mrs->prob_ewma = minstrel_filter_avg_add(&mrs->avg,
-+ cur_prob);
-+ } else if (unlikely(!mrs->att_hist)) {
- mrs->prob_ewma = cur_prob;
- } else {
- /*update exponential weighted moving avarage */
-@@ -200,7 +204,7 @@ minstrel_update_stats(struct minstrel_pr
- struct minstrel_rate_stats *tmp_mrs = &mi->r[tmp_prob_rate].stats;
-
- /* Update statistics of success probability per rate */
-- minstrel_calc_rate_stats(mrs);
-+ minstrel_calc_rate_stats(mp, mrs);
-
- /* Sample less often below the 10% chance of success.
- * Sample less often above the 95% chance of success. */
-@@ -289,7 +293,8 @@ minstrel_tx_status(void *priv, struct ie
- if (mi->sample_deferred > 0)
- mi->sample_deferred--;
-
-- if (time_after(jiffies, mi->last_stats_update + mp->update_interval))
-+ if (time_after(jiffies, mi->last_stats_update +
-+ mp->update_interval / (mp->new_avg ? 2 : 1)))
- minstrel_update_stats(mp, mi);
- }
-
---- a/net/mac80211/rc80211_minstrel.h
-+++ b/net/mac80211/rc80211_minstrel.h
-@@ -19,6 +19,21 @@
- #define MAX_THR_RATES 4
-
- /*
-+ * Coefficients for moving average with noise filter (period=16),
-+ * scaled by 10 bits
-+ *
-+ * a1 = exp(-pi * sqrt(2) / period)
-+ * coeff2 = 2 * a1 * cos(sqrt(2) * 2 * pi / period)
-+ * coeff3 = -sqr(a1)
-+ * coeff1 = 1 - coeff2 - coeff3
-+ */
-+#define MINSTREL_AVG_COEFF1 (MINSTREL_FRAC(1, 1) - \
-+ MINSTREL_AVG_COEFF2 - \
-+ MINSTREL_AVG_COEFF3)
-+#define MINSTREL_AVG_COEFF2 0x00001499
-+#define MINSTREL_AVG_COEFF3 -0x0000092e
-+
-+/*
- * Perform EWMA (Exponentially Weighted Moving Average) calculation
- */
- static inline int
-@@ -32,6 +47,41 @@ minstrel_ewma(int old, int new, int weig
- return old + incr;
- }
-
-+struct minstrel_avg_ctx {
-+ s32 prev[2];
-+};
-+
-+static inline int minstrel_filter_avg_add(struct minstrel_avg_ctx *ctx, s32 in)
-+{
-+ s32 out_1 = ctx->prev[0];
-+ s32 out_2 = ctx->prev[1];
-+ s32 val;
-+
-+ if (!in)
-+ in += 1;
-+
-+ if (!out_1) {
-+ val = out_1 = in;
-+ goto out;
-+ }
-+
-+ val = MINSTREL_AVG_COEFF1 * in;
-+ val += MINSTREL_AVG_COEFF2 * out_1;
-+ val += MINSTREL_AVG_COEFF3 * out_2;
-+ val >>= MINSTREL_SCALE;
-+
-+ if (val > 1 << MINSTREL_SCALE)
-+ val = 1 << MINSTREL_SCALE;
-+ if (val < 0)
-+ val = 1;
-+
-+out:
-+ ctx->prev[1] = out_1;
-+ ctx->prev[0] = val;
-+
-+ return val;
-+}
-+
- struct minstrel_rate_stats {
- /* current / last sampling period attempts/success counters */
- u16 attempts, last_attempts;
-@@ -40,6 +90,8 @@ struct minstrel_rate_stats {
- /* total attempts/success counters */
- u32 att_hist, succ_hist;
-
-+ struct minstrel_avg_ctx avg;
-+
- /* prob_ewma - exponential weighted moving average of prob */
- u16 prob_ewma;
-
-@@ -95,6 +147,7 @@ struct minstrel_sta_info {
- struct minstrel_priv {
- struct ieee80211_hw *hw;
- bool has_mrr;
-+ bool new_avg;
- u32 sample_switch;
- unsigned int cw_min;
- unsigned int cw_max;
-@@ -126,7 +179,8 @@ extern const struct rate_control_ops mac
- void minstrel_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir);
-
- /* Recalculate success probabilities and counters for a given rate using EWMA */
--void minstrel_calc_rate_stats(struct minstrel_rate_stats *mrs);
-+void minstrel_calc_rate_stats(struct minstrel_priv *mp,
-+ struct minstrel_rate_stats *mrs);
- int minstrel_get_tp_avg(struct minstrel_rate *mr, int prob_ewma);
-
- /* debugfs */
---- a/net/mac80211/rc80211_minstrel_ht.c
-+++ b/net/mac80211/rc80211_minstrel_ht.c
-@@ -737,7 +737,7 @@ minstrel_ht_update_stats(struct minstrel
-
- mrs = &mg->rates[i];
- mrs->retry_updated = false;
-- minstrel_calc_rate_stats(mrs);
-+ minstrel_calc_rate_stats(mp, mrs);
- cur_prob = mrs->prob_ewma;
-
- if (minstrel_ht_get_tp_avg(mi, group, i, cur_prob) == 0)
-@@ -773,6 +773,8 @@ minstrel_ht_update_stats(struct minstrel
-
- /* try to sample all available rates during each interval */
- mi->sample_count *= 8;
-+ if (mp->new_avg)
-+ mi->sample_count /= 2;
-
- if (sample)
- minstrel_ht_rate_sample_switch(mp, mi);
-@@ -889,6 +891,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;
- bool last, update = false;
- bool sample_status = false;
- int i;
-@@ -943,6 +946,10 @@ 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))
-+ update_interval /= 2;
- break;
-
- case MINSTREL_SAMPLE_ACTIVE:
-@@ -983,8 +990,7 @@ minstrel_ht_tx_status(void *priv, struct
- }
- }
-
-- if (time_after(jiffies, mi->last_stats_update +
-- mp->update_interval / 2)) {
-+ if (time_after(jiffies, mi->last_stats_update + update_interval)) {
- update = true;
- minstrel_ht_update_stats(mp, mi, true);
- }
-@@ -1665,6 +1671,7 @@ minstrel_ht_alloc(struct ieee80211_hw *h
-
- mp->hw = hw;
- mp->update_interval = HZ / 10;
-+ mp->new_avg = true;
-
- minstrel_ht_init_cck_rates(mp);
-
-@@ -1682,6 +1689,8 @@ 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
-
+++ /dev/null
-From: Felix Fietkau <nbd@nbd.name>
-Date: Tue, 8 Oct 2019 18:54:46 +0200
-Subject: [PATCH] mac80211: minstrel_ht: rename prob_ewma to prob_avg, use it
- for the new average
-
-Reduces per-rate data structure size
-
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/net/mac80211/rc80211_minstrel.c
-+++ b/net/mac80211/rc80211_minstrel.c
-@@ -70,7 +70,7 @@ rix_to_ndx(struct minstrel_sta_info *mi,
- }
-
- /* return current EMWA throughput */
--int minstrel_get_tp_avg(struct minstrel_rate *mr, int prob_ewma)
-+int minstrel_get_tp_avg(struct minstrel_rate *mr, int prob_avg)
- {
- int usecs;
-
-@@ -79,13 +79,13 @@ int minstrel_get_tp_avg(struct minstrel_
- usecs = 1000000;
-
- /* reset thr. below 10% success */
-- if (mr->stats.prob_ewma < MINSTREL_FRAC(10, 100))
-+ if (mr->stats.prob_avg < MINSTREL_FRAC(10, 100))
- return 0;
-
-- if (prob_ewma > MINSTREL_FRAC(90, 100))
-+ if (prob_avg > MINSTREL_FRAC(90, 100))
- return MINSTREL_TRUNC(100000 * (MINSTREL_FRAC(90, 100) / usecs));
- else
-- return MINSTREL_TRUNC(100000 * (prob_ewma / usecs));
-+ return MINSTREL_TRUNC(100000 * (prob_avg / usecs));
- }
-
- /* find & sort topmost throughput rates */
-@@ -98,8 +98,8 @@ minstrel_sort_best_tp_rates(struct minst
-
- for (j = MAX_THR_RATES; j > 0; --j) {
- tmp_mrs = &mi->r[tp_list[j - 1]].stats;
-- if (minstrel_get_tp_avg(&mi->r[i], cur_mrs->prob_ewma) <=
-- minstrel_get_tp_avg(&mi->r[tp_list[j - 1]], tmp_mrs->prob_ewma))
-+ if (minstrel_get_tp_avg(&mi->r[i], cur_mrs->prob_avg) <=
-+ minstrel_get_tp_avg(&mi->r[tp_list[j - 1]], tmp_mrs->prob_avg))
- break;
- }
-
-@@ -166,15 +166,15 @@ minstrel_calc_rate_stats(struct minstrel
- mrs->sample_skipped = 0;
- cur_prob = MINSTREL_FRAC(mrs->success, mrs->attempts);
- if (mp->new_avg) {
-- mrs->prob_ewma = minstrel_filter_avg_add(&mrs->avg,
-- cur_prob);
-+ minstrel_filter_avg_add(&mrs->prob_avg,
-+ &mrs->prob_avg_1, cur_prob);
- } else if (unlikely(!mrs->att_hist)) {
-- mrs->prob_ewma = cur_prob;
-+ mrs->prob_avg = cur_prob;
- } else {
- /*update exponential weighted moving avarage */
-- mrs->prob_ewma = minstrel_ewma(mrs->prob_ewma,
-- cur_prob,
-- EWMA_LEVEL);
-+ mrs->prob_avg = minstrel_ewma(mrs->prob_avg,
-+ cur_prob,
-+ EWMA_LEVEL);
- }
- mrs->att_hist += mrs->attempts;
- mrs->succ_hist += mrs->success;
-@@ -208,8 +208,8 @@ minstrel_update_stats(struct minstrel_pr
-
- /* Sample less often below the 10% chance of success.
- * Sample less often above the 95% chance of success. */
-- if (mrs->prob_ewma > MINSTREL_FRAC(95, 100) ||
-- mrs->prob_ewma < MINSTREL_FRAC(10, 100)) {
-+ if (mrs->prob_avg > MINSTREL_FRAC(95, 100) ||
-+ mrs->prob_avg < MINSTREL_FRAC(10, 100)) {
- mr->adjusted_retry_count = mrs->retry_count >> 1;
- if (mr->adjusted_retry_count > 2)
- mr->adjusted_retry_count = 2;
-@@ -229,14 +229,14 @@ minstrel_update_stats(struct minstrel_pr
- * choose the maximum throughput rate as max_prob_rate
- * (2) if all success probabilities < 95%, the rate with
- * highest success probability is chosen as max_prob_rate */
-- if (mrs->prob_ewma >= MINSTREL_FRAC(95, 100)) {
-- tmp_cur_tp = minstrel_get_tp_avg(mr, mrs->prob_ewma);
-+ if (mrs->prob_avg >= MINSTREL_FRAC(95, 100)) {
-+ tmp_cur_tp = minstrel_get_tp_avg(mr, mrs->prob_avg);
- tmp_prob_tp = minstrel_get_tp_avg(&mi->r[tmp_prob_rate],
-- tmp_mrs->prob_ewma);
-+ tmp_mrs->prob_avg);
- if (tmp_cur_tp >= tmp_prob_tp)
- tmp_prob_rate = i;
- } else {
-- if (mrs->prob_ewma >= tmp_mrs->prob_ewma)
-+ if (mrs->prob_avg >= tmp_mrs->prob_avg)
- tmp_prob_rate = i;
- }
- }
-@@ -426,7 +426,7 @@ minstrel_get_rate(void *priv, struct iee
- * has a probability of >95%, we shouldn't be attempting
- * to use it, as this only wastes precious airtime */
- if (!mrr_capable &&
-- (mi->r[ndx].stats.prob_ewma > MINSTREL_FRAC(95, 100)))
-+ (mi->r[ndx].stats.prob_avg > MINSTREL_FRAC(95, 100)))
- return;
-
- mi->prev_sample = true;
-@@ -577,7 +577,7 @@ static u32 minstrel_get_expected_through
- * computing cur_tp
- */
- tmp_mrs = &mi->r[idx].stats;
-- tmp_cur_tp = minstrel_get_tp_avg(&mi->r[idx], tmp_mrs->prob_ewma) * 10;
-+ tmp_cur_tp = minstrel_get_tp_avg(&mi->r[idx], tmp_mrs->prob_avg) * 10;
- tmp_cur_tp = tmp_cur_tp * 1200 * 8 / 1024;
-
- return tmp_cur_tp;
---- a/net/mac80211/rc80211_minstrel.h
-+++ b/net/mac80211/rc80211_minstrel.h
-@@ -47,14 +47,10 @@ minstrel_ewma(int old, int new, int weig
- return old + incr;
- }
-
--struct minstrel_avg_ctx {
-- s32 prev[2];
--};
--
--static inline int minstrel_filter_avg_add(struct minstrel_avg_ctx *ctx, s32 in)
-+static inline int minstrel_filter_avg_add(u16 *prev_1, u16 *prev_2, s32 in)
- {
-- s32 out_1 = ctx->prev[0];
-- s32 out_2 = ctx->prev[1];
-+ s32 out_1 = *prev_1;
-+ s32 out_2 = *prev_2;
- s32 val;
-
- if (!in)
-@@ -76,8 +72,8 @@ static inline int minstrel_filter_avg_ad
- val = 1;
-
- out:
-- ctx->prev[1] = out_1;
-- ctx->prev[0] = val;
-+ *prev_2 = out_1;
-+ *prev_1 = val;
-
- return val;
- }
-@@ -90,10 +86,9 @@ struct minstrel_rate_stats {
- /* total attempts/success counters */
- u32 att_hist, succ_hist;
-
-- struct minstrel_avg_ctx avg;
--
-- /* prob_ewma - exponential weighted moving average of prob */
-- u16 prob_ewma;
-+ /* prob_avg - moving average of prob */
-+ u16 prob_avg;
-+ u16 prob_avg_1;
-
- /* maximum retry counts */
- u8 retry_count;
-@@ -181,7 +176,7 @@ void minstrel_add_sta_debugfs(void *priv
- /* Recalculate success probabilities and counters for a given rate using EWMA */
- void minstrel_calc_rate_stats(struct minstrel_priv *mp,
- struct minstrel_rate_stats *mrs);
--int minstrel_get_tp_avg(struct minstrel_rate *mr, int prob_ewma);
-+int minstrel_get_tp_avg(struct minstrel_rate *mr, int prob_avg);
-
- /* debugfs */
- int minstrel_stats_open(struct inode *inode, struct file *file);
---- a/net/mac80211/rc80211_minstrel_debugfs.c
-+++ b/net/mac80211/rc80211_minstrel_debugfs.c
-@@ -90,8 +90,8 @@ minstrel_stats_open(struct inode *inode,
- p += sprintf(p, "%6u ", mr->perfect_tx_time);
-
- tp_max = minstrel_get_tp_avg(mr, MINSTREL_FRAC(100,100));
-- tp_avg = minstrel_get_tp_avg(mr, mrs->prob_ewma);
-- eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000);
-+ tp_avg = minstrel_get_tp_avg(mr, mrs->prob_avg);
-+ eprob = MINSTREL_TRUNC(mrs->prob_avg * 1000);
-
- p += sprintf(p, "%4u.%1u %4u.%1u %3u.%1u"
- " %3u %3u %-3u "
-@@ -147,8 +147,8 @@ minstrel_stats_csv_open(struct inode *in
- p += sprintf(p, "%u,",mr->perfect_tx_time);
-
- tp_max = minstrel_get_tp_avg(mr, MINSTREL_FRAC(100,100));
-- tp_avg = minstrel_get_tp_avg(mr, mrs->prob_ewma);
-- eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000);
-+ tp_avg = minstrel_get_tp_avg(mr, mrs->prob_avg);
-+ eprob = MINSTREL_TRUNC(mrs->prob_avg * 1000);
-
- p += sprintf(p, "%u.%u,%u.%u,%u.%u,%u,%u,%u,"
- "%llu,%llu,%d,%d\n",
---- a/net/mac80211/rc80211_minstrel_ht.c
-+++ b/net/mac80211/rc80211_minstrel_ht.c
-@@ -346,12 +346,12 @@ minstrel_ht_avg_ampdu_len(struct minstre
- */
- int
- minstrel_ht_get_tp_avg(struct minstrel_ht_sta *mi, int group, int rate,
-- int prob_ewma)
-+ int prob_avg)
- {
- unsigned int nsecs = 0;
-
- /* do not account throughput if sucess prob is below 10% */
-- if (prob_ewma < MINSTREL_FRAC(10, 100))
-+ if (prob_avg < MINSTREL_FRAC(10, 100))
- return 0;
-
- if (group != MINSTREL_CCK_GROUP)
-@@ -365,11 +365,11 @@ minstrel_ht_get_tp_avg(struct minstrel_h
- * account for collision related packet error rate fluctuation
- * (prob is scaled - see MINSTREL_FRAC above)
- */
-- if (prob_ewma > MINSTREL_FRAC(90, 100))
-+ if (prob_avg > MINSTREL_FRAC(90, 100))
- return MINSTREL_TRUNC(100000 * ((MINSTREL_FRAC(90, 100) * 1000)
- / nsecs));
- else
-- return MINSTREL_TRUNC(100000 * ((prob_ewma * 1000) / nsecs));
-+ return MINSTREL_TRUNC(100000 * ((prob_avg * 1000) / nsecs));
- }
-
- /*
-@@ -389,13 +389,13 @@ minstrel_ht_sort_best_tp_rates(struct mi
-
- cur_group = index / MCS_GROUP_RATES;
- cur_idx = index % MCS_GROUP_RATES;
-- cur_prob = mi->groups[cur_group].rates[cur_idx].prob_ewma;
-+ 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_prob = mi->groups[tmp_group].rates[tmp_idx].prob_ewma;
-+ 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 (cur_tp_avg < tmp_tp_avg ||
-@@ -432,7 +432,7 @@ minstrel_ht_set_best_prob_rate(struct mi
-
- tmp_group = mi->max_prob_rate / MCS_GROUP_RATES;
- tmp_idx = mi->max_prob_rate % MCS_GROUP_RATES;
-- tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_ewma;
-+ 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
-@@ -444,11 +444,11 @@ minstrel_ht_set_best_prob_rate(struct mi
-
- 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_ewma;
-+ max_gpr_prob = mi->groups[max_gpr_group].rates[max_gpr_idx].prob_avg;
-
-- if (mrs->prob_ewma > MINSTREL_FRAC(75, 100)) {
-+ if (mrs->prob_avg > MINSTREL_FRAC(75, 100)) {
- cur_tp_avg = minstrel_ht_get_tp_avg(mi, cur_group, cur_idx,
-- mrs->prob_ewma);
-+ mrs->prob_avg);
- if (cur_tp_avg > tmp_tp_avg)
- mi->max_prob_rate = index;
-
-@@ -458,9 +458,9 @@ minstrel_ht_set_best_prob_rate(struct mi
- if (cur_tp_avg > max_gpr_tp_avg)
- mg->max_group_prob_rate = index;
- } else {
-- if (mrs->prob_ewma > tmp_prob)
-+ if (mrs->prob_avg > tmp_prob)
- mi->max_prob_rate = index;
-- if (mrs->prob_ewma > max_gpr_prob)
-+ if (mrs->prob_avg > max_gpr_prob)
- mg->max_group_prob_rate = index;
- }
- }
-@@ -482,12 +482,12 @@ minstrel_ht_assign_best_tp_rates(struct
-
- tmp_group = tmp_cck_tp_rate[0] / MCS_GROUP_RATES;
- tmp_idx = tmp_cck_tp_rate[0] % MCS_GROUP_RATES;
-- tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_ewma;
-+ 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_prob = mi->groups[tmp_group].rates[tmp_idx].prob_ewma;
-+ 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);
-
- if (tmp_cck_tp_rate && tmp_cck_tp > tmp_mcs_tp) {
-@@ -518,7 +518,7 @@ minstrel_ht_prob_rate_reduce_streams(str
- continue;
-
- tmp_idx = mg->max_group_prob_rate % MCS_GROUP_RATES;
-- tmp_prob = mi->groups[group].rates[tmp_idx].prob_ewma;
-+ tmp_prob = mi->groups[group].rates[tmp_idx].prob_avg;
-
- if (tmp_tp < minstrel_ht_get_tp_avg(mi, group, tmp_idx, tmp_prob) &&
- (minstrel_mcs_groups[group].streams < tmp_max_streams)) {
-@@ -623,7 +623,7 @@ minstrel_ht_rate_sample_switch(struct mi
- * 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_ewma > MINSTREL_FRAC(75, 100);
-+ 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);
-@@ -738,7 +738,7 @@ minstrel_ht_update_stats(struct minstrel
- mrs = &mg->rates[i];
- mrs->retry_updated = false;
- minstrel_calc_rate_stats(mp, mrs);
-- cur_prob = mrs->prob_ewma;
-+ cur_prob = mrs->prob_avg;
-
- if (minstrel_ht_get_tp_avg(mi, group, i, cur_prob) == 0)
- continue;
-@@ -1012,7 +1012,7 @@ minstrel_calc_retransmit(struct minstrel
- unsigned int overhead = 0, overhead_rtscts = 0;
-
- mrs = minstrel_get_ratestats(mi, index);
-- if (mrs->prob_ewma < MINSTREL_FRAC(1, 10)) {
-+ if (mrs->prob_avg < MINSTREL_FRAC(1, 10)) {
- mrs->retry_count = 1;
- mrs->retry_count_rtscts = 1;
- return;
-@@ -1069,7 +1069,7 @@ minstrel_ht_set_rate(struct minstrel_pri
- if (!mrs->retry_updated)
- minstrel_calc_retransmit(mp, mi, index);
-
-- if (mrs->prob_ewma < MINSTREL_FRAC(20, 100) || !mrs->retry_count) {
-+ if (mrs->prob_avg < MINSTREL_FRAC(20, 100) || !mrs->retry_count) {
- ratetbl->rate[offset].count = 2;
- ratetbl->rate[offset].count_rts = 2;
- ratetbl->rate[offset].count_cts = 2;
-@@ -1103,11 +1103,11 @@ minstrel_ht_set_rate(struct minstrel_pri
- }
-
- static inline int
--minstrel_ht_get_prob_ewma(struct minstrel_ht_sta *mi, int rate)
-+minstrel_ht_get_prob_avg(struct minstrel_ht_sta *mi, int rate)
- {
- int group = rate / MCS_GROUP_RATES;
- rate %= MCS_GROUP_RATES;
-- return mi->groups[group].rates[rate].prob_ewma;
-+ return mi->groups[group].rates[rate].prob_avg;
- }
-
- static int
-@@ -1119,7 +1119,7 @@ minstrel_ht_get_max_amsdu_len(struct min
- unsigned int duration;
-
- /* Disable A-MSDU if max_prob_rate is bad */
-- if (mi->groups[group].rates[rate].prob_ewma < MINSTREL_FRAC(50, 100))
-+ if (mi->groups[group].rates[rate].prob_avg < MINSTREL_FRAC(50, 100))
- return 1;
-
- duration = g->duration[rate];
-@@ -1142,7 +1142,7 @@ minstrel_ht_get_max_amsdu_len(struct min
- * data packet size
- */
- if (duration > MCS_DURATION(1, 0, 260) ||
-- (minstrel_ht_get_prob_ewma(mi, mi->max_tp_rate[0]) <
-+ (minstrel_ht_get_prob_avg(mi, mi->max_tp_rate[0]) <
- MINSTREL_FRAC(75, 100)))
- return 3200;
-
-@@ -1247,7 +1247,7 @@ minstrel_get_sample_rate(struct minstrel
- * rate, to avoid wasting airtime.
- */
- sample_dur = minstrel_get_duration(sample_idx);
-- if (mrs->prob_ewma > MINSTREL_FRAC(95, 100) ||
-+ if (mrs->prob_avg > MINSTREL_FRAC(95, 100) ||
- minstrel_get_duration(mi->max_prob_rate) * 3 < sample_dur)
- return -1;
-
-@@ -1711,7 +1711,7 @@ static u32 minstrel_ht_get_expected_thro
-
- 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_ewma;
-+ prob = mi->groups[i].rates[j].prob_avg;
-
- /* convert tp_avg from pkt per second in kbps */
- tp_avg = minstrel_ht_get_tp_avg(mi, i, j, prob) * 10;
---- a/net/mac80211/rc80211_minstrel_ht.h
-+++ b/net/mac80211/rc80211_minstrel_ht.h
-@@ -119,6 +119,6 @@ struct minstrel_ht_sta_priv {
-
- void minstrel_ht_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir);
- int minstrel_ht_get_tp_avg(struct minstrel_ht_sta *mi, int group, int rate,
-- int prob_ewma);
-+ int prob_avg);
-
- #endif
---- a/net/mac80211/rc80211_minstrel_ht_debugfs.c
-+++ b/net/mac80211/rc80211_minstrel_ht_debugfs.c
-@@ -98,8 +98,8 @@ minstrel_ht_stats_dump(struct minstrel_h
- p += sprintf(p, "%6u ", tx_time);
-
- tp_max = minstrel_ht_get_tp_avg(mi, i, j, MINSTREL_FRAC(100, 100));
-- tp_avg = minstrel_ht_get_tp_avg(mi, i, j, mrs->prob_ewma);
-- eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000);
-+ tp_avg = minstrel_ht_get_tp_avg(mi, i, j, mrs->prob_avg);
-+ eprob = MINSTREL_TRUNC(mrs->prob_avg * 1000);
-
- p += sprintf(p, "%4u.%1u %4u.%1u %3u.%1u"
- " %3u %3u %-3u "
-@@ -243,8 +243,8 @@ minstrel_ht_stats_csv_dump(struct minstr
- p += sprintf(p, "%u,", tx_time);
-
- tp_max = minstrel_ht_get_tp_avg(mi, i, j, MINSTREL_FRAC(100, 100));
-- tp_avg = minstrel_ht_get_tp_avg(mi, i, j, mrs->prob_ewma);
-- eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000);
-+ tp_avg = minstrel_ht_get_tp_avg(mi, i, j, mrs->prob_avg);
-+ eprob = MINSTREL_TRUNC(mrs->prob_avg * 1000);
-
- p += sprintf(p, "%u.%u,%u.%u,%u.%u,%u,%u,"
- "%u,%llu,%llu,",
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
-@@ -324,6 +324,7 @@ struct sta_info *sta_info_alloc(struct i
+@@ -338,6 +338,7 @@ struct sta_info *sta_info_alloc(struct i
INIT_WORK(&sta->drv_deliver_wk, sta_deliver_ps_frames);
INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work);
mutex_init(&sta->ampdu_mlme.mtx);
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
-@@ -881,6 +881,7 @@ static void __ieee80211_tx_status(struct
+@@ -895,6 +895,7 @@ static void __ieee80211_tx_status(struct
int rates_idx;
bool send_to_cooked;
bool acked;
struct ieee80211_bar *bar;
int shift = 0;
int tid = IEEE80211_NUM_TIDS;
-@@ -898,6 +899,8 @@ static void __ieee80211_tx_status(struct
+@@ -913,6 +914,8 @@ static void __ieee80211_tx_status(struct
clear_sta_flag(sta, WLAN_STA_SP);
acked = !!(info->flags & IEEE80211_TX_STAT_ACK);
/* mesh Peer Service Period support */
if (ieee80211_vif_is_mesh(&sta->sdata->vif) &&
-@@ -962,12 +965,12 @@ static void __ieee80211_tx_status(struct
+@@ -977,12 +980,12 @@ static void __ieee80211_tx_status(struct
ieee80211_handle_filtered_frame(local, sta, skb);
return;
} else {
sta->status_stats.msdu_failed[tid]++;
sta->status_stats.msdu_retries[tid] +=
-@@ -994,7 +997,7 @@ static void __ieee80211_tx_status(struct
- info->status.tx_time, 0);
+@@ -1020,7 +1023,7 @@ static void __ieee80211_tx_status(struct
+ }
if (ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) {
- if (info->flags & IEEE80211_TX_STAT_ACK) {
if (sta->status_stats.lost_packets)
sta->status_stats.lost_packets = 0;
-@@ -1002,6 +1005,8 @@ static void __ieee80211_tx_status(struct
+@@ -1028,6 +1031,8 @@ static void __ieee80211_tx_status(struct
if (test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH))
sta->status_stats.last_tdls_pkt_time =
jiffies;
} else {
ieee80211_lost_packet(sta, info);
}
-@@ -1128,7 +1133,7 @@ void ieee80211_tx_status_ext(struct ieee
+@@ -1148,7 +1153,7 @@ void ieee80211_tx_status_ext(struct ieee
sta = container_of(pubsta, struct sta_info, sta);
sta->status_stats.retry_failed++;
sta->status_stats.retry_count += retry_count;
-@@ -1143,6 +1148,8 @@ void ieee80211_tx_status_ext(struct ieee
+@@ -1163,6 +1168,8 @@ void ieee80211_tx_status_ext(struct ieee
sta->status_stats.last_tdls_pkt_time = jiffies;
} else if (test_sta_flag(sta, WLAN_STA_PS_STA)) {
return;
+++ /dev/null
-From: John Crispin <john@phrozen.org>
-Date: Tue, 29 Oct 2019 10:13:02 +0100
-Subject: [PATCH] mac80211: move store skb ack code to its own function
-
-This patch moves the code handling SKBTX_WIFI_STATUS inside the TX path
-into an extra function. This allows us to reuse it inside the 802.11 encap
-offloading datapath.
-
-Signed-off-by: John Crispin <john@phrozen.org>
-Link: https://lore.kernel.org/r/20191029091304.7330-2-john@phrozen.org
-Signed-off-by: Johannes Berg <johannes.berg@intel.com>
----
-
---- a/net/mac80211/tx.c
-+++ b/net/mac80211/tx.c
-@@ -2445,6 +2445,33 @@ static int ieee80211_lookup_ra_sta(struc
- return 0;
- }
-
-+static int ieee80211_store_ack_skb(struct ieee80211_local *local,
-+ struct sk_buff *skb,
-+ u32 *info_flags)
-+{
-+ struct sk_buff *ack_skb = skb_clone_sk(skb);
-+ u16 info_id = 0;
-+
-+ if (ack_skb) {
-+ unsigned long flags;
-+ int id;
-+
-+ spin_lock_irqsave(&local->ack_status_lock, flags);
-+ id = idr_alloc(&local->ack_status_frames, ack_skb,
-+ 1, 0x10000, GFP_ATOMIC);
-+ spin_unlock_irqrestore(&local->ack_status_lock, flags);
-+
-+ if (id >= 0) {
-+ info_id = id;
-+ *info_flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
-+ } else {
-+ kfree_skb(ack_skb);
-+ }
-+ }
-+
-+ return info_id;
-+}
-+
- /**
- * ieee80211_build_hdr - build 802.11 header in the given frame
- * @sdata: virtual interface to build the header for
-@@ -2738,26 +2765,8 @@ static struct sk_buff *ieee80211_build_h
- }
-
- if (unlikely(!multicast && skb->sk &&
-- skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS)) {
-- struct sk_buff *ack_skb = skb_clone_sk(skb);
--
-- if (ack_skb) {
-- unsigned long flags;
-- int id;
--
-- spin_lock_irqsave(&local->ack_status_lock, flags);
-- id = idr_alloc(&local->ack_status_frames, ack_skb,
-- 1, 0x10000, GFP_ATOMIC);
-- spin_unlock_irqrestore(&local->ack_status_lock, flags);
--
-- if (id >= 0) {
-- info_id = id;
-- info_flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
-- } else {
-- kfree_skb(ack_skb);
-- }
-- }
-- }
-+ skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS))
-+ info_id = ieee80211_store_ack_skb(local, skb, &info_flags);
-
- /*
- * If the skb is shared we need to obtain our own copy.
+++ /dev/null
-From: =?UTF-8?q?Toke=20H=C3=B8iland-J=C3=B8rgensen?= <toke@redhat.com>
-Date: Wed, 23 Oct 2019 11:59:00 +0200
-Subject: [PATCH] mac80211: Shrink the size of ack_frame_id to make room for
- tx_time_est
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-To implement airtime queue limiting, we need to keep a running account of
-the estimated airtime of all skbs queued into the device. Do to this
-correctly, we need to store the airtime estimate into the skb so we can
-decrease the outstanding balance when the skb is freed. This means that the
-time estimate must be stored somewhere that will survive for the lifetime
-of the skb.
-
-To get this, decrease the size of the ack_frame_id field to 6 bits, and
-lower the size of the ID space accordingly. This leaves 10 bits for use for
-tx_time_est, which is enough to store a maximum of 4096 us, if we shift the
-values so they become units of 4us.
-
-Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
-Link: https://lore.kernel.org/r/157182474063.150713.16132669599100802716.stgit@toke.dk
-Signed-off-by: Johannes Berg <johannes.berg@intel.com>
----
-
---- a/include/net/mac80211.h
-+++ b/include/net/mac80211.h
-@@ -967,6 +967,7 @@ ieee80211_rate_get_vht_nss(const struct
- * @band: the band to transmit on (use for checking for races)
- * @hw_queue: HW queue to put the frame on, skb_get_queue_mapping() gives the AC
- * @ack_frame_id: internal frame ID for TX status, used internally
-+ * @tx_time_est: TX time estimate in units of 4us, used internally
- * @control: union part for control data
- * @control.rates: TX rates array to try
- * @control.rts_cts_rate_idx: rate for RTS or CTS
-@@ -1007,7 +1008,8 @@ struct ieee80211_tx_info {
-
- u8 hw_queue;
-
-- u16 ack_frame_id;
-+ u16 ack_frame_id:6;
-+ u16 tx_time_est:10;
-
- union {
- struct {
---- a/net/mac80211/cfg.c
-+++ b/net/mac80211/cfg.c
-@@ -3449,7 +3449,7 @@ int ieee80211_attach_ack_skb(struct ieee
-
- spin_lock_irqsave(&local->ack_status_lock, spin_flags);
- id = idr_alloc(&local->ack_status_frames, ack_skb,
-- 1, 0x10000, GFP_ATOMIC);
-+ 1, 0x40, GFP_ATOMIC);
- spin_unlock_irqrestore(&local->ack_status_lock, spin_flags);
-
- if (id < 0) {
---- a/net/mac80211/tx.c
-+++ b/net/mac80211/tx.c
-@@ -2458,7 +2458,7 @@ static int ieee80211_store_ack_skb(struc
-
- spin_lock_irqsave(&local->ack_status_lock, flags);
- id = idr_alloc(&local->ack_status_frames, ack_skb,
-- 1, 0x10000, GFP_ATOMIC);
-+ 1, 0x40, GFP_ATOMIC);
- spin_unlock_irqrestore(&local->ack_status_lock, flags);
-
- if (id >= 0) {
+++ /dev/null
-From: =?UTF-8?q?Toke=20H=C3=B8iland-J=C3=B8rgensen?= <toke@redhat.com>
-Date: Tue, 12 Nov 2019 14:08:35 +0100
-Subject: [PATCH] mac80211: Add new sta_info getter by sta/vif addrs
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-In ieee80211_tx_status() we don't have an sdata struct when looking up the
-destination sta. Instead, we just do a lookup by the vif addr that is the
-source of the packet being completed. Factor this out into a new sta_info
-getter helper, since we need to use it for accounting AQL as well.
-
-Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
-Link: https://lore.kernel.org/r/20191112130835.382062-1-toke@redhat.com
-[remove internal rcu_read_lock(), document instead]
-Signed-off-by: Johannes Berg <johannes.berg@intel.com>
----
-
---- a/net/mac80211/sta_info.c
-+++ b/net/mac80211/sta_info.c
-@@ -210,6 +210,20 @@ struct sta_info *sta_info_get_bss(struct
- return NULL;
- }
-
-+struct sta_info *sta_info_get_by_addrs(struct ieee80211_local *local,
-+ const u8 *sta_addr, const u8 *vif_addr)
-+{
-+ struct rhlist_head *tmp;
-+ struct sta_info *sta;
-+
-+ for_each_sta_info(local, sta_addr, sta, tmp) {
-+ if (ether_addr_equal(vif_addr, sta->sdata->vif.addr))
-+ return sta;
-+ }
-+
-+ return NULL;
-+}
-+
- struct sta_info *sta_info_get_by_idx(struct ieee80211_sub_if_data *sdata,
- int idx)
- {
---- a/net/mac80211/sta_info.h
-+++ b/net/mac80211/sta_info.h
-@@ -726,6 +726,10 @@ struct sta_info *sta_info_get(struct iee
- struct sta_info *sta_info_get_bss(struct ieee80211_sub_if_data *sdata,
- const u8 *addr);
-
-+/* user must hold sta_mtx or be in RCU critical section */
-+struct sta_info *sta_info_get_by_addrs(struct ieee80211_local *local,
-+ const u8 *sta_addr, const u8 *vif_addr);
-+
- #define for_each_sta_info(local, _addr, _sta, _tmp) \
- rhl_for_each_entry_rcu(_sta, _tmp, \
- sta_info_hash_lookup(local, _addr), hash_node)
---- a/net/mac80211/status.c
-+++ b/net/mac80211/status.c
-@@ -1086,19 +1086,13 @@ void ieee80211_tx_status(struct ieee8021
- .skb = skb,
- .info = IEEE80211_SKB_CB(skb),
- };
-- struct rhlist_head *tmp;
- struct sta_info *sta;
-
- rcu_read_lock();
-
-- for_each_sta_info(local, hdr->addr1, sta, tmp) {
-- /* skip wrong virtual interface */
-- if (!ether_addr_equal(hdr->addr2, sta->sdata->vif.addr))
-- continue;
--
-+ sta = sta_info_get_by_addrs(local, hdr->addr1, hdr->addr2);
-+ if (sta)
- status.sta = &sta->sta;
-- break;
-- }
-
- __ieee80211_tx_status(hw, &status);
- rcu_read_unlock();
+++ /dev/null
-From: =?UTF-8?q?Toke=20H=C3=B8iland-J=C3=B8rgensen?= <toke@redhat.com>
-Date: Mon, 18 Nov 2019 22:06:08 -0800
-Subject: [PATCH] mac80211: Import airtime calculation code from mt76
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Felix recently added code to calculate airtime of packets to the mt76
-driver. Import this into mac80211 so we can use it for airtime queue limit
-calculations.
-
-The airtime.c file is copied verbatim from the mt76 driver, and adjusted to
-be usable in mac80211. This involves:
-
-- Switching to mac80211 data structures.
-- Adding support for 160 MHz channels and HE mode.
-- Moving the symbol and duration calculations around a bit to avoid
- rounding with the higher rates and longer symbol times used for HE rates.
-
-The per-rate TX rate calculation is also split out to its own function so
-it can be used directly for the AQL calculations later.
-
-Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
-Link: https://lore.kernel.org/r/20191119060610.76681-3-kyan@google.com
-[fix HE_GROUP_IDX() to use 3 * bw, since there are 3 _gi values]
-Signed-off-by: Johannes Berg <johannes.berg@intel.com>
----
- create mode 100644 net/mac80211/airtime.c
-
---- a/include/net/mac80211.h
-+++ b/include/net/mac80211.h
-@@ -6419,4 +6419,33 @@ void ieee80211_nan_func_match(struct iee
- struct cfg80211_nan_match_params *match,
- gfp_t gfp);
-
-+/**
-+ * ieee80211_calc_rx_airtime - calculate estimated transmission airtime for RX.
-+ *
-+ * This function calculates the estimated airtime usage of a frame based on the
-+ * rate information in the RX status struct and the frame length.
-+ *
-+ * @hw: pointer as obtained from ieee80211_alloc_hw()
-+ * @status: &struct ieee80211_rx_status containing the transmission rate
-+ * information.
-+ * @len: frame length in bytes
-+ */
-+u32 ieee80211_calc_rx_airtime(struct ieee80211_hw *hw,
-+ struct ieee80211_rx_status *status,
-+ int len);
-+
-+/**
-+ * ieee80211_calc_tx_airtime - calculate estimated transmission airtime for TX.
-+ *
-+ * This function calculates the estimated airtime usage of a frame based on the
-+ * rate information in the TX info struct and the frame length.
-+ *
-+ * @hw: pointer as obtained from ieee80211_alloc_hw()
-+ * @info: &struct ieee80211_tx_info of the frame.
-+ * @len: frame length in bytes
-+ */
-+u32 ieee80211_calc_tx_airtime(struct ieee80211_hw *hw,
-+ struct ieee80211_tx_info *info,
-+ int len);
-+
- #endif /* MAC80211_H */
---- a/net/mac80211/Makefile
-+++ b/net/mac80211/Makefile
-@@ -31,7 +31,8 @@ mac80211-y := \
- chan.o \
- trace.o mlme.o \
- tdls.o \
-- ocb.o
-+ ocb.o \
-+ airtime.o
-
- mac80211-$(CPTCFG_MAC80211_LEDS) += led.o
- mac80211-$(CPTCFG_MAC80211_DEBUGFS) += \
---- /dev/null
-+++ b/net/mac80211/airtime.c
-@@ -0,0 +1,597 @@
-+// SPDX-License-Identifier: ISC
-+/*
-+ * Copyright (C) 2019 Felix Fietkau <nbd@nbd.name>
-+ */
-+
-+#include <net/mac80211.h>
-+#include "ieee80211_i.h"
-+#include "sta_info.h"
-+
-+#define AVG_PKT_SIZE 1024
-+
-+/* Number of bits for an average sized packet */
-+#define MCS_NBITS (AVG_PKT_SIZE << 3)
-+
-+/* Number of kilo-symbols (symbols * 1024) for a packet with (bps) bits per
-+ * symbol. We use k-symbols to avoid rounding in the _TIME macros below.
-+ */
-+#define MCS_N_KSYMS(bps) DIV_ROUND_UP(MCS_NBITS << 10, (bps))
-+
-+/* Transmission time (in 1024 * usec) for a packet containing (ksyms) * 1024
-+ * symbols.
-+ */
-+#define MCS_SYMBOL_TIME(sgi, ksyms) \
-+ (sgi ? \
-+ ((ksyms) * 4 * 18) / 20 : /* 3.6 us per sym */ \
-+ ((ksyms) * 4) /* 4.0 us per sym */ \
-+ )
-+
-+/* Transmit duration for the raw data part of an average sized packet */
-+#define MCS_DURATION(streams, sgi, bps) \
-+ ((u32)MCS_SYMBOL_TIME(sgi, MCS_N_KSYMS((streams) * (bps))))
-+
-+#define MCS_DURATION_S(shift, streams, sgi, bps) \
-+ ((u16)((MCS_DURATION(streams, sgi, bps) >> shift)))
-+
-+/* These should match the values in enum nl80211_he_gi */
-+#define HE_GI_08 0
-+#define HE_GI_16 1
-+#define HE_GI_32 2
-+
-+/* Transmission time (1024 usec) for a packet containing (ksyms) * k-symbols */
-+#define HE_SYMBOL_TIME(gi, ksyms) \
-+ (gi == HE_GI_08 ? \
-+ ((ksyms) * 16 * 17) / 20 : /* 13.6 us per sym */ \
-+ (gi == HE_GI_16 ? \
-+ ((ksyms) * 16 * 18) / 20 : /* 14.4 us per sym */ \
-+ ((ksyms) * 16) /* 16.0 us per sym */ \
-+ ))
-+
-+/* Transmit duration for the raw data part of an average sized packet */
-+#define HE_DURATION(streams, gi, bps) \
-+ ((u32)HE_SYMBOL_TIME(gi, MCS_N_KSYMS((streams) * (bps))))
-+
-+#define HE_DURATION_S(shift, streams, gi, bps) \
-+ (HE_DURATION(streams, gi, bps) >> shift)
-+
-+#define BW_20 0
-+#define BW_40 1
-+#define BW_80 2
-+#define BW_160 3
-+
-+/*
-+ * Define group sort order: HT40 -> SGI -> #streams
-+ */
-+#define IEEE80211_MAX_STREAMS 4
-+#define IEEE80211_HT_STREAM_GROUPS 4 /* BW(=2) * SGI(=2) */
-+#define IEEE80211_VHT_STREAM_GROUPS 8 /* BW(=4) * SGI(=2) */
-+
-+#define IEEE80211_HE_MAX_STREAMS 8
-+#define IEEE80211_HE_STREAM_GROUPS 12 /* BW(=4) * GI(=3) */
-+
-+#define IEEE80211_HT_GROUPS_NB (IEEE80211_MAX_STREAMS * \
-+ IEEE80211_HT_STREAM_GROUPS)
-+#define IEEE80211_VHT_GROUPS_NB (IEEE80211_MAX_STREAMS * \
-+ IEEE80211_VHT_STREAM_GROUPS)
-+#define IEEE80211_HE_GROUPS_NB (IEEE80211_HE_MAX_STREAMS * \
-+ IEEE80211_HE_STREAM_GROUPS)
-+#define IEEE80211_GROUPS_NB (IEEE80211_HT_GROUPS_NB + \
-+ IEEE80211_VHT_GROUPS_NB + \
-+ IEEE80211_HE_GROUPS_NB)
-+
-+#define IEEE80211_HT_GROUP_0 0
-+#define IEEE80211_VHT_GROUP_0 (IEEE80211_HT_GROUP_0 + IEEE80211_HT_GROUPS_NB)
-+#define IEEE80211_HE_GROUP_0 (IEEE80211_VHT_GROUP_0 + IEEE80211_VHT_GROUPS_NB)
-+
-+#define MCS_GROUP_RATES 12
-+
-+#define HT_GROUP_IDX(_streams, _sgi, _ht40) \
-+ IEEE80211_HT_GROUP_0 + \
-+ IEEE80211_MAX_STREAMS * 2 * _ht40 + \
-+ IEEE80211_MAX_STREAMS * _sgi + \
-+ _streams - 1
-+
-+#define _MAX(a, b) (((a)>(b))?(a):(b))
-+
-+#define GROUP_SHIFT(duration) \
-+ _MAX(0, 16 - __builtin_clz(duration))
-+
-+/* MCS rate information for an MCS group */
-+#define __MCS_GROUP(_streams, _sgi, _ht40, _s) \
-+ [HT_GROUP_IDX(_streams, _sgi, _ht40)] = { \
-+ .shift = _s, \
-+ .duration = { \
-+ MCS_DURATION_S(_s, _streams, _sgi, _ht40 ? 54 : 26), \
-+ MCS_DURATION_S(_s, _streams, _sgi, _ht40 ? 108 : 52), \
-+ MCS_DURATION_S(_s, _streams, _sgi, _ht40 ? 162 : 78), \
-+ MCS_DURATION_S(_s, _streams, _sgi, _ht40 ? 216 : 104), \
-+ MCS_DURATION_S(_s, _streams, _sgi, _ht40 ? 324 : 156), \
-+ MCS_DURATION_S(_s, _streams, _sgi, _ht40 ? 432 : 208), \
-+ MCS_DURATION_S(_s, _streams, _sgi, _ht40 ? 486 : 234), \
-+ MCS_DURATION_S(_s, _streams, _sgi, _ht40 ? 540 : 260) \
-+ } \
-+}
-+
-+#define MCS_GROUP_SHIFT(_streams, _sgi, _ht40) \
-+ GROUP_SHIFT(MCS_DURATION(_streams, _sgi, _ht40 ? 54 : 26))
-+
-+#define MCS_GROUP(_streams, _sgi, _ht40) \
-+ __MCS_GROUP(_streams, _sgi, _ht40, \
-+ MCS_GROUP_SHIFT(_streams, _sgi, _ht40))
-+
-+#define VHT_GROUP_IDX(_streams, _sgi, _bw) \
-+ (IEEE80211_VHT_GROUP_0 + \
-+ IEEE80211_MAX_STREAMS * 2 * (_bw) + \
-+ IEEE80211_MAX_STREAMS * (_sgi) + \
-+ (_streams) - 1)
-+
-+#define BW2VBPS(_bw, r4, r3, r2, r1) \
-+ (_bw == BW_160 ? r4 : _bw == BW_80 ? r3 : _bw == BW_40 ? r2 : r1)
-+
-+#define __VHT_GROUP(_streams, _sgi, _bw, _s) \
-+ [VHT_GROUP_IDX(_streams, _sgi, _bw)] = { \
-+ .shift = _s, \
-+ .duration = { \
-+ MCS_DURATION_S(_s, _streams, _sgi, \
-+ BW2VBPS(_bw, 234, 117, 54, 26)), \
-+ MCS_DURATION_S(_s, _streams, _sgi, \
-+ BW2VBPS(_bw, 468, 234, 108, 52)), \
-+ MCS_DURATION_S(_s, _streams, _sgi, \
-+ BW2VBPS(_bw, 702, 351, 162, 78)), \
-+ MCS_DURATION_S(_s, _streams, _sgi, \
-+ BW2VBPS(_bw, 936, 468, 216, 104)), \
-+ MCS_DURATION_S(_s, _streams, _sgi, \
-+ BW2VBPS(_bw, 1404, 702, 324, 156)), \
-+ MCS_DURATION_S(_s, _streams, _sgi, \
-+ BW2VBPS(_bw, 1872, 936, 432, 208)), \
-+ MCS_DURATION_S(_s, _streams, _sgi, \
-+ BW2VBPS(_bw, 2106, 1053, 486, 234)), \
-+ MCS_DURATION_S(_s, _streams, _sgi, \
-+ BW2VBPS(_bw, 2340, 1170, 540, 260)), \
-+ MCS_DURATION_S(_s, _streams, _sgi, \
-+ BW2VBPS(_bw, 2808, 1404, 648, 312)), \
-+ MCS_DURATION_S(_s, _streams, _sgi, \
-+ BW2VBPS(_bw, 3120, 1560, 720, 346)) \
-+ } \
-+}
-+
-+#define VHT_GROUP_SHIFT(_streams, _sgi, _bw) \
-+ GROUP_SHIFT(MCS_DURATION(_streams, _sgi, \
-+ BW2VBPS(_bw, 243, 117, 54, 26)))
-+
-+#define VHT_GROUP(_streams, _sgi, _bw) \
-+ __VHT_GROUP(_streams, _sgi, _bw, \
-+ VHT_GROUP_SHIFT(_streams, _sgi, _bw))
-+
-+
-+#define HE_GROUP_IDX(_streams, _gi, _bw) \
-+ (IEEE80211_HE_GROUP_0 + \
-+ IEEE80211_HE_MAX_STREAMS * 3 * (_bw) + \
-+ IEEE80211_HE_MAX_STREAMS * (_gi) + \
-+ (_streams) - 1)
-+
-+#define __HE_GROUP(_streams, _gi, _bw, _s) \
-+ [HE_GROUP_IDX(_streams, _gi, _bw)] = { \
-+ .shift = _s, \
-+ .duration = { \
-+ HE_DURATION_S(_s, _streams, _gi, \
-+ BW2VBPS(_bw, 979, 489, 230, 115)), \
-+ HE_DURATION_S(_s, _streams, _gi, \
-+ BW2VBPS(_bw, 1958, 979, 475, 230)), \
-+ HE_DURATION_S(_s, _streams, _gi, \
-+ BW2VBPS(_bw, 2937, 1468, 705, 345)), \
-+ HE_DURATION_S(_s, _streams, _gi, \
-+ BW2VBPS(_bw, 3916, 1958, 936, 475)), \
-+ HE_DURATION_S(_s, _streams, _gi, \
-+ BW2VBPS(_bw, 5875, 2937, 1411, 705)), \
-+ HE_DURATION_S(_s, _streams, _gi, \
-+ BW2VBPS(_bw, 7833, 3916, 1872, 936)), \
-+ HE_DURATION_S(_s, _streams, _gi, \
-+ BW2VBPS(_bw, 8827, 4406, 2102, 1051)), \
-+ HE_DURATION_S(_s, _streams, _gi, \
-+ BW2VBPS(_bw, 9806, 4896, 2347, 1166)), \
-+ HE_DURATION_S(_s, _streams, _gi, \
-+ BW2VBPS(_bw, 11764, 5875, 2808, 1411)), \
-+ HE_DURATION_S(_s, _streams, _gi, \
-+ BW2VBPS(_bw, 13060, 6523, 3124, 1555)), \
-+ HE_DURATION_S(_s, _streams, _gi, \
-+ BW2VBPS(_bw, 14702, 7344, 3513, 1756)), \
-+ HE_DURATION_S(_s, _streams, _gi, \
-+ BW2VBPS(_bw, 16329, 8164, 3902, 1944)) \
-+ } \
-+}
-+
-+#define HE_GROUP_SHIFT(_streams, _gi, _bw) \
-+ GROUP_SHIFT(HE_DURATION(_streams, _gi, \
-+ BW2VBPS(_bw, 979, 489, 230, 115)))
-+
-+#define HE_GROUP(_streams, _gi, _bw) \
-+ __HE_GROUP(_streams, _gi, _bw, \
-+ HE_GROUP_SHIFT(_streams, _gi, _bw))
-+struct mcs_group {
-+ u8 shift;
-+ u16 duration[MCS_GROUP_RATES];
-+};
-+
-+static const struct mcs_group airtime_mcs_groups[] = {
-+ MCS_GROUP(1, 0, BW_20),
-+ MCS_GROUP(2, 0, BW_20),
-+ MCS_GROUP(3, 0, BW_20),
-+ MCS_GROUP(4, 0, BW_20),
-+
-+ MCS_GROUP(1, 1, BW_20),
-+ MCS_GROUP(2, 1, BW_20),
-+ MCS_GROUP(3, 1, BW_20),
-+ MCS_GROUP(4, 1, BW_20),
-+
-+ MCS_GROUP(1, 0, BW_40),
-+ MCS_GROUP(2, 0, BW_40),
-+ MCS_GROUP(3, 0, BW_40),
-+ MCS_GROUP(4, 0, BW_40),
-+
-+ MCS_GROUP(1, 1, BW_40),
-+ MCS_GROUP(2, 1, BW_40),
-+ MCS_GROUP(3, 1, BW_40),
-+ MCS_GROUP(4, 1, BW_40),
-+
-+ VHT_GROUP(1, 0, BW_20),
-+ VHT_GROUP(2, 0, BW_20),
-+ VHT_GROUP(3, 0, BW_20),
-+ VHT_GROUP(4, 0, BW_20),
-+
-+ VHT_GROUP(1, 1, BW_20),
-+ VHT_GROUP(2, 1, BW_20),
-+ VHT_GROUP(3, 1, BW_20),
-+ VHT_GROUP(4, 1, BW_20),
-+
-+ VHT_GROUP(1, 0, BW_40),
-+ VHT_GROUP(2, 0, BW_40),
-+ VHT_GROUP(3, 0, BW_40),
-+ VHT_GROUP(4, 0, BW_40),
-+
-+ VHT_GROUP(1, 1, BW_40),
-+ VHT_GROUP(2, 1, BW_40),
-+ VHT_GROUP(3, 1, BW_40),
-+ VHT_GROUP(4, 1, BW_40),
-+
-+ VHT_GROUP(1, 0, BW_80),
-+ VHT_GROUP(2, 0, BW_80),
-+ VHT_GROUP(3, 0, BW_80),
-+ VHT_GROUP(4, 0, BW_80),
-+
-+ VHT_GROUP(1, 1, BW_80),
-+ VHT_GROUP(2, 1, BW_80),
-+ VHT_GROUP(3, 1, BW_80),
-+ VHT_GROUP(4, 1, BW_80),
-+
-+ VHT_GROUP(1, 0, BW_160),
-+ VHT_GROUP(2, 0, BW_160),
-+ VHT_GROUP(3, 0, BW_160),
-+ VHT_GROUP(4, 0, BW_160),
-+
-+ VHT_GROUP(1, 1, BW_160),
-+ VHT_GROUP(2, 1, BW_160),
-+ VHT_GROUP(3, 1, BW_160),
-+ VHT_GROUP(4, 1, BW_160),
-+
-+ HE_GROUP(1, HE_GI_08, BW_20),
-+ HE_GROUP(2, HE_GI_08, BW_20),
-+ HE_GROUP(3, HE_GI_08, BW_20),
-+ HE_GROUP(4, HE_GI_08, BW_20),
-+ HE_GROUP(5, HE_GI_08, BW_20),
-+ HE_GROUP(6, HE_GI_08, BW_20),
-+ HE_GROUP(7, HE_GI_08, BW_20),
-+ HE_GROUP(8, HE_GI_08, BW_20),
-+
-+ HE_GROUP(1, HE_GI_16, BW_20),
-+ HE_GROUP(2, HE_GI_16, BW_20),
-+ HE_GROUP(3, HE_GI_16, BW_20),
-+ HE_GROUP(4, HE_GI_16, BW_20),
-+ HE_GROUP(5, HE_GI_16, BW_20),
-+ HE_GROUP(6, HE_GI_16, BW_20),
-+ HE_GROUP(7, HE_GI_16, BW_20),
-+ HE_GROUP(8, HE_GI_16, BW_20),
-+
-+ HE_GROUP(1, HE_GI_32, BW_20),
-+ HE_GROUP(2, HE_GI_32, BW_20),
-+ HE_GROUP(3, HE_GI_32, BW_20),
-+ HE_GROUP(4, HE_GI_32, BW_20),
-+ HE_GROUP(5, HE_GI_32, BW_20),
-+ HE_GROUP(6, HE_GI_32, BW_20),
-+ HE_GROUP(7, HE_GI_32, BW_20),
-+ HE_GROUP(8, HE_GI_32, BW_20),
-+
-+ HE_GROUP(1, HE_GI_08, BW_40),
-+ HE_GROUP(2, HE_GI_08, BW_40),
-+ HE_GROUP(3, HE_GI_08, BW_40),
-+ HE_GROUP(4, HE_GI_08, BW_40),
-+ HE_GROUP(5, HE_GI_08, BW_40),
-+ HE_GROUP(6, HE_GI_08, BW_40),
-+ HE_GROUP(7, HE_GI_08, BW_40),
-+ HE_GROUP(8, HE_GI_08, BW_40),
-+
-+ HE_GROUP(1, HE_GI_16, BW_40),
-+ HE_GROUP(2, HE_GI_16, BW_40),
-+ HE_GROUP(3, HE_GI_16, BW_40),
-+ HE_GROUP(4, HE_GI_16, BW_40),
-+ HE_GROUP(5, HE_GI_16, BW_40),
-+ HE_GROUP(6, HE_GI_16, BW_40),
-+ HE_GROUP(7, HE_GI_16, BW_40),
-+ HE_GROUP(8, HE_GI_16, BW_40),
-+
-+ HE_GROUP(1, HE_GI_32, BW_40),
-+ HE_GROUP(2, HE_GI_32, BW_40),
-+ HE_GROUP(3, HE_GI_32, BW_40),
-+ HE_GROUP(4, HE_GI_32, BW_40),
-+ HE_GROUP(5, HE_GI_32, BW_40),
-+ HE_GROUP(6, HE_GI_32, BW_40),
-+ HE_GROUP(7, HE_GI_32, BW_40),
-+ HE_GROUP(8, HE_GI_32, BW_40),
-+
-+ HE_GROUP(1, HE_GI_08, BW_80),
-+ HE_GROUP(2, HE_GI_08, BW_80),
-+ HE_GROUP(3, HE_GI_08, BW_80),
-+ HE_GROUP(4, HE_GI_08, BW_80),
-+ HE_GROUP(5, HE_GI_08, BW_80),
-+ HE_GROUP(6, HE_GI_08, BW_80),
-+ HE_GROUP(7, HE_GI_08, BW_80),
-+ HE_GROUP(8, HE_GI_08, BW_80),
-+
-+ HE_GROUP(1, HE_GI_16, BW_80),
-+ HE_GROUP(2, HE_GI_16, BW_80),
-+ HE_GROUP(3, HE_GI_16, BW_80),
-+ HE_GROUP(4, HE_GI_16, BW_80),
-+ HE_GROUP(5, HE_GI_16, BW_80),
-+ HE_GROUP(6, HE_GI_16, BW_80),
-+ HE_GROUP(7, HE_GI_16, BW_80),
-+ HE_GROUP(8, HE_GI_16, BW_80),
-+
-+ HE_GROUP(1, HE_GI_32, BW_80),
-+ HE_GROUP(2, HE_GI_32, BW_80),
-+ HE_GROUP(3, HE_GI_32, BW_80),
-+ HE_GROUP(4, HE_GI_32, BW_80),
-+ HE_GROUP(5, HE_GI_32, BW_80),
-+ HE_GROUP(6, HE_GI_32, BW_80),
-+ HE_GROUP(7, HE_GI_32, BW_80),
-+ HE_GROUP(8, HE_GI_32, BW_80),
-+
-+ HE_GROUP(1, HE_GI_08, BW_160),
-+ HE_GROUP(2, HE_GI_08, BW_160),
-+ HE_GROUP(3, HE_GI_08, BW_160),
-+ HE_GROUP(4, HE_GI_08, BW_160),
-+ HE_GROUP(5, HE_GI_08, BW_160),
-+ HE_GROUP(6, HE_GI_08, BW_160),
-+ HE_GROUP(7, HE_GI_08, BW_160),
-+ HE_GROUP(8, HE_GI_08, BW_160),
-+
-+ HE_GROUP(1, HE_GI_16, BW_160),
-+ HE_GROUP(2, HE_GI_16, BW_160),
-+ HE_GROUP(3, HE_GI_16, BW_160),
-+ HE_GROUP(4, HE_GI_16, BW_160),
-+ HE_GROUP(5, HE_GI_16, BW_160),
-+ HE_GROUP(6, HE_GI_16, BW_160),
-+ HE_GROUP(7, HE_GI_16, BW_160),
-+ HE_GROUP(8, HE_GI_16, BW_160),
-+
-+ HE_GROUP(1, HE_GI_32, BW_160),
-+ HE_GROUP(2, HE_GI_32, BW_160),
-+ HE_GROUP(3, HE_GI_32, BW_160),
-+ HE_GROUP(4, HE_GI_32, BW_160),
-+ HE_GROUP(5, HE_GI_32, BW_160),
-+ HE_GROUP(6, HE_GI_32, BW_160),
-+ HE_GROUP(7, HE_GI_32, BW_160),
-+ HE_GROUP(8, HE_GI_32, BW_160),
-+};
-+
-+static u32
-+ieee80211_calc_legacy_rate_duration(u16 bitrate, bool short_pre,
-+ bool cck, int len)
-+{
-+ u32 duration;
-+
-+ if (cck) {
-+ duration = 144 + 48; /* preamble + PLCP */
-+ if (short_pre)
-+ duration >>= 1;
-+
-+ duration += 10; /* SIFS */
-+ } else {
-+ duration = 20 + 16; /* premable + SIFS */
-+ }
-+
-+ len <<= 3;
-+ duration += (len * 10) / bitrate;
-+
-+ return duration;
-+}
-+
-+u32 ieee80211_calc_rx_airtime(struct ieee80211_hw *hw,
-+ struct ieee80211_rx_status *status,
-+ int len)
-+{
-+ struct ieee80211_supported_band *sband;
-+ const struct ieee80211_rate *rate;
-+ bool sgi = status->enc_flags & RX_ENC_FLAG_SHORT_GI;
-+ bool sp = status->enc_flags & RX_ENC_FLAG_SHORTPRE;
-+ int bw, streams;
-+ int group, idx;
-+ u32 duration;
-+ bool cck;
-+
-+ switch (status->bw) {
-+ case RATE_INFO_BW_20:
-+ bw = BW_20;
-+ break;
-+ case RATE_INFO_BW_40:
-+ bw = BW_40;
-+ break;
-+ case RATE_INFO_BW_80:
-+ bw = BW_80;
-+ break;
-+ case RATE_INFO_BW_160:
-+ bw = BW_160;
-+ break;
-+ default:
-+ WARN_ON_ONCE(1);
-+ return 0;
-+ }
-+
-+ switch (status->encoding) {
-+ case RX_ENC_LEGACY:
-+ if (WARN_ON_ONCE(status->band > NL80211_BAND_5GHZ))
-+ return 0;
-+
-+ sband = hw->wiphy->bands[status->band];
-+ if (!sband || status->rate_idx > sband->n_bitrates)
-+ return 0;
-+
-+ rate = &sband->bitrates[status->rate_idx];
-+ cck = rate->flags & IEEE80211_RATE_MANDATORY_B;
-+
-+ return ieee80211_calc_legacy_rate_duration(rate->bitrate, sp,
-+ cck, len);
-+
-+ case RX_ENC_VHT:
-+ streams = status->nss;
-+ idx = status->rate_idx;
-+ group = VHT_GROUP_IDX(streams, sgi, bw);
-+ break;
-+ case RX_ENC_HT:
-+ streams = ((status->rate_idx >> 3) & 3) + 1;
-+ idx = status->rate_idx & 7;
-+ group = HT_GROUP_IDX(streams, sgi, bw);
-+ break;
-+ case RX_ENC_HE:
-+ streams = status->nss;
-+ idx = status->rate_idx;
-+ group = HE_GROUP_IDX(streams, status->he_gi, bw);
-+ break;
-+ default:
-+ WARN_ON_ONCE(1);
-+ return 0;
-+ }
-+
-+ if (WARN_ON_ONCE((status->encoding != RX_ENC_HE && streams > 4) ||
-+ (status->encoding == RX_ENC_HE && streams > 8)))
-+ return 0;
-+
-+ duration = airtime_mcs_groups[group].duration[idx];
-+ duration <<= airtime_mcs_groups[group].shift;
-+ duration *= len;
-+ duration /= AVG_PKT_SIZE;
-+ duration /= 1024;
-+
-+ duration += 36 + (streams << 2);
-+
-+ return duration;
-+}
-+EXPORT_SYMBOL_GPL(ieee80211_calc_rx_airtime);
-+
-+static u32 ieee80211_calc_tx_airtime_rate(struct ieee80211_hw *hw,
-+ struct ieee80211_tx_rate *rate,
-+ u8 band, int len)
-+{
-+ struct ieee80211_rx_status stat = {
-+ .band = band,
-+ };
-+
-+ if (rate->idx < 0 || !rate->count)
-+ return 0;
-+
-+ if (rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH)
-+ stat.bw = RATE_INFO_BW_80;
-+ else if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
-+ stat.bw = RATE_INFO_BW_40;
-+ else
-+ stat.bw = RATE_INFO_BW_20;
-+
-+ stat.enc_flags = 0;
-+ if (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
-+ stat.enc_flags |= RX_ENC_FLAG_SHORTPRE;
-+ if (rate->flags & IEEE80211_TX_RC_SHORT_GI)
-+ stat.enc_flags |= RX_ENC_FLAG_SHORT_GI;
-+
-+ stat.rate_idx = rate->idx;
-+ if (rate->flags & IEEE80211_TX_RC_VHT_MCS) {
-+ stat.encoding = RX_ENC_VHT;
-+ stat.rate_idx = ieee80211_rate_get_vht_mcs(rate);
-+ stat.nss = ieee80211_rate_get_vht_nss(rate);
-+ } else if (rate->flags & IEEE80211_TX_RC_MCS) {
-+ stat.encoding = RX_ENC_HT;
-+ } else {
-+ stat.encoding = RX_ENC_LEGACY;
-+ }
-+
-+ return ieee80211_calc_rx_airtime(hw, &stat, len);
-+}
-+
-+u32 ieee80211_calc_tx_airtime(struct ieee80211_hw *hw,
-+ struct ieee80211_tx_info *info,
-+ int len)
-+{
-+ u32 duration = 0;
-+ int i;
-+
-+ for (i = 0; i < ARRAY_SIZE(info->status.rates); i++) {
-+ struct ieee80211_tx_rate *rate = &info->status.rates[i];
-+ u32 cur_duration;
-+
-+ cur_duration = ieee80211_calc_tx_airtime_rate(hw, rate,
-+ info->band, len);
-+ if (!cur_duration)
-+ break;
-+
-+ duration += cur_duration * rate->count;
-+ }
-+
-+ return duration;
-+}
-+EXPORT_SYMBOL_GPL(ieee80211_calc_tx_airtime);
-+
-+u32 ieee80211_calc_expected_tx_airtime(struct ieee80211_hw *hw,
-+ struct ieee80211_vif *vif,
-+ struct ieee80211_sta *pubsta,
-+ int len)
-+{
-+ struct ieee80211_supported_band *sband;
-+ struct ieee80211_chanctx_conf *conf;
-+ int rateidx, shift = 0;
-+ bool cck, short_pream;
-+ u32 basic_rates;
-+ u8 band = 0;
-+ u16 rate;
-+
-+ len += 38; /* Ethernet header length */
-+
-+ conf = rcu_dereference(vif->chanctx_conf);
-+ if (conf) {
-+ band = conf->def.chan->band;
-+ shift = ieee80211_chandef_get_shift(&conf->def);
-+ }
-+
-+ if (pubsta) {
-+ struct sta_info *sta = container_of(pubsta, struct sta_info,
-+ sta);
-+
-+ return ieee80211_calc_tx_airtime_rate(hw,
-+ &sta->tx_stats.last_rate,
-+ band, len);
-+ }
-+
-+ if (!conf)
-+ return 0;
-+
-+ /* No station to get latest rate from, so calculate the worst-case
-+ * duration using the lowest configured basic rate.
-+ */
-+ sband = hw->wiphy->bands[band];
-+
-+ basic_rates = vif->bss_conf.basic_rates;
-+ short_pream = vif->bss_conf.use_short_preamble;
-+
-+ rateidx = basic_rates ? ffs(basic_rates) - 1 : 0;
-+ rate = sband->bitrates[rateidx].bitrate << shift;
-+ cck = sband->bitrates[rateidx].flags & IEEE80211_RATE_MANDATORY_B;
-+
-+ return ieee80211_calc_legacy_rate_duration(rate, short_pream, cck, len);
-+}
---- a/net/mac80211/ieee80211_i.h
-+++ b/net/mac80211/ieee80211_i.h
-@@ -2253,6 +2253,10 @@ const char *ieee80211_get_reason_code_st
-
- extern const struct ethtool_ops ieee80211_ethtool_ops;
-
-+u32 ieee80211_calc_expected_tx_airtime(struct ieee80211_hw *hw,
-+ struct ieee80211_vif *vif,
-+ struct ieee80211_sta *pubsta,
-+ int len);
- #ifdef CPTCFG_MAC80211_NOINLINE
- #define debug_noinline noinline
- #else
+++ /dev/null
-From: Kan Yan <kyan@google.com>
-Date: Mon, 18 Nov 2019 22:06:09 -0800
-Subject: [PATCH] mac80211: Implement Airtime-based Queue Limit (AQL)
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-In order for the Fq_CoDel algorithm integrated in mac80211 layer to operate
-effectively to control excessive queueing latency, the CoDel algorithm
-requires an accurate measure of how long packets stays in the queue, AKA
-sojourn time. The sojourn time measured at the mac80211 layer doesn't
-include queueing latency in the lower layer (firmware/hardware) and CoDel
-expects lower layer to have a short queue. However, most 802.11ac chipsets
-offload tasks such TX aggregation to firmware or hardware, thus have a deep
-lower layer queue.
-
-Without a mechanism to control the lower layer queue size, packets only
-stay in mac80211 layer transiently before being sent to firmware queue.
-As a result, the sojourn time measured by CoDel in the mac80211 layer is
-almost always lower than the CoDel latency target, hence CoDel does little
-to control the latency, even when the lower layer queue causes excessive
-latency.
-
-The Byte Queue Limits (BQL) mechanism is commonly used to address the
-similar issue with wired network interface. However, this method cannot be
-applied directly to the wireless network interface. "Bytes" is not a
-suitable measure of queue depth in the wireless network, as the data rate
-can vary dramatically from station to station in the same network, from a
-few Mbps to over Gbps.
-
-This patch implements an Airtime-based Queue Limit (AQL) to make CoDel work
-effectively with wireless drivers that utilized firmware/hardware
-offloading. AQL allows each txq to release just enough packets to the lower
-layer to form 1-2 large aggregations to keep hardware fully utilized and
-retains the rest of the frames in mac80211 layer to be controlled by the
-CoDel algorithm.
-
-Signed-off-by: Kan Yan <kyan@google.com>
-[ Toke: Keep API to set pending airtime internal, fix nits in commit msg ]
-Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
-Link: https://lore.kernel.org/r/20191119060610.76681-4-kyan@google.com
-Signed-off-by: Johannes Berg <johannes.berg@intel.com>
----
-
---- a/include/net/cfg80211.h
-+++ b/include/net/cfg80211.h
-@@ -2603,6 +2603,13 @@ enum wiphy_params_flags {
-
- #define IEEE80211_DEFAULT_AIRTIME_WEIGHT 256
-
-+/* The per TXQ device queue limit in airtime */
-+#define IEEE80211_DEFAULT_AQL_TXQ_LIMIT_L 5000
-+#define IEEE80211_DEFAULT_AQL_TXQ_LIMIT_H 12000
-+
-+/* The per interface airtime threshold to switch to lower queue limit */
-+#define IEEE80211_AQL_THRESHOLD 24000
-+
- /**
- * struct cfg80211_pmksa - PMK Security Association
- *
---- a/include/net/mac80211.h
-+++ b/include/net/mac80211.h
-@@ -5559,6 +5559,18 @@ void ieee80211_sta_register_airtime(stru
- u32 tx_airtime, u32 rx_airtime);
-
- /**
-+ * ieee80211_txq_airtime_check - check if a txq can send frame to device
-+ *
-+ * @hw: pointer obtained from ieee80211_alloc_hw()
-+ * @txq: pointer obtained from station or virtual interface
-+ *
-+ * Return true if the AQL's airtime limit has not been reached and the txq can
-+ * continue to send more packets to the device. Otherwise return false.
-+ */
-+bool
-+ieee80211_txq_airtime_check(struct ieee80211_hw *hw, struct ieee80211_txq *txq);
-+
-+/**
- * ieee80211_iter_keys - iterate keys programmed into the device
- * @hw: pointer obtained from ieee80211_alloc_hw()
- * @vif: virtual interface to iterate, may be %NULL for all
---- a/net/mac80211/debugfs.c
-+++ b/net/mac80211/debugfs.c
-@@ -148,6 +148,87 @@ static const struct file_operations aqm_
- .llseek = default_llseek,
- };
-
-+static ssize_t aql_txq_limit_read(struct file *file,
-+ char __user *user_buf,
-+ size_t count,
-+ loff_t *ppos)
-+{
-+ struct ieee80211_local *local = file->private_data;
-+ char buf[400];
-+ int len = 0;
-+
-+ len = scnprintf(buf, sizeof(buf),
-+ "AC AQL limit low AQL limit high\n"
-+ "VO %u %u\n"
-+ "VI %u %u\n"
-+ "BE %u %u\n"
-+ "BK %u %u\n",
-+ local->aql_txq_limit_low[IEEE80211_AC_VO],
-+ local->aql_txq_limit_high[IEEE80211_AC_VO],
-+ local->aql_txq_limit_low[IEEE80211_AC_VI],
-+ local->aql_txq_limit_high[IEEE80211_AC_VI],
-+ local->aql_txq_limit_low[IEEE80211_AC_BE],
-+ local->aql_txq_limit_high[IEEE80211_AC_BE],
-+ local->aql_txq_limit_low[IEEE80211_AC_BK],
-+ local->aql_txq_limit_high[IEEE80211_AC_BK]);
-+ return simple_read_from_buffer(user_buf, count, ppos,
-+ buf, len);
-+}
-+
-+static ssize_t aql_txq_limit_write(struct file *file,
-+ const char __user *user_buf,
-+ size_t count,
-+ loff_t *ppos)
-+{
-+ struct ieee80211_local *local = file->private_data;
-+ char buf[100];
-+ size_t len;
-+ u32 ac, q_limit_low, q_limit_high, q_limit_low_old, q_limit_high_old;
-+ struct sta_info *sta;
-+
-+ 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 (sscanf(buf, "%u %u %u", &ac, &q_limit_low, &q_limit_high) != 3)
-+ return -EINVAL;
-+
-+ if (ac >= IEEE80211_NUM_ACS)
-+ return -EINVAL;
-+
-+ q_limit_low_old = local->aql_txq_limit_low[ac];
-+ q_limit_high_old = local->aql_txq_limit_high[ac];
-+
-+ local->aql_txq_limit_low[ac] = q_limit_low;
-+ local->aql_txq_limit_high[ac] = q_limit_high;
-+
-+ mutex_lock(&local->sta_mtx);
-+ list_for_each_entry(sta, &local->sta_list, list) {
-+ /* If a sta has customized queue limits, keep it */
-+ if (sta->airtime[ac].aql_limit_low == q_limit_low_old &&
-+ sta->airtime[ac].aql_limit_high == q_limit_high_old) {
-+ sta->airtime[ac].aql_limit_low = q_limit_low;
-+ sta->airtime[ac].aql_limit_high = q_limit_high;
-+ }
-+ }
-+ mutex_unlock(&local->sta_mtx);
-+ return count;
-+}
-+
-+static const struct file_operations aql_txq_limit_ops = {
-+ .write = aql_txq_limit_write,
-+ .read = aql_txq_limit_read,
-+ .open = simple_open,
-+ .llseek = default_llseek,
-+};
-+
- static ssize_t force_tx_status_read(struct file *file,
- char __user *user_buf,
- size_t count,
-@@ -441,6 +522,10 @@ void debugfs_hw_add(struct ieee80211_loc
- debugfs_create_u16("airtime_flags", 0600,
- phyd, &local->airtime_flags);
-
-+ DEBUGFS_ADD(aql_txq_limit);
-+ debugfs_create_u32("aql_threshold", 0600,
-+ phyd, &local->aql_threshold);
-+
- statsd = debugfs_create_dir("statistics", phyd);
-
- /* if the dir failed, don't put all the other things into the root! */
---- a/net/mac80211/debugfs_sta.c
-+++ b/net/mac80211/debugfs_sta.c
-@@ -198,10 +198,12 @@ static ssize_t sta_airtime_read(struct f
- {
- struct sta_info *sta = file->private_data;
- struct ieee80211_local *local = sta->sdata->local;
-- size_t bufsz = 200;
-+ size_t bufsz = 400;
- char *buf = kzalloc(bufsz, GFP_KERNEL), *p = buf;
- u64 rx_airtime = 0, tx_airtime = 0;
- s64 deficit[IEEE80211_NUM_ACS];
-+ u32 q_depth[IEEE80211_NUM_ACS];
-+ u32 q_limit_l[IEEE80211_NUM_ACS], q_limit_h[IEEE80211_NUM_ACS];
- ssize_t rv;
- int ac;
-
-@@ -213,19 +215,22 @@ static ssize_t sta_airtime_read(struct f
- rx_airtime += sta->airtime[ac].rx_airtime;
- tx_airtime += sta->airtime[ac].tx_airtime;
- deficit[ac] = sta->airtime[ac].deficit;
-+ q_limit_l[ac] = sta->airtime[ac].aql_limit_low;
-+ q_limit_h[ac] = sta->airtime[ac].aql_limit_high;
- spin_unlock_bh(&local->active_txq_lock[ac]);
-+ q_depth[ac] = atomic_read(&sta->airtime[ac].aql_tx_pending);
- }
-
- p += scnprintf(p, bufsz + buf - p,
- "RX: %llu us\nTX: %llu us\nWeight: %u\n"
-- "Deficit: VO: %lld us VI: %lld us BE: %lld us BK: %lld us\n",
-- rx_airtime,
-- tx_airtime,
-- sta->airtime_weight,
-- deficit[0],
-- deficit[1],
-- deficit[2],
-- deficit[3]);
-+ "Deficit: VO: %lld us VI: %lld us BE: %lld us BK: %lld us\n"
-+ "Q depth: VO: %u us VI: %u us BE: %u us BK: %u us\n"
-+ "Q limit[low/high]: VO: %u/%u VI: %u/%u BE: %u/%u BK: %u/%u\n",
-+ rx_airtime, tx_airtime, sta->airtime_weight,
-+ deficit[0], deficit[1], deficit[2], deficit[3],
-+ q_depth[0], q_depth[1], q_depth[2], q_depth[3],
-+ q_limit_l[0], q_limit_h[0], q_limit_l[1], q_limit_h[1],
-+ q_limit_l[2], q_limit_h[2], q_limit_l[3], q_limit_h[3]),
-
- rv = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
- kfree(buf);
-@@ -237,7 +242,25 @@ static ssize_t sta_airtime_write(struct
- {
- struct sta_info *sta = file->private_data;
- struct ieee80211_local *local = sta->sdata->local;
-- int ac;
-+ u32 ac, q_limit_l, q_limit_h;
-+ char _buf[100] = {}, *buf = _buf;
-+
-+ if (count > sizeof(_buf))
-+ return -EINVAL;
-+
-+ if (copy_from_user(buf, userbuf, count))
-+ return -EFAULT;
-+
-+ buf[sizeof(_buf) - 1] = '\0';
-+ if (sscanf(buf, "queue limit %u %u %u", &ac, &q_limit_l, &q_limit_h)
-+ != 3)
-+ return -EINVAL;
-+
-+ if (ac >= IEEE80211_NUM_ACS)
-+ return -EINVAL;
-+
-+ sta->airtime[ac].aql_limit_low = q_limit_l;
-+ sta->airtime[ac].aql_limit_high = q_limit_h;
-
- for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
- spin_lock_bh(&local->active_txq_lock[ac]);
---- a/net/mac80211/ieee80211_i.h
-+++ b/net/mac80211/ieee80211_i.h
-@@ -1142,6 +1142,10 @@ struct ieee80211_local {
- u16 schedule_round[IEEE80211_NUM_ACS];
-
- u16 airtime_flags;
-+ u32 aql_txq_limit_low[IEEE80211_NUM_ACS];
-+ u32 aql_txq_limit_high[IEEE80211_NUM_ACS];
-+ u32 aql_threshold;
-+ atomic_t aql_total_pending_airtime;
-
- const struct ieee80211_ops *ops;
-
---- a/net/mac80211/main.c
-+++ b/net/mac80211/main.c
-@@ -669,8 +669,16 @@ struct ieee80211_hw *ieee80211_alloc_hw_
- for (i = 0; i < IEEE80211_NUM_ACS; i++) {
- INIT_LIST_HEAD(&local->active_txqs[i]);
- spin_lock_init(&local->active_txq_lock[i]);
-+ local->aql_txq_limit_low[i] = IEEE80211_DEFAULT_AQL_TXQ_LIMIT_L;
-+ local->aql_txq_limit_high[i] =
-+ IEEE80211_DEFAULT_AQL_TXQ_LIMIT_H;
- }
-- local->airtime_flags = AIRTIME_USE_TX | AIRTIME_USE_RX;
-+
-+ local->airtime_flags = AIRTIME_USE_TX |
-+ AIRTIME_USE_RX |
-+ AIRTIME_USE_AQL;
-+ local->aql_threshold = IEEE80211_AQL_THRESHOLD;
-+ atomic_set(&local->aql_total_pending_airtime, 0);
-
- INIT_LIST_HEAD(&local->chanctx_list);
- mutex_init(&local->chanctx_mtx);
---- a/net/mac80211/sta_info.c
-+++ b/net/mac80211/sta_info.c
-@@ -411,6 +411,9 @@ struct sta_info *sta_info_alloc(struct i
- skb_queue_head_init(&sta->ps_tx_buf[i]);
- skb_queue_head_init(&sta->tx_filtered[i]);
- sta->airtime[i].deficit = sta->airtime_weight;
-+ atomic_set(&sta->airtime[i].aql_tx_pending, 0);
-+ sta->airtime[i].aql_limit_low = local->aql_txq_limit_low[i];
-+ sta->airtime[i].aql_limit_high = local->aql_txq_limit_high[i];
- }
-
- for (i = 0; i < IEEE80211_NUM_TIDS; i++)
-@@ -1913,6 +1916,41 @@ void ieee80211_sta_register_airtime(stru
- }
- EXPORT_SYMBOL(ieee80211_sta_register_airtime);
-
-+void ieee80211_sta_update_pending_airtime(struct ieee80211_local *local,
-+ struct sta_info *sta, u8 ac,
-+ u16 tx_airtime, bool tx_completed)
-+{
-+ int tx_pending;
-+
-+ if (!tx_completed) {
-+ if (sta)
-+ atomic_add(tx_airtime,
-+ &sta->airtime[ac].aql_tx_pending);
-+
-+ atomic_add(tx_airtime, &local->aql_total_pending_airtime);
-+ return;
-+ }
-+
-+ if (sta) {
-+ tx_pending = atomic_sub_return(tx_airtime,
-+ &sta->airtime[ac].aql_tx_pending);
-+ if (WARN_ONCE(tx_pending < 0,
-+ "STA %pM AC %d txq pending airtime underflow: %u, %u",
-+ sta->addr, ac, tx_pending, tx_airtime))
-+ atomic_cmpxchg(&sta->airtime[ac].aql_tx_pending,
-+ tx_pending, 0);
-+ }
-+
-+ tx_pending = atomic_sub_return(tx_airtime,
-+ &local->aql_total_pending_airtime);
-+ if (WARN_ONCE(tx_pending < 0,
-+ "Device %s AC %d pending airtime underflow: %u, %u",
-+ wiphy_name(local->hw.wiphy), ac, tx_pending,
-+ tx_airtime))
-+ atomic_cmpxchg(&local->aql_total_pending_airtime,
-+ tx_pending, 0);
-+}
-+
- int sta_info_move_state(struct sta_info *sta,
- enum ieee80211_sta_state new_state)
- {
---- a/net/mac80211/sta_info.h
-+++ b/net/mac80211/sta_info.h
-@@ -128,13 +128,21 @@ enum ieee80211_agg_stop_reason {
- /* Debugfs flags to enable/disable use of RX/TX airtime in scheduler */
- #define AIRTIME_USE_TX BIT(0)
- #define AIRTIME_USE_RX BIT(1)
-+#define AIRTIME_USE_AQL BIT(2)
-
- struct airtime_info {
- u64 rx_airtime;
- u64 tx_airtime;
- s64 deficit;
-+ atomic_t aql_tx_pending; /* Estimated airtime for frames pending */
-+ u32 aql_limit_low;
-+ u32 aql_limit_high;
- };
-
-+void ieee80211_sta_update_pending_airtime(struct ieee80211_local *local,
-+ struct sta_info *sta, u8 ac,
-+ u16 tx_airtime, bool tx_completed);
-+
- struct sta_info;
-
- /**
---- a/net/mac80211/tx.c
-+++ b/net/mac80211/tx.c
-@@ -3700,7 +3700,8 @@ struct ieee80211_txq *ieee80211_next_txq
- {
- struct ieee80211_local *local = hw_to_local(hw);
- struct ieee80211_txq *ret = NULL;
-- struct txq_info *txqi = NULL;
-+ struct txq_info *txqi = NULL, *head = NULL;
-+ bool found_eligible_txq = false;
-
- spin_lock_bh(&local->active_txq_lock[ac]);
-
-@@ -3711,13 +3712,30 @@ struct ieee80211_txq *ieee80211_next_txq
- if (!txqi)
- goto out;
-
-+ if (txqi == head) {
-+ if (!found_eligible_txq)
-+ goto out;
-+ else
-+ found_eligible_txq = false;
-+ }
-+
-+ if (!head)
-+ head = txqi;
-+
- if (txqi->txq.sta) {
- struct sta_info *sta = container_of(txqi->txq.sta,
-- struct sta_info, sta);
-+ struct sta_info, sta);
-+ bool aql_check = ieee80211_txq_airtime_check(hw, &txqi->txq);
-+ s64 deficit = sta->airtime[txqi->txq.ac].deficit;
-
-- if (sta->airtime[txqi->txq.ac].deficit < 0) {
-+ if (aql_check)
-+ found_eligible_txq = true;
-+
-+ if (deficit < 0)
- sta->airtime[txqi->txq.ac].deficit +=
- sta->airtime_weight;
-+
-+ if (deficit < 0 || !aql_check) {
- list_move_tail(&txqi->schedule_order,
- &local->active_txqs[txqi->txq.ac]);
- goto begin;
-@@ -3771,6 +3789,33 @@ void __ieee80211_schedule_txq(struct iee
- }
- EXPORT_SYMBOL(__ieee80211_schedule_txq);
-
-+bool ieee80211_txq_airtime_check(struct ieee80211_hw *hw,
-+ struct ieee80211_txq *txq)
-+{
-+ struct sta_info *sta;
-+ struct ieee80211_local *local = hw_to_local(hw);
-+
-+ if (!(local->airtime_flags & AIRTIME_USE_AQL))
-+ return true;
-+
-+ if (!txq->sta)
-+ return true;
-+
-+ sta = container_of(txq->sta, struct sta_info, sta);
-+ if (atomic_read(&sta->airtime[txq->ac].aql_tx_pending) <
-+ sta->airtime[txq->ac].aql_limit_low)
-+ return true;
-+
-+ if (atomic_read(&local->aql_total_pending_airtime) <
-+ local->aql_threshold &&
-+ atomic_read(&sta->airtime[txq->ac].aql_tx_pending) <
-+ sta->airtime[txq->ac].aql_limit_high)
-+ return true;
-+
-+ return false;
-+}
-+EXPORT_SYMBOL(ieee80211_txq_airtime_check);
-+
- bool ieee80211_txq_may_transmit(struct ieee80211_hw *hw,
- struct ieee80211_txq *txq)
- {
+++ /dev/null
-From: =?UTF-8?q?Toke=20H=C3=B8iland-J=C3=B8rgensen?= <toke@redhat.com>
-Date: Mon, 18 Nov 2019 22:06:10 -0800
-Subject: [PATCH] mac80211: Use Airtime-based Queue Limits (AQL) on packet
- dequeue
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-The previous commit added the ability to throttle stations when they queue
-too much airtime in the hardware. This commit enables the functionality by
-calculating the expected airtime usage of each packet that is dequeued from
-the TXQs in mac80211, and accounting that as pending airtime.
-
-The estimated airtime for each skb is stored in the tx_info, so we can
-subtract the same amount from the running total when the skb is freed or
-recycled. The throttling mechanism relies on this accounting to be
-accurate (i.e., that we are not freeing skbs without subtracting any
-airtime they were accounted for), so we put the subtraction into
-ieee80211_report_used_skb(). As an optimisation, we also subtract the
-airtime on regular TX completion, zeroing out the value stored in the
-packet afterwards, to avoid having to do an expensive lookup of the station
-from the packet data on every packet.
-
-This patch does *not* include any mechanism to wake a throttled TXQ again,
-on the assumption that this will happen anyway as a side effect of whatever
-freed the skb (most commonly a TX completion).
-
-Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
-Link: https://lore.kernel.org/r/20191119060610.76681-5-kyan@google.com
-Signed-off-by: Johannes Berg <johannes.berg@intel.com>
----
-
---- a/include/net/mac80211.h
-+++ b/include/net/mac80211.h
-@@ -1060,6 +1060,22 @@ struct ieee80211_tx_info {
- };
- };
-
-+static inline u16
-+ieee80211_info_set_tx_time_est(struct ieee80211_tx_info *info, u16 tx_time_est)
-+{
-+ /* We only have 10 bits in tx_time_est, so store airtime
-+ * in increments of 4us and clamp the maximum to 2**12-1
-+ */
-+ info->tx_time_est = min_t(u16, tx_time_est, 4095) >> 2;
-+ return info->tx_time_est << 2;
-+}
-+
-+static inline u16
-+ieee80211_info_get_tx_time_est(struct ieee80211_tx_info *info)
-+{
-+ return info->tx_time_est << 2;
-+}
-+
- /**
- * struct ieee80211_tx_status - extended tx staus info for rate control
- *
---- a/net/mac80211/status.c
-+++ b/net/mac80211/status.c
-@@ -670,12 +670,26 @@ static void ieee80211_report_used_skb(st
- struct sk_buff *skb, bool dropped)
- {
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-+ u16 tx_time_est = ieee80211_info_get_tx_time_est(info);
- struct ieee80211_hdr *hdr = (void *)skb->data;
- bool acked = info->flags & IEEE80211_TX_STAT_ACK;
-
- if (dropped)
- acked = false;
-
-+ if (tx_time_est) {
-+ struct sta_info *sta;
-+
-+ rcu_read_lock();
-+
-+ sta = sta_info_get_by_addrs(local, hdr->addr1, hdr->addr2);
-+ ieee80211_sta_update_pending_airtime(local, sta,
-+ skb_get_queue_mapping(skb),
-+ tx_time_est,
-+ true);
-+ rcu_read_unlock();
-+ }
-+
- if (info->flags & IEEE80211_TX_INTFL_MLME_CONN_TX) {
- struct ieee80211_sub_if_data *sdata;
-
-@@ -885,6 +899,7 @@ static void __ieee80211_tx_status(struct
- struct ieee80211_bar *bar;
- int shift = 0;
- int tid = IEEE80211_NUM_TIDS;
-+ u16 tx_time_est;
-
- rates_idx = ieee80211_tx_get_rates(hw, info, &retry_count);
-
-@@ -996,6 +1011,17 @@ static void __ieee80211_tx_status(struct
- ieee80211_sta_register_airtime(&sta->sta, tid,
- info->status.tx_time, 0);
-
-+ if ((tx_time_est = ieee80211_info_get_tx_time_est(info)) > 0) {
-+ /* Do this here to avoid the expensive lookup of the sta
-+ * in ieee80211_report_used_skb().
-+ */
-+ ieee80211_sta_update_pending_airtime(local, sta,
-+ skb_get_queue_mapping(skb),
-+ tx_time_est,
-+ true);
-+ ieee80211_info_set_tx_time_est(info, 0);
-+ }
-+
- if (ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) {
- if (acked) {
- if (sta->status_stats.lost_packets)
---- a/net/mac80211/tx.c
-+++ b/net/mac80211/tx.c
-@@ -3559,6 +3559,9 @@ struct sk_buff *ieee80211_tx_dequeue(str
-
- WARN_ON_ONCE(softirq_count() == 0);
-
-+ if (!ieee80211_txq_airtime_check(hw, txq))
-+ return NULL;
-+
- begin:
- spin_lock_bh(&fq->lock);
-
-@@ -3687,6 +3690,21 @@ begin:
- }
-
- IEEE80211_SKB_CB(skb)->control.vif = vif;
-+
-+ if (local->airtime_flags & AIRTIME_USE_AQL) {
-+ u32 airtime;
-+
-+ airtime = ieee80211_calc_expected_tx_airtime(hw, vif, txq->sta,
-+ skb->len);
-+ if (airtime) {
-+ airtime = ieee80211_info_set_tx_time_est(info, airtime);
-+ ieee80211_sta_update_pending_airtime(local, tx.sta,
-+ txq->ac,
-+ airtime,
-+ false);
-+ }
-+ }
-+
- return skb;
-
- out:
+++ /dev/null
-From: Dan Carpenter <dan.carpenter@oracle.com>
-Date: Tue, 26 Nov 2019 15:09:39 +0300
-Subject: [PATCH] mac80211: airtime: Fix an off by one in
- ieee80211_calc_rx_airtime()
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-This code was copied from mt76 and inherited an off by one bug from
-there. The > should be >= so that we don't read one element beyond
-the end of the array.
-
-Fixes: db3e1c40cf2f ("mac80211: Import airtime calculation code from mt76")
-Reported-by: Toke Høiland-Jørgensen <toke@redhat.com>
-Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
-Acked-by: Toke Høiland-Jørgensen <toke@redhat.com>
-Link: https://lore.kernel.org/r/20191126120910.ftr4t7me3by32aiz@kili.mountain
-Signed-off-by: Johannes Berg <johannes.berg@intel.com>
----
-
---- a/net/mac80211/airtime.c
-+++ b/net/mac80211/airtime.c
-@@ -442,7 +442,7 @@ u32 ieee80211_calc_rx_airtime(struct iee
- return 0;
-
- sband = hw->wiphy->bands[status->band];
-- if (!sband || status->rate_idx > sband->n_bitrates)
-+ if (!sband || status->rate_idx >= sband->n_bitrates)
- return 0;
-
- rate = &sband->bitrates[status->rate_idx];
+++ /dev/null
-From: =?UTF-8?q?Toke=20H=C3=B8iland-J=C3=B8rgensen?= <toke@redhat.com>
-Date: Thu, 12 Dec 2019 12:14:37 +0100
-Subject: [PATCH] mac80211: Turn AQL into an NL80211_EXT_FEATURE
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Instead of just having an airtime flag in debugfs, turn AQL into a proper
-NL80211_EXT_FEATURE, so drivers can turn it on when they are ready, and so
-we also expose the presence of the feature to userspace.
-
-This also has the effect of flipping the default, so drivers have to opt in
-to using AQL instead of getting it by default with TXQs. To keep
-functionality the same as pre-patch, we set this feature for ath10k (which
-is where it is needed the most).
-
-While we're at it, split out the debugfs interface so AQL gets its own
-per-station debugfs file instead of using the 'airtime' file.
-
-[Johannes:]
-This effectively disables AQL for iwlwifi, where it fixes a number of
-issues:
- * TSO in iwlwifi is causing underflows and associated warnings in AQL
- * HE (802.11ax) rates aren't reported properly so at HE rates, AQL could
- never have a valid estimate (it'd use 6 Mbps instead of up to 2400!)
-
-Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
-Link: https://lore.kernel.org/r/20191212111437.224294-1-toke@redhat.com
-Fixes: 3ace10f5b5ad ("mac80211: Implement Airtime-based Queue Limit (AQL)")
-Signed-off-by: Johannes Berg <johannes.berg@intel.com>
----
-
---- a/drivers/net/wireless/ath/ath10k/mac.c
-+++ b/drivers/net/wireless/ath/ath10k/mac.c
-@@ -8870,6 +8870,7 @@ int ath10k_mac_register(struct ath10k *a
- wiphy_ext_feature_set(ar->hw->wiphy, NL80211_EXT_FEATURE_VHT_IBSS);
- wiphy_ext_feature_set(ar->hw->wiphy,
- NL80211_EXT_FEATURE_SET_SCAN_DWELL);
-+ wiphy_ext_feature_set(ar->hw->wiphy, NL80211_EXT_FEATURE_AQL);
-
- if (test_bit(WMI_SERVICE_TX_DATA_ACK_RSSI, ar->wmi.svc_map) ||
- test_bit(WMI_SERVICE_HTT_MGMT_TX_COMP_VALID_FLAGS, ar->wmi.svc_map))
---- a/include/uapi/linux/nl80211.h
-+++ b/include/uapi/linux/nl80211.h
-@@ -5484,6 +5484,10 @@ enum nl80211_feature_flags {
- * @NL80211_EXT_FEATURE_SAE_OFFLOAD: Device wants to do SAE authentication in
- * station mode (SAE password is passed as part of the connect command).
- *
-+ * @NL80211_EXT_FEATURE_AQL: The driver supports the Airtime Queue Limit (AQL)
-+ * feature, which prevents bufferbloat by using the expected transmission
-+ * time to limit the amount of data buffered in the hardware.
-+ *
- * @NUM_NL80211_EXT_FEATURES: number of extended features.
- * @MAX_NL80211_EXT_FEATURES: highest extended feature index.
- */
-@@ -5529,6 +5533,8 @@ enum nl80211_ext_feature_index {
- NL80211_EXT_FEATURE_EXT_KEY_ID,
- NL80211_EXT_FEATURE_STA_TX_PWR,
- NL80211_EXT_FEATURE_SAE_OFFLOAD,
-+ NL80211_EXT_FEATURE_VLAN_OFFLOAD,
-+ NL80211_EXT_FEATURE_AQL,
-
- /* add new features before the definition below */
- NUM_NL80211_EXT_FEATURES,
---- a/net/mac80211/debugfs_sta.c
-+++ b/net/mac80211/debugfs_sta.c
-@@ -202,8 +202,6 @@ static ssize_t sta_airtime_read(struct f
- char *buf = kzalloc(bufsz, GFP_KERNEL), *p = buf;
- u64 rx_airtime = 0, tx_airtime = 0;
- s64 deficit[IEEE80211_NUM_ACS];
-- u32 q_depth[IEEE80211_NUM_ACS];
-- u32 q_limit_l[IEEE80211_NUM_ACS], q_limit_h[IEEE80211_NUM_ACS];
- ssize_t rv;
- int ac;
-
-@@ -215,6 +213,56 @@ static ssize_t sta_airtime_read(struct f
- rx_airtime += sta->airtime[ac].rx_airtime;
- tx_airtime += sta->airtime[ac].tx_airtime;
- deficit[ac] = sta->airtime[ac].deficit;
-+ spin_unlock_bh(&local->active_txq_lock[ac]);
-+ }
-+
-+ p += scnprintf(p, bufsz + buf - p,
-+ "RX: %llu us\nTX: %llu us\nWeight: %u\n"
-+ "Deficit: VO: %lld us VI: %lld us BE: %lld us BK: %lld us\n",
-+ rx_airtime, tx_airtime, sta->airtime_weight,
-+ deficit[0], deficit[1], deficit[2], deficit[3]);
-+
-+ rv = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
-+ kfree(buf);
-+ return rv;
-+}
-+
-+static ssize_t sta_airtime_write(struct file *file, const char __user *userbuf,
-+ size_t count, loff_t *ppos)
-+{
-+ struct sta_info *sta = file->private_data;
-+ struct ieee80211_local *local = sta->sdata->local;
-+ int ac;
-+
-+ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
-+ spin_lock_bh(&local->active_txq_lock[ac]);
-+ sta->airtime[ac].rx_airtime = 0;
-+ sta->airtime[ac].tx_airtime = 0;
-+ sta->airtime[ac].deficit = sta->airtime_weight;
-+ spin_unlock_bh(&local->active_txq_lock[ac]);
-+ }
-+
-+ return count;
-+}
-+STA_OPS_RW(airtime);
-+
-+static ssize_t sta_aql_read(struct file *file, char __user *userbuf,
-+ size_t count, loff_t *ppos)
-+{
-+ struct sta_info *sta = file->private_data;
-+ struct ieee80211_local *local = sta->sdata->local;
-+ size_t bufsz = 400;
-+ char *buf = kzalloc(bufsz, GFP_KERNEL), *p = buf;
-+ u32 q_depth[IEEE80211_NUM_ACS];
-+ u32 q_limit_l[IEEE80211_NUM_ACS], q_limit_h[IEEE80211_NUM_ACS];
-+ ssize_t rv;
-+ int ac;
-+
-+ if (!buf)
-+ return -ENOMEM;
-+
-+ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
-+ spin_lock_bh(&local->active_txq_lock[ac]);
- q_limit_l[ac] = sta->airtime[ac].aql_limit_low;
- q_limit_h[ac] = sta->airtime[ac].aql_limit_high;
- spin_unlock_bh(&local->active_txq_lock[ac]);
-@@ -222,12 +270,8 @@ static ssize_t sta_airtime_read(struct f
- }
-
- p += scnprintf(p, bufsz + buf - p,
-- "RX: %llu us\nTX: %llu us\nWeight: %u\n"
-- "Deficit: VO: %lld us VI: %lld us BE: %lld us BK: %lld us\n"
- "Q depth: VO: %u us VI: %u us BE: %u us BK: %u us\n"
- "Q limit[low/high]: VO: %u/%u VI: %u/%u BE: %u/%u BK: %u/%u\n",
-- rx_airtime, tx_airtime, sta->airtime_weight,
-- deficit[0], deficit[1], deficit[2], deficit[3],
- q_depth[0], q_depth[1], q_depth[2], q_depth[3],
- q_limit_l[0], q_limit_h[0], q_limit_l[1], q_limit_h[1],
- q_limit_l[2], q_limit_h[2], q_limit_l[3], q_limit_h[3]),
-@@ -237,11 +281,10 @@ static ssize_t sta_airtime_read(struct f
- return rv;
- }
-
--static ssize_t sta_airtime_write(struct file *file, const char __user *userbuf,
-+static ssize_t sta_aql_write(struct file *file, const char __user *userbuf,
- size_t count, loff_t *ppos)
- {
- struct sta_info *sta = file->private_data;
-- struct ieee80211_local *local = sta->sdata->local;
- u32 ac, q_limit_l, q_limit_h;
- char _buf[100] = {}, *buf = _buf;
-
-@@ -252,7 +295,7 @@ static ssize_t sta_airtime_write(struct
- return -EFAULT;
-
- buf[sizeof(_buf) - 1] = '\0';
-- if (sscanf(buf, "queue limit %u %u %u", &ac, &q_limit_l, &q_limit_h)
-+ if (sscanf(buf, "limit %u %u %u", &ac, &q_limit_l, &q_limit_h)
- != 3)
- return -EINVAL;
-
-@@ -262,17 +305,10 @@ static ssize_t sta_airtime_write(struct
- sta->airtime[ac].aql_limit_low = q_limit_l;
- sta->airtime[ac].aql_limit_high = q_limit_h;
-
-- for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
-- spin_lock_bh(&local->active_txq_lock[ac]);
-- sta->airtime[ac].rx_airtime = 0;
-- sta->airtime[ac].tx_airtime = 0;
-- sta->airtime[ac].deficit = sta->airtime_weight;
-- spin_unlock_bh(&local->active_txq_lock[ac]);
-- }
--
- return count;
- }
--STA_OPS_RW(airtime);
-+STA_OPS_RW(aql);
-+
-
- static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf,
- size_t count, loff_t *ppos)
-@@ -1002,6 +1038,10 @@ void ieee80211_sta_debugfs_add(struct st
- NL80211_EXT_FEATURE_AIRTIME_FAIRNESS))
- DEBUGFS_ADD(airtime);
-
-+ if (wiphy_ext_feature_isset(local->hw.wiphy,
-+ NL80211_EXT_FEATURE_AQL))
-+ DEBUGFS_ADD(aql);
-+
- if (sizeof(sta->driver_buffered_tids) == sizeof(u32))
- debugfs_create_x32("driver_buffered_tids", 0400,
- sta->debugfs_dir,
---- a/net/mac80211/main.c
-+++ b/net/mac80211/main.c
-@@ -674,9 +674,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_
- IEEE80211_DEFAULT_AQL_TXQ_LIMIT_H;
- }
-
-- local->airtime_flags = AIRTIME_USE_TX |
-- AIRTIME_USE_RX |
-- AIRTIME_USE_AQL;
-+ local->airtime_flags = AIRTIME_USE_TX | AIRTIME_USE_RX;
- local->aql_threshold = IEEE80211_AQL_THRESHOLD;
- atomic_set(&local->aql_total_pending_airtime, 0);
-
---- a/net/mac80211/sta_info.c
-+++ b/net/mac80211/sta_info.c
-@@ -1922,6 +1922,9 @@ void ieee80211_sta_update_pending_airtim
- {
- int tx_pending;
-
-+ if (!wiphy_ext_feature_isset(local->hw.wiphy, NL80211_EXT_FEATURE_AQL))
-+ return;
-+
- if (!tx_completed) {
- if (sta)
- atomic_add(tx_airtime,
---- a/net/mac80211/sta_info.h
-+++ b/net/mac80211/sta_info.h
-@@ -128,7 +128,6 @@ enum ieee80211_agg_stop_reason {
- /* Debugfs flags to enable/disable use of RX/TX airtime in scheduler */
- #define AIRTIME_USE_TX BIT(0)
- #define AIRTIME_USE_RX BIT(1)
--#define AIRTIME_USE_AQL BIT(2)
-
- struct airtime_info {
- u64 rx_airtime;
---- a/net/mac80211/tx.c
-+++ b/net/mac80211/tx.c
-@@ -3691,7 +3691,7 @@ begin:
-
- IEEE80211_SKB_CB(skb)->control.vif = vif;
-
-- if (local->airtime_flags & AIRTIME_USE_AQL) {
-+ if (wiphy_ext_feature_isset(local->hw.wiphy, NL80211_EXT_FEATURE_AQL)) {
- u32 airtime;
-
- airtime = ieee80211_calc_expected_tx_airtime(hw, vif, txq->sta,
-@@ -3813,7 +3813,7 @@ bool ieee80211_txq_airtime_check(struct
- struct sta_info *sta;
- struct ieee80211_local *local = hw_to_local(hw);
-
-- if (!(local->airtime_flags & AIRTIME_USE_AQL))
-+ if (!wiphy_ext_feature_isset(local->hw.wiphy, NL80211_EXT_FEATURE_AQL))
- return true;
-
- if (!txq->sta)
+++ /dev/null
-From: Johannes Berg <johannes.berg@intel.com>
-Date: Wed, 15 Jan 2020 12:25:50 +0100
-Subject: [PATCH] mac80211: use more bits for ack_frame_id
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-It turns out that this wasn't a good idea, I hit a test failure in
-hwsim due to this. That particular failure was easily worked around,
-but it raised questions: if an AP needs to, for example, send action
-frames to each connected station, the current limit is nowhere near
-enough (especially if those stations are sleeping and the frames are
-queued for a while.)
-
-Shuffle around some bits to make more room for ack_frame_id to allow
-up to 8192 queued up frames, that's enough for queueing 4 frames to
-each connected station, even at the maximum of 2007 stations on a
-single AP.
-
-We take the bits from band (which currently only 2 but I leave 3 in
-case we add another band) and from the hw_queue, which can only need
-4 since it has a limit of 16 queues.
-
-Fixes: 6912daed05e1 ("mac80211: Shrink the size of ack_frame_id to make room for tx_time_est")
-Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-Acked-by: Toke Høiland-Jørgensen <toke@redhat.com>
----
-
---- a/include/net/mac80211.h
-+++ b/include/net/mac80211.h
-@@ -1004,12 +1004,11 @@ ieee80211_rate_get_vht_nss(const struct
- struct ieee80211_tx_info {
- /* common information */
- u32 flags;
-- u8 band;
--
-- u8 hw_queue;
--
-- u16 ack_frame_id:6;
-- u16 tx_time_est:10;
-+ u32 band:3,
-+ ack_frame_id:13,
-+ hw_queue:4,
-+ tx_time_est:10;
-+ /* 2 free bits */
-
- union {
- struct {
---- a/net/mac80211/cfg.c
-+++ b/net/mac80211/cfg.c
-@@ -3449,7 +3449,7 @@ int ieee80211_attach_ack_skb(struct ieee
-
- spin_lock_irqsave(&local->ack_status_lock, spin_flags);
- id = idr_alloc(&local->ack_status_frames, ack_skb,
-- 1, 0x40, GFP_ATOMIC);
-+ 1, 0x2000, GFP_ATOMIC);
- spin_unlock_irqrestore(&local->ack_status_lock, spin_flags);
-
- if (id < 0) {
---- a/net/mac80211/tx.c
-+++ b/net/mac80211/tx.c
-@@ -2458,7 +2458,7 @@ static int ieee80211_store_ack_skb(struc
-
- spin_lock_irqsave(&local->ack_status_lock, flags);
- id = idr_alloc(&local->ack_status_frames, ack_skb,
-- 1, 0x40, GFP_ATOMIC);
-+ 1, 0x2000, GFP_ATOMIC);
- spin_unlock_irqrestore(&local->ack_status_lock, flags);
-
- if (id >= 0) {
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
-@@ -3454,6 +3454,7 @@ struct cfg80211_update_owe_info {
+@@ -3458,6 +3458,7 @@ struct cfg80211_update_owe_info {
* (as advertised by the nl80211 feature flag.)
* @get_tx_power: store the current TX power into the dbm variable;
* return 0 if successful
*
* @set_wds_peer: set the WDS peer for a WDS interface
*
-@@ -3769,6 +3770,7 @@ struct cfg80211_ops {
+@@ -3773,6 +3774,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);
u8 ps_dtim_period;
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
-@@ -2373,6 +2373,9 @@ enum nl80211_commands {
- * the allowed channel bandwidth configurations. (u8 attribute)
- * Defined by IEEE P802.11ay/D4.0 section 9.4.2.251, Table 13.
+@@ -2400,6 +2400,9 @@ enum nl80211_commands {
+ * @NL80211_ATTR_VLAN_ID: VLAN ID (1..4094) for the station and VLAN group key
+ * (u16).
*
+ * @NL80211_ATTR_WIPHY_ANTENNA_GAIN: Configured antenna gain. Used to reduce
+ * transmit power to stay within regulatory limits. u32, dBi.
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
-@@ -2835,6 +2838,8 @@ enum nl80211_attrs {
- NL80211_ATTR_WIPHY_EDMG_CHANNELS,
- NL80211_ATTR_WIPHY_EDMG_BW_CONFIG,
+@@ -2864,6 +2867,8 @@ enum nl80211_attrs {
+
+ NL80211_ATTR_VLAN_ID,
+ NL80211_ATTR_WIPHY_ANTENNA_GAIN,
+
local->hw.max_mtu = IEEE80211_MAX_DATA_LEN;
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
-@@ -628,6 +628,7 @@ const struct nla_policy nl80211_policy[N
- .len = SAE_PASSWORD_MAX_LEN },
+@@ -630,6 +630,7 @@ const struct nla_policy nl80211_policy[N
[NL80211_ATTR_TWT_RESPONDER] = { .type = NLA_FLAG },
[NL80211_ATTR_HE_OBSS_PD] = NLA_POLICY_NESTED(he_obss_pd_policy),
+ [NL80211_ATTR_VLAN_ID] = NLA_POLICY_RANGE(NLA_U16, 1, VLAN_N_VID - 2),
+ [NL80211_ATTR_WIPHY_ANTENNA_GAIN] = { .type = NLA_U32 },
};
/* policy for the key attributes */
-@@ -2992,6 +2993,20 @@ static int nl80211_set_wiphy(struct sk_b
+@@ -2994,6 +2995,20 @@ static int nl80211_set_wiphy(struct sk_b
if (result)
return result;
}
--- a/nl80211.h
+++ b/nl80211.h
-@@ -2373,6 +2373,9 @@ enum nl80211_commands {
+@@ -249,6 +249,22 @@
+ */
+
+ /**
++ * DOC: VLAN offload support for setting group keys and binding STAs to VLANs
++ *
++ * By setting @NL80211_EXT_FEATURE_VLAN_OFFLOAD flag drivers can indicate they
++ * support offloading VLAN functionality in a manner where the driver exposes a
++ * single netdev that uses VLAN tagged frames and separate VLAN-specific netdevs
++ * can then be added using RTM_NEWLINK/IFLA_VLAN_ID similarly to the Ethernet
++ * case. Frames received from stations that are not assigned to any VLAN are
++ * delivered on the main netdev and frames to such stations can be sent through
++ * that main netdev.
++ *
++ * %NL80211_CMD_NEW_KEY (for group keys), %NL80211_CMD_NEW_STATION, and
++ * %NL80211_CMD_SET_STATION will optionally specify vlan_id using
++ * %NL80211_ATTR_VLAN_ID.
++ */
++
++/**
+ * enum nl80211_commands - supported nl80211 commands
+ *
+ * @NL80211_CMD_UNSPEC: unspecified command to catch errors
+@@ -571,6 +587,14 @@
+ * set of BSSID,frequency parameters is used (i.e., either the enforcing
+ * %NL80211_ATTR_MAC,%NL80211_ATTR_WIPHY_FREQ or the less strict
+ * %NL80211_ATTR_MAC_HINT and %NL80211_ATTR_WIPHY_FREQ_HINT).
++ * Driver shall not modify the IEs specified through %NL80211_ATTR_IE if
++ * %NL80211_ATTR_MAC is included. However, if %NL80211_ATTR_MAC_HINT is
++ * included, these IEs through %NL80211_ATTR_IE are specified by the user
++ * space based on the best possible BSS selected. Thus, if the driver ends
++ * up selecting a different BSS, it can modify these IEs accordingly (e.g.
++ * userspace asks the driver to perform PMKSA caching with BSS1 and the
++ * driver ends up selecting BSS2 with different PMKSA cache entry; RSNIE
++ * has to get updated with the apt PMKID).
+ * %NL80211_ATTR_PREV_BSSID can be used to request a reassociation within
+ * the ESS in case the device is already associated and an association with
+ * a different BSS is desired.
+@@ -2373,6 +2397,12 @@ enum nl80211_commands {
* the allowed channel bandwidth configurations. (u8 attribute)
* Defined by IEEE P802.11ay/D4.0 section 9.4.2.251, Table 13.
*
++ * @NL80211_ATTR_VLAN_ID: VLAN ID (1..4094) for the station and VLAN group key
++ * (u16).
++ *
+ * @NL80211_ATTR_WIPHY_ANTENNA_GAIN: Configured antenna gain. Used to reduce
+ * transmit power to stay within regulatory limits. u32, dBi.
+ *
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
-@@ -2835,6 +2838,8 @@ enum nl80211_attrs {
+@@ -2835,6 +2865,10 @@ enum nl80211_attrs {
NL80211_ATTR_WIPHY_EDMG_CHANNELS,
NL80211_ATTR_WIPHY_EDMG_BW_CONFIG,
++ NL80211_ATTR_VLAN_ID,
++
+ NL80211_ATTR_WIPHY_ANTENNA_GAIN,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
-@@ -5484,6 +5489,10 @@ enum nl80211_feature_flags {
+@@ -5484,6 +5518,14 @@ enum nl80211_feature_flags {
* @NL80211_EXT_FEATURE_SAE_OFFLOAD: Device wants to do SAE authentication in
* station mode (SAE password is passed as part of the connect command).
*
++ * @NL80211_EXT_FEATURE_VLAN_OFFLOAD: The driver supports a single netdev
++ * with VLAN tagged frames and separate VLAN-specific netdevs added using
++ * vconfig similarly to the Ethernet case.
++ *
+ * @NL80211_EXT_FEATURE_AQL: The driver supports the Airtime Queue Limit (AQL)
+ * feature, which prevents bufferbloat by using the expected transmission
+ * time to limit the amount of data buffered in the hardware.
* @NUM_NL80211_EXT_FEATURES: number of extended features.
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
*/
-@@ -5529,6 +5538,8 @@ enum nl80211_ext_feature_index {
+@@ -5529,6 +5571,8 @@ enum nl80211_ext_feature_index {
NL80211_EXT_FEATURE_EXT_KEY_ID,
NL80211_EXT_FEATURE_STA_TX_PWR,
NL80211_EXT_FEATURE_SAE_OFFLOAD,