summaryrefslogtreecommitdiff
path: root/sys/dev/ic/rtw.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/ic/rtw.c')
-rw-r--r--sys/dev/ic/rtw.c660
1 files changed, 447 insertions, 213 deletions
diff --git a/sys/dev/ic/rtw.c b/sys/dev/ic/rtw.c
index 6ff6745afa2..555ad4730db 100644
--- a/sys/dev/ic/rtw.c
+++ b/sys/dev/ic/rtw.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rtw.c,v 1.15 2005/02/08 11:08:56 jsg Exp $ */
+/* $OpenBSD: rtw.c,v 1.16 2005/02/14 12:49:29 jsg Exp $ */
/* $NetBSD: rtw.c,v 1.29 2004/12/27 19:49:16 dyoung Exp $ */
/*-
* Copyright (c) 2004, 2005 David Young. All rights reserved.
@@ -84,11 +84,10 @@
int rtw_rfprog_fallback = 0;
int rtw_host_rfio = 0;
-int rtw_flush_rfio = 1;
-int rtw_rfio_delay = 0;
#ifdef RTW_DEBUG
int rtw_debug = 0;
+int rtw_rxbufs_limit = RTW_RXQLEN;
#endif /* RTW_DEBUG */
#define NEXT_ATTACH_STATE(sc, state) do { \
@@ -104,13 +103,10 @@ void rtw_srom_defaults(struct rtw_srom *, u_int32_t *, u_int8_t *,
enum rtw_rfchipid *, u_int32_t *);
void rtw_txdesc_blk_init_all(struct rtw_txdesc_blk *);
void rtw_txsoft_blk_init_all(struct rtw_txsoft_blk *);
-void rtw_txdescs_sync(bus_dma_tag_t, bus_dmamap_t , struct rtw_txdesc_blk *,
- u_int, u_int, int);
-void rtw_txdescs_sync_all(bus_dma_tag_t, bus_dmamap_t,
- struct rtw_txdesc_blk *);
+void rtw_txdescs_sync(struct rtw_txdesc_blk *, u_int, u_int, int);
+void rtw_txdescs_sync_all(struct rtw_txdesc_blk *);
void rtw_rxbufs_release(bus_dma_tag_t, struct rtw_rxsoft *);
-void rtw_rxdesc_init_all(bus_dma_tag_t, bus_dmamap_t,
- struct rtw_rxdesc *, struct rtw_rxsoft *, int);
+void rtw_rxdesc_init(struct rtw_rxdesc_blk *, struct rtw_rxsoft *, int, int);
void rtw_io_enable(struct rtw_regs *, u_int8_t, int);
void rtw_intr_rx(struct rtw_softc *, u_int16_t);
void rtw_intr_beacon(struct rtw_softc *, u_int16_t);
@@ -137,8 +133,6 @@ void rtw_stop(struct ifnet *, int);
void rtw_maxim_pwrstate(struct rtw_regs *, enum rtw_pwrstate, int, int);
void rtw_philips_pwrstate(struct rtw_regs *, enum rtw_pwrstate, int, int);
void rtw_pwrstate0(struct rtw_softc *, enum rtw_pwrstate, int, int);
-void rtw_recv_beacon(struct rtw_softc *, struct mbuf *,
- struct ieee80211_node *, int, int, u_int32_t);
void rtw_join_bss(struct rtw_softc *, uint8_t *, enum ieee80211_opmode,
uint16_t);
void rtw_set_access1(struct rtw_regs *, enum rtw_access);
@@ -151,14 +145,14 @@ void rtw_set_rfprog(struct rtw_regs *, enum rtw_rfchipid,
u_int8_t rtw_chan2txpower(struct rtw_srom *, struct ieee80211com *,
struct ieee80211_channel *);
int rtw_txsoft_blk_init(struct rtw_txsoft_blk *);
-int rtw_rxsoft_init_all(bus_dma_tag_t, struct rtw_rxsoft *, u_int *,
- const char *);
+int rtw_rxsoft_init_all(bus_dma_tag_t, struct rtw_rxsoft *,
+ int *, const char *);
void rtw_txsoft_release(bus_dma_tag_t, struct ieee80211com *,
struct rtw_txsoft *);
-void rtw_txsofts_release(bus_dma_tag_t, bus_dmamap_t,
- struct ieee80211com *, struct rtw_txsoft_blk *);
+void rtw_txsofts_release(bus_dma_tag_t, struct ieee80211com *,
+ struct rtw_txsoft_blk *);
void rtw_hwring_setup(struct rtw_softc *);
-void rtw_swring_setup(struct rtw_softc *);
+int rtw_swring_setup(struct rtw_softc *);
void rtw_txdesc_blk_reset(struct rtw_txdesc_blk *);
void rtw_txdescs_reset(struct rtw_softc *);
void rtw_rxdescs_reset(struct rtw_softc *);
@@ -169,7 +163,7 @@ void rtw_set_nettype(struct rtw_softc *, enum ieee80211_opmode);
int rtw_init(struct ifnet *);
int rtw_ioctl(struct ifnet *, u_long, caddr_t);
int rtw_seg_too_short(bus_dmamap_t);
-struct mbuf * rtw_dmamap_load_txsoft(bus_dma_tag_t, bus_dmamap_t, struct mbuf *,
+struct mbuf *rtw_dmamap_load_txbuf(bus_dma_tag_t, bus_dmamap_t, struct mbuf *,
u_int, short *, const char *);
int rtw_newstate(struct ieee80211com *, enum ieee80211_state, int);
int rtw_media_change(struct ifnet *);
@@ -182,7 +176,6 @@ int rtw_recall_eeprom(struct rtw_regs *, const char *);
int rtw_reset(struct rtw_softc *);
int rtw_txdesc_dmamaps_create(bus_dma_tag_t, struct rtw_txsoft *, u_int);
int rtw_rxdesc_dmamaps_create(bus_dma_tag_t, struct rtw_rxsoft *, u_int);
-void rtw_rxsofts_setup(struct rtw_rxsoft *);
void rtw_rxdesc_dmamaps_destroy(bus_dma_tag_t, struct rtw_rxsoft *, u_int);
void rtw_txdesc_dmamaps_destroy(bus_dma_tag_t, struct rtw_txsoft *, u_int);
void rtw_srom_free(struct rtw_srom *);
@@ -190,10 +183,8 @@ void rtw_init_channels(enum rtw_locale, struct ieee80211_channel (*)[],
const char*);
void rtw_identify_country(struct rtw_regs *, enum rtw_locale *, const char *);
int rtw_identify_sta(struct rtw_regs *, u_int8_t (*)[], const char *);
-void rtw_rxdescs_sync(bus_dma_tag_t, bus_dmamap_t, u_int, u_int, int);
+void rtw_rxdescs_sync(struct rtw_rxdesc_blk *, int, int, int);
int rtw_rxsoft_alloc(bus_dma_tag_t, struct rtw_rxsoft *);
-void rtw_rxdesc_init(bus_dma_tag_t, bus_dmamap_t, struct rtw_rxdesc *,
- struct rtw_rxsoft *, int, int);
void rtw_collect_txpkt(struct rtw_softc *, struct rtw_txdesc_blk *,
struct rtw_txsoft *, int);
void rtw_collect_txring(struct rtw_softc *, struct rtw_txsoft_blk *,
@@ -211,6 +202,14 @@ void rtw_establish_hooks(struct rtw_hooks *, const char *, void *);
void rtw_disestablish_hooks(struct rtw_hooks *, const char *, void *);
void rtw_init_radiotap(struct rtw_softc *);
int rtw_txsoft_blk_setup(struct rtw_txsoft_blk *, u_int);
+void rtw_rxdesc_init_all(struct rtw_rxdesc_blk *, struct rtw_rxsoft *, int);
+int rtw_txring_choose(struct rtw_softc *, struct rtw_txsoft_blk **,
+ struct rtw_txdesc_blk **, int);
+struct mbuf *rtw_80211_dequeue(struct rtw_softc *, struct ifqueue *, int,
+ struct rtw_txsoft_blk **, struct rtw_txdesc_blk **,
+ struct ieee80211_node **, short *);
+void rtw_recv_beacon(struct rtw_softc *, struct mbuf *,
+ struct ieee80211_node *, int, int, uint32_t);
#ifdef RTW_DEBUG
@@ -602,14 +601,6 @@ rtw_rxdesc_dmamaps_create(bus_dma_tag_t dmat, struct rtw_rxsoft *descs,
}
void
-rtw_rxsofts_setup(struct rtw_rxsoft *descs)
-{
- int i;
- for (i = 0; i < RTW_RXQLEN; i++)
- descs[i].rs_mbuf = NULL;
-}
-
-void
rtw_rxdesc_dmamaps_destroy(bus_dma_tag_t dmat, struct rtw_rxsoft *descs,
u_int ndescs)
{
@@ -1016,36 +1007,34 @@ rtw_txsoft_blk_init_all(struct rtw_txsoft_blk *tsb)
}
void
-rtw_rxdescs_sync(bus_dma_tag_t dmat, bus_dmamap_t dmap, u_int desc0, u_int
- nsync, int ops)
+rtw_rxdescs_sync(struct rtw_rxdesc_blk *rdb, int desc0, int nsync, int ops)
{
- KASSERT(nsync <= RTW_RXQLEN);
+ KASSERT(nsync <= rdb->rdb_ndesc);
/* sync to end of ring */
- if (desc0 + nsync > RTW_RXQLEN) {
- bus_dmamap_sync(dmat, dmap,
+ if (desc0 + nsync > rdb->rdb_ndesc) {
+ bus_dmamap_sync(rdb->rdb_dmat, rdb->rdb_dmamap,
offsetof(struct rtw_descs, hd_rx[desc0]),
- sizeof(struct rtw_rxdesc) * (RTW_RXQLEN - desc0), ops);
- nsync -= (RTW_RXQLEN - desc0);
+ sizeof(struct rtw_rxdesc) * (rdb->rdb_ndesc - desc0), ops);
+ nsync -= (rdb->rdb_ndesc - desc0);
desc0 = 0;
}
- KASSERT(desc0 < RTW_RXQLEN);
- KASSERT(nsync <= RTW_RXQLEN);
- KASSERT(desc0 + nsync <= RTW_RXQLEN);
+ KASSERT(desc0 < rdb->rdb_ndesc);
+ KASSERT(nsync <= rdb->rdb_ndesc);
+ KASSERT(desc0 + nsync <= rdb->rdb_ndesc);
/* sync what remains */
- bus_dmamap_sync(dmat, dmap,
+ bus_dmamap_sync(rdb->rdb_dmat, rdb->rdb_dmamap,
offsetof(struct rtw_descs, hd_rx[desc0]),
sizeof(struct rtw_rxdesc) * nsync, ops);
}
void
-rtw_txdescs_sync(bus_dma_tag_t dmat, bus_dmamap_t dmap,
- struct rtw_txdesc_blk *tdb, u_int desc0, u_int nsync, int ops)
+rtw_txdescs_sync(struct rtw_txdesc_blk *tdb, u_int desc0, u_int nsync, int ops)
{
/* sync to end of ring */
if (desc0 + nsync > tdb->tdb_ndesc) {
- bus_dmamap_sync(dmat, dmap,
+ bus_dmamap_sync(tdb->tdb_dmat, tdb->tdb_dmamap,
tdb->tdb_ofs + sizeof(struct rtw_txdesc) * desc0,
sizeof(struct rtw_txdesc) * (tdb->tdb_ndesc - desc0),
ops);
@@ -1054,19 +1043,17 @@ rtw_txdescs_sync(bus_dma_tag_t dmat, bus_dmamap_t dmap,
}
/* sync what remains */
- bus_dmamap_sync(dmat, dmap,
+ bus_dmamap_sync(tdb->tdb_dmat, tdb->tdb_dmamap,
tdb->tdb_ofs + sizeof(struct rtw_txdesc) * desc0,
sizeof(struct rtw_txdesc) * nsync, ops);
}
void
-rtw_txdescs_sync_all(bus_dma_tag_t dmat, bus_dmamap_t dmap,
- struct rtw_txdesc_blk *tdb)
+rtw_txdescs_sync_all(struct rtw_txdesc_blk *tdb)
{
int pri;
for (pri = 0; pri < RTW_NTXPRI; pri++) {
- rtw_txdescs_sync(dmat, dmap,
- &tdb[pri], 0, tdb[pri].tdb_ndesc,
+ rtw_txdescs_sync(&tdb[pri], 0, tdb[pri].tdb_ndesc,
BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
}
}
@@ -1079,6 +1066,8 @@ rtw_rxbufs_release(bus_dma_tag_t dmat, struct rtw_rxsoft *desc)
for (i = 0; i < RTW_RXQLEN; i++) {
rs = &desc[i];
+ if (rs->rs_mbuf == NULL)
+ continue;
bus_dmamap_sync(dmat, rs->rs_dmamap, 0,
rs->rs_dmamap->dm_mapsize, BUS_DMASYNC_POSTREAD);
bus_dmamap_unload(dmat, rs->rs_dmamap);
@@ -1098,8 +1087,10 @@ rtw_rxsoft_alloc(bus_dma_tag_t dmat, struct rtw_rxsoft *rs)
return ENOBUFS;
MCLGET(m, M_DONTWAIT);
- if (m == NULL)
+ if ((m->m_flags & M_EXT) == 0) {
+ m_freem(m);
return ENOBUFS;
+ }
m->m_pkthdr.len = m->m_len = m->m_ext.ext_size;
@@ -1121,32 +1112,39 @@ rtw_rxsoft_alloc(bus_dma_tag_t dmat, struct rtw_rxsoft *rs)
int
rtw_rxsoft_init_all(bus_dma_tag_t dmat, struct rtw_rxsoft *desc,
- u_int *next, const char *dvname)
+ int *ndesc, const char *dvname)
{
- int i, rc;
+ int i, rc = 0;
struct rtw_rxsoft *rs;
for (i = 0; i < RTW_RXQLEN; i++) {
rs = &desc[i];
- if ((rc = rtw_rxsoft_alloc(dmat, rs)) == 0)
- continue;
- printf("%s: failed rtw_rxsoft_alloc after %d buffers, rc = %d\n",
- dvname, i, rc);
- if (i == 0) {
- rtw_rxbufs_release(dmat, desc);
- return rc;
+ /* we're in rtw_init, so there should be no mbufs allocated */
+ KASSERT(rs->rs_mbuf == NULL);
+#ifdef RTW_DEBUG
+ if (i == rtw_rxbufs_limit) {
+ printf("%s: TEST hit %d-buffer limit\n", dvname, i);
+ rc = ENOBUFS;
+ break;
+ }
+#endif /* RTW_DEBUG */
+ if ((rc = rtw_rxsoft_alloc(dmat, rs)) != 0) {
+ printf("%s: rtw_rxsoft_alloc failed, %d buffers, "
+ "rc %d\n", dvname, i, rc);
+ break;
}
}
- *next = 0;
- return 0;
+ *ndesc = i;
+ return rc;
}
void
-rtw_rxdesc_init(bus_dma_tag_t dmat, bus_dmamap_t dmam,
- struct rtw_rxdesc *rd, struct rtw_rxsoft *rs, int idx, int kick)
+rtw_rxdesc_init(struct rtw_rxdesc_blk *rdb, struct rtw_rxsoft *rs,
+ int idx, int kick)
{
- int is_last = (idx == RTW_RXQLEN - 1);
- u_int32_t ctl, octl, obuf;
+ int is_last = (idx == rdb->rdb_ndesc - 1);
+ uint32_t ctl, octl, obuf;
+ struct rtw_rxdesc *rd = &rdb->rdb_desc[idx];
obuf = rd->rd_buf;
rd->rd_buf = htole32(rs->rs_dmamap->dm_segs[0].ds_addr);
@@ -1168,28 +1166,29 @@ rtw_rxdesc_init(bus_dma_tag_t dmat, bus_dmamap_t dmam,
letoh32(rd->rd_ctl)));
/* sync the mbuf */
- bus_dmamap_sync(dmat, rs->rs_dmamap, 0, rs->rs_dmamap->dm_mapsize,
- BUS_DMASYNC_PREREAD);
+ bus_dmamap_sync(rdb->rdb_dmat, rs->rs_dmamap, 0,
+ rs->rs_dmamap->dm_mapsize, BUS_DMASYNC_PREREAD);
/* sync the descriptor */
- bus_dmamap_sync(dmat, dmam, RTW_DESC_OFFSET(hd_rx, idx),
- sizeof(struct rtw_rxdesc),
+ bus_dmamap_sync(rdb->rdb_dmat, rdb->rdb_dmamap,
+ RTW_DESC_OFFSET(hd_rx, idx), sizeof(struct rtw_rxdesc),
BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
}
void
-rtw_rxdesc_init_all(bus_dma_tag_t dmat, bus_dmamap_t dmam,
- struct rtw_rxdesc *desc, struct rtw_rxsoft *ctl, int kick)
+rtw_rxdesc_init_all(struct rtw_rxdesc_blk *rdb, struct rtw_rxsoft *ctl,
+ int kick)
{
int i;
struct rtw_rxdesc *rd;
struct rtw_rxsoft *rs;
- for (i = 0; i < RTW_RXQLEN; i++) {
- rd = &desc[i];
+ for (i = 0; i < rdb->rdb_ndesc; i++) {
+ rd = &rdb->rdb_desc[i];
rs = &ctl[i];
- rtw_rxdesc_init(dmat, dmam, rd, rs, i, kick);
+ rtw_rxdesc_init(rdb, rs, i, kick);
}
+ rdb->rdb_next = 0;
}
void
@@ -1220,27 +1219,33 @@ rtw_io_enable(struct rtw_regs *regs, u_int8_t flags, int enable)
void
rtw_intr_rx(struct rtw_softc *sc, u_int16_t isr)
{
+#define IS_BEACON(__fc0) \
+ ((__fc0 & (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) ==\
+ (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_BEACON))
+
static const int ratetbl[4] = {2, 4, 11, 22}; /* convert rates:
* hardware -> net80211
*/
-
u_int next, nproc = 0;
- int hwrate, len, rate, rssi;
+ int hwrate, len, rate, rssi, sq;
u_int32_t hrssi, hstat, htsfth, htsftl;
struct rtw_rxdesc *rd;
struct rtw_rxsoft *rs;
+ struct rtw_rxdesc_blk *rdb;
struct mbuf *m;
struct ieee80211com *ic = &sc->sc_ic;
struct ieee80211_node *ni;
struct ieee80211_frame *wh;
- KASSERT(sc->sc_rxnext < RTW_RXQLEN);
+ rdb = &sc->sc_rxdesc_blk;
+
+ KASSERT(rdb->rdb_next < rdb->rdb_ndesc);
- for (next = sc->sc_rxnext; ; next = (next + 1) % RTW_RXQLEN) {
- rtw_rxdescs_sync(sc->sc_dmat, sc->sc_desc_dmamap,
- next, 1, BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
- rd = &sc->sc_rxdesc[next];
+ for (next = rdb->rdb_next; ; next = (next + 1) % rdb->rdb_ndesc) {
+ rtw_rxdescs_sync(rdb, next, 1,
+ BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
+ rd = &rdb->rdb_desc[next];
rs = &sc->sc_rxsoft[next];
hstat = letoh32(rd->rd_stat);
@@ -1252,9 +1257,6 @@ rtw_intr_rx(struct rtw_softc *sc, u_int16_t isr)
("%s: rxdesc[%d] hstat %08x hrssi %08x htsft %08x%08x\n",
__func__, next, hstat, hrssi, htsfth, htsftl));
- KASSERT((hstat & (RTW_RXSTAT_FS|RTW_RXSTAT_LS)) ==
- (RTW_RXSTAT_FS|RTW_RXSTAT_LS));
-
++nproc;
/* still belongs to NIC */
@@ -1263,9 +1265,9 @@ rtw_intr_rx(struct rtw_softc *sc, u_int16_t isr)
break;
/* sometimes the NIC skips to the 0th descriptor */
- rtw_rxdescs_sync(sc->sc_dmat, sc->sc_desc_dmamap,
- 0, 1, BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
- rd = &sc->sc_rxdesc[0];
+ rtw_rxdescs_sync(rdb, 0, 1,
+ BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
+ rd = &rdb->rdb_desc[0];
if ((rd->rd_stat & htole32(RTW_RXSTAT_OWN)) != 0)
break;
RTW_DPRINTF(RTW_DEBUG_BUGS,
@@ -1366,6 +1368,12 @@ rtw_intr_rx(struct rtw_softc *sc, u_int16_t isr)
rssi |= 0x80;
}
+ sq = MASK_AND_RSHIFT(hrssi, RTW_RXRSSI_SQ);
+
+ /*
+ * Note well: now we cannot recycle the rs_mbuf unless
+ * we restore its original length.
+ */
m->m_pkthdr.rcvif = &sc->sc_if;
m->m_pkthdr.len = m->m_len = len;
m->m_flags |= M_HASFCS;
@@ -1390,14 +1398,14 @@ rtw_intr_rx(struct rtw_softc *sc, u_int16_t isr)
else
ieee80211_free_node(&sc->sc_ic, ni);
next:
- rtw_rxdesc_init(sc->sc_dmat, sc->sc_desc_dmamap,
- rd, rs, next, 0);
+ rtw_rxdesc_init(rdb, rs, next, 0);
}
- KASSERT(sc->sc_rxnext < RTW_RXQLEN);
+ rdb->rdb_next = next;
- sc->sc_rxnext = next;
+ KASSERT(rdb->rdb_next < rdb->rdb_ndesc);
return;
+#undef IS_BEACON
}
void
@@ -1425,8 +1433,8 @@ rtw_txsoft_release(bus_dma_tag_t dmat, struct ieee80211com *ic,
}
void
-rtw_txsofts_release(bus_dma_tag_t dmat, bus_dmamap_t desc_dmamap,
- struct ieee80211com *ic, struct rtw_txsoft_blk *tsb)
+rtw_txsofts_release(bus_dma_tag_t dmat, struct ieee80211com *ic,
+ struct rtw_txsoft_blk *tsb)
{
struct rtw_txsoft *ts;
@@ -1486,8 +1494,7 @@ rtw_collect_txring(struct rtw_softc *sc, struct rtw_txsoft_blk *tsb,
KASSERT(ndesc > 0);
- rtw_txdescs_sync(sc->sc_dmat, sc->sc_desc_dmamap, tdb,
- ts->ts_first, ndesc,
+ rtw_txdescs_sync(tdb, ts->ts_first, ndesc,
BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
if ((tdb->tdb_desc[ts->ts_last].td_stat &
@@ -1544,6 +1551,7 @@ rtw_dump_rings(struct rtw_softc *sc)
{
struct rtw_txdesc_blk *tdb;
struct rtw_rxdesc *rd;
+ struct rtw_rxdesc_blk *rdb;
int desc, pri;
if ((rtw_debug & RTW_DEBUG_IO_KICK) == 0)
@@ -1557,10 +1565,13 @@ rtw_dump_rings(struct rtw_softc *sc)
rtw_print_txdesc(sc, ".", NULL, tdb, desc);
}
+ rdb = &sc->sc_rxdesc_blk;
+
for (desc = 0; desc < RTW_RXQLEN; desc++) {
- rd = &sc->sc_rxdesc[desc];
- printf("%s: ctl %08x rsvd0/rssi %08x buf/tsftl %08x "
+ rd = &rdb->rdb_desc[desc];
+ printf("%s: %sctl %08x rsvd0/rssi %08x buf/tsftl %08x "
"rsvd1/tsfth %08x\n", __func__,
+ (desc >= rdb->rdb_ndesc) ? "UNUSED " : "",
letoh32(rd->rd_ctl), letoh32(rd->rd_rssi),
letoh32(rd->rd_buf), letoh32(rd->rd_tsfth));
}
@@ -1596,26 +1607,31 @@ rtw_hwring_setup(struct rtw_softc *sc)
#endif
}
-void
+int
rtw_swring_setup(struct rtw_softc *sc)
{
+ int rc;
+ struct rtw_rxdesc_blk *rdb;
+
rtw_txdesc_blk_init_all(&sc->sc_txdesc_blk[0]);
rtw_txsoft_blk_init_all(&sc->sc_txsoft_blk[0]);
- rtw_rxdescs_sync(sc->sc_dmat, sc->sc_desc_dmamap,
- 0, RTW_RXQLEN, BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
- rtw_rxsoft_init_all(sc->sc_dmat, sc->sc_rxsoft, &sc->sc_rxnext,
- sc->sc_dev.dv_xname);
- rtw_rxdesc_init_all(sc->sc_dmat, sc->sc_desc_dmamap,
- sc->sc_rxdesc, sc->sc_rxsoft, 1);
-
- rtw_txdescs_sync_all(sc->sc_dmat, sc->sc_desc_dmamap,
- &sc->sc_txdesc_blk[0]);
-#if 0 /* redundant with rtw_rxdesc_init_all */
- rtw_rxdescs_sync(sc->sc_dmat, sc->sc_desc_dmamap,
- 0, RTW_RXQLEN, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
-#endif
+ rdb = &sc->sc_rxdesc_blk;
+ if ((rc = rtw_rxsoft_init_all(sc->sc_dmat, sc->sc_rxsoft, &rdb->rdb_ndesc,
+ sc->sc_dev.dv_xname)) != 0 && rdb->rdb_ndesc == 0) {
+ printf("%s: could not allocate rx buffers\n",
+ sc->sc_dev.dv_xname);
+ return rc;
+ }
+
+ rdb = &sc->sc_rxdesc_blk;
+ rtw_rxdescs_sync(rdb, 0, rdb->rdb_ndesc,
+ BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
+ rtw_rxdesc_init_all(rdb, sc->sc_rxsoft, 1);
+
+ rtw_txdescs_sync_all(&sc->sc_txdesc_blk[0]);
+ return 0;
}
void
@@ -1624,7 +1640,7 @@ rtw_txdesc_blk_reset(struct rtw_txdesc_blk *tdb)
int i;
(void)memset(tdb->tdb_desc, 0,
- sizeof(tdb->tdb_desc[0]) *tdb->tdb_ndesc);
+ sizeof(tdb->tdb_desc[0]) * tdb->tdb_ndesc);
for (i = 0; i < tdb->tdb_ndesc; i++)
tdb->tdb_desc[i].td_next = htole32(RTW_NEXT_DESC(tdb, i));
tdb->tdb_nfree = tdb->tdb_ndesc;
@@ -1639,11 +1655,10 @@ rtw_txdescs_reset(struct rtw_softc *sc)
for (pri = 0; pri < RTW_NTXPRI; pri++) {
tdb = &sc->sc_txdesc_blk[pri];
- rtw_txsofts_release(sc->sc_dmat, sc->sc_desc_dmamap, &sc->sc_ic,
+ rtw_txsofts_release(sc->sc_dmat, &sc->sc_ic,
&sc->sc_txsoft_blk[pri]);
rtw_txdesc_blk_reset(tdb);
- rtw_txdescs_sync(sc->sc_dmat, sc->sc_desc_dmamap, tdb,
- 0, tdb->tdb_ndesc,
+ rtw_txdescs_sync(tdb, 0, tdb->tdb_ndesc,
BUS_DMASYNC_PREWRITE|BUS_DMASYNC_PREREAD);
}
}
@@ -1651,12 +1666,7 @@ rtw_txdescs_reset(struct rtw_softc *sc)
void
rtw_rxdescs_reset(struct rtw_softc *sc)
{
- /* Re-initialize descriptors, just in case. */
- rtw_rxdesc_init_all(sc->sc_dmat, sc->sc_desc_dmamap, sc->sc_rxdesc,
- &sc->sc_rxsoft[0], 1);
-
- /* Reset to start of ring. */
- sc->sc_rxnext = 0;
+ rtw_rxdesc_init_all(&sc->sc_rxdesc_blk, &sc->sc_rxsoft[0], 1);
}
void
@@ -1847,9 +1857,7 @@ rtw_stop(struct ifnet *ifp, int disable)
/* Stop the transmit and receive processes. First stop DMA,
* then disable receiver and transmitter.
*/
- RTW_WRITE8(regs, RTW_TPPOLL,
- RTW_TPPOLL_SBQ|RTW_TPPOLL_SHPQ|RTW_TPPOLL_SNPQ|
- RTW_TPPOLL_SLPQ);
+ RTW_WRITE8(regs, RTW_TPPOLL, RTW_TPPOLL_SALL);
RTW_SYNC(regs, RTW_TPPOLL, RTW_IMR);
@@ -1857,14 +1865,14 @@ rtw_stop(struct ifnet *ifp, int disable)
}
for (pri = 0; pri < RTW_NTXPRI; pri++) {
- rtw_txsofts_release(sc->sc_dmat, sc->sc_desc_dmamap, &sc->sc_ic,
+ rtw_txsofts_release(sc->sc_dmat, &sc->sc_ic,
&sc->sc_txsoft_blk[pri]);
}
- if (disable) {
+ rtw_rxbufs_release(sc->sc_dmat, &sc->sc_rxsoft[0]);
+
+ if (disable)
rtw_disable(sc);
- rtw_rxbufs_release(sc->sc_dmat, &sc->sc_rxsoft[0]);
- }
/* Mark the interface as not running. Cancel the watchdog timer. */
ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
@@ -2303,6 +2311,147 @@ allmulti:
return;
}
+#define IEEE80211_BEACON_TIMESTAMP_LEN 8
+#define IEEE80211_BEACON_BINTVL_LEN 2
+#define IEEE80211_BEACON_CAPINFO_LEN 2
+#define IEEE80211_TLV_SSID_LEN(__esslen) (2 + (__esslen))
+#define IEEE80211_TLV_SUPRATES_LEN(__nrates) (2 + (__nrates))
+#define IEEE80211_TLV_XSUPRATES_LEN(__nrates) (2 + (__nrates))
+#define IEEE80211_TLV_DSPARMS_LEN 3
+#define IEEE80211_TLV_IBSSPARMS 4
+#define IEEE80211_TLV_MIN_TIM 6
+
+#define IEEE80211_TLV_ALLRATES_LEN(__nrates) \
+ (((__nrates) > IEEE80211_RATE_SIZE) ? 4 + (__nrates) : 2 + (__nrates))
+
+/* TBD factor with ieee80211_getmbuf */
+static struct mbuf *
+rtw_getmbuf(int flags, int type, u_int pktlen)
+{
+ struct mbuf *m;
+
+ KASSERT2(pktlen <= MCLBYTES, ("802.11 packet too large: %u", pktlen));
+ MGETHDR(m, flags, type);
+ if (m == NULL || pktlen <= MHLEN)
+ return m;
+ MCLGET(m, flags);
+ if ((m->m_flags & M_EXT) != 0)
+ return m;
+ m_free(m);
+ return NULL;
+}
+
+/* TBD factor with ath_beacon_alloc */
+static struct mbuf *
+rtw_beacon_alloc(struct rtw_softc *sc, struct ieee80211_node *ni)
+{
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ieee80211_frame *wh;
+ struct mbuf *m;
+ int pktlen;
+ uint8_t *frm;
+ uint16_t capinfo;
+ struct ieee80211_rateset *rs;
+
+ /*
+ * NB: the beacon data buffer must be 32-bit aligned;
+ * we assume the mbuf routines will return us something
+ * with this alignment (perhaps should assert).
+ */
+ rs = &ni->ni_rates;
+ pktlen = sizeof(struct ieee80211_frame)
+ + IEEE80211_BEACON_TIMESTAMP_LEN
+ + IEEE80211_BEACON_BINTVL_LEN
+ + IEEE80211_BEACON_CAPINFO_LEN
+ + IEEE80211_TLV_SSID_LEN(ni->ni_esslen)
+ + IEEE80211_TLV_ALLRATES_LEN(rs->rs_nrates)
+ + IEEE80211_TLV_DSPARMS_LEN
+ + MAX(IEEE80211_TLV_IBSSPARMS, IEEE80211_TLV_MIN_TIM);
+
+ m = rtw_getmbuf(M_DONTWAIT, MT_DATA, pktlen);
+ if (m == NULL) {
+ RTW_DPRINTF(RTW_DEBUG_BEACON,
+ ("%s: cannot get mbuf/cluster; size %u\n",
+ __func__, pktlen));
+#if 0
+ sc->sc_stats.ast_be_nombuf++;
+#endif
+ return NULL;
+ }
+
+ wh = mtod(m, struct ieee80211_frame *);
+ wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT |
+ IEEE80211_FC0_SUBTYPE_BEACON;
+ wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
+ *(u_int16_t *)wh->i_dur = 0;
+ memcpy(wh->i_addr1, etherbroadcastaddr, IEEE80211_ADDR_LEN);
+ memcpy(wh->i_addr2, ic->ic_myaddr, IEEE80211_ADDR_LEN);
+ memcpy(wh->i_addr3, ni->ni_bssid, IEEE80211_ADDR_LEN);
+ *(u_int16_t *)wh->i_seq = 0;
+
+ /*
+ * beacon frame format
+ * [8] time stamp
+ * [2] beacon interval
+ * [2] cabability information
+ * [tlv] ssid
+ * [tlv] supported rates
+ * [tlv] parameter set (IBSS)
+ * [tlv] extended supported rates
+ */
+ frm = (u_int8_t *)&wh[1];
+ /* timestamp is set by hardware */
+ memset(frm, 0, IEEE80211_BEACON_TIMESTAMP_LEN);
+ frm += IEEE80211_BEACON_TIMESTAMP_LEN;
+ *(u_int16_t *)frm = htole16(ni->ni_intval);
+ frm += IEEE80211_BEACON_BINTVL_LEN;
+ if (ic->ic_opmode == IEEE80211_M_IBSS)
+ capinfo = IEEE80211_CAPINFO_IBSS;
+ else
+ capinfo = IEEE80211_CAPINFO_ESS;
+ if (ic->ic_flags & IEEE80211_F_WEPON)
+ capinfo |= IEEE80211_CAPINFO_PRIVACY;
+ if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) &&
+ IEEE80211_IS_CHAN_2GHZ(ni->ni_chan))
+ capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE;
+ if (ic->ic_flags & IEEE80211_F_SHSLOT)
+ capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME;
+ *(u_int16_t *)frm = htole16(capinfo);
+ frm += IEEE80211_BEACON_CAPINFO_LEN;
+ *frm++ = IEEE80211_ELEMID_SSID;
+ *frm++ = ni->ni_esslen;
+ memcpy(frm, ni->ni_essid, ni->ni_esslen);
+ frm += ni->ni_esslen;
+ frm = ieee80211_add_rates(frm, rs);
+ *frm++ = IEEE80211_ELEMID_DSPARMS;
+ *frm++ = 1;
+ *frm++ = ieee80211_chan2ieee(ic, ni->ni_chan);
+ if (ic->ic_opmode == IEEE80211_M_IBSS) {
+ *frm++ = IEEE80211_ELEMID_IBSSPARMS;
+ *frm++ = 2;
+ *frm++ = 0; *frm++ = 0; /* TODO: ATIM window */
+ } else {
+ /* TODO: TIM */
+ *frm++ = IEEE80211_ELEMID_TIM;
+ *frm++ = 4; /* length */
+ *frm++ = 0; /* DTIM count */
+ *frm++ = 1; /* DTIM period */
+ *frm++ = 0; /* bitmap control */
+ *frm++ = 0; /* Partial Virtual Bitmap (variable length) */
+ }
+ frm = ieee80211_add_xrates(frm, rs);
+ m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *);
+ m->m_pkthdr.rcvif = (void *)ni;
+ KASSERT2(m->m_pkthdr.len <= pktlen,
+ ("beacon bigger than expected, len %u calculated %u",
+ m->m_pkthdr.len, pktlen));
+
+ RTW_DPRINTF(RTW_DEBUG_BEACON,
+ ("%s: m %p len %u\n", __func__, m, m->m_len));
+
+ return m;
+}
+
/* Must be called at splnet. */
int
rtw_init(struct ifnet *ifp)
@@ -2326,13 +2475,14 @@ rtw_init(struct ifnet *ifp)
if ((rc = rtw_pwrstate(sc, RTW_OFF)) != 0)
goto out;
- rtw_swring_setup(sc);
+ if ((rc = rtw_swring_setup(sc)) != 0)
+ goto out;
rtw_transmit_config(regs);
rtw_set_access(regs, RTW_ACCESS_CONFIG);
- RTW_WRITE8(regs, RTW_MSR, 0x0); /* no link */
+ RTW_WRITE8(regs, RTW_MSR, 0x0); /* no link */
RTW_WBW(regs, RTW_MSR, RTW_BRSR);
/* long PLCP header, 1Mb/2Mb basic rate */
@@ -2378,6 +2528,7 @@ rtw_init(struct ifnet *ifp)
return ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
out:
+ printf("%s: interface not running\n", sc->sc_dev.dv_xname);
return rc;
}
@@ -2430,11 +2581,11 @@ rtw_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
rc = ether_addmulti(ifr, &sc->sc_ic.ic_ac);
else
rc = ether_delmulti(ifr, &sc->sc_ic.ic_ac);
- if (rc == ENETRESET) {
- if (sc->sc_flags & IFF_RUNNING)
- rtw_pktfilt_load(sc);
- rc = 0;
- }
+ if (rc != ENETRESET)
+ break;
+ if (ifp->if_flags & IFF_RUNNING)
+ rtw_pktfilt_load(sc);
+ rc = 0;
break;
default:
if ((rc = ieee80211_ioctl(ifp, cmd, data)) == ENETRESET) {
@@ -2449,6 +2600,50 @@ rtw_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
return rc;
}
+/* Select a transmit ring with at least one h/w and s/w descriptor free.
+ * Return 0 on success, -1 on failure.
+ */
+int
+rtw_txring_choose(struct rtw_softc *sc, struct rtw_txsoft_blk **tsbp,
+ struct rtw_txdesc_blk **tdbp, int pri)
+{
+ struct rtw_txsoft_blk *tsb;
+ struct rtw_txdesc_blk *tdb;
+
+ KASSERT(pri >= 0 && pri < RTW_NTXPRI);
+
+ tsb = &sc->sc_txsoft_blk[pri];
+ tdb = &sc->sc_txdesc_blk[pri];
+
+ if (SIMPLEQ_EMPTY(&tsb->tsb_freeq) || tdb->tdb_nfree == 0) {
+ *tsbp = NULL;
+ *tdbp = NULL;
+ return -1;
+ }
+ *tsbp = tsb;
+ *tdbp = tdb;
+ return 0;
+}
+
+struct mbuf *
+rtw_80211_dequeue(struct rtw_softc *sc, struct ifqueue *ifq, int pri,
+ struct rtw_txsoft_blk **tsbp, struct rtw_txdesc_blk **tdbp,
+ struct ieee80211_node **nip, short *if_flagsp)
+{
+ struct mbuf *m;
+
+ if (IF_IS_EMPTY(ifq))
+ return NULL;
+ if (rtw_txring_choose(sc, tsbp, tdbp, pri) == -1) {
+ *if_flagsp |= IFF_OACTIVE;
+ return NULL;
+ }
+ IF_DEQUEUE(ifq, m);
+ *nip = (struct ieee80211_node *)m->m_pkthdr.rcvif;
+ m->m_pkthdr.rcvif = NULL;
+ return m;
+}
+
/* Point *mp at the next 802.11 frame to transmit. Point *tsbp
* at the driver's selection of transmit control block for the packet.
*/
@@ -2457,69 +2652,71 @@ rtw_dequeue(struct ifnet *ifp, struct rtw_txsoft_blk **tsbp,
struct rtw_txdesc_blk **tdbp, struct mbuf **mp,
struct ieee80211_node **nip)
{
- struct rtw_txsoft_blk *tsb;
- struct rtw_txdesc_blk *tdb;
struct mbuf *m0;
struct rtw_softc *sc;
- struct ieee80211com *ic;
+ short *if_flagsp;
sc = (struct rtw_softc *)ifp->if_softc;
DPRINTF(sc, RTW_DEBUG_XMIT,
("%s: enter %s\n", sc->sc_dev.dv_xname, __func__));
- *mp = NULL;
- tsb = &sc->sc_txsoft_blk[RTW_TXPRIMD];
- tdb = &sc->sc_txdesc_blk[RTW_TXPRIMD];
+ if_flagsp = &ifp->if_flags;
- if (SIMPLEQ_EMPTY(&tsb->tsb_freeq) || tdb->tdb_nfree == 0) {
- DPRINTF(sc, RTW_DEBUG_XMIT,
- ("%s: out of descriptors\n", __func__));
- ifp->if_flags |= IFF_OACTIVE;
+ if (sc->sc_ic.ic_state == IEEE80211_S_RUN &&
+ (*mp = rtw_80211_dequeue(sc, &sc->sc_beaconq, RTW_TXPRIBCN, tsbp,
+ tdbp, nip, if_flagsp)) != NULL) {
+ DPRINTF(sc, RTW_DEBUG_XMIT, ("%s: dequeue beacon frame\n",
+ __func__));
return 0;
}
- ic = &sc->sc_ic;
+ if ((*mp = rtw_80211_dequeue(sc, &sc->sc_ic.ic_mgtq, RTW_TXPRIMD, tsbp,
+ tdbp, nip, if_flagsp)) != NULL) {
+ DPRINTF(sc, RTW_DEBUG_XMIT, ("%s: dequeue mgt frame\n",
+ __func__));
+ return 0;
+ }
- if (!IF_IS_EMPTY(&ic->ic_mgtq)) {
- IF_DEQUEUE(&ic->ic_mgtq, m0);
- *nip = (struct ieee80211_node *)m0->m_pkthdr.rcvif;
- m0->m_pkthdr.rcvif = NULL;
- DPRINTF(sc, RTW_DEBUG_XMIT,
- ("%s: dequeue mgt frame\n", __func__));
- } else if (ic->ic_state != IEEE80211_S_RUN) {
+ if (sc->sc_ic.ic_state != IEEE80211_S_RUN) {
DPRINTF(sc, RTW_DEBUG_XMIT, ("%s: not running\n", __func__));
return 0;
- } else if (!IF_IS_EMPTY(&ic->ic_pwrsaveq)) {
- IF_DEQUEUE(&ic->ic_pwrsaveq, m0);
- *nip = (struct ieee80211_node *)m0->m_pkthdr.rcvif;
- m0->m_pkthdr.rcvif = NULL;
- DPRINTF(sc, RTW_DEBUG_XMIT,
- ("%s: dequeue pwrsave frame\n", __func__));
- } else {
- IFQ_DEQUEUE(&ifp->if_snd, m0);
- if (m0 == NULL) {
- DPRINTF(sc, RTW_DEBUG_XMIT,
- ("%s: no frame\n", __func__));
- return 0;
- }
- DPRINTF(sc, RTW_DEBUG_XMIT,
- ("%s: dequeue data frame\n", __func__));
- ifp->if_opackets++;
+ }
+
+ if ((*mp = rtw_80211_dequeue(sc, &sc->sc_ic.ic_pwrsaveq, RTW_TXPRIHI,
+ tsbp, tdbp, nip, if_flagsp)) != NULL) {
+ DPRINTF(sc, RTW_DEBUG_XMIT, ("%s: dequeue pwrsave frame\n",
+ __func__));
+ return 0;
+ }
+
+ if (rtw_txring_choose(sc, tsbp, tdbp, RTW_TXPRIMD) == -1) {
+ DPRINTF(sc, RTW_DEBUG_XMIT, ("%s: no descriptor\n", __func__));
+ *if_flagsp |= IFF_OACTIVE;
+ return 0;
+ }
+
+ *mp = NULL;
+
+ IFQ_DEQUEUE(&ifp->if_snd, m0);
+ if (m0 == NULL) {
+ DPRINTF(sc, RTW_DEBUG_XMIT, ("%s: no frame/ring ready\n",
+ __func__));
+ return 0;
+ }
+ DPRINTF(sc, RTW_DEBUG_XMIT, ("%s: dequeue data frame\n", __func__));
+ ifp->if_opackets++;
#if NBPFILTER > 0
- if (ifp->if_bpf)
- bpf_mtap(ifp->if_bpf, m0);
+ if (ifp->if_bpf)
+ bpf_mtap(ifp->if_bpf, m0);
#endif
- if ((m0 = ieee80211_encap(ifp, m0, nip)) == NULL) {
- DPRINTF(sc, RTW_DEBUG_XMIT,
- ("%s: encap error\n", __func__));
- ifp->if_oerrors++;
- return -1;
- }
+ if ((m0 = ieee80211_encap(ifp, m0, nip)) == NULL) {
+ DPRINTF(sc, RTW_DEBUG_XMIT,
+ ("%s: encap error\n", __func__));
+ ifp->if_oerrors++;
+ return -1;
}
DPRINTF(sc, RTW_DEBUG_XMIT, ("%s: leave\n", __func__));
- *tsbp = tsb;
- *tdbp = tdb;
*mp = m0;
return 0;
}
@@ -2539,8 +2736,8 @@ rtw_seg_too_short(bus_dmamap_t dmamap)
/* TBD factor with atw_start */
struct mbuf *
-rtw_dmamap_load_txsoft(bus_dma_tag_t dmat, bus_dmamap_t dmam,
- struct mbuf *chain, u_int ndescfree, short *ifflagsp, const char *dvname)
+rtw_dmamap_load_txbuf(bus_dma_tag_t dmat, bus_dmamap_t dmam, struct mbuf *chain,
+ u_int ndescfree, short *ifflagsp, const char *dvname)
{
int first, rc;
struct mbuf *m, *m0;
@@ -2637,23 +2834,13 @@ rtw_start(struct ifnet *ifp)
DPRINTF(sc, RTW_DEBUG_XMIT,
("%s: enter %s\n", sc->sc_dev.dv_xname, __func__));
+ if ((ifp->if_flags & (IFF_RUNNING|IFF_OACTIVE)) != IFF_RUNNING)
+ goto out;
+
/* XXX do real rate control */
proto_ctl0 = RTW_TXCTL0_RTSRATE_1MBPS;
- switch (rate = MAX(2, ieee80211_get_rate(ic))) {
- case 2:
- proto_ctl0 |= RTW_TXCTL0_RATE_1MBPS;
- break;
- case 4:
- proto_ctl0 |= RTW_TXCTL0_RATE_2MBPS;
- break;
- case 11:
- proto_ctl0 |= RTW_TXCTL0_RATE_5MBPS;
- break;
- case 22:
- proto_ctl0 |= RTW_TXCTL0_RATE_11MBPS;
- break;
- }
+ rate = MAX(2, ieee80211_get_rate(ic));
if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) != 0)
proto_ctl0 |= RTW_TXCTL0_SPLCP;
@@ -2667,7 +2854,7 @@ rtw_start(struct ifnet *ifp)
dmamap = ts->ts_dmamap;
- m0 = rtw_dmamap_load_txsoft(sc->sc_dmat, dmamap, m0,
+ m0 = rtw_dmamap_load_txbuf(sc->sc_dmat, dmamap, m0,
tdb->tdb_nfree, &ifp->if_flags, sc->sc_dev.dv_xname);
if (m0 == NULL || dmamap->dm_nsegs == 0) {
@@ -2690,6 +2877,28 @@ rtw_start(struct ifnet *ifp)
wh = mtod(m0, struct ieee80211_frame *);
+ if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
+ IEEE80211_FC0_TYPE_MGT) {
+ ctl0 |= RTW_TXCTL0_RATE_1MBPS;
+ } else switch (rate) {
+ default:
+ case 2:
+ ctl0 |= RTW_TXCTL0_RATE_1MBPS;
+ break;
+ case 4:
+ ctl0 |= RTW_TXCTL0_RATE_2MBPS;
+ break;
+ case 11:
+ ctl0 |= RTW_TXCTL0_RATE_5MBPS;
+ break;
+ case 22:
+ ctl0 |= RTW_TXCTL0_RATE_11MBPS;
+ break;
+ }
+
+ if ((wh->i_fc[1] & IEEE80211_FC1_WEP) != 0)
+ ctl0 |= LSHIFT(sc->sc_txkey, RTW_TXCTL0_KEYID_MASK);
+
if (ieee80211_compute_duration(wh, m0->m_pkthdr.len,
ic->ic_flags, ic->ic_fragthreshold,
rate, &ts->ts_d0, &ts->ts_dn, &npkt,
@@ -2718,8 +2927,7 @@ rtw_start(struct ifnet *ifp)
ts->ts_first = tdb->tdb_next;
- rtw_txdescs_sync(sc->sc_dmat, sc->sc_desc_dmamap,
- tdb, ts->ts_first, dmamap->dm_nsegs,
+ rtw_txdescs_sync(tdb, ts->ts_first, dmamap->dm_nsegs,
BUS_DMASYNC_PREWRITE);
KASSERT(ts->ts_first < tdb->tdb_ndesc);
@@ -2762,8 +2970,7 @@ rtw_start(struct ifnet *ifp)
tdb->tdb_nfree -= dmamap->dm_nsegs;
tdb->tdb_next = desc;
- rtw_txdescs_sync(sc->sc_dmat, sc->sc_desc_dmamap,
- tdb, ts->ts_first, dmamap->dm_nsegs,
+ rtw_txdescs_sync(tdb, ts->ts_first, dmamap->dm_nsegs,
BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
tdb->tdb_desc[ts->ts_first].td_ctl0 |=
@@ -2773,22 +2980,23 @@ rtw_start(struct ifnet *ifp)
rtw_print_txdesc(sc, "OWN on", ts, tdb, ts->ts_first);
#endif /* RTW_DEBUG */
- rtw_txdescs_sync(sc->sc_dmat, sc->sc_desc_dmamap,
- tdb, ts->ts_first, 1,
+ rtw_txdescs_sync(tdb, ts->ts_first, 1,
BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
SIMPLEQ_REMOVE_HEAD(&tsb->tsb_freeq, ts_q);
SIMPLEQ_INSERT_TAIL(&tsb->tsb_dirtyq, ts, ts_q);
- tsb->tsb_tx_timer = 5;
- ifp->if_timer = 1;
+ if (tsb != &sc->sc_txsoft_blk[RTW_TXPRIBCN]) {
+ tsb->tsb_tx_timer = 5;
+ ifp->if_timer = 1;
+ }
tppoll = RTW_READ8(&sc->sc_regs, RTW_TPPOLL);
-
- /* TBD poke other queues. */
- RTW_WRITE8(&sc->sc_regs, RTW_TPPOLL, tppoll | RTW_TPPOLL_NPQ);
+ RTW_WRITE8(&sc->sc_regs, RTW_TPPOLL,
+ tppoll | (tsb->tsb_poll & RTW_TPPOLL_ALL));
RTW_SYNC(&sc->sc_regs, RTW_TPPOLL, RTW_TPPOLL);
}
+out:
DPRINTF(sc, RTW_DEBUG_XMIT, ("%s: leave\n", __func__));
return;
post_load_err:
@@ -2803,6 +3011,7 @@ post_dequeue_err:
void
rtw_watchdog(struct ifnet *ifp)
{
+ u_int8_t tppoll;
int pri;
struct rtw_softc *sc;
struct rtw_txsoft_blk *tsb;
@@ -2828,8 +3037,12 @@ rtw_watchdog(struct ifnet *ifp)
ifp->if_oerrors++;
/* Stop Tx DMA, disable transmitter, clear
* Tx rings, and restart.
+ *
+ * TBD Stop/restart just the broken ring?
*/
- RTW_WRITE8(&sc->sc_regs, RTW_TPPOLL, RTW_TPPOLL_SNPQ);
+ tppoll = RTW_READ8(&sc->sc_regs, RTW_TPPOLL);
+ RTW_WRITE8(&sc->sc_regs, RTW_TPPOLL,
+ tppoll | RTW_TPPOLL_SALL);
RTW_SYNC(&sc->sc_regs, RTW_TPPOLL, RTW_TPPOLL);
rtw_io_enable(&sc->sc_regs, RTW_CR_TE, 0);
rtw_txdescs_reset(sc);
@@ -2904,6 +3117,7 @@ rtw_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
{
struct ifnet *ifp = &ic->ic_if;
struct rtw_softc *sc = ifp->if_softc;
+ struct mbuf *m;
enum ieee80211_state ostate;
int error;
@@ -2943,9 +3157,16 @@ rtw_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
break;
case IEEE80211_S_RUN:
switch (ic->ic_opmode) {
- case IEEE80211_M_AHDEMO:
case IEEE80211_M_HOSTAP:
case IEEE80211_M_IBSS:
+ m = rtw_beacon_alloc(sc, ic->ic_bss);
+ if (m == NULL) {
+ printf("%s: could not allocate beacon\n",
+ sc->sc_dev.dv_xname);
+ } else
+ IF_ENQUEUE(&sc->sc_beaconq, m);
+ /*FALLTHROUGH*/
+ case IEEE80211_M_AHDEMO:
rtw_join_bss(sc, ic->ic_bss->ni_bssid, ic->ic_opmode,
ic->ic_bss->ni_intval);
break;
@@ -2973,7 +3194,7 @@ rtw_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
void
rtw_recv_beacon(struct rtw_softc *sc, struct mbuf *m,
- struct ieee80211_node *ni, int subtype, int rssi, u_int32_t rstamp)
+ struct ieee80211_node *ni, int subtype, int rssi, uint32_t rstamp)
{
(*sc->sc_mtbl.mt_recv_mgmt)(&sc->sc_ic, m, ni, subtype, rssi, rstamp);
return;
@@ -3214,12 +3435,19 @@ rtw_txsoft_blk_setup_all(struct rtw_softc *sc)
int pri, rc = 0;
int qlen[RTW_NTXPRI] =
{RTW_TXQLENLO, RTW_TXQLENMD, RTW_TXQLENHI, RTW_TXQLENBCN};
+ struct rtw_txsoft_blk *tsbs;
+
+ tsbs = sc->sc_txsoft_blk;
for (pri = 0; pri < RTW_NTXPRI; pri++) {
- rc = rtw_txsoft_blk_setup(&sc->sc_txsoft_blk[pri], qlen[pri]);
+ rc = rtw_txsoft_blk_setup(&tsbs[pri], qlen[pri]);
if (rc != 0)
break;
}
+ tsbs[RTW_TXPRILO].tsb_poll = RTW_TPPOLL_LPQ | RTW_TPPOLL_SLPQ;
+ tsbs[RTW_TXPRIMD].tsb_poll = RTW_TPPOLL_NPQ | RTW_TPPOLL_SNPQ;
+ tsbs[RTW_TXPRIHI].tsb_poll = RTW_TPPOLL_HPQ | RTW_TPPOLL_SHPQ;
+ tsbs[RTW_TXPRIBCN].tsb_poll = RTW_TPPOLL_BQ | RTW_TPPOLL_SBQ;
return rc;
}
@@ -3379,6 +3607,14 @@ rtw_attach(struct rtw_softc *sc)
}
NEXT_ATTACH_STATE(sc, FINISH_DESCMAP_CREATE);
+ sc->sc_rxdesc_blk.rdb_dmat = sc->sc_dmat;
+ sc->sc_rxdesc_blk.rdb_dmamap = sc->sc_desc_dmamap;
+
+ for (pri = 0; pri < RTW_NTXPRI; pri++) {
+ sc->sc_txdesc_blk[pri].tdb_dmat = sc->sc_dmat;
+ sc->sc_txdesc_blk[pri].tdb_dmamap = sc->sc_desc_dmamap;
+ }
+
rc = bus_dmamap_load(sc->sc_dmat, sc->sc_desc_dmamap, sc->sc_descs,
sizeof(struct rtw_descs), NULL, 0);
@@ -3397,9 +3633,7 @@ rtw_attach(struct rtw_softc *sc)
NEXT_ATTACH_STATE(sc, FINISH_TXDESCBLK_SETUP);
- sc->sc_rxdesc = &sc->sc_descs->hd_rx[0];
-
- rtw_rxsofts_setup(&sc->sc_rxsoft[0]);
+ sc->sc_rxdesc_blk.rdb_desc = &sc->sc_descs->hd_rx[0];
for (pri = 0; pri < RTW_NTXPRI; pri++) {
tsb = &sc->sc_txsoft_blk[pri];