summaryrefslogtreecommitdiffstats
path: root/sys/dev/ath/if_ath.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/ath/if_ath.c')
-rw-r--r--sys/dev/ath/if_ath.c1292
1 files changed, 192 insertions, 1100 deletions
diff --git a/sys/dev/ath/if_ath.c b/sys/dev/ath/if_ath.c
index b919249..63375bf 100644
--- a/sys/dev/ath/if_ath.c
+++ b/sys/dev/ath/if_ath.c
@@ -87,6 +87,11 @@ __FBSDID("$FreeBSD$");
#include <dev/ath/if_athvar.h>
#include <dev/ath/ath_hal/ah_devid.h> /* XXX for softled */
+#include <dev/ath/ath_hal/ah_diagcodes.h>
+
+#include <dev/ath/if_ath_debug.h>
+#include <dev/ath/if_ath_misc.h>
+#include <dev/ath/if_ath_tx.h>
#ifdef ATH_TX99_DIAG
#include <dev/ath/ath_tx99/ath_tx99.h>
@@ -108,15 +113,6 @@ __FBSDID("$FreeBSD$");
*/
CTASSERT(ATH_BCBUF <= 8);
-/* unaligned little endian access */
-#define LE_READ_2(p) \
- ((u_int16_t) \
- ((((u_int8_t *)(p))[0] ) | (((u_int8_t *)(p))[1] << 8)))
-#define LE_READ_4(p) \
- ((u_int32_t) \
- ((((u_int8_t *)(p))[0] ) | (((u_int8_t *)(p))[1] << 8) | \
- (((u_int8_t *)(p))[2] << 16) | (((u_int8_t *)(p))[3] << 24)))
-
static struct ieee80211vap *ath_vap_create(struct ieee80211com *,
const char name[IFNAMSIZ], int unit, int opmode,
int flags, const uint8_t bssid[IEEE80211_ADDR_LEN],
@@ -181,9 +177,6 @@ static int ath_tx_setup(struct ath_softc *, int, int);
static int ath_wme_update(struct ieee80211com *);
static void ath_tx_cleanupq(struct ath_softc *, struct ath_txq *);
static void ath_tx_cleanup(struct ath_softc *);
-static void ath_freetx(struct mbuf *);
-static int ath_tx_start(struct ath_softc *, struct ieee80211_node *,
- struct ath_buf *, struct mbuf *);
static void ath_tx_proc_q0(void *, int);
static void ath_tx_proc_q0123(void *, int);
static void ath_tx_proc(void *, int);
@@ -212,8 +205,6 @@ static int ath_rate_setup(struct ath_softc *, u_int mode);
static void ath_setcurmode(struct ath_softc *, enum ieee80211_phymode);
static void ath_sysctlattach(struct ath_softc *);
-static int ath_raw_xmit(struct ieee80211_node *,
- struct mbuf *, const struct ieee80211_bpf_params *);
static void ath_announce(struct ath_softc *);
static void ath_sysctl_stats_attach(struct ath_softc *sc);
@@ -273,6 +264,9 @@ SYSCTL_INT(_hw_ath, OID_AUTO, shortcal, CTLFLAG_RW, &ath_shortcalinterval,
static int ath_resetcalinterval = 20*60; /* reset cal state 20 mins */
SYSCTL_INT(_hw_ath, OID_AUTO, resetcal, CTLFLAG_RW, &ath_resetcalinterval,
0, "reset chip calibration results (secs)");
+static int ath_anicalinterval = 100; /* ANI calibration - 100 msec */
+SYSCTL_INT(_hw_ath, OID_AUTO, anical, CTLFLAG_RW, &ath_anicalinterval,
+ 0, "ANI calibration (msecs)");
static int ath_rxbuf = ATH_RXBUF; /* # rx buffers to allocate */
SYSCTL_INT(_hw_ath, OID_AUTO, rxbuf, CTLFLAG_RW, &ath_rxbuf,
@@ -287,67 +281,12 @@ static int ath_bstuck_threshold = 4; /* max missed beacons */
SYSCTL_INT(_hw_ath, OID_AUTO, bstuck, CTLFLAG_RW, &ath_bstuck_threshold,
0, "max missed beacon xmits before chip reset");
-#ifdef ATH_DEBUG
-enum {
- ATH_DEBUG_XMIT = 0x00000001, /* basic xmit operation */
- ATH_DEBUG_XMIT_DESC = 0x00000002, /* xmit descriptors */
- ATH_DEBUG_RECV = 0x00000004, /* basic recv operation */
- ATH_DEBUG_RECV_DESC = 0x00000008, /* recv descriptors */
- ATH_DEBUG_RATE = 0x00000010, /* rate control */
- ATH_DEBUG_RESET = 0x00000020, /* reset processing */
- ATH_DEBUG_MODE = 0x00000040, /* mode init/setup */
- ATH_DEBUG_BEACON = 0x00000080, /* beacon handling */
- ATH_DEBUG_WATCHDOG = 0x00000100, /* watchdog timeout */
- ATH_DEBUG_INTR = 0x00001000, /* ISR */
- ATH_DEBUG_TX_PROC = 0x00002000, /* tx ISR proc */
- ATH_DEBUG_RX_PROC = 0x00004000, /* rx ISR proc */
- ATH_DEBUG_BEACON_PROC = 0x00008000, /* beacon ISR proc */
- ATH_DEBUG_CALIBRATE = 0x00010000, /* periodic calibration */
- ATH_DEBUG_KEYCACHE = 0x00020000, /* key cache management */
- ATH_DEBUG_STATE = 0x00040000, /* 802.11 state transitions */
- ATH_DEBUG_NODE = 0x00080000, /* node management */
- ATH_DEBUG_LED = 0x00100000, /* led management */
- ATH_DEBUG_FF = 0x00200000, /* fast frames */
- ATH_DEBUG_DFS = 0x00400000, /* DFS processing */
- ATH_DEBUG_TDMA = 0x00800000, /* TDMA processing */
- ATH_DEBUG_TDMA_TIMER = 0x01000000, /* TDMA timer processing */
- ATH_DEBUG_REGDOMAIN = 0x02000000, /* regulatory processing */
- ATH_DEBUG_FATAL = 0x80000000, /* fatal errors */
- ATH_DEBUG_ANY = 0xffffffff
-};
-static int ath_debug = 0;
-SYSCTL_INT(_hw_ath, OID_AUTO, debug, CTLFLAG_RW, &ath_debug,
- 0, "control debugging printfs");
-TUNABLE_INT("hw.ath.debug", &ath_debug);
-
-#define IFF_DUMPPKTS(sc, m) \
- ((sc->sc_debug & (m)) || \
- (sc->sc_ifp->if_flags & (IFF_DEBUG|IFF_LINK2)) == (IFF_DEBUG|IFF_LINK2))
-#define DPRINTF(sc, m, fmt, ...) do { \
- if (sc->sc_debug & (m)) \
- device_printf(sc->sc_dev, fmt, __VA_ARGS__); \
-} while (0)
-#define KEYPRINTF(sc, ix, hk, mac) do { \
- if (sc->sc_debug & ATH_DEBUG_KEYCACHE) \
- ath_keyprint(sc, __func__, ix, hk, mac); \
-} while (0)
-static void ath_printrxbuf(struct ath_softc *, const struct ath_buf *bf,
- u_int ix, int);
-static void ath_printtxbuf(struct ath_softc *, const struct ath_buf *bf,
- u_int qnum, u_int ix, int done);
-#else
-#define IFF_DUMPPKTS(sc, m) \
- ((sc->sc_ifp->if_flags & (IFF_DEBUG|IFF_LINK2)) == (IFF_DEBUG|IFF_LINK2))
-#define DPRINTF(sc, m, fmt, ...) do { \
- (void) sc; \
-} while (0)
-#define KEYPRINTF(sc, k, ix, mac) do { \
- (void) sc; \
-} while (0)
-#endif
-
MALLOC_DEFINE(M_ATHDEV, "athdev", "ath driver dma buffers");
+#define HAL_MODE_HT20 (HAL_MODE_11NG_HT20 | HAL_MODE_11NA_HT20)
+#define HAL_MODE_HT40 \
+ (HAL_MODE_11NG_HT40PLUS | HAL_MODE_11NG_HT40MINUS | \
+ HAL_MODE_11NA_HT40PLUS | HAL_MODE_11NA_HT40MINUS)
int
ath_attach(u_int16_t devid, struct ath_softc *sc)
{
@@ -373,7 +312,7 @@ ath_attach(u_int16_t devid, struct ath_softc *sc)
if_initname(ifp, device_get_name(sc->sc_dev),
device_get_unit(sc->sc_dev));
- ah = ath_hal_attach(devid, sc, sc->sc_st, sc->sc_sh, &status);
+ ah = ath_hal_attach(devid, sc, sc->sc_st, sc->sc_sh, sc->sc_eepromdata, &status);
if (ah == NULL) {
if_printf(ifp, "unable to attach hardware; HAL status %u\n",
status);
@@ -676,6 +615,55 @@ ath_attach(u_int16_t devid, struct ath_softc *sc)
ic->ic_tdma_update = ath_tdma_update;
}
#endif
+
+ /*
+ * The if_ath 11n support is completely not ready for normal use.
+ * Enabling this option will likely break everything and everything.
+ * Don't think of doing that unless you know what you're doing.
+ */
+
+#ifdef DO_ATH_11N
+ /*
+ * Query HT capabilities
+ */
+ if (ath_hal_getcapability(ah, HAL_CAP_HT, 0, NULL) == HAL_OK &&
+ (wmodes & (HAL_MODE_HT20 | HAL_MODE_HT40))) {
+ int rxs, txs;
+
+ device_printf(sc->sc_dev, "[HT] enabling HT modes\n");
+ ic->ic_htcaps = IEEE80211_HTC_HT /* HT operation */
+ | IEEE80211_HTC_AMPDU /* A-MPDU tx/rx */
+ | IEEE80211_HTC_AMSDU /* A-MSDU tx/rx */
+ | IEEE80211_HTCAP_MAXAMSDU_3839 /* max A-MSDU length */
+ /* At the present time, the hardware doesn't support short-GI in 20mhz mode */
+#if 0
+ | IEEE80211_HTCAP_SHORTGI20 /* short GI in 20MHz */
+#endif
+ | IEEE80211_HTCAP_SMPS_OFF; /* SM power save off */
+ ;
+
+ if (wmodes & HAL_MODE_HT40)
+ ic->ic_htcaps |= IEEE80211_HTCAP_CHWIDTH40
+ | IEEE80211_HTCAP_SHORTGI40;
+
+ /*
+ * rx/tx stream is not currently used anywhere; it needs to be taken
+ * into account when negotiating which MCS rates it'll receive and
+ * what MCS rates are available for TX.
+ */
+ (void) ath_hal_getcapability(ah, HAL_CAP_STREAMS, 0, &rxs);
+ (void) ath_hal_getcapability(ah, HAL_CAP_STREAMS, 1, &txs);
+
+ ath_hal_getrxchainmask(ah, &sc->sc_rxchainmask);
+ ath_hal_gettxchainmask(ah, &sc->sc_txchainmask);
+
+ ic->ic_txstream = txs;
+ ic->ic_rxstream = rxs;
+
+ device_printf(sc->sc_dev, "[HT] %d RX streams; %d TX streams\n", rxs, txs);
+ }
+#endif
+
/*
* Indicate we need the 802.11 header padded to a
* 32-bit boundary for 4-address and QoS frames.
@@ -1460,7 +1448,7 @@ ath_hal_gethangstate(struct ath_hal *ah, uint32_t mask, uint32_t *hangs)
uint32_t rsize;
void *sp;
- if (!ath_hal_getdiagstate(ah, 32, &mask, sizeof(mask), &sp, &rsize))
+ if (!ath_hal_getdiagstate(ah, HAL_DIAG_CHECK_HANGS, &mask, sizeof(mask), &sp, &rsize))
return 0;
KASSERT(rsize == sizeof(uint32_t), ("resultsize %u", rsize));
*hangs = *(uint32_t *)sp;
@@ -1549,6 +1537,9 @@ ath_init(void *arg)
sc->sc_lastlongcal = 0;
sc->sc_resetcal = 1;
sc->sc_lastcalreset = 0;
+ sc->sc_lastani = 0;
+ sc->sc_lastshortcal = 0;
+ sc->sc_doresetcal = AH_FALSE;
/*
* Setup the hardware after reset: the key cache
@@ -1720,7 +1711,7 @@ ath_reset_vap(struct ieee80211vap *vap, u_long cmd)
return ath_reset(ifp);
}
-static struct ath_buf *
+struct ath_buf *
_ath_getbuf_locked(struct ath_softc *sc)
{
struct ath_buf *bf;
@@ -1740,7 +1731,7 @@ _ath_getbuf_locked(struct ath_softc *sc)
return bf;
}
-static struct ath_buf *
+struct ath_buf *
ath_getbuf(struct ath_softc *sc)
{
struct ath_buf *bf;
@@ -1758,54 +1749,6 @@ ath_getbuf(struct ath_softc *sc)
return bf;
}
-/*
- * Cleanup driver resources when we run out of buffers
- * while processing fragments; return the tx buffers
- * allocated and drop node references.
- */
-static void
-ath_txfrag_cleanup(struct ath_softc *sc,
- ath_bufhead *frags, struct ieee80211_node *ni)
-{
- struct ath_buf *bf, *next;
-
- ATH_TXBUF_LOCK_ASSERT(sc);
-
- STAILQ_FOREACH_SAFE(bf, frags, bf_list, next) {
- /* NB: bf assumed clean */
- STAILQ_REMOVE_HEAD(frags, bf_list);
- STAILQ_INSERT_HEAD(&sc->sc_txbuf, bf, bf_list);
- ieee80211_node_decref(ni);
- }
-}
-
-/*
- * Setup xmit of a fragmented frame. Allocate a buffer
- * for each frag and bump the node reference count to
- * reflect the held reference to be setup by ath_tx_start.
- */
-static int
-ath_txfrag_setup(struct ath_softc *sc, ath_bufhead *frags,
- struct mbuf *m0, struct ieee80211_node *ni)
-{
- struct mbuf *m;
- struct ath_buf *bf;
-
- ATH_TXBUF_LOCK(sc);
- for (m = m0->m_nextpkt; m != NULL; m = m->m_nextpkt) {
- bf = _ath_getbuf_locked(sc);
- if (bf == NULL) { /* out of buffers, cleanup */
- ath_txfrag_cleanup(sc, frags, ni);
- break;
- }
- ieee80211_node_incref(ni);
- STAILQ_INSERT_TAIL(frags, bf, bf_list);
- }
- ATH_TXBUF_UNLOCK(sc);
-
- return !STAILQ_EMPTY(frags);
-}
-
static void
ath_start(struct ifnet *ifp)
{
@@ -2048,10 +1991,10 @@ ath_keyset(struct ath_softc *sc, const struct ieee80211_key *k,
/*
* Group keys on hardware that supports multicast frame
* key search use a MAC that is the sender's address with
- * the high bit set instead of the app-specified address.
+ * the multicast bit set instead of the app-specified address.
*/
IEEE80211_ADDR_COPY(gmac, bss->ni_macaddr);
- gmac[0] |= 0x80;
+ gmac[0] |= 0x01;
mac = gmac;
} else
mac = k->wk_macaddr;
@@ -2383,7 +2326,6 @@ ath_key_update_end(struct ieee80211vap *vap)
* - when operating in mesh mode to detect neighbors
* o accept control frames:
* - when in monitor mode
- * XXX BAR frames for 11n
* XXX HT protection for 11n
*/
static u_int32_t
@@ -2422,6 +2364,8 @@ ath_calcrxfilter(struct ath_softc *sc)
}
if (ic->ic_opmode == IEEE80211_M_MONITOR)
rfilt |= HAL_RX_FILTER_CONTROL;
+ if (IEEE80211_IS_CHAN_HT(ic->ic_curchan))
+ rfilt |= HAL_RX_FILTER_COMPBAR;
DPRINTF(sc, ATH_DEBUG_MODE, "%s: RX filter 0x%x, %s if_flags 0x%x\n",
__func__, rfilt, ieee80211_opmode_name[ic->ic_opmode], ifp->if_flags);
return rfilt;
@@ -3774,7 +3718,6 @@ ath_rx_proc(void *arg, int npending)
struct mbuf *m;
struct ieee80211_node *ni;
int len, type, ngood;
- u_int phyerr;
HAL_STATUS status;
int16_t nf;
u_int64_t tsf;
@@ -3828,6 +3771,21 @@ ath_rx_proc(void *arg, int npending)
if (status == HAL_EINPROGRESS)
break;
STAILQ_REMOVE_HEAD(&sc->sc_rxbuf, bf_list);
+
+ /* These aren't specifically errors */
+ if (rs->rs_flags & HAL_RX_GI)
+ sc->sc_stats.ast_rx_halfgi++;
+ if (rs->rs_flags & HAL_RX_2040)
+ sc->sc_stats.ast_rx_2040++;
+ if (rs->rs_flags & HAL_RX_DELIM_CRC_PRE)
+ sc->sc_stats.ast_rx_pre_crc_err++;
+ if (rs->rs_flags & HAL_RX_DELIM_CRC_POST)
+ sc->sc_stats.ast_rx_post_crc_err++;
+ if (rs->rs_flags & HAL_RX_DECRYPT_BUSY)
+ sc->sc_stats.ast_rx_decrypt_busy_err++;
+ if (rs->rs_flags & HAL_RX_HI_RX_CHAIN)
+ sc->sc_stats.ast_rx_hi_rx_chain++;
+
if (rs->rs_status != 0) {
if (rs->rs_status & HAL_RXERR_CRC)
sc->sc_stats.ast_rx_crcerr++;
@@ -3835,8 +3793,9 @@ ath_rx_proc(void *arg, int npending)
sc->sc_stats.ast_rx_fifoerr++;
if (rs->rs_status & HAL_RXERR_PHY) {
sc->sc_stats.ast_rx_phyerr++;
- phyerr = rs->rs_phyerr & 0x1f;
- sc->sc_stats.ast_rx_phy[phyerr]++;
+ /* Be suitably paranoid about receiving phy errors out of the stats array bounds */
+ if (rs->rs_phyerr < 64)
+ sc->sc_stats.ast_rx_phy[rs->rs_phyerr]++;
goto rx_error; /* NB: don't count in ierrors */
}
if (rs->rs_status & HAL_RXERR_DECRYPT) {
@@ -4000,8 +3959,29 @@ rx_accept:
rs->rs_keyix == HAL_RXKEYIX_INVALID ?
IEEE80211_KEYIX_NONE : rs->rs_keyix);
sc->sc_lastrs = rs;
+ /* tag AMPDU aggregates for reorder processing */
+#if 0
+ /*
+ * Just make sure all frames are tagged for AMPDU reorder checking.
+ * As there seems to be some situations where single frames aren't
+ * matching a node but bump the seqno. This needs to be investigated.
+ */
+ m->m_flags |= M_AMPDU;
+#endif
+
+ /* Keep statistics on the number of aggregate packets received */
+ if (rs->rs_isaggr)
+ sc->sc_stats.ast_rx_agg++;
+
if (ni != NULL) {
/*
+ * Only punt packets for ampdu reorder processing for 11n nodes;
+ * net80211 enforces that M_AMPDU is only set for 11n nodes.
+ */
+ if (ni->ni_flags & IEEE80211_NODE_HT)
+ m->m_flags |= M_AMPDU;
+
+ /*
* Sending station is known, dispatch directly.
*/
type = ieee80211_input(ni, m, rs->rs_rssi, nf);
@@ -4277,7 +4257,7 @@ ath_tx_cleanup(struct ath_softc *sc)
* Return h/w rate index for an IEEE rate (w/o basic rate bit)
* using the current rates in sc_rixmap.
*/
-static __inline int
+int
ath_tx_findrix(const struct ath_softc *sc, uint8_t rate)
{
int rix = sc->sc_rixmap[rate];
@@ -4286,623 +4266,6 @@ ath_tx_findrix(const struct ath_softc *sc, uint8_t rate)
}
/*
- * Reclaim mbuf resources. For fragmented frames we
- * need to claim each frag chained with m_nextpkt.
- */
-static void
-ath_freetx(struct mbuf *m)
-{
- struct mbuf *next;
-
- do {
- next = m->m_nextpkt;
- m->m_nextpkt = NULL;
- m_freem(m);
- } while ((m = next) != NULL);
-}
-
-static int
-ath_tx_dmasetup(struct ath_softc *sc, struct ath_buf *bf, struct mbuf *m0)
-{
- struct mbuf *m;
- int error;
-
- /*
- * Load the DMA map so any coalescing is done. This
- * also calculates the number of descriptors we need.
- */
- error = bus_dmamap_load_mbuf_sg(sc->sc_dmat, bf->bf_dmamap, m0,
- bf->bf_segs, &bf->bf_nseg,
- BUS_DMA_NOWAIT);
- if (error == EFBIG) {
- /* XXX packet requires too many descriptors */
- bf->bf_nseg = ATH_TXDESC+1;
- } else if (error != 0) {
- sc->sc_stats.ast_tx_busdma++;
- ath_freetx(m0);
- return error;
- }
- /*
- * Discard null packets and check for packets that
- * require too many TX descriptors. We try to convert
- * the latter to a cluster.
- */
- if (bf->bf_nseg > ATH_TXDESC) { /* too many desc's, linearize */
- sc->sc_stats.ast_tx_linear++;
- m = m_collapse(m0, M_DONTWAIT, ATH_TXDESC);
- if (m == NULL) {
- ath_freetx(m0);
- sc->sc_stats.ast_tx_nombuf++;
- return ENOMEM;
- }
- m0 = m;
- error = bus_dmamap_load_mbuf_sg(sc->sc_dmat, bf->bf_dmamap, m0,
- bf->bf_segs, &bf->bf_nseg,
- BUS_DMA_NOWAIT);
- if (error != 0) {
- sc->sc_stats.ast_tx_busdma++;
- ath_freetx(m0);
- return error;
- }
- KASSERT(bf->bf_nseg <= ATH_TXDESC,
- ("too many segments after defrag; nseg %u", bf->bf_nseg));
- } else if (bf->bf_nseg == 0) { /* null packet, discard */
- sc->sc_stats.ast_tx_nodata++;
- ath_freetx(m0);
- return EIO;
- }
- DPRINTF(sc, ATH_DEBUG_XMIT, "%s: m %p len %u\n",
- __func__, m0, m0->m_pkthdr.len);
- bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap, BUS_DMASYNC_PREWRITE);
- bf->bf_m = m0;
-
- return 0;
-}
-
-static void
-ath_tx_handoff(struct ath_softc *sc, struct ath_txq *txq, struct ath_buf *bf)
-{
- struct ath_hal *ah = sc->sc_ah;
- struct ath_desc *ds, *ds0;
- int i;
-
- /*
- * Fillin the remainder of the descriptor info.
- */
- ds0 = ds = bf->bf_desc;
- for (i = 0; i < bf->bf_nseg; i++, ds++) {
- ds->ds_data = bf->bf_segs[i].ds_addr;
- if (i == bf->bf_nseg - 1)
- ds->ds_link = 0;
- else
- ds->ds_link = bf->bf_daddr + sizeof(*ds) * (i + 1);
- ath_hal_filltxdesc(ah, ds
- , bf->bf_segs[i].ds_len /* segment length */
- , i == 0 /* first segment */
- , i == bf->bf_nseg - 1 /* last segment */
- , ds0 /* first descriptor */
- );
- DPRINTF(sc, ATH_DEBUG_XMIT,
- "%s: %d: %08x %08x %08x %08x %08x %08x\n",
- __func__, i, ds->ds_link, ds->ds_data,
- ds->ds_ctl0, ds->ds_ctl1, ds->ds_hw[0], ds->ds_hw[1]);
- }
- /*
- * Insert the frame on the outbound list and pass it on
- * to the hardware. Multicast frames buffered for power
- * save stations and transmit from the CAB queue are stored
- * on a s/w only queue and loaded on to the CAB queue in
- * the SWBA handler since frames only go out on DTIM and
- * to avoid possible races.
- */
- ATH_TXQ_LOCK(txq);
- KASSERT((bf->bf_flags & ATH_BUF_BUSY) == 0,
- ("busy status 0x%x", bf->bf_flags));
- if (txq->axq_qnum != ATH_TXQ_SWQ) {
-#ifdef IEEE80211_SUPPORT_TDMA
- int qbusy;
-
- ATH_TXQ_INSERT_TAIL(txq, bf, bf_list);
- qbusy = ath_hal_txqenabled(ah, txq->axq_qnum);
- if (txq->axq_link == NULL) {
- /*
- * Be careful writing the address to TXDP. If
- * the tx q is enabled then this write will be
- * ignored. Normally this is not an issue but
- * when tdma is in use and the q is beacon gated
- * this race can occur. If the q is busy then
- * defer the work to later--either when another
- * packet comes along or when we prepare a beacon
- * frame at SWBA.
- */
- if (!qbusy) {
- ath_hal_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
- txq->axq_flags &= ~ATH_TXQ_PUTPENDING;
- DPRINTF(sc, ATH_DEBUG_XMIT,
- "%s: TXDP[%u] = %p (%p) depth %d\n",
- __func__, txq->axq_qnum,
- (caddr_t)bf->bf_daddr, bf->bf_desc,
- txq->axq_depth);
- } else {
- txq->axq_flags |= ATH_TXQ_PUTPENDING;
- DPRINTF(sc, ATH_DEBUG_TDMA | ATH_DEBUG_XMIT,
- "%s: Q%u busy, defer enable\n", __func__,
- txq->axq_qnum);
- }
- } else {
- *txq->axq_link = bf->bf_daddr;
- DPRINTF(sc, ATH_DEBUG_XMIT,
- "%s: link[%u](%p)=%p (%p) depth %d\n", __func__,
- txq->axq_qnum, txq->axq_link,
- (caddr_t)bf->bf_daddr, bf->bf_desc, txq->axq_depth);
- if ((txq->axq_flags & ATH_TXQ_PUTPENDING) && !qbusy) {
- /*
- * The q was busy when we previously tried
- * to write the address of the first buffer
- * in the chain. Since it's not busy now
- * handle this chore. We are certain the
- * buffer at the front is the right one since
- * axq_link is NULL only when the buffer list
- * is/was empty.
- */
- ath_hal_puttxbuf(ah, txq->axq_qnum,
- STAILQ_FIRST(&txq->axq_q)->bf_daddr);
- txq->axq_flags &= ~ATH_TXQ_PUTPENDING;
- DPRINTF(sc, ATH_DEBUG_TDMA | ATH_DEBUG_XMIT,
- "%s: Q%u restarted\n", __func__,
- txq->axq_qnum);
- }
- }
-#else
- ATH_TXQ_INSERT_TAIL(txq, bf, bf_list);
- if (txq->axq_link == NULL) {
- ath_hal_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
- DPRINTF(sc, ATH_DEBUG_XMIT,
- "%s: TXDP[%u] = %p (%p) depth %d\n",
- __func__, txq->axq_qnum,
- (caddr_t)bf->bf_daddr, bf->bf_desc,
- txq->axq_depth);
- } else {
- *txq->axq_link = bf->bf_daddr;
- DPRINTF(sc, ATH_DEBUG_XMIT,
- "%s: link[%u](%p)=%p (%p) depth %d\n", __func__,
- txq->axq_qnum, txq->axq_link,
- (caddr_t)bf->bf_daddr, bf->bf_desc, txq->axq_depth);
- }
-#endif /* IEEE80211_SUPPORT_TDMA */
- txq->axq_link = &bf->bf_desc[bf->bf_nseg - 1].ds_link;
- ath_hal_txstart(ah, txq->axq_qnum);
- } else {
- if (txq->axq_link != NULL) {
- struct ath_buf *last = ATH_TXQ_LAST(txq);
- struct ieee80211_frame *wh;
-
- /* mark previous frame */
- wh = mtod(last->bf_m, struct ieee80211_frame *);
- wh->i_fc[1] |= IEEE80211_FC1_MORE_DATA;
- bus_dmamap_sync(sc->sc_dmat, last->bf_dmamap,
- BUS_DMASYNC_PREWRITE);
-
- /* link descriptor */
- *txq->axq_link = bf->bf_daddr;
- }
- ATH_TXQ_INSERT_TAIL(txq, bf, bf_list);
- txq->axq_link = &bf->bf_desc[bf->bf_nseg - 1].ds_link;
- }
- ATH_TXQ_UNLOCK(txq);
-}
-
-static int
-ath_tx_start(struct ath_softc *sc, struct ieee80211_node *ni, struct ath_buf *bf,
- struct mbuf *m0)
-{
- struct ieee80211vap *vap = ni->ni_vap;
- struct ath_vap *avp = ATH_VAP(vap);
- struct ath_hal *ah = sc->sc_ah;
- struct ifnet *ifp = sc->sc_ifp;
- struct ieee80211com *ic = ifp->if_l2com;
- const struct chanAccParams *cap = &ic->ic_wme.wme_chanParams;
- int error, iswep, ismcast, isfrag, ismrr;
- int keyix, hdrlen, pktlen, try0;
- u_int8_t rix, txrate, ctsrate;
- u_int8_t cix = 0xff; /* NB: silence compiler */
- struct ath_desc *ds;
- struct ath_txq *txq;
- struct ieee80211_frame *wh;
- u_int subtype, flags, ctsduration;
- HAL_PKT_TYPE atype;
- const HAL_RATE_TABLE *rt;
- HAL_BOOL shortPreamble;
- struct ath_node *an;
- u_int pri;
-
- wh = mtod(m0, struct ieee80211_frame *);
- iswep = wh->i_fc[1] & IEEE80211_FC1_WEP;
- ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1);
- isfrag = m0->m_flags & M_FRAG;
- hdrlen = ieee80211_anyhdrsize(wh);
- /*
- * Packet length must not include any
- * pad bytes; deduct them here.
- */
- pktlen = m0->m_pkthdr.len - (hdrlen & 3);
-
- if (iswep) {
- const struct ieee80211_cipher *cip;
- struct ieee80211_key *k;
-
- /*
- * Construct the 802.11 header+trailer for an encrypted
- * frame. The only reason this can fail is because of an
- * unknown or unsupported cipher/key type.
- */
- k = ieee80211_crypto_encap(ni, m0);
- if (k == NULL) {
- /*
- * This can happen when the key is yanked after the
- * frame was queued. Just discard the frame; the
- * 802.11 layer counts failures and provides
- * debugging/diagnostics.
- */
- ath_freetx(m0);
- return EIO;
- }
- /*
- * Adjust the packet + header lengths for the crypto
- * additions and calculate the h/w key index. When
- * a s/w mic is done the frame will have had any mic
- * added to it prior to entry so m0->m_pkthdr.len will
- * account for it. Otherwise we need to add it to the
- * packet length.
- */
- cip = k->wk_cipher;
- hdrlen += cip->ic_header;
- pktlen += cip->ic_header + cip->ic_trailer;
- /* NB: frags always have any TKIP MIC done in s/w */
- if ((k->wk_flags & IEEE80211_KEY_SWMIC) == 0 && !isfrag)
- pktlen += cip->ic_miclen;
- keyix = k->wk_keyix;
-
- /* packet header may have moved, reset our local pointer */
- wh = mtod(m0, struct ieee80211_frame *);
- } else if (ni->ni_ucastkey.wk_cipher == &ieee80211_cipher_none) {
- /*
- * Use station key cache slot, if assigned.
- */
- keyix = ni->ni_ucastkey.wk_keyix;
- if (keyix == IEEE80211_KEYIX_NONE)
- keyix = HAL_TXKEYIX_INVALID;
- } else
- keyix = HAL_TXKEYIX_INVALID;
-
- pktlen += IEEE80211_CRC_LEN;
-
- /*
- * Load the DMA map so any coalescing is done. This
- * also calculates the number of descriptors we need.
- */
- error = ath_tx_dmasetup(sc, bf, m0);
- if (error != 0)
- return error;
- bf->bf_node = ni; /* NB: held reference */
- m0 = bf->bf_m; /* NB: may have changed */
- wh = mtod(m0, struct ieee80211_frame *);
-
- /* setup descriptors */
- ds = bf->bf_desc;
- rt = sc->sc_currates;
- KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode));
-
- /*
- * NB: the 802.11 layer marks whether or not we should
- * use short preamble based on the current mode and
- * negotiated parameters.
- */
- if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) &&
- (ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE)) {
- shortPreamble = AH_TRUE;
- sc->sc_stats.ast_tx_shortpre++;
- } else {
- shortPreamble = AH_FALSE;
- }
-
- an = ATH_NODE(ni);
- flags = HAL_TXDESC_CLRDMASK; /* XXX needed for crypto errs */
- ismrr = 0; /* default no multi-rate retry*/
- pri = M_WME_GETAC(m0); /* honor classification */
- /* XXX use txparams instead of fixed values */
- /*
- * Calculate Atheros packet type from IEEE80211 packet header,
- * setup for rate calculations, and select h/w transmit queue.
- */
- switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) {
- case IEEE80211_FC0_TYPE_MGT:
- subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
- if (subtype == IEEE80211_FC0_SUBTYPE_BEACON)
- atype = HAL_PKT_TYPE_BEACON;
- else if (subtype == IEEE80211_FC0_SUBTYPE_PROBE_RESP)
- atype = HAL_PKT_TYPE_PROBE_RESP;
- else if (subtype == IEEE80211_FC0_SUBTYPE_ATIM)
- atype = HAL_PKT_TYPE_ATIM;
- else
- atype = HAL_PKT_TYPE_NORMAL; /* XXX */
- rix = an->an_mgmtrix;
- txrate = rt->info[rix].rateCode;
- if (shortPreamble)
- txrate |= rt->info[rix].shortPreamble;
- try0 = ATH_TXMGTTRY;
- flags |= HAL_TXDESC_INTREQ; /* force interrupt */
- break;
- case IEEE80211_FC0_TYPE_CTL:
- atype = HAL_PKT_TYPE_PSPOLL; /* stop setting of duration */
- rix = an->an_mgmtrix;
- txrate = rt->info[rix].rateCode;
- if (shortPreamble)
- txrate |= rt->info[rix].shortPreamble;
- try0 = ATH_TXMGTTRY;
- flags |= HAL_TXDESC_INTREQ; /* force interrupt */
- break;
- case IEEE80211_FC0_TYPE_DATA:
- atype = HAL_PKT_TYPE_NORMAL; /* default */
- /*
- * Data frames: multicast frames go out at a fixed rate,
- * EAPOL frames use the mgmt frame rate; otherwise consult
- * the rate control module for the rate to use.
- */
- if (ismcast) {
- rix = an->an_mcastrix;
- txrate = rt->info[rix].rateCode;
- if (shortPreamble)
- txrate |= rt->info[rix].shortPreamble;
- try0 = 1;
- } else if (m0->m_flags & M_EAPOL) {
- /* XXX? maybe always use long preamble? */
- rix = an->an_mgmtrix;
- txrate = rt->info[rix].rateCode;
- if (shortPreamble)
- txrate |= rt->info[rix].shortPreamble;
- try0 = ATH_TXMAXTRY; /* XXX?too many? */
- } else {
- ath_rate_findrate(sc, an, shortPreamble, pktlen,
- &rix, &try0, &txrate);
- sc->sc_txrix = rix; /* for LED blinking */
- sc->sc_lastdatarix = rix; /* for fast frames */
- if (try0 != ATH_TXMAXTRY)
- ismrr = 1;
- }
- if (cap->cap_wmeParams[pri].wmep_noackPolicy)
- flags |= HAL_TXDESC_NOACK;
- break;
- default:
- if_printf(ifp, "bogus frame type 0x%x (%s)\n",
- wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK, __func__);
- /* XXX statistic */
- ath_freetx(m0);
- return EIO;
- }
- txq = sc->sc_ac2q[pri];
-
- /*
- * When servicing one or more stations in power-save mode
- * (or) if there is some mcast data waiting on the mcast
- * queue (to prevent out of order delivery) multicast
- * frames must be buffered until after the beacon.
- */
- if (ismcast && (vap->iv_ps_sta || avp->av_mcastq.axq_depth))
- txq = &avp->av_mcastq;
-
- /*
- * Calculate miscellaneous flags.
- */
- if (ismcast) {
- flags |= HAL_TXDESC_NOACK; /* no ack on broad/multicast */
- } else if (pktlen > vap->iv_rtsthreshold &&
- (ni->ni_ath_flags & IEEE80211_NODE_FF) == 0) {
- flags |= HAL_TXDESC_RTSENA; /* RTS based on frame length */
- cix = rt->info[rix].controlRate;
- sc->sc_stats.ast_tx_rts++;
- }
- if (flags & HAL_TXDESC_NOACK) /* NB: avoid double counting */
- sc->sc_stats.ast_tx_noack++;
-#ifdef IEEE80211_SUPPORT_TDMA
- if (sc->sc_tdma && (flags & HAL_TXDESC_NOACK) == 0) {
- DPRINTF(sc, ATH_DEBUG_TDMA,
- "%s: discard frame, ACK required w/ TDMA\n", __func__);
- sc->sc_stats.ast_tdma_ack++;
- ath_freetx(m0);
- return EIO;
- }
-#endif
-
- /*
- * If 802.11g protection is enabled, determine whether
- * to use RTS/CTS or just CTS. Note that this is only
- * done for OFDM unicast frames.
- */
- if ((ic->ic_flags & IEEE80211_F_USEPROT) &&
- rt->info[rix].phy == IEEE80211_T_OFDM &&
- (flags & HAL_TXDESC_NOACK) == 0) {
- /* XXX fragments must use CCK rates w/ protection */
- if (ic->ic_protmode == IEEE80211_PROT_RTSCTS)
- flags |= HAL_TXDESC_RTSENA;
- else if (ic->ic_protmode == IEEE80211_PROT_CTSONLY)
- flags |= HAL_TXDESC_CTSENA;
- if (isfrag) {
- /*
- * For frags it would be desirable to use the
- * highest CCK rate for RTS/CTS. But stations
- * farther away may detect it at a lower CCK rate
- * so use the configured protection rate instead
- * (for now).
- */
- cix = rt->info[sc->sc_protrix].controlRate;
- } else
- cix = rt->info[sc->sc_protrix].controlRate;
- sc->sc_stats.ast_tx_protect++;
- }
-
- /*
- * Calculate duration. This logically belongs in the 802.11
- * layer but it lacks sufficient information to calculate it.
- */
- if ((flags & HAL_TXDESC_NOACK) == 0 &&
- (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_CTL) {
- u_int16_t dur;
- if (shortPreamble)
- dur = rt->info[rix].spAckDuration;
- else
- dur = rt->info[rix].lpAckDuration;
- if (wh->i_fc[1] & IEEE80211_FC1_MORE_FRAG) {
- dur += dur; /* additional SIFS+ACK */
- KASSERT(m0->m_nextpkt != NULL, ("no fragment"));
- /*
- * Include the size of next fragment so NAV is
- * updated properly. The last fragment uses only
- * the ACK duration
- */
- dur += ath_hal_computetxtime(ah, rt,
- m0->m_nextpkt->m_pkthdr.len,
- rix, shortPreamble);
- }
- if (isfrag) {
- /*
- * Force hardware to use computed duration for next
- * fragment by disabling multi-rate retry which updates
- * duration based on the multi-rate duration table.
- */
- ismrr = 0;
- try0 = ATH_TXMGTTRY; /* XXX? */
- }
- *(u_int16_t *)wh->i_dur = htole16(dur);
- }
-
- /*
- * Calculate RTS/CTS rate and duration if needed.
- */
- ctsduration = 0;
- if (flags & (HAL_TXDESC_RTSENA|HAL_TXDESC_CTSENA)) {
- /*
- * CTS transmit rate is derived from the transmit rate
- * by looking in the h/w rate table. We must also factor
- * in whether or not a short preamble is to be used.
- */
- /* NB: cix is set above where RTS/CTS is enabled */
- KASSERT(cix != 0xff, ("cix not setup"));
- ctsrate = rt->info[cix].rateCode;
- /*
- * Compute the transmit duration based on the frame
- * size and the size of an ACK frame. We call into the
- * HAL to do the computation since it depends on the
- * characteristics of the actual PHY being used.
- *
- * NB: CTS is assumed the same size as an ACK so we can
- * use the precalculated ACK durations.
- */
- if (shortPreamble) {
- ctsrate |= rt->info[cix].shortPreamble;
- if (flags & HAL_TXDESC_RTSENA) /* SIFS + CTS */
- ctsduration += rt->info[cix].spAckDuration;
- ctsduration += ath_hal_computetxtime(ah,
- rt, pktlen, rix, AH_TRUE);
- if ((flags & HAL_TXDESC_NOACK) == 0) /* SIFS + ACK */
- ctsduration += rt->info[rix].spAckDuration;
- } else {
- if (flags & HAL_TXDESC_RTSENA) /* SIFS + CTS */
- ctsduration += rt->info[cix].lpAckDuration;
- ctsduration += ath_hal_computetxtime(ah,
- rt, pktlen, rix, AH_FALSE);
- if ((flags & HAL_TXDESC_NOACK) == 0) /* SIFS + ACK */
- ctsduration += rt->info[rix].lpAckDuration;
- }
- /*
- * Must disable multi-rate retry when using RTS/CTS.
- */
- ismrr = 0;
- try0 = ATH_TXMGTTRY; /* XXX */
- } else
- ctsrate = 0;
-
- /*
- * At this point we are committed to sending the frame
- * and we don't need to look at m_nextpkt; clear it in
- * case this frame is part of frag chain.
- */
- m0->m_nextpkt = NULL;
-
- if (IFF_DUMPPKTS(sc, ATH_DEBUG_XMIT))
- ieee80211_dump_pkt(ic, mtod(m0, const uint8_t *), m0->m_len,
- sc->sc_hwmap[rix].ieeerate, -1);
-
- if (ieee80211_radiotap_active_vap(vap)) {
- u_int64_t tsf = ath_hal_gettsf64(ah);
-
- sc->sc_tx_th.wt_tsf = htole64(tsf);
- sc->sc_tx_th.wt_flags = sc->sc_hwmap[rix].txflags;
- if (iswep)
- sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_WEP;
- if (isfrag)
- sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_FRAG;
- sc->sc_tx_th.wt_rate = sc->sc_hwmap[rix].ieeerate;
- sc->sc_tx_th.wt_txpower = ni->ni_txpower;
- sc->sc_tx_th.wt_antenna = sc->sc_txantenna;
-
- ieee80211_radiotap_tx(vap, m0);
- }
-
- /*
- * Determine if a tx interrupt should be generated for
- * this descriptor. We take a tx interrupt to reap
- * descriptors when the h/w hits an EOL condition or
- * when the descriptor is specifically marked to generate
- * an interrupt. We periodically mark descriptors in this
- * way to insure timely replenishing of the supply needed
- * for sending frames. Defering interrupts reduces system
- * load and potentially allows more concurrent work to be
- * done but if done to aggressively can cause senders to
- * backup.
- *
- * NB: use >= to deal with sc_txintrperiod changing
- * dynamically through sysctl.
- */
- if (flags & HAL_TXDESC_INTREQ) {
- txq->axq_intrcnt = 0;
- } else if (++txq->axq_intrcnt >= sc->sc_txintrperiod) {
- flags |= HAL_TXDESC_INTREQ;
- txq->axq_intrcnt = 0;
- }
-
- /*
- * Formulate first tx descriptor with tx controls.
- */
- /* XXX check return value? */
- ath_hal_setuptxdesc(ah, ds
- , pktlen /* packet length */
- , hdrlen /* header length */
- , atype /* Atheros packet type */
- , ni->ni_txpower /* txpower */
- , txrate, try0 /* series 0 rate/tries */
- , keyix /* key cache index */
- , sc->sc_txantenna /* antenna mode */
- , flags /* flags */
- , ctsrate /* rts/cts rate */
- , ctsduration /* rts/cts duration */
- );
- bf->bf_txflags = flags;
- /*
- * Setup the multi-rate retry state only when we're
- * going to use it. This assumes ath_hal_setuptxdesc
- * initializes the descriptors (so we don't have to)
- * when the hardware supports multi-rate retry and
- * we don't use it.
- */
- if (ismrr)
- ath_rate_setupxtxdesc(sc, an, ds, shortPreamble, rix);
-
- ath_tx_handoff(sc, txq, bf);
- return 0;
-}
-
-/*
* Process completed xmit descriptors from the specified queue.
*/
static int
@@ -5414,11 +4777,23 @@ ath_calibrate(void *arg)
struct ifnet *ifp = sc->sc_ifp;
struct ieee80211com *ic = ifp->if_l2com;
HAL_BOOL longCal, isCalDone;
+ HAL_BOOL aniCal, shortCal = AH_FALSE;
int nextcal;
if (ic->ic_flags & IEEE80211_F_SCAN) /* defer, off channel */
goto restart;
longCal = (ticks - sc->sc_lastlongcal >= ath_longcalinterval*hz);
+ aniCal = (ticks - sc->sc_lastani >= ath_anicalinterval*hz/1000);
+ if (sc->sc_doresetcal)
+ shortCal = (ticks - sc->sc_lastshortcal >= ath_shortcalinterval*hz/1000);
+
+ DPRINTF(sc, ATH_DEBUG_CALIBRATE, "%s: shortCal=%d; longCal=%d; aniCal=%d\n", __func__, shortCal, longCal, aniCal);
+ if (aniCal) {
+ sc->sc_stats.ast_ani_cal++;
+ sc->sc_lastani = ticks;
+ ath_hal_ani_poll(ah, sc->sc_curchan);
+ }
+
if (longCal) {
sc->sc_stats.ast_per_cal++;
sc->sc_lastlongcal = ticks;
@@ -5439,21 +4814,29 @@ ath_calibrate(void *arg)
if (sc->sc_resetcal) {
(void) ath_hal_calreset(ah, sc->sc_curchan);
sc->sc_lastcalreset = ticks;
+ sc->sc_lastshortcal = ticks;
sc->sc_resetcal = 0;
+ sc->sc_doresetcal = AH_TRUE;
}
}
- if (ath_hal_calibrateN(ah, sc->sc_curchan, longCal, &isCalDone)) {
- if (longCal) {
- /*
- * Calibrate noise floor data again in case of change.
- */
- ath_hal_process_noisefloor(ah);
+
+ /* Only call if we're doing a short/long cal, not for ANI calibration */
+ if (shortCal || longCal) {
+ if (ath_hal_calibrateN(ah, sc->sc_curchan, longCal, &isCalDone)) {
+ if (longCal) {
+ /*
+ * Calibrate noise floor data again in case of change.
+ */
+ ath_hal_process_noisefloor(ah);
+ }
+ } else {
+ DPRINTF(sc, ATH_DEBUG_ANY,
+ "%s: calibration of channel %u failed\n",
+ __func__, sc->sc_curchan->ic_freq);
+ sc->sc_stats.ast_per_calfail++;
}
- } else {
- DPRINTF(sc, ATH_DEBUG_ANY,
- "%s: calibration of channel %u failed\n",
- __func__, sc->sc_curchan->ic_freq);
- sc->sc_stats.ast_per_calfail++;
+ if (shortCal)
+ sc->sc_lastshortcal = ticks;
}
if (!isCalDone) {
restart:
@@ -5465,16 +4848,23 @@ restart:
* work when operating as an AP to improve operation right
* after startup.
*/
- nextcal = (1000*ath_shortcalinterval)/hz;
+ sc->sc_lastshortcal = ticks;
+ nextcal = ath_shortcalinterval*hz/1000;
if (sc->sc_opmode != HAL_M_HOSTAP)
nextcal *= 10;
+ sc->sc_doresetcal = AH_TRUE;
} else {
+ /* nextcal should be the shortest time for next event */
nextcal = ath_longcalinterval*hz;
if (sc->sc_lastcalreset == 0)
sc->sc_lastcalreset = sc->sc_lastlongcal;
else if (ticks - sc->sc_lastcalreset >= ath_resetcalinterval*hz)
sc->sc_resetcal = 1; /* setup reset next trip */
+ sc->sc_doresetcal = AH_FALSE;
}
+ /* ANI calibration may occur more often than short/long/resetcal */
+ if (ath_anicalinterval > 0)
+ nextcal = MIN(nextcal, ath_anicalinterval*hz/1000);
if (nextcal != 0) {
DPRINTF(sc, ATH_DEBUG_CALIBRATE, "%s: next +%u (%sisCalDone)\n",
@@ -6055,65 +5445,6 @@ ath_setcurmode(struct ath_softc *sc, enum ieee80211_phymode mode)
#undef N
}
-#ifdef ATH_DEBUG
-static void
-ath_printrxbuf(struct ath_softc *sc, const struct ath_buf *bf,
- u_int ix, int done)
-{
- const struct ath_rx_status *rs = &bf->bf_status.ds_rxstat;
- struct ath_hal *ah = sc->sc_ah;
- const struct ath_desc *ds;
- int i;
-
- for (i = 0, ds = bf->bf_desc; i < bf->bf_nseg; i++, ds++) {
- printf("R[%2u] (DS.V:%p DS.P:%p) L:%08x D:%08x%s\n"
- " %08x %08x %08x %08x\n",
- ix, ds, (const struct ath_desc *)bf->bf_daddr + i,
- ds->ds_link, ds->ds_data,
- !done ? "" : (rs->rs_status == 0) ? " *" : " !",
- ds->ds_ctl0, ds->ds_ctl1,
- ds->ds_hw[0], ds->ds_hw[1]);
- if (ah->ah_magic == 0x20065416) {
- printf(" %08x %08x %08x %08x %08x %08x %08x\n",
- ds->ds_hw[2], ds->ds_hw[3], ds->ds_hw[4],
- ds->ds_hw[5], ds->ds_hw[6], ds->ds_hw[7],
- ds->ds_hw[8]);
- }
- }
-}
-
-static void
-ath_printtxbuf(struct ath_softc *sc, const struct ath_buf *bf,
- u_int qnum, u_int ix, int done)
-{
- const struct ath_tx_status *ts = &bf->bf_status.ds_txstat;
- struct ath_hal *ah = sc->sc_ah;
- const struct ath_desc *ds;
- int i;
-
- printf("Q%u[%3u]", qnum, ix);
- for (i = 0, ds = bf->bf_desc; i < bf->bf_nseg; i++, ds++) {
- printf(" (DS.V:%p DS.P:%p) L:%08x D:%08x F:04%x%s\n"
- " %08x %08x %08x %08x %08x %08x\n",
- ds, (const struct ath_desc *)bf->bf_daddr + i,
- ds->ds_link, ds->ds_data, bf->bf_txflags,
- !done ? "" : (ts->ts_status == 0) ? " *" : " !",
- ds->ds_ctl0, ds->ds_ctl1,
- ds->ds_hw[0], ds->ds_hw[1], ds->ds_hw[2], ds->ds_hw[3]);
- if (ah->ah_magic == 0x20065416) {
- printf(" %08x %08x %08x %08x %08x %08x %08x %08x\n",
- ds->ds_hw[4], ds->ds_hw[5], ds->ds_hw[6],
- ds->ds_hw[7], ds->ds_hw[8], ds->ds_hw[9],
- ds->ds_hw[10],ds->ds_hw[11]);
- printf(" %08x %08x %08x %08x %08x %08x %08x %08x\n",
- ds->ds_hw[12],ds->ds_hw[13],ds->ds_hw[14],
- ds->ds_hw[15],ds->ds_hw[16],ds->ds_hw[17],
- ds->ds_hw[18], ds->ds_hw[19]);
- }
- }
-}
-#endif /* ATH_DEBUG */
-
static void
ath_watchdog(void *arg)
{
@@ -6565,10 +5896,10 @@ ath_sysctlattach(struct ath_softc *sc)
struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev);
struct ath_hal *ah = sc->sc_ah;
- SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"countrycode", CTLFLAG_RD, &sc->sc_eecc, 0,
"EEPROM country code");
- SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"regdomain", CTLFLAG_RD, &sc->sc_eerd, 0,
"EEPROM regdomain code");
#ifdef ATH_DEBUG
@@ -6591,10 +5922,10 @@ ath_sysctlattach(struct ath_softc *sc)
SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"ledpin", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
ath_sysctl_ledpin, "I", "GPIO pin connected to LED");
- SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"ledon", CTLFLAG_RW, &sc->sc_ledon, 0,
"setting to turn LED on");
- SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"ledidle", CTLFLAG_RW, &sc->sc_ledidle, 0,
"idle time for inactivity LED (ticks)");
SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
@@ -6608,7 +5939,7 @@ ath_sysctlattach(struct ath_softc *sc)
"diversity", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
ath_sysctl_diversity, "I", "antenna diversity");
sc->sc_txintrperiod = ATH_TXINTR_PERIOD;
- SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"txintrperiod", CTLFLAG_RW, &sc->sc_txintrperiod, 0,
"tx descriptor batching");
SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
@@ -6642,23 +5973,23 @@ ath_sysctlattach(struct ath_softc *sc)
ath_sysctl_intmit, "I", "interference mitigation");
}
sc->sc_monpass = HAL_RXERR_DECRYPT | HAL_RXERR_MIC;
- SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"monpass", CTLFLAG_RW, &sc->sc_monpass, 0,
"mask of error frames to pass when monitoring");
#ifdef IEEE80211_SUPPORT_TDMA
if (ath_hal_macversion(ah) > 0x78) {
sc->sc_tdmadbaprep = 2;
- SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"dbaprep", CTLFLAG_RW, &sc->sc_tdmadbaprep, 0,
"TDMA DBA preparation time");
sc->sc_tdmaswbaprep = 10;
- SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"swbaprep", CTLFLAG_RW, &sc->sc_tdmaswbaprep, 0,
"TDMA SWBA preparation time");
- SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"guardtime", CTLFLAG_RW, &sc->sc_tdmaguard, 0,
"TDMA slot guard time");
- SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"superframe", CTLFLAG_RD, &sc->sc_tdmabintval, 0,
"TDMA calculated super frame");
SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
@@ -6668,276 +5999,6 @@ ath_sysctlattach(struct ath_softc *sc)
#endif
}
-static int
-ath_tx_raw_start(struct ath_softc *sc, struct ieee80211_node *ni,
- struct ath_buf *bf, struct mbuf *m0,
- const struct ieee80211_bpf_params *params)
-{
- struct ifnet *ifp = sc->sc_ifp;
- struct ieee80211com *ic = ifp->if_l2com;
- struct ath_hal *ah = sc->sc_ah;
- struct ieee80211vap *vap = ni->ni_vap;
- int error, ismcast, ismrr;
- int keyix, hdrlen, pktlen, try0, txantenna;
- u_int8_t rix, cix, txrate, ctsrate, rate1, rate2, rate3;
- struct ieee80211_frame *wh;
- u_int flags, ctsduration;
- HAL_PKT_TYPE atype;
- const HAL_RATE_TABLE *rt;
- struct ath_desc *ds;
- u_int pri;
-
- wh = mtod(m0, struct ieee80211_frame *);
- ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1);
- hdrlen = ieee80211_anyhdrsize(wh);
- /*
- * Packet length must not include any
- * pad bytes; deduct them here.
- */
- /* XXX honor IEEE80211_BPF_DATAPAD */
- pktlen = m0->m_pkthdr.len - (hdrlen & 3) + IEEE80211_CRC_LEN;
-
- if (params->ibp_flags & IEEE80211_BPF_CRYPTO) {
- const struct ieee80211_cipher *cip;
- struct ieee80211_key *k;
-
- /*
- * Construct the 802.11 header+trailer for an encrypted
- * frame. The only reason this can fail is because of an
- * unknown or unsupported cipher/key type.
- */
- k = ieee80211_crypto_encap(ni, m0);
- if (k == NULL) {
- /*
- * This can happen when the key is yanked after the
- * frame was queued. Just discard the frame; the
- * 802.11 layer counts failures and provides
- * debugging/diagnostics.
- */
- ath_freetx(m0);
- return EIO;
- }
- /*
- * Adjust the packet + header lengths for the crypto
- * additions and calculate the h/w key index. When
- * a s/w mic is done the frame will have had any mic
- * added to it prior to entry so m0->m_pkthdr.len will
- * account for it. Otherwise we need to add it to the
- * packet length.
- */
- cip = k->wk_cipher;
- hdrlen += cip->ic_header;
- pktlen += cip->ic_header + cip->ic_trailer;
- /* NB: frags always have any TKIP MIC done in s/w */
- if ((k->wk_flags & IEEE80211_KEY_SWMIC) == 0)
- pktlen += cip->ic_miclen;
- keyix = k->wk_keyix;
-
- /* packet header may have moved, reset our local pointer */
- wh = mtod(m0, struct ieee80211_frame *);
- } else if (ni->ni_ucastkey.wk_cipher == &ieee80211_cipher_none) {
- /*
- * Use station key cache slot, if assigned.
- */
- keyix = ni->ni_ucastkey.wk_keyix;
- if (keyix == IEEE80211_KEYIX_NONE)
- keyix = HAL_TXKEYIX_INVALID;
- } else
- keyix = HAL_TXKEYIX_INVALID;
-
- error = ath_tx_dmasetup(sc, bf, m0);
- if (error != 0)
- return error;
- m0 = bf->bf_m; /* NB: may have changed */
- wh = mtod(m0, struct ieee80211_frame *);
- bf->bf_node = ni; /* NB: held reference */
-
- flags = HAL_TXDESC_CLRDMASK; /* XXX needed for crypto errs */
- flags |= HAL_TXDESC_INTREQ; /* force interrupt */
- if (params->ibp_flags & IEEE80211_BPF_RTS)
- flags |= HAL_TXDESC_RTSENA;
- else if (params->ibp_flags & IEEE80211_BPF_CTS)
- flags |= HAL_TXDESC_CTSENA;
- /* XXX leave ismcast to injector? */
- if ((params->ibp_flags & IEEE80211_BPF_NOACK) || ismcast)
- flags |= HAL_TXDESC_NOACK;
-
- rt = sc->sc_currates;
- KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode));
- rix = ath_tx_findrix(sc, params->ibp_rate0);
- txrate = rt->info[rix].rateCode;
- if (params->ibp_flags & IEEE80211_BPF_SHORTPRE)
- txrate |= rt->info[rix].shortPreamble;
- sc->sc_txrix = rix;
- try0 = params->ibp_try0;
- ismrr = (params->ibp_try1 != 0);
- txantenna = params->ibp_pri >> 2;
- if (txantenna == 0) /* XXX? */
- txantenna = sc->sc_txantenna;
- ctsduration = 0;
- if (flags & (HAL_TXDESC_CTSENA | HAL_TXDESC_RTSENA)) {
- cix = ath_tx_findrix(sc, params->ibp_ctsrate);
- ctsrate = rt->info[cix].rateCode;
- if (params->ibp_flags & IEEE80211_BPF_SHORTPRE) {
- ctsrate |= rt->info[cix].shortPreamble;
- if (flags & HAL_TXDESC_RTSENA) /* SIFS + CTS */
- ctsduration += rt->info[cix].spAckDuration;
- ctsduration += ath_hal_computetxtime(ah,
- rt, pktlen, rix, AH_TRUE);
- if ((flags & HAL_TXDESC_NOACK) == 0) /* SIFS + ACK */
- ctsduration += rt->info[rix].spAckDuration;
- } else {
- if (flags & HAL_TXDESC_RTSENA) /* SIFS + CTS */
- ctsduration += rt->info[cix].lpAckDuration;
- ctsduration += ath_hal_computetxtime(ah,
- rt, pktlen, rix, AH_FALSE);
- if ((flags & HAL_TXDESC_NOACK) == 0) /* SIFS + ACK */
- ctsduration += rt->info[rix].lpAckDuration;
- }
- ismrr = 0; /* XXX */
- } else
- ctsrate = 0;
- pri = params->ibp_pri & 3;
- /*
- * NB: we mark all packets as type PSPOLL so the h/w won't
- * set the sequence number, duration, etc.
- */
- atype = HAL_PKT_TYPE_PSPOLL;
-
- if (IFF_DUMPPKTS(sc, ATH_DEBUG_XMIT))
- ieee80211_dump_pkt(ic, mtod(m0, caddr_t), m0->m_len,
- sc->sc_hwmap[rix].ieeerate, -1);
-
- if (ieee80211_radiotap_active_vap(vap)) {
- u_int64_t tsf = ath_hal_gettsf64(ah);
-
- sc->sc_tx_th.wt_tsf = htole64(tsf);
- sc->sc_tx_th.wt_flags = sc->sc_hwmap[rix].txflags;
- if (wh->i_fc[1] & IEEE80211_FC1_WEP)
- sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_WEP;
- if (m0->m_flags & M_FRAG)
- sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_FRAG;
- sc->sc_tx_th.wt_rate = sc->sc_hwmap[rix].ieeerate;
- sc->sc_tx_th.wt_txpower = ni->ni_txpower;
- sc->sc_tx_th.wt_antenna = sc->sc_txantenna;
-
- ieee80211_radiotap_tx(vap, m0);
- }
-
- /*
- * Formulate first tx descriptor with tx controls.
- */
- ds = bf->bf_desc;
- /* XXX check return value? */
- ath_hal_setuptxdesc(ah, ds
- , pktlen /* packet length */
- , hdrlen /* header length */
- , atype /* Atheros packet type */
- , params->ibp_power /* txpower */
- , txrate, try0 /* series 0 rate/tries */
- , keyix /* key cache index */
- , txantenna /* antenna mode */
- , flags /* flags */
- , ctsrate /* rts/cts rate */
- , ctsduration /* rts/cts duration */
- );
- bf->bf_txflags = flags;
-
- if (ismrr) {
- rix = ath_tx_findrix(sc, params->ibp_rate1);
- rate1 = rt->info[rix].rateCode;
- if (params->ibp_flags & IEEE80211_BPF_SHORTPRE)
- rate1 |= rt->info[rix].shortPreamble;
- if (params->ibp_try2) {
- rix = ath_tx_findrix(sc, params->ibp_rate2);
- rate2 = rt->info[rix].rateCode;
- if (params->ibp_flags & IEEE80211_BPF_SHORTPRE)
- rate2 |= rt->info[rix].shortPreamble;
- } else
- rate2 = 0;
- if (params->ibp_try3) {
- rix = ath_tx_findrix(sc, params->ibp_rate3);
- rate3 = rt->info[rix].rateCode;
- if (params->ibp_flags & IEEE80211_BPF_SHORTPRE)
- rate3 |= rt->info[rix].shortPreamble;
- } else
- rate3 = 0;
- ath_hal_setupxtxdesc(ah, ds
- , rate1, params->ibp_try1 /* series 1 */
- , rate2, params->ibp_try2 /* series 2 */
- , rate3, params->ibp_try3 /* series 3 */
- );
- }
-
- /* NB: no buffered multicast in power save support */
- ath_tx_handoff(sc, sc->sc_ac2q[pri], bf);
- return 0;
-}
-
-static int
-ath_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
- const struct ieee80211_bpf_params *params)
-{
- struct ieee80211com *ic = ni->ni_ic;
- struct ifnet *ifp = ic->ic_ifp;
- struct ath_softc *sc = ifp->if_softc;
- struct ath_buf *bf;
- int error;
-
- if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || sc->sc_invalid) {
- DPRINTF(sc, ATH_DEBUG_XMIT, "%s: discard frame, %s", __func__,
- (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 ?
- "!running" : "invalid");
- m_freem(m);
- error = ENETDOWN;
- goto bad;
- }
- /*
- * Grab a TX buffer and associated resources.
- */
- bf = ath_getbuf(sc);
- if (bf == NULL) {
- sc->sc_stats.ast_tx_nobuf++;
- m_freem(m);
- error = ENOBUFS;
- goto bad;
- }
-
- if (params == NULL) {
- /*
- * Legacy path; interpret frame contents to decide
- * precisely how to send the frame.
- */
- if (ath_tx_start(sc, ni, bf, m)) {
- error = EIO; /* XXX */
- goto bad2;
- }
- } else {
- /*
- * Caller supplied explicit parameters to use in
- * sending the frame.
- */
- if (ath_tx_raw_start(sc, ni, bf, m, params)) {
- error = EIO; /* XXX */
- goto bad2;
- }
- }
- sc->sc_wd_timer = 5;
- ifp->if_opackets++;
- sc->sc_stats.ast_tx_raw++;
-
- return 0;
-bad2:
- ATH_TXBUF_LOCK(sc);
- STAILQ_INSERT_HEAD(&sc->sc_txbuf, bf, bf_list);
- ATH_TXBUF_UNLOCK(sc);
-bad:
- ifp->if_oerrors++;
- sc->sc_stats.ast_tx_raw_fail++;
- ieee80211_free_node(ni);
- return error;
-}
-
/*
* Announce various information on device/driver attach.
*/
@@ -7349,6 +6410,23 @@ ath_sysctl_clearstats(SYSCTL_HANDLER_ARGS)
}
static void
+ath_sysctl_stats_attach_rxphyerr(struct ath_softc *sc, struct sysctl_oid_list *parent)
+{
+ struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev);
+ struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev);
+ struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree);
+ int i;
+ char sn[8];
+
+ tree = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "rx_phy_err", CTLFLAG_RD, NULL, "Per-code RX PHY Errors");
+ child = SYSCTL_CHILDREN(tree);
+ for (i = 0; i < 64; i++) {
+ snprintf(sn, sizeof(sn), "%d", i);
+ SYSCTL_ADD_UINT(ctx, child, OID_AUTO, sn, CTLFLAG_RD, &sc->sc_stats.ast_rx_phy[i], 0, "");
+ }
+}
+
+static void
ath_sysctl_stats_attach(struct ath_softc *sc)
{
struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev);
@@ -7515,4 +6593,18 @@ ath_sysctl_stats_attach(struct ath_softc *sc)
&sc->sc_stats.ast_tx_nofrag, 0, "tx dropped 'cuz no ath frag buffer");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_be_missed", CTLFLAG_RD,
&sc->sc_stats.ast_be_missed, 0, "number of -missed- beacons");
+ SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_ani_cal", CTLFLAG_RD,
+ &sc->sc_stats.ast_ani_cal, 0, "number of ANI polls");
+ SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_rx_agg", CTLFLAG_RD,
+ &sc->sc_stats.ast_rx_agg, 0, "number of aggregate frames received");
+
+ SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_rx_halfgi", CTLFLAG_RD, &sc->sc_stats.ast_rx_halfgi, 0, "");
+ SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_rx_2040", CTLFLAG_RD, &sc->sc_stats.ast_rx_2040, 0, "");
+ SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_rx_pre_crc_err", CTLFLAG_RD, &sc->sc_stats.ast_rx_pre_crc_err, 0, "");
+ SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_rx_post_crc_err", CTLFLAG_RD, &sc->sc_stats.ast_rx_post_crc_err, 0, "");
+ SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_rx_decrypt_busy_err", CTLFLAG_RD, &sc->sc_stats.ast_rx_decrypt_busy_err, 0, "");
+ SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_rx_hi_rx_chain", CTLFLAG_RD, &sc->sc_stats.ast_rx_hi_rx_chain, 0, "");
+
+ /* Attach the RX phy error array */
+ ath_sysctl_stats_attach_rxphyerr(sc, child);
}
OpenPOWER on IntegriCloud