ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
        ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS);
        ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU);
-       ieee80211_hw_set(hw, TX_AMSDU);
 
-       /* TODO: avoid linearization for SDIO */
-       if (!mt76_is_sdio(dev))
-               ieee80211_hw_set(hw, TX_FRAG_LIST);
+       if (!(dev->drv->drv_flags & MT_DRV_AMSDU_OFFLOAD)) {
+               ieee80211_hw_set(hw, TX_AMSDU);
+
+               /* TODO: avoid linearization for SDIO */
+               if (!mt76_is_sdio(dev))
+                       ieee80211_hw_set(hw, TX_FRAG_LIST);
+       }
 
        ieee80211_hw_set(hw, MFP_CAPABLE);
        ieee80211_hw_set(hw, AP_LINK_PS);
 
        he->max_nss_mcs[CMD_HE_MCS_BW8080] = cap->he_mcs_nss_supp.tx_mcs_80p80;
 }
 
+static void
+mt7915_mcu_bss_hw_amsdu_tlv(struct sk_buff *skb)
+{
+#define TXD_CMP_MAP1           GENMASK(15, 0)
+#define TXD_CMP_MAP2           (GENMASK(31, 0) & ~BIT(23))
+       struct bss_info_hw_amsdu *amsdu;
+       struct tlv *tlv;
+
+       tlv = mt7915_mcu_add_tlv(skb, BSS_INFO_HW_AMSDU, sizeof(*amsdu));
+
+       amsdu = (struct bss_info_hw_amsdu *)tlv;
+       amsdu->cmp_bitmap_0 = cpu_to_le32(TXD_CMP_MAP1);
+       amsdu->cmp_bitmap_1 = cpu_to_le32(TXD_CMP_MAP2);
+       amsdu->trig_thres = cpu_to_le16(2);
+       amsdu->enable = true;
+}
+
 static void
 mt7915_mcu_bss_ext_tlv(struct sk_buff *skb, struct mt7915_vif *mvif)
 {
                mt7915_mcu_bss_rfch_tlv(skb, vif, phy);
                mt7915_mcu_bss_bmc_tlv(skb, phy);
                mt7915_mcu_bss_ra_tlv(skb, vif, phy);
+               mt7915_mcu_bss_hw_amsdu_tlv(skb);
 
                if (vif->bss_conf.he_support)
                        mt7915_mcu_bss_he_tlv(skb, vif, phy);
        struct sk_buff *skb;
        int ret;
 
+       if (enable && tx && !params->amsdu)
+               msta->wcid.amsdu = false;
+
        skb = mt7915_mcu_alloc_sta_req(dev, mvif, msta,
                                       MT7915_STA_UPDATE_MAX_SIZE);
        if (IS_ERR(skb))
                                       MCU_EXT_CMD_STA_REC_UPDATE, true);
 }
 
+static void
+mt7915_mcu_sta_amsdu_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
+{
+       struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
+       struct sta_rec_amsdu *amsdu;
+       struct tlv *tlv;
+
+       if (!sta->max_amsdu_len)
+           return;
+
+       tlv = mt7915_mcu_add_tlv(skb, STA_REC_HW_AMSDU, sizeof(*amsdu));
+       amsdu = (struct sta_rec_amsdu *)tlv;
+       amsdu->max_amsdu_num = 8;
+       amsdu->amsdu_en = true;
+       amsdu->max_mpdu_size = sta->max_amsdu_len >=
+                              IEEE80211_MAX_MPDU_LEN_VHT_7991;
+       msta->wcid.amsdu = true;
+}
+
+static bool
+mt7915_hw_amsdu_supported(struct ieee80211_vif *vif)
+{
+       switch (vif->type) {
+       case NL80211_IFTYPE_AP:
+       case NL80211_IFTYPE_STATION:
+               return true;
+       default:
+               return false;
+       }
+}
+
 static void
 mt7915_mcu_sta_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
                   struct ieee80211_sta *sta, struct ieee80211_vif *vif)
                tlv = mt7915_mcu_add_tlv(skb, STA_REC_HT, sizeof(*ht));
                ht = (struct sta_rec_ht *)tlv;
                ht->ht_cap = cpu_to_le16(sta->ht_cap.cap);
+
+               if (mt7915_hw_amsdu_supported(vif))
+                       mt7915_mcu_sta_amsdu_tlv(skb, sta);
        }
 
        /* starec vht */
 
        __le32 fast_interval;
 } __packed;
 
+struct bss_info_hw_amsdu {
+       __le16 tag;
+       __le16 len;
+       __le32 cmp_bitmap_0;
+       __le32 cmp_bitmap_1;
+       __le16 trig_thres;
+       u8 enable;
+       u8 rsv;
+} __packed;
+
 struct bss_info_he {
        __le16 tag;
        __le16 len;
        __le16 winsize;
 } __packed;
 
+struct sta_rec_amsdu {
+       __le16 tag;
+       __le16 len;
+       u8 max_amsdu_num;
+       u8 max_mpdu_size;
+       u8 amsdu_en;
+       u8 rsv;
+} __packed;
+
 struct sec_key {
        u8 cipher_id;
        u8 cipher_len;
                                         sizeof(struct sta_rec_ba) +    \
                                         sizeof(struct sta_rec_vht) +   \
                                         sizeof(struct sta_rec_uapsd) + \
+                                        sizeof(struct sta_rec_amsdu) + \
                                         sizeof(struct tlv) +           \
                                         MT7915_WTBL_UPDATE_MAX_SIZE)
 
                                         sizeof(struct bss_info_basic) +\
                                         sizeof(struct bss_info_rf_ch) +\
                                         sizeof(struct bss_info_ra) +   \
+                                        sizeof(struct bss_info_hw_amsdu) +\
                                         sizeof(struct bss_info_he) +   \
                                         sizeof(struct bss_info_bmc_rate) +\
                                         sizeof(struct bss_info_ext_bss) +\