From: Sepherosa Ziehau Date: Thu, 23 Aug 2012 05:27:15 +0000 (+0800) Subject: jme: Add TSO support X-Git-Tag: v3.2.0~284 X-Git-Url: https://gitweb.dragonflybsd.org/dragonfly.git/commitdiff_plain/1bedd927fdbd1e3b274b7948391a777aaa50d100?ds=sidebyside jme: Add TSO support --- diff --git a/sys/dev/netif/jme/if_jme.c b/sys/dev/netif/jme/if_jme.c index 06b43bfef2..4519480a72 100644 --- a/sys/dev/netif/jme/if_jme.c +++ b/sys/dev/netif/jme/if_jme.c @@ -56,7 +56,8 @@ #include #include -#include +#include +#include #include #include @@ -912,6 +913,7 @@ jme_attach(device_t dev) /* JMC250 supports Tx/Rx checksum offload and hardware vlan tagging. */ ifp->if_capabilities = IFCAP_HWCSUM | + IFCAP_TSO | IFCAP_VLAN_MTU | IFCAP_VLAN_HWTAGGING; if (sc->jme_cdata.jme_rx_ring_cnt > JME_NRXRING_MIN) @@ -925,7 +927,8 @@ jme_attach(device_t dev) ifp->if_capenable &= ~IFCAP_TXCSUM; if (ifp->if_capenable & IFCAP_TXCSUM) - ifp->if_hwassist = JME_CSUM_FEATURES; + ifp->if_hwassist |= JME_CSUM_FEATURES; + ifp->if_hwassist |= CSUM_TSO; /* Set up MII bus. */ error = mii_phy_probe(dev, &sc->jme_miibus, @@ -1212,7 +1215,7 @@ jme_dma_alloc(struct jme_softc *sc) BUS_SPACE_MAXADDR, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg */ - JME_JUMBO_FRAMELEN, /* maxsize */ + JME_TSO_MAXSIZE, /* maxsize */ JME_MAXTXSEGS, /* nsegments */ JME_MAXSEGSIZE, /* maxsegsize */ BUS_DMA_ALLOCNOW | BUS_DMA_WAITOK | BUS_DMA_ONEBPAGE,/* flags */ @@ -1528,6 +1531,34 @@ jme_resume(device_t dev) return (0); } +static __inline int +jme_tso_pullup(struct mbuf **mp) +{ + int hoff, iphlen, thoff; + struct mbuf *m; + + m = *mp; + KASSERT(M_WRITABLE(m), ("TSO mbuf not writable")); + + iphlen = m->m_pkthdr.csum_iphlen; + thoff = m->m_pkthdr.csum_thlen; + hoff = m->m_pkthdr.csum_lhlen; + + KASSERT(iphlen > 0, ("invalid ip hlen")); + KASSERT(thoff > 0, ("invalid tcp hlen")); + KASSERT(hoff > 0, ("invalid ether hlen")); + + 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; + } + return 0; +} + static int jme_encap(struct jme_softc *sc, struct mbuf **m_head) { @@ -1537,10 +1568,17 @@ jme_encap(struct jme_softc *sc, struct mbuf **m_head) bus_dma_segment_t txsegs[JME_MAXTXSEGS]; int maxsegs, nsegs; int error, i, prod, symbol_desc; - uint32_t cflags, flag64; + uint32_t cflags, flag64, mss; M_ASSERTPKTHDR((*m_head)); + if ((*m_head)->m_pkthdr.csum_flags & CSUM_TSO) { + /* XXX Is this necessary? */ + error = jme_tso_pullup(m_head); + if (error) + return error; + } + prod = sc->jme_cdata.jme_tx_prod; txd = &sc->jme_cdata.jme_txdesc[prod]; @@ -1553,7 +1591,7 @@ jme_encap(struct jme_softc *sc, struct mbuf **m_head) (JME_TXD_RSVD + symbol_desc); if (maxsegs > JME_MAXTXSEGS) maxsegs = JME_MAXTXSEGS; - KASSERT(maxsegs >= (sc->jme_txd_spare - symbol_desc), + KASSERT(maxsegs >= (JME_TXD_SPARE - symbol_desc), ("not enough segments %d", maxsegs)); error = bus_dmamap_load_mbuf_defrag(sc->jme_cdata.jme_tx_tag, @@ -1567,14 +1605,20 @@ jme_encap(struct jme_softc *sc, struct mbuf **m_head) m = *m_head; cflags = 0; + mss = 0; /* Configure checksum offload. */ - if (m->m_pkthdr.csum_flags & CSUM_IP) - cflags |= JME_TD_IPCSUM; - if (m->m_pkthdr.csum_flags & CSUM_TCP) - cflags |= JME_TD_TCPCSUM; - if (m->m_pkthdr.csum_flags & CSUM_UDP) - cflags |= JME_TD_UDPCSUM; + if (m->m_pkthdr.csum_flags & CSUM_TSO) { + mss = (uint32_t)m->m_pkthdr.tso_segsz << JME_TD_MSS_SHIFT; + cflags |= JME_TD_TSO; + } else if (m->m_pkthdr.csum_flags & JME_CSUM_FEATURES) { + if (m->m_pkthdr.csum_flags & CSUM_IP) + cflags |= JME_TD_IPCSUM; + if (m->m_pkthdr.csum_flags & CSUM_TCP) + cflags |= JME_TD_TCPCSUM; + if (m->m_pkthdr.csum_flags & CSUM_UDP) + cflags |= JME_TD_UDPCSUM; + } /* Configure VLAN. */ if (m->m_flags & M_VLANTAG) { @@ -1593,7 +1637,7 @@ jme_encap(struct jme_softc *sc, struct mbuf **m_head) * is just a symbol TX desc carrying no payload. */ flag64 = JME_TD_64BIT; - desc->buflen = 0; + desc->buflen = htole32(mss); desc->addr_lo = 0; /* No effective TX desc is consumed */ @@ -1607,7 +1651,7 @@ jme_encap(struct jme_softc *sc, struct mbuf **m_head) * the mbuf chain. */ flag64 = 0; - desc->buflen = htole32(txsegs[0].ds_len); + desc->buflen = htole32(mss | txsegs[0].ds_len); desc->addr_lo = htole32(JME_ADDR_LO(txsegs[0].ds_addr)); /* One effective TX desc is consumed */ @@ -1676,7 +1720,7 @@ jme_start(struct ifnet *ifp) * Check number of available TX descs, always * leave JME_TXD_RSVD free TX descs. */ - if (sc->jme_cdata.jme_tx_cnt + sc->jme_txd_spare > + if (sc->jme_cdata.jme_tx_cnt + JME_TXD_SPARE > sc->jme_cdata.jme_tx_desc_cnt - JME_TXD_RSVD) { ifp->if_flags |= IFF_OACTIVE; break; @@ -1777,8 +1821,10 @@ jme_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr) * FIFO size is just 2K. */ if (ifr->ifr_mtu >= JME_TX_FIFO_SIZE) { - ifp->if_capenable &= ~IFCAP_TXCSUM; - ifp->if_hwassist &= ~JME_CSUM_FEATURES; + ifp->if_capenable &= + ~(IFCAP_TXCSUM | IFCAP_TSO); + ifp->if_hwassist &= + ~(JME_CSUM_FEATURES | CSUM_TSO); } ifp->if_mtu = ifr->ifr_mtu; if (ifp->if_flags & IFF_RUNNING) @@ -1818,7 +1864,7 @@ jme_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr) if ((mask & IFCAP_TXCSUM) && ifp->if_mtu < JME_TX_FIFO_SIZE) { ifp->if_capenable ^= IFCAP_TXCSUM; - if (IFCAP_TXCSUM & ifp->if_capenable) + if (ifp->if_capenable & IFCAP_TXCSUM) ifp->if_hwassist |= JME_CSUM_FEATURES; else ifp->if_hwassist &= ~JME_CSUM_FEATURES; @@ -1839,6 +1885,14 @@ jme_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr) jme_set_vlan(sc); } + if ((mask & IFCAP_TSO) && ifp->if_mtu < JME_TX_FIFO_SIZE) { + ifp->if_capenable ^= IFCAP_TSO; + if (ifp->if_capenable & IFCAP_TSO) + ifp->if_hwassist |= CSUM_TSO; + else + ifp->if_hwassist &= ~CSUM_TSO; + } + if (mask & IFCAP_RSS) ifp->if_capenable ^= IFCAP_RSS; break; @@ -2092,10 +2146,11 @@ jme_txeof(struct jme_softc *sc) } sc->jme_cdata.jme_tx_cons = cons; - if (sc->jme_cdata.jme_tx_cnt < JME_MAXTXSEGS + 1) + /* 1 for symbol TX descriptor */ + if (sc->jme_cdata.jme_tx_cnt <= JME_MAXTXSEGS + 1) ifp->if_timer = 0; - if (sc->jme_cdata.jme_tx_cnt + sc->jme_txd_spare <= + if (sc->jme_cdata.jme_tx_cnt + JME_TXD_SPARE <= sc->jme_cdata.jme_tx_desc_cnt - JME_TXD_RSVD) ifp->if_flags &= ~IFF_OACTIVE; } @@ -2515,17 +2570,6 @@ jme_init(void *xsc) */ jme_set_msinum(sc); - sc->jme_txd_spare = - howmany(ifp->if_mtu + sizeof(struct ether_vlan_header), MCLBYTES); - KKASSERT(sc->jme_txd_spare >= 1); - - /* - * If we use 64bit address mode for transmitting, each Tx request - * needs one more symbol descriptor. - */ - if (sc->jme_lowaddr != BUS_SPACE_MAXADDR_32BIT) - sc->jme_txd_spare += 1; - if (JME_ENABLE_HWRSS(sc)) jme_enable_rss(sc); else diff --git a/sys/dev/netif/jme/if_jmevar.h b/sys/dev/netif/jme/if_jmevar.h index 2bc0be35a1..75a100e030 100644 --- a/sys/dev/netif/jme/if_jmevar.h +++ b/sys/dev/netif/jme/if_jmevar.h @@ -64,8 +64,8 @@ #define JME_TX_RING_ALIGN __VM_CACHELINE_SIZE #define JME_RX_RING_ALIGN __VM_CACHELINE_SIZE #define JME_MAXSEGSIZE 4096 -#define JME_TSO_MAXSIZE (65535 + sizeof(struct ether_vlan_header)) -#define JME_MAXTXSEGS 32 +#define JME_TSO_MAXSIZE (IP_MAXPACKET + sizeof(struct ether_vlan_header)) +#define JME_MAXTXSEGS 40 #define JME_RX_BUF_ALIGN sizeof(uint64_t) #define JME_SSB_ALIGN __VM_CACHELINE_SIZE @@ -274,8 +274,6 @@ struct jme_softc { uint32_t jme_txcsr; uint32_t jme_rxcsr; - int jme_txd_spare; - struct sysctl_ctx_list jme_sysctl_ctx; struct sysctl_oid *jme_sysctl_tree; @@ -310,6 +308,8 @@ do { \ #define JME_EEPROM_TIMEOUT 1000 #define JME_TXD_RSVD 1 +/* Large enough to cooperate 64K TSO segment and one spare TX descriptor */ +#define JME_TXD_SPARE 34 #define JME_ENABLE_HWRSS(sc) \ ((sc)->jme_cdata.jme_rx_ring_cnt > JME_NRXRING_MIN)