Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 5 Dec 2017 21:00:31 +0000 (UTC)
From:      Stephen Hurd <shurd@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r326578 - in head/sys: dev/bnxt net
Message-ID:  <201712052100.vB5L0VnS006611@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: shurd
Date: Tue Dec  5 21:00:31 2017
New Revision: 326578
URL: https://svnweb.freebsd.org/changeset/base/326578

Log:
  iflib: Support to padding Ethernet frames to a min size
  
  Some bnxt devices do not correctly send frames smaller than
  52 bytes (without CRC), so add a quirk that will pad frames to an
  arbitrary size before passing off to the encap routine.
  
  Reported by:	Bhargava Chenna Marreddy <bhargava.marreddy@broadcom.com>
  Sponsored by:	Limelight Networks
  Differential Revision:	https://reviews.freebsd.org/D13269

Modified:
  head/sys/dev/bnxt/bnxt.h
  head/sys/dev/bnxt/if_bnxt.c
  head/sys/net/iflib.c
  head/sys/net/iflib.h

Modified: head/sys/dev/bnxt/bnxt.h
==============================================================================
--- head/sys/dev/bnxt/bnxt.h	Tue Dec  5 20:43:24 2017	(r326577)
+++ head/sys/dev/bnxt/bnxt.h	Tue Dec  5 21:00:31 2017	(r326578)
@@ -236,6 +236,8 @@ __FBSDID("$FreeBSD$");
 		ifmedia_add(softc->media, IFM_ETHER | (ifm_speed), 0, NULL);	\
 } while(0)
 
+#define BNXT_MIN_FRAME_SIZE	52	/* Frames must be padded to this size for some A0 chips */
+
 /* NVRAM access */
 enum bnxt_nvm_directory_type {
 	BNX_DIR_TYPE_UNUSED = 0,

Modified: head/sys/dev/bnxt/if_bnxt.c
==============================================================================
--- head/sys/dev/bnxt/if_bnxt.c	Tue Dec  5 20:43:24 2017	(r326577)
+++ head/sys/dev/bnxt/if_bnxt.c	Tue Dec  5 21:00:31 2017	(r326578)
@@ -298,7 +298,7 @@ static struct if_shared_ctx bnxt_sctx_init = {
 	.isc_magic = IFLIB_MAGIC,
 	.isc_driver = &bnxt_iflib_driver,
 	.isc_nfl = 2,				// Number of Free Lists
-	.isc_flags = IFLIB_HAS_RXCQ | IFLIB_HAS_TXCQ,
+	.isc_flags = IFLIB_HAS_RXCQ | IFLIB_HAS_TXCQ | IFLIB_NEED_ETHER_PAD,
 	.isc_q_align = PAGE_SIZE,
 	.isc_tx_maxsize = BNXT_TSO_SIZE,
 	.isc_tx_maxsegsize = BNXT_TSO_SIZE,
@@ -793,6 +793,7 @@ bnxt_attach_pre(if_ctx_t ctx)
 	scctx->isc_tx_tso_size_max = BNXT_TSO_SIZE;
 	scctx->isc_tx_tso_segsize_max = BNXT_TSO_SIZE;
 	scctx->isc_vectors = softc->func.max_cp_rings;
+	scctx->isc_min_frame_size = BNXT_MIN_FRAME_SIZE;
 	scctx->isc_txrx = &bnxt_txrx;
 
 	if (scctx->isc_nrxd[0] <

Modified: head/sys/net/iflib.c
==============================================================================
--- head/sys/net/iflib.c	Tue Dec  5 20:43:24 2017	(r326577)
+++ head/sys/net/iflib.c	Tue Dec  5 21:00:31 2017	(r326578)
@@ -627,11 +627,14 @@ SYSCTL_INT(_net_iflib, OID_AUTO, txq_drain_encapfail, 
 
 
 static int iflib_encap_load_mbuf_fail;
+static int iflib_encap_pad_mbuf_fail;
 static int iflib_encap_txq_avail_fail;
 static int iflib_encap_txd_encap_fail;
 
 SYSCTL_INT(_net_iflib, OID_AUTO, encap_load_mbuf_fail, CTLFLAG_RD,
 		   &iflib_encap_load_mbuf_fail, 0, "# busdma load failures");
+SYSCTL_INT(_net_iflib, OID_AUTO, encap_pad_mbuf_fail, CTLFLAG_RD,
+		   &iflib_encap_pad_mbuf_fail, 0, "# runt frame pad failures");
 SYSCTL_INT(_net_iflib, OID_AUTO, encap_txq_avail_fail, CTLFLAG_RD,
 		   &iflib_encap_txq_avail_fail, 0, "# txq avail failures");
 SYSCTL_INT(_net_iflib, OID_AUTO, encap_txd_encap_fail, CTLFLAG_RD,
@@ -684,9 +687,10 @@ iflib_debug_reset(void)
 		iflib_fl_refills = iflib_fl_refills_large = iflib_tx_frees =
 		iflib_txq_drain_flushing = iflib_txq_drain_oactive =
 		iflib_txq_drain_notready = iflib_txq_drain_encapfail =
-		iflib_encap_load_mbuf_fail = iflib_encap_txq_avail_fail =
-		iflib_encap_txd_encap_fail = iflib_task_fn_rxs = iflib_rx_intr_enables =
-		iflib_fast_intrs = iflib_intr_link = iflib_intr_msix = iflib_rx_unavail =
+		iflib_encap_load_mbuf_fail = iflib_encap_pad_mbuf_fail =
+		iflib_encap_txq_avail_fail = iflib_encap_txd_encap_fail =
+		iflib_task_fn_rxs = iflib_rx_intr_enables = iflib_fast_intrs =
+		iflib_intr_link = iflib_intr_msix = iflib_rx_unavail =
 		iflib_rx_ctx_inactive = iflib_rx_zero_len = iflib_rx_if_input =
 		iflib_rx_mbuf_null = iflib_rxd_flush = 0;
 }
@@ -3103,6 +3107,35 @@ calc_next_txd(iflib_txq_t txq, int cidx, uint8_t qid)
 	return (next < end ? next : start);
 }
 
+/*
+ * Pad an mbuf to ensure a minimum ethernet frame size.
+ * min_frame_size is the frame size (less CRC) to pad the mbuf to
+ */
+static __noinline int
+iflib_ether_pad(device_t dev, struct mbuf *m_head, uint16_t min_frame_size)
+{
+	/*
+	 * 18 is enough bytes to pad an ARP packet to 46 bytes, and
+	 * and ARP message is the smallest common payload I can think of
+	 */
+	static char pad[18];	/* just zeros */
+	int n;
+
+	for (n = min_frame_size - m_head->m_pkthdr.len;
+	     n > 0; n -= sizeof(pad))
+		if (!m_append(m_head, min(n, sizeof(pad)), pad))
+			break;
+
+	if (n > 0) {
+		m_freem(m_head);
+		device_printf(dev, "cannot pad short frame\n");
+		DBG_COUNTER_INC(encap_pad_mbuf_fail);
+		return (ENOBUFS);
+	}
+
+	return 0;
+}
+
 static int
 iflib_encap(iflib_txq_t txq, struct mbuf **m_headp)
 {
@@ -3157,6 +3190,12 @@ iflib_encap(iflib_txq_t txq, struct mbuf **m_headp)
 		max_segs = scctx->isc_tx_nsegments;
 	}
 	m_head = *m_headp;
+	if ((sctx->isc_flags & IFLIB_NEED_ETHER_PAD) &&
+	    __predict_false(m_head->m_pkthdr.len < scctx->isc_min_frame_size)) {
+		err = iflib_ether_pad(ctx->ifc_dev, m_head, scctx->isc_min_frame_size);
+		if (err)
+			return err;
+	}
 
 	pkt_info_zero(&pi);
 	pi.ipi_mflags = (m_head->m_flags & (M_VLANTAG|M_BCAST|M_MCAST));

Modified: head/sys/net/iflib.h
==============================================================================
--- head/sys/net/iflib.h	Tue Dec  5 20:43:24 2017	(r326577)
+++ head/sys/net/iflib.h	Tue Dec  5 21:00:31 2017	(r326578)
@@ -217,6 +217,8 @@ typedef struct if_softc_ctx {
 
 	iflib_intr_mode_t isc_intr;
 	uint16_t isc_max_frame_size; /* set at init time by driver */
+	uint16_t isc_min_frame_size; /* set at init time by driver, only used if
+					IFLIB_NEED_ETHER_PAD is set. */
 	uint32_t isc_pause_frames;   /* set by driver for iflib_timer to detect */
 	pci_vendor_info_t isc_vendor_info;	/* set by iflib prior to attach_pre */
 	int isc_disable_msix;
@@ -314,6 +316,10 @@ typedef enum {
  * Driver needs csum zeroed for offloading
  */
 #define IFLIB_NEED_ZERO_CSUM	0x80
+/*
+ * Driver needs frames padded to some minimum length
+ */
+#define IFLIB_NEED_ETHER_PAD	0x100
 
 
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201712052100.vB5L0VnS006611>