From owner-freebsd-ppc@FreeBSD.ORG Sun Apr 15 23:48:08 2007 Return-Path: X-Original-To: freebsd-ppc@freebsd.org Delivered-To: freebsd-ppc@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id 756B316A400 for ; Sun, 15 Apr 2007 23:48:08 +0000 (UTC) (envelope-from pyunyh@gmail.com) Received: from wr-out-0506.google.com (wr-out-0506.google.com [64.233.184.232]) by mx1.freebsd.org (Postfix) with ESMTP id 2902C13C487 for ; Sun, 15 Apr 2007 23:48:08 +0000 (UTC) (envelope-from pyunyh@gmail.com) Received: by wr-out-0506.google.com with SMTP id 70so1387872wra for ; Sun, 15 Apr 2007 16:48:07 -0700 (PDT) DKIM-Signature: a=rsa-sha1; c=relaxed/relaxed; d=gmail.com; s=beta; h=domainkey-signature:received:received:received:received:date:from:to:cc:subject:message-id:reply-to:references:mime-version:content-type:content-disposition:in-reply-to:user-agent; b=Icl7CXOsBtYGZ3UyNk7OqH9NXj3s/wPXVsFwMxAfZbgsJyhK74pBj32A2bpPObwpzshjDNlOKjU8kWpeCF/7b7T/iECJ4gPD5wXv0grBmfiWHIggtqKxNsXXnpMSM0nZjS72YO1illon95KnQRZqPQCZ8b7yu1lpwqbtZne2gwc= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=beta; h=received:date:from:to:cc:subject:message-id:reply-to:references:mime-version:content-type:content-disposition:in-reply-to:user-agent; b=HxdaeXbXIPcBJaHQqIKTDYvneonIaAHanxcqmTdrzjJihVg/uzibOuLmjumu/xrFDqnJIwhtvomdAND8zdoNxyiUCR7d4wdpCRM3K9688Z5MpSnvlu0jPFHjmQoaCryxh8/XTL7L9+Op8AxZoGvgeBDXa+d7rD8WvFo2nWO81yI= Received: by 10.65.239.14 with SMTP id q14mr10829752qbr.1176680887136; Sun, 15 Apr 2007 16:48:07 -0700 (PDT) Received: from michelle.cdnetworks.co.kr ( [211.53.35.84]) by mx.google.com with ESMTP id 7sm22494651nzn.2007.04.15.16.48.04; Sun, 15 Apr 2007 16:48:05 -0700 (PDT) Received: from michelle.cdnetworks.co.kr (localhost.cdnetworks.co.kr [127.0.0.1]) by michelle.cdnetworks.co.kr (8.13.5/8.13.5) with ESMTP id l3FNmO9C021528 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Mon, 16 Apr 2007 08:48:24 +0900 (KST) (envelope-from pyunyh@gmail.com) Received: (from yongari@localhost) by michelle.cdnetworks.co.kr (8.13.5/8.13.5/Submit) id l3FNmO59021527; Mon, 16 Apr 2007 08:48:24 +0900 (KST) (envelope-from pyunyh@gmail.com) Date: Mon, 16 Apr 2007 08:48:24 +0900 From: Pyun YongHyeon To: Peter Grehan Message-ID: <20070415234823.GA21416@cdnetworks.co.kr> References: <20070414060841.GB12777@cdnetworks.co.kr> <46229F3F.40903@freebsd.org> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="d6Gm4EdcadzBjdND" Content-Disposition: inline In-Reply-To: <46229F3F.40903@freebsd.org> User-Agent: Mutt/1.4.2.1i Cc: freebsd-ppc@freebsd.org Subject: Re: CFT: gem(4) checksum offload support X-BeenThere: freebsd-ppc@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: pyunyh@gmail.com List-Id: Porting FreeBSD to the PowerPC List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 15 Apr 2007 23:48:08 -0000 --d6Gm4EdcadzBjdND Content-Type: text/plain; charset=us-ascii Content-Disposition: inline On Sun, Apr 15, 2007 at 02:55:11PM -0700, Peter Grehan wrote: > Hi, > > I get a compile error for this on ppc: > > /usr/home/grehan/freebsd/dev_head/src/sys/dev/gem/if_gem.c: In function > `gem_txdma_callback': > /usr/home/grehan/freebsd/dev_head/src/sys/dev/gem/if_gem.c:92: warning: > inlining failed in call to 'gem_txcksum': function body not available > /usr/home/grehan/freebsd/dev_head/src/sys/dev/gem/if_gem.c:505: warning: > called from here > *** Error code 1 > > Removing the __inline's fixed it, as I guess would re-ordering. > Thank you for testing. I guess you've tested it on RELENG_6. Here is updated patch. -- Regards, Pyun YongHyeon --d6Gm4EdcadzBjdND Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="gem.chksum.patch2" Index: if_gem.c =================================================================== RCS file: /home/ncvs/src/sys/dev/gem/if_gem.c,v retrieving revision 1.40 diff -u -r1.40 if_gem.c --- if_gem.c 6 Dec 2006 02:04:25 -0000 1.40 +++ if_gem.c 15 Apr 2007 23:45:59 -0000 @@ -65,6 +65,12 @@ #include #include +#include +#include +#include +#include +#include + #include #include @@ -74,6 +80,7 @@ #include #define TRIES 10000 +#define GEM_CSUM_FEATURES (CSUM_TCP) static void gem_start(struct ifnet *); static void gem_start_locked(struct ifnet *); @@ -82,6 +89,8 @@ static void gem_cddma_callback(void *, bus_dma_segment_t *, int, int); static void gem_txdma_callback(void *, bus_dma_segment_t *, int, bus_size_t, int); +static __inline void gem_txcksum(struct gem_softc *, struct mbuf *, uint64_t *); +static __inline void gem_rxcksum(struct mbuf *, uint64_t); static void gem_tick(void *); static int gem_watchdog(struct gem_softc *); static void gem_init(void *); @@ -264,6 +273,7 @@ device_printf(sc->sc_dev, "%ukB RX FIFO, %ukB TX FIFO\n", sc->sc_rxfifosize / 1024, v / 16); + sc->sc_csum_features = GEM_CSUM_FEATURES; /* Initialize ifnet structure. */ ifp->if_softc = sc; if_initname(ifp, device_get_name(sc->sc_dev), @@ -332,11 +342,12 @@ #endif /* - * Tell the upper layer(s) we support long frames. + * Tell the upper layer(s) we support long frames/checksum offloads. */ ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); - ifp->if_capabilities |= IFCAP_VLAN_MTU; - ifp->if_capenable |= IFCAP_VLAN_MTU; + ifp->if_capabilities |= IFCAP_VLAN_MTU | IFCAP_HWCSUM; + ifp->if_hwassist |= sc->sc_csum_features; + ifp->if_capenable |= IFCAP_VLAN_MTU | IFCAP_HWCSUM; return (0); @@ -440,6 +451,112 @@ GEM_UNLOCK(sc); } +static __inline void +gem_txcksum(struct gem_softc *sc, struct mbuf *m, uint64_t *cflags) +{ + struct ip *ip; + uint64_t offset, offset2; + char *p; + + offset = sizeof(struct ip) + ETHER_HDR_LEN; + for(; m && m->m_len == 0; m = m->m_next) + ; + if (m == NULL || m->m_len < ETHER_HDR_LEN) { + device_printf(sc->sc_dev, "%s: m_len < ETHER_HDR_LEN\n", + __func__); + /* checksum will be corrupted */ + goto sendit; + } + if (m->m_len < ETHER_HDR_LEN + sizeof(uint32_t)) { + if (m->m_len != ETHER_HDR_LEN) { + device_printf(sc->sc_dev, + "%s: m_len != ETHER_HDR_LEN\n", __func__); + /* checksum will be corrupted */ + goto sendit; + } + for(m = m->m_next; m && m->m_len == 0; m = m->m_next) + ; + if (m == NULL) { + /* checksum will be corrupted */ + goto sendit; + } + ip = mtod(m, struct ip *); + } else { + p = mtod(m, uint8_t *); + p += ETHER_HDR_LEN; + ip = (struct ip *)p; + } + offset = (ip->ip_hl << 2) + ETHER_HDR_LEN; + +sendit: + offset2 = m->m_pkthdr.csum_data; + *cflags = offset << GEM_TD_CXSUM_SSHIFT; + *cflags |= ((offset + offset2) << GEM_TD_CXSUM_OSHIFT); + *cflags |= GEM_TD_CXSUM_ENABLE; +} + +static __inline void +gem_rxcksum(struct mbuf *m, uint64_t flags) +{ + struct ether_header *eh; + struct ip *ip; + struct udphdr *uh; + int32_t hlen, len, pktlen; + uint16_t cksum, *opts; + uint32_t temp32; + + pktlen = m->m_pkthdr.len; + if (pktlen < sizeof(struct ether_header) + sizeof(struct ip)) + return; + eh = mtod(m, struct ether_header *); + if (eh->ether_type != htons(ETHERTYPE_IP)) + return; + ip = (struct ip *)(eh + 1); + if (ip->ip_v != IPVERSION) + return; + + hlen = ip->ip_hl << 2; + pktlen -= sizeof(struct ether_header); + if (hlen < sizeof(struct ip)) + return; + if (ntohs(ip->ip_len) < hlen) + return; + if (ntohs(ip->ip_len) != pktlen) + return; + if (ip->ip_off & htons(IP_MF | IP_OFFMASK)) + return; /* can't handle fragmented packet */ + + switch (ip->ip_p) { + case IPPROTO_TCP: + if (pktlen < (hlen + sizeof(struct tcphdr))) + return; + break; + case IPPROTO_UDP: + if (pktlen < (hlen + sizeof(struct udphdr))) + return; + uh = (struct udphdr *)((uint8_t *)ip + hlen); + if (uh->uh_sum == 0) + return; /* no checksum */ + break; + default: + return; + } + + cksum = ~(flags & GEM_RD_CHECKSUM); + /* checksum fixup for IP options */ + len = hlen - sizeof(struct ip); + if (len > 0) { + opts = (uint16_t *)(ip + 1); + for (; len > 0; len -= sizeof(uint16_t), opts++) { + temp32 = cksum - *opts; + temp32 = (temp32 >> 16) + (temp32 & 65535); + cksum = temp32 & 65535; + } + } + m->m_pkthdr.csum_flags |= CSUM_DATA_VALID; + m->m_pkthdr.csum_data = cksum; +} + static void gem_cddma_callback(xsc, segs, nsegs, error) void *xsc; @@ -470,7 +587,7 @@ struct gem_softc *sc = txd->txd_sc; struct gem_txsoft *txs = txd->txd_txs; bus_size_t len = 0; - uint64_t flags = 0; + uint64_t cflags, flags; int seg, nexttx; if (error != 0) @@ -488,6 +605,10 @@ txs->txs_ndescs = nsegs; nexttx = txs->txs_firstdesc; + + flags = cflags = 0; + if ((txd->m->m_pkthdr.csum_flags & sc->sc_csum_features) != 0) + gem_txcksum(sc, txd->m, &cflags); /* * Initialize the transmit descriptors. */ @@ -507,6 +628,7 @@ KASSERT(segs[seg].ds_len < GEM_TD_BUFSIZE, ("gem_txdma_callback: segment size too large!")); flags = segs[seg].ds_len & GEM_TD_BUFSIZE; + flags |= cflags; if (len == 0) { #ifdef GEM_DEBUG CTR2(KTR_GEM, "txdma_cb: start of packet at seg %d, " @@ -954,12 +1076,14 @@ /* Encode Receive Descriptor ring size: four possible values */ v = gem_ringsize(GEM_NRXDESC /*XXX*/); + /* Rx TCP/UDP checksum offset */ + v |= ((ETHER_HDR_LEN + sizeof(struct ip)) << + GEM_RX_CONFIG_CXM_START_SHFT); /* Enable DMA */ bus_space_write_4(t, h, GEM_RX_CONFIG, v|(GEM_THRSH_1024<txs_firstdesc = sc->sc_txnext; + txd.m = m0; error = bus_dmamap_load_mbuf(sc->sc_tdmatag, txs->txs_dmamap, m0, gem_txdma_callback, &txd, BUS_DMA_NOWAIT); if (error != 0) @@ -1454,8 +1579,7 @@ #endif /* - * No errors; receive the packet. Note the Gem - * includes the CRC with every packet. + * No errors; receive the packet. */ len = GEM_RD_BUFLEN(rxstat); @@ -1473,7 +1597,10 @@ m->m_data += 2; /* We're already off by two */ m->m_pkthdr.rcvif = ifp; - m->m_pkthdr.len = m->m_len = len - ETHER_CRC_LEN; + m->m_pkthdr.len = m->m_len = len; + + if ((ifp->if_capenable & IFCAP_RXCSUM) != 0) + gem_rxcksum(m, rxstat); /* Pass it on. */ GEM_UNLOCK(sc); @@ -1876,6 +2003,12 @@ if (ifp->if_drv_flags & IFF_DRV_RUNNING) gem_stop(ifp, 0); } + if ((ifp->if_flags & IFF_LINK0) != 0) + sc->sc_csum_features |= CSUM_UDP; + else + sc->sc_csum_features &= ~CSUM_UDP; + if ((ifp->if_capenable & IFCAP_TXCSUM) != 0) + ifp->if_hwassist = sc->sc_csum_features; sc->sc_ifflags = ifp->if_flags; GEM_UNLOCK(sc); break; @@ -1889,6 +2022,15 @@ case SIOCSIFMEDIA: error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii->mii_media, cmd); break; + case SIOCSIFCAP: + GEM_LOCK(sc); + ifp->if_capenable = ifr->ifr_reqcap; + if ((ifp->if_capenable & IFCAP_TXCSUM) != 0) + ifp->if_hwassist = sc->sc_csum_features; + else + ifp->if_hwassist = 0; + GEM_UNLOCK(sc); + break; default: error = ether_ioctl(ifp, cmd, data); break; Index: if_gemreg.h =================================================================== RCS file: /home/ncvs/src/sys/dev/gem/if_gemreg.h,v retrieving revision 1.3 diff -u -r1.3 if_gemreg.h --- if_gemreg.h 6 Jan 2005 01:42:42 -0000 1.3 +++ if_gemreg.h 15 Apr 2007 23:45:59 -0000 @@ -516,6 +516,10 @@ #define GEM_TD_START_OF_PACKET 0x0000000080000000LL #define GEM_TD_INTERRUPT_ME 0x0000000100000000LL /* Interrupt me now */ #define GEM_TD_NO_CRC 0x0000000200000000LL /* do not insert crc */ + +#define GEM_TD_CXSUM_SSHIFT 15 +#define GEM_TD_CXSUM_OSHIFT 21 + /* * Only need to set GEM_TD_CXSUM_ENABLE, GEM_TD_CXSUM_STUFF, * GEM_TD_CXSUM_START, and GEM_TD_INTERRUPT_ME in 1st descriptor of a group. Index: if_gemvar.h =================================================================== RCS file: /home/ncvs/src/sys/dev/gem/if_gemvar.h,v retrieving revision 1.12 diff -u -r1.12 if_gemvar.h --- if_gemvar.h 6 Dec 2006 02:04:25 -0000 1.12 +++ if_gemvar.h 15 Apr 2007 23:45:59 -0000 @@ -108,6 +108,7 @@ struct gem_txdma { struct gem_softc *txd_sc; struct gem_txsoft *txd_txs; + struct mbuf *m; }; /* @@ -189,6 +190,7 @@ int sc_inited; int sc_debug; int sc_ifflags; + int sc_csum_features; struct mtx sc_mtx; }; --d6Gm4EdcadzBjdND--