1a84fab3cSChristian Lamparter /*
2a84fab3cSChristian Lamparter  * Atheros CARL9170 driver
3a84fab3cSChristian Lamparter  *
4a84fab3cSChristian Lamparter  * 802.11 & command trap routines
5a84fab3cSChristian Lamparter  *
6a84fab3cSChristian Lamparter  * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
7a84fab3cSChristian Lamparter  * Copyright 2009, 2010, Christian Lamparter <chunkeey@googlemail.com>
8a84fab3cSChristian Lamparter  *
9a84fab3cSChristian Lamparter  * This program is free software; you can redistribute it and/or modify
10a84fab3cSChristian Lamparter  * it under the terms of the GNU General Public License as published by
11a84fab3cSChristian Lamparter  * the Free Software Foundation; either version 2 of the License, or
12a84fab3cSChristian Lamparter  * (at your option) any later version.
13a84fab3cSChristian Lamparter  *
14a84fab3cSChristian Lamparter  * This program is distributed in the hope that it will be useful,
15a84fab3cSChristian Lamparter  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16a84fab3cSChristian Lamparter  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17a84fab3cSChristian Lamparter  * GNU General Public License for more details.
18a84fab3cSChristian Lamparter  *
19a84fab3cSChristian Lamparter  * You should have received a copy of the GNU General Public License
20a84fab3cSChristian Lamparter  * along with this program; see the file COPYING.  If not, see
21a84fab3cSChristian Lamparter  * http://www.gnu.org/licenses/.
22a84fab3cSChristian Lamparter  *
23a84fab3cSChristian Lamparter  * This file incorporates work covered by the following copyright and
24a84fab3cSChristian Lamparter  * permission notice:
25a84fab3cSChristian Lamparter  *    Copyright (c) 2007-2008 Atheros Communications, Inc.
26a84fab3cSChristian Lamparter  *
27a84fab3cSChristian Lamparter  *    Permission to use, copy, modify, and/or distribute this software for any
28a84fab3cSChristian Lamparter  *    purpose with or without fee is hereby granted, provided that the above
29a84fab3cSChristian Lamparter  *    copyright notice and this permission notice appear in all copies.
30a84fab3cSChristian Lamparter  *
31a84fab3cSChristian Lamparter  *    THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
32a84fab3cSChristian Lamparter  *    WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
33a84fab3cSChristian Lamparter  *    MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
34a84fab3cSChristian Lamparter  *    ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
35a84fab3cSChristian Lamparter  *    WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
36a84fab3cSChristian Lamparter  *    ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
37a84fab3cSChristian Lamparter  *    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
38a84fab3cSChristian Lamparter  */
39a84fab3cSChristian Lamparter 
40a84fab3cSChristian Lamparter #include <linux/slab.h>
41a84fab3cSChristian Lamparter #include <linux/module.h>
42a84fab3cSChristian Lamparter #include <linux/etherdevice.h>
43a84fab3cSChristian Lamparter #include <linux/crc32.h>
44a84fab3cSChristian Lamparter #include <net/mac80211.h>
45a84fab3cSChristian Lamparter #include "carl9170.h"
46a84fab3cSChristian Lamparter #include "hw.h"
47a84fab3cSChristian Lamparter #include "cmd.h"
48a84fab3cSChristian Lamparter 
carl9170_dbg_message(struct ar9170 * ar,const char * buf,u32 len)49a84fab3cSChristian Lamparter static void carl9170_dbg_message(struct ar9170 *ar, const char *buf, u32 len)
50a84fab3cSChristian Lamparter {
51a84fab3cSChristian Lamparter 	bool restart = false;
52a84fab3cSChristian Lamparter 	enum carl9170_restart_reasons reason = CARL9170_RR_NO_REASON;
53a84fab3cSChristian Lamparter 
54a84fab3cSChristian Lamparter 	if (len > 3) {
55a84fab3cSChristian Lamparter 		if (memcmp(buf, CARL9170_ERR_MAGIC, 3) == 0) {
56a84fab3cSChristian Lamparter 			ar->fw.err_counter++;
57a84fab3cSChristian Lamparter 			if (ar->fw.err_counter > 3) {
58a84fab3cSChristian Lamparter 				restart = true;
59a84fab3cSChristian Lamparter 				reason = CARL9170_RR_TOO_MANY_FIRMWARE_ERRORS;
60a84fab3cSChristian Lamparter 			}
61a84fab3cSChristian Lamparter 		}
62a84fab3cSChristian Lamparter 
63a84fab3cSChristian Lamparter 		if (memcmp(buf, CARL9170_BUG_MAGIC, 3) == 0) {
64a84fab3cSChristian Lamparter 			ar->fw.bug_counter++;
65a84fab3cSChristian Lamparter 			restart = true;
66a84fab3cSChristian Lamparter 			reason = CARL9170_RR_FATAL_FIRMWARE_ERROR;
67a84fab3cSChristian Lamparter 		}
68a84fab3cSChristian Lamparter 	}
69a84fab3cSChristian Lamparter 
70a84fab3cSChristian Lamparter 	wiphy_info(ar->hw->wiphy, "FW: %.*s\n", len, buf);
71a84fab3cSChristian Lamparter 
72a84fab3cSChristian Lamparter 	if (restart)
73a84fab3cSChristian Lamparter 		carl9170_restart(ar, reason);
74a84fab3cSChristian Lamparter }
75a84fab3cSChristian Lamparter 
carl9170_handle_ps(struct ar9170 * ar,struct carl9170_rsp * rsp)76a84fab3cSChristian Lamparter static void carl9170_handle_ps(struct ar9170 *ar, struct carl9170_rsp *rsp)
77a84fab3cSChristian Lamparter {
78a84fab3cSChristian Lamparter 	u32 ps;
79a84fab3cSChristian Lamparter 	bool new_ps;
80a84fab3cSChristian Lamparter 
81a84fab3cSChristian Lamparter 	ps = le32_to_cpu(rsp->psm.state);
82a84fab3cSChristian Lamparter 
83a84fab3cSChristian Lamparter 	new_ps = (ps & CARL9170_PSM_COUNTER) != CARL9170_PSM_WAKE;
84a84fab3cSChristian Lamparter 	if (ar->ps.state != new_ps) {
85a84fab3cSChristian Lamparter 		if (!new_ps) {
86a84fab3cSChristian Lamparter 			ar->ps.sleep_ms = jiffies_to_msecs(jiffies -
87a84fab3cSChristian Lamparter 				ar->ps.last_action);
88a84fab3cSChristian Lamparter 		}
89a84fab3cSChristian Lamparter 
90a84fab3cSChristian Lamparter 		ar->ps.last_action = jiffies;
91a84fab3cSChristian Lamparter 
92a84fab3cSChristian Lamparter 		ar->ps.state = new_ps;
93a84fab3cSChristian Lamparter 	}
94a84fab3cSChristian Lamparter }
95a84fab3cSChristian Lamparter 
carl9170_check_sequence(struct ar9170 * ar,unsigned int seq)96a84fab3cSChristian Lamparter static int carl9170_check_sequence(struct ar9170 *ar, unsigned int seq)
97a84fab3cSChristian Lamparter {
98a84fab3cSChristian Lamparter 	if (ar->cmd_seq < -1)
99a84fab3cSChristian Lamparter 		return 0;
100a84fab3cSChristian Lamparter 
101a84fab3cSChristian Lamparter 	/*
102a84fab3cSChristian Lamparter 	 * Initialize Counter
103a84fab3cSChristian Lamparter 	 */
104a84fab3cSChristian Lamparter 	if (ar->cmd_seq < 0)
105a84fab3cSChristian Lamparter 		ar->cmd_seq = seq;
106a84fab3cSChristian Lamparter 
107a84fab3cSChristian Lamparter 	/*
108a84fab3cSChristian Lamparter 	 * The sequence is strictly monotonic increasing and it never skips!
109a84fab3cSChristian Lamparter 	 *
110a84fab3cSChristian Lamparter 	 * Therefore we can safely assume that whenever we received an
111a84fab3cSChristian Lamparter 	 * unexpected sequence we have lost some valuable data.
112a84fab3cSChristian Lamparter 	 */
113a84fab3cSChristian Lamparter 	if (seq != ar->cmd_seq) {
114a84fab3cSChristian Lamparter 		int count;
115a84fab3cSChristian Lamparter 
116a84fab3cSChristian Lamparter 		count = (seq - ar->cmd_seq) % ar->fw.cmd_bufs;
117a84fab3cSChristian Lamparter 
118a84fab3cSChristian Lamparter 		wiphy_err(ar->hw->wiphy, "lost %d command responses/traps! "
119a84fab3cSChristian Lamparter 			  "w:%d g:%d\n", count, ar->cmd_seq, seq);
120a84fab3cSChristian Lamparter 
121a84fab3cSChristian Lamparter 		carl9170_restart(ar, CARL9170_RR_LOST_RSP);
122a84fab3cSChristian Lamparter 		return -EIO;
123a84fab3cSChristian Lamparter 	}
124a84fab3cSChristian Lamparter 
125a84fab3cSChristian Lamparter 	ar->cmd_seq = (ar->cmd_seq + 1) % ar->fw.cmd_bufs;
126a84fab3cSChristian Lamparter 	return 0;
127a84fab3cSChristian Lamparter }
128a84fab3cSChristian Lamparter 
carl9170_cmd_callback(struct ar9170 * ar,u32 len,void * buffer)129a84fab3cSChristian Lamparter static void carl9170_cmd_callback(struct ar9170 *ar, u32 len, void *buffer)
130a84fab3cSChristian Lamparter {
131a84fab3cSChristian Lamparter 	/*
132a84fab3cSChristian Lamparter 	 * Some commands may have a variable response length
133a84fab3cSChristian Lamparter 	 * and we cannot predict the correct length in advance.
134a84fab3cSChristian Lamparter 	 * So we only check if we provided enough space for the data.
135a84fab3cSChristian Lamparter 	 */
136a84fab3cSChristian Lamparter 	if (unlikely(ar->readlen != (len - 4))) {
137a84fab3cSChristian Lamparter 		dev_warn(&ar->udev->dev, "received invalid command response:"
138a84fab3cSChristian Lamparter 			 "got %d, instead of %d\n", len - 4, ar->readlen);
139a84fab3cSChristian Lamparter 		print_hex_dump_bytes("carl9170 cmd:", DUMP_PREFIX_OFFSET,
140a84fab3cSChristian Lamparter 			ar->cmd_buf, (ar->cmd.hdr.len + 4) & 0x3f);
141a84fab3cSChristian Lamparter 		print_hex_dump_bytes("carl9170 rsp:", DUMP_PREFIX_OFFSET,
142a84fab3cSChristian Lamparter 			buffer, len);
143a84fab3cSChristian Lamparter 		/*
144a84fab3cSChristian Lamparter 		 * Do not complete. The command times out,
145a84fab3cSChristian Lamparter 		 * and we get a stack trace from there.
146a84fab3cSChristian Lamparter 		 */
147a84fab3cSChristian Lamparter 		carl9170_restart(ar, CARL9170_RR_INVALID_RSP);
148a84fab3cSChristian Lamparter 	}
149a84fab3cSChristian Lamparter 
150a84fab3cSChristian Lamparter 	spin_lock(&ar->cmd_lock);
151a84fab3cSChristian Lamparter 	if (ar->readbuf) {
152a84fab3cSChristian Lamparter 		if (len >= 4)
153a84fab3cSChristian Lamparter 			memcpy(ar->readbuf, buffer + 4, len - 4);
154a84fab3cSChristian Lamparter 
155a84fab3cSChristian Lamparter 		ar->readbuf = NULL;
156a84fab3cSChristian Lamparter 	}
157a84fab3cSChristian Lamparter 	complete(&ar->cmd_wait);
158a84fab3cSChristian Lamparter 	spin_unlock(&ar->cmd_lock);
159a84fab3cSChristian Lamparter }
160a84fab3cSChristian Lamparter 
carl9170_handle_command_response(struct ar9170 * ar,void * buf,u32 len)161a84fab3cSChristian Lamparter void carl9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len)
162a84fab3cSChristian Lamparter {
1632c208890SJoe Perches 	struct carl9170_rsp *cmd = buf;
164a84fab3cSChristian Lamparter 	struct ieee80211_vif *vif;
165a84fab3cSChristian Lamparter 
166a84fab3cSChristian Lamparter 	if ((cmd->hdr.cmd & CARL9170_RSP_FLAG) != CARL9170_RSP_FLAG) {
167a84fab3cSChristian Lamparter 		if (!(cmd->hdr.cmd & CARL9170_CMD_ASYNC_FLAG))
168a84fab3cSChristian Lamparter 			carl9170_cmd_callback(ar, len, buf);
169a84fab3cSChristian Lamparter 
170a84fab3cSChristian Lamparter 		return;
171a84fab3cSChristian Lamparter 	}
172a84fab3cSChristian Lamparter 
173a84fab3cSChristian Lamparter 	if (unlikely(cmd->hdr.len != (len - 4))) {
174a84fab3cSChristian Lamparter 		if (net_ratelimit()) {
175a84fab3cSChristian Lamparter 			wiphy_err(ar->hw->wiphy, "FW: received over-/under"
176a84fab3cSChristian Lamparter 				"sized event %x (%d, but should be %d).\n",
177a84fab3cSChristian Lamparter 			       cmd->hdr.cmd, cmd->hdr.len, len - 4);
178a84fab3cSChristian Lamparter 
179a84fab3cSChristian Lamparter 			print_hex_dump_bytes("dump:", DUMP_PREFIX_NONE,
180a84fab3cSChristian Lamparter 					     buf, len);
181a84fab3cSChristian Lamparter 		}
182a84fab3cSChristian Lamparter 
183a84fab3cSChristian Lamparter 		return;
184a84fab3cSChristian Lamparter 	}
185a84fab3cSChristian Lamparter 
186a84fab3cSChristian Lamparter 	/* hardware event handlers */
187a84fab3cSChristian Lamparter 	switch (cmd->hdr.cmd) {
188a84fab3cSChristian Lamparter 	case CARL9170_RSP_PRETBTT:
189a84fab3cSChristian Lamparter 		/* pre-TBTT event */
190a84fab3cSChristian Lamparter 		rcu_read_lock();
191a84fab3cSChristian Lamparter 		vif = carl9170_get_main_vif(ar);
192a84fab3cSChristian Lamparter 
193a84fab3cSChristian Lamparter 		if (!vif) {
194a84fab3cSChristian Lamparter 			rcu_read_unlock();
195a84fab3cSChristian Lamparter 			break;
196a84fab3cSChristian Lamparter 		}
197a84fab3cSChristian Lamparter 
198a84fab3cSChristian Lamparter 		switch (vif->type) {
199a84fab3cSChristian Lamparter 		case NL80211_IFTYPE_STATION:
200a84fab3cSChristian Lamparter 			carl9170_handle_ps(ar, cmd);
201a84fab3cSChristian Lamparter 			break;
202a84fab3cSChristian Lamparter 
203a84fab3cSChristian Lamparter 		case NL80211_IFTYPE_AP:
204a84fab3cSChristian Lamparter 		case NL80211_IFTYPE_ADHOC:
205da93c26dSJavier Lopez 		case NL80211_IFTYPE_MESH_POINT:
206a84fab3cSChristian Lamparter 			carl9170_update_beacon(ar, true);
207a84fab3cSChristian Lamparter 			break;
208a84fab3cSChristian Lamparter 
209a84fab3cSChristian Lamparter 		default:
210a84fab3cSChristian Lamparter 			break;
211a84fab3cSChristian Lamparter 		}
212a84fab3cSChristian Lamparter 		rcu_read_unlock();
213a84fab3cSChristian Lamparter 
214a84fab3cSChristian Lamparter 		break;
215a84fab3cSChristian Lamparter 
216a84fab3cSChristian Lamparter 
217a84fab3cSChristian Lamparter 	case CARL9170_RSP_TXCOMP:
218a84fab3cSChristian Lamparter 		/* TX status notification */
219a84fab3cSChristian Lamparter 		carl9170_tx_process_status(ar, cmd);
220a84fab3cSChristian Lamparter 		break;
221a84fab3cSChristian Lamparter 
222a84fab3cSChristian Lamparter 	case CARL9170_RSP_BEACON_CONFIG:
223a84fab3cSChristian Lamparter 		/*
224a84fab3cSChristian Lamparter 		 * (IBSS) beacon send notification
225a84fab3cSChristian Lamparter 		 * bytes: 04 c2 XX YY B4 B3 B2 B1
226a84fab3cSChristian Lamparter 		 *
227a84fab3cSChristian Lamparter 		 * XX always 80
228a84fab3cSChristian Lamparter 		 * YY always 00
229a84fab3cSChristian Lamparter 		 * B1-B4 "should" be the number of send out beacons.
230a84fab3cSChristian Lamparter 		 */
231a84fab3cSChristian Lamparter 		break;
232a84fab3cSChristian Lamparter 
233a84fab3cSChristian Lamparter 	case CARL9170_RSP_ATIM:
234a84fab3cSChristian Lamparter 		/* End of Atim Window */
235a84fab3cSChristian Lamparter 		break;
236a84fab3cSChristian Lamparter 
237a84fab3cSChristian Lamparter 	case CARL9170_RSP_WATCHDOG:
238a84fab3cSChristian Lamparter 		/* Watchdog Interrupt */
239a84fab3cSChristian Lamparter 		carl9170_restart(ar, CARL9170_RR_WATCHDOG);
240a84fab3cSChristian Lamparter 		break;
241a84fab3cSChristian Lamparter 
242a84fab3cSChristian Lamparter 	case CARL9170_RSP_TEXT:
243a84fab3cSChristian Lamparter 		/* firmware debug */
244a84fab3cSChristian Lamparter 		carl9170_dbg_message(ar, (char *)buf + 4, len - 4);
245a84fab3cSChristian Lamparter 		break;
246a84fab3cSChristian Lamparter 
247a84fab3cSChristian Lamparter 	case CARL9170_RSP_HEXDUMP:
248a84fab3cSChristian Lamparter 		wiphy_dbg(ar->hw->wiphy, "FW: HD %d\n", len - 4);
249a84fab3cSChristian Lamparter 		print_hex_dump_bytes("FW:", DUMP_PREFIX_NONE,
250a84fab3cSChristian Lamparter 				     (char *)buf + 4, len - 4);
251a84fab3cSChristian Lamparter 		break;
252a84fab3cSChristian Lamparter 
253a84fab3cSChristian Lamparter 	case CARL9170_RSP_RADAR:
254a84fab3cSChristian Lamparter 		if (!net_ratelimit())
255a84fab3cSChristian Lamparter 			break;
256a84fab3cSChristian Lamparter 
257a84fab3cSChristian Lamparter 		wiphy_info(ar->hw->wiphy, "FW: RADAR! Please report this "
258a84fab3cSChristian Lamparter 		       "incident to linux-wireless@vger.kernel.org !\n");
259a84fab3cSChristian Lamparter 		break;
260a84fab3cSChristian Lamparter 
261a84fab3cSChristian Lamparter 	case CARL9170_RSP_GPIO:
262a84fab3cSChristian Lamparter #ifdef CONFIG_CARL9170_WPC
263a84fab3cSChristian Lamparter 		if (ar->wps.pbc) {
264a84fab3cSChristian Lamparter 			bool state = !!(cmd->gpio.gpio & cpu_to_le32(
265a84fab3cSChristian Lamparter 				AR9170_GPIO_PORT_WPS_BUTTON_PRESSED));
266a84fab3cSChristian Lamparter 
267a84fab3cSChristian Lamparter 			if (state != ar->wps.pbc_state) {
268a84fab3cSChristian Lamparter 				ar->wps.pbc_state = state;
269a84fab3cSChristian Lamparter 				input_report_key(ar->wps.pbc, KEY_WPS_BUTTON,
270a84fab3cSChristian Lamparter 						 state);
271a84fab3cSChristian Lamparter 				input_sync(ar->wps.pbc);
272a84fab3cSChristian Lamparter 			}
273a84fab3cSChristian Lamparter 		}
274a84fab3cSChristian Lamparter #endif /* CONFIG_CARL9170_WPC */
275a84fab3cSChristian Lamparter 		break;
276a84fab3cSChristian Lamparter 
277a84fab3cSChristian Lamparter 	case CARL9170_RSP_BOOT:
278a84fab3cSChristian Lamparter 		complete(&ar->fw_boot_wait);
279a84fab3cSChristian Lamparter 		break;
280a84fab3cSChristian Lamparter 
281a84fab3cSChristian Lamparter 	default:
282a84fab3cSChristian Lamparter 		wiphy_err(ar->hw->wiphy, "FW: received unhandled event %x\n",
283a84fab3cSChristian Lamparter 			cmd->hdr.cmd);
284a84fab3cSChristian Lamparter 		print_hex_dump_bytes("dump:", DUMP_PREFIX_NONE, buf, len);
285a84fab3cSChristian Lamparter 		break;
286a84fab3cSChristian Lamparter 	}
287a84fab3cSChristian Lamparter }
288a84fab3cSChristian Lamparter 
carl9170_rx_mac_status(struct ar9170 * ar,struct ar9170_rx_head * head,struct ar9170_rx_macstatus * mac,struct ieee80211_rx_status * status)289a84fab3cSChristian Lamparter static int carl9170_rx_mac_status(struct ar9170 *ar,
290a84fab3cSChristian Lamparter 	struct ar9170_rx_head *head, struct ar9170_rx_macstatus *mac,
291a84fab3cSChristian Lamparter 	struct ieee80211_rx_status *status)
292a84fab3cSChristian Lamparter {
293a84fab3cSChristian Lamparter 	struct ieee80211_channel *chan;
294a84fab3cSChristian Lamparter 	u8 error, decrypt;
295a84fab3cSChristian Lamparter 
296a84fab3cSChristian Lamparter 	BUILD_BUG_ON(sizeof(struct ar9170_rx_head) != 12);
297a84fab3cSChristian Lamparter 	BUILD_BUG_ON(sizeof(struct ar9170_rx_macstatus) != 4);
298a84fab3cSChristian Lamparter 
299a84fab3cSChristian Lamparter 	error = mac->error;
300a84fab3cSChristian Lamparter 
301a84fab3cSChristian Lamparter 	if (error & AR9170_RX_ERROR_WRONG_RA) {
302a84fab3cSChristian Lamparter 		if (!ar->sniffer_enabled)
303a84fab3cSChristian Lamparter 			return -EINVAL;
304a84fab3cSChristian Lamparter 	}
305a84fab3cSChristian Lamparter 
306a84fab3cSChristian Lamparter 	if (error & AR9170_RX_ERROR_PLCP) {
307a84fab3cSChristian Lamparter 		if (!(ar->filter_state & FIF_PLCPFAIL))
308a84fab3cSChristian Lamparter 			return -EINVAL;
309a84fab3cSChristian Lamparter 
310a84fab3cSChristian Lamparter 		status->flag |= RX_FLAG_FAILED_PLCP_CRC;
311a84fab3cSChristian Lamparter 	}
312a84fab3cSChristian Lamparter 
313a84fab3cSChristian Lamparter 	if (error & AR9170_RX_ERROR_FCS) {
314a84fab3cSChristian Lamparter 		ar->tx_fcs_errors++;
315a84fab3cSChristian Lamparter 
316a84fab3cSChristian Lamparter 		if (!(ar->filter_state & FIF_FCSFAIL))
317a84fab3cSChristian Lamparter 			return -EINVAL;
318a84fab3cSChristian Lamparter 
319a84fab3cSChristian Lamparter 		status->flag |= RX_FLAG_FAILED_FCS_CRC;
320a84fab3cSChristian Lamparter 	}
321a84fab3cSChristian Lamparter 
322a84fab3cSChristian Lamparter 	decrypt = ar9170_get_decrypt_type(mac);
323a84fab3cSChristian Lamparter 	if (!(decrypt & AR9170_RX_ENC_SOFTWARE) &&
324a84fab3cSChristian Lamparter 	    decrypt != AR9170_ENC_ALG_NONE) {
325a84fab3cSChristian Lamparter 		if ((decrypt == AR9170_ENC_ALG_TKIP) &&
326a84fab3cSChristian Lamparter 		    (error & AR9170_RX_ERROR_MMIC))
327a84fab3cSChristian Lamparter 			status->flag |= RX_FLAG_MMIC_ERROR;
328a84fab3cSChristian Lamparter 
329a84fab3cSChristian Lamparter 		status->flag |= RX_FLAG_DECRYPTED;
330a84fab3cSChristian Lamparter 	}
331a84fab3cSChristian Lamparter 
332a84fab3cSChristian Lamparter 	if (error & AR9170_RX_ERROR_DECRYPT && !ar->sniffer_enabled)
333a84fab3cSChristian Lamparter 		return -ENODATA;
334a84fab3cSChristian Lamparter 
335a84fab3cSChristian Lamparter 	error &= ~(AR9170_RX_ERROR_MMIC |
336a84fab3cSChristian Lamparter 		   AR9170_RX_ERROR_FCS |
337a84fab3cSChristian Lamparter 		   AR9170_RX_ERROR_WRONG_RA |
338a84fab3cSChristian Lamparter 		   AR9170_RX_ERROR_DECRYPT |
339a84fab3cSChristian Lamparter 		   AR9170_RX_ERROR_PLCP);
340a84fab3cSChristian Lamparter 
341a84fab3cSChristian Lamparter 	/* drop any other error frames */
342a84fab3cSChristian Lamparter 	if (unlikely(error)) {
343a84fab3cSChristian Lamparter 		/* TODO: update netdevice's RX dropped/errors statistics */
344a84fab3cSChristian Lamparter 
345a84fab3cSChristian Lamparter 		if (net_ratelimit())
346a84fab3cSChristian Lamparter 			wiphy_dbg(ar->hw->wiphy, "received frame with "
347a84fab3cSChristian Lamparter 			       "suspicious error code (%#x).\n", error);
348a84fab3cSChristian Lamparter 
349a84fab3cSChristian Lamparter 		return -EINVAL;
350a84fab3cSChristian Lamparter 	}
351a84fab3cSChristian Lamparter 
352a84fab3cSChristian Lamparter 	chan = ar->channel;
353a84fab3cSChristian Lamparter 	if (chan) {
354a84fab3cSChristian Lamparter 		status->band = chan->band;
355a84fab3cSChristian Lamparter 		status->freq = chan->center_freq;
356a84fab3cSChristian Lamparter 	}
357a84fab3cSChristian Lamparter 
358a84fab3cSChristian Lamparter 	switch (mac->status & AR9170_RX_STATUS_MODULATION) {
359a84fab3cSChristian Lamparter 	case AR9170_RX_STATUS_MODULATION_CCK:
360a84fab3cSChristian Lamparter 		if (mac->status & AR9170_RX_STATUS_SHORT_PREAMBLE)
3617fdd69c5SJohannes Berg 			status->enc_flags |= RX_ENC_FLAG_SHORTPRE;
362a84fab3cSChristian Lamparter 		switch (head->plcp[0]) {
363a84fab3cSChristian Lamparter 		case AR9170_RX_PHY_RATE_CCK_1M:
364a84fab3cSChristian Lamparter 			status->rate_idx = 0;
365a84fab3cSChristian Lamparter 			break;
366a84fab3cSChristian Lamparter 		case AR9170_RX_PHY_RATE_CCK_2M:
367a84fab3cSChristian Lamparter 			status->rate_idx = 1;
368a84fab3cSChristian Lamparter 			break;
369a84fab3cSChristian Lamparter 		case AR9170_RX_PHY_RATE_CCK_5M:
370a84fab3cSChristian Lamparter 			status->rate_idx = 2;
371a84fab3cSChristian Lamparter 			break;
372a84fab3cSChristian Lamparter 		case AR9170_RX_PHY_RATE_CCK_11M:
373a84fab3cSChristian Lamparter 			status->rate_idx = 3;
374a84fab3cSChristian Lamparter 			break;
375a84fab3cSChristian Lamparter 		default:
376a84fab3cSChristian Lamparter 			if (net_ratelimit()) {
377a84fab3cSChristian Lamparter 				wiphy_err(ar->hw->wiphy, "invalid plcp cck "
378a84fab3cSChristian Lamparter 				       "rate (%x).\n", head->plcp[0]);
379a84fab3cSChristian Lamparter 			}
380a84fab3cSChristian Lamparter 
381a84fab3cSChristian Lamparter 			return -EINVAL;
382a84fab3cSChristian Lamparter 		}
383a84fab3cSChristian Lamparter 		break;
384a84fab3cSChristian Lamparter 
385a84fab3cSChristian Lamparter 	case AR9170_RX_STATUS_MODULATION_DUPOFDM:
386a84fab3cSChristian Lamparter 	case AR9170_RX_STATUS_MODULATION_OFDM:
387a84fab3cSChristian Lamparter 		switch (head->plcp[0] & 0xf) {
388a84fab3cSChristian Lamparter 		case AR9170_TXRX_PHY_RATE_OFDM_6M:
389a84fab3cSChristian Lamparter 			status->rate_idx = 0;
390a84fab3cSChristian Lamparter 			break;
391a84fab3cSChristian Lamparter 		case AR9170_TXRX_PHY_RATE_OFDM_9M:
392a84fab3cSChristian Lamparter 			status->rate_idx = 1;
393a84fab3cSChristian Lamparter 			break;
394a84fab3cSChristian Lamparter 		case AR9170_TXRX_PHY_RATE_OFDM_12M:
395a84fab3cSChristian Lamparter 			status->rate_idx = 2;
396a84fab3cSChristian Lamparter 			break;
397a84fab3cSChristian Lamparter 		case AR9170_TXRX_PHY_RATE_OFDM_18M:
398a84fab3cSChristian Lamparter 			status->rate_idx = 3;
399a84fab3cSChristian Lamparter 			break;
400a84fab3cSChristian Lamparter 		case AR9170_TXRX_PHY_RATE_OFDM_24M:
401a84fab3cSChristian Lamparter 			status->rate_idx = 4;
402a84fab3cSChristian Lamparter 			break;
403a84fab3cSChristian Lamparter 		case AR9170_TXRX_PHY_RATE_OFDM_36M:
404a84fab3cSChristian Lamparter 			status->rate_idx = 5;
405a84fab3cSChristian Lamparter 			break;
406a84fab3cSChristian Lamparter 		case AR9170_TXRX_PHY_RATE_OFDM_48M:
407a84fab3cSChristian Lamparter 			status->rate_idx = 6;
408a84fab3cSChristian Lamparter 			break;
409a84fab3cSChristian Lamparter 		case AR9170_TXRX_PHY_RATE_OFDM_54M:
410a84fab3cSChristian Lamparter 			status->rate_idx = 7;
411a84fab3cSChristian Lamparter 			break;
412a84fab3cSChristian Lamparter 		default:
413a84fab3cSChristian Lamparter 			if (net_ratelimit()) {
414a84fab3cSChristian Lamparter 				wiphy_err(ar->hw->wiphy, "invalid plcp ofdm "
415a84fab3cSChristian Lamparter 					"rate (%x).\n", head->plcp[0]);
416a84fab3cSChristian Lamparter 			}
417a84fab3cSChristian Lamparter 
418a84fab3cSChristian Lamparter 			return -EINVAL;
419a84fab3cSChristian Lamparter 		}
42057fbcce3SJohannes Berg 		if (status->band == NL80211_BAND_2GHZ)
421a84fab3cSChristian Lamparter 			status->rate_idx += 4;
422a84fab3cSChristian Lamparter 		break;
423a84fab3cSChristian Lamparter 
424a84fab3cSChristian Lamparter 	case AR9170_RX_STATUS_MODULATION_HT:
425a84fab3cSChristian Lamparter 		if (head->plcp[3] & 0x80)
426da6a4352SJohannes Berg 			status->bw = RATE_INFO_BW_40;
427a84fab3cSChristian Lamparter 		if (head->plcp[6] & 0x80)
4287fdd69c5SJohannes Berg 			status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
429a84fab3cSChristian Lamparter 
430dc76bb1eSDan Carpenter 		status->rate_idx = clamp(head->plcp[3] & 0x7f, 0, 75);
431da6a4352SJohannes Berg 		status->encoding = RX_ENC_HT;
432a84fab3cSChristian Lamparter 		break;
433a84fab3cSChristian Lamparter 
434a84fab3cSChristian Lamparter 	default:
435a84fab3cSChristian Lamparter 		BUG();
436a84fab3cSChristian Lamparter 		return -ENOSYS;
437a84fab3cSChristian Lamparter 	}
438a84fab3cSChristian Lamparter 
439a84fab3cSChristian Lamparter 	return 0;
440a84fab3cSChristian Lamparter }
441a84fab3cSChristian Lamparter 
carl9170_rx_phy_status(struct ar9170 * ar,struct ar9170_rx_phystatus * phy,struct ieee80211_rx_status * status)442a84fab3cSChristian Lamparter static void carl9170_rx_phy_status(struct ar9170 *ar,
443a84fab3cSChristian Lamparter 	struct ar9170_rx_phystatus *phy, struct ieee80211_rx_status *status)
444a84fab3cSChristian Lamparter {
445a84fab3cSChristian Lamparter 	int i;
446a84fab3cSChristian Lamparter 
447a84fab3cSChristian Lamparter 	BUILD_BUG_ON(sizeof(struct ar9170_rx_phystatus) != 20);
448a84fab3cSChristian Lamparter 
449a84fab3cSChristian Lamparter 	for (i = 0; i < 3; i++)
450a84fab3cSChristian Lamparter 		if (phy->rssi[i] != 0x80)
451a84fab3cSChristian Lamparter 			status->antenna |= BIT(i);
452a84fab3cSChristian Lamparter 
453a84fab3cSChristian Lamparter 	/* post-process RSSI */
454a84fab3cSChristian Lamparter 	for (i = 0; i < 7; i++)
455a84fab3cSChristian Lamparter 		if (phy->rssi[i] & 0x80)
456c452d944SHiroaki KAWAI 			phy->rssi[i] = ((~phy->rssi[i] & 0x7f) + 1) & 0x7f;
457a84fab3cSChristian Lamparter 
458a84fab3cSChristian Lamparter 	/* TODO: we could do something with phy_errors */
459a84fab3cSChristian Lamparter 	status->signal = ar->noise[0] + phy->rssi_combined;
460a84fab3cSChristian Lamparter }
461a84fab3cSChristian Lamparter 
carl9170_rx_copy_data(u8 * buf,int len)462a84fab3cSChristian Lamparter static struct sk_buff *carl9170_rx_copy_data(u8 *buf, int len)
463a84fab3cSChristian Lamparter {
464a84fab3cSChristian Lamparter 	struct sk_buff *skb;
465a84fab3cSChristian Lamparter 	int reserved = 0;
466a84fab3cSChristian Lamparter 	struct ieee80211_hdr *hdr = (void *) buf;
467a84fab3cSChristian Lamparter 
468a84fab3cSChristian Lamparter 	if (ieee80211_is_data_qos(hdr->frame_control)) {
469a84fab3cSChristian Lamparter 		u8 *qc = ieee80211_get_qos_ctl(hdr);
470a84fab3cSChristian Lamparter 		reserved += NET_IP_ALIGN;
471a84fab3cSChristian Lamparter 
47204b7dcf9SJohannes Berg 		if (*qc & IEEE80211_QOS_CTL_A_MSDU_PRESENT)
473a84fab3cSChristian Lamparter 			reserved += NET_IP_ALIGN;
474a84fab3cSChristian Lamparter 	}
475a84fab3cSChristian Lamparter 
476a84fab3cSChristian Lamparter 	if (ieee80211_has_a4(hdr->frame_control))
477a84fab3cSChristian Lamparter 		reserved += NET_IP_ALIGN;
478a84fab3cSChristian Lamparter 
479a84fab3cSChristian Lamparter 	reserved = 32 + (reserved & NET_IP_ALIGN);
480a84fab3cSChristian Lamparter 
481a84fab3cSChristian Lamparter 	skb = dev_alloc_skb(len + reserved);
482a84fab3cSChristian Lamparter 	if (likely(skb)) {
483a84fab3cSChristian Lamparter 		skb_reserve(skb, reserved);
48459ae1d12SJohannes Berg 		skb_put_data(skb, buf, len);
485a84fab3cSChristian Lamparter 	}
486a84fab3cSChristian Lamparter 
487a84fab3cSChristian Lamparter 	return skb;
488a84fab3cSChristian Lamparter }
489a84fab3cSChristian Lamparter 
carl9170_find_ie(u8 * data,unsigned int len,u8 ie)490a84fab3cSChristian Lamparter static u8 *carl9170_find_ie(u8 *data, unsigned int len, u8 ie)
491a84fab3cSChristian Lamparter {
492a84fab3cSChristian Lamparter 	struct ieee80211_mgmt *mgmt = (void *)data;
493a84fab3cSChristian Lamparter 	u8 *pos, *end;
494a84fab3cSChristian Lamparter 
495a84fab3cSChristian Lamparter 	pos = (u8 *)mgmt->u.beacon.variable;
496a84fab3cSChristian Lamparter 	end = data + len;
497a84fab3cSChristian Lamparter 	while (pos < end) {
498a84fab3cSChristian Lamparter 		if (pos + 2 + pos[1] > end)
499a84fab3cSChristian Lamparter 			return NULL;
500a84fab3cSChristian Lamparter 
501a84fab3cSChristian Lamparter 		if (pos[0] == ie)
502a84fab3cSChristian Lamparter 			return pos;
503a84fab3cSChristian Lamparter 
504a84fab3cSChristian Lamparter 		pos += 2 + pos[1];
505a84fab3cSChristian Lamparter 	}
506a84fab3cSChristian Lamparter 	return NULL;
507a84fab3cSChristian Lamparter }
508a84fab3cSChristian Lamparter 
509a84fab3cSChristian Lamparter /*
510a84fab3cSChristian Lamparter  * NOTE:
511a84fab3cSChristian Lamparter  *
512a84fab3cSChristian Lamparter  * The firmware is in charge of waking up the device just before
513a84fab3cSChristian Lamparter  * the AP is expected to transmit the next beacon.
514a84fab3cSChristian Lamparter  *
515a84fab3cSChristian Lamparter  * This leaves the driver with the important task of deciding when
516a84fab3cSChristian Lamparter  * to set the PHY back to bed again.
517a84fab3cSChristian Lamparter  */
carl9170_ps_beacon(struct ar9170 * ar,void * data,unsigned int len)518a84fab3cSChristian Lamparter static void carl9170_ps_beacon(struct ar9170 *ar, void *data, unsigned int len)
519a84fab3cSChristian Lamparter {
5202c208890SJoe Perches 	struct ieee80211_hdr *hdr = data;
521a84fab3cSChristian Lamparter 	struct ieee80211_tim_ie *tim_ie;
522e4e19c03SOleksij Rempel 	struct ath_common *common = &ar->common;
523a84fab3cSChristian Lamparter 	u8 *tim;
524a84fab3cSChristian Lamparter 	u8 tim_len;
525a84fab3cSChristian Lamparter 	bool cam;
526a84fab3cSChristian Lamparter 
527a84fab3cSChristian Lamparter 	if (likely(!(ar->hw->conf.flags & IEEE80211_CONF_PS)))
528a84fab3cSChristian Lamparter 		return;
529a84fab3cSChristian Lamparter 
530a84fab3cSChristian Lamparter 	/* min. beacon length + FCS_LEN */
531a84fab3cSChristian Lamparter 	if (len <= 40 + FCS_LEN)
532a84fab3cSChristian Lamparter 		return;
533a84fab3cSChristian Lamparter 
534e4e19c03SOleksij Rempel 	/* check if this really is a beacon */
535a84fab3cSChristian Lamparter 	/* and only beacons from the associated BSSID, please */
536e4e19c03SOleksij Rempel 	if (!ath_is_mybeacon(common, hdr) || !common->curaid)
537a84fab3cSChristian Lamparter 		return;
538a84fab3cSChristian Lamparter 
539a84fab3cSChristian Lamparter 	ar->ps.last_beacon = jiffies;
540a84fab3cSChristian Lamparter 
541a84fab3cSChristian Lamparter 	tim = carl9170_find_ie(data, len - FCS_LEN, WLAN_EID_TIM);
542a84fab3cSChristian Lamparter 	if (!tim)
543a84fab3cSChristian Lamparter 		return;
544a84fab3cSChristian Lamparter 
545a84fab3cSChristian Lamparter 	if (tim[1] < sizeof(*tim_ie))
546a84fab3cSChristian Lamparter 		return;
547a84fab3cSChristian Lamparter 
548a84fab3cSChristian Lamparter 	tim_len = tim[1];
549a84fab3cSChristian Lamparter 	tim_ie = (struct ieee80211_tim_ie *) &tim[2];
550a84fab3cSChristian Lamparter 
551a84fab3cSChristian Lamparter 	if (!WARN_ON_ONCE(!ar->hw->conf.ps_dtim_period))
552a84fab3cSChristian Lamparter 		ar->ps.dtim_counter = (tim_ie->dtim_count - 1) %
553a84fab3cSChristian Lamparter 			ar->hw->conf.ps_dtim_period;
554a84fab3cSChristian Lamparter 
555a84fab3cSChristian Lamparter 	/* Check whenever the PHY can be turned off again. */
556a84fab3cSChristian Lamparter 
557a84fab3cSChristian Lamparter 	/* 1. What about buffered unicast traffic for our AID? */
558a84fab3cSChristian Lamparter 	cam = ieee80211_check_tim(tim_ie, tim_len, ar->common.curaid);
559a84fab3cSChristian Lamparter 
560a84fab3cSChristian Lamparter 	/* 2. Maybe the AP wants to send multicast/broadcast data? */
5615820de53SChristian Lamparter 	cam |= !!(tim_ie->bitmap_ctrl & 0x01);
562a84fab3cSChristian Lamparter 
563a84fab3cSChristian Lamparter 	if (!cam) {
564a84fab3cSChristian Lamparter 		/* back to low-power land. */
565a84fab3cSChristian Lamparter 		ar->ps.off_override &= ~PS_OFF_BCN;
566a84fab3cSChristian Lamparter 		carl9170_ps_check(ar);
567a84fab3cSChristian Lamparter 	} else {
568a84fab3cSChristian Lamparter 		/* force CAM */
569a84fab3cSChristian Lamparter 		ar->ps.off_override |= PS_OFF_BCN;
570a84fab3cSChristian Lamparter 	}
571a84fab3cSChristian Lamparter }
572a84fab3cSChristian Lamparter 
carl9170_ba_check(struct ar9170 * ar,void * data,unsigned int len)573c9122c0dSChristian Lamparter static void carl9170_ba_check(struct ar9170 *ar, void *data, unsigned int len)
574c9122c0dSChristian Lamparter {
5758986992dSJoe Perches 	struct ieee80211_bar *bar = data;
576c9122c0dSChristian Lamparter 	struct carl9170_bar_list_entry *entry;
577c9122c0dSChristian Lamparter 	unsigned int queue;
578c9122c0dSChristian Lamparter 
579c9122c0dSChristian Lamparter 	if (likely(!ieee80211_is_back(bar->frame_control)))
580c9122c0dSChristian Lamparter 		return;
581c9122c0dSChristian Lamparter 
582c9122c0dSChristian Lamparter 	if (len <= sizeof(*bar) + FCS_LEN)
583c9122c0dSChristian Lamparter 		return;
584c9122c0dSChristian Lamparter 
585c9122c0dSChristian Lamparter 	queue = TID_TO_WME_AC(((le16_to_cpu(bar->control) &
586c9122c0dSChristian Lamparter 		IEEE80211_BAR_CTRL_TID_INFO_MASK) >>
587c9122c0dSChristian Lamparter 		IEEE80211_BAR_CTRL_TID_INFO_SHIFT) & 7);
588c9122c0dSChristian Lamparter 
589c9122c0dSChristian Lamparter 	rcu_read_lock();
590c9122c0dSChristian Lamparter 	list_for_each_entry_rcu(entry, &ar->bar_list[queue], list) {
591c9122c0dSChristian Lamparter 		struct sk_buff *entry_skb = entry->skb;
592c9122c0dSChristian Lamparter 		struct _carl9170_tx_superframe *super = (void *)entry_skb->data;
593c9122c0dSChristian Lamparter 		struct ieee80211_bar *entry_bar = (void *)super->frame_data;
594c9122c0dSChristian Lamparter 
595c9122c0dSChristian Lamparter #define TID_CHECK(a, b) (						\
596c9122c0dSChristian Lamparter 	((a) & cpu_to_le16(IEEE80211_BAR_CTRL_TID_INFO_MASK)) ==	\
597c9122c0dSChristian Lamparter 	((b) & cpu_to_le16(IEEE80211_BAR_CTRL_TID_INFO_MASK)))		\
598c9122c0dSChristian Lamparter 
599c9122c0dSChristian Lamparter 		if (bar->start_seq_num == entry_bar->start_seq_num &&
600c9122c0dSChristian Lamparter 		    TID_CHECK(bar->control, entry_bar->control) &&
6011283ac10SJulia Lawall 		    ether_addr_equal_64bits(bar->ra, entry_bar->ta) &&
6021283ac10SJulia Lawall 		    ether_addr_equal_64bits(bar->ta, entry_bar->ra)) {
603c9122c0dSChristian Lamparter 			struct ieee80211_tx_info *tx_info;
604c9122c0dSChristian Lamparter 
605c9122c0dSChristian Lamparter 			tx_info = IEEE80211_SKB_CB(entry_skb);
606c9122c0dSChristian Lamparter 			tx_info->flags |= IEEE80211_TX_STAT_ACK;
607c9122c0dSChristian Lamparter 
608c9122c0dSChristian Lamparter 			spin_lock_bh(&ar->bar_list_lock[queue]);
609c9122c0dSChristian Lamparter 			list_del_rcu(&entry->list);
610c9122c0dSChristian Lamparter 			spin_unlock_bh(&ar->bar_list_lock[queue]);
611c9122c0dSChristian Lamparter 			kfree_rcu(entry, head);
612c9122c0dSChristian Lamparter 			break;
613c9122c0dSChristian Lamparter 		}
614c9122c0dSChristian Lamparter 	}
615c9122c0dSChristian Lamparter 	rcu_read_unlock();
616c9122c0dSChristian Lamparter 
617c9122c0dSChristian Lamparter #undef TID_CHECK
618c9122c0dSChristian Lamparter }
619c9122c0dSChristian Lamparter 
carl9170_ampdu_check(struct ar9170 * ar,u8 * buf,u8 ms,struct ieee80211_rx_status * rx_status)62033dd7699SChristian Lamparter static bool carl9170_ampdu_check(struct ar9170 *ar, u8 *buf, u8 ms,
62133dd7699SChristian Lamparter 				 struct ieee80211_rx_status *rx_status)
6228f236d1bSChristian Lamparter {
6238f236d1bSChristian Lamparter 	__le16 fc;
6248f236d1bSChristian Lamparter 
6258f236d1bSChristian Lamparter 	if ((ms & AR9170_RX_STATUS_MPDU) == AR9170_RX_STATUS_MPDU_SINGLE) {
6268f236d1bSChristian Lamparter 		/*
6278f236d1bSChristian Lamparter 		 * This frame is not part of an aMPDU.
6288f236d1bSChristian Lamparter 		 * Therefore it is not subjected to any
6298f236d1bSChristian Lamparter 		 * of the following content restrictions.
6308f236d1bSChristian Lamparter 		 */
6318f236d1bSChristian Lamparter 		return true;
6328f236d1bSChristian Lamparter 	}
6338f236d1bSChristian Lamparter 
63433dd7699SChristian Lamparter 	rx_status->flag |= RX_FLAG_AMPDU_DETAILS | RX_FLAG_AMPDU_LAST_KNOWN;
63533dd7699SChristian Lamparter 	rx_status->ampdu_reference = ar->ampdu_ref;
63633dd7699SChristian Lamparter 
6378f236d1bSChristian Lamparter 	/*
6388f236d1bSChristian Lamparter 	 * "802.11n - 7.4a.3 A-MPDU contents" describes in which contexts
6398f236d1bSChristian Lamparter 	 * certain frame types can be part of an aMPDU.
6408f236d1bSChristian Lamparter 	 *
6418f236d1bSChristian Lamparter 	 * In order to keep the processing cost down, I opted for a
6428f236d1bSChristian Lamparter 	 * stateless filter solely based on the frame control field.
6438f236d1bSChristian Lamparter 	 */
6448f236d1bSChristian Lamparter 
6458f236d1bSChristian Lamparter 	fc = ((struct ieee80211_hdr *)buf)->frame_control;
6468f236d1bSChristian Lamparter 	if (ieee80211_is_data_qos(fc) && ieee80211_is_data_present(fc))
6478f236d1bSChristian Lamparter 		return true;
6488f236d1bSChristian Lamparter 
6498f236d1bSChristian Lamparter 	if (ieee80211_is_ack(fc) || ieee80211_is_back(fc) ||
6508f236d1bSChristian Lamparter 	    ieee80211_is_back_req(fc))
6518f236d1bSChristian Lamparter 		return true;
6528f236d1bSChristian Lamparter 
6538f236d1bSChristian Lamparter 	if (ieee80211_is_action(fc))
6548f236d1bSChristian Lamparter 		return true;
6558f236d1bSChristian Lamparter 
6568f236d1bSChristian Lamparter 	return false;
6578f236d1bSChristian Lamparter }
6588f236d1bSChristian Lamparter 
carl9170_handle_mpdu(struct ar9170 * ar,u8 * buf,int len,struct ieee80211_rx_status * status)6596c4a5f24SChristian Lamparter static int carl9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len,
6606c4a5f24SChristian Lamparter 				struct ieee80211_rx_status *status)
6616c4a5f24SChristian Lamparter {
6626c4a5f24SChristian Lamparter 	struct sk_buff *skb;
6636c4a5f24SChristian Lamparter 
6646c4a5f24SChristian Lamparter 	/* (driver) frame trap handler
6656c4a5f24SChristian Lamparter 	 *
6666c4a5f24SChristian Lamparter 	 * Because power-saving mode handing has to be implemented by
6676c4a5f24SChristian Lamparter 	 * the driver/firmware. We have to check each incoming beacon
6686c4a5f24SChristian Lamparter 	 * from the associated AP, if there's new data for us (either
6696c4a5f24SChristian Lamparter 	 * broadcast/multicast or unicast) we have to react quickly.
6706c4a5f24SChristian Lamparter 	 *
6716c4a5f24SChristian Lamparter 	 * So, if you have you want to add additional frame trap
6726c4a5f24SChristian Lamparter 	 * handlers, this would be the perfect place!
6736c4a5f24SChristian Lamparter 	 */
6746c4a5f24SChristian Lamparter 
6756c4a5f24SChristian Lamparter 	carl9170_ps_beacon(ar, buf, len);
6766c4a5f24SChristian Lamparter 
6776c4a5f24SChristian Lamparter 	carl9170_ba_check(ar, buf, len);
6786c4a5f24SChristian Lamparter 
6796c4a5f24SChristian Lamparter 	skb = carl9170_rx_copy_data(buf, len);
6806c4a5f24SChristian Lamparter 	if (!skb)
6816c4a5f24SChristian Lamparter 		return -ENOMEM;
6826c4a5f24SChristian Lamparter 
683fc5e286fSChristian Lamparter 	memcpy(IEEE80211_SKB_RXCB(skb), status, sizeof(*status));
6846c4a5f24SChristian Lamparter 	ieee80211_rx(ar->hw, skb);
6856c4a5f24SChristian Lamparter 	return 0;
6866c4a5f24SChristian Lamparter }
6876c4a5f24SChristian Lamparter 
688a84fab3cSChristian Lamparter /*
689a84fab3cSChristian Lamparter  * If the frame alignment is right (or the kernel has
690a84fab3cSChristian Lamparter  * CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS), and there
691a84fab3cSChristian Lamparter  * is only a single MPDU in the USB frame, then we could
692a84fab3cSChristian Lamparter  * submit to mac80211 the SKB directly. However, since
693a84fab3cSChristian Lamparter  * there may be multiple packets in one SKB in stream
694a84fab3cSChristian Lamparter  * mode, and we need to observe the proper ordering,
695a84fab3cSChristian Lamparter  * this is non-trivial.
696a84fab3cSChristian Lamparter  */
carl9170_rx_untie_data(struct ar9170 * ar,u8 * buf,int len)6976c4a5f24SChristian Lamparter static void carl9170_rx_untie_data(struct ar9170 *ar, u8 *buf, int len)
698a84fab3cSChristian Lamparter {
699a84fab3cSChristian Lamparter 	struct ar9170_rx_head *head;
700a84fab3cSChristian Lamparter 	struct ar9170_rx_macstatus *mac;
701a84fab3cSChristian Lamparter 	struct ar9170_rx_phystatus *phy = NULL;
702a84fab3cSChristian Lamparter 	struct ieee80211_rx_status status;
703a84fab3cSChristian Lamparter 	int mpdu_len;
7048f236d1bSChristian Lamparter 	u8 mac_status;
705a84fab3cSChristian Lamparter 
706a84fab3cSChristian Lamparter 	if (!IS_STARTED(ar))
707a84fab3cSChristian Lamparter 		return;
708a84fab3cSChristian Lamparter 
709c8a16c68SChristian Lamparter 	if (unlikely(len < sizeof(*mac)))
710c8a16c68SChristian Lamparter 		goto drop;
711a84fab3cSChristian Lamparter 
71233dd7699SChristian Lamparter 	memset(&status, 0, sizeof(status));
71333dd7699SChristian Lamparter 
714a84fab3cSChristian Lamparter 	mpdu_len = len - sizeof(*mac);
715a84fab3cSChristian Lamparter 
716a84fab3cSChristian Lamparter 	mac = (void *)(buf + mpdu_len);
7178f236d1bSChristian Lamparter 	mac_status = mac->status;
7188f236d1bSChristian Lamparter 	switch (mac_status & AR9170_RX_STATUS_MPDU) {
719a84fab3cSChristian Lamparter 	case AR9170_RX_STATUS_MPDU_FIRST:
72033dd7699SChristian Lamparter 		ar->ampdu_ref++;
721a84fab3cSChristian Lamparter 		/* Aggregated MPDUs start with an PLCP header */
722a84fab3cSChristian Lamparter 		if (likely(mpdu_len >= sizeof(struct ar9170_rx_head))) {
723a84fab3cSChristian Lamparter 			head = (void *) buf;
724a84fab3cSChristian Lamparter 
725a84fab3cSChristian Lamparter 			/*
726a84fab3cSChristian Lamparter 			 * The PLCP header needs to be cached for the
727a84fab3cSChristian Lamparter 			 * following MIDDLE + LAST A-MPDU packets.
728a84fab3cSChristian Lamparter 			 *
729a84fab3cSChristian Lamparter 			 * So, if you are wondering why all frames seem
730a84fab3cSChristian Lamparter 			 * to share a common RX status information,
731a84fab3cSChristian Lamparter 			 * then you have the answer right here...
732a84fab3cSChristian Lamparter 			 */
733a84fab3cSChristian Lamparter 			memcpy(&ar->rx_plcp, (void *) buf,
734a84fab3cSChristian Lamparter 			       sizeof(struct ar9170_rx_head));
735a84fab3cSChristian Lamparter 
736a84fab3cSChristian Lamparter 			mpdu_len -= sizeof(struct ar9170_rx_head);
737a84fab3cSChristian Lamparter 			buf += sizeof(struct ar9170_rx_head);
738a84fab3cSChristian Lamparter 
739a84fab3cSChristian Lamparter 			ar->rx_has_plcp = true;
740a84fab3cSChristian Lamparter 		} else {
741a84fab3cSChristian Lamparter 			if (net_ratelimit()) {
742a84fab3cSChristian Lamparter 				wiphy_err(ar->hw->wiphy, "plcp info "
743a84fab3cSChristian Lamparter 					"is clipped.\n");
744a84fab3cSChristian Lamparter 			}
745a84fab3cSChristian Lamparter 
746c8a16c68SChristian Lamparter 			goto drop;
747a84fab3cSChristian Lamparter 		}
748a84fab3cSChristian Lamparter 		break;
749a84fab3cSChristian Lamparter 
750a84fab3cSChristian Lamparter 	case AR9170_RX_STATUS_MPDU_LAST:
75133dd7699SChristian Lamparter 		status.flag |= RX_FLAG_AMPDU_IS_LAST;
75233dd7699SChristian Lamparter 
753a84fab3cSChristian Lamparter 		/*
754a84fab3cSChristian Lamparter 		 * The last frame of an A-MPDU has an extra tail
755a84fab3cSChristian Lamparter 		 * which does contain the phy status of the whole
756a84fab3cSChristian Lamparter 		 * aggregate.
757a84fab3cSChristian Lamparter 		 */
758a84fab3cSChristian Lamparter 		if (likely(mpdu_len >= sizeof(struct ar9170_rx_phystatus))) {
759a84fab3cSChristian Lamparter 			mpdu_len -= sizeof(struct ar9170_rx_phystatus);
760a84fab3cSChristian Lamparter 			phy = (void *)(buf + mpdu_len);
761a84fab3cSChristian Lamparter 		} else {
762a84fab3cSChristian Lamparter 			if (net_ratelimit()) {
763a84fab3cSChristian Lamparter 				wiphy_err(ar->hw->wiphy, "frame tail "
764a84fab3cSChristian Lamparter 					"is clipped.\n");
765a84fab3cSChristian Lamparter 			}
766a84fab3cSChristian Lamparter 
767c8a16c68SChristian Lamparter 			goto drop;
768a84fab3cSChristian Lamparter 		}
7696df74f61SGustavo A. R. Silva 		fallthrough;
770a84fab3cSChristian Lamparter 
771a84fab3cSChristian Lamparter 	case AR9170_RX_STATUS_MPDU_MIDDLE:
772a84fab3cSChristian Lamparter 		/*  These are just data + mac status */
773a84fab3cSChristian Lamparter 		if (unlikely(!ar->rx_has_plcp)) {
774a84fab3cSChristian Lamparter 			if (!net_ratelimit())
775a84fab3cSChristian Lamparter 				return;
776a84fab3cSChristian Lamparter 
777a84fab3cSChristian Lamparter 			wiphy_err(ar->hw->wiphy, "rx stream does not start "
778a84fab3cSChristian Lamparter 					"with a first_mpdu frame tag.\n");
779a84fab3cSChristian Lamparter 
780c8a16c68SChristian Lamparter 			goto drop;
781a84fab3cSChristian Lamparter 		}
782a84fab3cSChristian Lamparter 
783a84fab3cSChristian Lamparter 		head = &ar->rx_plcp;
784a84fab3cSChristian Lamparter 		break;
785a84fab3cSChristian Lamparter 
786a84fab3cSChristian Lamparter 	case AR9170_RX_STATUS_MPDU_SINGLE:
787a84fab3cSChristian Lamparter 		/* single mpdu has both: plcp (head) and phy status (tail) */
788a84fab3cSChristian Lamparter 		head = (void *) buf;
789a84fab3cSChristian Lamparter 
790a84fab3cSChristian Lamparter 		mpdu_len -= sizeof(struct ar9170_rx_head);
791a84fab3cSChristian Lamparter 		mpdu_len -= sizeof(struct ar9170_rx_phystatus);
792a84fab3cSChristian Lamparter 
793a84fab3cSChristian Lamparter 		buf += sizeof(struct ar9170_rx_head);
794a84fab3cSChristian Lamparter 		phy = (void *)(buf + mpdu_len);
795a84fab3cSChristian Lamparter 		break;
796a84fab3cSChristian Lamparter 
797a84fab3cSChristian Lamparter 	default:
79862acdcfaSArnd Bergmann 		BUG();
799a84fab3cSChristian Lamparter 		break;
800a84fab3cSChristian Lamparter 	}
801a84fab3cSChristian Lamparter 
802a84fab3cSChristian Lamparter 	/* FC + DU + RA + FCS */
803c8a16c68SChristian Lamparter 	if (unlikely(mpdu_len < (2 + 2 + ETH_ALEN + FCS_LEN)))
804c8a16c68SChristian Lamparter 		goto drop;
805a84fab3cSChristian Lamparter 
806c8a16c68SChristian Lamparter 	if (unlikely(carl9170_rx_mac_status(ar, head, mac, &status)))
807c8a16c68SChristian Lamparter 		goto drop;
808a84fab3cSChristian Lamparter 
80933dd7699SChristian Lamparter 	if (!carl9170_ampdu_check(ar, buf, mac_status, &status))
8108f236d1bSChristian Lamparter 		goto drop;
8118f236d1bSChristian Lamparter 
812a84fab3cSChristian Lamparter 	if (phy)
813a84fab3cSChristian Lamparter 		carl9170_rx_phy_status(ar, phy, &status);
814649a6ac4SChristian Lamparter 	else
815649a6ac4SChristian Lamparter 		status.flag |= RX_FLAG_NO_SIGNAL_VAL;
816a84fab3cSChristian Lamparter 
8176c4a5f24SChristian Lamparter 	if (carl9170_handle_mpdu(ar, buf, mpdu_len, &status))
818c8a16c68SChristian Lamparter 		goto drop;
819c8a16c68SChristian Lamparter 
820c8a16c68SChristian Lamparter 	return;
821c8a16c68SChristian Lamparter drop:
822a84fab3cSChristian Lamparter 	ar->rx_dropped++;
823a84fab3cSChristian Lamparter }
824a84fab3cSChristian Lamparter 
carl9170_rx_untie_cmds(struct ar9170 * ar,const u8 * respbuf,const unsigned int resplen)825a84fab3cSChristian Lamparter static void carl9170_rx_untie_cmds(struct ar9170 *ar, const u8 *respbuf,
826a84fab3cSChristian Lamparter 				   const unsigned int resplen)
827a84fab3cSChristian Lamparter {
828a84fab3cSChristian Lamparter 	struct carl9170_rsp *cmd;
829a84fab3cSChristian Lamparter 	int i = 0;
830a84fab3cSChristian Lamparter 
831a84fab3cSChristian Lamparter 	while (i < resplen) {
832a84fab3cSChristian Lamparter 		cmd = (void *) &respbuf[i];
833a84fab3cSChristian Lamparter 
834a84fab3cSChristian Lamparter 		i += cmd->hdr.len + 4;
835a84fab3cSChristian Lamparter 		if (unlikely(i > resplen))
836a84fab3cSChristian Lamparter 			break;
837a84fab3cSChristian Lamparter 
838b4764c80SChristian Lamparter 		if (carl9170_check_sequence(ar, cmd->hdr.seq))
839b4764c80SChristian Lamparter 			break;
840b4764c80SChristian Lamparter 
841a84fab3cSChristian Lamparter 		carl9170_handle_command_response(ar, cmd, cmd->hdr.len + 4);
842a84fab3cSChristian Lamparter 	}
843a84fab3cSChristian Lamparter 
844a84fab3cSChristian Lamparter 	if (unlikely(i != resplen)) {
845a84fab3cSChristian Lamparter 		if (!net_ratelimit())
846a84fab3cSChristian Lamparter 			return;
847a84fab3cSChristian Lamparter 
848a84fab3cSChristian Lamparter 		wiphy_err(ar->hw->wiphy, "malformed firmware trap:\n");
849a84fab3cSChristian Lamparter 		print_hex_dump_bytes("rxcmd:", DUMP_PREFIX_OFFSET,
850a84fab3cSChristian Lamparter 				     respbuf, resplen);
851a84fab3cSChristian Lamparter 	}
852a84fab3cSChristian Lamparter }
853a84fab3cSChristian Lamparter 
__carl9170_rx(struct ar9170 * ar,u8 * buf,unsigned int len)854a84fab3cSChristian Lamparter static void __carl9170_rx(struct ar9170 *ar, u8 *buf, unsigned int len)
855a84fab3cSChristian Lamparter {
856a84fab3cSChristian Lamparter 	unsigned int i = 0;
857a84fab3cSChristian Lamparter 
858a84fab3cSChristian Lamparter 	/* weird thing, but this is the same in the original driver */
859a84fab3cSChristian Lamparter 	while (len > 2 && i < 12 && buf[0] == 0xff && buf[1] == 0xff) {
860a84fab3cSChristian Lamparter 		i += 2;
861a84fab3cSChristian Lamparter 		len -= 2;
862a84fab3cSChristian Lamparter 		buf += 2;
863a84fab3cSChristian Lamparter 	}
864a84fab3cSChristian Lamparter 
865a84fab3cSChristian Lamparter 	if (unlikely(len < 4))
866a84fab3cSChristian Lamparter 		return;
867a84fab3cSChristian Lamparter 
868a84fab3cSChristian Lamparter 	/* found the 6 * 0xffff marker? */
869a84fab3cSChristian Lamparter 	if (i == 12)
870a84fab3cSChristian Lamparter 		carl9170_rx_untie_cmds(ar, buf, len);
871a84fab3cSChristian Lamparter 	else
8726c4a5f24SChristian Lamparter 		carl9170_rx_untie_data(ar, buf, len);
873a84fab3cSChristian Lamparter }
874a84fab3cSChristian Lamparter 
carl9170_rx_stream(struct ar9170 * ar,void * buf,unsigned int len)875a84fab3cSChristian Lamparter static void carl9170_rx_stream(struct ar9170 *ar, void *buf, unsigned int len)
876a84fab3cSChristian Lamparter {
877a84fab3cSChristian Lamparter 	unsigned int tlen, wlen = 0, clen = 0;
878a84fab3cSChristian Lamparter 	struct ar9170_stream *rx_stream;
879a84fab3cSChristian Lamparter 	u8 *tbuf;
880a84fab3cSChristian Lamparter 
881a84fab3cSChristian Lamparter 	tbuf = buf;
882a84fab3cSChristian Lamparter 	tlen = len;
883a84fab3cSChristian Lamparter 
884a84fab3cSChristian Lamparter 	while (tlen >= 4) {
885a84fab3cSChristian Lamparter 		rx_stream = (void *) tbuf;
886a84fab3cSChristian Lamparter 		clen = le16_to_cpu(rx_stream->length);
887a84fab3cSChristian Lamparter 		wlen = ALIGN(clen, 4);
888a84fab3cSChristian Lamparter 
889a84fab3cSChristian Lamparter 		/* check if this is stream has a valid tag.*/
890a84fab3cSChristian Lamparter 		if (rx_stream->tag != cpu_to_le16(AR9170_RX_STREAM_TAG)) {
891a84fab3cSChristian Lamparter 			/*
892a84fab3cSChristian Lamparter 			 * TODO: handle the highly unlikely event that the
893a84fab3cSChristian Lamparter 			 * corrupted stream has the TAG at the right position.
894a84fab3cSChristian Lamparter 			 */
895a84fab3cSChristian Lamparter 
896a84fab3cSChristian Lamparter 			/* check if the frame can be repaired. */
897a84fab3cSChristian Lamparter 			if (!ar->rx_failover_missing) {
898a84fab3cSChristian Lamparter 
899a84fab3cSChristian Lamparter 				/* this is not "short read". */
900a84fab3cSChristian Lamparter 				if (net_ratelimit()) {
901a84fab3cSChristian Lamparter 					wiphy_err(ar->hw->wiphy,
902a84fab3cSChristian Lamparter 						"missing tag!\n");
903a84fab3cSChristian Lamparter 				}
904a84fab3cSChristian Lamparter 
905a84fab3cSChristian Lamparter 				__carl9170_rx(ar, tbuf, tlen);
906a84fab3cSChristian Lamparter 				return;
907a84fab3cSChristian Lamparter 			}
908a84fab3cSChristian Lamparter 
909a84fab3cSChristian Lamparter 			if (ar->rx_failover_missing > tlen) {
910a84fab3cSChristian Lamparter 				if (net_ratelimit()) {
911a84fab3cSChristian Lamparter 					wiphy_err(ar->hw->wiphy,
912a84fab3cSChristian Lamparter 						"possible multi "
913a84fab3cSChristian Lamparter 						"stream corruption!\n");
914a84fab3cSChristian Lamparter 					goto err_telluser;
915a84fab3cSChristian Lamparter 				} else {
916a84fab3cSChristian Lamparter 					goto err_silent;
917a84fab3cSChristian Lamparter 				}
918a84fab3cSChristian Lamparter 			}
919a84fab3cSChristian Lamparter 
92059ae1d12SJohannes Berg 			skb_put_data(ar->rx_failover, tbuf, tlen);
921a84fab3cSChristian Lamparter 			ar->rx_failover_missing -= tlen;
922a84fab3cSChristian Lamparter 
923a84fab3cSChristian Lamparter 			if (ar->rx_failover_missing <= 0) {
924a84fab3cSChristian Lamparter 				/*
925a84fab3cSChristian Lamparter 				 * nested carl9170_rx_stream call!
926a84fab3cSChristian Lamparter 				 *
92725985edcSLucas De Marchi 				 * termination is guaranteed, even when the
928a84fab3cSChristian Lamparter 				 * combined frame also have an element with
929a84fab3cSChristian Lamparter 				 * a bad tag.
930a84fab3cSChristian Lamparter 				 */
931a84fab3cSChristian Lamparter 
932a84fab3cSChristian Lamparter 				ar->rx_failover_missing = 0;
933a84fab3cSChristian Lamparter 				carl9170_rx_stream(ar, ar->rx_failover->data,
934a84fab3cSChristian Lamparter 						   ar->rx_failover->len);
935a84fab3cSChristian Lamparter 
936a84fab3cSChristian Lamparter 				skb_reset_tail_pointer(ar->rx_failover);
937a84fab3cSChristian Lamparter 				skb_trim(ar->rx_failover, 0);
938a84fab3cSChristian Lamparter 			}
939a84fab3cSChristian Lamparter 
940a84fab3cSChristian Lamparter 			return;
941a84fab3cSChristian Lamparter 		}
942a84fab3cSChristian Lamparter 
943a84fab3cSChristian Lamparter 		/* check if stream is clipped */
944a84fab3cSChristian Lamparter 		if (wlen > tlen - 4) {
945a84fab3cSChristian Lamparter 			if (ar->rx_failover_missing) {
946a84fab3cSChristian Lamparter 				/* TODO: handle double stream corruption. */
947a84fab3cSChristian Lamparter 				if (net_ratelimit()) {
948a84fab3cSChristian Lamparter 					wiphy_err(ar->hw->wiphy, "double rx "
949a84fab3cSChristian Lamparter 						"stream corruption!\n");
950a84fab3cSChristian Lamparter 					goto err_telluser;
951a84fab3cSChristian Lamparter 				} else {
952a84fab3cSChristian Lamparter 					goto err_silent;
953a84fab3cSChristian Lamparter 				}
954a84fab3cSChristian Lamparter 			}
955a84fab3cSChristian Lamparter 
956a84fab3cSChristian Lamparter 			/*
957a84fab3cSChristian Lamparter 			 * save incomplete data set.
958a84fab3cSChristian Lamparter 			 * the firmware will resend the missing bits when
959a84fab3cSChristian Lamparter 			 * the rx - descriptor comes round again.
960a84fab3cSChristian Lamparter 			 */
961a84fab3cSChristian Lamparter 
96259ae1d12SJohannes Berg 			skb_put_data(ar->rx_failover, tbuf, tlen);
963a84fab3cSChristian Lamparter 			ar->rx_failover_missing = clen - tlen;
964a84fab3cSChristian Lamparter 			return;
965a84fab3cSChristian Lamparter 		}
966a84fab3cSChristian Lamparter 		__carl9170_rx(ar, rx_stream->payload, clen);
967a84fab3cSChristian Lamparter 
968a84fab3cSChristian Lamparter 		tbuf += wlen + 4;
969a84fab3cSChristian Lamparter 		tlen -= wlen + 4;
970a84fab3cSChristian Lamparter 	}
971a84fab3cSChristian Lamparter 
972a84fab3cSChristian Lamparter 	if (tlen) {
973a84fab3cSChristian Lamparter 		if (net_ratelimit()) {
974a84fab3cSChristian Lamparter 			wiphy_err(ar->hw->wiphy, "%d bytes of unprocessed "
975a84fab3cSChristian Lamparter 				"data left in rx stream!\n", tlen);
976a84fab3cSChristian Lamparter 		}
977a84fab3cSChristian Lamparter 
978a84fab3cSChristian Lamparter 		goto err_telluser;
979a84fab3cSChristian Lamparter 	}
980a84fab3cSChristian Lamparter 
981a84fab3cSChristian Lamparter 	return;
982a84fab3cSChristian Lamparter 
983a84fab3cSChristian Lamparter err_telluser:
984a84fab3cSChristian Lamparter 	wiphy_err(ar->hw->wiphy, "damaged RX stream data [want:%d, "
985a84fab3cSChristian Lamparter 		"data:%d, rx:%d, pending:%d ]\n", clen, wlen, tlen,
986a84fab3cSChristian Lamparter 		ar->rx_failover_missing);
987a84fab3cSChristian Lamparter 
988a84fab3cSChristian Lamparter 	if (ar->rx_failover_missing)
989a84fab3cSChristian Lamparter 		print_hex_dump_bytes("rxbuf:", DUMP_PREFIX_OFFSET,
990a84fab3cSChristian Lamparter 				     ar->rx_failover->data,
991a84fab3cSChristian Lamparter 				     ar->rx_failover->len);
992a84fab3cSChristian Lamparter 
993a84fab3cSChristian Lamparter 	print_hex_dump_bytes("stream:", DUMP_PREFIX_OFFSET,
994a84fab3cSChristian Lamparter 			     buf, len);
995a84fab3cSChristian Lamparter 
996a84fab3cSChristian Lamparter 	wiphy_err(ar->hw->wiphy, "please check your hardware and cables, if "
997a84fab3cSChristian Lamparter 		"you see this message frequently.\n");
998a84fab3cSChristian Lamparter 
999a84fab3cSChristian Lamparter err_silent:
1000a84fab3cSChristian Lamparter 	if (ar->rx_failover_missing) {
1001a84fab3cSChristian Lamparter 		skb_reset_tail_pointer(ar->rx_failover);
1002a84fab3cSChristian Lamparter 		skb_trim(ar->rx_failover, 0);
1003a84fab3cSChristian Lamparter 		ar->rx_failover_missing = 0;
1004a84fab3cSChristian Lamparter 	}
1005a84fab3cSChristian Lamparter }
1006a84fab3cSChristian Lamparter 
carl9170_rx(struct ar9170 * ar,void * buf,unsigned int len)1007a84fab3cSChristian Lamparter void carl9170_rx(struct ar9170 *ar, void *buf, unsigned int len)
1008a84fab3cSChristian Lamparter {
1009a84fab3cSChristian Lamparter 	if (ar->fw.rx_stream)
1010a84fab3cSChristian Lamparter 		carl9170_rx_stream(ar, buf, len);
1011a84fab3cSChristian Lamparter 	else
1012a84fab3cSChristian Lamparter 		__carl9170_rx(ar, buf, len);
1013a84fab3cSChristian Lamparter }
1014