From owner-svn-src-all@FreeBSD.ORG Mon Apr 26 21:08:15 2010 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 5AE631065676; Mon, 26 Apr 2010 21:08:15 +0000 (UTC) (envelope-from yongari@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 49C8F8FC1F; Mon, 26 Apr 2010 21:08:15 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id o3QL8Fv2001060; Mon, 26 Apr 2010 21:08:15 GMT (envelope-from yongari@svn.freebsd.org) Received: (from yongari@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id o3QL8Fws001058; Mon, 26 Apr 2010 21:08:15 GMT (envelope-from yongari@svn.freebsd.org) Message-Id: <201004262108.o3QL8Fws001058@svn.freebsd.org> From: Pyun YongHyeon Date: Mon, 26 Apr 2010 21:08:15 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r207251 - head/sys/dev/ale X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 26 Apr 2010 21:08:15 -0000 Author: yongari Date: Mon Apr 26 21:08:15 2010 New Revision: 207251 URL: http://svn.freebsd.org/changeset/base/207251 Log: 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 darkbeer dot org > MFC after: 1 week Modified: head/sys/dev/ale/if_ale.c Modified: head/sys/dev/ale/if_ale.c ============================================================================== --- head/sys/dev/ale/if_ale.c Mon Apr 26 20:55:03 2010 (r207250) +++ head/sys/dev/ale/if_ale.c Mon Apr 26 21:08:15 2010 (r207251) @@ -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);