mirror of
https://github.com/openwrt/openwrt.git
synced 2025-02-07 11:30:37 +00:00
mac80211: backport the txq scheduling / airtime fairness API
Signed-off-by: Felix Fietkau <nbd@nbd.name>
This commit is contained in:
parent
fb0a80f4cf
commit
04e4b779cc
@ -0,0 +1,292 @@
|
||||
From: =?UTF-8?q?Toke=20H=C3=B8iland-J=C3=B8rgensen?= <toke@toke.dk>
|
||||
Date: Tue, 18 Dec 2018 17:02:06 -0800
|
||||
Subject: [PATCH] mac80211: Add TXQ scheduling API
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
This adds an API to mac80211 to handle scheduling of TXQs. The interface
|
||||
between driver and mac80211 for TXQ handling is changed by adding two new
|
||||
functions: ieee80211_next_txq(), which will return the next TXQ to schedule
|
||||
in the current round-robin rotation, and ieee80211_return_txq(), which the
|
||||
driver uses to indicate that it has finished scheduling a TXQ (which will
|
||||
then be put back in the scheduling rotation if it isn't empty).
|
||||
|
||||
The driver must call ieee80211_txq_schedule_start() at the start of each
|
||||
scheduling session, and ieee80211_txq_schedule_end() at the end. The API
|
||||
then guarantees that the same TXQ is not returned twice in the same
|
||||
session (so a driver can loop on ieee80211_next_txq() without worrying
|
||||
about breaking the loop.
|
||||
|
||||
Usage of the new API is optional, so drivers can be ported one at a time.
|
||||
In this patch, the actual scheduling performed by mac80211 is simple
|
||||
round-robin, but a subsequent commit adds airtime fairness awareness to the
|
||||
scheduler.
|
||||
|
||||
Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
|
||||
[minor kernel-doc fix, propagate sparse locking checks out]
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
---
|
||||
|
||||
--- a/include/net/mac80211.h
|
||||
+++ b/include/net/mac80211.h
|
||||
@@ -107,9 +107,15 @@
|
||||
* The driver is expected to initialize its private per-queue data for stations
|
||||
* and interfaces in the .add_interface and .sta_add ops.
|
||||
*
|
||||
- * The driver can't access the queue directly. To dequeue a frame, it calls
|
||||
- * ieee80211_tx_dequeue(). Whenever mac80211 adds a new frame to a queue, it
|
||||
- * calls the .wake_tx_queue driver op.
|
||||
+ * The driver can't access the queue directly. To dequeue a frame from a
|
||||
+ * txq, it calls ieee80211_tx_dequeue(). Whenever mac80211 adds a new frame to a
|
||||
+ * queue, it calls the .wake_tx_queue driver op.
|
||||
+ *
|
||||
+ * Drivers can optionally delegate responsibility for scheduling queues to
|
||||
+ * mac80211, to take advantage of airtime fairness accounting. In this case, to
|
||||
+ * obtain the next queue to pull frames from, the driver calls
|
||||
+ * ieee80211_next_txq(). The driver is then expected to return the txq using
|
||||
+ * ieee80211_return_txq().
|
||||
*
|
||||
* For AP powersave TIM handling, the driver only needs to indicate if it has
|
||||
* buffered packets in the driver specific data structures by calling
|
||||
@@ -5979,7 +5985,8 @@ void ieee80211_unreserve_tid(struct ieee
|
||||
* ieee80211_tx_dequeue - dequeue a packet from a software tx queue
|
||||
*
|
||||
* @hw: pointer as obtained from ieee80211_alloc_hw()
|
||||
- * @txq: pointer obtained from station or virtual interface
|
||||
+ * @txq: pointer obtained from station or virtual interface, or from
|
||||
+ * ieee80211_next_txq()
|
||||
*
|
||||
* Returns the skb if successful, %NULL if no frame was available.
|
||||
*/
|
||||
@@ -5987,6 +5994,54 @@ struct sk_buff *ieee80211_tx_dequeue(str
|
||||
struct ieee80211_txq *txq);
|
||||
|
||||
/**
|
||||
+ * ieee80211_next_txq - get next tx queue to pull packets from
|
||||
+ *
|
||||
+ * @hw: pointer as obtained from ieee80211_alloc_hw()
|
||||
+ * @ac: AC number to return packets from.
|
||||
+ *
|
||||
+ * Should only be called between calls to ieee80211_txq_schedule_start()
|
||||
+ * and ieee80211_txq_schedule_end().
|
||||
+ * Returns the next txq if successful, %NULL if no queue is eligible. If a txq
|
||||
+ * is returned, it should be returned with ieee80211_return_txq() after the
|
||||
+ * driver has finished scheduling it.
|
||||
+ */
|
||||
+struct ieee80211_txq *ieee80211_next_txq(struct ieee80211_hw *hw, u8 ac);
|
||||
+
|
||||
+/**
|
||||
+ * ieee80211_return_txq - return a TXQ previously acquired by ieee80211_next_txq()
|
||||
+ *
|
||||
+ * @hw: pointer as obtained from ieee80211_alloc_hw()
|
||||
+ * @txq: pointer obtained from station or virtual interface
|
||||
+ *
|
||||
+ * Should only be called between calls to ieee80211_txq_schedule_start()
|
||||
+ * and ieee80211_txq_schedule_end().
|
||||
+ */
|
||||
+void ieee80211_return_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq);
|
||||
+
|
||||
+/**
|
||||
+ * ieee80211_txq_schedule_start - acquire locks for safe scheduling of an AC
|
||||
+ *
|
||||
+ * @hw: pointer as obtained from ieee80211_alloc_hw()
|
||||
+ * @ac: AC number to acquire locks for
|
||||
+ *
|
||||
+ * Acquire locks needed to schedule TXQs from the given AC. Should be called
|
||||
+ * before ieee80211_next_txq() or ieee80211_return_txq().
|
||||
+ */
|
||||
+void ieee80211_txq_schedule_start(struct ieee80211_hw *hw, u8 ac)
|
||||
+ __acquires(txq_lock);
|
||||
+
|
||||
+/**
|
||||
+ * ieee80211_txq_schedule_end - release locks for safe scheduling of an AC
|
||||
+ *
|
||||
+ * @hw: pointer as obtained from ieee80211_alloc_hw()
|
||||
+ * @ac: AC number to acquire locks for
|
||||
+ *
|
||||
+ * Release locks previously acquired by ieee80211_txq_schedule_end().
|
||||
+ */
|
||||
+void ieee80211_txq_schedule_end(struct ieee80211_hw *hw, u8 ac)
|
||||
+ __releases(txq_lock);
|
||||
+
|
||||
+/**
|
||||
* ieee80211_txq_get_depth - get pending frame/byte count of given txq
|
||||
*
|
||||
* The values are not guaranteed to be coherent with regard to each other, i.e.
|
||||
--- a/net/mac80211/agg-tx.c
|
||||
+++ b/net/mac80211/agg-tx.c
|
||||
@@ -229,7 +229,7 @@ ieee80211_agg_start_txq(struct sta_info
|
||||
clear_bit(IEEE80211_TXQ_STOP, &txqi->flags);
|
||||
local_bh_disable();
|
||||
rcu_read_lock();
|
||||
- drv_wake_tx_queue(sta->sdata->local, txqi);
|
||||
+ schedule_and_wake_txq(sta->sdata->local, txqi);
|
||||
rcu_read_unlock();
|
||||
local_bh_enable();
|
||||
}
|
||||
--- a/net/mac80211/driver-ops.h
|
||||
+++ b/net/mac80211/driver-ops.h
|
||||
@@ -1176,6 +1176,15 @@ static inline void drv_wake_tx_queue(str
|
||||
local->ops->wake_tx_queue(&local->hw, &txq->txq);
|
||||
}
|
||||
|
||||
+static inline void schedule_and_wake_txq(struct ieee80211_local *local,
|
||||
+ struct txq_info *txqi)
|
||||
+{
|
||||
+ spin_lock_bh(&local->active_txq_lock[txqi->txq.ac]);
|
||||
+ ieee80211_return_txq(&local->hw, &txqi->txq);
|
||||
+ spin_unlock_bh(&local->active_txq_lock[txqi->txq.ac]);
|
||||
+ drv_wake_tx_queue(local, txqi);
|
||||
+}
|
||||
+
|
||||
static inline int drv_start_nan(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
struct cfg80211_nan_conf *conf)
|
||||
--- a/net/mac80211/ieee80211_i.h
|
||||
+++ b/net/mac80211/ieee80211_i.h
|
||||
@@ -829,6 +829,8 @@ enum txq_info_flags {
|
||||
* 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
|
||||
*/
|
||||
struct txq_info {
|
||||
struct fq_tin tin;
|
||||
@@ -836,6 +838,8 @@ struct txq_info {
|
||||
struct codel_vars def_cvars;
|
||||
struct codel_stats cstats;
|
||||
struct sk_buff_head frags;
|
||||
+ struct list_head schedule_order;
|
||||
+ u16 schedule_round;
|
||||
unsigned long flags;
|
||||
|
||||
/* keep last! */
|
||||
@@ -1127,6 +1131,11 @@ struct ieee80211_local {
|
||||
struct codel_vars *cvars;
|
||||
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];
|
||||
+
|
||||
const struct ieee80211_ops *ops;
|
||||
|
||||
/*
|
||||
--- a/net/mac80211/main.c
|
||||
+++ b/net/mac80211/main.c
|
||||
@@ -652,6 +652,11 @@ struct ieee80211_hw *ieee80211_alloc_hw_
|
||||
spin_lock_init(&local->rx_path_lock);
|
||||
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]);
|
||||
+ }
|
||||
+
|
||||
INIT_LIST_HEAD(&local->chanctx_list);
|
||||
mutex_init(&local->chanctx_mtx);
|
||||
|
||||
--- a/net/mac80211/sta_info.c
|
||||
+++ b/net/mac80211/sta_info.c
|
||||
@@ -1244,7 +1244,7 @@ void ieee80211_sta_ps_deliver_wakeup(str
|
||||
if (!txq_has_queue(sta->sta.txq[i]))
|
||||
continue;
|
||||
|
||||
- drv_wake_tx_queue(local, to_txq_info(sta->sta.txq[i]));
|
||||
+ schedule_and_wake_txq(local, to_txq_info(sta->sta.txq[i]));
|
||||
}
|
||||
}
|
||||
|
||||
--- a/net/mac80211/tx.c
|
||||
+++ b/net/mac80211/tx.c
|
||||
@@ -1441,6 +1441,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);
|
||||
|
||||
txqi->txq.vif = &sdata->vif;
|
||||
|
||||
@@ -1464,6 +1465,9 @@ void ieee80211_txq_purge(struct ieee8021
|
||||
|
||||
fq_tin_reset(fq, tin, fq_skb_free_func);
|
||||
ieee80211_purge_tx_queue(&local->hw, &txqi->frags);
|
||||
+ 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]);
|
||||
}
|
||||
|
||||
void ieee80211_txq_set_params(struct ieee80211_local *local)
|
||||
@@ -1580,7 +1584,7 @@ static bool ieee80211_queue_skb(struct i
|
||||
ieee80211_txq_enqueue(local, txqi, skb);
|
||||
spin_unlock_bh(&fq->lock);
|
||||
|
||||
- drv_wake_tx_queue(local, txqi);
|
||||
+ schedule_and_wake_txq(local, txqi);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -3602,6 +3606,60 @@ out:
|
||||
}
|
||||
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 txq_info *txqi = NULL;
|
||||
+
|
||||
+ lockdep_assert_held(&local->active_txq_lock[ac]);
|
||||
+
|
||||
+ txqi = list_first_entry_or_null(&local->active_txqs[ac],
|
||||
+ struct txq_info,
|
||||
+ schedule_order);
|
||||
+
|
||||
+ if (!txqi || txqi->schedule_round == local->schedule_round[ac])
|
||||
+ return NULL;
|
||||
+
|
||||
+ list_del_init(&txqi->schedule_order);
|
||||
+ txqi->schedule_round = local->schedule_round[ac];
|
||||
+ return &txqi->txq;
|
||||
+}
|
||||
+EXPORT_SYMBOL(ieee80211_next_txq);
|
||||
+
|
||||
+void ieee80211_return_txq(struct ieee80211_hw *hw,
|
||||
+ struct ieee80211_txq *txq)
|
||||
+{
|
||||
+ struct ieee80211_local *local = hw_to_local(hw);
|
||||
+ struct txq_info *txqi = to_txq_info(txq);
|
||||
+
|
||||
+ lockdep_assert_held(&local->active_txq_lock[txq->ac]);
|
||||
+
|
||||
+ if (list_empty(&txqi->schedule_order) &&
|
||||
+ (!skb_queue_empty(&txqi->frags) || txqi->tin.backlog_packets))
|
||||
+ list_add_tail(&txqi->schedule_order,
|
||||
+ &local->active_txqs[txq->ac]);
|
||||
+}
|
||||
+EXPORT_SYMBOL(ieee80211_return_txq);
|
||||
+
|
||||
+void ieee80211_txq_schedule_start(struct ieee80211_hw *hw, u8 ac)
|
||||
+ __acquires(txq_lock)
|
||||
+{
|
||||
+ struct ieee80211_local *local = hw_to_local(hw);
|
||||
+
|
||||
+ spin_lock_bh(&local->active_txq_lock[ac]);
|
||||
+ local->schedule_round[ac]++;
|
||||
+}
|
||||
+EXPORT_SYMBOL(ieee80211_txq_schedule_start);
|
||||
+
|
||||
+void ieee80211_txq_schedule_end(struct ieee80211_hw *hw, u8 ac)
|
||||
+ __releases(txq_lock)
|
||||
+{
|
||||
+ struct ieee80211_local *local = hw_to_local(hw);
|
||||
+
|
||||
+ spin_unlock_bh(&local->active_txq_lock[ac]);
|
||||
+}
|
||||
+EXPORT_SYMBOL(ieee80211_txq_schedule_end);
|
||||
+
|
||||
void __ieee80211_subif_start_xmit(struct sk_buff *skb,
|
||||
struct net_device *dev,
|
||||
u32 info_flags)
|
@ -0,0 +1,202 @@
|
||||
From: =?UTF-8?q?Toke=20H=C3=B8iland-J=C3=B8rgensen?= <toke@toke.dk>
|
||||
Date: Tue, 18 Dec 2018 17:02:07 -0800
|
||||
Subject: [PATCH] cfg80211: Add airtime statistics and settings
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
This adds TX airtime statistics to the cfg80211 station dump (to go along
|
||||
with the RX info already present), and adds a new parameter to set the
|
||||
airtime weight of each station. The latter allows userspace to implement
|
||||
policies for different stations by varying their weights.
|
||||
|
||||
Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
|
||||
[rmanohar@codeaurora.org: fixed checkpatch warnings]
|
||||
Signed-off-by: Rajkumar Manoharan <rmanohar@codeaurora.org>
|
||||
[move airtime weight != 0 check into policy]
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
---
|
||||
|
||||
--- a/include/net/cfg80211.h
|
||||
+++ b/include/net/cfg80211.h
|
||||
@@ -988,6 +988,7 @@ enum station_parameters_apply_mask {
|
||||
* @support_p2p_ps: information if station supports P2P PS mechanism
|
||||
* @he_capa: HE capabilities of station
|
||||
* @he_capa_len: the length of the HE capabilities
|
||||
+ * @airtime_weight: airtime scheduler weight for this station
|
||||
*/
|
||||
struct station_parameters {
|
||||
const u8 *supported_rates;
|
||||
@@ -1017,6 +1018,7 @@ struct station_parameters {
|
||||
int support_p2p_ps;
|
||||
const struct ieee80211_he_cap_elem *he_capa;
|
||||
u8 he_capa_len;
|
||||
+ u16 airtime_weight;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -1284,6 +1286,8 @@ struct cfg80211_tid_stats {
|
||||
* @rx_beacon_signal_avg: signal strength average (in dBm) for beacons received
|
||||
* from this peer
|
||||
* @rx_duration: aggregate PPDU duration(usecs) for all the frames from a peer
|
||||
+ * @tx_duration: aggregate PPDU duration(usecs) for all the frames to a peer
|
||||
+ * @airtime_weight: current airtime scheduling weight
|
||||
* @pertid: per-TID statistics, see &struct cfg80211_tid_stats, using the last
|
||||
* (IEEE80211_NUM_TIDS) index for MSDUs not encapsulated in QoS-MPDUs.
|
||||
* Note that this doesn't use the @filled bit, but is used if non-NULL.
|
||||
@@ -1330,12 +1334,15 @@ struct station_info {
|
||||
|
||||
u32 expected_throughput;
|
||||
|
||||
- u64 rx_beacon;
|
||||
+ u64 tx_duration;
|
||||
u64 rx_duration;
|
||||
+ u64 rx_beacon;
|
||||
u8 rx_beacon_signal_avg;
|
||||
struct cfg80211_tid_stats *pertid;
|
||||
s8 ack_signal;
|
||||
s8 avg_ack_signal;
|
||||
+
|
||||
+ u16 airtime_weight;
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CPTCFG_CFG80211)
|
||||
@@ -2361,6 +2368,8 @@ enum wiphy_params_flags {
|
||||
WIPHY_PARAM_TXQ_QUANTUM = 1 << 8,
|
||||
};
|
||||
|
||||
+#define IEEE80211_DEFAULT_AIRTIME_WEIGHT 256
|
||||
+
|
||||
/**
|
||||
* struct cfg80211_pmksa - PMK Security Association
|
||||
*
|
||||
--- a/include/uapi/linux/nl80211.h
|
||||
+++ b/include/uapi/linux/nl80211.h
|
||||
@@ -2241,6 +2241,9 @@ enum nl80211_commands {
|
||||
* association request when used with NL80211_CMD_NEW_STATION). Can be set
|
||||
* only if %NL80211_STA_FLAG_WME is set.
|
||||
*
|
||||
+ * @NL80211_ATTR_AIRTIME_WEIGHT: Station's weight when scheduled by the airtime
|
||||
+ * scheduler.
|
||||
+ *
|
||||
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
|
||||
* @NL80211_ATTR_MAX: highest attribute number currently defined
|
||||
* @__NL80211_ATTR_AFTER_LAST: internal use
|
||||
@@ -2682,6 +2685,14 @@ enum nl80211_attrs {
|
||||
|
||||
NL80211_ATTR_HE_CAPABILITY,
|
||||
|
||||
+ /* not backported yet */
|
||||
+ NL80211_ATTR_FTM_RESPONDER,
|
||||
+ NL80211_ATTR_FTM_RESPONDER_STATS,
|
||||
+ NL80211_ATTR_TIMEOUT,
|
||||
+ NL80211_ATTR_PEER_MEASUREMENTS,
|
||||
+
|
||||
+ NL80211_ATTR_AIRTIME_WEIGHT,
|
||||
+
|
||||
/* add attributes here, update the policy in nl80211.c */
|
||||
|
||||
__NL80211_ATTR_AFTER_LAST,
|
||||
@@ -3052,6 +3063,9 @@ enum nl80211_sta_bss_param {
|
||||
* @NL80211_STA_INFO_ACK_SIGNAL: signal strength of the last ACK frame(u8, dBm)
|
||||
* @NL80211_STA_INFO_DATA_ACK_SIGNAL_AVG: avg signal strength of (data)
|
||||
* ACK frame (s8, dBm)
|
||||
+ * @NL80211_STA_INFO_TX_DURATION: aggregate PPDU duration for all frames
|
||||
+ * sent to the station (u64, usec)
|
||||
+ * @NL80211_STA_INFO_AIRTIME_WEIGHT: current airtime weight for station (u16)
|
||||
* @__NL80211_STA_INFO_AFTER_LAST: internal
|
||||
* @NL80211_STA_INFO_MAX: highest possible station info attribute
|
||||
*/
|
||||
@@ -3093,6 +3107,14 @@ enum nl80211_sta_info {
|
||||
NL80211_STA_INFO_ACK_SIGNAL,
|
||||
NL80211_STA_INFO_DATA_ACK_SIGNAL_AVG,
|
||||
|
||||
+ /* not backported yet */
|
||||
+ NL80211_STA_INFO_RX_MPDUS,
|
||||
+ NL80211_STA_INFO_FCS_ERROR_COUNT,
|
||||
+ NL80211_STA_INFO_CONNECTED_TO_GATE,
|
||||
+
|
||||
+ NL80211_STA_INFO_TX_DURATION,
|
||||
+ NL80211_STA_INFO_AIRTIME_WEIGHT,
|
||||
+
|
||||
/* keep last */
|
||||
__NL80211_STA_INFO_AFTER_LAST,
|
||||
NL80211_STA_INFO_MAX = __NL80211_STA_INFO_AFTER_LAST - 1
|
||||
@@ -5224,6 +5246,10 @@ enum nl80211_feature_flags {
|
||||
* except for supported rates from the probe request content if requested
|
||||
* by the %NL80211_SCAN_FLAG_MIN_PREQ_CONTENT flag.
|
||||
*
|
||||
+ * @NL80211_EXT_FEATURE_AIRTIME_FAIRNESS: Driver supports getting airtime
|
||||
+ * fairness for transmitted packets and has enabled airtime fairness
|
||||
+ * scheduling.
|
||||
+ *
|
||||
* @NUM_NL80211_EXT_FEATURES: number of extended features.
|
||||
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
|
||||
*/
|
||||
@@ -5260,6 +5286,12 @@ enum nl80211_ext_feature_index {
|
||||
NL80211_EXT_FEATURE_SCAN_RANDOM_SN,
|
||||
NL80211_EXT_FEATURE_SCAN_MIN_PREQ_CONTENT,
|
||||
|
||||
+ /* --- not backported yet --- */
|
||||
+ NL80211_EXT_FEATURE_CAN_REPLACE_PTK0,
|
||||
+ NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER,
|
||||
+
|
||||
+ NL80211_EXT_FEATURE_AIRTIME_FAIRNESS,
|
||||
+
|
||||
/* add new features before the definition below */
|
||||
NUM_NL80211_EXT_FEATURES,
|
||||
MAX_NL80211_EXT_FEATURES = NUM_NL80211_EXT_FEATURES - 1
|
||||
--- a/net/wireless/nl80211.c
|
||||
+++ b/net/wireless/nl80211.c
|
||||
@@ -430,6 +430,7 @@ static const struct nla_policy nl80211_p
|
||||
[NL80211_ATTR_TXQ_QUANTUM] = { .type = NLA_U32 },
|
||||
[NL80211_ATTR_HE_CAPABILITY] = { .type = NLA_BINARY,
|
||||
.len = NL80211_HE_MAX_CAPABILITY_LEN },
|
||||
+ [NL80211_ATTR_AIRTIME_WEIGHT] = NLA_POLICY_MIN(NLA_U16, 1),
|
||||
};
|
||||
|
||||
/* policy for the key attributes */
|
||||
@@ -4658,6 +4659,11 @@ static int nl80211_send_station(struct s
|
||||
PUT_SINFO(PLID, plid, u16);
|
||||
PUT_SINFO(PLINK_STATE, plink_state, u8);
|
||||
PUT_SINFO_U64(RX_DURATION, rx_duration);
|
||||
+ PUT_SINFO_U64(TX_DURATION, tx_duration);
|
||||
+
|
||||
+ if (wiphy_ext_feature_isset(&rdev->wiphy,
|
||||
+ NL80211_EXT_FEATURE_AIRTIME_FAIRNESS))
|
||||
+ PUT_SINFO(AIRTIME_WEIGHT, airtime_weight, u16);
|
||||
|
||||
switch (rdev->wiphy.signal_type) {
|
||||
case CFG80211_SIGNAL_TYPE_MBM:
|
||||
@@ -5294,6 +5300,15 @@ static int nl80211_set_station(struct sk
|
||||
nla_get_u8(info->attrs[NL80211_ATTR_OPMODE_NOTIF]);
|
||||
}
|
||||
|
||||
+ if (info->attrs[NL80211_ATTR_AIRTIME_WEIGHT])
|
||||
+ params.airtime_weight =
|
||||
+ nla_get_u16(info->attrs[NL80211_ATTR_AIRTIME_WEIGHT]);
|
||||
+
|
||||
+ if (params.airtime_weight &&
|
||||
+ !wiphy_ext_feature_isset(&rdev->wiphy,
|
||||
+ NL80211_EXT_FEATURE_AIRTIME_FAIRNESS))
|
||||
+ return -EOPNOTSUPP;
|
||||
+
|
||||
/* Include parameters for TDLS peer (will check later) */
|
||||
err = nl80211_set_station_tdls(info, ¶ms);
|
||||
if (err)
|
||||
@@ -5432,6 +5447,15 @@ static int nl80211_new_station(struct sk
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
+ if (info->attrs[NL80211_ATTR_AIRTIME_WEIGHT])
|
||||
+ params.airtime_weight =
|
||||
+ nla_get_u16(info->attrs[NL80211_ATTR_AIRTIME_WEIGHT]);
|
||||
+
|
||||
+ if (params.airtime_weight &&
|
||||
+ !wiphy_ext_feature_isset(&rdev->wiphy,
|
||||
+ NL80211_EXT_FEATURE_AIRTIME_FAIRNESS))
|
||||
+ return -EOPNOTSUPP;
|
||||
+
|
||||
err = nl80211_parse_sta_channel_info(info, ¶ms);
|
||||
if (err)
|
||||
return err;
|
@ -0,0 +1,522 @@
|
||||
From: =?UTF-8?q?Toke=20H=C3=B8iland-J=C3=B8rgensen?= <toke@toke.dk>
|
||||
Date: Tue, 18 Dec 2018 17:02:08 -0800
|
||||
Subject: [PATCH] mac80211: Add airtime accounting and scheduling to TXQs
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
This adds airtime accounting and scheduling to the mac80211 TXQ
|
||||
scheduler. A new callback, ieee80211_sta_register_airtime(), is added
|
||||
that drivers can call to report airtime usage for stations.
|
||||
|
||||
When airtime information is present, mac80211 will schedule TXQs
|
||||
(through ieee80211_next_txq()) in a way that enforces airtime fairness
|
||||
between active stations. This scheduling works the same way as the ath9k
|
||||
in-driver airtime fairness scheduling. If no airtime usage is reported
|
||||
by the driver, the scheduler will default to round-robin scheduling.
|
||||
|
||||
For drivers that don't control TXQ scheduling in software, a new API
|
||||
function, ieee80211_txq_may_transmit(), is added which the driver can use
|
||||
to check if the TXQ is eligible for transmission, or should be throttled to
|
||||
enforce fairness. Calls to this function must also be enclosed in
|
||||
ieee80211_txq_schedule_{start,end}() calls to ensure proper locking.
|
||||
|
||||
The API ieee80211_txq_may_transmit() also ensures that TXQ list will be
|
||||
aligned aginst driver's own round-robin scheduler list. i.e it rotates
|
||||
the TXQ list till it makes the requested node becomes the first entry
|
||||
in TXQ list. Thus both the TXQ list and driver's list are in sync.
|
||||
|
||||
Co-developed-by: Rajkumar Manoharan <rmanohar@codeaurora.org>
|
||||
Signed-off-by: Louie Lu <git@louie.lu>
|
||||
[added debugfs write op to reset airtime counter]
|
||||
Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
|
||||
Signed-off-by: Rajkumar Manoharan <rmanohar@codeaurora.org>
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
---
|
||||
|
||||
--- a/include/net/mac80211.h
|
||||
+++ b/include/net/mac80211.h
|
||||
@@ -2304,6 +2304,9 @@ enum ieee80211_hw_flags {
|
||||
* supported by HW.
|
||||
* @max_nan_de_entries: maximum number of NAN DE functions supported by the
|
||||
* device.
|
||||
+ *
|
||||
+ * @weight_multipler: Driver specific airtime weight multiplier used while
|
||||
+ * refilling deficit of each TXQ.
|
||||
*/
|
||||
struct ieee80211_hw {
|
||||
struct ieee80211_conf conf;
|
||||
@@ -2339,6 +2342,7 @@ struct ieee80211_hw {
|
||||
u8 n_cipher_schemes;
|
||||
const struct ieee80211_cipher_scheme *cipher_schemes;
|
||||
u8 max_nan_de_entries;
|
||||
+ u8 weight_multiplier;
|
||||
};
|
||||
|
||||
static inline bool _ieee80211_hw_check(struct ieee80211_hw *hw,
|
||||
@@ -5299,6 +5303,34 @@ void ieee80211_sta_eosp(struct ieee80211
|
||||
void ieee80211_send_eosp_nullfunc(struct ieee80211_sta *pubsta, int tid);
|
||||
|
||||
/**
|
||||
+ * ieee80211_sta_register_airtime - register airtime usage for a sta/tid
|
||||
+ *
|
||||
+ * Register airtime usage for a given sta on a given tid. The driver can call
|
||||
+ * this function to notify mac80211 that a station used a certain amount of
|
||||
+ * airtime. This information will be used by the TXQ scheduler to schedule
|
||||
+ * stations in a way that ensures airtime fairness.
|
||||
+ *
|
||||
+ * The reported airtime should as a minimum include all time that is spent
|
||||
+ * transmitting to the remote station, including overhead and padding, but not
|
||||
+ * including time spent waiting for a TXOP. If the time is not reported by the
|
||||
+ * hardware it can in some cases be calculated from the rate and known frame
|
||||
+ * composition. When possible, the time should include any failed transmission
|
||||
+ * attempts.
|
||||
+ *
|
||||
+ * The driver can either call this function synchronously for every packet or
|
||||
+ * aggregate, or asynchronously as airtime usage information becomes available.
|
||||
+ * TX and RX airtime can be reported together, or separately by setting one of
|
||||
+ * them to 0.
|
||||
+ *
|
||||
+ * @pubsta: the station
|
||||
+ * @tid: the TID to register airtime for
|
||||
+ * @tx_airtime: airtime used during TX (in usec)
|
||||
+ * @rx_airtime: airtime used during RX (in usec)
|
||||
+ */
|
||||
+void ieee80211_sta_register_airtime(struct ieee80211_sta *pubsta, u8 tid,
|
||||
+ u32 tx_airtime, u32 rx_airtime);
|
||||
+
|
||||
+/**
|
||||
* ieee80211_iter_keys - iterate keys programmed into the device
|
||||
* @hw: pointer obtained from ieee80211_alloc_hw()
|
||||
* @vif: virtual interface to iterate, may be %NULL for all
|
||||
@@ -6042,6 +6074,33 @@ void ieee80211_txq_schedule_end(struct i
|
||||
__releases(txq_lock);
|
||||
|
||||
/**
|
||||
+ * ieee80211_txq_may_transmit - check whether TXQ is allowed to transmit
|
||||
+ *
|
||||
+ * This function is used to check whether given txq is allowed to transmit by
|
||||
+ * the airtime scheduler, and can be used by drivers to access the airtime
|
||||
+ * fairness accounting without going using the scheduling order enfored by
|
||||
+ * next_txq().
|
||||
+ *
|
||||
+ * Returns %true if the airtime scheduler thinks the TXQ should be allowed to
|
||||
+ * transmit, and %false if it should be throttled. This function can also have
|
||||
+ * the side effect of rotating the TXQ in the scheduler rotation, which will
|
||||
+ * eventually bring the deficit to positive and allow the station to transmit
|
||||
+ * again.
|
||||
+ *
|
||||
+ * The API ieee80211_txq_may_transmit() also ensures that TXQ list will be
|
||||
+ * aligned aginst driver's own round-robin scheduler list. i.e it rotates
|
||||
+ * the TXQ list till it makes the requested node becomes the first entry
|
||||
+ * in TXQ list. Thus both the TXQ list and driver's list are in sync. If this
|
||||
+ * function returns %true, the driver is expected to schedule packets
|
||||
+ * for transmission, and then return the TXQ through ieee80211_return_txq().
|
||||
+ *
|
||||
+ * @hw: pointer as obtained from ieee80211_alloc_hw()
|
||||
+ * @txq: pointer obtained from station or virtual interface
|
||||
+ */
|
||||
+bool ieee80211_txq_may_transmit(struct ieee80211_hw *hw,
|
||||
+ struct ieee80211_txq *txq);
|
||||
+
|
||||
+/**
|
||||
* ieee80211_txq_get_depth - get pending frame/byte count of given txq
|
||||
*
|
||||
* The values are not guaranteed to be coherent with regard to each other, i.e.
|
||||
--- a/net/mac80211/cfg.c
|
||||
+++ b/net/mac80211/cfg.c
|
||||
@@ -1430,6 +1430,9 @@ static int sta_apply_parameters(struct i
|
||||
if (ieee80211_vif_is_mesh(&sdata->vif))
|
||||
sta_apply_mesh_params(local, sta, params);
|
||||
|
||||
+ if (params->airtime_weight)
|
||||
+ sta->airtime_weight = params->airtime_weight;
|
||||
+
|
||||
/* set the STA state after all sta info from usermode has been set */
|
||||
if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) ||
|
||||
set & BIT(NL80211_STA_FLAG_ASSOCIATED)) {
|
||||
--- a/net/mac80211/debugfs.c
|
||||
+++ b/net/mac80211/debugfs.c
|
||||
@@ -380,6 +380,9 @@ void debugfs_hw_add(struct ieee80211_loc
|
||||
if (local->ops->wake_tx_queue)
|
||||
DEBUGFS_ADD_MODE(aqm, 0600);
|
||||
|
||||
+ debugfs_create_u16("airtime_flags", 0600,
|
||||
+ phyd, &local->airtime_flags);
|
||||
+
|
||||
statsd = debugfs_create_dir("statistics", phyd);
|
||||
|
||||
/* if the dir failed, don't put all the other things into the root! */
|
||||
--- a/net/mac80211/debugfs_sta.c
|
||||
+++ b/net/mac80211/debugfs_sta.c
|
||||
@@ -178,9 +178,9 @@ static ssize_t sta_aqm_read(struct file
|
||||
txqi->tin.tx_bytes,
|
||||
txqi->tin.tx_packets,
|
||||
txqi->flags,
|
||||
- txqi->flags & (1<<IEEE80211_TXQ_STOP) ? "STOP" : "RUN",
|
||||
- txqi->flags & (1<<IEEE80211_TXQ_AMPDU) ? " AMPDU" : "",
|
||||
- txqi->flags & (1<<IEEE80211_TXQ_NO_AMSDU) ? " NO-AMSDU" : "");
|
||||
+ test_bit(IEEE80211_TXQ_STOP, &txqi->flags) ? "STOP" : "RUN",
|
||||
+ test_bit(IEEE80211_TXQ_AMPDU, &txqi->flags) ? " AMPDU" : "",
|
||||
+ test_bit(IEEE80211_TXQ_NO_AMSDU, &txqi->flags) ? " NO-AMSDU" : "");
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
@@ -192,6 +192,64 @@ static ssize_t sta_aqm_read(struct file
|
||||
}
|
||||
STA_OPS(aqm);
|
||||
|
||||
+static ssize_t sta_airtime_read(struct file *file, char __user *userbuf,
|
||||
+ size_t count, loff_t *ppos)
|
||||
+{
|
||||
+ struct sta_info *sta = file->private_data;
|
||||
+ struct ieee80211_local *local = sta->sdata->local;
|
||||
+ size_t bufsz = 200;
|
||||
+ char *buf = kzalloc(bufsz, GFP_KERNEL), *p = buf;
|
||||
+ u64 rx_airtime = 0, tx_airtime = 0;
|
||||
+ s64 deficit[IEEE80211_NUM_ACS];
|
||||
+ ssize_t rv;
|
||||
+ int ac;
|
||||
+
|
||||
+ if (!buf)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
|
||||
+ spin_lock_bh(&local->active_txq_lock[ac]);
|
||||
+ rx_airtime += sta->airtime[ac].rx_airtime;
|
||||
+ tx_airtime += sta->airtime[ac].tx_airtime;
|
||||
+ deficit[ac] = sta->airtime[ac].deficit;
|
||||
+ spin_unlock_bh(&local->active_txq_lock[ac]);
|
||||
+ }
|
||||
+
|
||||
+ p += scnprintf(p, bufsz + buf - p,
|
||||
+ "RX: %llu us\nTX: %llu us\nWeight: %u\n"
|
||||
+ "Deficit: VO: %lld us VI: %lld us BE: %lld us BK: %lld us\n",
|
||||
+ rx_airtime,
|
||||
+ tx_airtime,
|
||||
+ sta->airtime_weight,
|
||||
+ deficit[0],
|
||||
+ deficit[1],
|
||||
+ deficit[2],
|
||||
+ deficit[3]);
|
||||
+
|
||||
+ rv = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
|
||||
+ kfree(buf);
|
||||
+ return rv;
|
||||
+}
|
||||
+
|
||||
+static ssize_t sta_airtime_write(struct file *file, const char __user *userbuf,
|
||||
+ size_t count, loff_t *ppos)
|
||||
+{
|
||||
+ struct sta_info *sta = file->private_data;
|
||||
+ struct ieee80211_local *local = sta->sdata->local;
|
||||
+ int ac;
|
||||
+
|
||||
+ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
|
||||
+ spin_lock_bh(&local->active_txq_lock[ac]);
|
||||
+ sta->airtime[ac].rx_airtime = 0;
|
||||
+ sta->airtime[ac].tx_airtime = 0;
|
||||
+ sta->airtime[ac].deficit = sta->airtime_weight;
|
||||
+ spin_unlock_bh(&local->active_txq_lock[ac]);
|
||||
+ }
|
||||
+
|
||||
+ return count;
|
||||
+}
|
||||
+STA_OPS_RW(airtime);
|
||||
+
|
||||
static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
@@ -546,6 +604,10 @@ void ieee80211_sta_debugfs_add(struct st
|
||||
if (local->ops->wake_tx_queue)
|
||||
DEBUGFS_ADD(aqm);
|
||||
|
||||
+ if (wiphy_ext_feature_isset(local->hw.wiphy,
|
||||
+ NL80211_EXT_FEATURE_AIRTIME_FAIRNESS))
|
||||
+ DEBUGFS_ADD(airtime);
|
||||
+
|
||||
if (sizeof(sta->driver_buffered_tids) == sizeof(u32))
|
||||
debugfs_create_x32("driver_buffered_tids", 0400,
|
||||
sta->debugfs_dir,
|
||||
--- a/net/mac80211/ieee80211_i.h
|
||||
+++ b/net/mac80211/ieee80211_i.h
|
||||
@@ -1136,6 +1136,8 @@ struct ieee80211_local {
|
||||
struct list_head active_txqs[IEEE80211_NUM_ACS];
|
||||
u16 schedule_round[IEEE80211_NUM_ACS];
|
||||
|
||||
+ u16 airtime_flags;
|
||||
+
|
||||
const struct ieee80211_ops *ops;
|
||||
|
||||
/*
|
||||
--- a/net/mac80211/main.c
|
||||
+++ b/net/mac80211/main.c
|
||||
@@ -656,6 +656,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_
|
||||
INIT_LIST_HEAD(&local->active_txqs[i]);
|
||||
spin_lock_init(&local->active_txq_lock[i]);
|
||||
}
|
||||
+ local->airtime_flags = AIRTIME_USE_TX | AIRTIME_USE_RX;
|
||||
|
||||
INIT_LIST_HEAD(&local->chanctx_list);
|
||||
mutex_init(&local->chanctx_mtx);
|
||||
@@ -1142,6 +1143,9 @@ int ieee80211_register_hw(struct ieee802
|
||||
if (!local->hw.max_nan_de_entries)
|
||||
local->hw.max_nan_de_entries = IEEE80211_MAX_NAN_INSTANCE_ID;
|
||||
|
||||
+ if (!local->hw.weight_multiplier)
|
||||
+ local->hw.weight_multiplier = 1;
|
||||
+
|
||||
result = ieee80211_wep_init(local);
|
||||
if (result < 0)
|
||||
wiphy_debug(local->hw.wiphy, "Failed to initialize wep: %d\n",
|
||||
--- a/net/mac80211/sta_info.c
|
||||
+++ b/net/mac80211/sta_info.c
|
||||
@@ -90,7 +90,6 @@ static void __cleanup_single_sta(struct
|
||||
struct tid_ampdu_tx *tid_tx;
|
||||
struct ieee80211_sub_if_data *sdata = sta->sdata;
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
- struct fq *fq = &local->fq;
|
||||
struct ps_data *ps;
|
||||
|
||||
if (test_sta_flag(sta, WLAN_STA_PS_STA) ||
|
||||
@@ -115,9 +114,7 @@ static void __cleanup_single_sta(struct
|
||||
for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
|
||||
struct txq_info *txqi = to_txq_info(sta->sta.txq[i]);
|
||||
|
||||
- spin_lock_bh(&fq->lock);
|
||||
ieee80211_txq_purge(local, txqi);
|
||||
- spin_unlock_bh(&fq->lock);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -381,9 +378,12 @@ 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;
|
||||
}
|
||||
|
||||
for (i = 0; i < IEEE80211_NUM_TIDS; i++)
|
||||
@@ -1821,6 +1821,27 @@ 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)
|
||||
+{
|
||||
+ 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);
|
||||
+ u32 airtime = 0;
|
||||
+
|
||||
+ if (sta->local->airtime_flags & AIRTIME_USE_TX)
|
||||
+ airtime += tx_airtime;
|
||||
+ if (sta->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]);
|
||||
+}
|
||||
+EXPORT_SYMBOL(ieee80211_sta_register_airtime);
|
||||
+
|
||||
int sta_info_move_state(struct sta_info *sta,
|
||||
enum ieee80211_sta_state new_state)
|
||||
{
|
||||
@@ -2183,6 +2204,23 @@ void sta_set_sinfo(struct sta_info *sta,
|
||||
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_FAILED);
|
||||
}
|
||||
|
||||
+ if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_RX_DURATION))) {
|
||||
+ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
|
||||
+ sinfo->rx_duration += sta->airtime[ac].rx_airtime;
|
||||
+ sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_DURATION);
|
||||
+ }
|
||||
+
|
||||
+ if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_TX_DURATION))) {
|
||||
+ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
|
||||
+ sinfo->tx_duration += sta->airtime[ac].tx_airtime;
|
||||
+ sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_DURATION);
|
||||
+ }
|
||||
+
|
||||
+ if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_AIRTIME_WEIGHT))) {
|
||||
+ sinfo->airtime_weight = sta->airtime_weight;
|
||||
+ sinfo->filled |= BIT_ULL(NL80211_STA_INFO_AIRTIME_WEIGHT);
|
||||
+ }
|
||||
+
|
||||
sinfo->rx_dropped_misc = sta->rx_stats.dropped;
|
||||
if (sta->pcpu_rx_stats) {
|
||||
for_each_possible_cpu(cpu) {
|
||||
--- a/net/mac80211/sta_info.h
|
||||
+++ b/net/mac80211/sta_info.h
|
||||
@@ -127,6 +127,16 @@ enum ieee80211_agg_stop_reason {
|
||||
AGG_STOP_DESTROY_STA,
|
||||
};
|
||||
|
||||
+/* Debugfs flags to enable/disable use of RX/TX airtime in scheduler */
|
||||
+#define AIRTIME_USE_TX BIT(0)
|
||||
+#define AIRTIME_USE_RX BIT(1)
|
||||
+
|
||||
+struct airtime_info {
|
||||
+ u64 rx_airtime;
|
||||
+ u64 tx_airtime;
|
||||
+ s64 deficit;
|
||||
+};
|
||||
+
|
||||
struct sta_info;
|
||||
|
||||
/**
|
||||
@@ -563,6 +573,9 @@ struct sta_info {
|
||||
} tx_stats;
|
||||
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
|
||||
@@ -825,6 +825,12 @@ static void __ieee80211_tx_status(struct
|
||||
ieee80211_sta_tx_notify(sta->sdata, (void *) skb->data,
|
||||
acked, info->status.tx_time);
|
||||
|
||||
+ if (info->status.tx_time &&
|
||||
+ wiphy_ext_feature_isset(local->hw.wiphy,
|
||||
+ NL80211_EXT_FEATURE_AIRTIME_FAIRNESS))
|
||||
+ ieee80211_sta_register_airtime(&sta->sta, tid,
|
||||
+ info->status.tx_time, 0);
|
||||
+
|
||||
if (ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) {
|
||||
if (info->flags & IEEE80211_TX_STAT_ACK) {
|
||||
if (sta->status_stats.lost_packets)
|
||||
--- a/net/mac80211/tx.c
|
||||
+++ b/net/mac80211/tx.c
|
||||
@@ -1463,8 +1463,11 @@ void ieee80211_txq_purge(struct ieee8021
|
||||
struct fq *fq = &local->fq;
|
||||
struct fq_tin *tin = &txqi->tin;
|
||||
|
||||
+ spin_lock_bh(&fq->lock);
|
||||
fq_tin_reset(fq, tin, fq_skb_free_func);
|
||||
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]);
|
||||
@@ -3613,11 +3616,28 @@ struct ieee80211_txq *ieee80211_next_txq
|
||||
|
||||
lockdep_assert_held(&local->active_txq_lock[ac]);
|
||||
|
||||
+ begin:
|
||||
txqi = list_first_entry_or_null(&local->active_txqs[ac],
|
||||
struct txq_info,
|
||||
schedule_order);
|
||||
+ if (!txqi)
|
||||
+ return NULL;
|
||||
|
||||
- if (!txqi || txqi->schedule_round == local->schedule_round[ac])
|
||||
+ if (txqi->txq.sta) {
|
||||
+ struct sta_info *sta = container_of(txqi->txq.sta,
|
||||
+ struct sta_info, sta);
|
||||
+
|
||||
+ if (sta->airtime[txqi->txq.ac].deficit < 0) {
|
||||
+ sta->airtime[txqi->txq.ac].deficit +=
|
||||
+ sta->airtime_weight;
|
||||
+ list_move_tail(&txqi->schedule_order,
|
||||
+ &local->active_txqs[txqi->txq.ac]);
|
||||
+ goto begin;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+
|
||||
+ if (txqi->schedule_round == local->schedule_round[ac])
|
||||
return NULL;
|
||||
|
||||
list_del_init(&txqi->schedule_order);
|
||||
@@ -3635,12 +3655,74 @@ void ieee80211_return_txq(struct ieee802
|
||||
lockdep_assert_held(&local->active_txq_lock[txq->ac]);
|
||||
|
||||
if (list_empty(&txqi->schedule_order) &&
|
||||
- (!skb_queue_empty(&txqi->frags) || txqi->tin.backlog_packets))
|
||||
- list_add_tail(&txqi->schedule_order,
|
||||
- &local->active_txqs[txq->ac]);
|
||||
+ (!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 &&
|
||||
+ 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]);
|
||||
+ }
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_return_txq);
|
||||
|
||||
+bool ieee80211_txq_may_transmit(struct ieee80211_hw *hw,
|
||||
+ struct ieee80211_txq *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;
|
||||
+
|
||||
+ lockdep_assert_held(&local->active_txq_lock[ac]);
|
||||
+
|
||||
+ if (!txqi->txq.sta)
|
||||
+ goto out;
|
||||
+
|
||||
+ if (list_empty(&txqi->schedule_order))
|
||||
+ goto out;
|
||||
+
|
||||
+ list_for_each_entry_safe(iter, tmp, &local->active_txqs[ac],
|
||||
+ schedule_order) {
|
||||
+ if (iter == txqi)
|
||||
+ break;
|
||||
+
|
||||
+ 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]);
|
||||
+ }
|
||||
+
|
||||
+ 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]);
|
||||
+
|
||||
+ return false;
|
||||
+out:
|
||||
+ if (!list_empty(&txqi->schedule_order))
|
||||
+ list_del_init(&txqi->schedule_order);
|
||||
+
|
||||
+ return true;
|
||||
+}
|
||||
+EXPORT_SYMBOL(ieee80211_txq_may_transmit);
|
||||
+
|
||||
void ieee80211_txq_schedule_start(struct ieee80211_hw *hw, u8 ac)
|
||||
__acquires(txq_lock)
|
||||
{
|
@ -0,0 +1,73 @@
|
||||
From: =?UTF-8?q?Toke=20H=C3=B8iland-J=C3=B8rgensen?= <toke@redhat.com>
|
||||
Date: Tue, 22 Jan 2019 15:20:16 +0100
|
||||
Subject: [PATCH] mac80211: Expose ieee80211_schedule_txq() function
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Since we reworked ieee80211_return_txq() so it assumes that the caller
|
||||
takes care of logging, we need another function that can be called without
|
||||
holding any locks. Introduce ieee80211_schedule_txq() which serves this
|
||||
purpose.
|
||||
|
||||
Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
---
|
||||
|
||||
--- a/include/net/mac80211.h
|
||||
+++ b/include/net/mac80211.h
|
||||
@@ -6074,6 +6074,19 @@ void ieee80211_txq_schedule_end(struct i
|
||||
__releases(txq_lock);
|
||||
|
||||
/**
|
||||
+ * ieee80211_schedule_txq - schedule a TXQ for transmission
|
||||
+ *
|
||||
+ * @hw: pointer as obtained from ieee80211_alloc_hw()
|
||||
+ * @txq: pointer obtained from station or virtual interface
|
||||
+ *
|
||||
+ * Schedules a TXQ for transmission if it is not already scheduled. Takes a
|
||||
+ * lock, which means it must *not* be called between
|
||||
+ * ieee80211_txq_schedule_start() and ieee80211_txq_schedule_end()
|
||||
+ */
|
||||
+void ieee80211_schedule_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq)
|
||||
+ __acquires(txq_lock) __releases(txq_lock);
|
||||
+
|
||||
+/**
|
||||
* ieee80211_txq_may_transmit - check whether TXQ is allowed to transmit
|
||||
*
|
||||
* This function is used to check whether given txq is allowed to transmit by
|
||||
--- a/net/mac80211/driver-ops.h
|
||||
+++ b/net/mac80211/driver-ops.h
|
||||
@@ -1179,9 +1179,7 @@ static inline void drv_wake_tx_queue(str
|
||||
static inline void schedule_and_wake_txq(struct ieee80211_local *local,
|
||||
struct txq_info *txqi)
|
||||
{
|
||||
- spin_lock_bh(&local->active_txq_lock[txqi->txq.ac]);
|
||||
- ieee80211_return_txq(&local->hw, &txqi->txq);
|
||||
- spin_unlock_bh(&local->active_txq_lock[txqi->txq.ac]);
|
||||
+ ieee80211_schedule_txq(&local->hw, &txqi->txq);
|
||||
drv_wake_tx_queue(local, txqi);
|
||||
}
|
||||
|
||||
--- a/net/mac80211/tx.c
|
||||
+++ b/net/mac80211/tx.c
|
||||
@@ -3675,6 +3675,19 @@ void ieee80211_return_txq(struct ieee802
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_return_txq);
|
||||
|
||||
+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);
|
||||
+
|
||||
+ spin_lock_bh(&local->active_txq_lock[txq->ac]);
|
||||
+ ieee80211_return_txq(hw, txq);
|
||||
+ spin_unlock_bh(&local->active_txq_lock[txq->ac]);
|
||||
+}
|
||||
+EXPORT_SYMBOL(ieee80211_schedule_txq);
|
||||
+
|
||||
bool ieee80211_txq_may_transmit(struct ieee80211_hw *hw,
|
||||
struct ieee80211_txq *txq)
|
||||
{
|
@ -48,7 +48,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
if (likely(sta)) {
|
||||
if (!IS_ERR(sta))
|
||||
tx->sta = sta;
|
||||
@@ -3518,6 +3518,7 @@ begin:
|
||||
@@ -3525,6 +3525,7 @@ begin:
|
||||
tx.local = local;
|
||||
tx.skb = skb;
|
||||
tx.sdata = vif_to_sdata(info->control.vif);
|
||||
@ -56,7 +56,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
|
||||
if (txq->sta)
|
||||
tx.sta = container_of(txq->sta, struct sta_info, sta);
|
||||
@@ -3544,7 +3545,7 @@ begin:
|
||||
@@ -3551,7 +3552,7 @@ begin:
|
||||
|
||||
if (tx.key &&
|
||||
(tx.key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV))
|
||||
@ -65,7 +65,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
|
||||
ieee80211_xmit_fast_finish(sta->sdata, sta, pn_offs,
|
||||
tx.key, skb);
|
||||
@@ -3855,6 +3856,7 @@ ieee80211_build_data_template(struct iee
|
||||
@@ -4008,6 +4009,7 @@ ieee80211_build_data_template(struct iee
|
||||
hdr = (void *)skb->data;
|
||||
tx.sta = sta_info_get(sdata, hdr->addr1);
|
||||
tx.skb = skb;
|
||||
|
@ -20,7 +20,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
|
||||
--- a/include/net/mac80211.h
|
||||
+++ b/include/net/mac80211.h
|
||||
@@ -2134,6 +2134,9 @@ struct ieee80211_txq {
|
||||
@@ -2140,6 +2140,9 @@ struct ieee80211_txq {
|
||||
* @IEEE80211_HW_TX_STATUS_NO_AMPDU_LEN: Driver does not report accurate A-MPDU
|
||||
* length in tx status information
|
||||
*
|
||||
@ -30,7 +30,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
* @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays
|
||||
*/
|
||||
enum ieee80211_hw_flags {
|
||||
@@ -2180,6 +2183,7 @@ enum ieee80211_hw_flags {
|
||||
@@ -2186,6 +2189,7 @@ enum ieee80211_hw_flags {
|
||||
IEEE80211_HW_DEAUTH_NEED_MGD_TX_PREP,
|
||||
IEEE80211_HW_DOESNT_SUPPORT_QOS_NDP,
|
||||
IEEE80211_HW_TX_STATUS_NO_AMPDU_LEN,
|
||||
@ -38,7 +38,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
|
||||
/* keep last, obviously */
|
||||
NUM_IEEE80211_HW_FLAGS
|
||||
@@ -2462,6 +2466,40 @@ ieee80211_get_alt_retry_rate(const struc
|
||||
@@ -2472,6 +2476,40 @@ ieee80211_get_alt_retry_rate(const struc
|
||||
void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb);
|
||||
|
||||
/**
|
||||
@ -148,7 +148,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
out:
|
||||
--- a/net/mac80211/sta_info.h
|
||||
+++ b/net/mac80211/sta_info.h
|
||||
@@ -301,7 +301,7 @@ struct ieee80211_fast_tx {
|
||||
@@ -311,7 +311,7 @@ struct ieee80211_fast_tx {
|
||||
u8 hdr_len;
|
||||
u8 sa_offs, da_offs, pn_offs;
|
||||
u8 band;
|
||||
@ -227,7 +227,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
|
||||
if (likely(sta)) {
|
||||
if (!IS_ERR(sta))
|
||||
@@ -2215,7 +2214,7 @@ netdev_tx_t ieee80211_monitor_start_xmit
|
||||
@@ -2222,7 +2221,7 @@ netdev_tx_t ieee80211_monitor_start_xmit
|
||||
goto fail;
|
||||
|
||||
hdr = (struct ieee80211_hdr *)(skb->data + len_rthdr);
|
||||
@ -236,7 +236,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
|
||||
if (skb->len < len_rthdr + hdrlen)
|
||||
goto fail;
|
||||
@@ -2433,7 +2432,7 @@ static struct sk_buff *ieee80211_build_h
|
||||
@@ -2440,7 +2439,7 @@ static struct sk_buff *ieee80211_build_h
|
||||
struct ieee80211_chanctx_conf *chanctx_conf;
|
||||
struct ieee80211_sub_if_data *ap_sdata;
|
||||
enum nl80211_band band;
|
||||
@ -245,7 +245,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
|
||||
if (IS_ERR(sta))
|
||||
sta = NULL;
|
||||
@@ -2732,7 +2731,9 @@ static struct sk_buff *ieee80211_build_h
|
||||
@@ -2739,7 +2738,9 @@ static struct sk_buff *ieee80211_build_h
|
||||
}
|
||||
|
||||
skb_pull(skb, skip_header_bytes);
|
||||
@ -255,7 +255,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
|
||||
/*
|
||||
* So we need to modify the skb header and hence need a copy of
|
||||
@@ -2765,6 +2766,9 @@ static struct sk_buff *ieee80211_build_h
|
||||
@@ -2772,6 +2773,9 @@ static struct sk_buff *ieee80211_build_h
|
||||
memcpy(skb_push(skb, meshhdrlen), &mesh_hdr, meshhdrlen);
|
||||
#endif
|
||||
|
||||
@ -265,7 +265,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
if (ieee80211_is_data_qos(fc)) {
|
||||
__le16 *qos_control;
|
||||
|
||||
@@ -2940,6 +2944,8 @@ void ieee80211_check_fast_xmit(struct st
|
||||
@@ -2947,6 +2951,8 @@ void ieee80211_check_fast_xmit(struct st
|
||||
fc |= cpu_to_le16(IEEE80211_STYPE_QOS_DATA);
|
||||
}
|
||||
|
||||
@ -274,7 +274,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
/* We store the key here so there's no point in using rcu_dereference()
|
||||
* but that's fine because the code that changes the pointers will call
|
||||
* this function after doing so. For a single CPU that would be enough,
|
||||
@@ -3518,7 +3524,7 @@ begin:
|
||||
@@ -3525,7 +3531,7 @@ begin:
|
||||
tx.local = local;
|
||||
tx.skb = skb;
|
||||
tx.sdata = vif_to_sdata(info->control.vif);
|
||||
@ -283,7 +283,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
|
||||
if (txq->sta)
|
||||
tx.sta = container_of(txq->sta, struct sta_info, sta);
|
||||
@@ -3856,7 +3862,7 @@ ieee80211_build_data_template(struct iee
|
||||
@@ -4009,7 +4015,7 @@ ieee80211_build_data_template(struct iee
|
||||
hdr = (void *)skb->data;
|
||||
tx.sta = sta_info_get(sdata, hdr->addr1);
|
||||
tx.skb = skb;
|
||||
|
@ -38,7 +38,7 @@ Signed-off-by: Manikanta Pubbisetty <mpubbise@codeaurora.org>
|
||||
|
||||
--- a/include/net/cfg80211.h
|
||||
+++ b/include/net/cfg80211.h
|
||||
@@ -3448,7 +3448,8 @@ struct cfg80211_ops {
|
||||
@@ -3457,7 +3457,8 @@ struct cfg80211_ops {
|
||||
* on wiphy_new(), but can be changed by the driver if it has a good
|
||||
* reason to override the default
|
||||
* @WIPHY_FLAG_4ADDR_AP: supports 4addr mode even on AP (with a single station
|
||||
@ -81,7 +81,7 @@ Signed-off-by: Manikanta Pubbisetty <mpubbise@codeaurora.org>
|
||||
break;
|
||||
--- a/net/wireless/nl80211.c
|
||||
+++ b/net/wireless/nl80211.c
|
||||
@@ -3193,8 +3193,7 @@ static int nl80211_new_interface(struct
|
||||
@@ -3194,8 +3194,7 @@ static int nl80211_new_interface(struct
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -91,7 +91,7 @@ Signed-off-by: Manikanta Pubbisetty <mpubbise@codeaurora.org>
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if ((type == NL80211_IFTYPE_P2P_DEVICE || type == NL80211_IFTYPE_NAN ||
|
||||
@@ -3213,6 +3212,13 @@ static int nl80211_new_interface(struct
|
||||
@@ -3214,6 +3213,13 @@ static int nl80211_new_interface(struct
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
--- a/include/net/cfg80211.h
|
||||
+++ b/include/net/cfg80211.h
|
||||
@@ -2959,6 +2959,7 @@ struct cfg80211_external_auth_params {
|
||||
@@ -2968,6 +2968,7 @@ struct cfg80211_external_auth_params {
|
||||
* (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 @@
|
||||
*
|
||||
* @set_wds_peer: set the WDS peer for a WDS interface
|
||||
*
|
||||
@@ -3259,6 +3260,7 @@ struct cfg80211_ops {
|
||||
@@ -3268,6 +3269,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 @@
|
||||
const u8 *addr);
|
||||
--- a/include/net/mac80211.h
|
||||
+++ b/include/net/mac80211.h
|
||||
@@ -1389,6 +1389,7 @@ enum ieee80211_smps_mode {
|
||||
@@ -1395,6 +1395,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
|
||||
@@ -1409,6 +1410,7 @@ enum ieee80211_smps_mode {
|
||||
@@ -1415,6 +1416,7 @@ enum ieee80211_smps_mode {
|
||||
struct ieee80211_conf {
|
||||
u32 flags;
|
||||
int power_level, dynamic_ps_timeout;
|
||||
@ -36,45 +36,20 @@
|
||||
u8 ps_dtim_period;
|
||||
--- a/include/uapi/linux/nl80211.h
|
||||
+++ b/include/uapi/linux/nl80211.h
|
||||
@@ -2241,6 +2241,26 @@ enum nl80211_commands {
|
||||
* association request when used with NL80211_CMD_NEW_STATION). Can be set
|
||||
* only if %NL80211_STA_FLAG_WME is set.
|
||||
@@ -2244,6 +2244,9 @@ enum nl80211_commands {
|
||||
* @NL80211_ATTR_AIRTIME_WEIGHT: Station's weight when scheduled by the airtime
|
||||
* scheduler.
|
||||
*
|
||||
+ * @NL80211_ATTR_FTM_RESPONDER: nested attribute which user-space can include
|
||||
+ * in %NL80211_CMD_START_AP or %NL80211_CMD_SET_BEACON for fine timing
|
||||
+ * measurement (FTM) responder functionality and containing parameters as
|
||||
+ * possible, see &enum nl80211_ftm_responder_attr
|
||||
+ *
|
||||
+ * @NL80211_ATTR_FTM_RESPONDER_STATS: Nested attribute with FTM responder
|
||||
+ * statistics, see &enum nl80211_ftm_responder_stats.
|
||||
+ *
|
||||
+ * @NL80211_ATTR_TIMEOUT: Timeout for the given operation in milliseconds (u32),
|
||||
+ * if the attribute is not given no timeout is requested. Note that 0 is an
|
||||
+ * invalid value.
|
||||
+ *
|
||||
+ * @NL80211_ATTR_PEER_MEASUREMENTS: peer measurements request (and result)
|
||||
+ * data, uses nested attributes specified in
|
||||
+ * &enum nl80211_peer_measurement_attrs.
|
||||
+ * This is also used for capability advertisement in the wiphy information,
|
||||
+ * with the appropriate sub-attributes.
|
||||
+ * @NL80211_ATTR_WIPHY_ANTENNA_GAIN: Configured antenna gain. Used to reduce
|
||||
+ * transmit power to stay within regulatory limits. u32, dBi.
|
||||
+ *
|
||||
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
|
||||
* @NL80211_ATTR_MAX: highest attribute number currently defined
|
||||
* @__NL80211_ATTR_AFTER_LAST: internal use
|
||||
@@ -2682,6 +2702,16 @@ enum nl80211_attrs {
|
||||
@@ -2693,6 +2696,8 @@ enum nl80211_attrs {
|
||||
|
||||
NL80211_ATTR_HE_CAPABILITY,
|
||||
NL80211_ATTR_AIRTIME_WEIGHT,
|
||||
|
||||
+ NL80211_ATTR_FTM_RESPONDER,
|
||||
+
|
||||
+ NL80211_ATTR_FTM_RESPONDER_STATS,
|
||||
+
|
||||
+ NL80211_ATTR_TIMEOUT,
|
||||
+
|
||||
+ NL80211_ATTR_PEER_MEASUREMENTS,
|
||||
+
|
||||
+ NL80211_ATTR_WIPHY_ANTENNA_GAIN,
|
||||
+
|
||||
/* add attributes here, update the policy in nl80211.c */
|
||||
@ -82,7 +57,7 @@
|
||||
__NL80211_ATTR_AFTER_LAST,
|
||||
--- a/net/mac80211/cfg.c
|
||||
+++ b/net/mac80211/cfg.c
|
||||
@@ -2494,6 +2494,19 @@ static int ieee80211_get_tx_power(struct
|
||||
@@ -2497,6 +2497,19 @@ static int ieee80211_get_tx_power(struct
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -102,7 +77,7 @@
|
||||
static int ieee80211_set_wds_peer(struct wiphy *wiphy, struct net_device *dev,
|
||||
const u8 *addr)
|
||||
{
|
||||
@@ -3861,6 +3874,7 @@ const struct cfg80211_ops mac80211_confi
|
||||
@@ -3864,6 +3877,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,
|
||||
@ -112,7 +87,7 @@
|
||||
CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd)
|
||||
--- a/net/mac80211/ieee80211_i.h
|
||||
+++ b/net/mac80211/ieee80211_i.h
|
||||
@@ -1354,6 +1354,7 @@ struct ieee80211_local {
|
||||
@@ -1365,6 +1365,7 @@ struct ieee80211_local {
|
||||
int dynamic_ps_forced_timeout;
|
||||
|
||||
int user_power_level; /* in dBm, for all interfaces */
|
||||
@ -154,15 +129,15 @@
|
||||
local->user_power_level = IEEE80211_UNSET_POWER_LEVEL;
|
||||
--- a/net/wireless/nl80211.c
|
||||
+++ b/net/wireless/nl80211.c
|
||||
@@ -430,6 +430,7 @@ static const struct nla_policy nl80211_p
|
||||
[NL80211_ATTR_TXQ_QUANTUM] = { .type = NLA_U32 },
|
||||
@@ -431,6 +431,7 @@ static const struct nla_policy nl80211_p
|
||||
[NL80211_ATTR_HE_CAPABILITY] = { .type = NLA_BINARY,
|
||||
.len = NL80211_HE_MAX_CAPABILITY_LEN },
|
||||
[NL80211_ATTR_AIRTIME_WEIGHT] = NLA_POLICY_MIN(NLA_U16, 1),
|
||||
+ [NL80211_ATTR_WIPHY_ANTENNA_GAIN] = { .type = NLA_U32 },
|
||||
};
|
||||
|
||||
/* policy for the key attributes */
|
||||
@@ -2587,6 +2588,20 @@ static int nl80211_set_wiphy(struct sk_b
|
||||
@@ -2588,6 +2589,20 @@ static int nl80211_set_wiphy(struct sk_b
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
|
@ -1,21 +1,45 @@
|
||||
--- a/nl80211.h
|
||||
+++ b/nl80211.h
|
||||
@@ -2299,6 +2299,9 @@ enum nl80211_commands {
|
||||
@@ -2299,6 +2299,12 @@ enum nl80211_commands {
|
||||
* This is also used for capability advertisement in the wiphy information,
|
||||
* with the appropriate sub-attributes.
|
||||
*
|
||||
+ * @NL80211_ATTR_AIRTIME_WEIGHT: Station's weight when scheduled by the airtime
|
||||
+ * scheduler.
|
||||
+ *
|
||||
+ * @NL80211_ATTR_WIPHY_ANTENNA_GAIN: Configured antenna gain. Used to reduce
|
||||
+ * transmit power to stay within regulatory limits. u32, dBi.
|
||||
+ *
|
||||
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
|
||||
* @NL80211_ATTR_MAX: highest attribute number currently defined
|
||||
* @__NL80211_ATTR_AFTER_LAST: internal use
|
||||
@@ -2748,6 +2751,8 @@ enum nl80211_attrs {
|
||||
@@ -2748,6 +2754,10 @@ enum nl80211_attrs {
|
||||
|
||||
NL80211_ATTR_PEER_MEASUREMENTS,
|
||||
|
||||
+ NL80211_ATTR_AIRTIME_WEIGHT,
|
||||
+
|
||||
+ NL80211_ATTR_WIPHY_ANTENNA_GAIN,
|
||||
+
|
||||
/* add attributes here, update the policy in nl80211.c */
|
||||
|
||||
__NL80211_ATTR_AFTER_LAST,
|
||||
@@ -3125,6 +3135,9 @@ enum nl80211_sta_bss_param {
|
||||
* might not be fully accurate.
|
||||
* @NL80211_STA_INFO_CONNECTED_TO_GATE: set to true if STA has a path to a
|
||||
* mesh gate (u8, 0 or 1)
|
||||
+ * @NL80211_STA_INFO_TX_DURATION: aggregate PPDU duration for all frames
|
||||
+ * sent to the station (u64, usec)
|
||||
+ * @NL80211_STA_INFO_AIRTIME_WEIGHT: current airtime weight for station (u16)
|
||||
* @__NL80211_STA_INFO_AFTER_LAST: internal
|
||||
* @NL80211_STA_INFO_MAX: highest possible station info attribute
|
||||
*/
|
||||
@@ -3168,6 +3181,8 @@ enum nl80211_sta_info {
|
||||
NL80211_STA_INFO_RX_MPDUS,
|
||||
NL80211_STA_INFO_FCS_ERROR_COUNT,
|
||||
NL80211_STA_INFO_CONNECTED_TO_GATE,
|
||||
+ NL80211_STA_INFO_TX_DURATION,
|
||||
+ NL80211_STA_INFO_AIRTIME_WEIGHT,
|
||||
|
||||
/* keep last */
|
||||
__NL80211_STA_INFO_AFTER_LAST,
|
||||
|
Loading…
x
Reference in New Issue
Block a user