1a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter/*
2a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter * Atheros CARL9170 driver
3a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter *
4a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter * 802.11 & command trap routines
5a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter *
6a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
7a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter * Copyright 2009, 2010, Christian Lamparter <chunkeey@googlemail.com>
8a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter *
9a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter * This program is free software; you can redistribute it and/or modify
10a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter * it under the terms of the GNU General Public License as published by
11a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter * the Free Software Foundation; either version 2 of the License, or
12a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter * (at your option) any later version.
13a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter *
14a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter * This program is distributed in the hope that it will be useful,
15a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter * but WITHOUT ANY WARRANTY; without even the implied warranty of
16a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter * GNU General Public License for more details.
18a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter *
19a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter * You should have received a copy of the GNU General Public License
20a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter * along with this program; see the file COPYING.  If not, see
21a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter * http://www.gnu.org/licenses/.
22a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter *
23a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter * This file incorporates work covered by the following copyright and
24a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter * permission notice:
25a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter *    Copyright (c) 2007-2008 Atheros Communications, Inc.
26a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter *
27a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter *    Permission to use, copy, modify, and/or distribute this software for any
28a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter *    purpose with or without fee is hereby granted, provided that the above
29a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter *    copyright notice and this permission notice appear in all copies.
30a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter *
31a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter *    THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
32a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter *    WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
33a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter *    MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
34a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter *    ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
35a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter *    WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
36a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter *    ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
37a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter *    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
38a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter */
39a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
40a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter#include <linux/init.h>
41a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter#include <linux/slab.h>
42a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter#include <linux/module.h>
43a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter#include <linux/etherdevice.h>
44a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter#include <linux/crc32.h>
45a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter#include <net/mac80211.h>
46a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter#include "carl9170.h"
47a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter#include "hw.h"
48a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter#include "cmd.h"
49a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
50a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparterstatic void carl9170_dbg_message(struct ar9170 *ar, const char *buf, u32 len)
51a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter{
52a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	bool restart = false;
53a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	enum carl9170_restart_reasons reason = CARL9170_RR_NO_REASON;
54a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
55a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	if (len > 3) {
56a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		if (memcmp(buf, CARL9170_ERR_MAGIC, 3) == 0) {
57a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			ar->fw.err_counter++;
58a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			if (ar->fw.err_counter > 3) {
59a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter				restart = true;
60a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter				reason = CARL9170_RR_TOO_MANY_FIRMWARE_ERRORS;
61a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			}
62a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		}
63a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
64a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		if (memcmp(buf, CARL9170_BUG_MAGIC, 3) == 0) {
65a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			ar->fw.bug_counter++;
66a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			restart = true;
67a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			reason = CARL9170_RR_FATAL_FIRMWARE_ERROR;
68a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		}
69a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	}
70a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
71a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	wiphy_info(ar->hw->wiphy, "FW: %.*s\n", len, buf);
72a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
73a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	if (restart)
74a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		carl9170_restart(ar, reason);
75a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter}
76a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
77a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparterstatic void carl9170_handle_ps(struct ar9170 *ar, struct carl9170_rsp *rsp)
78a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter{
79a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	u32 ps;
80a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	bool new_ps;
81a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
82a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	ps = le32_to_cpu(rsp->psm.state);
83a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
84a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	new_ps = (ps & CARL9170_PSM_COUNTER) != CARL9170_PSM_WAKE;
85a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	if (ar->ps.state != new_ps) {
86a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		if (!new_ps) {
87a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			ar->ps.sleep_ms = jiffies_to_msecs(jiffies -
88a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter				ar->ps.last_action);
89a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		}
90a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
91a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		ar->ps.last_action = jiffies;
92a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
93a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		ar->ps.state = new_ps;
94a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	}
95a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter}
96a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
97a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparterstatic int carl9170_check_sequence(struct ar9170 *ar, unsigned int seq)
98a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter{
99a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	if (ar->cmd_seq < -1)
100a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		return 0;
101a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
102a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	/*
103a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	 * Initialize Counter
104a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	 */
105a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	if (ar->cmd_seq < 0)
106a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		ar->cmd_seq = seq;
107a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
108a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	/*
109a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	 * The sequence is strictly monotonic increasing and it never skips!
110a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	 *
111a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	 * Therefore we can safely assume that whenever we received an
112a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	 * unexpected sequence we have lost some valuable data.
113a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	 */
114a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	if (seq != ar->cmd_seq) {
115a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		int count;
116a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
117a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		count = (seq - ar->cmd_seq) % ar->fw.cmd_bufs;
118a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
119a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		wiphy_err(ar->hw->wiphy, "lost %d command responses/traps! "
120a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			  "w:%d g:%d\n", count, ar->cmd_seq, seq);
121a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
122a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		carl9170_restart(ar, CARL9170_RR_LOST_RSP);
123a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		return -EIO;
124a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	}
125a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
126a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	ar->cmd_seq = (ar->cmd_seq + 1) % ar->fw.cmd_bufs;
127a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	return 0;
128a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter}
129a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
130a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparterstatic void carl9170_cmd_callback(struct ar9170 *ar, u32 len, void *buffer)
131a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter{
132a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	/*
133a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	 * Some commands may have a variable response length
134a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	 * and we cannot predict the correct length in advance.
135a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	 * So we only check if we provided enough space for the data.
136a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	 */
137a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	if (unlikely(ar->readlen != (len - 4))) {
138a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		dev_warn(&ar->udev->dev, "received invalid command response:"
139a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			 "got %d, instead of %d\n", len - 4, ar->readlen);
140a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		print_hex_dump_bytes("carl9170 cmd:", DUMP_PREFIX_OFFSET,
141a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			ar->cmd_buf, (ar->cmd.hdr.len + 4) & 0x3f);
142a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		print_hex_dump_bytes("carl9170 rsp:", DUMP_PREFIX_OFFSET,
143a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			buffer, len);
144a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		/*
145a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		 * Do not complete. The command times out,
146a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		 * and we get a stack trace from there.
147a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		 */
148a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		carl9170_restart(ar, CARL9170_RR_INVALID_RSP);
149a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	}
150a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
151a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	spin_lock(&ar->cmd_lock);
152a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	if (ar->readbuf) {
153a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		if (len >= 4)
154a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			memcpy(ar->readbuf, buffer + 4, len - 4);
155a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
156a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		ar->readbuf = NULL;
157a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	}
158a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	complete(&ar->cmd_wait);
159a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	spin_unlock(&ar->cmd_lock);
160a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter}
161a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
162a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lampartervoid carl9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len)
163a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter{
164a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	struct carl9170_rsp *cmd = (void *) buf;
165a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	struct ieee80211_vif *vif;
166a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
167a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	if (carl9170_check_sequence(ar, cmd->hdr.seq))
168a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		return;
169a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
170a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	if ((cmd->hdr.cmd & CARL9170_RSP_FLAG) != CARL9170_RSP_FLAG) {
171a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		if (!(cmd->hdr.cmd & CARL9170_CMD_ASYNC_FLAG))
172a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			carl9170_cmd_callback(ar, len, buf);
173a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
174a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		return;
175a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	}
176a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
177a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	if (unlikely(cmd->hdr.len != (len - 4))) {
178a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		if (net_ratelimit()) {
179a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			wiphy_err(ar->hw->wiphy, "FW: received over-/under"
180a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter				"sized event %x (%d, but should be %d).\n",
181a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			       cmd->hdr.cmd, cmd->hdr.len, len - 4);
182a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
183a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			print_hex_dump_bytes("dump:", DUMP_PREFIX_NONE,
184a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter					     buf, len);
185a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		}
186a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
187a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		return;
188a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	}
189a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
190a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	/* hardware event handlers */
191a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	switch (cmd->hdr.cmd) {
192a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	case CARL9170_RSP_PRETBTT:
193a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		/* pre-TBTT event */
194a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		rcu_read_lock();
195a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		vif = carl9170_get_main_vif(ar);
196a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
197a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		if (!vif) {
198a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			rcu_read_unlock();
199a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			break;
200a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		}
201a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
202a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		switch (vif->type) {
203a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		case NL80211_IFTYPE_STATION:
204a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			carl9170_handle_ps(ar, cmd);
205a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			break;
206a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
207a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		case NL80211_IFTYPE_AP:
208a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		case NL80211_IFTYPE_ADHOC:
209a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			carl9170_update_beacon(ar, true);
210a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			break;
211a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
212a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		default:
213a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			break;
214a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		}
215a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		rcu_read_unlock();
216a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
217a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		break;
218a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
219a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
220a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	case CARL9170_RSP_TXCOMP:
221a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		/* TX status notification */
222a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		carl9170_tx_process_status(ar, cmd);
223a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		break;
224a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
225a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	case CARL9170_RSP_BEACON_CONFIG:
226a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		/*
227a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		 * (IBSS) beacon send notification
228a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		 * bytes: 04 c2 XX YY B4 B3 B2 B1
229a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		 *
230a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		 * XX always 80
231a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		 * YY always 00
232a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		 * B1-B4 "should" be the number of send out beacons.
233a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		 */
234a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		break;
235a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
236a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	case CARL9170_RSP_ATIM:
237a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		/* End of Atim Window */
238a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		break;
239a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
240a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	case CARL9170_RSP_WATCHDOG:
241a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		/* Watchdog Interrupt */
242a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		carl9170_restart(ar, CARL9170_RR_WATCHDOG);
243a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		break;
244a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
245a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	case CARL9170_RSP_TEXT:
246a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		/* firmware debug */
247a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		carl9170_dbg_message(ar, (char *)buf + 4, len - 4);
248a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		break;
249a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
250a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	case CARL9170_RSP_HEXDUMP:
251a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		wiphy_dbg(ar->hw->wiphy, "FW: HD %d\n", len - 4);
252a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		print_hex_dump_bytes("FW:", DUMP_PREFIX_NONE,
253a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter				     (char *)buf + 4, len - 4);
254a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		break;
255a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
256a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	case CARL9170_RSP_RADAR:
257a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		if (!net_ratelimit())
258a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			break;
259a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
260a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		wiphy_info(ar->hw->wiphy, "FW: RADAR! Please report this "
261a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		       "incident to linux-wireless@vger.kernel.org !\n");
262a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		break;
263a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
264a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	case CARL9170_RSP_GPIO:
265a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter#ifdef CONFIG_CARL9170_WPC
266a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		if (ar->wps.pbc) {
267a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			bool state = !!(cmd->gpio.gpio & cpu_to_le32(
268a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter				AR9170_GPIO_PORT_WPS_BUTTON_PRESSED));
269a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
270a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			if (state != ar->wps.pbc_state) {
271a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter				ar->wps.pbc_state = state;
272a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter				input_report_key(ar->wps.pbc, KEY_WPS_BUTTON,
273a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter						 state);
274a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter				input_sync(ar->wps.pbc);
275a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			}
276a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		}
277a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter#endif /* CONFIG_CARL9170_WPC */
278a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		break;
279a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
280a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	case CARL9170_RSP_BOOT:
281a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		complete(&ar->fw_boot_wait);
282a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		break;
283a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
284a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	default:
285a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		wiphy_err(ar->hw->wiphy, "FW: received unhandled event %x\n",
286a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			cmd->hdr.cmd);
287a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		print_hex_dump_bytes("dump:", DUMP_PREFIX_NONE, buf, len);
288a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		break;
289a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	}
290a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter}
291a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
292a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparterstatic int carl9170_rx_mac_status(struct ar9170 *ar,
293a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	struct ar9170_rx_head *head, struct ar9170_rx_macstatus *mac,
294a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	struct ieee80211_rx_status *status)
295a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter{
296a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	struct ieee80211_channel *chan;
297a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	u8 error, decrypt;
298a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
299a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	BUILD_BUG_ON(sizeof(struct ar9170_rx_head) != 12);
300a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	BUILD_BUG_ON(sizeof(struct ar9170_rx_macstatus) != 4);
301a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
302a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	error = mac->error;
303a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
304a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	if (error & AR9170_RX_ERROR_WRONG_RA) {
305a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		if (!ar->sniffer_enabled)
306a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			return -EINVAL;
307a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	}
308a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
309a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	if (error & AR9170_RX_ERROR_PLCP) {
310a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		if (!(ar->filter_state & FIF_PLCPFAIL))
311a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			return -EINVAL;
312a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
313a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		status->flag |= RX_FLAG_FAILED_PLCP_CRC;
314a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	}
315a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
316a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	if (error & AR9170_RX_ERROR_FCS) {
317a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		ar->tx_fcs_errors++;
318a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
319a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		if (!(ar->filter_state & FIF_FCSFAIL))
320a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			return -EINVAL;
321a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
322a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		status->flag |= RX_FLAG_FAILED_FCS_CRC;
323a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	}
324a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
325a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	decrypt = ar9170_get_decrypt_type(mac);
326a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	if (!(decrypt & AR9170_RX_ENC_SOFTWARE) &&
327a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	    decrypt != AR9170_ENC_ALG_NONE) {
328a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		if ((decrypt == AR9170_ENC_ALG_TKIP) &&
329a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		    (error & AR9170_RX_ERROR_MMIC))
330a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			status->flag |= RX_FLAG_MMIC_ERROR;
331a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
332a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		status->flag |= RX_FLAG_DECRYPTED;
333a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	}
334a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
335a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	if (error & AR9170_RX_ERROR_DECRYPT && !ar->sniffer_enabled)
336a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		return -ENODATA;
337a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
338a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	error &= ~(AR9170_RX_ERROR_MMIC |
339a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		   AR9170_RX_ERROR_FCS |
340a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		   AR9170_RX_ERROR_WRONG_RA |
341a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		   AR9170_RX_ERROR_DECRYPT |
342a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		   AR9170_RX_ERROR_PLCP);
343a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
344a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	/* drop any other error frames */
345a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	if (unlikely(error)) {
346a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		/* TODO: update netdevice's RX dropped/errors statistics */
347a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
348a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		if (net_ratelimit())
349a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			wiphy_dbg(ar->hw->wiphy, "received frame with "
350a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			       "suspicious error code (%#x).\n", error);
351a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
352a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		return -EINVAL;
353a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	}
354a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
355a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	chan = ar->channel;
356a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	if (chan) {
357a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		status->band = chan->band;
358a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		status->freq = chan->center_freq;
359a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	}
360a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
361a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	switch (mac->status & AR9170_RX_STATUS_MODULATION) {
362a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	case AR9170_RX_STATUS_MODULATION_CCK:
363a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		if (mac->status & AR9170_RX_STATUS_SHORT_PREAMBLE)
364a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			status->flag |= RX_FLAG_SHORTPRE;
365a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		switch (head->plcp[0]) {
366a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		case AR9170_RX_PHY_RATE_CCK_1M:
367a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			status->rate_idx = 0;
368a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			break;
369a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		case AR9170_RX_PHY_RATE_CCK_2M:
370a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			status->rate_idx = 1;
371a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			break;
372a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		case AR9170_RX_PHY_RATE_CCK_5M:
373a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			status->rate_idx = 2;
374a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			break;
375a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		case AR9170_RX_PHY_RATE_CCK_11M:
376a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			status->rate_idx = 3;
377a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			break;
378a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		default:
379a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			if (net_ratelimit()) {
380a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter				wiphy_err(ar->hw->wiphy, "invalid plcp cck "
381a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter				       "rate (%x).\n", head->plcp[0]);
382a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			}
383a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
384a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			return -EINVAL;
385a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		}
386a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		break;
387a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
388a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	case AR9170_RX_STATUS_MODULATION_DUPOFDM:
389a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	case AR9170_RX_STATUS_MODULATION_OFDM:
390a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		switch (head->plcp[0] & 0xf) {
391a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		case AR9170_TXRX_PHY_RATE_OFDM_6M:
392a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			status->rate_idx = 0;
393a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			break;
394a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		case AR9170_TXRX_PHY_RATE_OFDM_9M:
395a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			status->rate_idx = 1;
396a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			break;
397a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		case AR9170_TXRX_PHY_RATE_OFDM_12M:
398a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			status->rate_idx = 2;
399a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			break;
400a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		case AR9170_TXRX_PHY_RATE_OFDM_18M:
401a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			status->rate_idx = 3;
402a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			break;
403a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		case AR9170_TXRX_PHY_RATE_OFDM_24M:
404a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			status->rate_idx = 4;
405a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			break;
406a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		case AR9170_TXRX_PHY_RATE_OFDM_36M:
407a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			status->rate_idx = 5;
408a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			break;
409a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		case AR9170_TXRX_PHY_RATE_OFDM_48M:
410a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			status->rate_idx = 6;
411a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			break;
412a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		case AR9170_TXRX_PHY_RATE_OFDM_54M:
413a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			status->rate_idx = 7;
414a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			break;
415a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		default:
416a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			if (net_ratelimit()) {
417a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter				wiphy_err(ar->hw->wiphy, "invalid plcp ofdm "
418a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter					"rate (%x).\n", head->plcp[0]);
419a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			}
420a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
421a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			return -EINVAL;
422a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		}
423a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		if (status->band == IEEE80211_BAND_2GHZ)
424a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			status->rate_idx += 4;
425a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		break;
426a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
427a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	case AR9170_RX_STATUS_MODULATION_HT:
428a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		if (head->plcp[3] & 0x80)
429a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			status->flag |= RX_FLAG_40MHZ;
430a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		if (head->plcp[6] & 0x80)
431a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			status->flag |= RX_FLAG_SHORT_GI;
432a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
433a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		status->rate_idx = clamp(0, 75, head->plcp[3] & 0x7f);
434a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		status->flag |= RX_FLAG_HT;
435a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		break;
436a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
437a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	default:
438a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		BUG();
439a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		return -ENOSYS;
440a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	}
441a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
442a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	return 0;
443a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter}
444a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
445a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparterstatic void carl9170_rx_phy_status(struct ar9170 *ar,
446a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	struct ar9170_rx_phystatus *phy, struct ieee80211_rx_status *status)
447a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter{
448a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	int i;
449a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
450a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	BUILD_BUG_ON(sizeof(struct ar9170_rx_phystatus) != 20);
451a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
452a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	for (i = 0; i < 3; i++)
453a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		if (phy->rssi[i] != 0x80)
454a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			status->antenna |= BIT(i);
455a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
456a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	/* post-process RSSI */
457a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	for (i = 0; i < 7; i++)
458a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		if (phy->rssi[i] & 0x80)
459a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			phy->rssi[i] = ((phy->rssi[i] & 0x7f) + 1) & 0x7f;
460a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
461a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	/* TODO: we could do something with phy_errors */
462a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	status->signal = ar->noise[0] + phy->rssi_combined;
463a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter}
464a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
465a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparterstatic struct sk_buff *carl9170_rx_copy_data(u8 *buf, int len)
466a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter{
467a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	struct sk_buff *skb;
468a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	int reserved = 0;
469a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	struct ieee80211_hdr *hdr = (void *) buf;
470a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
471a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	if (ieee80211_is_data_qos(hdr->frame_control)) {
472a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		u8 *qc = ieee80211_get_qos_ctl(hdr);
473a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		reserved += NET_IP_ALIGN;
474a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
47504b7dcf979d71e870683c804802e44287a802760Johannes Berg		if (*qc & IEEE80211_QOS_CTL_A_MSDU_PRESENT)
476a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			reserved += NET_IP_ALIGN;
477a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	}
478a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
479a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	if (ieee80211_has_a4(hdr->frame_control))
480a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		reserved += NET_IP_ALIGN;
481a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
482a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	reserved = 32 + (reserved & NET_IP_ALIGN);
483a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
484a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	skb = dev_alloc_skb(len + reserved);
485a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	if (likely(skb)) {
486a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		skb_reserve(skb, reserved);
487a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		memcpy(skb_put(skb, len), buf, len);
488a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	}
489a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
490a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	return skb;
491a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter}
492a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
493a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparterstatic u8 *carl9170_find_ie(u8 *data, unsigned int len, u8 ie)
494a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter{
495a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	struct ieee80211_mgmt *mgmt = (void *)data;
496a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	u8 *pos, *end;
497a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
498a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	pos = (u8 *)mgmt->u.beacon.variable;
499a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	end = data + len;
500a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	while (pos < end) {
501a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		if (pos + 2 + pos[1] > end)
502a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			return NULL;
503a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
504a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		if (pos[0] == ie)
505a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			return pos;
506a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
507a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		pos += 2 + pos[1];
508a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	}
509a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	return NULL;
510a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter}
511a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
512a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter/*
513a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter * NOTE:
514a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter *
515a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter * The firmware is in charge of waking up the device just before
516a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter * the AP is expected to transmit the next beacon.
517a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter *
518a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter * This leaves the driver with the important task of deciding when
519a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter * to set the PHY back to bed again.
520a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter */
521a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparterstatic void carl9170_ps_beacon(struct ar9170 *ar, void *data, unsigned int len)
522a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter{
523a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	struct ieee80211_hdr *hdr = (void *) data;
524a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	struct ieee80211_tim_ie *tim_ie;
525a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	u8 *tim;
526a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	u8 tim_len;
527a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	bool cam;
528a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
529a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	if (likely(!(ar->hw->conf.flags & IEEE80211_CONF_PS)))
530a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		return;
531a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
532a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	/* check if this really is a beacon */
533a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	if (!ieee80211_is_beacon(hdr->frame_control))
534a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		return;
535a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
536a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	/* min. beacon length + FCS_LEN */
537a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	if (len <= 40 + FCS_LEN)
538a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		return;
539a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
540a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	/* and only beacons from the associated BSSID, please */
541a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	if (compare_ether_addr(hdr->addr3, ar->common.curbssid) ||
542a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	    !ar->common.curaid)
543a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		return;
544a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
545a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	ar->ps.last_beacon = jiffies;
546a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
547a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	tim = carl9170_find_ie(data, len - FCS_LEN, WLAN_EID_TIM);
548a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	if (!tim)
549a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		return;
550a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
551a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	if (tim[1] < sizeof(*tim_ie))
552a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		return;
553a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
554a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	tim_len = tim[1];
555a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	tim_ie = (struct ieee80211_tim_ie *) &tim[2];
556a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
557a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	if (!WARN_ON_ONCE(!ar->hw->conf.ps_dtim_period))
558a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		ar->ps.dtim_counter = (tim_ie->dtim_count - 1) %
559a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			ar->hw->conf.ps_dtim_period;
560a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
561a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	/* Check whenever the PHY can be turned off again. */
562a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
563a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	/* 1. What about buffered unicast traffic for our AID? */
564a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	cam = ieee80211_check_tim(tim_ie, tim_len, ar->common.curaid);
565a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
566a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	/* 2. Maybe the AP wants to send multicast/broadcast data? */
5675820de5303f73d48dcc3a053c875d1f0da7eef67Christian Lamparter	cam |= !!(tim_ie->bitmap_ctrl & 0x01);
568a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
569a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	if (!cam) {
570a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		/* back to low-power land. */
571a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		ar->ps.off_override &= ~PS_OFF_BCN;
572a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		carl9170_ps_check(ar);
573a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	} else {
574a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		/* force CAM */
575a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		ar->ps.off_override |= PS_OFF_BCN;
576a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	}
577a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter}
578a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
5798f236d1bef659ca69c912536a69b3031e5ba3269Christian Lamparterstatic bool carl9170_ampdu_check(struct ar9170 *ar, u8 *buf, u8 ms)
5808f236d1bef659ca69c912536a69b3031e5ba3269Christian Lamparter{
5818f236d1bef659ca69c912536a69b3031e5ba3269Christian Lamparter	__le16 fc;
5828f236d1bef659ca69c912536a69b3031e5ba3269Christian Lamparter
5838f236d1bef659ca69c912536a69b3031e5ba3269Christian Lamparter	if ((ms & AR9170_RX_STATUS_MPDU) == AR9170_RX_STATUS_MPDU_SINGLE) {
5848f236d1bef659ca69c912536a69b3031e5ba3269Christian Lamparter		/*
5858f236d1bef659ca69c912536a69b3031e5ba3269Christian Lamparter		 * This frame is not part of an aMPDU.
5868f236d1bef659ca69c912536a69b3031e5ba3269Christian Lamparter		 * Therefore it is not subjected to any
5878f236d1bef659ca69c912536a69b3031e5ba3269Christian Lamparter		 * of the following content restrictions.
5888f236d1bef659ca69c912536a69b3031e5ba3269Christian Lamparter		 */
5898f236d1bef659ca69c912536a69b3031e5ba3269Christian Lamparter		return true;
5908f236d1bef659ca69c912536a69b3031e5ba3269Christian Lamparter	}
5918f236d1bef659ca69c912536a69b3031e5ba3269Christian Lamparter
5928f236d1bef659ca69c912536a69b3031e5ba3269Christian Lamparter	/*
5938f236d1bef659ca69c912536a69b3031e5ba3269Christian Lamparter	 * "802.11n - 7.4a.3 A-MPDU contents" describes in which contexts
5948f236d1bef659ca69c912536a69b3031e5ba3269Christian Lamparter	 * certain frame types can be part of an aMPDU.
5958f236d1bef659ca69c912536a69b3031e5ba3269Christian Lamparter	 *
5968f236d1bef659ca69c912536a69b3031e5ba3269Christian Lamparter	 * In order to keep the processing cost down, I opted for a
5978f236d1bef659ca69c912536a69b3031e5ba3269Christian Lamparter	 * stateless filter solely based on the frame control field.
5988f236d1bef659ca69c912536a69b3031e5ba3269Christian Lamparter	 */
5998f236d1bef659ca69c912536a69b3031e5ba3269Christian Lamparter
6008f236d1bef659ca69c912536a69b3031e5ba3269Christian Lamparter	fc = ((struct ieee80211_hdr *)buf)->frame_control;
6018f236d1bef659ca69c912536a69b3031e5ba3269Christian Lamparter	if (ieee80211_is_data_qos(fc) && ieee80211_is_data_present(fc))
6028f236d1bef659ca69c912536a69b3031e5ba3269Christian Lamparter		return true;
6038f236d1bef659ca69c912536a69b3031e5ba3269Christian Lamparter
6048f236d1bef659ca69c912536a69b3031e5ba3269Christian Lamparter	if (ieee80211_is_ack(fc) || ieee80211_is_back(fc) ||
6058f236d1bef659ca69c912536a69b3031e5ba3269Christian Lamparter	    ieee80211_is_back_req(fc))
6068f236d1bef659ca69c912536a69b3031e5ba3269Christian Lamparter		return true;
6078f236d1bef659ca69c912536a69b3031e5ba3269Christian Lamparter
6088f236d1bef659ca69c912536a69b3031e5ba3269Christian Lamparter	if (ieee80211_is_action(fc))
6098f236d1bef659ca69c912536a69b3031e5ba3269Christian Lamparter		return true;
6108f236d1bef659ca69c912536a69b3031e5ba3269Christian Lamparter
6118f236d1bef659ca69c912536a69b3031e5ba3269Christian Lamparter	return false;
6128f236d1bef659ca69c912536a69b3031e5ba3269Christian Lamparter}
6138f236d1bef659ca69c912536a69b3031e5ba3269Christian Lamparter
614a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter/*
615a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter * If the frame alignment is right (or the kernel has
616a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter * CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS), and there
617a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter * is only a single MPDU in the USB frame, then we could
618a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter * submit to mac80211 the SKB directly. However, since
619a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter * there may be multiple packets in one SKB in stream
620a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter * mode, and we need to observe the proper ordering,
621a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter * this is non-trivial.
622a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter */
623a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
624a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparterstatic void carl9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len)
625a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter{
626a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	struct ar9170_rx_head *head;
627a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	struct ar9170_rx_macstatus *mac;
628a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	struct ar9170_rx_phystatus *phy = NULL;
629a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	struct ieee80211_rx_status status;
630a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	struct sk_buff *skb;
631a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	int mpdu_len;
6328f236d1bef659ca69c912536a69b3031e5ba3269Christian Lamparter	u8 mac_status;
633a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
634a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	if (!IS_STARTED(ar))
635a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		return;
636a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
637c8a16c68ef4eb7817e41759c7105678ebc155377Christian Lamparter	if (unlikely(len < sizeof(*mac)))
638c8a16c68ef4eb7817e41759c7105678ebc155377Christian Lamparter		goto drop;
639a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
640a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	mpdu_len = len - sizeof(*mac);
641a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
642a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	mac = (void *)(buf + mpdu_len);
6438f236d1bef659ca69c912536a69b3031e5ba3269Christian Lamparter	mac_status = mac->status;
6448f236d1bef659ca69c912536a69b3031e5ba3269Christian Lamparter	switch (mac_status & AR9170_RX_STATUS_MPDU) {
645a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	case AR9170_RX_STATUS_MPDU_FIRST:
646a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		/* Aggregated MPDUs start with an PLCP header */
647a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		if (likely(mpdu_len >= sizeof(struct ar9170_rx_head))) {
648a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			head = (void *) buf;
649a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
650a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			/*
651a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			 * The PLCP header needs to be cached for the
652a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			 * following MIDDLE + LAST A-MPDU packets.
653a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			 *
654a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			 * So, if you are wondering why all frames seem
655a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			 * to share a common RX status information,
656a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			 * then you have the answer right here...
657a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			 */
658a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			memcpy(&ar->rx_plcp, (void *) buf,
659a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			       sizeof(struct ar9170_rx_head));
660a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
661a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			mpdu_len -= sizeof(struct ar9170_rx_head);
662a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			buf += sizeof(struct ar9170_rx_head);
663a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
664a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			ar->rx_has_plcp = true;
665a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		} else {
666a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			if (net_ratelimit()) {
667a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter				wiphy_err(ar->hw->wiphy, "plcp info "
668a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter					"is clipped.\n");
669a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			}
670a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
671c8a16c68ef4eb7817e41759c7105678ebc155377Christian Lamparter			goto drop;
672a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		}
673a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		break;
674a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
675a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	case AR9170_RX_STATUS_MPDU_LAST:
676a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		/*
677a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		 * The last frame of an A-MPDU has an extra tail
678a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		 * which does contain the phy status of the whole
679a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		 * aggregate.
680a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		 */
681a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
682a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		if (likely(mpdu_len >= sizeof(struct ar9170_rx_phystatus))) {
683a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			mpdu_len -= sizeof(struct ar9170_rx_phystatus);
684a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			phy = (void *)(buf + mpdu_len);
685a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		} else {
686a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			if (net_ratelimit()) {
687a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter				wiphy_err(ar->hw->wiphy, "frame tail "
688a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter					"is clipped.\n");
689a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			}
690a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
691c8a16c68ef4eb7817e41759c7105678ebc155377Christian Lamparter			goto drop;
692a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		}
693a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
694a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	case AR9170_RX_STATUS_MPDU_MIDDLE:
695a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		/*  These are just data + mac status */
696a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		if (unlikely(!ar->rx_has_plcp)) {
697a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			if (!net_ratelimit())
698a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter				return;
699a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
700a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			wiphy_err(ar->hw->wiphy, "rx stream does not start "
701a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter					"with a first_mpdu frame tag.\n");
702a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
703c8a16c68ef4eb7817e41759c7105678ebc155377Christian Lamparter			goto drop;
704a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		}
705a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
706a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		head = &ar->rx_plcp;
707a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		break;
708a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
709a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	case AR9170_RX_STATUS_MPDU_SINGLE:
710a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		/* single mpdu has both: plcp (head) and phy status (tail) */
711a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		head = (void *) buf;
712a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
713a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		mpdu_len -= sizeof(struct ar9170_rx_head);
714a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		mpdu_len -= sizeof(struct ar9170_rx_phystatus);
715a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
716a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		buf += sizeof(struct ar9170_rx_head);
717a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		phy = (void *)(buf + mpdu_len);
718a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		break;
719a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
720a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	default:
721a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		BUG_ON(1);
722a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		break;
723a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	}
724a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
725a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	/* FC + DU + RA + FCS */
726c8a16c68ef4eb7817e41759c7105678ebc155377Christian Lamparter	if (unlikely(mpdu_len < (2 + 2 + ETH_ALEN + FCS_LEN)))
727c8a16c68ef4eb7817e41759c7105678ebc155377Christian Lamparter		goto drop;
728a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
729a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	memset(&status, 0, sizeof(status));
730c8a16c68ef4eb7817e41759c7105678ebc155377Christian Lamparter	if (unlikely(carl9170_rx_mac_status(ar, head, mac, &status)))
731c8a16c68ef4eb7817e41759c7105678ebc155377Christian Lamparter		goto drop;
732a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
7338f236d1bef659ca69c912536a69b3031e5ba3269Christian Lamparter	if (!carl9170_ampdu_check(ar, buf, mac_status))
7348f236d1bef659ca69c912536a69b3031e5ba3269Christian Lamparter		goto drop;
7358f236d1bef659ca69c912536a69b3031e5ba3269Christian Lamparter
736a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	if (phy)
737a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		carl9170_rx_phy_status(ar, phy, &status);
738a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
739a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	carl9170_ps_beacon(ar, buf, mpdu_len);
740a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
741a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	skb = carl9170_rx_copy_data(buf, mpdu_len);
742c8a16c68ef4eb7817e41759c7105678ebc155377Christian Lamparter	if (!skb)
743c8a16c68ef4eb7817e41759c7105678ebc155377Christian Lamparter		goto drop;
744c8a16c68ef4eb7817e41759c7105678ebc155377Christian Lamparter
745c8a16c68ef4eb7817e41759c7105678ebc155377Christian Lamparter	memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
746c8a16c68ef4eb7817e41759c7105678ebc155377Christian Lamparter	ieee80211_rx(ar->hw, skb);
747c8a16c68ef4eb7817e41759c7105678ebc155377Christian Lamparter	return;
748c8a16c68ef4eb7817e41759c7105678ebc155377Christian Lamparter
749c8a16c68ef4eb7817e41759c7105678ebc155377Christian Lamparterdrop:
750c8a16c68ef4eb7817e41759c7105678ebc155377Christian Lamparter	ar->rx_dropped++;
751a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter}
752a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
753a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparterstatic void carl9170_rx_untie_cmds(struct ar9170 *ar, const u8 *respbuf,
754a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter				   const unsigned int resplen)
755a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter{
756a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	struct carl9170_rsp *cmd;
757a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	int i = 0;
758a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
759a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	while (i < resplen) {
760a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		cmd = (void *) &respbuf[i];
761a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
762a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		i += cmd->hdr.len + 4;
763a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		if (unlikely(i > resplen))
764a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			break;
765a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
766a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		carl9170_handle_command_response(ar, cmd, cmd->hdr.len + 4);
767a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	}
768a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
769a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	if (unlikely(i != resplen)) {
770a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		if (!net_ratelimit())
771a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			return;
772a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
773a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		wiphy_err(ar->hw->wiphy, "malformed firmware trap:\n");
774a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		print_hex_dump_bytes("rxcmd:", DUMP_PREFIX_OFFSET,
775a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter				     respbuf, resplen);
776a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	}
777a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter}
778a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
779a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparterstatic void __carl9170_rx(struct ar9170 *ar, u8 *buf, unsigned int len)
780a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter{
781a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	unsigned int i = 0;
782a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
783a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	/* weird thing, but this is the same in the original driver */
784a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	while (len > 2 && i < 12 && buf[0] == 0xff && buf[1] == 0xff) {
785a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		i += 2;
786a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		len -= 2;
787a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		buf += 2;
788a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	}
789a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
790a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	if (unlikely(len < 4))
791a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		return;
792a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
793a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	/* found the 6 * 0xffff marker? */
794a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	if (i == 12)
795a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		carl9170_rx_untie_cmds(ar, buf, len);
796a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	else
797a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		carl9170_handle_mpdu(ar, buf, len);
798a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter}
799a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
800a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparterstatic void carl9170_rx_stream(struct ar9170 *ar, void *buf, unsigned int len)
801a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter{
802a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	unsigned int tlen, wlen = 0, clen = 0;
803a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	struct ar9170_stream *rx_stream;
804a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	u8 *tbuf;
805a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
806a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	tbuf = buf;
807a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	tlen = len;
808a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
809a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	while (tlen >= 4) {
810a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		rx_stream = (void *) tbuf;
811a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		clen = le16_to_cpu(rx_stream->length);
812a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		wlen = ALIGN(clen, 4);
813a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
814a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		/* check if this is stream has a valid tag.*/
815a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		if (rx_stream->tag != cpu_to_le16(AR9170_RX_STREAM_TAG)) {
816a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			/*
817a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			 * TODO: handle the highly unlikely event that the
818a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			 * corrupted stream has the TAG at the right position.
819a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			 */
820a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
821a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			/* check if the frame can be repaired. */
822a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			if (!ar->rx_failover_missing) {
823a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
824a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter				/* this is not "short read". */
825a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter				if (net_ratelimit()) {
826a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter					wiphy_err(ar->hw->wiphy,
827a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter						"missing tag!\n");
828a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter				}
829a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
830a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter				__carl9170_rx(ar, tbuf, tlen);
831a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter				return;
832a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			}
833a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
834a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			if (ar->rx_failover_missing > tlen) {
835a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter				if (net_ratelimit()) {
836a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter					wiphy_err(ar->hw->wiphy,
837a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter						"possible multi "
838a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter						"stream corruption!\n");
839a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter					goto err_telluser;
840a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter				} else {
841a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter					goto err_silent;
842a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter				}
843a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			}
844a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
845a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			memcpy(skb_put(ar->rx_failover, tlen), tbuf, tlen);
846a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			ar->rx_failover_missing -= tlen;
847a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
848a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			if (ar->rx_failover_missing <= 0) {
849a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter				/*
850a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter				 * nested carl9170_rx_stream call!
851a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter				 *
85225985edcedea6396277003854657b5f3cb31a628Lucas De Marchi				 * termination is guaranteed, even when the
853a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter				 * combined frame also have an element with
854a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter				 * a bad tag.
855a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter				 */
856a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
857a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter				ar->rx_failover_missing = 0;
858a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter				carl9170_rx_stream(ar, ar->rx_failover->data,
859a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter						   ar->rx_failover->len);
860a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
861a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter				skb_reset_tail_pointer(ar->rx_failover);
862a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter				skb_trim(ar->rx_failover, 0);
863a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			}
864a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
865a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			return;
866a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		}
867a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
868a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		/* check if stream is clipped */
869a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		if (wlen > tlen - 4) {
870a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			if (ar->rx_failover_missing) {
871a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter				/* TODO: handle double stream corruption. */
872a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter				if (net_ratelimit()) {
873a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter					wiphy_err(ar->hw->wiphy, "double rx "
874a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter						"stream corruption!\n");
875a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter					goto err_telluser;
876a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter				} else {
877a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter					goto err_silent;
878a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter				}
879a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			}
880a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
881a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			/*
882a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			 * save incomplete data set.
883a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			 * the firmware will resend the missing bits when
884a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			 * the rx - descriptor comes round again.
885a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			 */
886a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
887a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			memcpy(skb_put(ar->rx_failover, tlen), tbuf, tlen);
888a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			ar->rx_failover_missing = clen - tlen;
889a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			return;
890a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		}
891a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		__carl9170_rx(ar, rx_stream->payload, clen);
892a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
893a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		tbuf += wlen + 4;
894a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		tlen -= wlen + 4;
895a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	}
896a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
897a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	if (tlen) {
898a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		if (net_ratelimit()) {
899a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			wiphy_err(ar->hw->wiphy, "%d bytes of unprocessed "
900a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter				"data left in rx stream!\n", tlen);
901a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		}
902a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
903a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		goto err_telluser;
904a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	}
905a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
906a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	return;
907a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
908a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lampartererr_telluser:
909a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	wiphy_err(ar->hw->wiphy, "damaged RX stream data [want:%d, "
910a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		"data:%d, rx:%d, pending:%d ]\n", clen, wlen, tlen,
911a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		ar->rx_failover_missing);
912a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
913a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	if (ar->rx_failover_missing)
914a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		print_hex_dump_bytes("rxbuf:", DUMP_PREFIX_OFFSET,
915a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter				     ar->rx_failover->data,
916a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter				     ar->rx_failover->len);
917a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
918a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	print_hex_dump_bytes("stream:", DUMP_PREFIX_OFFSET,
919a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter			     buf, len);
920a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
921a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	wiphy_err(ar->hw->wiphy, "please check your hardware and cables, if "
922a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		"you see this message frequently.\n");
923a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
924a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lampartererr_silent:
925a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	if (ar->rx_failover_missing) {
926a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		skb_reset_tail_pointer(ar->rx_failover);
927a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		skb_trim(ar->rx_failover, 0);
928a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		ar->rx_failover_missing = 0;
929a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	}
930a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter}
931a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter
932a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lampartervoid carl9170_rx(struct ar9170 *ar, void *buf, unsigned int len)
933a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter{
934a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	if (ar->fw.rx_stream)
935a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		carl9170_rx_stream(ar, buf, len);
936a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter	else
937a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter		__carl9170_rx(ar, buf, len);
938a84fab3cbfdc427e7d366f1cc844f27b2084c26cChristian Lamparter}
939