From: Valentine Fatiev <valentinef@nvidia.com>
Subject: [PATCH] BACKPORT: drivers/net/ethernet/mellanox/mlx5/core/en_rx.c

Change-Id: Iac1f1b54f8b0e6d35caa85c42cd420c02dfffb21
---
 .../net/ethernet/mellanox/mlx5/core/en_rx.c   | 1627 ++++++++++++++++-
 1 file changed, 1556 insertions(+), 71 deletions(-)

--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
@@ -36,9 +36,17 @@
 #include <linux/bitmap.h>
 #include <linux/filter.h>
 #include <net/ip6_checksum.h>
+#ifdef HAVE_NET_PAGE_POOL_OLD_H
+#include <net/page_pool.h>
+#endif
+#ifdef HAVE_NET_PAGE_POOL_TYPES_H
+#include <net/page_pool/types.h>
 #include <net/page_pool/helpers.h>
+#endif
 #include <net/inet_ecn.h>
+#ifdef HAVE_NET_GRO_H
 #include <net/gro.h>
+#endif
 #include <net/udp.h>
 #include <net/tcp.h>
 #include <net/xdp_sock_drv.h>
@@ -271,6 +279,171 @@ static inline u32 mlx5e_decompress_cqes_
 	return mlx5e_decompress_cqes_cont(rq, wq, 1, budget_rem);
 }
 
