- Split transmit queue into one for each type. Apparently there will

be a race when using a single active queue for all transmit types.
- Last argument of usb_pause_mtx() is ticks and not milliseconds.
- Remove unused watchdog.
- Remove some unused fields from the RSU softc structure.
- Workaround usbd_transfer_start() recursion from inside of completion
callback.

MFC after:	3 days
This commit is contained in:
hselasky 2014-05-21 16:52:55 +00:00
parent 36bcae6396
commit 5b5a0e0ff5
2 changed files with 94 additions and 105 deletions

View File

@ -128,7 +128,10 @@ static const STRUCT_USB_HOST_ID rsu_devs[] = {
static device_probe_t rsu_match;
static device_attach_t rsu_attach;
static device_detach_t rsu_detach;
static usb_callback_t rsu_bulk_tx_callback;
static usb_callback_t rsu_bulk_tx_callback_0;
static usb_callback_t rsu_bulk_tx_callback_1;
static usb_callback_t rsu_bulk_tx_callback_2;
static usb_callback_t rsu_bulk_tx_callback_3;
static usb_callback_t rsu_bulk_rx_callback;
static usb_error_t rsu_do_request(struct rsu_softc *,
struct usb_device_request *, void *);
@ -187,11 +190,10 @@ static int rsu_raw_xmit(struct ieee80211_node *, struct mbuf *,
const struct ieee80211_bpf_params *);
static void rsu_init(void *);
static void rsu_init_locked(struct rsu_softc *);
static void rsu_watchdog(void *);
static int rsu_tx_start(struct rsu_softc *, struct ieee80211_node *,
struct mbuf *, struct rsu_data *, struct usb_xfer *);
struct mbuf *, struct rsu_data *);
static void rsu_start(struct ifnet *);
static void rsu_start_locked(struct ifnet *, struct usb_xfer *);
static void rsu_start_locked(struct ifnet *);
static int rsu_ioctl(struct ifnet *, u_long, caddr_t);
static void rsu_stop(struct ifnet *, int);
static void rsu_stop_locked(struct ifnet *, int);
@ -241,7 +243,7 @@ static const struct usb_config rsu_config[RSU_N_TRANSFER] = {
.pipe_bof = 1,
.force_short_xfer = 1
},
.callback = rsu_bulk_tx_callback,
.callback = rsu_bulk_tx_callback_0,
.timeout = RSU_TX_TIMEOUT
},
[RSU_BULK_TX_BK] = {
@ -254,7 +256,7 @@ static const struct usb_config rsu_config[RSU_N_TRANSFER] = {
.pipe_bof = 1,
.force_short_xfer = 1
},
.callback = rsu_bulk_tx_callback,
.callback = rsu_bulk_tx_callback_1,
.timeout = RSU_TX_TIMEOUT
},
[RSU_BULK_TX_VI] = {
@ -267,7 +269,7 @@ static const struct usb_config rsu_config[RSU_N_TRANSFER] = {
.pipe_bof = 1,
.force_short_xfer = 1
},
.callback = rsu_bulk_tx_callback,
.callback = rsu_bulk_tx_callback_2,
.timeout = RSU_TX_TIMEOUT
},
[RSU_BULK_TX_VO] = {
@ -280,7 +282,7 @@ static const struct usb_config rsu_config[RSU_N_TRANSFER] = {
.pipe_bof = 1,
.force_short_xfer = 1
},
.callback = rsu_bulk_tx_callback,
.callback = rsu_bulk_tx_callback_3,
.timeout = RSU_TX_TIMEOUT
},
};
@ -316,7 +318,6 @@ rsu_attach(device_t self)
MTX_DEF);
TIMEOUT_TASK_INIT(taskqueue_thread, &sc->calib_task, 0,
rsu_calib_task, sc);
callout_init(&sc->sc_watchdog_ch, 0);
iface_index = 0;
error = usbd_transfer_setup(uaa->device, &iface_index, sc->sc_xfer,
@ -428,7 +429,6 @@ rsu_detach(device_t self)
usbd_transfer_unsetup(sc->sc_xfer, RSU_N_TRANSFER);
ieee80211_ifdetach(ic);
callout_drain(&sc->sc_watchdog_ch);
taskqueue_drain_timeout(taskqueue_thread, &sc->calib_task);
/* Free Tx/Rx buffers. */
@ -598,9 +598,12 @@ rsu_alloc_tx_list(struct rsu_softc *sc)
if (error != 0)
return (error);
STAILQ_INIT(&sc->sc_tx_active);
STAILQ_INIT(&sc->sc_tx_inactive);
STAILQ_INIT(&sc->sc_tx_pending);
for (i = 0; i != RSU_MAX_TX_EP; i++) {
STAILQ_INIT(&sc->sc_tx_active[i]);
STAILQ_INIT(&sc->sc_tx_pending[i]);
}
for (i = 0; i < RSU_TX_LIST_COUNT; i++) {
STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, &sc->sc_tx[i], next);
@ -843,10 +846,12 @@ rsu_read_rom(struct rsu_softc *sc)
static int
rsu_fw_cmd(struct rsu_softc *sc, uint8_t code, void *buf, int len)
{
const uint8_t which = RSU_BULK_TX_VO - RSU_BULK_TX_BE;
struct rsu_data *data;
struct r92s_tx_desc *txd;
struct r92s_fw_cmd_hdr *cmd;
int cmdsz, xferlen;
int cmdsz;
int xferlen;
data = rsu_getbuf(sc);
if (data == NULL)
@ -879,8 +884,8 @@ rsu_fw_cmd(struct rsu_softc *sc, uint8_t code, void *buf, int len)
DPRINTFN(2, "Tx cmd code=0x%x len=0x%x\n", code, cmdsz);
data->buflen = xferlen;
STAILQ_INSERT_TAIL(&sc->sc_tx_pending, data, next);
usbd_transfer_start(sc->sc_xfer[RSU_BULK_TX_VO]);
STAILQ_INSERT_TAIL(&sc->sc_tx_pending[which], data, next);
usbd_transfer_start(sc->sc_xfer[which + RSU_BULK_TX_BE]);
return (0);
}
@ -1574,13 +1579,13 @@ rsu_txeof(struct usb_xfer *xfer, struct rsu_data *data)
ieee80211_free_node(data->ni);
data->ni = NULL;
}
sc->sc_tx_timer = 0;
ifp->if_opackets++;
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
}
static void
rsu_bulk_tx_callback(struct usb_xfer *xfer, usb_error_t error)
rsu_bulk_tx_callback_sub(struct usb_xfer *xfer, usb_error_t error,
uint8_t which)
{
struct rsu_softc *sc = usbd_xfer_softc(xfer);
struct ifnet *ifp = sc->sc_ifp;
@ -1590,37 +1595,36 @@ rsu_bulk_tx_callback(struct usb_xfer *xfer, usb_error_t error)
switch (USB_GET_STATE(xfer)) {
case USB_ST_TRANSFERRED:
data = STAILQ_FIRST(&sc->sc_tx_active);
data = STAILQ_FIRST(&sc->sc_tx_active[which]);
if (data == NULL)
goto tr_setup;
DPRINTF("transfer done %p\n", data);
STAILQ_REMOVE_HEAD(&sc->sc_tx_active, next);
STAILQ_REMOVE_HEAD(&sc->sc_tx_active[which], next);
rsu_txeof(xfer, data);
STAILQ_INSERT_TAIL(&sc->sc_tx_inactive, data, next);
/* FALLTHROUGH */
case USB_ST_SETUP:
tr_setup:
data = STAILQ_FIRST(&sc->sc_tx_pending);
data = STAILQ_FIRST(&sc->sc_tx_pending[which]);
if (data == NULL) {
DPRINTF("empty pending queue sc %p\n", sc);
return;
}
STAILQ_REMOVE_HEAD(&sc->sc_tx_pending, next);
STAILQ_INSERT_TAIL(&sc->sc_tx_active, data, next);
STAILQ_REMOVE_HEAD(&sc->sc_tx_pending[which], next);
STAILQ_INSERT_TAIL(&sc->sc_tx_active[which], data, next);
usbd_xfer_set_frame_data(xfer, 0, data->buf, data->buflen);
DPRINTF("submitting transfer %p\n", data);
usbd_transfer_submit(xfer);
rsu_start_locked(ifp, xfer);
break;
default:
data = STAILQ_FIRST(&sc->sc_tx_active);
if (data == NULL)
goto tr_setup;
if (data->ni != NULL) {
ieee80211_free_node(data->ni);
data->ni = NULL;
ifp->if_oerrors++;
data = STAILQ_FIRST(&sc->sc_tx_active[which]);
if (data != NULL) {
STAILQ_REMOVE_HEAD(&sc->sc_tx_active[which], next);
rsu_txeof(xfer, data);
STAILQ_INSERT_TAIL(&sc->sc_tx_inactive, data, next);
}
ifp->if_oerrors++;
if (error != USB_ERR_CANCELLED) {
usbd_xfer_set_stall(xfer);
goto tr_setup;
@ -1629,9 +1633,33 @@ rsu_bulk_tx_callback(struct usb_xfer *xfer, usb_error_t error)
}
}
static void
rsu_bulk_tx_callback_0(struct usb_xfer *xfer, usb_error_t error)
{
rsu_bulk_tx_callback_sub(xfer, error, 0);
}
static void
rsu_bulk_tx_callback_1(struct usb_xfer *xfer, usb_error_t error)
{
rsu_bulk_tx_callback_sub(xfer, error, 1);
}
static void
rsu_bulk_tx_callback_2(struct usb_xfer *xfer, usb_error_t error)
{
rsu_bulk_tx_callback_sub(xfer, error, 2);
}
static void
rsu_bulk_tx_callback_3(struct usb_xfer *xfer, usb_error_t error)
{
rsu_bulk_tx_callback_sub(xfer, error, 3);
}
static int
rsu_tx_start(struct rsu_softc *sc, struct ieee80211_node *ni,
struct mbuf *m0, struct rsu_data *data, struct usb_xfer *xfer_self)
struct mbuf *m0, struct rsu_data *data)
{
struct ifnet *ifp = sc->sc_ifp;
struct ieee80211com *ic = ifp->if_l2com;
@ -1639,15 +1667,11 @@ rsu_tx_start(struct rsu_softc *sc, struct ieee80211_node *ni,
struct ieee80211_frame *wh;
struct ieee80211_key *k = NULL;
struct r92s_tx_desc *txd;
struct usb_xfer *xfer;
uint8_t type, tid = 0;
int hasqos, xferlen;
struct usb_xfer *rsu_pipes[4] = {
sc->sc_xfer[RSU_BULK_TX_BE],
sc->sc_xfer[RSU_BULK_TX_BK],
sc->sc_xfer[RSU_BULK_TX_VI],
sc->sc_xfer[RSU_BULK_TX_VO]
};
uint8_t type;
uint8_t tid = 0;
uint8_t which;
int hasqos;
int xferlen;
RSU_ASSERT_LOCKED(sc);
@ -1668,12 +1692,12 @@ rsu_tx_start(struct rsu_softc *sc, struct ieee80211_node *ni,
switch (type) {
case IEEE80211_FC0_TYPE_CTL:
case IEEE80211_FC0_TYPE_MGT:
xfer = sc->sc_xfer[RSU_BULK_TX_VO];
which = RSU_BULK_TX_VO - RSU_BULK_TX_BE;
break;
default:
KASSERT(M_WME_GETAC(m0) < 4,
("unsupported WME pipe %d", M_WME_GETAC(m0)));
xfer = rsu_pipes[M_WME_GETAC(m0)];
which = M_WME_GETAC(m0) + RSU_BULK_TX_BE;
break;
}
hasqos = 0;
@ -1735,10 +1759,10 @@ rsu_tx_start(struct rsu_softc *sc, struct ieee80211_node *ni,
data->buflen = xferlen;
data->ni = ni;
data->m = m0;
STAILQ_INSERT_TAIL(&sc->sc_tx_pending, data, next);
STAILQ_INSERT_TAIL(&sc->sc_tx_pending[which], data, next);
if (xfer != xfer_self)
usbd_transfer_start(xfer);
/* start transfer, if any */
usbd_transfer_start(sc->sc_xfer[which + RSU_BULK_TX_BE]);
return (0);
}
@ -1751,17 +1775,17 @@ rsu_start(struct ifnet *ifp)
return;
RSU_LOCK(sc);
rsu_start_locked(ifp, NULL);
rsu_start_locked(ifp);
RSU_UNLOCK(sc);
}
static void
rsu_start_locked(struct ifnet *ifp, struct usb_xfer *xfer_self)
rsu_start_locked(struct ifnet *ifp)
{
struct rsu_softc *sc = ifp->if_softc;
struct ieee80211_node *ni;
struct mbuf *m;
struct rsu_data *bf;
struct mbuf *m;
RSU_ASSERT_LOCKED(sc);
@ -1769,39 +1793,19 @@ rsu_start_locked(struct ifnet *ifp, struct usb_xfer *xfer_self)
IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
if (m == NULL)
break;
bf = rsu_getbuf(sc);
if (bf == NULL) {
IFQ_DRV_PREPEND(&ifp->if_snd, m);
break;
}
ni = (struct ieee80211_node *)m->m_pkthdr.rcvif;
m->m_pkthdr.rcvif = NULL;
if (rsu_tx_start(sc, ni, m, bf, xfer_self) != 0) {
bf = rsu_getbuf(sc);
if (bf == NULL) {
ifp->if_iqdrops++;
m_freem(m);
ieee80211_free_node(ni);
} else if (rsu_tx_start(sc, ni, m, bf) != 0) {
ifp->if_oerrors++;
STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, bf, next);
ieee80211_free_node(ni);
break;
}
sc->sc_tx_timer = 5;
callout_reset(&sc->sc_watchdog_ch, hz, rsu_watchdog, sc);
}
}
static void
rsu_watchdog(void *arg)
{
struct rsu_softc *sc = arg;
struct ifnet *ifp = sc->sc_ifp;
if (sc->sc_tx_timer > 0) {
if (--sc->sc_tx_timer == 0) {
device_printf(sc->sc_dev, "device timeout\n");
/* rsu_init(ifp); XXX needs a process context! */
ifp->if_oerrors++;
return;
}
callout_reset(&sc->sc_watchdog_ch, hz, rsu_watchdog, sc);
}
}
@ -1933,7 +1937,7 @@ rsu_power_on_bcut(struct rsu_softc *sc)
/* Prevent eFuse leakage. */
rsu_write_1(sc, 0x37, 0xb0);
usb_pause_mtx(&sc->sc_mtx, 10);
usb_pause_mtx(&sc->sc_mtx, hz / 100);
rsu_write_1(sc, 0x37, 0x30);
/* Switch the control path to hardware. */
@ -2045,7 +2049,7 @@ rsu_power_off(struct rsu_softc *sc)
{
/* Turn RF off. */
rsu_write_1(sc, R92S_RF_CTRL, 0x00);
usb_pause_mtx(&sc->sc_mtx, 5);
usb_pause_mtx(&sc->sc_mtx, hz / 200);
/* Turn MAC off. */
/* Switch control path. */
@ -2073,6 +2077,7 @@ rsu_power_off(struct rsu_softc *sc)
static int
rsu_fw_loadsection(struct rsu_softc *sc, const uint8_t *buf, int len)
{
const uint8_t which = RSU_BULK_TX_VO - RSU_BULK_TX_BE;
struct rsu_data *data;
struct r92s_tx_desc *txd;
int mlen;
@ -2093,12 +2098,11 @@ rsu_fw_loadsection(struct rsu_softc *sc, const uint8_t *buf, int len)
memcpy(&txd[1], buf, mlen);
data->buflen = sizeof(*txd) + mlen;
DPRINTF("starting transfer %p\n", data);
STAILQ_INSERT_TAIL(&sc->sc_tx_pending, data, next);
STAILQ_INSERT_TAIL(&sc->sc_tx_pending[which], data, next);
buf += mlen;
len -= mlen;
}
usbd_transfer_start(sc->sc_xfer[RSU_BULK_TX_VO]);
usbd_transfer_start(sc->sc_xfer[RSU_BULK_TX_BE + which]);
return (0);
}
@ -2169,7 +2173,7 @@ rsu_load_firmware(struct rsu_softc *sc)
}
/* Wait for load to complete. */
for (ntries = 0; ntries < 10; ntries++) {
usb_pause_mtx(&sc->sc_mtx, 10);
usb_pause_mtx(&sc->sc_mtx, hz / 100);
reg = rsu_read_2(sc, R92S_TCR);
if (reg & R92S_TCR_IMEM_CODE_DONE)
break;
@ -2190,7 +2194,7 @@ rsu_load_firmware(struct rsu_softc *sc)
}
/* Wait for load to complete. */
for (ntries = 0; ntries < 10; ntries++) {
usb_pause_mtx(&sc->sc_mtx, 10);
usb_pause_mtx(&sc->sc_mtx, hz / 100);
reg = rsu_read_2(sc, R92S_TCR);
if (reg & R92S_TCR_EMEM_CODE_DONE)
break;
@ -2235,7 +2239,7 @@ rsu_load_firmware(struct rsu_softc *sc)
dmem = __DECONST(struct r92s_fw_priv *, &hdr->priv);
memset(dmem, 0, sizeof(*dmem));
dmem->hci_sel = R92S_HCI_SEL_USB | R92S_HCI_SEL_8172;
dmem->nendpoints = sc->npipes;
dmem->nendpoints = 0;
dmem->rf_config = 0x12; /* 1T2R */
dmem->vcs_type = R92S_VCS_TYPE_AUTO;
dmem->vcs_mode = R92S_VCS_MODE_RTS_CTS;
@ -2304,7 +2308,7 @@ rsu_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
return (ENOBUFS);
}
ifp->if_opackets++;
if (rsu_tx_start(sc, ni, m, bf, NULL) != 0) {
if (rsu_tx_start(sc, ni, m, bf) != 0) {
ieee80211_free_node(ni);
ifp->if_oerrors++;
STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, bf, next);
@ -2312,7 +2316,6 @@ rsu_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
return (EIO);
}
RSU_UNLOCK(sc);
sc->sc_tx_timer = 5;
return (0);
}
@ -2433,9 +2436,6 @@ rsu_init_locked(struct rsu_softc *sc)
/* We're ready to go. */
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
ifp->if_drv_flags |= IFF_DRV_RUNNING;
callout_reset(&sc->sc_watchdog_ch, hz, rsu_watchdog, sc);
return;
fail:
rsu_free_rx_list(sc);
@ -2460,7 +2460,6 @@ rsu_stop_locked(struct ifnet *ifp, int disable __unused)
int i;
ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
callout_stop(&sc->sc_watchdog_ch);
sc->sc_calibrating = 0;
taskqueue_cancel_timeout(taskqueue_thread, &sc->calib_task, NULL);

