[Make-wifi-fast] [PATCH v3 3/6] mac80211: Add airtime accounting and scheduling to TXQs

Louie Lu me at louie.lu
Thu Nov 15 03:18:58 EST 2018


Hi Rajkumar, Toke,

I found the series (v3,4/6) remove the debugfs remove reset station's
airtime method, and didn't added at here.

Not sure how to help this kind of situation, do I need a separate
patch to fix this, or posting the patch here is fine?

----

>From 3a4a856c397345311c9d7f3679828cadc40e6a80 Mon Sep 17 00:00:00 2001
From: Louie Lu <git at louie.lu>
Date: Thu, 15 Nov 2018 16:13:57 +0800
Subject: [PATCH] mac80211: Add reset for station's airtime

Let user can reset station airtime status by debugfs, it will
reset all airtime deficit to `sta->airtime_weight` and reset rx/tx
airtime accumulate to 0.

diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c
index 446908ab3f5d..d84d2369a76e 100644
--- a/net/mac80211/debugfs_sta.c
+++ b/net/mac80211/debugfs_sta.c
@@ -233,7 +233,28 @@ static ssize_t sta_airtime_read(struct file
*file, char __user *userbuf,
     kfree(buf);
     return rv;
 }
-STA_OPS(airtime);
+
+/*
+ * FIXME: This *only* reset station airtime, didn't accept input
+ */
+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)
-- 
2.18.0


