1 /* 2 * Copyright 2009 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 * This function will modify certain transmit queue properties depending on 33 * the operating mode of the station (AP or AdHoc). Parameters are AIFS 34 * settings and channel width min/max 35 */ 36 static int 37 arn_beaconq_config(struct arn_softc *sc) 38 { 39 struct ath_hal *ah = sc->sc_ah; 40 struct ath9k_tx_queue_info qi; 41 42 (void) ath9k_hw_get_txq_props(ah, sc->sc_beaconq, &qi); 43 if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP) { 44 /* Always burst out beacon and CAB traffic. */ 45 qi.tqi_aifs = 1; 46 qi.tqi_cwmin = 0; 47 qi.tqi_cwmax = 0; 48 } else { 49 /* Adhoc mode; important thing is to use 2x cwmin. */ 50 qi.tqi_aifs = sc->sc_beacon_qi.tqi_aifs; 51 qi.tqi_cwmin = 2*sc->sc_beacon_qi.tqi_cwmin; 52 qi.tqi_cwmax = sc->sc_beacon_qi.tqi_cwmax; 53 } 54 55 if (!ath9k_hw_set_txq_props(ah, sc->sc_beaconq, &qi)) { 56 arn_problem("unable to update h/w beacon queue parameters\n"); 57 return (0); 58 } else { 59 /* push to h/w */ 60 (void) ath9k_hw_resettxqueue(ah, sc->sc_beaconq); 61 return (1); 62 } 63 } 64 65 /* 66 * Associates the beacon frame buffer with a transmit descriptor. Will set 67 * up all required antenna switch parameters, rate codes, and channel flags. 68 * Beacons are always sent out at the lowest rate, and are not retried. 69 */ 70 71 static void 72 arn_beacon_setup(struct arn_softc *sc, struct ath_buf *bf) 73 { 74 #define USE_SHPREAMBLE(_ic) \ 75 (((_ic)->ic_flags & (IEEE80211_F_SHPREAMBLE | IEEE80211_F_USEBARKER))\ 76 == IEEE80211_F_SHPREAMBLE) 77 mblk_t *mp = bf->bf_m; 78 struct ath_hal *ah = sc->sc_ah; 79 struct ath_desc *ds; 80 /* LINTED E_FUNC_SET_NOT_USED */ 81 int flags, antenna = 0; 82 struct ath_rate_table *rt; 83 uint8_t rix, rate; 84 struct ath9k_11n_rate_series series[4]; 85 int ctsrate = 0; 86 int ctsduration = 0; 87 88 /* set up descriptors */ 89 ds = bf->bf_desc; 90 91 flags = ATH9K_TXDESC_NOACK; 92 if (sc->sc_ah->ah_opmode == ATH9K_M_IBSS && 93 (ah->ah_caps.hw_caps & ATH9K_HW_CAP_VEOL)) { 94 ds->ds_link = bf->bf_daddr; /* self-linked */ 95 flags |= ATH9K_TXDESC_VEOL; 96 /* 97 * Let hardware handle antenna switching. 98 */ 99 antenna = 0; 100 } else { 101 ds->ds_link = 0; 102 /* 103 * Switch antenna every 4 beacons. 104 * NB: assumes two antenna 105 */ 106 antenna = ((sc->ast_be_xmit / sc->sc_nbcnvaps) & 1 ? 2 : 1); 107 } 108 109 ds->ds_data = bf->bf_dma.cookie.dmac_address; 110 /* 111 * Calculate rate code. 112 * XXX everything at min xmit rate 113 */ 114 rix = 0; 115 rt = sc->hw_rate_table[sc->sc_curmode]; 116 rate = rt->info[rix].ratecode; 117 if (sc->sc_flags & SC_OP_PREAMBLE_SHORT) 118 rate |= rt->info[rix].short_preamble; 119 120 ath9k_hw_set11n_txdesc(ah, ds, 121 MBLKL(mp) + IEEE80211_CRC_LEN, /* frame length */ 122 ATH9K_PKT_TYPE_BEACON, /* Atheros packet type */ 123 MAX_RATE_POWER, /* FIXME */ 124 ATH9K_TXKEYIX_INVALID, /* no encryption */ 125 ATH9K_KEY_TYPE_CLEAR, /* no encryption */ 126 flags); /* no ack, veol for beacons */ 127 128 /* NB: beacon's BufLen must be a multiple of 4 bytes */ 129 (void) ath9k_hw_filltxdesc(ah, ds, 130 roundup(MBLKL(mp), 4), /* buffer length */ 131 B_TRUE, /* first segment */ 132 B_TRUE, /* last segment */ 133 ds); /* first descriptor */ 134 135 (void) memset(series, 0, sizeof (struct ath9k_11n_rate_series) * 4); 136 series[0].Tries = 1; 137 series[0].Rate = rate; 138 series[0].ChSel = sc->sc_tx_chainmask; 139 series[0].RateFlags = (ctsrate) ? ATH9K_RATESERIES_RTS_CTS : 0; 140 ath9k_hw_set11n_ratescenario(ah, ds, ds, 0, 141 ctsrate, ctsduration, series, 4, 0); 142 #undef USE_SHPREAMBLE 143 } 144 145 /* 146 * Startup beacon transmission for adhoc mode when they are sent entirely 147 * by the hardware using the self-linked descriptor + veol trick. 148 */ 149 static void 150 arn_beacon_start_adhoc(struct arn_softc *sc) 151 152 { 153 struct ath_buf *bf = list_head(&sc->sc_bcbuf_list); 154 struct ieee80211_node *in = bf->bf_in; 155 struct ieee80211com *ic = in->in_ic; 156 struct ath_hal *ah = sc->sc_ah; 157 mblk_t *mp; 158 159 mp = bf->bf_m; 160 if (ieee80211_beacon_update(ic, bf->bf_in, &sc->asc_boff, mp, 0)) 161 bcopy(mp->b_rptr, bf->bf_dma.mem_va, MBLKL(mp)); 162 163 /* Construct tx descriptor. */ 164 arn_beacon_setup(sc, bf); 165 166 /* 167 * Stop any current dma and put the new frame on the queue. 168 * This should never fail since we check above that no frames 169 * are still pending on the queue. 170 */ 171 if (!ath9k_hw_stoptxdma(ah, sc->sc_beaconq)) { 172 arn_problem("ath: beacon queue %d did not stop?\n", 173 sc->sc_beaconq); 174 } 175 ARN_DMA_SYNC(bf->bf_dma, DDI_DMA_SYNC_FORDEV); 176 177 /* NB: caller is known to have already stopped tx dma */ 178 (void) ath9k_hw_puttxbuf(ah, sc->sc_beaconq, bf->bf_daddr); 179 (void) ath9k_hw_txstart(ah, sc->sc_beaconq); 180 181 ARN_DBG((ARN_DBG_BEACON, "arn: arn_bstuck_process(): " 182 "TXDP%u = %llx (%p)\n", sc->sc_beaconq, 183 ito64(bf->bf_daddr), bf->bf_desc)); 184 } 185 186 uint32_t 187 arn_beaconq_setup(struct ath_hal *ah) 188 { 189 struct ath9k_tx_queue_info qi; 190 191 (void) memset(&qi, 0, sizeof (qi)); 192 qi.tqi_aifs = 1; 193 qi.tqi_cwmin = 0; 194 qi.tqi_cwmax = 0; 195 /* NB: don't enable any interrupts */ 196 return (ath9k_hw_setuptxqueue(ah, ATH9K_TX_QUEUE_BEACON, &qi)); 197 } 198 199 int 200 arn_beacon_alloc(struct arn_softc *sc, struct ieee80211_node *in) 201 { 202 ieee80211com_t *ic = in->in_ic; 203 struct ath_buf *bf; 204 mblk_t *mp; 205 206 mutex_enter(&sc->sc_bcbuflock); 207 bf = list_head(&sc->sc_bcbuf_list); 208 if (bf == NULL) { 209 arn_problem("arn: arn_beacon_alloc():" 210 "no dma buffers"); 211 mutex_exit(&sc->sc_bcbuflock); 212 return (ENOMEM); 213 } 214 215 mp = ieee80211_beacon_alloc(ic, in, &sc->asc_boff); 216 if (mp == NULL) { 217 arn_problem("ath: arn_beacon_alloc():" 218 "cannot get mbuf\n"); 219 mutex_exit(&sc->sc_bcbuflock); 220 return (ENOMEM); 221 } 222 ASSERT(mp->b_cont == NULL); 223 bf->bf_m = mp; 224 bcopy(mp->b_rptr, bf->bf_dma.mem_va, MBLKL(mp)); 225 bf->bf_in = ieee80211_ref_node(in); 226 mutex_exit(&sc->sc_bcbuflock); 227 228 return (0); 229 } 230 231 232 void 233 arn_beacon_return(struct arn_softc *sc) 234 { 235 struct ath_buf *bf; 236 237 mutex_enter(&sc->sc_bcbuflock); 238 bf = list_head(&sc->sc_bcbuf_list); 239 while (bf != NULL) { 240 if (bf->bf_m != NULL) { 241 freemsg(bf->bf_m); 242 bf->bf_m = NULL; 243 } 244 if (bf->bf_in != NULL) { 245 ieee80211_free_node(bf->bf_in); 246 bf->bf_in = NULL; 247 } 248 bf = list_next(&sc->sc_bcbuf_list, bf); 249 } 250 mutex_exit(&sc->sc_bcbuflock); 251 } 252 253 void 254 arn_beacon_config(struct arn_softc *sc) 255 256 { 257 struct ath_hal *ah = sc->sc_ah; 258 struct ath_beacon_config conf; 259 ieee80211com_t *ic = (ieee80211com_t *)sc; 260 struct ieee80211_node *in = ic->ic_bss; 261 uint32_t nexttbtt, intval; 262 263 (void) memset(&conf, 0, sizeof (struct ath_beacon_config)); 264 265 /* XXX fix me */ 266 conf.beacon_interval = in->in_intval ? 267 in->in_intval : ATH_DEFAULT_BINTVAL; 268 conf.listen_interval = 1; 269 conf.dtim_period = conf.beacon_interval; 270 conf.dtim_count = 1; 271 conf.bmiss_timeout = ATH_DEFAULT_BMISS_LIMIT * conf.beacon_interval; 272 273 /* extract tstamp from last beacon and convert to TU */ 274 // nexttbtt = TSF_TO_TU(sc->bc_tstamp >> 32, sc->bc_tstamp); 275 /* XXX fix me */ 276 nexttbtt = (ARN_LE_READ_32(in->in_tstamp.data + 4) << 22) | 277 (ARN_LE_READ_32(in->in_tstamp.data) >> 10); 278 279 /* XXX conditionalize multi-bss support? */ 280 if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP) { 281 /* 282 * For multi-bss ap support beacons are either staggered 283 * evenly over N slots or burst together. For the former 284 * arrange for the SWBA to be delivered for each slot. 285 * Slots that are not occupied will generate nothing. 286 */ 287 /* NB: the beacon interval is kept internally in TU's */ 288 intval = conf.beacon_interval & ATH9K_BEACON_PERIOD; 289 intval /= ATH_BCBUF; /* for staggered beacons */ 290 } else { 291 intval = conf.beacon_interval & ATH9K_BEACON_PERIOD; 292 } 293 294 if (nexttbtt == 0) /* e.g. for ap mode */ 295 nexttbtt = intval; 296 else if (intval) /* NB: can be 0 for monitor mode */ 297 nexttbtt = roundup(nexttbtt, intval); 298 299 ARN_DBG((ARN_DBG_BEACON, "arn: arn_beacon_config(): " 300 "nexttbtt %u intval %u (%u)\n", 301 nexttbtt, intval, conf.beacon_interval)); 302 303 /* Check for ATH9K_M_HOSTAP and sc_nostabeacons for WDS client */ 304 if (sc->sc_ah->ah_opmode == ATH9K_M_STA) { 305 struct ath9k_beacon_state bs; 306 uint64_t tsf; 307 uint32_t tsftu; 308 int dtimperiod, dtimcount, sleepduration; 309 int cfpperiod, cfpcount; 310 311 /* 312 * Setup dtim and cfp parameters according to 313 * last beacon we received (which may be none). 314 */ 315 dtimperiod = conf.dtim_period; 316 if (dtimperiod <= 0) /* NB: 0 if not known */ 317 dtimperiod = 1; 318 dtimcount = conf.dtim_count; 319 if (dtimcount >= dtimperiod) /* NB: sanity check */ 320 dtimcount = 0; 321 cfpperiod = 1; /* NB: no PCF support yet */ 322 cfpcount = 0; 323 324 sleepduration = conf.listen_interval * intval; 325 if (sleepduration <= 0) 326 sleepduration = intval; 327 328 #define FUDGE 2 329 /* 330 * Pull nexttbtt forward to reflect the current 331 * TSF and calculate dtim+cfp state for the result. 332 */ 333 tsf = ath9k_hw_gettsf64(ah); 334 tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE; 335 do { 336 nexttbtt += intval; 337 if (--dtimcount < 0) { 338 dtimcount = dtimperiod - 1; 339 if (--cfpcount < 0) 340 cfpcount = cfpperiod - 1; 341 } 342 } while (nexttbtt < tsftu); 343 #undef FUDGE 344 (void) memset(&bs, 0, sizeof (bs)); 345 bs.bs_intval = intval; 346 bs.bs_nexttbtt = nexttbtt; 347 bs.bs_dtimperiod = dtimperiod*intval; 348 bs.bs_nextdtim = bs.bs_nexttbtt + dtimcount*intval; 349 bs.bs_cfpperiod = cfpperiod*bs.bs_dtimperiod; 350 bs.bs_cfpnext = bs.bs_nextdtim + cfpcount*bs.bs_dtimperiod; 351 bs.bs_cfpmaxduration = 0; 352 353 /* 354 * Calculate the number of consecutive beacons to miss 355 * before taking a BMISS interrupt. The configuration 356 * is specified in TU so we only need calculate based 357 * on the beacon interval. Note that we clamp the 358 * result to at most 15 beacons. 359 */ 360 if (sleepduration > intval) { 361 bs.bs_bmissthreshold = conf.listen_interval * 362 ATH_DEFAULT_BMISS_LIMIT / 2; 363 } else { 364 bs.bs_bmissthreshold = 365 DIV_ROUND_UP(conf.bmiss_timeout, intval); 366 if (bs.bs_bmissthreshold > 15) 367 bs.bs_bmissthreshold = 15; 368 /* LINTED E_SUSPICIOUS_COMPARISON */ 369 else if (bs.bs_bmissthreshold <= 0) 370 bs.bs_bmissthreshold = 1; 371 } 372 373 /* 374 * Calculate sleep duration. The configuration is 375 * given in ms. We insure a multiple of the beacon 376 * period is used. Also, if the sleep duration is 377 * greater than the DTIM period then it makes senses 378 * to make it a multiple of that. 379 * 380 * XXX fixed at 100ms 381 */ 382 383 bs.bs_sleepduration = 384 roundup(IEEE80211_MS_TO_TU(100), sleepduration); 385 if (bs.bs_sleepduration > bs.bs_dtimperiod) 386 bs.bs_sleepduration = bs.bs_dtimperiod; 387 388 ARN_DBG((ARN_DBG_BEACON, "arn: arn_beacon_config(): " 389 "tsf %llu " 390 "tsf:tu %u " 391 "intval %u " 392 "nexttbtt %u " 393 "dtim %u " 394 "nextdtim %u " 395 "bmiss %u " 396 "sleep %u " 397 "cfp:period %u " 398 "maxdur %u " 399 "next %u " 400 "timoffset %u\n", 401 (unsigned long long)tsf, tsftu, 402 bs.bs_intval, 403 bs.bs_nexttbtt, 404 bs.bs_dtimperiod, 405 bs.bs_nextdtim, 406 bs.bs_bmissthreshold, 407 bs.bs_sleepduration, 408 bs.bs_cfpperiod, 409 bs.bs_cfpmaxduration, 410 bs.bs_cfpnext, 411 bs.bs_timoffset)); 412 413 (void) ath9k_hw_set_interrupts(ah, 0); 414 ath9k_hw_set_sta_beacon_timers(ah, &bs); 415 sc->sc_imask |= ATH9K_INT_BMISS; 416 (void) ath9k_hw_set_interrupts(ah, sc->sc_imask); 417 } else { 418 uint64_t tsf; 419 uint32_t tsftu; 420 (void) ath9k_hw_set_interrupts(ah, 0); 421 if (nexttbtt == intval) 422 intval |= ATH9K_BEACON_RESET_TSF; 423 if (sc->sc_ah->ah_opmode == ATH9K_M_IBSS) { 424 /* 425 * Pull nexttbtt forward to reflect the current 426 * TSF 427 */ 428 #define FUDGE 2 429 if (!(intval & ATH9K_BEACON_RESET_TSF)) { 430 tsf = ath9k_hw_gettsf64(ah); 431 tsftu = TSF_TO_TU((uint32_t)(tsf>>32), 432 (uint32_t)tsf) + FUDGE; 433 do { 434 nexttbtt += intval; 435 } while (nexttbtt < tsftu); 436 } 437 #undef FUDGE 438 ARN_DBG((ARN_DBG_BEACON, "arn: arn_beacon_config(): " 439 "IBSS nexttbtt %u intval %u (%u)\n", 440 nexttbtt, intval & ~ATH9K_BEACON_RESET_TSF, 441 conf.beacon_interval)); 442 443 /* 444 * In IBSS mode enable the beacon timers but only 445 * enable SWBA interrupts if we need to manually 446 * prepare beacon frames. Otherwise we use a 447 * self-linked tx descriptor and let the hardware 448 * deal with things. 449 */ 450 intval |= ATH9K_BEACON_ENA; 451 if (!(ah->ah_caps.hw_caps & ATH9K_HW_CAP_VEOL)) 452 sc->sc_imask |= ATH9K_INT_SWBA; 453 (void) arn_beaconq_config(sc); 454 } else if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP) { 455 /* 456 * In AP mode we enable the beacon timers and 457 * SWBA interrupts to prepare beacon frames. 458 */ 459 intval |= ATH9K_BEACON_ENA; 460 sc->sc_imask |= ATH9K_INT_SWBA; /* beacon prepare */ 461 (void) arn_beaconq_config(sc); 462 } 463 ath9k_hw_beaconinit(ah, nexttbtt, intval); 464 sc->sc_bmisscount = 0; 465 (void) ath9k_hw_set_interrupts(ah, sc->sc_imask); 466 /* 467 * When using a self-linked beacon descriptor in 468 * ibss mode load it once here. 469 */ 470 if (sc->sc_ah->ah_opmode == ATH9K_M_IBSS && 471 (ah->ah_caps.hw_caps & ATH9K_HW_CAP_VEOL)) 472 arn_beacon_start_adhoc(sc); 473 } 474 sc->sc_bsync = 0; 475 } 476 477 void 478 ath_beacon_sync(struct arn_softc *sc) 479 { 480 /* 481 * Resync beacon timers using the tsf of the 482 * beacon frame we just received. 483 */ 484 arn_beacon_config(sc); 485 sc->sc_flags |= SC_OP_BEACONS; 486 } 487 488 void 489 arn_bmiss_proc(void *arg) 490 { 491 struct arn_softc *sc = (struct arn_softc *)arg; 492 ieee80211com_t *ic = (ieee80211com_t *)sc; 493 uint64_t tsf, lastrx; 494 uint_t bmisstimeout; 495 496 if (ic->ic_opmode != IEEE80211_M_STA || 497 ic->ic_state != IEEE80211_S_RUN) { 498 return; 499 } 500 501 ARN_LOCK(sc); 502 lastrx = sc->sc_lastrx; 503 tsf = ath9k_hw_gettsf64(sc->sc_ah); 504 bmisstimeout = ic->ic_bmissthreshold * ic->ic_bss->in_intval * 1024; 505 506 ARN_DBG((ARN_DBG_BEACON, "arn_bmiss_proc():" 507 " tsf %llu, lastrx %llu (%lld), bmiss %u\n", 508 (unsigned long long)tsf, (unsigned long long)sc->sc_lastrx, 509 (long long)(tsf - lastrx), bmisstimeout)); 510 ARN_UNLOCK(sc); 511 512 /* temp workaround */ 513 if (tsf - lastrx > bmisstimeout) 514 ieee80211_beacon_miss(ic); 515 } 516