From owner-svn-src-stable-7@FreeBSD.ORG Tue Mar 23 22:14:05 2010 Return-Path: Delivered-To: svn-src-stable-7@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id A2F591065688; Tue, 23 Mar 2010 22:14:05 +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 90BA58FC19; Tue, 23 Mar 2010 22:14:05 +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 o2NME5KQ003436; Tue, 23 Mar 2010 22:14:05 GMT (envelope-from yongari@svn.freebsd.org) Received: (from yongari@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id o2NME5Vr003434; Tue, 23 Mar 2010 22:14:05 GMT (envelope-from yongari@svn.freebsd.org) Message-Id: <201003232214.o2NME5Vr003434@svn.freebsd.org> From: Pyun YongHyeon Date: Tue, 23 Mar 2010 22:14:05 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-7@freebsd.org X-SVN-Group: stable-7 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r205548 - stable/7/sys/dev/bce X-BeenThere: svn-src-stable-7@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for only the 7-stable src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 23 Mar 2010 22:14:05 -0000 Author: yongari Date: Tue Mar 23 22:14:05 2010 New Revision: 205548 URL: http://svn.freebsd.org/changeset/base/205548 Log: MFC r204373-204374: r204373: Move TSO setup to new function bce_tso_setup(). Also remove VLAN parsing code in TSO path as the controller requires VLAN hardware tagging to make TSO work over VLANs. While parsing the mbuf in TSO patch, always perform check for writable mbuf as bce(4) have to reset IP length and IP checksum field of IP header and make sure to ensure contiguous buffer before accessing IP/TCP headers. While I'm here replace magic number 40 to more readable sizeof(struct ip) + sizeof(struct tcphdr). r204374: Add TSO support on VLANs. bce(4) controllers require VLAN hardware tagging to make TSO work on VLANs so explicitly disable TSO on VLAN if VLAN hardware tagging is disabled. Modified: stable/7/sys/dev/bce/if_bce.c Directory Properties: stable/7/sys/ (props changed) stable/7/sys/cddl/contrib/opensolaris/ (props changed) stable/7/sys/contrib/dev/acpica/ (props changed) stable/7/sys/contrib/pf/ (props changed) Modified: stable/7/sys/dev/bce/if_bce.c ============================================================================== --- stable/7/sys/dev/bce/if_bce.c Tue Mar 23 22:11:39 2010 (r205547) +++ stable/7/sys/dev/bce/if_bce.c Tue Mar 23 22:14:05 2010 (r205548) @@ -403,6 +403,7 @@ static void bce_fill_pg_chain (struct b static void bce_free_pg_chain (struct bce_softc *); #endif +static struct mbuf *bce_tso_setup (struct bce_softc *, struct mbuf **, u16 *); static int bce_tx_encap (struct bce_softc *, struct mbuf **); static void bce_start_locked (struct ifnet *); static void bce_start (struct ifnet *); @@ -1057,7 +1058,8 @@ bce_attach(device_t dev) if (bce_tso_enable) { ifp->if_hwassist = BCE_IF_HWASSIST | CSUM_TSO; - ifp->if_capabilities = BCE_IF_CAPABILITIES | IFCAP_TSO4; + ifp->if_capabilities = BCE_IF_CAPABILITIES | IFCAP_TSO4 | + IFCAP_VLAN_HWTSO; } else { ifp->if_hwassist = BCE_IF_HWASSIST; ifp->if_capabilities = BCE_IF_CAPABILITIES; @@ -6585,6 +6587,110 @@ bce_init(void *xsc) } +static struct mbuf * +bce_tso_setup(struct bce_softc *sc, struct mbuf **m_head, u16 *flags) +{ + struct mbuf *m; + struct ether_header *eh; + struct ip *ip; + struct tcphdr *th; + u16 etype; + int hdr_len, ip_hlen = 0, tcp_hlen = 0, ip_len = 0; + + DBRUN(sc->requested_tso_frames++); + /* Controller requires to monify mbuf chains. */ + if (M_WRITABLE(*m_head) == 0) { + m = m_dup(*m_head, M_DONTWAIT); + m_freem(*m_head); + if (m == NULL) { + sc->mbuf_alloc_failed_count++; + *m_head = NULL; + return (NULL); + } + *m_head = m; + } + /* + * For TSO the controller needs two pieces of info, + * the MSS and the IP+TCP options length. + */ + m = m_pullup(*m_head, sizeof(struct ether_header) + sizeof(struct ip)); + if (m == NULL) { + *m_head = NULL; + return (NULL); + } + eh = mtod(m, struct ether_header *); + etype = ntohs(eh->ether_type); + + /* Check for supported TSO Ethernet types (only IPv4 for now) */ + switch (etype) { + case ETHERTYPE_IP: + ip = (struct ip *)(m->m_data + sizeof(struct ether_header)); + /* TSO only supported for TCP protocol. */ + if (ip->ip_p != IPPROTO_TCP) { + BCE_PRINTF("%s(%d): TSO enabled for non-TCP frame!.\n", + __FILE__, __LINE__); + m_freem(*m_head); + *m_head = NULL; + return (NULL); + } + + /* Get IP header length in bytes (min 20) */ + ip_hlen = ip->ip_hl << 2; + m = m_pullup(*m_head, sizeof(struct ether_header) + ip_hlen + + sizeof(struct tcphdr)); + if (m == NULL) { + *m_head = NULL; + return (NULL); + } + + /* Get the TCP header length in bytes (min 20) */ + th = (struct tcphdr *)((caddr_t)ip + ip_hlen); + tcp_hlen = (th->th_off << 2); + + /* Make sure all IP/TCP options live in the same buffer. */ + m = m_pullup(*m_head, sizeof(struct ether_header)+ ip_hlen + + tcp_hlen); + if (m == NULL) { + *m_head = NULL; + return (NULL); + } + + /* IP header length and checksum will be calc'd by hardware */ + ip_len = ip->ip_len; + ip->ip_len = 0; + ip->ip_sum = 0; + break; + case ETHERTYPE_IPV6: + BCE_PRINTF("%s(%d): TSO over IPv6 not supported!.\n", + __FILE__, __LINE__); + m_freem(*m_head); + *m_head = NULL; + return (NULL); + /* NOT REACHED */ + default: + BCE_PRINTF("%s(%d): TSO enabled for unsupported protocol!.\n", + __FILE__, __LINE__); + m_freem(*m_head); + *m_head = NULL; + return (NULL); + } + + hdr_len = sizeof(struct ether_header) + ip_hlen + tcp_hlen; + + DBPRINT(sc, BCE_EXTREME_SEND, "%s(): hdr_len = %d, e_hlen = %d, " + "ip_hlen = %d, tcp_hlen = %d, ip_len = %d\n", + __FUNCTION__, hdr_len, sizeof(struct ether_header), ip_hlen, + tcp_hlen, ip_len); + + /* Set the LSO flag in the TX BD */ + *flags |= TX_BD_FLAGS_SW_LSO; + /* Set the length of IP + TCP options (in 32 bit words) */ + *flags |= (((ip_hlen + tcp_hlen - sizeof(struct ip) - + sizeof(struct tcphdr)) >> 2) << 8); + return (*m_head); +} + + /****************************************************************************/ /* Encapsultes an mbuf cluster into the tx_bd chain structure and makes the */ /* memory visible to the controller. */ @@ -6601,12 +6707,8 @@ bce_tx_encap(struct bce_softc *sc, struc bus_dmamap_t map; struct tx_bd *txbd = NULL; struct mbuf *m0; - struct ether_vlan_header *eh; - struct ip *ip; - struct tcphdr *th; - u16 prod, chain_prod, etype, mss = 0, vlan_tag = 0, flags = 0; + u16 prod, chain_prod, mss = 0, vlan_tag = 0, flags = 0; u32 prod_bseq; - int hdr_len = 0, e_hlen = 0, ip_hlen = 0, tcp_hlen = 0, ip_len = 0; #ifdef BCE_DEBUG u16 debug_prod; @@ -6623,72 +6725,16 @@ bce_tx_encap(struct bce_softc *sc, struc /* Transfer any checksum offload flags to the bd. */ m0 = *m_head; if (m0->m_pkthdr.csum_flags) { - if (m0->m_pkthdr.csum_flags & CSUM_IP) - flags |= TX_BD_FLAGS_IP_CKSUM; - if (m0->m_pkthdr.csum_flags & (CSUM_TCP | CSUM_UDP)) - flags |= TX_BD_FLAGS_TCP_UDP_CKSUM; if (m0->m_pkthdr.csum_flags & CSUM_TSO) { - /* For TSO the controller needs two pieces of info, */ - /* the MSS and the IP+TCP options length. */ + m0 = bce_tso_setup(sc, m_head, &flags); + if (m0 == NULL) + goto bce_tx_encap_exit; mss = htole16(m0->m_pkthdr.tso_segsz); - - /* Map the header and find the Ethernet type & header length */ - eh = mtod(m0, struct ether_vlan_header *); - if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) { - etype = ntohs(eh->evl_proto); - e_hlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; - } else { - etype = ntohs(eh->evl_encap_proto); - e_hlen = ETHER_HDR_LEN; - } - - /* Check for supported TSO Ethernet types (only IPv4 for now) */ - switch (etype) { - case ETHERTYPE_IP: - ip = (struct ip *)(m0->m_data + e_hlen); - - /* TSO only supported for TCP protocol */ - if (ip->ip_p != IPPROTO_TCP) { - BCE_PRINTF("%s(%d): TSO enabled for non-TCP frame!.\n", - __FILE__, __LINE__); - goto bce_tx_encap_skip_tso; - } - - /* Get IP header length in bytes (min 20) */ - ip_hlen = ip->ip_hl << 2; - - /* Get the TCP header length in bytes (min 20) */ - th = (struct tcphdr *)((caddr_t)ip + ip_hlen); - tcp_hlen = (th->th_off << 2); - - /* IP header length and checksum will be calc'd by hardware */ - ip_len = ip->ip_len; - ip->ip_len = 0; - ip->ip_sum = 0; - break; - case ETHERTYPE_IPV6: - BCE_PRINTF("%s(%d): TSO over IPv6 not supported!.\n", - __FILE__, __LINE__); - goto bce_tx_encap_skip_tso; - default: - BCE_PRINTF("%s(%d): TSO enabled for unsupported protocol!.\n", - __FILE__, __LINE__); - goto bce_tx_encap_skip_tso; - } - - hdr_len = e_hlen + ip_hlen + tcp_hlen; - - DBPRINT(sc, BCE_EXTREME_SEND, - "%s(): hdr_len = %d, e_hlen = %d, ip_hlen = %d, tcp_hlen = %d, ip_len = %d\n", - __FUNCTION__, hdr_len, e_hlen, ip_hlen, tcp_hlen, ip_len); - - /* Set the LSO flag in the TX BD */ - flags |= TX_BD_FLAGS_SW_LSO; - /* Set the length of IP + TCP options (in 32 bit words) */ - flags |= (((ip_hlen + tcp_hlen - 40) >> 2) << 8); - -bce_tx_encap_skip_tso: - DBRUN(sc->requested_tso_frames++); + } else { + if (m0->m_pkthdr.csum_flags & CSUM_IP) + flags |= TX_BD_FLAGS_IP_CKSUM; + if (m0->m_pkthdr.csum_flags & (CSUM_TCP | CSUM_UDP)) + flags |= TX_BD_FLAGS_TCP_UDP_CKSUM; } } @@ -7131,6 +7177,9 @@ bce_ioctl(struct ifnet *ifp, u_long comm ifp->if_capabilities & IFCAP_VLAN_HWCSUM) ifp->if_capenable ^= IFCAP_VLAN_HWCSUM; + if ((mask & IFCAP_VLAN_HWTSO) != 0 && + (ifp->if_capabilities & IFCAP_VLAN_HWTSO) != 0) + ifp->if_capenable ^= IFCAP_VLAN_HWTSO; /* * Don't actually disable VLAN tag stripping as * management firmware (ASF/IPMI/UMP) requires the @@ -7139,8 +7188,12 @@ bce_ioctl(struct ifnet *ifp, u_long comm * appending stripped VLAN tag. */ if ((mask & IFCAP_VLAN_HWTAGGING) != 0 && - (ifp->if_capabilities & IFCAP_VLAN_HWTAGGING)) + (ifp->if_capabilities & IFCAP_VLAN_HWTAGGING)) { ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; + if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) + == 0) + ifp->if_capenable &= ~IFCAP_VLAN_HWTSO; + } VLAN_CAPABILITIES(ifp); break; default: