diff options
author | Damien Bergamini <damien@cvs.openbsd.org> | 2006-09-20 19:47:18 +0000 |
---|---|---|
committer | Damien Bergamini <damien@cvs.openbsd.org> | 2006-09-20 19:47:18 +0000 |
commit | 7d8d5a55d40262b0b99fdaad4a31450af6ec111a (patch) | |
tree | b7df8e2fb6ab514da4f0884695004cde068c42e0 | |
parent | 95ffeb8386a13b4e218f96731413b83602d55974 (diff) |
implement a zero-copy RX data path.
instead of copying the xfer buffer's content into a mbuf cluster, attach
the xfer buffer as a mbuf external storage and pass it to the net80211
layer as is.
maintain a reference count on the softc structure and wait in detach()
until all references have been released by the network layer.
-rw-r--r-- | sys/dev/usb/if_uath.c | 109 | ||||
-rw-r--r-- | sys/dev/usb/if_uathvar.h | 81 |
2 files changed, 101 insertions, 89 deletions
diff --git a/sys/dev/usb/if_uath.c b/sys/dev/usb/if_uath.c index 7e5d9d30b75..56a86f71780 100644 --- a/sys/dev/usb/if_uath.c +++ b/sys/dev/usb/if_uath.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_uath.c,v 1.9 2006/09/18 18:08:32 damien Exp $ */ +/* $OpenBSD: if_uath.c,v 1.10 2006/09/20 19:47:17 damien Exp $ */ /*- * Copyright (c) 2006 @@ -89,8 +89,8 @@ int uath_debug = 1; #define DPRINTFN(n, x) #endif -/* - * Various supported device vendors/products +/*- + * Various supported device vendors/products. * UB51: AR5005UG 802.11b/g, UB52: AR5005UX 802.11a/b/g */ #define UATH_DEV(v, p, f) \ @@ -138,6 +138,7 @@ Static int uath_alloc_tx_data_list(struct uath_softc *); Static void uath_free_tx_data_list(struct uath_softc *); Static int uath_alloc_rx_data_list(struct uath_softc *); Static void uath_free_rx_data_list(struct uath_softc *); +Static void uath_free_rx_data(caddr_t, u_int, void *); Static int uath_alloc_tx_cmd_list(struct uath_softc *); Static void uath_free_tx_cmd_list(struct uath_softc *); Static int uath_alloc_rx_cmd_list(struct uath_softc *); @@ -429,7 +430,7 @@ USB_DETACH(uath) struct ifnet *ifp = &sc->sc_ic.ic_if; int s; - s = splusb(); + s = splnet(); if (sc->sc_flags & UATH_FLAG_PRE_FIRMWARE) { uath_close_pipes(sc); @@ -443,6 +444,15 @@ USB_DETACH(uath) timeout_del(&sc->scan_to); timeout_del(&sc->stat_to); + ieee80211_ifdetach(ifp); /* free all nodes */ + if_detach(ifp); + + sc->sc_dying = 1; + DPRINTF(("reclaiming %d references\n", sc->sc_refcnt)); + while (sc->sc_refcnt > 0) + (void)tsleep(UATH_COND_NOREF(sc), 0, "uathdet", 0); + DPRINTF(("all references reclaimed\n")); + /* abort and free xfers */ uath_free_tx_data_list(sc); uath_free_rx_data_list(sc); @@ -452,9 +462,6 @@ USB_DETACH(uath) /* close Tx/Rx pipes */ uath_close_pipes(sc); - ieee80211_ifdetach(ifp); /* free all nodes */ - if_detach(ifp); - splx(s); usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, @@ -578,7 +585,7 @@ uath_alloc_rx_data_list(struct uath_softc *sc) { int i, error; - for (i = 0; i < UATH_RX_DATA_LIST_COUNT; i++) { + for (i = 0; i < UATH_RX_DATA_POOL_COUNT; i++) { struct uath_rx_data *data = &sc->rx_data[i]; data->sc = sc; /* backpointer for callbacks */ @@ -590,29 +597,14 @@ uath_alloc_rx_data_list(struct uath_softc *sc) error = ENOMEM; goto fail; } - if (usbd_alloc_buffer(data->xfer, sc->rxbufsz) == NULL) { + data->buf = usbd_alloc_buffer(data->xfer, sc->rxbufsz); + if (data->buf == NULL) { printf("%s: could not allocate xfer buffer\n", USBDEVNAME(sc->sc_dev)); error = ENOMEM; goto fail; } - - MGETHDR(data->m, M_DONTWAIT, MT_DATA); - if (data->m == NULL) { - printf("%s: could not allocate rx mbuf\n", - USBDEVNAME(sc->sc_dev)); - error = ENOMEM; - goto fail; - } - MCLGET(data->m, M_DONTWAIT); - if (!(data->m->m_flags & M_EXT)) { - printf("%s: could not allocate rx mbuf cluster\n", - USBDEVNAME(sc->sc_dev)); - error = ENOMEM; - goto fail; - } - - data->buf = mtod(data->m, uint8_t *); + SLIST_INSERT_HEAD(&sc->rx_freelist, data, next); } return 0; @@ -628,15 +620,23 @@ uath_free_rx_data_list(struct uath_softc *sc) /* make sure no transfers are pending */ usbd_abort_pipe(sc->data_rx_pipe); - for (i = 0; i < UATH_RX_DATA_LIST_COUNT; i++) { - struct uath_rx_data *data = &sc->rx_data[i]; + for (i = 0; i < UATH_RX_DATA_POOL_COUNT; i++) + if (sc->rx_data[i].xfer != NULL) + usbd_free_xfer(sc->rx_data[i].xfer); +} - if (data->xfer != NULL) - usbd_free_xfer(data->xfer); +Static void +uath_free_rx_data(caddr_t buf, u_int size, void *arg) +{ + struct uath_rx_data *data = arg; + struct uath_softc *sc = data->sc; - if (data->m != NULL) - m_freem(data->m); - } + /* put the buffer back in the free list */ + SLIST_INSERT_HEAD(&sc->rx_freelist, data, next); + + /* release reference to softc */ + if (--sc->sc_refcnt == 0 && sc->sc_dying) + wakeup(UATH_COND_NOREF(sc)); } Static int @@ -1001,6 +1001,7 @@ uath_cmd(struct uath_softc *sc, uint32_t code, const void *idata, int ilen, /* wait at most two seconds for command reply */ error = tsleep(cmd, PCATCH, "uathcmd", 2 * hz); + cmd->odata = NULL; /* in case answer is received too late */ splx(s); if (error != 0) { printf("%s: timeout waiting for command reply\n", @@ -1174,8 +1175,9 @@ uath_data_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, struct ifnet *ifp = &ic->ic_if; struct ieee80211_frame *wh; struct ieee80211_node *ni; + struct uath_rx_data *ndata; struct uath_rx_desc *desc; - struct mbuf *mnew, *m; + struct mbuf *m; uint32_t hdr; int s, len; @@ -1206,24 +1208,24 @@ uath_data_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, /* there's probably a "bad CRC" flag somewhere in the descriptor.. */ - MGETHDR(mnew, M_DONTWAIT, MT_DATA); - if (mnew == NULL) { - printf("%s: could not allocate rx mbuf\n", - USBDEVNAME(sc->sc_dev)); + MGETHDR(m, M_DONTWAIT, MT_DATA); + if (m == NULL) { ifp->if_ierrors++; goto skip; } - MCLGET(mnew, M_DONTWAIT); - if (!(mnew->m_flags & M_EXT)) { - printf("%s: could not allocate rx mbuf cluster\n", + + /* grab a new Rx buffer */ + ndata = SLIST_FIRST(&sc->rx_freelist); + if (ndata == NULL) { + printf("%s: could not allocate Rx buffer\n", USBDEVNAME(sc->sc_dev)); - m_freem(mnew); + m_freem(m); ifp->if_ierrors++; goto skip; } + SLIST_REMOVE_HEAD(&sc->rx_freelist, next); - m = data->m; - data->m = mnew; + MEXTADD(m, data->buf, sc->rxbufsz, 0, uath_free_rx_data, data); /* finalize mbuf */ m->m_pkthdr.rcvif = ifp; @@ -1231,7 +1233,7 @@ uath_data_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, m->m_pkthdr.len = m->m_len = betoh32(desc->len) - sizeof (struct uath_rx_desc); - data->buf = mtod(data->m, uint8_t *); + data = ndata; wh = mtod(m, struct ieee80211_frame *); if ((wh->i_fc[1] & IEEE80211_FC1_WEP) && @@ -1270,6 +1272,7 @@ uath_data_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, #endif s = splnet(); + sc->sc_refcnt++; ni = ieee80211_find_rxnode(ic, wh); ieee80211_input(ifp, m, ni, (int)betoh32(desc->rssi), 0); @@ -1278,9 +1281,10 @@ uath_data_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, splx(s); skip: /* setup a new transfer */ - usbd_setup_xfer(xfer, sc->data_rx_pipe, data, data->buf, sc->rxbufsz, - USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, uath_data_rxeof); - (void)usbd_transfer(xfer); + usbd_setup_xfer(data->xfer, sc->data_rx_pipe, data, data->buf, + sc->rxbufsz, USBD_SHORT_XFER_OK | USBD_NO_COPY, USBD_NO_TIMEOUT, + uath_data_rxeof); + (void)usbd_transfer(data->xfer); } Static int @@ -1778,7 +1782,7 @@ uath_set_rates(struct uath_softc *sc, const struct ieee80211_rateset *rs) bzero(&rates, sizeof rates); rates.magic1 = htobe32(0x02); - rates.size = htobe32(1 + UATH_MAX_NRATES); + rates.size = htobe32(1 + sizeof rates.rates); rates.nrates = rs->rs_nrates; bcopy(rs->rs_rates, rates.rates, rs->rs_nrates); @@ -1877,17 +1881,18 @@ uath_init(struct ifnet *ifp) * Queue Rx data xfers. */ for (i = 0; i < UATH_RX_DATA_LIST_COUNT; i++) { - struct uath_rx_data *data = &sc->rx_data[i]; + struct uath_rx_data *data = SLIST_FIRST(&sc->rx_freelist); usbd_setup_xfer(data->xfer, sc->data_rx_pipe, data, data->buf, - sc->rxbufsz, USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, - uath_data_rxeof); + sc->rxbufsz, USBD_SHORT_XFER_OK | USBD_NO_COPY, + USBD_NO_TIMEOUT, uath_data_rxeof); error = usbd_transfer(data->xfer); if (error != USBD_IN_PROGRESS && error != 0) { printf("%s: could not queue Rx transfer\n", USBDEVNAME(sc->sc_dev)); goto fail; } + SLIST_REMOVE_HEAD(&sc->rx_freelist, next); } error = uath_cmd_read(sc, UATH_CMD_07, 0, NULL, &val, diff --git a/sys/dev/usb/if_uathvar.h b/sys/dev/usb/if_uathvar.h index d73d6206662..8255c55513d 100644 --- a/sys/dev/usb/if_uathvar.h +++ b/sys/dev/usb/if_uathvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_uathvar.h,v 1.2 2006/09/16 19:56:44 damien Exp $ */ +/* $OpenBSD: if_uathvar.h,v 1.3 2006/09/20 19:47:17 damien Exp $ */ /*- * Copyright (c) 2006 @@ -24,6 +24,8 @@ #define UATH_RX_DATA_LIST_COUNT 1 /* 128 */ #define UATH_RX_CMD_LIST_COUNT 1 /* 30 */ +#define UATH_RX_DATA_POOL_COUNT (UATH_RX_DATA_LIST_COUNT + 24) + #define UATH_DATA_TIMEOUT 10000 #define UATH_CMD_TIMEOUT 1000 @@ -59,10 +61,10 @@ struct uath_tx_data { }; struct uath_rx_data { - struct uath_softc *sc; - usbd_xfer_handle xfer; - uint8_t *buf; - struct mbuf *m; + struct uath_softc *sc; + usbd_xfer_handle xfer; + uint8_t *buf; + SLIST_ENTRY(uath_rx_data) next; }; struct uath_tx_cmd { @@ -90,6 +92,7 @@ struct uath_wme_settings { /* condvars */ #define UATH_COND_INIT(sc) ((caddr_t)sc + 1) +#define UATH_COND_NOREF(sc) ((caddr_t)sc + 2) /* flags for sending firmware commands */ #define UATH_CMD_FLAG_ASYNC (1 << 0) @@ -97,57 +100,61 @@ struct uath_wme_settings { #define UATH_CMD_FLAG_MAGIC (1 << 2) struct uath_softc { - USBBASEDEVICE sc_dev; - struct ieee80211com sc_ic; - int (*sc_newstate)(struct ieee80211com *, - enum ieee80211_state, int); + USBBASEDEVICE sc_dev; + struct ieee80211com sc_ic; + int (*sc_newstate)(struct ieee80211com *, + enum ieee80211_state, int); + + struct uath_tx_data tx_data[UATH_TX_DATA_LIST_COUNT]; + struct uath_rx_data rx_data[UATH_RX_DATA_POOL_COUNT]; - struct uath_tx_data tx_data[UATH_TX_DATA_LIST_COUNT]; - struct uath_rx_data rx_data[UATH_RX_DATA_LIST_COUNT]; + struct uath_tx_cmd tx_cmd[UATH_TX_CMD_LIST_COUNT]; + struct uath_rx_cmd rx_cmd[UATH_RX_CMD_LIST_COUNT]; - struct uath_tx_cmd tx_cmd[UATH_TX_CMD_LIST_COUNT]; - struct uath_rx_cmd rx_cmd[UATH_RX_CMD_LIST_COUNT]; + SLIST_HEAD(, uath_rx_data) rx_freelist; - int sc_flags; + int sc_flags; + int sc_dying; + int sc_refcnt; - int data_idx; - int cmd_idx; - int tx_queued; + int data_idx; + int cmd_idx; + int tx_queued; - usbd_device_handle sc_udev; - usbd_interface_handle sc_iface; + usbd_device_handle sc_udev; + usbd_interface_handle sc_iface; - usbd_pipe_handle data_tx_pipe; - usbd_pipe_handle data_rx_pipe; - usbd_pipe_handle cmd_tx_pipe; - usbd_pipe_handle cmd_rx_pipe; + usbd_pipe_handle data_tx_pipe; + usbd_pipe_handle data_rx_pipe; + usbd_pipe_handle cmd_tx_pipe; + usbd_pipe_handle cmd_rx_pipe; - enum ieee80211_state sc_state; - int sc_arg; - struct usb_task sc_task; + enum ieee80211_state sc_state; + int sc_arg; + struct usb_task sc_task; - struct timeout scan_to; - struct timeout stat_to; + struct timeout scan_to; + struct timeout stat_to; - int sc_tx_timer; + int sc_tx_timer; - int rxbufsz; + int rxbufsz; #if NBPFILTER > 0 - caddr_t sc_drvbpf; + caddr_t sc_drvbpf; union { struct uath_rx_radiotap_header th; uint8_t pad[64]; - } sc_rxtapu; -#define sc_rxtap sc_rxtapu.th - int sc_rxtap_len; + } sc_rxtapu; +#define sc_rxtap sc_rxtapu.th + int sc_rxtap_len; union { struct uath_tx_radiotap_header th; uint8_t pad[64]; - } sc_txtapu; -#define sc_txtap sc_txtapu.th - int sc_txtap_len; + } sc_txtapu; +#define sc_txtap sc_txtapu.th + int sc_txtap_len; #endif }; |