PERFORCE change 172914 for review
Hans Petter Selasky
hselasky at FreeBSD.org
Sun Jan 10 11:49:15 UTC 2010
http://p4web.freebsd.org/chv.cgi?CH=172914
Change 172914 by hselasky at 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) <<<
More information about the p4-projects
mailing list