rum(4): add command queue for running sleepable tasks in non-sleepable contexts

Tested:

* Tested on WUSB54GC, STA mode.
* rum0: MAC/BBP RT2573 (rev 0x2573a), RF RT2528

Submitted by:	<s3erios@gmail.com>
Differential Revision:	https://reviews.freebsd.org/D3629
This commit is contained in:
Adrian Chadd 2015-10-03 05:46:35 +00:00
parent e7b7db3d59
commit f28c2f5e54
2 changed files with 103 additions and 7 deletions

View File

@ -158,6 +158,9 @@ static struct ieee80211vap *rum_vap_create(struct ieee80211com *,
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 @@ rum_attach(device_t self)
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 @@ rum_attach(device_t self)
&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_detach(device_t self)
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);
}
@ -624,6 +634,57 @@ rum_vap_delete(struct ieee80211vap *vap)
free(rvp, M_80211_VAP);
}
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)
{

View File

@ -67,6 +67,25 @@ struct rum_tx_data {
};
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 rum_softc {
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_softc {
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)