svn commit: r207546 - stable/8/sys/dev/ale

Pyun YongHyeon yongari at FreeBSD.org
Mon May 3 01:04:45 UTC 2010


Author: yongari
Date: Mon May  3 01:04:44 2010
New Revision: 207546
URL: http://svn.freebsd.org/changeset/base/207546

Log:
  MFC r207251:
    It seems ale(4) controllers do not like to see TCP payload in the
    first descriptor in TSO case. Otherwise controller can generate bad
    frames during TSO. To address it, make sure to pull up ethernet +
    IP + TCP header with options in first buffer. Also ensure the
    buffer length of the first descriptor for TSO covers entire ethernet
    + IP + TCP with options and setup additional Tx descriptor if the
    first buffer includes TCP payload.
  
    Tested by:	Amar Takhar <verm <> darkbeer dot org >

Modified:
  stable/8/sys/dev/ale/if_ale.c
Directory Properties:
  stable/8/sys/   (props changed)
  stable/8/sys/amd64/include/xen/   (props changed)
  stable/8/sys/cddl/contrib/opensolaris/   (props changed)
  stable/8/sys/contrib/dev/acpica/   (props changed)
  stable/8/sys/contrib/pf/   (props changed)
  stable/8/sys/dev/xen/xenpci/   (props changed)
  stable/8/sys/geom/sched/   (props changed)

Modified: stable/8/sys/dev/ale/if_ale.c
==============================================================================
--- stable/8/sys/dev/ale/if_ale.c	Mon May  3 00:56:26 2010	(r207545)
+++ stable/8/sys/dev/ale/if_ale.c	Mon May  3 01:04:44 2010	(r207546)
@@ -1585,7 +1585,7 @@ ale_encap(struct ale_softc *sc, struct m
 	struct tcphdr *tcp;
 	bus_dma_segment_t txsegs[ALE_MAXTXSEGS];
 	bus_dmamap_t map;
-	uint32_t cflags, ip_off, poff, vtag;
+	uint32_t cflags, hdrlen, ip_off, poff, vtag;
 	int error, i, nsegs, prod, si;
 
 	ALE_LOCK_ASSERT(sc);
@@ -1678,6 +1678,11 @@ ale_encap(struct ale_softc *sc, struct m
 				return (ENOBUFS);
 			}
 			tcp = (struct tcphdr *)(mtod(m, char *) + poff);
+			m = m_pullup(m, poff + (tcp->th_off << 2));
+			if (m == NULL) {
+				*m_head = NULL;
+				return (ENOBUFS);
+			}
 			/*
 			 * AR81xx requires IP/TCP header size and offset as
 			 * well as TCP pseudo checksum which complicates
@@ -1730,7 +1735,7 @@ ale_encap(struct ale_softc *sc, struct m
 	}
 
 	/* Check descriptor overrun. */
-	if (sc->ale_cdata.ale_tx_cnt + nsegs >= ALE_TX_RING_CNT - 2) {
+	if (sc->ale_cdata.ale_tx_cnt + nsegs >= ALE_TX_RING_CNT - 3) {
 		bus_dmamap_unload(sc->ale_cdata.ale_tx_tag, map);
 		return (ENOBUFS);
 	}
@@ -1782,8 +1787,32 @@ ale_encap(struct ale_softc *sc, struct m
 		cflags |= ALE_TD_INSERT_VLAN_TAG;
 	}
 
-	desc = NULL;
-	for (i = 0; i < nsegs; i++) {
+	i = 0;
+	if ((m->m_pkthdr.csum_flags & CSUM_TSO) != 0) {
+		/*
+		 * Make sure the first fragment contains
+		 * only ethernet and IP/TCP header with options.
+		 */
+		hdrlen =  poff + (tcp->th_off << 2);
+		desc = &sc->ale_cdata.ale_tx_ring[prod];
+		desc->addr = htole64(txsegs[i].ds_addr);
+		desc->len = htole32(ALE_TX_BYTES(hdrlen) | vtag);
+		desc->flags = htole32(cflags);
+		sc->ale_cdata.ale_tx_cnt++;
+		ALE_DESC_INC(prod, ALE_TX_RING_CNT);
+		if (m->m_len - hdrlen > 0) {
+			/* Handle remaining payload of the first fragment. */
+			desc = &sc->ale_cdata.ale_tx_ring[prod];
+			desc->addr = htole64(txsegs[i].ds_addr + hdrlen);
+			desc->len = htole32(ALE_TX_BYTES(m->m_len - hdrlen) |
+			    vtag);
+			desc->flags = htole32(cflags);
+			sc->ale_cdata.ale_tx_cnt++;
+			ALE_DESC_INC(prod, ALE_TX_RING_CNT);
+		}
+		i = 1;
+	}
+	for (; i < nsegs; i++) {
 		desc = &sc->ale_cdata.ale_tx_ring[prod];
 		desc->addr = htole64(txsegs[i].ds_addr);
 		desc->len = htole32(ALE_TX_BYTES(txsegs[i].ds_len) | vtag);


More information about the svn-src-stable-8 mailing list