ath10k: report estimated frame transmit airtime to improve fairness
authorKan Yan <kyan@google.com>
Mon, 11 Feb 2019 16:47:52 +0000 (18:47 +0200)
committerKalle Valo <kvalo@codeaurora.org>
Tue, 12 Feb 2019 18:44:58 +0000 (20:44 +0200)
The airtime of a transmitted frame will be estimated from last used tx rate
which the firmware reports with the peer stats feature
(WMI_SERVICE_PEER_STATS). The airtime is computed on the tx path and it
will be reported to mac80211 upon tx completion.

This change is based on Kan's orginal commit in Chromium tree
("CHROMIUM: ath10k: Implementing airtime fairness based TX scheduler")
ref: https://chromium-review.googlesource.com/588190

Tested on QCA4019 with firmware version 10.4-3.2.1.1-00015
Tested on QCA9984 with firmware version 10.4-3.9.0.1-00005

Signed-off-by: Kan Yan <kyan@google.com>
[rmanohar@codeaurora.org: ported only the airtime computation]
Signed-off-by: Rajkumar Manoharan <rmanohar@codeaurora.org>
[toke@redhat.com: Rebase to mac80211-next, add test note]
Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
drivers/net/wireless/ath/ath10k/core.h
drivers/net/wireless/ath/ath10k/htt_rx.c
drivers/net/wireless/ath/ath10k/mac.c
drivers/net/wireless/ath/ath10k/txrx.c

index 4b730eec88d27afb3235ca1f226b19dc27f9ce27..59958664dde453bde74038ee02630075c83c0ae7 100644 (file)
@@ -126,6 +126,7 @@ struct ath10k_skb_cb {
        u8 flags;
        u8 eid;
        u16 msdu_id;
+       u16 airtime_est;
        struct ieee80211_vif *vif;
        struct ieee80211_txq *txq;
 } __packed;
