=== ./if_rsu.c
==================================================================
--- ./if_rsu.c	(revision 266497)
+++ ./if_rsu.c	(local)
@@ -128,7 +128,10 @@
 static device_probe_t   rsu_match;
 static device_attach_t  rsu_attach;
 static device_detach_t  rsu_detach;
-static usb_callback_t   rsu_bulk_tx_callback;
+static usb_callback_t   rsu_bulk_tx_callback_0;
+static usb_callback_t   rsu_bulk_tx_callback_1;
+static usb_callback_t   rsu_bulk_tx_callback_2;
+static usb_callback_t   rsu_bulk_tx_callback_3;
 static usb_callback_t   rsu_bulk_rx_callback;
 static usb_error_t	rsu_do_request(struct rsu_softc *,
 			    struct usb_device_request *, void *);
@@ -241,7 +244,7 @@
 			.pipe_bof = 1,
 			.force_short_xfer = 1
 		},
-		.callback = rsu_bulk_tx_callback,
+		.callback = rsu_bulk_tx_callback_0,
 		.timeout = RSU_TX_TIMEOUT
 	},
 	[RSU_BULK_TX_BK] = {
@@ -254,7 +257,7 @@
 			.pipe_bof = 1,
 			.force_short_xfer = 1
 		},
-		.callback = rsu_bulk_tx_callback,
+		.callback = rsu_bulk_tx_callback_1,
 		.timeout = RSU_TX_TIMEOUT
 	},
 	[RSU_BULK_TX_VI] = {
@@ -267,7 +270,7 @@
 			.pipe_bof = 1,
 			.force_short_xfer = 1
 		},
-		.callback = rsu_bulk_tx_callback,
+		.callback = rsu_bulk_tx_callback_2,
 		.timeout = RSU_TX_TIMEOUT
 	},
 	[RSU_BULK_TX_VO] = {
@@ -280,7 +283,7 @@
 			.pipe_bof = 1,
 			.force_short_xfer = 1
 		},
-		.callback = rsu_bulk_tx_callback,
+		.callback = rsu_bulk_tx_callback_3,
 		.timeout = RSU_TX_TIMEOUT
 	},
 };
@@ -598,10 +601,13 @@
 	if (error != 0)
 		return (error);
 
-	STAILQ_INIT(&sc->sc_tx_active);
 	STAILQ_INIT(&sc->sc_tx_inactive);
-	STAILQ_INIT(&sc->sc_tx_pending);
 
+	for (i = 0; i != RSU_MAX_TX_EP; i++) {
+		STAILQ_INIT(&sc->sc_tx_active[i]);
+		STAILQ_INIT(&sc->sc_tx_pending[i]);
+	}
+
 	for (i = 0; i < RSU_TX_LIST_COUNT; i++) {
 		STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, &sc->sc_tx[i], next);
 	}
@@ -843,10 +849,12 @@
 static int
 rsu_fw_cmd(struct rsu_softc *sc, uint8_t code, void *buf, int len)
 {
+	const uint8_t which = RSU_BULK_TX_VO - RSU_BULK_TX_BE;
 	struct rsu_data *data;
 	struct r92s_tx_desc *txd;
 	struct r92s_fw_cmd_hdr *cmd;
-	int cmdsz, xferlen;
+	int cmdsz;
+	int xferlen;
 
 	data = rsu_getbuf(sc);
 	if (data == NULL)
@@ -879,8 +887,8 @@
 
 	DPRINTFN(2, "Tx cmd code=0x%x len=0x%x\n", code, cmdsz);
 	data->buflen = xferlen;
-	STAILQ_INSERT_TAIL(&sc->sc_tx_pending, data, next);
-	usbd_transfer_start(sc->sc_xfer[RSU_BULK_TX_VO]);
+	STAILQ_INSERT_TAIL(&sc->sc_tx_pending[which], data, next);
+	usbd_transfer_start(sc->sc_xfer[which + RSU_BULK_TX_BE]);
 
 	return (0);
 }
@@ -1580,7 +1588,7 @@
 }
 
 static void
-rsu_bulk_tx_callback(struct usb_xfer *xfer, usb_error_t error)
+rsu_bulk_tx_callback_sub(struct usb_xfer *xfer, usb_error_t error, uint8_t which)
 {
 	struct rsu_softc *sc = usbd_xfer_softc(xfer);
 	struct ifnet *ifp = sc->sc_ifp;
@@ -1590,23 +1598,23 @@
 
 	switch (USB_GET_STATE(xfer)) {
 	case USB_ST_TRANSFERRED:
-		data = STAILQ_FIRST(&sc->sc_tx_active);
+		data = STAILQ_FIRST(&sc->sc_tx_active[which]);
 		if (data == NULL)
 			goto tr_setup;
 		DPRINTF("transfer done %p\n", data);
-		STAILQ_REMOVE_HEAD(&sc->sc_tx_active, next);
+		STAILQ_REMOVE_HEAD(&sc->sc_tx_active[which], next);
 		rsu_txeof(xfer, data);
 		STAILQ_INSERT_TAIL(&sc->sc_tx_inactive, data, next);
 		/* FALLTHROUGH */
 	case USB_ST_SETUP:
 tr_setup:
-		data = STAILQ_FIRST(&sc->sc_tx_pending);
+		data = STAILQ_FIRST(&sc->sc_tx_pending[which]);
 		if (data == NULL) {
 			DPRINTF("empty pending queue sc %p\n", sc);
 			return;
 		}
-		STAILQ_REMOVE_HEAD(&sc->sc_tx_pending, next);
-		STAILQ_INSERT_TAIL(&sc->sc_tx_active, data, next);
+		STAILQ_REMOVE_HEAD(&sc->sc_tx_pending[which], next);
+		STAILQ_INSERT_TAIL(&sc->sc_tx_active[which], data, next);
 		usbd_xfer_set_frame_data(xfer, 0, data->buf, data->buflen);
 		DPRINTF("submitting transfer %p\n", data);
 		usbd_transfer_submit(xfer);
@@ -1613,14 +1621,21 @@
 		rsu_start_locked(ifp, xfer);
 		break;
 	default:
-		data = STAILQ_FIRST(&sc->sc_tx_active);
-		if (data == NULL)
+		data = STAILQ_FIRST(&sc->sc_tx_active[which]);
+		if (data == NULL) {
+			if (error == USB_ERR_CANCELLED)
+				break;
+
+			usbd_xfer_set_stall(xfer);
 			goto tr_setup;
-		if (data->ni != NULL) {
-			ieee80211_free_node(data->ni);
-			data->ni = NULL;
-			ifp->if_oerrors++;
 		}
+
+		STAILQ_REMOVE_HEAD(&sc->sc_tx_active[which], next);
+		rsu_txeof(xfer, data);
+		STAILQ_INSERT_TAIL(&sc->sc_tx_inactive, data, next);
+
+		ifp->if_oerrors++;
+
 		if (error != USB_ERR_CANCELLED) {
 			usbd_xfer_set_stall(xfer);
 			goto tr_setup;
@@ -1629,6 +1644,30 @@
 	}
 }
 
+static void
+rsu_bulk_tx_callback_0(struct usb_xfer *xfer, usb_error_t error)
+{
+	rsu_bulk_tx_callback_sub(xfer, error, 0);
+}
+
+static void
+rsu_bulk_tx_callback_1(struct usb_xfer *xfer, usb_error_t error)
+{
+	rsu_bulk_tx_callback_sub(xfer, error, 1);
+}
+
+static void
+rsu_bulk_tx_callback_2(struct usb_xfer *xfer, usb_error_t error)
+{
+	rsu_bulk_tx_callback_sub(xfer, error, 2);
+}
+
+static void
+rsu_bulk_tx_callback_3(struct usb_xfer *xfer, usb_error_t error)
+{
+	rsu_bulk_tx_callback_sub(xfer, error, 3);
+}
+
 static int
 rsu_tx_start(struct rsu_softc *sc, struct ieee80211_node *ni, 
     struct mbuf *m0, struct rsu_data *data, struct usb_xfer *xfer_self)
@@ -1639,15 +1678,11 @@
 	struct ieee80211_frame *wh;
 	struct ieee80211_key *k = NULL;
 	struct r92s_tx_desc *txd;
-	struct usb_xfer *xfer;
-	uint8_t type, tid = 0;
-	int hasqos, xferlen;
-	struct usb_xfer *rsu_pipes[4] = {
-		sc->sc_xfer[RSU_BULK_TX_BE],
-		sc->sc_xfer[RSU_BULK_TX_BK],
-		sc->sc_xfer[RSU_BULK_TX_VI],
-		sc->sc_xfer[RSU_BULK_TX_VO]
-	};
+	uint8_t type;
+	uint8_t tid = 0;
+	uint8_t which;
+	int hasqos;
+	int xferlen;
 
 	RSU_ASSERT_LOCKED(sc);
 
@@ -1668,12 +1703,12 @@
 	switch (type) {
 	case IEEE80211_FC0_TYPE_CTL:
 	case IEEE80211_FC0_TYPE_MGT:
-		xfer = sc->sc_xfer[RSU_BULK_TX_VO];
+		which = RSU_BULK_TX_VO - RSU_BULK_TX_BE;
 		break;
 	default:
 		KASSERT(M_WME_GETAC(m0) < 4,
 		    ("unsupported WME pipe %d", M_WME_GETAC(m0)));
-		xfer = rsu_pipes[M_WME_GETAC(m0)];
+		which = M_WME_GETAC(m0) + RSU_BULK_TX_BE;
 		break;
 	}
 	hasqos = 0;
@@ -1735,10 +1770,10 @@
 	data->buflen = xferlen;
 	data->ni = ni;
 	data->m = m0;
-	STAILQ_INSERT_TAIL(&sc->sc_tx_pending, data, next);
+	STAILQ_INSERT_TAIL(&sc->sc_tx_pending[which], data, next);
 
-	if (xfer != xfer_self)
-		usbd_transfer_start(xfer);
+	if (sc->sc_xfer[which + RSU_BULK_TX_BE] != xfer_self)
+		usbd_transfer_start(sc->sc_xfer[which + RSU_BULK_TX_BE]);
 	return (0);
 }
 
@@ -2073,6 +2108,7 @@
 static int
 rsu_fw_loadsection(struct rsu_softc *sc, const uint8_t *buf, int len)
 {
+	const uint8_t which = RSU_BULK_TX_VO - RSU_BULK_TX_BE;
 	struct rsu_data *data;
 	struct r92s_tx_desc *txd;
 	int mlen;
@@ -2093,11 +2129,11 @@
 		memcpy(&txd[1], buf, mlen);
 		data->buflen = sizeof(*txd) + mlen;
 		DPRINTF("starting transfer %p\n", data);
-		STAILQ_INSERT_TAIL(&sc->sc_tx_pending, data, next);
+		STAILQ_INSERT_TAIL(&sc->sc_tx_pending[which], data, next);
 		buf += mlen;
 		len -= mlen;
 	}
-	usbd_transfer_start(sc->sc_xfer[RSU_BULK_TX_VO]);
+	usbd_transfer_start(sc->sc_xfer[RSU_BULK_TX_BE + which]);
 
 	return (0);
 }
=== ./if_rsureg.h
==================================================================
--- ./if_rsureg.h	(revision 266497)
+++ ./if_rsureg.h	(local)
@@ -735,6 +735,8 @@
 #define	RSU_UNLOCK(sc)			mtx_unlock(&(sc)->sc_mtx)
 #define	RSU_ASSERT_LOCKED(sc)		mtx_assert(&(sc)->sc_mtx, MA_OWNED)
 
+#define	RSU_MAX_TX_EP			4
+
 struct rsu_softc {
 	struct ifnet			*sc_ifp;
 	device_t			sc_dev;
@@ -764,9 +766,9 @@
 
 	STAILQ_HEAD(, rsu_data)		sc_rx_active;
 	STAILQ_HEAD(, rsu_data)		sc_rx_inactive;
-	STAILQ_HEAD(, rsu_data)		sc_tx_active;
+	STAILQ_HEAD(, rsu_data)		sc_tx_active[RSU_MAX_TX_EP];
 	STAILQ_HEAD(, rsu_data)		sc_tx_inactive;
-	STAILQ_HEAD(, rsu_data)		sc_tx_pending;
+	STAILQ_HEAD(, rsu_data)		sc_tx_pending[RSU_MAX_TX_EP];
 
 	union {
 		struct rsu_rx_radiotap_header th;
