xmit.c revision d987160b710c98997015832422a05e18d9f0f925
1e4d6b7951812d98417feb10784e400e253caf633Michael Buesch/*
2e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
3e4d6b7951812d98417feb10784e400e253caf633Michael Buesch  Broadcom B43 wireless driver
4e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
5e4d6b7951812d98417feb10784e400e253caf633Michael Buesch  Transmission (TX/RX) related functions.
6e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
7e4d6b7951812d98417feb10784e400e253caf633Michael Buesch  Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
8e4d6b7951812d98417feb10784e400e253caf633Michael Buesch  Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
9e4d6b7951812d98417feb10784e400e253caf633Michael Buesch  Copyright (C) 2005, 2006 Michael Buesch <mb@bu3sch.de>
10e4d6b7951812d98417feb10784e400e253caf633Michael Buesch  Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
11e4d6b7951812d98417feb10784e400e253caf633Michael Buesch  Copyright (C) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
12e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
13e4d6b7951812d98417feb10784e400e253caf633Michael Buesch  This program is free software; you can redistribute it and/or modify
14e4d6b7951812d98417feb10784e400e253caf633Michael Buesch  it under the terms of the GNU General Public License as published by
15e4d6b7951812d98417feb10784e400e253caf633Michael Buesch  the Free Software Foundation; either version 2 of the License, or
16e4d6b7951812d98417feb10784e400e253caf633Michael Buesch  (at your option) any later version.
17e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
18e4d6b7951812d98417feb10784e400e253caf633Michael Buesch  This program is distributed in the hope that it will be useful,
19e4d6b7951812d98417feb10784e400e253caf633Michael Buesch  but WITHOUT ANY WARRANTY; without even the implied warranty of
20e4d6b7951812d98417feb10784e400e253caf633Michael Buesch  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21e4d6b7951812d98417feb10784e400e253caf633Michael Buesch  GNU General Public License for more details.
22e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
23e4d6b7951812d98417feb10784e400e253caf633Michael Buesch  You should have received a copy of the GNU General Public License
24e4d6b7951812d98417feb10784e400e253caf633Michael Buesch  along with this program; see the file COPYING.  If not, write to
25e4d6b7951812d98417feb10784e400e253caf633Michael Buesch  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
26e4d6b7951812d98417feb10784e400e253caf633Michael Buesch  Boston, MA 02110-1301, USA.
27e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
28e4d6b7951812d98417feb10784e400e253caf633Michael Buesch*/
29e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
30e4d6b7951812d98417feb10784e400e253caf633Michael Buesch#include "xmit.h"
31e4d6b7951812d98417feb10784e400e253caf633Michael Buesch#include "phy.h"
32e4d6b7951812d98417feb10784e400e253caf633Michael Buesch#include "dma.h"
33e4d6b7951812d98417feb10784e400e253caf633Michael Buesch#include "pio.h"
34e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
35e4d6b7951812d98417feb10784e400e253caf633Michael Buesch/* Extract the bitrate out of a CCK PLCP header. */
36e4d6b7951812d98417feb10784e400e253caf633Michael Bueschstatic u8 b43_plcp_get_bitrate_cck(struct b43_plcp_hdr6 *plcp)
37e4d6b7951812d98417feb10784e400e253caf633Michael Buesch{
38e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	switch (plcp->raw[0]) {
39e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	case 0x0A:
40e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		return B43_CCK_RATE_1MB;
41e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	case 0x14:
42e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		return B43_CCK_RATE_2MB;
43e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	case 0x37:
44e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		return B43_CCK_RATE_5MB;
45e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	case 0x6E:
46e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		return B43_CCK_RATE_11MB;
47e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	}
48e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	B43_WARN_ON(1);
49e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	return 0;
50e4d6b7951812d98417feb10784e400e253caf633Michael Buesch}
51e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
52e4d6b7951812d98417feb10784e400e253caf633Michael Buesch/* Extract the bitrate out of an OFDM PLCP header. */
53e4d6b7951812d98417feb10784e400e253caf633Michael Bueschstatic u8 b43_plcp_get_bitrate_ofdm(struct b43_plcp_hdr6 *plcp)
54e4d6b7951812d98417feb10784e400e253caf633Michael Buesch{
55e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	switch (plcp->raw[0] & 0xF) {
56e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	case 0xB:
57e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		return B43_OFDM_RATE_6MB;
58e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	case 0xF:
59e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		return B43_OFDM_RATE_9MB;
60e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	case 0xA:
61e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		return B43_OFDM_RATE_12MB;
62e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	case 0xE:
63e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		return B43_OFDM_RATE_18MB;
64e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	case 0x9:
65e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		return B43_OFDM_RATE_24MB;
66e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	case 0xD:
67e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		return B43_OFDM_RATE_36MB;
68e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	case 0x8:
69e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		return B43_OFDM_RATE_48MB;
70e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	case 0xC:
71e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		return B43_OFDM_RATE_54MB;
72e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	}
73e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	B43_WARN_ON(1);
74e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	return 0;
75e4d6b7951812d98417feb10784e400e253caf633Michael Buesch}
76e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
77e4d6b7951812d98417feb10784e400e253caf633Michael Bueschu8 b43_plcp_get_ratecode_cck(const u8 bitrate)
78e4d6b7951812d98417feb10784e400e253caf633Michael Buesch{
79e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	switch (bitrate) {
80e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	case B43_CCK_RATE_1MB:
81e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		return 0x0A;
82e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	case B43_CCK_RATE_2MB:
83e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		return 0x14;
84e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	case B43_CCK_RATE_5MB:
85e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		return 0x37;
86e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	case B43_CCK_RATE_11MB:
87e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		return 0x6E;
88e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	}
89e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	B43_WARN_ON(1);
90e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	return 0;
91e4d6b7951812d98417feb10784e400e253caf633Michael Buesch}
92e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
93e4d6b7951812d98417feb10784e400e253caf633Michael Bueschu8 b43_plcp_get_ratecode_ofdm(const u8 bitrate)
94e4d6b7951812d98417feb10784e400e253caf633Michael Buesch{
95e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	switch (bitrate) {
96e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	case B43_OFDM_RATE_6MB:
97e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		return 0xB;
98e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	case B43_OFDM_RATE_9MB:
99e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		return 0xF;
100e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	case B43_OFDM_RATE_12MB:
101e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		return 0xA;
102e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	case B43_OFDM_RATE_18MB:
103e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		return 0xE;
104e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	case B43_OFDM_RATE_24MB:
105e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		return 0x9;
106e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	case B43_OFDM_RATE_36MB:
107e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		return 0xD;
108e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	case B43_OFDM_RATE_48MB:
109e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		return 0x8;
110e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	case B43_OFDM_RATE_54MB:
111e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		return 0xC;
112e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	}
113e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	B43_WARN_ON(1);
114e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	return 0;
115e4d6b7951812d98417feb10784e400e253caf633Michael Buesch}
116e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
117e4d6b7951812d98417feb10784e400e253caf633Michael Bueschvoid b43_generate_plcp_hdr(struct b43_plcp_hdr4 *plcp,
118e4d6b7951812d98417feb10784e400e253caf633Michael Buesch			   const u16 octets, const u8 bitrate)
119e4d6b7951812d98417feb10784e400e253caf633Michael Buesch{
120e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	__le32 *data = &(plcp->data);
121e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	__u8 *raw = plcp->raw;
122e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
123e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	if (b43_is_ofdm_rate(bitrate)) {
1241a09404a2338163f181d170c7abdc2242b6c6f03Michael Buesch		u32 d;
1251a09404a2338163f181d170c7abdc2242b6c6f03Michael Buesch
1261a09404a2338163f181d170c7abdc2242b6c6f03Michael Buesch		d = b43_plcp_get_ratecode_ofdm(bitrate);
127e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		B43_WARN_ON(octets & 0xF000);
1281a09404a2338163f181d170c7abdc2242b6c6f03Michael Buesch		d |= (octets << 5);
1291a09404a2338163f181d170c7abdc2242b6c6f03Michael Buesch		*data = cpu_to_le32(d);
130e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	} else {
131e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		u32 plen;
132e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
133e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		plen = octets * 16 / bitrate;
134e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		if ((octets * 16 % bitrate) > 0) {
135e4d6b7951812d98417feb10784e400e253caf633Michael Buesch			plen++;
136e4d6b7951812d98417feb10784e400e253caf633Michael Buesch			if ((bitrate == B43_CCK_RATE_11MB)
137e4d6b7951812d98417feb10784e400e253caf633Michael Buesch			    && ((octets * 8 % 11) < 4)) {
138e4d6b7951812d98417feb10784e400e253caf633Michael Buesch				raw[1] = 0x84;
139e4d6b7951812d98417feb10784e400e253caf633Michael Buesch			} else
140e4d6b7951812d98417feb10784e400e253caf633Michael Buesch				raw[1] = 0x04;
141e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		} else
142e4d6b7951812d98417feb10784e400e253caf633Michael Buesch			raw[1] = 0x04;
143e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		*data |= cpu_to_le32(plen << 16);
144e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		raw[0] = b43_plcp_get_ratecode_cck(bitrate);
145e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	}
146e4d6b7951812d98417feb10784e400e253caf633Michael Buesch}
147e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
148e4d6b7951812d98417feb10784e400e253caf633Michael Bueschstatic u8 b43_calc_fallback_rate(u8 bitrate)
149e4d6b7951812d98417feb10784e400e253caf633Michael Buesch{
150e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	switch (bitrate) {
151e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	case B43_CCK_RATE_1MB:
152e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		return B43_CCK_RATE_1MB;
153e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	case B43_CCK_RATE_2MB:
154e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		return B43_CCK_RATE_1MB;
155e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	case B43_CCK_RATE_5MB:
156e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		return B43_CCK_RATE_2MB;
157e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	case B43_CCK_RATE_11MB:
158e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		return B43_CCK_RATE_5MB;
159e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	case B43_OFDM_RATE_6MB:
160e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		return B43_CCK_RATE_5MB;
161e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	case B43_OFDM_RATE_9MB:
162e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		return B43_OFDM_RATE_6MB;
163e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	case B43_OFDM_RATE_12MB:
164e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		return B43_OFDM_RATE_9MB;
165e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	case B43_OFDM_RATE_18MB:
166e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		return B43_OFDM_RATE_12MB;
167e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	case B43_OFDM_RATE_24MB:
168e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		return B43_OFDM_RATE_18MB;
169e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	case B43_OFDM_RATE_36MB:
170e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		return B43_OFDM_RATE_24MB;
171e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	case B43_OFDM_RATE_48MB:
172e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		return B43_OFDM_RATE_36MB;
173e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	case B43_OFDM_RATE_54MB:
174e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		return B43_OFDM_RATE_48MB;
175e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	}
176e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	B43_WARN_ON(1);
177e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	return 0;
178e4d6b7951812d98417feb10784e400e253caf633Michael Buesch}
179e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
180e4d6b7951812d98417feb10784e400e253caf633Michael Bueschstatic void generate_txhdr_fw4(struct b43_wldev *dev,
181e4d6b7951812d98417feb10784e400e253caf633Michael Buesch			       struct b43_txhdr_fw4 *txhdr,
182e4d6b7951812d98417feb10784e400e253caf633Michael Buesch			       const unsigned char *fragment_data,
183e4d6b7951812d98417feb10784e400e253caf633Michael Buesch			       unsigned int fragment_len,
184e4d6b7951812d98417feb10784e400e253caf633Michael Buesch			       const struct ieee80211_tx_control *txctl,
185e4d6b7951812d98417feb10784e400e253caf633Michael Buesch			       u16 cookie)
186e4d6b7951812d98417feb10784e400e253caf633Michael Buesch{
187e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	const struct b43_phy *phy = &dev->phy;
188e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	const struct ieee80211_hdr *wlhdr =
189e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	    (const struct ieee80211_hdr *)fragment_data;
190e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	int use_encryption = (!(txctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT));
191e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	u16 fctl = le16_to_cpu(wlhdr->frame_control);
192e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	u8 rate, rate_fb;
193e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	int rate_ofdm, rate_fb_ofdm;
194e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	unsigned int plcp_fragment_len;
195e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	u32 mac_ctl = 0;
196e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	u16 phy_ctl = 0;
197e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	u8 extra_ft = 0;
198e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
199e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	memset(txhdr, 0, sizeof(*txhdr));
200e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
201e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	rate = txctl->tx_rate;
202e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	rate_ofdm = b43_is_ofdm_rate(rate);
203e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	rate_fb = (txctl->alt_retry_rate == -1) ? rate : txctl->alt_retry_rate;
204e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	rate_fb_ofdm = b43_is_ofdm_rate(rate_fb);
205e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
206e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	if (rate_ofdm)
207e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		txhdr->phy_rate = b43_plcp_get_ratecode_ofdm(rate);
208e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	else
209e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		txhdr->phy_rate = b43_plcp_get_ratecode_cck(rate);
210e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	txhdr->mac_frame_ctl = wlhdr->frame_control;
211e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	memcpy(txhdr->tx_receiver, wlhdr->addr1, 6);
212e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
213e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	/* Calculate duration for fallback rate */
214e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	if ((rate_fb == rate) ||
215e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	    (wlhdr->duration_id & cpu_to_le16(0x8000)) ||
216e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	    (wlhdr->duration_id == cpu_to_le16(0))) {
217e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		/* If the fallback rate equals the normal rate or the
218e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		 * dur_id field contains an AID, CFP magic or 0,
219e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		 * use the original dur_id field. */
220e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		txhdr->dur_fb = wlhdr->duration_id;
221e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	} else {
222e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		int fbrate_base100kbps = B43_RATE_TO_BASE100KBPS(rate_fb);
223e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		txhdr->dur_fb = ieee80211_generic_frame_duration(dev->wl->hw,
224e4d6b7951812d98417feb10784e400e253caf633Michael Buesch								 dev->wl->if_id,
225e4d6b7951812d98417feb10784e400e253caf633Michael Buesch								 fragment_len,
226e4d6b7951812d98417feb10784e400e253caf633Michael Buesch								 fbrate_base100kbps);
227e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	}
228e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
229e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	plcp_fragment_len = fragment_len + FCS_LEN;
230e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	if (use_encryption) {
231e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		u8 key_idx = (u16) (txctl->key_idx);
232e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		struct b43_key *key;
233e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		int wlhdr_len;
234e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		size_t iv_len;
235e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
236e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		B43_WARN_ON(key_idx >= dev->max_nr_keys);
237e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		key = &(dev->key[key_idx]);
238e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		B43_WARN_ON(!key->keyconf);
239e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
240e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		/* Hardware appends ICV. */
241e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		plcp_fragment_len += txctl->icv_len;
242e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
243e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		key_idx = b43_kidx_to_fw(dev, key_idx);
244e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		mac_ctl |= (key_idx << B43_TX4_MAC_KEYIDX_SHIFT) &
245e4d6b7951812d98417feb10784e400e253caf633Michael Buesch			   B43_TX4_MAC_KEYIDX;
246e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		mac_ctl |= (key->algorithm << B43_TX4_MAC_KEYALG_SHIFT) &
247e4d6b7951812d98417feb10784e400e253caf633Michael Buesch			   B43_TX4_MAC_KEYALG;
248e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		wlhdr_len = ieee80211_get_hdrlen(fctl);
249e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		iv_len = min((size_t) txctl->iv_len,
250e4d6b7951812d98417feb10784e400e253caf633Michael Buesch			     ARRAY_SIZE(txhdr->iv));
251e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len);
252e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	}
253e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->plcp),
254e4d6b7951812d98417feb10784e400e253caf633Michael Buesch			      plcp_fragment_len, rate);
255e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->plcp_fb),
256e4d6b7951812d98417feb10784e400e253caf633Michael Buesch			      plcp_fragment_len, rate_fb);
257e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
258e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	/* Extra Frame Types */
259e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	if (rate_fb_ofdm)
260e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		extra_ft |= B43_TX4_EFT_FBOFDM;
261e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
262e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	/* Set channel radio code. Note that the micrcode ORs 0x100 to
263e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	 * this value before comparing it to the value in SHM, if this
264e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	 * is a 5Ghz packet.
265e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	 */
266e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	txhdr->chan_radio_code = phy->channel;
267e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
268e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	/* PHY TX Control word */
269e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	if (rate_ofdm)
270e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		phy_ctl |= B43_TX4_PHY_OFDM;
271e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	if (dev->short_preamble)
272e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		phy_ctl |= B43_TX4_PHY_SHORTPRMBL;
273e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	switch (txctl->antenna_sel_tx) {
274e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	case 0:
275e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		phy_ctl |= B43_TX4_PHY_ANTLAST;
276e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		break;
277e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	case 1:
278e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		phy_ctl |= B43_TX4_PHY_ANT0;
279e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		break;
280e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	case 2:
281e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		phy_ctl |= B43_TX4_PHY_ANT1;
282e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		break;
283e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	default:
284e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		B43_WARN_ON(1);
285e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	}
286e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
287e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	/* MAC control */
288e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	if (!(txctl->flags & IEEE80211_TXCTL_NO_ACK))
289e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		mac_ctl |= B43_TX4_MAC_ACK;
290e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	if (!(((fctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) &&
291e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	      ((fctl & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)))
292e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		mac_ctl |= B43_TX4_MAC_HWSEQ;
293e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	if (txctl->flags & IEEE80211_TXCTL_FIRST_FRAGMENT)
294e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		mac_ctl |= B43_TX4_MAC_STMSDU;
295e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	if (phy->type == B43_PHYTYPE_A)
296e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		mac_ctl |= B43_TX4_MAC_5GHZ;
297e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
298e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	/* Generate the RTS or CTS-to-self frame */
299e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	if ((txctl->flags & IEEE80211_TXCTL_USE_RTS_CTS) ||
300e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	    (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) {
301e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		unsigned int len;
302e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		struct ieee80211_hdr *hdr;
303e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		int rts_rate, rts_rate_fb;
304e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		int rts_rate_ofdm, rts_rate_fb_ofdm;
305e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
306e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		rts_rate = txctl->rts_cts_rate;
307e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		rts_rate_ofdm = b43_is_ofdm_rate(rts_rate);
308e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		rts_rate_fb = b43_calc_fallback_rate(rts_rate);
309e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		rts_rate_fb_ofdm = b43_is_ofdm_rate(rts_rate_fb);
310e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
311e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		if (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) {
312e4d6b7951812d98417feb10784e400e253caf633Michael Buesch			ieee80211_ctstoself_get(dev->wl->hw, dev->wl->if_id,
313e4d6b7951812d98417feb10784e400e253caf633Michael Buesch						fragment_data, fragment_len,
314e4d6b7951812d98417feb10784e400e253caf633Michael Buesch						txctl,
315e4d6b7951812d98417feb10784e400e253caf633Michael Buesch						(struct ieee80211_cts *)(txhdr->
316e4d6b7951812d98417feb10784e400e253caf633Michael Buesch									 rts_frame));
317e4d6b7951812d98417feb10784e400e253caf633Michael Buesch			mac_ctl |= B43_TX4_MAC_SENDCTS;
318e4d6b7951812d98417feb10784e400e253caf633Michael Buesch			len = sizeof(struct ieee80211_cts);
319e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		} else {
320e4d6b7951812d98417feb10784e400e253caf633Michael Buesch			ieee80211_rts_get(dev->wl->hw, dev->wl->if_id,
321e4d6b7951812d98417feb10784e400e253caf633Michael Buesch					  fragment_data, fragment_len, txctl,
322e4d6b7951812d98417feb10784e400e253caf633Michael Buesch					  (struct ieee80211_rts *)(txhdr->
323e4d6b7951812d98417feb10784e400e253caf633Michael Buesch								   rts_frame));
324e4d6b7951812d98417feb10784e400e253caf633Michael Buesch			mac_ctl |= B43_TX4_MAC_SENDRTS;
325e4d6b7951812d98417feb10784e400e253caf633Michael Buesch			len = sizeof(struct ieee80211_rts);
326e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		}
327e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		len += FCS_LEN;
328e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->
329e4d6b7951812d98417feb10784e400e253caf633Michael Buesch							       rts_plcp), len,
330e4d6b7951812d98417feb10784e400e253caf633Michael Buesch				      rts_rate);
331e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->
332e4d6b7951812d98417feb10784e400e253caf633Michael Buesch							       rts_plcp_fb),
333e4d6b7951812d98417feb10784e400e253caf633Michael Buesch				      len, rts_rate_fb);
334e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		hdr = (struct ieee80211_hdr *)(&txhdr->rts_frame);
335e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		txhdr->rts_dur_fb = hdr->duration_id;
336e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		if (rts_rate_ofdm) {
337e4d6b7951812d98417feb10784e400e253caf633Michael Buesch			extra_ft |= B43_TX4_EFT_RTSOFDM;
338e4d6b7951812d98417feb10784e400e253caf633Michael Buesch			txhdr->phy_rate_rts =
339e4d6b7951812d98417feb10784e400e253caf633Michael Buesch			    b43_plcp_get_ratecode_ofdm(rts_rate);
340e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		} else
341e4d6b7951812d98417feb10784e400e253caf633Michael Buesch			txhdr->phy_rate_rts =
342e4d6b7951812d98417feb10784e400e253caf633Michael Buesch			    b43_plcp_get_ratecode_cck(rts_rate);
343e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		if (rts_rate_fb_ofdm)
344e4d6b7951812d98417feb10784e400e253caf633Michael Buesch			extra_ft |= B43_TX4_EFT_RTSFBOFDM;
345e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		mac_ctl |= B43_TX4_MAC_LONGFRAME;
346e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	}
347e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
348e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	/* Magic cookie */
349e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	txhdr->cookie = cpu_to_le16(cookie);
350e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
351e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	/* Apply the bitfields */
352e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	txhdr->mac_ctl = cpu_to_le32(mac_ctl);
353e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	txhdr->phy_ctl = cpu_to_le16(phy_ctl);
354e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	txhdr->extra_ft = extra_ft;
355e4d6b7951812d98417feb10784e400e253caf633Michael Buesch}
356e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
357e4d6b7951812d98417feb10784e400e253caf633Michael Bueschvoid b43_generate_txhdr(struct b43_wldev *dev,
358e4d6b7951812d98417feb10784e400e253caf633Michael Buesch			u8 * txhdr,
359e4d6b7951812d98417feb10784e400e253caf633Michael Buesch			const unsigned char *fragment_data,
360e4d6b7951812d98417feb10784e400e253caf633Michael Buesch			unsigned int fragment_len,
361e4d6b7951812d98417feb10784e400e253caf633Michael Buesch			const struct ieee80211_tx_control *txctl, u16 cookie)
362e4d6b7951812d98417feb10784e400e253caf633Michael Buesch{
363e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	generate_txhdr_fw4(dev, (struct b43_txhdr_fw4 *)txhdr,
364e4d6b7951812d98417feb10784e400e253caf633Michael Buesch			   fragment_data, fragment_len, txctl, cookie);
365e4d6b7951812d98417feb10784e400e253caf633Michael Buesch}
366e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
367e4d6b7951812d98417feb10784e400e253caf633Michael Bueschstatic s8 b43_rssi_postprocess(struct b43_wldev *dev,
368e4d6b7951812d98417feb10784e400e253caf633Michael Buesch			       u8 in_rssi, int ofdm,
369e4d6b7951812d98417feb10784e400e253caf633Michael Buesch			       int adjust_2053, int adjust_2050)
370e4d6b7951812d98417feb10784e400e253caf633Michael Buesch{
371e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	struct b43_phy *phy = &dev->phy;
372e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	s32 tmp;
373e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
374e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	switch (phy->radio_ver) {
375e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	case 0x2050:
376e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		if (ofdm) {
377e4d6b7951812d98417feb10784e400e253caf633Michael Buesch			tmp = in_rssi;
378e4d6b7951812d98417feb10784e400e253caf633Michael Buesch			if (tmp > 127)
379e4d6b7951812d98417feb10784e400e253caf633Michael Buesch				tmp -= 256;
380e4d6b7951812d98417feb10784e400e253caf633Michael Buesch			tmp *= 73;
381e4d6b7951812d98417feb10784e400e253caf633Michael Buesch			tmp /= 64;
382e4d6b7951812d98417feb10784e400e253caf633Michael Buesch			if (adjust_2050)
383e4d6b7951812d98417feb10784e400e253caf633Michael Buesch				tmp += 25;
384e4d6b7951812d98417feb10784e400e253caf633Michael Buesch			else
385e4d6b7951812d98417feb10784e400e253caf633Michael Buesch				tmp -= 3;
386e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		} else {
387e4d6b7951812d98417feb10784e400e253caf633Michael Buesch			if (dev->dev->bus->sprom.r1.
388e4d6b7951812d98417feb10784e400e253caf633Michael Buesch			    boardflags_lo & B43_BFL_RSSI) {
389e4d6b7951812d98417feb10784e400e253caf633Michael Buesch				if (in_rssi > 63)
390e4d6b7951812d98417feb10784e400e253caf633Michael Buesch					in_rssi = 63;
391e4d6b7951812d98417feb10784e400e253caf633Michael Buesch				tmp = phy->nrssi_lt[in_rssi];
392e4d6b7951812d98417feb10784e400e253caf633Michael Buesch				tmp = 31 - tmp;
393e4d6b7951812d98417feb10784e400e253caf633Michael Buesch				tmp *= -131;
394e4d6b7951812d98417feb10784e400e253caf633Michael Buesch				tmp /= 128;
395e4d6b7951812d98417feb10784e400e253caf633Michael Buesch				tmp -= 57;
396e4d6b7951812d98417feb10784e400e253caf633Michael Buesch			} else {
397e4d6b7951812d98417feb10784e400e253caf633Michael Buesch				tmp = in_rssi;
398e4d6b7951812d98417feb10784e400e253caf633Michael Buesch				tmp = 31 - tmp;
399e4d6b7951812d98417feb10784e400e253caf633Michael Buesch				tmp *= -149;
400e4d6b7951812d98417feb10784e400e253caf633Michael Buesch				tmp /= 128;
401e4d6b7951812d98417feb10784e400e253caf633Michael Buesch				tmp -= 68;
402e4d6b7951812d98417feb10784e400e253caf633Michael Buesch			}
403e4d6b7951812d98417feb10784e400e253caf633Michael Buesch			if (phy->type == B43_PHYTYPE_G && adjust_2050)
404e4d6b7951812d98417feb10784e400e253caf633Michael Buesch				tmp += 25;
405e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		}
406e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		break;
407e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	case 0x2060:
408e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		if (in_rssi > 127)
409e4d6b7951812d98417feb10784e400e253caf633Michael Buesch			tmp = in_rssi - 256;
410e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		else
411e4d6b7951812d98417feb10784e400e253caf633Michael Buesch			tmp = in_rssi;
412e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		break;
413e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	default:
414e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		tmp = in_rssi;
415e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		tmp -= 11;
416e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		tmp *= 103;
417e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		tmp /= 64;
418e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		if (adjust_2053)
419e4d6b7951812d98417feb10784e400e253caf633Michael Buesch			tmp -= 109;
420e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		else
421e4d6b7951812d98417feb10784e400e253caf633Michael Buesch			tmp -= 83;
422e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	}
423e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
424e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	return (s8) tmp;
425e4d6b7951812d98417feb10784e400e253caf633Michael Buesch}
426e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
427e4d6b7951812d98417feb10784e400e253caf633Michael Buesch//TODO
428e4d6b7951812d98417feb10784e400e253caf633Michael Buesch#if 0
429e4d6b7951812d98417feb10784e400e253caf633Michael Bueschstatic s8 b43_rssinoise_postprocess(struct b43_wldev *dev, u8 in_rssi)
430e4d6b7951812d98417feb10784e400e253caf633Michael Buesch{
431e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	struct b43_phy *phy = &dev->phy;
432e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	s8 ret;
433e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
434e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	if (phy->type == B43_PHYTYPE_A) {
435e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		//TODO: Incomplete specs.
436e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		ret = 0;
437e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	} else
438e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		ret = b43_rssi_postprocess(dev, in_rssi, 0, 1, 1);
439e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
440e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	return ret;
441e4d6b7951812d98417feb10784e400e253caf633Michael Buesch}
442e4d6b7951812d98417feb10784e400e253caf633Michael Buesch#endif
443e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
444e4d6b7951812d98417feb10784e400e253caf633Michael Bueschvoid b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
445e4d6b7951812d98417feb10784e400e253caf633Michael Buesch{
446e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	struct ieee80211_rx_status status;
447e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	struct b43_plcp_hdr6 *plcp;
448e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	struct ieee80211_hdr *wlhdr;
449e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	const struct b43_rxhdr_fw4 *rxhdr = _rxhdr;
450e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	u16 fctl;
451e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	u16 phystat0, phystat3, chanstat, mactime;
452e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	u32 macstat;
453e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	u16 chanid;
454e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	u8 jssi;
455e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	int padding;
456e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
457e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	memset(&status, 0, sizeof(status));
458e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
459e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	/* Get metadata about the frame from the header. */
460e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	phystat0 = le16_to_cpu(rxhdr->phy_status0);
461e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	phystat3 = le16_to_cpu(rxhdr->phy_status3);
462e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	jssi = rxhdr->jssi;
463e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	macstat = le32_to_cpu(rxhdr->mac_status);
464e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	mactime = le16_to_cpu(rxhdr->mac_time);
465e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	chanstat = le16_to_cpu(rxhdr->channel);
466e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
467e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	if (macstat & B43_RX_MAC_FCSERR)
468e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		dev->wl->ieee_stats.dot11FCSErrorCount++;
469e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	if (macstat & B43_RX_MAC_DECERR) {
470e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		/* Decryption with the given key failed.
471e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		 * Drop the packet. We also won't be able to decrypt it with
472e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		 * the key in software. */
473e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		goto drop;
474e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	}
475e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
476e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	/* Skip PLCP and padding */
477e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	padding = (macstat & B43_RX_MAC_PADDING) ? 2 : 0;
478e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	if (unlikely(skb->len < (sizeof(struct b43_plcp_hdr6) + padding))) {
479e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		b43dbg(dev->wl, "RX: Packet size underrun (1)\n");
480e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		goto drop;
481e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	}
482e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	plcp = (struct b43_plcp_hdr6 *)(skb->data + padding);
483e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	skb_pull(skb, sizeof(struct b43_plcp_hdr6) + padding);
484e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	/* The skb contains the Wireless Header + payload data now */
485e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	if (unlikely(skb->len < (2 + 2 + 6 /*minimum hdr */  + FCS_LEN))) {
486e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		b43dbg(dev->wl, "RX: Packet size underrun (2)\n");
487e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		goto drop;
488e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	}
489e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	wlhdr = (struct ieee80211_hdr *)(skb->data);
490e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	fctl = le16_to_cpu(wlhdr->frame_control);
491e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	skb_trim(skb, skb->len - FCS_LEN);
492e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
493e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	if (macstat & B43_RX_MAC_DEC) {
494e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		unsigned int keyidx;
495e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		int wlhdr_len;
496e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
497e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		keyidx = ((macstat & B43_RX_MAC_KEYIDX)
498e4d6b7951812d98417feb10784e400e253caf633Michael Buesch			  >> B43_RX_MAC_KEYIDX_SHIFT);
499e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		/* We must adjust the key index here. We want the "physical"
500e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		 * key index, but the ucode passed it slightly different.
501e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		 */
502e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		keyidx = b43_kidx_to_raw(dev, keyidx);
503e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		B43_WARN_ON(keyidx >= dev->max_nr_keys);
504e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
505e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		if (dev->key[keyidx].algorithm != B43_SEC_ALGO_NONE) {
506e4d6b7951812d98417feb10784e400e253caf633Michael Buesch			wlhdr_len = ieee80211_get_hdrlen(fctl);
507e4d6b7951812d98417feb10784e400e253caf633Michael Buesch			if (unlikely(skb->len < (wlhdr_len + 3))) {
508e4d6b7951812d98417feb10784e400e253caf633Michael Buesch				b43dbg(dev->wl,
509e4d6b7951812d98417feb10784e400e253caf633Michael Buesch				       "RX: Packet size underrun (3)\n");
510e4d6b7951812d98417feb10784e400e253caf633Michael Buesch				goto drop;
511e4d6b7951812d98417feb10784e400e253caf633Michael Buesch			}
512e4d6b7951812d98417feb10784e400e253caf633Michael Buesch			status.flag |= RX_FLAG_DECRYPTED;
513e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		}
514e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	}
515e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
516e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	status.ssi = b43_rssi_postprocess(dev, jssi,
517e4d6b7951812d98417feb10784e400e253caf633Michael Buesch					  (phystat0 & B43_RX_PHYST0_OFDM),
518e4d6b7951812d98417feb10784e400e253caf633Michael Buesch					  (phystat0 & B43_RX_PHYST0_GAINCTL),
519e4d6b7951812d98417feb10784e400e253caf633Michael Buesch					  (phystat3 & B43_RX_PHYST3_TRSTATE));
520e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	status.noise = dev->stats.link_noise;
521e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	/* the next line looks wrong, but is what mac80211 wants */
522e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	status.signal = (jssi * 100) / B43_RX_MAX_SSI;
523e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	if (phystat0 & B43_RX_PHYST0_OFDM)
524e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		status.rate = b43_plcp_get_bitrate_ofdm(plcp);
525e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	else
526e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		status.rate = b43_plcp_get_bitrate_cck(plcp);
527e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	status.antenna = !!(phystat0 & B43_RX_PHYST0_ANT);
528e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	status.mactime = mactime;
529e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
530e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	chanid = (chanstat & B43_RX_CHAN_ID) >> B43_RX_CHAN_ID_SHIFT;
531e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	switch (chanstat & B43_RX_CHAN_PHYTYPE) {
532e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	case B43_PHYTYPE_A:
533e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		status.phymode = MODE_IEEE80211A;
534d987160b710c98997015832422a05e18d9f0f925Michael Buesch		B43_WARN_ON(1);
535d987160b710c98997015832422a05e18d9f0f925Michael Buesch		/* FIXME: We don't really know which value the "chanid" contains.
536d987160b710c98997015832422a05e18d9f0f925Michael Buesch		 *        So the following assignment might be wrong. */
537d987160b710c98997015832422a05e18d9f0f925Michael Buesch		status.channel = chanid;
538d987160b710c98997015832422a05e18d9f0f925Michael Buesch		status.freq = b43_channel_to_freq_5ghz(status.channel);
539e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		break;
540e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	case B43_PHYTYPE_G:
541e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		status.phymode = MODE_IEEE80211G;
542d987160b710c98997015832422a05e18d9f0f925Michael Buesch		/* chanid is the radio channel cookie value as used
543d987160b710c98997015832422a05e18d9f0f925Michael Buesch		 * to tune the radio. */
544e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		status.freq = chanid + 2400;
545d987160b710c98997015832422a05e18d9f0f925Michael Buesch		status.channel = b43_freq_to_channel_2ghz(status.freq);
546d987160b710c98997015832422a05e18d9f0f925Michael Buesch		break;
547d987160b710c98997015832422a05e18d9f0f925Michael Buesch	case B43_PHYTYPE_N:
548d987160b710c98997015832422a05e18d9f0f925Michael Buesch		status.phymode = 0xDEAD /*FIXME MODE_IEEE80211N*/;
549d987160b710c98997015832422a05e18d9f0f925Michael Buesch		/* chanid is the SHM channel cookie. Which is the plain
550d987160b710c98997015832422a05e18d9f0f925Michael Buesch		 * channel number in b43. */
551d987160b710c98997015832422a05e18d9f0f925Michael Buesch		status.channel = chanid;
552d987160b710c98997015832422a05e18d9f0f925Michael Buesch		if (chanstat & B43_RX_CHAN_5GHZ)
553d987160b710c98997015832422a05e18d9f0f925Michael Buesch			status.freq = b43_freq_to_channel_5ghz(status.freq);
554d987160b710c98997015832422a05e18d9f0f925Michael Buesch		else
555d987160b710c98997015832422a05e18d9f0f925Michael Buesch			status.freq = b43_freq_to_channel_2ghz(status.freq);
556e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		break;
557e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	default:
558e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		B43_WARN_ON(1);
559d987160b710c98997015832422a05e18d9f0f925Michael Buesch		goto drop;
560e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	}
561e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
562e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	dev->stats.last_rx = jiffies;
563e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	ieee80211_rx_irqsafe(dev->wl->hw, skb, &status);
564e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
565e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	return;
566e4d6b7951812d98417feb10784e400e253caf633Michael Bueschdrop:
567e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	b43dbg(dev->wl, "RX: Packet dropped\n");
568e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	dev_kfree_skb_any(skb);
569e4d6b7951812d98417feb10784e400e253caf633Michael Buesch}
570e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
571e4d6b7951812d98417feb10784e400e253caf633Michael Bueschvoid b43_handle_txstatus(struct b43_wldev *dev,
572e4d6b7951812d98417feb10784e400e253caf633Michael Buesch			 const struct b43_txstatus *status)
573e4d6b7951812d98417feb10784e400e253caf633Michael Buesch{
574e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	b43_debugfs_log_txstat(dev, status);
575e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
576e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	if (status->intermediate)
577e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		return;
578e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	if (status->for_ampdu)
579e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		return;
580e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	if (!status->acked)
581e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		dev->wl->ieee_stats.dot11ACKFailureCount++;
582e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	if (status->rts_count) {
583e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		if (status->rts_count == 0xF)	//FIXME
584e4d6b7951812d98417feb10784e400e253caf633Michael Buesch			dev->wl->ieee_stats.dot11RTSFailureCount++;
585e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		else
586e4d6b7951812d98417feb10784e400e253caf633Michael Buesch			dev->wl->ieee_stats.dot11RTSSuccessCount++;
587e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	}
588e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
589e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	if (b43_using_pio(dev))
590e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		b43_pio_handle_txstatus(dev, status);
591e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	else
592e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		b43_dma_handle_txstatus(dev, status);
593e4d6b7951812d98417feb10784e400e253caf633Michael Buesch}
594e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
595e4d6b7951812d98417feb10784e400e253caf633Michael Buesch/* Handle TX status report as received through DMA/PIO queues */
596e4d6b7951812d98417feb10784e400e253caf633Michael Bueschvoid b43_handle_hwtxstatus(struct b43_wldev *dev,
597e4d6b7951812d98417feb10784e400e253caf633Michael Buesch			   const struct b43_hwtxstatus *hw)
598e4d6b7951812d98417feb10784e400e253caf633Michael Buesch{
599e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	struct b43_txstatus status;
600e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	u8 tmp;
601e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
602e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	status.cookie = le16_to_cpu(hw->cookie);
603e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	status.seq = le16_to_cpu(hw->seq);
604e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	status.phy_stat = hw->phy_stat;
605e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	tmp = hw->count;
606e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	status.frame_count = (tmp >> 4);
607e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	status.rts_count = (tmp & 0x0F);
608e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	tmp = hw->flags;
609e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	status.supp_reason = ((tmp & 0x1C) >> 2);
610e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	status.pm_indicated = !!(tmp & 0x80);
611e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	status.intermediate = !!(tmp & 0x40);
612e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	status.for_ampdu = !!(tmp & 0x20);
613e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	status.acked = !!(tmp & 0x02);
614e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
615e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	b43_handle_txstatus(dev, &status);
616e4d6b7951812d98417feb10784e400e253caf633Michael Buesch}
617e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
618e4d6b7951812d98417feb10784e400e253caf633Michael Buesch/* Stop any TX operation on the device (suspend the hardware queues) */
619e4d6b7951812d98417feb10784e400e253caf633Michael Bueschvoid b43_tx_suspend(struct b43_wldev *dev)
620e4d6b7951812d98417feb10784e400e253caf633Michael Buesch{
621e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	if (b43_using_pio(dev))
622e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		b43_pio_freeze_txqueues(dev);
623e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	else
624e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		b43_dma_tx_suspend(dev);
625e4d6b7951812d98417feb10784e400e253caf633Michael Buesch}
626e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
627e4d6b7951812d98417feb10784e400e253caf633Michael Buesch/* Resume any TX operation on the device (resume the hardware queues) */
628e4d6b7951812d98417feb10784e400e253caf633Michael Bueschvoid b43_tx_resume(struct b43_wldev *dev)
629e4d6b7951812d98417feb10784e400e253caf633Michael Buesch{
630e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	if (b43_using_pio(dev))
631e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		b43_pio_thaw_txqueues(dev);
632e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	else
633e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		b43_dma_tx_resume(dev);
634e4d6b7951812d98417feb10784e400e253caf633Michael Buesch}
635e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
636e4d6b7951812d98417feb10784e400e253caf633Michael Buesch#if 0
637e4d6b7951812d98417feb10784e400e253caf633Michael Bueschstatic void upload_qos_parms(struct b43_wldev *dev,
638e4d6b7951812d98417feb10784e400e253caf633Michael Buesch			     const u16 * parms, u16 offset)
639e4d6b7951812d98417feb10784e400e253caf633Michael Buesch{
640e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	int i;
641e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
642e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	for (i = 0; i < B43_NR_QOSPARMS; i++) {
643e4d6b7951812d98417feb10784e400e253caf633Michael Buesch		b43_shm_write16(dev, B43_SHM_SHARED,
644e4d6b7951812d98417feb10784e400e253caf633Michael Buesch				offset + (i * 2), parms[i]);
645e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	}
646e4d6b7951812d98417feb10784e400e253caf633Michael Buesch}
647e4d6b7951812d98417feb10784e400e253caf633Michael Buesch#endif
648e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
649e4d6b7951812d98417feb10784e400e253caf633Michael Buesch/* Initialize the QoS parameters */
650e4d6b7951812d98417feb10784e400e253caf633Michael Bueschvoid b43_qos_init(struct b43_wldev *dev)
651e4d6b7951812d98417feb10784e400e253caf633Michael Buesch{
652e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	/* FIXME: This function must probably be called from the mac80211
653e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	 * config callback. */
654e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	return;
655e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
656e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	b43_hf_write(dev, b43_hf_read(dev) | B43_HF_EDCF);
657e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	//FIXME kill magic
658e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	b43_write16(dev, 0x688, b43_read16(dev, 0x688) | 0x4);
659e4d6b7951812d98417feb10784e400e253caf633Michael Buesch
660e4d6b7951812d98417feb10784e400e253caf633Michael Buesch	/*TODO: We might need some stack support here to get the values. */
661e4d6b7951812d98417feb10784e400e253caf633Michael Buesch}
662