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