+#ifndef HAVE_PAGE_POOL_DEFRAG_PAGE
+static inline void mlx5e_rx_cache_page_swap(struct mlx5e_page_cache *cache,
+					    u32 a, u32 b)
+{
+	struct mlx5e_alloc_unit tmp;
+
+	tmp = cache->page_cache[a];
+	cache->page_cache[a] = cache->page_cache[b];
+	cache->page_cache[b] = tmp;
+}
+
+static inline void
+mlx5e_rx_cache_reduce_reset_watch(struct mlx5e_page_cache *cache)
+{
+		struct mlx5e_page_cache_reduce *reduce = &cache->reduce;
+
+			reduce->next_ts = ilog2(cache->sz) == cache->log_min_sz ?
+						MAX_JIFFY_OFFSET :
+								jiffies + reduce->graceful_period;
+				reduce->successive = 0;
+}
+
+
+static inline bool mlx5e_rx_cache_is_empty(struct mlx5e_page_cache *cache)
+{
+	return cache->head < 0;
+}
+
+static inline bool mlx5e_rx_cache_page_busy(struct mlx5e_page_cache *cache,
+					    u32 i)
+{
+	return page_ref_count(cache->page_cache[i].page) != 1;
+}
+
+static inline bool mlx5e_rx_cache_check_reduce(struct mlx5e_rq *rq)
+{
+	struct mlx5e_page_cache *cache = &rq->page_cache;
+
+#ifdef HAVE_BASECODE_EXTRAS
+	if (!cache->page_cache)
+		return false;
+#endif
+	if (unlikely(test_bit(MLX5E_RQ_STATE_CACHE_REDUCE_PENDING, &rq->state)))
+		return false;
+
+	if (time_before(jiffies, cache->reduce.next_ts))
+		return false;
+
+	if (likely(!mlx5e_rx_cache_is_empty(cache)) &&
+	    mlx5e_rx_cache_page_busy(cache, cache->head))
+		goto reset_watch;
+
+	if (ilog2(cache->sz) == cache->log_min_sz)
+		goto reset_watch;
+
+	/* would like to reduce */
+	if (cache->reduce.successive < MLX5E_PAGE_CACHE_REDUCE_SUCCESSIVE_CNT) {
+		cache->reduce.successive++;
+		return false;
+	}
+
+	return true;
+
+reset_watch:
+	mlx5e_rx_cache_reduce_reset_watch(cache);
+	return false;
+}
+
+static inline void mlx5e_rx_cache_may_reduce(struct mlx5e_rq *rq)
+{
+	struct mlx5e_page_cache *cache = &rq->page_cache;
+	struct mlx5e_page_cache_reduce *reduce = &cache->reduce;
+	int max_new_head;
+
+	if (!mlx5e_rx_cache_check_reduce(rq))
+		return;
+
+	/* do reduce */
+	rq->stats->cache_rdc++;
+	cache->sz >>= 1;
+	max_new_head = (cache->sz >> 1) - 1;
+	if (cache->head > max_new_head) {
+		u32 npages = cache->head - max_new_head;
+
+		cache->head = max_new_head;
+		if (cache->lrs >= cache->head)
+			cache->lrs = 0;
+
+		memcpy(reduce->pending, &cache->page_cache[cache->head + 1],
+		       npages * sizeof(*reduce->pending));
+		reduce->npages = npages;
+		set_bit(MLX5E_RQ_STATE_CACHE_REDUCE_PENDING, &rq->state);
+	}
+
+	mlx5e_rx_cache_reduce_reset_watch(cache);
+
+}
+
+static inline bool mlx5e_rx_cache_extend(struct mlx5e_rq *rq)
+{
+	struct mlx5e_page_cache *cache = &rq->page_cache;
+	struct mlx5e_page_cache_reduce *reduce = &cache->reduce;
+	struct mlx5e_params *params = &rq->priv->channels.params;
+	u8 log_limit_sz = cache->log_min_sz + params->log_rx_page_cache_mult;
+
+	if (ilog2(cache->sz) >= log_limit_sz)
+		return false;
+
+	rq->stats->cache_ext++;
+	cache->sz <<= 1;
+
+	mlx5e_rx_cache_reduce_reset_watch(cache);
+	schedule_delayed_work_on(smp_processor_id(), &reduce->reduce_work,
+				 reduce->delay);
+	return true;
+}
+
+#ifndef HAVE_DEV_PAGE_IS_REUSABLE
+static inline bool mlx5e_page_is_reserved(struct page *page)
+{
+	return page_is_pfmemalloc(page) || page_to_nid(page) != numa_mem_id();
+}
+#endif
+
+static inline bool mlx5e_rx_cache_put(struct mlx5e_rq *rq, struct mlx5e_alloc_unit *au)
+{
+	struct mlx5e_page_cache *cache = &rq->page_cache;
+	struct mlx5e_rq_stats *stats = rq->stats;
+
+	if (unlikely(cache->head == cache->sz - 1)) {
+		if (!mlx5e_rx_cache_extend(rq)) {
+			rq->stats->cache_full++;
+			return false;
+		}
+	}
+
+#ifdef HAVE_DEV_PAGE_IS_REUSABLE
+	if (!dev_page_is_reusable(au->page)) {
+		stats->cache_waive++;
+		return false;
+	}
+#else
+	if (unlikely(mlx5e_page_is_reserved(au->page))) {
+		stats->cache_waive++;
+		return false;
+	}
+#endif
+
+	cache->page_cache[++cache->head] = *au;
+#if !defined(HAVE_PAGE_POOL_GET_DMA_ADDR) || !defined(HAVE_XSK_BUFF_GET_FRAME_DMA)
+#if defined(HAVE_PAGE_DMA_ADDR_ARRAY)
+	cache->page_cache[cache->head].addr = au->page->dma_addr[0];
+#elif defined(HAVE_PAGE_DMA_ADDR)
+	cache->page_cache[cache->head].addr = au->page->dma_addr;
+#else
+	cache->page_cache[cache->head].addr = au->addr;
+#endif
+#endif
+	return true;
+}
+#endif
+
+
+#ifdef HAVE_PAGE_POOL_DEFRAG_PAGE
+
 #define MLX5E_PAGECNT_BIAS_MAX (PAGE_SIZE / 64)
 
 static int mlx5e_page_alloc_fragmented(struct mlx5e_rq *rq,
@@ -298,9 +471,219 @@ static void mlx5e_page_release_fragmente
 	u16 drain_count = MLX5E_PAGECNT_BIAS_MAX - frag_page->frags;
 	struct page *page = frag_page->page;
 
+#ifdef HAVE_PAGE_POOL_PUT_UNREFED_PAGE
 	if (page_pool_unref_page(page, drain_count) == 0)
 		page_pool_put_unrefed_page(rq->page_pool, page, -1, true);
+#else
+	if (page_pool_defrag_page(page, drain_count) == 0)
+		page_pool_put_defragged_page(rq->page_pool, page, -1, true);
+#endif
+}
+#else /* HAVE_PAGE_POOL_DEFRAG_PAGE */
+static inline bool mlx5e_rx_cache_get(struct mlx5e_rq *rq, struct mlx5e_alloc_unit *au)
+{
+	struct mlx5e_page_cache *cache = &rq->page_cache;
+	struct mlx5e_rq_stats *stats = rq->stats;
+#ifdef HAVE_PAGE_POOL_GET_DMA_ADDR
+	dma_addr_t addr;
+#endif
+
+	if (unlikely(mlx5e_rx_cache_is_empty(cache)))
+		goto err_no_page;
+
+	mlx5e_rx_cache_page_swap(cache, cache->head, cache->lrs);
+	cache->lrs++;
+	if (cache->lrs >= cache->head)
+		cache->lrs = 0;
+	if (mlx5e_rx_cache_page_busy(cache, cache->head))
+		goto err_no_page;
+
+
+	*au = cache->page_cache[cache->head--];
+	stats->cache_reuse++;
+
+#ifdef HAVE_PAGE_POOL_GET_DMA_ADDR
+	addr = page_pool_get_dma_addr(au->page);
+	/* Non-XSK always uses PAGE_SIZE. */
+	dma_sync_single_for_device(rq->pdev, addr, PAGE_SIZE, rq->buff.map_dir);
+#else
+	dma_sync_single_for_device(rq->pdev, au->addr, PAGE_SIZE, rq->buff.map_dir);
+#endif
+
+	return true;
+
+err_no_page:
+	stats->cache_alloc++;
+	cache->reduce.successive = 0;
+
+	return false;
+}
+
+static inline int mlx5e_page_alloc_pool(struct mlx5e_rq *rq, struct mlx5e_alloc_unit *au)
+{
+	dma_addr_t addr;
+
+
+
+	if (mlx5e_rx_cache_get(rq, au))
+		return 0;
+
+#ifdef HAVE_NET_PAGE_POOL_H
+	au->page = page_pool_dev_alloc_pages(rq->page_pool);
+#else
+	au->page = dev_alloc_page();
+#endif
+	if (unlikely(!au->page))
+		return -ENOMEM;
+
+	/* Non-XSK always uses PAGE_SIZE. */
+	addr = dma_map_page(rq->pdev, au->page, 0, PAGE_SIZE, rq->buff.map_dir);
+#if !defined(HAVE_PAGE_POOL_GET_DMA_ADDR) || !defined(HAVE_XSK_BUFF_GET_FRAME_DMA)
+	au->addr = addr;
+#endif
+	if (unlikely(dma_mapping_error(rq->pdev, addr))) {
+#ifdef HAVE_NET_PAGE_POOL_H
+		page_pool_recycle_direct(rq->page_pool, au->page);
+#else
+		mlx5e_put_page(au->page);
+#endif
+		au->page = NULL;
+		return -ENOMEM;
+	}
+
+#ifdef HAVE_PAGE_DMA_ADDR
+#ifdef HAVE_PAGE_POOL_GET_DMA_ADDR
+	page_pool_set_dma_addr(au->page, addr);
+#elif defined (HAVE_PAGE_DMA_ADDR_ARRAY)
+	au->page->dma_addr[0] = addr;
+#else
+	au->page->dma_addr = addr;
+#endif
+#endif /* HAVE_PAGE_DMA_ADDR */
+
+	return 0;
+}
+#endif /* HAVE_PAGE_POOL_DEFRAG_PAGE */
+#ifndef HAVE_XSK_BUFF_ALLOC_BATCH
+static inline int mlx5e_page_alloc(struct mlx5e_rq *rq, struct mlx5e_alloc_unit *au)
+{
+
+#ifdef HAVE_XSK_ZERO_COPY_SUPPORT
+#ifdef HAVE_XSK_BUFF_ALLOC
+#ifdef HAVE_NETDEV_BPF_XSK_BUFF_POOL
+	if (rq->xsk_pool) {
+		au->xsk = xsk_buff_alloc(rq->xsk_pool);
+		return likely(au->xsk) ? 0 : -ENOMEM;
+#else
+	if (rq->umem) {
+		au->xsk = xsk_buff_alloc(rq->umem);
+		return likely(au->xsk) ? 0 : -ENOMEM;
+#endif /* HAVE_NETDEV_BPF_XSK_BUFF_POOL */
+#else
+	if (rq->umem) {
+		return mlx5e_xsk_page_alloc_pool(rq, au);
+#endif /* HAVE_XSK_BUFF_ALLOC */
+	}
+	else
+#endif /* HAVE_XSK_ZERO_COPY */
+		return mlx5e_page_alloc_pool(rq, au);
+}
+#endif /* HAVE_XSK_BUFF_ALLOC_BATCH */
+
+#ifndef HAVE_PAGE_POOL_DEFRAG_PAGE
+void mlx5e_page_dma_unmap(struct mlx5e_rq *rq,
+#ifdef HAVE_PAGE_DMA_ADDR
+			  struct page *page)
+#else
+			  struct mlx5e_alloc_unit *au)
+#endif
+{
+#ifdef HAVE_PAGE_POOL_GET_DMA_ADDR
+	dma_addr_t dma_addr = page_pool_get_dma_addr(page);
+#elif defined(HAVE_PAGE_DMA_ADDR_ARRAY)
+	dma_addr_t dma_addr = page->dma_addr[0];
+#elif defined(HAVE_PAGE_DMA_ADDR)
+	dma_addr_t dma_addr = page->dma_addr;
+#else
+	dma_addr_t dma_addr = au->addr;
+#endif
+#ifdef HAVE_XSK_ZERO_COPY_SUPPORT
+	dma_unmap_page_attrs(rq->pdev, dma_addr, PAGE_SIZE, rq->buff.map_dir,
+			     DMA_ATTR_SKIP_CPU_SYNC);
+#else
+	dma_unmap_page(rq->pdev, dma_addr, PAGE_SIZE, rq->buff.map_dir);
+#endif
+#ifdef HAVE_PAGE_POOL_GET_DMA_ADDR
+	page_pool_set_dma_addr(page, 0);
+#elif defined(HAVE_PAGE_DMA_ADDR_ARRAY)
+	page->dma_addr[0] = 0;
+#elif defined(HAVE_PAGE_DMA_ADDR)
+	page->dma_addr = 0;
+#else
+	au->addr = 0;
+#endif
+}
+#endif
+
+#ifndef HAVE_PAGE_POOL_DEFRAG_PAGE
+void mlx5e_page_release_dynamic(struct mlx5e_rq *rq, struct mlx5e_alloc_unit *au, bool recycle)
+{
+#ifndef HAVE_XSK_BUFF_ALLOC_BATCH
+#ifdef HAVE_XSK_ZERO_COPY_SUPPORT
+#ifdef HAVE_NETDEV_BPF_XSK_BUFF_POOL
+	if (rq->xsk_pool) {
+#else
+	if (rq->umem) {
+#endif
+		/* The `recycle` parameter is ignored, and the page is always
+		 * put into the Reuse Ring, because there is no way to return
+		 * the page to the userspace when the interface goes down.
+		 */
+#ifdef HAVE_XSK_BUFF_ALLOC
+		xsk_buff_free(au->xsk);
+#else
+		mlx5e_xsk_page_release(rq, au);
+#endif
+		return;
+	}
+#endif /* HAVE_XSK_ZERO_COPY_SUPPORT */
+#endif /* HAVE_XSK_BUFF_ALLOC_BATCH */
+
+#ifdef HAVE_NET_PAGE_POOL_H
+	if (likely(recycle)) {
+		if (mlx5e_rx_cache_put(rq, au))
+			return;
+
+#ifdef HAVE_PAGE_DMA_ADDR
+		mlx5e_page_dma_unmap(rq, au->page);
+#else
+		mlx5e_page_dma_unmap(rq, au);
+#endif
+		page_pool_recycle_direct(rq->page_pool, au->page);
+	} else {
+#ifdef HAVE_PAGE_DMA_ADDR
+		mlx5e_page_dma_unmap(rq, au->page);
+#else
+		mlx5e_page_dma_unmap(rq, au);
+#endif
+#ifdef HAVE_PAGE_POOL_RELEASE_PAGE
+		page_pool_release_page(rq->page_pool, au->page);
+#endif
+		mlx5e_put_page(au->page);
+	}
+#else
+	if (likely(recycle) && mlx5e_rx_cache_put(rq, au))
+		return;
+
+#ifdef HAVE_PAGE_DMA_ADDR
+	mlx5e_page_dma_unmap(rq, au->page);
+#else
+	mlx5e_page_dma_unmap(rq, au);
+#endif
+	mlx5e_put_page(au->page);
+#endif
 }
+#endif /* HAVE_PAGE_POOL_DEFRAG_PAGE */
 
 static inline int mlx5e_get_rx_frag(struct mlx5e_rq *rq,
 				    struct mlx5e_wqe_frag_info *frag)
@@ -308,16 +691,26 @@ static inline int mlx5e_get_rx_frag(stru
 	int err = 0;
 
 	if (!frag->offset)
+#ifdef HAVE_PAGE_POOL_DEFRAG_PAGE
 		/* On first frag (offset == 0), replenish page.
 		 * Other frags that point to the same page (with a different
 		 * offset) should just use the new one without replenishing again
 		 * by themselves.
 		 */
 		err = mlx5e_page_alloc_fragmented(rq, frag->frag_page);
+#else
+		/* on first frag (offset == 0), replenish page (alloc_unit actually).
+		 * other frags that point to the same alloc_unit (with a different
+		 * offset) should just use the new one without replenishing again
+		 * by themselves.
+		 */
+		err = mlx5e_page_alloc_pool(rq, frag->au);
+#endif
 
 	return err;
 }
 
+#ifdef HAVE_PAGE_POOL_DEFRAG_PAGE
 static bool mlx5e_frag_can_release(struct mlx5e_wqe_frag_info *frag)
 {
 #define CAN_RELEASE_MASK \
@@ -327,12 +720,23 @@ static bool mlx5e_frag_can_release(struc
 
 	return (frag->flags & CAN_RELEASE_MASK) == CAN_RELEASE_VALUE;
 }
+#endif
 
 static inline void mlx5e_put_rx_frag(struct mlx5e_rq *rq,
+#ifdef HAVE_PAGE_POOL_DEFRAG_PAGE
 				     struct mlx5e_wqe_frag_info *frag)
+#else
+				     struct mlx5e_wqe_frag_info *frag,
+				     bool recycle)
+#endif
 {
+#ifdef HAVE_PAGE_POOL_DEFRAG_PAGE
 	if (mlx5e_frag_can_release(frag))
 		mlx5e_page_release_fragmented(rq, frag->frag_page);
+#else
+	if (frag->last_in_page)
+		mlx5e_page_release_dynamic(rq, frag->au, recycle);
+#endif
 }
 
 static inline struct mlx5e_wqe_frag_info *get_frag(struct mlx5e_rq *rq, u16 ix)
@@ -354,11 +758,30 @@ static int mlx5e_alloc_rx_wqe(struct mlx
 		err = mlx5e_get_rx_frag(rq, frag);
 		if (unlikely(err))
 			goto free_frags;
-
+#ifdef HAVE_PAGE_POOL_DEFRAG_PAGE
 		frag->flags &= ~BIT(MLX5E_WQE_FRAG_SKIP_RELEASE);
+#endif
 
 		headroom = i == 0 ? rq->buff.headroom : 0;
+#ifdef HAVE_PAGE_POOL_DEFRAG_PAGE
 		addr = page_pool_get_dma_addr(frag->frag_page->page);
+#else
+	 	addr = 
+#if defined(HAVE_PAGE_POOL_GET_DMA_ADDR) && defined(HAVE_XSK_BUFF_GET_FRAME_DMA)
+#ifdef HAVE_XSK_ZERO_COPY_SUPPORT
+#ifdef HAVE_NETDEV_BPF_XSK_BUFF_POOL
+		rq->xsk_pool ?
+			xsk_buff_xdp_get_frame_dma(frag->au->xsk) :
+#else
+			rq->umem ?
+			xsk_buff_xdp_get_frame_dma(frag->au->xsk) :
+#endif
+#endif /* HAVE_XSK_ZERO_COPY_SUPPORT*/
+			page_pool_get_dma_addr(frag->au->page);
+#else
+		frag->au->addr;
+#endif
+#endif /* HAVE_PAGE_POOL_DEFRAG_PAGE */
 		wqe->data[i].addr = cpu_to_be64(addr + frag->offset + headroom);
 	}
 
@@ -366,44 +789,81 @@ static int mlx5e_alloc_rx_wqe(struct mlx
 
 free_frags:
 	while (--i >= 0)
+#ifdef HAVE_PAGE_POOL_DEFRAG_PAGE
 		mlx5e_put_rx_frag(rq, --frag);
+#else
+		mlx5e_put_rx_frag(rq, --frag, true);
+#endif /* HAVE_PAGE_POOL_DEFRAG_PAGE */
 
 	return err;
 }
 
 static inline void mlx5e_free_rx_wqe(struct mlx5e_rq *rq,
+#ifdef HAVE_PAGE_POOL_DEFRAG_PAGE
 				     struct mlx5e_wqe_frag_info *wi)
+#else
+				     struct mlx5e_wqe_frag_info *wi,
+				     bool recycle)
+#endif
 {
 	int i;
 
+#ifndef HAVE_PAGE_POOL_DEFRAG_PAGE
+#ifdef HAVE_XDP_SUPPORT
+#ifdef HAVE_NETDEV_BPF_XSK_BUFF_POOL
+	if (rq->xsk_pool) {
+		/* The `recycle` parameter is ignored, and the page is always
+		 * put into the Reuse Ring, because there is no way to return
+		 * the page to the userspace when the interface goes down.
+		 */
+		xsk_buff_free(wi->au->xsk);
+		return;
+	}
+#endif
+#endif
+#endif /* HAVE_PAGE_POOL_DEFRAG_PAGE */
+
 	for (i = 0; i < rq->wqe.info.num_frags; i++, wi++)
+#ifdef HAVE_PAGE_POOL_DEFRAG_PAGE
 		mlx5e_put_rx_frag(rq, wi);
+#else
+		mlx5e_put_rx_frag(rq, wi, recycle);
+#endif
 }
 
+#ifdef HAVE_PAGE_POOL_DEFRAG_PAGE
+#ifdef HAVE_XDP_SUPPORT
 static void mlx5e_xsk_free_rx_wqe(struct mlx5e_wqe_frag_info *wi)
 {
 	if (!(wi->flags & BIT(MLX5E_WQE_FRAG_SKIP_RELEASE)))
 		xsk_buff_free(*wi->xskp);
 }
+#endif
 
 static void mlx5e_dealloc_rx_wqe(struct mlx5e_rq *rq, u16 ix)
 {
 	struct mlx5e_wqe_frag_info *wi = get_frag(rq, ix);
+	int i;
 
+#ifdef HAVE_XDP_SUPPORT
 	if (rq->xsk_pool) {
 		mlx5e_xsk_free_rx_wqe(wi);
-	} else {
+	} else
+#endif
+	{
+
 		mlx5e_free_rx_wqe(rq, wi);
 
 		/* Avoid a second release of the wqe pages: dealloc is called
 		 * for the same missing wqes on regular RQ flush and on regular
 		 * RQ close. This happens when XSK RQs come into play.
 		 */
-		for (int i = 0; i < rq->wqe.info.num_frags; i++, wi++)
+		for (i = 0; i < rq->wqe.info.num_frags; i++, wi++)
 			wi->flags |= BIT(MLX5E_WQE_FRAG_SKIP_RELEASE);
 	}
 }
 
+#ifdef HAVE_XDP_SUPPORT
 static void mlx5e_xsk_free_rx_wqes(struct mlx5e_rq *rq, u16 ix, int wqe_bulk)
 {
 	struct mlx5_wq_cyc *wq = &rq->wqe.wq;
@@ -421,6 +881,7 @@ static void mlx5e_xsk_free_rx_wqes(struc
 		mlx5e_xsk_free_rx_wqe(wi);
 	}
 }
+#endif
 
 static void mlx5e_free_rx_wqes(struct mlx5e_rq *rq, u16 ix, int wqe_bulk)
 {
@@ -435,6 +896,14 @@ static void mlx5e_free_rx_wqes(struct ml
 		mlx5e_free_rx_wqe(rq, wi);
 	}
 }
+#else /* HAVE_PAGE_POOL_DEFRAG_PAGE */
+static void mlx5e_dealloc_rx_wqe(struct mlx5e_rq *rq, u16 ix)
+{
+	struct mlx5e_wqe_frag_info *wi = get_frag(rq, ix);
+
+	mlx5e_free_rx_wqe(rq, wi, false);
+}
+#endif /* HAVE_PAGE_POOL_DEFRAG_PAGE */
 
 static int mlx5e_alloc_rx_wqes(struct mlx5e_rq *rq, u16 ix, int wqe_bulk)
 {
@@ -454,12 +923,16 @@ static int mlx5e_alloc_rx_wqes(struct ml
 	return i;
 }
 
+#ifdef HAVE_PAGE_POOL_DEFRAG_PAGE
 static int mlx5e_refill_rx_wqes(struct mlx5e_rq *rq, u16 ix, int wqe_bulk)
 {
 	int remaining = wqe_bulk;
 	int total_alloc = 0;
 	int refill_alloc;
 	int refill;
+	int i;
+	int j;
+	int k;
 
 	/* The WQE bulk is split into smaller bulks that are sized
 	 * according to the page pool cache refill size to avoid overflowing
@@ -482,12 +955,12 @@ static int mlx5e_refill_rx_wqes(struct m
 err_free:
 	mlx5e_free_rx_wqes(rq, ix, total_alloc + refill_alloc);
 
-	for (int i = 0; i < total_alloc + refill; i++) {
-		int j = mlx5_wq_cyc_ctr2ix(&rq->wqe.wq, ix + i);
+	for (i = 0; i < total_alloc + refill; i++) {
 		struct mlx5e_wqe_frag_info *frag;
+		j = mlx5_wq_cyc_ctr2ix(&rq->wqe.wq, ix + i);
 
 		frag = get_frag(rq, j);
-		for (int k = 0; k < rq->wqe.info.num_frags; k++, frag++)
+		for (k = 0; k < rq->wqe.info.num_frags; k++, frag++)
 			frag->flags |= BIT(MLX5E_WQE_FRAG_SKIP_RELEASE);
 	}
 
@@ -497,30 +970,50 @@ err_free:
 static void
 mlx5e_add_skb_shared_info_frag(struct mlx5e_rq *rq, struct skb_shared_info *sinfo,
 			       struct xdp_buff *xdp, struct mlx5e_frag_page *frag_page,
+#ifdef HAVE_XDP_HAS_FRAGS
 			       u32 frag_offset, u32 len)
+#else
+			       u32 frag_offset, u32 len, bool *has_frags)
+#endif
 {
 	skb_frag_t *frag;
 
 	dma_addr_t addr = page_pool_get_dma_addr(frag_page->page);
 
 	dma_sync_single_for_cpu(rq->pdev, addr + frag_offset, len, rq->buff.map_dir);
+#ifdef HAVE_XDP_HAS_FRAGS
 	if (!xdp_buff_has_frags(xdp)) {
+#else
+	if (!*has_frags) {
+#endif
 		/* Init on the first fragment to avoid cold cache access
 		 * when possible.
 		 */
 		sinfo->nr_frags = 0;
 		sinfo->xdp_frags_size = 0;
+#ifdef HAVE_XDP_HAS_FRAGS
 		xdp_buff_set_frags_flag(xdp);
+#else
+		*has_frags = true;
+#endif
 	}
 
 	frag = &sinfo->frags[sinfo->nr_frags++];
+#ifdef HAVE_SKB_FRAG_FILL_PAGE_DESC
 	skb_frag_fill_page_desc(frag, frag_page->page, frag_offset, len);
+#else
+	__skb_frag_set_page(frag, frag_page->page);
+	skb_frag_off_set(frag, frag_offset);
+	skb_frag_size_set(frag, len);
+#endif
 
 	if (page_is_pfmemalloc(frag_page->page))
 		xdp_buff_set_frag_pfmemalloc(xdp);
 	sinfo->xdp_frags_size += len;
 }
+#endif
 
+#ifdef HAVE_PAGE_POOL_DEFRAG_PAGE
 static inline void
 mlx5e_add_skb_frag(struct mlx5e_rq *rq, struct sk_buff *skb,
 		   struct page *page, u32 frag_offset, u32 len,
@@ -533,6 +1026,29 @@ mlx5e_add_skb_frag(struct mlx5e_rq *rq,
 	skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
 			page, frag_offset, len, truesize);
 }
+#else /* HAVE_PAGE_POOL_DEFRAG_PAGE */
+static inline void
+mlx5e_add_skb_frag(struct mlx5e_rq *rq, struct sk_buff *skb,
+		   struct mlx5e_alloc_unit *au, u32 frag_offset, u32 len,
+		   unsigned int truesize)
+{
+#ifdef HAVE_PAGE_POOL_GET_DMA_ADDR
+	dma_addr_t addr = page_pool_get_dma_addr(au->page);
+
+	dma_sync_single_for_cpu(rq->pdev, addr + frag_offset, len,
+				rq->buff.map_dir);
+#else
+	dma_sync_single_for_cpu(rq->pdev, au->addr + frag_offset, len,
+				rq->buff.map_dir);
+#endif
+
+	page_ref_inc(au->page);
+
+	skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
+			au->page, frag_offset, len, truesize);
+}
+#endif /* HAVE_PAGE_POOL_DEFRAG_PAGE */
+
 
 static inline void
 mlx5e_copy_skb_header(struct mlx5e_rq *rq, struct sk_buff *skb,
@@ -548,11 +1064,13 @@ mlx5e_copy_skb_header(struct mlx5e_rq *r
 	skb_copy_to_linear_data(skb, from, len);
 }
 
+#ifdef HAVE_PAGE_POOL_DEFRAG_PAGE
 static void
 mlx5e_free_rx_mpwqe(struct mlx5e_rq *rq, struct mlx5e_mpw_info *wi)
 {
-	bool no_xdp_xmit;
 	int i;
+#ifdef HAVE_XDP_SUPPORT
+	bool no_xdp_xmit;
 
 	/* A common case for AF_XDP. */
 	if (bitmap_full(wi->skip_release_bitmap, rq->mpwqe.pages_per_wqe))
@@ -580,7 +1098,63 @@ mlx5e_free_rx_mpwqe(struct mlx5e_rq *rq,
 			}
 		}
 	}
