summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Gwynne <dlg@cvs.openbsd.org>2014-10-28 00:36:07 +0000
committerDavid Gwynne <dlg@cvs.openbsd.org>2014-10-28 00:36:07 +0000
commita949e5fc4ba61e7097b4bba394fa11f57ba81d39 (patch)
tree59314b425ef6d8b9b64fe1ad66f7253aa552a8db
parent3a6f3a2e376c2cc68a040bc433027dc7842092b0 (diff)
the if_rxring accounting would get screwed up if the first mbuf to
be put on the ring couldnt be allocated. this pulls the code that puts the mbufs on the ring out of myx_rx_fill so it can return early if firstmb cant be allocated, which puts it in the right place to return unused slots to the if_rxring. this means myx rx wont lock up if you're DoSsed to the point where you exhaust your mbuf pools and cant allocate mbufs for the ring. ok jmatthew@
-rw-r--r--sys/dev/pci/if_myx.c88
1 files changed, 50 insertions, 38 deletions
diff --git a/sys/dev/pci/if_myx.c b/sys/dev/pci/if_myx.c
index 0e601f76c4b..06d5524d039 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.70 2014/10/04 11:42:27 dlg Exp $ */
+/* $OpenBSD: if_myx.c,v 1.71 2014/10/28 00:36:06 dlg Exp $ */
/*
* Copyright (c) 2007 Reyk Floeter <reyk@openbsd.org>
@@ -1875,13 +1875,57 @@ myx_rx_zero(struct myx_softc *sc, int ring)
}
}
-int
-myx_rx_fill(struct myx_softc *sc, int ring)
+static inline int
+myx_rx_fill_slots(struct myx_softc *sc, int ring, u_int slots)
{
struct myx_rx_desc rxd;
struct myx_buf *mb, *firstmb;
u_int32_t offset = sc->sc_rx_ring_offset[ring];
- u_int idx, firstidx, slots;
+ u_int idx, firstidx;
+
+ firstmb = myx_buf_fill(sc, ring);
+ if (firstmb == NULL)
+ return (slots);
+
+ 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;
+ slots--;
+
+ while (slots > 0 && (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_bus_space_write(sc->sc_memt, sc->sc_memh,
+ offset + idx * sizeof(rxd), &rxd, sizeof(rxd));
+
+ idx++;
+ idx %= sc->sc_rx_ring_count;
+ slots--;
+ }
+
+ /* make sure the first descriptor is seen after the others */
+ if (idx != firstidx + 1) {
+ bus_space_barrier(sc->sc_memt, sc->sc_memh,
+ offset, sizeof(rxd) * sc->sc_rx_ring_count,
+ BUS_SPACE_BARRIER_WRITE);
+ }
+
+ 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 (slots);
+}
+
+int
+myx_rx_fill(struct myx_softc *sc, int ring)
+{
+ u_int slots;
int rv = 1;
if (!myx_ring_enter(&sc->sc_rx_ring_lock[ring]))
@@ -1892,44 +1936,12 @@ myx_rx_fill(struct myx_softc *sc, int ring)
slots = if_rxr_get(&sc->sc_rx_ring[ring], sc->sc_rx_ring_count);
mtx_leave(&sc->sc_rx_ring_lock[ring].mrl_mtx);
- if (slots-- == 0)
- continue;
-
- firstmb = myx_buf_fill(sc, ring);
- if (firstmb == NULL)
+ if (slots == 0)
continue;
+ slots = myx_rx_fill_slots(sc, ring, slots);
rv = 0;
- 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 (slots > 0 && (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_bus_space_write(sc->sc_memt, sc->sc_memh,
- offset + idx * sizeof(rxd), &rxd, sizeof(rxd));
-
- idx++;
- idx %= sc->sc_rx_ring_count;
- slots--;
- }
-
- /* make sure the first descriptor is seen after the others */
- if (idx != firstidx + 1) {
- bus_space_barrier(sc->sc_memt, sc->sc_memh,
- offset, sizeof(rxd) * sc->sc_rx_ring_count,
- BUS_SPACE_BARRIER_WRITE);
- }
-
- 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;
mtx_enter(&sc->sc_rx_ring_lock[ring].mrl_mtx);
if_rxr_put(&sc->sc_rx_ring[ring], slots);
mtx_leave(&sc->sc_rx_ring_lock[ring].mrl_mtx);