{
        struct ieee80211_sta *sta = params->sta;
        u16 tid = params->tid;
+       struct ieee80211_txq *txq = sta->txq[tid];
+       struct rtw_txq *rtwtxq = (struct rtw_txq *)txq->drv_priv;
 
        switch (params->action) {
        case IEEE80211_AMPDU_TX_START:
        case IEEE80211_AMPDU_TX_STOP_CONT:
        case IEEE80211_AMPDU_TX_STOP_FLUSH:
        case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
+               clear_bit(RTW_TXQ_AMPDU, &rtwtxq->flags);
                ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
                break;
        case IEEE80211_AMPDU_TX_OPERATIONAL:
+               set_bit(RTW_TXQ_AMPDU, &rtwtxq->flags);
+               break;
        case IEEE80211_AMPDU_RX_START:
        case IEEE80211_AMPDU_RX_STOP:
                break;
 
        }
 }
 
+struct rtw_txq_ba_iter_data {
+};
+
+static void rtw_txq_ba_iter(void *data, struct ieee80211_sta *sta)
+{
+       struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv;
+       int ret;
+       u8 tid;
+
+       tid = find_first_bit(si->tid_ba, IEEE80211_NUM_TIDS);
+       while (tid != IEEE80211_NUM_TIDS) {
+               clear_bit(tid, si->tid_ba);
+               ret = ieee80211_start_tx_ba_session(sta, tid, 0);
+               if (ret == -EINVAL) {
+                       struct ieee80211_txq *txq;
+                       struct rtw_txq *rtwtxq;
+
+                       txq = sta->txq[tid];
+                       rtwtxq = (struct rtw_txq *)txq->drv_priv;
+                       set_bit(RTW_TXQ_BLOCK_BA, &rtwtxq->flags);
+               }
+
+               tid = find_first_bit(si->tid_ba, IEEE80211_NUM_TIDS);
+       }
+}
+
+static void rtw_txq_ba_work(struct work_struct *work)
+{
+       struct rtw_dev *rtwdev = container_of(work, struct rtw_dev, ba_work);
+       struct rtw_txq_ba_iter_data data;
+
+       rtw_iterate_stas_atomic(rtwdev, rtw_txq_ba_iter, &data);
+}
+
 void rtw_get_channel_params(struct cfg80211_chan_def *chandef,
                            struct rtw_channel_params *chan_params)
 {
        INIT_DELAYED_WORK(&coex->bt_reenable_work, rtw_coex_bt_reenable_work);
        INIT_DELAYED_WORK(&coex->defreeze_work, rtw_coex_defreeze_work);
        INIT_WORK(&rtwdev->c2h_work, rtw_c2h_work);
+       INIT_WORK(&rtwdev->ba_work, rtw_txq_ba_work);
        skb_queue_head_init(&rtwdev->c2h_queue);
        skb_queue_head_init(&rtwdev->coex.queue);
        skb_queue_head_init(&rtwdev->tx_report.queue);
        ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS);
        ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
        ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU);
+       ieee80211_hw_set(hw, HAS_RATE_CONTROL);
 
        hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
                                     BIT(NL80211_IFTYPE_AP) |
 
        RTW_REGD_MAX
 };
 
+enum rtw_txq_flags {
+       RTW_TXQ_AMPDU,
+       RTW_TXQ_BLOCK_BA,
+};
+
 enum rtw_flags {
        RTW_FLAG_RUNNING,
        RTW_FLAG_FW_RUNNING,
 
 struct rtw_txq {
        struct list_head list;
+
+       unsigned long flags;
        unsigned long last_push;
 };
 
        bool updated;
        u8 init_ra_lv;
        u64 ra_mask;
+
+       DECLARE_BITMAP(tid_ba, IEEE80211_NUM_TIDS);
 };
 
 struct rtw_vif {
        spinlock_t txq_lock;
        struct list_head txqs;
        struct tasklet_struct tx_tasklet;
+       struct work_struct ba_work;
 
        struct rtw_tx_report tx_report;
 
 
 #define WLAN_AMPDU_MAX_TIME            0x70
 #define WLAN_RTS_LEN_TH                        0xFF
 #define WLAN_RTS_TX_TIME_TH            0x08
-#define WLAN_MAX_AGG_PKT_LIMIT         0x20
-#define WLAN_RTS_MAX_AGG_PKT_LIMIT     0x20
+#define WLAN_MAX_AGG_PKT_LIMIT         0x3f
+#define WLAN_RTS_MAX_AGG_PKT_LIMIT     0x3f
 #define WLAN_PRE_TXCNT_TIME_TH         0x1E0
 #define FAST_EDCA_VO_TH                0x06
 #define FAST_EDCA_VI_TH                0x06
 
        ieee80211_free_txskb(rtwdev->hw, skb);
 }
 
+static void rtw_txq_check_agg(struct rtw_dev *rtwdev,
+                             struct rtw_txq *rtwtxq,
+                             struct sk_buff *skb)
+{
+       struct ieee80211_txq *txq = rtwtxq_to_txq(rtwtxq);
+       struct ieee80211_tx_info *info;
+       struct rtw_sta_info *si;
+
+       if (test_bit(RTW_TXQ_AMPDU, &rtwtxq->flags)) {
+               info = IEEE80211_SKB_CB(skb);
+               info->flags |= IEEE80211_TX_CTL_AMPDU;
+               return;
+       }
+
+       if (skb_get_queue_mapping(skb) == IEEE80211_AC_VO)
+               return;
+
+       if (test_bit(RTW_TXQ_BLOCK_BA, &rtwtxq->flags))
+               return;
+
+       if (unlikely(skb->protocol == cpu_to_be16(ETH_P_PAE)))
+               return;
+
+       if (!txq->sta)
+               return;
+
+       si = (struct rtw_sta_info *)txq->sta->drv_priv;
+       set_bit(txq->tid, si->tid_ba);
+
+       ieee80211_queue_work(rtwdev->hw, &rtwdev->ba_work);
+}
+
 static bool rtw_txq_dequeue(struct rtw_dev *rtwdev,
                            struct rtw_txq *rtwtxq)
 {
        if (!skb)
                return false;
 
+       rtw_txq_check_agg(rtwdev, rtwtxq, skb);
+
        control.sta = txq->sta;
        rtw_tx(rtwdev, &control, skb);
        rtwtxq->last_push = jiffies;