From owner-svn-src-all@FreeBSD.ORG Sun May 20 02:49:43 2012 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 51120106566C; Sun, 20 May 2012 02:49:43 +0000 (UTC) (envelope-from adrian@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 39B878FC08; Sun, 20 May 2012 02:49:43 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.4/8.14.4) with ESMTP id q4K2ngED061747; Sun, 20 May 2012 02:49:42 GMT (envelope-from adrian@svn.freebsd.org) Received: (from adrian@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id q4K2ngrP061738; Sun, 20 May 2012 02:49:42 GMT (envelope-from adrian@svn.freebsd.org) Message-Id: <201205200249.q4K2ngrP061738@svn.freebsd.org> From: Adrian Chadd Date: Sun, 20 May 2012 02:49:42 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r235679 - in head/sys: conf dev/ath modules/ath X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 20 May 2012 02:49:43 -0000 Author: adrian Date: Sun May 20 02:49:42 2012 New Revision: 235679 URL: http://svn.freebsd.org/changeset/base/235679 Log: Migrate the TDMA management functions out of if_ath.c into if_ath_tdma.c. There's some TX path TDMA code in if_ath_tx.c which should be migrated out, but first I should likely try and verify/fix/repair the TDMA support in 9.x and -HEAD. Added: head/sys/dev/ath/if_ath_beacon.h (contents, props changed) head/sys/dev/ath/if_ath_tdma.c (contents, props changed) head/sys/dev/ath/if_ath_tdma.h (contents, props changed) Modified: head/sys/conf/files head/sys/dev/ath/if_ath.c head/sys/dev/ath/if_ath_misc.h head/sys/dev/ath/if_ath_rx.c head/sys/modules/ath/Makefile Modified: head/sys/conf/files ============================================================================== --- head/sys/conf/files Sun May 20 02:43:54 2012 (r235678) +++ head/sys/conf/files Sun May 20 02:49:42 2012 (r235679) @@ -720,6 +720,8 @@ dev/ath/if_ath_tx.c optional ath \ compile-with "${NORMAL_C} -I$S/dev/ath" dev/ath/if_ath_tx_ht.c optional ath \ compile-with "${NORMAL_C} -I$S/dev/ath" +dev/ath/if_ath_tdma.c optional ath \ + compile-with "${NORMAL_C} -I$S/dev/ath" dev/ath/if_ath_sysctl.c optional ath \ compile-with "${NORMAL_C} -I$S/dev/ath" dev/ath/if_ath_rx.c optional ath \ Modified: head/sys/dev/ath/if_ath.c ============================================================================== --- head/sys/dev/ath/if_ath.c Sun May 20 02:43:54 2012 (r235678) +++ head/sys/dev/ath/if_ath.c Sun May 20 02:49:42 2012 (r235679) @@ -108,6 +108,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #ifdef ATH_TX99_DIAG @@ -159,8 +160,6 @@ static int ath_beacon_alloc(struct ath_s static void ath_beacon_update(struct ieee80211vap *, int item); static void ath_beacon_setup(struct ath_softc *, struct ath_buf *); static void ath_beacon_proc(void *, int); -static struct ath_buf *ath_beacon_generate(struct ath_softc *, - struct ieee80211vap *); static void ath_bstuck_proc(void *, int); static void ath_reset_proc(void *, int); static void ath_beacon_return(struct ath_softc *, struct ath_buf *); @@ -178,7 +177,6 @@ static void ath_node_getsignal(const str static void ath_txq_init(struct ath_softc *sc, struct ath_txq *, int); static struct ath_txq *ath_txq_setup(struct ath_softc*, int qtype, int subtype); 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_tx_proc_q0(void *, int); @@ -213,16 +211,10 @@ static void ath_announce(struct ath_soft static void ath_dfs_tasklet(void *, int); #ifdef IEEE80211_SUPPORT_TDMA -static void ath_tdma_settimers(struct ath_softc *sc, u_int32_t nexttbtt, - u_int32_t bintval); -static void ath_tdma_bintvalsetup(struct ath_softc *sc, - const struct ieee80211_tdma_state *tdma); -static void ath_tdma_config(struct ath_softc *sc, struct ieee80211vap *vap); -static void ath_tdma_update(struct ieee80211_node *ni, - const struct ieee80211_tdma_param *tdma, int); -static void ath_tdma_beacon_send(struct ath_softc *sc, - struct ieee80211vap *vap); +#include +#endif +#if 0 #define TDMA_EP_MULTIPLIER (1<<10) /* pow2 to optimize out * and / */ #define TDMA_LPF_LEN 6 #define TDMA_DUMMY_MARKER 0x127 @@ -263,7 +255,7 @@ SYSCTL_INT(_hw_ath, OID_AUTO, txbuf, CTL 0, "tx buffers allocated"); TUNABLE_INT("hw.ath.txbuf", &ath_txbuf); -static int ath_bstuck_threshold = 4; /* max missed beacons */ +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"); @@ -2621,7 +2613,7 @@ ath_beaconq_setup(struct ath_hal *ah) /* * Setup the transmit queue parameters for the beacon queue. */ -static int +int ath_beaconq_config(struct ath_softc *sc) { #define ATH_EXPONENT_TO_VALUE(v) ((1<<(v))-1) @@ -2976,7 +2968,7 @@ ath_beacon_proc(void *arg, int pending) } } -static struct ath_buf * +struct ath_buf * ath_beacon_generate(struct ath_softc *sc, struct ieee80211vap *vap) { struct ath_vap *avp = ATH_VAP(vap); @@ -3876,7 +3868,7 @@ ath_txq_update(struct ath_softc *sc, int /* * Callback from the 802.11 layer to update WME parameters. */ -static int +int ath_wme_update(struct ieee80211com *ic) { struct ath_softc *sc = ic->ic_ifp->if_softc; @@ -5650,357 +5642,6 @@ ath_announce(struct ath_softc *sc) if_printf(ifp, "using multicast key search\n"); } -#ifdef IEEE80211_SUPPORT_TDMA -static void -ath_tdma_settimers(struct ath_softc *sc, u_int32_t nexttbtt, u_int32_t bintval) -{ - struct ath_hal *ah = sc->sc_ah; - HAL_BEACON_TIMERS bt; - - bt.bt_intval = bintval | HAL_BEACON_ENA; - bt.bt_nexttbtt = nexttbtt; - bt.bt_nextdba = (nexttbtt<<3) - sc->sc_tdmadbaprep; - bt.bt_nextswba = (nexttbtt<<3) - sc->sc_tdmaswbaprep; - bt.bt_nextatim = nexttbtt+1; - /* Enables TBTT, DBA, SWBA timers by default */ - bt.bt_flags = 0; - ath_hal_beaconsettimers(ah, &bt); -} - -/* - * Calculate the beacon interval. This is periodic in the - * superframe for the bss. We assume each station is configured - * identically wrt transmit rate so the guard time we calculate - * above will be the same on all stations. Note we need to - * factor in the xmit time because the hardware will schedule - * a frame for transmit if the start of the frame is within - * the burst time. When we get hardware that properly kills - * frames in the PCU we can reduce/eliminate the guard time. - * - * Roundup to 1024 is so we have 1 TU buffer in the guard time - * to deal with the granularity of the nexttbtt timer. 11n MAC's - * with 1us timer granularity should allow us to reduce/eliminate - * this. - */ -static void -ath_tdma_bintvalsetup(struct ath_softc *sc, - const struct ieee80211_tdma_state *tdma) -{ - /* copy from vap state (XXX check all vaps have same value?) */ - sc->sc_tdmaslotlen = tdma->tdma_slotlen; - - sc->sc_tdmabintval = roundup((sc->sc_tdmaslotlen+sc->sc_tdmaguard) * - tdma->tdma_slotcnt, 1024); - sc->sc_tdmabintval >>= 10; /* TSF -> TU */ - if (sc->sc_tdmabintval & 1) - sc->sc_tdmabintval++; - - if (tdma->tdma_slot == 0) { - /* - * Only slot 0 beacons; other slots respond. - */ - sc->sc_imask |= HAL_INT_SWBA; - sc->sc_tdmaswba = 0; /* beacon immediately */ - } else { - /* XXX all vaps must be slot 0 or slot !0 */ - sc->sc_imask &= ~HAL_INT_SWBA; - } -} - -/* - * Max 802.11 overhead. This assumes no 4-address frames and - * the encapsulation done by ieee80211_encap (llc). We also - * include potential crypto overhead. - */ -#define IEEE80211_MAXOVERHEAD \ - (sizeof(struct ieee80211_qosframe) \ - + sizeof(struct llc) \ - + IEEE80211_ADDR_LEN \ - + IEEE80211_WEP_IVLEN \ - + IEEE80211_WEP_KIDLEN \ - + IEEE80211_WEP_CRCLEN \ - + IEEE80211_WEP_MICLEN \ - + IEEE80211_CRC_LEN) - -/* - * Setup initially for tdma operation. Start the beacon - * timers and enable SWBA if we are slot 0. Otherwise - * we wait for slot 0 to arrive so we can sync up before - * starting to transmit. - */ -static void -ath_tdma_config(struct ath_softc *sc, struct ieee80211vap *vap) -{ - struct ath_hal *ah = sc->sc_ah; - struct ifnet *ifp = sc->sc_ifp; - struct ieee80211com *ic = ifp->if_l2com; - const struct ieee80211_txparam *tp; - const struct ieee80211_tdma_state *tdma = NULL; - int rix; - - if (vap == NULL) { - vap = TAILQ_FIRST(&ic->ic_vaps); /* XXX */ - if (vap == NULL) { - if_printf(ifp, "%s: no vaps?\n", __func__); - return; - } - } - /* XXX should take a locked ref to iv_bss */ - tp = vap->iv_bss->ni_txparms; - /* - * Calculate the guard time for each slot. This is the - * time to send a maximal-size frame according to the - * fixed/lowest transmit rate. Note that the interface - * mtu does not include the 802.11 overhead so we must - * tack that on (ath_hal_computetxtime includes the - * preamble and plcp in it's calculation). - */ - tdma = vap->iv_tdma; - if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) - rix = ath_tx_findrix(sc, tp->ucastrate); - else - rix = ath_tx_findrix(sc, tp->mcastrate); - /* XXX short preamble assumed */ - sc->sc_tdmaguard = ath_hal_computetxtime(ah, sc->sc_currates, - ifp->if_mtu + IEEE80211_MAXOVERHEAD, rix, AH_TRUE); - - ath_hal_intrset(ah, 0); - - ath_beaconq_config(sc); /* setup h/w beacon q */ - if (sc->sc_setcca) - ath_hal_setcca(ah, AH_FALSE); /* disable CCA */ - ath_tdma_bintvalsetup(sc, tdma); /* calculate beacon interval */ - ath_tdma_settimers(sc, sc->sc_tdmabintval, - sc->sc_tdmabintval | HAL_BEACON_RESET_TSF); - sc->sc_syncbeacon = 0; - - sc->sc_avgtsfdeltap = TDMA_DUMMY_MARKER; - sc->sc_avgtsfdeltam = TDMA_DUMMY_MARKER; - - ath_hal_intrset(ah, sc->sc_imask); - - DPRINTF(sc, ATH_DEBUG_TDMA, "%s: slot %u len %uus cnt %u " - "bsched %u guard %uus bintval %u TU dba prep %u\n", __func__, - tdma->tdma_slot, tdma->tdma_slotlen, tdma->tdma_slotcnt, - tdma->tdma_bintval, sc->sc_tdmaguard, sc->sc_tdmabintval, - sc->sc_tdmadbaprep); -} - -/* - * Update tdma operation. Called from the 802.11 layer - * when a beacon is received from the TDMA station operating - * in the slot immediately preceding us in the bss. Use - * the rx timestamp for the beacon frame to update our - * beacon timers so we follow their schedule. Note that - * by using the rx timestamp we implicitly include the - * propagation delay in our schedule. - */ -static void -ath_tdma_update(struct ieee80211_node *ni, - const struct ieee80211_tdma_param *tdma, int changed) -{ -#define TSF_TO_TU(_h,_l) \ - ((((u_int32_t)(_h)) << 22) | (((u_int32_t)(_l)) >> 10)) -#define TU_TO_TSF(_tu) (((u_int64_t)(_tu)) << 10) - struct ieee80211vap *vap = ni->ni_vap; - struct ieee80211com *ic = ni->ni_ic; - struct ath_softc *sc = ic->ic_ifp->if_softc; - struct ath_hal *ah = sc->sc_ah; - const HAL_RATE_TABLE *rt = sc->sc_currates; - u_int64_t tsf, rstamp, nextslot, nexttbtt; - u_int32_t txtime, nextslottu; - int32_t tudelta, tsfdelta; - const struct ath_rx_status *rs; - int rix; - - sc->sc_stats.ast_tdma_update++; - - /* - * Check for and adopt configuration changes. - */ - if (changed != 0) { - const struct ieee80211_tdma_state *ts = vap->iv_tdma; - - ath_tdma_bintvalsetup(sc, ts); - if (changed & TDMA_UPDATE_SLOTLEN) - ath_wme_update(ic); - - DPRINTF(sc, ATH_DEBUG_TDMA, - "%s: adopt slot %u slotcnt %u slotlen %u us " - "bintval %u TU\n", __func__, - ts->tdma_slot, ts->tdma_slotcnt, ts->tdma_slotlen, - sc->sc_tdmabintval); - - /* XXX right? */ - ath_hal_intrset(ah, sc->sc_imask); - /* NB: beacon timers programmed below */ - } - - /* extend rx timestamp to 64 bits */ - rs = sc->sc_lastrs; - tsf = ath_hal_gettsf64(ah); - rstamp = ath_extend_tsf(sc, rs->rs_tstamp, tsf); - /* - * The rx timestamp is set by the hardware on completing - * reception (at the point where the rx descriptor is DMA'd - * to the host). To find the start of our next slot we - * must adjust this time by the time required to send - * the packet just received. - */ - rix = rt->rateCodeToIndex[rs->rs_rate]; - txtime = ath_hal_computetxtime(ah, rt, rs->rs_datalen, rix, - rt->info[rix].shortPreamble); - /* NB: << 9 is to cvt to TU and /2 */ - nextslot = (rstamp - txtime) + (sc->sc_tdmabintval << 9); - nextslottu = TSF_TO_TU(nextslot>>32, nextslot) & HAL_BEACON_PERIOD; - - /* - * Retrieve the hardware NextTBTT in usecs - * and calculate the difference between what the - * other station thinks and what we have programmed. This - * lets us figure how to adjust our timers to match. The - * adjustments are done by pulling the TSF forward and possibly - * rewriting the beacon timers. - */ - nexttbtt = ath_hal_getnexttbtt(ah); - tsfdelta = (int32_t)((nextslot % TU_TO_TSF(HAL_BEACON_PERIOD + 1)) - nexttbtt); - - DPRINTF(sc, ATH_DEBUG_TDMA_TIMER, - "tsfdelta %d avg +%d/-%d\n", tsfdelta, - TDMA_AVG(sc->sc_avgtsfdeltap), TDMA_AVG(sc->sc_avgtsfdeltam)); - - if (tsfdelta < 0) { - TDMA_SAMPLE(sc->sc_avgtsfdeltap, 0); - TDMA_SAMPLE(sc->sc_avgtsfdeltam, -tsfdelta); - tsfdelta = -tsfdelta % 1024; - nextslottu++; - } else if (tsfdelta > 0) { - TDMA_SAMPLE(sc->sc_avgtsfdeltap, tsfdelta); - TDMA_SAMPLE(sc->sc_avgtsfdeltam, 0); - tsfdelta = 1024 - (tsfdelta % 1024); - nextslottu++; - } else { - TDMA_SAMPLE(sc->sc_avgtsfdeltap, 0); - TDMA_SAMPLE(sc->sc_avgtsfdeltam, 0); - } - tudelta = nextslottu - TSF_TO_TU(nexttbtt >> 32, nexttbtt); - - /* - * Copy sender's timetstamp into tdma ie so they can - * calculate roundtrip time. We submit a beacon frame - * below after any timer adjustment. The frame goes out - * at the next TBTT so the sender can calculate the - * roundtrip by inspecting the tdma ie in our beacon frame. - * - * NB: This tstamp is subtlely preserved when - * IEEE80211_BEACON_TDMA is marked (e.g. when the - * slot position changes) because ieee80211_add_tdma - * skips over the data. - */ - memcpy(ATH_VAP(vap)->av_boff.bo_tdma + - __offsetof(struct ieee80211_tdma_param, tdma_tstamp), - &ni->ni_tstamp.data, 8); -#if 0 - DPRINTF(sc, ATH_DEBUG_TDMA_TIMER, - "tsf %llu nextslot %llu (%d, %d) nextslottu %u nexttbtt %llu (%d)\n", - (unsigned long long) tsf, (unsigned long long) nextslot, - (int)(nextslot - tsf), tsfdelta, nextslottu, nexttbtt, tudelta); -#endif - /* - * Adjust the beacon timers only when pulling them forward - * or when going back by less than the beacon interval. - * Negative jumps larger than the beacon interval seem to - * cause the timers to stop and generally cause instability. - * This basically filters out jumps due to missed beacons. - */ - if (tudelta != 0 && (tudelta > 0 || -tudelta < sc->sc_tdmabintval)) { - ath_tdma_settimers(sc, nextslottu, sc->sc_tdmabintval); - sc->sc_stats.ast_tdma_timers++; - } - if (tsfdelta > 0) { - ath_hal_adjusttsf(ah, tsfdelta); - sc->sc_stats.ast_tdma_tsf++; - } - ath_tdma_beacon_send(sc, vap); /* prepare response */ -#undef TU_TO_TSF -#undef TSF_TO_TU -} - -/* - * Transmit a beacon frame at SWBA. Dynamic updates - * to the frame contents are done as needed. - */ -static void -ath_tdma_beacon_send(struct ath_softc *sc, struct ieee80211vap *vap) -{ - struct ath_hal *ah = sc->sc_ah; - struct ath_buf *bf; - int otherant; - - /* - * Check if the previous beacon has gone out. If - * not don't try to post another, skip this period - * and wait for the next. Missed beacons indicate - * a problem and should not occur. If we miss too - * many consecutive beacons reset the device. - */ - if (ath_hal_numtxpending(ah, sc->sc_bhalq) != 0) { - sc->sc_bmisscount++; - DPRINTF(sc, ATH_DEBUG_BEACON, - "%s: missed %u consecutive beacons\n", - __func__, sc->sc_bmisscount); - if (sc->sc_bmisscount >= ath_bstuck_threshold) - taskqueue_enqueue(sc->sc_tq, &sc->sc_bstucktask); - return; - } - if (sc->sc_bmisscount != 0) { - DPRINTF(sc, ATH_DEBUG_BEACON, - "%s: resume beacon xmit after %u misses\n", - __func__, sc->sc_bmisscount); - sc->sc_bmisscount = 0; - } - - /* - * Check recent per-antenna transmit statistics and flip - * the default antenna if noticeably more frames went out - * on the non-default antenna. - * XXX assumes 2 anntenae - */ - if (!sc->sc_diversity) { - otherant = sc->sc_defant & 1 ? 2 : 1; - if (sc->sc_ant_tx[otherant] > sc->sc_ant_tx[sc->sc_defant] + 2) - ath_setdefantenna(sc, otherant); - sc->sc_ant_tx[1] = sc->sc_ant_tx[2] = 0; - } - - bf = ath_beacon_generate(sc, vap); - if (bf != NULL) { - /* - * Stop any current dma and put the new frame on the queue. - * This should never fail since we check above that no frames - * are still pending on the queue. - */ - if (!ath_hal_stoptxdma(ah, sc->sc_bhalq)) { - DPRINTF(sc, ATH_DEBUG_ANY, - "%s: beacon queue %u did not stop?\n", - __func__, sc->sc_bhalq); - /* NB: the HAL still stops DMA, so proceed */ - } - ath_hal_puttxbuf(ah, sc->sc_bhalq, bf->bf_daddr); - ath_hal_txstart(ah, sc->sc_bhalq); - - sc->sc_stats.ast_be_xmit++; /* XXX per-vap? */ - - /* - * Record local TSF for our last send for use - * in arbitrating slot collisions. - */ - /* XXX should take a locked ref to iv_bss */ - vap->iv_bss->ni_tstamp.tsf = ath_hal_gettsf64(ah); - } -} -#endif /* IEEE80211_SUPPORT_TDMA */ - static void ath_dfs_tasklet(void *p, int npending) { Added: head/sys/dev/ath/if_ath_beacon.h ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/dev/ath/if_ath_beacon.h Sun May 20 02:49:42 2012 (r235679) @@ -0,0 +1,43 @@ +/*- + * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + * + * $FreeBSD$ + */ +#ifndef __IF_ATH_BEACON_H__ +#define __IF_ATH_BEACON_H__ + +extern int ath_bstuck_threshold; + +extern int ath_beaconq_config(struct ath_softc *sc); +extern void ath_beacon_config(struct ath_softc *sc, + struct ieee80211vap *vap); +extern struct ath_buf * ath_beacon_generate(struct ath_softc *sc, + struct ieee80211vap *vap); +extern int ath_wme_update(struct ieee80211com *ic); + +#endif Modified: head/sys/dev/ath/if_ath_misc.h ============================================================================== --- head/sys/dev/ath/if_ath_misc.h Sun May 20 02:43:54 2012 (r235678) +++ head/sys/dev/ath/if_ath_misc.h Sun May 20 02:49:42 2012 (r235679) @@ -80,6 +80,4 @@ extern void ath_setdefantenna(struct ath */ extern void ath_start(struct ifnet *ifp); -extern void ath_beacon_config(struct ath_softc *sc, struct ieee80211vap *vap); - #endif Modified: head/sys/dev/ath/if_ath_rx.c ============================================================================== --- head/sys/dev/ath/if_ath_rx.c Sun May 20 02:43:54 2012 (r235678) +++ head/sys/dev/ath/if_ath_rx.c Sun May 20 02:49:42 2012 (r235679) @@ -108,6 +108,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #ifdef ATH_TX99_DIAG Added: head/sys/dev/ath/if_ath_tdma.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/dev/ath/if_ath_tdma.c Sun May 20 02:49:42 2012 (r235679) @@ -0,0 +1,476 @@ +/*- + * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + */ + +#include +__FBSDID("$FreeBSD$"); + +/* + * Driver for the Atheros Wireless LAN controller. + * + * This software is derived from work of Atsushi Onoe; his contribution + * is greatly appreciated. + */ + +#include "opt_inet.h" +#include "opt_ath.h" +/* + * This is needed for register operations which are performed + * by the driver - eg, calls to ath_hal_gettsf32(). + * + * It's also required for any AH_DEBUG checks in here, eg the + * module dependencies. + */ +#include "opt_ah.h" +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* for mp_ncpus */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#ifdef IEEE80211_SUPPORT_SUPERG +#include +#endif +#ifdef IEEE80211_SUPPORT_TDMA +#include +#endif + +#include + +#ifdef INET +#include +#include +#endif + +#include +#include /* XXX for softled */ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef ATH_TX99_DIAG +#include +#endif + +#ifdef IEEE80211_SUPPORT_TDMA +#include + +static void ath_tdma_settimers(struct ath_softc *sc, u_int32_t nexttbtt, + u_int32_t bintval); +static void ath_tdma_bintvalsetup(struct ath_softc *sc, + const struct ieee80211_tdma_state *tdma); +#endif /* IEEE80211_SUPPORT_TDMA */ + +#ifdef IEEE80211_SUPPORT_TDMA +static void +ath_tdma_settimers(struct ath_softc *sc, u_int32_t nexttbtt, u_int32_t bintval) +{ + struct ath_hal *ah = sc->sc_ah; + HAL_BEACON_TIMERS bt; + + bt.bt_intval = bintval | HAL_BEACON_ENA; + bt.bt_nexttbtt = nexttbtt; + bt.bt_nextdba = (nexttbtt<<3) - sc->sc_tdmadbaprep; + bt.bt_nextswba = (nexttbtt<<3) - sc->sc_tdmaswbaprep; + bt.bt_nextatim = nexttbtt+1; + /* Enables TBTT, DBA, SWBA timers by default */ + bt.bt_flags = 0; + ath_hal_beaconsettimers(ah, &bt); +} + +/* + * Calculate the beacon interval. This is periodic in the + * superframe for the bss. We assume each station is configured + * identically wrt transmit rate so the guard time we calculate + * above will be the same on all stations. Note we need to + * factor in the xmit time because the hardware will schedule + * a frame for transmit if the start of the frame is within + * the burst time. When we get hardware that properly kills + * frames in the PCU we can reduce/eliminate the guard time. + * + * Roundup to 1024 is so we have 1 TU buffer in the guard time + * to deal with the granularity of the nexttbtt timer. 11n MAC's + * with 1us timer granularity should allow us to reduce/eliminate + * this. + */ +static void +ath_tdma_bintvalsetup(struct ath_softc *sc, + const struct ieee80211_tdma_state *tdma) +{ + /* copy from vap state (XXX check all vaps have same value?) */ + sc->sc_tdmaslotlen = tdma->tdma_slotlen; + + sc->sc_tdmabintval = roundup((sc->sc_tdmaslotlen+sc->sc_tdmaguard) * + tdma->tdma_slotcnt, 1024); + sc->sc_tdmabintval >>= 10; /* TSF -> TU */ + if (sc->sc_tdmabintval & 1) + sc->sc_tdmabintval++; + + if (tdma->tdma_slot == 0) { + /* + * Only slot 0 beacons; other slots respond. + */ + sc->sc_imask |= HAL_INT_SWBA; + sc->sc_tdmaswba = 0; /* beacon immediately */ + } else { + /* XXX all vaps must be slot 0 or slot !0 */ + sc->sc_imask &= ~HAL_INT_SWBA; + } +} + +/* + * Max 802.11 overhead. This assumes no 4-address frames and + * the encapsulation done by ieee80211_encap (llc). We also + * include potential crypto overhead. + */ +#define IEEE80211_MAXOVERHEAD \ + (sizeof(struct ieee80211_qosframe) \ + + sizeof(struct llc) \ + + IEEE80211_ADDR_LEN \ + + IEEE80211_WEP_IVLEN \ + + IEEE80211_WEP_KIDLEN \ + + IEEE80211_WEP_CRCLEN \ + + IEEE80211_WEP_MICLEN \ + + IEEE80211_CRC_LEN) + +/* + * Setup initially for tdma operation. Start the beacon + * timers and enable SWBA if we are slot 0. Otherwise + * we wait for slot 0 to arrive so we can sync up before + * starting to transmit. + */ +void +ath_tdma_config(struct ath_softc *sc, struct ieee80211vap *vap) +{ + struct ath_hal *ah = sc->sc_ah; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + const struct ieee80211_txparam *tp; + const struct ieee80211_tdma_state *tdma = NULL; + int rix; + + if (vap == NULL) { + vap = TAILQ_FIRST(&ic->ic_vaps); /* XXX */ + if (vap == NULL) { + if_printf(ifp, "%s: no vaps?\n", __func__); + return; + } + } + /* XXX should take a locked ref to iv_bss */ + tp = vap->iv_bss->ni_txparms; + /* + * Calculate the guard time for each slot. This is the + * time to send a maximal-size frame according to the + * fixed/lowest transmit rate. Note that the interface + * mtu does not include the 802.11 overhead so we must + * tack that on (ath_hal_computetxtime includes the + * preamble and plcp in it's calculation). + */ + tdma = vap->iv_tdma; + if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) + rix = ath_tx_findrix(sc, tp->ucastrate); + else + rix = ath_tx_findrix(sc, tp->mcastrate); + /* XXX short preamble assumed */ + sc->sc_tdmaguard = ath_hal_computetxtime(ah, sc->sc_currates, + ifp->if_mtu + IEEE80211_MAXOVERHEAD, rix, AH_TRUE); + + ath_hal_intrset(ah, 0); + + ath_beaconq_config(sc); /* setup h/w beacon q */ + if (sc->sc_setcca) + ath_hal_setcca(ah, AH_FALSE); /* disable CCA */ + ath_tdma_bintvalsetup(sc, tdma); /* calculate beacon interval */ + ath_tdma_settimers(sc, sc->sc_tdmabintval, + sc->sc_tdmabintval | HAL_BEACON_RESET_TSF); + sc->sc_syncbeacon = 0; + + sc->sc_avgtsfdeltap = TDMA_DUMMY_MARKER; + sc->sc_avgtsfdeltam = TDMA_DUMMY_MARKER; + + ath_hal_intrset(ah, sc->sc_imask); + + DPRINTF(sc, ATH_DEBUG_TDMA, "%s: slot %u len %uus cnt %u " + "bsched %u guard %uus bintval %u TU dba prep %u\n", __func__, + tdma->tdma_slot, tdma->tdma_slotlen, tdma->tdma_slotcnt, + tdma->tdma_bintval, sc->sc_tdmaguard, sc->sc_tdmabintval, + sc->sc_tdmadbaprep); +} + +/* + * Update tdma operation. Called from the 802.11 layer + * when a beacon is received from the TDMA station operating + * in the slot immediately preceding us in the bss. Use + * the rx timestamp for the beacon frame to update our + * beacon timers so we follow their schedule. Note that + * by using the rx timestamp we implicitly include the + * propagation delay in our schedule. + */ +void +ath_tdma_update(struct ieee80211_node *ni, + const struct ieee80211_tdma_param *tdma, int changed) +{ +#define TSF_TO_TU(_h,_l) \ + ((((u_int32_t)(_h)) << 22) | (((u_int32_t)(_l)) >> 10)) +#define TU_TO_TSF(_tu) (((u_int64_t)(_tu)) << 10) + struct ieee80211vap *vap = ni->ni_vap; + struct ieee80211com *ic = ni->ni_ic; + struct ath_softc *sc = ic->ic_ifp->if_softc; + struct ath_hal *ah = sc->sc_ah; + const HAL_RATE_TABLE *rt = sc->sc_currates; + u_int64_t tsf, rstamp, nextslot, nexttbtt; + u_int32_t txtime, nextslottu; + int32_t tudelta, tsfdelta; + const struct ath_rx_status *rs; + int rix; + + sc->sc_stats.ast_tdma_update++; + + /* + * Check for and adopt configuration changes. + */ + if (changed != 0) { + const struct ieee80211_tdma_state *ts = vap->iv_tdma; + + ath_tdma_bintvalsetup(sc, ts); + if (changed & TDMA_UPDATE_SLOTLEN) + ath_wme_update(ic); + + DPRINTF(sc, ATH_DEBUG_TDMA, + "%s: adopt slot %u slotcnt %u slotlen %u us " + "bintval %u TU\n", __func__, + ts->tdma_slot, ts->tdma_slotcnt, ts->tdma_slotlen, + sc->sc_tdmabintval); + + /* XXX right? */ + ath_hal_intrset(ah, sc->sc_imask); + /* NB: beacon timers programmed below */ + } + + /* extend rx timestamp to 64 bits */ + rs = sc->sc_lastrs; + tsf = ath_hal_gettsf64(ah); + rstamp = ath_extend_tsf(sc, rs->rs_tstamp, tsf); + /* + * The rx timestamp is set by the hardware on completing + * reception (at the point where the rx descriptor is DMA'd + * to the host). To find the start of our next slot we + * must adjust this time by the time required to send + * the packet just received. + */ + rix = rt->rateCodeToIndex[rs->rs_rate]; + txtime = ath_hal_computetxtime(ah, rt, rs->rs_datalen, rix, + rt->info[rix].shortPreamble); + /* NB: << 9 is to cvt to TU and /2 */ + nextslot = (rstamp - txtime) + (sc->sc_tdmabintval << 9); + nextslottu = TSF_TO_TU(nextslot>>32, nextslot) & HAL_BEACON_PERIOD; + + /* + * Retrieve the hardware NextTBTT in usecs + * and calculate the difference between what the + * other station thinks and what we have programmed. This + * lets us figure how to adjust our timers to match. The + * adjustments are done by pulling the TSF forward and possibly + * rewriting the beacon timers. + */ + nexttbtt = ath_hal_getnexttbtt(ah); + tsfdelta = (int32_t)((nextslot % TU_TO_TSF(HAL_BEACON_PERIOD + 1)) - nexttbtt); + + DPRINTF(sc, ATH_DEBUG_TDMA_TIMER, + "tsfdelta %d avg +%d/-%d\n", tsfdelta, + TDMA_AVG(sc->sc_avgtsfdeltap), TDMA_AVG(sc->sc_avgtsfdeltam)); + + if (tsfdelta < 0) { + TDMA_SAMPLE(sc->sc_avgtsfdeltap, 0); + TDMA_SAMPLE(sc->sc_avgtsfdeltam, -tsfdelta); + tsfdelta = -tsfdelta % 1024; + nextslottu++; + } else if (tsfdelta > 0) { + TDMA_SAMPLE(sc->sc_avgtsfdeltap, tsfdelta); + TDMA_SAMPLE(sc->sc_avgtsfdeltam, 0); + tsfdelta = 1024 - (tsfdelta % 1024); + nextslottu++; + } else { + TDMA_SAMPLE(sc->sc_avgtsfdeltap, 0); + TDMA_SAMPLE(sc->sc_avgtsfdeltam, 0); + } + tudelta = nextslottu - TSF_TO_TU(nexttbtt >> 32, nexttbtt); + + /* + * Copy sender's timetstamp into tdma ie so they can + * calculate roundtrip time. We submit a beacon frame + * below after any timer adjustment. The frame goes out + * at the next TBTT so the sender can calculate the + * roundtrip by inspecting the tdma ie in our beacon frame. + * + * NB: This tstamp is subtlely preserved when + * IEEE80211_BEACON_TDMA is marked (e.g. when the + * slot position changes) because ieee80211_add_tdma + * skips over the data. + */ + memcpy(ATH_VAP(vap)->av_boff.bo_tdma + + __offsetof(struct ieee80211_tdma_param, tdma_tstamp), + &ni->ni_tstamp.data, 8); +#if 0 + DPRINTF(sc, ATH_DEBUG_TDMA_TIMER, + "tsf %llu nextslot %llu (%d, %d) nextslottu %u nexttbtt %llu (%d)\n", + (unsigned long long) tsf, (unsigned long long) nextslot, + (int)(nextslot - tsf), tsfdelta, nextslottu, nexttbtt, tudelta); +#endif + /* + * Adjust the beacon timers only when pulling them forward + * or when going back by less than the beacon interval. + * Negative jumps larger than the beacon interval seem to + * cause the timers to stop and generally cause instability. + * This basically filters out jumps due to missed beacons. + */ + if (tudelta != 0 && (tudelta > 0 || -tudelta < sc->sc_tdmabintval)) { + ath_tdma_settimers(sc, nextslottu, sc->sc_tdmabintval); + sc->sc_stats.ast_tdma_timers++; + } + if (tsfdelta > 0) { + ath_hal_adjusttsf(ah, tsfdelta); + sc->sc_stats.ast_tdma_tsf++; + } + ath_tdma_beacon_send(sc, vap); /* prepare response */ +#undef TU_TO_TSF +#undef TSF_TO_TU +} + +/* + * Transmit a beacon frame at SWBA. Dynamic updates + * to the frame contents are done as needed. + */ +void +ath_tdma_beacon_send(struct ath_softc *sc, struct ieee80211vap *vap) +{ + struct ath_hal *ah = sc->sc_ah; + struct ath_buf *bf; + int otherant; + + /* + * Check if the previous beacon has gone out. If + * not don't try to post another, skip this period + * and wait for the next. Missed beacons indicate + * a problem and should not occur. If we miss too + * many consecutive beacons reset the device. + */ + if (ath_hal_numtxpending(ah, sc->sc_bhalq) != 0) { + sc->sc_bmisscount++; + DPRINTF(sc, ATH_DEBUG_BEACON, + "%s: missed %u consecutive beacons\n", + __func__, sc->sc_bmisscount); + if (sc->sc_bmisscount >= ath_bstuck_threshold) + taskqueue_enqueue(sc->sc_tq, &sc->sc_bstucktask); + return; + } + if (sc->sc_bmisscount != 0) { + DPRINTF(sc, ATH_DEBUG_BEACON, + "%s: resume beacon xmit after %u misses\n", + __func__, sc->sc_bmisscount); + sc->sc_bmisscount = 0; + } + + /* + * Check recent per-antenna transmit statistics and flip + * the default antenna if noticeably more frames went out + * on the non-default antenna. + * XXX assumes 2 anntenae + */ + if (!sc->sc_diversity) { + otherant = sc->sc_defant & 1 ? 2 : 1; + if (sc->sc_ant_tx[otherant] > sc->sc_ant_tx[sc->sc_defant] + 2) + ath_setdefantenna(sc, otherant); + sc->sc_ant_tx[1] = sc->sc_ant_tx[2] = 0; + } + + bf = ath_beacon_generate(sc, vap); + if (bf != NULL) { + /* + * Stop any current dma and put the new frame on the queue. + * This should never fail since we check above that no frames + * are still pending on the queue. + */ + if (!ath_hal_stoptxdma(ah, sc->sc_bhalq)) { + DPRINTF(sc, ATH_DEBUG_ANY, + "%s: beacon queue %u did not stop?\n", + __func__, sc->sc_bhalq); + /* NB: the HAL still stops DMA, so proceed */ + } + ath_hal_puttxbuf(ah, sc->sc_bhalq, bf->bf_daddr); + ath_hal_txstart(ah, sc->sc_bhalq); + + sc->sc_stats.ast_be_xmit++; /* XXX per-vap? */ + + /* + * Record local TSF for our last send for use + * in arbitrating slot collisions. + */ + /* XXX should take a locked ref to iv_bss */ + vap->iv_bss->ni_tstamp.tsf = ath_hal_gettsf64(ah); + } +} +#endif /* IEEE80211_SUPPORT_TDMA */ Added: head/sys/dev/ath/if_ath_tdma.h ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/dev/ath/if_ath_tdma.h Sun May 20 02:49:42 2012 (r235679) @@ -0,0 +1,55 @@ +/*- *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***