xref: /illumos-gate/usr/src/uts/common/io/arn/arn_recv.c (revision 411e5762bff38b7fee2b31a987c104503ddc9c9c)
1dd1de374Slin wang - Sun Microsystems - Beijing China /*
2c0c93480Slin 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 
26c0c93480Slin wang - Sun Microsystems - Beijing China /*
27c0c93480Slin wang - Sun Microsystems - Beijing China  * Setup and link descriptors.
28c0c93480Slin wang - Sun Microsystems - Beijing China  *
29c0c93480Slin wang - Sun Microsystems - Beijing China  * 11N: we can no longer afford to self link the last descriptor.
30c0c93480Slin wang - Sun Microsystems - Beijing China  * MAC acknowledges BA status as long as it copies frames to host
31c0c93480Slin wang - Sun Microsystems - Beijing China  * buffer (or rx fifo). This can incorrectly acknowledge packets
32c0c93480Slin wang - Sun Microsystems - Beijing China  * to a sender if last desc is self-linked.
33c0c93480Slin wang - Sun Microsystems - Beijing China  */
34c0c93480Slin wang - Sun Microsystems - Beijing China void
arn_rx_buf_link(struct arn_softc * sc,struct ath_buf * bf)35c0c93480Slin wang - Sun Microsystems - Beijing China arn_rx_buf_link(struct arn_softc *sc, struct ath_buf *bf)
36c0c93480Slin wang - Sun Microsystems - Beijing China {
37c0c93480Slin wang - Sun Microsystems - Beijing China 	struct ath_desc *ds;
38c0c93480Slin wang - Sun Microsystems - Beijing China 
39c0c93480Slin wang - Sun Microsystems - Beijing China 	ds = bf->bf_desc;
40c0c93480Slin wang - Sun Microsystems - Beijing China 	ds->ds_link = 0;
41c0c93480Slin wang - Sun Microsystems - Beijing China 	ds->ds_data = bf->bf_dma.cookie.dmac_address;
42c0c93480Slin wang - Sun Microsystems - Beijing China 
43c0c93480Slin wang - Sun Microsystems - Beijing China 	/* virtual addr of the beginning of the buffer. */
44c0c93480Slin wang - Sun Microsystems - Beijing China 	ds->ds_vdata = bf->bf_dma.mem_va;
45c0c93480Slin wang - Sun Microsystems - Beijing China 
46c0c93480Slin wang - Sun Microsystems - Beijing China 	/*
47c0c93480Slin wang - Sun Microsystems - Beijing China 	 * setup rx descriptors. The bf_dma.alength here tells the H/W
48c0c93480Slin wang - Sun Microsystems - Beijing China 	 * how much data it can DMA to us and that we are prepared
49c0c93480Slin wang - Sun Microsystems - Beijing China 	 * to process
50c0c93480Slin wang - Sun Microsystems - Beijing China 	 */
51c0c93480Slin wang - Sun Microsystems - Beijing China 	(void) ath9k_hw_setuprxdesc(sc->sc_ah, ds,
52c0c93480Slin wang - Sun Microsystems - Beijing China 	    bf->bf_dma.alength, /* buffer size */
53c0c93480Slin wang - Sun Microsystems - Beijing China 	    0);
54c0c93480Slin wang - Sun Microsystems - Beijing China 
55c0c93480Slin wang - Sun Microsystems - Beijing China 	if (sc->sc_rxlink == NULL)
56c0c93480Slin wang - Sun Microsystems - Beijing China 		ath9k_hw_putrxbuf(sc->sc_ah, bf->bf_daddr);
57c0c93480Slin wang - Sun Microsystems - Beijing China 	else
58c0c93480Slin wang - Sun Microsystems - Beijing China 		*sc->sc_rxlink = bf->bf_daddr;
59c0c93480Slin wang - Sun Microsystems - Beijing China 
60c0c93480Slin wang - Sun Microsystems - Beijing China 	sc->sc_rxlink = &ds->ds_link;
61c0c93480Slin wang - Sun Microsystems - Beijing China 	ath9k_hw_rxena(sc->sc_ah);
62c0c93480Slin wang - Sun Microsystems - Beijing China }
63c0c93480Slin wang - Sun Microsystems - Beijing China 
64dd1de374Slin wang - Sun Microsystems - Beijing China void
arn_setdefantenna(struct arn_softc * sc,uint32_t antenna)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
arn_extend_tsf(struct arn_softc * sc,uint32_t rstamp)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 
89c0c93480Slin wang - Sun Microsystems - Beijing China static int
arn_rx_prepare(struct ath_desc * ds,struct arn_softc * sc)90c0c93480Slin wang - Sun Microsystems - Beijing China arn_rx_prepare(struct ath_desc *ds, struct arn_softc *sc)
91c0c93480Slin wang - Sun Microsystems - Beijing China {
92c0c93480Slin wang - Sun Microsystems - Beijing China 	uint8_t phyerr;
93c0c93480Slin wang - Sun Microsystems - Beijing China 
94c0c93480Slin wang - Sun Microsystems - Beijing China 	if (ds->ds_rxstat.rs_more) {
95c0c93480Slin wang - Sun Microsystems - Beijing China 		/*
96c0c93480Slin wang - Sun Microsystems - Beijing China 		 * Frame spans multiple descriptors; this cannot happen yet
97c0c93480Slin wang - Sun Microsystems - Beijing China 		 * as we don't support jumbograms. If not in monitor mode,
98c0c93480Slin wang - Sun Microsystems - Beijing China 		 * discard the frame. Enable this if you want to see
99c0c93480Slin wang - Sun Microsystems - Beijing China 		 * error frames in Monitor mode.
100c0c93480Slin wang - Sun Microsystems - Beijing China 		 */
101c0c93480Slin wang - Sun Microsystems - Beijing China 		if (sc->sc_ah->ah_opmode != ATH9K_M_MONITOR)
102c0c93480Slin wang - Sun Microsystems - Beijing China 			goto rx_next;
103c0c93480Slin wang - Sun Microsystems - Beijing China 	} else if (ds->ds_rxstat.rs_status != 0) {
104c0c93480Slin wang - Sun Microsystems - Beijing China 		if (ds->ds_rxstat.rs_status & ATH9K_RXERR_CRC) {
105c0c93480Slin wang - Sun Microsystems - Beijing China 			sc->sc_stats.ast_rx_crcerr++;
106c0c93480Slin wang - Sun Microsystems - Beijing China 			goto rx_next; /* should ignore? */
107c0c93480Slin wang - Sun Microsystems - Beijing China 		}
108c0c93480Slin wang - Sun Microsystems - Beijing China 
109c0c93480Slin wang - Sun Microsystems - Beijing China 		if (ds->ds_rxstat.rs_status & ATH9K_RXERR_FIFO) {
110c0c93480Slin wang - Sun Microsystems - Beijing China 				sc->sc_stats.ast_rx_fifoerr++;
111c0c93480Slin wang - Sun Microsystems - Beijing China 		}
112c0c93480Slin wang - Sun Microsystems - Beijing China 
113c0c93480Slin wang - Sun Microsystems - Beijing China 		if (ds->ds_rxstat.rs_status & ATH9K_RXERR_PHY) {
114c0c93480Slin wang - Sun Microsystems - Beijing China 				sc->sc_stats.ast_rx_phyerr++;
115c0c93480Slin wang - Sun Microsystems - Beijing China 				phyerr = ds->ds_rxstat.rs_phyerr & 0x1f;
116c0c93480Slin wang - Sun Microsystems - Beijing China 				sc->sc_stats.ast_rx_phy[phyerr]++;
117c0c93480Slin wang - Sun Microsystems - Beijing China 			goto rx_next;
118c0c93480Slin wang - Sun Microsystems - Beijing China 		}
119c0c93480Slin wang - Sun Microsystems - Beijing China 
120c0c93480Slin wang - Sun Microsystems - Beijing China 		if (ds->ds_rxstat.rs_status & ATH9K_RXERR_DECRYPT) {
121c0c93480Slin wang - Sun Microsystems - Beijing China 			sc->sc_stats.ast_rx_badcrypt++;
122c0c93480Slin wang - Sun Microsystems - Beijing China 		}
123c0c93480Slin wang - Sun Microsystems - Beijing China 
124c0c93480Slin wang - Sun Microsystems - Beijing China 		/*
125c0c93480Slin wang - Sun Microsystems - Beijing China 		 * Reject error frames with the exception of
126c0c93480Slin wang - Sun Microsystems - Beijing China 		 * decryption and MIC failures. For monitor mode,
127c0c93480Slin wang - Sun Microsystems - Beijing China 		 * we also ignore the CRC error.
128c0c93480Slin wang - Sun Microsystems - Beijing China 		 */
129c0c93480Slin wang - Sun Microsystems - Beijing China 		if (sc->sc_ah->ah_opmode == ATH9K_M_MONITOR) {
130c0c93480Slin wang - Sun Microsystems - Beijing China 			if (ds->ds_rxstat.rs_status &
131c0c93480Slin wang - Sun Microsystems - Beijing China 			    ~(ATH9K_RXERR_DECRYPT |
132c0c93480Slin wang - Sun Microsystems - Beijing China 			    ATH9K_RXERR_MIC |
133c0c93480Slin wang - Sun Microsystems - Beijing China 			    ATH9K_RXERR_CRC))
134c0c93480Slin wang - Sun Microsystems - Beijing China 				goto rx_next;
135c0c93480Slin wang - Sun Microsystems - Beijing China 		} else {
136c0c93480Slin wang - Sun Microsystems - Beijing China 			if (ds->ds_rxstat.rs_status &
137c0c93480Slin wang - Sun Microsystems - Beijing China 			    ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC)) {
138c0c93480Slin wang - Sun Microsystems - Beijing China 				goto rx_next;
139c0c93480Slin wang - Sun Microsystems - Beijing China 			}
140c0c93480Slin wang - Sun Microsystems - Beijing China 		}
141c0c93480Slin wang - Sun Microsystems - Beijing China 	}
142c0c93480Slin wang - Sun Microsystems - Beijing China 
143c0c93480Slin wang - Sun Microsystems - Beijing China 	return (1);
144c0c93480Slin wang - Sun Microsystems - Beijing China rx_next:
145c0c93480Slin wang - Sun Microsystems - Beijing China 	return (0);
146c0c93480Slin wang - Sun Microsystems - Beijing China }
147c0c93480Slin wang - Sun Microsystems - Beijing China 
148c0c93480Slin wang - Sun Microsystems - Beijing China 
149dd1de374Slin wang - Sun Microsystems - Beijing China static void
arn_opmode_init(struct arn_softc * sc)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
arn_calcrxfilter(struct arn_softc * sc)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 
242c0c93480Slin wang - Sun Microsystems - Beijing China /*
243c0c93480Slin wang - Sun Microsystems - Beijing China  * When block ACK agreement has been set up between station and AP,
244c0c93480Slin wang - Sun Microsystems - Beijing China  * Net80211 module will call this function to inform hardware about
245c0c93480Slin wang - Sun Microsystems - Beijing China  * informations of this BA agreement.
246c0c93480Slin wang - Sun Microsystems - Beijing China  * When AP wants to delete BA agreement that was originated by it,
247c0c93480Slin wang - Sun Microsystems - Beijing China  * Net80211 modele will call this function to clean up relevant
248c0c93480Slin wang - Sun Microsystems - Beijing China  * information in hardware.
249c0c93480Slin wang - Sun Microsystems - Beijing China  */
250c0c93480Slin wang - Sun Microsystems - Beijing China 
251c0c93480Slin wang - Sun Microsystems - Beijing China void
arn_ampdu_recv_action(struct ieee80211_node * in,const uint8_t * frm,const uint8_t * efrm)252c0c93480Slin wang - Sun Microsystems - Beijing China arn_ampdu_recv_action(struct ieee80211_node *in,
253c0c93480Slin wang - Sun Microsystems - Beijing China     const uint8_t *frm,
254c0c93480Slin wang - Sun Microsystems - Beijing China     const uint8_t *efrm)
255c0c93480Slin wang - Sun Microsystems - Beijing China {
256c0c93480Slin wang - Sun Microsystems - Beijing China 	struct ieee80211com *ic;
257c0c93480Slin wang - Sun Microsystems - Beijing China 	struct arn_softc *sc;
258c0c93480Slin wang - Sun Microsystems - Beijing China 
259c0c93480Slin wang - Sun Microsystems - Beijing China 	if ((in == NULL) || (frm == NULL) || (ic = in->in_ic) == NULL) {
260c0c93480Slin wang - Sun Microsystems - Beijing China 		ARN_DBG((ARN_DBG_FATAL,
261c0c93480Slin wang - Sun Microsystems - Beijing China 		    "Unknown AMPDU action or NULL node index\n"));
262c0c93480Slin wang - Sun Microsystems - Beijing China 		return;
263c0c93480Slin wang - Sun Microsystems - Beijing China 	}
264c0c93480Slin wang - Sun Microsystems - Beijing China 
265c0c93480Slin wang - Sun Microsystems - Beijing China 	sc = (struct arn_softc *)ic;
266c0c93480Slin wang - Sun Microsystems - Beijing China 
267c0c93480Slin wang - Sun Microsystems - Beijing China 	if (!(sc->sc_flags & SC_OP_RXAGGR))
268c0c93480Slin wang - Sun Microsystems - Beijing China 		return;
269c0c93480Slin wang - Sun Microsystems - Beijing China 	else
270c0c93480Slin wang - Sun Microsystems - Beijing China 		sc->sc_recv_action(in, frm, efrm);
271c0c93480Slin wang - Sun Microsystems - Beijing China }
272c0c93480Slin wang - Sun Microsystems - Beijing China 
273dd1de374Slin wang - Sun Microsystems - Beijing China int
arn_startrecv(struct arn_softc * sc)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 
279c0c93480Slin wang - Sun Microsystems - Beijing China 	/* rx descriptor link set up */
280c0c93480Slin wang - Sun Microsystems - Beijing China 	mutex_enter(&sc->sc_rxbuflock);
281c0c93480Slin wang - Sun Microsystems - Beijing China 	if (list_empty(&sc->sc_rxbuf_list))
282c0c93480Slin wang - Sun Microsystems - Beijing China 		goto start_recv;
283c0c93480Slin 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 
293c0c93480Slin wang - Sun Microsystems - Beijing China 
294c0c93480Slin wang - Sun Microsystems - Beijing China 	/* We could have deleted elements so the list may be empty now */
295c0c93480Slin wang - Sun Microsystems - Beijing China 	if (list_empty(&sc->sc_rxbuf_list))
296c0c93480Slin wang - Sun Microsystems - Beijing China 		goto start_recv;
297c0c93480Slin 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 
303c0c93480Slin wang - Sun Microsystems - Beijing China start_recv:
304c0c93480Slin 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
arn_stoprecv(struct arn_softc * sc)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
arn_recv_mgmt(struct ieee80211com * ic,mblk_t * mp,struct ieee80211_node * in,int subtype,int rssi,uint32_t rstamp)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
arn_printrxbuf(struct ath_buf * bf,int32_t done)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
arn_rx_handler(struct arn_softc * sc)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;
429c0c93480Slin wang - Sun Microsystems - Beijing China 	int32_t len, ngood = 0, loop = 1;
430c0c93480Slin wang - Sun Microsystems - Beijing China 	uint32_t subtype;
431dd1de374Slin wang - Sun Microsystems - Beijing China 	int status;
432c0c93480Slin wang - Sun Microsystems - Beijing China 	int last_rssi = ATH_RSSI_DUMMY_MARKER;
433c0c93480Slin 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;
436c0c93480Slin wang - Sun Microsystems - Beijing China #ifdef ARN_DBG_AMSDU
437c0c93480Slin wang - Sun Microsystems - Beijing China 	uint8_t qos;
438c0c93480Slin 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"));
446c0c93480Slin 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 		}
450*411e5762SToomas Soome 		ASSERT(bf->bf_dma.cookie.dmac_address != 0);
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) {
468c0c93480Slin wang - Sun Microsystems - Beijing China 			struct ath_buf *tbf;
469c0c93480Slin wang - Sun Microsystems - Beijing China 			struct ath_desc *tds;
470c0c93480Slin wang - Sun Microsystems - Beijing China 
471c0c93480Slin wang - Sun Microsystems - Beijing China 			if (list_is_last(&bf->bf_node, &sc->sc_rxbuf_list)) {
472c0c93480Slin wang - Sun Microsystems - Beijing China 				ARN_DBG((ARN_DBG_RECV, "arn: arn_rx_handler(): "
473c0c93480Slin wang - Sun Microsystems - Beijing China 				    "List is in last! \n"));
474c0c93480Slin wang - Sun Microsystems - Beijing China 				sc->sc_rxlink = NULL;
475c0c93480Slin wang - Sun Microsystems - Beijing China 				break;
476c0c93480Slin wang - Sun Microsystems - Beijing China 			}
477c0c93480Slin wang - Sun Microsystems - Beijing China 
478c0c93480Slin wang - Sun Microsystems - Beijing China 			tbf = list_object(&sc->sc_rxbuf_list,
479c0c93480Slin wang - Sun Microsystems - Beijing China 			    bf->bf_node.list_next);
480c0c93480Slin wang - Sun Microsystems - Beijing China 
481c0c93480Slin wang - Sun Microsystems - Beijing China 			/*
482c0c93480Slin wang - Sun Microsystems - Beijing China 			 * On some hardware the descriptor status words could
483c0c93480Slin wang - Sun Microsystems - Beijing China 			 * get corrupted, including the done bit. Because of
484c0c93480Slin wang - Sun Microsystems - Beijing China 			 * this, check if the next descriptor's done bit is
485c0c93480Slin wang - Sun Microsystems - Beijing China 			 * set or not.
486c0c93480Slin wang - Sun Microsystems - Beijing China 			 *
487c0c93480Slin wang - Sun Microsystems - Beijing China 			 * If the next descriptor's done bit is set, the current
488c0c93480Slin wang - Sun Microsystems - Beijing China 			 * descriptor has been corrupted. Force s/w to discard
489c0c93480Slin wang - Sun Microsystems - Beijing China 			 * this descriptor and continue...
490c0c93480Slin wang - Sun Microsystems - Beijing China 			 */
491c0c93480Slin wang - Sun Microsystems - Beijing China 
492c0c93480Slin wang - Sun Microsystems - Beijing China 			tds = tbf->bf_desc;
493c0c93480Slin wang - Sun Microsystems - Beijing China 			status = ath9k_hw_rxprocdesc(ah, tds, tbf->bf_daddr,
494c0c93480Slin wang - Sun Microsystems - Beijing China 			    PA2DESC(sc, tds->ds_link), 0);
495c0c93480Slin 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 			}
499c0c93480Slin 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++;
509c0c93480Slin wang - Sun Microsystems - Beijing China 			goto requeue;
510dd1de374Slin wang - Sun Microsystems - Beijing China 		}
511dd1de374Slin wang - Sun Microsystems - Beijing China 
512c0c93480Slin wang - Sun Microsystems - Beijing China 		/* The status portion of the descriptor could get corrupted. */
513c0c93480Slin wang - Sun Microsystems - Beijing China 		if (sc->rx_dmabuf_size < rs->rs_datalen) {
514c0c93480Slin wang - Sun Microsystems - Beijing China 			arn_problem("Requeued because of wrong rs_datalen\n");
515c0c93480Slin wang - Sun Microsystems - Beijing China 			goto requeue;
516c0c93480Slin wang - Sun Microsystems - Beijing China 		}
517c0c93480Slin wang - Sun Microsystems - Beijing China 
518c0c93480Slin wang - Sun Microsystems - Beijing China 		if (!arn_rx_prepare(ds, sc))
519c0c93480Slin wang - Sun Microsystems - Beijing China 			goto requeue;
520c0c93480Slin wang - Sun Microsystems - Beijing China 
521c0c93480Slin 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);
539c0c93480Slin 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 
544c0c93480Slin wang - Sun Microsystems - Beijing China #ifdef DEBUG
545c0c93480Slin wang - Sun Microsystems - Beijing China 		arn_printrxbuf(bf, status == 0);
546c0c93480Slin wang - Sun Microsystems - Beijing China #endif
547c0c93480Slin wang - Sun Microsystems - Beijing China 
548c0c93480Slin wang - Sun Microsystems - Beijing China #ifdef ARN_DBG_AMSDU
549c0c93480Slin wang - Sun Microsystems - Beijing China 		if (IEEE80211_IS_DATA_QOS(wh)) {
550c0c93480Slin wang - Sun Microsystems - Beijing China 			if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) ==
551c0c93480Slin wang - Sun Microsystems - Beijing China 			    IEEE80211_FC1_DIR_DSTODS)
552c0c93480Slin wang - Sun Microsystems - Beijing China 				qos = ((struct ieee80211_qosframe_addr4 *)
553c0c93480Slin wang - Sun Microsystems - Beijing China 				    wh)->i_qos[0];
554c0c93480Slin wang - Sun Microsystems - Beijing China 			else
555c0c93480Slin wang - Sun Microsystems - Beijing China 				qos =
556c0c93480Slin wang - Sun Microsystems - Beijing China 				    ((struct ieee80211_qosframe *)wh)->i_qos[0];
557c0c93480Slin wang - Sun Microsystems - Beijing China 
558c0c93480Slin wang - Sun Microsystems - Beijing China 			if (qos & IEEE80211_QOS_AMSDU)
559c0c93480Slin wang - Sun Microsystems - Beijing China 				arn_dump_pkg((unsigned char *)bf->bf_dma.mem_va,
560c0c93480Slin wang - Sun Microsystems - Beijing China 				    len, 1, 1);
561c0c93480Slin wang - Sun Microsystems - Beijing China 		}
562c0c93480Slin wang - Sun Microsystems - Beijing China #endif /* ARN_DBG_AMSDU */
563c0c93480Slin 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);
570c0c93480Slin wang - Sun Microsystems - Beijing China 		an = ATH_NODE(in);
571c0c93480Slin wang - Sun Microsystems - Beijing China 
572c0c93480Slin wang - Sun Microsystems - Beijing China 		/*
573c0c93480Slin wang - Sun Microsystems - Beijing China 		 * Theory for reporting quality:
574c0c93480Slin wang - Sun Microsystems - Beijing China 		 *
575c0c93480Slin wang - Sun Microsystems - Beijing China 		 * At a hardware RSSI of 45 you will be able to use
576c0c93480Slin wang - Sun Microsystems - Beijing China 		 * MCS 7 reliably.
577c0c93480Slin wang - Sun Microsystems - Beijing China 		 * At a hardware RSSI of 45 you will be able to use
578c0c93480Slin wang - Sun Microsystems - Beijing China 		 * MCS 15 reliably.
579c0c93480Slin wang - Sun Microsystems - Beijing China 		 * At a hardware RSSI of 35 you should be able use
580c0c93480Slin wang - Sun Microsystems - Beijing China 		 * 54 Mbps reliably.
581c0c93480Slin wang - Sun Microsystems - Beijing China 		 *
582c0c93480Slin wang - Sun Microsystems - Beijing China 		 * MCS 7  is the highets MCS index usable by a 1-stream device.
583c0c93480Slin wang - Sun Microsystems - Beijing China 		 * MCS 15 is the highest MCS index usable by a 2-stream device.
584c0c93480Slin wang - Sun Microsystems - Beijing China 		 *
585c0c93480Slin wang - Sun Microsystems - Beijing China 		 * All ath9k devices are either 1-stream or 2-stream.
586c0c93480Slin wang - Sun Microsystems - Beijing China 		 *
587c0c93480Slin wang - Sun Microsystems - Beijing China 		 * How many bars you see is derived from the qual reporting.
588c0c93480Slin wang - Sun Microsystems - Beijing China 		 *
589c0c93480Slin wang - Sun Microsystems - Beijing China 		 * A more elaborate scheme can be used here but it requires
590c0c93480Slin wang - Sun Microsystems - Beijing China 		 * tables of SNR/throughput for each possible mode used. For
591c0c93480Slin wang - Sun Microsystems - Beijing China 		 * the MCS table you can refer to the wireless wiki:
592c0c93480Slin wang - Sun Microsystems - Beijing China 		 *
593c0c93480Slin wang - Sun Microsystems - Beijing China 		 * http://wireless.kernel.org/en/developers/Documentation/
594c0c93480Slin wang - Sun Microsystems - Beijing China 		 * ieee80211/802.11n
595c0c93480Slin wang - Sun Microsystems - Beijing China 		 */
596c0c93480Slin wang - Sun Microsystems - Beijing China 		if (ds->ds_rxstat.rs_rssi != ATH9K_RSSI_BAD &&
597c0c93480Slin wang - Sun Microsystems - Beijing China 		    !ds->ds_rxstat.rs_moreaggr) {
598c0c93480Slin wang - Sun Microsystems - Beijing China 		    /* LINTED: E_CONSTANT_CONDITION */
599c0c93480Slin wang - Sun Microsystems - Beijing China 			ATH_RSSI_LPF(an->last_rssi, ds->ds_rxstat.rs_rssi);
600c0c93480Slin wang - Sun Microsystems - Beijing China 		}
601c0c93480Slin wang - Sun Microsystems - Beijing China 		last_rssi = an->last_rssi;
602c0c93480Slin wang - Sun Microsystems - Beijing China 
603c0c93480Slin wang - Sun Microsystems - Beijing China 		if (last_rssi != ATH_RSSI_DUMMY_MARKER)
604c0c93480Slin wang - Sun Microsystems - Beijing China 			ds->ds_rxstat.rs_rssi = ATH_EP_RND(last_rssi,
605c0c93480Slin 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 		/*
619c0c93480Slin wang - Sun Microsystems - Beijing China 		 * signal (13-15) DLADM_WLAN_STRENGTH_EXCELLENT
620c0c93480Slin wang - Sun Microsystems - Beijing China 		 * signal (10-12) DLADM_WLAN_STRENGTH_VERY_GOOD
621c0c93480Slin wang - Sun Microsystems - Beijing China 		 * signal (6-9)    DLADM_WLAN_STRENGTH_GOOD
622c0c93480Slin wang - Sun Microsystems - Beijing China 		 * signal (3-5)    DLADM_WLAN_STRENGTH_WEAK
623c0c93480Slin 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 		 */
635c0c93480Slin 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);
638c0c93480Slin wang - Sun Microsystems - Beijing China 		}
6393ae945c3Slin wang - Sun Microsystems - Beijing China 		else
640c0c93480Slin wang - Sun Microsystems - Beijing China 			(void) ieee80211_input(ic, rx_mp, in, rs->rs_rssi,
641c0c93480Slin 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 
671c0c93480Slin 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
arn_softint_handler(caddr_t data)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