From owner-svn-src-all@FreeBSD.ORG Wed Feb 13 00:47:48 2013 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.FreeBSD.org [8.8.178.115]) by hub.freebsd.org (Postfix) with ESMTP id 1C2D78B4; Wed, 13 Feb 2013 00:47:48 +0000 (UTC) (envelope-from yongari@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) by mx1.freebsd.org (Postfix) with ESMTP id 0DA4CE74; Wed, 13 Feb 2013 00:47:48 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.5/8.14.5) with ESMTP id r1D0lla4050133; Wed, 13 Feb 2013 00:47:47 GMT (envelope-from yongari@svn.freebsd.org) Received: (from yongari@localhost) by svn.freebsd.org (8.14.5/8.14.5/Submit) id r1D0llvh050129; Wed, 13 Feb 2013 00:47:47 GMT (envelope-from yongari@svn.freebsd.org) Message-Id: <201302130047.r1D0llvh050129@svn.freebsd.org> From: Pyun YongHyeon Date: Wed, 13 Feb 2013 00:47:47 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org Subject: svn commit: r246725 - stable/8/sys/dev/age X-SVN-Group: stable-8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 13 Feb 2013 00:47:48 -0000 Author: yongari Date: Wed Feb 13 00:47:47 2013 New Revision: 246725 URL: http://svnweb.freebsd.org/changeset/base/246725 Log: MFC r246341: Rework jumbo frame handling. QAC confirmed that the controller requires 8 bytes alignment on RX buffer. Given that non-jumbo frame works on any alignments I guess this DMA limitation for RX buffer could be jumbo frame specific one. Also I'm not sure whether this DMA limitation is related with 64bit DMA. Previously age(4) disabled 64bit DMA addressing due to silent data corruption. So we may need more testing on re-enabling 64bit DMA in future. While I'm here, change mbuf chaining algorithm to use fixed sized buffer and force software checksum if controller reports length error. According to QAC, RFD is not updated at all for jumbo frame so it works just like alc(4) controllers. This change also added alignment fixup for strict alignment architectures. Because I'm not aware of any non-x86 machines that use age(4) controllers it's just for completeness at this moment. Wit this change, jumbo frame should work with age(4). Modified: stable/8/sys/dev/age/if_age.c stable/8/sys/dev/age/if_agevar.h Directory Properties: stable/8/sys/ (props changed) stable/8/sys/dev/ (props changed) stable/8/sys/dev/age/ (props changed) Modified: stable/8/sys/dev/age/if_age.c ============================================================================== --- stable/8/sys/dev/age/if_age.c Wed Feb 13 00:46:41 2013 (r246724) +++ stable/8/sys/dev/age/if_age.c Wed Feb 13 00:47:47 2013 (r246725) @@ -142,6 +142,9 @@ static int age_init_rx_ring(struct age_s static void age_init_rr_ring(struct age_softc *); static void age_init_cmb_block(struct age_softc *); static void age_init_smb_block(struct age_softc *); +#ifndef __NO_STRICT_ALIGNMENT +static struct mbuf *age_fixup_rx(struct ifnet *, struct mbuf *); +#endif static int age_newbuf(struct age_softc *, struct age_rxdesc *); static void age_rxvlan(struct age_softc *); static void age_rxfilter(struct age_softc *); @@ -1133,7 +1136,7 @@ again: /* Create tag for Rx buffers. */ error = bus_dma_tag_create( sc->age_cdata.age_buffer_tag, /* parent */ - 1, 0, /* alignment, boundary */ + AGE_RX_BUF_ALIGN, 0, /* alignment, boundary */ BUS_SPACE_MAXADDR, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg */ @@ -2268,16 +2271,53 @@ age_txintr(struct age_softc *sc, int tpd } } +#ifndef __NO_STRICT_ALIGNMENT +static struct mbuf * +age_fixup_rx(struct ifnet *ifp, struct mbuf *m) +{ + struct mbuf *n; + int i; + uint16_t *src, *dst; + + src = mtod(m, uint16_t *); + dst = src - 3; + + if (m->m_next == NULL) { + for (i = 0; i < (m->m_len / sizeof(uint16_t) + 1); i++) + *dst++ = *src++; + m->m_data -= 6; + return (m); + } + /* + * Append a new mbuf to received mbuf chain and copy ethernet + * header from the mbuf chain. This can save lots of CPU + * cycles for jumbo frame. + */ + MGETHDR(n, M_NOWAIT, MT_DATA); + if (n == NULL) { + ifp->if_iqdrops++; + m_freem(m); + return (NULL); + } + bcopy(m->m_data, n->m_data, ETHER_HDR_LEN); + m->m_data += ETHER_HDR_LEN; + m->m_len -= ETHER_HDR_LEN; + n->m_len = ETHER_HDR_LEN; + M_MOVE_PKTHDR(n, m); + n->m_next = m; + return (n); +} +#endif + /* Receive a frame. */ static void age_rxeof(struct age_softc *sc, struct rx_rdesc *rxrd) { struct age_rxdesc *rxd; - struct rx_desc *desc; struct ifnet *ifp; struct mbuf *mp, *m; uint32_t status, index, vtag; - int count, nsegs, pktlen; + int count, nsegs; int rx_cons; AGE_LOCK_ASSERT(sc); @@ -2289,9 +2329,7 @@ age_rxeof(struct age_softc *sc, struct r nsegs = AGE_RX_NSEGS(index); sc->age_cdata.age_rxlen = AGE_RX_BYTES(le32toh(rxrd->len)); - if ((status & AGE_RRD_ERROR) != 0 && - (status & (AGE_RRD_CRC | AGE_RRD_CODE | AGE_RRD_DRIBBLE | - AGE_RRD_RUNT | AGE_RRD_OFLOW | AGE_RRD_TRUNC)) != 0) { + if ((status & (AGE_RRD_ERROR | AGE_RRD_LENGTH_NOK)) != 0) { /* * We want to pass the following frames to upper * layer regardless of error status of Rx return @@ -2301,33 +2339,31 @@ age_rxeof(struct age_softc *sc, struct r * o frame length and protocol specific length * does not match. */ - sc->age_cdata.age_rx_cons += nsegs; - sc->age_cdata.age_rx_cons %= AGE_RX_RING_CNT; - return; + status |= AGE_RRD_IPCSUM_NOK | AGE_RRD_TCP_UDPCSUM_NOK; + if ((status & (AGE_RRD_CRC | AGE_RRD_CODE | AGE_RRD_DRIBBLE | + AGE_RRD_RUNT | AGE_RRD_OFLOW | AGE_RRD_TRUNC)) != 0) + return; } - pktlen = 0; for (count = 0; count < nsegs; count++, AGE_DESC_INC(rx_cons, AGE_RX_RING_CNT)) { rxd = &sc->age_cdata.age_rxdesc[rx_cons]; mp = rxd->rx_m; - desc = rxd->rx_desc; /* Add a new receive buffer to the ring. */ if (age_newbuf(sc, rxd) != 0) { ifp->if_iqdrops++; /* Reuse Rx buffers. */ - if (sc->age_cdata.age_rxhead != NULL) { + if (sc->age_cdata.age_rxhead != NULL) m_freem(sc->age_cdata.age_rxhead); - AGE_RXCHAIN_RESET(sc); - } break; } - /* The length of the first mbuf is computed last. */ - if (count != 0) { - mp->m_len = AGE_RX_BYTES(le32toh(desc->len)); - pktlen += mp->m_len; - } + /* + * Assume we've received a full sized frame. + * Actual size is fixed when we encounter the end of + * multi-segmented frame. + */ + mp->m_len = AGE_RX_BUF_SIZE; /* Chain received mbufs. */ if (sc->age_cdata.age_rxhead == NULL) { @@ -2342,14 +2378,20 @@ age_rxeof(struct age_softc *sc, struct r } if (count == nsegs - 1) { + /* Last desc. for this frame. */ + m = sc->age_cdata.age_rxhead; + m->m_flags |= M_PKTHDR; /* * It seems that L1 controller has no way * to tell hardware to strip CRC bytes. */ - sc->age_cdata.age_rxlen -= ETHER_CRC_LEN; + m->m_pkthdr.len = sc->age_cdata.age_rxlen - + ETHER_CRC_LEN; if (nsegs > 1) { + /* Set last mbuf size. */ + mp->m_len = sc->age_cdata.age_rxlen - + ((nsegs - 1) * AGE_RX_BUF_SIZE); /* Remove the CRC bytes in chained mbufs. */ - pktlen -= ETHER_CRC_LEN; if (mp->m_len <= ETHER_CRC_LEN) { sc->age_cdata.age_rxtail = sc->age_cdata.age_rxprev_tail; @@ -2360,15 +2402,9 @@ age_rxeof(struct age_softc *sc, struct r } else { mp->m_len -= ETHER_CRC_LEN; } - } - - m = sc->age_cdata.age_rxhead; - m->m_flags |= M_PKTHDR; + } else + m->m_len = m->m_pkthdr.len; m->m_pkthdr.rcvif = ifp; - m->m_pkthdr.len = sc->age_cdata.age_rxlen; - /* Set the first mbuf length. */ - m->m_len = sc->age_cdata.age_rxlen - pktlen; - /* * Set checksum information. * It seems that L1 controller can compute partial @@ -2383,9 +2419,9 @@ age_rxeof(struct age_softc *sc, struct r */ if ((ifp->if_capenable & IFCAP_RXCSUM) != 0 && (status & AGE_RRD_IPV4) != 0) { - m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED; if ((status & AGE_RRD_IPCSUM_NOK) == 0) - m->m_pkthdr.csum_flags |= CSUM_IP_VALID; + m->m_pkthdr.csum_flags |= + CSUM_IP_CHECKED | CSUM_IP_VALID; if ((status & (AGE_RRD_TCP | AGE_RRD_UDP)) && (status & AGE_RRD_TCP_UDPCSUM_NOK) == 0) { m->m_pkthdr.csum_flags |= @@ -2406,22 +2442,21 @@ age_rxeof(struct age_softc *sc, struct r m->m_pkthdr.ether_vtag = AGE_RX_VLAN_TAG(vtag); m->m_flags |= M_VLANTAG; } - +#ifndef __NO_STRICT_ALIGNMENT + m = age_fixup_rx(ifp, m); + if (m != NULL) +#endif + { /* Pass it on. */ AGE_UNLOCK(sc); (*ifp->if_input)(ifp, m); AGE_LOCK(sc); - - /* Reset mbuf chains. */ - AGE_RXCHAIN_RESET(sc); + } } } - if (count != nsegs) { - sc->age_cdata.age_rx_cons += nsegs; - sc->age_cdata.age_rx_cons %= AGE_RX_RING_CNT; - } else - sc->age_cdata.age_rx_cons = rx_cons; + /* Reset mbuf chains. */ + AGE_RXCHAIN_RESET(sc); } static int @@ -2456,16 +2491,16 @@ age_rxintr(struct age_softc *sc, int rr_ * I'm not sure whether this check is really needed. */ pktlen = AGE_RX_BYTES(le32toh(rxrd->len)); - if (nsegs != ((pktlen + (MCLBYTES - ETHER_ALIGN - 1)) / - (MCLBYTES - ETHER_ALIGN))) + if (nsegs != (pktlen + (AGE_RX_BUF_SIZE - 1)) / AGE_RX_BUF_SIZE) break; - prog++; /* Received a frame. */ age_rxeof(sc, rxrd); /* Clear return ring. */ rxrd->index = 0; AGE_DESC_INC(rr_cons, AGE_RR_RING_CNT); + sc->age_cdata.age_rx_cons += nsegs; + sc->age_cdata.age_rx_cons %= AGE_RX_RING_CNT; } if (prog > 0) { @@ -3065,7 +3100,9 @@ age_newbuf(struct age_softc *sc, struct if (m == NULL) return (ENOBUFS); m->m_len = m->m_pkthdr.len = MCLBYTES; - m_adj(m, ETHER_ALIGN); +#ifndef __NO_STRICT_ALIGNMENT + m_adj(m, AGE_RX_BUF_ALIGN); +#endif if (bus_dmamap_load_mbuf_sg(sc->age_cdata.age_rx_tag, sc->age_cdata.age_rx_sparemap, m, segs, &nsegs, 0) != 0) { Modified: stable/8/sys/dev/age/if_agevar.h ============================================================================== --- stable/8/sys/dev/age/if_agevar.h Wed Feb 13 00:46:41 2013 (r246724) +++ stable/8/sys/dev/age/if_agevar.h Wed Feb 13 00:47:47 2013 (r246725) @@ -43,6 +43,12 @@ #define AGE_TSO_MAXSEGSIZE 4096 #define AGE_TSO_MAXSIZE (65535 + sizeof(struct ether_vlan_header)) #define AGE_MAXTXSEGS 32 +#define AGE_RX_BUF_ALIGN 8 +#ifndef __NO_STRICT_ALIGNMENT +#define AGE_RX_BUF_SIZE (MCLBYTES - AGE_RX_BUF_ALIGN) +#else +#define AGE_RX_BUF_SIZE (MCLBYTES) +#endif #define AGE_ADDR_LO(x) ((uint64_t) (x) & 0xFFFFFFFF) #define AGE_ADDR_HI(x) ((uint64_t) (x) >> 32)