mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-20 06:08:08 +00:00
mac80211: add airtime fairness improvements
This reverts the airtime scheduler back from the virtual-time based scheduler
to the deficit round robin scheduler implementation.
This reduces burstiness and improves fairness by improving interaction with AQL.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
(cherry-picked from commit 6d49a25804
)
This commit is contained in:
parent
a4390ea283
commit
aab535d2bb
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,52 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Mon, 20 Jun 2022 14:53:04 +0200
|
||||
Subject: [PATCH] mac80211: make sta airtime deficit field s32 instead of
|
||||
s64
|
||||
|
||||
32 bit is more than enough range for the airtime deficit
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- 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];
|
||||
+ s32 deficit[IEEE80211_NUM_ACS];
|
||||
ssize_t rv;
|
||||
int ac;
|
||||
|
||||
@@ -219,7 +219,7 @@ static ssize_t sta_airtime_read(struct f
|
||||
|
||||
p += scnprintf(p, bufsz + buf - p,
|
||||
"RX: %llu us\nTX: %llu us\nWeight: %u\n"
|
||||
- "Deficit: VO: %lld us VI: %lld us BE: %lld us BK: %lld us\n",
|
||||
+ "Deficit: VO: %d us VI: %d us BE: %d us BK: %d us\n",
|
||||
rx_airtime, tx_airtime, sta->airtime_weight,
|
||||
deficit[0], deficit[1], deficit[2], deficit[3]);
|
||||
|
||||
--- a/net/mac80211/sta_info.h
|
||||
+++ b/net/mac80211/sta_info.h
|
||||
@@ -138,7 +138,7 @@ enum ieee80211_agg_stop_reason {
|
||||
struct airtime_info {
|
||||
u64 rx_airtime;
|
||||
u64 tx_airtime;
|
||||
- s64 deficit;
|
||||
+ s32 deficit;
|
||||
atomic_t aql_tx_pending; /* Estimated airtime for frames pending */
|
||||
u32 aql_limit_low;
|
||||
u32 aql_limit_high;
|
||||
--- a/net/mac80211/tx.c
|
||||
+++ b/net/mac80211/tx.c
|
||||
@@ -3847,7 +3847,7 @@ struct ieee80211_txq *ieee80211_next_txq
|
||||
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;
|
||||
+ s32 deficit = sta->airtime[txqi->txq.ac].deficit;
|
||||
|
||||
if (aql_check)
|
||||
found_eligible_txq = true;
|
@ -0,0 +1,48 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Mon, 20 Jun 2022 14:59:09 +0200
|
||||
Subject: [PATCH] mac80211: consider aql_tx_pending when checking airtime
|
||||
deficit
|
||||
|
||||
When queueing packets for a station, deficit only gets added once the packets
|
||||
have been transmitted, which could be much later. During that time, a lot of
|
||||
temporary unfairness could happen, which could lead to bursty behavior.
|
||||
Fix this by subtracting the aql_tx_pending when checking the deficit in tx
|
||||
scheduling.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/tx.c
|
||||
+++ b/net/mac80211/tx.c
|
||||
@@ -3817,6 +3817,13 @@ out:
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_tx_dequeue);
|
||||
|
||||
+static inline s32 ieee80211_sta_deficit(struct sta_info *sta, u8 ac)
|
||||
+{
|
||||
+ struct airtime_info *air_info = &sta->airtime[ac];
|
||||
+
|
||||
+ return air_info->deficit - atomic_read(&air_info->aql_tx_pending);
|
||||
+}
|
||||
+
|
||||
struct ieee80211_txq *ieee80211_next_txq(struct ieee80211_hw *hw, u8 ac)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
@@ -3847,7 +3854,7 @@ struct ieee80211_txq *ieee80211_next_txq
|
||||
struct sta_info *sta = container_of(txqi->txq.sta,
|
||||
struct sta_info, sta);
|
||||
bool aql_check = ieee80211_txq_airtime_check(hw, &txqi->txq);
|
||||
- s32 deficit = sta->airtime[txqi->txq.ac].deficit;
|
||||
+ s32 deficit = ieee80211_sta_deficit(sta, txqi->txq.ac);
|
||||
|
||||
if (aql_check)
|
||||
found_eligible_txq = true;
|
||||
@@ -3972,7 +3979,7 @@ bool ieee80211_txq_may_transmit(struct i
|
||||
continue;
|
||||
}
|
||||
sta = container_of(iter->txq.sta, struct sta_info, sta);
|
||||
- if (sta->airtime[ac].deficit < 0)
|
||||
+ if (ieee80211_sta_deficit(sta, ac) < 0)
|
||||
sta->airtime[ac].deficit += sta->airtime_weight;
|
||||
list_move_tail(&iter->schedule_order, &local->active_txqs[ac]);
|
||||
}
|
@ -0,0 +1,118 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Mon, 20 Jun 2022 20:52:50 +0200
|
||||
Subject: [PATCH] mac80211: keep recently active tx queues in scheduling
|
||||
list
|
||||
|
||||
This allows proper deficit accounting to ensure that they don't carry their
|
||||
deficit until the next time they become active
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/ieee80211_i.h
|
||||
+++ b/net/mac80211/ieee80211_i.h
|
||||
@@ -83,6 +83,13 @@ extern const u8 ieee80211_ac_to_qos_mask
|
||||
|
||||
#define IEEE80211_MAX_NAN_INSTANCE_ID 255
|
||||
|
||||
+
|
||||
+/*
|
||||
+ * Keep a station's queues on the active list for deficit accounting purposes
|
||||
+ * if it was active or queued during the last 100ms
|
||||
+ */
|
||||
+#define AIRTIME_ACTIVE_DURATION (HZ / 10)
|
||||
+
|
||||
struct ieee80211_bss {
|
||||
u32 device_ts_beacon, device_ts_presp;
|
||||
|
||||
--- a/net/mac80211/sta_info.h
|
||||
+++ b/net/mac80211/sta_info.h
|
||||
@@ -138,6 +138,7 @@ enum ieee80211_agg_stop_reason {
|
||||
struct airtime_info {
|
||||
u64 rx_airtime;
|
||||
u64 tx_airtime;
|
||||
+ u32 last_active;
|
||||
s32 deficit;
|
||||
atomic_t aql_tx_pending; /* Estimated airtime for frames pending */
|
||||
u32 aql_limit_low;
|
||||
--- a/net/mac80211/tx.c
|
||||
+++ b/net/mac80211/tx.c
|
||||
@@ -3824,6 +3824,36 @@ static inline s32 ieee80211_sta_deficit(
|
||||
return air_info->deficit - atomic_read(&air_info->aql_tx_pending);
|
||||
}
|
||||
|
||||
+static void
|
||||
+ieee80211_txq_set_active(struct txq_info *txqi)
|
||||
+{
|
||||
+ struct sta_info *sta;
|
||||
+
|
||||
+ if (!txqi->txq.sta)
|
||||
+ return;
|
||||
+
|
||||
+ sta = container_of(txqi->txq.sta, struct sta_info, sta);
|
||||
+ sta->airtime[txqi->txq.ac].last_active = (u32)jiffies;
|
||||
+}
|
||||
+
|
||||
+static bool
|
||||
+ieee80211_txq_keep_active(struct txq_info *txqi)
|
||||
+{
|
||||
+ struct sta_info *sta;
|
||||
+ u32 diff;
|
||||
+
|
||||
+ if (!txqi->txq.sta)
|
||||
+ return false;
|
||||
+
|
||||
+ sta = container_of(txqi->txq.sta, struct sta_info, sta);
|
||||
+ if (ieee80211_sta_deficit(sta, txqi->txq.ac) >= 0)
|
||||
+ return false;
|
||||
+
|
||||
+ diff = (u32)jiffies - sta->airtime[txqi->txq.ac].last_active;
|
||||
+
|
||||
+ return diff <= AIRTIME_ACTIVE_DURATION;
|
||||
+}
|
||||
+
|
||||
struct ieee80211_txq *ieee80211_next_txq(struct ieee80211_hw *hw, u8 ac)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
@@ -3870,7 +3900,6 @@ struct ieee80211_txq *ieee80211_next_txq
|
||||
}
|
||||
}
|
||||
|
||||
-
|
||||
if (txqi->schedule_round == local->schedule_round[ac])
|
||||
goto out;
|
||||
|
||||
@@ -3890,12 +3919,13 @@ void __ieee80211_schedule_txq(struct iee
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
struct txq_info *txqi = to_txq_info(txq);
|
||||
+ bool has_queue;
|
||||
|
||||
spin_lock_bh(&local->active_txq_lock[txq->ac]);
|
||||
|
||||
+ has_queue = force || txq_has_queue(txq);
|
||||
if (list_empty(&txqi->schedule_order) &&
|
||||
- (force || !skb_queue_empty(&txqi->frags) ||
|
||||
- txqi->tin.backlog_packets)) {
|
||||
+ (has_queue || ieee80211_txq_keep_active(txqi))) {
|
||||
/* 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
|
||||
@@ -3903,7 +3933,7 @@ void __ieee80211_schedule_txq(struct iee
|
||||
* get immediately moved to the back of the list on the next
|
||||
* call to ieee80211_next_txq().
|
||||
*/
|
||||
- if (txqi->txq.sta && local->airtime_flags &&
|
||||
+ if (txqi->txq.sta && local->airtime_flags && has_queue &&
|
||||
wiphy_ext_feature_isset(local->hw.wiphy,
|
||||
NL80211_EXT_FEATURE_AIRTIME_FAIRNESS))
|
||||
list_add(&txqi->schedule_order,
|
||||
@@ -3911,6 +3941,8 @@ void __ieee80211_schedule_txq(struct iee
|
||||
else
|
||||
list_add_tail(&txqi->schedule_order,
|
||||
&local->active_txqs[txq->ac]);
|
||||
+ if (has_queue)
|
||||
+ ieee80211_txq_set_active(txqi);
|
||||
}
|
||||
|
||||
spin_unlock_bh(&local->active_txq_lock[txq->ac]);
|
@ -0,0 +1,131 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Mon, 20 Jun 2022 21:26:34 +0200
|
||||
Subject: [PATCH] mac80211: add a per-PHY AQL limit to improve fairness
|
||||
|
||||
In order to maintain fairness, the amount of queueing needs to be limited
|
||||
beyond the simple per-station AQL budget, otherwise the driver can simply
|
||||
repeatedly do scheduling rounds until all queues that have not used their
|
||||
AQL budget become eligble.
|
||||
|
||||
To be conservative, use the high AQL limit for the first txq and add half
|
||||
of the low AQL for each subsequent queue.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/ieee80211_i.h
|
||||
+++ b/net/mac80211/ieee80211_i.h
|
||||
@@ -1211,6 +1211,7 @@ struct ieee80211_local {
|
||||
u32 aql_txq_limit_high[IEEE80211_NUM_ACS];
|
||||
u32 aql_threshold;
|
||||
atomic_t aql_total_pending_airtime;
|
||||
+ atomic_t aql_ac_pending_airtime[IEEE80211_NUM_ACS];
|
||||
|
||||
const struct ieee80211_ops *ops;
|
||||
|
||||
--- a/net/mac80211/main.c
|
||||
+++ b/net/mac80211/main.c
|
||||
@@ -712,6 +712,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_
|
||||
local->aql_txq_limit_low[i] = IEEE80211_DEFAULT_AQL_TXQ_LIMIT_L;
|
||||
local->aql_txq_limit_high[i] =
|
||||
IEEE80211_DEFAULT_AQL_TXQ_LIMIT_H;
|
||||
+ atomic_set(&local->aql_ac_pending_airtime[i], 0);
|
||||
}
|
||||
|
||||
local->airtime_flags = AIRTIME_USE_TX | AIRTIME_USE_RX;
|
||||
--- a/net/mac80211/sta_info.c
|
||||
+++ b/net/mac80211/sta_info.c
|
||||
@@ -1929,6 +1929,7 @@ void ieee80211_sta_update_pending_airtim
|
||||
&sta->airtime[ac].aql_tx_pending);
|
||||
|
||||
atomic_add(tx_airtime, &local->aql_total_pending_airtime);
|
||||
+ atomic_add(tx_airtime, &local->aql_ac_pending_airtime[ac]);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1940,14 +1941,17 @@ void ieee80211_sta_update_pending_airtim
|
||||
tx_pending, 0);
|
||||
}
|
||||
|
||||
+ atomic_sub(tx_airtime, &local->aql_total_pending_airtime);
|
||||
tx_pending = atomic_sub_return(tx_airtime,
|
||||
- &local->aql_total_pending_airtime);
|
||||
+ &local->aql_ac_pending_airtime[ac]);
|
||||
if (WARN_ONCE(tx_pending < 0,
|
||||
"Device %s AC %d pending airtime underflow: %u, %u",
|
||||
wiphy_name(local->hw.wiphy), ac, tx_pending,
|
||||
- tx_airtime))
|
||||
- atomic_cmpxchg(&local->aql_total_pending_airtime,
|
||||
+ tx_airtime)) {
|
||||
+ atomic_cmpxchg(&local->aql_ac_pending_airtime[ac],
|
||||
tx_pending, 0);
|
||||
+ atomic_sub(tx_pending, &local->aql_total_pending_airtime);
|
||||
+ }
|
||||
}
|
||||
|
||||
int sta_info_move_state(struct sta_info *sta,
|
||||
--- a/net/mac80211/tx.c
|
||||
+++ b/net/mac80211/tx.c
|
||||
@@ -3863,6 +3863,9 @@ struct ieee80211_txq *ieee80211_next_txq
|
||||
|
||||
spin_lock_bh(&local->active_txq_lock[ac]);
|
||||
|
||||
+ if (!local->schedule_round[ac])
|
||||
+ goto out;
|
||||
+
|
||||
begin:
|
||||
txqi = list_first_entry_or_null(&local->active_txqs[ac],
|
||||
struct txq_info,
|
||||
@@ -3984,6 +3987,25 @@ bool ieee80211_txq_airtime_check(struct
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_txq_airtime_check);
|
||||
|
||||
+static bool
|
||||
+ieee80211_txq_schedule_airtime_check(struct ieee80211_local *local, u8 ac)
|
||||
+{
|
||||
+ unsigned int num_txq = 0;
|
||||
+ struct txq_info *txq;
|
||||
+ u32 aql_limit;
|
||||
+
|
||||
+ if (!wiphy_ext_feature_isset(local->hw.wiphy, NL80211_EXT_FEATURE_AQL))
|
||||
+ return true;
|
||||
+
|
||||
+ list_for_each_entry(txq, &local->active_txqs[ac], schedule_order)
|
||||
+ num_txq++;
|
||||
+
|
||||
+ aql_limit = (num_txq - 1) * local->aql_txq_limit_low[ac] / 2 +
|
||||
+ local->aql_txq_limit_high[ac];
|
||||
+
|
||||
+ return atomic_read(&local->aql_ac_pending_airtime[ac]) < aql_limit;
|
||||
+}
|
||||
+
|
||||
bool ieee80211_txq_may_transmit(struct ieee80211_hw *hw,
|
||||
struct ieee80211_txq *txq)
|
||||
{
|
||||
@@ -4000,6 +4022,9 @@ bool ieee80211_txq_may_transmit(struct i
|
||||
if (list_empty(&txqi->schedule_order))
|
||||
goto out;
|
||||
|
||||
+ if (!ieee80211_txq_schedule_airtime_check(local, ac))
|
||||
+ goto out;
|
||||
+
|
||||
list_for_each_entry_safe(iter, tmp, &local->active_txqs[ac],
|
||||
schedule_order) {
|
||||
if (iter == txqi)
|
||||
@@ -4039,7 +4064,15 @@ void ieee80211_txq_schedule_start(struct
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
|
||||
spin_lock_bh(&local->active_txq_lock[ac]);
|
||||
- local->schedule_round[ac]++;
|
||||
+
|
||||
+ if (ieee80211_txq_schedule_airtime_check(local, ac)) {
|
||||
+ local->schedule_round[ac]++;
|
||||
+ if (!local->schedule_round[ac])
|
||||
+ local->schedule_round[ac]++;
|
||||
+ } else {
|
||||
+ local->schedule_round[ac] = 0;
|
||||
+ }
|
||||
+
|
||||
spin_unlock_bh(&local->active_txq_lock[ac]);
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_txq_schedule_start);
|
@ -0,0 +1,58 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Sat, 25 Jun 2022 21:25:40 +0200
|
||||
Subject: [PATCH] mac80211: add debugfs file to display per-phy AQL pending
|
||||
airtime
|
||||
|
||||
Now that the global pending airtime is more relevant for airtime fairness,
|
||||
it makes sense to make it accessible via debugfs for debugging
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/debugfs.c
|
||||
+++ b/net/mac80211/debugfs.c
|
||||
@@ -201,6 +201,36 @@ static const struct file_operations airt
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
+static ssize_t aql_pending_read(struct file *file,
|
||||
+ char __user *user_buf,
|
||||
+ size_t count, loff_t *ppos)
|
||||
+{
|
||||
+ struct ieee80211_local *local = file->private_data;
|
||||
+ char buf[400];
|
||||
+ int len = 0;
|
||||
+
|
||||
+ len = scnprintf(buf, sizeof(buf),
|
||||
+ "AC AQL pending\n"
|
||||
+ "VO %u us\n"
|
||||
+ "VI %u us\n"
|
||||
+ "BE %u us\n"
|
||||
+ "BK %u us\n"
|
||||
+ "total %u us\n",
|
||||
+ atomic_read(&local->aql_ac_pending_airtime[IEEE80211_AC_VO]),
|
||||
+ atomic_read(&local->aql_ac_pending_airtime[IEEE80211_AC_VI]),
|
||||
+ atomic_read(&local->aql_ac_pending_airtime[IEEE80211_AC_BE]),
|
||||
+ atomic_read(&local->aql_ac_pending_airtime[IEEE80211_AC_BK]),
|
||||
+ atomic_read(&local->aql_total_pending_airtime));
|
||||
+ return simple_read_from_buffer(user_buf, count, ppos,
|
||||
+ buf, len);
|
||||
+}
|
||||
+
|
||||
+static const struct file_operations aql_pending_ops = {
|
||||
+ .read = aql_pending_read,
|
||||
+ .open = simple_open,
|
||||
+ .llseek = default_llseek,
|
||||
+};
|
||||
+
|
||||
static ssize_t aql_txq_limit_read(struct file *file,
|
||||
char __user *user_buf,
|
||||
size_t count,
|
||||
@@ -628,6 +658,7 @@ void debugfs_hw_add(struct ieee80211_loc
|
||||
DEBUGFS_ADD(hw_conf);
|
||||
DEBUGFS_ADD_MODE(force_tx_status, 0600);
|
||||
DEBUGFS_ADD_MODE(aql_enable, 0600);
|
||||
+ DEBUGFS_ADD(aql_pending);
|
||||
|
||||
if (local->ops->wake_tx_queue)
|
||||
DEBUGFS_ADD_MODE(aqm, 0600);
|
@ -0,0 +1,36 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Sat, 25 Jun 2022 23:10:19 +0200
|
||||
Subject: [PATCH] mac80211: only accumulate airtime deficit for active
|
||||
clients
|
||||
|
||||
When a client does not generate any local tx activity, accumulating airtime
|
||||
deficit for the round-robin scheduler can be harmful. If this goes on for too
|
||||
long, the deficit could grow quite large, which might cause unreasonable
|
||||
initial latency once the client becomes active
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/sta_info.c
|
||||
+++ b/net/mac80211/sta_info.c
|
||||
@@ -1900,6 +1900,7 @@ void ieee80211_sta_register_airtime(stru
|
||||
struct ieee80211_local *local = sta->sdata->local;
|
||||
u8 ac = ieee80211_ac_from_tid(tid);
|
||||
u32 airtime = 0;
|
||||
+ u32 diff;
|
||||
|
||||
if (sta->local->airtime_flags & AIRTIME_USE_TX)
|
||||
airtime += tx_airtime;
|
||||
@@ -1909,7 +1910,11 @@ void ieee80211_sta_register_airtime(stru
|
||||
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;
|
||||
+
|
||||
+ diff = (u32)jiffies - sta->airtime[ac].last_active;
|
||||
+ if (diff <= AIRTIME_ACTIVE_DURATION)
|
||||
+ sta->airtime[ac].deficit -= airtime;
|
||||
+
|
||||
spin_unlock_bh(&local->active_txq_lock[ac]);
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_sta_register_airtime);
|
@ -57,7 +57,7 @@
|
||||
__NL80211_ATTR_AFTER_LAST,
|
||||
--- a/net/mac80211/cfg.c
|
||||
+++ b/net/mac80211/cfg.c
|
||||
@@ -2845,6 +2845,19 @@ static int ieee80211_get_tx_power(struct
|
||||
@@ -2812,6 +2812,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);
|
||||
@@ -4549,6 +4562,7 @@ const struct cfg80211_ops mac80211_confi
|
||||
@@ -4516,6 +4529,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,
|
||||
@ -87,7 +87,7 @@
|
||||
CFG80211_TESTMODE_DUMP(ieee80211_testmode_dump)
|
||||
--- a/net/mac80211/ieee80211_i.h
|
||||
+++ b/net/mac80211/ieee80211_i.h
|
||||
@@ -1464,6 +1464,7 @@ struct ieee80211_local {
|
||||
@@ -1443,6 +1443,7 @@ struct ieee80211_local {
|
||||
int dynamic_ps_forced_timeout;
|
||||
|
||||
int user_power_level; /* in dBm, for all interfaces */
|
||||
|
Loading…
Reference in New Issue
Block a user