PERFORCE change 172914 for review

Hans Petter Selasky hselasky at FreeBSD.org
Sun Jan 10 11:49:15 UTC 2010


http://p4web.freebsd.org/chv.cgi?CH=172914

Change 172914 by hselasky at hselasky_laptop001 on 2010/01/10 11:48:34

	
	USB WLAN:
		- fixes and corrections to RUN driver.
		- patch by: HPS

Affected files ...

.. //depot/projects/usb/src/sys/dev/usb/wlan/if_run.c#2 edit
.. //depot/projects/usb/src/sys/dev/usb/wlan/if_runreg.h#2 edit
.. //depot/projects/usb/src/sys/dev/usb/wlan/if_runvar.h#2 edit

Differences ...

==== //depot/projects/usb/src/sys/dev/usb/wlan/if_run.c#2 (text+ko) ====

@@ -75,7 +75,7 @@
 #define USB_DEBUG_VAR run_debug
 #include <dev/usb/usb_debug.h>
 
-#include "rt2860reg.h"		/* shared with ral(4) */
+#include "if_runreg.h"		/* shared with ral(4) */
 #include "if_runvar.h"
 
 #define nitems(_a)      (sizeof((_a)) / sizeof((_a)[0]))
@@ -266,15 +266,22 @@
 static device_detach_t	run_detach;
 
 static usb_callback_t	run_bulk_rx_callback;
-static usb_callback_t	run_bulk_tx_callback;
+static usb_callback_t	run_bulk_tx_callback0;
+static usb_callback_t	run_bulk_tx_callback1;
+static usb_callback_t	run_bulk_tx_callback2;
+static usb_callback_t	run_bulk_tx_callback3;
+static usb_callback_t	run_bulk_tx_callback4;
+static usb_callback_t	run_bulk_tx_callback5;
 
+static void		run_bulk_tx_callbackN(struct usb_xfer *xfer, 
+			    usb_error_t error, unsigned int index);
 static struct ieee80211vap *run_vap_create(struct ieee80211com *,
                             const char name[IFNAMSIZ], int unit, int opmode,
                             int flags, const uint8_t bssid[IEEE80211_ADDR_LEN],
                             const uint8_t mac[IEEE80211_ADDR_LEN]);
 static void             run_vap_delete(struct ieee80211vap *);
-static void		run_setup_tx_list(struct run_softc *);
-static void		run_unsetup_tx_list(struct run_softc *);
+static void		run_setup_tx_list(struct run_softc *sc, struct run_endpoint_queue *pq);
+static void		run_unsetup_tx_list(struct run_softc *sc, struct run_endpoint_queue *pq);
 static int		run_load_microcode(struct run_softc *);
 static int		run_reset(struct run_softc *);
 static usb_error_t	run_do_request(struct run_softc *sc,
@@ -314,9 +321,9 @@
 static void		run_iter_func(void *, struct ieee80211_node *);
 static void		run_newassoc(struct ieee80211_node *, int);
 static void		run_rx_frame(struct run_softc *, struct mbuf *, uint32_t);
-static void		run_tx_free(struct run_tx_data *, int);
+static void		run_tx_free(struct run_endpoint_queue *pq, struct run_tx_data *, int);
 static void		run_set_tx_desc(struct run_softc *, struct run_tx_data *,
-			    uint8_t, uint8_t, uint8_t, uint8_t, uint8_t);
+			    uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t);
 static int		run_tx(struct run_softc *, struct mbuf *,
 			    struct ieee80211_node *);
 static int		run_tx_mgt(struct run_softc *, struct mbuf *, struct ieee80211_node *);
@@ -326,7 +333,6 @@
 			    struct ieee80211_node *, const struct ieee80211_bpf_params *);
 static int		run_raw_xmit(struct ieee80211_node *, struct mbuf *,
 			    const struct ieee80211_bpf_params *);
-static void		run_start_task(void *, int);
 static void		run_start(struct ifnet *);
 static int		run_ioctl(struct ifnet *, u_long, caddr_t);
 static void		run_select_chan_group(struct run_softc *, int);
@@ -363,6 +369,7 @@
 static void		run_init(void *);
 static void		run_init_locked(struct run_softc *);
 static void		run_stop(void *);
+static void		run_delay(struct run_softc *, unsigned int);
 
 static const struct {
 	uint32_t	reg;
@@ -406,7 +413,7 @@
 	.direction = UE_DIR_OUT,
 	.bufsize = RUN_MAX_TXSZ,
 	.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
-	.callback = run_bulk_tx_callback,
+	.callback = run_bulk_tx_callback0,
 	.timeout = 5000,	/* ms */
     },
     [RUN_BULK_TX_BK] = {
@@ -416,7 +423,7 @@
 	.ep_index = 1,
 	.bufsize = RUN_MAX_TXSZ,
 	.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
-	.callback = run_bulk_tx_callback,
+	.callback = run_bulk_tx_callback1,
 	.timeout = 5000,	/* ms */
     },
     [RUN_BULK_TX_VI] = {
@@ -426,7 +433,7 @@
 	.ep_index = 2,
 	.bufsize = RUN_MAX_TXSZ,
 	.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
-	.callback = run_bulk_tx_callback,
+	.callback = run_bulk_tx_callback2,
 	.timeout = 5000,	/* ms */
     },
     [RUN_BULK_TX_VO] = {
@@ -436,18 +443,17 @@
 	.ep_index = 3,
 	.bufsize = RUN_MAX_TXSZ,
 	.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
-	.callback = run_bulk_tx_callback,
+	.callback = run_bulk_tx_callback3,
 	.timeout = 5000,	/* ms */
     },
