xref: /freebsd/sys/dev/rtwn/usb/rtwn_usb_rx.c (revision 28e89934a9bec3eca08f4d291a5699485c29d203)
1 /*	$OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $	*/
2 
3 /*-
4  * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
5  * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org>
6  * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
7  *
8  * Permission to use, copy, modify, and distribute this software for any
9  * purpose with or without fee is hereby granted, provided that the above
10  * copyright notice and this permission notice appear in all copies.
11  *
12  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19  */
20 
21 #include <sys/cdefs.h>
22 #include "opt_wlan.h"
23 
24 #include <sys/param.h>
25 #include <sys/lock.h>
26 #include <sys/mutex.h>
27 #include <sys/mbuf.h>
28 #include <sys/kernel.h>
29 #include <sys/socket.h>
30 #include <sys/systm.h>
31 #include <sys/malloc.h>
32 #include <sys/queue.h>
33 #include <sys/taskqueue.h>
34 #include <sys/bus.h>
35 #include <sys/endian.h>
36 
37 #include <net/if.h>
38 #include <net/if_var.h>
39 #include <net/ethernet.h>
40 #include <net/if_dl.h>
41 #include <net/if_media.h>
42 
43 #include <net80211/ieee80211_var.h>
44 #include <net80211/ieee80211_radiotap.h>
45 #ifdef	IEEE80211_SUPPORT_SUPERG
46 #include <net80211/ieee80211_superg.h>
47 #endif
48 
49 #include <dev/usb/usb.h>
50 #include <dev/usb/usbdi.h>
51 
52 #include <dev/rtwn/if_rtwnreg.h>
53 #include <dev/rtwn/if_rtwnvar.h>
54 
55 #include <dev/rtwn/if_rtwn_debug.h>
56 #include <dev/rtwn/if_rtwn_ridx.h>
57 #include <dev/rtwn/if_rtwn_rx.h>
58 #include <dev/rtwn/if_rtwn_task.h>
59 #include <dev/rtwn/if_rtwn_tx.h>
60 
61 #include <dev/rtwn/usb/rtwn_usb_var.h>
62 #include <dev/rtwn/usb/rtwn_usb_rx.h>
63 
64 static struct mbuf *	rtwn_rxeof(struct rtwn_softc *, struct rtwn_data *,
65 			    uint8_t *, int);
66 
67 static int
rtwn_rx_check_pre_alloc(struct rtwn_softc * sc,struct rtwn_rx_stat_common * stat)68 rtwn_rx_check_pre_alloc(struct rtwn_softc *sc,
69     struct rtwn_rx_stat_common *stat)
70 {
71 	uint32_t rxdw0;
72 	int pktlen;
73 
74 	RTWN_ASSERT_LOCKED(sc);
75 
76 	/*
77 	 * don't pass packets to the ieee80211 framework if the driver isn't
78 	 * RUNNING.
79 	 */
80 	if (!(sc->sc_flags & RTWN_RUNNING))
81 		return (-1);
82 
83 	rxdw0 = le32toh(stat->rxdw0);
84 	if (__predict_false(rxdw0 & (RTWN_RXDW0_CRCERR | RTWN_RXDW0_ICVERR))) {
85 		/*
86 		 * This should not happen since we setup our Rx filter
87 		 * to not receive these frames.
88 		 */
89 		RTWN_DPRINTF(sc, RTWN_DEBUG_RECV,
90 		    "%s: RX flags error (%s)\n", __func__,
91 		    rxdw0 & RTWN_RXDW0_CRCERR ? "CRC" : "ICV");
92 		return (-1);
93 	}
94 
95 	pktlen = MS(rxdw0, RTWN_RXDW0_PKTLEN);
96 	if (__predict_false(pktlen < sizeof(struct ieee80211_frame_ack))) {
97 		/*
98 		 * Should not happen (because of Rx filter setup).
99 		 */
100 		RTWN_DPRINTF(sc, RTWN_DEBUG_RECV,
101 		    "%s: frame is too short: %d\n", __func__, pktlen);
102 		return (-1);
103 	}
104 
105 	return (0);
106 }
107 
108 static struct mbuf *
rtwn_rx_copy_to_mbuf(struct rtwn_softc * sc,struct rtwn_rx_stat_common * stat,int totlen)109 rtwn_rx_copy_to_mbuf(struct rtwn_softc *sc, struct rtwn_rx_stat_common *stat,
110     int totlen)
111 {
112 	struct ieee80211com *ic = &sc->sc_ic;
113 	struct mbuf *m;
114 
115 	RTWN_ASSERT_LOCKED(sc);
116 
117 	/* Dump Rx descriptor. */
118 	RTWN_DPRINTF(sc, RTWN_DEBUG_RECV_DESC,
119 	    "%s: dw: 0 %08X, 1 %08X, 2 %08X, 3 %08X, 4 %08X, tsfl %08X\n",
120 	    __func__, le32toh(stat->rxdw0), le32toh(stat->rxdw1),
121 	    le32toh(stat->rxdw2), le32toh(stat->rxdw3), le32toh(stat->rxdw4),
122 	    le32toh(stat->tsf_low));
123 
124 	if (rtwn_rx_check_pre_alloc(sc, stat) != 0)
125 		goto fail;
126 
127 	/*
128 	 * Note: this can require >4 KiB (eg de-aggregating an A-MSDU
129 	 * from an USB frame.  See kern/286366 for more information.
130 	 */
131 	m = m_get3(totlen, M_NOWAIT, MT_DATA, M_PKTHDR);
132 	if (__predict_false(m == NULL)) {
133 		device_printf(sc->sc_dev,
134 		    "%s: could not allocate RX mbuf (%d bytes)\n",
135 		    __func__, totlen);
136 		goto fail;
137 	}
138 
139 	/* Finalize mbuf. */
140 	memcpy(mtod(m, uint8_t *), (uint8_t *)stat, totlen);
141 	m->m_pkthdr.len = m->m_len = totlen;
142 
143 	if (rtwn_check_frame(sc, m) != 0) {
144 		m_freem(m);
145 		goto fail;
146 	}
147 
148 	return (m);
149 fail:
150 	counter_u64_add(ic->ic_ierrors, 1);
151 	return (NULL);
152 }
153 
154 static struct mbuf *
rtwn_rxeof_fragmented(struct rtwn_usb_softc * uc,struct rtwn_data * data,uint8_t * buf,int len)155 rtwn_rxeof_fragmented(struct rtwn_usb_softc *uc, struct rtwn_data *data,
156     uint8_t *buf, int len)
157 {
158 	struct rtwn_softc *sc = &uc->uc_sc;
159 	struct ieee80211com *ic = &sc->sc_ic;
160 	struct rtwn_rx_stat_common *stat = &uc->uc_rx_stat;
161 	uint32_t rxdw0;
162 	int totlen, pktlen, infosz, min_len;
163 	int orig_len = len;
164 	int alloc_mbuf = 0;
165 
166 	/* Check if Rx descriptor is not truncated. */
167 	if (uc->uc_rx_stat_len < sizeof(*stat)) {
168 		min_len = min(sizeof(*stat) - uc->uc_rx_stat_len, len);
169 		memcpy((uint8_t *)stat + uc->uc_rx_stat_len, buf, min_len);
170 
171 		uc->uc_rx_stat_len += min_len;
172 		buf += min_len;
173 		len -= min_len;
174 
175 		if (uc->uc_rx_stat_len < sizeof(*stat))
176 			goto end;
177 
178 		KASSERT(data->m == NULL, ("%s: data->m != NULL!\n", __func__));
179 		alloc_mbuf = 1;
180 
181 		/* Dump Rx descriptor. */
182 		RTWN_DPRINTF(sc, RTWN_DEBUG_RECV_DESC,
183 		    "%s: dw: 0 %08X, 1 %08X, 2 %08X, 3 %08X, 4 %08X, "
184 		    "tsfl %08X\n", __func__, le32toh(stat->rxdw0),
185 		    le32toh(stat->rxdw1), le32toh(stat->rxdw2),
186 		    le32toh(stat->rxdw3), le32toh(stat->rxdw4),
187 		    le32toh(stat->tsf_low));
188 	}
189 
190 	rxdw0 = le32toh(stat->rxdw0);
191 	pktlen = MS(rxdw0, RTWN_RXDW0_PKTLEN);
192 	infosz = MS(rxdw0, RTWN_RXDW0_INFOSZ) * 8;
193 	totlen = sizeof(*stat) + infosz + pktlen;
194 	if (alloc_mbuf) {
195 		if (rtwn_rx_check_pre_alloc(sc, stat) == 0) {
196 			data->m = m_getm(NULL, totlen, M_NOWAIT, MT_DATA);
197 			if (data->m != NULL) {
198 				m_copyback(data->m, 0, uc->uc_rx_stat_len,
199 				    (caddr_t)stat);
200 
201 				if (rtwn_check_frame(sc, data->m) != 0) {
202 					m_freem(data->m);
203 					data->m = NULL;
204 					counter_u64_add(ic->ic_ierrors, 1);
205 				}
206 			} else
207 				counter_u64_add(ic->ic_ierrors, 1);
208 		} else
209 			counter_u64_add(ic->ic_ierrors, 1);
210 
211 		uc->uc_rx_off = sizeof(*stat);
212 	}
213 
214 	/* If mbuf allocation fails just discard the data. */
215 	min_len = min(totlen - uc->uc_rx_off, len);
216 	if (data->m != NULL)
217 		m_copyback(data->m, uc->uc_rx_off, min_len, buf);
218 
219 	uc->uc_rx_off += min_len;
220 	if (uc->uc_rx_off == totlen) {
221 		/* Align next frame. */
222 		min_len = rtwn_usb_align_rx(uc,
223 		    orig_len - len + min_len, orig_len);
224 		min_len -= (orig_len - len);
225 		KASSERT(len >= min_len, ("%s: len (%d) < min_len (%d)!\n",
226 		    __func__, len, min_len));
227 
228 		/* Clear mbuf stats. */
229 		uc->uc_rx_stat_len = 0;
230 		uc->uc_rx_off = 0;
231 	}
232 	len -= min_len;
233 	buf += min_len;
234 end:
235 	if (uc->uc_rx_stat_len == 0)
236 		return (rtwn_rxeof(sc, data, buf, len));
237 	else
238 		return (NULL);
239 }
240 
241 static struct mbuf *
rtwn_rxeof(struct rtwn_softc * sc,struct rtwn_data * data,uint8_t * buf,int len)242 rtwn_rxeof(struct rtwn_softc *sc, struct rtwn_data *data, uint8_t *buf,
243     int len)
244 {
245 	struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc);
246 	struct rtwn_rx_stat_common *stat;
247 	struct mbuf *m, *m0 = NULL;
248 	uint32_t rxdw0;
249 	int totlen, pktlen, infosz;
250 
251 	/* Prepend defragmented frame (if any). */
252 	if (data->m != NULL) {
253 		m0 = m = data->m;
254 		data->m = NULL;
255 	}
256 
257 	/* Process packets. */
258 	while (len >= sizeof(*stat)) {
259 		stat = (struct rtwn_rx_stat_common *)buf;
260 		rxdw0 = le32toh(stat->rxdw0);
261 
262 		pktlen = MS(rxdw0, RTWN_RXDW0_PKTLEN);
263 		if (__predict_false(pktlen == 0))
264 			break;
265 
266 		infosz = MS(rxdw0, RTWN_RXDW0_INFOSZ) * 8;
267 
268 		/* Make sure everything fits in xfer. */
269 		totlen = sizeof(*stat) + infosz + pktlen;
270 		if (totlen > len) {
271 			RTWN_DPRINTF(sc, RTWN_DEBUG_RECV,
272 			    "%s: frame is fragmented (totlen %d len %d)\n",
273 			    __func__, totlen, len);
274 			break;
275 		}
276 
277 		if (m0 == NULL)
278 			m0 = m = rtwn_rx_copy_to_mbuf(sc, stat, totlen);
279 		else {
280 			m->m_nextpkt = rtwn_rx_copy_to_mbuf(sc, stat, totlen);
281 			if (m->m_nextpkt != NULL)
282 				m = m->m_nextpkt;
283 		}
284 
285 		/* Align next frame. */
286 		totlen = rtwn_usb_align_rx(uc, totlen, len);
287 		buf += totlen;
288 		len -= totlen;
289 	}
290 
291 	if (len > 0)
292 		(void)rtwn_rxeof_fragmented(uc, data, buf, len);
293 
294 	return (m0);
295 }
296 
297 static struct mbuf *
rtwn_report_intr(struct rtwn_usb_softc * uc,struct usb_xfer * xfer,struct rtwn_data * data)298 rtwn_report_intr(struct rtwn_usb_softc *uc, struct usb_xfer *xfer,
299     struct rtwn_data *data)
300 {
301 	struct rtwn_softc *sc = &uc->uc_sc;
302 	struct ieee80211com *ic = &sc->sc_ic;
303 	uint8_t *buf;
304 	int len;
305 
306 	usbd_xfer_status(xfer, &len, NULL, NULL, NULL);
307 
308 	if (__predict_false(len < sizeof(struct rtwn_rx_stat_common) &&
309 	    uc->uc_rx_stat_len == 0)) {
310 		counter_u64_add(ic->ic_ierrors, 1);
311 		return (NULL);
312 	}
313 
314 	buf = data->buf;
315 	if (uc->uc_rx_stat_len > 0)
316 		return (rtwn_rxeof_fragmented(uc, data, data->buf, len));
317 
318 	switch (rtwn_classify_intr(sc, buf, len)) {
319 	case RTWN_RX_DATA:
320 		return (rtwn_rxeof(sc, data, buf, len));
321 	case RTWN_RX_TX_REPORT:
322 		if (sc->sc_ratectl != RTWN_RATECTL_NET80211) {
323 			/* shouldn't happen */
324 			device_printf(sc->sc_dev,
325 			    "%s called while ratectl = %d!\n",
326 			    __func__, sc->sc_ratectl);
327 			break;
328 		}
329 
330 		RTWN_NT_LOCK(sc);
331 		rtwn_handle_tx_report(sc, buf, len);
332 		RTWN_NT_UNLOCK(sc);
333 
334 #ifdef IEEE80211_SUPPORT_SUPERG
335 		/*
336 		 * NB: this will executed only when 'report' bit is set.
337 		 */
338 		if (sc->sc_tx_n_active > 0 && --sc->sc_tx_n_active <= 1)
339 			rtwn_cmd_sleepable(sc, NULL, 0, rtwn_ff_flush_all);
340 #endif
341 		break;
342 	case RTWN_RX_TX_REPORT2:
343 		if (sc->sc_ratectl != RTWN_RATECTL_NET80211) {
344 			/* shouldn't happen */
345 			device_printf(sc->sc_dev,
346 			    "%s called while ratectl = %d!\n",
347 			    __func__, sc->sc_ratectl);
348 			break;
349 		}
350 
351 		RTWN_NT_LOCK(sc);
352 		rtwn_handle_tx_report2(sc, buf, len);
353 		RTWN_NT_UNLOCK(sc);
354 
355 #ifdef IEEE80211_SUPPORT_SUPERG
356 		/*
357 		 * NB: this will executed only when 'report' bit is set.
358 		 */
359 		if (sc->sc_tx_n_active > 0 && --sc->sc_tx_n_active <= 1)
360 			rtwn_cmd_sleepable(sc, NULL, 0, rtwn_ff_flush_all);
361 #endif
362 		break;
363 	case RTWN_RX_OTHER:
364 		rtwn_handle_c2h_report(sc, buf, len);
365 		break;
366 	default:
367 		/* NOTREACHED */
368 		KASSERT(0, ("unknown Rx classification code"));
369 		break;
370 	}
371 
372 	return (NULL);
373 }
374 
375 static struct ieee80211_node *
rtwn_rx_frame(struct rtwn_softc * sc,struct mbuf * m)376 rtwn_rx_frame(struct rtwn_softc *sc, struct mbuf *m)
377 {
378 	struct rtwn_rx_stat_common stat;
379 
380 	/* Imitate PCIe layout. */
381 	m_copydata(m, 0, sizeof(stat), (caddr_t)&stat);
382 	m_adj(m, sizeof(stat));
383 
384 	return (rtwn_rx_common(sc, m, &stat));
385 }
386 
387 void
rtwn_bulk_rx_callback(struct usb_xfer * xfer,usb_error_t error)388 rtwn_bulk_rx_callback(struct usb_xfer *xfer, usb_error_t error)
389 {
390 	struct rtwn_usb_softc *uc = usbd_xfer_softc(xfer);
391 	struct rtwn_softc *sc = &uc->uc_sc;
392 	struct ieee80211com *ic = &sc->sc_ic;
393 	struct ieee80211_node *ni;
394 	struct mbuf *m0, *m = NULL, *next;
395 	struct rtwn_data *data;
396 
397 	RTWN_ASSERT_LOCKED(sc);
398 
399 	switch (USB_GET_STATE(xfer)) {
400 	case USB_ST_TRANSFERRED:
401 		data = STAILQ_FIRST(&uc->uc_rx_active);
402 		if (data == NULL)
403 			goto tr_setup;
404 		STAILQ_REMOVE_HEAD(&uc->uc_rx_active, next);
405 		m = rtwn_report_intr(uc, xfer, data);
406 		STAILQ_INSERT_TAIL(&uc->uc_rx_inactive, data, next);
407 		/* FALLTHROUGH */
408 	case USB_ST_SETUP:
409 tr_setup:
410 		data = STAILQ_FIRST(&uc->uc_rx_inactive);
411 		if (data == NULL) {
412 			KASSERT(m == NULL, ("mbuf isn't NULL"));
413 			goto finish;
414 		}
415 		STAILQ_REMOVE_HEAD(&uc->uc_rx_inactive, next);
416 		STAILQ_INSERT_TAIL(&uc->uc_rx_active, data, next);
417 		usbd_xfer_set_frame_data(xfer, 0, data->buf,
418 		    usbd_xfer_max_len(xfer));
419 		usbd_transfer_submit(xfer);
420 
421 		/*
422 		 * To avoid LOR we should unlock our private mutex here to call
423 		 * ieee80211_input() because here is at the end of a USB
424 		 * callback and safe to unlock.
425 		 */
426 		m0 = m;
427 		while (m != NULL) {
428 			M_ASSERTPKTHDR(m);
429 			m->m_pkthdr.PH_loc.ptr = rtwn_rx_frame(sc, m);
430 			m = m->m_nextpkt;
431 		}
432 		RTWN_UNLOCK(sc);
433 		m = m0;
434 		while (m != NULL) {
435 			next = m->m_nextpkt;
436 			m->m_nextpkt = NULL;
437 
438 			ni = m->m_pkthdr.PH_loc.ptr;
439 			m->m_pkthdr.PH_loc.ptr = NULL;
440 			if (ni != NULL) {
441 				(void)ieee80211_input_mimo(ni, m);
442 				ieee80211_free_node(ni);
443 			} else {
444 				(void)ieee80211_input_mimo_all(ic, m);
445 			}
446 			m = next;
447 		}
448 		RTWN_LOCK(sc);
449 		break;
450 	default:
451 		/* needs it to the inactive queue due to a error. */
452 		data = STAILQ_FIRST(&uc->uc_rx_active);
453 		if (data != NULL) {
454 			STAILQ_REMOVE_HEAD(&uc->uc_rx_active, next);
455 			STAILQ_INSERT_TAIL(&uc->uc_rx_inactive, data, next);
456 		}
457 		if (error != USB_ERR_CANCELLED) {
458 			/* XXX restart device if frame was fragmented? */
459 
460 			usbd_xfer_set_stall(xfer);
461 			counter_u64_add(ic->ic_ierrors, 1);
462 			goto tr_setup;
463 		}
464 		break;
465 	}
466 finish:
467 	/* Kick-start more transmit in case we stalled */
468 	rtwn_start(sc);
469 }
470