summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorDavid Gwynne <dlg@cvs.openbsd.org>2013-01-14 04:02:03 +0000
committerDavid Gwynne <dlg@cvs.openbsd.org>2013-01-14 04:02:03 +0000
commit688fed501ad413b54e4e5fa6357045cb110b35e7 (patch)
treee6c633ca08101a080e7064635a44a60b39000124 /sys/dev
parenta33271a418b0f6585254ee33098f746e8d97a957 (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.c165
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 *