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/byteorder.h> 23 24 #include "arn_core.h" 25 26 void 27 arn_setdefantenna(struct arn_softc *sc, uint32_t antenna) 28 { 29 /* XXX block beacon interrupts */ 30 ath9k_hw_setantenna(sc->sc_ah, antenna); 31 sc->sc_defant = (uint8_t)antenna; /* LINT */ 32 sc->sc_rxotherant = 0; 33 } 34 35 /* 36 * Extend 15-bit time stamp from rx descriptor to 37 * a full 64-bit TSF using the current h/w TSF. 38 */ 39 40 static uint64_t 41 arn_extend_tsf(struct arn_softc *sc, uint32_t rstamp) 42 { 43 uint64_t tsf; 44 45 tsf = ath9k_hw_gettsf64(sc->sc_ah); 46 if ((tsf & 0x7fff) < rstamp) 47 tsf -= 0x8000; 48 return ((tsf & ~0x7fff) | rstamp); 49 } 50 51 static void 52 arn_opmode_init(struct arn_softc *sc) 53 { 54 struct ath_hal *ah = sc->sc_ah; 55 uint32_t rfilt; 56 uint32_t mfilt[2]; 57 ieee80211com_t *ic = (ieee80211com_t *)sc; 58 59 /* configure rx filter */ 60 rfilt = arn_calcrxfilter(sc); 61 ath9k_hw_setrxfilter(ah, rfilt); 62 63 /* configure bssid mask */ 64 if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) 65 (void) ath9k_hw_setbssidmask(ah, sc->sc_bssidmask); 66 67 /* configure operational mode */ 68 ath9k_hw_setopmode(ah); 69 70 /* Handle any link-level address change. */ 71 (void) ath9k_hw_setmac(ah, sc->sc_myaddr); 72 73 /* calculate and install multicast filter */ 74 mfilt[0] = ~((uint32_t)0); /* LINT */ 75 mfilt[1] = ~((uint32_t)0); /* LINT */ 76 77 ath9k_hw_setmcastfilter(ah, mfilt[0], mfilt[1]); 78 79 ARN_DBG((ARN_DBG_RECV, "arn: arn_opmode_init(): " 80 "mode = %d RX filter 0x%x, MC filter %08x:%08x\n", 81 ic->ic_opmode, rfilt, mfilt[0], mfilt[1])); 82 } 83 84 /* 85 * Calculate the receive filter according to the 86 * operating mode and state: 87 * 88 * o always accept unicast, broadcast, and multicast traffic 89 * o maintain current state of phy error reception (the hal 90 * may enable phy error frames for noise immunity work) 91 * o probe request frames are accepted only when operating in 92 * hostap, adhoc, or monitor modes 93 * o enable promiscuous mode according to the interface state 94 * o accept beacons: 95 * - when operating in adhoc mode so the 802.11 layer creates 96 * node table entries for peers, 97 * - when operating in station mode for collecting rssi data when 98 * the station is otherwise quiet, or 99 * - when operating as a repeater so we see repeater-sta beacons 100 * - when scanning 101 */ 102 103 uint32_t 104 arn_calcrxfilter(struct arn_softc *sc) 105 { 106 #define RX_FILTER_PRESERVE (ATH9K_RX_FILTER_PHYERR | \ 107 ATH9K_RX_FILTER_PHYRADAR) 108 109 uint32_t rfilt; 110 111 rfilt = (ath9k_hw_getrxfilter(sc->sc_ah) & RX_FILTER_PRESERVE) | 112 ATH9K_RX_FILTER_UCAST | ATH9K_RX_FILTER_BCAST | 113 ATH9K_RX_FILTER_MCAST; 114 115 /* If not a STA, enable processing of Probe Requests */ 116 if (sc->sc_ah->ah_opmode != ATH9K_M_STA) 117 rfilt |= ATH9K_RX_FILTER_PROBEREQ; 118 119 /* Can't set HOSTAP into promiscous mode */ 120 if (((sc->sc_ah->ah_opmode != ATH9K_M_HOSTAP) && 121 (sc->sc_promisc)) || 122 (sc->sc_ah->ah_opmode == ATH9K_M_MONITOR)) { 123 rfilt |= ATH9K_RX_FILTER_PROM; 124 /* ??? To prevent from sending ACK */ 125 rfilt &= ~ATH9K_RX_FILTER_UCAST; 126 } 127 128 if (sc->sc_ah->ah_opmode == ATH9K_M_STA || 129 sc->sc_ah->ah_opmode == ATH9K_M_IBSS) 130 rfilt |= ATH9K_RX_FILTER_BEACON; 131 132 /* 133 * If in HOSTAP mode, want to enable reception of PSPOLL 134 * frames & beacon frames 135 */ 136 if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP) 137 rfilt |= (ATH9K_RX_FILTER_BEACON | ATH9K_RX_FILTER_PSPOLL); 138 139 return (rfilt); 140 141 #undef RX_FILTER_PRESERVE 142 } 143 144 int 145 arn_startrecv(struct arn_softc *sc) 146 { 147 struct ath_hal *ah = sc->sc_ah; 148 struct ath_buf *bf; 149 150 /* clean up rx link firstly */ 151 sc->sc_rxlink = NULL; 152 153 /* rx descriptor link set up */ 154 bf = list_head(&sc->sc_rxbuf_list); 155 while (bf != NULL) { 156 arn_rx_buf_link(sc, bf); 157 bf = list_next(&sc->sc_rxbuf_list, bf); 158 } 159 160 bf = list_head(&sc->sc_rxbuf_list); 161 162 ath9k_hw_putrxbuf(ah, bf->bf_daddr); 163 ath9k_hw_rxena(ah); 164 165 arn_opmode_init(sc); 166 ath9k_hw_startpcureceive(ah); 167 168 return (0); 169 } 170 171 boolean_t 172 arn_stoprecv(struct arn_softc *sc) 173 { 174 struct ath_hal *ah = sc->sc_ah; 175 boolean_t stopped; 176 177 ath9k_hw_stoppcurecv(ah); 178 ath9k_hw_setrxfilter(ah, 0); 179 stopped = ath9k_hw_stopdmarecv(ah); 180 181 /* 3ms is long enough for 1 frame ??? */ 182 drv_usecwait(3000); 183 184 sc->sc_rxlink = NULL; 185 186 return (stopped); 187 } 188 189 /* 190 * Intercept management frames to collect beacon rssi data 191 * and to do ibss merges. 192 */ 193 194 void 195 arn_recv_mgmt(struct ieee80211com *ic, mblk_t *mp, struct ieee80211_node *in, 196 int subtype, int rssi, uint32_t rstamp) 197 { 198 struct arn_softc *sc = (struct arn_softc *)ic; 199 200 /* 201 * Call up first so subsequent work can use information 202 * potentially stored in the node (e.g. for ibss merge). 203 */ 204 sc->sc_recv_mgmt(ic, mp, in, subtype, rssi, rstamp); 205 206 ARN_LOCK(sc); 207 switch (subtype) { 208 case IEEE80211_FC0_SUBTYPE_BEACON: 209 /* update rssi statistics */ 210 if (sc->sc_bsync && in == ic->ic_bss && 211 ic->ic_state == IEEE80211_S_RUN) { 212 /* 213 * Resync beacon timers using the tsf of the beacon 214 * frame we just received. 215 */ 216 arn_beacon_config(sc); 217 } 218 /* FALLTHRU */ 219 case IEEE80211_FC0_SUBTYPE_PROBE_RESP: 220 if (ic->ic_opmode == IEEE80211_M_IBSS && 221 ic->ic_state == IEEE80211_S_RUN && 222 (in->in_capinfo & IEEE80211_CAPINFO_IBSS)) { 223 uint64_t tsf = arn_extend_tsf(sc, rstamp); 224 /* 225 * Handle ibss merge as needed; check the tsf on the 226 * frame before attempting the merge. The 802.11 spec 227 * says the station should change it's bssid to match 228 * the oldest station with the same ssid, where oldest 229 * is determined by the tsf. Note that hardware 230 * reconfiguration happens through callback to 231 * ath_newstate as the state machine will go from 232 * RUN -> RUN when this happens. 233 */ 234 if (LE_64(in->in_tstamp.tsf) >= tsf) { 235 ARN_DBG((ARN_DBG_BEACON, "arn: arn_recv_mgmt:" 236 "ibss merge, rstamp %u tsf %lu " 237 "tstamp %lu\n", rstamp, tsf, 238 in->in_tstamp.tsf)); 239 ARN_UNLOCK(sc); 240 ARN_DBG((ARN_DBG_BEACON, "arn_recv_mgmt():" 241 "ibss_merge: rstamp=%d in_tstamp=%02x %02x" 242 " %02x %02x %02x %02x %02x %02x\n", 243 rstamp, in->in_tstamp.data[0], 244 in->in_tstamp.data[1], 245 in->in_tstamp.data[2], 246 in->in_tstamp.data[3], 247 in->in_tstamp.data[4], 248 in->in_tstamp.data[5], 249 in->in_tstamp.data[6], 250 in->in_tstamp.data[7])); 251 (void) ieee80211_ibss_merge(in); 252 return; 253 } 254 } 255 break; 256 } 257 ARN_UNLOCK(sc); 258 } 259 260 static void 261 arn_printrxbuf(struct ath_buf *bf, int32_t done) 262 { 263 struct ath_desc *ds = bf->bf_desc; 264 const struct ath_rx_status *rs = &ds->ds_rxstat; 265 266 ARN_DBG((ARN_DBG_RECV, "arn: R (%p %p) %08x %08x %08x " 267 "%08x %08x %08x %c\n", 268 ds, bf->bf_daddr, 269 ds->ds_link, ds->ds_data, 270 ds->ds_ctl0, ds->ds_ctl1, 271 ds->ds_hw[0], ds->ds_hw[1], 272 !done ? ' ' : (rs->rs_status == 0) ? '*' : '!')); 273 } 274 275 static void 276 arn_rx_handler(struct arn_softc *sc) 277 { 278 #define PA2DESC(_sc, _pa) \ 279 ((struct ath_desc *)((caddr_t)(_sc)->sc_desc + \ 280 ((_pa) - (_sc)->sc_desc_dma.cookie.dmac_address))) 281 282 ieee80211com_t *ic = (ieee80211com_t *)sc; 283 struct ath_buf *bf; 284 struct ath_hal *ah = sc->sc_ah; 285 struct ath_desc *ds; 286 struct ath_rx_status *rs; 287 mblk_t *rx_mp; 288 struct ieee80211_frame *wh; 289 int32_t len, ngood, loop = 1; 290 uint8_t phyerr; 291 int status; 292 struct ieee80211_node *in; 293 uint32_t cur_signal; 294 uint32_t subtype; 295 296 ngood = 0; 297 do { 298 mutex_enter(&sc->sc_rxbuflock); 299 bf = list_head(&sc->sc_rxbuf_list); 300 if (bf == NULL) { 301 ARN_DBG((ARN_DBG_RECV, "arn: arn_rx_handler(): " 302 "no buffer\n")); 303 mutex_exit(&sc->sc_rxbuflock); 304 break; 305 } 306 ASSERT(bf->bf_dma.cookie.dmac_address != NULL); 307 ds = bf->bf_desc; 308 if (ds->ds_link == bf->bf_daddr) { 309 /* 310 * Never process the self-linked entry at the end, 311 * this may be met at heavy load. 312 */ 313 mutex_exit(&sc->sc_rxbuflock); 314 break; 315 } 316 317 /* 318 * Must provide the virtual address of the current 319 * descriptor, the physical address, and the virtual 320 * address of the next descriptor in the h/w chain. 321 * This allows the HAL to look ahead to see if the 322 * hardware is done with a descriptor by checking the 323 * done bit in the following descriptor and the address 324 * of the current descriptor the DMA engine is working 325 * on. All this is necessary because of our use of 326 * a self-linked list to avoid rx overruns. 327 */ 328 status = ath9k_hw_rxprocdesc(ah, ds, 329 bf->bf_daddr, 330 PA2DESC(sc, ds->ds_link), 0); 331 if (status == EINPROGRESS) { 332 mutex_exit(&sc->sc_rxbuflock); 333 break; 334 } 335 list_remove(&sc->sc_rxbuf_list, bf); 336 mutex_exit(&sc->sc_rxbuflock); 337 338 rs = &ds->ds_rxstat; 339 if (rs->rs_status != 0) { 340 if (rs->rs_status & ATH9K_RXERR_CRC) { 341 sc->sc_stats.ast_rx_crcerr++; 342 } 343 if (rs->rs_status & ATH9K_RXERR_FIFO) { 344 sc->sc_stats.ast_rx_fifoerr++; 345 } 346 if (rs->rs_status & ATH9K_RXERR_DECRYPT) { 347 sc->sc_stats.ast_rx_badcrypt++; 348 } 349 if (rs->rs_status & ATH9K_RXERR_PHY) { 350 sc->sc_stats.ast_rx_phyerr++; 351 phyerr = rs->rs_phyerr & 0x1f; 352 sc->sc_stats.ast_rx_phy[phyerr]++; 353 } 354 goto rx_next; 355 } 356 len = rs->rs_datalen; 357 358 /* less than sizeof(struct ieee80211_frame) */ 359 if (len < 20) { 360 sc->sc_stats.ast_rx_tooshort++; 361 goto rx_next; 362 } 363 364 if ((rx_mp = allocb(sc->sc_dmabuf_size, BPRI_MED)) == NULL) { 365 arn_problem("arn: arn_rx_handler(): " 366 "allocing mblk buffer failed.\n"); 367 return; 368 } 369 370 ARN_DMA_SYNC(bf->bf_dma, DDI_DMA_SYNC_FORCPU); 371 bcopy(bf->bf_dma.mem_va, rx_mp->b_rptr, len); 372 373 rx_mp->b_wptr += len; 374 wh = (struct ieee80211_frame *)rx_mp->b_rptr; 375 376 if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == 377 IEEE80211_FC0_TYPE_CTL) { 378 /* 379 * Ignore control frame received in promisc mode. 380 */ 381 freemsg(rx_mp); 382 goto rx_next; 383 } 384 385 /* Remove the CRC at the end of IEEE80211 frame */ 386 rx_mp->b_wptr -= IEEE80211_CRC_LEN; 387 388 /* 389 * Locate the node for sender, track state, and then 390 * pass the (referenced) node up to the 802.11 layer 391 * for its use. 392 */ 393 in = ieee80211_find_rxnode(ic, wh); 394 395 if (ds->ds_rxstat.rs_rssi < 0) 396 ds->ds_rxstat.rs_rssi = 0; 397 398 if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == 399 IEEE80211_FC0_TYPE_MGT) { 400 subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; 401 /* Update Beacon RSSI, this is used by ANI. */ 402 if (subtype == IEEE80211_FC0_SUBTYPE_BEACON) 403 sc->sc_halstats.ns_avgbrssi = 404 ds->ds_rxstat.rs_rssi; 405 } 406 407 #ifdef DEBUG 408 arn_printrxbuf(bf, status == 0); 409 #endif 410 411 /* 412 * signal 13-15 DLADM_WLAN_STRENGTH_EXCELLENT 413 * signal 10-12 DLADM_WLAN_STRENGTH_VERY_GOOD 414 * signal 6-9 DLADM_WLAN_STRENGTH_GOOD 415 * signal 3-5 DLADM_WLAN_STRENGTH_WEAK 416 * signal 0-2 DLADM_WLAN_STRENGTH_VERY_WEAK 417 */ 418 if (rs->rs_rssi == 0) 419 cur_signal = 0; 420 else if (rs->rs_rssi >= 45) 421 cur_signal = MAX_RSSI; 422 else 423 cur_signal = rs->rs_rssi * MAX_RSSI / 45 + 1; 424 425 /* 426 * Send the frame to net80211 for processing 427 */ 428 if (cur_signal <= 2 && ic->ic_state == IEEE80211_S_RUN) 429 (void) ieee80211_input(ic, rx_mp, in, 430 (rs->rs_rssi + 10), rs->rs_tstamp); 431 else 432 (void) ieee80211_input(ic, rx_mp, in, 433 rs->rs_rssi, rs->rs_tstamp); 434 435 /* release node */ 436 ieee80211_free_node(in); 437 438 /* 439 * Arrange to update the last rx timestamp only for 440 * frames from our ap when operating in station mode. 441 * This assumes the rx key is always setup when associated. 442 */ 443 if (ic->ic_opmode == IEEE80211_M_STA && 444 rs->rs_keyix != ATH9K_RXKEYIX_INVALID) { 445 ngood++; 446 } 447 448 /* 449 * change the default rx antenna if rx diversity chooses the 450 * other antenna 3 times in a row. 451 */ 452 if (sc->sc_defant != ds->ds_rxstat.rs_antenna) { 453 if (++sc->sc_rxotherant >= 3) { 454 ath9k_hw_setantenna(sc->sc_ah, 455 ds->ds_rxstat.rs_antenna); 456 sc->sc_defant = ds->ds_rxstat.rs_antenna; 457 sc->sc_rxotherant = 0; 458 } 459 } else { 460 sc->sc_rxotherant = 0; 461 } 462 463 rx_next: 464 mutex_enter(&sc->sc_rxbuflock); 465 list_insert_tail(&sc->sc_rxbuf_list, bf); 466 mutex_exit(&sc->sc_rxbuflock); 467 arn_rx_buf_link(sc, bf); 468 } while (loop); 469 470 if (ngood) 471 sc->sc_lastrx = ath9k_hw_gettsf64(ah); 472 473 #undef PA2DESC 474 } 475 476 uint_t 477 arn_softint_handler(caddr_t data) 478 { 479 struct arn_softc *sc = (struct arn_softc *)data; 480 481 ARN_LOCK(sc); 482 483 if (sc->sc_rx_pend) { 484 /* Soft interrupt for this driver */ 485 sc->sc_rx_pend = 0; 486 ARN_UNLOCK(sc); 487 arn_rx_handler(sc); 488 return (DDI_INTR_CLAIMED); 489 } 490 491 ARN_UNLOCK(sc); 492 493 return (DDI_INTR_UNCLAIMED); 494 } 495