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