Index: if_em.c =================================================================== RCS file: /pool/ncvs/src/sys/dev/em/if_em.c,v retrieving revision 1.122 diff -u -r1.122 if_em.c --- if_em.c 27 Jul 2006 00:43:34 -0000 1.122 +++ if_em.c 29 Jul 2006 06:53:18 -0000 @@ -214,6 +214,7 @@ static void em_txeof(struct em_softc *); static int em_allocate_receive_structures(struct em_softc *); static int em_allocate_transmit_structures(struct em_softc *); +static __inline void em_discard_rxbuf(struct em_softc *, int); static int em_rxeof(struct em_softc *, int); #ifndef __NO_STRICT_ALIGNMENT static int em_fixup_rx(struct em_softc *); @@ -227,7 +228,7 @@ static void em_set_multi(struct em_softc *); static void em_print_hw_stats(struct em_softc *); static void em_update_link_status(struct em_softc *); -static int em_get_buf(int i, struct em_softc *, struct mbuf *); +static int em_get_buf(struct em_softc *, int i); static void em_enable_vlans(struct em_softc *); static void em_disable_vlans(struct em_softc *); static int em_encap(struct em_softc *, struct mbuf **); @@ -2732,46 +2733,49 @@ * **********************************************************************/ static int -em_get_buf(int i, struct em_softc *sc, struct mbuf *mp) +em_get_buf(struct em_softc *sc, int i) { - struct ifnet *ifp = sc->ifp; + struct mbuf *m; bus_dma_segment_t segs[1]; + bus_dmamap_t map; struct em_buffer *rx_buffer; int error, nsegs; - if (mp == NULL) { - mp = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); - if (mp == NULL) { - sc->mbuf_cluster_failed++; - return (ENOBUFS); - } - mp->m_len = mp->m_pkthdr.len = MCLBYTES; - } else { - mp->m_len = mp->m_pkthdr.len = MCLBYTES; - mp->m_data = mp->m_ext.ext_buf; - mp->m_next = NULL; - } - - if (ifp->if_mtu <= ETHERMTU) - m_adj(mp, ETHER_ALIGN); - - rx_buffer = &sc->rx_buffer_area[i]; + m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); + if (m == NULL) { + sc->mbuf_cluster_failed++; + return (ENOBUFS); + } + m->m_len = m->m_pkthdr.len = MCLBYTES; + if (sc->hw.max_frame_size <= (MCLBYTES - ETHER_ALIGN)) + m_adj(m, ETHER_ALIGN); /* * Using memory from the mbuf cluster pool, invoke the * bus_dma machinery to arrange the memory mapping. */ - error = bus_dmamap_load_mbuf_sg(sc->rxtag, rx_buffer->map, - mp, segs, &nsegs, 0); + error = bus_dmamap_load_mbuf_sg(sc->rxtag, sc->rx_sparemap, + m, segs, &nsegs, 0); if (error != 0) { - m_free(mp); + m_free(m); return (error); } /* If nsegs is wrong then the stack is corrupt. */ KASSERT(nsegs == 1, ("Too many segments returned!")); - rx_buffer->m_head = mp; - sc->rx_desc_base[i].buffer_addr = htole64(segs[0].ds_addr); + + rx_buffer = &sc->rx_buffer_area[i]; + if (rx_buffer->m_head != NULL) + bus_dmamap_unload(sc->rxtag, rx_buffer->map); + + map = rx_buffer->map; + rx_buffer->map = sc->rx_sparemap; + sc->rx_sparemap = map; bus_dmamap_sync(sc->rxtag, rx_buffer->map, BUS_DMASYNC_PREREAD); + rx_buffer->m_head = m; + + sc->rx_desc_base[i].buffer_addr = htole64(segs[0].ds_addr); + /* Zero out the receive descriptors status. */ + sc->rx_desc_base[i].status = 0; return (0); } @@ -2818,6 +2822,12 @@ goto fail; } + error = bus_dmamap_create(sc->rxtag, BUS_DMA_NOWAIT, &sc->rx_sparemap); + if (error) { + device_printf(dev, "%s: bus_dmamap_create failed: %d\n", + __func__, error); + goto fail; + } rx_buffer = sc->rx_buffer_area; for (i = 0; i < sc->num_rx_desc; i++, rx_buffer++) { error = bus_dmamap_create(sc->rxtag, BUS_DMA_NOWAIT, @@ -2830,7 +2840,7 @@ } for (i = 0; i < sc->num_rx_desc; i++) { - error = em_get_buf(i, sc, NULL); + error = em_get_buf(sc, i); if (error) goto fail; } @@ -2965,6 +2975,12 @@ INIT_DEBUGOUT("free_receive_structures: begin"); + if (sc->rx_sparemap) { + bus_dmamap_sync(sc->rxtag, sc->rx_sparemap, + BUS_DMASYNC_POSTREAD); + bus_dmamap_destroy(sc->rxtag, sc->rx_sparemap); + sc->rx_sparemap = NULL; + } if (sc->rx_buffer_area != NULL) { rx_buffer = sc->rx_buffer_area; for (i = 0; i < sc->num_rx_desc; i++, rx_buffer++) { @@ -2995,6 +3011,26 @@ } } +static __inline void +em_discard_rxbuf(struct em_softc *sc, int i) +{ + struct mbuf *m; + + /* Reuse loaded DMA map and just updates mbuf chain */ + m = sc->rx_buffer_area[i].m_head; + m->m_len = m->m_pkthdr.len = MCLBYTES; + m->m_data = m->m_ext.ext_buf; + m->m_next = NULL; + if (sc->hw.max_frame_size <= (MCLBYTES - ETHER_ALIGN)) + m_adj(m, ETHER_ALIGN); + if (sc->fmp != NULL) + m_freem(sc->fmp); + sc->fmp = NULL; + sc->lmp = NULL; + /* Zero out the receive descriptors status. */ + sc->rx_desc_base[i].status = 0; +} + /********************************************************************* * * This routine executes in interrupt context. It replenishes @@ -3033,10 +3069,12 @@ struct mbuf *m = NULL; mp = sc->rx_buffer_area[i].m_head; + /* + * Can't defer bus_dmamap_sync(9) because TBI_ACCEPT + * needs to access the last received byte in the mbuf. + */ bus_dmamap_sync(sc->rxtag, sc->rx_buffer_area[i].map, BUS_DMASYNC_POSTREAD); - bus_dmamap_unload(sc->rxtag, - sc->rx_buffer_area[i].map); accept_frame = 1; prev_len_adj = 0; @@ -3075,14 +3113,9 @@ } if (accept_frame) { - if (em_get_buf(i, sc, NULL) == ENOBUFS) { - sc->dropped_pkts++; - em_get_buf(i, sc, mp); - if (sc->fmp != NULL) - m_freem(sc->fmp); - sc->fmp = NULL; - sc->lmp = NULL; - break; + if (em_get_buf(sc, i) != 0) { + ifp->if_iqdrops++; + goto discard; } /* Assign correct length to the current fragment */ @@ -3116,7 +3149,8 @@ em_receive_checksum(sc, current_desc, sc->fmp); #ifndef __NO_STRICT_ALIGNMENT - if (ifp->if_mtu > ETHERMTU && + if (sc->hw.max_frame_size > + (MCLBYTES - ETHER_ALIGN) && em_fixup_rx(sc) != 0) goto skip; #endif @@ -3132,16 +3166,10 @@ sc->lmp = NULL; } } else { - sc->dropped_pkts++; - em_get_buf(i, sc, mp); - if (sc->fmp != NULL) - m_freem(sc->fmp); - sc->fmp = NULL; - sc->lmp = NULL; +discard: + em_discard_rxbuf(sc, i); } - /* Zero out the receive descriptors status. */ - current_desc->status = 0; bus_dmamap_sync(sc->rxdma.dma_tag, sc->rxdma.dma_map, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); Index: if_em.h =================================================================== RCS file: /pool/ncvs/src/sys/dev/em/if_em.h,v retrieving revision 1.45 diff -u -r1.45 if_em.h --- if_em.h 20 Jul 2006 04:18:45 -0000 1.45 +++ if_em.h 29 Jul 2006 06:53:24 -0000 @@ -314,6 +314,7 @@ int rx_process_limit; struct em_buffer *rx_buffer_area; bus_dma_tag_t rxtag; + bus_dmamap_t rx_sparemap; /* First/last mbuf pointers, for collecting multisegment RX packets. */ struct mbuf *fmp;