mac80211: Turn AQL into an NL80211_EXT_FEATURE
authorToke Høiland-Jørgensen <toke@redhat.com>
Thu, 12 Dec 2019 11:14:37 +0000 (12:14 +0100)
committerJohannes Berg <johannes.berg@intel.com>
Fri, 13 Dec 2019 09:34:04 +0000 (10:34 +0100)
Instead of just having an airtime flag in debugfs, turn AQL into a proper
NL80211_EXT_FEATURE, so drivers can turn it on when they are ready, and so
we also expose the presence of the feature to userspace.

This also has the effect of flipping the default, so drivers have to opt in
to using AQL instead of getting it by default with TXQs. To keep
functionality the same as pre-patch, we set this feature for ath10k (which
is where it is needed the most).

While we're at it, split out the debugfs interface so AQL gets its own
per-station debugfs file instead of using the 'airtime' file.

[Johannes:]
This effectively disables AQL for iwlwifi, where it fixes a number of
issues:
 * TSO in iwlwifi is causing underflows and associated warnings in AQL
 * HE (802.11ax) rates aren't reported properly so at HE rates, AQL could
   never have a valid estimate (it'd use 6 Mbps instead of up to 2400!)

Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
Link: https://lore.kernel.org/r/20191212111437.224294-1-toke@redhat.com
Fixes: 3ace10f5b5ad ("mac80211: Implement Airtime-based Queue Limit (AQL)")
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
drivers/net/wireless/ath/ath10k/mac.c
include/uapi/linux/nl80211.h
net/mac80211/debugfs_sta.c
net/mac80211/main.c
net/mac80211/sta_info.c
net/mac80211/sta_info.h
net/mac80211/tx.c

index 83cc8778ca1e31aabf5a5f56c6a0520d10216706..978f0037ed522e6047543cfee078110986c6880e 100644 (file)
@@ -8958,6 +8958,7 @@ int ath10k_mac_register(struct ath10k *ar)
        wiphy_ext_feature_set(ar->hw->wiphy, NL80211_EXT_FEATURE_VHT_IBSS);
        wiphy_ext_feature_set(ar->hw->wiphy,
                              NL80211_EXT_FEATURE_SET_SCAN_DWELL);
+       wiphy_ext_feature_set(ar->hw->wiphy, NL80211_EXT_FEATURE_AQL);
 
        if (test_bit(WMI_SERVICE_TX_DATA_ACK_RSSI, ar->wmi.svc_map) ||
            test_bit(WMI_SERVICE_HTT_MGMT_TX_COMP_VALID_FLAGS, ar->wmi.svc_map))
index 341e0e8cae46244debd4fe85152daed8927cbdef..5eab191607f86ca64cf6d10267d95c355a95e949 100644 (file)
@@ -5517,6 +5517,10 @@ enum nl80211_feature_flags {
  *     with VLAN tagged frames and separate VLAN-specific netdevs added using
  *     vconfig similarly to the Ethernet case.
  *
+ * @NL80211_EXT_FEATURE_AQL: The driver supports the Airtime Queue Limit (AQL)
+ *     feature, which prevents bufferbloat by using the expected transmission
+ *     time to limit the amount of data buffered in the hardware.
+ *
  * @NUM_NL80211_EXT_FEATURES: number of extended features.
  * @MAX_NL80211_EXT_FEATURES: highest extended feature index.
  */
@@ -5563,6 +5567,7 @@ enum nl80211_ext_feature_index {
        NL80211_EXT_FEATURE_STA_TX_PWR,
        NL80211_EXT_FEATURE_SAE_OFFLOAD,
        NL80211_EXT_FEATURE_VLAN_OFFLOAD,
+       NL80211_EXT_FEATURE_AQL,
 
        /* add new features before the definition below */
        NUM_NL80211_EXT_FEATURES,
index b3c9001d1f43d92a87104738b2de972a7e5425e2..c80b1e163ea4e6e7405af33acbc02b4fa2c1343c 100644 (file)
@@ -201,8 +201,6 @@ static ssize_t sta_airtime_read(struct file *file, char __user *userbuf,
        char *buf = kzalloc(bufsz, GFP_KERNEL), *p = buf;
        u64 rx_airtime = 0, tx_airtime = 0;
        s64 deficit[IEEE80211_NUM_ACS];
-       u32 q_depth[IEEE80211_NUM_ACS];
-       u32 q_limit_l[IEEE80211_NUM_ACS], q_limit_h[IEEE80211_NUM_ACS];
        ssize_t rv;
        int ac;
 
@@ -214,6 +212,56 @@ static ssize_t sta_airtime_read(struct file *file, char __user *userbuf,
                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_aql_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 = 400;
+       char *buf = kzalloc(bufsz, GFP_KERNEL), *p = buf;
+       u32 q_depth[IEEE80211_NUM_ACS];
+       u32 q_limit_l[IEEE80211_NUM_ACS], q_limit_h[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]);
                q_limit_l[ac] = sta->airtime[ac].aql_limit_low;
                q_limit_h[ac] = sta->airtime[ac].aql_limit_high;
                spin_unlock_bh(&local->active_txq_lock[ac]);
@@ -221,12 +269,8 @@ static ssize_t sta_airtime_read(struct file *file, char __user *userbuf,
        }
 
        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"
                "Q depth: VO: %u us VI: %u us BE: %u us BK: %u us\n"
                "Q limit[low/high]: VO: %u/%u VI: %u/%u BE: %u/%u BK: %u/%u\n",
-               rx_airtime, tx_airtime, sta->airtime_weight,
-               deficit[0], deficit[1], deficit[2], deficit[3],
                q_depth[0], q_depth[1], q_depth[2], q_depth[3],
                q_limit_l[0], q_limit_h[0], q_limit_l[1], q_limit_h[1],
                q_limit_l[2], q_limit_h[2], q_limit_l[3], q_limit_h[3]),
@@ -236,11 +280,10 @@ static ssize_t sta_airtime_read(struct file *file, char __user *userbuf,
        return rv;
 }
 
-static ssize_t sta_airtime_write(struct file *file, const char __user *userbuf,
+static ssize_t sta_aql_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;
        u32 ac, q_limit_l, q_limit_h;
        char _buf[100] = {}, *buf = _buf;
 
@@ -251,7 +294,7 @@ static ssize_t sta_airtime_write(struct file *file, const char __user *userbuf,
                return -EFAULT;
 
        buf[sizeof(_buf) - 1] = '\0';
-       if (sscanf(buf, "queue limit %u %u %u", &ac, &q_limit_l, &q_limit_h)
+       if (sscanf(buf, "limit %u %u %u", &ac, &q_limit_l, &q_limit_h)
            != 3)
                return -EINVAL;
 
@@ -261,17 +304,10 @@ static ssize_t sta_airtime_write(struct file *file, const char __user *userbuf,
        sta->airtime[ac].aql_limit_low = q_limit_l;
        sta->airtime[ac].aql_limit_high = q_limit_h;
 
-       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);
+STA_OPS_RW(aql);
+
 
 static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf,
                                        size_t count, loff_t *ppos)
@@ -996,6 +1032,10 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta)
                                    NL80211_EXT_FEATURE_AIRTIME_FAIRNESS))
                DEBUGFS_ADD(airtime);
 
+       if (wiphy_ext_feature_isset(local->hw.wiphy,
+                                   NL80211_EXT_FEATURE_AQL))
+               DEBUGFS_ADD(aql);
+
        debugfs_create_xul("driver_buffered_tids", 0400, sta->debugfs_dir,
                           &sta->driver_buffered_tids);
 
index 6cca0853f183f8737846c272418b4fe37ceb8dbd..4c2b5ba3ac094ff45718bda3a7b7fdd0431df959 100644 (file)
@@ -672,9 +672,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len,
                        IEEE80211_DEFAULT_AQL_TXQ_LIMIT_H;
        }
 
-       local->airtime_flags = AIRTIME_USE_TX |
-                              AIRTIME_USE_RX |
-                              AIRTIME_USE_AQL;
+       local->airtime_flags = AIRTIME_USE_TX | AIRTIME_USE_RX;
        local->aql_threshold = IEEE80211_AQL_THRESHOLD;
        atomic_set(&local->aql_total_pending_airtime, 0);
 
index 8eafd81e97b4858453f88cd692e2c949f1579b6e..0f5f406788852e2ee052fbeac52f236a081534a2 100644 (file)
@@ -1916,6 +1916,9 @@ void ieee80211_sta_update_pending_airtime(struct ieee80211_local *local,
 {
        int tx_pending;
 
+       if (!wiphy_ext_feature_isset(local->hw.wiphy, NL80211_EXT_FEATURE_AQL))
+               return;
+
        if (!tx_completed) {
                if (sta)
                        atomic_add(tx_airtime,
index ad5d8a4ae56d1e8eac382c7eb1e700d859e47860..c00e28585f9dbf92be06aef1245d05a987e1dc4f 100644 (file)
@@ -127,7 +127,6 @@ enum ieee80211_agg_stop_reason {
 /* Debugfs flags to enable/disable use of RX/TX airtime in scheduler */
 #define AIRTIME_USE_TX         BIT(0)
 #define AIRTIME_USE_RX         BIT(1)
-#define AIRTIME_USE_AQL                BIT(2)
 
 struct airtime_info {
        u64 rx_airtime;
index 38b58a00db46cf3ce0e0e427ea151c2cc942cee9..a8a7306a1f56c01bfaad49c412bc20222d642c61 100644 (file)
@@ -3677,7 +3677,7 @@ begin:
 
        IEEE80211_SKB_CB(skb)->control.vif = vif;
 
-       if (local->airtime_flags & AIRTIME_USE_AQL) {
+       if (wiphy_ext_feature_isset(local->hw.wiphy, NL80211_EXT_FEATURE_AQL)) {
                u32 airtime;
 
                airtime = ieee80211_calc_expected_tx_airtime(hw, vif, txq->sta,
@@ -3799,7 +3799,7 @@ bool ieee80211_txq_airtime_check(struct ieee80211_hw *hw,
        struct sta_info *sta;
        struct ieee80211_local *local = hw_to_local(hw);
 
-       if (!(local->airtime_flags & AIRTIME_USE_AQL))
+       if (!wiphy_ext_feature_isset(local->hw.wiphy, NL80211_EXT_FEATURE_AQL))
                return true;
 
        if (!txq->sta)