diff options
author | David Gwynne <dlg@cvs.openbsd.org> | 2013-01-14 04:02:03 +0000 |
---|---|---|
committer | David Gwynne <dlg@cvs.openbsd.org> | 2013-01-14 04:02:03 +0000 |
commit | 688fed501ad413b54e4e5fa6357045cb110b35e7 (patch) | |
tree | e6c633ca08101a080e7064635a44a60b39000124 /sys/dev | |
parent | a33271a418b0f6585254ee33098f746e8d97a957 (diff) |
the myri doco suggests its nice to post stuff by filling in everything
in the rings except the first descriptor. once you've written as
much as you can out, then you go back and post the first descriptor
to signal that the chip should go ahead and work.
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/pci/if_myx.c | 165 |
1 files changed, 108 insertions, 57 deletions
diff --git a/sys/dev/pci/if_myx.c b/sys/dev/pci/if_myx.c index a9b51c2eb45..89e064f8d2b 100644 --- a/sys/dev/pci/if_myx.c +++ b/sys/dev/pci/if_myx.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_myx.c,v 1.32 2013/01/14 00:47:53 dlg Exp $ */ +/* $OpenBSD: if_myx.c,v 1.33 2013/01/14 04:02:02 dlg Exp $ */ /* * Copyright (c) 2007 Reyk Floeter <reyk@openbsd.org> @@ -177,6 +177,10 @@ void myx_iff(struct myx_softc *); void myx_down(struct myx_softc *); void myx_start(struct ifnet *); +void myx_write_txd_head(struct myx_softc *, struct myx_buf *, u_int8_t, + u_int32_t, u_int); +void myx_write_txd_tail(struct myx_softc *, struct myx_buf *, u_int8_t, + u_int32_t, u_int); int myx_load_buf(struct myx_softc *, struct myx_buf *, struct mbuf *); int myx_setlladdr(struct myx_softc *, u_int32_t, u_int8_t *); int myx_intr(void *); @@ -1366,21 +1370,66 @@ myx_down(struct myx_softc *sc) bus_dmamap_sync(sc->sc_dmat, sc->sc_zerodma.mxm_map, 0, sc->sc_zerodma.mxm_map->dm_mapsize, BUS_DMASYNC_POSTREAD); myx_dmamem_free(sc, &sc->sc_zerodma); +} + +void +myx_write_txd_head(struct myx_softc *sc, struct myx_buf *mb, u_int8_t flags, + u_int32_t offset, u_int idx) +{ + struct myx_tx_desc txd; + bus_dmamap_t map = mb->mb_map; + + bzero(&txd, sizeof(txd)); + txd.tx_addr = htobe64(map->dm_segs[0].ds_addr); + txd.tx_length = htobe16(map->dm_segs[0].ds_len); + txd.tx_nsegs = map->dm_nsegs + (map->dm_mapsize < 60 ? 1 : 0); + txd.tx_flags = flags | MYXTXD_FLAGS_FIRST; + myx_write(sc, offset + sizeof(txd) * idx, &txd, sizeof(txd)); +} +void +myx_write_txd_tail(struct myx_softc *sc, struct myx_buf *mb, u_int8_t flags, + u_int32_t offset, u_int idx) +{ + struct myx_tx_desc txd; + bus_dmamap_t zmap = sc->sc_zerodma.mxm_map; + bus_dmamap_t map = mb->mb_map; + int i; + + for (i = 1; i < map->dm_nsegs; i++) { + bzero(&txd, sizeof(txd)); + txd.tx_addr = htobe64(map->dm_segs[i].ds_addr); + txd.tx_length = htobe16(map->dm_segs[i].ds_len); + txd.tx_flags = flags; + + myx_write(sc, offset + + sizeof(txd) * ((idx + i) % sc->sc_tx_ring_count), + &txd, sizeof(txd)); + } + + /* pad runt frames */ + if (map->dm_mapsize < 60) { + bzero(&txd, sizeof(txd)); + txd.tx_addr = htobe64(zmap->dm_segs[0].ds_addr); + txd.tx_length = htobe16(60 - map->dm_mapsize); + txd.tx_flags = flags; + + myx_write(sc, offset + + sizeof(txd) * ((idx + i) % sc->sc_tx_ring_count), + &txd, sizeof(txd)); + } } void myx_start(struct ifnet *ifp) { - struct myx_tx_desc txd; + struct myx_buf_list list = SIMPLEQ_HEAD_INITIALIZER(list); struct myx_softc *sc = ifp->if_softc; bus_dmamap_t map; - bus_dmamap_t zmap = sc->sc_zerodma.mxm_map; - struct myx_buf *mb; + struct myx_buf *mb, *firstmb; struct mbuf *m; u_int32_t offset = sc->sc_tx_ring_offset; - u_int idx; - u_int i; + u_int idx, firstidx; u_int8_t flags; if (!ISSET(ifp->if_flags, IFF_RUNNING) || @@ -1388,8 +1437,6 @@ myx_start(struct ifnet *ifp) IFQ_IS_EMPTY(&ifp->if_snd)) return; - idx = sc->sc_tx_ring_idx; - for (;;) { if (sc->sc_tx_free <= sc->sc_tx_nsegs) { SET(ifp->if_flags, IFF_OACTIVE); @@ -1420,59 +1467,52 @@ myx_start(struct ifnet *ifp) #endif mb->mb_m = m; - map = mb->mb_map; + map = mb->mb_map; bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, BUS_DMASYNC_POSTWRITE); - myx_buf_put(&sc->sc_tx_buf_list, mb); - - flags = MYXTXD_FLAGS_NO_TSO; - if (m->m_pkthdr.len < 1520) - flags |= MYXTXD_FLAGS_SMALL; + myx_buf_put(&list, mb); - for (i = 1; i < map->dm_nsegs; i++) { - bzero(&txd, sizeof(txd)); - txd.tx_addr = htobe64(map->dm_segs[i].ds_addr); - txd.tx_length = htobe16(map->dm_segs[i].ds_len); - txd.tx_flags = flags; + sc->sc_tx_free -= map->dm_nsegs + + (map->dm_mapsize < 60 ? 1 : 0); + } - /* complicated maths is cool */ - myx_write(sc, offset + sizeof(txd) * - ((idx + i) % sc->sc_tx_ring_count), - &txd, sizeof(txd)); - } + /* post the first descriptor last */ + firstmb = myx_buf_get(&list); + if (firstmb == NULL) + return; + myx_buf_put(&sc->sc_tx_buf_list, firstmb); - /* pad runt frames */ - if (map->dm_mapsize < 60) { - bzero(&txd, sizeof(txd)); - txd.tx_addr = htobe64(zmap->dm_segs[0].ds_addr); - txd.tx_length = htobe16(60 - map->dm_mapsize); - txd.tx_flags = flags; + idx = firstidx = sc->sc_tx_ring_idx; + idx += firstmb->mb_map->dm_nsegs + + (firstmb->mb_map->dm_mapsize < 60 ? 1 : 0); + idx %= sc->sc_tx_ring_count; - myx_write(sc, offset + sizeof(txd) * - ((idx + i) % sc->sc_tx_ring_count), - &txd, sizeof(txd)); + while ((mb = myx_buf_get(&list)) != NULL) { + myx_buf_put(&sc->sc_tx_buf_list, mb); - i++; - } + map = mb->mb_map; - /* commit by posting the first descriptor */ - bzero(&txd, sizeof(txd)); - txd.tx_addr = htobe64(map->dm_segs[0].ds_addr); - txd.tx_length = htobe16(map->dm_segs[0].ds_len); - txd.tx_nsegs = i; - txd.tx_flags = flags | MYXTXD_FLAGS_FIRST; + flags = MYXTXD_FLAGS_NO_TSO; + if (map->dm_mapsize < 1520) + flags |= MYXTXD_FLAGS_SMALL; - myx_write(sc, offset + idx * sizeof(txd), - &txd, sizeof(txd)); + myx_write_txd_head(sc, mb, flags, offset, idx); + myx_write_txd_tail(sc, mb, flags, offset, idx); - sc->sc_tx_free -= i; - idx += i; + idx += map->dm_nsegs + (map->dm_mapsize < 60 ? 1 : 0); idx %= sc->sc_tx_ring_count; } - sc->sc_tx_ring_idx = idx; + + /* go back and post first mb */ + flags = MYXTXD_FLAGS_NO_TSO; + if (firstmb->mb_map->dm_mapsize < 1520) + flags |= MYXTXD_FLAGS_SMALL; + + myx_write_txd_tail(sc, firstmb, flags, offset, firstidx); + myx_write_txd_head(sc, firstmb, flags, offset, firstidx); } int @@ -1702,27 +1742,38 @@ int myx_rx_fill(struct myx_softc *sc, int ring) { struct myx_rx_desc rxd; - struct myx_buf *mb; + struct myx_buf *mb, *firstmb; u_int32_t offset = sc->sc_rx_ring_offset[ring]; - u_int idx; - int ret = 1; + u_int idx, firstidx; - idx = sc->sc_rx_ring_idx[ring]; - while ((mb = myx_buf_fill(sc, ring)) != NULL) { - rxd.rx_addr = htobe64(mb->mb_map->dm_segs[0].ds_addr); + firstmb = myx_buf_fill(sc, ring); + if (firstmb == NULL) + return (1); + + myx_buf_put(&sc->sc_rx_buf_list[ring], firstmb); + firstidx = sc->sc_rx_ring_idx[ring]; + idx = firstidx + 1; + idx %= sc->sc_rx_ring_count; + + while ((mb = myx_buf_fill(sc, ring)) != NULL) { myx_buf_put(&sc->sc_rx_buf_list[ring], mb); + + rxd.rx_addr = htobe64(mb->mb_map->dm_segs[0].ds_addr); myx_write(sc, offset + idx * sizeof(rxd), &rxd, sizeof(rxd)); - if (++idx >= sc->sc_rx_ring_count) - idx = 0; - - ret = 0; + idx++; + idx %= sc->sc_rx_ring_count; } + + rxd.rx_addr = htobe64(firstmb->mb_map->dm_segs[0].ds_addr); + myx_write(sc, offset + firstidx * sizeof(rxd), + &rxd, sizeof(rxd)); + sc->sc_rx_ring_idx[ring] = idx; - return (ret); + return (0); } struct myx_buf * |