Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- From patchwork Tue Nov 19 06:06:07 2019
- Content-Type: text/plain; charset="utf-8"
- MIME-Version: 1.0
- Content-Transfer-Encoding: 8bit
- X-Patchwork-Submitter: Kan Yan <kyan@google.com>
- X-Patchwork-Id: 11250877
- X-Patchwork-Delegate: johannes@sipsolutions.net
- Return-Path: <SRS0=eo9X=ZL=vger.kernel.org=linux-wireless-owner@kernel.org>
- Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org
- [172.30.200.123])
- by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 97F14930
- for <patchwork-linux-wireless@patchwork.kernel.org>;
- Tue, 19 Nov 2019 06:06:25 +0000 (UTC)
- Received: from vger.kernel.org (vger.kernel.org [209.132.180.67])
- by mail.kernel.org (Postfix) with ESMTP id 7734720672
- for <patchwork-linux-wireless@patchwork.kernel.org>;
- Tue, 19 Nov 2019 06:06:25 +0000 (UTC)
- Authentication-Results: mail.kernel.org;
- dkim=pass (2048-bit key) header.d=google.com header.i=@google.com
- header.b="jzcfBOXO"
- Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand
- id S1728994AbfKSGGY (ORCPT
- <rfc822;patchwork-linux-wireless@patchwork.kernel.org>);
- Tue, 19 Nov 2019 01:06:24 -0500
- Received: from mail-pg1-f202.google.com ([209.85.215.202]:54341 "EHLO
- mail-pg1-f202.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org
- with ESMTP id S1728017AbfKSGGX (ORCPT
- <rfc822;linux-wireless@vger.kernel.org>);
- Tue, 19 Nov 2019 01:06:23 -0500
- Received: by mail-pg1-f202.google.com with SMTP id t28so14933858pgl.21
- for <linux-wireless@vger.kernel.org>;
- Mon, 18 Nov 2019 22:06:21 -0800 (PST)
- DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
- d=google.com; s=20161025;
- h=date:in-reply-to:message-id:mime-version:references:subject:from:to
- :cc:content-transfer-encoding;
- bh=SUJ++x/TlhzzyCi0jS7LtcmTW7wMb85gdnxub2e66+4=;
- b=jzcfBOXOxGybpn7TTyB80D1IkGi0bBq0gVKYBPTYxT3//xKRGogjWxHWfnUxLuQ6YF
- NUAibcBr6n7a2nLtzBvI1I/He3pN/eVNDKWeJqYZbYsd1e0gXsJXnTZ0pqpCzOi8f+3o
- fFHs+UGbTbQ3XIFzivdY7soT8yuSQwMlDXDRNYyktpg4/qepd+pTOYIpPIz4/S2UEkDh
- 7xOgJBp13PkQ34TvIckWDeiQdHqoNlPAUBEhFycLMS2E01YXo096G8e6p3or2T3fLjfG
- 4gmAFDtJPjGPuiFOViOrxXCIWg84AeT4iBVFhGsqhaFHxdRAYzggxqLkRclxkfxv4Rnq
- IEBA==
- X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
- d=1e100.net; s=20161025;
- h=x-gm-message-state:date:in-reply-to:message-id:mime-version
- :references:subject:from:to:cc:content-transfer-encoding;
- bh=SUJ++x/TlhzzyCi0jS7LtcmTW7wMb85gdnxub2e66+4=;
- b=VdCLKYUgoukaLMEzApy7mDNUHyPknx1Lb7ZnJAK73AYoCU01rksYh3bwvliY1XNu8h
- wt+j/Xeo8FtKmTgdX2P57B/AD6Tb3M1mfUeexgRfBDnIYzTmME8d2UvlahaTpvApDeW1
- HIFgNGvnCrRWwYjb1JM91P+ZbhZd8SJ53XZTmbjN+4ajLrF6scspfsbzMrm3yJqcDWEQ
- 3I4+inXgaTcykB2cwKV+VcIok5yp6KDftvVvjdhcV3aQAiCrxBBBCLGrjViuQ9vUTeqQ
- 3zJva+XTOxoCvlcDDoOrf0oAifty38zQcqyj87xXdQzYHxIGUkWh9I8cCGI1coUDGztW
- FWlw==
- X-Gm-Message-State: APjAAAUcfgy++sF4qvWYNEreAdurouFwF+fC1HjEXImvjP+1pjuviFB5
- kuA45Vu28r8izcB5dd96kWaZM19V
- X-Google-Smtp-Source:
- APXvYqzNV134LcY9JhSizYZkLWNChU1nezzOzXKtuUuyFIXvORQzS+wTNUd+ckq/gOiolRVK8ppuCq/Q
- X-Received: by 2002:a63:495b:: with SMTP id y27mr3614518pgk.438.1574143580296;
- Mon, 18 Nov 2019 22:06:20 -0800 (PST)
- Date: Mon, 18 Nov 2019 22:06:07 -0800
- In-Reply-To: <20191119060610.76681-1-kyan@google.com>
- Message-Id: <20191119060610.76681-2-kyan@google.com>
- Mime-Version: 1.0
- References: <20191119060610.76681-1-kyan@google.com>
- X-Mailer: git-send-email 2.24.0.432.g9d3f5f5b63-goog
- Subject: [PATCH v11 1/4] mac80211: Add new sta_info getter by sta/vif addrs
- From: Kan Yan <kyan@google.com>
- To: johannes@sipsolutions.net
- Cc: linux-wireless@vger.kernel.org,
- make-wifi-fast@lists.bufferbloat.net, toke@redhat.com,
- nbd@nbd.name, yiboz@codeaurora.org, john@phrozen.org,
- lorenzo@kernel.org, rmanohar@codeaurora.org, kevinhayes@google.com
- Sender: linux-wireless-owner@vger.kernel.org
- Precedence: bulk
- List-ID: <linux-wireless.vger.kernel.org>
- X-Mailing-List: linux-wireless@vger.kernel.org
- From: Toke Høiland-Jørgensen <toke@redhat.com>
- In ieee80211_tx_status() we don't have an sdata struct when looking up the
- destination sta. Instead, we just do a lookup by the vif addr that is the
- source of the packet being completed. Factor this out into a new sta_info
- getter helper, since we need to use it for accounting AQL as well.
- Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
- ---
- net/mac80211/sta_info.c | 20 ++++++++++++++++++++
- net/mac80211/sta_info.h | 3 +++
- net/mac80211/status.c | 10 ++--------
- 3 files changed, 25 insertions(+), 8 deletions(-)
- --- a/net/mac80211/sta_info.c
- +++ b/net/mac80211/sta_info.c
- @@ -210,6 +210,20 @@ struct sta_info *sta_info_get_bss(struct
- return NULL;
- }
- +struct sta_info *sta_info_get_by_addrs(struct ieee80211_local *local,
- + const u8 *sta_addr, const u8 *vif_addr)
- +{
- + struct rhlist_head *tmp;
- + struct sta_info *sta;
- +
- + for_each_sta_info(local, sta_addr, sta, tmp) {
- + if (ether_addr_equal(vif_addr, sta->sdata->vif.addr))
- + return sta;
- + }
- +
- + return NULL;
- +}
- +
- struct sta_info *sta_info_get_by_idx(struct ieee80211_sub_if_data *sdata,
- int idx)
- {
- @@ -397,6 +411,9 @@ struct sta_info *sta_info_alloc(struct i
- skb_queue_head_init(&sta->ps_tx_buf[i]);
- skb_queue_head_init(&sta->tx_filtered[i]);
- sta->airtime[i].deficit = sta->airtime_weight;
- + atomic_set(&sta->airtime[i].aql_tx_pending, 0);
- + sta->airtime[i].aql_limit_low = local->aql_txq_limit_low[i];
- + sta->airtime[i].aql_limit_high = local->aql_txq_limit_high[i];
- }
- for (i = 0; i < IEEE80211_NUM_TIDS; i++)
- @@ -1894,6 +1911,41 @@ void ieee80211_sta_register_airtime(stru
- }
- EXPORT_SYMBOL(ieee80211_sta_register_airtime);
- +void ieee80211_sta_update_pending_airtime(struct ieee80211_local *local,
- + struct sta_info *sta, u8 ac,
- + u16 tx_airtime, bool tx_completed)
- +{
- + int tx_pending;
- +
- + if (!tx_completed) {
- + if (sta)
- + atomic_add(tx_airtime,
- + &sta->airtime[ac].aql_tx_pending);
- +
- + atomic_add(tx_airtime, &local->aql_total_pending_airtime);
- + return;
- + }
- +
- + if (sta) {
- + tx_pending = atomic_sub_return(tx_airtime,
- + &sta->airtime[ac].aql_tx_pending);
- + if (WARN_ONCE(tx_pending < 0,
- + "STA %pM AC %d txq pending airtime underflow: %u, %u",
- + sta->addr, ac, tx_pending, tx_airtime))
- + atomic_cmpxchg(&sta->airtime[ac].aql_tx_pending,
- + tx_pending, 0);
- + }
- +
- + tx_pending = atomic_sub_return(tx_airtime,
- + &local->aql_total_pending_airtime);
- + if (WARN_ONCE(tx_pending < 0,
- + "Device %s AC %d pending airtime underflow: %u, %u",
- + wiphy_name(local->hw.wiphy), ac, tx_pending,
- + tx_airtime))
- + atomic_cmpxchg(&local->aql_total_pending_airtime,
- + tx_pending, 0);
- +}
- +
- int sta_info_move_state(struct sta_info *sta,
- enum ieee80211_sta_state new_state)
- {
- --- a/net/mac80211/sta_info.h
- +++ b/net/mac80211/sta_info.h
- @@ -127,13 +127,21 @@ 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;
- u64 tx_airtime;
- s64 deficit;
- + atomic_t aql_tx_pending; /* Estimated airtime for frames pending */
- + u32 aql_limit_low;
- + u32 aql_limit_high;
- };
- +void ieee80211_sta_update_pending_airtime(struct ieee80211_local *local,
- + struct sta_info *sta, u8 ac,
- + u16 tx_airtime, bool tx_completed);
- +
- struct sta_info;
- /**
- @@ -725,6 +733,10 @@ struct sta_info *sta_info_get(struct iee
- struct sta_info *sta_info_get_bss(struct ieee80211_sub_if_data *sdata,
- const u8 *addr);
- +/* user must hold sta_mtx or be in RCU critical section */
- +struct sta_info *sta_info_get_by_addrs(struct ieee80211_local *local,
- + const u8 *sta_addr, const u8 *vif_addr);
- +
- #define for_each_sta_info(local, _addr, _sta, _tmp) \
- rhl_for_each_entry_rcu(_sta, _tmp, \
- sta_info_hash_lookup(local, _addr), hash_node)
- --- a/net/mac80211/status.c
- +++ b/net/mac80211/status.c
- @@ -670,12 +670,26 @@ static void ieee80211_report_used_skb(st
- struct sk_buff *skb, bool dropped)
- {
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- + u16 tx_time_est = ieee80211_info_get_tx_time_est(info);
- struct ieee80211_hdr *hdr = (void *)skb->data;
- bool acked = info->flags & IEEE80211_TX_STAT_ACK;
- if (dropped)
- acked = false;
- + if (tx_time_est) {
- + struct sta_info *sta;
- +
- + rcu_read_lock();
- +
- + sta = sta_info_get_by_addrs(local, hdr->addr1, hdr->addr2);
- + ieee80211_sta_update_pending_airtime(local, sta,
- + skb_get_queue_mapping(skb),
- + tx_time_est,
- + true);
- + rcu_read_unlock();
- + }
- +
- if (info->flags & IEEE80211_TX_INTFL_MLME_CONN_TX) {
- struct ieee80211_sub_if_data *sdata;
- @@ -884,6 +898,7 @@ static void __ieee80211_tx_status(struct
- struct ieee80211_bar *bar;
- int shift = 0;
- int tid = IEEE80211_NUM_TIDS;
- + u16 tx_time_est;
- rates_idx = ieee80211_tx_get_rates(hw, info, &retry_count);
- @@ -993,6 +1008,17 @@ static void __ieee80211_tx_status(struct
- ieee80211_sta_register_airtime(&sta->sta, tid,
- info->status.tx_time, 0);
- + if ((tx_time_est = ieee80211_info_get_tx_time_est(info)) > 0) {
- + /* Do this here to avoid the expensive lookup of the sta
- + * in ieee80211_report_used_skb().
- + */
- + ieee80211_sta_update_pending_airtime(local, sta,
- + skb_get_queue_mapping(skb),
- + tx_time_est,
- + true);
- + ieee80211_info_set_tx_time_est(info, 0);
- + }
- +
- if (ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) {
- if (info->flags & IEEE80211_TX_STAT_ACK) {
- if (sta->status_stats.lost_packets)
- @@ -1080,19 +1106,13 @@ void ieee80211_tx_status(struct ieee8021
- .skb = skb,
- .info = IEEE80211_SKB_CB(skb),
- };
- - struct rhlist_head *tmp;
- struct sta_info *sta;
- rcu_read_lock();
- - for_each_sta_info(local, hdr->addr1, sta, tmp) {
- - /* skip wrong virtual interface */
- - if (!ether_addr_equal(hdr->addr2, sta->sdata->vif.addr))
- - continue;
- -
- + sta = sta_info_get_by_addrs(local, hdr->addr1, hdr->addr2);
- + if (sta)
- status.sta = &sta->sta;
- - break;
- - }
- __ieee80211_tx_status(hw, &status);
- rcu_read_unlock();
- --- a/include/net/mac80211.h
- +++ b/include/net/mac80211.h
- @@ -1073,6 +1073,22 @@ struct ieee80211_tx_status {
- struct rate_info *rate;
- };
- +static inline u16
- +ieee80211_info_set_tx_time_est(struct ieee80211_tx_info *info, u16 tx_time_est)
- +{
- + /* We only have 10 bits in tx_time_est, so store airtime
- + * in increments of 4us and clamp the maximum to 2**12-1
- + */
- + info->tx_time_est = min_t(u16, tx_time_est, 4095) >> 2;
- + return info->tx_time_est << 2;
- +}
- +
- +static inline u16
- +ieee80211_info_get_tx_time_est(struct ieee80211_tx_info *info)
- +{
- + return info->tx_time_est << 2;
- +}
- +
- /**
- * struct ieee80211_scan_ies - descriptors for different blocks of IEs
- *
- @@ -5559,6 +5575,18 @@ void ieee80211_sta_register_airtime(stru
- u32 tx_airtime, u32 rx_airtime);
- /**
- + * ieee80211_txq_airtime_check - check if a txq can send frame to device
- + *
- + * @hw: pointer obtained from ieee80211_alloc_hw()
- + * @txq: pointer obtained from station or virtual interface
- + *
- + * Return true if the AQL's airtime limit has not been reached and the txq can
- + * continue to send more packets to the device. Otherwise return false.
- + */
- +bool
- +ieee80211_txq_airtime_check(struct ieee80211_hw *hw, struct ieee80211_txq *txq);
- +
- +/**
- * 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
- @@ -6417,4 +6445,33 @@ void ieee80211_nan_func_match(struct iee
- struct cfg80211_nan_match_params *match,
- gfp_t gfp);
- +/**
- + * ieee80211_calc_rx_airtime - calculate estimated transmission airtime for RX.
- + *
- + * This function calculates the estimated airtime usage of a frame based on the
- + * rate information in the RX status struct and the frame length.
- + *
- + * @hw: pointer as obtained from ieee80211_alloc_hw()
- + * @status: &struct ieee80211_rx_status containing the transmission rate
- + * information.
- + * @len: frame length in bytes
- + */
- +u32 ieee80211_calc_rx_airtime(struct ieee80211_hw *hw,
- + struct ieee80211_rx_status *status,
- + int len);
- +
- +/**
- + * ieee80211_calc_tx_airtime - calculate estimated transmission airtime for TX.
- + *
- + * This function calculates the estimated airtime usage of a frame based on the
- + * rate information in the TX info struct and the frame length.
- + *
- + * @hw: pointer as obtained from ieee80211_alloc_hw()
- + * @info: &struct ieee80211_tx_info of the frame.
- + * @len: frame length in bytes
- + */
- +u32 ieee80211_calc_tx_airtime(struct ieee80211_hw *hw,
- + struct ieee80211_tx_info *info,
- + int len);
- +
- #endif /* MAC80211_H */
- --- a/net/mac80211/Makefile
- +++ b/net/mac80211/Makefile
- @@ -31,7 +31,8 @@ mac80211-y := \
- chan.o \
- trace.o mlme.o \
- tdls.o \
- - ocb.o
- + ocb.o \
- + airtime.o
- mac80211-$(CPTCFG_MAC80211_LEDS) += led.o
- mac80211-$(CPTCFG_MAC80211_DEBUGFS) += \
- --- /dev/null
- +++ b/net/mac80211/airtime.c
- @@ -0,0 +1,597 @@
- +// SPDX-License-Identifier: ISC
- +/*
- + * Copyright (C) 2019 Felix Fietkau <nbd@nbd.name>
- + */
- +
- +#include <net/mac80211.h>
- +#include "ieee80211_i.h"
- +#include "sta_info.h"
- +
- +#define AVG_PKT_SIZE 1024
- +
- +/* Number of bits for an average sized packet */
- +#define MCS_NBITS (AVG_PKT_SIZE << 3)
- +
- +/* Number of kilo-symbols (symbols * 1024) for a packet with (bps) bits per
- + * symbol. We use k-symbols to avoid rounding in the _TIME macros below.
- + */
- +#define MCS_N_KSYMS(bps) DIV_ROUND_UP(MCS_NBITS << 10, (bps))
- +
- +/* Transmission time (in 1024 * usec) for a packet containing (ksyms) * 1024
- + * symbols.
- + */
- +#define MCS_SYMBOL_TIME(sgi, ksyms) \
- + (sgi ? \
- + ((ksyms) * 4 * 18) / 20 : /* 3.6 us per sym */ \
- + ((ksyms) * 4) /* 4.0 us per sym */ \
- + )
- +
- +/* Transmit duration for the raw data part of an average sized packet */
- +#define MCS_DURATION(streams, sgi, bps) \
- + ((u32)MCS_SYMBOL_TIME(sgi, MCS_N_KSYMS((streams) * (bps))))
- +
- +#define MCS_DURATION_S(shift, streams, sgi, bps) \
- + ((u16)((MCS_DURATION(streams, sgi, bps) >> shift)))
- +
- +/* These should match the values in enum nl80211_he_gi */
- +#define HE_GI_08 0
- +#define HE_GI_16 1
- +#define HE_GI_32 2
- +
- +/* Transmission time (1024 usec) for a packet containing (ksyms) * k-symbols */
- +#define HE_SYMBOL_TIME(gi, ksyms) \
- + (gi == HE_GI_08 ? \
- + ((ksyms) * 16 * 17) / 20 : /* 13.6 us per sym */ \
- + (gi == HE_GI_16 ? \
- + ((ksyms) * 16 * 18) / 20 : /* 14.4 us per sym */ \
- + ((ksyms) * 16) /* 16.0 us per sym */ \
- + ))
- +
- +/* Transmit duration for the raw data part of an average sized packet */
- +#define HE_DURATION(streams, gi, bps) \
- + ((u32)HE_SYMBOL_TIME(gi, MCS_N_KSYMS((streams) * (bps))))
- +
- +#define HE_DURATION_S(shift, streams, gi, bps) \
- + (HE_DURATION(streams, gi, bps) >> shift)
- +
- +#define BW_20 0
- +#define BW_40 1
- +#define BW_80 2
- +#define BW_160 3
- +
- +/*
- + * Define group sort order: HT40 -> SGI -> #streams
- + */
- +#define IEEE80211_MAX_STREAMS 4
- +#define IEEE80211_HT_STREAM_GROUPS 4 /* BW(=2) * SGI(=2) */
- +#define IEEE80211_VHT_STREAM_GROUPS 8 /* BW(=4) * SGI(=2) */
- +
- +#define IEEE80211_HE_MAX_STREAMS 8
- +#define IEEE80211_HE_STREAM_GROUPS 12 /* BW(=4) * GI(=3) */
- +
- +#define IEEE80211_HT_GROUPS_NB (IEEE80211_MAX_STREAMS * \
- + IEEE80211_HT_STREAM_GROUPS)
- +#define IEEE80211_VHT_GROUPS_NB (IEEE80211_MAX_STREAMS * \
- + IEEE80211_VHT_STREAM_GROUPS)
- +#define IEEE80211_HE_GROUPS_NB (IEEE80211_HE_MAX_STREAMS * \
- + IEEE80211_HE_STREAM_GROUPS)
- +#define IEEE80211_GROUPS_NB (IEEE80211_HT_GROUPS_NB + \
- + IEEE80211_VHT_GROUPS_NB + \
- + IEEE80211_HE_GROUPS_NB)
- +
- +#define IEEE80211_HT_GROUP_0 0
- +#define IEEE80211_VHT_GROUP_0 (IEEE80211_HT_GROUP_0 + IEEE80211_HT_GROUPS_NB)
- +#define IEEE80211_HE_GROUP_0 (IEEE80211_VHT_GROUP_0 + IEEE80211_VHT_GROUPS_NB)
- +
- +#define MCS_GROUP_RATES 12
- +
- +#define HT_GROUP_IDX(_streams, _sgi, _ht40) \
- + IEEE80211_HT_GROUP_0 + \
- + IEEE80211_MAX_STREAMS * 2 * _ht40 + \
- + IEEE80211_MAX_STREAMS * _sgi + \
- + _streams - 1
- +
- +#define _MAX(a, b) (((a)>(b))?(a):(b))
- +
- +#define GROUP_SHIFT(duration) \
- + _MAX(0, 16 - __builtin_clz(duration))
- +
- +/* MCS rate information for an MCS group */
- +#define __MCS_GROUP(_streams, _sgi, _ht40, _s) \
- + [HT_GROUP_IDX(_streams, _sgi, _ht40)] = { \
- + .shift = _s, \
- + .duration = { \
- + MCS_DURATION_S(_s, _streams, _sgi, _ht40 ? 54 : 26), \
- + MCS_DURATION_S(_s, _streams, _sgi, _ht40 ? 108 : 52), \
- + MCS_DURATION_S(_s, _streams, _sgi, _ht40 ? 162 : 78), \
- + MCS_DURATION_S(_s, _streams, _sgi, _ht40 ? 216 : 104), \
- + MCS_DURATION_S(_s, _streams, _sgi, _ht40 ? 324 : 156), \
- + MCS_DURATION_S(_s, _streams, _sgi, _ht40 ? 432 : 208), \
- + MCS_DURATION_S(_s, _streams, _sgi, _ht40 ? 486 : 234), \
- + MCS_DURATION_S(_s, _streams, _sgi, _ht40 ? 540 : 260) \
- + } \
- +}
- +
- +#define MCS_GROUP_SHIFT(_streams, _sgi, _ht40) \
- + GROUP_SHIFT(MCS_DURATION(_streams, _sgi, _ht40 ? 54 : 26))
- +
- +#define MCS_GROUP(_streams, _sgi, _ht40) \
- + __MCS_GROUP(_streams, _sgi, _ht40, \
- + MCS_GROUP_SHIFT(_streams, _sgi, _ht40))
- +
- +#define VHT_GROUP_IDX(_streams, _sgi, _bw) \
- + (IEEE80211_VHT_GROUP_0 + \
- + IEEE80211_MAX_STREAMS * 2 * (_bw) + \
- + IEEE80211_MAX_STREAMS * (_sgi) + \
- + (_streams) - 1)
- +
- +#define BW2VBPS(_bw, r4, r3, r2, r1) \
- + (_bw == BW_160 ? r4 : _bw == BW_80 ? r3 : _bw == BW_40 ? r2 : r1)
- +
- +#define __VHT_GROUP(_streams, _sgi, _bw, _s) \
- + [VHT_GROUP_IDX(_streams, _sgi, _bw)] = { \
- + .shift = _s, \
- + .duration = { \
- + MCS_DURATION_S(_s, _streams, _sgi, \
- + BW2VBPS(_bw, 234, 117, 54, 26)), \
- + MCS_DURATION_S(_s, _streams, _sgi, \
- + BW2VBPS(_bw, 468, 234, 108, 52)), \
- + MCS_DURATION_S(_s, _streams, _sgi, \
- + BW2VBPS(_bw, 702, 351, 162, 78)), \
- + MCS_DURATION_S(_s, _streams, _sgi, \
- + BW2VBPS(_bw, 936, 468, 216, 104)), \
- + MCS_DURATION_S(_s, _streams, _sgi, \
- + BW2VBPS(_bw, 1404, 702, 324, 156)), \
- + MCS_DURATION_S(_s, _streams, _sgi, \
- + BW2VBPS(_bw, 1872, 936, 432, 208)), \
- + MCS_DURATION_S(_s, _streams, _sgi, \
- + BW2VBPS(_bw, 2106, 1053, 486, 234)), \
- + MCS_DURATION_S(_s, _streams, _sgi, \
- + BW2VBPS(_bw, 2340, 1170, 540, 260)), \
- + MCS_DURATION_S(_s, _streams, _sgi, \
- + BW2VBPS(_bw, 2808, 1404, 648, 312)), \
- + MCS_DURATION_S(_s, _streams, _sgi, \
- + BW2VBPS(_bw, 3120, 1560, 720, 346)) \
- + } \
- +}
- +
- +#define VHT_GROUP_SHIFT(_streams, _sgi, _bw) \
- + GROUP_SHIFT(MCS_DURATION(_streams, _sgi, \
- + BW2VBPS(_bw, 243, 117, 54, 26)))
- +
- +#define VHT_GROUP(_streams, _sgi, _bw) \
- + __VHT_GROUP(_streams, _sgi, _bw, \
- + VHT_GROUP_SHIFT(_streams, _sgi, _bw))
- +
- +
- +#define HE_GROUP_IDX(_streams, _gi, _bw) \
- + (IEEE80211_HE_GROUP_0 + \
- + IEEE80211_HE_MAX_STREAMS * 2 * (_bw) + \
- + IEEE80211_HE_MAX_STREAMS * (_gi) + \
- + (_streams) - 1)
- +
- +#define __HE_GROUP(_streams, _gi, _bw, _s) \
- + [HE_GROUP_IDX(_streams, _gi, _bw)] = { \
- + .shift = _s, \
- + .duration = { \
- + HE_DURATION_S(_s, _streams, _gi, \
- + BW2VBPS(_bw, 979, 489, 230, 115)), \
- + HE_DURATION_S(_s, _streams, _gi, \
- + BW2VBPS(_bw, 1958, 979, 475, 230)), \
- + HE_DURATION_S(_s, _streams, _gi, \
- + BW2VBPS(_bw, 2937, 1468, 705, 345)), \
- + HE_DURATION_S(_s, _streams, _gi, \
- + BW2VBPS(_bw, 3916, 1958, 936, 475)), \
- + HE_DURATION_S(_s, _streams, _gi, \
- + BW2VBPS(_bw, 5875, 2937, 1411, 705)), \
- + HE_DURATION_S(_s, _streams, _gi, \
- + BW2VBPS(_bw, 7833, 3916, 1872, 936)), \
- + HE_DURATION_S(_s, _streams, _gi, \
- + BW2VBPS(_bw, 8827, 4406, 2102, 1051)), \
- + HE_DURATION_S(_s, _streams, _gi, \
- + BW2VBPS(_bw, 9806, 4896, 2347, 1166)), \
- + HE_DURATION_S(_s, _streams, _gi, \
- + BW2VBPS(_bw, 11764, 5875, 2808, 1411)), \
- + HE_DURATION_S(_s, _streams, _gi, \
- + BW2VBPS(_bw, 13060, 6523, 3124, 1555)), \
- + HE_DURATION_S(_s, _streams, _gi, \
- + BW2VBPS(_bw, 14702, 7344, 3513, 1756)), \
- + HE_DURATION_S(_s, _streams, _gi, \
- + BW2VBPS(_bw, 16329, 8164, 3902, 1944)) \
- + } \
- +}
- +
- +#define HE_GROUP_SHIFT(_streams, _gi, _bw) \
- + GROUP_SHIFT(HE_DURATION(_streams, _gi, \
- + BW2VBPS(_bw, 979, 489, 230, 115)))
- +
- +#define HE_GROUP(_streams, _gi, _bw) \
- + __HE_GROUP(_streams, _gi, _bw, \
- + HE_GROUP_SHIFT(_streams, _gi, _bw))
- +struct mcs_group {
- + u8 shift;
- + u16 duration[MCS_GROUP_RATES];
- +};
- +
- +static const struct mcs_group airtime_mcs_groups[] = {
- + MCS_GROUP(1, 0, BW_20),
- + MCS_GROUP(2, 0, BW_20),
- + MCS_GROUP(3, 0, BW_20),
- + MCS_GROUP(4, 0, BW_20),
- +
- + MCS_GROUP(1, 1, BW_20),
- + MCS_GROUP(2, 1, BW_20),
- + MCS_GROUP(3, 1, BW_20),
- + MCS_GROUP(4, 1, BW_20),
- +
- + MCS_GROUP(1, 0, BW_40),
- + MCS_GROUP(2, 0, BW_40),
- + MCS_GROUP(3, 0, BW_40),
- + MCS_GROUP(4, 0, BW_40),
- +
- + MCS_GROUP(1, 1, BW_40),
- + MCS_GROUP(2, 1, BW_40),
- + MCS_GROUP(3, 1, BW_40),
- + MCS_GROUP(4, 1, BW_40),
- +
- + VHT_GROUP(1, 0, BW_20),
- + VHT_GROUP(2, 0, BW_20),
- + VHT_GROUP(3, 0, BW_20),
- + VHT_GROUP(4, 0, BW_20),
- +
- + VHT_GROUP(1, 1, BW_20),
- + VHT_GROUP(2, 1, BW_20),
- + VHT_GROUP(3, 1, BW_20),
- + VHT_GROUP(4, 1, BW_20),
- +
- + VHT_GROUP(1, 0, BW_40),
- + VHT_GROUP(2, 0, BW_40),
- + VHT_GROUP(3, 0, BW_40),
- + VHT_GROUP(4, 0, BW_40),
- +
- + VHT_GROUP(1, 1, BW_40),
- + VHT_GROUP(2, 1, BW_40),
- + VHT_GROUP(3, 1, BW_40),
- + VHT_GROUP(4, 1, BW_40),
- +
- + VHT_GROUP(1, 0, BW_80),
- + VHT_GROUP(2, 0, BW_80),
- + VHT_GROUP(3, 0, BW_80),
- + VHT_GROUP(4, 0, BW_80),
- +
- + VHT_GROUP(1, 1, BW_80),
- + VHT_GROUP(2, 1, BW_80),
- + VHT_GROUP(3, 1, BW_80),
- + VHT_GROUP(4, 1, BW_80),
- +
- + VHT_GROUP(1, 0, BW_160),
- + VHT_GROUP(2, 0, BW_160),
- + VHT_GROUP(3, 0, BW_160),
- + VHT_GROUP(4, 0, BW_160),
- +
- + VHT_GROUP(1, 1, BW_160),
- + VHT_GROUP(2, 1, BW_160),
- + VHT_GROUP(3, 1, BW_160),
- + VHT_GROUP(4, 1, BW_160),
- +
- + HE_GROUP(1, HE_GI_08, BW_20),
- + HE_GROUP(2, HE_GI_08, BW_20),
- + HE_GROUP(3, HE_GI_08, BW_20),
- + HE_GROUP(4, HE_GI_08, BW_20),
- + HE_GROUP(5, HE_GI_08, BW_20),
- + HE_GROUP(6, HE_GI_08, BW_20),
- + HE_GROUP(7, HE_GI_08, BW_20),
- + HE_GROUP(8, HE_GI_08, BW_20),
- +
- + HE_GROUP(1, HE_GI_16, BW_20),
- + HE_GROUP(2, HE_GI_16, BW_20),
- + HE_GROUP(3, HE_GI_16, BW_20),
- + HE_GROUP(4, HE_GI_16, BW_20),
- + HE_GROUP(5, HE_GI_16, BW_20),
- + HE_GROUP(6, HE_GI_16, BW_20),
- + HE_GROUP(7, HE_GI_16, BW_20),
- + HE_GROUP(8, HE_GI_16, BW_20),
- +
- + HE_GROUP(1, HE_GI_32, BW_20),
- + HE_GROUP(2, HE_GI_32, BW_20),
- + HE_GROUP(3, HE_GI_32, BW_20),
- + HE_GROUP(4, HE_GI_32, BW_20),
- + HE_GROUP(5, HE_GI_32, BW_20),
- + HE_GROUP(6, HE_GI_32, BW_20),
- + HE_GROUP(7, HE_GI_32, BW_20),
- + HE_GROUP(8, HE_GI_32, BW_20),
- +
- + HE_GROUP(1, HE_GI_08, BW_40),
- + HE_GROUP(2, HE_GI_08, BW_40),
- + HE_GROUP(3, HE_GI_08, BW_40),
- + HE_GROUP(4, HE_GI_08, BW_40),
- + HE_GROUP(5, HE_GI_08, BW_40),
- + HE_GROUP(6, HE_GI_08, BW_40),
- + HE_GROUP(7, HE_GI_08, BW_40),
- + HE_GROUP(8, HE_GI_08, BW_40),
- +
- + HE_GROUP(1, HE_GI_16, BW_40),
- + HE_GROUP(2, HE_GI_16, BW_40),
- + HE_GROUP(3, HE_GI_16, BW_40),
- + HE_GROUP(4, HE_GI_16, BW_40),
- + HE_GROUP(5, HE_GI_16, BW_40),
- + HE_GROUP(6, HE_GI_16, BW_40),
- + HE_GROUP(7, HE_GI_16, BW_40),
- + HE_GROUP(8, HE_GI_16, BW_40),
- +
- + HE_GROUP(1, HE_GI_32, BW_40),
- + HE_GROUP(2, HE_GI_32, BW_40),
- + HE_GROUP(3, HE_GI_32, BW_40),
- + HE_GROUP(4, HE_GI_32, BW_40),
- + HE_GROUP(5, HE_GI_32, BW_40),
- + HE_GROUP(6, HE_GI_32, BW_40),
- + HE_GROUP(7, HE_GI_32, BW_40),
- + HE_GROUP(8, HE_GI_32, BW_40),
- +
- + HE_GROUP(1, HE_GI_08, BW_80),
- + HE_GROUP(2, HE_GI_08, BW_80),
- + HE_GROUP(3, HE_GI_08, BW_80),
- + HE_GROUP(4, HE_GI_08, BW_80),
- + HE_GROUP(5, HE_GI_08, BW_80),
- + HE_GROUP(6, HE_GI_08, BW_80),
- + HE_GROUP(7, HE_GI_08, BW_80),
- + HE_GROUP(8, HE_GI_08, BW_80),
- +
- + HE_GROUP(1, HE_GI_16, BW_80),
- + HE_GROUP(2, HE_GI_16, BW_80),
- + HE_GROUP(3, HE_GI_16, BW_80),
- + HE_GROUP(4, HE_GI_16, BW_80),
- + HE_GROUP(5, HE_GI_16, BW_80),
- + HE_GROUP(6, HE_GI_16, BW_80),
- + HE_GROUP(7, HE_GI_16, BW_80),
- + HE_GROUP(8, HE_GI_16, BW_80),
- +
- + HE_GROUP(1, HE_GI_32, BW_80),
- + HE_GROUP(2, HE_GI_32, BW_80),
- + HE_GROUP(3, HE_GI_32, BW_80),
- + HE_GROUP(4, HE_GI_32, BW_80),
- + HE_GROUP(5, HE_GI_32, BW_80),
- + HE_GROUP(6, HE_GI_32, BW_80),
- + HE_GROUP(7, HE_GI_32, BW_80),
- + HE_GROUP(8, HE_GI_32, BW_80),
- +
- + HE_GROUP(1, HE_GI_08, BW_160),
- + HE_GROUP(2, HE_GI_08, BW_160),
- + HE_GROUP(3, HE_GI_08, BW_160),
- + HE_GROUP(4, HE_GI_08, BW_160),
- + HE_GROUP(5, HE_GI_08, BW_160),
- + HE_GROUP(6, HE_GI_08, BW_160),
- + HE_GROUP(7, HE_GI_08, BW_160),
- + HE_GROUP(8, HE_GI_08, BW_160),
- +
- + HE_GROUP(1, HE_GI_16, BW_160),
- + HE_GROUP(2, HE_GI_16, BW_160),
- + HE_GROUP(3, HE_GI_16, BW_160),
- + HE_GROUP(4, HE_GI_16, BW_160),
- + HE_GROUP(5, HE_GI_16, BW_160),
- + HE_GROUP(6, HE_GI_16, BW_160),
- + HE_GROUP(7, HE_GI_16, BW_160),
- + HE_GROUP(8, HE_GI_16, BW_160),
- +
- + HE_GROUP(1, HE_GI_32, BW_160),
- + HE_GROUP(2, HE_GI_32, BW_160),
- + HE_GROUP(3, HE_GI_32, BW_160),
- + HE_GROUP(4, HE_GI_32, BW_160),
- + HE_GROUP(5, HE_GI_32, BW_160),
- + HE_GROUP(6, HE_GI_32, BW_160),
- + HE_GROUP(7, HE_GI_32, BW_160),
- + HE_GROUP(8, HE_GI_32, BW_160),
- +};
- +
- +static u32
- +ieee80211_calc_legacy_rate_duration(u16 bitrate, bool short_pre,
- + bool cck, int len)
- +{
- + u32 duration;
- +
- + if (cck) {
- + duration = 144 + 48; /* preamble + PLCP */
- + if (short_pre)
- + duration >>= 1;
- +
- + duration += 10; /* SIFS */
- + } else {
- + duration = 20 + 16; /* premable + SIFS */
- + }
- +
- + len <<= 3;
- + duration += (len * 10) / bitrate;
- +
- + return duration;
- +}
- +
- +u32 ieee80211_calc_rx_airtime(struct ieee80211_hw *hw,
- + struct ieee80211_rx_status *status,
- + int len)
- +{
- + struct ieee80211_supported_band *sband;
- + const struct ieee80211_rate *rate;
- + bool sgi = status->enc_flags & RX_ENC_FLAG_SHORT_GI;
- + bool sp = status->enc_flags & RX_ENC_FLAG_SHORTPRE;
- + int bw, streams;
- + int group, idx;
- + u32 duration;
- + bool cck;
- +
- + switch (status->bw) {
- + case RATE_INFO_BW_20:
- + bw = BW_20;
- + break;
- + case RATE_INFO_BW_40:
- + bw = BW_40;
- + break;
- + case RATE_INFO_BW_80:
- + bw = BW_80;
- + break;
- + case RATE_INFO_BW_160:
- + bw = BW_160;
- + break;
- + default:
- + WARN_ON_ONCE(1);
- + return 0;
- + }
- +
- + switch (status->encoding) {
- + case RX_ENC_LEGACY:
- + if (WARN_ON_ONCE(status->band > NL80211_BAND_5GHZ))
- + return 0;
- +
- + sband = hw->wiphy->bands[status->band];
- + if (!sband || status->rate_idx > sband->n_bitrates)
- + return 0;
- +
- + rate = &sband->bitrates[status->rate_idx];
- + cck = rate->flags & IEEE80211_RATE_MANDATORY_B;
- +
- + return ieee80211_calc_legacy_rate_duration(rate->bitrate, sp,
- + cck, len);
- +
- + case RX_ENC_VHT:
- + streams = status->nss;
- + idx = status->rate_idx;
- + group = VHT_GROUP_IDX(streams, sgi, bw);
- + break;
- + case RX_ENC_HT:
- + streams = ((status->rate_idx >> 3) & 3) + 1;
- + idx = status->rate_idx & 7;
- + group = HT_GROUP_IDX(streams, sgi, bw);
- + break;
- + case RX_ENC_HE:
- + streams = status->nss;
- + idx = status->rate_idx;
- + group = HE_GROUP_IDX(streams, status->he_gi, bw);
- + break;
- + default:
- + WARN_ON_ONCE(1);
- + return 0;
- + }
- +
- + if (WARN_ON_ONCE((status->encoding != RX_ENC_HE && streams > 4) ||
- + (status->encoding == RX_ENC_HE && streams > 8)))
- + return 0;
- +
- + duration = airtime_mcs_groups[group].duration[idx];
- + duration <<= airtime_mcs_groups[group].shift;
- + duration *= len;
- + duration /= AVG_PKT_SIZE;
- + duration /= 1024;
- +
- + duration += 36 + (streams << 2);
- +
- + return duration;
- +}
- +EXPORT_SYMBOL_GPL(ieee80211_calc_rx_airtime);
- +
- +static u32 ieee80211_calc_tx_airtime_rate(struct ieee80211_hw *hw,
- + struct ieee80211_tx_rate *rate,
- + u8 band, int len)
- +{
- + struct ieee80211_rx_status stat = {
- + .band = band,
- + };
- +
- + if (rate->idx < 0 || !rate->count)
- + return 0;
- +
- + if (rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH)
- + stat.bw = RATE_INFO_BW_80;
- + else if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
- + stat.bw = RATE_INFO_BW_40;
- + else
- + stat.bw = RATE_INFO_BW_20;
- +
- + stat.enc_flags = 0;
- + if (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
- + stat.enc_flags |= RX_ENC_FLAG_SHORTPRE;
- + if (rate->flags & IEEE80211_TX_RC_SHORT_GI)
- + stat.enc_flags |= RX_ENC_FLAG_SHORT_GI;
- +
- + stat.rate_idx = rate->idx;
- + if (rate->flags & IEEE80211_TX_RC_VHT_MCS) {
- + stat.encoding = RX_ENC_VHT;
- + stat.rate_idx = ieee80211_rate_get_vht_mcs(rate);
- + stat.nss = ieee80211_rate_get_vht_nss(rate);
- + } else if (rate->flags & IEEE80211_TX_RC_MCS) {
- + stat.encoding = RX_ENC_HT;
- + } else {
- + stat.encoding = RX_ENC_LEGACY;
- + }
- +
- + return ieee80211_calc_rx_airtime(hw, &stat, len);
- +}
- +
- +u32 ieee80211_calc_tx_airtime(struct ieee80211_hw *hw,
- + struct ieee80211_tx_info *info,
- + int len)
- +{
- + u32 duration = 0;
- + int i;
- +
- + for (i = 0; i < ARRAY_SIZE(info->status.rates); i++) {
- + struct ieee80211_tx_rate *rate = &info->status.rates[i];
- + u32 cur_duration;
- +
- + cur_duration = ieee80211_calc_tx_airtime_rate(hw, rate,
- + info->band, len);
- + if (!cur_duration)
- + break;
- +
- + duration += cur_duration * rate->count;
- + }
- +
- + return duration;
- +}
- +EXPORT_SYMBOL_GPL(ieee80211_calc_tx_airtime);
- +
- +u32 ieee80211_calc_expected_tx_airtime(struct ieee80211_hw *hw,
- + struct ieee80211_vif *vif,
- + struct ieee80211_sta *pubsta,
- + int len)
- +{
- + struct ieee80211_supported_band *sband;
- + struct ieee80211_chanctx_conf *conf;
- + int rateidx, shift = 0;
- + bool cck, short_pream;
- + u32 basic_rates;
- + u8 band = 0;
- + u16 rate;
- +
- + len += 38; /* Ethernet header length */
- +
- + conf = rcu_dereference(vif->chanctx_conf);
- + if (conf) {
- + band = conf->def.chan->band;
- + shift = ieee80211_chandef_get_shift(&conf->def);
- + }
- +
- + if (pubsta) {
- + struct sta_info *sta = container_of(pubsta, struct sta_info,
- + sta);
- +
- + return ieee80211_calc_tx_airtime_rate(hw,
- + &sta->tx_stats.last_rate,
- + band, len);
- + }
- +
- + if (!conf)
- + return 0;
- +
- + /* No station to get latest rate from, so calculate the worst-case
- + * duration using the lowest configured basic rate.
- + */
- + sband = hw->wiphy->bands[band];
- +
- + basic_rates = vif->bss_conf.basic_rates;
- + short_pream = vif->bss_conf.use_short_preamble;
- +
- + rateidx = basic_rates ? ffs(basic_rates) - 1 : 0;
- + rate = sband->bitrates[rateidx].bitrate << shift;
- + cck = sband->bitrates[rateidx].flags & IEEE80211_RATE_MANDATORY_B;
- +
- + return ieee80211_calc_legacy_rate_duration(rate, short_pream, cck, len);
- +}
- --- a/net/mac80211/ieee80211_i.h
- +++ b/net/mac80211/ieee80211_i.h
- @@ -1142,6 +1142,10 @@ struct ieee80211_local {
- u16 schedule_round[IEEE80211_NUM_ACS];
- u16 airtime_flags;
- + u32 aql_txq_limit_low[IEEE80211_NUM_ACS];
- + u32 aql_txq_limit_high[IEEE80211_NUM_ACS];
- + u32 aql_threshold;
- + atomic_t aql_total_pending_airtime;
- const struct ieee80211_ops *ops;
- @@ -2254,6 +2258,10 @@ const char *ieee80211_get_reason_code_st
- extern const struct ethtool_ops ieee80211_ethtool_ops;
- +u32 ieee80211_calc_expected_tx_airtime(struct ieee80211_hw *hw,
- + struct ieee80211_vif *vif,
- + struct ieee80211_sta *pubsta,
- + int len);
- #ifdef CPTCFG_MAC80211_NOINLINE
- #define debug_noinline noinline
- #else
- --- a/include/net/cfg80211.h
- +++ b/include/net/cfg80211.h
- @@ -2603,6 +2603,13 @@ enum wiphy_params_flags {
- #define IEEE80211_DEFAULT_AIRTIME_WEIGHT 256
- +/* The per TXQ device queue limit in airtime */
- +#define IEEE80211_DEFAULT_AQL_TXQ_LIMIT_L 5000
- +#define IEEE80211_DEFAULT_AQL_TXQ_LIMIT_H 12000
- +
- +/* The per interface airtime threshold to switch to lower queue limit */
- +#define IEEE80211_AQL_THRESHOLD 24000
- +
- /**
- * struct cfg80211_pmksa - PMK Security Association
- *
- --- a/net/mac80211/debugfs.c
- +++ b/net/mac80211/debugfs.c
- @@ -148,6 +148,87 @@ static const struct file_operations aqm_
- .llseek = default_llseek,
- };
- +static ssize_t aql_txq_limit_read(struct file *file,
- + char __user *user_buf,
- + size_t count,
- + loff_t *ppos)
- +{
- + struct ieee80211_local *local = file->private_data;
- + char buf[400];
- + int len = 0;
- +
- + len = scnprintf(buf, sizeof(buf),
- + "AC AQL limit low AQL limit high\n"
- + "VO %u %u\n"
- + "VI %u %u\n"
- + "BE %u %u\n"
- + "BK %u %u\n",
- + local->aql_txq_limit_low[IEEE80211_AC_VO],
- + local->aql_txq_limit_high[IEEE80211_AC_VO],
- + local->aql_txq_limit_low[IEEE80211_AC_VI],
- + local->aql_txq_limit_high[IEEE80211_AC_VI],
- + local->aql_txq_limit_low[IEEE80211_AC_BE],
- + local->aql_txq_limit_high[IEEE80211_AC_BE],
- + local->aql_txq_limit_low[IEEE80211_AC_BK],
- + local->aql_txq_limit_high[IEEE80211_AC_BK]);
- + return simple_read_from_buffer(user_buf, count, ppos,
- + buf, len);
- +}
- +
- +static ssize_t aql_txq_limit_write(struct file *file,
- + const char __user *user_buf,
- + size_t count,
- + loff_t *ppos)
- +{
- + struct ieee80211_local *local = file->private_data;
- + char buf[100];
- + size_t len;
- + u32 ac, q_limit_low, q_limit_high, q_limit_low_old, q_limit_high_old;
- + struct sta_info *sta;
- +
- + if (count > sizeof(buf))
- + return -EINVAL;
- +
- + if (copy_from_user(buf, user_buf, count))
- + return -EFAULT;
- +
- + buf[sizeof(buf) - 1] = 0;
- + len = strlen(buf);
- + if (len > 0 && buf[len - 1] == '\n')
- + buf[len - 1] = 0;
- +
- + if (sscanf(buf, "%u %u %u", &ac, &q_limit_low, &q_limit_high) != 3)
- + return -EINVAL;
- +
- + if (ac >= IEEE80211_NUM_ACS)
- + return -EINVAL;
- +
- + q_limit_low_old = local->aql_txq_limit_low[ac];
- + q_limit_high_old = local->aql_txq_limit_high[ac];
- +
- + local->aql_txq_limit_low[ac] = q_limit_low;
- + local->aql_txq_limit_high[ac] = q_limit_high;
- +
- + mutex_lock(&local->sta_mtx);
- + list_for_each_entry(sta, &local->sta_list, list) {
- + /* If a sta has customized queue limits, keep it */
- + if (sta->airtime[ac].aql_limit_low == q_limit_low_old &&
- + sta->airtime[ac].aql_limit_high == q_limit_high_old) {
- + sta->airtime[ac].aql_limit_low = q_limit_low;
- + sta->airtime[ac].aql_limit_high = q_limit_high;
- + }
- + }
- + mutex_unlock(&local->sta_mtx);
- + return count;
- +}
- +
- +static const struct file_operations aql_txq_limit_ops = {
- + .write = aql_txq_limit_write,
- + .read = aql_txq_limit_read,
- + .open = simple_open,
- + .llseek = default_llseek,
- +};
- +
- static ssize_t force_tx_status_read(struct file *file,
- char __user *user_buf,
- size_t count,
- @@ -441,6 +522,10 @@ void debugfs_hw_add(struct ieee80211_loc
- debugfs_create_u16("airtime_flags", 0600,
- phyd, &local->airtime_flags);
- + DEBUGFS_ADD(aql_txq_limit);
- + debugfs_create_u32("aql_threshold", 0600,
- + phyd, &local->aql_threshold);
- +
- 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
- @@ -197,10 +197,12 @@ static ssize_t sta_airtime_read(struct f
- {
- struct sta_info *sta = file->private_data;
- struct ieee80211_local *local = sta->sdata->local;
- - size_t bufsz = 200;
- + size_t bufsz = 400;
- 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;
- @@ -212,19 +214,22 @@ static ssize_t sta_airtime_read(struct f
- rx_airtime += sta->airtime[ac].rx_airtime;
- tx_airtime += sta->airtime[ac].tx_airtime;
- deficit[ac] = sta->airtime[ac].deficit;
- + 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]);
- + q_depth[ac] = atomic_read(&sta->airtime[ac].aql_tx_pending);
- }
- 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]);
- + "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]),
- rv = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
- kfree(buf);
- @@ -236,7 +241,25 @@ static ssize_t sta_airtime_write(struct
- {
- struct sta_info *sta = file->private_data;
- struct ieee80211_local *local = sta->sdata->local;
- - int ac;
- + u32 ac, q_limit_l, q_limit_h;
- + char _buf[100] = {}, *buf = _buf;
- +
- + if (count > sizeof(_buf))
- + return -EINVAL;
- +
- + if (copy_from_user(buf, userbuf, count))
- + return -EFAULT;
- +
- + buf[sizeof(_buf) - 1] = '\0';
- + if (sscanf(buf, "queue limit %u %u %u", &ac, &q_limit_l, &q_limit_h)
- + != 3)
- + return -EINVAL;
- +
- + if (ac >= IEEE80211_NUM_ACS)
- + return -EINVAL;
- +
- + 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]);
- --- a/net/mac80211/main.c
- +++ b/net/mac80211/main.c
- @@ -676,8 +676,16 @@ struct ieee80211_hw *ieee80211_alloc_hw_
- for (i = 0; i < IEEE80211_NUM_ACS; i++) {
- INIT_LIST_HEAD(&local->active_txqs[i]);
- spin_lock_init(&local->active_txq_lock[i]);
- + local->aql_txq_limit_low[i] = IEEE80211_DEFAULT_AQL_TXQ_LIMIT_L;
- + local->aql_txq_limit_high[i] =
- + IEEE80211_DEFAULT_AQL_TXQ_LIMIT_H;
- }
- - local->airtime_flags = AIRTIME_USE_TX | AIRTIME_USE_RX;
- +
- + local->airtime_flags = AIRTIME_USE_TX |
- + AIRTIME_USE_RX |
- + AIRTIME_USE_AQL;
- + local->aql_threshold = IEEE80211_AQL_THRESHOLD;
- + atomic_set(&local->aql_total_pending_airtime, 0);
- INIT_LIST_HEAD(&local->chanctx_list);
- mutex_init(&local->chanctx_mtx);
- --- a/net/mac80211/tx.c
- +++ b/net/mac80211/tx.c
- @@ -3535,6 +3535,9 @@ struct sk_buff *ieee80211_tx_dequeue(str
- WARN_ON_ONCE(softirq_count() == 0);
- + if (!ieee80211_txq_airtime_check(hw, txq))
- + return NULL;
- +
- begin:
- spin_lock_bh(&fq->lock);
- @@ -3645,6 +3648,21 @@ begin:
- }
- IEEE80211_SKB_CB(skb)->control.vif = vif;
- +
- + if (local->airtime_flags & AIRTIME_USE_AQL) {
- + u32 airtime;
- +
- + airtime = ieee80211_calc_expected_tx_airtime(hw, vif, txq->sta,
- + skb->len);
- + if (airtime) {
- + airtime = ieee80211_info_set_tx_time_est(info, airtime);
- + ieee80211_sta_update_pending_airtime(local, tx.sta,
- + txq->ac,
- + airtime,
- + false);
- + }
- + }
- +
- return skb;
- out:
- @@ -3658,7 +3676,8 @@ struct ieee80211_txq *ieee80211_next_txq
- {
- struct ieee80211_local *local = hw_to_local(hw);
- struct ieee80211_txq *ret = NULL;
- - struct txq_info *txqi = NULL;
- + struct txq_info *txqi = NULL, *head = NULL;
- + bool found_eligible_txq = false;
- spin_lock_bh(&local->active_txq_lock[ac]);
- @@ -3669,13 +3688,30 @@ struct ieee80211_txq *ieee80211_next_txq
- if (!txqi)
- goto out;
- + if (txqi == head) {
- + if (!found_eligible_txq)
- + goto out;
- + else
- + found_eligible_txq = false;
- + }
- +
- + if (!head)
- + head = txqi;
- +
- if (txqi->txq.sta) {
- struct sta_info *sta = container_of(txqi->txq.sta,
- - struct sta_info, sta);
- + struct sta_info, sta);
- + bool aql_check = ieee80211_txq_airtime_check(hw, &txqi->txq);
- + s64 deficit = sta->airtime[txqi->txq.ac].deficit;
- - if (sta->airtime[txqi->txq.ac].deficit < 0) {
- + if (aql_check)
- + found_eligible_txq = true;
- +
- + if (deficit < 0)
- sta->airtime[txqi->txq.ac].deficit +=
- sta->airtime_weight;
- +
- + if (deficit < 0 || !aql_check) {
- list_move_tail(&txqi->schedule_order,
- &local->active_txqs[txqi->txq.ac]);
- goto begin;
- @@ -3729,6 +3765,33 @@ void __ieee80211_schedule_txq(struct iee
- }
- EXPORT_SYMBOL(__ieee80211_schedule_txq);
- +bool ieee80211_txq_airtime_check(struct ieee80211_hw *hw,
- + struct ieee80211_txq *txq)
- +{
- + struct sta_info *sta;
- + struct ieee80211_local *local = hw_to_local(hw);
- +
- + if (!(local->airtime_flags & AIRTIME_USE_AQL))
- + return true;
- +
- + if (!txq->sta)
- + return true;
- +
- + sta = container_of(txq->sta, struct sta_info, sta);
- + if (atomic_read(&sta->airtime[txq->ac].aql_tx_pending) <
- + sta->airtime[txq->ac].aql_limit_low)
- + return true;
- +
- + if (atomic_read(&local->aql_total_pending_airtime) <
- + local->aql_threshold &&
- + atomic_read(&sta->airtime[txq->ac].aql_tx_pending) <
- + sta->airtime[txq->ac].aql_limit_high)
- + return true;
- +
- + return false;
- +}
- +EXPORT_SYMBOL(ieee80211_txq_airtime_check);
- +
- bool ieee80211_txq_may_transmit(struct ieee80211_hw *hw,
- struct ieee80211_txq *txq)
- {
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement