Index: head/sys/dev/usb/wlan/if_rum.c =================================================================== --- head/sys/dev/usb/wlan/if_rum.c +++ head/sys/dev/usb/wlan/if_rum.c @@ -158,6 +158,9 @@ int, const uint8_t [IEEE80211_ADDR_LEN], const uint8_t [IEEE80211_ADDR_LEN]); static void rum_vap_delete(struct ieee80211vap *); +static void rum_cmdq_cb(void *, int); +static int rum_cmd_sleepable(struct rum_softc *, const void *, + size_t, uint8_t, uint8_t, CMD_FUNC_PROTO); static void rum_tx_free(struct rum_tx_data *, int); static void rum_setup_tx_list(struct rum_softc *); static void rum_unsetup_tx_list(struct rum_softc *); @@ -438,8 +441,8 @@ sc->sc_udev = uaa->device; sc->sc_dev = self; - mtx_init(&sc->sc_mtx, device_get_nameunit(self), - MTX_NETWORK_LOCK, MTX_DEF); + RUM_LOCK_INIT(sc); + RUM_CMDQ_LOCK_INIT(sc); mbufq_init(&sc->sc_snd, ifqmaxlen); iface_index = RT2573_IFACE_INDEX; @@ -516,6 +519,8 @@ &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap), RT2573_RX_RADIOTAP_PRESENT); + TASK_INIT(&sc->cmdq_task, 0, rum_cmdq_cb, sc); + if (bootverbose) ieee80211_announce(ic); @@ -545,10 +550,15 @@ rum_unsetup_tx_list(sc); RUM_UNLOCK(sc); - if (ic->ic_softc == sc) + if (ic->ic_softc == sc) { + ieee80211_draintask(ic, &sc->cmdq_task); ieee80211_ifdetach(ic); + } + mbufq_drain(&sc->sc_snd); - mtx_destroy(&sc->sc_mtx); + RUM_CMDQ_LOCK_DESTROY(sc); + RUM_LOCK_DESTROY(sc); + return (0); } @@ -625,6 +635,57 @@ } static void +rum_cmdq_cb(void *arg, int pending) +{ + struct rum_softc *sc = arg; + struct rum_cmdq *rc; + + RUM_CMDQ_LOCK(sc); + while (sc->cmdq[sc->cmdq_first].func != NULL) { + rc = &sc->cmdq[sc->cmdq_first]; + RUM_CMDQ_UNLOCK(sc); + + RUM_LOCK(sc); + rc->func(sc, &rc->data, rc->rn_id, rc->rvp_id); + RUM_UNLOCK(sc); + + RUM_CMDQ_LOCK(sc); + memset(rc, 0, sizeof (*rc)); + sc->cmdq_first = (sc->cmdq_first + 1) % RUM_CMDQ_SIZE; + } + RUM_CMDQ_UNLOCK(sc); +} + +static int +rum_cmd_sleepable(struct rum_softc *sc, const void *ptr, size_t len, + uint8_t rn_id, uint8_t rvp_id, CMD_FUNC_PROTO) +{ + struct ieee80211com *ic = &sc->sc_ic; + + KASSERT(len <= sizeof(union sec_param), ("buffer overflow")); + + RUM_CMDQ_LOCK(sc); + if (sc->cmdq[sc->cmdq_last].func != NULL) { + device_printf(sc->sc_dev, "%s: cmdq overflow\n", __func__); + RUM_CMDQ_UNLOCK(sc); + + return EAGAIN; + } + + if (ptr != NULL) + memcpy(&sc->cmdq[sc->cmdq_last].data, ptr, len); + sc->cmdq[sc->cmdq_last].rn_id = rn_id; + sc->cmdq[sc->cmdq_last].rvp_id = rvp_id; + sc->cmdq[sc->cmdq_last].func = func; + sc->cmdq_last = (sc->cmdq_last + 1) % RUM_CMDQ_SIZE; + RUM_CMDQ_UNLOCK(sc); + + ieee80211_runtask(ic, &sc->cmdq_task); + + return 0; +} + +static void rum_tx_free(struct rum_tx_data *data, int txerr) { struct rum_softc *sc = data->sc; Index: head/sys/dev/usb/wlan/if_rumvar.h =================================================================== --- head/sys/dev/usb/wlan/if_rumvar.h +++ head/sys/dev/usb/wlan/if_rumvar.h @@ -67,6 +67,25 @@ }; typedef STAILQ_HEAD(, rum_tx_data) rum_txdhead; +union sec_param { + struct ieee80211_key key; + uint8_t macaddr[IEEE80211_ADDR_LEN]; + struct ieee80211vap *vap; +}; +#define CMD_FUNC_PROTO void (*func)(struct rum_softc *, \ + union sec_param *, uint8_t, \ + uint8_t) + +struct rum_cmdq { + union sec_param data; + + uint8_t rn_id; + uint8_t rvp_id; + + CMD_FUNC_PROTO; +}; +#define RUM_CMDQ_SIZE 16 + struct rum_vap { struct ieee80211vap vap; struct ieee80211_beacon_offsets bo; @@ -103,6 +122,12 @@ struct mtx sc_mtx; + struct rum_cmdq cmdq[RUM_CMDQ_SIZE]; + struct mtx cmdq_mtx; + struct task cmdq_task; + uint8_t cmdq_first; + uint8_t cmdq_last; + uint32_t sta[6]; uint32_t rf_regs[4]; uint8_t txpow[44]; @@ -128,6 +153,16 @@ struct rum_tx_radiotap_header sc_txtap; }; -#define RUM_LOCK(sc) mtx_lock(&(sc)->sc_mtx) -#define RUM_UNLOCK(sc) mtx_unlock(&(sc)->sc_mtx) -#define RUM_LOCK_ASSERT(sc) mtx_assert(&(sc)->sc_mtx, MA_OWNED) +#define RUM_LOCK_INIT(sc) \ + mtx_init(&(sc)->sc_mtx, device_get_nameunit((sc)->sc_dev), \ + MTX_NETWORK_LOCK, MTX_DEF); +#define RUM_LOCK(sc) mtx_lock(&(sc)->sc_mtx) +#define RUM_UNLOCK(sc) mtx_unlock(&(sc)->sc_mtx) +#define RUM_LOCK_ASSERT(sc) mtx_assert(&(sc)->sc_mtx, MA_OWNED) +#define RUM_LOCK_DESTROY(sc) mtx_destroy(&(sc)->sc_mtx) + +#define RUM_CMDQ_LOCK_INIT(sc) \ + mtx_init(&(sc)->cmdq_mtx, "cmdq lock", NULL, MTX_DEF) +#define RUM_CMDQ_LOCK(sc) mtx_lock(&(sc)->cmdq_mtx) +#define RUM_CMDQ_UNLOCK(sc) mtx_unlock(&(sc)->cmdq_mtx) +#define RUM_CMDQ_LOCK_DESTROY(sc) mtx_destroy(&(sc)->cmdq_mtx)