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