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