-#ifdef SIX	/* see enum in if_runvar.h */
     [RUN_BULK_TX_HCCA] = {
 	.type = UE_BULK,
 	.endpoint = UE_ADDR_ANY,
 	.direction = UE_DIR_OUT,
 	.ep_index = 4,
 	.bufsize = RUN_MAX_TXSZ,
-	.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
-	.callback = run_bulk_tx_callback,
+	.flags = {.pipe_bof = 1,.force_short_xfer = 1,.no_pipe_ok = 1,},
+	.callback = run_bulk_tx_callback4,
 	.timeout = 5000,	/* ms */
     },
     [RUN_BULK_TX_PRIO] = {
@@ -456,11 +462,10 @@
 	.direction = UE_DIR_OUT,
 	.ep_index = 5,
 	.bufsize = RUN_MAX_TXSZ,
-	.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
-	.callback = run_bulk_tx_callback,
+	.flags = {.pipe_bof = 1,.force_short_xfer = 1,.no_pipe_ok = 1,},
+	.callback = run_bulk_tx_callback5,
 	.timeout = 5000,	/* ms */
     },
-#endif	/* SIX */
     [RUN_BULK_RX] = {
 	.type = UE_BULK,
 	.endpoint = UE_ADDR_ANY,
@@ -502,26 +507,16 @@
 
 	mtx_init(&sc->sc_mtx, device_get_nameunit(sc->sc_dev),
 	    MTX_NETWORK_LOCK, MTX_DEF);
-	mtx_init(&sc->rx_cb_mtx, device_get_nameunit(sc->sc_dev),
-	    "USB NIC Rx callback", MTX_DEF);	/* for Rx callback lock */
 
 	iface_index = RT2860_IFACE_INDEX;
 	/* Rx transfer has own lock */
 	error = usbd_transfer_setup(uaa->device, &iface_index,
-	    sc->sc_xfer, run_config, RUN_N_XFER -1, sc, &sc->sc_mtx);
+	    sc->sc_xfer, run_config, RUN_N_XFER, sc, &sc->sc_mtx);
 	if (error) {
 		device_printf(self, "could not allocate USB Tx transfers, "
 		    "err=%s\n", usbd_errstr(error));
 		goto detach;
 	}
-	error = usbd_transfer_setup(uaa->device, &iface_index,
-	    &sc->sc_xfer[RUN_N_XFER -1], &run_config[RUN_N_XFER -1], 1,
-	    sc, &sc->rx_cb_mtx);
-	if (error) {
-		device_printf(self, "could not allocate USB Rx transfers, "
-		    "err=%s\n", usbd_errstr(error));
-		goto detach;
-	}
 
 	RUN_LOCK(sc);
 
@@ -533,7 +528,7 @@
 		}
 		if (sc->mac_rev != 0 && sc->mac_rev != 0xffffffff)
 			break;
-		DELAY(10);
+		run_delay(sc, 10);
 	}
 	if (ntries == 100) {
 		printf("%s: timeout waiting for NIC to initialize\n",
@@ -663,13 +658,15 @@
 	struct run_softc	*sc = device_get_softc(self);
 	struct ifnet		*ifp = sc->sc_ifp;
 	struct ieee80211com	*ic;
+	int i;
 
 	/* stop all USB transfers */
 	usbd_transfer_unsetup(sc->sc_xfer, RUN_N_XFER);
 
 	RUN_LOCK(sc);
 	/* free TX list, if any */
-	run_unsetup_tx_list(sc);
+	for (i = 0; i != RUN_EP_QUEUES; i++)
+		run_unsetup_tx_list(sc, &sc->sc_epq[i]);
 	RUN_UNLOCK(sc);
 
 	if (ifp) {
@@ -679,9 +676,8 @@
 	}
 
 	mtx_destroy(&sc->sc_mtx);
-	mtx_destroy(&sc->rx_cb_mtx);
 
-	return 0;
+	return (0);
 }
 
 static struct ieee80211vap *
@@ -720,7 +716,6 @@
 	vap->iv_newstate = run_newstate;
 
 	TASK_INIT(&rvp->amrr_task, 0, run_amrr_cb, rvp);
-	TASK_INIT(&sc->start_task, 0, run_start_task, ic->ic_ifp);
 	TASK_INIT(&sc->wme_task, 0, run_wme_update_cb, ic);
 	callout_init((struct callout *)&rvp->amrr_ch, 1);
 	ieee80211_amrr_init(&rvp->amrr, vap,
@@ -763,38 +758,36 @@
 }
 
 static void
-run_setup_tx_list(struct run_softc *sc)
+run_setup_tx_list(struct run_softc *sc, struct run_endpoint_queue *pq)
 {
-	struct run_tx_data	*data;
+	struct run_tx_data *data;
 
-	sc->tx_nfree = 0;
-	STAILQ_INIT(&sc->tx_q);
-	STAILQ_INIT(&sc->tx_free);
+	memset(pq, 0, sizeof(*pq));
 
-	for (data = &sc->txq[0];
-	    data < &sc->txq[RUN_TX_RING_COUNT]; data++){
-		memset(data->desc, 0, sizeof (struct rt2870_txd) +
-		    sizeof (struct rt2860_txwi));
+	STAILQ_INIT(&pq->tx_qh);
+	STAILQ_INIT(&pq->tx_fh);
 
+	for (data = &pq->tx_data[0];
+	    data < &pq->tx_data[RUN_TX_RING_COUNT]; data++) {
 		data->sc = sc;
-		STAILQ_INSERT_TAIL(&sc->tx_free, data, next);
-		sc->tx_nfree++;
+		STAILQ_INSERT_TAIL(&pq->tx_fh, data, next);
 	}
+	pq->tx_nfree = RUN_TX_RING_COUNT;
 }
 
 static void
-run_unsetup_tx_list(struct run_softc *sc)
+run_unsetup_tx_list(struct run_softc *sc, struct run_endpoint_queue *pq)
 {
-	struct run_tx_data	*data;
+	struct run_tx_data *data;
 
 	/* make sure any subsequent use of the queues will fail */
-	sc->tx_nfree = 0;
-	STAILQ_INIT(&sc->tx_q);
-	STAILQ_INIT(&sc->tx_free);
+	pq->tx_nfree = 0;
+	STAILQ_INIT(&pq->tx_fh);
+	STAILQ_INIT(&pq->tx_qh);
 
 	/* free up all node references and mbufs */
-	for (data = &sc->txq[0];
-	    data < &sc->txq[RUN_TX_RING_COUNT]; data++){
+	for (data = &pq->tx_data[0];
+	    data < &pq->tx_data[RUN_TX_RING_COUNT]; data++){
 		if (data->m != NULL) {
 			m_freem(data->m);
 			data->m = NULL;
@@ -864,8 +857,8 @@
 	if ((error = usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, NULL)) != 0)
 		return error;
 
-	/*TODO make macro */
-	usb_pause_mtx(&sc->sc_mtx, 10);
+	run_delay(sc, 10);
+
 	run_write(sc, RT2860_H2M_MAILBOX, 0);
 	if ((error = run_mcu_cmd(sc, RT2860_MCU_CMD_BOOT, 0)) != 0)
 		return error;
@@ -876,7 +869,7 @@
 			return error;
 		if (tmp & RT2860_MCU_READY)
 			break;
-		DELAY(1000);
+		run_delay(sc, 1000);
 	}
 	if (ntries == 1000) {
 		printf("%s: timeout waiting for MCU to initialize\n",
@@ -917,7 +910,7 @@
 			break;
 		DPRINTFN(1, "Control request failed, %s (retrying)\n",
 		    usbd_errstr(err));
-		DELAY(10);
+		run_delay(sc, 10);
 	}
 	return (err);
 }
@@ -1038,7 +1031,7 @@
 			return error;
 		if (!(tmp & RT3070_EFSROM_KICK))
 			break;
-		DELAY(2);
+		run_delay(sc, 2);
 	}
 	if (ntries == 100)
 		return ETIMEDOUT;
@@ -1603,6 +1596,7 @@
 		break;
 	default:
 		DPRINTFN(6, "undefined case\n");
+		break;
 	}
 
 	RUN_UNLOCK(sc);
@@ -2071,7 +2065,7 @@
 	return rxchain;
 }
 
-static __inline void	/* big but inlined only once */
+static void
 run_rx_frame(struct run_softc *sc, struct mbuf *m, uint32_t dmalen)
 {
 	struct ifnet		*ifp = sc->sc_ifp;
@@ -2089,6 +2083,8 @@
 	rxwi = mtod(m, struct rt2860_rxwi *);
 	len = le16toh(rxwi->len) & 0xfff;
 	if (__predict_false(len > dmalen)) {
+		m_freem(m);
+		ifp->if_ierrors++;
 		DPRINTF("bad RXWI length %u > %u\n", len, dmalen);
 		return;
 	}
@@ -2097,6 +2093,7 @@
 	flags = le32toh(rxd->flags);
 
 	if (__predict_false(flags & (RT2860_RX_CRCERR | RT2860_RX_ICVERR))) {
+		m_freem(m);
 		ifp->if_ierrors++;
 		DPRINTF("%s error.\n", (flags & RT2860_RX_CRCERR)?"CRC":"ICV");
 		return;
@@ -2133,17 +2130,14 @@
 	m->m_pkthdr.rcvif = ifp;
 	m->m_pkthdr.len = m->m_len = len;
 
-#if 1
-	DPRINTFN(3, "addr1 %s\n", ether_sprintf(mtod(m, struct ieee80211_frame_min *)->i_addr1));
-#endif
-
 	ni = ieee80211_find_rxnode(ic,
 	    mtod(m, struct ieee80211_frame_min *));
 	if (ni != NULL) {
 		(void)ieee80211_input(ni, m, rssi, nf);
 		ieee80211_free_node(ni);
-	} else
+	} else {
 		(void)ieee80211_input_all(ic, m, rssi, nf);
+	}
 
 	if(__predict_false(ieee80211_radiotap_active(ic))){
 		struct run_rx_radiotap_header *tap = &sc->sc_rxtap;
@@ -2180,10 +2174,7 @@
 			}
 			break;
 		}
-		//ieee80211_radiotap_rx(vap, m);
 	}
-
-	return;
 }
 
 static void
@@ -2191,9 +2182,10 @@
 {
 	struct run_softc	*sc = usbd_xfer_softc(xfer);
 	struct ifnet		*ifp = sc->sc_ifp;
-	struct mbuf		*m, *m0;
-	uint32_t	dmalen;
-	int		xferlen;
+	struct mbuf		*m = NULL;
+	struct mbuf		*m0;
+	uint32_t		dmalen;
+	int			xferlen;
 
 	usbd_xfer_status(xfer, &xferlen, NULL, NULL, NULL);
 
@@ -2205,117 +2197,113 @@
 		if (xferlen < sizeof (uint32_t) +
 		    sizeof (struct rt2860_rxwi) + sizeof (struct rt2870_rxd)) {
 			DPRINTF("xfer too short %d\n", xferlen);
-			goto tr_set;
+			goto tr_setup;
 		}
 
-#if 1
-		if(xferlen > MJUMPAGESIZE)
-			DPRINTF("rx buf overflow\n");
-#endif
-
 		m = sc->rx_m;
 		sc->rx_m = NULL;
-		m->m_pkthdr.len = m->m_len = xferlen;
-
-		mtx_unlock(&sc->rx_cb_mtx);
-		/* HW can aggregate multiple 802.11 frames in a single USB xfer */
-		for(;;){
-			dmalen = le32toh(*mtod(m, uint32_t *)) & 0xffff;
-
-			if (__predict_false(dmalen == 0 || (dmalen & 3) != 0)) {
-				DPRINTF("bad DMA length %u\n", dmalen);
-				break;
-			}
-			if (__predict_false(dmalen + 8 > xferlen)) {
-				DPRINTF("bad DMA length %u > %d\n",
-				    dmalen + 8, xferlen);
-				break;
-			}
-
-			/* If it is the last one or a single frame, we won't copy. */
-			if((xferlen -= dmalen + 8) <= 8){
-				/* trim 32-bit DMA-len header */
-				m->m_data += 4;
-				m->m_pkthdr.len = m->m_len -= 4;
-				run_rx_frame(sc, m, dmalen);
-				break;
-			}
-
-			/* copy aggregated frames to another mbuf */
-			m0 = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
-			if (__predict_false(m0 == NULL)) {
-				DPRINTF("could not allocate mbuf\n");
-				ifp->if_ierrors++;
-				return;
-			}
-			m_copydata(m, 4 /* skip 32-bit DMA-len header */,
-			    dmalen + sizeof(struct rt2870_rxd), mtod(m0, caddr_t));
-			m0->m_pkthdr.len = m0->m_len =
-			    dmalen + sizeof(struct rt2870_rxd);
-			run_rx_frame(sc, m0, dmalen);
 
-			/* update data ptr */
-			m->m_data += dmalen + 8;
-			m->m_pkthdr.len = m->m_len -= dmalen + 8;
-		}
-
-		mtx_lock(&sc->rx_cb_mtx);
-
 		/* FALLTHROUGH */
 	case USB_ST_SETUP:
-		if(__predict_false(sc->rx_m != NULL)){
-			DPRINTF("rx buf is full\n");
-			ifp->if_ierrors++;
-			return;
+tr_setup:
+		if (sc->rx_m == NULL) {
+			sc->rx_m = m_getjcl(M_DONTWAIT, MT_DATA, M_PKTHDR,
+			    MJUMPAGESIZE /* xfer can be bigger than MCLBYTES */);
 		}
-		sc->rx_m = m_getjcl(M_DONTWAIT, MT_DATA, M_PKTHDR,
-		    MJUMPAGESIZE /* xfer can be begger than MCLBYTES */);
-		if (__predict_false(sc->rx_m == NULL)) {
-			DPRINTF("could not allocate mbuf\n");
+		if (sc->rx_m == NULL) {
+			DPRINTF("could not allocate mbuf - idle with stall\n");
 			ifp->if_ierrors++;
-			return;
+			usbd_xfer_set_stall(xfer);
+			usbd_xfer_set_frames(xfer, 0);
+		} else {
+			/*
+			 * Directly loading a mbuf cluster into DMA to
+			 * save some data copying. This works because
+			 * there is only one cluster.
+			 */
+			usbd_xfer_set_frame_data(xfer, 0, 
+			    mtod(sc->rx_m, caddr_t), RUN_MAX_RXSZ);
+			usbd_xfer_set_frames(xfer, 1);
 		}
-tr_set:
-		/*
-		 * directly loading a mbuf cluster into DMA
-		 * to save some data copying
-		 * This works because there is only one cluster.
-		 */
-		usbd_xfer_set_frame_data(xfer, 0, mtod(sc->rx_m, caddr_t),
-		    usbd_xfer_max_len(xfer));
 		usbd_transfer_submit(xfer);
+		break;
 
-		return;
-
 	default:	/* Error */
 		if (error != USB_ERR_CANCELLED) {
 			/* try to clear stall first */
 			usbd_xfer_set_stall(xfer);
-			if(__predict_true(sc->rx_m != NULL))
-				goto tr_set;
-			sc->rx_m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
-			if (__predict_false(sc->rx_m == NULL)) {
-				DPRINTF("could not allocate mbuf\n");
-				ifp->if_ierrors++;
-				return;
-			}
-				goto tr_set;
+
+			if (error == USB_ERR_TIMEOUT)
+				device_printf(sc->sc_dev, "device timeout\n");
+
+			ifp->if_ierrors++;
+
+			goto tr_setup;
 		}
 		if(sc->rx_m != NULL){
-			m_free(sc->rx_m);
+			m_freem(sc->rx_m);
 			sc->rx_m = NULL;
 		}
+		break;
+	}
+
+	if (m == NULL)
+		return;
+
+	/* inputting all the frames must be last */
+
+	RUN_UNLOCK(sc);
+
+	m->m_pkthdr.len = m->m_len = xferlen;
+
+	/* HW can aggregate multiple 802.11 frames in a single USB xfer */
+	for(;;) {
+		dmalen = le32toh(*mtod(m, uint32_t *)) & 0xffff;
+
+		if ((dmalen == 0) || ((dmalen & 3) != 0)) {
+			DPRINTF("bad DMA length %u\n", dmalen);
+			break;
+		}
+		if ((dmalen + 8) > xferlen) {
+			DPRINTF("bad DMA length %u > %d\n",
+			dmalen + 8, xferlen);
+			break;
+		}
+
+		/* If it is the last one or a single frame, we won't copy. */
+		if((xferlen -= dmalen + 8) <= 8){
+			/* trim 32-bit DMA-len header */
+			m->m_data += 4;
+			m->m_pkthdr.len = m->m_len -= 4;
+			run_rx_frame(sc, m, dmalen);
+			break;
+		}
+
+		/* copy aggregated frames to another mbuf */
+		m0 = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+		if (__predict_false(m0 == NULL)) {
+			DPRINTF("could not allocate mbuf\n");
+			ifp->if_ierrors++;
+			break;
+		}
+		m_copydata(m, 4 /* skip 32-bit DMA-len header */,
+		    dmalen + sizeof(struct rt2870_rxd), mtod(m0, caddr_t));
+		m0->m_pkthdr.len = m0->m_len =
+		    dmalen + sizeof(struct rt2870_rxd);
+		run_rx_frame(sc, m0, dmalen);
+
+		/* update data ptr */
+		m->m_data += dmalen + 8;
+		m->m_pkthdr.len = m->m_len -= dmalen + 8;
 	}
-	return;
+
+	RUN_LOCK(sc);
 }
 
-static __inline void
-run_tx_free(struct run_tx_data *data, int txerr)
+static void
+run_tx_free(struct run_endpoint_queue *pq,
+    struct run_tx_data *data, int txerr)
 {
-	struct run_softc	*sc = data->sc;
-	struct ifnet		*ifp = sc->sc_ifp;
-	struct ieee80211com	*ic = ifp->if_l2com;
-
 	if (data->m != NULL) {
 		if (data->m->m_flags & M_TXCB)
 			ieee80211_process_callback(data->ni, data->m,
@@ -2323,33 +2311,27 @@
 		m_freem(data->m);
 		data->m = NULL;
 
-		if(data->ni == NULL)
+		if(data->ni == NULL) {
 			DPRINTF("no node\n");
-		else{
+		} else {
 			ieee80211_free_node(data->ni);
 			data->ni = NULL;
 		}
 	}
 
-	STAILQ_INSERT_TAIL(&sc->tx_free, data, next);
-	sc->tx_nfree++;
-	if(__predict_false(ifp->if_drv_flags & IFF_DRV_OACTIVE &&
-	    sc->tx_nfree > RUN_TX_RING_COUNT - 2)){
-		/* call run_start() when tx ring gets 'almost' empty */
-		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
-		if(sc->dequeue == RUN_NO_DEQUEUE)
-			ieee80211_runtask(ic, &sc->start_task);
-	}
+	STAILQ_INSERT_TAIL(&pq->tx_fh, data, next);
+	pq->tx_nfree++;
 }
 
 static void
-run_bulk_tx_callback(struct usb_xfer *xfer, usb_error_t error)
+run_bulk_tx_callbackN(struct usb_xfer *xfer, usb_error_t error, unsigned int index)
 {
 	struct run_softc	*sc = usbd_xfer_softc(xfer);
 	struct ifnet		*ifp = sc->sc_ifp;
 	struct run_tx_data	*data;
 	struct ieee80211vap	*vap = NULL;
 	struct usb_page_cache	*pc;
+	struct run_endpoint_queue *pq = &sc->sc_epq[index];
 	struct mbuf		*m;
 	usb_frlength_t		size;
 	unsigned int		len;
@@ -2359,103 +2341,167 @@
 
 	switch (USB_GET_STATE(xfer)){
 	case USB_ST_TRANSFERRED:
-		DPRINTFN(11, "transfer complete, %d bytes\n", actlen);
+		DPRINTFN(11, "transfer complete: %d "
+		    "bytes @ index %d\n", actlen, index);
+
 		data = usbd_xfer_get_priv(xfer);
-		run_tx_free(data, 0);
+
+		run_tx_free(pq, data, 0);
+
 		usbd_xfer_set_priv(xfer, NULL);
 
 		ifp->if_opackets++;
 
 		/* FALLTHROUGH */
 	case USB_ST_SETUP:
-tr_set:;
-		data = STAILQ_FIRST(&sc->tx_q);
-		if(__predict_false(data == NULL)){
+tr_setup:
+		data = STAILQ_FIRST(&pq->tx_qh);
+		if(data == NULL)
 			break;
-		}
-		STAILQ_REMOVE_HEAD(&sc->tx_q, next);
+
+		STAILQ_REMOVE_HEAD(&pq->tx_qh, next);
 
 		m = data->m;
-		if (__predict_false(m->m_pkthdr.len > RUN_MAX_TXSZ)) {
+		if (m->m_pkthdr.len > RUN_MAX_TXSZ) {
 			DPRINTF("data overflow, %u bytes\n",
 			    m->m_pkthdr.len);
-			error = 10;	/* just give non 0 */
-			goto fail;	/* sorry for an extra goto */
+
+			ifp->if_oerrors++;
+
+			run_tx_free(pq, data, 1);
+
+			goto tr_setup;
 		}
 
 		pc = usbd_xfer_get_frame(xfer, 0);
-		size = sizeof(struct rt2870_txd) + sizeof(struct rt2860_txwi);
+		size = sizeof(data->desc);
 		usbd_copy_in(pc, 0, &data->desc, size);
 		usbd_m_copy_in(pc, size, m, 0, m->m_pkthdr.len);
 
-	if(data->ni != NULL){
-		if((vap = data->ni->ni_vap) != NULL);
-		if (__predict_false(ieee80211_radiotap_active_vap(vap))) {
+		vap = data->ni->ni_vap;
+		if (ieee80211_radiotap_active_vap(vap)) {
 			struct run_tx_radiotap_header *tap = &sc->sc_txtap;
 
 			tap->wt_flags = 0;
 			tap->wt_rate = rt2860_rates[data->ridx].rate;
 			tap->wt_chan_freq = htole16(vap->iv_bss->ni_chan->ic_freq);
 			tap->wt_chan_flags = htole16(vap->iv_bss->ni_chan->ic_flags);
-			tap->wt_hwqueue = data->qid;
+			tap->wt_hwqueue = index;
 			if (data->mcs & RT2860_PHY_SHPRE)
 				tap->wt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
 
 			ieee80211_radiotap_tx(vap, m);
 		}
-	}
+
 		/* align end on a 4-bytes boundary */
-		len = (size + 4 + m->m_pkthdr.len + 3) & ~3;
+		len = (size + m->m_pkthdr.len + 3) & ~3;
 
-		DPRINTFN(11, "sending frame len=%u xferlen=%u\n",
-		    m->m_pkthdr.len, len);
+		DPRINTFN(11, "sending frame len=%u xferlen=%u @ index %d\n",
+			m->m_pkthdr.len, len, index);
 
 		usbd_xfer_set_frame_len(xfer, 0, len);
 		usbd_xfer_set_priv(xfer, data);
 
 		usbd_transfer_submit(xfer);
 
+		RUN_UNLOCK(sc);
+		run_start(ifp);
+		RUN_LOCK(sc);
+
 		break;
+
 	default:
 		DPRINTF("USB transfer error, %s\n",
 		    usbd_errstr(error));
 
 		data = usbd_xfer_get_priv(xfer);
-fail:
+
 		ifp->if_oerrors++;
 
 		if (data != NULL) {
-			run_tx_free(data, error);
+			run_tx_free(pq, data, error);
 			usbd_xfer_set_priv(xfer, NULL);
 		}
 
-		if (error == USB_ERR_TIMEOUT){
-			device_printf(sc->sc_dev, "device timeout\n");
-			/* check if timeout is caused due to livelock */
-			run_usb_timeout(sc);
+		if (error != USB_ERR_CANCELLED) {
+			if (error == USB_ERR_TIMEOUT) {
+				device_printf(sc->sc_dev, "device timeout\n");
+
+				/* defer until later */
+				sc->sc_usb_timeout = 1;
+
+				/* XXX this should be in a separate task! */
+				run_usb_timeout(sc);
+			}
+
+			/*
+			 * Try to clear stall first, also if other
+			 * errors occur, hence clearing stall
+			 * introduces a 50 ms delay:
+			 */
+			usbd_xfer_set_stall(xfer);
+			goto tr_setup;
 		}
-		if (error == USB_ERR_STALLED)
-			usbd_xfer_set_stall(xfer);
-			goto tr_set;
 		break;
 	}
 }
 
 static void
+run_bulk_tx_callback0(struct usb_xfer *xfer, usb_error_t error)
+{
+	run_bulk_tx_callbackN(xfer, error, 0);
+}
+
+static void
+run_bulk_tx_callback1(struct usb_xfer *xfer, usb_error_t error)
+{
+	run_bulk_tx_callbackN(xfer, error, 1);
+}
+
+static void
+run_bulk_tx_callback2(struct usb_xfer *xfer, usb_error_t error)
+{
+	run_bulk_tx_callbackN(xfer, error, 2);
+}
+
+static void
+run_bulk_tx_callback3(struct usb_xfer *xfer, usb_error_t error)
+{
+	run_bulk_tx_callbackN(xfer, error, 3);
+}
+
+static void
+run_bulk_tx_callback4(struct usb_xfer *xfer, usb_error_t error)
+{
+	run_bulk_tx_callbackN(xfer, error, 4);
+}
+
+static void
+run_bulk_tx_callback5(struct usb_xfer *xfer, usb_error_t error)
+{
+	run_bulk_tx_callbackN(xfer, error, 5);
+}
+
+static void
 run_set_tx_desc(struct run_softc *sc, struct run_tx_data *data,
-    uint8_t wflags, uint8_t xflags, uint8_t opflags, uint8_t dflags, uint8_t type)
+	uint8_t wflags, uint8_t xflags, uint8_t opflags, uint8_t dflags,
+	uint8_t type, uint8_t pad)
 {
 	struct mbuf		*m = data->m;
 	struct ieee80211com	*ic = sc->sc_ifp->if_l2com;
+	struct ieee80211vap	*vap = &sc->sc_rvp->vap;
+	struct ieee80211_frame	*wh;
 	struct rt2870_txd	*txd;
 	struct rt2860_txwi	*txwi;
 	int	xferlen;
-	uint8_t	mcs, ridx = data->ridx;
+	uint8_t	mcs;
+	uint8_t ridx = data->ridx;
 
 	/* get MCS code from rate index */
 	data->mcs = mcs = rt2860_rates[ridx].mcs;
 
-	xferlen = sizeof (*txwi) + m->m_pkthdr.len;
+	xferlen = sizeof(*txwi) + m->m_pkthdr.len;
+
 	/* roundup to 32-bit alignment */
 	xferlen = (xferlen + 3) & ~3;
 
@@ -2469,7 +2515,7 @@
 	txwi->xflags = xflags;
 	txwi->wcid = (type == IEEE80211_FC0_TYPE_DATA) ?
 	    RUN_AID2WCID(data->ni->ni_associd) : 0xff;
-	txwi->len = htole16(m->m_pkthdr.len);
+	txwi->len = htole16(m->m_pkthdr.len - pad);
 	if (rt2860_rates[ridx].phy == IEEE80211_T_DS) {
 		txwi->phy = htole16(RT2860_PHY_CCK);
 		if (ridx != RT2860_RIDX_CCK1 &&
@@ -2479,9 +2525,6 @@
 		txwi->phy = htole16(RT2860_PHY_OFDM);
 	txwi->phy |= htole16(mcs);
 
-#if 1
-	struct ieee80211vap	*vap = &sc->sc_rvp->vap;
-	struct ieee80211_frame	*wh;
 	wh = mtod(m, struct ieee80211_frame *);
 
 	/* check if RTS/CTS or CTS-to-self protection is required */
@@ -2491,22 +2534,31 @@
 	      rt2860_rates[ridx].phy == IEEE80211_T_OFDM)))
 		txwi->txop = RT2860_TX_TXOP_HT | opflags;
 	else
-#endif
 		txwi->txop = RT2860_TX_TXOP_BACKOFF | opflags;
 }
 
+/* This function must be called locked */
 static int
 run_tx(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
 {
-	struct ifnet			*ifp = sc->sc_ifp;
 	struct ieee80211com		*ic = sc->sc_ifp->if_l2com;
 	struct ieee80211vap		*vap = &sc->sc_rvp->vap;
 	struct ieee80211_frame		*wh;
 	const struct ieee80211_txparam	*tp;
 	struct run_tx_data		*data;
-	uint16_t	qos, dur;
-	uint8_t		*frm, type, tid, qid, qflags, pad, xflags = 0;
-	int		hasqos, ridx, ctl_ridx, error = 0;
+	uint16_t	qos;
+	uint16_t	dur;
+	uint8_t		type;
+	uint8_t		tid;
+	uint8_t		qid;
+	uint8_t		qflags;
+	uint8_t		pad;
+	uint8_t		xflags = 0;
+	int		hasqos;
+	int		ridx;
+	int		ctl_ridx;
+
+	RUN_LOCK_ASSERT(sc, MA_OWNED);
 
 	wh = mtod(m, struct ieee80211_frame *);
 
@@ -2519,35 +2571,28 @@
 	 * seem to have only 4 TX bulk endpoints (Fukaumi Naoki).
 	 */
 	if ((hasqos = IEEE80211_QOS_HAS_SEQ(wh))) {
+		uint8_t	*frm;
+
 		if(IEEE80211_HAS_ADDR4(wh))
 			frm = ((struct ieee80211_qosframe_addr4 *)wh)->i_qos;
 		else
 			frm =((struct ieee80211_qosframe *)wh)->i_qos;
+
 		qos = le16toh(*(const uint16_t *)frm);
 		tid = qos & IEEE80211_QOS_TID;
+		qid = TID_TO_WME_AC(tid);
 		pad = 2;
-
-		/*
-		 * This is my best guess based on original code.
-		 * I don't have data sheet.
-		 */
-#ifdef	SIX
-		qid = tid <= 6? tid: 6;
-		qflags = qid < 5? RT2860_TX_QSEL_EDCA : RT2860_TX_QSEL_HCCA;
-#else
-		qid = TID_TO_WME_AC(tid);
-		qflags = RT2860_TX_QSEL_EDCA;
-#endif
-		DPRINTFN(8, "qos %d\tqid %d\ttid %d\tqflags %x\n",
-		    qos, qid, tid, qflags);
 	} else {
 		qos = 0;
 		tid = 0;
 		qid = WME_AC_BE;
-		qflags = RT2860_TX_QSEL_EDCA;
 		pad = 0;
 	}
+	qflags = (qid < 4) ? RT2860_TX_QSEL_EDCA : RT2860_TX_QSEL_HCCA;
 
+	DPRINTFN(8, "qos %d\tqid %d\ttid %d\tqflags %x\n",
+	    qos, qid, tid, qflags);
+
 	tp = &vap->iv_txparms[ieee80211_chan2mode(ni->ni_chan)];
 
 	/* pickup a rate index */
@@ -2578,110 +2623,31 @@
 		*(uint16_t *)wh->i_dur = htole16(dur + sc->sifs);
 	}
 
-	RUN_LOCK(sc);
-	/* save one for mgt packet, just in case */
-	if (__predict_false(sc->tx_nfree < 3)) {
-		/*
-		 * Stop dequeuing when the last txq ring is used,
-		 * so that we don't have to call IFQ_DRV_PREPEND().
-		 * (no txq, no dequeue)
-		 *
-		 * Returning '-1' cause the process exit from the loop in run_start().
-		 * (Don't for get to mark flag as not dequeuing.)
-		 *
-		 * It would be better to put these in run_start(),
-		 * but do these here while holding a lock.
-		 */
-		sc->dequeue = RUN_NO_DEQUEUE;
-		ifp->if_drv_flags |= IFF_DRV_OACTIVE;
-		if(sc->tx_nfree == 2){
-			error = -1;
-			DPRINTFN(4, "the last of txq ring used\n");
-			/* continue to process packet */
-		} else {
-			/* shouldn't reach here, but just in case */
-			IFQ_DRV_PREPEND(&ifp->if_snd, m);
-			RUN_UNLOCK(sc);
-			DPRINTF("txq ring is full\n");
-			return -1;
-		}
+	/* reserve slots for mgmt packets, just in case */
+	if (sc->sc_epq[qid].tx_nfree < 3) {
+		DPRINTF("tx ring %d is full\n", qid);
+		return (-1);
 	}
-	data = STAILQ_FIRST(&sc->tx_free);
-	STAILQ_REMOVE_HEAD(&sc->tx_free, next);
-	sc->tx_nfree--;
-	RUN_UNLOCK(sc);	/* to be kept lockd, or not to be */
+
+	data = STAILQ_FIRST(&sc->sc_epq[qid].tx_fh);
+	STAILQ_REMOVE_HEAD(&sc->sc_epq[qid].tx_fh, next);
+	sc->sc_epq[qid].tx_nfree--;
 
 	data->m = m;
 	data->ni = ni;
 	data->ridx = ridx;
-	data->qid = qid;
 
-#if 1
-	/*
-	 * We could call run_set_tx_desc() instead,
-	 * but context switching is expensive.
-	 * (The file size is almost the same.)
-	 */
-	struct rt2870_txd	*txd;
-	struct rt2860_txwi	*txwi;
-	int	xferlen;
-	uint8_t	mcs;
+	run_set_tx_desc(sc, data, 0, xflags, 0, qflags, type, pad);
 
-	/* get MCS code from rate index */
-	data->mcs = mcs = rt2860_rates[ridx].mcs;
+        STAILQ_INSERT_TAIL(&sc->sc_epq[qid].tx_qh, data, next);
 
-	xferlen = sizeof (*txwi) + m->m_pkthdr.len;
-	/* roundup to 32-bit alignment */
-	xferlen = (xferlen + 3) & ~3;
-
-	txd = (struct rt2870_txd *)&data->desc;
-	txd->flags = qflags;

>>> TRUNCATED FOR MAIL (1000 lines) <<<


More information about the p4-projects mailing list