Author: adrian
Date: Thu Sep 18 16:20:17 2014
New Revision: 271784
URL: http://svnweb.freebsd.org/changeset/base/271784

Log:
  Fix the handling of EOP in status descriptors for if_igb(4) and don't
  double-free mbufs.
  
  Like ixgbe(4) chipsets, EOP is only set on the final descriptor
  in a chain of descriptors.  So, to free the whole list of descriptors,
  we should free the current slot _and_ the assembled list of descriptors
  that make up the fragment list.
  
  The existing code was setting discard once it saw EOP + an error status;
  it then freed all the subsequent descriptors until the next EOP. That's
  totally the wrong order.

Modified:
  head/sys/dev/e1000/if_igb.c
  head/sys/dev/e1000/if_igb.h

Modified: head/sys/dev/e1000/if_igb.c
==============================================================================
--- head/sys/dev/e1000/if_igb.c Thu Sep 18 16:17:20 2014        (r271783)
+++ head/sys/dev/e1000/if_igb.c Thu Sep 18 16:20:17 2014        (r271784)
@@ -4495,7 +4495,6 @@ skip_head:
 
        rxr->fmp = NULL;
        rxr->lmp = NULL;
-       rxr->discard = FALSE;
 
        bus_dmamap_sync(rxr->rxdma.dma_tag, rxr->rxdma.dma_map,
            BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
@@ -5039,15 +5038,16 @@ igb_rxeof(struct igb_queue *que, int cou
                pkt_info = le16toh(cur->wb.lower.lo_dword.hs_rss.pkt_info);
                eop = ((staterr & E1000_RXD_STAT_EOP) == E1000_RXD_STAT_EOP);
 
-               /* Make sure all segments of a bad packet are discarded */
-               if (((staterr & E1000_RXDEXT_ERR_FRAME_ERR_MASK) != 0) ||
-                   (rxr->discard)) {
+               /*
+                * Free the frame (all segments) if we're at EOP and
+                * it's an error.
+                *
+                * The datasheet states that EOP + status is only valid for
+                * the final segment in a multi-segment frame.
+                */
+               if (eop && ((staterr & E1000_RXDEXT_ERR_FRAME_ERR_MASK) != 0)) {
                        adapter->dropped_pkts++;
                        ++rxr->rx_discarded;
-                       if (!eop) /* Catch subsequent segs */
-                               rxr->discard = TRUE;
-                       else
-                               rxr->discard = FALSE;
                        igb_rx_discard(rxr, i);
                        goto next_desc;
                }

Modified: head/sys/dev/e1000/if_igb.h
==============================================================================
--- head/sys/dev/e1000/if_igb.h Thu Sep 18 16:17:20 2014        (r271783)
+++ head/sys/dev/e1000/if_igb.h Thu Sep 18 16:20:17 2014        (r271784)
@@ -336,7 +336,6 @@ struct rx_ring {
        struct lro_ctrl         lro;
        bool                    lro_enabled;
        bool                    hdr_split;
-       bool                    discard;
        struct mtx              rx_mtx;
        char                    mtx_name[16];
        u32                     next_to_refresh;
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to