Date: Sun, 10 Jan 2010 11:49:14 GMT From: Hans Petter Selasky <hselasky@FreeBSD.org> To: Perforce Change Reviews <perforce@FreeBSD.org> Subject: PERFORCE change 172914 for review Message-ID: <201001101149.o0ABnEeu044011@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://p4web.freebsd.org/chv.cgi?CH=172914 Change 172914 by hselasky@hselasky_laptop001 on 2010/01/10 11:48:34 USB WLAN: - fixes and corrections to RUN driver. - patch by: HPS Affected files ... .. //depot/projects/usb/src/sys/dev/usb/wlan/if_run.c#2 edit .. //depot/projects/usb/src/sys/dev/usb/wlan/if_runreg.h#2 edit .. //depot/projects/usb/src/sys/dev/usb/wlan/if_runvar.h#2 edit Differences ... ==== //depot/projects/usb/src/sys/dev/usb/wlan/if_run.c#2 (text+ko) ==== @@ -75,7 +75,7 @@ #define USB_DEBUG_VAR run_debug #include <dev/usb/usb_debug.h> -#include "rt2860reg.h" /* shared with ral(4) */ +#include "if_runreg.h" /* shared with ral(4) */ #include "if_runvar.h" #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) @@ -266,15 +266,22 @@ static device_detach_t run_detach; static usb_callback_t run_bulk_rx_callback; -static usb_callback_t run_bulk_tx_callback; +static usb_callback_t run_bulk_tx_callback0; +static usb_callback_t run_bulk_tx_callback1; +static usb_callback_t run_bulk_tx_callback2; +static usb_callback_t run_bulk_tx_callback3; +static usb_callback_t run_bulk_tx_callback4; +static usb_callback_t run_bulk_tx_callback5; +static void run_bulk_tx_callbackN(struct usb_xfer *xfer, + usb_error_t error, unsigned int index); static struct ieee80211vap *run_vap_create(struct ieee80211com *, const char name[IFNAMSIZ], int unit, int opmode, int flags, const uint8_t bssid[IEEE80211_ADDR_LEN], const uint8_t mac[IEEE80211_ADDR_LEN]); static void run_vap_delete(struct ieee80211vap *); -static void run_setup_tx_list(struct run_softc *); -static void run_unsetup_tx_list(struct run_softc *); +static void run_setup_tx_list(struct run_softc *sc, struct run_endpoint_queue *pq); +static void run_unsetup_tx_list(struct run_softc *sc, struct run_endpoint_queue *pq); static int run_load_microcode(struct run_softc *); static int run_reset(struct run_softc *); static usb_error_t run_do_request(struct run_softc *sc, @@ -314,9 +321,9 @@ static void run_iter_func(void *, struct ieee80211_node *); static void run_newassoc(struct ieee80211_node *, int); static void run_rx_frame(struct run_softc *, struct mbuf *, uint32_t); -static void run_tx_free(struct run_tx_data *, int); +static void run_tx_free(struct run_endpoint_queue *pq, struct run_tx_data *, int); static void run_set_tx_desc(struct run_softc *, struct run_tx_data *, - uint8_t, uint8_t, uint8_t, uint8_t, uint8_t); + uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t); static int run_tx(struct run_softc *, struct mbuf *, struct ieee80211_node *); static int run_tx_mgt(struct run_softc *, struct mbuf *, struct ieee80211_node *); @@ -326,7 +333,6 @@ struct ieee80211_node *, const struct ieee80211_bpf_params *); static int run_raw_xmit(struct ieee80211_node *, struct mbuf *, const struct ieee80211_bpf_params *); -static void run_start_task(void *, int); static void run_start(struct ifnet *); static int run_ioctl(struct ifnet *, u_long, caddr_t); static void run_select_chan_group(struct run_softc *, int); @@ -363,6 +369,7 @@ static void run_init(void *); static void run_init_locked(struct run_softc *); static void run_stop(void *); +static void run_delay(struct run_softc *, unsigned int); static const struct { uint32_t reg; @@ -406,7 +413,7 @@ .direction = UE_DIR_OUT, .bufsize = RUN_MAX_TXSZ, .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, - .callback = run_bulk_tx_callback, + .callback = run_bulk_tx_callback0, .timeout = 5000, /* ms */ }, [RUN_BULK_TX_BK] = { @@ -416,7 +423,7 @@ .ep_index = 1, .bufsize = RUN_MAX_TXSZ, .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, - .callback = run_bulk_tx_callback, + .callback = run_bulk_tx_callback1, .timeout = 5000, /* ms */ }, [RUN_BULK_TX_VI] = { @@ -426,7 +433,7 @@ .ep_index = 2, .bufsize = RUN_MAX_TXSZ, .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, - .callback = run_bulk_tx_callback, + .callback = run_bulk_tx_callback2, .timeout = 5000, /* ms */ }, [RUN_BULK_TX_VO] = { @@ -436,18 +443,17 @@ .ep_index = 3, .bufsize = RUN_MAX_TXSZ, .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, - .callback = run_bulk_tx_callback, + .callback = run_bulk_tx_callback3, .timeout = 5000, /* ms */ }, -#ifdef SIX /* see enum in if_runvar.h */ [RUN_BULK_TX_HCCA] = { .type = UE_BULK, .endpoint = UE_ADDR_ANY, .direction = UE_DIR_OUT, .ep_index = 4, .bufsize = RUN_MAX_TXSZ, - .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, - .callback = run_bulk_tx_callback, + .flags = {.pipe_bof = 1,.force_short_xfer = 1,.no_pipe_ok = 1,}, + .callback = run_bulk_tx_callback4, .timeout = 5000, /* ms */ }, [RUN_BULK_TX_PRIO] = { @@ -456,11 +462,10 @@ .direction = UE_DIR_OUT, .ep_index = 5, .bufsize = RUN_MAX_TXSZ, - .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, - .callback = run_bulk_tx_callback, + .flags = {.pipe_bof = 1,.force_short_xfer = 1,.no_pipe_ok = 1,}, + .callback = run_bulk_tx_callback5, .timeout = 5000, /* ms */ }, -#endif /* SIX */ [RUN_BULK_RX] = { .type = UE_BULK, .endpoint = UE_ADDR_ANY, @@ -502,26 +507,16 @@ mtx_init(&sc->sc_mtx, device_get_nameunit(sc->sc_dev), MTX_NETWORK_LOCK, MTX_DEF); - mtx_init(&sc->rx_cb_mtx, device_get_nameunit(sc->sc_dev), - "USB NIC Rx callback", MTX_DEF); /* for Rx callback lock */ iface_index = RT2860_IFACE_INDEX; /* Rx transfer has own lock */ error = usbd_transfer_setup(uaa->device, &iface_index, - sc->sc_xfer, run_config, RUN_N_XFER -1, sc, &sc->sc_mtx); + sc->sc_xfer, run_config, RUN_N_XFER, sc, &sc->sc_mtx); if (error) { device_printf(self, "could not allocate USB Tx transfers, " "err=%s\n", usbd_errstr(error)); goto detach; } - error = usbd_transfer_setup(uaa->device, &iface_index, - &sc->sc_xfer[RUN_N_XFER -1], &run_config[RUN_N_XFER -1], 1, - sc, &sc->rx_cb_mtx); - if (error) { - device_printf(self, "could not allocate USB Rx transfers, " - "err=%s\n", usbd_errstr(error)); - goto detach; - } RUN_LOCK(sc); @@ -533,7 +528,7 @@ } if (sc->mac_rev != 0 && sc->mac_rev != 0xffffffff) break; - DELAY(10); + run_delay(sc, 10); } if (ntries == 100) { printf("%s: timeout waiting for NIC to initialize\n", @@ -663,13 +658,15 @@ struct run_softc *sc = device_get_softc(self); struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic; + int i; /* stop all USB transfers */ usbd_transfer_unsetup(sc->sc_xfer, RUN_N_XFER); RUN_LOCK(sc); /* free TX list, if any */ - run_unsetup_tx_list(sc); + for (i = 0; i != RUN_EP_QUEUES; i++) + run_unsetup_tx_list(sc, &sc->sc_epq[i]); RUN_UNLOCK(sc); if (ifp) { @@ -679,9 +676,8 @@ } mtx_destroy(&sc->sc_mtx); - mtx_destroy(&sc->rx_cb_mtx); - return 0; + return (0); } static struct ieee80211vap * @@ -720,7 +716,6 @@ vap->iv_newstate = run_newstate; TASK_INIT(&rvp->amrr_task, 0, run_amrr_cb, rvp); - TASK_INIT(&sc->start_task, 0, run_start_task, ic->ic_ifp); TASK_INIT(&sc->wme_task, 0, run_wme_update_cb, ic); callout_init((struct callout *)&rvp->amrr_ch, 1); ieee80211_amrr_init(&rvp->amrr, vap, @@ -763,38 +758,36 @@ } static void -run_setup_tx_list(struct run_softc *sc) +run_setup_tx_list(struct run_softc *sc, struct run_endpoint_queue *pq) { - struct run_tx_data *data; + struct run_tx_data *data; - sc->tx_nfree = 0; - STAILQ_INIT(&sc->tx_q); - STAILQ_INIT(&sc->tx_free); + memset(pq, 0, sizeof(*pq)); - for (data = &sc->txq[0]; - data < &sc->txq[RUN_TX_RING_COUNT]; data++){ - memset(data->desc, 0, sizeof (struct rt2870_txd) + - sizeof (struct rt2860_txwi)); + STAILQ_INIT(&pq->tx_qh); + STAILQ_INIT(&pq->tx_fh); + for (data = &pq->tx_data[0]; + data < &pq->tx_data[RUN_TX_RING_COUNT]; data++) { data->sc = sc; - STAILQ_INSERT_TAIL(&sc->tx_free, data, next); - sc->tx_nfree++; + STAILQ_INSERT_TAIL(&pq->tx_fh, data, next); } + pq->tx_nfree = RUN_TX_RING_COUNT; } static void -run_unsetup_tx_list(struct run_softc *sc) +run_unsetup_tx_list(struct run_softc *sc, struct run_endpoint_queue *pq) { - struct run_tx_data *data; + struct run_tx_data *data; /* make sure any subsequent use of the queues will fail */ - sc->tx_nfree = 0; - STAILQ_INIT(&sc->tx_q); - STAILQ_INIT(&sc->tx_free); + pq->tx_nfree = 0; + STAILQ_INIT(&pq->tx_fh); + STAILQ_INIT(&pq->tx_qh); /* free up all node references and mbufs */ - for (data = &sc->txq[0]; - data < &sc->txq[RUN_TX_RING_COUNT]; data++){ + for (data = &pq->tx_data[0]; + data < &pq->tx_data[RUN_TX_RING_COUNT]; data++){ if (data->m != NULL) { m_freem(data->m); data->m = NULL; @@ -864,8 +857,8 @@ if ((error = usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, NULL)) != 0) return error; - /*TODO make macro */ - usb_pause_mtx(&sc->sc_mtx, 10); + run_delay(sc, 10); + run_write(sc, RT2860_H2M_MAILBOX, 0); if ((error = run_mcu_cmd(sc, RT2860_MCU_CMD_BOOT, 0)) != 0) return error; @@ -876,7 +869,7 @@ return error; if (tmp & RT2860_MCU_READY) break; - DELAY(1000); + run_delay(sc, 1000); } if (ntries == 1000) { printf("%s: timeout waiting for MCU to initialize\n", @@ -917,7 +910,7 @@ break; DPRINTFN(1, "Control request failed, %s (retrying)\n", usbd_errstr(err)); - DELAY(10); + run_delay(sc, 10); } return (err); } @@ -1038,7 +1031,7 @@ return error; if (!(tmp & RT3070_EFSROM_KICK)) break; - DELAY(2); + run_delay(sc, 2); } if (ntries == 100) return ETIMEDOUT; @@ -1603,6 +1596,7 @@ break; default: DPRINTFN(6, "undefined case\n"); + break; } RUN_UNLOCK(sc); @@ -2071,7 +2065,7 @@ return rxchain; } -static __inline void /* big but inlined only once */ +static void run_rx_frame(struct run_softc *sc, struct mbuf *m, uint32_t dmalen) { struct ifnet *ifp = sc->sc_ifp; @@ -2089,6 +2083,8 @@ rxwi = mtod(m, struct rt2860_rxwi *); len = le16toh(rxwi->len) & 0xfff; if (__predict_false(len > dmalen)) { + m_freem(m); + ifp->if_ierrors++; DPRINTF("bad RXWI length %u > %u\n", len, dmalen); return; } @@ -2097,6 +2093,7 @@ flags = le32toh(rxd->flags); if (__predict_false(flags & (RT2860_RX_CRCERR | RT2860_RX_ICVERR))) { + m_freem(m); ifp->if_ierrors++; DPRINTF("%s error.\n", (flags & RT2860_RX_CRCERR)?"CRC":"ICV"); return; @@ -2133,17 +2130,14 @@ m->m_pkthdr.rcvif = ifp; m->m_pkthdr.len = m->m_len = len; -#if 1 - DPRINTFN(3, "addr1 %s\n", ether_sprintf(mtod(m, struct ieee80211_frame_min *)->i_addr1)); -#endif - ni = ieee80211_find_rxnode(ic, mtod(m, struct ieee80211_frame_min *)); if (ni != NULL) { (void)ieee80211_input(ni, m, rssi, nf); ieee80211_free_node(ni); - } else + } else { (void)ieee80211_input_all(ic, m, rssi, nf); + } if(__predict_false(ieee80211_radiotap_active(ic))){ struct run_rx_radiotap_header *tap = &sc->sc_rxtap; @@ -2180,10 +2174,7 @@ } break; } - //ieee80211_radiotap_rx(vap, m); } - - return; } static void @@ -2191,9 +2182,10 @@ { struct run_softc *sc = usbd_xfer_softc(xfer); struct ifnet *ifp = sc->sc_ifp; - struct mbuf *m, *m0; - uint32_t dmalen; - int xferlen; + struct mbuf *m = NULL; + struct mbuf *m0; + uint32_t dmalen; + int xferlen; usbd_xfer_status(xfer, &xferlen, NULL, NULL, NULL); @@ -2205,117 +2197,113 @@ if (xferlen < sizeof (uint32_t) + sizeof (struct rt2860_rxwi) + sizeof (struct rt2870_rxd)) { DPRINTF("xfer too short %d\n", xferlen); - goto tr_set; + goto tr_setup; } -#if 1 - if(xferlen > MJUMPAGESIZE) - DPRINTF("rx buf overflow\n"); -#endif - m = sc->rx_m; sc->rx_m = NULL; - m->m_pkthdr.len = m->m_len = xferlen; - - mtx_unlock(&sc->rx_cb_mtx); - /* HW can aggregate multiple 802.11 frames in a single USB xfer */ - for(;;){ - dmalen = le32toh(*mtod(m, uint32_t *)) & 0xffff; - - if (__predict_false(dmalen == 0 || (dmalen & 3) != 0)) { - DPRINTF("bad DMA length %u\n", dmalen); - break; - } - if (__predict_false(dmalen + 8 > xferlen)) { - DPRINTF("bad DMA length %u > %d\n", - dmalen + 8, xferlen); - break; - } - - /* If it is the last one or a single frame, we won't copy. */ - if((xferlen -= dmalen + 8) <= 8){ - /* trim 32-bit DMA-len header */ - m->m_data += 4; - m->m_pkthdr.len = m->m_len -= 4; - run_rx_frame(sc, m, dmalen); - break; - } - - /* copy aggregated frames to another mbuf */ - m0 = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); - if (__predict_false(m0 == NULL)) { - DPRINTF("could not allocate mbuf\n"); - ifp->if_ierrors++; - return; - } - m_copydata(m, 4 /* skip 32-bit DMA-len header */, - dmalen + sizeof(struct rt2870_rxd), mtod(m0, caddr_t)); - m0->m_pkthdr.len = m0->m_len = - dmalen + sizeof(struct rt2870_rxd); - run_rx_frame(sc, m0, dmalen); - /* update data ptr */ - m->m_data += dmalen + 8; - m->m_pkthdr.len = m->m_len -= dmalen + 8; - } - - mtx_lock(&sc->rx_cb_mtx); - /* FALLTHROUGH */ case USB_ST_SETUP: - if(__predict_false(sc->rx_m != NULL)){ - DPRINTF("rx buf is full\n"); - ifp->if_ierrors++; - return; +tr_setup: + if (sc->rx_m == NULL) { + sc->rx_m = m_getjcl(M_DONTWAIT, MT_DATA, M_PKTHDR, + MJUMPAGESIZE /* xfer can be bigger than MCLBYTES */); } - sc->rx_m = m_getjcl(M_DONTWAIT, MT_DATA, M_PKTHDR, - MJUMPAGESIZE /* xfer can be begger than MCLBYTES */); - if (__predict_false(sc->rx_m == NULL)) { - DPRINTF("could not allocate mbuf\n"); + if (sc->rx_m == NULL) { + DPRINTF("could not allocate mbuf - idle with stall\n"); ifp->if_ierrors++; - return; + usbd_xfer_set_stall(xfer); + usbd_xfer_set_frames(xfer, 0); + } else { + /* + * Directly loading a mbuf cluster into DMA to + * save some data copying. This works because + * there is only one cluster. + */ + usbd_xfer_set_frame_data(xfer, 0, + mtod(sc->rx_m, caddr_t), RUN_MAX_RXSZ); + usbd_xfer_set_frames(xfer, 1); } -tr_set: - /* - * directly loading a mbuf cluster into DMA - * to save some data copying - * This works because there is only one cluster. - */ - usbd_xfer_set_frame_data(xfer, 0, mtod(sc->rx_m, caddr_t), - usbd_xfer_max_len(xfer)); usbd_transfer_submit(xfer); + break; - return; - default: /* Error */ if (error != USB_ERR_CANCELLED) { /* try to clear stall first */ usbd_xfer_set_stall(xfer); - if(__predict_true(sc->rx_m != NULL)) - goto tr_set; - sc->rx_m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); - if (__predict_false(sc->rx_m == NULL)) { - DPRINTF("could not allocate mbuf\n"); - ifp->if_ierrors++; - return; - } - goto tr_set; + + if (error == USB_ERR_TIMEOUT) + device_printf(sc->sc_dev, "device timeout\n"); + + ifp->if_ierrors++; + + goto tr_setup; } if(sc->rx_m != NULL){ - m_free(sc->rx_m); + m_freem(sc->rx_m); sc->rx_m = NULL; } + break; + } + + if (m == NULL) + return; + + /* inputting all the frames must be last */ + + RUN_UNLOCK(sc); + + m->m_pkthdr.len = m->m_len = xferlen; + + /* HW can aggregate multiple 802.11 frames in a single USB xfer */ + for(;;) { + dmalen = le32toh(*mtod(m, uint32_t *)) & 0xffff; + + if ((dmalen == 0) || ((dmalen & 3) != 0)) { + DPRINTF("bad DMA length %u\n", dmalen); + break; + } + if ((dmalen + 8) > xferlen) { + DPRINTF("bad DMA length %u > %d\n", + dmalen + 8, xferlen); + break; + } + + /* If it is the last one or a single frame, we won't copy. */ + if((xferlen -= dmalen + 8) <= 8){ + /* trim 32-bit DMA-len header */ + m->m_data += 4; + m->m_pkthdr.len = m->m_len -= 4; + run_rx_frame(sc, m, dmalen); + break; + } + + /* copy aggregated frames to another mbuf */ + m0 = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); + if (__predict_false(m0 == NULL)) { + DPRINTF("could not allocate mbuf\n"); + ifp->if_ierrors++; + break; + } + m_copydata(m, 4 /* skip 32-bit DMA-len header */, + dmalen + sizeof(struct rt2870_rxd), mtod(m0, caddr_t)); + m0->m_pkthdr.len = m0->m_len = + dmalen + sizeof(struct rt2870_rxd); + run_rx_frame(sc, m0, dmalen); + + /* update data ptr */ + m->m_data += dmalen + 8; + m->m_pkthdr.len = m->m_len -= dmalen + 8; } - return; + + RUN_LOCK(sc); } -static __inline void -run_tx_free(struct run_tx_data *data, int txerr) +static void +run_tx_free(struct run_endpoint_queue *pq, + struct run_tx_data *data, int txerr) { - struct run_softc *sc = data->sc; - struct ifnet *ifp = sc->sc_ifp; - struct ieee80211com *ic = ifp->if_l2com; - if (data->m != NULL) { if (data->m->m_flags & M_TXCB) ieee80211_process_callback(data->ni, data->m, @@ -2323,33 +2311,27 @@ m_freem(data->m); data->m = NULL; - if(data->ni == NULL) + if(data->ni == NULL) { DPRINTF("no node\n"); - else{ + } else { ieee80211_free_node(data->ni); data->ni = NULL; } } - STAILQ_INSERT_TAIL(&sc->tx_free, data, next); - sc->tx_nfree++; - if(__predict_false(ifp->if_drv_flags & IFF_DRV_OACTIVE && - sc->tx_nfree > RUN_TX_RING_COUNT - 2)){ - /* call run_start() when tx ring gets 'almost' empty */ - ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; - if(sc->dequeue == RUN_NO_DEQUEUE) - ieee80211_runtask(ic, &sc->start_task); - } + STAILQ_INSERT_TAIL(&pq->tx_fh, data, next); + pq->tx_nfree++; } static void -run_bulk_tx_callback(struct usb_xfer *xfer, usb_error_t error) +run_bulk_tx_callbackN(struct usb_xfer *xfer, usb_error_t error, unsigned int index) { struct run_softc *sc = usbd_xfer_softc(xfer); struct ifnet *ifp = sc->sc_ifp; struct run_tx_data *data; struct ieee80211vap *vap = NULL; struct usb_page_cache *pc; + struct run_endpoint_queue *pq = &sc->sc_epq[index]; struct mbuf *m; usb_frlength_t size; unsigned int len; @@ -2359,103 +2341,167 @@ switch (USB_GET_STATE(xfer)){ case USB_ST_TRANSFERRED: - DPRINTFN(11, "transfer complete, %d bytes\n", actlen); + DPRINTFN(11, "transfer complete: %d " + "bytes @ index %d\n", actlen, index); + data = usbd_xfer_get_priv(xfer); - run_tx_free(data, 0); + + run_tx_free(pq, data, 0); + usbd_xfer_set_priv(xfer, NULL); ifp->if_opackets++; /* FALLTHROUGH */ case USB_ST_SETUP: -tr_set:; - data = STAILQ_FIRST(&sc->tx_q); - if(__predict_false(data == NULL)){ +tr_setup: + data = STAILQ_FIRST(&pq->tx_qh); + if(data == NULL) break; - } - STAILQ_REMOVE_HEAD(&sc->tx_q, next); + + STAILQ_REMOVE_HEAD(&pq->tx_qh, next); m = data->m; - if (__predict_false(m->m_pkthdr.len > RUN_MAX_TXSZ)) { + if (m->m_pkthdr.len > RUN_MAX_TXSZ) { DPRINTF("data overflow, %u bytes\n", m->m_pkthdr.len); - error = 10; /* just give non 0 */ - goto fail; /* sorry for an extra goto */ + + ifp->if_oerrors++; + + run_tx_free(pq, data, 1); + + goto tr_setup; } pc = usbd_xfer_get_frame(xfer, 0); - size = sizeof(struct rt2870_txd) + sizeof(struct rt2860_txwi); + size = sizeof(data->desc); usbd_copy_in(pc, 0, &data->desc, size); usbd_m_copy_in(pc, size, m, 0, m->m_pkthdr.len); - if(data->ni != NULL){ - if((vap = data->ni->ni_vap) != NULL); - if (__predict_false(ieee80211_radiotap_active_vap(vap))) { + vap = data->ni->ni_vap; + if (ieee80211_radiotap_active_vap(vap)) { struct run_tx_radiotap_header *tap = &sc->sc_txtap; tap->wt_flags = 0; tap->wt_rate = rt2860_rates[data->ridx].rate; tap->wt_chan_freq = htole16(vap->iv_bss->ni_chan->ic_freq); tap->wt_chan_flags = htole16(vap->iv_bss->ni_chan->ic_flags); - tap->wt_hwqueue = data->qid; + tap->wt_hwqueue = index; if (data->mcs & RT2860_PHY_SHPRE) tap->wt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; ieee80211_radiotap_tx(vap, m); } - } + /* align end on a 4-bytes boundary */ - len = (size + 4 + m->m_pkthdr.len + 3) & ~3; + len = (size + m->m_pkthdr.len + 3) & ~3; - DPRINTFN(11, "sending frame len=%u xferlen=%u\n", - m->m_pkthdr.len, len); + DPRINTFN(11, "sending frame len=%u xferlen=%u @ index %d\n", + m->m_pkthdr.len, len, index); usbd_xfer_set_frame_len(xfer, 0, len); usbd_xfer_set_priv(xfer, data); usbd_transfer_submit(xfer); + RUN_UNLOCK(sc); + run_start(ifp); + RUN_LOCK(sc); + break; + default: DPRINTF("USB transfer error, %s\n", usbd_errstr(error)); data = usbd_xfer_get_priv(xfer); -fail: + ifp->if_oerrors++; if (data != NULL) { - run_tx_free(data, error); + run_tx_free(pq, data, error); usbd_xfer_set_priv(xfer, NULL); } - if (error == USB_ERR_TIMEOUT){ - device_printf(sc->sc_dev, "device timeout\n"); - /* check if timeout is caused due to livelock */ - run_usb_timeout(sc); + if (error != USB_ERR_CANCELLED) { + if (error == USB_ERR_TIMEOUT) { + device_printf(sc->sc_dev, "device timeout\n"); + + /* defer until later */ + sc->sc_usb_timeout = 1; + + /* XXX this should be in a separate task! */ + run_usb_timeout(sc); + } + + /* + * Try to clear stall first, also if other + * errors occur, hence clearing stall + * introduces a 50 ms delay: + */ + usbd_xfer_set_stall(xfer); + goto tr_setup; } - if (error == USB_ERR_STALLED) - usbd_xfer_set_stall(xfer); - goto tr_set; break; } } static void +run_bulk_tx_callback0(struct usb_xfer *xfer, usb_error_t error) +{ + run_bulk_tx_callbackN(xfer, error, 0); +} + +static void +run_bulk_tx_callback1(struct usb_xfer *xfer, usb_error_t error) +{ + run_bulk_tx_callbackN(xfer, error, 1); +} + +static void +run_bulk_tx_callback2(struct usb_xfer *xfer, usb_error_t error) +{ + run_bulk_tx_callbackN(xfer, error, 2); +} + +static void +run_bulk_tx_callback3(struct usb_xfer *xfer, usb_error_t error) +{ + run_bulk_tx_callbackN(xfer, error, 3); +} + +static void +run_bulk_tx_callback4(struct usb_xfer *xfer, usb_error_t error) +{ + run_bulk_tx_callbackN(xfer, error, 4); +} + +static void +run_bulk_tx_callback5(struct usb_xfer *xfer, usb_error_t error) +{ + run_bulk_tx_callbackN(xfer, error, 5); +} + +static void run_set_tx_desc(struct run_softc *sc, struct run_tx_data *data, - uint8_t wflags, uint8_t xflags, uint8_t opflags, uint8_t dflags, uint8_t type) + uint8_t wflags, uint8_t xflags, uint8_t opflags, uint8_t dflags, + uint8_t type, uint8_t pad) { struct mbuf *m = data->m; struct ieee80211com *ic = sc->sc_ifp->if_l2com; + struct ieee80211vap *vap = &sc->sc_rvp->vap; + struct ieee80211_frame *wh; struct rt2870_txd *txd; struct rt2860_txwi *txwi; int xferlen; - uint8_t mcs, ridx = data->ridx; + uint8_t mcs; + uint8_t ridx = data->ridx; /* get MCS code from rate index */ data->mcs = mcs = rt2860_rates[ridx].mcs; - xferlen = sizeof (*txwi) + m->m_pkthdr.len; + xferlen = sizeof(*txwi) + m->m_pkthdr.len; + /* roundup to 32-bit alignment */ xferlen = (xferlen + 3) & ~3; @@ -2469,7 +2515,7 @@ txwi->xflags = xflags; txwi->wcid = (type == IEEE80211_FC0_TYPE_DATA) ? RUN_AID2WCID(data->ni->ni_associd) : 0xff; - txwi->len = htole16(m->m_pkthdr.len); + txwi->len = htole16(m->m_pkthdr.len - pad); if (rt2860_rates[ridx].phy == IEEE80211_T_DS) { txwi->phy = htole16(RT2860_PHY_CCK); if (ridx != RT2860_RIDX_CCK1 && @@ -2479,9 +2525,6 @@ txwi->phy = htole16(RT2860_PHY_OFDM); txwi->phy |= htole16(mcs); -#if 1 - struct ieee80211vap *vap = &sc->sc_rvp->vap; - struct ieee80211_frame *wh; wh = mtod(m, struct ieee80211_frame *); /* check if RTS/CTS or CTS-to-self protection is required */ @@ -2491,22 +2534,31 @@ rt2860_rates[ridx].phy == IEEE80211_T_OFDM))) txwi->txop = RT2860_TX_TXOP_HT | opflags; else -#endif txwi->txop = RT2860_TX_TXOP_BACKOFF | opflags; } +/* This function must be called locked */ static int run_tx(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni) { - struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic = sc->sc_ifp->if_l2com; struct ieee80211vap *vap = &sc->sc_rvp->vap; struct ieee80211_frame *wh; const struct ieee80211_txparam *tp; struct run_tx_data *data; - uint16_t qos, dur; - uint8_t *frm, type, tid, qid, qflags, pad, xflags = 0; - int hasqos, ridx, ctl_ridx, error = 0; + uint16_t qos; + uint16_t dur; + uint8_t type; + uint8_t tid; + uint8_t qid; + uint8_t qflags; + uint8_t pad; + uint8_t xflags = 0; + int hasqos; + int ridx; + int ctl_ridx; + + RUN_LOCK_ASSERT(sc, MA_OWNED); wh = mtod(m, struct ieee80211_frame *); @@ -2519,35 +2571,28 @@ * seem to have only 4 TX bulk endpoints (Fukaumi Naoki). */ if ((hasqos = IEEE80211_QOS_HAS_SEQ(wh))) { + uint8_t *frm; + if(IEEE80211_HAS_ADDR4(wh)) frm = ((struct ieee80211_qosframe_addr4 *)wh)->i_qos; else frm =((struct ieee80211_qosframe *)wh)->i_qos; + qos = le16toh(*(const uint16_t *)frm); tid = qos & IEEE80211_QOS_TID; + qid = TID_TO_WME_AC(tid); pad = 2; - - /* - * This is my best guess based on original code. - * I don't have data sheet. - */ -#ifdef SIX - qid = tid <= 6? tid: 6; - qflags = qid < 5? RT2860_TX_QSEL_EDCA : RT2860_TX_QSEL_HCCA; -#else - qid = TID_TO_WME_AC(tid); - qflags = RT2860_TX_QSEL_EDCA; -#endif - DPRINTFN(8, "qos %d\tqid %d\ttid %d\tqflags %x\n", - qos, qid, tid, qflags); } else { qos = 0; tid = 0; qid = WME_AC_BE; - qflags = RT2860_TX_QSEL_EDCA; pad = 0; } + qflags = (qid < 4) ? RT2860_TX_QSEL_EDCA : RT2860_TX_QSEL_HCCA; + DPRINTFN(8, "qos %d\tqid %d\ttid %d\tqflags %x\n", + qos, qid, tid, qflags); + tp = &vap->iv_txparms[ieee80211_chan2mode(ni->ni_chan)]; /* pickup a rate index */ @@ -2578,110 +2623,31 @@ *(uint16_t *)wh->i_dur = htole16(dur + sc->sifs); } - RUN_LOCK(sc); - /* save one for mgt packet, just in case */ - if (__predict_false(sc->tx_nfree < 3)) { - /* - * Stop dequeuing when the last txq ring is used, - * so that we don't have to call IFQ_DRV_PREPEND(). - * (no txq, no dequeue) - * - * Returning '-1' cause the process exit from the loop in run_start(). - * (Don't for get to mark flag as not dequeuing.) - * - * It would be better to put these in run_start(), - * but do these here while holding a lock. - */ - sc->dequeue = RUN_NO_DEQUEUE; - ifp->if_drv_flags |= IFF_DRV_OACTIVE; - if(sc->tx_nfree == 2){ - error = -1; - DPRINTFN(4, "the last of txq ring used\n"); - /* continue to process packet */ - } else { - /* shouldn't reach here, but just in case */ - IFQ_DRV_PREPEND(&ifp->if_snd, m); - RUN_UNLOCK(sc); - DPRINTF("txq ring is full\n"); - return -1; - } + /* reserve slots for mgmt packets, just in case */ + if (sc->sc_epq[qid].tx_nfree < 3) { + DPRINTF("tx ring %d is full\n", qid); + return (-1); } - data = STAILQ_FIRST(&sc->tx_free); - STAILQ_REMOVE_HEAD(&sc->tx_free, next); - sc->tx_nfree--; - RUN_UNLOCK(sc); /* to be kept lockd, or not to be */ + + data = STAILQ_FIRST(&sc->sc_epq[qid].tx_fh); + STAILQ_REMOVE_HEAD(&sc->sc_epq[qid].tx_fh, next); + sc->sc_epq[qid].tx_nfree--; data->m = m; data->ni = ni; data->ridx = ridx; - data->qid = qid; -#if 1 - /* - * We could call run_set_tx_desc() instead, - * but context switching is expensive. - * (The file size is almost the same.) - */ - struct rt2870_txd *txd; - struct rt2860_txwi *txwi; - int xferlen; - uint8_t mcs; + run_set_tx_desc(sc, data, 0, xflags, 0, qflags, type, pad); - /* get MCS code from rate index */ - data->mcs = mcs = rt2860_rates[ridx].mcs; + STAILQ_INSERT_TAIL(&sc->sc_epq[qid].tx_qh, data, next); - xferlen = sizeof (*txwi) + m->m_pkthdr.len; - /* roundup to 32-bit alignment */ - xferlen = (xferlen + 3) & ~3; - - txd = (struct rt2870_txd *)&data->desc; - txd->flags = qflags; >>> TRUNCATED FOR MAIL (1000 lines) <<<
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201001101149.o0ABnEeu044011>