1dd1de374Slin wang - Sun Microsystems - Beijing China /* 2*c0c93480Slin wang - Sun Microsystems - Beijing China * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 3dd1de374Slin wang - Sun Microsystems - Beijing China * Use is subject to license terms. 4dd1de374Slin wang - Sun Microsystems - Beijing China */ 5dd1de374Slin wang - Sun Microsystems - Beijing China 6dd1de374Slin wang - Sun Microsystems - Beijing China /* 7dd1de374Slin wang - Sun Microsystems - Beijing China * Copyright (c) 2008 Atheros Communications Inc. 8dd1de374Slin wang - Sun Microsystems - Beijing China * 9dd1de374Slin wang - Sun Microsystems - Beijing China * Permission to use, copy, modify, and/or distribute this software for any 10dd1de374Slin wang - Sun Microsystems - Beijing China * purpose with or without fee is hereby granted, provided that the above 11dd1de374Slin wang - Sun Microsystems - Beijing China * copyright notice and this permission notice appear in all copies. 12dd1de374Slin wang - Sun Microsystems - Beijing China * 13dd1de374Slin wang - Sun Microsystems - Beijing China * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 14dd1de374Slin wang - Sun Microsystems - Beijing China * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 15dd1de374Slin wang - Sun Microsystems - Beijing China * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 16dd1de374Slin wang - Sun Microsystems - Beijing China * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 17dd1de374Slin wang - Sun Microsystems - Beijing China * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 18dd1de374Slin wang - Sun Microsystems - Beijing China * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 19dd1de374Slin wang - Sun Microsystems - Beijing China * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 20dd1de374Slin wang - Sun Microsystems - Beijing China */ 21dd1de374Slin wang - Sun Microsystems - Beijing China 22dd1de374Slin wang - Sun Microsystems - Beijing China #include <sys/byteorder.h> 23dd1de374Slin wang - Sun Microsystems - Beijing China 24dd1de374Slin wang - Sun Microsystems - Beijing China #include "arn_core.h" 25dd1de374Slin wang - Sun Microsystems - Beijing China 26*c0c93480Slin wang - Sun Microsystems - Beijing China /* 27*c0c93480Slin wang - Sun Microsystems - Beijing China * Setup and link descriptors. 28*c0c93480Slin wang - Sun Microsystems - Beijing China * 29*c0c93480Slin wang - Sun Microsystems - Beijing China * 11N: we can no longer afford to self link the last descriptor. 30*c0c93480Slin wang - Sun Microsystems - Beijing China * MAC acknowledges BA status as long as it copies frames to host 31*c0c93480Slin wang - Sun Microsystems - Beijing China * buffer (or rx fifo). This can incorrectly acknowledge packets 32*c0c93480Slin wang - Sun Microsystems - Beijing China * to a sender if last desc is self-linked. 33*c0c93480Slin wang - Sun Microsystems - Beijing China */ 34*c0c93480Slin wang - Sun Microsystems - Beijing China void 35*c0c93480Slin wang - Sun Microsystems - Beijing China arn_rx_buf_link(struct arn_softc *sc, struct ath_buf *bf) 36*c0c93480Slin wang - Sun Microsystems - Beijing China { 37*c0c93480Slin wang - Sun Microsystems - Beijing China struct ath_desc *ds; 38*c0c93480Slin wang - Sun Microsystems - Beijing China 39*c0c93480Slin wang - Sun Microsystems - Beijing China ds = bf->bf_desc; 40*c0c93480Slin wang - Sun Microsystems - Beijing China ds->ds_link = 0; 41*c0c93480Slin wang - Sun Microsystems - Beijing China ds->ds_data = bf->bf_dma.cookie.dmac_address; 42*c0c93480Slin wang - Sun Microsystems - Beijing China 43*c0c93480Slin wang - Sun Microsystems - Beijing China /* virtual addr of the beginning of the buffer. */ 44*c0c93480Slin wang - Sun Microsystems - Beijing China ds->ds_vdata = bf->bf_dma.mem_va; 45*c0c93480Slin wang - Sun Microsystems - Beijing China 46*c0c93480Slin wang - Sun Microsystems - Beijing China /* 47*c0c93480Slin wang - Sun Microsystems - Beijing China * setup rx descriptors. The bf_dma.alength here tells the H/W 48*c0c93480Slin wang - Sun Microsystems - Beijing China * how much data it can DMA to us and that we are prepared 49*c0c93480Slin wang - Sun Microsystems - Beijing China * to process 50*c0c93480Slin wang - Sun Microsystems - Beijing China */ 51*c0c93480Slin wang - Sun Microsystems - Beijing China (void) ath9k_hw_setuprxdesc(sc->sc_ah, ds, 52*c0c93480Slin wang - Sun Microsystems - Beijing China bf->bf_dma.alength, /* buffer size */ 53*c0c93480Slin wang - Sun Microsystems - Beijing China 0); 54*c0c93480Slin wang - Sun Microsystems - Beijing China 55*c0c93480Slin wang - Sun Microsystems - Beijing China if (sc->sc_rxlink == NULL) 56*c0c93480Slin wang - Sun Microsystems - Beijing China ath9k_hw_putrxbuf(sc->sc_ah, bf->bf_daddr); 57*c0c93480Slin wang - Sun Microsystems - Beijing China else 58*c0c93480Slin wang - Sun Microsystems - Beijing China *sc->sc_rxlink = bf->bf_daddr; 59*c0c93480Slin wang - Sun Microsystems - Beijing China 60*c0c93480Slin wang - Sun Microsystems - Beijing China sc->sc_rxlink = &ds->ds_link; 61*c0c93480Slin wang - Sun Microsystems - Beijing China ath9k_hw_rxena(sc->sc_ah); 62*c0c93480Slin wang - Sun Microsystems - Beijing China } 63*c0c93480Slin wang - Sun Microsystems - Beijing China 64dd1de374Slin wang - Sun Microsystems - Beijing China void 65dd1de374Slin wang - Sun Microsystems - Beijing China arn_setdefantenna(struct arn_softc *sc, uint32_t antenna) 66dd1de374Slin wang - Sun Microsystems - Beijing China { 67dd1de374Slin wang - Sun Microsystems - Beijing China /* XXX block beacon interrupts */ 68dd1de374Slin wang - Sun Microsystems - Beijing China ath9k_hw_setantenna(sc->sc_ah, antenna); 69dd1de374Slin wang - Sun Microsystems - Beijing China sc->sc_defant = (uint8_t)antenna; /* LINT */ 70dd1de374Slin wang - Sun Microsystems - Beijing China sc->sc_rxotherant = 0; 71dd1de374Slin wang - Sun Microsystems - Beijing China } 72dd1de374Slin wang - Sun Microsystems - Beijing China 73dd1de374Slin wang - Sun Microsystems - Beijing China /* 74dd1de374Slin wang - Sun Microsystems - Beijing China * Extend 15-bit time stamp from rx descriptor to 75dd1de374Slin wang - Sun Microsystems - Beijing China * a full 64-bit TSF using the current h/w TSF. 76dd1de374Slin wang - Sun Microsystems - Beijing China */ 77dd1de374Slin wang - Sun Microsystems - Beijing China 78dd1de374Slin wang - Sun Microsystems - Beijing China static uint64_t 79dd1de374Slin wang - Sun Microsystems - Beijing China arn_extend_tsf(struct arn_softc *sc, uint32_t rstamp) 80dd1de374Slin wang - Sun Microsystems - Beijing China { 81dd1de374Slin wang - Sun Microsystems - Beijing China uint64_t tsf; 82dd1de374Slin wang - Sun Microsystems - Beijing China 83dd1de374Slin wang - Sun Microsystems - Beijing China tsf = ath9k_hw_gettsf64(sc->sc_ah); 84dd1de374Slin wang - Sun Microsystems - Beijing China if ((tsf & 0x7fff) < rstamp) 85dd1de374Slin wang - Sun Microsystems - Beijing China tsf -= 0x8000; 86dd1de374Slin wang - Sun Microsystems - Beijing China return ((tsf & ~0x7fff) | rstamp); 87dd1de374Slin wang - Sun Microsystems - Beijing China } 88dd1de374Slin wang - Sun Microsystems - Beijing China 89*c0c93480Slin wang - Sun Microsystems - Beijing China static int 90*c0c93480Slin wang - Sun Microsystems - Beijing China arn_rx_prepare(struct ath_desc *ds, struct arn_softc *sc) 91*c0c93480Slin wang - Sun Microsystems - Beijing China { 92*c0c93480Slin wang - Sun Microsystems - Beijing China uint8_t phyerr; 93*c0c93480Slin wang - Sun Microsystems - Beijing China 94*c0c93480Slin wang - Sun Microsystems - Beijing China if (ds->ds_rxstat.rs_more) { 95*c0c93480Slin wang - Sun Microsystems - Beijing China /* 96*c0c93480Slin wang - Sun Microsystems - Beijing China * Frame spans multiple descriptors; this cannot happen yet 97*c0c93480Slin wang - Sun Microsystems - Beijing China * as we don't support jumbograms. If not in monitor mode, 98*c0c93480Slin wang - Sun Microsystems - Beijing China * discard the frame. Enable this if you want to see 99*c0c93480Slin wang - Sun Microsystems - Beijing China * error frames in Monitor mode. 100*c0c93480Slin wang - Sun Microsystems - Beijing China */ 101*c0c93480Slin wang - Sun Microsystems - Beijing China if (sc->sc_ah->ah_opmode != ATH9K_M_MONITOR) 102*c0c93480Slin wang - Sun Microsystems - Beijing China goto rx_next; 103*c0c93480Slin wang - Sun Microsystems - Beijing China } else if (ds->ds_rxstat.rs_status != 0) { 104*c0c93480Slin wang - Sun Microsystems - Beijing China if (ds->ds_rxstat.rs_status & ATH9K_RXERR_CRC) { 105*c0c93480Slin wang - Sun Microsystems - Beijing China sc->sc_stats.ast_rx_crcerr++; 106*c0c93480Slin wang - Sun Microsystems - Beijing China goto rx_next; /* should ignore? */ 107*c0c93480Slin wang - Sun Microsystems - Beijing China } 108*c0c93480Slin wang - Sun Microsystems - Beijing China 109*c0c93480Slin wang - Sun Microsystems - Beijing China if (ds->ds_rxstat.rs_status & ATH9K_RXERR_FIFO) { 110*c0c93480Slin wang - Sun Microsystems - Beijing China sc->sc_stats.ast_rx_fifoerr++; 111*c0c93480Slin wang - Sun Microsystems - Beijing China } 112*c0c93480Slin wang - Sun Microsystems - Beijing China 113*c0c93480Slin wang - Sun Microsystems - Beijing China if (ds->ds_rxstat.rs_status & ATH9K_RXERR_PHY) { 114*c0c93480Slin wang - Sun Microsystems - Beijing China sc->sc_stats.ast_rx_phyerr++; 115*c0c93480Slin wang - Sun Microsystems - Beijing China phyerr = ds->ds_rxstat.rs_phyerr & 0x1f; 116*c0c93480Slin wang - Sun Microsystems - Beijing China sc->sc_stats.ast_rx_phy[phyerr]++; 117*c0c93480Slin wang - Sun Microsystems - Beijing China goto rx_next; 118*c0c93480Slin wang - Sun Microsystems - Beijing China } 119*c0c93480Slin wang - Sun Microsystems - Beijing China 120*c0c93480Slin wang - Sun Microsystems - Beijing China if (ds->ds_rxstat.rs_status & ATH9K_RXERR_DECRYPT) { 121*c0c93480Slin wang - Sun Microsystems - Beijing China sc->sc_stats.ast_rx_badcrypt++; 122*c0c93480Slin wang - Sun Microsystems - Beijing China } 123*c0c93480Slin wang - Sun Microsystems - Beijing China 124*c0c93480Slin wang - Sun Microsystems - Beijing China /* 125*c0c93480Slin wang - Sun Microsystems - Beijing China * Reject error frames with the exception of 126*c0c93480Slin wang - Sun Microsystems - Beijing China * decryption and MIC failures. For monitor mode, 127*c0c93480Slin wang - Sun Microsystems - Beijing China * we also ignore the CRC error. 128*c0c93480Slin wang - Sun Microsystems - Beijing China */ 129*c0c93480Slin wang - Sun Microsystems - Beijing China if (sc->sc_ah->ah_opmode == ATH9K_M_MONITOR) { 130*c0c93480Slin wang - Sun Microsystems - Beijing China if (ds->ds_rxstat.rs_status & 131*c0c93480Slin wang - Sun Microsystems - Beijing China ~(ATH9K_RXERR_DECRYPT | 132*c0c93480Slin wang - Sun Microsystems - Beijing China ATH9K_RXERR_MIC | 133*c0c93480Slin wang - Sun Microsystems - Beijing China ATH9K_RXERR_CRC)) 134*c0c93480Slin wang - Sun Microsystems - Beijing China goto rx_next; 135*c0c93480Slin wang - Sun Microsystems - Beijing China } else { 136*c0c93480Slin wang - Sun Microsystems - Beijing China if (ds->ds_rxstat.rs_status & 137*c0c93480Slin wang - Sun Microsystems - Beijing China ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC)) { 138*c0c93480Slin wang - Sun Microsystems - Beijing China goto rx_next; 139*c0c93480Slin wang - Sun Microsystems - Beijing China } 140*c0c93480Slin wang - Sun Microsystems - Beijing China } 141*c0c93480Slin wang - Sun Microsystems - Beijing China } 142*c0c93480Slin wang - Sun Microsystems - Beijing China 143*c0c93480Slin wang - Sun Microsystems - Beijing China return (1); 144*c0c93480Slin wang - Sun Microsystems - Beijing China rx_next: 145*c0c93480Slin wang - Sun Microsystems - Beijing China return (0); 146*c0c93480Slin wang - Sun Microsystems - Beijing China } 147*c0c93480Slin wang - Sun Microsystems - Beijing China 148*c0c93480Slin wang - Sun Microsystems - Beijing China 149dd1de374Slin wang - Sun Microsystems - Beijing China static void 150dd1de374Slin wang - Sun Microsystems - Beijing China arn_opmode_init(struct arn_softc *sc) 151dd1de374Slin wang - Sun Microsystems - Beijing China { 152dd1de374Slin wang - Sun Microsystems - Beijing China struct ath_hal *ah = sc->sc_ah; 153dd1de374Slin wang - Sun Microsystems - Beijing China uint32_t rfilt; 154dd1de374Slin wang - Sun Microsystems - Beijing China uint32_t mfilt[2]; 155dd1de374Slin wang - Sun Microsystems - Beijing China ieee80211com_t *ic = (ieee80211com_t *)sc; 156dd1de374Slin wang - Sun Microsystems - Beijing China 157dd1de374Slin wang - Sun Microsystems - Beijing China /* configure rx filter */ 158dd1de374Slin wang - Sun Microsystems - Beijing China rfilt = arn_calcrxfilter(sc); 159dd1de374Slin wang - Sun Microsystems - Beijing China ath9k_hw_setrxfilter(ah, rfilt); 160dd1de374Slin wang - Sun Microsystems - Beijing China 161dd1de374Slin wang - Sun Microsystems - Beijing China /* configure bssid mask */ 162dd1de374Slin wang - Sun Microsystems - Beijing China if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) 163dd1de374Slin wang - Sun Microsystems - Beijing China (void) ath9k_hw_setbssidmask(ah, sc->sc_bssidmask); 164dd1de374Slin wang - Sun Microsystems - Beijing China 165dd1de374Slin wang - Sun Microsystems - Beijing China /* configure operational mode */ 166dd1de374Slin wang - Sun Microsystems - Beijing China ath9k_hw_setopmode(ah); 167dd1de374Slin wang - Sun Microsystems - Beijing China 168dd1de374Slin wang - Sun Microsystems - Beijing China /* Handle any link-level address change. */ 169dd1de374Slin wang - Sun Microsystems - Beijing China (void) ath9k_hw_setmac(ah, sc->sc_myaddr); 170dd1de374Slin wang - Sun Microsystems - Beijing China 171dd1de374Slin wang - Sun Microsystems - Beijing China /* calculate and install multicast filter */ 172dd1de374Slin wang - Sun Microsystems - Beijing China mfilt[0] = ~((uint32_t)0); /* LINT */ 173dd1de374Slin wang - Sun Microsystems - Beijing China mfilt[1] = ~((uint32_t)0); /* LINT */ 174dd1de374Slin wang - Sun Microsystems - Beijing China 175dd1de374Slin wang - Sun Microsystems - Beijing China ath9k_hw_setmcastfilter(ah, mfilt[0], mfilt[1]); 176dd1de374Slin wang - Sun Microsystems - Beijing China 177dd1de374Slin wang - Sun Microsystems - Beijing China ARN_DBG((ARN_DBG_RECV, "arn: arn_opmode_init(): " 178dd1de374Slin wang - Sun Microsystems - Beijing China "mode = %d RX filter 0x%x, MC filter %08x:%08x\n", 179dd1de374Slin wang - Sun Microsystems - Beijing China ic->ic_opmode, rfilt, mfilt[0], mfilt[1])); 180dd1de374Slin wang - Sun Microsystems - Beijing China } 181dd1de374Slin wang - Sun Microsystems - Beijing China 182dd1de374Slin wang - Sun Microsystems - Beijing China /* 183dd1de374Slin wang - Sun Microsystems - Beijing China * Calculate the receive filter according to the 184dd1de374Slin wang - Sun Microsystems - Beijing China * operating mode and state: 185dd1de374Slin wang - Sun Microsystems - Beijing China * 186dd1de374Slin wang - Sun Microsystems - Beijing China * o always accept unicast, broadcast, and multicast traffic 187dd1de374Slin wang - Sun Microsystems - Beijing China * o maintain current state of phy error reception (the hal 188dd1de374Slin wang - Sun Microsystems - Beijing China * may enable phy error frames for noise immunity work) 189dd1de374Slin wang - Sun Microsystems - Beijing China * o probe request frames are accepted only when operating in 190dd1de374Slin wang - Sun Microsystems - Beijing China * hostap, adhoc, or monitor modes 191dd1de374Slin wang - Sun Microsystems - Beijing China * o enable promiscuous mode according to the interface state 192dd1de374Slin wang - Sun Microsystems - Beijing China * o accept beacons: 193dd1de374Slin wang - Sun Microsystems - Beijing China * - when operating in adhoc mode so the 802.11 layer creates 194dd1de374Slin wang - Sun Microsystems - Beijing China * node table entries for peers, 195dd1de374Slin wang - Sun Microsystems - Beijing China * - when operating in station mode for collecting rssi data when 196dd1de374Slin wang - Sun Microsystems - Beijing China * the station is otherwise quiet, or 197dd1de374Slin wang - Sun Microsystems - Beijing China * - when operating as a repeater so we see repeater-sta beacons 198dd1de374Slin wang - Sun Microsystems - Beijing China * - when scanning 199dd1de374Slin wang - Sun Microsystems - Beijing China */ 200dd1de374Slin wang - Sun Microsystems - Beijing China 201dd1de374Slin wang - Sun Microsystems - Beijing China uint32_t 202dd1de374Slin wang - Sun Microsystems - Beijing China arn_calcrxfilter(struct arn_softc *sc) 203dd1de374Slin wang - Sun Microsystems - Beijing China { 204dd1de374Slin wang - Sun Microsystems - Beijing China #define RX_FILTER_PRESERVE (ATH9K_RX_FILTER_PHYERR | \ 205dd1de374Slin wang - Sun Microsystems - Beijing China ATH9K_RX_FILTER_PHYRADAR) 206dd1de374Slin wang - Sun Microsystems - Beijing China 207dd1de374Slin wang - Sun Microsystems - Beijing China uint32_t rfilt; 208dd1de374Slin wang - Sun Microsystems - Beijing China 209dd1de374Slin wang - Sun Microsystems - Beijing China rfilt = (ath9k_hw_getrxfilter(sc->sc_ah) & RX_FILTER_PRESERVE) | 210dd1de374Slin wang - Sun Microsystems - Beijing China ATH9K_RX_FILTER_UCAST | ATH9K_RX_FILTER_BCAST | 211dd1de374Slin wang - Sun Microsystems - Beijing China ATH9K_RX_FILTER_MCAST; 212dd1de374Slin wang - Sun Microsystems - Beijing China 213dd1de374Slin wang - Sun Microsystems - Beijing China /* If not a STA, enable processing of Probe Requests */ 214dd1de374Slin wang - Sun Microsystems - Beijing China if (sc->sc_ah->ah_opmode != ATH9K_M_STA) 215dd1de374Slin wang - Sun Microsystems - Beijing China rfilt |= ATH9K_RX_FILTER_PROBEREQ; 216dd1de374Slin wang - Sun Microsystems - Beijing China 217dd1de374Slin wang - Sun Microsystems - Beijing China /* Can't set HOSTAP into promiscous mode */ 218dd1de374Slin wang - Sun Microsystems - Beijing China if (((sc->sc_ah->ah_opmode != ATH9K_M_HOSTAP) && 219dd1de374Slin wang - Sun Microsystems - Beijing China (sc->sc_promisc)) || 220dd1de374Slin wang - Sun Microsystems - Beijing China (sc->sc_ah->ah_opmode == ATH9K_M_MONITOR)) { 221dd1de374Slin wang - Sun Microsystems - Beijing China rfilt |= ATH9K_RX_FILTER_PROM; 222dd1de374Slin wang - Sun Microsystems - Beijing China /* ??? To prevent from sending ACK */ 223dd1de374Slin wang - Sun Microsystems - Beijing China rfilt &= ~ATH9K_RX_FILTER_UCAST; 224dd1de374Slin wang - Sun Microsystems - Beijing China } 225dd1de374Slin wang - Sun Microsystems - Beijing China 226dd1de374Slin wang - Sun Microsystems - Beijing China if (sc->sc_ah->ah_opmode == ATH9K_M_STA || 227dd1de374Slin wang - Sun Microsystems - Beijing China sc->sc_ah->ah_opmode == ATH9K_M_IBSS) 228dd1de374Slin wang - Sun Microsystems - Beijing China rfilt |= ATH9K_RX_FILTER_BEACON; 229dd1de374Slin wang - Sun Microsystems - Beijing China 230dd1de374Slin wang - Sun Microsystems - Beijing China /* 231dd1de374Slin wang - Sun Microsystems - Beijing China * If in HOSTAP mode, want to enable reception of PSPOLL 232dd1de374Slin wang - Sun Microsystems - Beijing China * frames & beacon frames 233dd1de374Slin wang - Sun Microsystems - Beijing China */ 234dd1de374Slin wang - Sun Microsystems - Beijing China if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP) 235dd1de374Slin wang - Sun Microsystems - Beijing China rfilt |= (ATH9K_RX_FILTER_BEACON | ATH9K_RX_FILTER_PSPOLL); 236dd1de374Slin wang - Sun Microsystems - Beijing China 237dd1de374Slin wang - Sun Microsystems - Beijing China return (rfilt); 238dd1de374Slin wang - Sun Microsystems - Beijing China 239dd1de374Slin wang - Sun Microsystems - Beijing China #undef RX_FILTER_PRESERVE 240dd1de374Slin wang - Sun Microsystems - Beijing China } 241dd1de374Slin wang - Sun Microsystems - Beijing China 242*c0c93480Slin wang - Sun Microsystems - Beijing China /* 243*c0c93480Slin wang - Sun Microsystems - Beijing China * When block ACK agreement has been set up between station and AP, 244*c0c93480Slin wang - Sun Microsystems - Beijing China * Net80211 module will call this function to inform hardware about 245*c0c93480Slin wang - Sun Microsystems - Beijing China * informations of this BA agreement. 246*c0c93480Slin wang - Sun Microsystems - Beijing China * When AP wants to delete BA agreement that was originated by it, 247*c0c93480Slin wang - Sun Microsystems - Beijing China * Net80211 modele will call this function to clean up relevant 248*c0c93480Slin wang - Sun Microsystems - Beijing China * information in hardware. 249*c0c93480Slin wang - Sun Microsystems - Beijing China */ 250*c0c93480Slin wang - Sun Microsystems - Beijing China 251*c0c93480Slin wang - Sun Microsystems - Beijing China void 252*c0c93480Slin wang - Sun Microsystems - Beijing China arn_ampdu_recv_action(struct ieee80211_node *in, 253*c0c93480Slin wang - Sun Microsystems - Beijing China const uint8_t *frm, 254*c0c93480Slin wang - Sun Microsystems - Beijing China const uint8_t *efrm) 255*c0c93480Slin wang - Sun Microsystems - Beijing China { 256*c0c93480Slin wang - Sun Microsystems - Beijing China struct ieee80211com *ic; 257*c0c93480Slin wang - Sun Microsystems - Beijing China struct arn_softc *sc; 258*c0c93480Slin wang - Sun Microsystems - Beijing China 259*c0c93480Slin wang - Sun Microsystems - Beijing China if ((in == NULL) || (frm == NULL) || (ic = in->in_ic) == NULL) { 260*c0c93480Slin wang - Sun Microsystems - Beijing China ARN_DBG((ARN_DBG_FATAL, 261*c0c93480Slin wang - Sun Microsystems - Beijing China "Unknown AMPDU action or NULL node index\n")); 262*c0c93480Slin wang - Sun Microsystems - Beijing China return; 263*c0c93480Slin wang - Sun Microsystems - Beijing China } 264*c0c93480Slin wang - Sun Microsystems - Beijing China 265*c0c93480Slin wang - Sun Microsystems - Beijing China sc = (struct arn_softc *)ic; 266*c0c93480Slin wang - Sun Microsystems - Beijing China 267*c0c93480Slin wang - Sun Microsystems - Beijing China if (!(sc->sc_flags & SC_OP_RXAGGR)) 268*c0c93480Slin wang - Sun Microsystems - Beijing China return; 269*c0c93480Slin wang - Sun Microsystems - Beijing China else 270*c0c93480Slin wang - Sun Microsystems - Beijing China sc->sc_recv_action(in, frm, efrm); 271*c0c93480Slin wang - Sun Microsystems - Beijing China } 272*c0c93480Slin wang - Sun Microsystems - Beijing China 273dd1de374Slin wang - Sun Microsystems - Beijing China int 274dd1de374Slin wang - Sun Microsystems - Beijing China arn_startrecv(struct arn_softc *sc) 275dd1de374Slin wang - Sun Microsystems - Beijing China { 276dd1de374Slin wang - Sun Microsystems - Beijing China struct ath_hal *ah = sc->sc_ah; 277dd1de374Slin wang - Sun Microsystems - Beijing China struct ath_buf *bf; 278dd1de374Slin wang - Sun Microsystems - Beijing China 279*c0c93480Slin wang - Sun Microsystems - Beijing China /* rx descriptor link set up */ 280*c0c93480Slin wang - Sun Microsystems - Beijing China mutex_enter(&sc->sc_rxbuflock); 281*c0c93480Slin wang - Sun Microsystems - Beijing China if (list_empty(&sc->sc_rxbuf_list)) 282*c0c93480Slin wang - Sun Microsystems - Beijing China goto start_recv; 283*c0c93480Slin wang - Sun Microsystems - Beijing China 284dd1de374Slin wang - Sun Microsystems - Beijing China /* clean up rx link firstly */ 285dd1de374Slin wang - Sun Microsystems - Beijing China sc->sc_rxlink = NULL; 286dd1de374Slin wang - Sun Microsystems - Beijing China 287dd1de374Slin wang - Sun Microsystems - Beijing China bf = list_head(&sc->sc_rxbuf_list); 288dd1de374Slin wang - Sun Microsystems - Beijing China while (bf != NULL) { 289dd1de374Slin wang - Sun Microsystems - Beijing China arn_rx_buf_link(sc, bf); 290dd1de374Slin wang - Sun Microsystems - Beijing China bf = list_next(&sc->sc_rxbuf_list, bf); 291dd1de374Slin wang - Sun Microsystems - Beijing China } 292dd1de374Slin wang - Sun Microsystems - Beijing China 293*c0c93480Slin wang - Sun Microsystems - Beijing China 294*c0c93480Slin wang - Sun Microsystems - Beijing China /* We could have deleted elements so the list may be empty now */ 295*c0c93480Slin wang - Sun Microsystems - Beijing China if (list_empty(&sc->sc_rxbuf_list)) 296*c0c93480Slin wang - Sun Microsystems - Beijing China goto start_recv; 297*c0c93480Slin wang - Sun Microsystems - Beijing China 298dd1de374Slin wang - Sun Microsystems - Beijing China bf = list_head(&sc->sc_rxbuf_list); 299dd1de374Slin wang - Sun Microsystems - Beijing China 300dd1de374Slin wang - Sun Microsystems - Beijing China ath9k_hw_putrxbuf(ah, bf->bf_daddr); 301dd1de374Slin wang - Sun Microsystems - Beijing China ath9k_hw_rxena(ah); 302dd1de374Slin wang - Sun Microsystems - Beijing China 303*c0c93480Slin wang - Sun Microsystems - Beijing China start_recv: 304*c0c93480Slin wang - Sun Microsystems - Beijing China mutex_exit(&sc->sc_rxbuflock); 305dd1de374Slin wang - Sun Microsystems - Beijing China arn_opmode_init(sc); 306dd1de374Slin wang - Sun Microsystems - Beijing China ath9k_hw_startpcureceive(ah); 307dd1de374Slin wang - Sun Microsystems - Beijing China 308dd1de374Slin wang - Sun Microsystems - Beijing China return (0); 309dd1de374Slin wang - Sun Microsystems - Beijing China } 310dd1de374Slin wang - Sun Microsystems - Beijing China 311dd1de374Slin wang - Sun Microsystems - Beijing China boolean_t 312dd1de374Slin wang - Sun Microsystems - Beijing China arn_stoprecv(struct arn_softc *sc) 313dd1de374Slin wang - Sun Microsystems - Beijing China { 314dd1de374Slin wang - Sun Microsystems - Beijing China struct ath_hal *ah = sc->sc_ah; 315dd1de374Slin wang - Sun Microsystems - Beijing China boolean_t stopped; 316dd1de374Slin wang - Sun Microsystems - Beijing China 317dd1de374Slin wang - Sun Microsystems - Beijing China ath9k_hw_stoppcurecv(ah); 318dd1de374Slin wang - Sun Microsystems - Beijing China ath9k_hw_setrxfilter(ah, 0); 319dd1de374Slin wang - Sun Microsystems - Beijing China stopped = ath9k_hw_stopdmarecv(ah); 320dd1de374Slin wang - Sun Microsystems - Beijing China 321dd1de374Slin wang - Sun Microsystems - Beijing China /* 3ms is long enough for 1 frame ??? */ 322dd1de374Slin wang - Sun Microsystems - Beijing China drv_usecwait(3000); 323dd1de374Slin wang - Sun Microsystems - Beijing China 324dd1de374Slin wang - Sun Microsystems - Beijing China sc->sc_rxlink = NULL; 325dd1de374Slin wang - Sun Microsystems - Beijing China 326dd1de374Slin wang - Sun Microsystems - Beijing China return (stopped); 327dd1de374Slin wang - Sun Microsystems - Beijing China } 328dd1de374Slin wang - Sun Microsystems - Beijing China 329dd1de374Slin wang - Sun Microsystems - Beijing China /* 330dd1de374Slin wang - Sun Microsystems - Beijing China * Intercept management frames to collect beacon rssi data 331dd1de374Slin wang - Sun Microsystems - Beijing China * and to do ibss merges. 332dd1de374Slin wang - Sun Microsystems - Beijing China */ 333dd1de374Slin wang - Sun Microsystems - Beijing China 334dd1de374Slin wang - Sun Microsystems - Beijing China void 335dd1de374Slin wang - Sun Microsystems - Beijing China arn_recv_mgmt(struct ieee80211com *ic, mblk_t *mp, struct ieee80211_node *in, 336dd1de374Slin wang - Sun Microsystems - Beijing China int subtype, int rssi, uint32_t rstamp) 337dd1de374Slin wang - Sun Microsystems - Beijing China { 338dd1de374Slin wang - Sun Microsystems - Beijing China struct arn_softc *sc = (struct arn_softc *)ic; 339dd1de374Slin wang - Sun Microsystems - Beijing China 340dd1de374Slin wang - Sun Microsystems - Beijing China /* 341dd1de374Slin wang - Sun Microsystems - Beijing China * Call up first so subsequent work can use information 342dd1de374Slin wang - Sun Microsystems - Beijing China * potentially stored in the node (e.g. for ibss merge). 343dd1de374Slin wang - Sun Microsystems - Beijing China */ 344dd1de374Slin wang - Sun Microsystems - Beijing China sc->sc_recv_mgmt(ic, mp, in, subtype, rssi, rstamp); 345dd1de374Slin wang - Sun Microsystems - Beijing China 346dd1de374Slin wang - Sun Microsystems - Beijing China ARN_LOCK(sc); 347dd1de374Slin wang - Sun Microsystems - Beijing China switch (subtype) { 348dd1de374Slin wang - Sun Microsystems - Beijing China case IEEE80211_FC0_SUBTYPE_BEACON: 349dd1de374Slin wang - Sun Microsystems - Beijing China /* update rssi statistics */ 350dd1de374Slin wang - Sun Microsystems - Beijing China if (sc->sc_bsync && in == ic->ic_bss && 351dd1de374Slin wang - Sun Microsystems - Beijing China ic->ic_state == IEEE80211_S_RUN) { 352dd1de374Slin wang - Sun Microsystems - Beijing China /* 353dd1de374Slin wang - Sun Microsystems - Beijing China * Resync beacon timers using the tsf of the beacon 354dd1de374Slin wang - Sun Microsystems - Beijing China * frame we just received. 355dd1de374Slin wang - Sun Microsystems - Beijing China */ 356dd1de374Slin wang - Sun Microsystems - Beijing China arn_beacon_config(sc); 357dd1de374Slin wang - Sun Microsystems - Beijing China } 358dd1de374Slin wang - Sun Microsystems - Beijing China /* FALLTHRU */ 359dd1de374Slin wang - Sun Microsystems - Beijing China case IEEE80211_FC0_SUBTYPE_PROBE_RESP: 360dd1de374Slin wang - Sun Microsystems - Beijing China if (ic->ic_opmode == IEEE80211_M_IBSS && 361dd1de374Slin wang - Sun Microsystems - Beijing China ic->ic_state == IEEE80211_S_RUN && 362dd1de374Slin wang - Sun Microsystems - Beijing China (in->in_capinfo & IEEE80211_CAPINFO_IBSS)) { 363dd1de374Slin wang - Sun Microsystems - Beijing China uint64_t tsf = arn_extend_tsf(sc, rstamp); 364dd1de374Slin wang - Sun Microsystems - Beijing China /* 365dd1de374Slin wang - Sun Microsystems - Beijing China * Handle ibss merge as needed; check the tsf on the 366dd1de374Slin wang - Sun Microsystems - Beijing China * frame before attempting the merge. The 802.11 spec 367dd1de374Slin wang - Sun Microsystems - Beijing China * says the station should change it's bssid to match 368dd1de374Slin wang - Sun Microsystems - Beijing China * the oldest station with the same ssid, where oldest 369dd1de374Slin wang - Sun Microsystems - Beijing China * is determined by the tsf. Note that hardware 370dd1de374Slin wang - Sun Microsystems - Beijing China * reconfiguration happens through callback to 371dd1de374Slin wang - Sun Microsystems - Beijing China * ath_newstate as the state machine will go from 372dd1de374Slin wang - Sun Microsystems - Beijing China * RUN -> RUN when this happens. 373dd1de374Slin wang - Sun Microsystems - Beijing China */ 374dd1de374Slin wang - Sun Microsystems - Beijing China if (LE_64(in->in_tstamp.tsf) >= tsf) { 375dd1de374Slin wang - Sun Microsystems - Beijing China ARN_DBG((ARN_DBG_BEACON, "arn: arn_recv_mgmt:" 376dd1de374Slin wang - Sun Microsystems - Beijing China "ibss merge, rstamp %u tsf %lu " 377dd1de374Slin wang - Sun Microsystems - Beijing China "tstamp %lu\n", rstamp, tsf, 378dd1de374Slin wang - Sun Microsystems - Beijing China in->in_tstamp.tsf)); 379dd1de374Slin wang - Sun Microsystems - Beijing China ARN_UNLOCK(sc); 380dd1de374Slin wang - Sun Microsystems - Beijing China ARN_DBG((ARN_DBG_BEACON, "arn_recv_mgmt():" 381dd1de374Slin wang - Sun Microsystems - Beijing China "ibss_merge: rstamp=%d in_tstamp=%02x %02x" 382dd1de374Slin wang - Sun Microsystems - Beijing China " %02x %02x %02x %02x %02x %02x\n", 383dd1de374Slin wang - Sun Microsystems - Beijing China rstamp, in->in_tstamp.data[0], 384dd1de374Slin wang - Sun Microsystems - Beijing China in->in_tstamp.data[1], 385dd1de374Slin wang - Sun Microsystems - Beijing China in->in_tstamp.data[2], 386dd1de374Slin wang - Sun Microsystems - Beijing China in->in_tstamp.data[3], 387dd1de374Slin wang - Sun Microsystems - Beijing China in->in_tstamp.data[4], 388dd1de374Slin wang - Sun Microsystems - Beijing China in->in_tstamp.data[5], 389dd1de374Slin wang - Sun Microsystems - Beijing China in->in_tstamp.data[6], 390dd1de374Slin wang - Sun Microsystems - Beijing China in->in_tstamp.data[7])); 391dd1de374Slin wang - Sun Microsystems - Beijing China (void) ieee80211_ibss_merge(in); 392dd1de374Slin wang - Sun Microsystems - Beijing China return; 393dd1de374Slin wang - Sun Microsystems - Beijing China } 394dd1de374Slin wang - Sun Microsystems - Beijing China } 395dd1de374Slin wang - Sun Microsystems - Beijing China break; 396dd1de374Slin wang - Sun Microsystems - Beijing China } 397dd1de374Slin wang - Sun Microsystems - Beijing China ARN_UNLOCK(sc); 398dd1de374Slin wang - Sun Microsystems - Beijing China } 399dd1de374Slin wang - Sun Microsystems - Beijing China 400dd1de374Slin wang - Sun Microsystems - Beijing China static void 401dd1de374Slin wang - Sun Microsystems - Beijing China arn_printrxbuf(struct ath_buf *bf, int32_t done) 402dd1de374Slin wang - Sun Microsystems - Beijing China { 403dd1de374Slin wang - Sun Microsystems - Beijing China struct ath_desc *ds = bf->bf_desc; 404dd1de374Slin wang - Sun Microsystems - Beijing China const struct ath_rx_status *rs = &ds->ds_rxstat; 405dd1de374Slin wang - Sun Microsystems - Beijing China 406dd1de374Slin wang - Sun Microsystems - Beijing China ARN_DBG((ARN_DBG_RECV, "arn: R (%p %p) %08x %08x %08x " 407dd1de374Slin wang - Sun Microsystems - Beijing China "%08x %08x %08x %c\n", 408dd1de374Slin wang - Sun Microsystems - Beijing China ds, bf->bf_daddr, 409dd1de374Slin wang - Sun Microsystems - Beijing China ds->ds_link, ds->ds_data, 410dd1de374Slin wang - Sun Microsystems - Beijing China ds->ds_ctl0, ds->ds_ctl1, 411dd1de374Slin wang - Sun Microsystems - Beijing China ds->ds_hw[0], ds->ds_hw[1], 412dd1de374Slin wang - Sun Microsystems - Beijing China !done ? ' ' : (rs->rs_status == 0) ? '*' : '!')); 413dd1de374Slin wang - Sun Microsystems - Beijing China } 414dd1de374Slin wang - Sun Microsystems - Beijing China 415dd1de374Slin wang - Sun Microsystems - Beijing China static void 416dd1de374Slin wang - Sun Microsystems - Beijing China arn_rx_handler(struct arn_softc *sc) 417dd1de374Slin wang - Sun Microsystems - Beijing China { 418dd1de374Slin wang - Sun Microsystems - Beijing China #define PA2DESC(_sc, _pa) \ 419dd1de374Slin wang - Sun Microsystems - Beijing China ((struct ath_desc *)((caddr_t)(_sc)->sc_desc + \ 420dd1de374Slin wang - Sun Microsystems - Beijing China ((_pa) - (_sc)->sc_desc_dma.cookie.dmac_address))) 421dd1de374Slin wang - Sun Microsystems - Beijing China 422dd1de374Slin wang - Sun Microsystems - Beijing China ieee80211com_t *ic = (ieee80211com_t *)sc; 423dd1de374Slin wang - Sun Microsystems - Beijing China struct ath_buf *bf; 424dd1de374Slin wang - Sun Microsystems - Beijing China struct ath_hal *ah = sc->sc_ah; 425dd1de374Slin wang - Sun Microsystems - Beijing China struct ath_desc *ds; 426dd1de374Slin wang - Sun Microsystems - Beijing China struct ath_rx_status *rs; 427dd1de374Slin wang - Sun Microsystems - Beijing China mblk_t *rx_mp; 428dd1de374Slin wang - Sun Microsystems - Beijing China struct ieee80211_frame *wh; 429*c0c93480Slin wang - Sun Microsystems - Beijing China int32_t len, ngood = 0, loop = 1; 430*c0c93480Slin wang - Sun Microsystems - Beijing China uint32_t subtype; 431dd1de374Slin wang - Sun Microsystems - Beijing China int status; 432*c0c93480Slin wang - Sun Microsystems - Beijing China int last_rssi = ATH_RSSI_DUMMY_MARKER; 433*c0c93480Slin wang - Sun Microsystems - Beijing China struct ath_node *an; 434dd1de374Slin wang - Sun Microsystems - Beijing China struct ieee80211_node *in; 4353ae945c3Slin wang - Sun Microsystems - Beijing China uint32_t cur_signal; 436*c0c93480Slin wang - Sun Microsystems - Beijing China #ifdef ARN_DBG_AMSDU 437*c0c93480Slin wang - Sun Microsystems - Beijing China uint8_t qos; 438*c0c93480Slin wang - Sun Microsystems - Beijing China #endif 439dd1de374Slin wang - Sun Microsystems - Beijing China 440dd1de374Slin wang - Sun Microsystems - Beijing China do { 441dd1de374Slin wang - Sun Microsystems - Beijing China mutex_enter(&sc->sc_rxbuflock); 442dd1de374Slin wang - Sun Microsystems - Beijing China bf = list_head(&sc->sc_rxbuf_list); 443dd1de374Slin wang - Sun Microsystems - Beijing China if (bf == NULL) { 444dd1de374Slin wang - Sun Microsystems - Beijing China ARN_DBG((ARN_DBG_RECV, "arn: arn_rx_handler(): " 445dd1de374Slin wang - Sun Microsystems - Beijing China "no buffer\n")); 446*c0c93480Slin wang - Sun Microsystems - Beijing China sc->sc_rxlink = NULL; 447dd1de374Slin wang - Sun Microsystems - Beijing China mutex_exit(&sc->sc_rxbuflock); 448dd1de374Slin wang - Sun Microsystems - Beijing China break; 449dd1de374Slin wang - Sun Microsystems - Beijing China } 450dd1de374Slin wang - Sun Microsystems - Beijing China ASSERT(bf->bf_dma.cookie.dmac_address != NULL); 451dd1de374Slin wang - Sun Microsystems - Beijing China ds = bf->bf_desc; 452dd1de374Slin wang - Sun Microsystems - Beijing China 453dd1de374Slin wang - Sun Microsystems - Beijing China /* 454dd1de374Slin wang - Sun Microsystems - Beijing China * Must provide the virtual address of the current 455dd1de374Slin wang - Sun Microsystems - Beijing China * descriptor, the physical address, and the virtual 456dd1de374Slin wang - Sun Microsystems - Beijing China * address of the next descriptor in the h/w chain. 457dd1de374Slin wang - Sun Microsystems - Beijing China * This allows the HAL to look ahead to see if the 458dd1de374Slin wang - Sun Microsystems - Beijing China * hardware is done with a descriptor by checking the 459dd1de374Slin wang - Sun Microsystems - Beijing China * done bit in the following descriptor and the address 460dd1de374Slin wang - Sun Microsystems - Beijing China * of the current descriptor the DMA engine is working 461dd1de374Slin wang - Sun Microsystems - Beijing China * on. All this is necessary because of our use of 462dd1de374Slin wang - Sun Microsystems - Beijing China * a self-linked list to avoid rx overruns. 463dd1de374Slin wang - Sun Microsystems - Beijing China */ 464dd1de374Slin wang - Sun Microsystems - Beijing China status = ath9k_hw_rxprocdesc(ah, ds, 465dd1de374Slin wang - Sun Microsystems - Beijing China bf->bf_daddr, 466dd1de374Slin wang - Sun Microsystems - Beijing China PA2DESC(sc, ds->ds_link), 0); 467dd1de374Slin wang - Sun Microsystems - Beijing China if (status == EINPROGRESS) { 468*c0c93480Slin wang - Sun Microsystems - Beijing China struct ath_buf *tbf; 469*c0c93480Slin wang - Sun Microsystems - Beijing China struct ath_desc *tds; 470*c0c93480Slin wang - Sun Microsystems - Beijing China 471*c0c93480Slin wang - Sun Microsystems - Beijing China if (list_is_last(&bf->bf_node, &sc->sc_rxbuf_list)) { 472*c0c93480Slin wang - Sun Microsystems - Beijing China ARN_DBG((ARN_DBG_RECV, "arn: arn_rx_handler(): " 473*c0c93480Slin wang - Sun Microsystems - Beijing China "List is in last! \n")); 474*c0c93480Slin wang - Sun Microsystems - Beijing China sc->sc_rxlink = NULL; 475*c0c93480Slin wang - Sun Microsystems - Beijing China break; 476*c0c93480Slin wang - Sun Microsystems - Beijing China } 477*c0c93480Slin wang - Sun Microsystems - Beijing China 478*c0c93480Slin wang - Sun Microsystems - Beijing China tbf = list_object(&sc->sc_rxbuf_list, 479*c0c93480Slin wang - Sun Microsystems - Beijing China bf->bf_node.list_next); 480*c0c93480Slin wang - Sun Microsystems - Beijing China 481*c0c93480Slin wang - Sun Microsystems - Beijing China /* 482*c0c93480Slin wang - Sun Microsystems - Beijing China * On some hardware the descriptor status words could 483*c0c93480Slin wang - Sun Microsystems - Beijing China * get corrupted, including the done bit. Because of 484*c0c93480Slin wang - Sun Microsystems - Beijing China * this, check if the next descriptor's done bit is 485*c0c93480Slin wang - Sun Microsystems - Beijing China * set or not. 486*c0c93480Slin wang - Sun Microsystems - Beijing China * 487*c0c93480Slin wang - Sun Microsystems - Beijing China * If the next descriptor's done bit is set, the current 488*c0c93480Slin wang - Sun Microsystems - Beijing China * descriptor has been corrupted. Force s/w to discard 489*c0c93480Slin wang - Sun Microsystems - Beijing China * this descriptor and continue... 490*c0c93480Slin wang - Sun Microsystems - Beijing China */ 491*c0c93480Slin wang - Sun Microsystems - Beijing China 492*c0c93480Slin wang - Sun Microsystems - Beijing China tds = tbf->bf_desc; 493*c0c93480Slin wang - Sun Microsystems - Beijing China status = ath9k_hw_rxprocdesc(ah, tds, tbf->bf_daddr, 494*c0c93480Slin wang - Sun Microsystems - Beijing China PA2DESC(sc, tds->ds_link), 0); 495*c0c93480Slin wang - Sun Microsystems - Beijing China if (status == EINPROGRESS) { 496dd1de374Slin wang - Sun Microsystems - Beijing China mutex_exit(&sc->sc_rxbuflock); 497dd1de374Slin wang - Sun Microsystems - Beijing China break; 498dd1de374Slin wang - Sun Microsystems - Beijing China } 499*c0c93480Slin wang - Sun Microsystems - Beijing China } 500dd1de374Slin wang - Sun Microsystems - Beijing China list_remove(&sc->sc_rxbuf_list, bf); 501dd1de374Slin wang - Sun Microsystems - Beijing China mutex_exit(&sc->sc_rxbuflock); 502dd1de374Slin wang - Sun Microsystems - Beijing China 503dd1de374Slin wang - Sun Microsystems - Beijing China rs = &ds->ds_rxstat; 504dd1de374Slin wang - Sun Microsystems - Beijing China len = rs->rs_datalen; 505dd1de374Slin wang - Sun Microsystems - Beijing China 506dd1de374Slin wang - Sun Microsystems - Beijing China /* less than sizeof(struct ieee80211_frame) */ 507dd1de374Slin wang - Sun Microsystems - Beijing China if (len < 20) { 508dd1de374Slin wang - Sun Microsystems - Beijing China sc->sc_stats.ast_rx_tooshort++; 509*c0c93480Slin wang - Sun Microsystems - Beijing China goto requeue; 510dd1de374Slin wang - Sun Microsystems - Beijing China } 511dd1de374Slin wang - Sun Microsystems - Beijing China 512*c0c93480Slin wang - Sun Microsystems - Beijing China /* The status portion of the descriptor could get corrupted. */ 513*c0c93480Slin wang - Sun Microsystems - Beijing China if (sc->rx_dmabuf_size < rs->rs_datalen) { 514*c0c93480Slin wang - Sun Microsystems - Beijing China arn_problem("Requeued because of wrong rs_datalen\n"); 515*c0c93480Slin wang - Sun Microsystems - Beijing China goto requeue; 516*c0c93480Slin wang - Sun Microsystems - Beijing China } 517*c0c93480Slin wang - Sun Microsystems - Beijing China 518*c0c93480Slin wang - Sun Microsystems - Beijing China if (!arn_rx_prepare(ds, sc)) 519*c0c93480Slin wang - Sun Microsystems - Beijing China goto requeue; 520*c0c93480Slin wang - Sun Microsystems - Beijing China 521*c0c93480Slin wang - Sun Microsystems - Beijing China if ((rx_mp = allocb(sc->rx_dmabuf_size, BPRI_MED)) == NULL) { 522dd1de374Slin wang - Sun Microsystems - Beijing China arn_problem("arn: arn_rx_handler(): " 523dd1de374Slin wang - Sun Microsystems - Beijing China "allocing mblk buffer failed.\n"); 524dd1de374Slin wang - Sun Microsystems - Beijing China return; 525dd1de374Slin wang - Sun Microsystems - Beijing China } 526dd1de374Slin wang - Sun Microsystems - Beijing China 527dd1de374Slin wang - Sun Microsystems - Beijing China ARN_DMA_SYNC(bf->bf_dma, DDI_DMA_SYNC_FORCPU); 528dd1de374Slin wang - Sun Microsystems - Beijing China bcopy(bf->bf_dma.mem_va, rx_mp->b_rptr, len); 529dd1de374Slin wang - Sun Microsystems - Beijing China 530dd1de374Slin wang - Sun Microsystems - Beijing China rx_mp->b_wptr += len; 531dd1de374Slin wang - Sun Microsystems - Beijing China wh = (struct ieee80211_frame *)rx_mp->b_rptr; 532dd1de374Slin wang - Sun Microsystems - Beijing China 533dd1de374Slin wang - Sun Microsystems - Beijing China if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == 534dd1de374Slin wang - Sun Microsystems - Beijing China IEEE80211_FC0_TYPE_CTL) { 535dd1de374Slin wang - Sun Microsystems - Beijing China /* 536dd1de374Slin wang - Sun Microsystems - Beijing China * Ignore control frame received in promisc mode. 537dd1de374Slin wang - Sun Microsystems - Beijing China */ 538dd1de374Slin wang - Sun Microsystems - Beijing China freemsg(rx_mp); 539*c0c93480Slin wang - Sun Microsystems - Beijing China goto requeue; 540dd1de374Slin wang - Sun Microsystems - Beijing China } 541dd1de374Slin wang - Sun Microsystems - Beijing China /* Remove the CRC at the end of IEEE80211 frame */ 542dd1de374Slin wang - Sun Microsystems - Beijing China rx_mp->b_wptr -= IEEE80211_CRC_LEN; 543dd1de374Slin wang - Sun Microsystems - Beijing China 544*c0c93480Slin wang - Sun Microsystems - Beijing China #ifdef DEBUG 545*c0c93480Slin wang - Sun Microsystems - Beijing China arn_printrxbuf(bf, status == 0); 546*c0c93480Slin wang - Sun Microsystems - Beijing China #endif 547*c0c93480Slin wang - Sun Microsystems - Beijing China 548*c0c93480Slin wang - Sun Microsystems - Beijing China #ifdef ARN_DBG_AMSDU 549*c0c93480Slin wang - Sun Microsystems - Beijing China if (IEEE80211_IS_DATA_QOS(wh)) { 550*c0c93480Slin wang - Sun Microsystems - Beijing China if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == 551*c0c93480Slin wang - Sun Microsystems - Beijing China IEEE80211_FC1_DIR_DSTODS) 552*c0c93480Slin wang - Sun Microsystems - Beijing China qos = ((struct ieee80211_qosframe_addr4 *) 553*c0c93480Slin wang - Sun Microsystems - Beijing China wh)->i_qos[0]; 554*c0c93480Slin wang - Sun Microsystems - Beijing China else 555*c0c93480Slin wang - Sun Microsystems - Beijing China qos = 556*c0c93480Slin wang - Sun Microsystems - Beijing China ((struct ieee80211_qosframe *)wh)->i_qos[0]; 557*c0c93480Slin wang - Sun Microsystems - Beijing China 558*c0c93480Slin wang - Sun Microsystems - Beijing China if (qos & IEEE80211_QOS_AMSDU) 559*c0c93480Slin wang - Sun Microsystems - Beijing China arn_dump_pkg((unsigned char *)bf->bf_dma.mem_va, 560*c0c93480Slin wang - Sun Microsystems - Beijing China len, 1, 1); 561*c0c93480Slin wang - Sun Microsystems - Beijing China } 562*c0c93480Slin wang - Sun Microsystems - Beijing China #endif /* ARN_DBG_AMSDU */ 563*c0c93480Slin wang - Sun Microsystems - Beijing China 564dd1de374Slin wang - Sun Microsystems - Beijing China /* 565dd1de374Slin wang - Sun Microsystems - Beijing China * Locate the node for sender, track state, and then 566dd1de374Slin wang - Sun Microsystems - Beijing China * pass the (referenced) node up to the 802.11 layer 567dd1de374Slin wang - Sun Microsystems - Beijing China * for its use. 568dd1de374Slin wang - Sun Microsystems - Beijing China */ 569dd1de374Slin wang - Sun Microsystems - Beijing China in = ieee80211_find_rxnode(ic, wh); 570*c0c93480Slin wang - Sun Microsystems - Beijing China an = ATH_NODE(in); 571*c0c93480Slin wang - Sun Microsystems - Beijing China 572*c0c93480Slin wang - Sun Microsystems - Beijing China /* 573*c0c93480Slin wang - Sun Microsystems - Beijing China * Theory for reporting quality: 574*c0c93480Slin wang - Sun Microsystems - Beijing China * 575*c0c93480Slin wang - Sun Microsystems - Beijing China * At a hardware RSSI of 45 you will be able to use 576*c0c93480Slin wang - Sun Microsystems - Beijing China * MCS 7 reliably. 577*c0c93480Slin wang - Sun Microsystems - Beijing China * At a hardware RSSI of 45 you will be able to use 578*c0c93480Slin wang - Sun Microsystems - Beijing China * MCS 15 reliably. 579*c0c93480Slin wang - Sun Microsystems - Beijing China * At a hardware RSSI of 35 you should be able use 580*c0c93480Slin wang - Sun Microsystems - Beijing China * 54 Mbps reliably. 581*c0c93480Slin wang - Sun Microsystems - Beijing China * 582*c0c93480Slin wang - Sun Microsystems - Beijing China * MCS 7 is the highets MCS index usable by a 1-stream device. 583*c0c93480Slin wang - Sun Microsystems - Beijing China * MCS 15 is the highest MCS index usable by a 2-stream device. 584*c0c93480Slin wang - Sun Microsystems - Beijing China * 585*c0c93480Slin wang - Sun Microsystems - Beijing China * All ath9k devices are either 1-stream or 2-stream. 586*c0c93480Slin wang - Sun Microsystems - Beijing China * 587*c0c93480Slin wang - Sun Microsystems - Beijing China * How many bars you see is derived from the qual reporting. 588*c0c93480Slin wang - Sun Microsystems - Beijing China * 589*c0c93480Slin wang - Sun Microsystems - Beijing China * A more elaborate scheme can be used here but it requires 590*c0c93480Slin wang - Sun Microsystems - Beijing China * tables of SNR/throughput for each possible mode used. For 591*c0c93480Slin wang - Sun Microsystems - Beijing China * the MCS table you can refer to the wireless wiki: 592*c0c93480Slin wang - Sun Microsystems - Beijing China * 593*c0c93480Slin wang - Sun Microsystems - Beijing China * http://wireless.kernel.org/en/developers/Documentation/ 594*c0c93480Slin wang - Sun Microsystems - Beijing China * ieee80211/802.11n 595*c0c93480Slin wang - Sun Microsystems - Beijing China */ 596*c0c93480Slin wang - Sun Microsystems - Beijing China if (ds->ds_rxstat.rs_rssi != ATH9K_RSSI_BAD && 597*c0c93480Slin wang - Sun Microsystems - Beijing China !ds->ds_rxstat.rs_moreaggr) { 598*c0c93480Slin wang - Sun Microsystems - Beijing China /* LINTED: E_CONSTANT_CONDITION */ 599*c0c93480Slin wang - Sun Microsystems - Beijing China ATH_RSSI_LPF(an->last_rssi, ds->ds_rxstat.rs_rssi); 600*c0c93480Slin wang - Sun Microsystems - Beijing China } 601*c0c93480Slin wang - Sun Microsystems - Beijing China last_rssi = an->last_rssi; 602*c0c93480Slin wang - Sun Microsystems - Beijing China 603*c0c93480Slin wang - Sun Microsystems - Beijing China if (last_rssi != ATH_RSSI_DUMMY_MARKER) 604*c0c93480Slin wang - Sun Microsystems - Beijing China ds->ds_rxstat.rs_rssi = ATH_EP_RND(last_rssi, 605*c0c93480Slin wang - Sun Microsystems - Beijing China ATH_RSSI_EP_MULTIPLIER); 606dd1de374Slin wang - Sun Microsystems - Beijing China 6073ae945c3Slin wang - Sun Microsystems - Beijing China if (ds->ds_rxstat.rs_rssi < 0) 6083ae945c3Slin wang - Sun Microsystems - Beijing China ds->ds_rxstat.rs_rssi = 0; 6093ae945c3Slin wang - Sun Microsystems - Beijing China 6103ae945c3Slin wang - Sun Microsystems - Beijing China if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == 6113ae945c3Slin wang - Sun Microsystems - Beijing China IEEE80211_FC0_TYPE_MGT) { 6123ae945c3Slin wang - Sun Microsystems - Beijing China subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; 6133ae945c3Slin wang - Sun Microsystems - Beijing China if (subtype == IEEE80211_FC0_SUBTYPE_BEACON) 6143ae945c3Slin wang - Sun Microsystems - Beijing China sc->sc_halstats.ns_avgbrssi = 6153ae945c3Slin wang - Sun Microsystems - Beijing China ds->ds_rxstat.rs_rssi; 6163ae945c3Slin wang - Sun Microsystems - Beijing China } 6173ae945c3Slin wang - Sun Microsystems - Beijing China 6183ae945c3Slin wang - Sun Microsystems - Beijing China /* 619*c0c93480Slin wang - Sun Microsystems - Beijing China * signal (13-15) DLADM_WLAN_STRENGTH_EXCELLENT 620*c0c93480Slin wang - Sun Microsystems - Beijing China * signal (10-12) DLADM_WLAN_STRENGTH_VERY_GOOD 621*c0c93480Slin wang - Sun Microsystems - Beijing China * signal (6-9) DLADM_WLAN_STRENGTH_GOOD 622*c0c93480Slin wang - Sun Microsystems - Beijing China * signal (3-5) DLADM_WLAN_STRENGTH_WEAK 623*c0c93480Slin wang - Sun Microsystems - Beijing China * signal (0-2) DLADM_WLAN_STRENGTH_VERY_WEAK 6243ae945c3Slin wang - Sun Microsystems - Beijing China */ 6253ae945c3Slin wang - Sun Microsystems - Beijing China if (rs->rs_rssi == 0) 6263ae945c3Slin wang - Sun Microsystems - Beijing China cur_signal = 0; 6273ae945c3Slin wang - Sun Microsystems - Beijing China else if (rs->rs_rssi >= 45) 6283ae945c3Slin wang - Sun Microsystems - Beijing China cur_signal = MAX_RSSI; 6293ae945c3Slin wang - Sun Microsystems - Beijing China else 6303ae945c3Slin wang - Sun Microsystems - Beijing China cur_signal = rs->rs_rssi * MAX_RSSI / 45 + 1; 6313ae945c3Slin wang - Sun Microsystems - Beijing China 632dd1de374Slin wang - Sun Microsystems - Beijing China /* 633dd1de374Slin wang - Sun Microsystems - Beijing China * Send the frame to net80211 for processing 634dd1de374Slin wang - Sun Microsystems - Beijing China */ 635*c0c93480Slin wang - Sun Microsystems - Beijing China if (cur_signal <= 2 && ic->ic_state == IEEE80211_S_RUN) { 6363ae945c3Slin wang - Sun Microsystems - Beijing China (void) ieee80211_input(ic, rx_mp, in, 6373ae945c3Slin wang - Sun Microsystems - Beijing China (rs->rs_rssi + 10), rs->rs_tstamp); 638*c0c93480Slin wang - Sun Microsystems - Beijing China } 6393ae945c3Slin wang - Sun Microsystems - Beijing China else 640*c0c93480Slin wang - Sun Microsystems - Beijing China (void) ieee80211_input(ic, rx_mp, in, rs->rs_rssi, 641*c0c93480Slin wang - Sun Microsystems - Beijing China rs->rs_tstamp); 642dd1de374Slin wang - Sun Microsystems - Beijing China 643dd1de374Slin wang - Sun Microsystems - Beijing China /* release node */ 644dd1de374Slin wang - Sun Microsystems - Beijing China ieee80211_free_node(in); 645dd1de374Slin wang - Sun Microsystems - Beijing China 646dd1de374Slin wang - Sun Microsystems - Beijing China /* 647dd1de374Slin wang - Sun Microsystems - Beijing China * Arrange to update the last rx timestamp only for 648dd1de374Slin wang - Sun Microsystems - Beijing China * frames from our ap when operating in station mode. 649dd1de374Slin wang - Sun Microsystems - Beijing China * This assumes the rx key is always setup when associated. 650dd1de374Slin wang - Sun Microsystems - Beijing China */ 651dd1de374Slin wang - Sun Microsystems - Beijing China if (ic->ic_opmode == IEEE80211_M_STA && 652dd1de374Slin wang - Sun Microsystems - Beijing China rs->rs_keyix != ATH9K_RXKEYIX_INVALID) { 653dd1de374Slin wang - Sun Microsystems - Beijing China ngood++; 654dd1de374Slin wang - Sun Microsystems - Beijing China } 655dd1de374Slin wang - Sun Microsystems - Beijing China 656dd1de374Slin wang - Sun Microsystems - Beijing China /* 657dd1de374Slin wang - Sun Microsystems - Beijing China * change the default rx antenna if rx diversity chooses the 658dd1de374Slin wang - Sun Microsystems - Beijing China * other antenna 3 times in a row. 659dd1de374Slin wang - Sun Microsystems - Beijing China */ 660dd1de374Slin wang - Sun Microsystems - Beijing China if (sc->sc_defant != ds->ds_rxstat.rs_antenna) { 661dd1de374Slin wang - Sun Microsystems - Beijing China if (++sc->sc_rxotherant >= 3) { 662dd1de374Slin wang - Sun Microsystems - Beijing China ath9k_hw_setantenna(sc->sc_ah, 663dd1de374Slin wang - Sun Microsystems - Beijing China ds->ds_rxstat.rs_antenna); 664dd1de374Slin wang - Sun Microsystems - Beijing China sc->sc_defant = ds->ds_rxstat.rs_antenna; 665dd1de374Slin wang - Sun Microsystems - Beijing China sc->sc_rxotherant = 0; 666dd1de374Slin wang - Sun Microsystems - Beijing China } 667dd1de374Slin wang - Sun Microsystems - Beijing China } else { 668dd1de374Slin wang - Sun Microsystems - Beijing China sc->sc_rxotherant = 0; 669dd1de374Slin wang - Sun Microsystems - Beijing China } 670dd1de374Slin wang - Sun Microsystems - Beijing China 671*c0c93480Slin wang - Sun Microsystems - Beijing China requeue: 672dd1de374Slin wang - Sun Microsystems - Beijing China mutex_enter(&sc->sc_rxbuflock); 673dd1de374Slin wang - Sun Microsystems - Beijing China list_insert_tail(&sc->sc_rxbuf_list, bf); 674dd1de374Slin wang - Sun Microsystems - Beijing China mutex_exit(&sc->sc_rxbuflock); 675dd1de374Slin wang - Sun Microsystems - Beijing China arn_rx_buf_link(sc, bf); 676dd1de374Slin wang - Sun Microsystems - Beijing China } while (loop); 677dd1de374Slin wang - Sun Microsystems - Beijing China 678dd1de374Slin wang - Sun Microsystems - Beijing China if (ngood) 679dd1de374Slin wang - Sun Microsystems - Beijing China sc->sc_lastrx = ath9k_hw_gettsf64(ah); 680dd1de374Slin wang - Sun Microsystems - Beijing China 681dd1de374Slin wang - Sun Microsystems - Beijing China #undef PA2DESC 682dd1de374Slin wang - Sun Microsystems - Beijing China } 683dd1de374Slin wang - Sun Microsystems - Beijing China 684dd1de374Slin wang - Sun Microsystems - Beijing China uint_t 685dd1de374Slin wang - Sun Microsystems - Beijing China arn_softint_handler(caddr_t data) 686dd1de374Slin wang - Sun Microsystems - Beijing China { 687dd1de374Slin wang - Sun Microsystems - Beijing China struct arn_softc *sc = (struct arn_softc *)data; 688dd1de374Slin wang - Sun Microsystems - Beijing China 689dd1de374Slin wang - Sun Microsystems - Beijing China ARN_LOCK(sc); 690dd1de374Slin wang - Sun Microsystems - Beijing China 691dd1de374Slin wang - Sun Microsystems - Beijing China if (sc->sc_rx_pend) { 692dd1de374Slin wang - Sun Microsystems - Beijing China /* Soft interrupt for this driver */ 693dd1de374Slin wang - Sun Microsystems - Beijing China sc->sc_rx_pend = 0; 694dd1de374Slin wang - Sun Microsystems - Beijing China ARN_UNLOCK(sc); 695dd1de374Slin wang - Sun Microsystems - Beijing China arn_rx_handler(sc); 696dd1de374Slin wang - Sun Microsystems - Beijing China return (DDI_INTR_CLAIMED); 697dd1de374Slin wang - Sun Microsystems - Beijing China } 698dd1de374Slin wang - Sun Microsystems - Beijing China 699dd1de374Slin wang - Sun Microsystems - Beijing China ARN_UNLOCK(sc); 700dd1de374Slin wang - Sun Microsystems - Beijing China 701dd1de374Slin wang - Sun Microsystems - Beijing China return (DDI_INTR_UNCLAIMED); 702dd1de374Slin wang - Sun Microsystems - Beijing China } 703