diff options
Diffstat (limited to 'sys/dev/ath/if_ath.c')
-rw-r--r-- | sys/dev/ath/if_ath.c | 1292 |
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); } |