/* RX data path */
 
+int mlx5e_xsk_alloc_rx_wqes_batched(struct mlx5e_rq *rq, u16 ix, int wqe_bulk)
+{
+       struct mlx5_wq_cyc *wq = &rq->wqe.wq;
+       struct xdp_buff **buffs;
+       u32 contig, alloc;
+       int i;
+
+       /* mlx5e_init_frags_partition creates a 1:1 mapping between
+        * rq->wqe.frags and rq->wqe.alloc_units, which allows us to
+        * allocate XDP buffers straight into alloc_units.
+        */
+       BUILD_BUG_ON(sizeof(rq->wqe.alloc_units[0]) !=
+                    sizeof(rq->wqe.alloc_units[0].xsk));
+       buffs = (struct xdp_buff **)rq->wqe.alloc_units;
+       contig = mlx5_wq_cyc_get_size(wq) - ix;
+       if (wqe_bulk <= contig) {
+               alloc = xsk_buff_alloc_batch(rq->xsk_pool, buffs + ix, wqe_bulk);
+       } else {
+               alloc = xsk_buff_alloc_batch(rq->xsk_pool, buffs + ix, contig);
+               if (likely(alloc == contig))
+                       alloc += xsk_buff_alloc_batch(rq->xsk_pool, buffs, wqe_bulk - contig);
+       }
+
+       for (i = 0; i < alloc; i++) {
+               int j = mlx5_wq_cyc_ctr2ix(wq, ix + i);
+               struct mlx5e_wqe_frag_info *frag;
+               struct mlx5e_rx_wqe_cyc *wqe;
+               dma_addr_t addr;
+
+               wqe = mlx5_wq_cyc_get_wqe(wq, j);
+               /* Assumes log_num_frags == 0. */
+               frag = &rq->wqe.frags[j];
+
+               addr = xsk_buff_xdp_get_frame_dma(frag->au->xsk);
+               wqe->data[0].addr = cpu_to_be64(addr + rq->buff.headroom);
+       }
+
+       return alloc;
+}
+
 int mlx5e_xsk_alloc_rx_wqes(struct mlx5e_rq *rq, u16 ix, int wqe_bulk)
 {
        struct mlx5_wq_cyc *wq = &rq->wqe.wq;
 
 
 /* RX data path */
 
+int mlx5e_xsk_alloc_rx_wqes_batched(struct mlx5e_rq *rq, u16 ix, int wqe_bulk);
 int mlx5e_xsk_alloc_rx_wqes(struct mlx5e_rq *rq, u16 ix, int wqe_bulk);
 struct sk_buff *mlx5e_xsk_skb_from_cqe_mpwrq_linear(struct mlx5e_rq *rq,
                                                    struct mlx5e_mpw_info *wi,
 
        struct mlx5e_wqe_frag_info *prev = NULL;
        int i;
 
+       if (rq->xsk_pool) {
+               /* Assumptions used by XSK batched allocator. */
+               WARN_ON(rq->wqe.info.num_frags != 1);
+               WARN_ON(rq->wqe.info.log_num_frags != 0);
+               WARN_ON(rq->wqe.info.arr[0].frag_stride != PAGE_SIZE);
+       }
+
        next_frag.au = &rq->wqe.alloc_units[0];
 
        for (i = 0; i < mlx5_wq_cyc_get_size(&rq->wqe.wq); i++) {
 
 
        if (!rq->xsk_pool)
                count = mlx5e_alloc_rx_wqes(rq, head, wqe_bulk);
+       else if (likely(!rq->xsk_pool->dma_need_sync))
+               count = mlx5e_xsk_alloc_rx_wqes_batched(rq, head, wqe_bulk);
        else
+               /* If dma_need_sync is true, it's more efficient to call
+                * xsk_buff_alloc in a loop, rather than xsk_buff_alloc_batch,
+                * because the latter does the same check and returns only one
+                * frame.
+                */
                count = mlx5e_xsk_alloc_rx_wqes(rq, head, wqe_bulk);
 
        mlx5_wq_cyc_push_n(wq, count);