View File

@ -1,4 +1,3 @@
/*-
* Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
*
@ -18,9 +17,6 @@
* $FreeBSD$
*/
/* Maximum number of pipes is 11. */
#define R92S_MAX_EP 11
/* USB Requests. */
#define R92S_REQ_REGS 0x05
@ -519,7 +515,7 @@ struct r92s_rx_stat {
uint32_t rxdw4;
uint32_t rxdw5;
} __packed __attribute__((aligned(4)));
} __packed __aligned(4);
/* Rx PHY descriptor. */
struct r92s_rx_phystat {
@ -531,7 +527,7 @@ struct r92s_rx_phystat {
uint32_t phydw5;
uint32_t phydw6;
uint32_t phydw7;
} __packed __attribute__((aligned(4)));
} __packed __aligned(4);
/* Rx PHY CCK descriptor. */
struct r92s_rx_cck {
@ -595,18 +591,14 @@ struct r92s_tx_desc {
uint16_t txbufsize;
uint16_t reserved1;
} __packed __attribute__((aligned(4)));
} __packed __aligned(4);
/*
* Driver definitions.
*/
#define RSU_RX_LIST_COUNT 1
#ifdef __OpenBSD__
#define RSU_TX_LIST_COUNT (8 + 1) /* NB: +1 for FW commands. */
#else
#define RSU_TX_LIST_COUNT 32
#endif
#define RSU_HOST_CMD_RING_COUNT 32
@ -735,6 +727,8 @@ struct rsu_vap {
#define RSU_UNLOCK(sc) mtx_unlock(&(sc)->sc_mtx)
#define RSU_ASSERT_LOCKED(sc) mtx_assert(&(sc)->sc_mtx, MA_OWNED)
#define RSU_MAX_TX_EP 4
struct rsu_softc {
struct ifnet *sc_ifp;
device_t sc_dev;
@ -743,15 +737,11 @@ struct rsu_softc {
enum ieee80211_state, int);
struct usbd_interface *sc_iface;
struct timeout_task calib_task;
struct callout sc_watchdog_ch;
struct usbd_pipe *pipe[R92S_MAX_EP];
int npipes;
const uint8_t *qid2idx;
struct mtx sc_mtx;
u_int cut;
int scan_pass;
int sc_tx_timer;
struct rsu_host_cmd_ring cmdq;
struct rsu_data sc_rx[RSU_RX_LIST_COUNT];
struct rsu_data sc_tx[RSU_TX_LIST_COUNT];
@ -764,9 +754,9 @@ struct rsu_softc {
STAILQ_HEAD(, rsu_data) sc_rx_active;
STAILQ_HEAD(, rsu_data) sc_rx_inactive;
STAILQ_HEAD(, rsu_data) sc_tx_active;
STAILQ_HEAD(, rsu_data) sc_tx_active[RSU_MAX_TX_EP];
STAILQ_HEAD(, rsu_data) sc_tx_inactive;
STAILQ_HEAD(, rsu_data) sc_tx_pending;
STAILQ_HEAD(, rsu_data) sc_tx_pending[RSU_MAX_TX_EP];
union {
struct rsu_rx_radiotap_header th;