summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
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 *