*/
 void ice_clean_rx_ring(struct ice_rx_ring *rx_ring)
 {
+       struct xdp_buff *xdp = &rx_ring->xdp;
        struct device *dev = rx_ring->dev;
        u32 size;
        u16 i;
        if (!rx_ring->rx_buf)
                return;
 
-       if (rx_ring->skb) {
-               dev_kfree_skb(rx_ring->skb);
-               rx_ring->skb = NULL;
-       }
-
        if (rx_ring->xsk_pool) {
                ice_xsk_clean_rx_ring(rx_ring);
                goto rx_skip_free;
        }
 
+       if (xdp->data) {
+               xdp_return_buff(xdp);
+               xdp->data = NULL;
+       }
+
        /* Free all the Rx ring sk_buffs */
        for (i = 0; i < rx_ring->count; i++) {
                struct ice_rx_buf *rx_buf = &rx_ring->rx_buf[i];
 
        rx_ring->next_to_alloc = 0;
        rx_ring->next_to_clean = 0;
+       rx_ring->first_desc = 0;
        rx_ring->next_to_use = 0;
 }
 
 
        rx_ring->next_to_use = 0;
        rx_ring->next_to_clean = 0;
+       rx_ring->first_desc = 0;
 
        if (ice_is_xdp_ena_vsi(rx_ring->vsi))
                WRITE_ONCE(rx_ring->xdp_prog, rx_ring->vsi->xdp_prog);
        }
 exit:
        rx_buf->act = ret;
+       if (unlikely(xdp_buff_has_frags(xdp)))
+               ice_set_rx_bufs_act(xdp, rx_ring, ret);
 }
 
 /**
  * buffers. Then bump tail at most one time. Grouping like this lets us avoid
  * multiple tail writes per call.
  */
-bool ice_alloc_rx_bufs(struct ice_rx_ring *rx_ring, u16 cleaned_count)
+bool ice_alloc_rx_bufs(struct ice_rx_ring *rx_ring, unsigned int cleaned_count)
 {
        union ice_32b_rx_flex_desc *rx_desc;
        u16 ntu = rx_ring->next_to_use;
 }
 
 /**
- * ice_add_rx_frag - Add contents of Rx buffer to sk_buff as a frag
+ * ice_add_xdp_frag - Add contents of Rx buffer to xdp buf as a frag
  * @rx_ring: Rx descriptor ring to transact packets on
- * @xdp: XDP buffer
+ * @xdp: xdp buff to place the data into
  * @rx_buf: buffer containing page to add
- * @skb: sk_buff to place the data into
  * @size: packet length from rx_desc
  *
- * This function will add the data contained in rx_buf->page to the skb.
- * It will just attach the page as a frag to the skb.
- * The function will then update the page offset.
+ * This function will add the data contained in rx_buf->page to the xdp buf.
+ * It will just attach the page as a frag.
  */
