};
 };
 
+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_tx_status - extended tx status info for rate control
  *
 
                                      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;
 
        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);
 
                        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)
 
 
        WARN_ON_ONCE(softirq_count() == 0);
 
+       if (!ieee80211_txq_airtime_check(hw, txq))
+               return NULL;
+
 begin:
        spin_lock_bh(&fq->lock);
 
        }
 
        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: