diff options
author | 2009-07-08 20:18:05 +0000 | |
---|---|---|
committer | 2009-07-08 20:18:05 +0000 | |
commit | e99a34813c233c414d093bc5f6ae793a9912d0c2 (patch) | |
tree | c6bf6a261bb981444306ef5939091f6942b71372 | |
parent | Detect nexthop change. (diff) | |
download | wireguard-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.c | 317 | ||||
-rw-r--r-- | sys/dev/pci/if_skvar.h | 16 |
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; }; |