spin_lock_irqsave(&wcn->dxe_lock, flags);
        skb = wcn->tx_ack_skb;
        wcn->tx_ack_skb = NULL;
+       del_timer(&wcn->tx_ack_timer);
        spin_unlock_irqrestore(&wcn->dxe_lock, flags);
 
        if (!skb) {
 
        if (status == 1)
                info->flags |= IEEE80211_TX_STAT_ACK;
+       else
+               info->flags &= ~IEEE80211_TX_STAT_ACK;
 
        wcn36xx_dbg(WCN36XX_DBG_DXE, "dxe tx ack status: %d\n", status);
 
        ieee80211_wake_queues(wcn->hw);
 }
 
+static void wcn36xx_dxe_tx_timer(struct timer_list *t)
+{
+       struct wcn36xx *wcn = from_timer(wcn, t, tx_ack_timer);
+       struct ieee80211_tx_info *info;
+       unsigned long flags;
+       struct sk_buff *skb;
+
+       /* TX Timeout */
+       wcn36xx_dbg(WCN36XX_DBG_DXE, "TX timeout\n");
+
+       spin_lock_irqsave(&wcn->dxe_lock, flags);
+       skb = wcn->tx_ack_skb;
+       wcn->tx_ack_skb = NULL;
+       spin_unlock_irqrestore(&wcn->dxe_lock, flags);
+
+       if (!skb)
+               return;
+
+       info = IEEE80211_SKB_CB(skb);
+       info->flags &= ~IEEE80211_TX_STAT_ACK;
+       info->flags &= ~IEEE80211_TX_STAT_NOACK_TRANSMITTED;
+
+       ieee80211_tx_status_irqsafe(wcn->hw, skb);
+       ieee80211_wake_queues(wcn->hw);
+}
+
 static void reap_tx_dxes(struct wcn36xx *wcn, struct wcn36xx_dxe_ch *ch)
 {
        struct wcn36xx_dxe_ctl *ctl;
 {
        struct wcn36xx *wcn = (struct wcn36xx *)dev;
        int int_src, int_reason;
+       bool transmitted = false;
 
        wcn36xx_dxe_read_register(wcn, WCN36XX_DXE_INT_SRC_RAW_REG, &int_src);
 
                            int_reason);
 
                if (int_reason & (WCN36XX_CH_STAT_INT_DONE_MASK |
-                                 WCN36XX_CH_STAT_INT_ED_MASK))
+                                 WCN36XX_CH_STAT_INT_ED_MASK)) {
                        reap_tx_dxes(wcn, &wcn->dxe_tx_h_ch);
+                       transmitted = true;
+               }
        }
 
        if (int_src & WCN36XX_INT_MASK_CHAN_TX_L) {
                            int_reason);
 
                if (int_reason & (WCN36XX_CH_STAT_INT_DONE_MASK |
-                                 WCN36XX_CH_STAT_INT_ED_MASK))
+                                 WCN36XX_CH_STAT_INT_ED_MASK)) {
                        reap_tx_dxes(wcn, &wcn->dxe_tx_l_ch);
+                       transmitted = true;
+               }
+       }
+
+       spin_lock(&wcn->dxe_lock);
+       if (wcn->tx_ack_skb && transmitted) {
+               struct ieee80211_tx_info *info = IEEE80211_SKB_CB(wcn->tx_ack_skb);
+
+               /* TX complete, no need to wait for 802.11 ack indication */
+               if (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS &&
+                   info->flags & IEEE80211_TX_CTL_NO_ACK) {
+                       info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED;
+                       del_timer(&wcn->tx_ack_timer);
+                       ieee80211_tx_status_irqsafe(wcn->hw, wcn->tx_ack_skb);
+                       wcn->tx_ack_skb = NULL;
+                       ieee80211_wake_queues(wcn->hw);
+               }
        }
+       spin_unlock(&wcn->dxe_lock);
 
        return IRQ_HANDLED;
 }
        if (ret < 0)
                goto out_err_irq;
 
+       timer_setup(&wcn->tx_ack_timer, wcn36xx_dxe_tx_timer, 0);
+
        return 0;
 
 out_err_irq:
 {
        free_irq(wcn->tx_irq, wcn);
        free_irq(wcn->rx_irq, wcn);
+       del_timer(&wcn->tx_ack_timer);
 
        if (wcn->tx_ack_skb) {
                ieee80211_tx_status_irqsafe(wcn->hw, wcn->tx_ack_skb);
 
                bd->dpu_sign = __vif_priv->self_ucast_dpu_sign;
        }
 
-       if (ieee80211_is_nullfunc(hdr->frame_control) ||
-          (sta_priv && !sta_priv->is_data_encrypted))
+       if (ieee80211_is_any_nullfunc(hdr->frame_control) ||
+          (sta_priv && !sta_priv->is_data_encrypted)) {
                bd->dpu_ne = 1;
+       }
 
        if (bcast) {
                bd->ub = 1;
 
        bd.dpu_rf = WCN36XX_BMU_WQ_TX;
 
-       bd.tx_comp = !!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS);
-       if (bd.tx_comp) {
+       if (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) {
                wcn36xx_dbg(WCN36XX_DBG_DXE, "TX_ACK status requested\n");
+
                spin_lock_irqsave(&wcn->dxe_lock, flags);
                if (wcn->tx_ack_skb) {
                        spin_unlock_irqrestore(&wcn->dxe_lock, flags);
 
                /* Only one at a time is supported by fw. Stop the TX queues
                 * until the ack status gets back.
-                *
-                * TODO: Add watchdog in case FW does not answer
                 */
                ieee80211_stop_queues(wcn->hw);
+
+               /* TX watchdog if no TX irq or ack indication received  */
+               mod_timer(&wcn->tx_ack_timer, jiffies + HZ / 10);
+
+               /* Request ack indication from the firmware */
+               if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
+                       bd.tx_comp = 1;
        }
 
        /* Data frames served first*/
        bd.tx_bd_sign = 0xbdbdbdbd;
 
        ret = wcn36xx_dxe_tx_frame(wcn, vif_priv, &bd, skb, is_low);
-       if (ret && bd.tx_comp) {
+       if (ret && (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS)) {
                /* If the skb has not been transmitted,
                 * don't keep a reference to it.
                 */