1dd1de374Slin wang - Sun Microsystems - Beijing China /* 2*c0c93480Slin wang - Sun Microsystems - Beijing China * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 3dd1de374Slin wang - Sun Microsystems - Beijing China * Use is subject to license terms. 4dd1de374Slin wang - Sun Microsystems - Beijing China */ 5dd1de374Slin wang - Sun Microsystems - Beijing China 6dd1de374Slin wang - Sun Microsystems - Beijing China /* 7dd1de374Slin wang - Sun Microsystems - Beijing China * Copyright (c) 2008 Atheros Communications Inc. 8dd1de374Slin wang - Sun Microsystems - Beijing China * 9dd1de374Slin wang - Sun Microsystems - Beijing China * Permission to use, copy, modify, and/or distribute this software for any 10dd1de374Slin wang - Sun Microsystems - Beijing China * purpose with or without fee is hereby granted, provided that the above 11dd1de374Slin wang - Sun Microsystems - Beijing China * copyright notice and this permission notice appear in all copies. 12dd1de374Slin wang - Sun Microsystems - Beijing China * 13dd1de374Slin wang - Sun Microsystems - Beijing China * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 14dd1de374Slin wang - Sun Microsystems - Beijing China * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 15dd1de374Slin wang - Sun Microsystems - Beijing China * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 16dd1de374Slin wang - Sun Microsystems - Beijing China * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 17dd1de374Slin wang - Sun Microsystems - Beijing China * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 18dd1de374Slin wang - Sun Microsystems - Beijing China * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 19dd1de374Slin wang - Sun Microsystems - Beijing China * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 20dd1de374Slin wang - Sun Microsystems - Beijing China */ 21dd1de374Slin wang - Sun Microsystems - Beijing China 22dd1de374Slin wang - Sun Microsystems - Beijing China #include <sys/param.h> 23dd1de374Slin wang - Sun Microsystems - Beijing China #include <sys/strsun.h> 24dd1de374Slin wang - Sun Microsystems - Beijing China #include <inet/common.h> 25dd1de374Slin wang - Sun Microsystems - Beijing China #include <inet/nd.h> 26dd1de374Slin wang - Sun Microsystems - Beijing China #include <inet/mi.h> 27dd1de374Slin wang - Sun Microsystems - Beijing China #include <inet/wifi_ioctl.h> 28dd1de374Slin wang - Sun Microsystems - Beijing China 29dd1de374Slin wang - Sun Microsystems - Beijing China #include "arn_core.h" 30dd1de374Slin wang - Sun Microsystems - Beijing China 31dd1de374Slin wang - Sun Microsystems - Beijing China /* 32dd1de374Slin wang - Sun Microsystems - Beijing China * This function will modify certain transmit queue properties depending on 33dd1de374Slin wang - Sun Microsystems - Beijing China * the operating mode of the station (AP or AdHoc). Parameters are AIFS 34dd1de374Slin wang - Sun Microsystems - Beijing China * settings and channel width min/max 35dd1de374Slin wang - Sun Microsystems - Beijing China */ 36*c0c93480Slin wang - Sun Microsystems - Beijing China 37dd1de374Slin wang - Sun Microsystems - Beijing China static int 383ae945c3Slin wang - Sun Microsystems - Beijing China /* LINTED E_STATIC_UNUSED */ 39dd1de374Slin wang - Sun Microsystems - Beijing China arn_beaconq_config(struct arn_softc *sc) 40dd1de374Slin wang - Sun Microsystems - Beijing China { 41dd1de374Slin wang - Sun Microsystems - Beijing China struct ath_hal *ah = sc->sc_ah; 42dd1de374Slin wang - Sun Microsystems - Beijing China struct ath9k_tx_queue_info qi; 43dd1de374Slin wang - Sun Microsystems - Beijing China 44dd1de374Slin wang - Sun Microsystems - Beijing China (void) ath9k_hw_get_txq_props(ah, sc->sc_beaconq, &qi); 45dd1de374Slin wang - Sun Microsystems - Beijing China if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP) { 46dd1de374Slin wang - Sun Microsystems - Beijing China /* Always burst out beacon and CAB traffic. */ 47dd1de374Slin wang - Sun Microsystems - Beijing China qi.tqi_aifs = 1; 48dd1de374Slin wang - Sun Microsystems - Beijing China qi.tqi_cwmin = 0; 49dd1de374Slin wang - Sun Microsystems - Beijing China qi.tqi_cwmax = 0; 50dd1de374Slin wang - Sun Microsystems - Beijing China } else { 51dd1de374Slin wang - Sun Microsystems - Beijing China /* Adhoc mode; important thing is to use 2x cwmin. */ 52dd1de374Slin wang - Sun Microsystems - Beijing China qi.tqi_aifs = sc->sc_beacon_qi.tqi_aifs; 53dd1de374Slin wang - Sun Microsystems - Beijing China qi.tqi_cwmin = 2*sc->sc_beacon_qi.tqi_cwmin; 54dd1de374Slin wang - Sun Microsystems - Beijing China qi.tqi_cwmax = sc->sc_beacon_qi.tqi_cwmax; 55dd1de374Slin wang - Sun Microsystems - Beijing China } 56dd1de374Slin wang - Sun Microsystems - Beijing China 57dd1de374Slin wang - Sun Microsystems - Beijing China if (!ath9k_hw_set_txq_props(ah, sc->sc_beaconq, &qi)) { 58dd1de374Slin wang - Sun Microsystems - Beijing China arn_problem("unable to update h/w beacon queue parameters\n"); 59dd1de374Slin wang - Sun Microsystems - Beijing China return (0); 60dd1de374Slin wang - Sun Microsystems - Beijing China } else { 61dd1de374Slin wang - Sun Microsystems - Beijing China /* push to h/w */ 62dd1de374Slin wang - Sun Microsystems - Beijing China (void) ath9k_hw_resettxqueue(ah, sc->sc_beaconq); 63dd1de374Slin wang - Sun Microsystems - Beijing China return (1); 64dd1de374Slin wang - Sun Microsystems - Beijing China } 65dd1de374Slin wang - Sun Microsystems - Beijing China } 66dd1de374Slin wang - Sun Microsystems - Beijing China 67dd1de374Slin wang - Sun Microsystems - Beijing China /* 68dd1de374Slin wang - Sun Microsystems - Beijing China * Associates the beacon frame buffer with a transmit descriptor. Will set 69dd1de374Slin wang - Sun Microsystems - Beijing China * up all required antenna switch parameters, rate codes, and channel flags. 70dd1de374Slin wang - Sun Microsystems - Beijing China * Beacons are always sent out at the lowest rate, and are not retried. 71dd1de374Slin wang - Sun Microsystems - Beijing China */ 72*c0c93480Slin wang - Sun Microsystems - Beijing China #ifdef ARN_IBSS 73dd1de374Slin wang - Sun Microsystems - Beijing China static void 74dd1de374Slin wang - Sun Microsystems - Beijing China arn_beacon_setup(struct arn_softc *sc, struct ath_buf *bf) 75dd1de374Slin wang - Sun Microsystems - Beijing China { 76dd1de374Slin wang - Sun Microsystems - Beijing China #define USE_SHPREAMBLE(_ic) \ 77dd1de374Slin wang - Sun Microsystems - Beijing China (((_ic)->ic_flags & (IEEE80211_F_SHPREAMBLE | IEEE80211_F_USEBARKER))\ 78dd1de374Slin wang - Sun Microsystems - Beijing China == IEEE80211_F_SHPREAMBLE) 79dd1de374Slin wang - Sun Microsystems - Beijing China mblk_t *mp = bf->bf_m; 80dd1de374Slin wang - Sun Microsystems - Beijing China struct ath_hal *ah = sc->sc_ah; 81dd1de374Slin wang - Sun Microsystems - Beijing China struct ath_desc *ds; 82dd1de374Slin wang - Sun Microsystems - Beijing China /* LINTED E_FUNC_SET_NOT_USED */ 83dd1de374Slin wang - Sun Microsystems - Beijing China int flags, antenna = 0; 84dd1de374Slin wang - Sun Microsystems - Beijing China struct ath_rate_table *rt; 85dd1de374Slin wang - Sun Microsystems - Beijing China uint8_t rix, rate; 86dd1de374Slin wang - Sun Microsystems - Beijing China struct ath9k_11n_rate_series series[4]; 87dd1de374Slin wang - Sun Microsystems - Beijing China int ctsrate = 0; 88dd1de374Slin wang - Sun Microsystems - Beijing China int ctsduration = 0; 89dd1de374Slin wang - Sun Microsystems - Beijing China 90dd1de374Slin wang - Sun Microsystems - Beijing China /* set up descriptors */ 91dd1de374Slin wang - Sun Microsystems - Beijing China ds = bf->bf_desc; 92dd1de374Slin wang - Sun Microsystems - Beijing China 93dd1de374Slin wang - Sun Microsystems - Beijing China flags = ATH9K_TXDESC_NOACK; 94dd1de374Slin wang - Sun Microsystems - Beijing China if (sc->sc_ah->ah_opmode == ATH9K_M_IBSS && 95dd1de374Slin wang - Sun Microsystems - Beijing China (ah->ah_caps.hw_caps & ATH9K_HW_CAP_VEOL)) { 96dd1de374Slin wang - Sun Microsystems - Beijing China ds->ds_link = bf->bf_daddr; /* self-linked */ 97dd1de374Slin wang - Sun Microsystems - Beijing China flags |= ATH9K_TXDESC_VEOL; 98dd1de374Slin wang - Sun Microsystems - Beijing China /* 99dd1de374Slin wang - Sun Microsystems - Beijing China * Let hardware handle antenna switching. 100dd1de374Slin wang - Sun Microsystems - Beijing China */ 101dd1de374Slin wang - Sun Microsystems - Beijing China antenna = 0; 102dd1de374Slin wang - Sun Microsystems - Beijing China } else { 103dd1de374Slin wang - Sun Microsystems - Beijing China ds->ds_link = 0; 104dd1de374Slin wang - Sun Microsystems - Beijing China /* 105dd1de374Slin wang - Sun Microsystems - Beijing China * Switch antenna every 4 beacons. 106dd1de374Slin wang - Sun Microsystems - Beijing China * NB: assumes two antenna 107dd1de374Slin wang - Sun Microsystems - Beijing China */ 108dd1de374Slin wang - Sun Microsystems - Beijing China antenna = ((sc->ast_be_xmit / sc->sc_nbcnvaps) & 1 ? 2 : 1); 109dd1de374Slin wang - Sun Microsystems - Beijing China } 110dd1de374Slin wang - Sun Microsystems - Beijing China 111dd1de374Slin wang - Sun Microsystems - Beijing China ds->ds_data = bf->bf_dma.cookie.dmac_address; 112dd1de374Slin wang - Sun Microsystems - Beijing China /* 113dd1de374Slin wang - Sun Microsystems - Beijing China * Calculate rate code. 114dd1de374Slin wang - Sun Microsystems - Beijing China * XXX everything at min xmit rate 115dd1de374Slin wang - Sun Microsystems - Beijing China */ 116dd1de374Slin wang - Sun Microsystems - Beijing China rix = 0; 117dd1de374Slin wang - Sun Microsystems - Beijing China rt = sc->hw_rate_table[sc->sc_curmode]; 118dd1de374Slin wang - Sun Microsystems - Beijing China rate = rt->info[rix].ratecode; 119dd1de374Slin wang - Sun Microsystems - Beijing China if (sc->sc_flags & SC_OP_PREAMBLE_SHORT) 120dd1de374Slin wang - Sun Microsystems - Beijing China rate |= rt->info[rix].short_preamble; 121dd1de374Slin wang - Sun Microsystems - Beijing China 122dd1de374Slin wang - Sun Microsystems - Beijing China ath9k_hw_set11n_txdesc(ah, ds, 123dd1de374Slin wang - Sun Microsystems - Beijing China MBLKL(mp) + IEEE80211_CRC_LEN, /* frame length */ 124dd1de374Slin wang - Sun Microsystems - Beijing China ATH9K_PKT_TYPE_BEACON, /* Atheros packet type */ 125dd1de374Slin wang - Sun Microsystems - Beijing China MAX_RATE_POWER, /* FIXME */ 126dd1de374Slin wang - Sun Microsystems - Beijing China ATH9K_TXKEYIX_INVALID, /* no encryption */ 127dd1de374Slin wang - Sun Microsystems - Beijing China ATH9K_KEY_TYPE_CLEAR, /* no encryption */ 128dd1de374Slin wang - Sun Microsystems - Beijing China flags); /* no ack, veol for beacons */ 129dd1de374Slin wang - Sun Microsystems - Beijing China 130dd1de374Slin wang - Sun Microsystems - Beijing China /* NB: beacon's BufLen must be a multiple of 4 bytes */ 131dd1de374Slin wang - Sun Microsystems - Beijing China (void) ath9k_hw_filltxdesc(ah, ds, 132dd1de374Slin wang - Sun Microsystems - Beijing China roundup(MBLKL(mp), 4), /* buffer length */ 133dd1de374Slin wang - Sun Microsystems - Beijing China B_TRUE, /* first segment */ 134dd1de374Slin wang - Sun Microsystems - Beijing China B_TRUE, /* last segment */ 135dd1de374Slin wang - Sun Microsystems - Beijing China ds); /* first descriptor */ 136dd1de374Slin wang - Sun Microsystems - Beijing China 137dd1de374Slin wang - Sun Microsystems - Beijing China (void) memset(series, 0, sizeof (struct ath9k_11n_rate_series) * 4); 138dd1de374Slin wang - Sun Microsystems - Beijing China series[0].Tries = 1; 139dd1de374Slin wang - Sun Microsystems - Beijing China series[0].Rate = rate; 140dd1de374Slin wang - Sun Microsystems - Beijing China series[0].ChSel = sc->sc_tx_chainmask; 141dd1de374Slin wang - Sun Microsystems - Beijing China series[0].RateFlags = (ctsrate) ? ATH9K_RATESERIES_RTS_CTS : 0; 142dd1de374Slin wang - Sun Microsystems - Beijing China ath9k_hw_set11n_ratescenario(ah, ds, ds, 0, 143dd1de374Slin wang - Sun Microsystems - Beijing China ctsrate, ctsduration, series, 4, 0); 144dd1de374Slin wang - Sun Microsystems - Beijing China #undef USE_SHPREAMBLE 145dd1de374Slin wang - Sun Microsystems - Beijing China } 146*c0c93480Slin wang - Sun Microsystems - Beijing China #endif 147dd1de374Slin wang - Sun Microsystems - Beijing China 148dd1de374Slin wang - Sun Microsystems - Beijing China /* 149dd1de374Slin wang - Sun Microsystems - Beijing China * Startup beacon transmission for adhoc mode when they are sent entirely 150dd1de374Slin wang - Sun Microsystems - Beijing China * by the hardware using the self-linked descriptor + veol trick. 151dd1de374Slin wang - Sun Microsystems - Beijing China */ 152*c0c93480Slin wang - Sun Microsystems - Beijing China #ifdef ARN_IBSS 153dd1de374Slin wang - Sun Microsystems - Beijing China static void 154dd1de374Slin wang - Sun Microsystems - Beijing China arn_beacon_start_adhoc(struct arn_softc *sc) 155dd1de374Slin wang - Sun Microsystems - Beijing China 156dd1de374Slin wang - Sun Microsystems - Beijing China { 157dd1de374Slin wang - Sun Microsystems - Beijing China struct ath_buf *bf = list_head(&sc->sc_bcbuf_list); 158dd1de374Slin wang - Sun Microsystems - Beijing China struct ieee80211_node *in = bf->bf_in; 159dd1de374Slin wang - Sun Microsystems - Beijing China struct ieee80211com *ic = in->in_ic; 160dd1de374Slin wang - Sun Microsystems - Beijing China struct ath_hal *ah = sc->sc_ah; 161dd1de374Slin wang - Sun Microsystems - Beijing China mblk_t *mp; 162dd1de374Slin wang - Sun Microsystems - Beijing China 163dd1de374Slin wang - Sun Microsystems - Beijing China mp = bf->bf_m; 164dd1de374Slin wang - Sun Microsystems - Beijing China if (ieee80211_beacon_update(ic, bf->bf_in, &sc->asc_boff, mp, 0)) 165dd1de374Slin wang - Sun Microsystems - Beijing China bcopy(mp->b_rptr, bf->bf_dma.mem_va, MBLKL(mp)); 166dd1de374Slin wang - Sun Microsystems - Beijing China 167dd1de374Slin wang - Sun Microsystems - Beijing China /* Construct tx descriptor. */ 168dd1de374Slin wang - Sun Microsystems - Beijing China arn_beacon_setup(sc, bf); 169dd1de374Slin wang - Sun Microsystems - Beijing China 170dd1de374Slin wang - Sun Microsystems - Beijing China /* 171dd1de374Slin wang - Sun Microsystems - Beijing China * Stop any current dma and put the new frame on the queue. 172dd1de374Slin wang - Sun Microsystems - Beijing China * This should never fail since we check above that no frames 173dd1de374Slin wang - Sun Microsystems - Beijing China * are still pending on the queue. 174dd1de374Slin wang - Sun Microsystems - Beijing China */ 175dd1de374Slin wang - Sun Microsystems - Beijing China if (!ath9k_hw_stoptxdma(ah, sc->sc_beaconq)) { 176dd1de374Slin wang - Sun Microsystems - Beijing China arn_problem("ath: beacon queue %d did not stop?\n", 177dd1de374Slin wang - Sun Microsystems - Beijing China sc->sc_beaconq); 178dd1de374Slin wang - Sun Microsystems - Beijing China } 179dd1de374Slin wang - Sun Microsystems - Beijing China ARN_DMA_SYNC(bf->bf_dma, DDI_DMA_SYNC_FORDEV); 180dd1de374Slin wang - Sun Microsystems - Beijing China 181dd1de374Slin wang - Sun Microsystems - Beijing China /* NB: caller is known to have already stopped tx dma */ 182dd1de374Slin wang - Sun Microsystems - Beijing China (void) ath9k_hw_puttxbuf(ah, sc->sc_beaconq, bf->bf_daddr); 183dd1de374Slin wang - Sun Microsystems - Beijing China (void) ath9k_hw_txstart(ah, sc->sc_beaconq); 184dd1de374Slin wang - Sun Microsystems - Beijing China 185dd1de374Slin wang - Sun Microsystems - Beijing China ARN_DBG((ARN_DBG_BEACON, "arn: arn_bstuck_process(): " 186dd1de374Slin wang - Sun Microsystems - Beijing China "TXDP%u = %llx (%p)\n", sc->sc_beaconq, 187dd1de374Slin wang - Sun Microsystems - Beijing China ito64(bf->bf_daddr), bf->bf_desc)); 188dd1de374Slin wang - Sun Microsystems - Beijing China } 189*c0c93480Slin wang - Sun Microsystems - Beijing China #endif /* ARN_IBSS */ 190dd1de374Slin wang - Sun Microsystems - Beijing China 191dd1de374Slin wang - Sun Microsystems - Beijing China uint32_t 192dd1de374Slin wang - Sun Microsystems - Beijing China arn_beaconq_setup(struct ath_hal *ah) 193dd1de374Slin wang - Sun Microsystems - Beijing China { 194dd1de374Slin wang - Sun Microsystems - Beijing China struct ath9k_tx_queue_info qi; 195dd1de374Slin wang - Sun Microsystems - Beijing China 196dd1de374Slin wang - Sun Microsystems - Beijing China (void) memset(&qi, 0, sizeof (qi)); 197dd1de374Slin wang - Sun Microsystems - Beijing China qi.tqi_aifs = 1; 198dd1de374Slin wang - Sun Microsystems - Beijing China qi.tqi_cwmin = 0; 199dd1de374Slin wang - Sun Microsystems - Beijing China qi.tqi_cwmax = 0; 200dd1de374Slin wang - Sun Microsystems - Beijing China /* NB: don't enable any interrupts */ 201dd1de374Slin wang - Sun Microsystems - Beijing China return (ath9k_hw_setuptxqueue(ah, ATH9K_TX_QUEUE_BEACON, &qi)); 202dd1de374Slin wang - Sun Microsystems - Beijing China } 203dd1de374Slin wang - Sun Microsystems - Beijing China 204dd1de374Slin wang - Sun Microsystems - Beijing China int 205dd1de374Slin wang - Sun Microsystems - Beijing China arn_beacon_alloc(struct arn_softc *sc, struct ieee80211_node *in) 206dd1de374Slin wang - Sun Microsystems - Beijing China { 207dd1de374Slin wang - Sun Microsystems - Beijing China ieee80211com_t *ic = in->in_ic; 208dd1de374Slin wang - Sun Microsystems - Beijing China struct ath_buf *bf; 209dd1de374Slin wang - Sun Microsystems - Beijing China mblk_t *mp; 210dd1de374Slin wang - Sun Microsystems - Beijing China 211dd1de374Slin wang - Sun Microsystems - Beijing China mutex_enter(&sc->sc_bcbuflock); 212dd1de374Slin wang - Sun Microsystems - Beijing China bf = list_head(&sc->sc_bcbuf_list); 213dd1de374Slin wang - Sun Microsystems - Beijing China if (bf == NULL) { 214dd1de374Slin wang - Sun Microsystems - Beijing China arn_problem("arn: arn_beacon_alloc():" 215dd1de374Slin wang - Sun Microsystems - Beijing China "no dma buffers"); 216dd1de374Slin wang - Sun Microsystems - Beijing China mutex_exit(&sc->sc_bcbuflock); 217dd1de374Slin wang - Sun Microsystems - Beijing China return (ENOMEM); 218dd1de374Slin wang - Sun Microsystems - Beijing China } 219dd1de374Slin wang - Sun Microsystems - Beijing China 220dd1de374Slin wang - Sun Microsystems - Beijing China mp = ieee80211_beacon_alloc(ic, in, &sc->asc_boff); 221dd1de374Slin wang - Sun Microsystems - Beijing China if (mp == NULL) { 222dd1de374Slin wang - Sun Microsystems - Beijing China arn_problem("ath: arn_beacon_alloc():" 223dd1de374Slin wang - Sun Microsystems - Beijing China "cannot get mbuf\n"); 224dd1de374Slin wang - Sun Microsystems - Beijing China mutex_exit(&sc->sc_bcbuflock); 225dd1de374Slin wang - Sun Microsystems - Beijing China return (ENOMEM); 226dd1de374Slin wang - Sun Microsystems - Beijing China } 227dd1de374Slin wang - Sun Microsystems - Beijing China ASSERT(mp->b_cont == NULL); 228dd1de374Slin wang - Sun Microsystems - Beijing China bf->bf_m = mp; 229dd1de374Slin wang - Sun Microsystems - Beijing China bcopy(mp->b_rptr, bf->bf_dma.mem_va, MBLKL(mp)); 230dd1de374Slin wang - Sun Microsystems - Beijing China bf->bf_in = ieee80211_ref_node(in); 231dd1de374Slin wang - Sun Microsystems - Beijing China mutex_exit(&sc->sc_bcbuflock); 232dd1de374Slin wang - Sun Microsystems - Beijing China 233dd1de374Slin wang - Sun Microsystems - Beijing China return (0); 234dd1de374Slin wang - Sun Microsystems - Beijing China } 235dd1de374Slin wang - Sun Microsystems - Beijing China 236dd1de374Slin wang - Sun Microsystems - Beijing China 237dd1de374Slin wang - Sun Microsystems - Beijing China void 238dd1de374Slin wang - Sun Microsystems - Beijing China arn_beacon_return(struct arn_softc *sc) 239dd1de374Slin wang - Sun Microsystems - Beijing China { 240dd1de374Slin wang - Sun Microsystems - Beijing China struct ath_buf *bf; 241dd1de374Slin wang - Sun Microsystems - Beijing China 242dd1de374Slin wang - Sun Microsystems - Beijing China mutex_enter(&sc->sc_bcbuflock); 243dd1de374Slin wang - Sun Microsystems - Beijing China bf = list_head(&sc->sc_bcbuf_list); 244dd1de374Slin wang - Sun Microsystems - Beijing China while (bf != NULL) { 245dd1de374Slin wang - Sun Microsystems - Beijing China if (bf->bf_m != NULL) { 246dd1de374Slin wang - Sun Microsystems - Beijing China freemsg(bf->bf_m); 247dd1de374Slin wang - Sun Microsystems - Beijing China bf->bf_m = NULL; 248dd1de374Slin wang - Sun Microsystems - Beijing China } 249dd1de374Slin wang - Sun Microsystems - Beijing China if (bf->bf_in != NULL) { 250dd1de374Slin wang - Sun Microsystems - Beijing China ieee80211_free_node(bf->bf_in); 251dd1de374Slin wang - Sun Microsystems - Beijing China bf->bf_in = NULL; 252dd1de374Slin wang - Sun Microsystems - Beijing China } 253dd1de374Slin wang - Sun Microsystems - Beijing China bf = list_next(&sc->sc_bcbuf_list, bf); 254dd1de374Slin wang - Sun Microsystems - Beijing China } 255dd1de374Slin wang - Sun Microsystems - Beijing China mutex_exit(&sc->sc_bcbuflock); 256dd1de374Slin wang - Sun Microsystems - Beijing China } 257dd1de374Slin wang - Sun Microsystems - Beijing China 258dd1de374Slin wang - Sun Microsystems - Beijing China void 259dd1de374Slin wang - Sun Microsystems - Beijing China arn_beacon_config(struct arn_softc *sc) 260*c0c93480Slin wang - Sun Microsystems - Beijing China 261dd1de374Slin wang - Sun Microsystems - Beijing China { 262dd1de374Slin wang - Sun Microsystems - Beijing China struct ath_beacon_config conf; 263dd1de374Slin wang - Sun Microsystems - Beijing China ieee80211com_t *ic = (ieee80211com_t *)sc; 264dd1de374Slin wang - Sun Microsystems - Beijing China struct ieee80211_node *in = ic->ic_bss; 2653ae945c3Slin wang - Sun Microsystems - Beijing China 266*c0c93480Slin wang - Sun Microsystems - Beijing China /* New added */ 2673ae945c3Slin wang - Sun Microsystems - Beijing China struct ath9k_beacon_state bs; 2683ae945c3Slin wang - Sun Microsystems - Beijing China int dtimperiod, dtimcount, sleepduration; 2693ae945c3Slin wang - Sun Microsystems - Beijing China int cfpperiod, cfpcount; 2703ae945c3Slin wang - Sun Microsystems - Beijing China uint32_t nexttbtt = 0, intval, tsftu; 2713ae945c3Slin wang - Sun Microsystems - Beijing China uint64_t tsf; 272dd1de374Slin wang - Sun Microsystems - Beijing China 273dd1de374Slin wang - Sun Microsystems - Beijing China (void) memset(&conf, 0, sizeof (struct ath_beacon_config)); 274dd1de374Slin wang - Sun Microsystems - Beijing China 275dd1de374Slin wang - Sun Microsystems - Beijing China /* XXX fix me */ 276dd1de374Slin wang - Sun Microsystems - Beijing China conf.beacon_interval = in->in_intval ? 277dd1de374Slin wang - Sun Microsystems - Beijing China in->in_intval : ATH_DEFAULT_BINTVAL; 278*c0c93480Slin wang - Sun Microsystems - Beijing China ARN_DBG((ARN_DBG_BEACON, "arn: arn_beacon_config():" 279*c0c93480Slin wang - Sun Microsystems - Beijing China "conf.beacon_interval = %d\n", conf.beacon_interval)); 280dd1de374Slin wang - Sun Microsystems - Beijing China conf.listen_interval = 1; 281dd1de374Slin wang - Sun Microsystems - Beijing China conf.dtim_period = conf.beacon_interval; 282dd1de374Slin wang - Sun Microsystems - Beijing China conf.dtim_count = 1; 283dd1de374Slin wang - Sun Microsystems - Beijing China conf.bmiss_timeout = ATH_DEFAULT_BMISS_LIMIT * conf.beacon_interval; 284dd1de374Slin wang - Sun Microsystems - Beijing China 2853ae945c3Slin wang - Sun Microsystems - Beijing China (void) memset(&bs, 0, sizeof (bs)); 286dd1de374Slin wang - Sun Microsystems - Beijing China intval = conf.beacon_interval & ATH9K_BEACON_PERIOD; 287dd1de374Slin wang - Sun Microsystems - Beijing China 288dd1de374Slin wang - Sun Microsystems - Beijing China /* 289dd1de374Slin wang - Sun Microsystems - Beijing China * Setup dtim and cfp parameters according to 290dd1de374Slin wang - Sun Microsystems - Beijing China * last beacon we received (which may be none). 291dd1de374Slin wang - Sun Microsystems - Beijing China */ 292dd1de374Slin wang - Sun Microsystems - Beijing China dtimperiod = conf.dtim_period; 293dd1de374Slin wang - Sun Microsystems - Beijing China if (dtimperiod <= 0) /* NB: 0 if not known */ 294dd1de374Slin wang - Sun Microsystems - Beijing China dtimperiod = 1; 295dd1de374Slin wang - Sun Microsystems - Beijing China dtimcount = conf.dtim_count; 296dd1de374Slin wang - Sun Microsystems - Beijing China if (dtimcount >= dtimperiod) /* NB: sanity check */ 297dd1de374Slin wang - Sun Microsystems - Beijing China dtimcount = 0; 298dd1de374Slin wang - Sun Microsystems - Beijing China cfpperiod = 1; /* NB: no PCF support yet */ 299dd1de374Slin wang - Sun Microsystems - Beijing China cfpcount = 0; 300dd1de374Slin wang - Sun Microsystems - Beijing China 301dd1de374Slin wang - Sun Microsystems - Beijing China sleepduration = conf.listen_interval * intval; 302dd1de374Slin wang - Sun Microsystems - Beijing China if (sleepduration <= 0) 303dd1de374Slin wang - Sun Microsystems - Beijing China sleepduration = intval; 304dd1de374Slin wang - Sun Microsystems - Beijing China 305dd1de374Slin wang - Sun Microsystems - Beijing China /* 306dd1de374Slin wang - Sun Microsystems - Beijing China * Pull nexttbtt forward to reflect the current 307dd1de374Slin wang - Sun Microsystems - Beijing China * TSF and calculate dtim+cfp state for the result. 308dd1de374Slin wang - Sun Microsystems - Beijing China */ 3093ae945c3Slin wang - Sun Microsystems - Beijing China tsf = ath9k_hw_gettsf64(sc->sc_ah); 310dd1de374Slin wang - Sun Microsystems - Beijing China tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE; 311dd1de374Slin wang - Sun Microsystems - Beijing China do { 312dd1de374Slin wang - Sun Microsystems - Beijing China nexttbtt += intval; 313dd1de374Slin wang - Sun Microsystems - Beijing China if (--dtimcount < 0) { 314dd1de374Slin wang - Sun Microsystems - Beijing China dtimcount = dtimperiod - 1; 315dd1de374Slin wang - Sun Microsystems - Beijing China if (--cfpcount < 0) 316dd1de374Slin wang - Sun Microsystems - Beijing China cfpcount = cfpperiod - 1; 317dd1de374Slin wang - Sun Microsystems - Beijing China } 318dd1de374Slin wang - Sun Microsystems - Beijing China } while (nexttbtt < tsftu); 3193ae945c3Slin wang - Sun Microsystems - Beijing China 320dd1de374Slin wang - Sun Microsystems - Beijing China bs.bs_intval = intval; 321dd1de374Slin wang - Sun Microsystems - Beijing China bs.bs_nexttbtt = nexttbtt; 322dd1de374Slin wang - Sun Microsystems - Beijing China bs.bs_dtimperiod = dtimperiod*intval; 323dd1de374Slin wang - Sun Microsystems - Beijing China bs.bs_nextdtim = bs.bs_nexttbtt + dtimcount*intval; 324dd1de374Slin wang - Sun Microsystems - Beijing China bs.bs_cfpperiod = cfpperiod*bs.bs_dtimperiod; 325dd1de374Slin wang - Sun Microsystems - Beijing China bs.bs_cfpnext = bs.bs_nextdtim + cfpcount*bs.bs_dtimperiod; 326dd1de374Slin wang - Sun Microsystems - Beijing China bs.bs_cfpmaxduration = 0; 327dd1de374Slin wang - Sun Microsystems - Beijing China 328dd1de374Slin wang - Sun Microsystems - Beijing China /* 3293ae945c3Slin wang - Sun Microsystems - Beijing China * Calculate the number of consecutive beacons to miss* before taking 3303ae945c3Slin wang - Sun Microsystems - Beijing China * a BMISS interrupt. The configuration is specified in TU so we only 3313ae945c3Slin wang - Sun Microsystems - Beijing China * need calculate based on the beacon interval. Note that we clamp the 332dd1de374Slin wang - Sun Microsystems - Beijing China * result to at most 15 beacons. 333dd1de374Slin wang - Sun Microsystems - Beijing China */ 334dd1de374Slin wang - Sun Microsystems - Beijing China if (sleepduration > intval) { 335dd1de374Slin wang - Sun Microsystems - Beijing China bs.bs_bmissthreshold = conf.listen_interval * 336dd1de374Slin wang - Sun Microsystems - Beijing China ATH_DEFAULT_BMISS_LIMIT / 2; 337dd1de374Slin wang - Sun Microsystems - Beijing China } else { 3383ae945c3Slin wang - Sun Microsystems - Beijing China bs.bs_bmissthreshold = DIV_ROUND_UP(conf.bmiss_timeout, intval); 339dd1de374Slin wang - Sun Microsystems - Beijing China if (bs.bs_bmissthreshold > 15) 340dd1de374Slin wang - Sun Microsystems - Beijing China bs.bs_bmissthreshold = 15; 3413ae945c3Slin wang - Sun Microsystems - Beijing China else if (bs.bs_bmissthreshold == 0) 342dd1de374Slin wang - Sun Microsystems - Beijing China bs.bs_bmissthreshold = 1; 343dd1de374Slin wang - Sun Microsystems - Beijing China } 344dd1de374Slin wang - Sun Microsystems - Beijing China 345dd1de374Slin wang - Sun Microsystems - Beijing China /* 3463ae945c3Slin wang - Sun Microsystems - Beijing China * Calculate sleep duration. The configuration is given in ms. 3473ae945c3Slin wang - Sun Microsystems - Beijing China * We ensure a multiple of the beacon period is used. Also, if the sleep 3483ae945c3Slin wang - Sun Microsystems - Beijing China * duration is greater than the DTIM period then it makes senses 349dd1de374Slin wang - Sun Microsystems - Beijing China * to make it a multiple of that. 350dd1de374Slin wang - Sun Microsystems - Beijing China * 351dd1de374Slin wang - Sun Microsystems - Beijing China * XXX fixed at 100ms 352dd1de374Slin wang - Sun Microsystems - Beijing China */ 353dd1de374Slin wang - Sun Microsystems - Beijing China 3543ae945c3Slin wang - Sun Microsystems - Beijing China bs.bs_sleepduration = roundup(IEEE80211_MS_TO_TU(100), sleepduration); 355dd1de374Slin wang - Sun Microsystems - Beijing China if (bs.bs_sleepduration > bs.bs_dtimperiod) 356dd1de374Slin wang - Sun Microsystems - Beijing China bs.bs_sleepduration = bs.bs_dtimperiod; 357dd1de374Slin wang - Sun Microsystems - Beijing China 3583ae945c3Slin wang - Sun Microsystems - Beijing China /* TSF out of range threshold fixed at 1 second */ 3593ae945c3Slin wang - Sun Microsystems - Beijing China bs.bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD; 360dd1de374Slin wang - Sun Microsystems - Beijing China 3613ae945c3Slin wang - Sun Microsystems - Beijing China ARN_DBG((ARN_DBG_BEACON, "arn: arn_beacon_config(): " 362*c0c93480Slin wang - Sun Microsystems - Beijing China "tsf %llu " 363*c0c93480Slin wang - Sun Microsystems - Beijing China "tsf:tu %u " 364*c0c93480Slin wang - Sun Microsystems - Beijing China "intval %u " 365*c0c93480Slin wang - Sun Microsystems - Beijing China "nexttbtt %u " 366*c0c93480Slin wang - Sun Microsystems - Beijing China "dtim %u " 367*c0c93480Slin wang - Sun Microsystems - Beijing China "nextdtim %u " 368*c0c93480Slin wang - Sun Microsystems - Beijing China "bmiss %u " 369*c0c93480Slin wang - Sun Microsystems - Beijing China "sleep %u " 370*c0c93480Slin wang - Sun Microsystems - Beijing China "cfp:period %u " 371*c0c93480Slin wang - Sun Microsystems - Beijing China "maxdur %u " 372*c0c93480Slin wang - Sun Microsystems - Beijing China "next %u " 373*c0c93480Slin wang - Sun Microsystems - Beijing China "timoffset %u\n", 374*c0c93480Slin wang - Sun Microsystems - Beijing China (unsigned long long)tsf, tsftu, 375*c0c93480Slin wang - Sun Microsystems - Beijing China bs.bs_intval, 376*c0c93480Slin wang - Sun Microsystems - Beijing China bs.bs_nexttbtt, 377*c0c93480Slin wang - Sun Microsystems - Beijing China bs.bs_dtimperiod, 378*c0c93480Slin wang - Sun Microsystems - Beijing China bs.bs_nextdtim, 379*c0c93480Slin wang - Sun Microsystems - Beijing China bs.bs_bmissthreshold, 380*c0c93480Slin wang - Sun Microsystems - Beijing China bs.bs_sleepduration, 381*c0c93480Slin wang - Sun Microsystems - Beijing China bs.bs_cfpperiod, 382*c0c93480Slin wang - Sun Microsystems - Beijing China bs.bs_cfpmaxduration, 383*c0c93480Slin wang - Sun Microsystems - Beijing China bs.bs_cfpnext, 384*c0c93480Slin wang - Sun Microsystems - Beijing China bs.bs_timoffset)); 3853ae945c3Slin wang - Sun Microsystems - Beijing China 3863ae945c3Slin wang - Sun Microsystems - Beijing China /* Set the computed STA beacon timers */ 3873ae945c3Slin wang - Sun Microsystems - Beijing China 3883ae945c3Slin wang - Sun Microsystems - Beijing China (void) ath9k_hw_set_interrupts(sc->sc_ah, 0); 3893ae945c3Slin wang - Sun Microsystems - Beijing China ath9k_hw_set_sta_beacon_timers(sc->sc_ah, &bs); 390dd1de374Slin wang - Sun Microsystems - Beijing China sc->sc_imask |= ATH9K_INT_BMISS; 3913ae945c3Slin wang - Sun Microsystems - Beijing China (void) ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_imask); 392dd1de374Slin wang - Sun Microsystems - Beijing China } 393dd1de374Slin wang - Sun Microsystems - Beijing China 394dd1de374Slin wang - Sun Microsystems - Beijing China void 395dd1de374Slin wang - Sun Microsystems - Beijing China ath_beacon_sync(struct arn_softc *sc) 396dd1de374Slin wang - Sun Microsystems - Beijing China { 397dd1de374Slin wang - Sun Microsystems - Beijing China /* 398dd1de374Slin wang - Sun Microsystems - Beijing China * Resync beacon timers using the tsf of the 399dd1de374Slin wang - Sun Microsystems - Beijing China * beacon frame we just received. 400dd1de374Slin wang - Sun Microsystems - Beijing China */ 401dd1de374Slin wang - Sun Microsystems - Beijing China arn_beacon_config(sc); 402dd1de374Slin wang - Sun Microsystems - Beijing China sc->sc_flags |= SC_OP_BEACONS; 403dd1de374Slin wang - Sun Microsystems - Beijing China } 404dd1de374Slin wang - Sun Microsystems - Beijing China 405dd1de374Slin wang - Sun Microsystems - Beijing China void 406dd1de374Slin wang - Sun Microsystems - Beijing China arn_bmiss_proc(void *arg) 407dd1de374Slin wang - Sun Microsystems - Beijing China { 408dd1de374Slin wang - Sun Microsystems - Beijing China struct arn_softc *sc = (struct arn_softc *)arg; 409dd1de374Slin wang - Sun Microsystems - Beijing China ieee80211com_t *ic = (ieee80211com_t *)sc; 410dd1de374Slin wang - Sun Microsystems - Beijing China uint64_t tsf, lastrx; 411dd1de374Slin wang - Sun Microsystems - Beijing China uint_t bmisstimeout; 412dd1de374Slin wang - Sun Microsystems - Beijing China 413dd1de374Slin wang - Sun Microsystems - Beijing China if (ic->ic_opmode != IEEE80211_M_STA || 414dd1de374Slin wang - Sun Microsystems - Beijing China ic->ic_state != IEEE80211_S_RUN) { 415dd1de374Slin wang - Sun Microsystems - Beijing China return; 416dd1de374Slin wang - Sun Microsystems - Beijing China } 417dd1de374Slin wang - Sun Microsystems - Beijing China 418dd1de374Slin wang - Sun Microsystems - Beijing China ARN_LOCK(sc); 419dd1de374Slin wang - Sun Microsystems - Beijing China lastrx = sc->sc_lastrx; 420dd1de374Slin wang - Sun Microsystems - Beijing China tsf = ath9k_hw_gettsf64(sc->sc_ah); 421dd1de374Slin wang - Sun Microsystems - Beijing China bmisstimeout = ic->ic_bmissthreshold * ic->ic_bss->in_intval * 1024; 422dd1de374Slin wang - Sun Microsystems - Beijing China 423dd1de374Slin wang - Sun Microsystems - Beijing China ARN_DBG((ARN_DBG_BEACON, "arn_bmiss_proc():" 424dd1de374Slin wang - Sun Microsystems - Beijing China " tsf %llu, lastrx %llu (%lld), bmiss %u\n", 425dd1de374Slin wang - Sun Microsystems - Beijing China (unsigned long long)tsf, (unsigned long long)sc->sc_lastrx, 426dd1de374Slin wang - Sun Microsystems - Beijing China (long long)(tsf - lastrx), bmisstimeout)); 427dd1de374Slin wang - Sun Microsystems - Beijing China ARN_UNLOCK(sc); 428dd1de374Slin wang - Sun Microsystems - Beijing China 429dd1de374Slin wang - Sun Microsystems - Beijing China /* temp workaround */ 430*c0c93480Slin wang - Sun Microsystems - Beijing China if ((tsf - lastrx) > bmisstimeout) 431dd1de374Slin wang - Sun Microsystems - Beijing China ieee80211_beacon_miss(ic); 432dd1de374Slin wang - Sun Microsystems - Beijing China } 433