@@ -865,10 +865,6 @@ ice_add_xdp_frag(struct ice_rx_ring *rx_ring, struct xdp_buff *xdp,
865865 __skb_fill_page_desc_noacc (sinfo , sinfo -> nr_frags ++ , rx_buf -> page ,
866866 rx_buf -> page_offset , size );
867867 sinfo -> xdp_frags_size += size ;
868- /* remember frag count before XDP prog execution; bpf_xdp_adjust_tail()
869- * can pop off frags but driver has to handle it on its own
870- */
871- rx_ring -> nr_frags = sinfo -> nr_frags ;
872868
873869 if (page_is_pfmemalloc (rx_buf -> page ))
874870 xdp_buff_set_frag_pfmemalloc (xdp );
@@ -939,20 +935,20 @@ ice_get_rx_buf(struct ice_rx_ring *rx_ring, const unsigned int size,
939935/**
940936 * ice_get_pgcnts - grab page_count() for gathered fragments
941937 * @rx_ring: Rx descriptor ring to store the page counts on
938+ * @ntc: the next to clean element (not included in this frame!)
942939 *
943940 * This function is intended to be called right before running XDP
944941 * program so that the page recycling mechanism will be able to take
945942 * a correct decision regarding underlying pages; this is done in such
946943 * way as XDP program can change the refcount of page
947944 */
948- static void ice_get_pgcnts (struct ice_rx_ring * rx_ring )
945+ static void ice_get_pgcnts (struct ice_rx_ring * rx_ring , unsigned int ntc )
949946{
950- u32 nr_frags = rx_ring -> nr_frags + 1 ;
951947 u32 idx = rx_ring -> first_desc ;
952948 struct ice_rx_buf * rx_buf ;
953949 u32 cnt = rx_ring -> count ;
954950
955- for ( int i = 0 ; i < nr_frags ; i ++ ) {
951+ while ( idx != ntc ) {
956952 rx_buf = & rx_ring -> rx_buf [idx ];
957953 rx_buf -> pgcnt = page_count (rx_buf -> page );
958954
@@ -1125,62 +1121,51 @@ ice_put_rx_buf(struct ice_rx_ring *rx_ring, struct ice_rx_buf *rx_buf)
11251121}
11261122
11271123/**
1128- * ice_put_rx_mbuf - ice_put_rx_buf() caller, for all frame frags
1124+ * ice_put_rx_mbuf - ice_put_rx_buf() caller, for all buffers in frame
11291125 * @rx_ring: Rx ring with all the auxiliary data
11301126 * @xdp: XDP buffer carrying linear + frags part
1131- * @xdp_xmit: XDP_TX/XDP_REDIRECT verdict storage
1132- * @ntc: a current next_to_clean value to be stored at rx_ring
1127+ * @ntc: the next to clean element (not included in this frame!)
11331128 * @verdict: return code from XDP program execution
11341129 *
1135- * Walk through gathered fragments and satisfy internal page
1136- * recycle mechanism; we take here an action related to verdict
1137- * returned by XDP program;
1130+ * Called after XDP program is completed, or on error with verdict set to
1131+ * ICE_XDP_CONSUMED.
1132+ *
1133+ * Walk through buffers from first_desc to the end of the frame, releasing
1134+ * buffers and satisfying internal page recycle mechanism. The action depends
1135+ * on verdict from XDP program.
11381136 */
11391137static void ice_put_rx_mbuf (struct ice_rx_ring * rx_ring , struct xdp_buff * xdp ,
1140- u32 * xdp_xmit , u32 ntc , u32 verdict )
1138+ u32 ntc , u32 verdict )
11411139{
1142- u32 nr_frags = rx_ring -> nr_frags + 1 ;
11431140 u32 idx = rx_ring -> first_desc ;
11441141 u32 cnt = rx_ring -> count ;
1145- u32 post_xdp_frags = 1 ;
11461142 struct ice_rx_buf * buf ;
1147- int i ;
1143+ u32 xdp_frags = 0 ;
1144+ int i = 0 ;
11481145
11491146 if (unlikely (xdp_buff_has_frags (xdp )))
1150- post_xdp_frags + = xdp_get_shared_info_from_buff (xdp )-> nr_frags ;
1147+ xdp_frags = xdp_get_shared_info_from_buff (xdp )-> nr_frags ;
11511148
1152- for ( i = 0 ; i < post_xdp_frags ; i ++ ) {
1149+ while ( idx != ntc ) {
11531150 buf = & rx_ring -> rx_buf [idx ];
1151+ if (++ idx == cnt )
1152+ idx = 0 ;
11541153
1155- if (verdict & (ICE_XDP_TX | ICE_XDP_REDIR )) {
1154+ /* An XDP program could release fragments from the end of the
1155+ * buffer. For these, we need to keep the pagecnt_bias as-is.
1156+ * To do this, only adjust pagecnt_bias for fragments up to
1157+ * the total remaining after the XDP program has run.
1158+ */
1159+ if (verdict != ICE_XDP_CONSUMED )
11561160 ice_rx_buf_adjust_pg_offset (buf , xdp -> frame_sz );
1157- * xdp_xmit |= verdict ;
1158- } else if (verdict & ICE_XDP_CONSUMED ) {
1161+ else if (i ++ <= xdp_frags )
11591162 buf -> pagecnt_bias ++ ;
1160- } else if (verdict == ICE_XDP_PASS ) {
1161- ice_rx_buf_adjust_pg_offset (buf , xdp -> frame_sz );
1162- }
11631163
11641164 ice_put_rx_buf (rx_ring , buf );
1165-
1166- if (++ idx == cnt )
1167- idx = 0 ;
1168- }
1169- /* handle buffers that represented frags released by XDP prog;
1170- * for these we keep pagecnt_bias as-is; refcount from struct page
1171- * has been decremented within XDP prog and we do not have to increase
1172- * the biased refcnt
1173- */
1174- for (; i < nr_frags ; i ++ ) {
1175- buf = & rx_ring -> rx_buf [idx ];
1176- ice_put_rx_buf (rx_ring , buf );
1177- if (++ idx == cnt )
1178- idx = 0 ;
11791165 }
11801166
11811167 xdp -> data = NULL ;
11821168 rx_ring -> first_desc = ntc ;
1183- rx_ring -> nr_frags = 0 ;
11841169}
11851170
11861171/**
@@ -1260,6 +1245,10 @@ int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget)
12601245 /* retrieve a buffer from the ring */
12611246 rx_buf = ice_get_rx_buf (rx_ring , size , ntc );
12621247
1248+ /* Increment ntc before calls to ice_put_rx_mbuf() */
1249+ if (++ ntc == cnt )
1250+ ntc = 0 ;
1251+
12631252 if (!xdp -> data ) {
12641253 void * hard_start ;
12651254
@@ -1268,24 +1257,23 @@ int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget)
12681257 xdp_prepare_buff (xdp , hard_start , offset , size , !!offset );
12691258 xdp_buff_clear_frags_flag (xdp );
12701259 } else if (ice_add_xdp_frag (rx_ring , xdp , rx_buf , size )) {
1271- ice_put_rx_mbuf (rx_ring , xdp , NULL , ntc , ICE_XDP_CONSUMED );
1260+ ice_put_rx_mbuf (rx_ring , xdp , ntc , ICE_XDP_CONSUMED );
12721261 break ;
12731262 }
1274- if (++ ntc == cnt )
1275- ntc = 0 ;
12761263
12771264 /* skip if it is NOP desc */
12781265 if (ice_is_non_eop (rx_ring , rx_desc ))
12791266 continue ;
12801267
1281- ice_get_pgcnts (rx_ring );
1268+ ice_get_pgcnts (rx_ring , ntc );
12821269 xdp_verdict = ice_run_xdp (rx_ring , xdp , xdp_prog , xdp_ring , rx_desc );
12831270 if (xdp_verdict == ICE_XDP_PASS )
12841271 goto construct_skb ;
12851272 total_rx_bytes += xdp_get_buff_len (xdp );
12861273 total_rx_pkts ++ ;
12871274
1288- ice_put_rx_mbuf (rx_ring , xdp , & xdp_xmit , ntc , xdp_verdict );
1275+ ice_put_rx_mbuf (rx_ring , xdp , ntc , xdp_verdict );
1276+ xdp_xmit |= xdp_verdict & (ICE_XDP_TX | ICE_XDP_REDIR );
12891277
12901278 continue ;
12911279construct_skb :
@@ -1298,7 +1286,7 @@ int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget)
12981286 rx_ring -> ring_stats -> rx_stats .alloc_page_failed ++ ;
12991287 xdp_verdict = ICE_XDP_CONSUMED ;
13001288 }
1301- ice_put_rx_mbuf (rx_ring , xdp , & xdp_xmit , ntc , xdp_verdict );
1289+ ice_put_rx_mbuf (rx_ring , xdp , ntc , xdp_verdict );
13021290
13031291 if (!skb )
13041292 break ;
0 commit comments