summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoravos <avos@FreeBSD.org>2015-11-09 23:46:13 +0000
committeravos <avos@FreeBSD.org>2015-11-09 23:46:13 +0000
commit820825160a2e550b12f084256f78512c36ef6819 (patch)
tree0c226f8c36f9f664c221bbd6f4e4b41d4e2f9911
parentff421684e76825a024077a1a68e8179de1469bb5 (diff)
downloadFreeBSD-src-820825160a2e550b12f084256f78512c36ef6819.zip
FreeBSD-src-820825160a2e550b12f084256f78512c36ef6819.tar.gz
urtwn(4): refactor and fix TX path.
- Split urtwn_tx_start() into urtwn_tx_data() and urtwn_tx_start() (the last will be used for beacon updates / raw xmit path). - Remove unneeded code from _urtwn_getbuf(). - Use CCK11 for data frames in 11b mode. - Send EAPOL frames at 1 Mbps. - Reduce code duplication in urtwn_tx_data(). - Fix sequence numbering. - Add IEEE80211_RADIOTAP_F_WEP flag for encrypted frames. - Check URTWN_RUNNING flag under lock. Tested with RTL8188EU, STA mode. Reviewed by: kevlo Approved by: adrian (mentor) Differential Revision: https://reviews.freebsd.org/D4017
-rw-r--r--sys/dev/usb/wlan/if_urtwn.c250
-rw-r--r--sys/dev/usb/wlan/if_urtwnreg.h4
2 files changed, 147 insertions, 107 deletions
diff --git a/sys/dev/usb/wlan/if_urtwn.c b/sys/dev/usb/wlan/if_urtwn.c
index 46890ac..675810a 100644
--- a/sys/dev/usb/wlan/if_urtwn.c
+++ b/sys/dev/usb/wlan/if_urtwn.c
@@ -230,9 +230,11 @@ static void urtwn_watchdog(void *);
static void urtwn_update_avgrssi(struct urtwn_softc *, int, int8_t);
static int8_t urtwn_get_rssi(struct urtwn_softc *, int, void *);
static int8_t urtwn_r88e_get_rssi(struct urtwn_softc *, int, void *);
-static int urtwn_tx_start(struct urtwn_softc *,
+static int urtwn_tx_data(struct urtwn_softc *,
struct ieee80211_node *, struct mbuf *,
struct urtwn_data *);
+static void urtwn_tx_start(struct urtwn_softc *, struct mbuf *,
+ uint8_t, struct urtwn_data *);
static int urtwn_transmit(struct ieee80211com *, struct mbuf *);
static void urtwn_start(struct urtwn_softc *);
static void urtwn_parent(struct ieee80211com *);
@@ -989,8 +991,6 @@ _urtwn_getbuf(struct urtwn_softc *sc)
if (bf != NULL)
STAILQ_REMOVE_HEAD(&sc->sc_tx_inactive, next);
else
- bf = NULL;
- if (bf == NULL)
DPRINTF("%s: %s\n", __func__, "out of xmit buffers");
return (bf);
}
@@ -1774,56 +1774,37 @@ urtwn_r88e_get_rssi(struct urtwn_softc *sc, int rate, void *physt)
}
static int
-urtwn_tx_start(struct urtwn_softc *sc, struct ieee80211_node *ni,
- struct mbuf *m0, struct urtwn_data *data)
+urtwn_tx_data(struct urtwn_softc *sc, struct ieee80211_node *ni,
+ struct mbuf *m, struct urtwn_data *data)
{
struct ieee80211_frame *wh;
- struct ieee80211_key *k;
+ struct ieee80211_key *k = NULL;
struct ieee80211com *ic = &sc->sc_ic;
struct ieee80211vap *vap = ni->ni_vap;
- struct usb_xfer *xfer;
struct r92c_tx_desc *txd;
- uint8_t raid, type;
- uint16_t sum;
- int i, xferlen;
- struct usb_xfer *urtwn_pipes[4] = {
- sc->sc_xfer[URTWN_BULK_TX_BE],
- sc->sc_xfer[URTWN_BULK_TX_BK],
- sc->sc_xfer[URTWN_BULK_TX_VI],
- sc->sc_xfer[URTWN_BULK_TX_VO]
- };
+ uint8_t macid, raid, ridx, subtype, type, qsel;
+ int ismcast;
URTWN_ASSERT_LOCKED(sc);
/*
* Software crypto.
*/
- wh = mtod(m0, struct ieee80211_frame *);
+ wh = mtod(m, struct ieee80211_frame *);
type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
+ subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
+ ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1);
if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
- k = ieee80211_crypto_encap(ni, m0);
+ k = ieee80211_crypto_encap(ni, m);
if (k == NULL) {
device_printf(sc->sc_dev,
"ieee80211_crypto_encap returns NULL.\n");
- /* XXX we don't expect the fragmented frames */
return (ENOBUFS);
}
/* in case packet header moved, reset pointer */
- wh = mtod(m0, struct ieee80211_frame *);
- }
-
- switch (type) {
- case IEEE80211_FC0_TYPE_CTL:
- case IEEE80211_FC0_TYPE_MGT:
- xfer = sc->sc_xfer[URTWN_BULK_TX_VO];
- break;
- default:
- KASSERT(M_WME_GETAC(m0) < 4,
- ("unsupported WME pipe %d", M_WME_GETAC(m0)));
- xfer = urtwn_pipes[M_WME_GETAC(m0)];
- break;
+ wh = mtod(m, struct ieee80211_frame *);
}
/* Fill Tx descriptor. */
@@ -1831,71 +1812,79 @@ urtwn_tx_start(struct urtwn_softc *sc, struct ieee80211_node *ni,
memset(txd, 0, sizeof(*txd));
txd->txdw0 |= htole32(
- SM(R92C_TXDW0_PKTLEN, m0->m_pkthdr.len) |
SM(R92C_TXDW0_OFFSET, sizeof(*txd)) |
R92C_TXDW0_OWN | R92C_TXDW0_FSG | R92C_TXDW0_LSG);
- if (IEEE80211_IS_MULTICAST(wh->i_addr1))
+ if (ismcast)
txd->txdw0 |= htole32(R92C_TXDW0_BMCAST);
- if (!IEEE80211_IS_MULTICAST(wh->i_addr1) &&
- type == IEEE80211_FC0_TYPE_DATA) {
- if (ic->ic_curmode == IEEE80211_MODE_11B)
- raid = R92C_RAID_11B;
- else
- raid = R92C_RAID_11BG;
- if (sc->chip & URTWN_CHIP_88E) {
- txd->txdw1 |= htole32(
- SM(R88E_TXDW1_MACID, URTWN_MACID_BSS) |
- SM(R92C_TXDW1_QSEL, R92C_TXDW1_QSEL_BE) |
- SM(R92C_TXDW1_RAID, raid));
- txd->txdw2 |= htole32(R88E_TXDW2_AGGBK);
- } else {
- txd->txdw1 |= htole32(
- SM(R92C_TXDW1_MACID, URTWN_MACID_BSS) |
- SM(R92C_TXDW1_QSEL, R92C_TXDW1_QSEL_BE) |
- SM(R92C_TXDW1_RAID, raid) | R92C_TXDW1_AGGBK);
- }
- if (ic->ic_flags & IEEE80211_F_USEPROT) {
- if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) {
- txd->txdw4 |= htole32(R92C_TXDW4_CTS2SELF |
- R92C_TXDW4_HWRTSEN);
- } else if (ic->ic_protmode == IEEE80211_PROT_RTSCTS) {
- txd->txdw4 |= htole32(R92C_TXDW4_RTSEN |
- R92C_TXDW4_HWRTSEN);
+
+ raid = R92C_RAID_11B; /* by default */
+ ridx = URTWN_RIDX_CCK1;
+ if (!ismcast) {
+ macid = URTWN_MACID_BSS;
+
+ if (type == IEEE80211_FC0_TYPE_DATA) {
+ qsel = R92C_TXDW1_QSEL_BE;
+
+ if (!(m->m_flags & M_EAPOL)) {
+ if (ic->ic_curmode != IEEE80211_MODE_11B) {
+ raid = R92C_RAID_11BG;
+ ridx = URTWN_RIDX_OFDM54;
+ } else
+ ridx = URTWN_RIDX_CCK11;
}
- }
- /* Send RTS at OFDM24. */
- txd->txdw4 |= htole32(SM(R92C_TXDW4_RTSRATE,
- URTWN_RIDX_OFDM24));
- txd->txdw5 |= htole32(0x0001ff00);
- /* Send data at OFDM54. */
- txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE,
- URTWN_RIDX_OFDM54));
+
+ if (sc->chip & URTWN_CHIP_88E)
+ txd->txdw2 |= htole32(R88E_TXDW2_AGGBK);
+ else
+ txd->txdw1 |= htole32(R92C_TXDW1_AGGBK);
+
+ if (ic->ic_flags & IEEE80211_F_USEPROT) {
+ switch (ic->ic_protmode) {
+ case IEEE80211_PROT_CTSONLY:
+ txd->txdw4 |= htole32(
+ R92C_TXDW4_CTS2SELF |
+ R92C_TXDW4_HWRTSEN);
+ break;
+ case IEEE80211_PROT_RTSCTS:
+ txd->txdw4 |= htole32(
+ R92C_TXDW4_RTSEN |
+ R92C_TXDW4_HWRTSEN);
+ break;
+ default:
+ break;
+ }
+ }
+ txd->txdw4 |= htole32(SM(R92C_TXDW4_RTSRATE,
+ URTWN_RIDX_OFDM24));
+ txd->txdw5 |= htole32(0x0001ff00);
+ } else /* IEEE80211_FC0_TYPE_MGT */
+ qsel = R92C_TXDW1_QSEL_MGNT;
} else {
- txd->txdw1 |= htole32(
- SM(R92C_TXDW1_MACID, 0) |
- SM(R92C_TXDW1_QSEL, R92C_TXDW1_QSEL_MGNT) |
- SM(R92C_TXDW1_RAID, R92C_RAID_11B));
+ macid = URTWN_MACID_BC;
+ qsel = R92C_TXDW1_QSEL_MGNT;
+ }
+
+ txd->txdw1 |= htole32(
+ SM(R92C_TXDW1_QSEL, qsel) |
+ SM(R92C_TXDW1_RAID, raid));
- /* Force CCK1. */
+ if (sc->chip & URTWN_CHIP_88E)
+ txd->txdw1 |= htole32(SM(R88E_TXDW1_MACID, macid));
+ else
+ txd->txdw1 |= htole32(SM(R92C_TXDW1_MACID, macid));
+
+ txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE, ridx));
+ /* not sure here */
+ if (ridx <= URTWN_RIDX_CCK11)
txd->txdw4 |= htole32(R92C_TXDW4_DRVRATE);
- txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE,
- URTWN_RIDX_CCK1));
- }
- /* Set sequence number (already little endian). */
- txd->txdseq |= *(uint16_t *)wh->i_seq;
if (!IEEE80211_QOS_HAS_SEQ(wh)) {
/* Use HW sequence numbering for non-QoS frames. */
- txd->txdw4 |= htole32(R92C_TXDW4_HWSEQ);
- txd->txdseq |= htole16(0x8000);
- } else
- txd->txdw4 |= htole32(R92C_TXDW4_QOS);
-
- /* Compute Tx descriptor checksum. */
- sum = 0;
- for (i = 0; i < sizeof(*txd) / 2; i++)
- sum ^= ((uint16_t *)txd)[i];
- txd->txdsum = sum; /* NB: already little endian. */
+ txd->txdseq = htole16(R92C_TXDSEQ_HWSEQ_EN);
+ } else {
+ /* Set sequence number. */
+ txd->txdseq = htole16(M_SEQNO_GET(m) % IEEE80211_SEQ_RANGE);
+ }
if (ieee80211_radiotap_active_vap(vap)) {
struct urtwn_tx_radiotap_header *tap = &sc->sc_txtap;
@@ -1903,19 +1892,64 @@ urtwn_tx_start(struct urtwn_softc *sc, struct ieee80211_node *ni,
tap->wt_flags = 0;
tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq);
tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags);
- ieee80211_radiotap_tx(vap, m0);
+ if (k != NULL)
+ tap->wt_flags |= IEEE80211_RADIOTAP_F_WEP;
+ ieee80211_radiotap_tx(vap, m);
}
- xferlen = sizeof(*txd) + m0->m_pkthdr.len;
- m_copydata(m0, 0, m0->m_pkthdr.len, (caddr_t)&txd[1]);
+ data->ni = ni;
+
+ urtwn_tx_start(sc, m, type, data);
+
+ return (0);
+}
+
+static void
+urtwn_tx_start(struct urtwn_softc *sc, struct mbuf *m, uint8_t type,
+ struct urtwn_data *data)
+{
+ struct usb_xfer *xfer;
+ struct r92c_tx_desc *txd;
+ uint16_t ac, sum;
+ int i, xferlen;
+ struct usb_xfer *urtwn_pipes[WME_NUM_AC] = {
+ sc->sc_xfer[URTWN_BULK_TX_BE],
+ sc->sc_xfer[URTWN_BULK_TX_BK],
+ sc->sc_xfer[URTWN_BULK_TX_VI],
+ sc->sc_xfer[URTWN_BULK_TX_VO]
+ };
+
+ URTWN_ASSERT_LOCKED(sc);
+
+ ac = M_WME_GETAC(m);
+
+ switch (type) {
+ case IEEE80211_FC0_TYPE_CTL:
+ case IEEE80211_FC0_TYPE_MGT:
+ xfer = sc->sc_xfer[URTWN_BULK_TX_VO];
+ break;
+ default:
+ xfer = urtwn_pipes[ac];
+ break;
+ }
+
+ txd = (struct r92c_tx_desc *)data->buf;
+ txd->txdw0 |= htole32(SM(R92C_TXDW0_PKTLEN, m->m_pkthdr.len));
+
+ /* Compute Tx descriptor checksum. */
+ sum = 0;
+ for (i = 0; i < sizeof(*txd) / 2; i++)
+ sum ^= ((uint16_t *)txd)[i];
+ txd->txdsum = sum; /* NB: already little endian. */
+
+ xferlen = sizeof(*txd) + m->m_pkthdr.len;
+ m_copydata(m, 0, m->m_pkthdr.len, (caddr_t)&txd[1]);
data->buflen = xferlen;
- data->ni = ni;
- data->m = m0;
+ data->m = m;
STAILQ_INSERT_TAIL(&sc->sc_tx_pending, data, next);
usbd_transfer_start(xfer);
- return (0);
}
static int
@@ -1956,7 +1990,7 @@ urtwn_start(struct urtwn_softc *sc)
}
ni = (struct ieee80211_node *)m->m_pkthdr.rcvif;
m->m_pkthdr.rcvif = NULL;
- if (urtwn_tx_start(sc, ni, m, bf) != 0) {
+ if (urtwn_tx_data(sc, ni, m, bf) != 0) {
if_inc_counter(ni->ni_vap->iv_ifp,
IFCOUNTER_OERRORS, 1);
STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, bf, next);
@@ -3526,30 +3560,36 @@ urtwn_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
struct ieee80211com *ic = ni->ni_ic;
struct urtwn_softc *sc = ic->ic_softc;
struct urtwn_data *bf;
+ int error;
/* prevent management frames from being sent if we're not ready */
+ URTWN_LOCK(sc);
if (!(sc->sc_flags & URTWN_RUNNING)) {
- m_freem(m);
- return (ENETDOWN);
+ error = ENETDOWN;
+ goto end;
}
- URTWN_LOCK(sc);
+
bf = urtwn_getbuf(sc);
if (bf == NULL) {
- m_freem(m);
- URTWN_UNLOCK(sc);
- return (ENOBUFS);
+ error = ENOBUFS;
+ goto end;
}
- if (urtwn_tx_start(sc, ni, m, bf) != 0) {
- m_freem(m);
+ if ((error = urtwn_tx_data(sc, ni, m, bf)) != 0) {
STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, bf, next);
- URTWN_UNLOCK(sc);
- return (EIO);
+ goto end;
}
+
sc->sc_txtimer = 5;
+ callout_reset(&sc->sc_watchdog_ch, hz, urtwn_watchdog, sc);
+
+end:
+ if (error != 0)
+ m_freem(m);
+
URTWN_UNLOCK(sc);
- return (0);
+ return (error);
}
static void
diff --git a/sys/dev/usb/wlan/if_urtwnreg.h b/sys/dev/usb/wlan/if_urtwnreg.h
index 8c9fb7a..f48f959 100644
--- a/sys/dev/usb/wlan/if_urtwnreg.h
+++ b/sys/dev/usb/wlan/if_urtwnreg.h
@@ -1037,12 +1037,12 @@ struct r92c_tx_desc {
uint16_t txdw3;
uint16_t txdseq;
+#define R92C_TXDSEQ_HWSEQ_EN 0x8000
uint32_t txdw4;
#define R92C_TXDW4_RTSRATE_M 0x0000003f
#define R92C_TXDW4_RTSRATE_S 0
-#define R92C_TXDW4_QOS 0x00000040
-#define R92C_TXDW4_HWSEQ 0x00000080
+#define R92C_TXDW4_HWSEQ_QOS 0x00000040
#define R92C_TXDW4_DRVRATE 0x00000100
#define R92C_TXDW4_CTS2SELF 0x00000800
#define R92C_TXDW4_RTSEN 0x00001000
OpenPOWER on IntegriCloud