1
0
Fork 0
mirror of https://git.openwrt.org/openwrt/openwrt.git synced 2024-05-19 14:06:29 +02:00

mac80211: Update to version 5.14.13-1

The removed patches were applied upstream.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
This commit is contained in:
Hauke Mehrtens 2021-10-10 21:24:14 +02:00
parent 1c0d5ee8e6
commit cfe0eb7485
22 changed files with 154 additions and 1916 deletions

View File

@ -10,10 +10,10 @@ include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=mac80211
PKG_VERSION:=5.13.19-1
PKG_VERSION:=5.14.13-1
PKG_RELEASE:=1
PKG_SOURCE_URL:=@KERNEL/linux/kernel/projects/backports/stable/v5.13.19/
PKG_HASH:=1eb761c1664d59a0a2d52847f240c9d02fc2e56fb27d862d2949bfb275187eef
PKG_SOURCE_URL:=@KERNEL/linux/kernel/projects/backports/stable/v5.14.13/
PKG_HASH:=042aef20caf17ef649502d5f2e744a7676abe7faed18de83c96f37bc029635fe
PKG_SOURCE:=backports-$(PKG_VERSION).tar.xz
PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/backports-$(PKG_VERSION)

View File

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

View File

@ -12,9 +12,9 @@ Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c
@@ -12,6 +12,36 @@
#include "common.h"
#include "of.h"
@@ -58,6 +58,36 @@ static int brcmf_of_get_country_codes(st
return 0;
}
+/* TODO: FIXME: Use DT */
+static void brcmf_of_probe_cc(struct device *dev,
@ -49,12 +49,12 @@ Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type,
struct brcmf_mp_device *settings)
{
@@ -43,6 +73,8 @@ void brcmf_of_probe(struct device *dev,
@@ -90,6 +120,8 @@ void brcmf_of_probe(struct device *dev,
of_node_put(root);
}
+ brcmf_of_probe_cc(dev, settings);
+
if (!np || bus_type != BRCMF_BUSTYPE_SDIO ||
!of_device_is_compatible(np, "brcm,bcm4329-fmac"))
if (!np || !of_device_is_compatible(np, "brcm,bcm4329-fmac"))
return;

View File

@ -64,7 +64,7 @@
brcmf_cfg80211_dump_station(struct wiphy *wiphy, struct net_device *ndev,
int idx, u8 *mac, struct station_info *sinfo)
{
@@ -3008,6 +3065,7 @@ static s32 brcmf_inform_single_bss(struc
@@ -3013,6 +3070,7 @@ static s32 brcmf_inform_single_bss(struc
struct brcmu_chan ch;
u16 channel;
u32 freq;
@ -72,7 +72,7 @@
u16 notify_capability;
u16 notify_interval;
u8 *notify_ie;
@@ -3032,6 +3090,17 @@ static s32 brcmf_inform_single_bss(struc
@@ -3037,6 +3095,17 @@ static s32 brcmf_inform_single_bss(struc
band = NL80211_BAND_5GHZ;
freq = ieee80211_channel_to_frequency(channel, band);
@ -90,7 +90,7 @@
bss_data.chan = ieee80211_get_channel(wiphy, freq);
bss_data.scan_width = NL80211_BSS_CHAN_WIDTH_20;
bss_data.boottime_ns = ktime_to_ns(ktime_get_boottime());
@@ -5560,6 +5629,7 @@ static struct cfg80211_ops brcmf_cfg8021
@@ -5565,6 +5634,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,
@ -100,7 +100,7 @@
.add_key = brcmf_cfg80211_add_key,
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
@@ -1356,6 +1356,8 @@ int brcmf_attach(struct device *dev)
@@ -1361,6 +1361,8 @@ int brcmf_attach(struct device *dev)
/* Link to bus module */
drvr->hdrlen = 0;
@ -109,7 +109,7 @@
/* Attach and link in the protocol */
ret = brcmf_proto_attach(drvr);
@@ -1438,6 +1440,12 @@ void brcmf_detach(struct device *dev)
@@ -1443,6 +1445,12 @@ void brcmf_detach(struct device *dev)
if (drvr == NULL)
return;

View File

@ -18,7 +18,7 @@
static int ieee80211_ifa6_changed(struct notifier_block *nb,
unsigned long data, void *arg)
{
@@ -1319,14 +1319,14 @@ int ieee80211_register_hw(struct ieee802
@@ -1324,14 +1324,14 @@ int ieee80211_register_hw(struct ieee802
wiphy_unlock(hw->wiphy);
rtnl_unlock();
@ -35,7 +35,7 @@
local->ifa6_notifier.notifier_call = ieee80211_ifa6_changed;
result = register_inet6addr_notifier(&local->ifa6_notifier);
if (result)
@@ -1335,13 +1335,13 @@ int ieee80211_register_hw(struct ieee802
@@ -1340,13 +1340,13 @@ int ieee80211_register_hw(struct ieee802
return 0;
@ -52,7 +52,7 @@
fail_ifa:
#endif
wiphy_unregister(local->hw.wiphy);
@@ -1369,10 +1369,10 @@ void ieee80211_unregister_hw(struct ieee
@@ -1374,10 +1374,10 @@ void ieee80211_unregister_hw(struct ieee
tasklet_kill(&local->tx_pending_tasklet);
tasklet_kill(&local->tasklet);

View File

@ -1,6 +1,6 @@
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -2462,7 +2462,7 @@ static int ieee80211_scan(struct wiphy *
@@ -2487,7 +2487,7 @@ static int ieee80211_scan(struct wiphy *
* the frames sent while scanning on other channel will be
* lost)
*/

View File

@ -11,7 +11,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -2990,15 +2990,19 @@ static void mac80211_hwsim_he_capab(stru
@@ -2992,15 +2992,19 @@ static void mac80211_hwsim_he_capab(stru
{
u16 n_iftype_data;
@ -34,7 +34,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
return;
}
@@ -3288,6 +3292,12 @@ static int mac80211_hwsim_new_radio(stru
@@ -3290,6 +3294,12 @@ static int mac80211_hwsim_new_radio(stru
sband->vht_cap.vht_mcs.tx_mcs_map =
sband->vht_cap.vht_mcs.rx_mcs_map;
break;
@ -47,7 +47,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
case NL80211_BAND_S1GHZ:
memcpy(&sband->s1g_cap, &hwsim_s1g_cap,
sizeof(sband->s1g_cap));
@@ -3298,6 +3308,13 @@ static int mac80211_hwsim_new_radio(stru
@@ -3300,6 +3310,13 @@ static int mac80211_hwsim_new_radio(stru
continue;
}
@ -61,7 +61,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
sband->ht_cap.ht_supported = true;
sband->ht_cap.cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
IEEE80211_HT_CAP_GRN_FLD |
@@ -3311,10 +3328,6 @@ static int mac80211_hwsim_new_radio(stru
@@ -3313,10 +3330,6 @@ static int mac80211_hwsim_new_radio(stru
sband->ht_cap.mcs.rx_mask[0] = 0xff;
sband->ht_cap.mcs.rx_mask[1] = 0xff;
sband->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;

View File

@ -117,7 +117,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
}
}
@@ -1206,7 +1169,7 @@ minstrel_ht_tx_status(void *priv, struct
@@ -1183,7 +1146,7 @@ minstrel_ht_tx_status(void *priv, struct
struct ieee80211_tx_info *info = st->info;
struct minstrel_ht_sta *mi = priv_sta;
struct ieee80211_tx_rate *ar = info->status.rates;
@ -126,7 +126,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
struct minstrel_priv *mp = priv;
u32 update_interval = mp->update_interval;
bool last, update = false;
@@ -1252,18 +1215,13 @@ minstrel_ht_tx_status(void *priv, struct
@@ -1233,18 +1196,13 @@ minstrel_ht_tx_status(void *priv, struct
/*
* check for sudden death of spatial multiplexing,
* downgrade to a lower number of streams if necessary.

View File

@ -1,126 +0,0 @@
From: Felix Fietkau <nbd@nbd.name>
Date: Thu, 17 Jun 2021 17:56:54 +0200
Subject: [PATCH] mac80211: move A-MPDU session check from minstrel_ht to
mac80211
This avoids calling back into tx handlers from within the rate control module.
Preparation for deferring rate control until tx dequeue
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -6192,6 +6192,11 @@ enum rate_control_capabilities {
* otherwise the NSS difference doesn't bother us.
*/
RATE_CTRL_CAPA_VHT_EXT_NSS_BW = BIT(0),
+ /**
+ * @RATE_CTRL_CAPA_AMPDU_TRIGGER:
+ * mac80211 should start A-MPDU sessions on tx
+ */
+ RATE_CTRL_CAPA_AMPDU_TRIGGER = BIT(1),
};
struct rate_control_ops {
--- a/net/mac80211/rc80211_minstrel_ht.c
+++ b/net/mac80211/rc80211_minstrel_ht.c
@@ -1140,29 +1140,6 @@ minstrel_downgrade_prob_rate(struct mins
}
static void
-minstrel_aggr_check(struct ieee80211_sta *pubsta, struct sk_buff *skb)
-{
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
- struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
- u16 tid;
-
- if (skb_get_queue_mapping(skb) == IEEE80211_AC_VO)
- return;
-
- if (unlikely(!ieee80211_is_data_qos(hdr->frame_control)))
- return;
-
- if (unlikely(skb->protocol == cpu_to_be16(ETH_P_PAE)))
- return;
-
- tid = ieee80211_get_tid(hdr);
- if (likely(sta->ampdu_mlme.tid_tx[tid]))
- return;
-
- ieee80211_start_tx_ba_session(pubsta, tid, 0);
-}
-
-static void
minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband,
void *priv_sta, struct ieee80211_tx_status *st)
{
@@ -1457,10 +1434,6 @@ minstrel_ht_get_rate(void *priv, struct
struct minstrel_priv *mp = priv;
u16 sample_idx;
- if (!(info->flags & IEEE80211_TX_CTL_AMPDU) &&
- !minstrel_ht_is_legacy_group(MI_RATE_GROUP(mi->max_prob_rate)))
- minstrel_aggr_check(sta, txrc->skb);
-
info->flags |= mi->tx_flags;
#ifdef CPTCFG_MAC80211_DEBUGFS
@@ -1866,6 +1839,7 @@ static u32 minstrel_ht_get_expected_thro
static const struct rate_control_ops mac80211_minstrel_ht = {
.name = "minstrel_ht",
+ .capa = RATE_CTRL_CAPA_AMPDU_TRIGGER,
.tx_status_ext = minstrel_ht_tx_status,
.get_rate = minstrel_ht_get_rate,
.rate_init = minstrel_ht_rate_init,
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -3951,6 +3951,29 @@ void ieee80211_txq_schedule_start(struct
}
EXPORT_SYMBOL(ieee80211_txq_schedule_start);
+static void
+ieee80211_aggr_check(struct ieee80211_sub_if_data *sdata,
+ struct sta_info *sta,
+ struct sk_buff *skb)
+{
+ struct rate_control_ref *ref = sdata->local->rate_ctrl;
+ u16 tid;
+
+ if (!ref || !(ref->ops->capa & RATE_CTRL_CAPA_AMPDU_TRIGGER))
+ return;
+
+ if (!sta || !sta->sta.ht_cap.ht_supported ||
+ !sta->sta.wme || skb_get_queue_mapping(skb) == IEEE80211_AC_VO ||
+ skb->protocol == sdata->control_port_protocol)
+ return;
+
+ tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
+ if (likely(sta->ampdu_mlme.tid_tx[tid]))
+ return;
+
+ ieee80211_start_tx_ba_session(&sta->sta, tid, 0);
+}
+
void __ieee80211_subif_start_xmit(struct sk_buff *skb,
struct net_device *dev,
u32 info_flags,
@@ -3981,6 +4004,8 @@ void __ieee80211_subif_start_xmit(struct
skb_get_hash(skb);
}
+ ieee80211_aggr_check(sdata, sta, skb);
+
if (sta) {
struct ieee80211_fast_tx *fast_tx;
@@ -4244,6 +4269,8 @@ static void ieee80211_8023_xmit(struct i
memset(info, 0, sizeof(*info));
+ ieee80211_aggr_check(sdata, sta, skb);
+
tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[tid]);
if (tid_tx) {

View File

@ -1,114 +0,0 @@
From: Ryder Lee <ryder.lee@mediatek.com>
Date: Fri, 28 May 2021 14:05:41 +0800
Subject: [PATCH] mac80211: call ieee80211_tx_h_rate_ctrl() when dequeue
Make ieee80211_tx_h_rate_ctrl() get called on dequeue to improve
performance since it reduces the turnaround time for rate control.
Signed-off-by: Ryder Lee <ryder.lee@mediatek.com>
---
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1768,8 +1768,6 @@ static int invoke_tx_handlers_early(stru
CALL_TXH(ieee80211_tx_h_ps_buf);
CALL_TXH(ieee80211_tx_h_check_control_port_protocol);
CALL_TXH(ieee80211_tx_h_select_key);
- if (!ieee80211_hw_check(&tx->local->hw, HAS_RATE_CONTROL))
- CALL_TXH(ieee80211_tx_h_rate_ctrl);
txh_done:
if (unlikely(res == TX_DROP)) {
@@ -1802,6 +1800,9 @@ static int invoke_tx_handlers_late(struc
goto txh_done;
}
+ if (!ieee80211_hw_check(&tx->local->hw, HAS_RATE_CONTROL))
+ CALL_TXH(ieee80211_tx_h_rate_ctrl);
+
CALL_TXH(ieee80211_tx_h_michael_mic_add);
CALL_TXH(ieee80211_tx_h_sequence);
CALL_TXH(ieee80211_tx_h_fragment);
@@ -3391,15 +3392,21 @@ out:
* Can be called while the sta lock is held. Anything that can cause packets to
* be generated will cause deadlock!
*/
-static void ieee80211_xmit_fast_finish(struct ieee80211_sub_if_data *sdata,
- struct sta_info *sta, u8 pn_offs,
- struct ieee80211_key *key,
- struct sk_buff *skb)
+static ieee80211_tx_result
+ieee80211_xmit_fast_finish(struct ieee80211_sub_if_data *sdata,
+ struct sta_info *sta, u8 pn_offs,
+ struct ieee80211_key *key,
+ struct ieee80211_tx_data *tx)
{
+ struct sk_buff *skb = tx->skb;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *hdr = (void *)skb->data;
u8 tid = IEEE80211_NUM_TIDS;
+ if (!ieee80211_hw_check(&tx->local->hw, HAS_RATE_CONTROL) &&
+ ieee80211_tx_h_rate_ctrl(tx) != TX_CONTINUE)
+ return TX_DROP;
+
if (key)
info->control.hw_key = &key->conf;
@@ -3448,6 +3455,8 @@ static void ieee80211_xmit_fast_finish(s
break;
}
}
+
+ return TX_CONTINUE;
}
static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
@@ -3551,24 +3560,17 @@ static bool ieee80211_xmit_fast(struct i
tx.sta = sta;
tx.key = fast_tx->key;
- if (!ieee80211_hw_check(&local->hw, HAS_RATE_CONTROL)) {
- tx.skb = skb;
- r = ieee80211_tx_h_rate_ctrl(&tx);
- skb = tx.skb;
- tx.skb = NULL;
-
- if (r != TX_CONTINUE) {
- if (r != TX_QUEUED)
- kfree_skb(skb);
- return true;
- }
- }
-
if (ieee80211_queue_skb(local, sdata, sta, skb))
return true;
- ieee80211_xmit_fast_finish(sdata, sta, fast_tx->pn_offs,
- fast_tx->key, skb);
+ tx.skb = skb;
+ r = ieee80211_xmit_fast_finish(sdata, sta, fast_tx->pn_offs,
+ fast_tx->key, &tx);
+ tx.skb = NULL;
+ if (r == TX_DROP) {
+ kfree_skb(skb);
+ return true;
+ }
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
sdata = container_of(sdata->bss,
@@ -3685,8 +3687,12 @@ begin:
(tx.key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV))
pn_offs = ieee80211_hdrlen(hdr->frame_control);
- ieee80211_xmit_fast_finish(sta->sdata, sta, pn_offs,
- tx.key, skb);
+ r = ieee80211_xmit_fast_finish(sta->sdata, sta, pn_offs,
+ tx.key, &tx);
+ if (r != TX_CONTINUE) {
+ ieee80211_free_txskb(&local->hw, skb);
+ goto begin;
+ }
} else {
if (invoke_tx_handlers_late(&tx))
goto begin;

View File

@ -1,126 +0,0 @@
From: Ryder Lee <ryder.lee@mediatek.com>
Date: Fri, 28 May 2021 14:05:43 +0800
Subject: [PATCH] mac80211: add rate control support for encap offload
The software rate control cannot deal with encap offload, so fix it.
Signed-off-by: Ryder Lee <ryder.lee@mediatek.com>
---
--- a/net/mac80211/rate.c
+++ b/net/mac80211/rate.c
@@ -297,15 +297,11 @@ void ieee80211_check_rate_mask(struct ie
static bool rc_no_data_or_no_ack_use_min(struct ieee80211_tx_rate_control *txrc)
{
struct sk_buff *skb = txrc->skb;
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- __le16 fc;
-
- fc = hdr->frame_control;
return (info->flags & (IEEE80211_TX_CTL_NO_ACK |
IEEE80211_TX_CTL_USE_MINRATE)) ||
- !ieee80211_is_data(fc);
+ !ieee80211_is_tx_data(skb);
}
static void rc_send_low_basicrate(struct ieee80211_tx_rate *rate,
@@ -870,7 +866,6 @@ void ieee80211_get_tx_rates(struct ieee8
int max_rates)
{
struct ieee80211_sub_if_data *sdata;
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_supported_band *sband;
@@ -882,7 +877,7 @@ void ieee80211_get_tx_rates(struct ieee8
sdata = vif_to_sdata(vif);
sband = sdata->local->hw.wiphy->bands[info->band];
- if (ieee80211_is_data(hdr->frame_control))
+ if (ieee80211_is_tx_data(skb))
rate_control_apply_mask(sdata, sta, sband, dest, max_rates);
if (dest[0].idx < 0)
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -666,6 +666,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee8021
u32 len;
struct ieee80211_tx_rate_control txrc;
struct ieee80211_sta_rates *ratetbl = NULL;
+ bool encap = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP;
bool assoc = false;
memset(&txrc, 0, sizeof(txrc));
@@ -707,7 +708,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee8021
* just wants a probe response.
*/
if (tx->sdata->vif.bss_conf.use_short_preamble &&
- (ieee80211_is_data(hdr->frame_control) ||
+ (ieee80211_is_tx_data(tx->skb) ||
(tx->sta && test_sta_flag(tx->sta, WLAN_STA_SHORT_PREAMBLE))))
txrc.short_preamble = true;
@@ -729,7 +730,8 @@ ieee80211_tx_h_rate_ctrl(struct ieee8021
"%s: Dropped data frame as no usable bitrate found while "
"scanning and associated. Target station: "
"%pM on %d GHz band\n",
- tx->sdata->name, hdr->addr1,
+ tx->sdata->name,
+ encap ? ((struct ethhdr *)hdr)->h_dest : hdr->addr1,
info->band ? 5 : 2))
return TX_DROP;
@@ -763,7 +765,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee8021
if (txrc.reported_rate.idx < 0) {
txrc.reported_rate = tx->rate;
- if (tx->sta && ieee80211_is_data(hdr->frame_control))
+ if (tx->sta && ieee80211_is_tx_data(tx->skb))
tx->sta->tx_stats.last_rate = txrc.reported_rate;
} else if (tx->sta)
tx->sta->tx_stats.last_rate = txrc.reported_rate;
@@ -3675,8 +3677,16 @@ begin:
else
info->flags &= ~IEEE80211_TX_CTL_AMPDU;
- if (info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP)
+ if (info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) {
+ if (!ieee80211_hw_check(&local->hw, HAS_RATE_CONTROL)) {
+ r = ieee80211_tx_h_rate_ctrl(&tx);
+ if (r != TX_CONTINUE) {
+ ieee80211_free_txskb(&local->hw, skb);
+ goto begin;
+ }
+ }
goto encap_out;
+ }
if (info->control.flags & IEEE80211_TX_CTRL_FAST_XMIT) {
struct sta_info *sta = container_of(txq->sta, struct sta_info,
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -6765,4 +6765,22 @@ struct sk_buff *ieee80211_get_fils_disco
struct sk_buff *
ieee80211_get_unsol_bcast_probe_resp_tmpl(struct ieee80211_hw *hw,
struct ieee80211_vif *vif);
+
+/**
+ * ieee80211_is_tx_data - check if frame is a data frame
+ *
+ * The function is used to check if a frame is a data frame. Frames with
+ * hardware encapsulation enabled are data frames.
+ *
+ * @skb: the frame to be transmitted.
+ */
+static inline bool ieee80211_is_tx_data(struct sk_buff *skb)
+{
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct ieee80211_hdr *hdr = (void *) skb->data;
+
+ return info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP ||
+ ieee80211_is_data(hdr->frame_control);
+}
+
#endif /* MAC80211_H */

View File

@ -1,112 +0,0 @@
From: Felix Fietkau <nbd@nbd.name>
Date: Tue, 29 Jun 2021 13:25:09 +0200
Subject: [PATCH] mac80211: fix starting aggregation sessions on mesh
interfaces
The logic for starting aggregation sessions was recently moved from minstrel_ht
to mac80211, into the subif tx handler just after the sta lookup.
Unfortunately this didn't work for mesh interfaces, since the sta lookup is
deferred until a much later point in time on those.
Fix this by also calling the aggregation check right after the deferred sta
lookup.
Fixes: 08a46c642001 ("mac80211: move A-MPDU session check from minstrel_ht to mac80211")
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1146,6 +1146,29 @@ static bool ieee80211_tx_prep_agg(struct
return queued;
}
+static void
+ieee80211_aggr_check(struct ieee80211_sub_if_data *sdata,
+ struct sta_info *sta,
+ struct sk_buff *skb)
+{
+ struct rate_control_ref *ref = sdata->local->rate_ctrl;
+ u16 tid;
+
+ if (!ref || !(ref->ops->capa & RATE_CTRL_CAPA_AMPDU_TRIGGER))
+ return;
+
+ if (!sta || !sta->sta.ht_cap.ht_supported ||
+ !sta->sta.wme || skb_get_queue_mapping(skb) == IEEE80211_AC_VO ||
+ skb->protocol == sdata->control_port_protocol)
+ return;
+
+ tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
+ if (likely(sta->ampdu_mlme.tid_tx[tid]))
+ return;
+
+ ieee80211_start_tx_ba_session(&sta->sta, tid, 0);
+}
+
/*
* initialises @tx
* pass %NULL for the station if unknown, a valid pointer if known
@@ -1159,6 +1182,7 @@ ieee80211_tx_prepare(struct ieee80211_su
struct ieee80211_local *local = sdata->local;
struct ieee80211_hdr *hdr;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ bool aggr_check = false;
int tid;
memset(tx, 0, sizeof(*tx));
@@ -1187,8 +1211,10 @@ ieee80211_tx_prepare(struct ieee80211_su
} else if (tx->sdata->control_port_protocol == tx->skb->protocol) {
tx->sta = sta_info_get_bss(sdata, hdr->addr1);
}
- if (!tx->sta && !is_multicast_ether_addr(hdr->addr1))
+ if (!tx->sta && !is_multicast_ether_addr(hdr->addr1)) {
tx->sta = sta_info_get(sdata, hdr->addr1);
+ aggr_check = true;
+ }
}
if (tx->sta && ieee80211_is_data_qos(hdr->frame_control) &&
@@ -1198,8 +1224,12 @@ ieee80211_tx_prepare(struct ieee80211_su
struct tid_ampdu_tx *tid_tx;
tid = ieee80211_get_tid(hdr);
-
tid_tx = rcu_dereference(tx->sta->ampdu_mlme.tid_tx[tid]);
+ if (!tid_tx && aggr_check) {
+ ieee80211_aggr_check(sdata, tx->sta, skb);
+ tid_tx = rcu_dereference(tx->sta->ampdu_mlme.tid_tx[tid]);
+ }
+
if (tid_tx) {
bool queued;
@@ -3967,29 +3997,6 @@ void ieee80211_txq_schedule_start(struct
}
EXPORT_SYMBOL(ieee80211_txq_schedule_start);
-static void
-ieee80211_aggr_check(struct ieee80211_sub_if_data *sdata,
- struct sta_info *sta,
- struct sk_buff *skb)
-{
- struct rate_control_ref *ref = sdata->local->rate_ctrl;
- u16 tid;
-
- if (!ref || !(ref->ops->capa & RATE_CTRL_CAPA_AMPDU_TRIGGER))
- return;
-
- if (!sta || !sta->sta.ht_cap.ht_supported ||
- !sta->sta.wme || skb_get_queue_mapping(skb) == IEEE80211_AC_VO ||
- skb->protocol == sdata->control_port_protocol)
- return;
-
- tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
- if (likely(sta->ampdu_mlme.tid_tx[tid]))
- return;
-
- ieee80211_start_tx_ba_session(&sta->sta, tid, 0);
-}
-
void __ieee80211_subif_start_xmit(struct sk_buff *skb,
struct net_device *dev,
u32 info_flags,

View File

@ -1,39 +0,0 @@
From: Johannes Berg <johannes.berg@intel.com>
Date: Fri, 18 Jun 2021 13:41:44 +0300
Subject: [PATCH] mac80211: rearrange struct txq_info for fewer holes
We can slightly decrease the size of struct txq_info by
rearranging some fields for fewer holes, so do that.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
Link: https://lore.kernel.org/r/iwlwifi.20210618133832.1bf019a1fe2e.Ib54622b8d6dc1a9a7dc484e573c073119450538b@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -5,7 +5,7 @@
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
* Copyright 2007-2010 Johannes Berg <johannes@sipsolutions.net>
* Copyright 2013-2015 Intel Mobile Communications GmbH
- * Copyright (C) 2018-2020 Intel Corporation
+ * Copyright (C) 2018-2021 Intel Corporation
*/
#ifndef IEEE80211_I_H
@@ -843,9 +843,12 @@ struct txq_info {
struct fq_tin tin;
struct codel_vars def_cvars;
struct codel_stats cstats;
- struct sk_buff_head frags;
- struct list_head schedule_order;
+
u16 schedule_round;
+ struct list_head schedule_order;
+
+ struct sk_buff_head frags;
+
unsigned long flags;
/* keep last! */

View File

@ -1,1277 +0,0 @@
From: =?UTF-8?q?Toke=20H=C3=B8iland-J=C3=B8rgensen?= <toke@redhat.com>
Date: Wed, 23 Jun 2021 15:47:55 +0200
Subject: [PATCH] mac80211: Switch to a virtual time-based airtime scheduler
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This switches the airtime scheduler in mac80211 to use a virtual
time-based scheduler instead of the round-robin scheduler used before.
This has a couple of advantages:
- No need to sync up the round-robin scheduler in firmware/hardware with
the round-robin airtime scheduler.
- If several stations are eligible for transmission we can schedule both
of them; no need to hard-block the scheduling rotation until the head
of the queue has used up its quantum.
- The check of whether a station is eligible for transmission becomes
simpler (in ieee80211_txq_may_transmit()).
The drawback is that scheduling becomes slightly more expensive, as we
need to maintain an rbtree of TXQs sorted by virtual time. This means
that ieee80211_register_airtime() becomes O(logN) in the number of
currently scheduled TXQs because it can change the order of the
scheduled stations. We mitigate this overhead by only resorting when a
station changes position in the tree, and hopefully N rarely grows too
big (it's only TXQs currently backlogged, not all associated stations),
so it shouldn't be too big of an issue.
To prevent divisions in the fast path, we maintain both station sums and
pre-computed reciprocals of the sums. This turns the fast-path operation
into a multiplication, with divisions only happening as the number of
active stations change (to re-compute the current sum of all active
station weights). To prevent this re-computation of the reciprocal from
happening too frequently, we use a time-based notion of station
activity, instead of updating the weight every time a station gets
scheduled or de-scheduled. As queues can oscillate between empty and
occupied quite frequently, this can significantly cut down on the number
of re-computations. It also has the added benefit of making the station
airtime calculation independent on whether the queue happened to have
drained at the time an airtime value was accounted.
Co-developed-by: Yibo Zhao <yiboz@codeaurora.org>
Signed-off-by: Yibo Zhao <yiboz@codeaurora.org>
Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
Link: https://lore.kernel.org/r/20210623134755.235545-1-toke@redhat.com
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -6589,9 +6589,6 @@ static inline void ieee80211_txq_schedul
{
}
-void __ieee80211_schedule_txq(struct ieee80211_hw *hw,
- struct ieee80211_txq *txq, bool force);
-
/**
* ieee80211_schedule_txq - schedule a TXQ for transmission
*
@@ -6604,11 +6601,7 @@ void __ieee80211_schedule_txq(struct iee
* The driver may call this function if it has buffered packets for
* this TXQ internally.
*/
-static inline void
-ieee80211_schedule_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq)
-{
- __ieee80211_schedule_txq(hw, txq, true);
-}
+void ieee80211_schedule_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq);
/**
* ieee80211_return_txq - return a TXQ previously acquired by ieee80211_next_txq()
@@ -6620,12 +6613,8 @@ ieee80211_schedule_txq(struct ieee80211_
* The driver may set force=true if it has buffered packets for this TXQ
* internally.
*/
-static inline void
-ieee80211_return_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq,
- bool force)
-{
- __ieee80211_schedule_txq(hw, txq, force);
-}
+void ieee80211_return_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq,
+ bool force);
/**
* ieee80211_txq_may_transmit - check whether TXQ is allowed to transmit
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1460,6 +1460,38 @@ static void sta_apply_mesh_params(struct
#endif
}
+static void sta_apply_airtime_params(struct ieee80211_local *local,
+ struct sta_info *sta,
+ struct station_parameters *params)
+{
+ u8 ac;
+
+ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
+ struct airtime_sched_info *air_sched = &local->airtime[ac];
+ struct airtime_info *air_info = &sta->airtime[ac];
+ struct txq_info *txqi;
+ u8 tid;
+
+ spin_lock_bh(&air_sched->lock);
+ for (tid = 0; tid < IEEE80211_NUM_TIDS + 1; tid++) {
+ if (air_info->weight == params->airtime_weight ||
+ !sta->sta.txq[tid] ||
+ ac != ieee80211_ac_from_tid(tid))
+ continue;
+
+ airtime_weight_set(air_info, params->airtime_weight);
+
+ txqi = to_txq_info(sta->sta.txq[tid]);
+ if (RB_EMPTY_NODE(&txqi->schedule_order))
+ continue;
+
+ ieee80211_update_airtime_weight(local, air_sched,
+ 0, true);
+ }
+ spin_unlock_bh(&air_sched->lock);
+ }
+}
+
static int sta_apply_parameters(struct ieee80211_local *local,
struct sta_info *sta,
struct station_parameters *params)
@@ -1647,7 +1679,8 @@ static int sta_apply_parameters(struct i
sta_apply_mesh_params(local, sta, params);
if (params->airtime_weight)
- sta->airtime_weight = params->airtime_weight;
+ sta_apply_airtime_params(local, sta, params);
+
/* set the STA state after all sta info from usermode has been set */
if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) ||
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -216,14 +216,14 @@ static ssize_t aql_txq_limit_read(struct
"VI %u %u\n"
"BE %u %u\n"
"BK %u %u\n",
- local->aql_txq_limit_low[IEEE80211_AC_VO],
- local->aql_txq_limit_high[IEEE80211_AC_VO],
- local->aql_txq_limit_low[IEEE80211_AC_VI],
- local->aql_txq_limit_high[IEEE80211_AC_VI],
- local->aql_txq_limit_low[IEEE80211_AC_BE],
- local->aql_txq_limit_high[IEEE80211_AC_BE],
- local->aql_txq_limit_low[IEEE80211_AC_BK],
- local->aql_txq_limit_high[IEEE80211_AC_BK]);
+ local->airtime[IEEE80211_AC_VO].aql_txq_limit_low,
+ local->airtime[IEEE80211_AC_VO].aql_txq_limit_high,
+ local->airtime[IEEE80211_AC_VI].aql_txq_limit_low,
+ local->airtime[IEEE80211_AC_VI].aql_txq_limit_high,
+ local->airtime[IEEE80211_AC_BE].aql_txq_limit_low,
+ local->airtime[IEEE80211_AC_BE].aql_txq_limit_high,
+ local->airtime[IEEE80211_AC_BK].aql_txq_limit_low,
+ local->airtime[IEEE80211_AC_BK].aql_txq_limit_high);
return simple_read_from_buffer(user_buf, count, ppos,
buf, len);
}
@@ -255,11 +255,11 @@ static ssize_t aql_txq_limit_write(struc
if (ac >= IEEE80211_NUM_ACS)
return -EINVAL;
- q_limit_low_old = local->aql_txq_limit_low[ac];
- q_limit_high_old = local->aql_txq_limit_high[ac];
+ q_limit_low_old = local->airtime[ac].aql_txq_limit_low;
+ q_limit_high_old = local->airtime[ac].aql_txq_limit_high;
- local->aql_txq_limit_low[ac] = q_limit_low;
- local->aql_txq_limit_high[ac] = q_limit_high;
+ local->airtime[ac].aql_txq_limit_low = q_limit_low;
+ local->airtime[ac].aql_txq_limit_high = q_limit_high;
mutex_lock(&local->sta_mtx);
list_for_each_entry(sta, &local->sta_list, list) {
@@ -382,6 +382,46 @@ static const struct file_operations forc
.llseek = default_llseek,
};
+static ssize_t airtime_read(struct file *file,
+ char __user *user_buf,
+ size_t count,
+ loff_t *ppos)
+{
+ struct ieee80211_local *local = file->private_data;
+ char buf[200];
+ u64 v_t[IEEE80211_NUM_ACS];
+ u64 wt[IEEE80211_NUM_ACS];
+ int len = 0, ac;
+
+ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
+ spin_lock_bh(&local->airtime[ac].lock);
+ v_t[ac] = local->airtime[ac].v_t;
+ wt[ac] = local->airtime[ac].weight_sum;
+ spin_unlock_bh(&local->airtime[ac].lock);
+ }
+ len = scnprintf(buf, sizeof(buf),
+ "\tVO VI BE BK\n"
+ "Virt-t\t%-10llu %-10llu %-10llu %-10llu\n"
+ "Weight\t%-10llu %-10llu %-10llu %-10llu\n",
+ v_t[0],
+ v_t[1],
+ v_t[2],
+ v_t[3],
+ wt[0],
+ wt[1],
+ wt[2],
+ wt[3]);
+
+ return simple_read_from_buffer(user_buf, count, ppos,
+ buf, len);
+}
+
+static const struct file_operations airtime_ops = {
+ .read = airtime_read,
+ .open = simple_open,
+ .llseek = default_llseek,
+};
+
#ifdef CONFIG_PM
static ssize_t reset_write(struct file *file, const char __user *user_buf,
size_t count, loff_t *ppos)
@@ -632,7 +672,11 @@ void debugfs_hw_add(struct ieee80211_loc
if (local->ops->wake_tx_queue)
DEBUGFS_ADD_MODE(aqm, 0600);
- DEBUGFS_ADD_MODE(airtime_flags, 0600);
+ if (wiphy_ext_feature_isset(local->hw.wiphy,
+ NL80211_EXT_FEATURE_AIRTIME_FAIRNESS)) {
+ DEBUGFS_ADD_MODE(airtime, 0600);
+ DEBUGFS_ADD_MODE(airtime_flags, 0600);
+ }
DEBUGFS_ADD(aql_txq_limit);
debugfs_create_u32("aql_threshold", 0600,
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -513,6 +513,34 @@ static ssize_t ieee80211_if_fmt_aqm(
}
IEEE80211_IF_FILE_R(aqm);
+static ssize_t ieee80211_if_fmt_airtime(
+ const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
+{
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_txq *txq = sdata->vif.txq;
+ struct airtime_info *air_info;
+ int len;
+
+ if (!txq)
+ return 0;
+
+ spin_lock_bh(&local->airtime[txq->ac].lock);
+ air_info = to_airtime_info(txq);
+ len = scnprintf(buf,
+ buflen,
+ "RX: %llu us\nTX: %llu us\nWeight: %u\n"
+ "Virt-T: %lld us\n",
+ air_info->rx_airtime,
+ air_info->tx_airtime,
+ air_info->weight,
+ air_info->v_t);
+ spin_unlock_bh(&local->airtime[txq->ac].lock);
+
+ return len;
+}
+
+IEEE80211_IF_FILE_R(airtime);
+
IEEE80211_IF_FILE(multicast_to_unicast, u.ap.multicast_to_unicast, HEX);
/* IBSS attributes */
@@ -658,8 +686,10 @@ static void add_common_files(struct ieee
if (sdata->local->ops->wake_tx_queue &&
sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE &&
- sdata->vif.type != NL80211_IFTYPE_NAN)
+ sdata->vif.type != NL80211_IFTYPE_NAN) {
DEBUGFS_ADD(aqm);
+ DEBUGFS_ADD(airtime);
+ }
}
static void add_sta_files(struct ieee80211_sub_if_data *sdata)
--- a/net/mac80211/debugfs_sta.c
+++ b/net/mac80211/debugfs_sta.c
@@ -202,7 +202,7 @@ static ssize_t sta_airtime_read(struct f
size_t bufsz = 400;
char *buf = kzalloc(bufsz, GFP_KERNEL), *p = buf;
u64 rx_airtime = 0, tx_airtime = 0;
- s64 deficit[IEEE80211_NUM_ACS];
+ u64 v_t[IEEE80211_NUM_ACS];
ssize_t rv;
int ac;
@@ -210,18 +210,18 @@ static ssize_t sta_airtime_read(struct f
return -ENOMEM;
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
- spin_lock_bh(&local->active_txq_lock[ac]);
+ spin_lock_bh(&local->airtime[ac].lock);
rx_airtime += sta->airtime[ac].rx_airtime;
tx_airtime += sta->airtime[ac].tx_airtime;
- deficit[ac] = sta->airtime[ac].deficit;
- spin_unlock_bh(&local->active_txq_lock[ac]);
+ v_t[ac] = sta->airtime[ac].v_t;
+ spin_unlock_bh(&local->airtime[ac].lock);
}
p += scnprintf(p, bufsz + buf - p,
"RX: %llu us\nTX: %llu us\nWeight: %u\n"
- "Deficit: VO: %lld us VI: %lld us BE: %lld us BK: %lld us\n",
- rx_airtime, tx_airtime, sta->airtime_weight,
- deficit[0], deficit[1], deficit[2], deficit[3]);
+ "Virt-T: VO: %lld us VI: %lld us BE: %lld us BK: %lld us\n",
+ rx_airtime, tx_airtime, sta->airtime[0].weight,
+ v_t[0], v_t[1], v_t[2], v_t[3]);
rv = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
kfree(buf);
@@ -236,11 +236,11 @@ static ssize_t sta_airtime_write(struct
int ac;
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
- spin_lock_bh(&local->active_txq_lock[ac]);
+ spin_lock_bh(&local->airtime[ac].lock);
sta->airtime[ac].rx_airtime = 0;
sta->airtime[ac].tx_airtime = 0;
- sta->airtime[ac].deficit = sta->airtime_weight;
- spin_unlock_bh(&local->active_txq_lock[ac]);
+ sta->airtime[ac].v_t = 0;
+ spin_unlock_bh(&local->airtime[ac].lock);
}
return count;
@@ -263,10 +263,10 @@ static ssize_t sta_aql_read(struct file
return -ENOMEM;
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
- spin_lock_bh(&local->active_txq_lock[ac]);
+ spin_lock_bh(&local->airtime[ac].lock);
q_limit_l[ac] = sta->airtime[ac].aql_limit_low;
q_limit_h[ac] = sta->airtime[ac].aql_limit_high;
- spin_unlock_bh(&local->active_txq_lock[ac]);
+ spin_unlock_bh(&local->airtime[ac].lock);
q_depth[ac] = atomic_read(&sta->airtime[ac].aql_tx_pending);
}
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -835,20 +835,16 @@ enum txq_info_flags {
* @def_flow: used as a fallback flow when a packet destined to @tin hashes to
* a fq_flow which is already owned by a different tin
* @def_cvars: codel vars for @def_flow
- * @frags: used to keep fragments created after dequeue
* @schedule_order: used with ieee80211_local->active_txqs
- * @schedule_round: counter to prevent infinite loops on TXQ scheduling
+ * @frags: used to keep fragments created after dequeue
*/
struct txq_info {
struct fq_tin tin;
struct codel_vars def_cvars;
struct codel_stats cstats;
-
- u16 schedule_round;
- struct list_head schedule_order;
+ struct rb_node schedule_order;
struct sk_buff_head frags;
-
unsigned long flags;
/* keep last! */
@@ -925,6 +921,8 @@ struct ieee80211_sub_if_data {
struct ieee80211_tx_queue_params tx_conf[IEEE80211_NUM_ACS];
struct mac80211_qos_map __rcu *qos_map;
+ struct airtime_info airtime[IEEE80211_NUM_ACS];
+
struct work_struct csa_finalize_work;
bool csa_block_tx; /* write-protected by sdata_lock and local->mtx */
struct cfg80211_chan_def csa_chandef;
@@ -1137,6 +1135,44 @@ enum mac80211_scan_state {
SCAN_ABORT,
};
+/**
+ * struct airtime_sched_info - state used for airtime scheduling and AQL
+ *
+ * @lock: spinlock that protects all the fields in this struct
+ * @active_txqs: rbtree of currently backlogged queues, sorted by virtual time
+ * @schedule_pos: the current position maintained while a driver walks the tree
+ * with ieee80211_next_txq()
+ * @active_list: list of struct airtime_info structs that were active within
+ * the last AIRTIME_ACTIVE_DURATION (100 ms), used to compute
+ * weight_sum
+ * @last_weight_update: used for rate limiting walking active_list
+ * @last_schedule_time: tracks the last time a transmission was scheduled; used
+ * for catching up v_t if no stations are eligible for
+ * transmission.
+ * @v_t: global virtual time; queues with v_t < this are eligible for
+ * transmission
+ * @weight_sum: total sum of all active stations used for dividing airtime
+ * @weight_sum_reciprocal: reciprocal of weight_sum (to avoid divisions in fast
+ * path - see comment above
+ * IEEE80211_RECIPROCAL_DIVISOR_64)
+ * @aql_txq_limit_low: AQL limit when total outstanding airtime
+ * is < IEEE80211_AQL_THRESHOLD
+ * @aql_txq_limit_high: AQL limit when total outstanding airtime
+ * is > IEEE80211_AQL_THRESHOLD
+ */
+struct airtime_sched_info {
+ spinlock_t lock;
+ struct rb_root_cached active_txqs;
+ struct rb_node *schedule_pos;
+ struct list_head active_list;
+ u64 last_weight_update;
+ u64 last_schedule_activity;
+ u64 v_t;
+ u64 weight_sum;
+ u64 weight_sum_reciprocal;
+ u32 aql_txq_limit_low;
+ u32 aql_txq_limit_high;
+};
DECLARE_STATIC_KEY_FALSE(aql_disable);
struct ieee80211_local {
@@ -1150,13 +1186,8 @@ struct ieee80211_local {
struct codel_params cparams;
/* protects active_txqs and txqi->schedule_order */
- spinlock_t active_txq_lock[IEEE80211_NUM_ACS];
- struct list_head active_txqs[IEEE80211_NUM_ACS];
- u16 schedule_round[IEEE80211_NUM_ACS];
-
+ struct airtime_sched_info airtime[IEEE80211_NUM_ACS];
u16 airtime_flags;
- u32 aql_txq_limit_low[IEEE80211_NUM_ACS];
- u32 aql_txq_limit_high[IEEE80211_NUM_ACS];
u32 aql_threshold;
atomic_t aql_total_pending_airtime;
@@ -1574,6 +1605,125 @@ static inline bool txq_has_queue(struct
return !(skb_queue_empty(&txqi->frags) && !txqi->tin.backlog_packets);
}
+static inline struct airtime_info *to_airtime_info(struct ieee80211_txq *txq)
+{
+ struct ieee80211_sub_if_data *sdata;
+ struct sta_info *sta;
+
+ if (txq->sta) {
+ sta = container_of(txq->sta, struct sta_info, sta);
+ return &sta->airtime[txq->ac];
+ }
+
+ sdata = vif_to_sdata(txq->vif);
+ return &sdata->airtime[txq->ac];
+}
+
+/* To avoid divisions in the fast path, we keep pre-computed reciprocals for
+ * airtime weight calculations. There are two different weights to keep track
+ * of: The per-station weight and the sum of weights per phy.
+ *
+ * For the per-station weights (kept in airtime_info below), we use 32-bit
+ * reciprocals with a devisor of 2^19. This lets us keep the multiplications and
+ * divisions for the station weights as 32-bit operations at the cost of a bit
+ * of rounding error for high weights; but the choice of divisor keeps rounding
+ * errors <10% for weights <2^15, assuming no more than 8ms of airtime is
+ * reported at a time.
+ *
+ * For the per-phy sum of weights the values can get higher, so we use 64-bit
+ * operations for those with a 32-bit divisor, which should avoid any
+ * significant rounding errors.
+ */
+#define IEEE80211_RECIPROCAL_DIVISOR_64 0x100000000ULL
+#define IEEE80211_RECIPROCAL_SHIFT_64 32
+#define IEEE80211_RECIPROCAL_DIVISOR_32 0x80000U
+#define IEEE80211_RECIPROCAL_SHIFT_32 19
+
+static inline void airtime_weight_set(struct airtime_info *air_info, u16 weight)
+{
+ if (air_info->weight == weight)
+ return;
+
+ air_info->weight = weight;
+ if (weight) {
+ air_info->weight_reciprocal =
+ IEEE80211_RECIPROCAL_DIVISOR_32 / weight;
+ } else {
+ air_info->weight_reciprocal = 0;
+ }
+}
+
+static inline void airtime_weight_sum_set(struct airtime_sched_info *air_sched,
+ int weight_sum)
+{
+ if (air_sched->weight_sum == weight_sum)
+ return;
+
+ air_sched->weight_sum = weight_sum;
+ if (air_sched->weight_sum) {
+ air_sched->weight_sum_reciprocal = IEEE80211_RECIPROCAL_DIVISOR_64;
+ do_div(air_sched->weight_sum_reciprocal, air_sched->weight_sum);
+ } else {
+ air_sched->weight_sum_reciprocal = 0;
+ }
+}
+
+/* A problem when trying to enforce airtime fairness is that we want to divide
+ * the airtime between the currently *active* stations. However, basing this on
+ * the instantaneous queue state of stations doesn't work, as queues tend to
+ * oscillate very quickly between empty and occupied, leading to the scheduler
+ * thinking only a single station is active when deciding whether to allow
+ * transmission (and thus not throttling correctly).
+ *
+ * To fix this we use a timer-based notion of activity: a station is considered
+ * active if it has been scheduled within the last 100 ms; we keep a separate
+ * list of all the stations considered active in this manner, and lazily update
+ * the total weight of active stations from this list (filtering the stations in
+ * the list by their 'last active' time).
+ *
+ * We add one additional safeguard to guard against stations that manage to get
+ * scheduled every 100 ms but don't transmit a lot of data, and thus don't use
+ * up any airtime. Such stations would be able to get priority for an extended
+ * period of time if they do start transmitting at full capacity again, and so
+ * we add an explicit maximum for how far behind a station is allowed to fall in
+ * the virtual airtime domain. This limit is set to a relatively high value of
+ * 20 ms because the main mechanism for catching up idle stations is the active
+ * state as described above; i.e., the hard limit should only be hit in
+ * pathological cases.
+ */
+#define AIRTIME_ACTIVE_DURATION (100 * NSEC_PER_MSEC)
+#define AIRTIME_MAX_BEHIND 20000 /* 20 ms */
+
+static inline bool airtime_is_active(struct airtime_info *air_info, u64 now)
+{
+ return air_info->last_scheduled >= now - AIRTIME_ACTIVE_DURATION;
+}
+
+static inline void airtime_set_active(struct airtime_sched_info *air_sched,
+ struct airtime_info *air_info, u64 now)
+{
+ air_info->last_scheduled = now;
+ air_sched->last_schedule_activity = now;
+ list_move_tail(&air_info->list, &air_sched->active_list);
+}
+
+static inline bool airtime_catchup_v_t(struct airtime_sched_info *air_sched,
+ u64 v_t, u64 now)
+{
+ air_sched->v_t = v_t;
+ return true;
+}
+
+static inline void init_airtime_info(struct airtime_info *air_info,
+ struct airtime_sched_info *air_sched)
+{
+ atomic_set(&air_info->aql_tx_pending, 0);
+ air_info->aql_limit_low = air_sched->aql_txq_limit_low;
+ air_info->aql_limit_high = air_sched->aql_txq_limit_high;
+ airtime_weight_set(air_info, IEEE80211_DEFAULT_AIRTIME_WEIGHT);
+ INIT_LIST_HEAD(&air_info->list);
+}
+
static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr)
{
return ether_addr_equal(raddr, addr) ||
@@ -1816,6 +1966,14 @@ int ieee80211_tx_control_port(struct wip
u64 *cookie);
int ieee80211_probe_mesh_link(struct wiphy *wiphy, struct net_device *dev,
const u8 *buf, size_t len);
+void ieee80211_resort_txq(struct ieee80211_hw *hw,
+ struct ieee80211_txq *txq);
+void ieee80211_unschedule_txq(struct ieee80211_hw *hw,
+ struct ieee80211_txq *txq,
+ bool purge);
+void ieee80211_update_airtime_weight(struct ieee80211_local *local,
+ struct airtime_sched_info *air_sched,
+ u64 now, bool force);
/* HT */
void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata,
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -2041,6 +2041,9 @@ int ieee80211_if_add(struct ieee80211_lo
}
}
+ for (i = 0; i < IEEE80211_NUM_ACS; i++)
+ init_airtime_info(&sdata->airtime[i], &local->airtime[i]);
+
ieee80211_set_default_queues(sdata);
sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL;
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -707,10 +707,13 @@ struct ieee80211_hw *ieee80211_alloc_hw_
spin_lock_init(&local->queue_stop_reason_lock);
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
- INIT_LIST_HEAD(&local->active_txqs[i]);
- spin_lock_init(&local->active_txq_lock[i]);
- local->aql_txq_limit_low[i] = IEEE80211_DEFAULT_AQL_TXQ_LIMIT_L;
- local->aql_txq_limit_high[i] =
+ struct airtime_sched_info *air_sched = &local->airtime[i];
+
+ air_sched->active_txqs = RB_ROOT_CACHED;
+ INIT_LIST_HEAD(&air_sched->active_list);
+ spin_lock_init(&air_sched->lock);
+ air_sched->aql_txq_limit_low = IEEE80211_DEFAULT_AQL_TXQ_LIMIT_L;
+ air_sched->aql_txq_limit_high =
IEEE80211_DEFAULT_AQL_TXQ_LIMIT_H;
}
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1563,12 +1563,8 @@ static void sta_ps_start(struct sta_info
for (tid = 0; tid < IEEE80211_NUM_TIDS; tid++) {
struct ieee80211_txq *txq = sta->sta.txq[tid];
- struct txq_info *txqi = to_txq_info(txq);
- spin_lock(&local->active_txq_lock[txq->ac]);
- if (!list_empty(&txqi->schedule_order))
- list_del_init(&txqi->schedule_order);
- spin_unlock(&local->active_txq_lock[txq->ac]);
+ ieee80211_unschedule_txq(&local->hw, txq, false);
if (txq_has_queue(txq))
set_bit(tid, &sta->txq_buffered_tids);
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -426,15 +426,11 @@ struct sta_info *sta_info_alloc(struct i
if (sta_prepare_rate_control(local, sta, gfp))
goto free_txq;
- sta->airtime_weight = IEEE80211_DEFAULT_AIRTIME_WEIGHT;
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
skb_queue_head_init(&sta->ps_tx_buf[i]);
skb_queue_head_init(&sta->tx_filtered[i]);
- sta->airtime[i].deficit = sta->airtime_weight;
- atomic_set(&sta->airtime[i].aql_tx_pending, 0);
- sta->airtime[i].aql_limit_low = local->aql_txq_limit_low[i];
- sta->airtime[i].aql_limit_high = local->aql_txq_limit_high[i];
+ init_airtime_info(&sta->airtime[i], &local->airtime[i]);
}
for (i = 0; i < IEEE80211_NUM_TIDS; i++)
@@ -1893,24 +1889,59 @@ void ieee80211_sta_set_buffered(struct i
}
EXPORT_SYMBOL(ieee80211_sta_set_buffered);
-void ieee80211_sta_register_airtime(struct ieee80211_sta *pubsta, u8 tid,
- u32 tx_airtime, u32 rx_airtime)
+void ieee80211_register_airtime(struct ieee80211_txq *txq,
+ u32 tx_airtime, u32 rx_airtime)
{
- struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
- struct ieee80211_local *local = sta->sdata->local;
- u8 ac = ieee80211_ac_from_tid(tid);
+ struct ieee80211_sub_if_data *sdata = vif_to_sdata(txq->vif);
+ struct ieee80211_local *local = sdata->local;
+ u64 weight_sum, weight_sum_reciprocal;
+ struct airtime_sched_info *air_sched;
+ struct airtime_info *air_info;
u32 airtime = 0;
- if (sta->local->airtime_flags & AIRTIME_USE_TX)
+ air_sched = &local->airtime[txq->ac];
+ air_info = to_airtime_info(txq);
+
+ if (local->airtime_flags & AIRTIME_USE_TX)
airtime += tx_airtime;
- if (sta->local->airtime_flags & AIRTIME_USE_RX)
+ if (local->airtime_flags & AIRTIME_USE_RX)
airtime += rx_airtime;
- spin_lock_bh(&local->active_txq_lock[ac]);
- sta->airtime[ac].tx_airtime += tx_airtime;
- sta->airtime[ac].rx_airtime += rx_airtime;
- sta->airtime[ac].deficit -= airtime;
- spin_unlock_bh(&local->active_txq_lock[ac]);
+ /* Weights scale so the unit weight is 256 */
+ airtime <<= 8;
+
+ spin_lock_bh(&air_sched->lock);
+
+ air_info->tx_airtime += tx_airtime;
+ air_info->rx_airtime += rx_airtime;
+
+ if (air_sched->weight_sum) {
+ weight_sum = air_sched->weight_sum;
+ weight_sum_reciprocal = air_sched->weight_sum_reciprocal;
+ } else {
+ weight_sum = air_info->weight;
+ weight_sum_reciprocal = air_info->weight_reciprocal;
+ }
+
+ /* Round the calculation of global vt */
+ air_sched->v_t += (u64)((airtime + (weight_sum >> 1)) *
+ weight_sum_reciprocal) >> IEEE80211_RECIPROCAL_SHIFT_64;
+ air_info->v_t += (u32)((airtime + (air_info->weight >> 1)) *
+ air_info->weight_reciprocal) >> IEEE80211_RECIPROCAL_SHIFT_32;
+ ieee80211_resort_txq(&local->hw, txq);
+
+ spin_unlock_bh(&air_sched->lock);
+}
+
+void ieee80211_sta_register_airtime(struct ieee80211_sta *pubsta, u8 tid,
+ u32 tx_airtime, u32 rx_airtime)
+{
+ struct ieee80211_txq *txq = pubsta->txq[tid];
+
+ if (!txq)
+ return;
+
+ ieee80211_register_airtime(txq, tx_airtime, rx_airtime);
}
EXPORT_SYMBOL(ieee80211_sta_register_airtime);
@@ -2354,7 +2385,7 @@ void sta_set_sinfo(struct sta_info *sta,
}
if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_AIRTIME_WEIGHT))) {
- sinfo->airtime_weight = sta->airtime_weight;
+ sinfo->airtime_weight = sta->airtime[0].weight;
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_AIRTIME_WEIGHT);
}
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -135,18 +135,25 @@ enum ieee80211_agg_stop_reason {
#define AIRTIME_USE_TX BIT(0)
#define AIRTIME_USE_RX BIT(1)
+
struct airtime_info {
u64 rx_airtime;
u64 tx_airtime;
- s64 deficit;
+ u64 v_t;
+ u64 last_scheduled;
+ struct list_head list;
atomic_t aql_tx_pending; /* Estimated airtime for frames pending */
u32 aql_limit_low;
u32 aql_limit_high;
+ u32 weight_reciprocal;
+ u16 weight;
};
void ieee80211_sta_update_pending_airtime(struct ieee80211_local *local,
struct sta_info *sta, u8 ac,
u16 tx_airtime, bool tx_completed);
+void ieee80211_register_airtime(struct ieee80211_txq *txq,
+ u32 tx_airtime, u32 rx_airtime);
struct sta_info;
@@ -515,7 +522,6 @@ struct ieee80211_fragment_cache {
* @tid_seq: per-TID sequence numbers for sending to this STA
* @airtime: per-AC struct airtime_info describing airtime statistics for this
* station
- * @airtime_weight: station weight for airtime fairness calculation purposes
* @ampdu_mlme: A-MPDU state machine state
* @mesh: mesh STA information
* @debugfs_dir: debug filesystem directory dentry
@@ -646,7 +652,6 @@ struct sta_info {
u16 tid_seq[IEEE80211_QOS_CTL_TID_MASK + 1];
struct airtime_info airtime[IEEE80211_NUM_ACS];
- u16 airtime_weight;
/*
* Aggregation information, locked with lock.
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -970,6 +970,25 @@ static void __ieee80211_tx_status(struct
if (!(info->flags & IEEE80211_TX_CTL_INJECTED) && acked)
ieee80211_frame_acked(sta, skb);
+ } else if (wiphy_ext_feature_isset(local->hw.wiphy,
+ NL80211_EXT_FEATURE_AIRTIME_FAIRNESS)) {
+ struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_txq *txq;
+ u32 airtime;
+
+ /* Account airtime to multicast queue */
+ sdata = ieee80211_sdata_from_skb(local, skb);
+
+ if (sdata && (txq = sdata->vif.txq)) {
+ airtime = info->status.tx_time ?:
+ ieee80211_calc_expected_tx_airtime(hw,
+ &sdata->vif,
+ NULL,
+ skb->len,
+ false);
+
+ ieee80211_register_airtime(txq, airtime, 0);
+ }
}
/* SNMP counters
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -18,6 +18,7 @@
#include <linux/bitmap.h>
#include <linux/rcupdate.h>
#include <linux/export.h>
+#include <linux/timekeeping.h>
#include <net/net_namespace.h>
#include <net/ieee80211_radiotap.h>
#include <net/cfg80211.h>
@@ -1479,7 +1480,7 @@ void ieee80211_txq_init(struct ieee80211
codel_vars_init(&txqi->def_cvars);
codel_stats_init(&txqi->cstats);
__skb_queue_head_init(&txqi->frags);
- INIT_LIST_HEAD(&txqi->schedule_order);
+ RB_CLEAR_NODE(&txqi->schedule_order);
txqi->txq.vif = &sdata->vif;
@@ -1523,9 +1524,7 @@ void ieee80211_txq_purge(struct ieee8021
ieee80211_purge_tx_queue(&local->hw, &txqi->frags);
spin_unlock_bh(&fq->lock);
- spin_lock_bh(&local->active_txq_lock[txqi->txq.ac]);
- list_del_init(&txqi->schedule_order);
- spin_unlock_bh(&local->active_txq_lock[txqi->txq.ac]);
+ ieee80211_unschedule_txq(&local->hw, &txqi->txq, true);
}
void ieee80211_txq_set_params(struct ieee80211_local *local)
@@ -3812,102 +3811,259 @@ EXPORT_SYMBOL(ieee80211_tx_dequeue);
struct ieee80211_txq *ieee80211_next_txq(struct ieee80211_hw *hw, u8 ac)
{
struct ieee80211_local *local = hw_to_local(hw);
+ struct airtime_sched_info *air_sched;
+ u64 now = ktime_get_boottime_ns();
struct ieee80211_txq *ret = NULL;
- struct txq_info *txqi = NULL, *head = NULL;
- bool found_eligible_txq = false;
+ struct airtime_info *air_info;
+ struct txq_info *txqi = NULL;
+ struct rb_node *node;
+ bool first = false;
- spin_lock_bh(&local->active_txq_lock[ac]);
+ air_sched = &local->airtime[ac];
+ spin_lock_bh(&air_sched->lock);
- begin:
- txqi = list_first_entry_or_null(&local->active_txqs[ac],
- struct txq_info,
- schedule_order);
- if (!txqi)
+ node = air_sched->schedule_pos;
+
+begin:
+ if (!node) {
+ node = rb_first_cached(&air_sched->active_txqs);
+ first = true;
+ } else {
+ node = rb_next(node);
+ }
+
+ if (!node)
goto out;
- if (txqi == head) {
- if (!found_eligible_txq)
- goto out;
- else
- found_eligible_txq = false;
+ txqi = container_of(node, struct txq_info, schedule_order);
+ air_info = to_airtime_info(&txqi->txq);
+
+ if (air_info->v_t > air_sched->v_t &&
+ (!first || !airtime_catchup_v_t(air_sched, air_info->v_t, now)))
+ goto out;
+
+ if (!ieee80211_txq_airtime_check(hw, &txqi->txq)) {
+ first = false;
+ goto begin;
}
- if (!head)
- head = txqi;
+ air_sched->schedule_pos = node;
+ air_sched->last_schedule_activity = now;
+ ret = &txqi->txq;
+out:
+ spin_unlock_bh(&air_sched->lock);
+ return ret;
+}
+EXPORT_SYMBOL(ieee80211_next_txq);
- if (txqi->txq.sta) {
- struct sta_info *sta = container_of(txqi->txq.sta,
- struct sta_info, sta);
- bool aql_check = ieee80211_txq_airtime_check(hw, &txqi->txq);
- s64 deficit = sta->airtime[txqi->txq.ac].deficit;
+static void __ieee80211_insert_txq(struct rb_root_cached *root,
+ struct txq_info *txqi)
+{
+ struct rb_node **new = &root->rb_root.rb_node;
+ struct airtime_info *old_air, *new_air;
+ struct rb_node *parent = NULL;
+ struct txq_info *__txqi;
+ bool leftmost = true;
+
+ while (*new) {
+ parent = *new;
+ __txqi = rb_entry(parent, struct txq_info, schedule_order);
+ old_air = to_airtime_info(&__txqi->txq);
+ new_air = to_airtime_info(&txqi->txq);
- if (aql_check)
- found_eligible_txq = true;
+ if (new_air->v_t <= old_air->v_t) {
+ new = &parent->rb_left;
+ } else {
+ new = &parent->rb_right;
+ leftmost = false;
+ }
+ }
- if (deficit < 0)
- sta->airtime[txqi->txq.ac].deficit +=
- sta->airtime_weight;
-
- if (deficit < 0 || !aql_check) {
- list_move_tail(&txqi->schedule_order,
- &local->active_txqs[txqi->txq.ac]);
- goto begin;
+ rb_link_node(&txqi->schedule_order, parent, new);
+ rb_insert_color_cached(&txqi->schedule_order, root, leftmost);
+}
+
+void ieee80211_resort_txq(struct ieee80211_hw *hw,
+ struct ieee80211_txq *txq)
+{
+ struct airtime_info *air_info = to_airtime_info(txq);
+ struct ieee80211_local *local = hw_to_local(hw);
+ struct txq_info *txqi = to_txq_info(txq);
+ struct airtime_sched_info *air_sched;
+
+ air_sched = &local->airtime[txq->ac];
+
+ lockdep_assert_held(&air_sched->lock);
+
+ if (!RB_EMPTY_NODE(&txqi->schedule_order)) {
+ struct airtime_info *a_prev = NULL, *a_next = NULL;
+ struct txq_info *t_prev, *t_next;
+ struct rb_node *n_prev, *n_next;
+
+ /* Erasing a node can cause an expensive rebalancing operation,
+ * so we check the previous and next nodes first and only remove
+ * and re-insert if the current node is not already in the
+ * correct position.
+ */
+ if ((n_prev = rb_prev(&txqi->schedule_order)) != NULL) {
+ t_prev = container_of(n_prev, struct txq_info,
+ schedule_order);
+ a_prev = to_airtime_info(&t_prev->txq);
+ }
+
+ if ((n_next = rb_next(&txqi->schedule_order)) != NULL) {
+ t_next = container_of(n_next, struct txq_info,
+ schedule_order);
+ a_next = to_airtime_info(&t_next->txq);
}
+
+ if ((!a_prev || a_prev->v_t <= air_info->v_t) &&
+ (!a_next || a_next->v_t > air_info->v_t))
+ return;
+
+ if (air_sched->schedule_pos == &txqi->schedule_order)
+ air_sched->schedule_pos = n_prev;
+
+ rb_erase_cached(&txqi->schedule_order,
+ &air_sched->active_txqs);
+ RB_CLEAR_NODE(&txqi->schedule_order);
+ __ieee80211_insert_txq(&air_sched->active_txqs, txqi);
}
+}
+
+void ieee80211_update_airtime_weight(struct ieee80211_local *local,
+ struct airtime_sched_info *air_sched,
+ u64 now, bool force)
+{
+ struct airtime_info *air_info, *tmp;
+ u64 weight_sum = 0;
+
+ if (unlikely(!now))
+ now = ktime_get_boottime_ns();
+
+ lockdep_assert_held(&air_sched->lock);
+
+ if (!force && (air_sched->last_weight_update <
+ now - AIRTIME_ACTIVE_DURATION))
+ return;
+
+ list_for_each_entry_safe(air_info, tmp,
+ &air_sched->active_list, list) {
+ if (airtime_is_active(air_info, now))
+ weight_sum += air_info->weight;
+ else
+ list_del_init(&air_info->list);
+ }
+ airtime_weight_sum_set(air_sched, weight_sum);
+ air_sched->last_weight_update = now;
+}
+void ieee80211_schedule_txq(struct ieee80211_hw *hw,
+ struct ieee80211_txq *txq)
+ __acquires(txq_lock) __releases(txq_lock)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+ struct txq_info *txqi = to_txq_info(txq);
+ struct airtime_sched_info *air_sched;
+ u64 now = ktime_get_boottime_ns();
+ struct airtime_info *air_info;
+ u8 ac = txq->ac;
+ bool was_active;
- if (txqi->schedule_round == local->schedule_round[ac])
+ air_sched = &local->airtime[ac];
+ air_info = to_airtime_info(txq);
+
+ spin_lock_bh(&air_sched->lock);
+ was_active = airtime_is_active(air_info, now);
+ airtime_set_active(air_sched, air_info, now);
+
+ if (!RB_EMPTY_NODE(&txqi->schedule_order))
goto out;
- list_del_init(&txqi->schedule_order);
- txqi->schedule_round = local->schedule_round[ac];
- ret = &txqi->txq;
+ /* If the station has been inactive for a while, catch up its v_t so it
+ * doesn't get indefinite priority; see comment above the definition of
+ * AIRTIME_MAX_BEHIND.
+ */
+ if ((!was_active && air_info->v_t < air_sched->v_t) ||
+ air_info->v_t < air_sched->v_t - AIRTIME_MAX_BEHIND)
+ air_info->v_t = air_sched->v_t;
+
+ ieee80211_update_airtime_weight(local, air_sched, now, !was_active);
+ __ieee80211_insert_txq(&air_sched->active_txqs, txqi);
out:
- spin_unlock_bh(&local->active_txq_lock[ac]);
- return ret;
+ spin_unlock_bh(&air_sched->lock);
}
-EXPORT_SYMBOL(ieee80211_next_txq);
+EXPORT_SYMBOL(ieee80211_schedule_txq);
-void __ieee80211_schedule_txq(struct ieee80211_hw *hw,
- struct ieee80211_txq *txq,
- bool force)
+static void __ieee80211_unschedule_txq(struct ieee80211_hw *hw,
+ struct ieee80211_txq *txq,
+ bool purge)
{
struct ieee80211_local *local = hw_to_local(hw);
struct txq_info *txqi = to_txq_info(txq);
+ struct airtime_sched_info *air_sched;
+ struct airtime_info *air_info;
- spin_lock_bh(&local->active_txq_lock[txq->ac]);
+ air_sched = &local->airtime[txq->ac];
+ air_info = to_airtime_info(&txqi->txq);
- if (list_empty(&txqi->schedule_order) &&
- (force || !skb_queue_empty(&txqi->frags) ||
- txqi->tin.backlog_packets)) {
- /* If airtime accounting is active, always enqueue STAs at the
- * head of the list to ensure that they only get moved to the
- * back by the airtime DRR scheduler once they have a negative
- * deficit. A station that already has a negative deficit will
- * get immediately moved to the back of the list on the next
- * call to ieee80211_next_txq().
- */
- if (txqi->txq.sta && local->airtime_flags &&
- wiphy_ext_feature_isset(local->hw.wiphy,
- NL80211_EXT_FEATURE_AIRTIME_FAIRNESS))
- list_add(&txqi->schedule_order,
- &local->active_txqs[txq->ac]);
- else
- list_add_tail(&txqi->schedule_order,
- &local->active_txqs[txq->ac]);
+ lockdep_assert_held(&air_sched->lock);
+
+ if (purge) {
+ list_del_init(&air_info->list);
+ ieee80211_update_airtime_weight(local, air_sched, 0, true);
}
- spin_unlock_bh(&local->active_txq_lock[txq->ac]);
+ if (RB_EMPTY_NODE(&txqi->schedule_order))
+ return;
+
+ if (air_sched->schedule_pos == &txqi->schedule_order)
+ air_sched->schedule_pos = rb_prev(&txqi->schedule_order);
+
+ if (!purge)
+ airtime_set_active(air_sched, air_info,
+ ktime_get_boottime_ns());
+
+ rb_erase_cached(&txqi->schedule_order,
+ &air_sched->active_txqs);
+ RB_CLEAR_NODE(&txqi->schedule_order);
+}
+
+void ieee80211_unschedule_txq(struct ieee80211_hw *hw,
+ struct ieee80211_txq *txq,
+ bool purge)
+ __acquires(txq_lock) __releases(txq_lock)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+
+ spin_lock_bh(&local->airtime[txq->ac].lock);
+ __ieee80211_unschedule_txq(hw, txq, purge);
+ spin_unlock_bh(&local->airtime[txq->ac].lock);
+}
+
+void ieee80211_return_txq(struct ieee80211_hw *hw,
+ struct ieee80211_txq *txq, bool force)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+ struct txq_info *txqi = to_txq_info(txq);
+
+ spin_lock_bh(&local->airtime[txq->ac].lock);
+
+ if (!RB_EMPTY_NODE(&txqi->schedule_order) && !force &&
+ !txq_has_queue(txq))
+ __ieee80211_unschedule_txq(hw, txq, false);
+
+ spin_unlock_bh(&local->airtime[txq->ac].lock);
}
-EXPORT_SYMBOL(__ieee80211_schedule_txq);
+EXPORT_SYMBOL(ieee80211_return_txq);
DEFINE_STATIC_KEY_FALSE(aql_disable);
bool ieee80211_txq_airtime_check(struct ieee80211_hw *hw,
struct ieee80211_txq *txq)
{
- struct sta_info *sta;
+ struct airtime_info *air_info = to_airtime_info(txq);
struct ieee80211_local *local = hw_to_local(hw);
if (!wiphy_ext_feature_isset(local->hw.wiphy, NL80211_EXT_FEATURE_AQL))
@@ -3922,15 +4078,12 @@ bool ieee80211_txq_airtime_check(struct
if (unlikely(txq->tid == IEEE80211_NUM_TIDS))
return true;
- sta = container_of(txq->sta, struct sta_info, sta);
- if (atomic_read(&sta->airtime[txq->ac].aql_tx_pending) <
- sta->airtime[txq->ac].aql_limit_low)
+ if (atomic_read(&air_info->aql_tx_pending) < air_info->aql_limit_low)
return true;
if (atomic_read(&local->aql_total_pending_airtime) <
local->aql_threshold &&
- atomic_read(&sta->airtime[txq->ac].aql_tx_pending) <
- sta->airtime[txq->ac].aql_limit_high)
+ atomic_read(&air_info->aql_tx_pending) < air_info->aql_limit_high)
return true;
return false;
@@ -3940,60 +4093,59 @@ EXPORT_SYMBOL(ieee80211_txq_airtime_chec
bool ieee80211_txq_may_transmit(struct ieee80211_hw *hw,
struct ieee80211_txq *txq)
{
+ struct txq_info *first_txqi = NULL, *txqi = to_txq_info(txq);
struct ieee80211_local *local = hw_to_local(hw);
- struct txq_info *iter, *tmp, *txqi = to_txq_info(txq);
- struct sta_info *sta;
- u8 ac = txq->ac;
+ struct airtime_sched_info *air_sched;
+ struct airtime_info *air_info;
+ struct rb_node *node = NULL;
+ bool ret = false;
+ u64 now;
- spin_lock_bh(&local->active_txq_lock[ac]);
- if (!txqi->txq.sta)
- goto out;
+ if (!ieee80211_txq_airtime_check(hw, txq))
+ return false;
+
+ air_sched = &local->airtime[txq->ac];
+ spin_lock_bh(&air_sched->lock);
- if (list_empty(&txqi->schedule_order))
+ if (RB_EMPTY_NODE(&txqi->schedule_order))
goto out;
- list_for_each_entry_safe(iter, tmp, &local->active_txqs[ac],
- schedule_order) {
- if (iter == txqi)
- break;
+ now = ktime_get_boottime_ns();
- if (!iter->txq.sta) {
- list_move_tail(&iter->schedule_order,
- &local->active_txqs[ac]);
- continue;
- }
- sta = container_of(iter->txq.sta, struct sta_info, sta);
- if (sta->airtime[ac].deficit < 0)
- sta->airtime[ac].deficit += sta->airtime_weight;
- list_move_tail(&iter->schedule_order, &local->active_txqs[ac]);
+ /* Like in ieee80211_next_txq(), make sure the first station in the
+ * scheduling order is eligible for transmission to avoid starvation.
+ */
+ node = rb_first_cached(&air_sched->active_txqs);
+ if (node) {
+ first_txqi = container_of(node, struct txq_info,
+ schedule_order);
+ air_info = to_airtime_info(&first_txqi->txq);
+
+ if (air_sched->v_t < air_info->v_t)
+ airtime_catchup_v_t(air_sched, air_info->v_t, now);
}
- sta = container_of(txqi->txq.sta, struct sta_info, sta);
- if (sta->airtime[ac].deficit >= 0)
- goto out;
-
- sta->airtime[ac].deficit += sta->airtime_weight;
- list_move_tail(&txqi->schedule_order, &local->active_txqs[ac]);
- spin_unlock_bh(&local->active_txq_lock[ac]);
+ air_info = to_airtime_info(&txqi->txq);
+ if (air_info->v_t <= air_sched->v_t) {
+ air_sched->last_schedule_activity = now;
+ ret = true;
+ }
- return false;
out:
- if (!list_empty(&txqi->schedule_order))
- list_del_init(&txqi->schedule_order);
- spin_unlock_bh(&local->active_txq_lock[ac]);
-
- return true;
+ spin_unlock_bh(&air_sched->lock);
+ return ret;
}
EXPORT_SYMBOL(ieee80211_txq_may_transmit);
void ieee80211_txq_schedule_start(struct ieee80211_hw *hw, u8 ac)
{
struct ieee80211_local *local = hw_to_local(hw);
+ struct airtime_sched_info *air_sched = &local->airtime[ac];
- spin_lock_bh(&local->active_txq_lock[ac]);
- local->schedule_round[ac]++;
- spin_unlock_bh(&local->active_txq_lock[ac]);
+ spin_lock_bh(&air_sched->lock);
+ air_sched->schedule_pos = NULL;
+ spin_unlock_bh(&air_sched->lock);
}
EXPORT_SYMBOL(ieee80211_txq_schedule_start);

View File

@ -1,26 +0,0 @@
From: Ryder Lee <ryder.lee@mediatek.com>
Date: Fri, 18 Jun 2021 04:38:59 +0800
Subject: [PATCH] mac80211: check per vif offload_flags in Tx path
offload_flags has been introduced to indicate encap status of each interface.
An interface can encap offload at runtime, or if it has some extra limitations
it can simply override the flags, so it's more flexible to check offload_flags
in Tx path.
Signed-off-by: Ryder Lee <ryder.lee@mediatek.com>
Link: https://lore.kernel.org/r/177785418cf407808bf3a44760302d0647076990.1623961575.git.ryder.lee@mediatek.com
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -3318,6 +3318,9 @@ static bool ieee80211_amsdu_aggregate(st
if (!ieee80211_hw_check(&local->hw, TX_AMSDU))
return false;
+ if (sdata->vif.offload_flags & IEEE80211_OFFLOAD_ENCAP_ENABLED)
+ return false;
+
if (skb_is_gso(skb))
return false;

View File

@ -23,8 +23,8 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1253,6 +1253,27 @@ struct cfg80211_csa_settings {
#define CFG80211_MAX_NUM_DIFFERENT_CHANNELS 10
@@ -1258,6 +1258,27 @@ struct cfg80211_csa_settings {
};
/**
+ * struct cfg80211_color_change_settings - color change settings
@ -51,7 +51,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
* struct iface_combination_params - input parameters for interface combinations
*
* Used to pass interface combination parameters
@@ -3991,6 +4012,8 @@ struct mgmt_frame_regs {
@@ -4000,6 +4021,8 @@ struct mgmt_frame_regs {
* given TIDs. This callback may sleep.
*
* @set_sar_specs: Update the SAR (TX power) settings.
@ -60,7 +60,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
*/
struct cfg80211_ops {
int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@@ -4318,6 +4341,9 @@ struct cfg80211_ops {
@@ -4327,6 +4350,9 @@ struct cfg80211_ops {
const u8 *peer, u8 tids);
int (*set_sar_specs)(struct wiphy *wiphy,
struct cfg80211_sar_specs *sar);
@ -70,7 +70,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
};
/*
@@ -8209,4 +8235,70 @@ void cfg80211_update_owe_info_event(stru
@@ -8226,4 +8252,70 @@ void cfg80211_update_owe_info_event(stru
*/
void cfg80211_bss_flush(struct wiphy *wiphy);
@ -210,7 +210,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -5950,6 +5989,9 @@ enum nl80211_feature_flags {
@@ -5953,6 +5992,9 @@ enum nl80211_feature_flags {
* frame protection for all management frames exchanged during the
* negotiation and range measurement procedure.
*
@ -220,7 +220,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
* @NUM_NL80211_EXT_FEATURES: number of extended features.
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
*/
@@ -6014,6 +6056,7 @@ enum nl80211_ext_feature_index {
@@ -6017,6 +6059,7 @@ enum nl80211_ext_feature_index {
NL80211_EXT_FEATURE_SECURE_LTF,
NL80211_EXT_FEATURE_SECURE_RTT,
NL80211_EXT_FEATURE_PROT_RANGE_NEGO_AND_MEASURE,
@ -241,7 +241,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
};
/* policy for the key attributes */
@@ -14815,6 +14819,106 @@ bad_tid_conf:
@@ -14823,6 +14827,106 @@ bad_tid_conf:
return ret;
}
@ -348,7 +348,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
#define NL80211_FLAG_NEED_WIPHY 0x01
#define NL80211_FLAG_NEED_NETDEV 0x02
#define NL80211_FLAG_NEED_RTNL 0x04
@@ -15815,6 +15919,14 @@ static const struct genl_small_ops nl802
@@ -15823,6 +15927,14 @@ static const struct genl_small_ops nl802
.internal_flags = NL80211_FLAG_NEED_WIPHY |
NL80211_FLAG_NEED_RTNL,
},
@ -363,7 +363,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
};
static struct genl_family nl80211_fam __genl_ro_after_init = {
@@ -17446,6 +17558,51 @@ void cfg80211_ch_switch_started_notify(s
@@ -17454,6 +17566,51 @@ void cfg80211_ch_switch_started_notify(s
}
EXPORT_SYMBOL(cfg80211_ch_switch_started_notify);
@ -417,7 +417,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
const struct cfg80211_chan_def *chandef,
--- a/net/wireless/rdev-ops.h
+++ b/net/wireless/rdev-ops.h
@@ -1358,4 +1358,17 @@ static inline int rdev_set_sar_specs(str
@@ -1368,4 +1368,17 @@ static inline int rdev_set_sar_specs(str
return ret;
}
@ -437,7 +437,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
#endif /* __CFG80211_RDEV_OPS */
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -3565,6 +3565,52 @@ TRACE_EVENT(rdev_set_sar_specs,
@@ -3597,6 +3597,52 @@ TRACE_EVENT(rdev_set_sar_specs,
WIPHY_PR_ARG, __entry->type, __entry->num)
);

View File

@ -19,7 +19,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1713,6 +1713,10 @@ enum ieee80211_offload_flags {
@@ -1715,6 +1715,10 @@ enum ieee80211_offload_flags {
* protected by fq->lock.
* @offload_flags: 802.3 -> 802.11 enapsulation offload flags, see
* &enum ieee80211_offload_flags.
@ -30,7 +30,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
*/
struct ieee80211_vif {
enum nl80211_iftype type;
@@ -1741,6 +1745,9 @@ struct ieee80211_vif {
@@ -1743,6 +1747,9 @@ struct ieee80211_vif {
bool txqs_stopped[IEEE80211_NUM_ACS];
@ -40,7 +40,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
/* must be last */
u8 drv_priv[] __aligned(sizeof(void *));
};
@@ -4992,6 +4999,16 @@ void ieee80211_csa_finish(struct ieee802
@@ -5016,6 +5023,16 @@ void ieee80211_csa_finish(struct ieee802
bool ieee80211_beacon_cntdwn_is_complete(struct ieee80211_vif *vif);
/**
@ -57,7 +57,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
* ieee80211_proberesp_get - retrieve a Probe Response template
* @hw: pointer obtained from ieee80211_alloc_hw().
* @vif: &struct ieee80211_vif pointer from the add_interface callback.
@@ -6756,6 +6773,18 @@ ieee80211_get_unsol_bcast_probe_resp_tmp
@@ -6780,6 +6797,18 @@ ieee80211_get_unsol_bcast_probe_resp_tmp
struct ieee80211_vif *vif);
/**
@ -161,7 +161,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
if (err < 0)
return err;
ieee80211_bss_info_change_notify(sdata, err);
@@ -3163,7 +3171,7 @@ static int ieee80211_set_after_csa_beaco
@@ -3155,7 +3163,7 @@ static int ieee80211_set_after_csa_beaco
switch (sdata->vif.type) {
case NL80211_IFTYPE_AP:
err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon,
@ -170,7 +170,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
kfree(sdata->u.ap.next_beacon);
sdata->u.ap.next_beacon = NULL;
@@ -3329,7 +3337,7 @@ static int ieee80211_set_csa_beacon(stru
@@ -3321,7 +3329,7 @@ static int ieee80211_set_csa_beacon(stru
csa.n_counter_offsets_presp = params->n_counter_offsets_presp;
csa.count = params->count;
@ -179,7 +179,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
if (err < 0) {
kfree(sdata->u.ap.next_beacon);
return err;
@@ -3418,6 +3426,15 @@ static int ieee80211_set_csa_beacon(stru
@@ -3410,6 +3418,15 @@ static int ieee80211_set_csa_beacon(stru
return 0;
}
@ -195,7 +195,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
static int
__ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_csa_settings *params)
@@ -3486,6 +3503,10 @@ __ieee80211_channel_switch(struct wiphy
@@ -3478,6 +3495,10 @@ __ieee80211_channel_switch(struct wiphy
goto out;
}
@ -206,7 +206,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
err = ieee80211_set_csa_beacon(sdata, params, &changed);
if (err) {
ieee80211_vif_unreserve_chanctx(sdata);
@@ -4137,6 +4158,196 @@ static int ieee80211_set_sar_specs(struc
@@ -4129,6 +4150,196 @@ static int ieee80211_set_sar_specs(struc
return local->ops->set_sar_specs(&local->hw, sar);
}
@ -403,7 +403,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
const struct cfg80211_ops mac80211_config_ops = {
.add_virtual_intf = ieee80211_add_iface,
.del_virtual_intf = ieee80211_del_iface,
@@ -4240,4 +4451,5 @@ const struct cfg80211_ops mac80211_confi
@@ -4232,4 +4443,5 @@ const struct cfg80211_ops mac80211_confi
.set_tid_config = ieee80211_set_tid_config,
.reset_tid_config = ieee80211_reset_tid_config,
.set_sar_specs = ieee80211_set_sar_specs,
@ -433,7 +433,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
struct list_head assigned_chanctx_list; /* protected by chanctx_mtx */
struct list_head reserved_chanctx_list; /* protected by chanctx_mtx */
@@ -1895,6 +1903,9 @@ void ieee80211_csa_finalize_work(struct
@@ -1891,6 +1899,9 @@ void ieee80211_csa_finalize_work(struct
int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_csa_settings *params);
@ -453,7 +453,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
cancel_delayed_work_sync(&sdata->dfs_cac_timer_work);
@@ -1595,6 +1596,7 @@ static void ieee80211_setup_sdata(struct
@@ -1608,6 +1609,7 @@ static void ieee80211_setup_sdata(struct
INIT_WORK(&sdata->work, ieee80211_iface_work);
INIT_WORK(&sdata->recalc_smps, ieee80211_recalc_smps_work);
INIT_WORK(&sdata->csa_finalize_work, ieee80211_csa_finalize_work);
@ -463,7 +463,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -4784,11 +4784,11 @@ static int ieee80211_beacon_add_tim(stru
@@ -4796,11 +4796,11 @@ static int ieee80211_beacon_add_tim(stru
static void ieee80211_set_beacon_cntdwn(struct ieee80211_sub_if_data *sdata,
struct beacon_data *beacon)
{
@ -477,7 +477,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
switch (sdata->vif.type) {
case NL80211_IFTYPE_AP:
@@ -4808,21 +4808,27 @@ static void ieee80211_set_beacon_cntdwn(
@@ -4820,21 +4820,27 @@ static void ieee80211_set_beacon_cntdwn(
}
rcu_read_lock();
@ -514,7 +514,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
}
rcu_read_unlock();
}
@@ -5032,6 +5038,7 @@ __ieee80211_beacon_get(struct ieee80211_
@@ -5044,6 +5050,7 @@ __ieee80211_beacon_get(struct ieee80211_
if (offs) {
offs->tim_offset = beacon->head_len;
offs->tim_length = skb->len - beacon->head_len;

View File

@ -73,7 +73,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
} u;
} __packed action;
} u;
@@ -2879,6 +2925,7 @@ enum ieee80211_eid {
@@ -2881,6 +2927,7 @@ enum ieee80211_eid {
WLAN_EID_AID_RESPONSE = 211,
WLAN_EID_S1G_BCN_COMPAT = 213,
WLAN_EID_S1G_SHORT_BCN_INTERVAL = 214,
@ -81,7 +81,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
WLAN_EID_S1G_CAPABILITIES = 217,
WLAN_EID_VENDOR_SPECIFIC = 221,
WLAN_EID_QOS_PARAMETER = 222,
@@ -2947,6 +2994,7 @@ enum ieee80211_category {
@@ -2950,6 +2997,7 @@ enum ieee80211_category {
WLAN_CATEGORY_FST = 18,
WLAN_CATEGORY_UNPROT_DMG = 20,
WLAN_CATEGORY_VHT = 21,
@ -89,7 +89,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
WLAN_CATEGORY_VENDOR_SPECIFIC_PROTECTED = 126,
WLAN_CATEGORY_VENDOR_SPECIFIC = 127,
};
@@ -3020,6 +3068,20 @@ enum ieee80211_key_len {
@@ -3023,6 +3071,20 @@ enum ieee80211_key_len {
WLAN_KEY_LEN_BIP_GMAC_256 = 32,
};

View File

@ -1,3 +1,4 @@
From f5a4c24e689f54e66201f04d343bdd2e8a1d7923 Mon Sep 17 00:00:00 2001
From: Lorenzo Bianconi <lorenzo@kernel.org>
Date: Mon, 23 Aug 2021 20:02:39 +0200
Subject: [PATCH] mac80211: introduce individual TWT support in AP mode
@ -24,10 +25,33 @@ Link: https://lore.kernel.org/r/257512f2e22ba42b9f2624942a128dd8f141de4b.1629741
fix to use ieee80211_get_he_iftype_cap() correctly]
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
include/net/mac80211.h | 12 +++
net/mac80211/driver-ops.h | 36 ++++++++
net/mac80211/ieee80211_i.h | 6 ++
net/mac80211/iface.c | 41 +++++++++
net/mac80211/rx.c | 73 +++++++++++++++
net/mac80211/s1g.c | 180 +++++++++++++++++++++++++++++++++++++
net/mac80211/status.c | 17 +++-
net/mac80211/trace.h | 67 ++++++++++++++
8 files changed, 430 insertions(+), 2 deletions(-)
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -4229,6 +4229,11 @@ struct ieee80211_ops {
@@ -3930,6 +3930,13 @@ struct ieee80211_prep_tx_info {
* @set_sar_specs: Update the SAR (TX power) settings.
* @sta_set_decap_offload: Called to notify the driver when a station is allowed
* to use rx decapsulation offload
+ * @add_twt_setup: Update hw with TWT agreement parameters received from the peer.
+ * This callback allows the hw to check if requested parameters
+ * are supported and if there is enough room for a new agreement.
+ * The hw is expected to set agreement result in the req_type field of
+ * twt structure.
+ * @twt_teardown_request: Update the hw with TWT teardown request received
+ * from the peer.
*/
struct ieee80211_ops {
void (*tx)(struct ieee80211_hw *hw,
@@ -4253,6 +4260,11 @@ struct ieee80211_ops {
void (*sta_set_decap_offload)(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta, bool enabled);
@ -41,7 +65,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
/**
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -1429,4 +1429,40 @@ static inline void drv_sta_set_decap_off
@@ -1447,4 +1447,40 @@ static inline void drv_sta_set_decap_off
trace_drv_return_void(local);
}
@ -92,7 +116,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
u8 needed_rx_chains;
enum ieee80211_smps_mode smps_mode;
@@ -2088,6 +2089,11 @@ ieee80211_he_op_ie_to_bss_conf(struct ie
@@ -2083,6 +2084,11 @@ ieee80211_he_op_ie_to_bss_conf(struct ie
/* S1G */
void ieee80211_s1g_sta_rate_init(struct sta_info *sta);
@ -122,8 +146,25 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
INIT_WORK(&sdata->work, ieee80211_iface_work);
return 0;
@@ -1396,6 +1398,24 @@ static void ieee80211_if_setup_no_queue(
dev->priv_flags |= IFF_NO_QUEUE;
@@ -1459,6 +1461,16 @@ static void ieee80211_iface_process_skb(
WARN_ON(1);
break;
}
+ } else if (ieee80211_is_action(mgmt->frame_control) &&
+ mgmt->u.action.category == WLAN_CATEGORY_S1G) {
+ switch (mgmt->u.action.u.s1g.action_code) {
+ case WLAN_S1G_TWT_TEARDOWN:
+ case WLAN_S1G_TWT_SETUP:
+ ieee80211_s1g_rx_twt_action(sdata, skb);
+ break;
+ default:
+ break;
+ }
} else if (ieee80211_is_ext(mgmt->frame_control)) {
if (sdata->vif.type == NL80211_IFTYPE_STATION)
ieee80211_sta_rx_queued_ext(sdata, skb);
@@ -1514,6 +1526,24 @@ static void ieee80211_iface_process_skb(
}
}
+static void ieee80211_iface_process_status(struct ieee80211_sub_if_data *sdata,
@ -147,37 +188,24 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
static void ieee80211_iface_work(struct work_struct *work)
{
struct ieee80211_sub_if_data *sdata =
@@ -1474,6 +1494,16 @@ static void ieee80211_iface_work(struct
WARN_ON(1);
break;
}
+ } else if (ieee80211_is_action(mgmt->frame_control) &&
+ mgmt->u.action.category == WLAN_CATEGORY_S1G) {
+ switch (mgmt->u.action.u.s1g.action_code) {
+ case WLAN_S1G_TWT_TEARDOWN:
+ case WLAN_S1G_TWT_SETUP:
+ ieee80211_s1g_rx_twt_action(sdata, skb);
+ break;
+ default:
+ break;
+ }
} else if (ieee80211_is_ext(mgmt->frame_control)) {
if (sdata->vif.type == NL80211_IFTYPE_STATION)
ieee80211_sta_rx_queued_ext(sdata, skb);
@@ -1530,6 +1560,12 @@ static void ieee80211_iface_work(struct
@@ -1543,6 +1573,16 @@ static void ieee80211_iface_work(struct
kcov_remote_stop();
}
+ /* process status queue */
+ while ((skb = skb_dequeue(&sdata->status_queue))) {
+ kcov_remote_start_common(skb_get_kcov_handle(skb));
+
+ ieee80211_iface_process_status(sdata, skb);
+ kfree_skb(skb);
+
+ kcov_remote_stop();
+ }
+
/* then other type-dependent work */
switch (sdata->vif.type) {
case NL80211_IFTYPE_STATION:
@@ -1593,6 +1629,7 @@ static void ieee80211_setup_sdata(struct
@@ -1606,6 +1646,7 @@ static void ieee80211_setup_sdata(struct
}
skb_queue_head_init(&sdata->skb_queue);
@ -187,7 +215,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
INIT_WORK(&sdata->csa_finalize_work, ieee80211_csa_finalize_work);
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -3198,6 +3198,68 @@ ieee80211_rx_h_mgmt_check(struct ieee802
@@ -3211,6 +3211,68 @@ ieee80211_rx_h_mgmt_check(struct ieee802
return RX_CONTINUE;
}
@ -256,7 +284,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
static ieee80211_rx_result debug_noinline
ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
{
@@ -3477,6 +3539,17 @@ ieee80211_rx_h_action(struct ieee80211_r
@@ -3490,6 +3552,17 @@ ieee80211_rx_h_action(struct ieee80211_r
!mesh_path_sel_is_hwmp(sdata))
break;
goto queue;
@ -500,7 +528,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
rcu_read_unlock();
--- a/net/mac80211/trace.h
+++ b/net/mac80211/trace.h
@@ -2804,6 +2804,73 @@ DEFINE_EVENT(sta_flag_evt, drv_sta_set_d
@@ -2825,6 +2825,73 @@ DEFINE_EVENT(sta_flag_evt, drv_sta_set_d
TP_ARGS(local, sdata, sta, enabled)
);

View File

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

View File

@ -1,6 +1,6 @@
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -3826,6 +3826,7 @@ struct mgmt_frame_regs {
@@ -3835,6 +3835,7 @@ struct mgmt_frame_regs {
* (as advertised by the nl80211 feature flag.)
* @get_tx_power: store the current TX power into the dbm variable;
* return 0 if successful
@ -8,7 +8,7 @@
*
* @rfkill_poll: polls the hw rfkill line, use cfg80211 reporting
* functions to adjust rfkill hw state
@@ -4150,6 +4151,7 @@ struct cfg80211_ops {
@@ -4159,6 +4160,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);
@ -18,7 +18,7 @@
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1564,6 +1564,7 @@ enum ieee80211_smps_mode {
@@ -1566,6 +1566,7 @@ enum ieee80211_smps_mode {
*
* @power_level: requested transmit power (in dBm), backward compatibility
* value only that is set to the minimum of all interfaces
@ -26,7 +26,7 @@
*
* @chandef: the channel definition to tune to
* @radar_enabled: whether radar detection is enabled
@@ -1584,6 +1585,7 @@ enum ieee80211_smps_mode {
@@ -1586,6 +1587,7 @@ enum ieee80211_smps_mode {
struct ieee80211_conf {
u32 flags;
int power_level, dynamic_ps_timeout;
@ -57,7 +57,7 @@
__NL80211_ATTR_AFTER_LAST,
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -2768,6 +2768,19 @@ static int ieee80211_get_tx_power(struct
@@ -2760,6 +2760,19 @@ static int ieee80211_get_tx_power(struct
return 0;
}
@ -77,7 +77,7 @@
static void ieee80211_rfkill_poll(struct wiphy *wiphy)
{
struct ieee80211_local *local = wiphy_priv(wiphy);
@@ -4403,6 +4416,7 @@ const struct cfg80211_ops mac80211_confi
@@ -4395,6 +4408,7 @@ const struct cfg80211_ops mac80211_confi
.set_wiphy_params = ieee80211_set_wiphy_params,
.set_tx_power = ieee80211_set_tx_power,
.get_tx_power = ieee80211_get_tx_power,
@ -137,7 +137,7 @@
};
/* policy for the key attributes */
@@ -3317,6 +3318,20 @@ static int nl80211_set_wiphy(struct sk_b
@@ -3325,6 +3326,20 @@ static int nl80211_set_wiphy(struct sk_b
goto out;
}

View File

@ -1,5 +1,14 @@
--- a/nl80211.h
+++ b/nl80211.h
@@ -11,7 +11,7 @@
* Copyright 2008 Jouni Malinen <jouni.malinen@atheros.com>
* Copyright 2008 Colin McCabe <colin@cozybit.com>
* Copyright 2015-2017 Intel Deutschland GmbH
- * Copyright (C) 2018-2020 Intel Corporation
+ * Copyright (C) 2018-2021 Intel Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -655,6 +655,9 @@
* When a security association was established on an 802.1X network using
* fast transition, this event should be followed by an
@ -160,7 +169,24 @@
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -5896,6 +5981,22 @@ enum nl80211_feature_flags {
@@ -3613,6 +3698,8 @@ enum nl80211_mpath_info {
* defined
* @NL80211_BAND_IFTYPE_ATTR_HE_6GHZ_CAPA: HE 6GHz band capabilities (__le16),
* given for all 6 GHz band channels
+ * @NL80211_BAND_IFTYPE_ATTR_VENDOR_ELEMS: vendor element capabilities that are
+ * advertised on this band/for this iftype (binary)
* @__NL80211_BAND_IFTYPE_ATTR_AFTER_LAST: internal use
*/
enum nl80211_band_iftype_attr {
@@ -3624,6 +3711,7 @@ enum nl80211_band_iftype_attr {
NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET,
NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE,
NL80211_BAND_IFTYPE_ATTR_HE_6GHZ_CAPA,
+ NL80211_BAND_IFTYPE_ATTR_VENDOR_ELEMS,
/* keep last */
__NL80211_BAND_IFTYPE_ATTR_AFTER_LAST,
@@ -5896,6 +5984,22 @@ enum nl80211_feature_flags {
* @NL80211_EXT_FEATURE_UNSOL_BCAST_PROBE_RESP: Driver/device supports
* unsolicited broadcast probe response transmission
*
@ -183,7 +209,7 @@
* @NUM_NL80211_EXT_FEATURES: number of extended features.
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
*/
@@ -5956,6 +6057,11 @@ enum nl80211_ext_feature_index {
@@ -5956,6 +6060,11 @@ enum nl80211_ext_feature_index {
NL80211_EXT_FEATURE_SAE_OFFLOAD_AP,
NL80211_EXT_FEATURE_FILS_DISCOVERY,
NL80211_EXT_FEATURE_UNSOL_BCAST_PROBE_RESP,
@ -195,7 +221,7 @@
/* add new features before the definition below */
NUM_NL80211_EXT_FEATURES,
@@ -6253,11 +6359,13 @@ struct nl80211_vendor_cmd_info {
@@ -6253,11 +6362,13 @@ struct nl80211_vendor_cmd_info {
* @NL80211_TDLS_PEER_HT: TDLS peer is HT capable.
* @NL80211_TDLS_PEER_VHT: TDLS peer is VHT capable.
* @NL80211_TDLS_PEER_WMM: TDLS peer is WMM capable.
@ -209,25 +235,29 @@
};
/**
@@ -6849,6 +6957,9 @@ enum nl80211_peer_measurement_ftm_capa {
@@ -6849,6 +6960,12 @@ enum nl80211_peer_measurement_ftm_capa {
* if neither %NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED nor
* %NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED is set, EDCA based
* ranging will be used.
+ * @NL80211_PMSR_FTM_REQ_ATTR_LMR_FEEDBACK: negotiate for LMR feedback. Only
+ * valid if either %NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED or
+ * %NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED is set.
+ * @NL80211_PMSR_FTM_REQ_ATTR_BSS_COLOR: optional. The BSS color of the
+ * responder. Only valid if %NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED
+ * or %NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED is set.
*
* @NUM_NL80211_PMSR_FTM_REQ_ATTR: internal
* @NL80211_PMSR_FTM_REQ_ATTR_MAX: highest attribute number
@@ -6867,6 +6978,7 @@ enum nl80211_peer_measurement_ftm_req {
@@ -6867,6 +6984,8 @@ enum nl80211_peer_measurement_ftm_req {
NL80211_PMSR_FTM_REQ_ATTR_REQUEST_CIVICLOC,
NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED,
NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED,
+ NL80211_PMSR_FTM_REQ_ATTR_LMR_FEEDBACK,
+ NL80211_PMSR_FTM_REQ_ATTR_BSS_COLOR,
/* keep last */
NUM_NL80211_PMSR_FTM_REQ_ATTR,
@@ -7124,4 +7236,115 @@ enum nl80211_unsol_bcast_probe_resp_attr
@@ -7124,4 +7243,115 @@ enum nl80211_unsol_bcast_probe_resp_attr
NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_MAX =
__NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_LAST - 1
};