svn commit: r317868 - head/sys/mips/atheros/ar531x

Adrian Chadd adrian at FreeBSD.org
Sat May 6 06:06:13 UTC 2017


Author: adrian
Date: Sat May  6 06:06:11 2017
New Revision: 317868
URL: https://svnweb.freebsd.org/changeset/base/317868

Log:
  [ar531x] [if_are] Fix if_are behaviour under high load traffic
  
  * use ifqmaxlen
  * handle (inefficiently for now) meeting padding and alignment requirements for
    transmit mbufs.
  * change how TX ring handling is done
  
  Submitted by:	Hiroki Mori <yamori813 at yahoo.co.jp>
  Differential Revision:	https://reviews.freebsd.org/D10557

Modified:
  head/sys/mips/atheros/ar531x/if_are.c
  head/sys/mips/atheros/ar531x/if_arereg.h

Modified: head/sys/mips/atheros/ar531x/if_are.c
==============================================================================
--- head/sys/mips/atheros/ar531x/if_are.c	Sat May  6 06:01:17 2017	(r317867)
+++ head/sys/mips/atheros/ar531x/if_are.c	Sat May  6 06:06:11 2017	(r317868)
@@ -302,9 +302,9 @@ are_attach(device_t dev)
 	ifp->if_init = are_init;
 	sc->are_if_flags = ifp->if_flags;
 
-	/* XXX: add real size */
-	IFQ_SET_MAXLEN(&ifp->if_snd, 9);
-	ifp->if_snd.ifq_maxlen = 9;
+	/* ifqmaxlen is sysctl value in net/if.c */
+	IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
+	ifp->if_snd.ifq_maxlen = ifqmaxlen;
 	IFQ_SET_READY(&ifp->if_snd);
 
 	/* Tell the upper layer(s) we support long frames. */
@@ -686,19 +686,92 @@ are_encap(struct are_softc *sc, struct m
 {
 	struct are_txdesc	*txd;
 	struct are_desc		*desc, *prev_desc;
+	struct mbuf		*m;
 	bus_dma_segment_t	txsegs[ARE_MAXFRAGS];
 	uint32_t		link_addr;
 	int			error, i, nsegs, prod, si, prev_prod;
 	int			txstat;
+	int			startcount;
+	int			padlen;
+
+	startcount = sc->are_cdata.are_tx_cnt;
 
 	ARE_LOCK_ASSERT(sc);
 
+	/*
+	 * Some VIA Rhine wants packet buffers to be longword
+	 * aligned, but very often our mbufs aren't. Rather than
+	 * waste time trying to decide when to copy and when not
+	 * to copy, just do it all the time.
+	 */
+	m = m_defrag(*m_head, M_NOWAIT);
+	if (m == NULL) {
+		device_printf(sc->are_dev, "are_encap m_defrag error\n");
+		m_freem(*m_head);
+		*m_head = NULL;
+		return (ENOBUFS);
+	}
+	*m_head = m;
+
+	/*
+	 * The Rhine chip doesn't auto-pad, so we have to make
+	 * sure to pad short frames out to the minimum frame length
+	 * ourselves.
+	 */
+	if ((*m_head)->m_pkthdr.len < ARE_MIN_FRAMELEN) {
+		m = *m_head;
+		padlen = ARE_MIN_FRAMELEN - m->m_pkthdr.len;
+		if (M_WRITABLE(m) == 0) {
+			/* Get a writable copy. */
+			m = m_dup(*m_head, M_NOWAIT);
+			m_freem(*m_head);
+			if (m == NULL) {
+				device_printf(sc->are_dev, "are_encap m_dup error\n");
+				*m_head = NULL;
+				return (ENOBUFS);
+			}
+			*m_head = m;
+		}
+		if (m->m_next != NULL || M_TRAILINGSPACE(m) < padlen) {
+			m = m_defrag(m, M_NOWAIT);
+			if (m == NULL) {
+				device_printf(sc->are_dev, "are_encap m_defrag error\n");
+				m_freem(*m_head);
+				*m_head = NULL;
+				return (ENOBUFS);
+			}
+		}
+		/*
+		 * Manually pad short frames, and zero the pad space
+		 * to avoid leaking data.
+		 */
+		bzero(mtod(m, char *) + m->m_pkthdr.len, padlen);
+		m->m_pkthdr.len += padlen;
+		m->m_len = m->m_pkthdr.len;
+		*m_head = m;
+	}
+
 	prod = sc->are_cdata.are_tx_prod;
 	txd = &sc->are_cdata.are_txdesc[prod];
-	error = bus_dmamap_load_mbuf_sg(sc->are_cdata.are_tx_tag, txd->tx_dmamap,
-	    *m_head, txsegs, &nsegs, BUS_DMA_NOWAIT);
+	error = bus_dmamap_load_mbuf_sg(sc->are_cdata.are_tx_tag,
+	    txd->tx_dmamap, *m_head, txsegs, &nsegs, BUS_DMA_NOWAIT);
 	if (error == EFBIG) {
-		panic("EFBIG");
+		device_printf(sc->are_dev, "are_encap EFBIG error\n");
+		m = m_defrag(*m_head, M_NOWAIT);
+		if (m == NULL) {
+			m_freem(*m_head);
+			*m_head = NULL;
+			return (ENOBUFS);
+		}
+		*m_head = m;
+		error = bus_dmamap_load_mbuf_sg(sc->are_cdata.are_tx_tag,
+		    txd->tx_dmamap, *m_head, txsegs, &nsegs, BUS_DMA_NOWAIT);
+		if (error != 0) {
+			m_freem(*m_head);
+			*m_head = NULL;
+			return (error);
+		}
+
 	} else if (error != 0)
 		return (error);
 	if (nsegs == 0) {
@@ -729,13 +802,12 @@ are_encap(struct are_softc *sc, struct m
 	for (i = 0; i < nsegs; i++) {
 		desc = &sc->are_rdata.are_tx_ring[prod];
 		desc->are_stat = ADSTAT_OWN;
-		desc->are_devcs = ARE_DMASIZE(txsegs[i].ds_len) | ADCTL_CH;
-		if (i == 0)
-			desc->are_devcs |= ADCTL_Tx_FS;
+		desc->are_devcs = ARE_DMASIZE(txsegs[i].ds_len);
 		desc->are_addr = txsegs[i].ds_addr;
 		/* link with previous descriptor */
-		if (prev_desc)
-			prev_desc->are_link = ARE_TX_RING_ADDR(sc, prod);
+		/* end of descriptor */
+		if (prod == ARE_TX_RING_CNT - 1)
+			desc->are_devcs |= ADCTL_ER;
 
 		sc->are_cdata.are_tx_cnt++;
 		prev_desc = desc;
@@ -761,16 +833,16 @@ are_encap(struct are_softc *sc, struct m
 	/* Start transmitting */
 	/* Check if new list is queued in NDPTR */
 	txstat = (CSR_READ_4(sc, CSR_STATUS) >> 20) & 7;
-	if (txstat == 0 || txstat == 6) {
-		/* Transmit Process Stat is stop or suspended */
-		CSR_WRITE_4(sc, CSR_TXPOLL, TXPOLL_TPD);
+	if (startcount == 0 && (txstat == 0 || txstat == 6)) {
+		desc = &sc->are_rdata.are_tx_ring[si];
+		desc->are_devcs |= ADCTL_Tx_FS;
 	}
 	else {
 		link_addr = ARE_TX_RING_ADDR(sc, si);
 		/* Get previous descriptor */
 		si = (si + ARE_TX_RING_CNT - 1) % ARE_TX_RING_CNT;
 		desc = &sc->are_rdata.are_tx_ring[si];
-		desc->are_link = link_addr;
+		desc->are_devcs &= ~(ADCTL_Tx_IC | ADCTL_Tx_LS);
 	}
 
 	return (0);
@@ -782,6 +854,7 @@ are_start_locked(struct ifnet *ifp)
 	struct are_softc		*sc;
 	struct mbuf		*m_head;
 	int			enq;
+	int			txstat;
 
 	sc = ifp->if_softc;
 
@@ -816,6 +889,14 @@ are_start_locked(struct ifnet *ifp)
 		 */
 		ETHER_BPF_MTAP(ifp, m_head);
 	}
+
+	if (enq > 0) { 
+		txstat = (CSR_READ_4(sc, CSR_STATUS) >> 20) & 7;
+		if (txstat == 0 || txstat == 6) {
+			/* Transmit Process Stat is stop or suspended */
+			CSR_WRITE_4(sc, CSR_TXPOLL, TXPOLL_TPD);
+		}
+	}
 }
 
 static void

Modified: head/sys/mips/atheros/ar531x/if_arereg.h
==============================================================================
--- head/sys/mips/atheros/ar531x/if_arereg.h	Sat May  6 06:01:17 2017	(r317867)
+++ head/sys/mips/atheros/ar531x/if_arereg.h	Sat May  6 06:06:11 2017	(r317868)
@@ -44,6 +44,8 @@ struct are_desc {
 #define	ARE_TX_RING_CNT		128
 #define	ARE_TX_RING_SIZE		sizeof(struct are_desc) * ARE_TX_RING_CNT
 #define	ARE_RX_RING_SIZE		sizeof(struct are_desc) * ARE_RX_RING_CNT
+
+#define	ARE_MIN_FRAMELEN		60
 #define	ARE_RING_ALIGN		sizeof(struct are_desc)
 #define	ARE_RX_ALIGN		sizeof(uint32_t)
 #define	ARE_MAXFRAGS		8


More information about the svn-src-head mailing list