Convert if_rsu to use a deferred transmit task rather than using rsu_start()

to do it directly.

Ensure that we re-queue starting transmit upon TX completion.

This solves two issues:

* It stops tx stalls - before this, if the transmit path filled the
  mbuf queue then it'd never start another transmit.

* It enforces ordering - this is very required for 802.11n which
  requires frames to be transmitted in the order they're queued.
  Since everything remotely involved in USB has an unlock/thing/relock
  pattern with that mutex, the only way to guarantee TX ordering is
  to 100% defer it into a separate thread.

This now survives an iperf test and gets a reliable 30mbit/sec.
This commit is contained in:
Adrian Chadd 2015-09-21 02:30:22 +00:00
parent 829e0b0b84
commit 77435f1835
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=288052
2 changed files with 43 additions and 2 deletions

View File

@ -190,6 +190,7 @@ static uint8_t rsu_efuse_read_1(struct rsu_softc *, uint16_t);
static int rsu_read_rom(struct rsu_softc *); static int rsu_read_rom(struct rsu_softc *);
static int rsu_fw_cmd(struct rsu_softc *, uint8_t, void *, int); static int rsu_fw_cmd(struct rsu_softc *, uint8_t, void *, int);
static void rsu_calib_task(void *, int); static void rsu_calib_task(void *, int);
static void rsu_tx_task(void *, int);
static int rsu_newstate(struct ieee80211vap *, enum ieee80211_state, int); static int rsu_newstate(struct ieee80211vap *, enum ieee80211_state, int);
#ifdef notyet #ifdef notyet
static void rsu_set_key(struct rsu_softc *, const struct ieee80211_key *); static void rsu_set_key(struct rsu_softc *, const struct ieee80211_key *);
@ -217,6 +218,7 @@ static int rsu_tx_start(struct rsu_softc *, struct ieee80211_node *,
struct mbuf *, struct rsu_data *); struct mbuf *, struct rsu_data *);
static int rsu_transmit(struct ieee80211com *, struct mbuf *); static int rsu_transmit(struct ieee80211com *, struct mbuf *);
static void rsu_start(struct rsu_softc *); static void rsu_start(struct rsu_softc *);
static void _rsu_start(struct rsu_softc *);
static void rsu_parent(struct ieee80211com *); static void rsu_parent(struct ieee80211com *);
static void rsu_stop(struct rsu_softc *); static void rsu_stop(struct rsu_softc *);
static void rsu_ms_delay(struct rsu_softc *, int); static void rsu_ms_delay(struct rsu_softc *, int);
@ -379,6 +381,7 @@ rsu_attach(device_t self)
MTX_DEF); MTX_DEF);
TIMEOUT_TASK_INIT(taskqueue_thread, &sc->calib_task, 0, TIMEOUT_TASK_INIT(taskqueue_thread, &sc->calib_task, 0,
rsu_calib_task, sc); rsu_calib_task, sc);
TASK_INIT(&sc->tx_task, 0, rsu_tx_task, sc);
mbufq_init(&sc->sc_snd, ifqmaxlen); mbufq_init(&sc->sc_snd, ifqmaxlen);
/* Allocate Tx/Rx buffers. */ /* Allocate Tx/Rx buffers. */
@ -513,6 +516,7 @@ rsu_detach(device_t self)
ieee80211_ifdetach(ic); ieee80211_ifdetach(ic);
taskqueue_drain_timeout(taskqueue_thread, &sc->calib_task); taskqueue_drain_timeout(taskqueue_thread, &sc->calib_task);
taskqueue_drain(taskqueue_thread, &sc->tx_task);
/* Free Tx/Rx buffers. */ /* Free Tx/Rx buffers. */
rsu_free_tx_list(sc); rsu_free_tx_list(sc);
@ -1026,6 +1030,16 @@ rsu_calib_task(void *arg, int pending __unused)
RSU_UNLOCK(sc); RSU_UNLOCK(sc);
} }
static void
rsu_tx_task(void *arg, int pending __unused)
{
struct rsu_softc *sc = arg;
RSU_LOCK(sc);
_rsu_start(sc);
RSU_UNLOCK(sc);
}
static int static int
rsu_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) rsu_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
{ {
@ -1050,6 +1064,7 @@ rsu_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
sc->sc_calibrating = 0; sc->sc_calibrating = 0;
RSU_UNLOCK(sc); RSU_UNLOCK(sc);
taskqueue_drain_timeout(taskqueue_thread, &sc->calib_task); taskqueue_drain_timeout(taskqueue_thread, &sc->calib_task);
taskqueue_drain(taskqueue_thread, &sc->tx_task);
/* Disassociate from our current BSS. */ /* Disassociate from our current BSS. */
RSU_LOCK(sc); RSU_LOCK(sc);
rsu_disconnect(sc); rsu_disconnect(sc);
@ -1838,19 +1853,34 @@ rsu_bulk_tx_callback_sub(struct usb_xfer *xfer, usb_error_t error,
static void static void
rsu_bulk_tx_callback_be_bk(struct usb_xfer *xfer, usb_error_t error) rsu_bulk_tx_callback_be_bk(struct usb_xfer *xfer, usb_error_t error)
{ {
struct rsu_softc *sc = usbd_xfer_softc(xfer);
rsu_bulk_tx_callback_sub(xfer, error, RSU_BULK_TX_BE_BK); rsu_bulk_tx_callback_sub(xfer, error, RSU_BULK_TX_BE_BK);
/* This kicks the TX taskqueue */
rsu_start(sc);
} }
static void static void
rsu_bulk_tx_callback_vi_vo(struct usb_xfer *xfer, usb_error_t error) rsu_bulk_tx_callback_vi_vo(struct usb_xfer *xfer, usb_error_t error)
{ {
struct rsu_softc *sc = usbd_xfer_softc(xfer);
rsu_bulk_tx_callback_sub(xfer, error, RSU_BULK_TX_VI_VO); rsu_bulk_tx_callback_sub(xfer, error, RSU_BULK_TX_VI_VO);
/* This kicks the TX taskqueue */
rsu_start(sc);
} }
static void static void
rsu_bulk_tx_callback_h2c(struct usb_xfer *xfer, usb_error_t error) rsu_bulk_tx_callback_h2c(struct usb_xfer *xfer, usb_error_t error)
{ {
struct rsu_softc *sc = usbd_xfer_softc(xfer);
rsu_bulk_tx_callback_sub(xfer, error, RSU_BULK_TX_H2C); rsu_bulk_tx_callback_sub(xfer, error, RSU_BULK_TX_H2C);
/* This kicks the TX taskqueue */
rsu_start(sc);
} }
static int static int
@ -2008,9 +2038,11 @@ rsu_transmit(struct ieee80211com *ic, struct mbuf *m)
RSU_UNLOCK(sc); RSU_UNLOCK(sc);
return (error); return (error);
} }
rsu_start(sc);
RSU_UNLOCK(sc); RSU_UNLOCK(sc);
/* This kicks the TX taskqueue */
rsu_start(sc);
return (0); return (0);
} }
@ -2030,7 +2062,7 @@ rsu_drain_mbufq(struct rsu_softc *sc)
} }
static void static void
rsu_start(struct rsu_softc *sc) _rsu_start(struct rsu_softc *sc)
{ {
struct ieee80211_node *ni; struct ieee80211_node *ni;
struct rsu_data *bf; struct rsu_data *bf;
@ -2062,6 +2094,13 @@ rsu_start(struct rsu_softc *sc)
} }
} }
static void
rsu_start(struct rsu_softc *sc)
{
taskqueue_enqueue(taskqueue_thread, &sc->tx_task);
}
static void static void
rsu_parent(struct ieee80211com *ic) rsu_parent(struct ieee80211com *ic)
{ {
@ -2684,6 +2723,7 @@ rsu_stop(struct rsu_softc *sc)
sc->sc_running = 0; sc->sc_running = 0;
sc->sc_calibrating = 0; sc->sc_calibrating = 0;
taskqueue_cancel_timeout(taskqueue_thread, &sc->calib_task, NULL); taskqueue_cancel_timeout(taskqueue_thread, &sc->calib_task, NULL);
taskqueue_cancel(taskqueue_thread, &sc->tx_task, NULL);
/* Power off adapter. */ /* Power off adapter. */
rsu_power_off(sc); rsu_power_off(sc);

View File

@ -740,6 +740,7 @@ struct rsu_softc {
enum ieee80211_state, int); enum ieee80211_state, int);
struct usbd_interface *sc_iface; struct usbd_interface *sc_iface;
struct timeout_task calib_task; struct timeout_task calib_task;
struct task tx_task;
const uint8_t *qid2idx; const uint8_t *qid2idx;
struct mtx sc_mtx; struct mtx sc_mtx;
int sc_ht; int sc_ht;