summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien Bergamini <damien@cvs.openbsd.org>2006-09-20 19:47:18 +0000
committerDamien Bergamini <damien@cvs.openbsd.org>2006-09-20 19:47:18 +0000
commit7d8d5a55d40262b0b99fdaad4a31450af6ec111a (patch)
treeb7df8e2fb6ab514da4f0884695004cde068c42e0
parent95ffeb8386a13b4e218f96731413b83602d55974 (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.c109
-rw-r--r--sys/dev/usb/if_uathvar.h81
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
};