Rajkumar Manoharan <rmanohar at codeaurora.org> 於 2018年11月13日 週二 上午6:52寫道:
>
> From: Toke Høiland-Jørgensen <toke at toke.dk>
>
> 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 at codeaurora.org>
> Signed-off-by: Toke Høiland-Jørgensen <toke at toke.dk>
> Signed-off-by: Rajkumar Manoharan <rmanohar at codeaurora.org>
> ---
>  include/net/mac80211.h     | 59 ++++++++++++++++++++++++++++++
>  net/mac80211/cfg.c         |  3 ++
>  net/mac80211/debugfs.c     |  3 ++
>  net/mac80211/debugfs_sta.c | 50 ++++++++++++++++++++++++--
>  net/mac80211/ieee80211_i.h |  2 ++
>  net/mac80211/main.c        |  4 +++
>  net/mac80211/sta_info.c    | 44 +++++++++++++++++++++--
>  net/mac80211/sta_info.h    | 13 +++++++
>  net/mac80211/status.c      |  6 ++++
>  net/mac80211/tx.c          | 90 +++++++++++++++++++++++++++++++++++++++++++---
>  10 files changed, 264 insertions(+), 10 deletions(-)
>
> diff --git a/include/net/mac80211.h b/include/net/mac80211.h
> index 18b11c119b7e..c43d615ee9b1 100644
> --- a/include/net/mac80211.h
> +++ b/include/net/mac80211.h
> @@ -2357,6 +2357,9 @@ enum ieee80211_hw_flags {
>   * @tx_sk_pacing_shift: Pacing shift to set on TCP sockets when frames from
>   *     them are encountered. The default should typically not be changed,
>   *     unless the driver has good reasons for needing more buffers.
> + *
> + * @weight_multipler: Driver specific airtime weight multiplier used while
> + *     refilling deficit of each TXQ.
>   */
>  struct ieee80211_hw {
>         struct ieee80211_conf conf;
> @@ -2393,6 +2396,7 @@ struct ieee80211_hw {
>         const struct ieee80211_cipher_scheme *cipher_schemes;
>         u8 max_nan_de_entries;
>         u8 tx_sk_pacing_shift;
> +       u8 weight_multiplier;
>  };
>
>  static inline bool _ieee80211_hw_check(struct ieee80211_hw *hw,
> @@ -5393,6 +5397,34 @@ void ieee80211_sta_block_awake(struct ieee80211_hw *hw,
>  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
> @@ -6150,6 +6182,33 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
>  void ieee80211_txq_schedule_end(struct ieee80211_hw *hw, u8 ac);
>
>  /**
> + * 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.
> diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
> index 818aa0060349..57c59e5ceb98 100644
> --- a/net/mac80211/cfg.c
> +++ b/net/mac80211/cfg.c
> @@ -1447,6 +1447,9 @@ static int sta_apply_parameters(struct ieee80211_local *local,
>         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)) {
> diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
> index 3fe541e358f3..81c5fec2eae7 100644
> --- a/net/mac80211/debugfs.c
> +++ b/net/mac80211/debugfs.c
> @@ -383,6 +383,9 @@ void debugfs_hw_add(struct ieee80211_local *local)
>         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! */
> diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c
> index af5185a836e5..446908ab3f5d 100644
> --- a/net/mac80211/debugfs_sta.c
> +++ b/net/mac80211/debugfs_sta.c
> @@ -181,9 +181,9 @@ static ssize_t sta_aqm_read(struct file *file, char __user *userbuf,
>                                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();
> @@ -195,6 +195,46 @@ static ssize_t sta_aqm_read(struct file *file, char __user *userbuf,
>  }
>  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;
> +}
> +STA_OPS(airtime);
> +
>  static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf,
>                                         size_t count, loff_t *ppos)
>  {
> @@ -906,6 +946,10 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta)
>         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,
> diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
> index 33763a2eac81..c5b6ba571288 100644
> --- a/net/mac80211/ieee80211_i.h
> +++ b/net/mac80211/ieee80211_i.h
> @@ -1137,6 +1137,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;
>
>         /*
> diff --git a/net/mac80211/main.c b/net/mac80211/main.c
> index ba64757afea4..3710727fa9c1 100644
> --- a/net/mac80211/main.c
> +++ b/net/mac80211/main.c
> @@ -667,6 +667,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len,
>                 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);
> @@ -1153,6 +1154,9 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
>         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",
> diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
> index c2f5cb7df54f..25d47b2af7a9 100644
> --- a/net/mac80211/sta_info.c
> +++ b/net/mac80211/sta_info.c
> @@ -90,7 +90,6 @@ static void __cleanup_single_sta(struct sta_info *sta)
>         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) ||
> @@ -120,9 +119,7 @@ static void __cleanup_single_sta(struct sta_info *sta)
>
>                         txqi = to_txq_info(sta->sta.txq[i]);
>
> -                       spin_lock_bh(&fq->lock);
>                         ieee80211_txq_purge(local, txqi);
> -                       spin_unlock_bh(&fq->lock);
>                 }
>         }
>
> @@ -387,9 +384,12 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
>         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++)
> @@ -1826,6 +1826,27 @@ void ieee80211_sta_set_buffered(struct ieee80211_sta *pubsta,
>  }
>  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)
>  {
> @@ -2188,6 +2209,23 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo,
>                 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(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(NL80211_STA_INFO_TX_DURATION);
> +       }
> +
> +       if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_AIRTIME_WEIGHT))) {
> +               sinfo->airtime_weight = sta->airtime_weight;
> +               sinfo->filled |= BIT(NL80211_STA_INFO_AIRTIME_WEIGHT);
> +       }
> +
>         sinfo->rx_dropped_misc = sta->rx_stats.dropped;
>         if (sta->pcpu_rx_stats) {
>                 for_each_possible_cpu(cpu) {
> diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
> index 9a04327d71d1..b1b0fd6a2e21 100644
> --- 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.
>          */
> diff --git a/net/mac80211/status.c b/net/mac80211/status.c
> index aa4afbf0abaf..a1f1256448f5 100644
> --- a/net/mac80211/status.c
> +++ b/net/mac80211/status.c
> @@ -818,6 +818,12 @@ static void __ieee80211_tx_status(struct ieee80211_hw *hw,
>                         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)
> diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
> index 305965283506..3f417e80e041 100644
> --- a/net/mac80211/tx.c
> +++ b/net/mac80211/tx.c
> @@ -1488,8 +1488,11 @@ void ieee80211_txq_purge(struct ieee80211_local *local,
>         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]);
> @@ -3638,11 +3641,28 @@ struct ieee80211_txq *ieee80211_next_txq(struct ieee80211_hw *hw, u8 ac)
>
>         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->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 || txqi->schedule_round == local->schedule_round[ac])
> +       if (txqi->schedule_round == local->schedule_round[ac])
>                 return NULL;
>
>         list_del_init(&txqi->schedule_order);
> @@ -3660,12 +3680,74 @@ void ieee80211_return_txq(struct ieee80211_hw *hw,
>         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)
>  {
>         struct ieee80211_local *local = hw_to_local(hw);
> --
> 1.9.1
>
> _______________________________________________
> Make-wifi-fast mailing list
> Make-wifi-fast at lists.bufferbloat.net
> https://lists.bufferbloat.net/listinfo/make-wifi-fast


More information about the Make-wifi-fast mailing list