--- //depot/vendor/freebsd/src/sys/dev/bfe/if_bfe.c 2006/05/28 20:39:02 +++ //depot/user/jhb/acpipci/dev/bfe/if_bfe.c 2006/12/11 14:32:43 @@ -126,7 +126,6 @@ static void bfe_core_reset (struct bfe_softc *); static void bfe_core_disable (struct bfe_softc *); static int bfe_dma_alloc (device_t); -static void bfe_dma_map_desc (void *, bus_dma_segment_t *, int, int); static void bfe_dma_map (void *, bus_dma_segment_t *, int, int); static void bfe_cam_write (struct bfe_softc *, u_char *, int); @@ -255,7 +254,7 @@ BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, - 1, + BFE_TX_LIST_CNT / 4, BUS_SPACE_MAXSIZE_32BIT, BUS_DMA_ALLOCNOW, NULL, NULL, @@ -518,7 +517,7 @@ int i; for(i = 0; i < BFE_TX_LIST_CNT; i++) { - if(sc->bfe_tx_ring[i].bfe_mbuf != NULL) { + if (sc->bfe_tx_ring[i].bfe_mbuf != NULL) { m_freem(sc->bfe_tx_ring[i].bfe_mbuf); sc->bfe_tx_ring[i].bfe_mbuf = NULL; bus_dmamap_unload(sc->bfe_tag, @@ -567,11 +566,12 @@ static int bfe_list_newbuf(struct bfe_softc *sc, int c, struct mbuf *m) { + bus_dma_segment_t segs[1]; struct bfe_rxheader *rx_header; struct bfe_desc *d; struct bfe_data *r; u_int32_t ctrl; - int error; + int error, nsegs; if ((c < 0) || (c >= BFE_RX_LIST_CNT)) return (EINVAL); @@ -593,10 +593,16 @@ sc->bfe_rx_cnt = c; d = &sc->bfe_rx_list[c]; r = &sc->bfe_rx_ring[c]; - error = bus_dmamap_load(sc->bfe_tag, r->bfe_map, mtod(m, void *), - MCLBYTES, bfe_dma_map_desc, d, BUS_DMA_NOWAIT); - if (error) + error = bus_dmamap_load_mbuf_sg(sc->bfe_tag, r->bfe_map, m, segs, + &nsegs, 0); + if (error) { printf("Serious error: bfe failed to map RX buffer\n"); + return (error); + } + + /* The chip needs all addresses to be added to BFE_PCI_DMA */ + d->bfe_addr = segs[0].ds_addr + BFE_PCI_DMA; + bus_dmamap_sync(sc->bfe_tag, r->bfe_map, BUS_DMASYNC_PREWRITE); ctrl = ETHER_MAX_LEN + 32; @@ -905,16 +911,6 @@ } static void -bfe_dma_map_desc(void *arg, bus_dma_segment_t *segs, int nseg, int error) -{ - struct bfe_desc *d; - - d = arg; - /* The chip needs all addresses to be added to BFE_PCI_DMA */ - d->bfe_addr = segs->ds_addr + BFE_PCI_DMA; -} - -static void bfe_release_resources(struct bfe_softc *sc) { device_t dev; @@ -1098,12 +1094,13 @@ /* Go through the mbufs and free those that have been transmitted */ while(i != chipidx) { struct bfe_data *r = &sc->bfe_tx_ring[i]; - if(r->bfe_mbuf != NULL) { + + if (r->bfe_mbuf != NULL) { ifp->if_opackets++; m_freem(r->bfe_mbuf); r->bfe_mbuf = NULL; + bus_dmamap_unload(sc->bfe_tag, r->bfe_map); } - bus_dmamap_unload(sc->bfe_tag, r->bfe_map); sc->bfe_tx_cnt--; BFE_INC(i, BFE_TX_LIST_CNT); } @@ -1258,81 +1255,85 @@ static int bfe_encap(struct bfe_softc *sc, struct mbuf **m_head, u_int32_t *txidx) { + bus_dma_segment_t segs[BFE_TX_LIST_CNT / 4]; + bus_dmamap_t map; struct bfe_desc *d = NULL; - struct bfe_data *r = NULL; + struct bfe_data *r = NULL, *first; struct mbuf *m; u_int32_t frag, cur, cnt = 0; - int chainlen = 0; - int error; + int error, nsegs; - if(BFE_TX_LIST_CNT - sc->bfe_tx_cnt < 2) + if (BFE_TX_LIST_CNT - sc->bfe_tx_cnt < 2) return (ENOBUFS); + + cur = frag = *txidx; + first = &sc->bfe_tx_ring[cur]; + error = bus_dmamap_load_mbuf_sg(sc->bfe_tag, first->bfe_map, *m_head, + segs, &nsegs, 0); /* - * Count the number of frags in this chain to see if - * we need to m_defrag. Since the descriptor list is shared - * by all packets, we'll m_defrag long chains so that they - * do not use up the entire list, even if they would fit. + * If the chain won't give us enough free descriptors, treat it as + * EFBIG and defrag. */ - for(m = *m_head; m != NULL; m = m->m_next) - chainlen++; + if (error == 0 && ((BFE_TX_LIST_CNT - (nsegs + sc->bfe_tx_cnt)) < 2)) { + bus_dmamap_unload(sc->bfe_tag, first->bfe_map); + error = EFBIG; + } - - if ((chainlen > BFE_TX_LIST_CNT / 4) || - ((BFE_TX_LIST_CNT - (chainlen + sc->bfe_tx_cnt)) < 2)) { + /* + * Chain is too long, so defrag and try again. + */ + if (error == EFBIG) { m = m_defrag(*m_head, M_DONTWAIT); if (m == NULL) return (ENOBUFS); *m_head = m; + error = bus_dmamap_load_mbuf_sg(sc->bfe_tag, first->bfe_map, + *m_head, segs, &nsegs, 0); + if (error) + return (error); } /* - * Start packing the mbufs in this chain into - * the fragment pointers. Stop when we run out - * of fragments or hit the end of the mbuf chain. + * Pack the segments into the fragment pointers. */ - cur = frag = *txidx; - cnt = 0; + for (cnt = 0; cnt < nsegs; cnt++) { + d = &sc->bfe_tx_list[cur]; + r = &sc->bfe_tx_ring[cur]; + d->bfe_ctrl = BFE_DESC_LEN & segs[cnt].ds_len; + /* always interrupt on completion */ + d->bfe_ctrl |= BFE_DESC_IOC; - for(m = *m_head; m != NULL; m = m->m_next) { - if(m->m_len != 0) { - if((BFE_TX_LIST_CNT - (sc->bfe_tx_cnt + cnt)) < 2) - return (ENOBUFS); + /* + * XXX: Should we do this last to avoid the chip reading + * a partial chain? + */ + if (cnt == 0) + /* Set start of frame */ + d->bfe_ctrl |= BFE_DESC_SOF; + if (cur == BFE_TX_LIST_CNT - 1) + /* + * Tell the chip to wrap to the start of + * the descriptor list + */ + d->bfe_ctrl |= BFE_DESC_EOT; - d = &sc->bfe_tx_list[cur]; - r = &sc->bfe_tx_ring[cur]; - d->bfe_ctrl = BFE_DESC_LEN & m->m_len; - /* always intterupt on completion */ - d->bfe_ctrl |= BFE_DESC_IOC; - if(cnt == 0) - /* Set start of frame */ - d->bfe_ctrl |= BFE_DESC_SOF; - if(cur == BFE_TX_LIST_CNT - 1) - /* - * Tell the chip to wrap to the start of - * the descriptor list - */ - d->bfe_ctrl |= BFE_DESC_EOT; + /* The chip needs all addresses to be added to BFE_PCI_DMA */ + d->bfe_addr = segs[cnt].ds_addr + BFE_PCI_DMA; - error = bus_dmamap_load(sc->bfe_tag, - r->bfe_map, mtod(m, void*), m->m_len, - bfe_dma_map_desc, d, BUS_DMA_NOWAIT); - if (error) - return (ENOBUFS); - bus_dmamap_sync(sc->bfe_tag, r->bfe_map, - BUS_DMASYNC_PREWRITE); - - frag = cur; - BFE_INC(cur, BFE_TX_LIST_CNT); - cnt++; - } + frag = cur; + BFE_INC(cur, BFE_TX_LIST_CNT); } - if (m != NULL) - return (ENOBUFS); + bus_dmamap_sync(sc->bfe_tag, first->bfe_map, BUS_DMASYNC_PREWRITE); sc->bfe_tx_list[frag].bfe_ctrl |= BFE_DESC_EOF; sc->bfe_tx_ring[frag].bfe_mbuf = *m_head; + if (first != &sc->bfe_tx_ring[frag]) { + map = first->bfe_map; + first->bfe_map = sc->bfe_rx_ring[frag].bfe_map; + sc->bfe_rx_ring[frag].bfe_map = map; + } bus_dmamap_sync(sc->bfe_tx_tag, sc->bfe_tx_map, BUS_DMASYNC_PREWRITE); *txidx = cur;