From 66deb1c161ab4c6f597f27eebee9e294d8f08dd5 Mon Sep 17 00:00:00 2001 From: Sepherosa Ziehau Date: Sun, 29 Jul 2012 13:29:49 +0800 Subject: [PATCH] bnx: Add TSO support Obtained-from: FreeBSD if_bge.c For TSO header information, ether_tso_pullup() is used instead of making our own wheel. BNX_TSO_DEBUG is added to help testing various TCP parameters tuning --- sys/conf/options | 3 + sys/dev/netif/bge/if_bgereg.h | 5 +- sys/dev/netif/bnx/Makefile | 7 +- sys/dev/netif/bnx/if_bnx.c | 130 +++++++++++++++++++++++++++++----- sys/dev/netif/bnx/if_bnxvar.h | 6 +- 5 files changed, 129 insertions(+), 22 deletions(-) diff --git a/sys/conf/options b/sys/conf/options index a74fd9c5f5..5c0a22ef52 100644 --- a/sys/conf/options +++ b/sys/conf/options @@ -617,6 +617,9 @@ AH_SUPPORT_AR5416 opt_ah.h # bce driver BCE_DEBUG opt_bce.h +# bnx driver +BNX_TSO_DEBUG opt_bnx.h + # ed driver ED_NO_MIIBUS opt_ed.h diff --git a/sys/dev/netif/bge/if_bgereg.h b/sys/dev/netif/bge/if_bgereg.h index f8ce12bea5..175aca1638 100644 --- a/sys/dev/netif/bge/if_bgereg.h +++ b/sys/dev/netif/bge/if_bgereg.h @@ -1474,6 +1474,7 @@ #define BGE_RDMAMODE_FIFO_SIZE_128 0x00020000 #define BGE_RDMAMODE_FIFO_LONG_BURST 0x00030000 #define BGE_RDMAMODE_MULT_DMA_RD_DIS 0x01000000 +#define BGE_RDMAMODE_TSO4_ENABLE 0x08000000 #define BGE_RDMAMODE_H2BNC_VLAN_DET 0x20000000 /* Read DMA status register */ @@ -2068,11 +2069,11 @@ struct bge_tx_bd { uint16_t bge_flags; uint16_t bge_len; uint16_t bge_vlan_tag; - uint16_t bge_rsvd; + uint16_t bge_mss; #else uint16_t bge_len; uint16_t bge_flags; - uint16_t bge_rsvd; + uint16_t bge_mss; uint16_t bge_vlan_tag; #endif }; diff --git a/sys/dev/netif/bnx/Makefile b/sys/dev/netif/bnx/Makefile index 35f2d6fb16..090e1e481f 100644 --- a/sys/dev/netif/bnx/Makefile +++ b/sys/dev/netif/bnx/Makefile @@ -1,11 +1,16 @@ KMOD= if_bnx SRCS= if_bnx.c SRCS+= miibus_if.h device_if.h bus_if.h pci_if.h -SRCS+= opt_polling.h +SRCS+= opt_polling.h opt_bnx.h .ifndef BUILDING_WITH_KERNEL + opt_polling.h: echo '#define DEVICE_POLLING 1' > ${.OBJDIR}/${.TARGET} + +opt_bnx.h: + touch ${.OBJDIR}/${.TARGET} + .endif .include diff --git a/sys/dev/netif/bnx/if_bnx.c b/sys/dev/netif/bnx/if_bnx.c index 18e3b5a378..806c80c652 100644 --- a/sys/dev/netif/bnx/if_bnx.c +++ b/sys/dev/netif/bnx/if_bnx.c @@ -33,7 +33,7 @@ * $FreeBSD: src/sys/dev/bge/if_bge.c,v 1.3.2.39 2005/07/03 03:41:18 silby Exp $ */ - +#include "opt_bnx.h" #include "opt_polling.h" #include @@ -50,6 +50,9 @@ #include #include +#include +#include + #include #include #include @@ -180,6 +183,8 @@ static void bnx_dma_block_free(bus_dma_tag_t, bus_dmamap_t, void *); static struct mbuf * bnx_defrag_shortdma(struct mbuf *); static int bnx_encap(struct bnx_softc *, struct mbuf **, uint32_t *); +static int bnx_setup_tso(struct bnx_softc *, struct mbuf **, + uint16_t *, uint16_t *); static void bnx_reset(struct bnx_softc *); static int bnx_chipinit(struct bnx_softc *); @@ -1629,6 +1634,8 @@ bnx_blockinit(struct bnx_softc *sc) */ val &= ~BGE_RDMAMODE_MULT_DMA_RD_DIS; } + if (sc->bnx_flags & BNX_FLAG_TSO) + val |= BGE_RDMAMODE_TSO4_ENABLE; val |= BGE_RDMAMODE_FIFO_LONG_BURST; CSR_WRITE_4(sc, BGE_RDMA_MODE, val); DELAY(40); @@ -1652,7 +1659,12 @@ bnx_blockinit(struct bnx_softc *sc) CSR_WRITE_4(sc, BGE_SDC_MODE, val); /* Turn on send data initiator state machine */ - CSR_WRITE_4(sc, BGE_SDI_MODE, BGE_SDIMODE_ENABLE); + if (sc->bnx_flags & BNX_FLAG_TSO) { + CSR_WRITE_4(sc, BGE_SDI_MODE, BGE_SDIMODE_ENABLE | + BGE_SDIMODE_HW_LSO_PRE_DMA); + } else { + CSR_WRITE_4(sc, BGE_SDI_MODE, BGE_SDIMODE_ENABLE); + } /* Turn on send BD initiator state machine */ CSR_WRITE_4(sc, BGE_SBDI_MODE, BGE_SBDIMODE_ENABLE); @@ -1743,6 +1755,10 @@ bnx_attach(device_t dev) driver_intr_t *intr_func; uintptr_t mii_priv = 0; u_int intr_flags; +#ifdef BNX_TSO_DEBUG + char desc[32]; + int i; +#endif sc = device_get_softc(dev); sc->bnx_dev = dev; @@ -1841,6 +1857,11 @@ bnx_attach(device_t dev) } sc->bnx_flags |= BNX_FLAG_SHORTDMA; + sc->bnx_flags |= BNX_FLAG_TSO; + if (sc->bnx_asicrev == BGE_ASICREV_BCM5719 && + sc->bnx_chipid == BGE_CHIPID_BCM5719_A0) + sc->bnx_flags &= ~BNX_FLAG_TSO; + if (sc->bnx_asicrev == BGE_ASICREV_BCM5717 || BNX_IS_57765_FAMILY(sc)) { /* @@ -1963,6 +1984,10 @@ bnx_attach(device_t dev) ifp->if_capabilities |= IFCAP_HWCSUM; ifp->if_hwassist = BNX_CSUM_FEATURES; + if (sc->bnx_flags & BNX_FLAG_TSO) { + ifp->if_capabilities |= IFCAP_TSO; + ifp->if_hwassist |= CSUM_TSO; + } ifp->if_capenable = ifp->if_capabilities; /* @@ -2141,6 +2166,15 @@ bnx_attach(device_t dev) sc, 0, bnx_sysctl_tx_coal_bds_int, "I", "Transmit max coalesced BD count during interrupt."); +#ifdef BNX_TSO_DEBUG + for (i = 0; i < BNX_TSO_NSTATS; ++i) { + ksnprintf(desc, sizeof(desc), "tso%d", i + 1); + SYSCTL_ADD_ULONG(&sc->bnx_sysctl_ctx, + SYSCTL_CHILDREN(sc->bnx_sysctl_tree), OID_AUTO, + desc, CTLFLAG_RW, &sc->bnx_tsosegs[i], ""); + } +#endif + /* * Call MI attach routine. */ @@ -2771,13 +2805,31 @@ static int bnx_encap(struct bnx_softc *sc, struct mbuf **m_head0, uint32_t *txidx) { struct bge_tx_bd *d = NULL; - uint16_t csum_flags = 0; + uint16_t csum_flags = 0, vlan_tag = 0, mss = 0; bus_dma_segment_t segs[BNX_NSEG_NEW]; bus_dmamap_t map; int error, maxsegs, nsegs, idx, i; struct mbuf *m_head = *m_head0, *m_new; - if (m_head->m_pkthdr.csum_flags) { + if (m_head->m_pkthdr.csum_flags & CSUM_TSO) { +#ifdef BNX_TSO_DEBUG + int tso_nsegs; +#endif + + error = bnx_setup_tso(sc, m_head0, &mss, &csum_flags); + if (error) + return error; + m_head = *m_head0; + +#ifdef BNX_TSO_DEBUG + tso_nsegs = (m_head->m_pkthdr.len / m_head->m_pkthdr.segsz) - 1; + if (tso_nsegs > (BNX_TSO_NSTATS - 1)) + tso_nsegs = BNX_TSO_NSTATS - 1; + else if (tso_nsegs < 0) + tso_nsegs = 0; + sc->bnx_tsosegs[tso_nsegs]++; +#endif + } else if (m_head->m_pkthdr.csum_flags & BNX_CSUM_FEATURES) { if (m_head->m_pkthdr.csum_flags & CSUM_IP) csum_flags |= BGE_TXBDFLAG_IP_CSUM; if (m_head->m_pkthdr.csum_flags & (CSUM_TCP | CSUM_UDP)) @@ -2787,6 +2839,10 @@ bnx_encap(struct bnx_softc *sc, struct mbuf **m_head0, uint32_t *txidx) else if (m_head->m_flags & M_FRAG) csum_flags |= BGE_TXBDFLAG_IP_FRAG; } + if (m_head->m_flags & M_VLANTAG) { + csum_flags |= BGE_TXBDFLAG_VLAN_TAG; + vlan_tag = m_head->m_pkthdr.ether_vlantag; + } idx = *txidx; map = sc->bnx_cdata.bnx_tx_dmamap[idx]; @@ -2822,7 +2878,8 @@ bnx_encap(struct bnx_softc *sc, struct mbuf **m_head0, uint32_t *txidx) } *m_head0 = m_head = m_new; } - if (sc->bnx_force_defrag && m_head->m_next != NULL) { + if ((m_head->m_pkthdr.csum_flags & CSUM_TSO) == 0 && + sc->bnx_force_defrag && m_head->m_next != NULL) { /* * Forcefully defragment mbuf chain to overcome hardware * limitation which only support a single outstanding @@ -2849,6 +2906,8 @@ bnx_encap(struct bnx_softc *sc, struct mbuf **m_head0, uint32_t *txidx) d->bge_addr.bge_addr_hi = BGE_ADDR_HI(segs[i].ds_addr); d->bge_len = segs[i].ds_len; d->bge_flags = csum_flags; + d->bge_vlan_tag = vlan_tag; + d->bge_mss = mss; if (i == nsegs - 1) break; @@ -2857,15 +2916,6 @@ bnx_encap(struct bnx_softc *sc, struct mbuf **m_head0, uint32_t *txidx) /* Mark the last segment as end of packet... */ d->bge_flags |= BGE_TXBDFLAG_END; - /* Set vlan tag to the first segment of the packet. */ - d = &sc->bnx_ldata.bnx_tx_ring[*txidx]; - if (m_head->m_flags & M_VLANTAG) { - d->bge_flags |= BGE_TXBDFLAG_VLAN_TAG; - d->bge_vlan_tag = m_head->m_pkthdr.ether_vlantag; - } else { - d->bge_vlan_tag = 0; - } - /* * Insure that the map for this transmission is placed at * the array index of the last descriptor in this chain. @@ -3252,10 +3302,17 @@ bnx_ioctl(struct ifnet *ifp, u_long command, caddr_t data, struct ucred *cr) mask = ifr->ifr_reqcap ^ ifp->if_capenable; if (mask & IFCAP_HWCSUM) { ifp->if_capenable ^= (mask & IFCAP_HWCSUM); - if (IFCAP_HWCSUM & ifp->if_capenable) - ifp->if_hwassist = BNX_CSUM_FEATURES; + if (ifp->if_capenable & IFCAP_TXCSUM) + ifp->if_hwassist |= BNX_CSUM_FEATURES; else - ifp->if_hwassist = 0; + ifp->if_hwassist &= ~BNX_CSUM_FEATURES; + } + if (mask & IFCAP_TSO) { + ifp->if_capenable ^= (mask & IFCAP_TSO); + if (ifp->if_capenable & IFCAP_TSO) + ifp->if_hwassist |= CSUM_TSO; + else + ifp->if_hwassist &= ~CSUM_TSO; } break; default: @@ -3467,6 +3524,7 @@ static int bnx_dma_alloc(struct bnx_softc *sc) { struct ifnet *ifp = &sc->arpcom.ac_if; + bus_size_t txmaxsz; int i, error; /* @@ -3533,10 +3591,14 @@ bnx_dma_alloc(struct bnx_softc *sc) /* * Create DMA tag and maps for TX mbufs. */ + if (sc->bnx_flags & BNX_FLAG_TSO) + txmaxsz = IP_MAXPACKET + sizeof(struct ether_vlan_header); + else + txmaxsz = BNX_JUMBO_FRAMELEN; error = bus_dma_tag_create(sc->bnx_cdata.bnx_parent_tag, 1, 0, BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, - BNX_JUMBO_FRAMELEN, BNX_NSEG_NEW, MCLBYTES, + txmaxsz, BNX_NSEG_NEW, PAGE_SIZE, BUS_DMA_ALLOCNOW | BUS_DMA_WAITOK | BUS_DMA_ONEBPAGE, &sc->bnx_cdata.bnx_tx_mtag); @@ -4209,3 +4271,35 @@ bnx_dma_swap_options(struct bnx_softc *sc) } return dma_options; } + +static int +bnx_setup_tso(struct bnx_softc *sc, struct mbuf **mp, + uint16_t *mss0, uint16_t *flags0) +{ + struct mbuf *m; + struct ip *ip; + struct tcphdr *th; + int thoff, iphlen, hoff, hlen; + boolean_t ret; + uint16_t flags, mss; + + ret = ether_tso_pullup(mp, &hoff, &ip, &iphlen, &th, &thoff); + if (!ret) + return ENOBUFS; + + m = *mp; + mss = m->m_pkthdr.segsz; + flags = BGE_TXBDFLAG_CPU_PRE_DMA | BGE_TXBDFLAG_CPU_POST_DMA; + + ip->ip_len = htons(mss + iphlen + thoff); + th->th_sum = 0; + + hlen = (iphlen + thoff) >> 2; + mss |= ((hlen & 0x3) << 14); + flags |= ((hlen & 0xf8) << 7) | ((hlen & 0x4) << 2); + + *mss0 = mss; + *flags0 = flags; + + return 0; +} diff --git a/sys/dev/netif/bnx/if_bnxvar.h b/sys/dev/netif/bnx/if_bnxvar.h index b2c242ddf8..2624e2bd4d 100644 --- a/sys/dev/netif/bnx/if_bnxvar.h +++ b/sys/dev/netif/bnx/if_bnxvar.h @@ -210,6 +210,7 @@ struct bnx_softc { #define BNX_FLAG_57765_PLUS 0x00000040 #define BNX_FLAG_57765_FAMILY 0x00000080 #define BNX_FLAG_STATUSTAG_BUG 0x00000100 +#define BNX_FLAG_TSO 0x00000200 #define BNX_FLAG_NO_EEPROM 0x10000000 #define BNX_FLAG_SHORTDMA 0x40000000 @@ -263,9 +264,12 @@ struct bnx_softc { void (*bnx_link_upd)(struct bnx_softc *, uint32_t); uint32_t bnx_link_chg; + +#define BNX_TSO_NSTATS 45 + u_long bnx_tsosegs[BNX_TSO_NSTATS]; }; -#define BNX_NSEG_NEW 32 +#define BNX_NSEG_NEW 40 #define BNX_NSEG_SPARE 5 #define BNX_NSEG_RSVD 16 -- 2.41.0