From 77ddf3d34ae0435089c95b84cb92928f5776fe6e Mon Sep 17 00:00:00 2001 From: Andrew Thompson Date: Fri, 27 Feb 2009 21:14:29 +0000 Subject: [PATCH] Partial sync to //depot/projects/usb - Reissue the ctrl request on failure - Ensure Tx and ctrl requests are not interleaved - Add promisc callbacks Obtained from: Hans Petter Selasky --- sys/dev/usb/wlan/if_rum.c | 192 +++++++++++++++++++++++++++------- sys/dev/usb/wlan/if_rumvar.h | 3 + sys/dev/usb/wlan/if_ural.c | 134 +++++++++++++++++++++--- sys/dev/usb/wlan/if_uralvar.h | 3 + sys/dev/usb/wlan/if_zyd.c | 89 +++++++++++++--- sys/dev/usb/wlan/if_zydreg.h | 6 +- 6 files changed, 358 insertions(+), 69 deletions(-) diff --git a/sys/dev/usb/wlan/if_rum.c b/sys/dev/usb/wlan/if_rum.c index a9d13a55674..b164ef22008 100644 --- a/sys/dev/usb/wlan/if_rum.c +++ b/sys/dev/usb/wlan/if_rum.c @@ -54,9 +54,6 @@ SYSCTL_INT(_hw_usb2_rum, OID_AUTO, debug, CTLFLAG_RW, &rum_debug, 0, "Debug level"); #endif -#define rum_do_request(sc,req,data) \ - usb2_do_request_proc((sc)->sc_udev, &(sc)->sc_tq, req, data, 0, NULL, 5000) - static const struct usb2_device_id rum_devs[] = { { USB_VP(USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_HWU54DM) }, { USB_VP(USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_RT2573_2) }, @@ -118,6 +115,7 @@ static device_detach_t rum_detach; 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; @@ -125,7 +123,10 @@ static usb2_proc_callback_t rum_promisctask; static usb2_proc_callback_t rum_amrr_task; static usb2_proc_callback_t rum_init_task; static usb2_proc_callback_t rum_stop_task; +static usb2_proc_callback_t rum_flush_task; +static usb2_error_t rum_do_request(struct rum_softc *sc, + struct usb2_device_request *req, void *data); static struct ieee80211vap *rum_vap_create(struct ieee80211com *, const char name[IFNAMSIZ], int unit, int opmode, int flags, const uint8_t bssid[IEEE80211_ADDR_LEN], @@ -153,8 +154,8 @@ static void rum_eeprom_read(struct rum_softc *, uint16_t, void *, static uint32_t rum_read(struct rum_softc *, uint16_t); static void rum_read_multi(struct rum_softc *, uint16_t, void *, int); -static void rum_write(struct rum_softc *, uint16_t, uint32_t); -static void rum_write_multi(struct rum_softc *, uint16_t, void *, +static usb2_error_t rum_write(struct rum_softc *, uint16_t, uint32_t); +static usb2_error_t rum_write_multi(struct rum_softc *, uint16_t, void *, size_t); static void rum_bbp_write(struct rum_softc *, uint8_t, uint8_t); static uint8_t rum_bbp_read(struct rum_softc *, uint8_t); @@ -171,11 +172,13 @@ static void rum_enable_tsf_sync(struct rum_softc *); static void rum_update_slot(struct ifnet *); static void rum_set_bssid(struct rum_softc *, const uint8_t *); static void rum_set_macaddr(struct rum_softc *, const uint8_t *); +static void rum_update_mcast(struct ifnet *); +static void rum_update_promisc(struct ifnet *); static const char *rum_get_rf(int); static void rum_read_eeprom(struct rum_softc *); static int rum_bbp_init(struct rum_softc *); static void rum_init(void *); -static int rum_load_microcode(struct rum_softc *, const u_char *, +static void rum_load_microcode(struct rum_softc *, const uint8_t *, size_t); static int rum_prepare_beacon(struct rum_softc *, struct ieee80211vap *); @@ -405,6 +408,8 @@ rum_attach(device_t self) 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); @@ -441,7 +446,6 @@ rum_attach_post(struct usb2_proc_msg *pm) struct ifnet *ifp; struct ieee80211com *ic; unsigned int ntries; - int error; uint32_t tmp; uint8_t bands; @@ -463,12 +467,12 @@ rum_attach_post(struct usb2_proc_msg *pm) device_printf(sc->sc_dev, "MAC/BBP RT2573 (rev 0x%05x), RF %s\n", tmp, rum_get_rf(sc->rf_rev)); - error = rum_load_microcode(sc, rt2573_ucode, sizeof(rt2573_ucode)); - if (error != 0) { - RUM_UNLOCK(sc); - device_printf(sc->sc_dev, "could not load 8051 microcode\n"); + rum_load_microcode(sc, rt2573_ucode, sizeof(rt2573_ucode)); + + /* XXX Async attach race */ + if (usb2_proc_is_gone(&sc->sc_tq)) return; - } + RUM_UNLOCK(sc); ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); @@ -514,6 +518,8 @@ rum_attach_post(struct usb2_proc_msg *pm) ieee80211_init_channels(ic, NULL, &bands); ieee80211_ifattach(ic); + ic->ic_update_mcast = rum_update_mcast; + ic->ic_update_promisc = rum_update_promisc; ic->ic_newassoc = rum_newassoc; ic->ic_raw_xmit = rum_raw_xmit; ic->ic_node_alloc = rum_node_alloc; @@ -568,12 +574,33 @@ rum_detach(device_t self) ieee80211_ifdetach(ic); if_free(ifp); } - + cv_destroy(&sc->sc_cmd_cv); mtx_destroy(&sc->sc_mtx); return (0); } +static usb2_error_t +rum_do_request(struct rum_softc *sc, + struct usb2_device_request *req, void *data) +{ + usb2_error_t err; + int ntries = 10; + + while (ntries--) { + err = usb2_do_request_proc(sc->sc_udev, &sc->sc_tq, + req, data, 0, NULL, 250 /* ms */); + if (err == 0) + break; + + DPRINTFN(1, "Control request failed, %s (retrying)\n", + usb2_errstr(err)); + if (rum_pause(sc, hz / 100)) + break; + } + return (err); +} + static struct ieee80211vap * rum_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, int opmode, int flags, @@ -612,10 +639,24 @@ rum_vap_create(struct ieee80211com *ic, return vap; } +static void +rum_flush_task(struct usb2_proc_msg *pm) +{ + /* Nothing to do */ +} + static void rum_vap_delete(struct ieee80211vap *vap) { struct rum_vap *rvp = RUM_VAP(vap); + struct rum_softc *sc = rvp->sc; + + RUM_LOCK(sc); + /* wait for any pending tasks to complete */ + rum_queue_command(sc, rum_flush_task, + &sc->sc_synctask[0].hdr, + &sc->sc_synctask[1].hdr); + RUM_UNLOCK(sc); usb2_callout_drain(&rvp->amrr_ch); ieee80211_amrr_cleanup(&rvp->amrr); @@ -791,6 +832,10 @@ rum_bulk_write_callback(struct usb2_xfer *xfer) 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); @@ -806,6 +851,10 @@ rum_bulk_write_callback(struct usb2_xfer *xfer) /* 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); @@ -1042,8 +1091,6 @@ rum_setup_tx_desc(struct rum_softc *sc, struct rum_tx_desc *desc, } } -#define RUM_TX_TIMEOUT 5000 - static int rum_sendprot(struct rum_softc *sc, const struct mbuf *m, struct ieee80211_node *ni, int prot, int rate) @@ -1079,7 +1126,7 @@ rum_sendprot(struct rum_softc *sc, } if (mprot == NULL) { /* XXX stat + msg */ - return ENOBUFS; + return (ENOBUFS); } data = STAILQ_FIRST(&sc->tx_free); STAILQ_REMOVE_HEAD(&sc->tx_free, next); @@ -1153,7 +1200,7 @@ rum_tx_mgt(struct rum_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) STAILQ_INSERT_TAIL(&sc->tx_q, data, next); usb2_transfer_start(sc->sc_xfer[RUM_BULK_WR]); - return 0; + return (0); } static int @@ -1315,6 +1362,7 @@ rum_start(struct ifnet *ifp) m = ieee80211_encap(ni, m); if (m == NULL) { ieee80211_free_node(ni); + ifp->if_oerrors++; continue; } if (rum_tx_data(sc, m, ni) != 0) { @@ -1420,15 +1468,15 @@ rum_read_multi(struct rum_softc *sc, uint16_t reg, void *buf, int len) } } -static void +static usb2_error_t rum_write(struct rum_softc *sc, uint16_t reg, uint32_t val) { uint32_t tmp = htole32(val); - rum_write_multi(sc, reg, &tmp, sizeof tmp); + return (rum_write_multi(sc, reg, &tmp, sizeof tmp)); } -static void +static usb2_error_t rum_write_multi(struct rum_softc *sc, uint16_t reg, void *buf, size_t len) { struct usb2_device_request req; @@ -1446,6 +1494,7 @@ rum_write_multi(struct rum_softc *sc, uint16_t reg, void *buf, size_t len) "could not multi write MAC register: %s\n", usb2_errstr(error)); } + return (error); } static void @@ -1454,6 +1503,8 @@ rum_bbp_write(struct rum_softc *sc, uint8_t reg, uint8_t val) uint32_t tmp; int ntries; + DPRINTFN(2, "reg=0x%08x\n", reg); + for (ntries = 0; ntries < 100; ntries++) { if (!(rum_read(sc, RT2573_PHY_CSR3) & RT2573_BBP_BUSY)) break; @@ -1475,6 +1526,8 @@ rum_bbp_read(struct rum_softc *sc, uint8_t reg) uint32_t val; int ntries; + DPRINTFN(2, "reg=0x%08x\n", reg); + for (ntries = 0; ntries < 100; ntries++) { if (!(rum_read(sc, RT2573_PHY_CSR3) & RT2573_BBP_BUSY)) break; @@ -1720,6 +1773,9 @@ rum_set_chan(struct rum_softc *sc, struct ieee80211_channel *c) if (bbp94 != RT2573_BBPR94_DEFAULT) rum_bbp_write(sc, 94, bbp94); + + /* give the chip some extra time to do the switchover */ + rum_pause(sc, hz / 100); } /* @@ -1817,6 +1873,27 @@ rum_promisctask(struct usb2_proc_msg *pm) "entering" : "leaving"); } +static void +rum_update_mcast(struct ifnet *ifp) +{ + /* not supported */ +} + +static void +rum_update_promisc(struct ifnet *ifp) +{ + struct rum_softc *sc = ifp->if_softc; + + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) + return; + + RUM_LOCK(sc); + rum_queue_command(sc, rum_promisctask, + &sc->sc_promisctask[0].hdr, + &sc->sc_promisctask[1].hdr); + RUM_UNLOCK(sc); +} + static const char * rum_get_rf(int rev) { @@ -2080,16 +2157,23 @@ rum_stop_task(struct usb2_proc_msg *pm) rum_write(sc, RT2573_MAC_CSR1, 0); } -static int -rum_load_microcode(struct rum_softc *sc, const u_char *ucode, size_t size) +static void +rum_load_microcode(struct rum_softc *sc, const uint8_t *ucode, size_t size) { struct usb2_device_request req; uint16_t reg = RT2573_MCU_CODE_BASE; - usb2_error_t error; + usb2_error_t err; /* copy firmware image into NIC */ - for (; size >= 4; reg += 4, ucode += 4, size -= 4) - rum_write(sc, reg, UGETDW(ucode)); + for (; size >= 4; reg += 4, ucode += 4, size -= 4) { + err = rum_write(sc, reg, UGETDW(ucode)); + if (err) { + /* firmware already loaded ? */ + device_printf(sc->sc_dev, "Firmware load " + "failure! (ignored)\n"); + break; + } + } req.bmRequestType = UT_WRITE_VENDOR_DEVICE; req.bRequest = RT2573_MCU_CNTL; @@ -2097,12 +2181,14 @@ rum_load_microcode(struct rum_softc *sc, const u_char *ucode, size_t size) USETW(req.wIndex, 0); USETW(req.wLength, 0); - error = rum_do_request(sc, &req, NULL); - if (error != 0) { + err = rum_do_request(sc, &req, NULL); + if (err != 0) { device_printf(sc->sc_dev, "could not run firmware: %s\n", - usb2_errstr(error)); + usb2_errstr(err)); } - return error; + + /* give the chip some time to boot */ + rum_pause(sc, hz / 8); } static int @@ -2384,6 +2470,33 @@ rum_pause(struct rum_softc *sc, int timeout) return (0); } +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); + + /* make sure any hardware buffers are emptied */ + rum_pause(sc, hz / 1000); + + /* 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) @@ -2392,10 +2505,6 @@ rum_queue_command(struct rum_softc *sc, usb2_proc_callback_t *fn, RUM_LOCK_ASSERT(sc, MA_OWNED); - if (usb2_proc_is_gone(&sc->sc_tq)) { - DPRINTF("proc is gone\n"); - return; /* nothing to do */ - } /* * NOTE: The task cannot get executed before we drop the * "sc_mtx" mutex. It is safe to update fields in the message @@ -2405,14 +2514,19 @@ rum_queue_command(struct rum_softc *sc, usb2_proc_callback_t *fn, 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 and stop must be synchronous! - */ - if ((fn == rum_init_task) || (fn == rum_stop_task)) - usb2_proc_mwait(&sc->sc_tq, t0, t1); + /* 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); } static device_method_t rum_methods[] = { diff --git a/sys/dev/usb/wlan/if_rumvar.h b/sys/dev/usb/wlan/if_rumvar.h index fc66510e00e..ed08e36e9a1 100644 --- a/sys/dev/usb/wlan/if_rumvar.h +++ b/sys/dev/usb/wlan/if_rumvar.h @@ -56,6 +56,7 @@ struct rum_softc; struct rum_task { struct usb2_proc_msg hdr; + usb2_proc_callback_t *func; struct rum_softc *sc; }; @@ -102,6 +103,7 @@ struct rum_softc { 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; @@ -123,6 +125,7 @@ struct rum_softc { int tx_nfree; struct rum_rx_desc sc_rx_desc; + struct cv sc_cmd_cv; struct mtx sc_mtx; uint32_t sta[6]; diff --git a/sys/dev/usb/wlan/if_ural.c b/sys/dev/usb/wlan/if_ural.c index e911f2b9678..8db1bdab6cb 100644 --- a/sys/dev/usb/wlan/if_ural.c +++ b/sys/dev/usb/wlan/if_ural.c @@ -55,9 +55,6 @@ SYSCTL_INT(_hw_usb2_ural, OID_AUTO, debug, CTLFLAG_RW, &ural_debug, 0, "Debug level"); #endif -#define ural_do_request(sc,req,data) \ - usb2_do_request_proc((sc)->sc_udev, &(sc)->sc_tq, req, data, 0, NULL, 5000) - #define URAL_RSSI(rssi) \ ((rssi) > (RAL_NOISE_FLOOR + RAL_RSSI_CORR) ? \ ((rssi) - (RAL_NOISE_FLOOR + RAL_RSSI_CORR)) : 0) @@ -98,6 +95,7 @@ static const struct usb2_device_id ural_devs[] = { 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; @@ -105,7 +103,10 @@ static usb2_proc_callback_t ural_promisctask; static usb2_proc_callback_t ural_amrr_task; static usb2_proc_callback_t ural_init_task; static usb2_proc_callback_t ural_stop_task; +static usb2_proc_callback_t ural_flush_task; +static usb2_error_t ural_do_request(struct ural_softc *sc, + struct usb2_device_request *req, void *data); static struct ieee80211vap *ural_vap_create(struct ieee80211com *, const char name[IFNAMSIZ], int unit, int opmode, int flags, const uint8_t bssid[IEEE80211_ADDR_LEN], @@ -154,6 +155,8 @@ static void ural_set_basicrates(struct ural_softc *, const struct ieee80211_channel *); static void ural_set_bssid(struct ural_softc *, const uint8_t *); static void ural_set_macaddr(struct ural_softc *, uint8_t *); +static void ural_update_mcast(struct ifnet *); +static void ural_update_promisc(struct ifnet *); static const char *ural_get_rf(int); static void ural_read_eeprom(struct ural_softc *); static int ural_bbp_init(struct ural_softc *); @@ -408,6 +411,8 @@ ural_attach(device_t self) 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, @@ -451,6 +456,11 @@ ural_attach_post(struct usb2_proc_msg *pm) /* retrieve MAC address and various other things from EEPROM */ ural_read_eeprom(sc); + + /* XXX Async attach race */ + if (usb2_proc_is_gone(&sc->sc_tq)) + return; + RAL_UNLOCK(sc); device_printf(sc->sc_dev, "MAC/BBP RT2570 (rev 0x%02x), RF %s\n", @@ -499,6 +509,8 @@ ural_attach_post(struct usb2_proc_msg *pm) ieee80211_init_channels(ic, NULL, &bands); ieee80211_ifattach(ic); + ic->ic_update_mcast = ural_update_mcast; + ic->ic_update_promisc = ural_update_promisc; ic->ic_newassoc = ural_newassoc; ic->ic_raw_xmit = ural_raw_xmit; ic->ic_node_alloc = ural_node_alloc; @@ -553,12 +565,33 @@ ural_detach(device_t self) ieee80211_ifdetach(ic); if_free(ifp); } - + cv_destroy(&sc->sc_cmd_cv); mtx_destroy(&sc->sc_mtx); return (0); } +static usb2_error_t +ural_do_request(struct ural_softc *sc, + struct usb2_device_request *req, void *data) +{ + usb2_error_t err; + int ntries = 10; + + while (ntries--) { + err = usb2_do_request_proc(sc->sc_udev, &sc->sc_tq, + req, data, 0, NULL, 250 /* ms */); + if (err == 0) + break; + + DPRINTFN(1, "Control request failed, %s (retrying)\n", + usb2_errstr(err)); + if (ural_pause(sc, hz / 100)) + break; + } + return (err); +} + static struct ieee80211vap * ural_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, int opmode, int flags, @@ -597,10 +630,24 @@ ural_vap_create(struct ieee80211com *ic, return vap; } +static void +ural_flush_task(struct usb2_proc_msg *pm) +{ + /* nothing to do */ +} + static void ural_vap_delete(struct ieee80211vap *vap) { struct ural_vap *uvp = URAL_VAP(vap); + struct ural_softc *sc = uvp->sc; + + RAL_LOCK(sc); + /* wait for any pending tasks to complete */ + ural_queue_command(sc, ural_flush_task, + &sc->sc_synctask[0].hdr, + &sc->sc_synctask[1].hdr); + RAL_UNLOCK(sc); usb2_callout_drain(&uvp->amrr_ch); ieee80211_amrr_cleanup(&uvp->amrr); @@ -825,6 +872,10 @@ ural_bulk_write_callback(struct usb2_xfer *xfer) 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); @@ -840,6 +891,10 @@ ural_bulk_write_callback(struct usb2_xfer *xfer) /* 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); @@ -1389,6 +1444,7 @@ ural_start(struct ifnet *ifp) m = ieee80211_encap(ni, m); if (m == NULL) { ieee80211_free_node(ni); + ifp->if_oerrors++; continue; } if (ural_tx_data(sc, m, ni) != 0) { @@ -1798,6 +1854,9 @@ ural_set_chan(struct ural_softc *sc, struct ieee80211_channel *c) /* XXX doesn't belong here */ /* update basic rate set */ ural_set_basicrates(sc, c); + + /* give the hardware some time to do the switchover */ + ural_pause(sc, hz / 100); } /* @@ -1967,6 +2026,27 @@ ural_promisctask(struct usb2_proc_msg *pm) "entering" : "leaving"); } +static void +ural_update_mcast(struct ifnet *ifp) +{ + /* not supported */ +} + +static void +ural_update_promisc(struct ifnet *ifp) +{ + struct ural_softc *sc = ifp->if_softc; + + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) + return; + + RAL_LOCK(sc); + ural_queue_command(sc, ural_promisctask, + &sc->sc_promisctask[0].hdr, + &sc->sc_promisctask[1].hdr); + RAL_UNLOCK(sc); +} + static const char * ural_get_rf(int rev) { @@ -2165,6 +2245,7 @@ ural_init_task(struct usb2_proc_msg *pm) ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; ifp->if_drv_flags |= IFF_DRV_RUNNING; + usb2_transfer_set_stall(sc->sc_xfer[URAL_BULK_WR]); usb2_transfer_start(sc->sc_xfer[URAL_BULK_RD]); return; @@ -2217,6 +2298,8 @@ ural_stop_task(struct usb2_proc_msg *pm) /* wait a little */ ural_pause(sc, hz / 10); ural_write(sc, RAL_MAC_CSR1, 0); + /* wait a little */ + ural_pause(sc, hz / 10); } static int @@ -2331,6 +2414,33 @@ ural_pause(struct ural_softc *sc, int timeout) return (0); } +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); + + /* make sure any hardware FIFOs are emptied */ + ural_pause(sc, hz / 1000); + + /* 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) @@ -2339,10 +2449,6 @@ ural_queue_command(struct ural_softc *sc, usb2_proc_callback_t *fn, RAL_LOCK_ASSERT(sc, MA_OWNED); - if (usb2_proc_is_gone(&sc->sc_tq)) { - DPRINTF("proc is gone\n"); - return; /* nothing to do */ - } /* * NOTE: The task cannot get executed before we drop the * "sc_mtx" mutex. It is safe to update fields in the message @@ -2352,13 +2458,17 @@ ural_queue_command(struct ural_softc *sc, usb2_proc_callback_t *fn, 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 and stop must be synchronous! + * Init, stop and flush must be synchronous! */ - if ((fn == ural_init_task) || (fn == ural_stop_task)) + if ((fn == ural_init_task) || (fn == ural_stop_task) || + (fn == ural_stop_task)) usb2_proc_mwait(&sc->sc_tq, t0, t1); } - diff --git a/sys/dev/usb/wlan/if_uralvar.h b/sys/dev/usb/wlan/if_uralvar.h index b9d378326f0..5e723392b52 100644 --- a/sys/dev/usb/wlan/if_uralvar.h +++ b/sys/dev/usb/wlan/if_uralvar.h @@ -61,6 +61,7 @@ struct ural_softc; struct ural_task { struct usb2_proc_msg hdr; + usb2_proc_callback_t *func; struct ural_softc *sc; }; @@ -111,6 +112,7 @@ struct ural_softc { 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; @@ -127,6 +129,7 @@ struct ural_softc { 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]; diff --git a/sys/dev/usb/wlan/if_zyd.c b/sys/dev/usb/wlan/if_zyd.c index 1d8b38fc1e2..c2694b5ddad 100644 --- a/sys/dev/usb/wlan/if_zyd.c +++ b/sys/dev/usb/wlan/if_zyd.c @@ -91,6 +91,7 @@ static usb2_proc_callback_t zyd_scantask; static usb2_proc_callback_t zyd_multitask; static usb2_proc_callback_t zyd_init_task; static usb2_proc_callback_t zyd_stop_task; +static usb2_proc_callback_t zyd_flush_task; static struct ieee80211vap *zyd_vap_create(struct ieee80211com *, const char name[IFNAMSIZ], int unit, int opmode, @@ -323,7 +324,7 @@ zyd_attach(device_t dev) mtx_init(&sc->sc_mtx, device_get_nameunit(sc->sc_dev), MTX_NETWORK_LOCK, MTX_DEF); - + cv_init(&sc->sc_cmd_cv, "wtxdone"); STAILQ_INIT(&sc->sc_rqh); iface_index = ZYD_IFACE_INDEX; @@ -370,6 +371,10 @@ zyd_attach_post(struct usb2_proc_msg *pm) return; } + /* XXX Async attach race */ + if (usb2_proc_is_gone(&sc->sc_tq)) + return; + ZYD_UNLOCK(sc); ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); @@ -459,7 +464,7 @@ zyd_detach(device_t dev) ieee80211_ifdetach(ic); if_free(ifp); } - + cv_destroy(&sc->sc_cmd_cv); mtx_destroy(&sc->sc_mtx); return (0); @@ -471,6 +476,7 @@ zyd_vap_create(struct ieee80211com *ic, const uint8_t bssid[IEEE80211_ADDR_LEN], const uint8_t mac[IEEE80211_ADDR_LEN]) { + struct zyd_softc *sc = ic->ic_ifp->if_softc; struct zyd_vap *zvp; struct ieee80211vap *vap; @@ -489,6 +495,7 @@ zyd_vap_create(struct ieee80211com *ic, zvp->newstate = vap->iv_newstate; vap->iv_newstate = zyd_newstate; + zvp->sc = sc; ieee80211_amrr_init(&zvp->amrr, vap, IEEE80211_AMRR_MIN_SUCCESS_THRESHOLD, IEEE80211_AMRR_MAX_SUCCESS_THRESHOLD, @@ -501,10 +508,24 @@ zyd_vap_create(struct ieee80211com *ic, return (vap); } +static void +zyd_flush_task(struct usb2_proc_msg *_pm) +{ + /* nothing to do */ +} + static void zyd_vap_delete(struct ieee80211vap *vap) { struct zyd_vap *zvp = ZYD_VAP(vap); + struct zyd_softc *sc = zvp->sc; + + ZYD_LOCK(sc); + /* wait for any pending tasks to complete */ + zyd_queue_command(sc, zyd_flush_task, + &sc->sc_synctask[0].hdr, + &sc->sc_synctask[1].hdr); + ZYD_UNLOCK(sc); ieee80211_amrr_cleanup(&zvp->amrr); ieee80211_vap_detach(vap); @@ -2478,6 +2499,10 @@ zyd_bulk_write_callback(struct usb2_xfer *xfer) 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", @@ -2494,6 +2519,10 @@ zyd_bulk_write_callback(struct usb2_xfer *xfer) /* 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); @@ -2732,9 +2761,9 @@ zyd_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) ZYD_LOCK(sc); if (ifp->if_flags & IFF_UP) { if (ifp->if_drv_flags & IFF_DRV_RUNNING) { - if ((ifp->if_flags ^ sc->sc_if_flags) & - (IFF_ALLMULTI | IFF_PROMISC)) - zyd_set_multi(sc); + zyd_queue_command(sc, zyd_multitask, + &sc->sc_mcasttask[0].hdr, + &sc->sc_mcasttask[1].hdr); } else { zyd_queue_command(sc, zyd_init_task, &sc->sc_synctask[0].hdr, @@ -2748,7 +2777,6 @@ zyd_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) &sc->sc_synctask[1].hdr); } } - sc->sc_if_flags = ifp->if_flags; ZYD_UNLOCK(sc); if (startall) ieee80211_start_all(ic); @@ -2868,6 +2896,7 @@ zyd_init_task(struct usb2_proc_msg *pm) ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; ifp->if_drv_flags |= IFF_DRV_RUNNING; + usb2_transfer_set_stall(sc->sc_xfer[ZYD_BULK_WR]); usb2_transfer_start(sc->sc_xfer[ZYD_BULK_RD]); usb2_transfer_start(sc->sc_xfer[ZYD_INTR_RD]); @@ -3067,6 +3096,33 @@ zyd_scantask(struct usb2_proc_msg *pm) } } +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); + + /* make sure any hardware FIFOs are emptied */ + usb2_pause_mtx(&sc->sc_mtx, hz / 1000); + + /* 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) @@ -3075,10 +3131,6 @@ zyd_queue_command(struct zyd_softc *sc, usb2_proc_callback_t *fn, ZYD_LOCK_ASSERT(sc, MA_OWNED); - if (usb2_proc_is_gone(&sc->sc_tq)) { - DPRINTF(sc, ZYD_DEBUG_STATE, "proc is gone\n"); - return; /* nothing to do */ - } /* * NOTE: The task cannot get executed before we drop the * "sc_mtx" mutex. It is safe to update fields in the message @@ -3088,14 +3140,19 @@ zyd_queue_command(struct zyd_softc *sc, usb2_proc_callback_t *fn, 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)) - usb2_proc_mwait(&sc->sc_tq, t0, t1); + /* 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); } static device_method_t zyd_methods[] = { diff --git a/sys/dev/usb/wlan/if_zydreg.h b/sys/dev/usb/wlan/if_zydreg.h index 8ef34e35472..fabed614c6a 100644 --- a/sys/dev/usb/wlan/if_zydreg.h +++ b/sys/dev/usb/wlan/if_zydreg.h @@ -1165,6 +1165,7 @@ struct zyd_mac_pair { struct zyd_task { struct usb2_proc_msg hdr; + usb2_proc_callback_t *func; struct zyd_softc *sc; }; @@ -1247,6 +1248,7 @@ struct zyd_vap { struct ieee80211vap vap; int (*newstate)(struct ieee80211vap *, enum ieee80211_state, int); + struct zyd_softc *sc; struct ieee80211_amrr amrr; }; #define ZYD_VAP(vap) ((struct zyd_vap *)(vap)) @@ -1266,6 +1268,7 @@ struct zyd_softc { struct usb2_process sc_tq; struct usb2_xfer *sc_xfer[ZYD_N_TRANSFER]; + struct zyd_task *sc_last_task; enum ieee80211_state sc_state; int sc_arg; @@ -1273,7 +1276,6 @@ struct zyd_softc { #define ZYD_FLAG_FWLOADED (1 << 0) #define ZYD_FLAG_INITONCE (1 << 1) #define ZYD_FLAG_INITDONE (1 << 2) - int sc_if_flags; struct zyd_task sc_synctask[2]; struct zyd_task sc_mcasttask[2]; @@ -1315,7 +1317,7 @@ struct zyd_softc { uint8_t sc_ofdm54_cal[14]; struct mtx sc_mtx; - struct cv sc_intr_cv; + struct cv sc_cmd_cv; struct zyd_tx_data tx_data[ZYD_TX_LIST_CNT]; zyd_txdhead tx_q; zyd_txdhead tx_free; -- 2.45.2