summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsthen <sthen@openbsd.org>2009-07-08 20:18:05 +0000
committersthen <sthen@openbsd.org>2009-07-08 20:18:05 +0000
commite99a34813c233c414d093bc5f6ae793a9912d0c2 (patch)
treec6bf6a261bb981444306ef5939091f6942b71372
parentDetect nexthop change. (diff)
downloadwireguard-openbsd-e99a34813c233c414d093bc5f6ae793a9912d0c2.tar.xz
wireguard-openbsd-e99a34813c233c414d093bc5f6ae793a9912d0c2.zip
revert MCLGETI for sk(4) for now. commit requested by deraadt@
-rw-r--r--sys/dev/pci/if_sk.c317
-rw-r--r--sys/dev/pci/if_skvar.h16
2 files changed, 242 insertions, 91 deletions
diff --git a/sys/dev/pci/if_sk.c b/sys/dev/pci/if_sk.c
index b54538ef0a8..f6bda5d48ca 100644
--- a/sys/dev/pci/if_sk.c
+++ b/sys/dev/pci/if_sk.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_sk.c,v 1.151 2009/03/30 19:09:43 kettenis Exp $ */
+/* $OpenBSD: if_sk.c,v 1.152 2009/07/08 20:18:05 sthen Exp $ */
/*
* Copyright (c) 1997, 1998, 1999, 2000
@@ -155,10 +155,12 @@ void sk_watchdog(struct ifnet *);
int sk_ifmedia_upd(struct ifnet *);
void sk_ifmedia_sts(struct ifnet *, struct ifmediareq *);
void sk_reset(struct sk_softc *);
-int sk_newbuf(struct sk_if_softc *);
+int sk_newbuf(struct sk_if_softc *, int, struct mbuf *, bus_dmamap_t);
+int sk_alloc_jumbo_mem(struct sk_if_softc *);
+void *sk_jalloc(struct sk_if_softc *);
+void sk_jfree(caddr_t, u_int, void *);
int sk_init_rx_ring(struct sk_if_softc *);
int sk_init_tx_ring(struct sk_if_softc *);
-void sk_fill_rx_ring(struct sk_if_softc *);
int sk_xmac_miibus_readreg(struct device *, int, int);
void sk_xmac_miibus_writereg(struct device *, int, int, int);
@@ -571,23 +573,21 @@ sk_init_rx_ring(struct sk_if_softc *sc_if)
sizeof(struct ip));
}
+ for (i = 0; i < SK_RX_RING_CNT; i++) {
+ if (sk_newbuf(sc_if, i, NULL,
+ sc_if->sk_cdata.sk_rx_jumbo_map) == ENOBUFS) {
+ printf("%s: failed alloc of %dth mbuf\n",
+ sc_if->sk_dev.dv_xname, i);
+ return (ENOBUFS);
+ }
+ }
+
sc_if->sk_cdata.sk_rx_prod = 0;
sc_if->sk_cdata.sk_rx_cons = 0;
- sc_if->sk_cdata.sk_rx_cnt = 0;
- sk_fill_rx_ring(sc_if);
return (0);
}
-void
-sk_fill_rx_ring(struct sk_if_softc *sc_if)
-{
- while (sc_if->sk_cdata.sk_rx_cnt < SK_RX_RING_CNT) {
- if (sk_newbuf(sc_if) == ENOBUFS)
- break;
- }
-}
-
int
sk_init_tx_ring(struct sk_if_softc *sc_if)
{
@@ -635,66 +635,199 @@ sk_init_tx_ring(struct sk_if_softc *sc_if)
}
int
-sk_newbuf(struct sk_if_softc *sc_if)
+sk_newbuf(struct sk_if_softc *sc_if, int i, struct mbuf *m,
+ bus_dmamap_t dmamap)
{
+ struct mbuf *m_new = NULL;
struct sk_chain *c;
struct sk_rx_desc *r;
- struct mbuf *m;
- bus_dmamap_t dmamap;
- u_int32_t sk_ctl;
- int i, error;
- MGETHDR(m, M_DONTWAIT, MT_DATA);
- if (m == NULL)
- return (ENOBUFS);
+ if (m == NULL) {
+ caddr_t buf = NULL;
- MCLGETI(m, M_DONTWAIT, &sc_if->arpcom.ac_if, SK_JLEN);
- if ((m->m_flags & M_EXT) == 0) {
- m_freem(m);
- return (ENOBUFS);
+ MGETHDR(m_new, M_DONTWAIT, MT_DATA);
+ if (m_new == NULL)
+ return (ENOBUFS);
+
+ /* Allocate the jumbo buffer */
+ buf = sk_jalloc(sc_if);
+ if (buf == NULL) {
+ m_freem(m_new);
+ DPRINTFN(1, ("%s jumbo allocation failed -- packet "
+ "dropped!\n", sc_if->arpcom.ac_if.if_xname));
+ return (ENOBUFS);
+ }
+
+ /* Attach the buffer to the mbuf */
+ m_new->m_len = m_new->m_pkthdr.len = SK_JLEN;
+ MEXTADD(m_new, buf, SK_JLEN, 0, sk_jfree, sc_if);
+ } else {
+ /*
+ * We're re-using a previously allocated mbuf;
+ * be sure to re-init pointers and lengths to
+ * default values.
+ */
+ m_new = m;
+ m_new->m_len = m_new->m_pkthdr.len = SK_JLEN;
+ m_new->m_data = m_new->m_ext.ext_buf;
}
- m->m_len = m->m_pkthdr.len = SK_JLEN;
- m_adj(m, ETHER_ALIGN);
+ m_adj(m_new, ETHER_ALIGN);
- dmamap = sc_if->sk_cdata.sk_rx_map[sc_if->sk_cdata.sk_rx_prod];
+ c = &sc_if->sk_cdata.sk_rx_chain[i];
+ r = c->sk_desc;
+ c->sk_mbuf = m_new;
+ r->sk_data_lo = htole32(dmamap->dm_segs[0].ds_addr +
+ (((vaddr_t)m_new->m_data
+ - (vaddr_t)sc_if->sk_cdata.sk_jumbo_buf)));
+ r->sk_ctl = htole32(SK_JLEN | SK_RXSTAT);
+
+ SK_CDRXSYNC(sc_if, i, BUS_DMASYNC_PREWRITE|BUS_DMASYNC_PREREAD);
+
+ return (0);
+}
- error = bus_dmamap_load_mbuf(sc_if->sk_softc->sc_dmatag, dmamap, m,
- BUS_DMA_READ|BUS_DMA_NOWAIT);
- if (error) {
- m_freem(m);
+/*
+ * Memory management for jumbo frames.
+ */
+
+int
+sk_alloc_jumbo_mem(struct sk_if_softc *sc_if)
+{
+ struct sk_softc *sc = sc_if->sk_softc;
+ caddr_t ptr, kva;
+ bus_dma_segment_t seg;
+ int i, rseg, state, error;
+ struct sk_jpool_entry *entry;
+
+ state = error = 0;
+
+ /* Grab a big chunk o' storage. */
+ if (bus_dmamem_alloc(sc->sc_dmatag, SK_JMEM, PAGE_SIZE, 0,
+ &seg, 1, &rseg, BUS_DMA_NOWAIT)) {
+ printf(": can't alloc rx buffers");
return (ENOBUFS);
}
- if (dmamap->dm_nsegs > (SK_RX_RING_CNT - sc_if->sk_cdata.sk_rx_cnt)) {
- bus_dmamap_unload(sc_if->sk_softc->sc_dmatag, dmamap);
- m_freem(m);
- return (ENOBUFS);
+ state = 1;
+ if (bus_dmamem_map(sc->sc_dmatag, &seg, rseg, SK_JMEM, &kva,
+ BUS_DMA_NOWAIT)) {
+ printf(": can't map dma buffers (%d bytes)", SK_JMEM);
+ error = ENOBUFS;
+ goto out;
}
- bus_dmamap_sync(sc_if->sk_softc->sc_dmatag, dmamap, 0,
- dmamap->dm_mapsize, BUS_DMASYNC_PREREAD);
+ state = 2;
+ if (bus_dmamap_create(sc->sc_dmatag, SK_JMEM, 1, SK_JMEM, 0,
+ BUS_DMA_NOWAIT, &sc_if->sk_cdata.sk_rx_jumbo_map)) {
+ printf(": can't create dma map");
+ error = ENOBUFS;
+ goto out;
+ }
- c = &sc_if->sk_cdata.sk_rx_chain[sc_if->sk_cdata.sk_rx_prod];
- r = c->sk_desc;
- c->sk_mbuf = m;
+ state = 3;
+ if (bus_dmamap_load(sc->sc_dmatag, sc_if->sk_cdata.sk_rx_jumbo_map,
+ kva, SK_JMEM, NULL, BUS_DMA_NOWAIT)) {
+ printf(": can't load dma map");
+ error = ENOBUFS;
+ goto out;
+ }
- sk_ctl = SK_RXSTAT;
- for (i = 0; i < dmamap->dm_nsegs; i++) {
- r->sk_data_lo = htole32(dmamap->dm_segs[i].ds_addr);
- r->sk_ctl = htole32(dmamap->dm_segs[i].ds_len | sk_ctl);
- sk_ctl &= ~SK_RXCTL_FIRSTFRAG;
+ state = 4;
+ sc_if->sk_cdata.sk_jumbo_buf = (caddr_t)kva;
+ DPRINTFN(1,("sk_jumbo_buf = 0x%08X\n", sc_if->sk_cdata.sk_jumbo_buf));
- SK_INC(sc_if->sk_cdata.sk_rx_prod, SK_RX_RING_CNT);
- sc_if->sk_cdata.sk_rx_cnt++;
+ LIST_INIT(&sc_if->sk_jfree_listhead);
+ LIST_INIT(&sc_if->sk_jinuse_listhead);
- c = &sc_if->sk_cdata.sk_rx_chain[sc_if->sk_cdata.sk_rx_prod];
- r = c->sk_desc;
- c->sk_mbuf = NULL;
+ /*
+ * Now divide it up into 9K pieces and save the addresses
+ * in an array.
+ */
+ ptr = sc_if->sk_cdata.sk_jumbo_buf;
+ for (i = 0; i < SK_JSLOTS; i++) {
+ sc_if->sk_cdata.sk_jslots[i] = ptr;
+ ptr += SK_JLEN;
+ entry = malloc(sizeof(struct sk_jpool_entry),
+ M_DEVBUF, M_NOWAIT);
+ if (entry == NULL) {
+ sc_if->sk_cdata.sk_jumbo_buf = NULL;
+ printf(": no memory for jumbo buffer queue!");
+ error = ENOBUFS;
+ goto out;
+ }
+ entry->slot = i;
+ LIST_INSERT_HEAD(&sc_if->sk_jfree_listhead,
+ entry, jpool_entries);
+ }
+out:
+ if (error != 0) {
+ switch (state) {
+ case 4:
+ bus_dmamap_unload(sc->sc_dmatag,
+ sc_if->sk_cdata.sk_rx_jumbo_map);
+ case 3:
+ bus_dmamap_destroy(sc->sc_dmatag,
+ sc_if->sk_cdata.sk_rx_jumbo_map);
+ case 2:
+ bus_dmamem_unmap(sc->sc_dmatag, kva, SK_JMEM);
+ case 1:
+ bus_dmamem_free(sc->sc_dmatag, &seg, rseg);
+ break;
+ default:
+ break;
+ }
}
- SK_CDRXSYNC(sc_if, i, BUS_DMASYNC_PREWRITE|BUS_DMASYNC_PREREAD);
+ return (error);
+}
- return (0);
+/*
+ * Allocate a jumbo buffer.
+ */
+void *
+sk_jalloc(struct sk_if_softc *sc_if)
+{
+ struct sk_jpool_entry *entry;
+
+ entry = LIST_FIRST(&sc_if->sk_jfree_listhead);
+
+ if (entry == NULL)
+ return (NULL);
+
+ LIST_REMOVE(entry, jpool_entries);
+ LIST_INSERT_HEAD(&sc_if->sk_jinuse_listhead, entry, jpool_entries);
+ return (sc_if->sk_cdata.sk_jslots[entry->slot]);
+}
+
+/*
+ * Release a jumbo buffer.
+ */
+void
+sk_jfree(caddr_t buf, u_int size, void *arg)
+{
+ struct sk_jpool_entry *entry;
+ struct sk_if_softc *sc;
+ int i;
+
+ /* Extract the softc struct pointer. */
+ sc = (struct sk_if_softc *)arg;
+
+ if (sc == NULL)
+ panic("sk_jfree: can't find softc pointer!");
+
+ /* calculate the slot this buffer belongs to */
+ i = ((vaddr_t)buf
+ - (vaddr_t)sc->sk_cdata.sk_jumbo_buf) / SK_JLEN;
+
+ if ((i < 0) || (i >= SK_JSLOTS))
+ panic("sk_jfree: asked to free buffer that we don't manage!");
+
+ entry = LIST_FIRST(&sc->sk_jinuse_listhead);
+ if (entry == NULL)
+ panic("sk_jfree: buffer not in use!");
+ entry->slot = i;
+ LIST_REMOVE(entry, jpool_entries);
+ LIST_INSERT_HEAD(&sc->sk_jfree_listhead, entry, jpool_entries);
}
/*
@@ -897,7 +1030,6 @@ sk_attach(struct device *parent, struct device *self, void *aux)
caddr_t kva;
bus_dma_segment_t seg;
int i, rseg;
- int error;
sc_if->sk_port = sa->skc_port;
sc_if->sk_softc = sc;
@@ -1024,13 +1156,10 @@ sk_attach(struct device *parent, struct device *self, void *aux)
sc_if->sk_rdata = (struct sk_ring_data *)kva;
bzero(sc_if->sk_rdata, sizeof(struct sk_ring_data));
- for (i = 0; i < SK_RX_RING_CNT; i++) {
- if ((error = bus_dmamap_create(sc->sc_dmatag, SK_JLEN, 4,
- SK_JLEN, 0, 0, &sc_if->sk_cdata.sk_rx_map[i])) != 0) {
- printf("\n%s: unable to create rx DMA map %d, "
- "error = %d\n", sc->sk_dev.dv_xname, i, error);
- goto fail_4;
- }
+ /* Try to allocate memory for jumbo buffers. */
+ if (sk_alloc_jumbo_mem(sc_if)) {
+ printf(": jumbo buffer allocation failed\n");
+ goto fail_3;
}
ifp = &sc_if->arpcom.ac_if;
@@ -1112,13 +1241,6 @@ sk_attach(struct device *parent, struct device *self, void *aux)
DPRINTFN(2, ("sk_attach: end\n"));
return;
-fail_4:
- for (i = 0; i < SK_RX_RING_CNT; i++) {
- if (sc_if->sk_cdata.sk_rx_map[i] != NULL)
- bus_dmamap_destroy(sc->sc_dmatag,
- sc_if->sk_cdata.sk_rx_map[i]);
- }
-
fail_3:
bus_dmamap_destroy(sc->sc_dmatag, sc_if->sk_ring_map);
fail_2:
@@ -1588,39 +1710,39 @@ sk_rxeof(struct sk_if_softc *sc_if)
DPRINTFN(2, ("sk_rxeof\n"));
+ i = sc_if->sk_cdata.sk_rx_prod;
+
for (;;) {
- cur = sc_if->sk_cdata.sk_rx_cons;
+ cur = i;
/* Sync the descriptor */
SK_CDRXSYNC(sc_if, cur,
BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
- cur_rx = &sc_if->sk_cdata.sk_rx_chain[cur];
- if (cur_rx->sk_mbuf == NULL)
- break;
-
- sk_ctl = letoh32(sc_if->sk_rdata->sk_rx_ring[cur].sk_ctl);
- if ((sk_ctl & SK_RXCTL_OWN) != 0)
+ sk_ctl = letoh32(sc_if->sk_rdata->sk_rx_ring[i].sk_ctl);
+ if ((sk_ctl & SK_RXCTL_OWN) != 0) {
+ /* Invalidate the descriptor -- it's not ready yet */
+ SK_CDRXSYNC(sc_if, cur, BUS_DMASYNC_PREREAD);
+ sc_if->sk_cdata.sk_rx_prod = i;
break;
+ }
+ cur_rx = &sc_if->sk_cdata.sk_rx_chain[cur];
cur_desc = &sc_if->sk_rdata->sk_rx_ring[cur];
- dmamap = sc_if->sk_cdata.sk_rx_map[cur];
- for (i = 0; i < dmamap->dm_nsegs; i++) {
- SK_INC(sc_if->sk_cdata.sk_rx_cons, SK_RX_RING_CNT);
- sc_if->sk_cdata.sk_rx_cnt--;
- }
+ dmamap = sc_if->sk_cdata.sk_rx_jumbo_map;
bus_dmamap_sync(sc_if->sk_softc->sc_dmatag, dmamap, 0,
dmamap->dm_mapsize, BUS_DMASYNC_POSTREAD);
- bus_dmamap_unload(sc_if->sk_softc->sc_dmatag, dmamap);
rxstat = letoh32(cur_desc->sk_xmac_rxstat);
m = cur_rx->sk_mbuf;
cur_rx->sk_mbuf = NULL;
total_len = SK_RXBYTES(letoh32(cur_desc->sk_ctl));
- csum1 = letoh16(sc_if->sk_rdata->sk_rx_ring[cur].sk_csum1);
- csum2 = letoh16(sc_if->sk_rdata->sk_rx_ring[cur].sk_csum2);
+ csum1 = letoh16(sc_if->sk_rdata->sk_rx_ring[i].sk_csum1);
+ csum2 = letoh16(sc_if->sk_rdata->sk_rx_ring[i].sk_csum2);
+
+ SK_INC(i, SK_RX_RING_CNT);
if ((sk_ctl & (SK_RXCTL_STATUS_VALID | SK_RXCTL_FIRSTFRAG |
SK_RXCTL_LASTFRAG)) != (SK_RXCTL_STATUS_VALID |
@@ -1629,12 +1751,31 @@ sk_rxeof(struct sk_if_softc *sc_if)
total_len > SK_JUMBO_FRAMELEN ||
sk_rxvalid(sc, rxstat, total_len) == 0) {
ifp->if_ierrors++;
- m_freem(m);
+ sk_newbuf(sc_if, cur, m, dmamap);
continue;
}
- m->m_pkthdr.rcvif = ifp;
- m->m_pkthdr.len = m->m_len = total_len;
+ /*
+ * Try to allocate a new jumbo buffer. If that
+ * fails, copy the packet to mbufs and put the
+ * jumbo buffer back in the ring so it can be
+ * re-used. If allocating mbufs fails, then we
+ * have to drop the packet.
+ */
+ if (sk_newbuf(sc_if, cur, NULL, dmamap) == ENOBUFS) {
+ struct mbuf *m0;
+ m0 = m_devget(mtod(m, char *), total_len, ETHER_ALIGN,
+ ifp, NULL);
+ sk_newbuf(sc_if, cur, m, dmamap);
+ if (m0 == NULL) {
+ ifp->if_ierrors++;
+ continue;
+ }
+ m = m0;
+ } else {
+ m->m_pkthdr.rcvif = ifp;
+ m->m_pkthdr.len = m->m_len = total_len;
+ }
ifp->if_ipackets++;
@@ -1648,8 +1789,6 @@ sk_rxeof(struct sk_if_softc *sc_if)
/* pass it on. */
ether_input_mbuf(ifp, m);
}
-
- sk_fill_rx_ring(sc_if);
}
void
diff --git a/sys/dev/pci/if_skvar.h b/sys/dev/pci/if_skvar.h
index b6dd3ad6464..f846246c822 100644
--- a/sys/dev/pci/if_skvar.h
+++ b/sys/dev/pci/if_skvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_skvar.h,v 1.4 2009/03/30 19:09:43 kettenis Exp $ */
+/* $OpenBSD: if_skvar.h,v 1.5 2009/07/08 20:18:05 sthen Exp $ */
/* $NetBSD: if_skvar.h,v 1.6 2005/05/30 04:35:22 christos Exp $ */
/*-
@@ -26,7 +26,7 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
-/* $OpenBSD: if_skvar.h,v 1.4 2009/03/30 19:09:43 kettenis Exp $ */
+/* $OpenBSD: if_skvar.h,v 1.5 2009/07/08 20:18:05 sthen Exp $ */
/*
* Copyright (c) 1997, 1998, 1999, 2000
@@ -81,6 +81,11 @@
#ifndef _DEV_PCI_IF_SKVAR_H_
#define _DEV_PCI_IF_SKVAR_H_
+struct sk_jpool_entry {
+ int slot;
+ LIST_ENTRY(sk_jpool_entry) jpool_entries;
+};
+
struct sk_chain {
void *sk_desc;
struct mbuf *sk_mbuf;
@@ -106,12 +111,17 @@ struct sk_chain_data {
struct sk_chain sk_rx_chain[SK_RX_RING_CNT];
struct sk_txmap_entry *sk_tx_map[SK_TX_RING_CNT];
bus_dmamap_t sk_rx_map[SK_RX_RING_CNT];
+ bus_dmamap_t sk_rx_jumbo_map;
int sk_tx_prod;
int sk_tx_cons;
int sk_tx_cnt;
int sk_rx_prod;
int sk_rx_cons;
int sk_rx_cnt;
+ /* Stick the jumbo mem management stuff here too. */
+ caddr_t sk_jslots[SK_JSLOTS];
+ void *sk_jumbo_buf;
+
};
struct sk_ring_data {
@@ -210,6 +220,8 @@ struct sk_if_softc {
struct sk_softc *sk_softc; /* parent controller */
int sk_tx_bmu; /* TX BMU register */
int sk_if_flags;
+ LIST_HEAD(__sk_jfreehead, sk_jpool_entry) sk_jfree_listhead;
+ LIST_HEAD(__sk_jinusehead, sk_jpool_entry) sk_jinuse_listhead;
SIMPLEQ_HEAD(__sk_txmaphead, sk_txmap_entry) sk_txmap_head;
};