diff options
Diffstat (limited to 'sys/dev/sk/if_sk.c')
-rw-r--r-- | sys/dev/sk/if_sk.c | 402 |
1 files changed, 141 insertions, 261 deletions
diff --git a/sys/dev/sk/if_sk.c b/sys/dev/sk/if_sk.c index c51b4d1..9dee683 100644 --- a/sys/dev/sk/if_sk.c +++ b/sys/dev/sk/if_sk.c @@ -227,9 +227,9 @@ static int sk_newbuf(struct sk_if_softc *, int); static int sk_jumbo_newbuf(struct sk_if_softc *, int); static void sk_dmamap_cb(void *, bus_dma_segment_t *, int, int); static int sk_dma_alloc(struct sk_if_softc *); +static int sk_dma_jumbo_alloc(struct sk_if_softc *); static void sk_dma_free(struct sk_if_softc *); -static void *sk_jalloc(struct sk_if_softc *); -static void sk_jfree(void *, void *); +static void sk_dma_jumbo_free(struct sk_if_softc *); static int sk_init_rx_ring(struct sk_if_softc *); static int sk_init_jumbo_rx_ring(struct sk_if_softc *); static void sk_init_tx_ring(struct sk_if_softc *); @@ -263,6 +263,10 @@ static void sk_setpromisc(struct sk_if_softc *); static int sysctl_int_range(SYSCTL_HANDLER_ARGS, int low, int high); static int sysctl_hw_sk_int_mod(SYSCTL_HANDLER_ARGS); +/* Tunables. */ +static int jumbo_disable = 0; +TUNABLE_INT("hw.skc.jumbo_disable", &jumbo_disable); + /* * It seems that SK-NET GENESIS supports very simple checksum offload * capability for Tx and I believe it can generate 0 checksum value for @@ -1044,24 +1048,15 @@ sk_jumbo_newbuf(sc_if, idx) bus_dma_segment_t segs[1]; bus_dmamap_t map; int nsegs; - void *buf; - MGETHDR(m, M_DONTWAIT, MT_DATA); + m = m_getjcl(M_DONTWAIT, MT_DATA, M_PKTHDR, MJUM9BYTES); if (m == NULL) return (ENOBUFS); - buf = sk_jalloc(sc_if); - if (buf == NULL) { - m_freem(m); - return (ENOBUFS); - } - /* Attach the buffer to the mbuf */ - MEXTADD(m, buf, SK_JLEN, sk_jfree, (struct sk_if_softc *)sc_if, buf, 0, - EXT_NET_DRV); if ((m->m_flags & M_EXT) == 0) { m_freem(m); return (ENOBUFS); } - m->m_pkthdr.len = m->m_len = SK_JLEN; + m->m_pkthdr.len = m->m_len = MJUM9BYTES; /* * Adjust alignment so packet payload begins on a * longword boundary. Mandatory for Alpha, useful on @@ -1149,15 +1144,22 @@ sk_ioctl(ifp, command, data) error = 0; switch(command) { case SIOCSIFMTU: - SK_IF_LOCK(sc_if); - if (ifr->ifr_mtu > SK_JUMBO_MTU) + if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > SK_JUMBO_MTU) error = EINVAL; - else { - ifp->if_mtu = ifr->ifr_mtu; - ifp->if_drv_flags &= ~IFF_DRV_RUNNING; - sk_init_locked(sc_if); + else if (ifp->if_mtu != ifr->ifr_mtu) { + if (sc_if->sk_jumbo_disable != 0 && + ifr->ifr_mtu > SK_MAX_FRAMELEN) + error = EINVAL; + else { + SK_IF_LOCK(sc_if); + ifp->if_mtu = ifr->ifr_mtu; + if (ifp->if_drv_flags & IFF_DRV_RUNNING) { + ifp->if_drv_flags &= ~IFF_DRV_RUNNING; + sk_init_locked(sc_if); + } + SK_IF_UNLOCK(sc_if); + } } - SK_IF_UNLOCK(sc_if); break; case SIOCSIFFLAGS: SK_IF_LOCK(sc_if); @@ -1374,6 +1376,7 @@ sk_attach(dev) error = ENOMEM; goto fail; } + sk_dma_jumbo_alloc(sc_if); ifp = sc_if->sk_ifp = if_alloc(IFT_ETHER); if (ifp == NULL) { @@ -1855,6 +1858,7 @@ sk_detach(dev) device_delete_child(dev, sc_if->sk_miibus); */ bus_generic_detach(dev); + sk_dma_jumbo_free(sc_if); sk_dma_free(sc_if); SK_IF_UNLOCK(sc_if); @@ -1928,15 +1932,8 @@ sk_dma_alloc(sc_if) struct sk_dmamap_arg ctx; struct sk_txdesc *txd; struct sk_rxdesc *rxd; - struct sk_rxdesc *jrxd; - u_int8_t *ptr; - struct sk_jpool_entry *entry; int error, i; - mtx_init(&sc_if->sk_jlist_mtx, "sk_jlist_mtx", NULL, MTX_DEF); - SLIST_INIT(&sc_if->sk_jfree_listhead); - SLIST_INIT(&sc_if->sk_jinuse_listhead); - /* create parent tag */ /* * XXX @@ -1963,6 +1960,7 @@ sk_dma_alloc(sc_if) "failed to create parent DMA tag\n"); goto fail; } + /* create tag for Tx ring */ error = bus_dma_tag_create(sc_if->sk_cdata.sk_parent_tag,/* parent */ SK_RING_ALIGN, 0, /* algnmnt, boundary */ @@ -1999,42 +1997,6 @@ sk_dma_alloc(sc_if) goto fail; } - /* create tag for jumbo Rx ring */ - error = bus_dma_tag_create(sc_if->sk_cdata.sk_parent_tag,/* parent */ - SK_RING_ALIGN, 0, /* algnmnt, boundary */ - BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ - BUS_SPACE_MAXADDR, /* highaddr */ - NULL, NULL, /* filter, filterarg */ - SK_JUMBO_RX_RING_SZ, /* maxsize */ - 1, /* nsegments */ - SK_JUMBO_RX_RING_SZ, /* maxsegsize */ - 0, /* flags */ - NULL, NULL, /* lockfunc, lockarg */ - &sc_if->sk_cdata.sk_jumbo_rx_ring_tag); - if (error != 0) { - device_printf(sc_if->sk_if_dev, - "failed to allocate jumbo Rx ring DMA tag\n"); - goto fail; - } - - /* create tag for jumbo buffer blocks */ - error = bus_dma_tag_create(sc_if->sk_cdata.sk_parent_tag,/* parent */ - PAGE_SIZE, 0, /* algnmnt, boundary */ - BUS_SPACE_MAXADDR, /* lowaddr */ - BUS_SPACE_MAXADDR, /* highaddr */ - NULL, NULL, /* filter, filterarg */ - SK_JMEM, /* maxsize */ - 1, /* nsegments */ - SK_JMEM, /* maxsegsize */ - 0, /* flags */ - NULL, NULL, /* lockfunc, lockarg */ - &sc_if->sk_cdata.sk_jumbo_tag); - if (error != 0) { - device_printf(sc_if->sk_if_dev, - "failed to allocate jumbo Rx buffer block DMA tag\n"); - goto fail; - } - /* create tag for Tx buffers */ error = bus_dma_tag_create(sc_if->sk_cdata.sk_parent_tag,/* parent */ 1, 0, /* algnmnt, boundary */ @@ -2071,24 +2033,6 @@ sk_dma_alloc(sc_if) goto fail; } - /* create tag for jumbo Rx buffers */ - error = bus_dma_tag_create(sc_if->sk_cdata.sk_parent_tag,/* parent */ - PAGE_SIZE, 0, /* algnmnt, boundary */ - BUS_SPACE_MAXADDR, /* lowaddr */ - BUS_SPACE_MAXADDR, /* highaddr */ - NULL, NULL, /* filter, filterarg */ - MCLBYTES * SK_MAXRXSEGS, /* maxsize */ - SK_MAXRXSEGS, /* nsegments */ - SK_JLEN, /* maxsegsize */ - 0, /* flags */ - NULL, NULL, /* lockfunc, lockarg */ - &sc_if->sk_cdata.sk_jumbo_rx_tag); - if (error != 0) { - device_printf(sc_if->sk_if_dev, - "failed to allocate jumbo Rx DMA tag\n"); - goto fail; - } - /* allocate DMA'able memory and load the DMA map for Tx ring */ error = bus_dmamem_alloc(sc_if->sk_cdata.sk_tx_ring_tag, (void **)&sc_if->sk_rdata.sk_tx_ring, BUS_DMA_NOWAIT | BUS_DMA_ZERO, @@ -2131,28 +2075,6 @@ sk_dma_alloc(sc_if) } sc_if->sk_rdata.sk_rx_ring_paddr = ctx.sk_busaddr; - /* allocate DMA'able memory and load the DMA map for jumbo Rx ring */ - error = bus_dmamem_alloc(sc_if->sk_cdata.sk_jumbo_rx_ring_tag, - (void **)&sc_if->sk_rdata.sk_jumbo_rx_ring, - BUS_DMA_NOWAIT|BUS_DMA_ZERO, &sc_if->sk_cdata.sk_jumbo_rx_ring_map); - if (error != 0) { - device_printf(sc_if->sk_if_dev, - "failed to allocate DMA'able memory for jumbo Rx ring\n"); - goto fail; - } - - ctx.sk_busaddr = 0; - error = bus_dmamap_load(sc_if->sk_cdata.sk_jumbo_rx_ring_tag, - sc_if->sk_cdata.sk_jumbo_rx_ring_map, - sc_if->sk_rdata.sk_jumbo_rx_ring, SK_JUMBO_RX_RING_SZ, sk_dmamap_cb, - &ctx, BUS_DMA_NOWAIT); - if (error != 0) { - device_printf(sc_if->sk_if_dev, - "failed to load DMA'able memory for jumbo Rx ring\n"); - goto fail; - } - sc_if->sk_rdata.sk_jumbo_rx_ring_paddr = ctx.sk_busaddr; - /* create DMA maps for Tx buffers */ for (i = 0; i < SK_TX_RING_CNT; i++) { txd = &sc_if->sk_cdata.sk_txdesc[i]; @@ -2166,6 +2088,7 @@ sk_dma_alloc(sc_if) goto fail; } } + /* create DMA maps for Rx buffers */ if ((error = bus_dmamap_create(sc_if->sk_cdata.sk_rx_tag, 0, &sc_if->sk_cdata.sk_rx_sparemap)) != 0) { @@ -2185,12 +2108,88 @@ sk_dma_alloc(sc_if) goto fail; } } + +fail: + return (error); +} + +static int +sk_dma_jumbo_alloc(sc_if) + struct sk_if_softc *sc_if; +{ + struct sk_dmamap_arg ctx; + struct sk_rxdesc *jrxd; + int error, i; + + if (jumbo_disable != 0) { + device_printf(sc_if->sk_if_dev, "disabling jumbo frame support\n"); + sc_if->sk_jumbo_disable = 1; + return (0); + } + /* create tag for jumbo Rx ring */ + error = bus_dma_tag_create(sc_if->sk_cdata.sk_parent_tag,/* parent */ + SK_RING_ALIGN, 0, /* algnmnt, boundary */ + BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + SK_JUMBO_RX_RING_SZ, /* maxsize */ + 1, /* nsegments */ + SK_JUMBO_RX_RING_SZ, /* maxsegsize */ + 0, /* flags */ + NULL, NULL, /* lockfunc, lockarg */ + &sc_if->sk_cdata.sk_jumbo_rx_ring_tag); + if (error != 0) { + device_printf(sc_if->sk_if_dev, + "failed to allocate jumbo Rx ring DMA tag\n"); + goto jumbo_fail; + } + + /* create tag for jumbo Rx buffers */ + error = bus_dma_tag_create(sc_if->sk_cdata.sk_parent_tag,/* parent */ + 1, 0, /* algnmnt, boundary */ + BUS_SPACE_MAXADDR, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + MJUM9BYTES, /* maxsize */ + 1, /* nsegments */ + MJUM9BYTES, /* maxsegsize */ + 0, /* flags */ + NULL, NULL, /* lockfunc, lockarg */ + &sc_if->sk_cdata.sk_jumbo_rx_tag); + if (error != 0) { + device_printf(sc_if->sk_if_dev, + "failed to allocate jumbo Rx DMA tag\n"); + goto jumbo_fail; + } + + /* allocate DMA'able memory and load the DMA map for jumbo Rx ring */ + error = bus_dmamem_alloc(sc_if->sk_cdata.sk_jumbo_rx_ring_tag, + (void **)&sc_if->sk_rdata.sk_jumbo_rx_ring, + BUS_DMA_NOWAIT|BUS_DMA_ZERO, &sc_if->sk_cdata.sk_jumbo_rx_ring_map); + if (error != 0) { + device_printf(sc_if->sk_if_dev, + "failed to allocate DMA'able memory for jumbo Rx ring\n"); + goto jumbo_fail; + } + + ctx.sk_busaddr = 0; + error = bus_dmamap_load(sc_if->sk_cdata.sk_jumbo_rx_ring_tag, + sc_if->sk_cdata.sk_jumbo_rx_ring_map, + sc_if->sk_rdata.sk_jumbo_rx_ring, SK_JUMBO_RX_RING_SZ, sk_dmamap_cb, + &ctx, BUS_DMA_NOWAIT); + if (error != 0) { + device_printf(sc_if->sk_if_dev, + "failed to load DMA'able memory for jumbo Rx ring\n"); + goto jumbo_fail; + } + sc_if->sk_rdata.sk_jumbo_rx_ring_paddr = ctx.sk_busaddr; + /* create DMA maps for jumbo Rx buffers */ if ((error = bus_dmamap_create(sc_if->sk_cdata.sk_jumbo_rx_tag, 0, &sc_if->sk_cdata.sk_jumbo_rx_sparemap)) != 0) { device_printf(sc_if->sk_if_dev, "failed to create spare jumbo Rx dmamap\n"); - goto fail; + goto jumbo_fail; } for (i = 0; i < SK_JUMBO_RX_RING_CNT; i++) { jrxd = &sc_if->sk_cdata.sk_jumbo_rxdesc[i]; @@ -2201,55 +2200,18 @@ sk_dma_alloc(sc_if) if (error != 0) { device_printf(sc_if->sk_if_dev, "failed to create jumbo Rx dmamap\n"); - goto fail; + goto jumbo_fail; } } - /* allocate DMA'able memory and load the DMA map for jumbo buf */ - error = bus_dmamem_alloc(sc_if->sk_cdata.sk_jumbo_tag, - (void **)&sc_if->sk_rdata.sk_jumbo_buf, - BUS_DMA_NOWAIT|BUS_DMA_ZERO, &sc_if->sk_cdata.sk_jumbo_map); - if (error != 0) { - device_printf(sc_if->sk_if_dev, - "failed to allocate DMA'able memory for jumbo buf\n"); - goto fail; - } - - ctx.sk_busaddr = 0; - error = bus_dmamap_load(sc_if->sk_cdata.sk_jumbo_tag, - sc_if->sk_cdata.sk_jumbo_map, - sc_if->sk_rdata.sk_jumbo_buf, SK_JMEM, sk_dmamap_cb, - &ctx, BUS_DMA_NOWAIT); - if (error != 0) { - device_printf(sc_if->sk_if_dev, - "failed to load DMA'able memory for jumbobuf\n"); - goto fail; - } - sc_if->sk_rdata.sk_jumbo_buf_paddr = ctx.sk_busaddr; - - /* - * Now divide it up into 9K pieces and save the addresses - * in an array. - */ - ptr = sc_if->sk_rdata.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) { - device_printf(sc_if->sk_if_dev, - "no memory for jumbo buffers!\n"); - error = ENOMEM; - goto fail; - } - entry->slot = i; - SLIST_INSERT_HEAD(&sc_if->sk_jfree_listhead, entry, - jpool_entries); - } + return (0); -fail: - return (error); +jumbo_fail: + sk_dma_jumbo_free(sc_if); + device_printf(sc_if->sk_if_dev, "disabling jumbo frame support due to " + "resource shortage\n"); + sc_if->sk_jumbo_disable = 1; + return (0); } static void @@ -2258,39 +2220,8 @@ sk_dma_free(sc_if) { struct sk_txdesc *txd; struct sk_rxdesc *rxd; - struct sk_rxdesc *jrxd; - struct sk_jpool_entry *entry; int i; - SK_JLIST_LOCK(sc_if); - while ((entry = SLIST_FIRST(&sc_if->sk_jinuse_listhead))) { - device_printf(sc_if->sk_if_dev, - "asked to free buffer that is in use!\n"); - SLIST_REMOVE_HEAD(&sc_if->sk_jinuse_listhead, jpool_entries); - SLIST_INSERT_HEAD(&sc_if->sk_jfree_listhead, entry, - jpool_entries); - } - - while (!SLIST_EMPTY(&sc_if->sk_jfree_listhead)) { - entry = SLIST_FIRST(&sc_if->sk_jfree_listhead); - SLIST_REMOVE_HEAD(&sc_if->sk_jfree_listhead, jpool_entries); - free(entry, M_DEVBUF); - } - SK_JLIST_UNLOCK(sc_if); - - /* destroy jumbo buffer block */ - if (sc_if->sk_cdata.sk_jumbo_map) - bus_dmamap_unload(sc_if->sk_cdata.sk_jumbo_tag, - sc_if->sk_cdata.sk_jumbo_map); - - if (sc_if->sk_rdata.sk_jumbo_buf) { - bus_dmamem_free(sc_if->sk_cdata.sk_jumbo_tag, - sc_if->sk_rdata.sk_jumbo_buf, - sc_if->sk_cdata.sk_jumbo_map); - sc_if->sk_rdata.sk_jumbo_buf = NULL; - sc_if->sk_cdata.sk_jumbo_map = 0; - } - /* Tx ring */ if (sc_if->sk_cdata.sk_tx_ring_tag) { if (sc_if->sk_cdata.sk_tx_ring_map) @@ -2321,21 +2252,6 @@ sk_dma_free(sc_if) bus_dma_tag_destroy(sc_if->sk_cdata.sk_rx_ring_tag); sc_if->sk_cdata.sk_rx_ring_tag = NULL; } - /* jumbo Rx ring */ - if (sc_if->sk_cdata.sk_jumbo_rx_ring_tag) { - if (sc_if->sk_cdata.sk_jumbo_rx_ring_map) - bus_dmamap_unload(sc_if->sk_cdata.sk_jumbo_rx_ring_tag, - sc_if->sk_cdata.sk_jumbo_rx_ring_map); - if (sc_if->sk_cdata.sk_jumbo_rx_ring_map && - sc_if->sk_rdata.sk_jumbo_rx_ring) - bus_dmamem_free(sc_if->sk_cdata.sk_jumbo_rx_ring_tag, - sc_if->sk_rdata.sk_jumbo_rx_ring, - sc_if->sk_cdata.sk_jumbo_rx_ring_map); - sc_if->sk_rdata.sk_jumbo_rx_ring = NULL; - sc_if->sk_cdata.sk_jumbo_rx_ring_map = 0; - bus_dma_tag_destroy(sc_if->sk_cdata.sk_jumbo_rx_ring_tag); - sc_if->sk_cdata.sk_jumbo_rx_ring_tag = NULL; - } /* Tx buffers */ if (sc_if->sk_cdata.sk_tx_tag) { for (i = 0; i < SK_TX_RING_CNT; i++) { @@ -2367,6 +2283,36 @@ sk_dma_free(sc_if) bus_dma_tag_destroy(sc_if->sk_cdata.sk_rx_tag); sc_if->sk_cdata.sk_rx_tag = NULL; } + + if (sc_if->sk_cdata.sk_parent_tag) { + bus_dma_tag_destroy(sc_if->sk_cdata.sk_parent_tag); + sc_if->sk_cdata.sk_parent_tag = NULL; + } +} + +static void +sk_dma_jumbo_free(sc_if) + struct sk_if_softc *sc_if; +{ + struct sk_rxdesc *jrxd; + int i; + + /* jumbo Rx ring */ + if (sc_if->sk_cdata.sk_jumbo_rx_ring_tag) { + if (sc_if->sk_cdata.sk_jumbo_rx_ring_map) + bus_dmamap_unload(sc_if->sk_cdata.sk_jumbo_rx_ring_tag, + sc_if->sk_cdata.sk_jumbo_rx_ring_map); + if (sc_if->sk_cdata.sk_jumbo_rx_ring_map && + sc_if->sk_rdata.sk_jumbo_rx_ring) + bus_dmamem_free(sc_if->sk_cdata.sk_jumbo_rx_ring_tag, + sc_if->sk_rdata.sk_jumbo_rx_ring, + sc_if->sk_cdata.sk_jumbo_rx_ring_map); + sc_if->sk_rdata.sk_jumbo_rx_ring = NULL; + sc_if->sk_cdata.sk_jumbo_rx_ring_map = 0; + bus_dma_tag_destroy(sc_if->sk_cdata.sk_jumbo_rx_ring_tag); + sc_if->sk_cdata.sk_jumbo_rx_ring_tag = NULL; + } + /* jumbo Rx buffers */ if (sc_if->sk_cdata.sk_jumbo_rx_tag) { for (i = 0; i < SK_JUMBO_RX_RING_CNT; i++) { @@ -2386,72 +2332,6 @@ sk_dma_free(sc_if) bus_dma_tag_destroy(sc_if->sk_cdata.sk_jumbo_rx_tag); sc_if->sk_cdata.sk_jumbo_rx_tag = NULL; } - - if (sc_if->sk_cdata.sk_parent_tag) { - bus_dma_tag_destroy(sc_if->sk_cdata.sk_parent_tag); - sc_if->sk_cdata.sk_parent_tag = NULL; - } - mtx_destroy(&sc_if->sk_jlist_mtx); -} - -/* - * Allocate a jumbo buffer. - */ -static void * -sk_jalloc(sc_if) - struct sk_if_softc *sc_if; -{ - struct sk_jpool_entry *entry; - - SK_JLIST_LOCK(sc_if); - - entry = SLIST_FIRST(&sc_if->sk_jfree_listhead); - - if (entry == NULL) { - SK_JLIST_UNLOCK(sc_if); - return (NULL); - } - - SLIST_REMOVE_HEAD(&sc_if->sk_jfree_listhead, jpool_entries); - SLIST_INSERT_HEAD(&sc_if->sk_jinuse_listhead, entry, jpool_entries); - - SK_JLIST_UNLOCK(sc_if); - - return (sc_if->sk_cdata.sk_jslots[entry->slot]); -} - -/* - * Release a jumbo buffer. - */ -static void -sk_jfree(buf, args) - void *buf; - void *args; -{ - struct sk_if_softc *sc_if; - struct sk_jpool_entry *entry; - int i; - - /* Extract the softc struct pointer. */ - sc_if = (struct sk_if_softc *)args; - KASSERT(sc_if != NULL, ("%s: can't find softc pointer!", __func__)); - - SK_JLIST_LOCK(sc_if); - /* calculate the slot this buffer belongs to */ - i = ((vm_offset_t)buf - - (vm_offset_t)sc_if->sk_rdata.sk_jumbo_buf) / SK_JLEN; - KASSERT(i >= 0 && i < SK_JSLOTS, - ("%s: asked to free buffer that we don't manage!", __func__)); - - entry = SLIST_FIRST(&sc_if->sk_jinuse_listhead); - KASSERT(entry != NULL, ("%s: buffer not in use!", __func__)); - entry->slot = i; - SLIST_REMOVE_HEAD(&sc_if->sk_jinuse_listhead, jpool_entries); - SLIST_INSERT_HEAD(&sc_if->sk_jfree_listhead, entry, jpool_entries); - if (SLIST_EMPTY(&sc_if->sk_jinuse_listhead)) - wakeup(sc_if); - - SK_JLIST_UNLOCK(sc_if); } static void |