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:
parent
1c0d5ee8e6
commit
cfe0eb7485
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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)
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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) {
|
|
@ -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;
|
|
@ -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 */
|
|
@ -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,
|
|
@ -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! */
|
|
@ -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);
|
||||
|
|
@ -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;
|
||||
|
|
@ -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)
|
||||
);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
@ -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)
|
||||
);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue