PERFORCE change 157611 for review

Hans Petter Selasky hselasky at FreeBSD.org
Thu Feb 12 13:10:28 PST 2009


http://perforce.freebsd.org/chv.cgi?CH=157611

Change 157611 by hselasky at hselasky_laptop001 on 2009/02/12 21:10:08

	
	USB WLAN: Put more seatbelts on the drivers like in the original USB2 version.
	- Remove cmd request structure from the stack in ZYD driver.
	- Make drivers wait for transmit to complete and then halt
	  transmit during any pending command operations. Probably
	  not all command operations, like reading the status
	  counters needs this halt (TODO).

Affected files ...

.. //depot/projects/usb/src/sys/dev/usb2/wlan/if_rum2.c#39 edit
.. //depot/projects/usb/src/sys/dev/usb2/wlan/if_rumvar.h#9 edit
.. //depot/projects/usb/src/sys/dev/usb2/wlan/if_ural2.c#38 edit
.. //depot/projects/usb/src/sys/dev/usb2/wlan/if_uralvar.h#9 edit
.. //depot/projects/usb/src/sys/dev/usb2/wlan/if_zyd2.c#39 edit
.. //depot/projects/usb/src/sys/dev/usb2/wlan/if_zydreg.h#10 edit

Differences ...

==== //depot/projects/usb/src/sys/dev/usb2/wlan/if_rum2.c#39 (text+ko) ====

@@ -116,6 +116,7 @@
 static usb2_callback_t rum_bulk_read_callback;
 static usb2_callback_t rum_bulk_write_callback;
 
+static usb2_proc_callback_t rum_command_wrapper;
 static usb2_proc_callback_t rum_attach_post;
 static usb2_proc_callback_t rum_task;
 static usb2_proc_callback_t rum_scantask;
@@ -408,6 +409,8 @@
 	mtx_init(&sc->sc_mtx, device_get_nameunit(self),
 	    MTX_NETWORK_LOCK, MTX_DEF);
 
+	cv_init(&sc->sc_cmd_cv, "wtxdone");
+
 	iface_index = RT2573_IFACE_INDEX;
 	error = usb2_transfer_setup(uaa->device, &iface_index,
 	    sc->sc_xfer, rum_config, RUM_N_TRANSFER, sc, &sc->sc_mtx);
@@ -573,6 +576,8 @@
 		if_free(ifp);
 	}
 
+	cv_destroy(&sc->sc_cmd_cv);
+
 	mtx_destroy(&sc->sc_mtx);
 
 	return (0);
@@ -839,6 +844,10 @@
 	struct mbuf *m;
 	unsigned int len;
 
+	/* wakeup waiting command, if any */
+	if (sc->sc_last_task != NULL)
+		cv_signal(&sc->sc_cmd_cv);
+
 	switch (USB_GET_STATE(xfer)) {
 	case USB_ST_TRANSFERRED:
 		DPRINTFN(11, "transfer complete, %d bytes\n", xfer->actlen);
@@ -853,6 +862,10 @@
 		/* FALLTHROUGH */
 	case USB_ST_SETUP:
 tr_setup:
+		/* wait for command to complete, if any */
+		if (sc->sc_last_task != NULL)
+			break;
+
 		data = STAILQ_FIRST(&sc->tx_q);
 		if (data) {
 			STAILQ_REMOVE_HEAD(&sc->tx_q, next);
@@ -2166,7 +2179,8 @@
 		err = rum_write(sc, reg, UGETDW(ucode));
 		if (err) {
 			/* firmware already loaded ? */
-			device_printf(sc->sc_dev, "Firmware load failed.\n");
+			device_printf(sc->sc_dev, "Firmware load "
+			    "failure! (ignored)\n");
 			break;
 		}
 	}
@@ -2466,6 +2480,30 @@
 }
 
 static void
+rum_command_wrapper(struct usb2_proc_msg *pm)
+{
+	struct rum_task *task = (struct rum_task *)pm;
+	struct rum_softc *sc = task->sc;
+	struct ifnet *ifp;
+
+	/* wait for pending transfer, if any */
+	while (usb2_transfer_pending(sc->sc_xfer[RUM_BULK_WR]))
+		cv_wait(&sc->sc_cmd_cv, &sc->sc_mtx);
+
+	/* execute task */
+	task->func(pm);
+
+	/* check if this is the last task executed */
+	if (sc->sc_last_task == task) {
+		sc->sc_last_task = NULL;
+		ifp = sc->sc_ifp;
+		/* re-start TX, if any */
+		if ((ifp != NULL) && (ifp->if_drv_flags & IFF_DRV_RUNNING))
+			usb2_transfer_start(sc->sc_xfer[RUM_BULK_WR]);
+	}
+}
+
+static void
 rum_queue_command(struct rum_softc *sc, usb2_proc_callback_t *fn,
     struct usb2_proc_msg *t0, struct usb2_proc_msg *t1)
 {
@@ -2482,15 +2520,19 @@
 	  usb2_proc_msignal(&sc->sc_tq, t0, t1);
 
 	/* Setup callback and softc pointers */
-	task->hdr.pm_callback = fn;
+	task->hdr.pm_callback = rum_command_wrapper;
+	task->func = fn;
 	task->sc = sc;
 
-        /*
-         * Init, stop and flush must be synchronous!
-         */
-        if ((fn == rum_init_task) || (fn == rum_stop_task) || 
+	/* Make sure that any TX operation will stop */
+	sc->sc_last_task = task;
+
+	/*
+	 * Init, stop and flush must be synchronous!
+	 */
+	if ((fn == rum_init_task) || (fn == rum_stop_task) || 
 	    (fn == rum_flush_task))
-                usb2_proc_mwait(&sc->sc_tq, t0, t1);
+		usb2_proc_mwait(&sc->sc_tq, t0, t1);
 }
 
 static device_method_t rum_methods[] = {

==== //depot/projects/usb/src/sys/dev/usb2/wlan/if_rumvar.h#9 (text+ko) ====

@@ -55,6 +55,7 @@
 
 struct rum_task {
 	struct usb2_proc_msg	hdr;
+	usb2_proc_callback_t	*func;
 	struct rum_softc	*sc;
 };
 
@@ -101,6 +102,7 @@
 
 	const struct ieee80211_rate_table *sc_rates;
 	struct usb2_xfer		*sc_xfer[RUM_N_TRANSFER];
+	struct rum_task			*sc_last_task;
 
 	uint8_t				rf_rev;
 	uint8_t				rffreq;
@@ -121,6 +123,7 @@
 	rum_txdhead			tx_free;
 	struct rum_rx_desc		sc_rx_desc;
 
+	struct cv			sc_cmd_cv;
 	struct mtx			sc_mtx;
 
 	uint32_t			sta[6];

==== //depot/projects/usb/src/sys/dev/usb2/wlan/if_ural2.c#38 (text+ko) ====

@@ -95,6 +95,7 @@
 static usb2_callback_t ural_bulk_read_callback;
 static usb2_callback_t ural_bulk_write_callback;
 
+static usb2_proc_callback_t ural_command_wrapper;
 static usb2_proc_callback_t ural_attach_post;
 static usb2_proc_callback_t ural_task;
 static usb2_proc_callback_t ural_scantask;
@@ -411,6 +412,8 @@
 	mtx_init(&sc->sc_mtx, device_get_nameunit(self),
 	    MTX_NETWORK_LOCK, MTX_DEF);
 
+	cv_init(&sc->sc_cmd_cv, "wtxdone");
+
 	iface_index = RAL_IFACE_INDEX;
 	error = usb2_transfer_setup(uaa->device,
 	    &iface_index, sc->sc_xfer, ural_config,
@@ -564,6 +567,8 @@
 		if_free(ifp);
 	}
 
+	cv_destroy(&sc->sc_cmd_cv);
+
 	mtx_destroy(&sc->sc_mtx);
 
 	return (0);
@@ -876,6 +881,10 @@
 	struct mbuf *m;
 	unsigned int len;
 
+	/* wakeup waiting command, if any */
+	if (sc->sc_last_task != NULL)
+		cv_signal(&sc->sc_cmd_cv);
+
 	switch (USB_GET_STATE(xfer)) {
 	case USB_ST_TRANSFERRED:
 		DPRINTFN(11, "transfer complete, %d bytes\n", xfer->actlen);
@@ -890,6 +899,10 @@
 		/* FALLTHROUGH */
 	case USB_ST_SETUP:
 tr_setup:
+		/* wait for command to complete, if any */
+		if (sc->sc_last_task != NULL)
+			break;
+
 		data = STAILQ_FIRST(&sc->tx_q);
 		if (data) {
 			STAILQ_REMOVE_HEAD(&sc->tx_q, next);
@@ -2395,6 +2408,30 @@
 }
 
 static void
+ural_command_wrapper(struct usb2_proc_msg *pm)
+{
+	struct ural_task *task = (struct ural_task *)pm;
+	struct ural_softc *sc = task->sc;
+	struct ifnet *ifp;
+
+	/* wait for pending transfer, if any */
+	while (usb2_transfer_pending(sc->sc_xfer[URAL_BULK_WR]))
+		cv_wait(&sc->sc_cmd_cv, &sc->sc_mtx);
+
+	/* execute task */
+	task->func(pm);
+
+	/* check if this is the last task executed */
+	if (sc->sc_last_task == task) {
+		sc->sc_last_task = NULL;
+		ifp = sc->sc_ifp;
+		/* re-start TX, if any */
+		if ((ifp != NULL) && (ifp->if_drv_flags & IFF_DRV_RUNNING))
+			usb2_transfer_start(sc->sc_xfer[URAL_BULK_WR]);
+	}
+}
+
+static void
 ural_queue_command(struct ural_softc *sc, usb2_proc_callback_t *fn,
     struct usb2_proc_msg *t0, struct usb2_proc_msg *t1)
 {
@@ -2411,9 +2448,13 @@
 	  usb2_proc_msignal(&sc->sc_tq, t0, t1);
 
 	/* Setup callback and softc pointers */
-	task->hdr.pm_callback = fn;
+	task->hdr.pm_callback = ural_command_wrapper;
+	task->func = fn;
 	task->sc = sc;
 
+	/* Make sure that any TX operation will stop */
+	sc->sc_last_task = task;
+
 	/*
 	 * Init, stop and flush must be synchronous!
 	 */

==== //depot/projects/usb/src/sys/dev/usb2/wlan/if_uralvar.h#9 (text+ko) ====

@@ -60,6 +60,7 @@
 
 struct ural_task {
 	struct usb2_proc_msg	hdr;
+	usb2_proc_callback_t	*func;
 	struct ural_softc	*sc;
 };
 
@@ -110,6 +111,7 @@
 	uint8_t				rf_rev;
 
 	struct usb2_xfer		*sc_xfer[URAL_N_TRANSFER];
+	struct ural_task		*sc_last_task;
 
 	enum ieee80211_state		sc_state;
 	int				sc_arg;
@@ -125,6 +127,7 @@
 	struct ural_rx_desc		sc_rx_desc;
 
 	struct mtx			sc_mtx;
+	struct cv			sc_cmd_cv;
 
 	uint16_t			sta[11];
 	uint32_t			rf_regs[4];

==== //depot/projects/usb/src/sys/dev/usb2/wlan/if_zyd2.c#39 (text+ko) ====

@@ -325,7 +325,8 @@
 	mtx_init(&sc->sc_mtx, device_get_nameunit(sc->sc_dev),
 	    MTX_NETWORK_LOCK, MTX_DEF);
 
-	STAILQ_INIT(&sc->sc_rqh);
+	cv_init(&sc->sc_cmd_cv, "wtxdone");
+	cv_init(&sc->sc_intr_cv, "zydcmd");
 
 	iface_index = ZYD_IFACE_INDEX;
 	error = usb2_transfer_setup(uaa->device,
@@ -469,6 +470,9 @@
 		if_free(ifp);
 	}
 
+	cv_destroy(&sc->sc_cmd_cv);
+	cv_destroy(&sc->sc_intr_cv);
+
 	mtx_destroy(&sc->sc_mtx);
 
 	return (0);
@@ -744,11 +748,13 @@
 			datalen = xfer->actlen - sizeof(cmd->code);
 			datalen -= 2;	/* XXX: padding? */
 
-			STAILQ_FOREACH(rqp, &sc->sc_rqh, rq) {
+			rqp = sc->sc_curr_rq;
+			if (rqp != NULL) {
 				int i, cnt;
 
 				if (rqp->olen != datalen)
-					continue;
+					break;
+
 				cnt = rqp->olen / sizeof(struct zyd_pair);
 				for (i = 0; i < cnt; i++) {
 					if (*(((const uint16_t *)rqp->idata) + i) !=
@@ -756,16 +762,15 @@
 						break;
 				}
 				if (i != cnt)
-					continue;
+					break;
 				/* copy answer into caller-supplied buffer */
 				bcopy(cmd->data, rqp->odata, rqp->olen);
 				DPRINTF(sc, ZYD_DEBUG_CMD,
 				    "command %p complete, data = %*D \n",
 				    rqp, rqp->olen, rqp->odata, ":");
-				wakeup(rqp);	/* wakeup caller */
-				break;
-			}
-			if (rqp == NULL) {
+				/* wakeup caller */
+				cv_signal(&sc->sc_intr_cv);
+			} else {
 				device_printf(sc->sc_dev,
 				    "unexpected IORD notification %*D\n",
 				    datalen, cmd->data, ":");
@@ -805,25 +810,26 @@
 
 	switch (USB_GET_STATE(xfer)) {
 	case USB_ST_TRANSFERRED:
-		rqp = xfer->priv_fifo;
+		rqp = sc->sc_curr_rq;
 		DPRINTF(sc, ZYD_DEBUG_CMD, "command %p transferred\n", rqp);
-		if ((rqp->flags & ZYD_CMD_FLAG_READ) == 0)
-			wakeup(rqp);	/* wakeup caller */
+		if (rqp != NULL) {
+			if ((rqp->flags & ZYD_CMD_FLAG_READ) == 0)
+				cv_signal(&sc->sc_intr_cv);	/* wakeup caller */
+		}
 
 		/* FALLTHROUGH */
 	case USB_ST_SETUP:
 tr_setup:
-		STAILQ_FOREACH(rqp, &sc->sc_rqh, rq) {
+		rqp = sc->sc_curr_rq;
+		if (rqp != NULL) {
 			if (rqp->flags & ZYD_CMD_FLAG_SENT)
-				continue;
+				break;
 
 			usb2_copy_in(xfer->frbuffers, 0, rqp->cmd, rqp->ilen);
 
 			xfer->frlengths[0] = rqp->ilen;
-			xfer->priv_fifo = rqp;
 			rqp->flags |= ZYD_CMD_FLAG_SENT;
 			usb2_start_hardware(xfer);
-			break;
 		}
 		break;
 
@@ -844,38 +850,42 @@
 zyd_cmd(struct zyd_softc *sc, uint16_t code, const void *idata, int ilen,
     void *odata, int olen, unsigned int flags)
 {
-	struct zyd_cmd cmd;
-	struct zyd_rq rq;
 	int error;
 
-	if (ilen > sizeof(cmd.data))
+	if (ilen > sizeof(sc->sc_cmd.data))
 		return (EINVAL);
 
 	if (usb2_proc_is_gone(&sc->sc_tq))
 		return (ENXIO);
 
-	cmd.code = htole16(code);
-	bcopy(idata, cmd.data, ilen);
+	sc->sc_cmd.code = htole16(code);
+	bcopy(idata, sc->sc_cmd.data, ilen);
 	DPRINTF(sc, ZYD_DEBUG_CMD, "sending cmd %p = %*D\n",
-	    &rq, ilen, idata, ":");
+	    &sc->sc_rq, ilen, idata, ":");
+
+	sc->sc_rq.cmd = &sc->sc_cmd;
+	sc->sc_rq.idata = idata;
+	sc->sc_rq.odata = odata;
+	sc->sc_rq.ilen = sizeof(uint16_t) + ilen;
+	sc->sc_rq.olen = olen;
+	sc->sc_rq.flags = flags;
+
+	/* set our hint */
+	sc->sc_curr_rq = &sc->sc_rq;
 
-	rq.cmd = &cmd;
-	rq.idata = idata;
-	rq.odata = odata;
-	rq.ilen = sizeof(uint16_t) + ilen;
-	rq.olen = olen;
-	rq.flags = flags;
-	STAILQ_INSERT_TAIL(&sc->sc_rqh, &rq, rq);
 	usb2_transfer_start(sc->sc_xfer[ZYD_INTR_RD]);
 	usb2_transfer_start(sc->sc_xfer[ZYD_INTR_WR]);
 
 	/* wait at most one second for command reply */
-	error = mtx_sleep(&rq, &sc->sc_mtx, 0 , "zydcmd", hz);
+	error = cv_timedwait(&sc->sc_intr_cv, &sc->sc_mtx, hz);
 	if (error)
 		device_printf(sc->sc_dev, "command timeout\n");
-	STAILQ_REMOVE(&sc->sc_rqh, &rq, zyd_rq, rq);
+
+	/* clear our hint */
+	sc->sc_curr_rq = NULL;
+
 	DPRINTF(sc, ZYD_DEBUG_CMD, "finsihed cmd %p, error = %d \n",
-	    &rq, error);
+	    &sc->sc_rq, error);
 
 	return (error);
 }
@@ -2511,6 +2521,10 @@
 	struct zyd_tx_data *data;
 	struct mbuf *m;
 
+	/* wakeup any waiting command, if any */
+	if (sc->sc_last_task != NULL)
+		cv_signal(&sc->sc_cmd_cv);
+
 	switch (USB_GET_STATE(xfer)) {
 	case USB_ST_TRANSFERRED:
 		DPRINTF(sc, ZYD_DEBUG_ANY, "transfer complete, %u bytes\n",
@@ -2526,6 +2540,10 @@
 		/* FALLTHROUGH */
 	case USB_ST_SETUP:
 tr_setup:
+		/* wait for command to complete, if any */
+		if (sc->sc_last_task != NULL)
+			break;
+
 		data = STAILQ_FIRST(&sc->tx_q);
 		if (data) {
 			STAILQ_REMOVE_HEAD(&sc->tx_q, next);
@@ -3099,6 +3117,30 @@
 }
 
 static void
+zyd_command_wrapper(struct usb2_proc_msg *pm)
+{
+	struct zyd_task *task = (struct zyd_task *)pm;
+	struct zyd_softc *sc = task->sc;
+	struct ifnet *ifp;
+
+	/* wait for pending transfer, if any */
+	while (usb2_transfer_pending(sc->sc_xfer[ZYD_BULK_WR]))
+		cv_wait(&sc->sc_cmd_cv, &sc->sc_mtx);
+
+	/* execute task */
+	task->func(pm);
+
+	/* check if this is the last task executed */
+	if (sc->sc_last_task == task) {
+		sc->sc_last_task = NULL;
+		ifp = sc->sc_ifp;
+		/* re-start TX, if any */
+		if ((ifp != NULL) && (ifp->if_drv_flags & IFF_DRV_RUNNING))
+			usb2_transfer_start(sc->sc_xfer[ZYD_BULK_WR]);
+	}
+}
+
+static void
 zyd_queue_command(struct zyd_softc *sc, usb2_proc_callback_t *fn,
     struct usb2_proc_msg *t0, struct usb2_proc_msg *t1)
 {
@@ -3115,15 +3157,19 @@
 	  usb2_proc_msignal(&sc->sc_tq, t0, t1);
 
 	/* Setup callback and softc pointers */
-	task->hdr.pm_callback = fn;
+	task->hdr.pm_callback = zyd_command_wrapper;
+	task->func = fn;
 	task->sc = sc;
 
-        /*
-         * Init and stop must be synchronous!
-         */
-        if ((fn == zyd_init_task) || (fn == zyd_stop_task) ||
+	/* Make sure that any TX operation will stop */
+	sc->sc_last_task = task;
+
+	/*
+	 * Init and stop must be synchronous!
+	 */
+	if ((fn == zyd_init_task) || (fn == zyd_stop_task) ||
 	    (fn == zyd_flush_task))
-                usb2_proc_mwait(&sc->sc_tq, t0, t1);
+		usb2_proc_mwait(&sc->sc_tq, t0, t1);
 }
 
 static device_method_t zyd_methods[] = {

==== //depot/projects/usb/src/sys/dev/usb2/wlan/if_zydreg.h#10 (text+ko) ====

@@ -1165,6 +1165,7 @@
 
 struct zyd_task {
 	struct usb2_proc_msg	hdr;
+	usb2_proc_callback_t	*func;
 	struct zyd_softc	*sc;
 };
 
@@ -1267,6 +1268,8 @@
 	struct usb2_process	sc_tq;
 
 	struct usb2_xfer	*sc_xfer[ZYD_N_TRANSFER];
+	struct zyd_task		*sc_last_task;
+	struct zyd_rq		*sc_curr_rq;
 
 	enum ieee80211_state	sc_state;
 	int			sc_arg;
@@ -1285,10 +1288,9 @@
 	struct zyd_task		sc_task[2];
 
 	struct zyd_rf		sc_rf;
+	struct zyd_cmd		sc_cmd;
+	struct zyd_rq		sc_rq;
 
-	STAILQ_HEAD(, zyd_rq)	sc_rtx;
-	STAILQ_HEAD(, zyd_rq)	sc_rqh;
-
 	uint8_t			sc_bssid[IEEE80211_ADDR_LEN];
 	uint16_t		sc_fwbase;
 	uint8_t			sc_regdomain;
@@ -1315,6 +1317,7 @@
 	uint8_t			sc_ofdm54_cal[14];
 
 	struct mtx		sc_mtx;
+	struct cv		sc_cmd_cv;
 	struct cv		sc_intr_cv;
 	struct zyd_tx_data	tx_data[ZYD_TX_LIST_CNT];
 	zyd_txdhead		tx_q;


More information about the p4-projects mailing list