diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 0424180..418eb19 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -90,6 +90,9 @@
 /* The magic used by QCA spec */
 #define ATH10K_SMBIOS_BDF_EXT_MAGIC "BDF_"
 
+/* Number of TID target accepts from host */
+#define ATH10K_MAX_TIDS	0x8
+
 struct ath10k;
 
 static inline const char *ath10k_bus_str(enum ath10k_bus bus)
@@ -116,6 +119,7 @@ enum ath10k_skb_flags {
 	ATH10K_SKB_F_DELIVER_CAB = BIT(2),
 	ATH10K_SKB_F_MGMT = BIT(3),
 	ATH10K_SKB_F_QOS = BIT(4),
+	ATH10K_SKB_F_NOACK_TID = BIT(5),
 };
 
 struct ath10k_skb_cb {
@@ -498,6 +502,10 @@ struct ath10k_sta {
 	u64 rx_duration;
 	struct ath10k_htt_tx_stats *tx_stats;
 
+	/* TID bitmap for station's NoAck policy, protected by conf_mutex */
+	int noack_map;
+	struct work_struct noack_map_wk;
+
 #ifdef CONFIG_MAC80211_DEBUGFS
 	/* protected by conf_mutex */
 	bool aggr_mode;
@@ -573,6 +581,9 @@ struct ath10k_vif {
 	struct work_struct ap_csa_work;
 	struct delayed_work connection_loss_work;
 	struct cfg80211_bitrate_mask bitrate_mask;
+
+	/* TID bitmap for station's NoAck policy, protected by conf_mutex */
+	int noack_map;
 };
 
 struct ath10k_vif_iter {
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index a1c2801..54ec919 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -2940,6 +2940,39 @@ static void ath10k_bss_disassoc(struct ieee80211_hw *hw,
 	cancel_delayed_work_sync(&arvif->connection_loss_work);
 }
 
+static int
+ath10k_mac_set_noack_tid_bitmap(struct ath10k *ar,
+				struct wmi_per_peer_per_tid_cfg_arg *arg,
+				int noack_map)
+{
+	int tid, ret;
+
+	for (tid = 0; tid < ATH10K_MAX_TIDS; tid++) {
+		if (noack_map & BIT(tid)) {
+			arg->ack_policy = WMI_PEER_TID_CONFIG_NOACK;
+			/* It is preferred to transmit the noack policy frames
+			 * in basic rate. for 5G -> 6Mbps 2G -> 1Mbps
+			 */
+			arg->rate_ctrl =
+				WMI_TID_CONFIG_RATE_CONTROL_DEFAULT_LOWEST_RATE;
+			arg->aggr_control = WMI_TID_CONFIG_AGGR_CONTROL_DISABLE;
+		} else {
+			arg->ack_policy = WMI_PEER_TID_CONFIG_ACK;
+			arg->rate_ctrl = WMI_TID_CONFIG_RATE_CONTROL_AUTO;
+			arg->aggr_control = WMI_TID_CONFIG_AGGR_CONTROL_ENABLE;
+		}
+
+		arg->tid = tid;
+		ret = ath10k_wmi_set_per_peer_per_tid_cfg(ar, arg);
+		if (ret) {
+			ath10k_warn(ar, "failed to set noack map for STA %pM for vdev %i: %d\n",
+				    arg->peer_macaddr.addr, arg->vdev_id, ret);
+			break;
+		}
+	}
+	return ret;
+}
+
 static int ath10k_station_assoc(struct ath10k *ar,
 				struct ieee80211_vif *vif,
 				struct ieee80211_sta *sta,
@@ -2947,6 +2980,7 @@ static int ath10k_station_assoc(struct ath10k *ar,
 {
 	struct ath10k_vif *arvif = (void *)vif->drv_priv;
 	struct wmi_peer_assoc_complete_arg peer_arg;
+	struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
 	int ret = 0;
 
 	lockdep_assert_held(&ar->conf_mutex);
@@ -3005,6 +3039,23 @@ static int ath10k_station_assoc(struct ath10k *ar,
 		}
 	}
 
+	if (arvif->noack_map) {
+		struct wmi_per_peer_per_tid_cfg_arg arg = {};
+
+		arg.vdev_id = arvif->vdev_id;
+		ether_addr_copy(arg.peer_macaddr.addr, sta->addr);
+
+		ret = ath10k_mac_set_noack_tid_bitmap(ar, &arg,
+						      arvif->noack_map);
+		if (ret)
+			return ret;
+	}
+
+	/* Assign default noack_map value (-1) to newly connecting station.
+	 * This default value used to identify the station configured with
+	 * vif specific noack configuration rather than station specific.
+	 */
+	arsta->noack_map = -1;
 	return ret;
 }
 
@@ -3543,10 +3594,15 @@ static void ath10k_tx_h_add_p2p_noa_ie(struct ath10k *ar,
 static void ath10k_mac_tx_h_fill_cb(struct ath10k *ar,
 				    struct ieee80211_vif *vif,
 				    struct ieee80211_txq *txq,
+				    struct ieee80211_sta *sta,
 				    struct sk_buff *skb)
 {
 	struct ieee80211_hdr *hdr = (void *)skb->data;
 	struct ath10k_skb_cb *cb = ATH10K_SKB_CB(skb);
+	struct ath10k_vif *arvif = (void *)vif->drv_priv;
+	int noack_map = arvif->noack_map;
+	struct ath10k_sta *arsta;
+	u8 tid, *p;
 
 	cb->flags = 0;
 	if (!ath10k_tx_h_use_hwcrypto(vif, skb))
@@ -3555,8 +3611,20 @@ static void ath10k_mac_tx_h_fill_cb(struct ath10k *ar,
 	if (ieee80211_is_mgmt(hdr->frame_control))
 		cb->flags |= ATH10K_SKB_F_MGMT;
 
-	if (ieee80211_is_data_qos(hdr->frame_control))
+	if (ieee80211_is_data_qos(hdr->frame_control)) {
 		cb->flags |= ATH10K_SKB_F_QOS;
+		p = ieee80211_get_qos_ctl(hdr);
+		tid = (*p) & IEEE80211_QOS_CTL_TID_MASK;
+
+		if (sta) {
+			arsta = (struct ath10k_sta *)sta->drv_priv;
+			if (arsta->noack_map != -1)
+				noack_map = arsta->noack_map;
+		}
+
+		if (noack_map & BIT(tid))
+			cb->flags |= ATH10K_SKB_F_NOACK_TID;
+	}
 
 	cb->vif = vif;
 	cb->txq = txq;
@@ -3987,7 +4055,7 @@ int ath10k_mac_tx_push_txq(struct ieee80211_hw *hw,
 		return -ENOENT;
 	}
 
-	ath10k_mac_tx_h_fill_cb(ar, vif, txq, skb);
+	ath10k_mac_tx_h_fill_cb(ar, vif, txq, sta, skb);
 
 	skb_len = skb->len;
 	txmode = ath10k_mac_tx_h_get_txmode(ar, vif, sta, skb);
@@ -4258,7 +4326,7 @@ static void ath10k_mac_op_tx(struct ieee80211_hw *hw,
 	bool is_presp;
 	int ret;
 
-	ath10k_mac_tx_h_fill_cb(ar, vif, txq, skb);
+	ath10k_mac_tx_h_fill_cb(ar, vif, txq, sta, skb);
 
 	txmode = ath10k_mac_tx_h_get_txmode(ar, vif, sta, skb);
 	txpath = ath10k_mac_tx_h_get_txpath(ar, skb, txmode);
@@ -6247,6 +6315,42 @@ static void ath10k_mac_dec_num_stations(struct ath10k_vif *arvif,
 	ar->num_stations--;
 }
 
+struct ath10k_mac_iter_noack_map_data {
+	struct ieee80211_vif *curr_vif;
+	struct ath10k *ar;
+};
+
+static void ath10k_sta_set_noack_tid_bitmap(struct work_struct *wk)
+{
+	struct wmi_per_peer_per_tid_cfg_arg arg = {};
+	struct ieee80211_sta *sta;
+	struct ath10k_sta *arsta;
+	struct ath10k_vif *arvif;
+	struct ath10k *ar;
+
+	arsta = container_of(wk, struct ath10k_sta, noack_map_wk);
+	sta = container_of((void *)arsta, struct ieee80211_sta, drv_priv);
+	arvif = arsta->arvif;
+	ar = arvif->ar;
+
+	arg.vdev_id = arvif->vdev_id;
+	ether_addr_copy(arg.peer_macaddr.addr, sta->addr);
+	ath10k_mac_set_noack_tid_bitmap(ar, &arg, arvif->noack_map);
+}
+
+static void ath10k_mac_vif_stations_noack_map(void *data,
+					      struct ieee80211_sta *sta)
+{
+	struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
+	struct ath10k_mac_iter_noack_map_data *iter_data = data;
+	struct ieee80211_vif *sta_vif = arsta->arvif->vif;
+
+	if (sta_vif != iter_data->curr_vif || arsta->noack_map != -1)
+		return;
+
+	ieee80211_queue_work(iter_data->ar->hw, &arsta->noack_map_wk);
+}
+
 static int ath10k_sta_state(struct ieee80211_hw *hw,
 			    struct ieee80211_vif *vif,
 			    struct ieee80211_sta *sta,
@@ -6266,6 +6370,8 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
 		arsta->arvif = arvif;
 		arsta->peer_ps_state = WMI_PEER_PS_STATE_DISABLED;
 		INIT_WORK(&arsta->update_wk, ath10k_sta_rc_update_wk);
+		INIT_WORK(&arsta->noack_map_wk,
+			  ath10k_sta_set_noack_tid_bitmap);
 
 		for (i = 0; i < ARRAY_SIZE(sta->txq); i++)
 			ath10k_mac_txq_init(sta->txq[i]);
@@ -6273,8 +6379,10 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
 
 	/* cancel must be done outside the mutex to avoid deadlock */
 	if ((old_state == IEEE80211_STA_NONE &&
-	     new_state == IEEE80211_STA_NOTEXIST))
+	     new_state == IEEE80211_STA_NOTEXIST)) {
 		cancel_work_sync(&arsta->update_wk);
+		cancel_work_sync(&arsta->noack_map_wk);
+	}
 
 	mutex_lock(&ar->conf_mutex);
 
@@ -7882,6 +7990,55 @@ static void ath10k_sta_statistics(struct ieee80211_hw *hw,
 	sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE);
 }
 
+static int ath10k_mac_op_set_noack_tid_bitmap(struct ieee80211_hw *hw,
+					      struct ieee80211_vif *vif,
+					      struct ieee80211_sta *sta,
+					      int noack_map)
+{
+	struct ath10k_vif *arvif = (void *)vif->drv_priv;
+	struct ath10k_mac_iter_noack_map_data data = {};
+	struct wmi_per_peer_per_tid_cfg_arg arg = {};
+	struct ath10k *ar = hw->priv;
+	struct ath10k_sta *arsta;
+	int ret;
+
+	mutex_lock(&ar->conf_mutex);
+
+	arg.vdev_id = arvif->vdev_id;
+	if (sta) {
+		arsta = (struct ath10k_sta *)sta->drv_priv;
+		ether_addr_copy(arg.peer_macaddr.addr, sta->addr);
+		if (arsta->noack_map == noack_map)
+			goto exit;
+
+		if (noack_map == -1)
+			ret = ath10k_mac_set_noack_tid_bitmap(ar, &arg,
+							      arvif->noack_map);
+		else
+			ret = ath10k_mac_set_noack_tid_bitmap(ar, &arg,
+							      noack_map);
+		if (!ret)
+			arsta->noack_map = noack_map;
+
+		goto exit;
+	}
+
+	if (arvif->noack_map == noack_map)
+		goto exit;
+
+	data.curr_vif = vif;
+	data.ar = ar;
+	arvif->noack_map = noack_map;
+	ieee80211_iterate_stations_atomic(hw,
+					  ath10k_mac_vif_stations_noack_map,
+					  &data);
+	arvif->noack_map = noack_map;
+
+exit:
+	mutex_unlock(&ar->conf_mutex);
+	return ret;
+}
+
 static const struct ieee80211_ops ath10k_ops = {
 	.tx				= ath10k_mac_op_tx,
 	.wake_tx_queue			= ath10k_mac_op_wake_tx_queue,
@@ -7924,6 +8081,7 @@ static void ath10k_sta_statistics(struct ieee80211_hw *hw,
 	.switch_vif_chanctx		= ath10k_mac_op_switch_vif_chanctx,
 	.sta_pre_rcu_remove		= ath10k_mac_op_sta_pre_rcu_remove,
 	.sta_statistics			= ath10k_sta_statistics,
+	.set_noack_tid_bitmap           = ath10k_mac_op_set_noack_tid_bitmap,
 
 	CFG80211_TESTMODE_CMD(ath10k_tm_cmd)
 
@@ -8578,6 +8736,12 @@ int ath10k_mac_register(struct ath10k *ar)
 		wiphy_ext_feature_set(ar->hw->wiphy,
 				      NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT);
 
+	if (test_bit(WMI_SERVICE_PEER_TID_CONFIGS_SUPPORT, ar->wmi.svc_map))
+		wiphy_ext_feature_set(ar->hw->wiphy,
+				      NL80211_EXT_FEATURE_PER_STA_NOACK_MAP);
+	else
+		ar->ops->set_noack_tid_bitmap = NULL;
+
 	/*
 	 * on LL hardware queues are managed entirely by the FW
 	 * so we only advertise to mac we can do the queues thing
diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c
index 23606b6..3b385d4 100644
--- a/drivers/net/wireless/ath/ath10k/txrx.c
+++ b/drivers/net/wireless/ath/ath10k/txrx.c
@@ -61,6 +61,7 @@ int ath10k_txrx_tx_unref(struct ath10k_htt *htt,
 	struct ath10k_skb_cb *skb_cb;
 	struct ath10k_txq *artxq;
 	struct sk_buff *msdu;
+	u8 flags;
 
 	ath10k_dbg(ar, ATH10K_DBG_HTT,
 		   "htt tx completion msdu_id %u status %d\n",
@@ -89,6 +90,8 @@ int ath10k_txrx_tx_unref(struct ath10k_htt *htt,
 		artxq->num_fw_queued--;
 	}
 
+	flags = skb_cb->flags;
+
 	ath10k_htt_tx_free_msdu_id(htt, tx_done->msdu_id);
 	ath10k_htt_tx_dec_pending(htt);
 	if (htt->num_pending_tx == 0)
@@ -104,18 +107,21 @@ int ath10k_txrx_tx_unref(struct ath10k_htt *htt,
 	memset(&info->status, 0, sizeof(info->status));
 	trace_ath10k_txrx_tx_unref(ar, tx_done->msdu_id);
 
-	if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
+	if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) &&
+	    !(flags & ATH10K_SKB_F_NOACK_TID))
 		info->flags |= IEEE80211_TX_STAT_ACK;
 
 	if (tx_done->status == HTT_TX_COMPL_STATE_NOACK)
 		info->flags &= ~IEEE80211_TX_STAT_ACK;
 
 	if ((tx_done->status == HTT_TX_COMPL_STATE_ACK) &&
-	    (info->flags & IEEE80211_TX_CTL_NO_ACK))
+	    ((info->flags & IEEE80211_TX_CTL_NO_ACK) ||
+	    (flags & ATH10K_SKB_F_NOACK_TID)))
 		info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED;
 
 	if (tx_done->status == HTT_TX_COMPL_STATE_DISCARD) {
-		if (info->flags & IEEE80211_TX_CTL_NO_ACK)
+		if ((info->flags & IEEE80211_TX_CTL_NO_ACK) ||
+		    (flags & ATH10K_SKB_F_NOACK_TID))
 			info->flags &= ~IEEE80211_TX_STAT_NOACK_TRANSMITTED;
 		else
 			info->flags &= ~IEEE80211_TX_STAT_ACK;
