local->aql_txq_limit_low[i] = IEEE80211_DEFAULT_AQL_TXQ_LIMIT_L;
                local->aql_txq_limit_high[i] =
                        IEEE80211_DEFAULT_AQL_TXQ_LIMIT_H;
+               atomic_set(&local->aql_ac_pending_airtime[i], 0);
        }
 
        local->airtime_flags = AIRTIME_USE_TX | AIRTIME_USE_RX;
 
                                   &sta->airtime[ac].aql_tx_pending);
 
                atomic_add(tx_airtime, &local->aql_total_pending_airtime);
+               atomic_add(tx_airtime, &local->aql_ac_pending_airtime[ac]);
                return;
        }
 
                                       tx_pending, 0);
        }
 
+       atomic_sub(tx_airtime, &local->aql_total_pending_airtime);
        tx_pending = atomic_sub_return(tx_airtime,
-                                      &local->aql_total_pending_airtime);
+                                      &local->aql_ac_pending_airtime[ac]);
        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_airtime)) {
+               atomic_cmpxchg(&local->aql_ac_pending_airtime[ac],
                               tx_pending, 0);
+               atomic_sub(tx_pending, &local->aql_total_pending_airtime);
+       }
 }
 
 int sta_info_move_state(struct sta_info *sta,
 
 
        spin_lock_bh(&local->active_txq_lock[ac]);
 
+       if (!local->schedule_round[ac])
+               goto out;
+
  begin:
        txqi = list_first_entry_or_null(&local->active_txqs[ac],
                                        struct txq_info,
 }
 EXPORT_SYMBOL(ieee80211_txq_airtime_check);
 
+static bool
+ieee80211_txq_schedule_airtime_check(struct ieee80211_local *local, u8 ac)
+{
+       unsigned int num_txq = 0;
+       struct txq_info *txq;
+       u32 aql_limit;
+
+       if (!wiphy_ext_feature_isset(local->hw.wiphy, NL80211_EXT_FEATURE_AQL))
+               return true;
+
+       list_for_each_entry(txq, &local->active_txqs[ac], schedule_order)
+               num_txq++;
+
+       aql_limit = (num_txq - 1) * local->aql_txq_limit_low[ac] / 2 +
+                   local->aql_txq_limit_high[ac];
+
+       return atomic_read(&local->aql_ac_pending_airtime[ac]) < aql_limit;
+}
+
 bool ieee80211_txq_may_transmit(struct ieee80211_hw *hw,
                                struct ieee80211_txq *txq)
 {
        if (list_empty(&txqi->schedule_order))
                goto out;
 
+       if (!ieee80211_txq_schedule_airtime_check(local, ac))
+               goto out;
+
        list_for_each_entry_safe(iter, tmp, &local->active_txqs[ac],
                                 schedule_order) {
                if (iter == txqi)
        struct ieee80211_local *local = hw_to_local(hw);
 
        spin_lock_bh(&local->active_txq_lock[ac]);
-       local->schedule_round[ac]++;
+
+       if (ieee80211_txq_schedule_airtime_check(local, ac)) {
+               local->schedule_round[ac]++;
+               if (!local->schedule_round[ac])
+                       local->schedule_round[ac]++;
+       } else {
+               local->schedule_round[ac] = 0;
+       }
+
        spin_unlock_bh(&local->active_txq_lock[ac]);
 }
 EXPORT_SYMBOL(ieee80211_txq_schedule_start);