@@ -498,6 +499,7 @@ struct ath10k_sta {
        u16 peer_id;
        struct rate_info txrate;
        struct ieee80211_tx_info tx_info;
+       u32 last_tx_bitrate;
 
        struct work_struct update_wk;
        u64 rx_duration;
index 98c525189087a42423229439341958c42f076ed4..77f494d52ec3194690702c71a43a6be86d34e04b 100644 (file)
@@ -3080,6 +3080,7 @@ ath10k_update_per_peer_tx_stats(struct ath10k *ar,
 
        arsta->txrate.nss = txrate.nss;
        arsta->txrate.bw = ath10k_bw_to_mac80211_bw(txrate.bw);
+       arsta->last_tx_bitrate = cfg80211_calculate_bitrate(&arsta->txrate);
        if (sgi)
                arsta->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
 
index 0d5215da410ad191427e81f05942ffa858c1d180..88c7b58c9e2f66c3b8ccafbbe28c5ba8b5d347d5 100644 (file)
@@ -3544,7 +3544,7 @@ static void ath10k_tx_h_add_p2p_noa_ie(struct ath10k *ar,
 static void ath10k_mac_tx_h_fill_cb(struct ath10k *ar,
                                    struct ieee80211_vif *vif,
                                    struct ieee80211_txq *txq,
-                                   struct sk_buff *skb)
+                                   struct sk_buff *skb, u16 airtime)
 {
        struct ieee80211_hdr *hdr = (void *)skb->data;
        struct ath10k_skb_cb *cb = ATH10K_SKB_CB(skb);
@@ -3561,6 +3561,7 @@ static void ath10k_mac_tx_h_fill_cb(struct ath10k *ar,
 
        cb->vif = vif;
        cb->txq = txq;
+       cb->airtime_est = airtime;
 }
 
 bool ath10k_mac_tx_frm_has_freq(struct ath10k *ar)
@@ -3948,6 +3949,49 @@ static bool ath10k_mac_tx_can_push(struct ieee80211_hw *hw,
        return false;
 }
 
+/* Return estimated airtime in microsecond, which is calculated using last
+ * reported TX rate. This is just a rough estimation because host driver has no
+ * knowledge of the actual transmit rate, retries or aggregation. If actual
+ * airtime can be reported by firmware, then delta between estimated and actual
+ * airtime can be adjusted from deficit.
+ */
+#define IEEE80211_ATF_OVERHEAD         100     /* IFS + some slot time */
+#define IEEE80211_ATF_OVERHEAD_IFS     16      /* IFS only */
+static u16 ath10k_mac_update_airtime(struct ath10k *ar,
+                                    struct ieee80211_txq *txq,
+                                    struct sk_buff *skb)
+{
+       struct ath10k_sta *arsta;
+       u32 pktlen;
+       u16 airtime = 0;
+
+       if (!txq || !txq->sta)
+               return airtime;
+
+       spin_lock_bh(&ar->data_lock);
+       arsta = (struct ath10k_sta *)txq->sta->drv_priv;
+
+       pktlen = skb->len + 38; /* Assume MAC header 30, SNAP 8 for most case */
+       if (arsta->last_tx_bitrate) {
+               /* airtime in us, last_tx_bitrate in 100kbps */
+               airtime = (pktlen * 8 * (1000 / 100))
+                               / arsta->last_tx_bitrate;
+               /* overhead for media access time and IFS */
+               airtime += IEEE80211_ATF_OVERHEAD_IFS;
+       } else {
+               /* This is mostly for throttle excessive BC/MC frames, and the
+                * airtime/rate doesn't need be exact. Airtime of BC/MC frames
+                * in 2G get some discount, which helps prevent very low rate
+                * frames from being blocked for too long.
+                */
+               airtime = (pktlen * 8 * (1000 / 100)) / 60; /* 6M */
+               airtime += IEEE80211_ATF_OVERHEAD;
+       }
+       spin_unlock_bh(&ar->data_lock);
+
+       return airtime;
+}
+
 int ath10k_mac_tx_push_txq(struct ieee80211_hw *hw,
                           struct ieee80211_txq *txq)
 {
@@ -3963,6 +4007,7 @@ int ath10k_mac_tx_push_txq(struct ieee80211_hw *hw,
        size_t skb_len;
        bool is_mgmt, is_presp;
        int ret;
+       u16 airtime;
 
        spin_lock_bh(&ar->htt.tx_lock);
        ret = ath10k_htt_tx_inc_pending(htt);
@@ -3980,7 +4025,8 @@ int ath10k_mac_tx_push_txq(struct ieee80211_hw *hw,
                return -ENOENT;
        }
 
-       ath10k_mac_tx_h_fill_cb(ar, vif, txq, skb);
+       airtime = ath10k_mac_update_airtime(ar, txq, skb);
+       ath10k_mac_tx_h_fill_cb(ar, vif, txq, skb, airtime);
 
        skb_len = skb->len;
        txmode = ath10k_mac_tx_h_get_txmode(ar, vif, sta, skb);
@@ -4247,8 +4293,10 @@ static void ath10k_mac_op_tx(struct ieee80211_hw *hw,
        bool is_mgmt;
        bool is_presp;
        int ret;
+       u16 airtime;
 
-       ath10k_mac_tx_h_fill_cb(ar, vif, txq, skb);
+       airtime = ath10k_mac_update_airtime(ar, txq, skb);
+       ath10k_mac_tx_h_fill_cb(ar, vif, txq, skb, airtime);
 
        txmode = ath10k_mac_tx_h_get_txmode(ar, vif, sta, skb);
        txpath = ath10k_mac_tx_h_get_txpath(ar, skb, txmode);
@@ -8604,6 +8652,9 @@ int ath10k_mac_register(struct ath10k *ar)
                wiphy_ext_feature_set(ar->hw->wiphy,
                                      NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT);
 
+       if (ath10k_peer_stats_enabled(ar))
+               wiphy_ext_feature_set(ar->hw->wiphy,
+                                     NL80211_EXT_FEATURE_AIRTIME_FAIRNESS);
        /*
         * on LL hardware queues are managed entirely by the FW
         * so we only advertise to mac we can do the queues thing
index f13d88906b5a723d1d17939e2ae552676f8206aa..44c13b884603c952290b4184e5e55e2cc91741e7 100644 (file)
@@ -95,6 +95,10 @@ int ath10k_txrx_tx_unref(struct ath10k_htt *htt,
                wake_up(&htt->empty_tx_wq);
        spin_unlock_bh(&htt->tx_lock);
 
+       if (txq && txq->sta)
+               ieee80211_sta_register_airtime(txq->sta, txq->tid,
+                                              skb_cb->airtime_est, 0);
+
        if (ar->bus_param.dev_type != ATH10K_DEV_TYPE_HL)
                dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE);