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