19999SWang.Lin@Sun.COM /*
2*11729SWang.Lin@Sun.COM * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
39999SWang.Lin@Sun.COM * Use is subject to license terms.
49999SWang.Lin@Sun.COM */
59999SWang.Lin@Sun.COM
69999SWang.Lin@Sun.COM /*
79999SWang.Lin@Sun.COM * Copyright (c) 2008 Atheros Communications Inc.
89999SWang.Lin@Sun.COM *
99999SWang.Lin@Sun.COM * Permission to use, copy, modify, and/or distribute this software for any
109999SWang.Lin@Sun.COM * purpose with or without fee is hereby granted, provided that the above
119999SWang.Lin@Sun.COM * copyright notice and this permission notice appear in all copies.
129999SWang.Lin@Sun.COM *
139999SWang.Lin@Sun.COM * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
149999SWang.Lin@Sun.COM * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
159999SWang.Lin@Sun.COM * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
169999SWang.Lin@Sun.COM * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
179999SWang.Lin@Sun.COM * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
189999SWang.Lin@Sun.COM * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
199999SWang.Lin@Sun.COM * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
209999SWang.Lin@Sun.COM */
219999SWang.Lin@Sun.COM
229999SWang.Lin@Sun.COM #include <sys/byteorder.h>
239999SWang.Lin@Sun.COM
249999SWang.Lin@Sun.COM #include "arn_core.h"
259999SWang.Lin@Sun.COM
26*11729SWang.Lin@Sun.COM /*
27*11729SWang.Lin@Sun.COM * Setup and link descriptors.
28*11729SWang.Lin@Sun.COM *
29*11729SWang.Lin@Sun.COM * 11N: we can no longer afford to self link the last descriptor.
30*11729SWang.Lin@Sun.COM * MAC acknowledges BA status as long as it copies frames to host
31*11729SWang.Lin@Sun.COM * buffer (or rx fifo). This can incorrectly acknowledge packets
32*11729SWang.Lin@Sun.COM * to a sender if last desc is self-linked.
33*11729SWang.Lin@Sun.COM */
34*11729SWang.Lin@Sun.COM void
arn_rx_buf_link(struct arn_softc * sc,struct ath_buf * bf)35*11729SWang.Lin@Sun.COM arn_rx_buf_link(struct arn_softc *sc, struct ath_buf *bf)
36*11729SWang.Lin@Sun.COM {
37*11729SWang.Lin@Sun.COM struct ath_desc *ds;
38*11729SWang.Lin@Sun.COM
39*11729SWang.Lin@Sun.COM ds = bf->bf_desc;
40*11729SWang.Lin@Sun.COM ds->ds_link = 0;
41*11729SWang.Lin@Sun.COM ds->ds_data = bf->bf_dma.cookie.dmac_address;
42*11729SWang.Lin@Sun.COM
43*11729SWang.Lin@Sun.COM /* virtual addr of the beginning of the buffer. */
44*11729SWang.Lin@Sun.COM ds->ds_vdata = bf->bf_dma.mem_va;
45*11729SWang.Lin@Sun.COM
46*11729SWang.Lin@Sun.COM /*
47*11729SWang.Lin@Sun.COM * setup rx descriptors. The bf_dma.alength here tells the H/W
48*11729SWang.Lin@Sun.COM * how much data it can DMA to us and that we are prepared
49*11729SWang.Lin@Sun.COM * to process
50*11729SWang.Lin@Sun.COM */
51*11729SWang.Lin@Sun.COM (void) ath9k_hw_setuprxdesc(sc->sc_ah, ds,
52*11729SWang.Lin@Sun.COM bf->bf_dma.alength, /* buffer size */
53*11729SWang.Lin@Sun.COM 0);
54*11729SWang.Lin@Sun.COM
55*11729SWang.Lin@Sun.COM if (sc->sc_rxlink == NULL)
56*11729SWang.Lin@Sun.COM ath9k_hw_putrxbuf(sc->sc_ah, bf->bf_daddr);
57*11729SWang.Lin@Sun.COM else
58*11729SWang.Lin@Sun.COM *sc->sc_rxlink = bf->bf_daddr;
59*11729SWang.Lin@Sun.COM
60*11729SWang.Lin@Sun.COM sc->sc_rxlink = &ds->ds_link;
61*11729SWang.Lin@Sun.COM ath9k_hw_rxena(sc->sc_ah);
62*11729SWang.Lin@Sun.COM }
63*11729SWang.Lin@Sun.COM
649999SWang.Lin@Sun.COM void
arn_setdefantenna(struct arn_softc * sc,uint32_t antenna)659999SWang.Lin@Sun.COM arn_setdefantenna(struct arn_softc *sc, uint32_t antenna)
669999SWang.Lin@Sun.COM {
679999SWang.Lin@Sun.COM /* XXX block beacon interrupts */
689999SWang.Lin@Sun.COM ath9k_hw_setantenna(sc->sc_ah, antenna);
699999SWang.Lin@Sun.COM sc->sc_defant = (uint8_t)antenna; /* LINT */
709999SWang.Lin@Sun.COM sc->sc_rxotherant = 0;
719999SWang.Lin@Sun.COM }
729999SWang.Lin@Sun.COM
739999SWang.Lin@Sun.COM /*
749999SWang.Lin@Sun.COM * Extend 15-bit time stamp from rx descriptor to
759999SWang.Lin@Sun.COM * a full 64-bit TSF using the current h/w TSF.
769999SWang.Lin@Sun.COM */
779999SWang.Lin@Sun.COM
789999SWang.Lin@Sun.COM static uint64_t
arn_extend_tsf(struct arn_softc * sc,uint32_t rstamp)799999SWang.Lin@Sun.COM arn_extend_tsf(struct arn_softc *sc, uint32_t rstamp)
809999SWang.Lin@Sun.COM {
819999SWang.Lin@Sun.COM uint64_t tsf;
829999SWang.Lin@Sun.COM
839999SWang.Lin@Sun.COM tsf = ath9k_hw_gettsf64(sc->sc_ah);
849999SWang.Lin@Sun.COM if ((tsf & 0x7fff) < rstamp)
859999SWang.Lin@Sun.COM tsf -= 0x8000;
869999SWang.Lin@Sun.COM return ((tsf & ~0x7fff) | rstamp);
879999SWang.Lin@Sun.COM }
889999SWang.Lin@Sun.COM
89*11729SWang.Lin@Sun.COM static int
arn_rx_prepare(struct ath_desc * ds,struct arn_softc * sc)90*11729SWang.Lin@Sun.COM arn_rx_prepare(struct ath_desc *ds, struct arn_softc *sc)
91*11729SWang.Lin@Sun.COM {
92*11729SWang.Lin@Sun.COM uint8_t phyerr;
93*11729SWang.Lin@Sun.COM
94*11729SWang.Lin@Sun.COM if (ds->ds_rxstat.rs_more) {
95*11729SWang.Lin@Sun.COM /*
96*11729SWang.Lin@Sun.COM * Frame spans multiple descriptors; this cannot happen yet
97*11729SWang.Lin@Sun.COM * as we don't support jumbograms. If not in monitor mode,
98*11729SWang.Lin@Sun.COM * discard the frame. Enable this if you want to see
99*11729SWang.Lin@Sun.COM * error frames in Monitor mode.
100*11729SWang.Lin@Sun.COM */
101*11729SWang.Lin@Sun.COM if (sc->sc_ah->ah_opmode != ATH9K_M_MONITOR)
102*11729SWang.Lin@Sun.COM goto rx_next;
103*11729SWang.Lin@Sun.COM } else if (ds->ds_rxstat.rs_status != 0) {
104*11729SWang.Lin@Sun.COM if (ds->ds_rxstat.rs_status & ATH9K_RXERR_CRC) {
105*11729SWang.Lin@Sun.COM sc->sc_stats.ast_rx_crcerr++;
106*11729SWang.Lin@Sun.COM goto rx_next; /* should ignore? */
107*11729SWang.Lin@Sun.COM }
108*11729SWang.Lin@Sun.COM
109*11729SWang.Lin@Sun.COM if (ds->ds_rxstat.rs_status & ATH9K_RXERR_FIFO) {
110*11729SWang.Lin@Sun.COM sc->sc_stats.ast_rx_fifoerr++;
111*11729SWang.Lin@Sun.COM }
112*11729SWang.Lin@Sun.COM
113*11729SWang.Lin@Sun.COM if (ds->ds_rxstat.rs_status & ATH9K_RXERR_PHY) {
114*11729SWang.Lin@Sun.COM sc->sc_stats.ast_rx_phyerr++;
115*11729SWang.Lin@Sun.COM phyerr = ds->ds_rxstat.rs_phyerr & 0x1f;
116*11729SWang.Lin@Sun.COM sc->sc_stats.ast_rx_phy[phyerr]++;
117*11729SWang.Lin@Sun.COM goto rx_next;
118*11729SWang.Lin@Sun.COM }
119*11729SWang.Lin@Sun.COM
120*11729SWang.Lin@Sun.COM if (ds->ds_rxstat.rs_status & ATH9K_RXERR_DECRYPT) {
121*11729SWang.Lin@Sun.COM sc->sc_stats.ast_rx_badcrypt++;
122*11729SWang.Lin@Sun.COM }
123*11729SWang.Lin@Sun.COM
124*11729SWang.Lin@Sun.COM /*
125*11729SWang.Lin@Sun.COM * Reject error frames with the exception of
126*11729SWang.Lin@Sun.COM * decryption and MIC failures. For monitor mode,
127*11729SWang.Lin@Sun.COM * we also ignore the CRC error.
128*11729SWang.Lin@Sun.COM */
129*11729SWang.Lin@Sun.COM if (sc->sc_ah->ah_opmode == ATH9K_M_MONITOR) {
130*11729SWang.Lin@Sun.COM if (ds->ds_rxstat.rs_status &
131*11729SWang.Lin@Sun.COM ~(ATH9K_RXERR_DECRYPT |
132*11729SWang.Lin@Sun.COM ATH9K_RXERR_MIC |
133*11729SWang.Lin@Sun.COM ATH9K_RXERR_CRC))
134*11729SWang.Lin@Sun.COM goto rx_next;
135*11729SWang.Lin@Sun.COM } else {
136*11729SWang.Lin@Sun.COM if (ds->ds_rxstat.rs_status &
137*11729SWang.Lin@Sun.COM ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC)) {
138*11729SWang.Lin@Sun.COM goto rx_next;
139*11729SWang.Lin@Sun.COM }
140*11729SWang.Lin@Sun.COM }
141*11729SWang.Lin@Sun.COM }
142*11729SWang.Lin@Sun.COM
143*11729SWang.Lin@Sun.COM return (1);
144*11729SWang.Lin@Sun.COM rx_next:
145*11729SWang.Lin@Sun.COM return (0);
146*11729SWang.Lin@Sun.COM }
147*11729SWang.Lin@Sun.COM
148*11729SWang.Lin@Sun.COM
1499999SWang.Lin@Sun.COM static void
arn_opmode_init(struct arn_softc * sc)1509999SWang.Lin@Sun.COM arn_opmode_init(struct arn_softc *sc)
1519999SWang.Lin@Sun.COM {
1529999SWang.Lin@Sun.COM struct ath_hal *ah = sc->sc_ah;
1539999SWang.Lin@Sun.COM uint32_t rfilt;
1549999SWang.Lin@Sun.COM uint32_t mfilt[2];
1559999SWang.Lin@Sun.COM ieee80211com_t *ic = (ieee80211com_t *)sc;
1569999SWang.Lin@Sun.COM
1579999SWang.Lin@Sun.COM /* configure rx filter */
1589999SWang.Lin@Sun.COM rfilt = arn_calcrxfilter(sc);
1599999SWang.Lin@Sun.COM ath9k_hw_setrxfilter(ah, rfilt);
1609999SWang.Lin@Sun.COM
1619999SWang.Lin@Sun.COM /* configure bssid mask */
1629999SWang.Lin@Sun.COM if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK)
1639999SWang.Lin@Sun.COM (void) ath9k_hw_setbssidmask(ah, sc->sc_bssidmask);
1649999SWang.Lin@Sun.COM
1659999SWang.Lin@Sun.COM /* configure operational mode */
1669999SWang.Lin@Sun.COM ath9k_hw_setopmode(ah);
1679999SWang.Lin@Sun.COM
1689999SWang.Lin@Sun.COM /* Handle any link-level address change. */
1699999SWang.Lin@Sun.COM (void) ath9k_hw_setmac(ah, sc->sc_myaddr);
1709999SWang.Lin@Sun.COM
1719999SWang.Lin@Sun.COM /* calculate and install multicast filter */
1729999SWang.Lin@Sun.COM mfilt[0] = ~((uint32_t)0); /* LINT */
1739999SWang.Lin@Sun.COM mfilt[1] = ~((uint32_t)0); /* LINT */
1749999SWang.Lin@Sun.COM
1759999SWang.Lin@Sun.COM ath9k_hw_setmcastfilter(ah, mfilt[0], mfilt[1]);
1769999SWang.Lin@Sun.COM
1779999SWang.Lin@Sun.COM ARN_DBG((ARN_DBG_RECV, "arn: arn_opmode_init(): "
1789999SWang.Lin@Sun.COM "mode = %d RX filter 0x%x, MC filter %08x:%08x\n",
1799999SWang.Lin@Sun.COM ic->ic_opmode, rfilt, mfilt[0], mfilt[1]));
1809999SWang.Lin@Sun.COM }
1819999SWang.Lin@Sun.COM
1829999SWang.Lin@Sun.COM /*
1839999SWang.Lin@Sun.COM * Calculate the receive filter according to the
1849999SWang.Lin@Sun.COM * operating mode and state:
1859999SWang.Lin@Sun.COM *
1869999SWang.Lin@Sun.COM * o always accept unicast, broadcast, and multicast traffic
1879999SWang.Lin@Sun.COM * o maintain current state of phy error reception (the hal
1889999SWang.Lin@Sun.COM * may enable phy error frames for noise immunity work)
1899999SWang.Lin@Sun.COM * o probe request frames are accepted only when operating in
1909999SWang.Lin@Sun.COM * hostap, adhoc, or monitor modes
1919999SWang.Lin@Sun.COM * o enable promiscuous mode according to the interface state
1929999SWang.Lin@Sun.COM * o accept beacons:
1939999SWang.Lin@Sun.COM * - when operating in adhoc mode so the 802.11 layer creates
1949999SWang.Lin@Sun.COM * node table entries for peers,
1959999SWang.Lin@Sun.COM * - when operating in station mode for collecting rssi data when
1969999SWang.Lin@Sun.COM * the station is otherwise quiet, or
1979999SWang.Lin@Sun.COM * - when operating as a repeater so we see repeater-sta beacons
1989999SWang.Lin@Sun.COM * - when scanning
1999999SWang.Lin@Sun.COM */
2009999SWang.Lin@Sun.COM
2019999SWang.Lin@Sun.COM uint32_t
arn_calcrxfilter(struct arn_softc * sc)2029999SWang.Lin@Sun.COM arn_calcrxfilter(struct arn_softc *sc)
2039999SWang.Lin@Sun.COM {
2049999SWang.Lin@Sun.COM #define RX_FILTER_PRESERVE (ATH9K_RX_FILTER_PHYERR | \
2059999SWang.Lin@Sun.COM ATH9K_RX_FILTER_PHYRADAR)
2069999SWang.Lin@Sun.COM
2079999SWang.Lin@Sun.COM uint32_t rfilt;
2089999SWang.Lin@Sun.COM
2099999SWang.Lin@Sun.COM rfilt = (ath9k_hw_getrxfilter(sc->sc_ah) & RX_FILTER_PRESERVE) |
2109999SWang.Lin@Sun.COM ATH9K_RX_FILTER_UCAST | ATH9K_RX_FILTER_BCAST |
2119999SWang.Lin@Sun.COM ATH9K_RX_FILTER_MCAST;
2129999SWang.Lin@Sun.COM
2139999SWang.Lin@Sun.COM /* If not a STA, enable processing of Probe Requests */
2149999SWang.Lin@Sun.COM if (sc->sc_ah->ah_opmode != ATH9K_M_STA)
2159999SWang.Lin@Sun.COM rfilt |= ATH9K_RX_FILTER_PROBEREQ;
2169999SWang.Lin@Sun.COM
2179999SWang.Lin@Sun.COM /* Can't set HOSTAP into promiscous mode */
2189999SWang.Lin@Sun.COM if (((sc->sc_ah->ah_opmode != ATH9K_M_HOSTAP) &&
2199999SWang.Lin@Sun.COM (sc->sc_promisc)) ||
2209999SWang.Lin@Sun.COM (sc->sc_ah->ah_opmode == ATH9K_M_MONITOR)) {
2219999SWang.Lin@Sun.COM rfilt |= ATH9K_RX_FILTER_PROM;
2229999SWang.Lin@Sun.COM /* ??? To prevent from sending ACK */
2239999SWang.Lin@Sun.COM rfilt &= ~ATH9K_RX_FILTER_UCAST;
2249999SWang.Lin@Sun.COM }
2259999SWang.Lin@Sun.COM
2269999SWang.Lin@Sun.COM if (sc->sc_ah->ah_opmode == ATH9K_M_STA ||
2279999SWang.Lin@Sun.COM sc->sc_ah->ah_opmode == ATH9K_M_IBSS)
2289999SWang.Lin@Sun.COM rfilt |= ATH9K_RX_FILTER_BEACON;
2299999SWang.Lin@Sun.COM
2309999SWang.Lin@Sun.COM /*
2319999SWang.Lin@Sun.COM * If in HOSTAP mode, want to enable reception of PSPOLL
2329999SWang.Lin@Sun.COM * frames & beacon frames
2339999SWang.Lin@Sun.COM */
2349999SWang.Lin@Sun.COM if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP)
2359999SWang.Lin@Sun.COM rfilt |= (ATH9K_RX_FILTER_BEACON | ATH9K_RX_FILTER_PSPOLL);
2369999SWang.Lin@Sun.COM
2379999SWang.Lin@Sun.COM return (rfilt);
2389999SWang.Lin@Sun.COM
2399999SWang.Lin@Sun.COM #undef RX_FILTER_PRESERVE
2409999SWang.Lin@Sun.COM }
2419999SWang.Lin@Sun.COM
242*11729SWang.Lin@Sun.COM /*
243*11729SWang.Lin@Sun.COM * When block ACK agreement has been set up between station and AP,
244*11729SWang.Lin@Sun.COM * Net80211 module will call this function to inform hardware about
245*11729SWang.Lin@Sun.COM * informations of this BA agreement.
246*11729SWang.Lin@Sun.COM * When AP wants to delete BA agreement that was originated by it,
247*11729SWang.Lin@Sun.COM * Net80211 modele will call this function to clean up relevant
248*11729SWang.Lin@Sun.COM * information in hardware.
249*11729SWang.Lin@Sun.COM */
250*11729SWang.Lin@Sun.COM
251*11729SWang.Lin@Sun.COM void
arn_ampdu_recv_action(struct ieee80211_node * in,const uint8_t * frm,const uint8_t * efrm)252*11729SWang.Lin@Sun.COM arn_ampdu_recv_action(struct ieee80211_node *in,
253*11729SWang.Lin@Sun.COM const uint8_t *frm,
254*11729SWang.Lin@Sun.COM const uint8_t *efrm)
255*11729SWang.Lin@Sun.COM {
256*11729SWang.Lin@Sun.COM struct ieee80211com *ic;
257*11729SWang.Lin@Sun.COM struct arn_softc *sc;
258*11729SWang.Lin@Sun.COM
259*11729SWang.Lin@Sun.COM if ((in == NULL) || (frm == NULL) || (ic = in->in_ic) == NULL) {
260*11729SWang.Lin@Sun.COM ARN_DBG((ARN_DBG_FATAL,
261*11729SWang.Lin@Sun.COM "Unknown AMPDU action or NULL node index\n"));
262*11729SWang.Lin@Sun.COM return;
263*11729SWang.Lin@Sun.COM }
264*11729SWang.Lin@Sun.COM
265*11729SWang.Lin@Sun.COM sc = (struct arn_softc *)ic;
266*11729SWang.Lin@Sun.COM
267*11729SWang.Lin@Sun.COM if (!(sc->sc_flags & SC_OP_RXAGGR))
268*11729SWang.Lin@Sun.COM return;
269*11729SWang.Lin@Sun.COM else
270*11729SWang.Lin@Sun.COM sc->sc_recv_action(in, frm, efrm);
271*11729SWang.Lin@Sun.COM }
272*11729SWang.Lin@Sun.COM
2739999SWang.Lin@Sun.COM int
arn_startrecv(struct arn_softc * sc)2749999SWang.Lin@Sun.COM arn_startrecv(struct arn_softc *sc)
2759999SWang.Lin@Sun.COM {
2769999SWang.Lin@Sun.COM struct ath_hal *ah = sc->sc_ah;
2779999SWang.Lin@Sun.COM struct ath_buf *bf;
2789999SWang.Lin@Sun.COM
279*11729SWang.Lin@Sun.COM /* rx descriptor link set up */
280*11729SWang.Lin@Sun.COM mutex_enter(&sc->sc_rxbuflock);
281*11729SWang.Lin@Sun.COM if (list_empty(&sc->sc_rxbuf_list))
282*11729SWang.Lin@Sun.COM goto start_recv;
283*11729SWang.Lin@Sun.COM
2849999SWang.Lin@Sun.COM /* clean up rx link firstly */
2859999SWang.Lin@Sun.COM sc->sc_rxlink = NULL;
2869999SWang.Lin@Sun.COM
2879999SWang.Lin@Sun.COM bf = list_head(&sc->sc_rxbuf_list);
2889999SWang.Lin@Sun.COM while (bf != NULL) {
2899999SWang.Lin@Sun.COM arn_rx_buf_link(sc, bf);
2909999SWang.Lin@Sun.COM bf = list_next(&sc->sc_rxbuf_list, bf);
2919999SWang.Lin@Sun.COM }
2929999SWang.Lin@Sun.COM
293*11729SWang.Lin@Sun.COM
294*11729SWang.Lin@Sun.COM /* We could have deleted elements so the list may be empty now */
295*11729SWang.Lin@Sun.COM if (list_empty(&sc->sc_rxbuf_list))
296*11729SWang.Lin@Sun.COM goto start_recv;
297*11729SWang.Lin@Sun.COM
2989999SWang.Lin@Sun.COM bf = list_head(&sc->sc_rxbuf_list);
2999999SWang.Lin@Sun.COM
3009999SWang.Lin@Sun.COM ath9k_hw_putrxbuf(ah, bf->bf_daddr);
3019999SWang.Lin@Sun.COM ath9k_hw_rxena(ah);
3029999SWang.Lin@Sun.COM
303*11729SWang.Lin@Sun.COM start_recv:
304*11729SWang.Lin@Sun.COM mutex_exit(&sc->sc_rxbuflock);
3059999SWang.Lin@Sun.COM arn_opmode_init(sc);
3069999SWang.Lin@Sun.COM ath9k_hw_startpcureceive(ah);
3079999SWang.Lin@Sun.COM
3089999SWang.Lin@Sun.COM return (0);
3099999SWang.Lin@Sun.COM }
3109999SWang.Lin@Sun.COM
3119999SWang.Lin@Sun.COM boolean_t
arn_stoprecv(struct arn_softc * sc)3129999SWang.Lin@Sun.COM arn_stoprecv(struct arn_softc *sc)
3139999SWang.Lin@Sun.COM {
3149999SWang.Lin@Sun.COM struct ath_hal *ah = sc->sc_ah;
3159999SWang.Lin@Sun.COM boolean_t stopped;
3169999SWang.Lin@Sun.COM
3179999SWang.Lin@Sun.COM ath9k_hw_stoppcurecv(ah);
3189999SWang.Lin@Sun.COM ath9k_hw_setrxfilter(ah, 0);
3199999SWang.Lin@Sun.COM stopped = ath9k_hw_stopdmarecv(ah);
3209999SWang.Lin@Sun.COM
3219999SWang.Lin@Sun.COM /* 3ms is long enough for 1 frame ??? */
3229999SWang.Lin@Sun.COM drv_usecwait(3000);
3239999SWang.Lin@Sun.COM
3249999SWang.Lin@Sun.COM sc->sc_rxlink = NULL;
3259999SWang.Lin@Sun.COM
3269999SWang.Lin@Sun.COM return (stopped);
3279999SWang.Lin@Sun.COM }
3289999SWang.Lin@Sun.COM
3299999SWang.Lin@Sun.COM /*
3309999SWang.Lin@Sun.COM * Intercept management frames to collect beacon rssi data
3319999SWang.Lin@Sun.COM * and to do ibss merges.
3329999SWang.Lin@Sun.COM */
3339999SWang.Lin@Sun.COM
3349999SWang.Lin@Sun.COM void
arn_recv_mgmt(struct ieee80211com * ic,mblk_t * mp,struct ieee80211_node * in,int subtype,int rssi,uint32_t rstamp)3359999SWang.Lin@Sun.COM arn_recv_mgmt(struct ieee80211com *ic, mblk_t *mp, struct ieee80211_node *in,
3369999SWang.Lin@Sun.COM int subtype, int rssi, uint32_t rstamp)
3379999SWang.Lin@Sun.COM {
3389999SWang.Lin@Sun.COM struct arn_softc *sc = (struct arn_softc *)ic;
3399999SWang.Lin@Sun.COM
3409999SWang.Lin@Sun.COM /*
3419999SWang.Lin@Sun.COM * Call up first so subsequent work can use information
3429999SWang.Lin@Sun.COM * potentially stored in the node (e.g. for ibss merge).
3439999SWang.Lin@Sun.COM */
3449999SWang.Lin@Sun.COM sc->sc_recv_mgmt(ic, mp, in, subtype, rssi, rstamp);
3459999SWang.Lin@Sun.COM
3469999SWang.Lin@Sun.COM ARN_LOCK(sc);
3479999SWang.Lin@Sun.COM switch (subtype) {
3489999SWang.Lin@Sun.COM case IEEE80211_FC0_SUBTYPE_BEACON:
3499999SWang.Lin@Sun.COM /* update rssi statistics */
3509999SWang.Lin@Sun.COM if (sc->sc_bsync && in == ic->ic_bss &&
3519999SWang.Lin@Sun.COM ic->ic_state == IEEE80211_S_RUN) {
3529999SWang.Lin@Sun.COM /*
3539999SWang.Lin@Sun.COM * Resync beacon timers using the tsf of the beacon
3549999SWang.Lin@Sun.COM * frame we just received.
3559999SWang.Lin@Sun.COM */
3569999SWang.Lin@Sun.COM arn_beacon_config(sc);
3579999SWang.Lin@Sun.COM }
3589999SWang.Lin@Sun.COM /* FALLTHRU */
3599999SWang.Lin@Sun.COM case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
3609999SWang.Lin@Sun.COM if (ic->ic_opmode == IEEE80211_M_IBSS &&
3619999SWang.Lin@Sun.COM ic->ic_state == IEEE80211_S_RUN &&
3629999SWang.Lin@Sun.COM (in->in_capinfo & IEEE80211_CAPINFO_IBSS)) {
3639999SWang.Lin@Sun.COM uint64_t tsf = arn_extend_tsf(sc, rstamp);
3649999SWang.Lin@Sun.COM /*
3659999SWang.Lin@Sun.COM * Handle ibss merge as needed; check the tsf on the
3669999SWang.Lin@Sun.COM * frame before attempting the merge. The 802.11 spec
3679999SWang.Lin@Sun.COM * says the station should change it's bssid to match
3689999SWang.Lin@Sun.COM * the oldest station with the same ssid, where oldest
3699999SWang.Lin@Sun.COM * is determined by the tsf. Note that hardware
3709999SWang.Lin@Sun.COM * reconfiguration happens through callback to
3719999SWang.Lin@Sun.COM * ath_newstate as the state machine will go from
3729999SWang.Lin@Sun.COM * RUN -> RUN when this happens.
3739999SWang.Lin@Sun.COM */
3749999SWang.Lin@Sun.COM if (LE_64(in->in_tstamp.tsf) >= tsf) {
3759999SWang.Lin@Sun.COM ARN_DBG((ARN_DBG_BEACON, "arn: arn_recv_mgmt:"
3769999SWang.Lin@Sun.COM "ibss merge, rstamp %u tsf %lu "
3779999SWang.Lin@Sun.COM "tstamp %lu\n", rstamp, tsf,
3789999SWang.Lin@Sun.COM in->in_tstamp.tsf));
3799999SWang.Lin@Sun.COM ARN_UNLOCK(sc);
3809999SWang.Lin@Sun.COM ARN_DBG((ARN_DBG_BEACON, "arn_recv_mgmt():"
3819999SWang.Lin@Sun.COM "ibss_merge: rstamp=%d in_tstamp=%02x %02x"
3829999SWang.Lin@Sun.COM " %02x %02x %02x %02x %02x %02x\n",
3839999SWang.Lin@Sun.COM rstamp, in->in_tstamp.data[0],
3849999SWang.Lin@Sun.COM in->in_tstamp.data[1],
3859999SWang.Lin@Sun.COM in->in_tstamp.data[2],
3869999SWang.Lin@Sun.COM in->in_tstamp.data[3],
3879999SWang.Lin@Sun.COM in->in_tstamp.data[4],
3889999SWang.Lin@Sun.COM in->in_tstamp.data[5],
3899999SWang.Lin@Sun.COM in->in_tstamp.data[6],
3909999SWang.Lin@Sun.COM in->in_tstamp.data[7]));
3919999SWang.Lin@Sun.COM (void) ieee80211_ibss_merge(in);
3929999SWang.Lin@Sun.COM return;
3939999SWang.Lin@Sun.COM }
3949999SWang.Lin@Sun.COM }
3959999SWang.Lin@Sun.COM break;
3969999SWang.Lin@Sun.COM }
3979999SWang.Lin@Sun.COM ARN_UNLOCK(sc);
3989999SWang.Lin@Sun.COM }
3999999SWang.Lin@Sun.COM
4009999SWang.Lin@Sun.COM static void
arn_printrxbuf(struct ath_buf * bf,int32_t done)4019999SWang.Lin@Sun.COM arn_printrxbuf(struct ath_buf *bf, int32_t done)
4029999SWang.Lin@Sun.COM {
4039999SWang.Lin@Sun.COM struct ath_desc *ds = bf->bf_desc;
4049999SWang.Lin@Sun.COM const struct ath_rx_status *rs = &ds->ds_rxstat;
4059999SWang.Lin@Sun.COM
4069999SWang.Lin@Sun.COM ARN_DBG((ARN_DBG_RECV, "arn: R (%p %p) %08x %08x %08x "
4079999SWang.Lin@Sun.COM "%08x %08x %08x %c\n",
4089999SWang.Lin@Sun.COM ds, bf->bf_daddr,
4099999SWang.Lin@Sun.COM ds->ds_link, ds->ds_data,
4109999SWang.Lin@Sun.COM ds->ds_ctl0, ds->ds_ctl1,
4119999SWang.Lin@Sun.COM ds->ds_hw[0], ds->ds_hw[1],
4129999SWang.Lin@Sun.COM !done ? ' ' : (rs->rs_status == 0) ? '*' : '!'));
4139999SWang.Lin@Sun.COM }
4149999SWang.Lin@Sun.COM
4159999SWang.Lin@Sun.COM static void
arn_rx_handler(struct arn_softc * sc)4169999SWang.Lin@Sun.COM arn_rx_handler(struct arn_softc *sc)
4179999SWang.Lin@Sun.COM {
4189999SWang.Lin@Sun.COM #define PA2DESC(_sc, _pa) \
4199999SWang.Lin@Sun.COM ((struct ath_desc *)((caddr_t)(_sc)->sc_desc + \
4209999SWang.Lin@Sun.COM ((_pa) - (_sc)->sc_desc_dma.cookie.dmac_address)))
4219999SWang.Lin@Sun.COM
4229999SWang.Lin@Sun.COM ieee80211com_t *ic = (ieee80211com_t *)sc;
4239999SWang.Lin@Sun.COM struct ath_buf *bf;
4249999SWang.Lin@Sun.COM struct ath_hal *ah = sc->sc_ah;
4259999SWang.Lin@Sun.COM struct ath_desc *ds;
4269999SWang.Lin@Sun.COM struct ath_rx_status *rs;
4279999SWang.Lin@Sun.COM mblk_t *rx_mp;
4289999SWang.Lin@Sun.COM struct ieee80211_frame *wh;
429*11729SWang.Lin@Sun.COM int32_t len, ngood = 0, loop = 1;
430*11729SWang.Lin@Sun.COM uint32_t subtype;
4319999SWang.Lin@Sun.COM int status;
432*11729SWang.Lin@Sun.COM int last_rssi = ATH_RSSI_DUMMY_MARKER;
433*11729SWang.Lin@Sun.COM struct ath_node *an;
4349999SWang.Lin@Sun.COM struct ieee80211_node *in;
43511377SWang.Lin@Sun.COM uint32_t cur_signal;
436*11729SWang.Lin@Sun.COM #ifdef ARN_DBG_AMSDU
437*11729SWang.Lin@Sun.COM uint8_t qos;
438*11729SWang.Lin@Sun.COM #endif
4399999SWang.Lin@Sun.COM
4409999SWang.Lin@Sun.COM do {
4419999SWang.Lin@Sun.COM mutex_enter(&sc->sc_rxbuflock);
4429999SWang.Lin@Sun.COM bf = list_head(&sc->sc_rxbuf_list);
4439999SWang.Lin@Sun.COM if (bf == NULL) {
4449999SWang.Lin@Sun.COM ARN_DBG((ARN_DBG_RECV, "arn: arn_rx_handler(): "
4459999SWang.Lin@Sun.COM "no buffer\n"));
446*11729SWang.Lin@Sun.COM sc->sc_rxlink = NULL;
4479999SWang.Lin@Sun.COM mutex_exit(&sc->sc_rxbuflock);
4489999SWang.Lin@Sun.COM break;
4499999SWang.Lin@Sun.COM }
4509999SWang.Lin@Sun.COM ASSERT(bf->bf_dma.cookie.dmac_address != NULL);
4519999SWang.Lin@Sun.COM ds = bf->bf_desc;
4529999SWang.Lin@Sun.COM
4539999SWang.Lin@Sun.COM /*
4549999SWang.Lin@Sun.COM * Must provide the virtual address of the current
4559999SWang.Lin@Sun.COM * descriptor, the physical address, and the virtual
4569999SWang.Lin@Sun.COM * address of the next descriptor in the h/w chain.
4579999SWang.Lin@Sun.COM * This allows the HAL to look ahead to see if the
4589999SWang.Lin@Sun.COM * hardware is done with a descriptor by checking the
4599999SWang.Lin@Sun.COM * done bit in the following descriptor and the address
4609999SWang.Lin@Sun.COM * of the current descriptor the DMA engine is working
4619999SWang.Lin@Sun.COM * on. All this is necessary because of our use of
4629999SWang.Lin@Sun.COM * a self-linked list to avoid rx overruns.
4639999SWang.Lin@Sun.COM */
4649999SWang.Lin@Sun.COM status = ath9k_hw_rxprocdesc(ah, ds,
4659999SWang.Lin@Sun.COM bf->bf_daddr,
4669999SWang.Lin@Sun.COM PA2DESC(sc, ds->ds_link), 0);
4679999SWang.Lin@Sun.COM if (status == EINPROGRESS) {
468*11729SWang.Lin@Sun.COM struct ath_buf *tbf;
469*11729SWang.Lin@Sun.COM struct ath_desc *tds;
470*11729SWang.Lin@Sun.COM
471*11729SWang.Lin@Sun.COM if (list_is_last(&bf->bf_node, &sc->sc_rxbuf_list)) {
472*11729SWang.Lin@Sun.COM ARN_DBG((ARN_DBG_RECV, "arn: arn_rx_handler(): "
473*11729SWang.Lin@Sun.COM "List is in last! \n"));
474*11729SWang.Lin@Sun.COM sc->sc_rxlink = NULL;
475*11729SWang.Lin@Sun.COM break;
476*11729SWang.Lin@Sun.COM }
477*11729SWang.Lin@Sun.COM
478*11729SWang.Lin@Sun.COM tbf = list_object(&sc->sc_rxbuf_list,
479*11729SWang.Lin@Sun.COM bf->bf_node.list_next);
480*11729SWang.Lin@Sun.COM
481*11729SWang.Lin@Sun.COM /*
482*11729SWang.Lin@Sun.COM * On some hardware the descriptor status words could
483*11729SWang.Lin@Sun.COM * get corrupted, including the done bit. Because of
484*11729SWang.Lin@Sun.COM * this, check if the next descriptor's done bit is
485*11729SWang.Lin@Sun.COM * set or not.
486*11729SWang.Lin@Sun.COM *
487*11729SWang.Lin@Sun.COM * If the next descriptor's done bit is set, the current
488*11729SWang.Lin@Sun.COM * descriptor has been corrupted. Force s/w to discard
489*11729SWang.Lin@Sun.COM * this descriptor and continue...
490*11729SWang.Lin@Sun.COM */
491*11729SWang.Lin@Sun.COM
492*11729SWang.Lin@Sun.COM tds = tbf->bf_desc;
493*11729SWang.Lin@Sun.COM status = ath9k_hw_rxprocdesc(ah, tds, tbf->bf_daddr,
494*11729SWang.Lin@Sun.COM PA2DESC(sc, tds->ds_link), 0);
495*11729SWang.Lin@Sun.COM if (status == EINPROGRESS) {
496*11729SWang.Lin@Sun.COM mutex_exit(&sc->sc_rxbuflock);
497*11729SWang.Lin@Sun.COM break;
498*11729SWang.Lin@Sun.COM }
4999999SWang.Lin@Sun.COM }
5009999SWang.Lin@Sun.COM list_remove(&sc->sc_rxbuf_list, bf);
5019999SWang.Lin@Sun.COM mutex_exit(&sc->sc_rxbuflock);
5029999SWang.Lin@Sun.COM
5039999SWang.Lin@Sun.COM rs = &ds->ds_rxstat;
5049999SWang.Lin@Sun.COM len = rs->rs_datalen;
5059999SWang.Lin@Sun.COM
5069999SWang.Lin@Sun.COM /* less than sizeof(struct ieee80211_frame) */
5079999SWang.Lin@Sun.COM if (len < 20) {
5089999SWang.Lin@Sun.COM sc->sc_stats.ast_rx_tooshort++;
509*11729SWang.Lin@Sun.COM goto requeue;
5109999SWang.Lin@Sun.COM }
5119999SWang.Lin@Sun.COM
512*11729SWang.Lin@Sun.COM /* The status portion of the descriptor could get corrupted. */
513*11729SWang.Lin@Sun.COM if (sc->rx_dmabuf_size < rs->rs_datalen) {
514*11729SWang.Lin@Sun.COM arn_problem("Requeued because of wrong rs_datalen\n");
515*11729SWang.Lin@Sun.COM goto requeue;
516*11729SWang.Lin@Sun.COM }
517*11729SWang.Lin@Sun.COM
518*11729SWang.Lin@Sun.COM if (!arn_rx_prepare(ds, sc))
519*11729SWang.Lin@Sun.COM goto requeue;
520*11729SWang.Lin@Sun.COM
521*11729SWang.Lin@Sun.COM if ((rx_mp = allocb(sc->rx_dmabuf_size, BPRI_MED)) == NULL) {
5229999SWang.Lin@Sun.COM arn_problem("arn: arn_rx_handler(): "
5239999SWang.Lin@Sun.COM "allocing mblk buffer failed.\n");
5249999SWang.Lin@Sun.COM return;
5259999SWang.Lin@Sun.COM }
5269999SWang.Lin@Sun.COM
5279999SWang.Lin@Sun.COM ARN_DMA_SYNC(bf->bf_dma, DDI_DMA_SYNC_FORCPU);
5289999SWang.Lin@Sun.COM bcopy(bf->bf_dma.mem_va, rx_mp->b_rptr, len);
5299999SWang.Lin@Sun.COM
5309999SWang.Lin@Sun.COM rx_mp->b_wptr += len;
5319999SWang.Lin@Sun.COM wh = (struct ieee80211_frame *)rx_mp->b_rptr;
5329999SWang.Lin@Sun.COM
5339999SWang.Lin@Sun.COM if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
5349999SWang.Lin@Sun.COM IEEE80211_FC0_TYPE_CTL) {
5359999SWang.Lin@Sun.COM /*
5369999SWang.Lin@Sun.COM * Ignore control frame received in promisc mode.
5379999SWang.Lin@Sun.COM */
5389999SWang.Lin@Sun.COM freemsg(rx_mp);
539*11729SWang.Lin@Sun.COM goto requeue;
5409999SWang.Lin@Sun.COM }
5419999SWang.Lin@Sun.COM /* Remove the CRC at the end of IEEE80211 frame */
5429999SWang.Lin@Sun.COM rx_mp->b_wptr -= IEEE80211_CRC_LEN;
5439999SWang.Lin@Sun.COM
544*11729SWang.Lin@Sun.COM #ifdef DEBUG
545*11729SWang.Lin@Sun.COM arn_printrxbuf(bf, status == 0);
546*11729SWang.Lin@Sun.COM #endif
547*11729SWang.Lin@Sun.COM
548*11729SWang.Lin@Sun.COM #ifdef ARN_DBG_AMSDU
549*11729SWang.Lin@Sun.COM if (IEEE80211_IS_DATA_QOS(wh)) {
550*11729SWang.Lin@Sun.COM if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) ==
551*11729SWang.Lin@Sun.COM IEEE80211_FC1_DIR_DSTODS)
552*11729SWang.Lin@Sun.COM qos = ((struct ieee80211_qosframe_addr4 *)
553*11729SWang.Lin@Sun.COM wh)->i_qos[0];
554*11729SWang.Lin@Sun.COM else
555*11729SWang.Lin@Sun.COM qos =
556*11729SWang.Lin@Sun.COM ((struct ieee80211_qosframe *)wh)->i_qos[0];
557*11729SWang.Lin@Sun.COM
558*11729SWang.Lin@Sun.COM if (qos & IEEE80211_QOS_AMSDU)
559*11729SWang.Lin@Sun.COM arn_dump_pkg((unsigned char *)bf->bf_dma.mem_va,
560*11729SWang.Lin@Sun.COM len, 1, 1);
561*11729SWang.Lin@Sun.COM }
562*11729SWang.Lin@Sun.COM #endif /* ARN_DBG_AMSDU */
563*11729SWang.Lin@Sun.COM
5649999SWang.Lin@Sun.COM /*
5659999SWang.Lin@Sun.COM * Locate the node for sender, track state, and then
5669999SWang.Lin@Sun.COM * pass the (referenced) node up to the 802.11 layer
5679999SWang.Lin@Sun.COM * for its use.
5689999SWang.Lin@Sun.COM */
5699999SWang.Lin@Sun.COM in = ieee80211_find_rxnode(ic, wh);
570*11729SWang.Lin@Sun.COM an = ATH_NODE(in);
571*11729SWang.Lin@Sun.COM
572*11729SWang.Lin@Sun.COM /*
573*11729SWang.Lin@Sun.COM * Theory for reporting quality:
574*11729SWang.Lin@Sun.COM *
575*11729SWang.Lin@Sun.COM * At a hardware RSSI of 45 you will be able to use
576*11729SWang.Lin@Sun.COM * MCS 7 reliably.
577*11729SWang.Lin@Sun.COM * At a hardware RSSI of 45 you will be able to use
578*11729SWang.Lin@Sun.COM * MCS 15 reliably.
579*11729SWang.Lin@Sun.COM * At a hardware RSSI of 35 you should be able use
580*11729SWang.Lin@Sun.COM * 54 Mbps reliably.
581*11729SWang.Lin@Sun.COM *
582*11729SWang.Lin@Sun.COM * MCS 7 is the highets MCS index usable by a 1-stream device.
583*11729SWang.Lin@Sun.COM * MCS 15 is the highest MCS index usable by a 2-stream device.
584*11729SWang.Lin@Sun.COM *
585*11729SWang.Lin@Sun.COM * All ath9k devices are either 1-stream or 2-stream.
586*11729SWang.Lin@Sun.COM *
587*11729SWang.Lin@Sun.COM * How many bars you see is derived from the qual reporting.
588*11729SWang.Lin@Sun.COM *
589*11729SWang.Lin@Sun.COM * A more elaborate scheme can be used here but it requires
590*11729SWang.Lin@Sun.COM * tables of SNR/throughput for each possible mode used. For
591*11729SWang.Lin@Sun.COM * the MCS table you can refer to the wireless wiki:
592*11729SWang.Lin@Sun.COM *
593*11729SWang.Lin@Sun.COM * http://wireless.kernel.org/en/developers/Documentation/
594*11729SWang.Lin@Sun.COM * ieee80211/802.11n
595*11729SWang.Lin@Sun.COM */
596*11729SWang.Lin@Sun.COM if (ds->ds_rxstat.rs_rssi != ATH9K_RSSI_BAD &&
597*11729SWang.Lin@Sun.COM !ds->ds_rxstat.rs_moreaggr) {
598*11729SWang.Lin@Sun.COM /* LINTED: E_CONSTANT_CONDITION */
599*11729SWang.Lin@Sun.COM ATH_RSSI_LPF(an->last_rssi, ds->ds_rxstat.rs_rssi);
600*11729SWang.Lin@Sun.COM }
601*11729SWang.Lin@Sun.COM last_rssi = an->last_rssi;
602*11729SWang.Lin@Sun.COM
603*11729SWang.Lin@Sun.COM if (last_rssi != ATH_RSSI_DUMMY_MARKER)
604*11729SWang.Lin@Sun.COM ds->ds_rxstat.rs_rssi = ATH_EP_RND(last_rssi,
605*11729SWang.Lin@Sun.COM ATH_RSSI_EP_MULTIPLIER);
6069999SWang.Lin@Sun.COM
60711377SWang.Lin@Sun.COM if (ds->ds_rxstat.rs_rssi < 0)
60811377SWang.Lin@Sun.COM ds->ds_rxstat.rs_rssi = 0;
60911377SWang.Lin@Sun.COM
61011377SWang.Lin@Sun.COM if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
61111377SWang.Lin@Sun.COM IEEE80211_FC0_TYPE_MGT) {
61211377SWang.Lin@Sun.COM subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
61311377SWang.Lin@Sun.COM if (subtype == IEEE80211_FC0_SUBTYPE_BEACON)
61411377SWang.Lin@Sun.COM sc->sc_halstats.ns_avgbrssi =
61511377SWang.Lin@Sun.COM ds->ds_rxstat.rs_rssi;
61611377SWang.Lin@Sun.COM }
61711377SWang.Lin@Sun.COM
61811377SWang.Lin@Sun.COM /*
619*11729SWang.Lin@Sun.COM * signal (13-15) DLADM_WLAN_STRENGTH_EXCELLENT
620*11729SWang.Lin@Sun.COM * signal (10-12) DLADM_WLAN_STRENGTH_VERY_GOOD
621*11729SWang.Lin@Sun.COM * signal (6-9) DLADM_WLAN_STRENGTH_GOOD
622*11729SWang.Lin@Sun.COM * signal (3-5) DLADM_WLAN_STRENGTH_WEAK
623*11729SWang.Lin@Sun.COM * signal (0-2) DLADM_WLAN_STRENGTH_VERY_WEAK
62411377SWang.Lin@Sun.COM */
62511377SWang.Lin@Sun.COM if (rs->rs_rssi == 0)
62611377SWang.Lin@Sun.COM cur_signal = 0;
62711377SWang.Lin@Sun.COM else if (rs->rs_rssi >= 45)
62811377SWang.Lin@Sun.COM cur_signal = MAX_RSSI;
62911377SWang.Lin@Sun.COM else
63011377SWang.Lin@Sun.COM cur_signal = rs->rs_rssi * MAX_RSSI / 45 + 1;
63111377SWang.Lin@Sun.COM
6329999SWang.Lin@Sun.COM /*
6339999SWang.Lin@Sun.COM * Send the frame to net80211 for processing
6349999SWang.Lin@Sun.COM */
635*11729SWang.Lin@Sun.COM if (cur_signal <= 2 && ic->ic_state == IEEE80211_S_RUN) {
63611377SWang.Lin@Sun.COM (void) ieee80211_input(ic, rx_mp, in,
63711377SWang.Lin@Sun.COM (rs->rs_rssi + 10), rs->rs_tstamp);
638*11729SWang.Lin@Sun.COM }
63911377SWang.Lin@Sun.COM else
640*11729SWang.Lin@Sun.COM (void) ieee80211_input(ic, rx_mp, in, rs->rs_rssi,
641*11729SWang.Lin@Sun.COM rs->rs_tstamp);
6429999SWang.Lin@Sun.COM
6439999SWang.Lin@Sun.COM /* release node */
6449999SWang.Lin@Sun.COM ieee80211_free_node(in);
6459999SWang.Lin@Sun.COM
6469999SWang.Lin@Sun.COM /*
6479999SWang.Lin@Sun.COM * Arrange to update the last rx timestamp only for
6489999SWang.Lin@Sun.COM * frames from our ap when operating in station mode.
6499999SWang.Lin@Sun.COM * This assumes the rx key is always setup when associated.
6509999SWang.Lin@Sun.COM */
6519999SWang.Lin@Sun.COM if (ic->ic_opmode == IEEE80211_M_STA &&
6529999SWang.Lin@Sun.COM rs->rs_keyix != ATH9K_RXKEYIX_INVALID) {
6539999SWang.Lin@Sun.COM ngood++;
6549999SWang.Lin@Sun.COM }
6559999SWang.Lin@Sun.COM
6569999SWang.Lin@Sun.COM /*
6579999SWang.Lin@Sun.COM * change the default rx antenna if rx diversity chooses the
6589999SWang.Lin@Sun.COM * other antenna 3 times in a row.
6599999SWang.Lin@Sun.COM */
6609999SWang.Lin@Sun.COM if (sc->sc_defant != ds->ds_rxstat.rs_antenna) {
6619999SWang.Lin@Sun.COM if (++sc->sc_rxotherant >= 3) {
6629999SWang.Lin@Sun.COM ath9k_hw_setantenna(sc->sc_ah,
6639999SWang.Lin@Sun.COM ds->ds_rxstat.rs_antenna);
6649999SWang.Lin@Sun.COM sc->sc_defant = ds->ds_rxstat.rs_antenna;
6659999SWang.Lin@Sun.COM sc->sc_rxotherant = 0;
6669999SWang.Lin@Sun.COM }
6679999SWang.Lin@Sun.COM } else {
6689999SWang.Lin@Sun.COM sc->sc_rxotherant = 0;
6699999SWang.Lin@Sun.COM }
6709999SWang.Lin@Sun.COM
671*11729SWang.Lin@Sun.COM requeue:
6729999SWang.Lin@Sun.COM mutex_enter(&sc->sc_rxbuflock);
6739999SWang.Lin@Sun.COM list_insert_tail(&sc->sc_rxbuf_list, bf);
6749999SWang.Lin@Sun.COM mutex_exit(&sc->sc_rxbuflock);
6759999SWang.Lin@Sun.COM arn_rx_buf_link(sc, bf);
6769999SWang.Lin@Sun.COM } while (loop);
6779999SWang.Lin@Sun.COM
6789999SWang.Lin@Sun.COM if (ngood)
6799999SWang.Lin@Sun.COM sc->sc_lastrx = ath9k_hw_gettsf64(ah);
6809999SWang.Lin@Sun.COM
6819999SWang.Lin@Sun.COM #undef PA2DESC
6829999SWang.Lin@Sun.COM }
6839999SWang.Lin@Sun.COM
6849999SWang.Lin@Sun.COM uint_t
arn_softint_handler(caddr_t data)6859999SWang.Lin@Sun.COM arn_softint_handler(caddr_t data)
6869999SWang.Lin@Sun.COM {
6879999SWang.Lin@Sun.COM struct arn_softc *sc = (struct arn_softc *)data;
6889999SWang.Lin@Sun.COM
6899999SWang.Lin@Sun.COM ARN_LOCK(sc);
6909999SWang.Lin@Sun.COM
6919999SWang.Lin@Sun.COM if (sc->sc_rx_pend) {
6929999SWang.Lin@Sun.COM /* Soft interrupt for this driver */
6939999SWang.Lin@Sun.COM sc->sc_rx_pend = 0;
6949999SWang.Lin@Sun.COM ARN_UNLOCK(sc);
6959999SWang.Lin@Sun.COM arn_rx_handler(sc);
6969999SWang.Lin@Sun.COM return (DDI_INTR_CLAIMED);
6979999SWang.Lin@Sun.COM }
6989999SWang.Lin@Sun.COM
6999999SWang.Lin@Sun.COM ARN_UNLOCK(sc);
7009999SWang.Lin@Sun.COM
7019999SWang.Lin@Sun.COM return (DDI_INTR_UNCLAIMED);
7029999SWang.Lin@Sun.COM }
703