-static void
-ice_add_rx_frag(struct ice_rx_ring *rx_ring, struct xdp_buff *xdp,
-               struct ice_rx_buf *rx_buf, struct sk_buff *skb,
-               unsigned int size)
+static int
+ice_add_xdp_frag(struct ice_rx_ring *rx_ring, struct xdp_buff *xdp,
+                struct ice_rx_buf *rx_buf, const unsigned int size)
 {
+       struct skb_shared_info *sinfo = xdp_get_shared_info_from_buff(xdp);
+
        if (!size)
-               return;
-       skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, rx_buf->page,
-                       rx_buf->page_offset, size, xdp->frame_sz);
+               return 0;
+
+       if (!xdp_buff_has_frags(xdp)) {
+               sinfo->nr_frags = 0;
+               sinfo->xdp_frags_size = 0;
+               xdp_buff_set_frags_flag(xdp);
+       }
+
+       if (unlikely(sinfo->nr_frags == MAX_SKB_FRAGS)) {
+               if (unlikely(xdp_buff_has_frags(xdp)))
+                       ice_set_rx_bufs_act(xdp, rx_ring, ICE_XDP_CONSUMED);
+               return -ENOMEM;
+       }
+
+       __skb_fill_page_desc_noacc(sinfo, sinfo->nr_frags++, rx_buf->page,
+                                  rx_buf->page_offset, size);
+       sinfo->xdp_frags_size += size;
+
+       if (page_is_pfmemalloc(rx_buf->page))
+               xdp_buff_set_frag_pfmemalloc(xdp);
+
+       return 0;
 }
 
 /**
 /**
  * ice_build_skb - Build skb around an existing buffer
  * @rx_ring: Rx descriptor ring to transact packets on
- * @rx_buf: Rx buffer to pull data from
  * @xdp: xdp_buff pointing to the data
  *
- * This function builds an skb around an existing Rx buffer, taking care
- * to set up the skb correctly and avoid any memcpy overhead.
+ * This function builds an skb around an existing XDP buffer, taking care
+ * to set up the skb correctly and avoid any memcpy overhead. Driver has
+ * already combined frags (if any) to skb_shared_info.
  */
 static struct sk_buff *
