diff options
author | David Gwynne <dlg@cvs.openbsd.org> | 2014-08-20 00:50:46 +0000 |
---|---|---|
committer | David Gwynne <dlg@cvs.openbsd.org> | 2014-08-20 00:50:46 +0000 |
commit | 25e7542b81ef634c7383c789195b91c744e8fce0 (patch) | |
tree | acb204acfbdba5d1ec73c21a9fb8c3c2f7f0313a /sys/dev/pci/if_sk.c | |
parent | a8078e17e95e05b865117842de85bf69f5ad99f8 (diff) |
replace sks jumbo allocator with MCLGETI. the system provides jumbos in
the right shape now, we dont have to do it by hand all over the place
any more.
rework the rxr ring management to use if_rxring while here.
largely based on if_sk.c r1.152 and if_skvar.h r1.4 by kettenis.
tested by me on:
skc0 at pci3 dev 11 function 0 "Schneider & Koch SK-98xx" rev 0x12, GEnesis (0x0): apic 3 int 5
sk0 at skc0 port A: address 00:00:5a:99:8a:ec
xmphy0 at sk0 phy 0: XMAC II Gigabit PHY, rev. 2
and this from ian mcwilliam
skc0 at pci0 dev 9 function 0 "D-Link DGE-530T B1" rev 0x11, Yukon Lite (0x9): apic 2 int 17
sk0 at skc0 port A: address 00:17:9a:ba:b5:39
eephy0 at sk0 phy 0: 88E1011 Gigabit PHY, rev. 5
tested by brad@ too
Diffstat (limited to 'sys/dev/pci/if_sk.c')
-rw-r--r-- | sys/dev/pci/if_sk.c | 338 |
1 files changed, 99 insertions, 239 deletions
diff --git a/sys/dev/pci/if_sk.c b/sys/dev/pci/if_sk.c index 2b499683e0d..896ca6cc4c3 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.170 2014/07/22 13:12:11 mpi Exp $ */ +/* $OpenBSD: if_sk.c,v 1.171 2014/08/20 00:50:45 dlg Exp $ */ /* * Copyright (c) 1997, 1998, 1999, 2000 @@ -153,12 +153,10 @@ void sk_watchdog(struct ifnet *); int sk_ifmedia_upd(struct ifnet *); void sk_ifmedia_sts(struct ifnet *, struct ifmediareq *); void skc_reset(struct sk_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_newbuf(struct sk_if_softc *); int sk_reset(struct sk_if_softc *); int sk_init_rx_ring(struct sk_if_softc *); +void sk_fill_rx_ring(struct sk_if_softc *); int sk_init_tx_ring(struct sk_if_softc *); int sk_xmac_miibus_readreg(struct device *, int, int); @@ -547,21 +545,29 @@ sk_init_rx_ring(struct sk_if_softc *sc_if) rd->sk_rx_ring[i].sk_next = htole32(SK_RX_RING_ADDR(sc_if, nexti)); } - 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; + if_rxr_init(&sc_if->sk_cdata.sk_rx_ring, 2, SK_RX_RING_CNT); + + sk_fill_rx_ring(sc_if); + return (0); } +void +sk_fill_rx_ring(struct sk_if_softc *sc_if) +{ + struct if_rxring *rxr = &sc_if->sk_cdata.sk_rx_ring; + u_int slots; + + for (slots = if_rxr_get(rxr, SK_RX_RING_CNT); slots > 0; slots--) { + if (sk_newbuf(sc_if) == ENOBUFS) + break; + } + if_rxr_put(rxr, slots); +} + int sk_init_tx_ring(struct sk_if_softc *sc_if) { @@ -609,199 +615,49 @@ sk_init_tx_ring(struct sk_if_softc *sc_if) } int -sk_newbuf(struct sk_if_softc *sc_if, int i, struct mbuf *m, - bus_dmamap_t dmamap) +sk_newbuf(struct sk_if_softc *sc_if) { - struct mbuf *m_new = NULL; + struct mbuf *m; struct sk_chain *c; struct sk_rx_desc *r; + bus_dmamap_t dmamap; + u_int prod; + int error; - if (m == NULL) { - caddr_t buf = NULL; - - 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_adj(m_new, ETHER_ALIGN); - - 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); -} - -/* - * 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"); + m = MCLGETI(NULL, M_DONTWAIT, NULL, SK_JLEN); + if (m == NULL) 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; - } - - 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; - } - - 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; - } - 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)); + m->m_len = m->m_pkthdr.len = SK_JLEN; + m_adj(m, ETHER_ALIGN); - LIST_INIT(&sc_if->sk_jfree_listhead); - LIST_INIT(&sc_if->sk_jinuse_listhead); + prod = sc_if->sk_cdata.sk_rx_prod; + dmamap = sc_if->sk_cdata.sk_rx_map[prod]; - /* - * 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; - } + error = bus_dmamap_load_mbuf(sc_if->sk_softc->sc_dmatag, dmamap, m, + BUS_DMA_READ|BUS_DMA_NOWAIT); + if (error) { + m_freem(m); + return (ENOBUFS); } - return (error); -} - -/* - * 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); + bus_dmamap_sync(sc_if->sk_softc->sc_dmatag, dmamap, 0, + dmamap->dm_mapsize, BUS_DMASYNC_PREREAD); - 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]); -} + c = &sc_if->sk_cdata.sk_rx_chain[prod]; + c->sk_mbuf = m; -/* - * 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!"); + r = c->sk_desc; + r->sk_data_lo = htole32(dmamap->dm_segs[0].ds_addr); + r->sk_data_hi = htole32(((u_int64_t)dmamap->dm_segs[0].ds_addr) >> 32); + r->sk_ctl = htole32(dmamap->dm_segs[0].ds_len | SK_RXSTAT); - /* calculate the slot this buffer belongs to */ - i = ((vaddr_t)buf - - (vaddr_t)sc->sk_cdata.sk_jumbo_buf) / SK_JLEN; + SK_CDRXSYNC(sc_if, prod, BUS_DMASYNC_PREWRITE|BUS_DMASYNC_PREREAD); - if ((i < 0) || (i >= SK_JSLOTS)) - panic("sk_jfree: asked to free buffer that we don't manage!"); + SK_INC(prod, SK_RX_RING_CNT); + sc_if->sk_cdata.sk_rx_prod = prod; - 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); + return (0); } /* @@ -869,6 +725,12 @@ sk_ioctl(struct ifnet *ifp, u_long command, caddr_t data) error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); break; + case SIOCGIFRXR: + error = if_rxr_ioctl((struct if_rxrinfo *)ifr->ifr_data, + NULL, SK_JLEN, &sc_if->sk_cdata.sk_rx_ring); + + break; + default: error = ether_ioctl(ifp, &sc_if->arpcom, command, data); } @@ -997,7 +859,7 @@ sk_attach(struct device *parent, struct device *self, void *aux) struct skc_attach_args *sa = aux; struct ifnet *ifp; caddr_t kva; - int i; + int i, error; sc_if->sk_port = sa->skc_port; sc_if->sk_softc = sc; @@ -1124,10 +986,14 @@ sk_attach(struct device *parent, struct device *self, void *aux) } sc_if->sk_rdata = (struct sk_ring_data *)kva; - /* Try to allocate memory for jumbo buffers. */ - if (sk_alloc_jumbo_mem(sc_if)) { - printf(": jumbo buffer allocation failed\n"); - goto fail_3; + for (i = 0; i < SK_RX_RING_CNT; i++) { + error = bus_dmamap_create(sc->sc_dmatag, SK_JLEN, 1, + SK_JLEN, 0, 0, &sc_if->sk_cdata.sk_rx_map[i]); + if (error != 0) { + printf(": unable to create rx DMA map %d, " + "error = %d\n", i, error); + goto fail_4; + } } ifp = &sc_if->arpcom.ac_if; @@ -1193,12 +1059,18 @@ 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) + continue; -fail_2: + bus_dmamap_destroy(sc->sc_dmatag, sc_if->sk_cdata.sk_rx_map[i]); + } +fail_3: bus_dmamem_unmap(sc->sc_dmatag, kva, sizeof(struct sk_ring_data)); -fail_1: +fail_2: bus_dmamem_free(sc->sc_dmatag, &sc_if->sk_ring_seg, sc_if->sk_ring_nseg); -fail_3: +fail_1: bus_dmamap_destroy(sc->sc_dmatag, sc_if->sk_ring_map); fail: sc->sk_if[sa->skc_port] = NULL; @@ -1718,45 +1590,44 @@ sk_rxeof(struct sk_if_softc *sc_if) { struct sk_softc *sc = sc_if->sk_softc; struct ifnet *ifp = &sc_if->arpcom.ac_if; + struct if_rxring *rxr = &sc_if->sk_cdata.sk_rx_ring; struct mbuf *m; struct sk_chain *cur_rx; struct sk_rx_desc *cur_desc; - int i, cur, total_len = 0; + int cur, total_len = 0; u_int32_t rxstat, sk_ctl; bus_dmamap_t dmamap; DPRINTFN(2, ("sk_rxeof\n")); - i = sc_if->sk_cdata.sk_rx_prod; - - for (;;) { - cur = i; - + cur = sc_if->sk_cdata.sk_rx_cons; + while (if_rxr_inuse(rxr) > 0) { /* Sync the descriptor */ SK_CDRXSYNC(sc_if, cur, BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); - 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; + 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) 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_jumbo_map; + dmamap = sc_if->sk_cdata.sk_rx_map[cur]; 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)); + if_rxr_put(rxr, 1); + SK_INC(cur, SK_RX_RING_CNT); - SK_INC(i, SK_RX_RING_CNT); + total_len = SK_RXBYTES(letoh32(cur_desc->sk_ctl)); + rxstat = letoh32(cur_desc->sk_xmac_rxstat); if ((sk_ctl & (SK_RXCTL_STATUS_VALID | SK_RXCTL_FIRSTFRAG | SK_RXCTL_LASTFRAG)) != (SK_RXCTL_STATUS_VALID | @@ -1765,31 +1636,12 @@ sk_rxeof(struct sk_if_softc *sc_if) total_len > SK_JUMBO_FRAMELEN || sk_rxvalid(sc, rxstat, total_len) == 0) { ifp->if_ierrors++; - sk_newbuf(sc_if, cur, m, dmamap); + m_freem(m); continue; } - /* - * 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); - 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; - } + m->m_pkthdr.rcvif = ifp; + m->m_pkthdr.len = m->m_len = total_len; ifp->if_ipackets++; @@ -1801,6 +1653,9 @@ sk_rxeof(struct sk_if_softc *sc_if) /* pass it on. */ ether_input_mbuf(ifp, m); } + sc_if->sk_cdata.sk_rx_cons = cur; + + sk_fill_rx_ring(sc_if); } void @@ -2570,6 +2425,7 @@ sk_stop(struct sk_if_softc *sc_if, int softonly) { struct sk_softc *sc = sc_if->sk_softc; struct ifnet *ifp = &sc_if->arpcom.ac_if; + bus_dmamap_t dmamap; struct sk_txmap_entry *dma; int i; u_int32_t val; @@ -2660,6 +2516,10 @@ sk_stop(struct sk_if_softc *sc_if, int softonly) /* Free RX and TX mbufs still in the queues. */ for (i = 0; i < SK_RX_RING_CNT; i++) { if (sc_if->sk_cdata.sk_rx_chain[i].sk_mbuf != NULL) { + dmamap = sc_if->sk_cdata.sk_rx_map[i]; + 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); m_freem(sc_if->sk_cdata.sk_rx_chain[i].sk_mbuf); sc_if->sk_cdata.sk_rx_chain[i].sk_mbuf = NULL; } |