diff --git a/sys/dev/rtwn/if_rtwnvar.h b/sys/dev/rtwn/if_rtwnvar.h --- a/sys/dev/rtwn/if_rtwnvar.h +++ b/sys/dev/rtwn/if_rtwnvar.h @@ -32,7 +32,7 @@ #define RTWN_MACID_VALID 0x8000 #define RTWN_MACID_LIMIT 128 -#define RTWN_TX_TIMEOUT 5000 /* ms */ +#define RTWN_TX_TIMEOUT 1000 /* ms */ #define RTWN_MAX_EPOUT 4 #define RTWN_PORT_COUNT 2 diff --git a/sys/dev/rtwn/usb/rtwn_usb_attach.c b/sys/dev/rtwn/usb/rtwn_usb_attach.c --- a/sys/dev/rtwn/usb/rtwn_usb_attach.c +++ b/sys/dev/rtwn/usb/rtwn_usb_attach.c @@ -156,10 +156,12 @@ if (error != 0) return (error); - STAILQ_INIT(&uc->uc_tx_active); - STAILQ_INIT(&uc->uc_tx_inactive); - STAILQ_INIT(&uc->uc_tx_pending); + for (i = RTWN_BULK_TX_FIRST; i < RTWN_BULK_EP_COUNT; i++) { + STAILQ_INIT(&uc->uc_tx_active[i]); + STAILQ_INIT(&uc->uc_tx_pending[i]); + } + STAILQ_INIT(&uc->uc_tx_inactive); for (i = 0; i < RTWN_USB_TX_LIST_COUNT; i++) STAILQ_INSERT_HEAD(&uc->uc_tx_inactive, &uc->uc_tx[i], next); @@ -207,23 +209,29 @@ rtwn_usb_free_tx_list(struct rtwn_softc *sc) { struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); + int i; rtwn_usb_free_list(sc, uc->uc_tx, RTWN_USB_TX_LIST_COUNT); - STAILQ_INIT(&uc->uc_tx_active); + for (i = RTWN_BULK_TX_FIRST; i < RTWN_BULK_EP_COUNT; i++) { + STAILQ_INIT(&uc->uc_tx_active[i]); + STAILQ_INIT(&uc->uc_tx_pending[i]); + } STAILQ_INIT(&uc->uc_tx_inactive); - STAILQ_INIT(&uc->uc_tx_pending); } static void rtwn_usb_reset_lists(struct rtwn_softc *sc, struct ieee80211vap *vap) { struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); + int i; RTWN_ASSERT_LOCKED(sc); - rtwn_usb_reset_tx_list(uc, &uc->uc_tx_active, vap); - rtwn_usb_reset_tx_list(uc, &uc->uc_tx_pending, vap); + for (i = RTWN_BULK_TX_FIRST; i < RTWN_BULK_EP_COUNT; i++) { + rtwn_usb_reset_tx_list(uc, &uc->uc_tx_active[i], vap); + rtwn_usb_reset_tx_list(uc, &uc->uc_tx_pending[i], vap); + } if (vap == NULL) { rtwn_usb_reset_rx_list(uc); sc->qfullmsk = 0; @@ -295,7 +303,7 @@ /* abort any pending transfers */ RTWN_UNLOCK(sc); - for (i = 0; i < RTWN_N_TRANSFER; i++) + for (i = 0; i < RTWN_BULK_EP_COUNT; i++) usbd_transfer_drain(uc->uc_xfer[i]); RTWN_LOCK(sc); } @@ -432,7 +440,7 @@ rtwn_usb_free_rx_list(sc); /* Detach all USB transfers. */ - usbd_transfer_unsetup(uc->uc_xfer, RTWN_N_TRANSFER); + usbd_transfer_unsetup(uc->uc_xfer, RTWN_BULK_EP_COUNT); rtwn_detach_private(sc); mtx_destroy(&sc->sc_mtx); diff --git a/sys/dev/rtwn/usb/rtwn_usb_ep.c b/sys/dev/rtwn/usb/rtwn_usb_ep.c --- a/sys/dev/rtwn/usb/rtwn_usb_ep.c +++ b/sys/dev/rtwn/usb/rtwn_usb_ep.c @@ -55,7 +55,7 @@ #include -static const struct usb_config rtwn_config_common[RTWN_N_TRANSFER] = { +static const struct usb_config rtwn_config_common[RTWN_BULK_EP_COUNT] = { [RTWN_BULK_RX] = { .type = UE_BULK, .endpoint = UE_ADDR_ANY, @@ -76,7 +76,7 @@ .pipe_bof = 1, .force_short_xfer = 1, }, - .callback = rtwn_bulk_tx_callback, + .callback = rtwn_bulk_tx_callback_be, .timeout = RTWN_TX_TIMEOUT, /* ms */ }, [RTWN_BULK_TX_BK] = { @@ -89,7 +89,7 @@ .pipe_bof = 1, .force_short_xfer = 1, }, - .callback = rtwn_bulk_tx_callback, + .callback = rtwn_bulk_tx_callback_bk, .timeout = RTWN_TX_TIMEOUT, /* ms */ }, [RTWN_BULK_TX_VI] = { @@ -102,7 +102,7 @@ .pipe_bof = 1, .force_short_xfer = 1 }, - .callback = rtwn_bulk_tx_callback, + .callback = rtwn_bulk_tx_callback_vi, .timeout = RTWN_TX_TIMEOUT, /* ms */ }, [RTWN_BULK_TX_VO] = { @@ -115,7 +115,7 @@ .pipe_bof = 1, .force_short_xfer = 1 }, - .callback = rtwn_bulk_tx_callback, + .callback = rtwn_bulk_tx_callback_vo, .timeout = RTWN_TX_TIMEOUT, /* ms */ }, }; @@ -200,22 +200,33 @@ /* NB: keep in sync with rtwn_dma_init(). */ rtwn_config[RTWN_BULK_TX_VO].endpoint = addr[0]; + uc->wme2qid[WME_AC_VO] = RTWN_BULK_TX_VO; switch (uc->ntx) { case 4: case 3: rtwn_config[RTWN_BULK_TX_BE].endpoint = addr[2]; rtwn_config[RTWN_BULK_TX_BK].endpoint = addr[2]; rtwn_config[RTWN_BULK_TX_VI].endpoint = addr[1]; + uc->wme2qid[WME_AC_BE] = RTWN_BULK_TX_BE; + uc->wme2qid[WME_AC_BK] = RTWN_BULK_TX_BE; + uc->wme2qid[WME_AC_VI] = RTWN_BULK_TX_VI; break; case 2: rtwn_config[RTWN_BULK_TX_BE].endpoint = addr[1]; rtwn_config[RTWN_BULK_TX_BK].endpoint = addr[1]; rtwn_config[RTWN_BULK_TX_VI].endpoint = addr[0]; + uc->wme2qid[WME_AC_BE] = RTWN_BULK_TX_VI; + uc->wme2qid[WME_AC_BK] = RTWN_BULK_TX_VI; + uc->wme2qid[WME_AC_VI] = RTWN_BULK_TX_VO; break; case 1: rtwn_config[RTWN_BULK_TX_BE].endpoint = addr[0]; rtwn_config[RTWN_BULK_TX_BK].endpoint = addr[0]; rtwn_config[RTWN_BULK_TX_VI].endpoint = addr[0]; + + uc->wme2qid[WME_AC_BE] = RTWN_BULK_TX_VO; + uc->wme2qid[WME_AC_BK] = RTWN_BULK_TX_VO; + uc->wme2qid[WME_AC_VI] = RTWN_BULK_TX_VO; break; default: KASSERT(0, ("unhandled number of endpoints %d\n", uc->ntx)); @@ -225,7 +236,7 @@ rtwn_config[RTWN_BULK_RX].bufsize = uc->uc_rx_buf_size * RTWN_USB_RXBUFSZ_UNIT; error = usbd_transfer_setup(uc->uc_udev, &iface_index, - uc->uc_xfer, rtwn_config, RTWN_N_TRANSFER, uc, &sc->sc_mtx); + uc->uc_xfer, rtwn_config, RTWN_BULK_EP_COUNT, uc, &sc->sc_mtx); free(rtwn_config, M_TEMP); if (error) { diff --git a/sys/dev/rtwn/usb/rtwn_usb_tx.h b/sys/dev/rtwn/usb/rtwn_usb_tx.h --- a/sys/dev/rtwn/usb/rtwn_usb_tx.h +++ b/sys/dev/rtwn/usb/rtwn_usb_tx.h @@ -17,7 +17,10 @@ #ifndef RTWN_USB_TX_H #define RTWN_USB_TX_H -void rtwn_bulk_tx_callback(struct usb_xfer *, usb_error_t); +void rtwn_bulk_tx_callback_bk(struct usb_xfer *, usb_error_t); +void rtwn_bulk_tx_callback_be(struct usb_xfer *, usb_error_t); +void rtwn_bulk_tx_callback_vi(struct usb_xfer *, usb_error_t); +void rtwn_bulk_tx_callback_vo(struct usb_xfer *, usb_error_t); int rtwn_usb_tx_start(struct rtwn_softc *, struct ieee80211_node *, struct mbuf *, uint8_t *, uint8_t, int); diff --git a/sys/dev/rtwn/usb/rtwn_usb_tx.c b/sys/dev/rtwn/usb/rtwn_usb_tx.c --- a/sys/dev/rtwn/usb/rtwn_usb_tx.c +++ b/sys/dev/rtwn/usb/rtwn_usb_tx.c @@ -65,10 +65,6 @@ static void rtwn_usb_txeof(struct rtwn_usb_softc *, struct rtwn_data *, int); -static const uint8_t wme2qid[] = - { RTWN_BULK_TX_BE, RTWN_BULK_TX_BK, - RTWN_BULK_TX_VI, RTWN_BULK_TX_VO }; - static struct rtwn_data * _rtwn_usb_getbuf(struct rtwn_usb_softc *uc) { @@ -105,6 +101,7 @@ rtwn_usb_txeof(struct rtwn_usb_softc *uc, struct rtwn_data *data, int status) { struct rtwn_softc *sc = &uc->uc_sc; + bool is_empty = true; RTWN_ASSERT_LOCKED(sc); @@ -120,42 +117,54 @@ STAILQ_INSERT_TAIL(&uc->uc_tx_inactive, data, next); sc->qfullmsk = 0; + #ifndef D4054 - if (STAILQ_EMPTY(&uc->uc_tx_active) && STAILQ_EMPTY(&uc->uc_tx_pending)) + for (int i = RTWN_BULK_TX_FIRST; i < RTWN_BULK_EP_COUNT; i++) { + if (!STAILQ_EMPTY(&uc->uc_tx_active[i]) || + !STAILQ_EMPTY(&uc->uc_tx_pending[i])) + is_empty = false; + } + + if (is_empty) sc->sc_tx_timer = 0; else sc->sc_tx_timer = 5; #endif } -void -rtwn_bulk_tx_callback(struct usb_xfer *xfer, usb_error_t error) +static void +rtwn_bulk_tx_callback_qid(struct usb_xfer *xfer, usb_error_t error, int qid) { struct rtwn_usb_softc *uc = usbd_xfer_softc(xfer); struct rtwn_softc *sc = &uc->uc_sc; struct rtwn_data *data; + bool do_is_empty_check = false; + int i; + + RTWN_DPRINTF(sc, RTWN_DEBUG_XMIT, + "%s: called, qid=%d\n", __func__, qid); RTWN_ASSERT_LOCKED(sc); switch (USB_GET_STATE(xfer)){ case USB_ST_TRANSFERRED: - data = STAILQ_FIRST(&uc->uc_tx_active); + data = STAILQ_FIRST(&uc->uc_tx_active[qid]); if (data == NULL) goto tr_setup; - STAILQ_REMOVE_HEAD(&uc->uc_tx_active, next); + STAILQ_REMOVE_HEAD(&uc->uc_tx_active[qid], next); rtwn_usb_txeof(uc, data, 0); /* FALLTHROUGH */ case USB_ST_SETUP: tr_setup: - data = STAILQ_FIRST(&uc->uc_tx_pending); + data = STAILQ_FIRST(&uc->uc_tx_pending[qid]); if (data == NULL) { RTWN_DPRINTF(sc, RTWN_DEBUG_XMIT, "%s: empty pending queue\n", __func__); - sc->sc_tx_n_active = 0; + do_is_empty_check = true; goto finish; } - STAILQ_REMOVE_HEAD(&uc->uc_tx_pending, next); - STAILQ_INSERT_TAIL(&uc->uc_tx_active, data, next); + STAILQ_REMOVE_HEAD(&uc->uc_tx_pending[qid], next); + STAILQ_INSERT_TAIL(&uc->uc_tx_active[qid], data, next); /* * Note: if this is a beacon frame, ensure that it will go @@ -169,11 +178,17 @@ sc->sc_tx_n_active++; break; default: - data = STAILQ_FIRST(&uc->uc_tx_active); + data = STAILQ_FIRST(&uc->uc_tx_active[qid]); if (data == NULL) goto tr_setup; - STAILQ_REMOVE_HEAD(&uc->uc_tx_active, next); + STAILQ_REMOVE_HEAD(&uc->uc_tx_active[qid], next); rtwn_usb_txeof(uc, data, 1); + if (error != 0) + device_printf(sc->sc_dev, + "%s: called; txeof qid=%d, error=%s\n", + __func__, + qid, + usbd_errstr(error)); if (error != USB_ERR_CANCELLED) { usbd_xfer_set_stall(xfer); goto tr_setup; @@ -181,6 +196,19 @@ break; } finish: + + /* + * Clear sc_tx_n_active if all the pending transfers are 0. + * + * This is currently a crutch because net80211 doesn't provide + * a way to defer all the FF checks or one of the FF checks. + * Eventually this should just be tracked per-endpoint. + */ + for (i = RTWN_BULK_TX_FIRST; i < RTWN_BULK_EP_COUNT; i++) + if (STAILQ_FIRST(&uc->uc_tx_pending[i]) != NULL) + do_is_empty_check = false; + if (do_is_empty_check) + sc->sc_tx_n_active = 0; #ifdef IEEE80211_SUPPORT_SUPERG /* * If the TX active queue drops below a certain @@ -210,6 +238,34 @@ rtwn_start(sc); } +void +rtwn_bulk_tx_callback_be(struct usb_xfer *xfer, usb_error_t error) +{ + + rtwn_bulk_tx_callback_qid(xfer, error, RTWN_BULK_TX_BE); +} + +void +rtwn_bulk_tx_callback_bk(struct usb_xfer *xfer, usb_error_t error) +{ + + rtwn_bulk_tx_callback_qid(xfer, error, RTWN_BULK_TX_BK); +} + +void +rtwn_bulk_tx_callback_vi(struct usb_xfer *xfer, usb_error_t error) +{ + + rtwn_bulk_tx_callback_qid(xfer, error, RTWN_BULK_TX_VI); +} + +void +rtwn_bulk_tx_callback_vo(struct usb_xfer *xfer, usb_error_t error) +{ + + rtwn_bulk_tx_callback_qid(xfer, error, RTWN_BULK_TX_VO); +} + static void rtwn_usb_tx_checksum(struct rtwn_tx_desc_common *txd) { @@ -226,6 +282,7 @@ struct rtwn_data *data; struct usb_xfer *xfer; uint16_t ac; + int qid = 0; RTWN_ASSERT_LOCKED(sc); @@ -236,17 +293,23 @@ if (data == NULL) return (ENOBUFS); + /* TODO: should really get a consistent AC/TID, ath(4) style */ ac = M_WME_GETAC(m); switch (type) { case IEEE80211_FC0_TYPE_CTL: case IEEE80211_FC0_TYPE_MGT: - xfer = uc->uc_xfer[RTWN_BULK_TX_VO]; + qid = RTWN_BULK_TX_VO; break; default: - xfer = uc->uc_xfer[wme2qid[ac]]; + qid = uc->wme2qid[ac]; break; } + xfer = uc->uc_xfer[qid]; + + RTWN_DPRINTF(sc, RTWN_DEBUG_XMIT, + "%s: called, ac=%d, qid=%d, xfer=%p\n", + __func__, ac, qid, xfer); txd = (struct rtwn_tx_desc_common *)tx_desc; txd->pktlen = htole16(m->m_pkthdr.len); @@ -264,6 +327,7 @@ data->buflen = m->m_pkthdr.len + sc->txdesc_len; data->id = id; data->ni = ni; + data->qid = qid; if (data->ni != NULL) { data->m = m; #ifndef D4054 @@ -271,7 +335,7 @@ #endif } - STAILQ_INSERT_TAIL(&uc->uc_tx_pending, data, next); + STAILQ_INSERT_TAIL(&uc->uc_tx_pending[qid], data, next); if (STAILQ_EMPTY(&uc->uc_tx_inactive)) sc->qfullmsk = 1; diff --git a/sys/dev/rtwn/usb/rtwn_usb_var.h b/sys/dev/rtwn/usb/rtwn_usb_var.h --- a/sys/dev/rtwn/usb/rtwn_usb_var.h +++ b/sys/dev/rtwn/usb/rtwn_usb_var.h @@ -37,6 +37,7 @@ uint8_t *buf; /* 'id' is meaningful for beacons only */ int id; + int qid; uint16_t buflen; struct mbuf *m; struct ieee80211_node *ni; @@ -50,15 +51,16 @@ RTWN_BULK_TX_BK, /* = WME_AC_BK */ RTWN_BULK_TX_VI, /* = WME_AC_VI */ RTWN_BULK_TX_VO, /* = WME_AC_VO */ - RTWN_N_TRANSFER = 5, + RTWN_BULK_EP_COUNT = 5, }; #define RTWN_EP_QUEUES RTWN_BULK_RX +#define RTWN_BULK_TX_FIRST RTWN_BULK_TX_BE struct rtwn_usb_softc { struct rtwn_softc uc_sc; /* must be the first */ struct usb_device *uc_udev; - struct usb_xfer *uc_xfer[RTWN_N_TRANSFER]; + struct usb_xfer *uc_xfer[RTWN_BULK_EP_COUNT]; struct rtwn_data uc_rx[RTWN_USB_RX_LIST_COUNT]; rtwn_datahead uc_rx_active; @@ -70,14 +72,16 @@ int uc_rx_off; struct rtwn_data uc_tx[RTWN_USB_TX_LIST_COUNT]; - rtwn_datahead uc_tx_active; + rtwn_datahead uc_tx_active[RTWN_BULK_EP_COUNT]; rtwn_datahead uc_tx_inactive; - rtwn_datahead uc_tx_pending; + rtwn_datahead uc_tx_pending[RTWN_BULK_EP_COUNT]; int (*uc_align_rx)(int, int); int ntx; int tx_agg_desc_num; + + uint8_t wme2qid[4]; }; #define RTWN_USB_SOFTC(sc) ((struct rtwn_usb_softc *)(sc))