if (ab->hw_params->ring_mask->host2rxdma[grp_id]) {
                struct ath12k_dp *dp = &ab->dp;
                struct dp_rxdma_ring *rx_ring = &dp->rx_refill_buf_ring;
+               LIST_HEAD(list);
 
-               ath12k_dp_rx_bufs_replenish(ab, rx_ring, 0);
+               ath12k_dp_rx_bufs_replenish(ab, rx_ring, &list, 0);
        }
 
        /* TODO: Implement handler for other interrupts */
 
 static void ath12k_dp_cc_cleanup(struct ath12k_base *ab)
 {
-       struct ath12k_rx_desc_info *desc_info, *tmp;
+       struct ath12k_rx_desc_info *desc_info;
        struct ath12k_tx_desc_info *tx_desc_info, *tmp1;
        struct ath12k_dp *dp = &ab->dp;
        struct sk_buff *skb;
-       int i;
+       int i, j;
        u32 pool_id, tx_spt_page;
 
        if (!dp->spt_info)
        /* RX Descriptor cleanup */
        spin_lock_bh(&dp->rx_desc_lock);
 
-       list_for_each_entry_safe(desc_info, tmp, &dp->rx_desc_used_list, list) {
-               list_del(&desc_info->list);
-               skb = desc_info->skb;
+       for (i = 0; i < ATH12K_NUM_RX_SPT_PAGES; i++) {
+               desc_info = dp->spt_info->rxbaddr[i];
 
-               if (!skb)
-                       continue;
+               for (j = 0; j < ATH12K_MAX_SPT_ENTRIES; j++) {
+                       if (!desc_info[j].in_use) {
+                               list_del(&desc_info[j].list);
+                               continue;
+                       }
 
-               dma_unmap_single(ab->dev, ATH12K_SKB_RXCB(skb)->paddr,
-                                skb->len + skb_tailroom(skb), DMA_FROM_DEVICE);
-               dev_kfree_skb_any(skb);
+                       skb = desc_info[j].skb;
+                       if (!skb)
+                               continue;
+
+                       dma_unmap_single(ab->dev, ATH12K_SKB_RXCB(skb)->paddr,
+                                        skb->len + skb_tailroom(skb), DMA_FROM_DEVICE);
+                       dev_kfree_skb_any(skb);
+               }
        }
 
        for (i = 0; i < ATH12K_NUM_RX_SPT_PAGES; i++) {
        u32 cmem_base;
 
        INIT_LIST_HEAD(&dp->rx_desc_free_list);
-       INIT_LIST_HEAD(&dp->rx_desc_used_list);
        spin_lock_init(&dp->rx_desc_lock);
 
        for (i = 0; i < ATH12K_HW_MAX_QUEUES; i++) {
 
        return -ETIMEDOUT;
 }
 
+static size_t ath12k_dp_list_cut_nodes(struct list_head *list,
+                                      struct list_head *head,
+                                      size_t count)
+{
+       struct list_head *cur;
+       struct ath12k_rx_desc_info *rx_desc;
+       size_t nodes = 0;
+
+       if (!count) {
+               INIT_LIST_HEAD(list);
+               goto out;
+       }
+
+       list_for_each(cur, head) {
+               if (!count)
+                       break;
+
+               rx_desc = list_entry(cur, struct ath12k_rx_desc_info, list);
+               rx_desc->in_use = true;
+
+               count--;
+               nodes++;
+       }
+
+       list_cut_before(list, head, cur);
+out:
+       return nodes;
+}
+
+static void ath12k_dp_rx_enqueue_free(struct ath12k_dp *dp,
+                                     struct list_head *used_list)
+{
+       struct ath12k_rx_desc_info *rx_desc, *safe;
+
+       /* Reset the use flag */
+       list_for_each_entry_safe(rx_desc, safe, used_list, list)
+               rx_desc->in_use = false;
+
+       spin_lock_bh(&dp->rx_desc_lock);
+       list_splice_tail(used_list, &dp->rx_desc_free_list);
+       spin_unlock_bh(&dp->rx_desc_lock);
+}
+
 /* Returns number of Rx buffers replenished */
 int ath12k_dp_rx_bufs_replenish(struct ath12k_base *ab,
                                struct dp_rxdma_ring *rx_ring,
+                               struct list_head *used_list,
                                int req_entries)
 {
        struct ath12k_buffer_addr *desc;
        req_entries = min(num_free, req_entries);
        num_remain = req_entries;
 
+       if (!num_remain)
+               goto skip_replenish;
+
+       /* Get the descriptor from free list */
+       if (list_empty(used_list)) {
+               spin_lock_bh(&dp->rx_desc_lock);
+               req_entries = ath12k_dp_list_cut_nodes(used_list,
+                                                      &dp->rx_desc_free_list,
+                                                      num_remain);
+               spin_unlock_bh(&dp->rx_desc_lock);
+               num_remain = req_entries;
+       }
+
        while (num_remain > 0) {
                skb = dev_alloc_skb(DP_RX_BUFFER_SIZE +
                                    DP_RX_BUFFER_ALIGN_SIZE);
                if (dma_mapping_error(ab->dev, paddr))
                        goto fail_free_skb;
 
-               spin_lock_bh(&dp->rx_desc_lock);
-
-               /* Get desc from free list and store in used list
-                * for cleanup purposes
-                *
-                * TODO: pass the removed descs rather than
-                * add/read to optimize
-                */
-               rx_desc = list_first_entry_or_null(&dp->rx_desc_free_list,
+               rx_desc = list_first_entry_or_null(used_list,
                                                   struct ath12k_rx_desc_info,
                                                   list);
-               if (!rx_desc) {
-                       spin_unlock_bh(&dp->rx_desc_lock);
+               if (!rx_desc)
                        goto fail_dma_unmap;
-               }
 
                rx_desc->skb = skb;
                cookie = rx_desc->cookie;
-               list_del(&rx_desc->list);
-               list_add_tail(&rx_desc->list, &dp->rx_desc_used_list);
-
-               spin_unlock_bh(&dp->rx_desc_lock);
 
                desc = ath12k_hal_srng_src_get_next_entry(ab, srng);
                if (!desc)
-                       goto fail_buf_unassign;
+                       goto fail_dma_unmap;
 
+               list_del(&rx_desc->list);
                ATH12K_SKB_RXCB(skb)->paddr = paddr;
 
                num_remain--;
                ath12k_hal_rx_buf_addr_info_set(desc, paddr, cookie, mgr);
        }
 
+skip_replenish:
        ath12k_hal_srng_access_end(ab, srng);
 
+       if (!list_empty(used_list))
+               ath12k_dp_rx_enqueue_free(dp, used_list);
+
        spin_unlock_bh(&srng->lock);
 
        return req_entries - num_remain;
 
-fail_buf_unassign:
-       spin_lock_bh(&dp->rx_desc_lock);
-       list_del(&rx_desc->list);
-       list_add_tail(&rx_desc->list, &dp->rx_desc_free_list);
-       rx_desc->skb = NULL;
-       spin_unlock_bh(&dp->rx_desc_lock);
 fail_dma_unmap:
        dma_unmap_single(ab->dev, paddr, skb->len + skb_tailroom(skb),
                         DMA_FROM_DEVICE);
 
        ath12k_hal_srng_access_end(ab, srng);
 
+       if (!list_empty(used_list))
+               ath12k_dp_rx_enqueue_free(dp, used_list);
+
        spin_unlock_bh(&srng->lock);
 
        return req_entries - num_remain;
 static int ath12k_dp_rxdma_ring_buf_setup(struct ath12k_base *ab,
                                          struct dp_rxdma_ring *rx_ring)
 {
+       LIST_HEAD(list);
+
        rx_ring->bufs_max = rx_ring->refill_buf_ring.size /
                        ath12k_hal_srng_get_entrysize(ab, HAL_RXDMA_BUF);
 
-       ath12k_dp_rx_bufs_replenish(ab, rx_ring, 0);
+       ath12k_dp_rx_bufs_replenish(ab, rx_ring, &list, 0);
 
        return 0;
 }
 int ath12k_dp_rx_process(struct ath12k_base *ab, int ring_id,
                         struct napi_struct *napi, int budget)
 {
+       LIST_HEAD(rx_desc_used_list);
        struct ath12k_rx_desc_info *desc_info;
        struct ath12k_dp *dp = &ab->dp;
        struct dp_rxdma_ring *rx_ring = &dp->rx_refill_buf_ring;
                msdu = desc_info->skb;
                desc_info->skb = NULL;
 
-               spin_lock_bh(&dp->rx_desc_lock);
-               list_move_tail(&desc_info->list, &dp->rx_desc_free_list);
-               spin_unlock_bh(&dp->rx_desc_lock);
+               list_add_tail(&desc_info->list, &rx_desc_used_list);
 
                rxcb = ATH12K_SKB_RXCB(msdu);
                dma_unmap_single(ab->dev, rxcb->paddr,
        if (!total_msdu_reaped)
                goto exit;
 
-       ath12k_dp_rx_bufs_replenish(ab, rx_ring, num_buffs_reaped);
+       ath12k_dp_rx_bufs_replenish(ab, rx_ring, &rx_desc_used_list,
+                                   num_buffs_reaped);
 
        ath12k_dp_rx_process_received_packets(ab, napi, &msdu_list,
                                              ring_id);
        }
 
        desc_info->skb = defrag_skb;
+       desc_info->in_use = true;
 
        list_del(&desc_info->list);
-       list_add_tail(&desc_info->list, &dp->rx_desc_used_list);
        spin_unlock_bh(&dp->rx_desc_lock);
 
        ATH12K_SKB_RXCB(defrag_skb)->paddr = buf_paddr;
 
 err_free_desc:
        spin_lock_bh(&dp->rx_desc_lock);
-       list_del(&desc_info->list);
-       list_add_tail(&desc_info->list, &dp->rx_desc_free_list);
+       desc_info->in_use = false;
        desc_info->skb = NULL;
+       list_add_tail(&desc_info->list, &dp->rx_desc_free_list);
        spin_unlock_bh(&dp->rx_desc_lock);
 err_unmap_dma:
        dma_unmap_single(ab->dev, buf_paddr, defrag_skb->len + skb_tailroom(defrag_skb),
 
 static int
 ath12k_dp_process_rx_err_buf(struct ath12k *ar, struct hal_reo_dest_ring *desc,
+                            struct list_head *used_list,
                             bool drop, u32 cookie)
 {
        struct ath12k_base *ab = ar->ab;
 
        msdu = desc_info->skb;
        desc_info->skb = NULL;
-       spin_lock_bh(&ab->dp.rx_desc_lock);
-       list_move_tail(&desc_info->list, &ab->dp.rx_desc_free_list);
-       spin_unlock_bh(&ab->dp.rx_desc_lock);
+
+       list_add_tail(&desc_info->list, used_list);
 
        rxcb = ATH12K_SKB_RXCB(msdu);
        dma_unmap_single(ar->ab->dev, rxcb->paddr,
        struct hal_reo_dest_ring *reo_desc;
        struct dp_rxdma_ring *rx_ring;
        struct dp_srng *reo_except;
+       LIST_HEAD(rx_desc_used_list);
        u32 desc_bank, num_msdus;
        struct hal_srng *srng;
        struct ath12k_dp *dp;
                        pdev_id = ath12k_hw_mac_id_to_pdev_id(ab->hw_params, mac_id);
                        ar = ab->pdevs[pdev_id].ar;
 
-                       if (!ath12k_dp_process_rx_err_buf(ar, reo_desc, drop,
+                       if (!ath12k_dp_process_rx_err_buf(ar, reo_desc,
+                                                         &rx_desc_used_list,
+                                                         drop,
                                                          msdu_cookies[i]))
                                tot_n_bufs_reaped++;
                }
 
        rx_ring = &dp->rx_refill_buf_ring;
 
-       ath12k_dp_rx_bufs_replenish(ab, rx_ring, tot_n_bufs_reaped);
+       ath12k_dp_rx_bufs_replenish(ab, rx_ring, &rx_desc_used_list,
+                                   tot_n_bufs_reaped);
 
        return tot_n_bufs_reaped;
 }
 int ath12k_dp_rx_process_wbm_err(struct ath12k_base *ab,
                                 struct napi_struct *napi, int budget)
 {
+       LIST_HEAD(rx_desc_used_list);
        struct ath12k *ar;
        struct ath12k_dp *dp = &ab->dp;
        struct dp_rxdma_ring *rx_ring;
                msdu = desc_info->skb;
                desc_info->skb = NULL;
 
-               spin_lock_bh(&dp->rx_desc_lock);
-               list_move_tail(&desc_info->list, &dp->rx_desc_free_list);
-               spin_unlock_bh(&dp->rx_desc_lock);
+               list_add_tail(&desc_info->list, &rx_desc_used_list);
 
                rxcb = ATH12K_SKB_RXCB(msdu);
                dma_unmap_single(ab->dev, rxcb->paddr,
        if (!num_buffs_reaped)
                goto done;
 
-       ath12k_dp_rx_bufs_replenish(ab, rx_ring, num_buffs_reaped);
+       ath12k_dp_rx_bufs_replenish(ab, rx_ring, &rx_desc_used_list,
+                                   num_buffs_reaped);
 
        rcu_read_lock();
        while ((msdu = __skb_dequeue(&msdu_list))) {