+#else
+	if (bitmap_full(wi->skip_release_bitmap, rq->mpwqe.pages_per_wqe))
+		return;
+
+
+	for (i = 0; i < rq->mpwqe.pages_per_wqe; i++) {
+			struct mlx5e_frag_page *frag_page;
+
+			frag_page = &wi->alloc_units.frag_pages[i];
+			mlx5e_page_release_fragmented(rq, frag_page);
+	}
+#endif
 }
+#else /* HAVE_PAGE_POOL_DEFRAG_PAGE */
+static void
+mlx5e_free_rx_mpwqe(struct mlx5e_rq *rq, struct mlx5e_mpw_info *wi, bool recycle)
+{
+#ifdef HAVE_XDP_SUPPORT
+	struct mlx5e_alloc_unit *alloc_units = wi->alloc_units;
+	bool no_xdp_xmit;
+	int i;
+
+	/* A common case for AF_XDP. */
+	if (bitmap_full(wi->skip_release_bitmap, rq->mpwqe.pages_per_wqe))
+		return;
+
+	no_xdp_xmit = bitmap_empty(wi->skip_release_bitmap, rq->mpwqe.pages_per_wqe);
+
+#ifdef HAVE_NETDEV_BPF_XSK_BUFF_POOL
+	if (rq->xsk_pool) {
+		/* The `recycle` parameter is ignored, and the page is always
+		 * put into the Reuse Ring, because there is no way to return
+		 * the page to the userspace when the interface goes down.
+		 */
+		for (i = 0; i < rq->mpwqe.pages_per_wqe; i++)
+			if (no_xdp_xmit || !test_bit(i, wi->skip_release_bitmap))
+				xsk_buff_free(alloc_units[i].xsk);
+	} else
+#endif
+	{
+		for (i = 0; i < rq->mpwqe.pages_per_wqe; i++)
+			if (no_xdp_xmit || !test_bit(i, wi->skip_release_bitmap))
+				mlx5e_page_release_dynamic(rq, &alloc_units[i], recycle);
+	}
+#else
+	struct mlx5e_alloc_unit *alloc_units = &wi->alloc_units[0];
+	int i;
+
+	if (bitmap_full(wi->skip_release_bitmap, rq->mpwqe.pages_per_wqe))
+		return;
+
+
+	for (i = 0; i < rq->mpwqe.pages_per_wqe; i++, alloc_units++)
+		mlx5e_page_release_dynamic(rq, alloc_units, recycle);
+#endif
+}
+#endif /* HAVE_PAGE_POOL_DEFRAG_PAGE */
 
 static void mlx5e_post_rx_mpwqe(struct mlx5e_rq *rq, u8 n)
 {
@@ -596,6 +1170,10 @@ static void mlx5e_post_rx_mpwqe(struct m
 	dma_wmb();
 
 	mlx5_wq_ll_update_db_record(wq);
+
+#ifndef HAVE_PAGE_POOL_DEFRAG_PAGE
+	mlx5e_rx_cache_may_reduce(rq);
+#endif
 }
 
 /* This function returns the size of the continuous free space inside a bitmap
@@ -635,6 +1213,7 @@ static void build_klm_umr(struct mlx5e_i
 	umr_wqe->uctrl.mkey_mask     = cpu_to_be64(MLX5_MKEY_MASK_FREE);
 }
 
+#ifdef HAVE_PAGE_POOL_DEFRAG_PAGE
 static int mlx5e_build_shampo_hd_umr(struct mlx5e_rq *rq,
 				     struct mlx5e_icosq *sq,
 				     u16 klm_entries, u16 index)
@@ -710,12 +1289,98 @@ err_unmap:
 		dma_info = &shampo->info[--index];
 		if (!(i & (MLX5E_SHAMPO_WQ_HEADER_PER_PAGE - 1))) {
 			dma_info->addr = ALIGN_DOWN(dma_info->addr, PAGE_SIZE);
-			mlx5e_page_release_fragmented(rq, dma_info->frag_page);
+			mlx5e_page_release_fragmented(rq, dma_info->frag_page);
+		}
+	}
+	rq->stats->buff_alloc_err++;
+	return err;
+}
+
+#else /* HAVE_PAGE_POOL_DEFRAG_PAGE */
+static int mlx5e_build_shampo_hd_umr(struct mlx5e_rq *rq,
+				     struct mlx5e_icosq *sq,
+				     u16 klm_entries, u16 index)
+{
+	struct mlx5e_shampo_hd *shampo = rq->mpwqe.shampo;
+	u16 entries, pi, header_offset, err, wqe_bbs, new_entries;
+	u32 lkey = rq->mdev->mlx5e_res.hw_objs.mkey;
+	struct page *page = shampo->last_page;
+	u64 addr = shampo->last_addr;
+	struct mlx5e_dma_info *dma_info;
+	struct mlx5e_umr_wqe *umr_wqe;
+	int headroom, i;
+
+	headroom = rq->buff.headroom;
+	new_entries = klm_entries - (shampo->pi & (MLX5_UMR_KLM_NUM_ENTRIES_ALIGNMENT - 1));
+	entries = ALIGN(klm_entries, MLX5_UMR_KLM_NUM_ENTRIES_ALIGNMENT);
+	wqe_bbs = MLX5E_KLM_UMR_WQEBBS(entries);
+	pi = mlx5e_icosq_get_next_pi(sq, wqe_bbs);
+	umr_wqe = mlx5_wq_cyc_get_wqe(&sq->wq, pi);
+	build_klm_umr(sq, umr_wqe, shampo->key, index, entries, wqe_bbs);
+
+	for (i = 0; i < entries; i++, index++) {
+		dma_info = &shampo->info[index];
+		if (i >= klm_entries || (index < shampo->pi && shampo->pi - index <
+					 MLX5_UMR_KLM_NUM_ENTRIES_ALIGNMENT))
+			goto update_klm;
+		header_offset = (index & (MLX5E_SHAMPO_WQ_HEADER_PER_PAGE - 1)) <<
+			MLX5E_SHAMPO_LOG_MAX_HEADER_ENTRY_SIZE;
+		if (!(header_offset & (PAGE_SIZE - 1))) {
+			struct mlx5e_alloc_unit au;
+
+			err = mlx5e_page_alloc_pool(rq, &au);
+			if (unlikely(err))
+				goto err_unmap;
+			page = dma_info->page = au.page;
+			addr = dma_info->addr =
+#ifdef HAVE_PAGE_POOL_GET_DMA_ADDR
+				page_pool_get_dma_addr(au.page);
+#else
+ 				au.addr;
+#endif
+		} else {
+			dma_info->addr = addr + header_offset;
+			dma_info->page = page;
+		}
+
+update_klm:
+		umr_wqe->inline_klms[i].bcount =
+			cpu_to_be32(MLX5E_RX_MAX_HEAD);
+		umr_wqe->inline_klms[i].key    = cpu_to_be32(lkey);
+		umr_wqe->inline_klms[i].va     =
+			cpu_to_be64(dma_info->addr + headroom);
+	}
+
+	sq->db.wqe_info[pi] = (struct mlx5e_icosq_wqe_info) {
+		.wqe_type	= MLX5E_ICOSQ_WQE_SHAMPO_HD_UMR,
+		.num_wqebbs	= wqe_bbs,
+		.shampo.len	= new_entries,
+	};
+
+	shampo->pi = (shampo->pi + new_entries) & (shampo->hd_per_wq - 1);
+	shampo->last_page = page;
+	shampo->last_addr = addr;
+	sq->pc += wqe_bbs;
+	sq->doorbell_cseg = &umr_wqe->ctrl;
+
+	return 0;
+
+err_unmap:
+	while (--i >= 0) {
+		dma_info = &shampo->info[--index];
+		if (!(i & (MLX5E_SHAMPO_WQ_HEADER_PER_PAGE - 1))) {
+			struct mlx5e_alloc_unit au = {
+				.page = dma_info->page,
+			};
+
+			dma_info->addr = ALIGN_DOWN(dma_info->addr, PAGE_SIZE);
+			mlx5e_page_release_dynamic(rq, &au, true);
 		}
 	}
 	rq->stats->buff_alloc_err++;
 	return err;
 }
+#endif /* HAVE_PAGE_POOL_DEFRAG_PAGE */
 
 static int mlx5e_alloc_rx_hd_mpwqe(struct mlx5e_rq *rq)
 {
@@ -756,6 +1421,7 @@ static int mlx5e_alloc_rx_hd_mpwqe(struc
 	return 0;
 }
 
+#ifdef HAVE_PAGE_POOL_DEFRAG_PAGE
 static int mlx5e_alloc_rx_mpwqe(struct mlx5e_rq *rq, u16 ix)
 {
 	struct mlx5e_mpw_info *wi = mlx5e_get_mpw_info(rq, ix);
@@ -838,6 +1504,164 @@ err:
 
 	return err;
 }
+#else
+static int mlx5e_alloc_rx_mpwqe(struct mlx5e_rq *rq, u16 ix)
+{
+	struct mlx5e_mpw_info *wi = mlx5e_get_mpw_info(rq, ix);
+	struct mlx5e_alloc_unit *au = &wi->alloc_units[0];
+	struct mlx5e_icosq *sq = rq->icosq;
+	struct mlx5_wq_cyc *wq = &sq->wq;
+	struct mlx5e_umr_wqe *umr_wqe;
+	u32 offset; /* 17-bit value with MTT. */
+	u16 pi;
+	int err;
+	int i;
+
+#if defined(HAVE_XSK_ZERO_COPY_SUPPORT) && !defined(HAVE_XSK_BUFF_ALLOC_BATCH)
+#ifdef HAVE_NETDEV_BPF_XSK_BUFF_POOL
+	if (rq->xsk_pool &&
+	    unlikely(!xsk_buff_can_alloc(rq->xsk_pool, rq->mpwqe.pages_per_wqe))) {
+#elif defined(HAVE_XSK_BUFF_ALLOC)
+	if (rq->umem &&
+	    unlikely(!xsk_buff_can_alloc(rq->umem, rq->mpwqe.pages_per_wqe))) {
+
+#else
+	if (rq->umem &&
+	    unlikely(!mlx5e_xsk_pages_enough_umem(rq, rq->mpwqe.pages_per_wqe))) {
+#endif
+		err = -ENOMEM;
+			goto err;
+	}
+#endif /* HAVE_XSK_ZERO_COPY_SUPPORT && !HAVE_XSK_BUFF_ALLOC_BATCH */
+	if (test_bit(MLX5E_RQ_STATE_SHAMPO, &rq->state)) {
+		err = mlx5e_alloc_rx_hd_mpwqe(rq);
+		if (unlikely(err))
+			goto err;
+	}
+
+	pi = mlx5e_icosq_get_next_pi(sq, rq->mpwqe.umr_wqebbs);
+	umr_wqe = mlx5_wq_cyc_get_wqe(wq, pi);
+	memcpy(umr_wqe, &rq->mpwqe.umr_wqe, sizeof(struct mlx5e_umr_wqe));
+
+#ifndef HAVE_XSK_BUFF_ALLOC_BATCH
+	if (unlikely(rq->mpwqe.umr_mode)) {
+		for (i = 0; i < rq->mpwqe.pages_per_wqe; i++, au++) {
+			dma_addr_t addr;
+
+			err = mlx5e_page_alloc(rq, au);
+			if (unlikely(err))
+				goto err_unmap;
+			/* Unaligned means XSK. */
+			addr =
+#if defined(HAVE_PAGE_POOL_GET_DMA_ADDR) && defined(HAVE_XSK_BUFF_GET_FRAME_DMA)
+				xsk_buff_xdp_get_frame_dma(au->xsk);
+#else
+				au->addr;
+#endif
+			umr_wqe->inline_ksms[i] = (struct mlx5_ksm) {
+				.key = rq->mkey_be,
+				.va = cpu_to_be64(addr),
+			};
+		}
+	} else {
+		for (i = 0; i < rq->mpwqe.pages_per_wqe; i++, au++) {
+			dma_addr_t addr;
+
+			err = mlx5e_page_alloc(rq, au);
+			if (unlikely(err))
+				goto err_unmap;
+			addr =
+#if defined(HAVE_PAGE_POOL_GET_DMA_ADDR) && defined(HAVE_XSK_BUFF_GET_FRAME_DMA)
+#ifdef HAVE_XSK_ZERO_COPY_SUPPORT
+#ifdef HAVE_NETDEV_BPF_XSK_BUFF_POOL
+                 rq->xsk_pool ?
+                         xsk_buff_xdp_get_frame_dma(au->xsk) :
+#else
+		 rq->umem ?
+                         xsk_buff_xdp_get_frame_dma(au->xsk) :
+#endif
+#endif
+				page_pool_get_dma_addr(au->page);
+#else
+			au->addr;
+#endif
+		umr_wqe->inline_mtts[i] = (struct mlx5_mtt) {
+			.ptag = cpu_to_be64(addr | MLX5_EN_WR),
+		};
+		}
+	}
+#else
+	for (i = 0; i < rq->mpwqe.pages_per_wqe; i++, au++) {
+		dma_addr_t addr;
+
+		err = mlx5e_page_alloc_pool(rq, au);
+		if (unlikely(err))
+			goto err_unmap;
+                 addr =
+#ifdef HAVE_PAGE_POOL_GET_DMA_ADDR
+		page_pool_get_dma_addr(au->page);
+#else
+		 au->addr;
+#endif
+		umr_wqe->inline_mtts[i] = (struct mlx5_mtt) {
+			.ptag = cpu_to_be64(addr | MLX5_EN_WR),
+		};
+	}
+#endif
+
+	/* Pad if needed, in case the value set to ucseg->xlt_octowords
+	 * in mlx5e_build_umr_wqe() needed alignment.
+	 */
+	if (rq->mpwqe.pages_per_wqe & (MLX5_UMR_MTT_NUM_ENTRIES_ALIGNMENT - 1)) {
+		int pad = ALIGN(rq->mpwqe.pages_per_wqe, MLX5_UMR_MTT_NUM_ENTRIES_ALIGNMENT) -
+			rq->mpwqe.pages_per_wqe;
+
+		memset(&umr_wqe->inline_mtts[rq->mpwqe.pages_per_wqe], 0,
+		       sizeof(*umr_wqe->inline_mtts) * pad);
+	}
+
+	bitmap_zero(wi->skip_release_bitmap, rq->mpwqe.pages_per_wqe);
+	wi->consumed_strides = 0;
+
+	umr_wqe->ctrl.opmod_idx_opcode =
+		cpu_to_be32((sq->pc << MLX5_WQE_CTRL_WQE_INDEX_SHIFT) |
+			    MLX5_OPCODE_UMR);
+
+#ifndef HAVE_XSK_BUFF_ALLOC_BATCH
+	offset = ix * rq->mpwqe.mtts_per_wqe;
+if (!rq->mpwqe.umr_mode)
+		offset = MLX5_ALIGNED_MTTS_OCTW(offset);
+#else
+		offset = (ix * rq->mpwqe.mtts_per_wqe) * sizeof(struct mlx5_mtt) / MLX5_OCTWORD;
+#endif
+
+	umr_wqe->uctrl.xlt_offset = cpu_to_be16(offset);
+
+	sq->db.wqe_info[pi] = (struct mlx5e_icosq_wqe_info) {
+		.wqe_type   = MLX5E_ICOSQ_WQE_UMR_RX,
+		.num_wqebbs = rq->mpwqe.umr_wqebbs,
+		.umr.rq     = rq,
+	};
+
+	sq->pc += rq->mpwqe.umr_wqebbs;
+
+	sq->doorbell_cseg = &umr_wqe->ctrl;
+
+	return 0;
+
+err_unmap:
+	while (--i >= 0) {
+		au--;
+		mlx5e_page_release_dynamic(rq, au, true);
+	}
+
+err:
+	rq->stats->buff_alloc_err++;
+
+	return err;
+}
+
+#endif
 
 /* This function is responsible to dealloc SHAMPO header buffer.
  * close == true specifies that we are in the middle of closing RQ operation so
@@ -848,7 +1672,11 @@ err:
 void mlx5e_shampo_dealloc_hd(struct mlx5e_rq *rq, u16 len, u16 start, bool close)
 {
 	struct mlx5e_shampo_hd *shampo = rq->mpwqe.shampo;
+#ifdef HAVE_PAGE_POOL_DEFRAG_PAGE
 	struct mlx5e_frag_page *deleted_page = NULL;
+#else
+	struct page *deleted_page = NULL;
+#endif
 	int hd_per_wq = shampo->hd_per_wq;
 	struct mlx5e_dma_info *hd_info;
 	int i, index = start;
@@ -862,12 +1690,23 @@ void mlx5e_shampo_dealloc_hd(struct mlx5
 
 		hd_info = &shampo->info[index];
 		hd_info->addr = ALIGN_DOWN(hd_info->addr, PAGE_SIZE);
+#ifdef HAVE_PAGE_POOL_DEFRAG_PAGE
 		if (hd_info->frag_page && hd_info->frag_page != deleted_page) {
 			deleted_page = hd_info->frag_page;
 			mlx5e_page_release_fragmented(rq, hd_info->frag_page);
 		}
 
 		hd_info->frag_page = NULL;
+#else
+		if (hd_info->page != deleted_page) {
+			struct mlx5e_alloc_unit au = {
+				.page = hd_info->page,
+			};
+
+			deleted_page = hd_info->page;
+			mlx5e_page_release_dynamic(rq, &au, false);
+		}
+#endif
 	}
 
 	if (start + len > hd_per_wq) {
@@ -882,13 +1721,18 @@ void mlx5e_shampo_dealloc_hd(struct mlx5
 static void mlx5e_dealloc_rx_mpwqe(struct mlx5e_rq *rq, u16 ix)
 {
 	struct mlx5e_mpw_info *wi = mlx5e_get_mpw_info(rq, ix);
+#ifdef HAVE_PAGE_POOL_DEFRAG_PAGE
 	/* This function is called on rq/netdev close. */
 	mlx5e_free_rx_mpwqe(rq, wi);
 
 	/* Avoid a second release of the wqe pages: dealloc is called also
 	 * for missing wqes on an already flushed RQ.
 	 */
+#else
+	mlx5e_free_rx_mpwqe(rq, wi, false);
+#endif
 	bitmap_fill(wi->skip_release_bitmap, rq->mpwqe.pages_per_wqe);
+
 }
 
 INDIRECT_CALLABLE_SCOPE bool mlx5e_post_rx_wqes(struct mlx5e_rq *rq)
@@ -904,8 +1748,10 @@ INDIRECT_CALLABLE_SCOPE bool mlx5e_post_
 	if (mlx5_wq_cyc_missing(wq) < rq->wqe.info.wqe_bulk)
 		return false;
 
+#ifdef HAVE_PAGE_POLL_NID_CHANGED
 	if (rq->page_pool)
 		page_pool_nid_changed(rq->page_pool, numa_mem_id());
+#endif
 
 	wqe_bulk = mlx5_wq_cyc_missing(wq);
 	head = mlx5_wq_cyc_get_head(wq);
@@ -914,10 +1760,15 @@ INDIRECT_CALLABLE_SCOPE bool mlx5e_post_
 	 * WQEs that aren't completed yet. Stop earlier.
 	 */
 	wqe_bulk -= (head + wqe_bulk) & rq->wqe.info.wqe_index_mask;
-
+#ifdef HAVE_PAGE_POOL_DEFRAG_PAGE
+#ifdef HAVE_XDP_SUPPORT
 	if (!rq->xsk_pool) {
 		count = mlx5e_refill_rx_wqes(rq, head, wqe_bulk);
+#ifdef HAVE_SKIP_CALLING_NOP_SYNC_OPS //forwardport
+	} else if (likely(!dma_dev_need_sync(rq->pdev))) {
+#else
 	} else if (likely(!rq->xsk_pool->dma_need_sync)) {
+#endif
 		mlx5e_xsk_free_rx_wqes(rq, head, wqe_bulk);
 		count = mlx5e_xsk_alloc_rx_wqes_batched(rq, head, wqe_bulk);
 	} else {
@@ -929,6 +1780,23 @@ INDIRECT_CALLABLE_SCOPE bool mlx5e_post_
 		 */
 		count = mlx5e_xsk_alloc_rx_wqes(rq, head, wqe_bulk);
 	}
+#else
+	count = mlx5e_refill_rx_wqes(rq, head, wqe_bulk);
+#endif /* HAVE_XDP_SUPPORT */
+#else /* HAVE_PAGE_POOL_DEFRAG_PAGE */
+#ifdef HAVE_XSK_ZERO_COPY_SUPPORT
+#ifdef HAVE_NETDEV_BPF_XSK_BUFF_POOL
+	if (!rq->xsk_pool)
+#else
+	if (!rq->umem)
+#endif
+		count = mlx5e_alloc_rx_wqes(rq, head, wqe_bulk);
+	else
+		count = mlx5e_xsk_alloc_rx_wqes(rq, head, wqe_bulk);
+#else
+		count = mlx5e_alloc_rx_wqes(rq, head, wqe_bulk);
+#endif
+#endif /* HAVE_PAGE_POOL_DEFRAG_PAGE */
 
 	mlx5_wq_cyc_push_n(wq, count);
 	if (unlikely(count != wqe_bulk)) {
@@ -940,7 +1808,9 @@ INDIRECT_CALLABLE_SCOPE bool mlx5e_post_
 	dma_wmb();
 
 	mlx5_wq_cyc_update_db_record(wq);
-
+#ifndef HAVE_PAGE_POOL_DEFRAG_PAGE
+	mlx5e_rx_cache_may_reduce(rq);
+#endif
 	return busy;
 }
 
@@ -967,7 +1837,7 @@ void mlx5e_free_icosq_descs(struct mlx5e
 		ci = mlx5_wq_cyc_ctr2ix(&sq->wq, sqcc);
 		wi = &sq->db.wqe_info[ci];
 		sqcc += wi->num_wqebbs;
-#ifdef CONFIG_MLX5_EN_TLS
+#ifdef HAVE_KTLS_RX_SUPPORT
 		switch (wi->wqe_type) {
 		case MLX5E_ICOSQ_WQE_SET_PSV_TLS:
 			mlx5e_ktls_handle_ctx_completion(wi);
@@ -1062,7 +1932,7 @@ int mlx5e_poll_ico_cq(struct mlx5e_cq *c
 			case MLX5E_ICOSQ_WQE_SHAMPO_HD_UMR:
 				mlx5e_handle_shampo_hd_umr(wi->shampo, sq);
 				break;
-#ifdef CONFIG_MLX5_EN_TLS
+#ifdef HAVE_KTLS_RX_SUPPORT
 			case MLX5E_ICOSQ_WQE_UMR_TLS:
 				break;
 			case MLX5E_ICOSQ_WQE_SET_PSV_TLS:
@@ -1113,19 +1983,35 @@ INDIRECT_CALLABLE_SCOPE bool mlx5e_post_
 	if (likely(missing < rq->mpwqe.min_wqe_bulk))
 		return false;
 
+#ifdef HAVE_PAGE_POLL_NID_CHANGED
 	if (rq->page_pool)
 		page_pool_nid_changed(rq->page_pool, numa_mem_id());
+#endif
 
 	head = rq->mpwqe.actual_wq_head;
 	i = missing;
 	do {
+#ifdef HAVE_PAGE_POOL_DEFRAG_PAGE
 		struct mlx5e_mpw_info *wi = mlx5e_get_mpw_info(rq, head);
 
 		/* Deferred free for better page pool cache usage. */
 		mlx5e_free_rx_mpwqe(rq, wi);
+#endif
 
-		alloc_err = rq->xsk_pool ? mlx5e_xsk_alloc_rx_mpwqe(rq, head) :
-					   mlx5e_alloc_rx_mpwqe(rq, head);
+               alloc_err =
+#if defined(HAVE_XSK_BUFF_ALLOC_BATCH) && defined(HAVE_XSK_ZERO_COPY_SUPPORT)
+#ifdef HAVE_NETDEV_BPF_XSK_BUFF_POOL
+                       rq->xsk_pool ?
+                       mlx5e_xsk_alloc_rx_mpwqe(rq, head) :
+                       mlx5e_alloc_rx_mpwqe(rq, head);
+#else
+               rq->umem ?
+                       mlx5e_xsk_alloc_rx_mpwqe(rq, head) :
+                       mlx5e_alloc_rx_mpwqe(rq, head);
+#endif
+#else
+               mlx5e_alloc_rx_mpwqe(rq, head);
+#endif
 
 		if (unlikely(alloc_err))
 			break;
@@ -1147,8 +2033,14 @@ INDIRECT_CALLABLE_SCOPE bool mlx5e_post_
 	 * the driver when it refills the Fill Ring.
 	 * 2. Otherwise, busy poll by rescheduling the NAPI poll.
 	 */
+#ifdef HAVE_XSK_ZERO_COPY_SUPPORT
+#ifdef HAVE_NETDEV_BPF_XSK_BUFF_POOL
 	if (unlikely(alloc_err == -ENOMEM && rq->xsk_pool))
+#else
+	if (unlikely(alloc_err == -ENOMEM && rq->umem))
+#endif
 		return true;
+#endif
 
 	return false;
 }
@@ -1228,7 +2120,11 @@ static void *mlx5e_shampo_get_packet_hd(
 	struct mlx5e_dma_info *last_head = &rq->mpwqe.shampo->info[header_index];
 	u16 head_offset = (last_head->addr & (PAGE_SIZE - 1)) + rq->buff.headroom;
 
+#ifdef HAVE_PAGE_POOL_DEFRAG_PAGE
 	return page_address(last_head->frag_page->page) + head_offset;
+#else
+	return page_address(last_head->page) + head_offset;
+#endif
 }
 
 static void mlx5e_shampo_update_ipv4_udp_hdr(struct mlx5e_rq *rq, struct iphdr *ipv4)
@@ -1651,118 +2547,316 @@ static inline void mlx5e_complete_rx_cqe
 		rq->dim_obj.sample.pkt_ctr  = rq->stats->packets;
 		rq->dim_obj.sample.byte_ctr = rq->stats->bytes;
 	}
-}
+}
+
+static inline
+struct sk_buff *mlx5e_build_linear_skb(struct mlx5e_rq *rq, void *va,
+				       u32 frag_size, u16 headroom,
+				       u32 cqe_bcnt, u32 metasize)
+{
+#ifdef HAVE_NAPI_BUILD_SKB
+	struct sk_buff *skb = napi_build_skb(va, frag_size);
+#else
+	struct sk_buff *skb = build_skb(va, frag_size);
+#endif
+
+	if (unlikely(!skb)) {
+		rq->stats->buff_alloc_err++;
+		return NULL;
+	}
+
+	skb_reserve(skb, headroom);
+	skb_put(skb, cqe_bcnt);
+	if (metasize)
+		skb_metadata_set(skb, metasize);
+	return skb;
+}
+
+#ifdef HAVE_PAGE_POOL_DEFRAG_PAGE
+static void mlx5e_fill_mxbuf(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe,
+			     void *va, u16 headroom, u32 frame_sz, u32 len,
+			     struct mlx5e_xdp_buff *mxbuf)
+{
+	xdp_init_buff(&mxbuf->xdp, frame_sz, &rq->xdp_rxq);
+	xdp_prepare_buff(&mxbuf->xdp, va, headroom, len, true);
+#ifdef HAVE_XDP_METADATA_OPS
+	mxbuf->cqe = cqe;
+	mxbuf->rq = rq;
+#endif
+}
+
+static struct sk_buff *
+mlx5e_skb_from_cqe_linear(struct mlx5e_rq *rq, struct mlx5e_wqe_frag_info *wi,
+			  struct mlx5_cqe64 *cqe, u32 cqe_bcnt)
+{
+	struct mlx5e_frag_page *frag_page = wi->frag_page;
+	u16 rx_headroom = rq->buff.headroom;
+#ifdef HAVE_XDP_SUPPORT
+	struct bpf_prog *prog;
+#endif
+	struct sk_buff *skb;
+	u32 metasize = 0;
+	void *va, *data;
+	dma_addr_t addr;
+	u32 frag_size;
+
+	va             = page_address(frag_page->page) + wi->offset;
+	data           = va + rx_headroom;
+	frag_size      = MLX5_SKB_FRAG_SZ(rx_headroom + cqe_bcnt);
+
+	addr = page_pool_get_dma_addr(frag_page->page);
+	dma_sync_single_range_for_cpu(rq->pdev, addr, wi->offset,
+				      frag_size, rq->buff.map_dir);
+	net_prefetch(data);
+
+#ifdef HAVE_XDP_SUPPORT
+	prog = rcu_dereference(rq->xdp_prog);
+	if (prog) {
+		struct mlx5e_xdp_buff mxbuf;
+
+		net_prefetchw(va); /* xdp_frame data area */
+		mlx5e_fill_mxbuf(rq, cqe, va, rx_headroom, rq->buff.frame0_sz,
+				 cqe_bcnt, &mxbuf);
+		if (mlx5e_xdp_handle(rq, prog, &mxbuf))
+			return NULL; /* page/packet was consumed by XDP */
+
+		rx_headroom = mxbuf.xdp.data - mxbuf.xdp.data_hard_start;
+		metasize = mxbuf.xdp.data - mxbuf.xdp.data_meta;
+		cqe_bcnt = mxbuf.xdp.data_end - mxbuf.xdp.data;
+	}
+#endif
+	frag_size = MLX5_SKB_FRAG_SZ(rx_headroom + cqe_bcnt);
+	skb = mlx5e_build_linear_skb(rq, va, frag_size, rx_headroom, cqe_bcnt, metasize);
+	if (unlikely(!skb))
+		return NULL;
+
+	/* queue up for recycling/reuse */
+	skb_mark_for_recycle(skb);
+	frag_page->frags++;
+
+	return skb;
+}
+
+static struct sk_buff *
+mlx5e_skb_from_cqe_nonlinear(struct mlx5e_rq *rq, struct mlx5e_wqe_frag_info *wi,
+			     struct mlx5_cqe64 *cqe, u32 cqe_bcnt)
+{
+	struct mlx5e_rq_frag_info *frag_info = &rq->wqe.info.arr[0];
+	struct mlx5e_wqe_frag_info *head_wi = wi;
+	u16 rx_headroom = rq->buff.headroom;
+	struct mlx5e_frag_page *frag_page;
+	struct skb_shared_info *sinfo;
+	struct mlx5e_xdp_buff mxbuf;
+	u32 frag_consumed_bytes;
+#ifdef HAVE_XDP_SUPPORT
+	struct bpf_prog *prog;
+#endif
+	struct sk_buff *skb;
+	dma_addr_t addr;
+	u32 truesize;
+	void *va;
+#ifndef HAVE_XDP_HAS_FRAGS
+	bool has_frags = false;
+#endif
+
+	frag_page = wi->frag_page;
+
+	va = page_address(frag_page->page) + wi->offset;
+	frag_consumed_bytes = min_t(u32, frag_info->frag_size, cqe_bcnt);
+
+	addr = page_pool_get_dma_addr(frag_page->page);
+	dma_sync_single_range_for_cpu(rq->pdev, addr, wi->offset,
+				      rq->buff.frame0_sz, rq->buff.map_dir);
+	net_prefetchw(va); /* xdp_frame data area */
+	net_prefetch(va + rx_headroom);
+
+	mlx5e_fill_mxbuf(rq, cqe, va, rx_headroom, rq->buff.frame0_sz,
+			 frag_consumed_bytes, &mxbuf);
+	sinfo = xdp_get_shared_info_from_buff(&mxbuf.xdp);
+	truesize = 0;
+
+	cqe_bcnt -= frag_consumed_bytes;
+	frag_info++;
+	wi++;
+
+	while (cqe_bcnt) {
+		frag_page = wi->frag_page;
+
+		frag_consumed_bytes = min_t(u32, frag_info->frag_size, cqe_bcnt);
+
+		mlx5e_add_skb_shared_info_frag(rq, sinfo, &mxbuf.xdp, frag_page,
+#ifdef HAVE_XDP_HAS_FRAGS
+					       wi->offset, frag_consumed_bytes);
+#else
+					       wi->offset, frag_consumed_bytes, &has_frags);
+#endif
+		truesize += frag_info->frag_stride;
+
+		cqe_bcnt -= frag_consumed_bytes;
+		frag_info++;
+		wi++;
+	}
 
-static inline
-struct sk_buff *mlx5e_build_linear_skb(struct mlx5e_rq *rq, void *va,
-				       u32 frag_size, u16 headroom,
-				       u32 cqe_bcnt, u32 metasize)
-{
-	struct sk_buff *skb = napi_build_skb(va, frag_size);
+#ifdef HAVE_XDP_SUPPORT
+	prog = rcu_dereference(rq->xdp_prog);
+	if (prog && mlx5e_xdp_handle(rq, prog, &mxbuf)) {
+		if (__test_and_clear_bit(MLX5E_RQ_FLAG_XDP_XMIT, rq->flags)) {
+			struct mlx5e_wqe_frag_info *pwi;
 
-	if (unlikely(!skb)) {
-		rq->stats->buff_alloc_err++;
-		return NULL;
+			for (pwi = head_wi; pwi < wi; pwi++)
+				pwi->frag_page->frags++;
+		}
+		return NULL; /* page/packet was consumed by XDP */
 	}
+#endif
 
-	skb_reserve(skb, headroom);
-	skb_put(skb, cqe_bcnt);
+	skb = mlx5e_build_linear_skb(rq, mxbuf.xdp.data_hard_start, rq->buff.frame0_sz,
+				     mxbuf.xdp.data - mxbuf.xdp.data_hard_start,
+				     mxbuf.xdp.data_end - mxbuf.xdp.data,
+				     mxbuf.xdp.data - mxbuf.xdp.data_meta);
+	if (unlikely(!skb))
+		return NULL;
 
-	if (metasize)
-		skb_metadata_set(skb, metasize);
+	skb_mark_for_recycle(skb);
+	head_wi->frag_page->frags++;
+
+#ifdef HAVE_XDP_HAS_FRAGS
+	if (xdp_buff_has_frags(&mxbuf.xdp)) {
+#else
+	if (has_frags) {
+#endif
+		struct mlx5e_wqe_frag_info *pwi;
+
+		/* sinfo->nr_frags is reset by build_skb, calculate again. */
+		xdp_update_skb_shared_info(skb, wi - head_wi - 1,
+					   sinfo->xdp_frags_size, truesize,
+					   xdp_buff_is_frag_pfmemalloc(&mxbuf.xdp));
+
+		for (pwi = head_wi + 1; pwi < wi; pwi++)
+			pwi->frag_page->frags++;
+	}
 
 	return skb;
 }
 
+#else /* HAVE_PAGE_POOL_DEFRAG_PAGE */
+
 static void mlx5e_fill_mxbuf(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe,
-			     void *va, u16 headroom, u32 frame_sz, u32 len,
+			     void *va, u16 headroom, u32 len,
 			     struct mlx5e_xdp_buff *mxbuf)
 {
-	xdp_init_buff(&mxbuf->xdp, frame_sz, &rq->xdp_rxq);
+	xdp_init_buff(&mxbuf->xdp, rq->buff.frame0_sz, &rq->xdp_rxq);
 	xdp_prepare_buff(&mxbuf->xdp, va, headroom, len, true);
+#ifdef HAVE_XDP_METADATA_OPS
 	mxbuf->cqe = cqe;
 	mxbuf->rq = rq;
+#endif
 }
 
 static struct sk_buff *
 mlx5e_skb_from_cqe_linear(struct mlx5e_rq *rq, struct mlx5e_wqe_frag_info *wi,
 			  struct mlx5_cqe64 *cqe, u32 cqe_bcnt)
 {
-	struct mlx5e_frag_page *frag_page = wi->frag_page;
+	struct mlx5e_alloc_unit *au = wi->au;
 	u16 rx_headroom = rq->buff.headroom;
+#ifdef HAVE_XDP_SUPPORT
 	struct bpf_prog *prog;
+#endif
 	struct sk_buff *skb;
 	u32 metasize = 0;
 	void *va, *data;
+#ifdef HAVE_PAGE_POOL_GET_DMA_ADDR
 	dma_addr_t addr;
+#endif
 	u32 frag_size;
 
-	va             = page_address(frag_page->page) + wi->offset;
+	va             = page_address(au->page) + wi->offset;
 	data           = va + rx_headroom;
 	frag_size      = MLX5_SKB_FRAG_SZ(rx_headroom + cqe_bcnt);
 
-	addr = page_pool_get_dma_addr(frag_page->page);
+#ifdef HAVE_PAGE_POOL_GET_DMA_ADDR
+	addr = page_pool_get_dma_addr(au->page);
 	dma_sync_single_range_for_cpu(rq->pdev, addr, wi->offset,
 				      frag_size, rq->buff.map_dir);
+#else
+	dma_sync_single_range_for_cpu(rq->pdev, au->addr, wi->offset,
+				      frag_size, rq->buff.map_dir);
+#endif
 	net_prefetch(data);
 
+#ifdef HAVE_XDP_SUPPORT
 	prog = rcu_dereference(rq->xdp_prog);
 	if (prog) {
 		struct mlx5e_xdp_buff mxbuf;
 
 		net_prefetchw(va); /* xdp_frame data area */
-		mlx5e_fill_mxbuf(rq, cqe, va, rx_headroom, rq->buff.frame0_sz,
-				 cqe_bcnt, &mxbuf);
-		if (mlx5e_xdp_handle(rq, prog, &mxbuf))
+		mlx5e_fill_mxbuf(rq, cqe, va, rx_headroom, cqe_bcnt, &mxbuf);
+		if (mlx5e_xdp_handle(rq, au, prog, &mxbuf))
 			return NULL; /* page/packet was consumed by XDP */
 
 		rx_headroom = mxbuf.xdp.data - mxbuf.xdp.data_hard_start;
 		metasize = mxbuf.xdp.data - mxbuf.xdp.data_meta;
 		cqe_bcnt = mxbuf.xdp.data_end - mxbuf.xdp.data;
 	}
+#endif
 	frag_size = MLX5_SKB_FRAG_SZ(rx_headroom + cqe_bcnt);
 	skb = mlx5e_build_linear_skb(rq, va, frag_size, rx_headroom, cqe_bcnt, metasize);
 	if (unlikely(!skb))
 		return NULL;
 
 	/* queue up for recycling/reuse */
-	skb_mark_for_recycle(skb);
-	frag_page->frags++;
+	page_ref_inc(au->page);
 
 	return skb;
 }
-
 static struct sk_buff *
 mlx5e_skb_from_cqe_nonlinear(struct mlx5e_rq *rq, struct mlx5e_wqe_frag_info *wi,
 			     struct mlx5_cqe64 *cqe, u32 cqe_bcnt)
 {
 	struct mlx5e_rq_frag_info *frag_info = &rq->wqe.info.arr[0];
 	struct mlx5e_wqe_frag_info *head_wi = wi;
+	struct mlx5e_alloc_unit *au = wi->au;
 	u16 rx_headroom = rq->buff.headroom;
-	struct mlx5e_frag_page *frag_page;
 	struct skb_shared_info *sinfo;
 	struct mlx5e_xdp_buff mxbuf;
 	u32 frag_consumed_bytes;
+#ifdef HAVE_XDP_SUPPORT
 	struct bpf_prog *prog;
+#endif
 	struct sk_buff *skb;
+#ifdef HAVE_PAGE_POOL_GET_DMA_ADDR
 	dma_addr_t addr;
+#endif
+	void *hard_start;
+	u32 metasize;
 	u32 truesize;
 	void *va;
+#ifndef HAVE_XDP_HAS_FRAGS
+	bool frag_pfmemalloc = false;
+	bool has_frags = false;
+	u32 frag_size;
+#endif
 
-	frag_page = wi->frag_page;
-
-	va = page_address(frag_page->page) + wi->offset;
+	va = page_address(au->page) + wi->offset;
 	frag_consumed_bytes = min_t(u32, frag_info->frag_size, cqe_bcnt);
 
-	addr = page_pool_get_dma_addr(frag_page->page);
+#ifdef HAVE_PAGE_POOL_GET_DMA_ADDR
+	addr = page_pool_get_dma_addr(au->page);
 	dma_sync_single_range_for_cpu(rq->pdev, addr, wi->offset,
 				      rq->buff.frame0_sz, rq->buff.map_dir);
+#else
+	dma_sync_single_range_for_cpu(rq->pdev, au->addr, wi->offset,
+				      rq->buff.frame0_sz, rq->buff.map_dir);
+#endif
 	net_prefetchw(va); /* xdp_frame data area */
 	net_prefetch(va + rx_headroom);
 
-	mlx5e_fill_mxbuf(rq, cqe, va, rx_headroom, rq->buff.frame0_sz,
-			 frag_consumed_bytes, &mxbuf);
+	mlx5e_fill_mxbuf(rq, cqe, va, rx_headroom, frag_consumed_bytes, &mxbuf);
+#ifndef HAVE_XDP_BUFF_HAS_FRAME_SZ
+	sinfo = xdp_get_shared_info_from_buff(&mxbuf.xdp, rq->buff.frame0_sz);
+#else
 	sinfo = xdp_get_shared_info_from_buff(&mxbuf.xdp);
+#endif
 	truesize = 0;
 
 	cqe_bcnt -= frag_consumed_bytes;
@@ -1770,12 +2864,59 @@ mlx5e_skb_from_cqe_nonlinear(struct mlx5
 	wi++;
 
 	while (cqe_bcnt) {
-		frag_page = wi->frag_page;
+		skb_frag_t *frag;
+
+		au = wi->au;
 
 		frag_consumed_bytes = min_t(u32, frag_info->frag_size, cqe_bcnt);
 
-		mlx5e_add_skb_shared_info_frag(rq, sinfo, &mxbuf.xdp, frag_page,
-					       wi->offset, frag_consumed_bytes);
+#ifdef HAVE_PAGE_POOL_GET_DMA_ADDR
+		addr = page_pool_get_dma_addr(au->page);
+		dma_sync_single_for_cpu(rq->pdev, addr + wi->offset,
+					frag_consumed_bytes, rq->buff.map_dir);
+#else
+		dma_sync_single_for_cpu(rq->pdev, au->addr + wi->offset,
+					frag_consumed_bytes, rq->buff.map_dir);
+#endif
+
+#ifdef HAVE_XDP_HAS_FRAGS
+		if (!xdp_buff_has_frags(&mxbuf.xdp)) {
+#else
+		if (!has_frags) {
+#endif
+			/* Init on the first fragment to avoid cold cache access
+			 * when possible.
+			 */
+			sinfo->nr_frags = 0;
+#ifdef HAVE_XDP_HAS_FRAGS
+			sinfo->xdp_frags_size = 0;
+			xdp_buff_set_frags_flag(&mxbuf.xdp);
+#else
+			frag_size = 0;
+			has_frags = true;
+#endif
+		}
+
+		frag = &sinfo->frags[sinfo->nr_frags++];
+#ifdef HAVE_SKB_FRAG_FILL_PAGE_DESC
+		skb_frag_fill_page_desc(frag, au->page, wi->offset, frag_consumed_bytes);
+#else
+		__skb_frag_set_page(frag, au->page);
+		skb_frag_off_set(frag, wi->offset);
+		skb_frag_size_set(frag, frag_consumed_bytes);
+#endif
+
+		if (page_is_pfmemalloc(au->page))
+#ifdef HAVE_XDP_HAS_FRAGS
+			xdp_buff_set_frag_pfmemalloc(&mxbuf.xdp);
+#else
+			frag_pfmemalloc = true;
+#endif
+#ifdef HAVE_XDP_HAS_FRAGS
+		sinfo->xdp_frags_size += frag_consumed_bytes;
+#else
+		frag_size += frag_consumed_bytes;
+#endif
 		truesize += frag_info->frag_stride;
 
 		cqe_bcnt -= frag_consumed_bytes;
@@ -1783,39 +2924,55 @@ mlx5e_skb_from_cqe_nonlinear(struct mlx5
 		wi++;
 	}
 
+#ifdef HAVE_XDP_SUPPORT
 	prog = rcu_dereference(rq->xdp_prog);
-	if (prog && mlx5e_xdp_handle(rq, prog, &mxbuf)) {
-		if (__test_and_clear_bit(MLX5E_RQ_FLAG_XDP_XMIT, rq->flags)) {
-			struct mlx5e_wqe_frag_info *pwi;
+	if (prog && mlx5e_xdp_handle(rq, head_wi->au, prog, &mxbuf)) {
+		if (test_bit(MLX5E_RQ_FLAG_XDP_XMIT, rq->flags)) {
+			int i;
 
-			for (pwi = head_wi; pwi < wi; pwi++)
-				pwi->frag_page->frags++;
+			for (i = wi - head_wi; i < rq->wqe.info.num_frags; i++)
+				mlx5e_put_rx_frag(rq, &head_wi[i], true);
 		}
 		return NULL; /* page/packet was consumed by XDP */
 	}
 
-	skb = mlx5e_build_linear_skb(rq, mxbuf.xdp.data_hard_start, rq->buff.frame0_sz,
-				     mxbuf.xdp.data - mxbuf.xdp.data_hard_start,
+#endif
+	metasize = mxbuf.xdp.data - mxbuf.xdp.data_meta;
+	hard_start = mxbuf.xdp.data_hard_start;
+	skb = mlx5e_build_linear_skb(rq, hard_start, rq->buff.frame0_sz,
+				     mxbuf.xdp.data - hard_start,
 				     mxbuf.xdp.data_end - mxbuf.xdp.data,
-				     mxbuf.xdp.data - mxbuf.xdp.data_meta);
+				     metasize);
 	if (unlikely(!skb))
 		return NULL;
 
-	skb_mark_for_recycle(skb);
-	head_wi->frag_page->frags++;
-
+	page_ref_inc(head_wi->au->page);
+#ifdef HAVE_XDP_HAS_FRAGS
 	if (xdp_buff_has_frags(&mxbuf.xdp)) {
+#else
+	if (unlikely(has_frags)) {
+#endif
+		int i;
+
 		/* sinfo->nr_frags is reset by build_skb, calculate again. */
 		xdp_update_skb_shared_info(skb, wi - head_wi - 1,
+#ifdef HAVE_XDP_HAS_FRAGS
 					   sinfo->xdp_frags_size, truesize,
 					   xdp_buff_is_frag_pfmemalloc(&mxbuf.xdp));
+#else
+					   frag_size, truesize, frag_pfmemalloc);
+#endif
 
-		for (struct mlx5e_wqe_frag_info *pwi = head_wi + 1; pwi < wi; pwi++)
-			pwi->frag_page->frags++;
+		for (i = 0; i < sinfo->nr_frags; i++) {
+			skb_frag_t *frag = &sinfo->frags[i];
+
+			page_ref_inc(skb_frag_page(frag));
+		}
 	}
 
 	return skb;
 }
+#endif /* HAVE_PAGE_POOL_DEFRAG_PAGE */
 
 static void trigger_report(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe)
 {
@@ -1837,6 +2994,9 @@ static void mlx5e_handle_rx_err_cqe(stru
 
 static void mlx5e_handle_rx_cqe(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe)
 {
+#ifdef CONFIG_COMPAT_LRO_ENABLED_IPOIB
+	struct mlx5e_priv *priv = netdev_priv(rq->netdev);
+#endif
 	struct mlx5_wq_cyc *wq = &rq->wqe.wq;
 	struct mlx5e_wqe_frag_info *wi;
 	struct sk_buff *skb;
@@ -1849,19 +3009,41 @@ static void mlx5e_handle_rx_cqe(struct m
 
 	if (unlikely(MLX5E_RX_ERR_CQE(cqe))) {
 		mlx5e_handle_rx_err_cqe(rq, cqe);
+#ifdef HAVE_PAGE_POOL_DEFRAG_PAGE
 		goto wq_cyc_pop;
+#else
+		goto free_wqe;
+#endif
 	}
 
+#ifdef HAVE_XSK_ZERO_COPY_SUPPORT
 	skb = INDIRECT_CALL_3(rq->wqe.skb_from_cqe,
 			      mlx5e_skb_from_cqe_linear,
 			      mlx5e_skb_from_cqe_nonlinear,
 			      mlx5e_xsk_skb_from_cqe_linear,
 			      rq, wi, cqe, cqe_bcnt);
+#else
+	skb = INDIRECT_CALL_2(rq->wqe.skb_from_cqe,
+			      mlx5e_skb_from_cqe_linear,
+			      mlx5e_skb_from_cqe_nonlinear,
+			      rq, wi, cqe, cqe_bcnt);
+#endif
 	if (!skb) {
+#ifdef HAVE_PAGE_POOL_DEFRAG_PAGE
 		/* probably for XDP */
 		if (__test_and_clear_bit(MLX5E_RQ_FLAG_XDP_XMIT, rq->flags))
 			wi->frag_page->frags++;
 		goto wq_cyc_pop;
+#else
+		/* probably for XDP */
+		if (__test_and_clear_bit(MLX5E_RQ_FLAG_XDP_XMIT, rq->flags)) {
+			/* do not return page to cache,
+			 * it will be returned on XDP_TX completion.
+			 */
+			goto wq_cyc_pop;
+		}
+		goto free_wqe;
+#endif
 	}
 
 	mlx5e_complete_rx_cqe(rq, cqe, cqe_bcnt, skb);
@@ -1869,11 +3051,24 @@ static void mlx5e_handle_rx_cqe(struct m
 	if (mlx5e_cqe_regb_chain(cqe))
 		if (!mlx5e_tc_update_skb_nic(cqe, skb)) {
 			dev_kfree_skb_any(skb);
+#ifdef HAVE_PAGE_POOL_DEFRAG_PAGE
 			goto wq_cyc_pop;
+#else
+			goto free_wqe;
+#endif
 		}
 
+#ifdef CONFIG_COMPAT_LRO_ENABLED_IPOIB
+	if (IS_SW_LRO(&priv->channels.params))
+		lro_receive_skb(&rq->sw_lro->lro_mgr, skb, NULL);
+	else
+#endif
 	napi_gro_receive(rq->cq.napi, skb);
 
+#ifndef HAVE_PAGE_POOL_DEFRAG_PAGE
+free_wqe:
+	mlx5e_free_rx_wqe(rq, wi, true);
+#endif
 wq_cyc_pop:
 	mlx5_wq_cyc_pop(wq);
 }
@@ -1956,7 +3151,11 @@ static void mlx5e_handle_rx_cqe_rep(stru
 
 	if (unlikely(MLX5E_RX_ERR_CQE(cqe))) {
 		mlx5e_handle_rx_err_cqe(rq, cqe);
+#ifdef HAVE_PAGE_POOL_DEFRAG_PAGE
 		goto wq_cyc_pop;
+#else
+		goto free_wqe;
+#endif
 	}
 
 	skb = INDIRECT_CALL_2(rq->wqe.skb_from_cqe,
@@ -1964,10 +3163,21 @@ static void mlx5e_handle_rx_cqe_rep(stru
 			      mlx5e_skb_from_cqe_nonlinear,
 			      rq, wi, cqe, cqe_bcnt);
 	if (!skb) {
+#ifdef HAVE_PAGE_POOL_DEFRAG_PAGE
 		/* probably for XDP */
 		if (__test_and_clear_bit(MLX5E_RQ_FLAG_XDP_XMIT, rq->flags))
 			wi->frag_page->frags++;
 		goto wq_cyc_pop;
+#else
+		/* probably for XDP */
+		if (__test_and_clear_bit(MLX5E_RQ_FLAG_XDP_XMIT, rq->flags)) {
+			/* do not return page to cache,
+			 * it will be returned on XDP_TX completion.
+			 */
+			goto wq_cyc_pop;
+		}
+		goto free_wqe;
+#endif
 	}
 
 	mlx5e_complete_rx_cqe(rq, cqe, cqe_bcnt, skb);
@@ -1980,6 +3190,10 @@ static void mlx5e_handle_rx_cqe_rep(stru
 
 	mlx5e_rep_tc_receive(cqe, rq, skb);
 
+#ifndef HAVE_PAGE_POOL_DEFRAG_PAGE
+free_wqe:
+	mlx5e_free_rx_wqe(rq, wi, true);
+#endif
 wq_cyc_pop:
 	mlx5_wq_cyc_pop(wq);
 }
@@ -2035,6 +3249,9 @@ mpwrq_cqe_out:
 
 	wq  = &rq->mpwqe.wq;
 	wqe = mlx5_wq_ll_get_wqe(wq, wqe_id);
+#ifndef HAVE_PAGE_POOL_DEFRAG_PAGE
+	mlx5e_free_rx_mpwqe(rq, wi, true);
+#endif
 	mlx5_wq_ll_pop(wq, cqe->wqe_id, &wqe->next.next_wqe_index);
 }
 
@@ -2046,8 +3263,12 @@ const struct mlx5e_rx_handlers mlx5e_rx_
 
 static void
 mlx5e_fill_skb_data(struct sk_buff *skb, struct mlx5e_rq *rq,
+#ifdef HAVE_PAGE_POOL_DEFRAG_PAGE
 		    struct mlx5e_frag_page *frag_page,
 		    u32 data_bcnt, u32 data_offset)
+#else
+		    struct mlx5e_alloc_unit *au, u32 data_bcnt, u32 data_offset)
+#endif
 {
 	net_prefetchw(skb->data);
 
@@ -2061,16 +3282,26 @@ mlx5e_fill_skb_data(struct sk_buff *skb,
 		else
 			truesize = ALIGN(pg_consumed_bytes, BIT(rq->mpwqe.log_stride_sz));
 
+#ifdef HAVE_PAGE_POOL_DEFRAG_PAGE
 		frag_page->frags++;
 		mlx5e_add_skb_frag(rq, skb, frag_page->page, data_offset,
 				   pg_consumed_bytes, truesize);
+#else
+		mlx5e_add_skb_frag(rq, skb, au, data_offset,
+				   pg_consumed_bytes, truesize);
+#endif
 
 		data_bcnt -= pg_consumed_bytes;
 		data_offset = 0;
+#ifdef HAVE_PAGE_POOL_DEFRAG_PAGE
 		frag_page++;
+#else
+		au++;
+#endif
 	}
 }
 
+#ifdef HAVE_PAGE_POOL_DEFRAG_PAGE
 static struct sk_buff *
 mlx5e_skb_from_cqe_mpwrq_nonlinear(struct mlx5e_rq *rq, struct mlx5e_mpw_info *wi,
 				   struct mlx5_cqe64 *cqe, u16 cqe_bcnt, u32 head_offset,
@@ -2084,13 +3315,19 @@ mlx5e_skb_from_cqe_mpwrq_nonlinear(struc
 	struct skb_shared_info *sinfo;
 	struct mlx5e_xdp_buff mxbuf;
 	unsigned int truesize = 0;
+#ifdef HAVE_XDP_SUPPORT
 	struct bpf_prog *prog;
+#endif
 	struct sk_buff *skb;
 	u32 linear_frame_sz;
 	u16 linear_data_len;
 	u16 linear_hr;
 	void *va;
+#ifndef HAVE_XDP_HAS_FRAGS
+	bool has_frags = false;
+#endif
 
+#ifdef HAVE_XDP_SUPPORT
 	prog = rcu_dereference(rq->xdp_prog);
 
 	if (prog) {
@@ -2105,7 +3342,9 @@ mlx5e_skb_from_cqe_mpwrq_nonlinear(struc
 		linear_hr = XDP_PACKET_HEADROOM;
 		linear_data_len = 0;
 		linear_frame_sz = MLX5_SKB_FRAG_SZ(linear_hr + MLX5E_RX_MAX_HEAD);
-	} else {
+	} else
+#endif
+	{
 		skb = napi_alloc_skb(rq->cq.napi,
 				     ALIGN(MLX5E_RX_MAX_HEAD, sizeof(long)));
 		if (unlikely(!skb)) {
@@ -2142,12 +3381,17 @@ mlx5e_skb_from_cqe_mpwrq_nonlinear(struc
 			truesize += ALIGN(pg_consumed_bytes, BIT(rq->mpwqe.log_stride_sz));
 
 		mlx5e_add_skb_shared_info_frag(rq, sinfo, &mxbuf.xdp, frag_page, frag_offset,
+#ifdef HAVE_XDP_HAS_FRAGS
 					       pg_consumed_bytes);
+#else
+					       pg_consumed_bytes, &has_frags);
+#endif
 		byte_cnt -= pg_consumed_bytes;
 		frag_offset = 0;
 		frag_page++;
 	}
 
+#ifdef HAVE_XDP_SUPPORT
 	if (prog) {
 		if (mlx5e_xdp_handle(rq, prog, &mxbuf)) {
 			if (__test_and_clear_bit(MLX5E_RQ_FLAG_XDP_XMIT, rq->flags)) {
@@ -2189,10 +3433,16 @@ mlx5e_skb_from_cqe_mpwrq_nonlinear(struc
 			while (++pagep < frag_page);
 		}
 		__pskb_pull_tail(skb, headlen);
-	} else {
+	} else 
+#endif
+	{
 		dma_addr_t addr;
 
+#ifdef HAVE_XDP_HAS_FRAGS
 		if (xdp_buff_has_frags(&mxbuf.xdp)) {
+#else
+		if (has_frags) {
+#endif
 			struct mlx5e_frag_page *pagep;
 
 			xdp_update_skb_shared_info(skb, sinfo->nr_frags,
@@ -2223,7 +3473,9 @@ mlx5e_skb_from_cqe_mpwrq_linear(struct m
 {
 	struct mlx5e_frag_page *frag_page = &wi->alloc_units.frag_pages[page_idx];
 	u16 rx_headroom = rq->buff.headroom;
+#ifdef HAVE_XDP_SUPPORT
 	struct bpf_prog *prog;
+#endif
 	struct sk_buff *skb;
 	u32 metasize = 0;
 	void *va, *data;
@@ -2245,6 +3497,7 @@ mlx5e_skb_from_cqe_mpwrq_linear(struct m
 				      frag_size, rq->buff.map_dir);
 	net_prefetch(data);
 
+#ifdef HAVE_XDP_SUPPORT
 	prog = rcu_dereference(rq->xdp_prog);
 	if (prog) {
 		struct mlx5e_xdp_buff mxbuf;
@@ -2262,6 +3515,7 @@ mlx5e_skb_from_cqe_mpwrq_linear(struct m
 		metasize = mxbuf.xdp.data - mxbuf.xdp.data_meta;
 		cqe_bcnt = mxbuf.xdp.data_end - mxbuf.xdp.data;
 	}
+#endif
 	frag_size = MLX5_SKB_FRAG_SZ(rx_headroom + cqe_bcnt);
 	skb = mlx5e_build_linear_skb(rq, va, frag_size, rx_headroom, cqe_bcnt, metasize);
 	if (unlikely(!skb))
@@ -2274,6 +3528,123 @@ mlx5e_skb_from_cqe_mpwrq_linear(struct m
 	return skb;
 }
 
+#else /* HAVE_PAGE_POOL_DEFRAG_PAGE */
+static struct sk_buff *
+mlx5e_skb_from_cqe_mpwrq_nonlinear(struct mlx5e_rq *rq, struct mlx5e_mpw_info *wi,
+				   struct mlx5_cqe64 *cqe, u16 cqe_bcnt, u32 head_offset,
+				   u32 page_idx)
+{
+	struct mlx5e_alloc_unit *au = &wi->alloc_units[page_idx];
+	u16 headlen = min_t(u16, MLX5E_RX_MAX_HEAD, cqe_bcnt);
+	u32 frag_offset    = head_offset + headlen;
+	u32 byte_cnt       = cqe_bcnt - headlen;
+	struct mlx5e_alloc_unit *head_au = au;
+	struct sk_buff *skb;
+#ifdef HAVE_PAGE_POOL_GET_DMA_ADDR
+	dma_addr_t addr;
+#endif
+
+	skb = napi_alloc_skb(rq->cq.napi,
+			     ALIGN(MLX5E_RX_MAX_HEAD, sizeof(long)));
+	if (unlikely(!skb)) {
+		rq->stats->buff_alloc_err++;
+		return NULL;
+	}
+
+	net_prefetchw(skb->data);
+
+	/* Non-linear mode, hence non-XSK, which always uses PAGE_SIZE. */
+	if (unlikely(frag_offset >= PAGE_SIZE)) {
+		au++;
+		frag_offset -= PAGE_SIZE;
+	}
+
+	mlx5e_fill_skb_data(skb, rq, au, byte_cnt, frag_offset);
+	/* copy header */
+#ifdef HAVE_PAGE_POOL_GET_DMA_ADDR
+	addr = page_pool_get_dma_addr(head_au->page);
+	mlx5e_copy_skb_header(rq, skb, head_au->page, addr,
+			      head_offset, head_offset, headlen);
+#else
+	mlx5e_copy_skb_header(rq, skb, head_au->page, head_au->addr,
+			      head_offset, head_offset, headlen);
+#endif
+	/* skb linear part was allocated with headlen and aligned to long */
+	skb->tail += headlen;
+	skb->len  += headlen;
+
+	return skb;
+}
+
+static struct sk_buff *
+mlx5e_skb_from_cqe_mpwrq_linear(struct mlx5e_rq *rq, struct mlx5e_mpw_info *wi,
+				struct mlx5_cqe64 *cqe, u16 cqe_bcnt, u32 head_offset,
+				u32 page_idx)
+{
+	struct mlx5e_alloc_unit *au = &wi->alloc_units[page_idx];
+	u16 rx_headroom = rq->buff.headroom;
+#ifdef HAVE_XDP_SUPPORT
+	struct bpf_prog *prog;
+#endif
+	struct sk_buff *skb;
+	u32 metasize = 0;
+	void *va, *data;
+#ifdef HAVE_PAGE_POOL_GET_DMA_ADDR
+	dma_addr_t addr;
+#endif
+	u32 frag_size;
+
+	/* Check packet size. Note LRO doesn't use linear SKB */
+	if (unlikely(cqe_bcnt > rq->hw_mtu + rq->pet_hdr_size)) {
+		rq->stats->oversize_pkts_sw_drop++;
+		return NULL;
+	}
+
+	va             = page_address(au->page) + head_offset;
+	data           = va + rx_headroom;
+	frag_size      = MLX5_SKB_FRAG_SZ(rx_headroom + cqe_bcnt);
+
+#ifdef HAVE_PAGE_POOL_GET_DMA_ADDR
+	addr = page_pool_get_dma_addr(au->page);
+	dma_sync_single_range_for_cpu(rq->pdev, addr, head_offset,
+				      frag_size, rq->buff.map_dir);
+#else
+	dma_sync_single_range_for_cpu(rq->pdev, au->addr, head_offset,
+				      frag_size, rq->buff.map_dir);
+#endif
+	net_prefetch(data);
+
+#ifdef HAVE_XDP_SUPPORT
+	prog = rcu_dereference(rq->xdp_prog);
+	if (prog) {
+		struct mlx5e_xdp_buff mxbuf;
+
+		net_prefetchw(va); /* xdp_frame data area */
+		mlx5e_fill_mxbuf(rq, cqe, va, rx_headroom, cqe_bcnt, &mxbuf);
+		if (mlx5e_xdp_handle(rq, au, prog, &mxbuf)) {
+			if (__test_and_clear_bit(MLX5E_RQ_FLAG_XDP_XMIT, rq->flags))
+				__set_bit(page_idx, wi->skip_release_bitmap); /* non-atomic */
+			return NULL; /* page/packet was consumed by XDP */
+		}
+
+		rx_headroom = mxbuf.xdp.data - mxbuf.xdp.data_hard_start;
+		metasize = mxbuf.xdp.data - mxbuf.xdp.data_meta;
+		cqe_bcnt = mxbuf.xdp.data_end - mxbuf.xdp.data;
+	}
+#endif
+	frag_size = MLX5_SKB_FRAG_SZ(rx_headroom + cqe_bcnt);
+	skb = mlx5e_build_linear_skb(rq, va, frag_size, rx_headroom, cqe_bcnt, metasize);
+	if (unlikely(!skb))
+		return NULL;
+
+	/* queue up for recycling/reuse */
+	page_ref_inc(au->page);
+
+	return skb;
+}
+#endif /* HAVE_PAGE_POOL_DEFRAG_PAGE */
+
+#ifdef HAVE_SHAMPO_SUPPORT
 static struct sk_buff *
 mlx5e_skb_from_cqe_shampo(struct mlx5e_rq *rq, struct mlx5e_mpw_info *wi,
 			  struct mlx5_cqe64 *cqe, u16 header_index)
@@ -2286,7 +3657,11 @@ mlx5e_skb_from_cqe_shampo(struct mlx5e_r
 	void *hdr, *data;
 	u32 frag_size;
 
+#ifdef HAVE_PAGE_POOL_DEFRAG_PAGE
 	hdr		= page_address(head->frag_page->page) + head_offset;
+#else
+	hdr		= page_address(head->page) + head_offset;
+#endif
 	data		= hdr + rx_headroom;
 	frag_size	= MLX5_SKB_FRAG_SZ(rx_headroom + head_size);
 
@@ -2300,7 +3675,12 @@ mlx5e_skb_from_cqe_shampo(struct mlx5e_r
 		if (unlikely(!skb))
 			return NULL;
 
+#ifdef HAVE_PAGE_POOL_DEFRAG_PAGE
 		head->frag_page->frags++;
+#else
+		/* queue up for recycling/reuse */
+		page_ref_inc(head->page);
+#endif
 	} else {
 		/* allocate SKB and copy header for large header */
 		rq->stats->gro_large_hds++;
@@ -2312,7 +3692,12 @@ mlx5e_skb_from_cqe_shampo(struct mlx5e_r
 		}
 
 		prefetchw(skb->data);
+#ifdef HAVE_PAGE_POOL_DEFRAG_PAGE
 		mlx5e_copy_skb_header(rq, skb, head->frag_page->page, head->addr,
+#else
+
+		mlx5e_copy_skb_header(rq, skb, head->page, head->addr,
+#endif
 				      head_offset + rx_headroom,
 				      rx_headroom, head_size);
 		/* skb linear part was allocated with headlen and aligned to long */
@@ -2320,8 +3705,10 @@ mlx5e_skb_from_cqe_shampo(struct mlx5e_r
 		skb->len  += head_size;
 	}
 
+#ifdef HAVE_PAGE_POOL_DEFRAG_PAGE
 	/* queue up for recycling/reuse */
 	skb_mark_for_recycle(skb);
+#endif
 
 	return skb;
 }
@@ -2357,7 +3744,14 @@ mlx5e_hw_gro_skb_has_enough_space(struct
 {
 	int nr_frags = skb_shinfo(skb)->nr_frags;
 
-	return PAGE_SIZE * nr_frags + data_bcnt <= GRO_LEGACY_MAX_SIZE;
+	return PAGE_SIZE * nr_frags + data_bcnt <=
+#ifdef HAVE_GRO_LEGACY_MAX_SIZE
+	GRO_LEGACY_MAX_SIZE;
+#elif defined(HAVE_GRO_MAX_SIZE)
+	GRO_MAX_SIZE;
+#else
+	GSO_MAX_SIZE;
+#endif
 }
 
 static void
@@ -2367,10 +3761,19 @@ mlx5e_free_rx_shampo_hd_entry(struct mlx
 	u64 addr = shampo->info[header_index].addr;
 
 	if (((header_index + 1) & (MLX5E_SHAMPO_WQ_HEADER_PER_PAGE - 1)) == 0) {
+#ifdef HAVE_PAGE_POOL_DEFRAG_PAGE
 		struct mlx5e_dma_info *dma_info = &shampo->info[header_index];
 
 		dma_info->addr = ALIGN_DOWN(addr, PAGE_SIZE);
 		mlx5e_page_release_fragmented(rq, dma_info->frag_page);
+#else
+		struct mlx5e_alloc_unit au = {
+			.page = shampo->info[header_index].page,
+		};
+
+		shampo->info[header_index].addr = ALIGN_DOWN(addr, PAGE_SIZE);
+		mlx5e_page_release_dynamic(rq, &au, true);
+#endif
 	}
 	bitmap_clear(shampo->bitmap, header_index, 1);
 }
@@ -2391,6 +3794,9 @@ static void mlx5e_handle_rx_cqe_mpwrq_sh
 	bool match		= cqe->shampo.match;
 	struct mlx5e_rq_stats *stats = rq->stats;
 	struct mlx5e_rx_wqe_ll *wqe;
+#ifndef HAVE_PAGE_POOL_DEFRAG_PAGE
+	struct mlx5e_alloc_unit *au;
+#endif
 	struct mlx5e_mpw_info *wi;
 	struct mlx5_wq_ll *wq;
 
@@ -2440,10 +3846,15 @@ static void mlx5e_handle_rx_cqe_mpwrq_sh
 	}
 
 	if (likely(head_size)) {
+#ifdef HAVE_PAGE_POOL_DEFRAG_PAGE
 		struct mlx5e_frag_page *frag_page;
 
 		frag_page = &wi->alloc_units.frag_pages[page_idx];
 		mlx5e_fill_skb_data(*skb, rq, frag_page, data_bcnt, data_offset);
+#else
+		au = &wi->alloc_units[page_idx];
+		mlx5e_fill_skb_data(*skb, rq, au, data_bcnt, data_offset);
+#endif
 	}
 
 	mlx5e_shampo_complete_rx_cqe(rq, cqe, cqe_bcnt, *skb);
@@ -2457,8 +3868,12 @@ mpwrq_cqe_out:
 
 	wq  = &rq->mpwqe.wq;
 	wqe = mlx5_wq_ll_get_wqe(wq, wqe_id);
+#ifndef HAVE_PAGE_POOL_DEFRAG_PAGE
+	mlx5e_free_rx_mpwqe(rq, wi, true);
+#endif
 	mlx5_wq_ll_pop(wq, cqe->wqe_id, &wqe->next.next_wqe_index);
 }
+#endif /* HAVE_SHAMPO_SUPPORT */
 
 static void mlx5e_handle_rx_cqe_mpwrq(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe)
 {
@@ -2491,12 +3906,20 @@ static void mlx5e_handle_rx_cqe_mpwrq(st
 
 	cqe_bcnt = mpwrq_get_cqe_byte_cnt(cqe);
 
+#ifdef HAVE_XSK_ZERO_COPY_SUPPORT
 	skb = INDIRECT_CALL_3(rq->mpwqe.skb_from_cqe_mpwrq,
-			      mlx5e_skb_from_cqe_mpwrq_linear,
-			      mlx5e_skb_from_cqe_mpwrq_nonlinear,
-			      mlx5e_xsk_skb_from_cqe_mpwrq_linear,
-			      rq, wi, cqe, cqe_bcnt, head_offset,
-			      page_idx);
+				mlx5e_skb_from_cqe_mpwrq_linear,
+				mlx5e_skb_from_cqe_mpwrq_nonlinear,
+				mlx5e_xsk_skb_from_cqe_mpwrq_linear,
+				rq, wi, cqe, cqe_bcnt, head_offset,
+				page_idx);
+#else
+	skb = INDIRECT_CALL_2(rq->mpwqe.skb_from_cqe_mpwrq,
+				mlx5e_skb_from_cqe_mpwrq_linear,
+				mlx5e_skb_from_cqe_mpwrq_nonlinear,
+				rq, wi, cqe, cqe_bcnt, head_offset,
+				page_idx);
+#endif
 	if (!skb)
 		goto mpwrq_cqe_out;
 
@@ -2516,6 +3939,9 @@ mpwrq_cqe_out:
 
 	wq  = &rq->mpwqe.wq;
 	wqe = mlx5_wq_ll_get_wqe(wq, wqe_id);
+#ifndef HAVE_PAGE_POOL_DEFRAG_PAGE
+	mlx5e_free_rx_mpwqe(rq, wi, true);
+#endif
 	mlx5_wq_ll_pop(wq, cqe->wqe_id, &wqe->next.next_wqe_index);
 }
 
@@ -2618,8 +4044,10 @@ int mlx5e_poll_rx_cq(struct mlx5e_cq *cq
 	if (test_bit(MLX5E_RQ_STATE_SHAMPO, &rq->state) && rq->hw_gro_data->skb)
 		mlx5e_shampo_flush_skb(rq, NULL, false);
 
+#ifdef HAVE_XDP_SUPPORT
 	if (rcu_access_pointer(rq->xdp_prog))
 		mlx5e_xdp_rx_poll_complete(rq);
+#endif
 
 	mlx5_cqwq_update_db_record(cqwq);
 
@@ -2729,6 +4157,9 @@ static inline void mlx5i_complete_rx_cqe
 
 static void mlx5i_handle_rx_cqe(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe)
 {
+#ifdef CONFIG_COMPAT_LRO_ENABLED_IPOIB
+	struct mlx5e_priv *priv = mlx5i_epriv(rq->netdev);
+#endif
 	struct mlx5_wq_cyc *wq = &rq->wqe.wq;
 	struct mlx5e_wqe_frag_info *wi;
 	struct sk_buff *skb;
@@ -2741,7 +4172,11 @@ static void mlx5i_handle_rx_cqe(struct m
 
 	if (unlikely(MLX5E_RX_ERR_CQE(cqe))) {
 		rq->stats->wqe_err++;
+#ifdef HAVE_PAGE_POOL_DEFRAG_PAGE
 		goto wq_cyc_pop;
+#else
+		goto wq_free_wqe;
+#endif
 	}
 
 	skb = INDIRECT_CALL_2(rq->wqe.skb_from_cqe,
@@ -2749,16 +4184,34 @@ static void mlx5i_handle_rx_cqe(struct m
 			      mlx5e_skb_from_cqe_nonlinear,
 			      rq, wi, cqe, cqe_bcnt);
 	if (!skb)
+#ifdef HAVE_PAGE_POOL_DEFRAG_PAGE
 		goto wq_cyc_pop;
+#else
+		goto wq_free_wqe;
+#endif
 
 	mlx5i_complete_rx_cqe(rq, cqe, cqe_bcnt, skb);
 	if (unlikely(!skb->dev)) {
 		dev_kfree_skb_any(skb);
+#ifdef HAVE_PAGE_POOL_DEFRAG_PAGE
 		goto wq_cyc_pop;
+#else
+		goto wq_free_wqe;
+#endif
 	}
+#ifdef CONFIG_COMPAT_LRO_ENABLED_IPOIB
+	if (priv->netdev->features & NETIF_F_LRO)
+		lro_receive_skb(&rq->sw_lro->lro_mgr, skb, NULL);
+	else
+#endif
 	napi_gro_receive(rq->cq.napi, skb);
 
+#ifdef HAVE_PAGE_POOL_DEFRAG_PAGE
 wq_cyc_pop:
+#else
+wq_free_wqe:
+	mlx5e_free_rx_wqe(rq, wi, true);
+#endif
 	mlx5_wq_cyc_pop(wq);
 }
 
@@ -2782,11 +4235,18 @@ int mlx5e_rq_set_handlers(struct mlx5e_r
 
 	switch (rq->wq_type) {
 	case MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ:
+#ifdef HAVE_XSK_ZERO_COPY_SUPPORT
 		rq->mpwqe.skb_from_cqe_mpwrq = xsk ?
 			mlx5e_xsk_skb_from_cqe_mpwrq_linear :
 			mlx5e_rx_mpwqe_is_linear_skb(mdev, params, NULL) ?
 				mlx5e_skb_from_cqe_mpwrq_linear :
 				mlx5e_skb_from_cqe_mpwrq_nonlinear;
+#else
+		rq->mpwqe.skb_from_cqe_mpwrq =
+			mlx5e_rx_mpwqe_is_linear_skb(mdev, params, NULL) ?
+			mlx5e_skb_from_cqe_mpwrq_linear :
+			mlx5e_skb_from_cqe_mpwrq_nonlinear;
+#endif
 		rq->post_wqes = mlx5e_post_rx_mpwqes;
 		rq->dealloc_wqe = mlx5e_dealloc_rx_mpwqe;
 
@@ -2806,11 +4266,17 @@ int mlx5e_rq_set_handlers(struct mlx5e_r
 
 		break;
 	default: /* MLX5_WQ_TYPE_CYCLIC */
+#ifdef HAVE_XSK_ZERO_COPY_SUPPORT
 		rq->wqe.skb_from_cqe = xsk ?
 			mlx5e_xsk_skb_from_cqe_linear :
 			mlx5e_rx_is_linear_skb(mdev, params, NULL) ?
 				mlx5e_skb_from_cqe_linear :
 				mlx5e_skb_from_cqe_nonlinear;
+#else
+		rq->wqe.skb_from_cqe = mlx5e_rx_is_linear_skb(mdev, params, NULL) ?
+			mlx5e_skb_from_cqe_linear :
+			mlx5e_skb_from_cqe_nonlinear;
+#endif
 		rq->post_wqes = mlx5e_post_rx_wqes;
 		rq->dealloc_wqe = mlx5e_dealloc_rx_wqe;
 		rq->handle_rx_cqe = priv->profile->rx_handlers->handle_rx_cqe;
@@ -2823,6 +4289,7 @@ int mlx5e_rq_set_handlers(struct mlx5e_r
 	return 0;
 }
 
+#ifdef HAVE_DEVLINK_TRAP_SUPPORT
 static void mlx5e_trap_handle_rx_cqe(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe)
 {
 	struct mlx5_wq_cyc *wq = &rq->wqe.wq;
@@ -2839,21 +4306,38 @@ static void mlx5e_trap_handle_rx_cqe(str
 
 	if (unlikely(MLX5E_RX_ERR_CQE(cqe))) {
 		rq->stats->wqe_err++;
+#ifdef HAVE_PAGE_POOL_DEFRAG_PAGE
 		goto wq_cyc_pop;
+#else
+		goto free_wqe;
+#endif
 	}
 
 	skb = mlx5e_skb_from_cqe_nonlinear(rq, wi, cqe, cqe_bcnt);
 	if (!skb)
+#ifdef HAVE_PAGE_POOL_DEFRAG_PAGE
 		goto wq_cyc_pop;
+#else
+		goto free_wqe;
+#endif
 
 	mlx5e_complete_rx_cqe(rq, cqe, cqe_bcnt, skb);
 	skb_push(skb, ETH_HLEN);
 
 	mlx5_devlink_trap_report(rq->mdev, trap_id, skb,
+#ifdef HAVE_NET_DEVICE_DEVLINK_PORT
 				 rq->netdev->devlink_port);
+#else
+				 mlx5e_devlink_get_dl_port(netdev_priv(rq->netdev)));
+#endif
 	dev_kfree_skb_any(skb);
 
+#ifdef HAVE_PAGE_POOL_DEFRAG_PAGE
 wq_cyc_pop:
+#else
+free_wqe:
+	mlx5e_free_rx_wqe(rq, wi, false);
+#endif
 	mlx5_wq_cyc_pop(wq);
 }
 
@@ -2866,3 +4350,4 @@ void mlx5e_rq_set_trap_handlers(struct m
 	rq->dealloc_wqe = mlx5e_dealloc_rx_wqe;
 	rq->handle_rx_cqe = mlx5e_trap_handle_rx_cqe;
 }
+#endif /* HAVE_DEVLINK_TRAP_SUPPORT */
