Date: Thu, 18 Sep 2014 16:20:18 +0000 (UTC) From: Adrian Chadd <adrian@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r271784 - head/sys/dev/e1000 Message-ID: <201409181620.s8IGKI4o024082@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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;
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201409181620.s8IGKI4o024082>