From owner-svn-src-head@FreeBSD.ORG Tue Oct 30 07:55:04 2012 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id 699B1A6C; Tue, 30 Oct 2012 07:55:04 +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 472328FC0A; Tue, 30 Oct 2012 07:55:04 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.4/8.14.4) with ESMTP id q9U7t4OY046180; Tue, 30 Oct 2012 07:55:04 GMT (envelope-from yongari@svn.freebsd.org) Received: (from yongari@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id q9U7t4fZ046178; Tue, 30 Oct 2012 07:55:04 GMT (envelope-from yongari@svn.freebsd.org) Message-Id: <201210300755.q9U7t4fZ046178@svn.freebsd.org> From: Pyun YongHyeon Date: Tue, 30 Oct 2012 07:55:04 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r242348 - head/sys/dev/age X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 30 Oct 2012 07:55:04 -0000 Author: yongari Date: Tue Oct 30 07:55:03 2012 New Revision: 242348 URL: http://svn.freebsd.org/changeset/base/242348 Log: TSO engine of L1 requires a separate DMA descriptor for TCP payload. This means driver has to split a TX buffer into two pieces of TX buffers when the TX buffer contains both ethernet/IP/TCP header and partial TCP payload. The controller does not require all header should be in a TX buffer but driver forced it to compute IP/TCP header size/offset which is required parameter to configure DMA descriptor for TSO. While here, slightly reorder DMA descriptor setup to enhance readability and remove unnecessary code for TSO(upper stack never requests TSO when the frame length is less than or equal to MTU). Reported by: Yamagi Burmeister yamagi dot org> Tested by: Yamagi Burmeister yamagi dot org> MFC After: 1 week Modified: head/sys/dev/age/if_age.c Modified: head/sys/dev/age/if_age.c ============================================================================== --- head/sys/dev/age/if_age.c Tue Oct 30 07:51:18 2012 (r242347) +++ head/sys/dev/age/if_age.c Tue Oct 30 07:55:03 2012 (r242348) @@ -1495,7 +1495,7 @@ age_encap(struct age_softc *sc, struct m struct tcphdr *tcp; bus_dma_segment_t txsegs[AGE_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; AGE_LOCK_ASSERT(sc); @@ -1562,8 +1562,12 @@ age_encap(struct age_softc *sc, struct m *m_head = NULL; return (ENOBUFS); } - ip = (struct ip *)(mtod(m, char *) + ip_off); tcp = (struct tcphdr *)(mtod(m, char *) + poff); + m = m_pullup(m, poff + (tcp->th_off << 2)); + if (m == NULL) { + *m_head = NULL; + return (ENOBUFS); + } /* * L1 requires IP/TCP header size and offset as * well as TCP pseudo checksum which complicates @@ -1578,14 +1582,11 @@ age_encap(struct age_softc *sc, struct m * Reset IP checksum and recompute TCP pseudo * checksum as NDIS specification said. */ + ip = (struct ip *)(mtod(m, char *) + ip_off); + tcp = (struct tcphdr *)(mtod(m, char *) + poff); ip->ip_sum = 0; - if (poff + (tcp->th_off << 2) == m->m_pkthdr.len) - tcp->th_sum = in_pseudo(ip->ip_src.s_addr, - ip->ip_dst.s_addr, - htons((tcp->th_off << 2) + IPPROTO_TCP)); - else - tcp->th_sum = in_pseudo(ip->ip_src.s_addr, - ip->ip_dst.s_addr, htons(IPPROTO_TCP)); + tcp->th_sum = in_pseudo(ip->ip_src.s_addr, + ip->ip_dst.s_addr, htons(IPPROTO_TCP)); } *m_head = m; } @@ -1627,23 +1628,48 @@ age_encap(struct age_softc *sc, struct m } m = *m_head; + /* Configure VLAN hardware tag insertion. */ + if ((m->m_flags & M_VLANTAG) != 0) { + vtag = AGE_TX_VLAN_TAG(m->m_pkthdr.ether_vtag); + vtag = ((vtag << AGE_TD_VLAN_SHIFT) & AGE_TD_VLAN_MASK); + cflags |= AGE_TD_INSERT_VLAN_TAG; + } + + desc = NULL; + i = 0; if ((m->m_pkthdr.csum_flags & CSUM_TSO) != 0) { - /* Configure TSO. */ - if (poff + (tcp->th_off << 2) == m->m_pkthdr.len) { - /* Not TSO but IP/TCP checksum offload. */ - cflags |= AGE_TD_IPCSUM | AGE_TD_TCPCSUM; - /* Clear TSO in order not to set AGE_TD_TSO_HDR. */ - m->m_pkthdr.csum_flags &= ~CSUM_TSO; - } else { - /* Request TSO and set MSS. */ - cflags |= AGE_TD_TSO_IPV4; - cflags |= AGE_TD_IPCSUM | AGE_TD_TCPCSUM; - cflags |= ((uint32_t)m->m_pkthdr.tso_segsz << - AGE_TD_TSO_MSS_SHIFT); - } + /* Request TSO and set MSS. */ + cflags |= AGE_TD_TSO_IPV4; + cflags |= AGE_TD_IPCSUM | AGE_TD_TCPCSUM; + cflags |= ((uint32_t)m->m_pkthdr.tso_segsz << + AGE_TD_TSO_MSS_SHIFT); /* Set IP/TCP header size. */ cflags |= ip->ip_hl << AGE_TD_IPHDR_LEN_SHIFT; cflags |= tcp->th_off << AGE_TD_TSO_TCPHDR_LEN_SHIFT; + /* + * L1 requires the first buffer should only hold IP/TCP + * header data. TCP payload should be handled in other + * descriptors. + */ + hdrlen = poff + (tcp->th_off << 2); + desc = &sc->age_rdata.age_tx_ring[prod]; + desc->addr = htole64(txsegs[0].ds_addr); + desc->len = htole32(AGE_TX_BYTES(hdrlen) | vtag); + desc->flags = htole32(cflags); + sc->age_cdata.age_tx_cnt++; + AGE_DESC_INC(prod, AGE_TX_RING_CNT); + if (m->m_len - hdrlen > 0) { + /* Handle remaining payload of the 1st fragment. */ + desc = &sc->age_rdata.age_tx_ring[prod]; + desc->addr = htole64(txsegs[0].ds_addr + hdrlen); + desc->len = htole32(AGE_TX_BYTES(m->m_len - hdrlen) | + vtag); + desc->flags = htole32(cflags); + sc->age_cdata.age_tx_cnt++; + AGE_DESC_INC(prod, AGE_TX_RING_CNT); + } + /* Handle remaining fragments. */ + i = 1; } else if ((m->m_pkthdr.csum_flags & AGE_CSUM_FEATURES) != 0) { /* Configure Tx IP/TCP/UDP checksum offload. */ cflags |= AGE_TD_CSUM; @@ -1657,16 +1683,7 @@ age_encap(struct age_softc *sc, struct m cflags |= ((poff + m->m_pkthdr.csum_data) << AGE_TD_CSUM_XSUMOFFSET_SHIFT); } - - /* Configure VLAN hardware tag insertion. */ - if ((m->m_flags & M_VLANTAG) != 0) { - vtag = AGE_TX_VLAN_TAG(m->m_pkthdr.ether_vtag); - vtag = ((vtag << AGE_TD_VLAN_SHIFT) & AGE_TD_VLAN_MASK); - cflags |= AGE_TD_INSERT_VLAN_TAG; - } - - desc = NULL; - for (i = 0; i < nsegs; i++) { + for (; i < nsegs; i++) { desc = &sc->age_rdata.age_tx_ring[prod]; desc->addr = htole64(txsegs[i].ds_addr); desc->len = htole32(AGE_TX_BYTES(txsegs[i].ds_len) | vtag);