From eefd160d115faf0e7f93de4da6d8aefcd644b83a Mon Sep 17 00:00:00 2001 From: Sepherosa Ziehau Date: Fri, 10 Aug 2012 16:22:44 +0800 Subject: [PATCH] bce: Add TSO support Obatined-from: FreeBSD With following modification: These chips can handle ip.ip_len and tcphdr.th_sum, if they are setup according to Microsoft LSO specification, so ip.ip_len should not be cleared and tcphdr.th_sum should be left as it is. According-to: bnx2 --- sys/dev/netif/bce/if_bce.c | 81 ++++++++++++++++++++++++++++++++++++----- sys/dev/netif/bce/if_bcereg.h | 10 +++--- 2 files changed, 77 insertions(+), 14 deletions(-) diff --git a/sys/dev/netif/bce/if_bce.c b/sys/dev/netif/bce/if_bce.c index ea252de..b963e1a 100644 --- a/sys/dev/netif/bce/if_bce.c +++ b/sys/dev/netif/bce/if_bce.c @@ -68,6 +68,9 @@ #include #include +#include +#include + #include #include #include @@ -417,6 +420,8 @@ static void bce_free_rx_chain(struct bce_softc *); static void bce_free_tx_chain(struct bce_softc *); static int bce_encap(struct bce_softc *, struct mbuf **); +static int bce_tso_setup(struct bce_softc *, struct mbuf **, + uint16_t *, uint16_t *); static void bce_start(struct ifnet *); static int bce_ioctl(struct ifnet *, u_long, caddr_t, struct ucred *); static void bce_watchdog(struct ifnet *); @@ -952,7 +957,7 @@ bce_attach(device_t dev) ifp->if_poll = bce_poll; #endif ifp->if_mtu = ETHERMTU; - ifp->if_hwassist = BCE_IF_HWASSIST; + ifp->if_hwassist = BCE_CSUM_FEATURES | CSUM_TSO; ifp->if_capabilities = BCE_IF_CAPABILITIES; ifp->if_capenable = ifp->if_capabilities; ifq_set_maxlen(&ifp->if_snd, USABLE_TX_BD(sc)); @@ -2436,8 +2441,8 @@ bce_dma_alloc(struct bce_softc *sc) rc = bus_dma_tag_create(sc->parent_tag, 1, 0, BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, - /* BCE_MAX_JUMBO_ETHER_MTU_VLAN */MCLBYTES, - BCE_MAX_SEGMENTS, MCLBYTES, + IP_MAXPACKET + sizeof(struct ether_vlan_header), + BCE_MAX_SEGMENTS, PAGE_SIZE, BUS_DMA_ALLOCNOW | BUS_DMA_WAITOK | BUS_DMA_ONEBPAGE, &sc->tx_mbuf_tag); @@ -4845,13 +4850,18 @@ bce_encap(struct bce_softc *sc, struct mbuf **m_head) bus_dmamap_t map, tmp_map; struct mbuf *m0 = *m_head; struct tx_bd *txbd = NULL; - uint16_t vlan_tag = 0, flags = 0; + uint16_t vlan_tag = 0, flags = 0, mss = 0; uint16_t chain_prod, chain_prod_start, prod; uint32_t prod_bseq; int i, error, maxsegs, nsegs; /* Transfer any checksum offload flags to the bd. */ - if (m0->m_pkthdr.csum_flags) { + if (m0->m_pkthdr.csum_flags & CSUM_TSO) { + error = bce_tso_setup(sc, m_head, &flags, &mss); + if (error) + return ENOBUFS; + m0 = *m_head; + } else if (m0->m_pkthdr.csum_flags & BCE_CSUM_FEATURES) { if (m0->m_pkthdr.csum_flags & CSUM_IP) flags |= TX_BD_FLAGS_IP_CKSUM; if (m0->m_pkthdr.csum_flags & (CSUM_TCP | CSUM_UDP)) @@ -4901,9 +4911,11 @@ bce_encap(struct bce_softc *sc, struct mbuf **m_head) txbd->tx_bd_haddr_lo = htole32(BCE_ADDR_LO(segs[i].ds_addr)); txbd->tx_bd_haddr_hi = htole32(BCE_ADDR_HI(segs[i].ds_addr)); - txbd->tx_bd_mss_nbytes = htole16(segs[i].ds_len); + txbd->tx_bd_mss_nbytes = htole32(mss << 16) | + htole16(segs[i].ds_len); txbd->tx_bd_vlan_tag = htole16(vlan_tag); txbd->tx_bd_flags = htole16(flags); + prod_bseq += segs[i].ds_len; if (i == 0) txbd->tx_bd_flags |= htole16(TX_BD_FLAGS_START); @@ -5106,10 +5118,17 @@ bce_ioctl(struct ifnet *ifp, u_long command, caddr_t data, struct ucred *cr) if (mask & IFCAP_HWCSUM) { ifp->if_capenable ^= (mask & IFCAP_HWCSUM); - if (IFCAP_HWCSUM & ifp->if_capenable) - ifp->if_hwassist = BCE_IF_HWASSIST; + if (ifp->if_capenable & IFCAP_TXCSUM) + ifp->if_hwassist |= BCE_CSUM_FEATURES; + else + ifp->if_hwassist &= ~BCE_CSUM_FEATURES; + } + if (mask & IFCAP_TSO) { + ifp->if_capenable ^= IFCAP_TSO; + if (ifp->if_capenable & IFCAP_TSO) + ifp->if_hwassist |= CSUM_TSO; else - ifp->if_hwassist = 0; + ifp->if_hwassist &= ~CSUM_TSO; } break; @@ -7913,3 +7932,47 @@ bce_coal_change(struct bce_softc *sc) sc->bce_coalchg_mask = 0; } + +static int +bce_tso_setup(struct bce_softc *sc, struct mbuf **mp, + uint16_t *flags0, uint16_t *mss0) +{ + struct mbuf *m; + uint16_t flags; + int thoff, iphlen, hoff; + + m = *mp; + KASSERT(M_WRITABLE(m), ("TSO mbuf not writable")); + + hoff = m->m_pkthdr.csum_lhlen; + iphlen = m->m_pkthdr.csum_iphlen; + thoff = m->m_pkthdr.csum_thlen; + + KASSERT(hoff >= sizeof(struct ether_header), + ("invalid ether header len %d", hoff)); + KASSERT(iphlen >= sizeof(struct ip), + ("invalid ip header len %d", iphlen)); + KASSERT(thoff >= sizeof(struct tcphdr), + ("invalid tcp header len %d", thoff)); + + if (__predict_false(m->m_len < hoff + iphlen + thoff)) { + m = m_pullup(m, hoff + iphlen + thoff); + if (m == NULL) { + *mp = NULL; + return ENOBUFS; + } + *mp = m; + } + + /* 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 |= (((iphlen + thoff - + sizeof(struct ip) - sizeof(struct tcphdr)) >> 2) << 8); + + *mss0 = htole16(m->m_pkthdr.tso_segsz); + *flags0 = flags; + + return 0; +} diff --git a/sys/dev/netif/bce/if_bcereg.h b/sys/dev/netif/bce/if_bcereg.h index 88d9c6b..cd06cf1 100644 --- a/sys/dev/netif/bce/if_bcereg.h +++ b/sys/dev/netif/bce/if_bcereg.h @@ -5669,7 +5669,7 @@ struct l2_fhdr { #define TOTAL_TX_BD(sc) (TOTAL_TX_BD_PER_PAGE * (sc)->tx_pages) #define USABLE_TX_BD(sc) (USABLE_TX_BD_PER_PAGE * (sc)->tx_pages) #define MAX_TX_BD(sc) (TOTAL_TX_BD((sc)) - 1) -#define BCE_TX_SPARE_SPACE 5 +#define BCE_TX_SPARE_SPACE 33 #define RX_PAGES_DEFAULT 2 #define RX_PAGES_MAX 256 @@ -5800,7 +5800,7 @@ struct fw_info { #define BCE_TX_TIMEOUT 5 -#define BCE_MAX_SEGMENTS 32 +#define BCE_MAX_SEGMENTS 40 #define BCE_DMA_ALIGN 8 #define BCE_DMA_RX_ALIGN 16 #define BCE_DMA_BOUNDARY 0 @@ -5819,16 +5819,16 @@ struct fw_info { * solution later. */ #ifdef BCE_IP_CSUM -#define BCE_IF_HWASSIST (CSUM_IP | CSUM_TCP | CSUM_UDP) +#define BCE_CSUM_FEATURES (CSUM_IP | CSUM_TCP | CSUM_UDP) #else -#define BCE_IF_HWASSIST (CSUM_TCP | CSUM_UDP) +#define BCE_CSUM_FEATURES (CSUM_TCP | CSUM_UDP) #endif /* NOTE: This hardware also can do VLAN csum offload */ #define BCE_IF_CAPABILITIES (IFCAP_VLAN_MTU | \ IFCAP_VLAN_HWTAGGING | \ IFCAP_HWCSUM | \ - IFCAP_JUMBO_MTU) + IFCAP_TSO) #define BCE_MIN_MTU 60 #define BCE_MIN_ETHER_MTU 64 -- 1.7.7.2