complete(&wl->txq_thread_started);
        while (1) {
-               wait_for_completion(&wl->txq_event);
-
+               if (wait_for_completion_interruptible(&wl->txq_event))
+                       continue;
                if (wl->close) {
                        complete(&wl->txq_thread_started);
 
                                srcu_idx = srcu_read_lock(&wl->srcu);
                                list_for_each_entry_rcu(ifc, &wl->vif_list,
                                                        list) {
-                                       if (ifc->mac_opened && ifc->ndev)
+                                       if (ifc->mac_opened &&
+                                           netif_queue_stopped(ifc->ndev))
                                                netif_wake_queue(ifc->ndev);
                                }
                                srcu_read_unlock(&wl->srcu, srcu_idx);
                        }
-               } while (ret == WILC_VMM_ENTRY_FULL_RETRY && !wl->close);
+                       if (ret != WILC_VMM_ENTRY_FULL_RETRY)
+                               break;
+                       /* Back off TX task from sending packets for some time.
+                        * msleep_interruptible will allow RX task to run and
+                        * free buffers. TX task will be in TASK_INTERRUPTIBLE
+                        * state which will put the thread back to CPU running
+                        * queue when it's signaled even if the timeout isn't
+                        * elapsed. This gives faster chance for reserved SK
+                        * buffers to be free.
+                        */
+                       msleep_interruptible(TX_BACKOFF_WEIGHT_MS);
+               } while (!wl->close);
        }
        return 0;
 }
 
 #define TCP_ACK_FILTER_LINK_SPEED_THRESH       54
 #define DEFAULT_LINK_SPEED                     72
 
+#define TX_BACKOFF_WEIGHT_MS                   1
+
 struct wilc_wfi_stats {
        unsigned long rx_packets;
        unsigned long tx_packets;