enum iwl_bt_coex_lut_type ret;
        u16 phy_ctx_id;
 
-       lockdep_assert_held(&mvm->mutex);
+       /*
+        * Checking that we hold mvm->mutex is a good idea, but the rate
+        * control can't acquire the mutex since it runs in Tx path.
+        * So this is racy in that case, but in the worst case, the AMPDU
+        * size limit will be wrong for a short time which is not a big
+        * issue.
+        */
 
        rcu_read_lock();
 
                IWL_ERR(mvm, "Failed to update the ctrl_kill_msk\n");
 }
 
+#define LINK_QUAL_AGG_TIME_LIMIT_DEF   (4000)
+#define LINK_QUAL_AGG_TIME_LIMIT_BT_ACT        (1200)
+
+u16 iwl_mvm_bt_coex_agg_time_limit(struct iwl_mvm *mvm,
+                                  struct ieee80211_sta *sta)
+{
+       struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv;
+       enum iwl_bt_coex_lut_type lut_type;
+
+       if (le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) <
+           BT_LOW_TRAFFIC)
+               return LINK_QUAL_AGG_TIME_LIMIT_DEF;
+
+       lut_type = iwl_get_coex_type(mvm, mvmsta->vif);
+
+       if (lut_type == BT_COEX_LOOSE_LUT)
+               return LINK_QUAL_AGG_TIME_LIMIT_DEF;
+
+       /* tight coex, high bt traffic, reduce AGG time limit */
+       return LINK_QUAL_AGG_TIME_LIMIT_BT_ACT;
+}
+
 void iwl_mvm_bt_coex_vif_change(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
 {
        if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_NEWBT_COEX))
 
                                   struct ieee80211_sta *sta,
                                   struct iwl_lq_sta *lq_sta);
 static void rs_fill_link_cmd(struct iwl_mvm *mvm,
+                            struct ieee80211_sta *sta,
                             struct iwl_lq_sta *lq_sta, u32 rate_n_flags);
 static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search);
 
                       lq_sta->lq.sta_id, lq_sta->dbg_fixed_rate);
 
        if (lq_sta->dbg_fixed_rate) {
-               rs_fill_link_cmd(NULL, lq_sta, lq_sta->dbg_fixed_rate);
+               rs_fill_link_cmd(NULL, NULL, lq_sta, lq_sta->dbg_fixed_rate);
                iwl_mvm_send_lq_cmd(lq_sta->drv, &lq_sta->lq, CMD_ASYNC, false);
        }
 }
  * setup rate table in uCode
  */
 static void rs_update_rate_tbl(struct iwl_mvm *mvm,
+                              struct ieee80211_sta *sta,
                               struct iwl_lq_sta *lq_sta,
                               struct iwl_scale_tbl_info *tbl,
                               int index)
 
        /* Update uCode's rate table. */
        rate = rate_n_flags_from_tbl(mvm, tbl, index);
-       rs_fill_link_cmd(mvm, lq_sta, rate);
+       rs_fill_link_cmd(mvm, sta, lq_sta, rate);
        iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, CMD_ASYNC, false);
 }
 
                        tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
                        /* get "active" rate info */
                        index = iwl_hwrate_to_plcp_idx(tbl->current_rate);
-                       rs_update_rate_tbl(mvm, lq_sta, tbl, index);
+                       rs_update_rate_tbl(mvm, sta, lq_sta, tbl, index);
                }
                return;
        }
 lq_update:
        /* Replace uCode's rate table for the destination station. */
        if (update_lq)
-               rs_update_rate_tbl(mvm, lq_sta, tbl, index);
+               rs_update_rate_tbl(mvm, sta, lq_sta, tbl, index);
 
        rs_stay_in_table(lq_sta, false);
 
                        IWL_DEBUG_RATE(mvm,
                                       "Switch current  mcs: %X index: %d\n",
                                       tbl->current_rate, index);
-                       rs_fill_link_cmd(mvm, lq_sta, tbl->current_rate);
+                       rs_fill_link_cmd(mvm, sta, lq_sta, tbl->current_rate);
                        iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, CMD_ASYNC, false);
                } else {
                        done_search = 1;
        rate = rate_n_flags_from_tbl(mvm, tbl, rate_idx);
        tbl->current_rate = rate;
        rs_set_expected_tpt_table(lq_sta, tbl);
-       rs_fill_link_cmd(NULL, lq_sta, rate);
+       rs_fill_link_cmd(NULL, NULL, lq_sta, rate);
        /* TODO restore station should remember the lq cmd */
        iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, CMD_SYNC, true);
 }
 }
 
 static void rs_fill_link_cmd(struct iwl_mvm *mvm,
+                            struct ieee80211_sta *sta,
                             struct iwl_lq_sta *lq_sta, u32 new_rate)
 {
        struct iwl_scale_tbl_info tbl_type;
        lq_cmd->agg_time_limit =
                cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF);
 
+       if (sta)
+               lq_cmd->agg_time_limit =
+                       cpu_to_le16(iwl_mvm_bt_coex_agg_time_limit(mvm, sta));
+
        /*
         * overwrite if needed, pass aggregation time limit
         * to uCode in uSec - This is racy - but heh, at least it helps...