spin_unlock_irqrestore(&wl->wl_lock, flags);
 }
 
-#define TX_DUMMY_PACKET_SIZE 1400
 int wl1271_tx_dummy_packet(struct wl1271 *wl)
 {
-       struct sk_buff *skb = NULL;
+       unsigned long flags;
+
+       spin_lock_irqsave(&wl->wl_lock, flags);
+       set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
+       wl->tx_queue_count++;
+       spin_unlock_irqrestore(&wl->wl_lock, flags);
+
+       /* The FW is low on RX memory blocks, so send the dummy packet asap */
+       if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
+               wl1271_tx_work_locked(wl);
+
+       /*
+        * If the FW TX is busy, TX work will be scheduled by the threaded
+        * interrupt handler function
+        */
+       return 0;
+}
+
+/*
+ * The size of the dummy packet should be at least 1400 bytes. However, in
+ * order to minimize the number of bus transactions, aligning it to 512 bytes
+ * boundaries could be beneficial, performance wise
+ */
+#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
+
+struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
+{
+       struct sk_buff *skb;
        struct ieee80211_hdr_3addr *hdr;
-       int ret = 0;
+       unsigned int dummy_packet_size;
+
+       dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
+                           sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
 
-       skb = dev_alloc_skb(
-               sizeof(struct wl1271_tx_hw_descr) + sizeof(*hdr) +
-               TX_DUMMY_PACKET_SIZE);
+       skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
        if (!skb) {
-               wl1271_warning("failed to allocate buffer for dummy packet");
-               ret = -ENOMEM;
-               goto out;
+               wl1271_warning("Failed to allocate a dummy packet skb");
+               return NULL;
        }
 
        skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
        hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
        memset(hdr, 0, sizeof(*hdr));
        hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
-                                        IEEE80211_FCTL_TODS  |
-                                        IEEE80211_STYPE_NULLFUNC);
-
-       memcpy(hdr->addr1, wl->bssid, ETH_ALEN);
-       memcpy(hdr->addr2, wl->mac_addr, ETH_ALEN);
-       memcpy(hdr->addr3, wl->bssid, ETH_ALEN);
+                                        IEEE80211_STYPE_NULLFUNC |
+                                        IEEE80211_FCTL_TODS);
 
-       skb_put(skb, TX_DUMMY_PACKET_SIZE);
+       memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
 
-       memset(skb->data, 0, TX_DUMMY_PACKET_SIZE);
-
-       skb->pkt_type = TX_PKT_TYPE_DUMMY_REQ;
        /* Dummy packets require the TID to be management */
        skb->priority = WL1271_TID_MGMT;
-       /* CONF_TX_AC_VO */
-       skb->queue_mapping = 0;
 
-       wl1271_op_tx(wl->hw, skb);
+       /* Initialize all fields that might be used */
+       skb->queue_mapping = 0;
+       memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
 
-out:
-       return ret;
+       return skb;
 }
 
+
 static struct notifier_block wl1271_dev_notifier = {
        .notifier_call = wl1271_dev_notify,
 };
                goto err_hw;
        }
 
+       wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
+       if (!wl->dummy_packet) {
+               ret = -ENOMEM;
+               goto err_aggr;
+       }
+
        /* Register platform device */
        ret = platform_device_register(wl->plat_dev);
        if (ret) {
                wl1271_error("couldn't register platform device");
-               goto err_aggr;
+               goto err_dummy_packet;
        }
        dev_set_drvdata(&wl->plat_dev->dev, wl);
 
 err_platform:
        platform_device_unregister(wl->plat_dev);
 
+err_dummy_packet:
+       dev_kfree_skb(wl->dummy_packet);
+
 err_aggr:
        free_pages((unsigned long)wl->aggr_buf, order);
 
 int wl1271_free_hw(struct wl1271 *wl)
 {
        platform_device_unregister(wl->plat_dev);
+       dev_kfree_skb(wl->dummy_packet);
        free_pages((unsigned long)wl->aggr_buf,
                        get_order(WL1271_AGGR_BUFFER_SIZE));
        kfree(wl->plat_dev);
 
        return ret;
 }
 
+static bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb)
+{
+       return wl->dummy_packet == skb;
+}
+
 static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
                              u32 extra, struct ieee80211_tx_info *control,
                              u8 hlid)
        ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
        desc->tid = skb->priority;
 
-       if (skb->pkt_type == TX_PKT_TYPE_DUMMY_REQ) {
+       if (wl12xx_is_dummy_packet(wl, skb)) {
                /*
                 * FW expects the dummy packet to have an invalid session id -
                 * any session id that is different than the one set in the join
        memcpy(wl->aggr_buf + buf_offset, skb->data, skb->len);
        memset(wl->aggr_buf + buf_offset + skb->len, 0, total_len - skb->len);
 
+       /* Revert side effects in the dummy packet skb, so it can be reused */
+       if (wl12xx_is_dummy_packet(wl, skb))
+               skb_pull(skb, sizeof(struct wl1271_tx_hw_descr));
+
        return total_len;
 }
 
 
 static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl)
 {
+       unsigned long flags;
+       struct sk_buff *skb = NULL;
+
        if (wl->bss_type == BSS_TYPE_AP_BSS)
-               return wl1271_ap_skb_dequeue(wl);
+               skb = wl1271_ap_skb_dequeue(wl);
+       else
+               skb = wl1271_sta_skb_dequeue(wl);
 
-       return wl1271_sta_skb_dequeue(wl);
+       if (!skb &&
+           test_and_clear_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags)) {
+               skb = wl->dummy_packet;
+               spin_lock_irqsave(&wl->wl_lock, flags);
+               wl->tx_queue_count--;
+               spin_unlock_irqrestore(&wl->wl_lock, flags);
+       }
+
+       return skb;
 }
 
 static void wl1271_skb_queue_head(struct wl1271 *wl, struct sk_buff *skb)
        unsigned long flags;
        int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
 
-       if (wl->bss_type == BSS_TYPE_AP_BSS) {
+       if (wl12xx_is_dummy_packet(wl, skb)) {
+               set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
+       } else if (wl->bss_type == BSS_TYPE_AP_BSS) {
                u8 hlid = wl1271_tx_get_hlid(skb);
                skb_queue_head(&wl->links[hlid].tx_queue[q], skb);
 
        skb = wl->tx_frames[id];
        info = IEEE80211_SKB_CB(skb);
 
-       if (skb->pkt_type == TX_PKT_TYPE_DUMMY_REQ) {
-               dev_kfree_skb(skb);
+       if (wl12xx_is_dummy_packet(wl, skb)) {
                wl1271_free_tx_id(wl, id);
                return;
        }
                                wl1271_debug(DEBUG_TX, "freeing skb 0x%p",
                                             skb);
 
-                               if (skb->pkt_type == TX_PKT_TYPE_DUMMY_REQ) {
-                                       dev_kfree_skb(skb);
-                               } else {
+                               if (!wl12xx_is_dummy_packet(wl, skb)) {
                                        info = IEEE80211_SKB_CB(skb);
                                        info->status.rates[0].idx = -1;
                                        info->status.rates[0].count = 0;
                wl1271_free_tx_id(wl, i);
                wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb);
 
-               if (skb->pkt_type == TX_PKT_TYPE_DUMMY_REQ) {
-                       dev_kfree_skb(skb);
-               } else {
+               if (!wl12xx_is_dummy_packet(wl, skb)) {
                        /*
                         * Remove private headers before passing the skb to
                         * mac80211