-ice_build_skb(struct ice_rx_ring *rx_ring, struct ice_rx_buf *rx_buf,
-             struct xdp_buff *xdp)
+ice_build_skb(struct ice_rx_ring *rx_ring, struct xdp_buff *xdp)
 {
        u8 metasize = xdp->data - xdp->data_meta;
+       struct skb_shared_info *sinfo = NULL;
+       unsigned int nr_frags;
        struct sk_buff *skb;
 
+       if (unlikely(xdp_buff_has_frags(xdp))) {
+               sinfo = xdp_get_shared_info_from_buff(xdp);
+               nr_frags = sinfo->nr_frags;
+       }
+
        /* Prefetch first cache line of first page. If xdp->data_meta
         * is unused, this points exactly as xdp->data, otherwise we
         * likely have a consumer accessing first few bytes of meta
        if (metasize)
                skb_metadata_set(skb, metasize);
 
+       if (unlikely(xdp_buff_has_frags(xdp)))
+               xdp_update_skb_shared_info(skb, nr_frags,
+                                          sinfo->xdp_frags_size,
+                                          nr_frags * xdp->frame_sz,
+                                          xdp_buff_is_frag_pfmemalloc(xdp));
+
        return skb;
 }
 
  * skb correctly.
  */
 static struct sk_buff *
-ice_construct_skb(struct ice_rx_ring *rx_ring, struct ice_rx_buf *rx_buf,
-                 struct xdp_buff *xdp)
+ice_construct_skb(struct ice_rx_ring *rx_ring, struct xdp_buff *xdp)
 {
        unsigned int size = xdp->data_end - xdp->data;
+       struct skb_shared_info *sinfo = NULL;
+       struct ice_rx_buf *rx_buf;
+       unsigned int nr_frags = 0;
        unsigned int headlen;
        struct sk_buff *skb;
 
        /* prefetch first cache line of first page */
        net_prefetch(xdp->data);
 
+       if (unlikely(xdp_buff_has_frags(xdp))) {
+               sinfo = xdp_get_shared_info_from_buff(xdp);
+               nr_frags = sinfo->nr_frags;
+       }
+
        /* allocate a skb to store the frags */
        skb = __napi_alloc_skb(&rx_ring->q_vector->napi, ICE_RX_HDR_SIZE,
                               GFP_ATOMIC | __GFP_NOWARN);
        if (unlikely(!skb))
                return NULL;
 
+       rx_buf = &rx_ring->rx_buf[rx_ring->first_desc];
        skb_record_rx_queue(skb, rx_ring->q_index);
        /* Determine available headroom for copy */
        headlen = size;
        /* if we exhaust the linear part then add what is left as a frag */
        size -= headlen;
        if (size) {
+               /* besides adding here a partial frag, we are going to add
+                * frags from xdp_buff, make sure there is enough space for
+                * them
+                */
+               if (unlikely(nr_frags >= MAX_SKB_FRAGS - 1)) {
+                       dev_kfree_skb(skb);
+                       return NULL;
+               }
                skb_add_rx_frag(skb, 0, rx_buf->page,
                                rx_buf->page_offset + headlen, size,
                                xdp->frame_sz);
                 * need for adjusting page offset and we can reuse this buffer
                 * as-is
                 */
-               rx_buf->act = ICE_XDP_CONSUMED;
+               rx_buf->act = ICE_SKB_CONSUMED;
+       }
+
+       if (unlikely(xdp_buff_has_frags(xdp))) {
+               struct skb_shared_info *skinfo = skb_shinfo(skb);
+
+               memcpy(&skinfo->frags[skinfo->nr_frags], &sinfo->frags[0],
+                      sizeof(skb_frag_t) * nr_frags);
+
+               xdp_update_skb_shared_info(skb, skinfo->nr_frags + nr_frags,
+                                          sinfo->xdp_frags_size,
+                                          nr_frags * xdp->frame_sz,
+                                          xdp_buff_is_frag_pfmemalloc(xdp));
        }
 
        return skb;
 int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget)
 {
        unsigned int total_rx_bytes = 0, total_rx_pkts = 0;
-       u16 cleaned_count = ICE_DESC_UNUSED(rx_ring);
        unsigned int offset = rx_ring->rx_offset;
        struct xdp_buff *xdp = &rx_ring->xdp;
        struct ice_tx_ring *xdp_ring = NULL;
-       struct sk_buff *skb = rx_ring->skb;
        struct bpf_prog *xdp_prog = NULL;
        u32 ntc = rx_ring->next_to_clean;
        u32 cnt = rx_ring->count;
        u32 cached_ntc = ntc;
        u32 xdp_xmit = 0;
        bool failure;
+       u32 first;
 
        /* Frame size depend on rx_ring setup when PAGE_SIZE=4K */
 #if (PAGE_SIZE < 8192)
        while (likely(total_rx_pkts < (unsigned int)budget)) {
                union ice_32b_rx_flex_desc *rx_desc;
                struct ice_rx_buf *rx_buf;
-               unsigned char *hard_start;
+               struct sk_buff *skb;
                unsigned int size;
                u16 stat_err_bits;
                u16 vlan_tag = 0;
                                ice_vc_fdir_irq_handler(ctrl_vsi, rx_desc);
                        if (++ntc == cnt)
                                ntc = 0;
-                       cleaned_count++;
                        continue;
                }
 
                /* retrieve a buffer from the ring */
                rx_buf = ice_get_rx_buf(rx_ring, size, ntc);
 
-               if (!size) {
-                       xdp->data = NULL;
-                       xdp->data_end = NULL;
-                       xdp->data_hard_start = NULL;
-                       xdp->data_meta = NULL;
-                       goto construct_skb;
-               }
+               if (!xdp->data) {
+                       void *hard_start;
 
-               hard_start = page_address(rx_buf->page) + rx_buf->page_offset -
-                            offset;
-               xdp_prepare_buff(xdp, hard_start, offset, size, !!offset);
+                       hard_start = page_address(rx_buf->page) + rx_buf->page_offset -
+                                    offset;
+                       xdp_prepare_buff(xdp, hard_start, offset, size, !!offset);
 #if (PAGE_SIZE > 4096)
-               /* At larger PAGE_SIZE, frame_sz depend on len size */
-               xdp->frame_sz = ice_rx_frame_truesize(rx_ring, size);
+                       /* At larger PAGE_SIZE, frame_sz depend on len size */
+                       xdp->frame_sz = ice_rx_frame_truesize(rx_ring, size);
 #endif
+                       xdp_buff_clear_frags_flag(xdp);
+               } else if (ice_add_xdp_frag(rx_ring, xdp, rx_buf, size)) {
+                       break;
+               }
+               if (++ntc == cnt)
+                       ntc = 0;
+
+               /* skip if it is NOP desc */
+               if (ice_is_non_eop(rx_ring, rx_desc))
+                       continue;
 
                ice_run_xdp(rx_ring, xdp, xdp_prog, xdp_ring, rx_buf);
                if (rx_buf->act == ICE_XDP_PASS)
                        goto construct_skb;
-               total_rx_bytes += size;
+               total_rx_bytes += xdp_get_buff_len(xdp);
                total_rx_pkts++;
 
-               cleaned_count++;
-               if (++ntc == cnt)
-                       ntc = 0;
+               xdp->data = NULL;
+               rx_ring->first_desc = ntc;
                continue;
 construct_skb:
-               if (skb) {
-                       ice_add_rx_frag(rx_ring, xdp, rx_buf, skb, size);
-               } else if (likely(xdp->data)) {
-                       if (ice_ring_uses_build_skb(rx_ring))
-                               skb = ice_build_skb(rx_ring, rx_buf, xdp);
-                       else
-                               skb = ice_construct_skb(rx_ring, rx_buf, xdp);
-               }
+               if (likely(ice_ring_uses_build_skb(rx_ring)))
+                       skb = ice_build_skb(rx_ring, xdp);
+               else
+                       skb = ice_construct_skb(rx_ring, xdp);
                /* exit if we failed to retrieve a buffer */
                if (!skb) {
-                       rx_ring->ring_stats->rx_stats.alloc_buf_failed++;
-                       if (rx_buf)
-                               rx_buf->pagecnt_bias++;
+                       rx_ring->ring_stats->rx_stats.alloc_page_failed++;
+                       rx_buf->act = ICE_XDP_CONSUMED;
+                       if (unlikely(xdp_buff_has_frags(xdp)))
+                               ice_set_rx_bufs_act(xdp, rx_ring,
+                                                   ICE_XDP_CONSUMED);
+                       xdp->data = NULL;
+                       rx_ring->first_desc = ntc;
                        break;
                }
-
-               if (++ntc == cnt)
-                       ntc = 0;
-               cleaned_count++;
-
-               /* skip if it is NOP desc */
-               if (ice_is_non_eop(rx_ring, rx_desc))
-                       continue;
+               xdp->data = NULL;
+               rx_ring->first_desc = ntc;
 
                stat_err_bits = BIT(ICE_RX_FLEX_DESC_STATUS0_RXE_S);
                if (unlikely(ice_test_staterr(rx_desc->wb.status_error0,
                vlan_tag = ice_get_vlan_tag_from_rx_desc(rx_desc);
 
                /* pad the skb if needed, to make a valid ethernet frame */
-               if (eth_skb_pad(skb)) {
-                       skb = NULL;
+               if (eth_skb_pad(skb))
                        continue;
-               }
 
                /* probably a little skewed due to removing CRC */
                total_rx_bytes += skb->len;
                ice_trace(clean_rx_irq_indicate, rx_ring, rx_desc, skb);
                /* send completed skb up the stack */
                ice_receive_skb(rx_ring, skb, vlan_tag);
-               skb = NULL;
 
                /* update budget accounting */
                total_rx_pkts++;
        }
 
-       while (cached_ntc != ntc) {
+       first = rx_ring->first_desc;
+       while (cached_ntc != first) {
                struct ice_rx_buf *buf = &rx_ring->rx_buf[cached_ntc];
 
                if (buf->act & (ICE_XDP_TX | ICE_XDP_REDIR)) {
        }
        rx_ring->next_to_clean = ntc;
        /* return up to cleaned_count buffers to hardware */
-       failure = ice_alloc_rx_bufs(rx_ring, cleaned_count);
+       failure = ice_alloc_rx_bufs(rx_ring, ICE_RX_DESC_UNUSED(rx_ring));
 
        if (xdp_xmit)
                ice_finalize_xdp_rx(xdp_ring, xdp_xmit);
-       rx_ring->skb = skb;
 
        if (rx_ring->ring_stats)
                ice_update_rx_ring_stats(rx_ring, total_rx_pkts,
 
        (u16)((((R)->next_to_clean > (R)->next_to_use) ? 0 : (R)->count) + \
              (R)->next_to_clean - (R)->next_to_use - 1)
 
+#define ICE_RX_DESC_UNUSED(R)  \
+       ((((R)->first_desc > (R)->next_to_use) ? 0 : (R)->count) + \
+             (R)->first_desc - (R)->next_to_use - 1)
+
 #define ICE_RING_QUARTER(R) ((R)->count >> 2)
 
 #define ICE_TX_FLAGS_TSO       BIT(0)
 #define ICE_XDP_TX             BIT(1)
 #define ICE_XDP_REDIR          BIT(2)
 #define ICE_XDP_EXIT           BIT(3)
+#define ICE_SKB_CONSUMED       ICE_XDP_CONSUMED
 
 #define ICE_RX_DMA_ATTR \
        (DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_WEAK_ORDERING)
        struct ice_vsi *vsi;            /* Backreference to associated VSI */
        struct ice_q_vector *q_vector;  /* Backreference to associated vector */
        u8 __iomem *tail;
+       u16 q_index;                    /* Queue number of ring */
+
+       u16 count;                      /* Number of descriptors */
+       u16 reg_idx;                    /* HW register index of the ring */
+       u16 next_to_alloc;
+       /* CL2 - 2nd cacheline starts here */
        union {
                struct ice_rx_buf *rx_buf;
                struct xdp_buff **xdp_buf;
        };
-       /* CL2 - 2nd cacheline starts here */
-       struct xdp_rxq_info xdp_rxq;
+       struct xdp_buff xdp;
        /* CL3 - 3rd cacheline starts here */
-       u16 q_index;                    /* Queue number of ring */
-
-       u16 count;                      /* Number of descriptors */
-       u16 reg_idx;                    /* HW register index of the ring */
+       struct bpf_prog *xdp_prog;
+       u16 rx_offset;
 
        /* used in interrupt processing */
        u16 next_to_use;
        u16 next_to_clean;
-       u16 next_to_alloc;
-       u16 rx_offset;
-       u16 rx_buf_len;
+       u16 first_desc;
 
        /* stats structs */
        struct ice_ring_stats *ring_stats;
 
        struct rcu_head rcu;            /* to avoid race on free */
-       /* CL4 - 3rd cacheline starts here */
+       /* CL4 - 4th cacheline starts here */
        struct ice_channel *ch;
-       struct bpf_prog *xdp_prog;
        struct ice_tx_ring *xdp_ring;
        struct xsk_buff_pool *xsk_pool;
-       struct xdp_buff xdp;
-       struct sk_buff *skb;
        dma_addr_t dma;                 /* physical address of ring */
        u64 cached_phctime;
+       u16 rx_buf_len;
        u8 dcb_tc;                      /* Traffic class of ring */
        u8 ptp_rx;
 #define ICE_RX_FLAGS_RING_BUILD_SKB    BIT(1)
 #define ICE_RX_FLAGS_CRC_STRIP_DIS     BIT(2)
        u8 flags;
+       /* CL5 - 5th cacheline starts here */
+       struct xdp_rxq_info xdp_rxq;
 } ____cacheline_internodealigned_in_smp;
 
 struct ice_tx_ring {
 
 union ice_32b_rx_flex_desc;
 
-bool ice_alloc_rx_bufs(struct ice_rx_ring *rxr, u16 cleaned_count);
+bool ice_alloc_rx_bufs(struct ice_rx_ring *rxr, unsigned int cleaned_count);
 netdev_tx_t ice_start_xmit(struct sk_buff *skb, struct net_device *netdev);
 u16
 ice_select_queue(struct net_device *dev, struct sk_buff *skb,