xmit.c revision 0a6e1bee5770a6d4c4569a4720614402ab5f9d7a
175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger/*
275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger  Broadcom B43legacy wireless driver
475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger  Transmission (TX/RX) related functions.
675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger  Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger  Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger  Copyright (C) 2005, 2006 Michael Buesch <mb@bu3sch.de>
1075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger  Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
1175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger  Copyright (C) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
1275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger  Copyright (C) 2007 Larry Finger <Larry.Finger@lwfinger.net>
1375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
1475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger  This program is free software; you can redistribute it and/or modify
1575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger  it under the terms of the GNU General Public License as published by
1675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger  the Free Software Foundation; either version 2 of the License, or
1775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger  (at your option) any later version.
1875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
1975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger  This program is distributed in the hope that it will be useful,
2075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger  but WITHOUT ANY WARRANTY; without even the implied warranty of
2175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
2275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger  GNU General Public License for more details.
2375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
2475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger  You should have received a copy of the GNU General Public License
2575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger  along with this program; see the file COPYING.  If not, write to
2675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
2775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger  Boston, MA 02110-1301, USA.
2875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
2975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger*/
3075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
3175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger#include <net/dst.h>
3275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
3375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger#include "xmit.h"
3475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger#include "phy.h"
3575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger#include "dma.h"
3675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger#include "pio.h"
3775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
3875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
3975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger/* Extract the bitrate out of a CCK PLCP header. */
4075388acd0cd827dc1498043daa7d1c760902cd67Larry Fingerstatic u8 b43legacy_plcp_get_bitrate_cck(struct b43legacy_plcp_hdr6 *plcp)
4175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger{
4275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	switch (plcp->raw[0]) {
4375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	case 0x0A:
4475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		return B43legacy_CCK_RATE_1MB;
4575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	case 0x14:
4675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		return B43legacy_CCK_RATE_2MB;
4775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	case 0x37:
4875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		return B43legacy_CCK_RATE_5MB;
4975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	case 0x6E:
5075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		return B43legacy_CCK_RATE_11MB;
5175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	}
5275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	B43legacy_BUG_ON(1);
5375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	return 0;
5475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger}
5575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
5675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger/* Extract the bitrate out of an OFDM PLCP header. */
5775388acd0cd827dc1498043daa7d1c760902cd67Larry Fingerstatic u8 b43legacy_plcp_get_bitrate_ofdm(struct b43legacy_plcp_hdr6 *plcp)
5875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger{
5975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	switch (plcp->raw[0] & 0xF) {
6075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	case 0xB:
6175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		return B43legacy_OFDM_RATE_6MB;
6275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	case 0xF:
6375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		return B43legacy_OFDM_RATE_9MB;
6475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	case 0xA:
6575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		return B43legacy_OFDM_RATE_12MB;
6675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	case 0xE:
6775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		return B43legacy_OFDM_RATE_18MB;
6875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	case 0x9:
6975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		return B43legacy_OFDM_RATE_24MB;
7075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	case 0xD:
7175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		return B43legacy_OFDM_RATE_36MB;
7275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	case 0x8:
7375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		return B43legacy_OFDM_RATE_48MB;
7475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	case 0xC:
7575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		return B43legacy_OFDM_RATE_54MB;
7675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	}
7775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	B43legacy_BUG_ON(1);
7875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	return 0;
7975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger}
8075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
8175388acd0cd827dc1498043daa7d1c760902cd67Larry Fingeru8 b43legacy_plcp_get_ratecode_cck(const u8 bitrate)
8275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger{
8375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	switch (bitrate) {
8475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	case B43legacy_CCK_RATE_1MB:
8575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		return 0x0A;
8675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	case B43legacy_CCK_RATE_2MB:
8775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		return 0x14;
8875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	case B43legacy_CCK_RATE_5MB:
8975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		return 0x37;
9075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	case B43legacy_CCK_RATE_11MB:
9175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		return 0x6E;
9275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	}
9375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	B43legacy_BUG_ON(1);
9475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	return 0;
9575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger}
9675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
9775388acd0cd827dc1498043daa7d1c760902cd67Larry Fingeru8 b43legacy_plcp_get_ratecode_ofdm(const u8 bitrate)
9875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger{
9975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	switch (bitrate) {
10075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	case B43legacy_OFDM_RATE_6MB:
10175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		return 0xB;
10275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	case B43legacy_OFDM_RATE_9MB:
10375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		return 0xF;
10475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	case B43legacy_OFDM_RATE_12MB:
10575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		return 0xA;
10675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	case B43legacy_OFDM_RATE_18MB:
10775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		return 0xE;
10875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	case B43legacy_OFDM_RATE_24MB:
10975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		return 0x9;
11075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	case B43legacy_OFDM_RATE_36MB:
11175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		return 0xD;
11275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	case B43legacy_OFDM_RATE_48MB:
11375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		return 0x8;
11475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	case B43legacy_OFDM_RATE_54MB:
11575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		return 0xC;
11675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	}
11775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	B43legacy_BUG_ON(1);
11875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	return 0;
11975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger}
12075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
12175388acd0cd827dc1498043daa7d1c760902cd67Larry Fingervoid b43legacy_generate_plcp_hdr(struct b43legacy_plcp_hdr4 *plcp,
12275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger				 const u16 octets, const u8 bitrate)
12375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger{
12475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	__le32 *data = &(plcp->data);
12575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	__u8 *raw = plcp->raw;
12675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
12775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	if (b43legacy_is_ofdm_rate(bitrate)) {
12875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		u16 d;
12975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
13075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		d = b43legacy_plcp_get_ratecode_ofdm(bitrate);
13175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		B43legacy_WARN_ON(octets & 0xF000);
13275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		d |= (octets << 5);
13375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		*data = cpu_to_le32(d);
13475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	} else {
13575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		u32 plen;
13675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
13775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		plen = octets * 16 / bitrate;
13875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		if ((octets * 16 % bitrate) > 0) {
13975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			plen++;
14075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			if ((bitrate == B43legacy_CCK_RATE_11MB)
14175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			    && ((octets * 8 % 11) < 4))
14275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger				raw[1] = 0x84;
14375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			else
14475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger				raw[1] = 0x04;
14575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		} else
14675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			raw[1] = 0x04;
14775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		*data |= cpu_to_le32(plen << 16);
14875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		raw[0] = b43legacy_plcp_get_ratecode_cck(bitrate);
14975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	}
15075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger}
15175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
15275388acd0cd827dc1498043daa7d1c760902cd67Larry Fingerstatic u8 b43legacy_calc_fallback_rate(u8 bitrate)
15375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger{
15475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	switch (bitrate) {
15575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	case B43legacy_CCK_RATE_1MB:
15675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		return B43legacy_CCK_RATE_1MB;
15775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	case B43legacy_CCK_RATE_2MB:
15875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		return B43legacy_CCK_RATE_1MB;
15975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	case B43legacy_CCK_RATE_5MB:
16075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		return B43legacy_CCK_RATE_2MB;
16175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	case B43legacy_CCK_RATE_11MB:
16275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		return B43legacy_CCK_RATE_5MB;
16375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	case B43legacy_OFDM_RATE_6MB:
16475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		return B43legacy_CCK_RATE_5MB;
16575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	case B43legacy_OFDM_RATE_9MB:
16675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		return B43legacy_OFDM_RATE_6MB;
16775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	case B43legacy_OFDM_RATE_12MB:
16875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		return B43legacy_OFDM_RATE_9MB;
16975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	case B43legacy_OFDM_RATE_18MB:
17075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		return B43legacy_OFDM_RATE_12MB;
17175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	case B43legacy_OFDM_RATE_24MB:
17275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		return B43legacy_OFDM_RATE_18MB;
17375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	case B43legacy_OFDM_RATE_36MB:
17475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		return B43legacy_OFDM_RATE_24MB;
17575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	case B43legacy_OFDM_RATE_48MB:
17675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		return B43legacy_OFDM_RATE_36MB;
17775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	case B43legacy_OFDM_RATE_54MB:
17875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		return B43legacy_OFDM_RATE_48MB;
17975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	}
18075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	B43legacy_BUG_ON(1);
18175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	return 0;
18275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger}
18375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
18475388acd0cd827dc1498043daa7d1c760902cd67Larry Fingerstatic void generate_txhdr_fw3(struct b43legacy_wldev *dev,
18575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			       struct b43legacy_txhdr_fw3 *txhdr,
18675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			       const unsigned char *fragment_data,
18775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			       unsigned int fragment_len,
18875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			       const struct ieee80211_tx_control *txctl,
18975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			       u16 cookie)
19075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger{
19175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	const struct ieee80211_hdr *wlhdr;
19275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	int use_encryption = (!(txctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT));
19375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	u16 fctl;
19475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	u8 rate;
19575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	u8 rate_fb;
19675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	int rate_ofdm;
19775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	int rate_fb_ofdm;
19875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	unsigned int plcp_fragment_len;
19975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	u32 mac_ctl = 0;
20075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	u16 phy_ctl = 0;
20175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
20275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	wlhdr = (const struct ieee80211_hdr *)fragment_data;
20375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	fctl = le16_to_cpu(wlhdr->frame_control);
20475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
20575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	memset(txhdr, 0, sizeof(*txhdr));
20675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
20775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	rate = txctl->tx_rate;
20875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	rate_ofdm = b43legacy_is_ofdm_rate(rate);
20975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	rate_fb = (txctl->alt_retry_rate == -1) ? rate : txctl->alt_retry_rate;
21075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	rate_fb_ofdm = b43legacy_is_ofdm_rate(rate_fb);
21175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
21275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	txhdr->mac_frame_ctl = wlhdr->frame_control;
21375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	memcpy(txhdr->tx_receiver, wlhdr->addr1, 6);
21475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
21575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	/* Calculate duration for fallback rate */
21675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	if ((rate_fb == rate) ||
21775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	    (wlhdr->duration_id & cpu_to_le16(0x8000)) ||
21875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	    (wlhdr->duration_id == cpu_to_le16(0))) {
21975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		/* If the fallback rate equals the normal rate or the
22075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		 * dur_id field contains an AID, CFP magic or 0,
22175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		 * use the original dur_id field. */
22275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		txhdr->dur_fb = wlhdr->duration_id;
22375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	} else {
22475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		int fbrate_base100kbps = B43legacy_RATE_TO_100KBPS(rate_fb);
22575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		txhdr->dur_fb = ieee80211_generic_frame_duration(dev->wl->hw,
22675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger							 dev->wl->if_id,
22775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger							 fragment_len,
22875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger							 fbrate_base100kbps);
22975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	}
23075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
23175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	plcp_fragment_len = fragment_len + FCS_LEN;
23275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	if (use_encryption) {
23375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		u8 key_idx = (u16)(txctl->key_idx);
23475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		struct b43legacy_key *key;
23575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		int wlhdr_len;
23675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		size_t iv_len;
23775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
23875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		B43legacy_WARN_ON(key_idx >= dev->max_nr_keys);
23975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		key = &(dev->key[key_idx]);
24075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
24175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		if (key->enabled) {
24275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			/* Hardware appends ICV. */
24375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			plcp_fragment_len += txctl->icv_len;
24475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
24575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			key_idx = b43legacy_kidx_to_fw(dev, key_idx);
24675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			mac_ctl |= (key_idx << B43legacy_TX4_MAC_KEYIDX_SHIFT) &
24775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger				   B43legacy_TX4_MAC_KEYIDX;
24875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			mac_ctl |= (key->algorithm <<
24975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger				   B43legacy_TX4_MAC_KEYALG_SHIFT) &
25075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger				   B43legacy_TX4_MAC_KEYALG;
25175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			wlhdr_len = ieee80211_get_hdrlen(fctl);
25275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			iv_len = min((size_t)txctl->iv_len,
25375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger				     ARRAY_SIZE(txhdr->iv));
25475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			memcpy(txhdr->iv, ((u8 *)wlhdr) + wlhdr_len, iv_len);
25575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		}
25675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	}
25775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	b43legacy_generate_plcp_hdr((struct b43legacy_plcp_hdr4 *)
25875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger				    (&txhdr->plcp), plcp_fragment_len,
25975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger				    rate);
26075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	b43legacy_generate_plcp_hdr((struct b43legacy_plcp_hdr4 *)
26175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger				    (&txhdr->plcp_fb), plcp_fragment_len,
26275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger				    rate_fb);
26375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
26475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	/* PHY TX Control word */
26575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	if (rate_ofdm)
26675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		phy_ctl |= B43legacy_TX4_PHY_OFDM;
26775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	if (dev->short_preamble)
26875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		phy_ctl |= B43legacy_TX4_PHY_SHORTPRMBL;
26975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	switch (txctl->antenna_sel_tx) {
27075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	case 0:
27175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		phy_ctl |= B43legacy_TX4_PHY_ANTLAST;
27275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		break;
27375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	case 1:
27475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		phy_ctl |= B43legacy_TX4_PHY_ANT0;
27575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		break;
27675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	case 2:
27775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		phy_ctl |= B43legacy_TX4_PHY_ANT1;
27875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		break;
27975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	default:
28075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		B43legacy_BUG_ON(1);
28175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	}
28275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
28375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	/* MAC control */
28475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	if (!(txctl->flags & IEEE80211_TXCTL_NO_ACK))
28575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		mac_ctl |= B43legacy_TX4_MAC_ACK;
28675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	if (!(((fctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) &&
28775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	      ((fctl & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)))
28875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		mac_ctl |= B43legacy_TX4_MAC_HWSEQ;
28975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	if (txctl->flags & IEEE80211_TXCTL_FIRST_FRAGMENT)
29075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		mac_ctl |= B43legacy_TX4_MAC_STMSDU;
29175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	if (rate_fb_ofdm)
29275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		mac_ctl |= B43legacy_TX4_MAC_FALLBACKOFDM;
2930a6e1bee5770a6d4c4569a4720614402ab5f9d7aStefano Brivio	if (txctl->flags & IEEE80211_TXCTL_LONG_RETRY_LIMIT)
2940a6e1bee5770a6d4c4569a4720614402ab5f9d7aStefano Brivio		mac_ctl |= B43legacy_TX4_MAC_LONGFRAME;
29575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
29675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	/* Generate the RTS or CTS-to-self frame */
29775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	if ((txctl->flags & IEEE80211_TXCTL_USE_RTS_CTS) ||
29875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	    (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) {
29975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		unsigned int len;
30075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		struct ieee80211_hdr *hdr;
30175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		int rts_rate;
30275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		int rts_rate_fb;
30375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		int rts_rate_ofdm;
30475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		int rts_rate_fb_ofdm;
30575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
30675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		rts_rate = txctl->rts_cts_rate;
30775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		rts_rate_ofdm = b43legacy_is_ofdm_rate(rts_rate);
30875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		rts_rate_fb = b43legacy_calc_fallback_rate(rts_rate);
30975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		rts_rate_fb_ofdm = b43legacy_is_ofdm_rate(rts_rate_fb);
31075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		if (rts_rate_fb_ofdm)
31175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			mac_ctl |= B43legacy_TX4_MAC_CTSFALLBACKOFDM;
31275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
31375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		if (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) {
31475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			ieee80211_ctstoself_get(dev->wl->hw,
31575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger						dev->wl->if_id,
31675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger						fragment_data,
31775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger						fragment_len, txctl,
31875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger						(struct ieee80211_cts *)
31975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger						(txhdr->rts_frame));
32075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			mac_ctl |= B43legacy_TX4_MAC_SENDCTS;
32175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			len = sizeof(struct ieee80211_cts);
32275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		} else {
32375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			ieee80211_rts_get(dev->wl->hw,
32475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger					  dev->wl->if_id,
32575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger					  fragment_data, fragment_len, txctl,
32675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger					  (struct ieee80211_rts *)
32775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger					  (txhdr->rts_frame));
32875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			mac_ctl |= B43legacy_TX4_MAC_SENDRTS;
32975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			len = sizeof(struct ieee80211_rts);
33075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		}
33175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		len += FCS_LEN;
33275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		b43legacy_generate_plcp_hdr((struct b43legacy_plcp_hdr4 *)
33375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger					    (&txhdr->rts_plcp),
33475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger					    len, rts_rate);
33575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		b43legacy_generate_plcp_hdr((struct b43legacy_plcp_hdr4 *)
33675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger					    (&txhdr->rts_plcp_fb),
33775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger					    len, rts_rate_fb);
33875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		hdr = (struct ieee80211_hdr *)(&txhdr->rts_frame);
33975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		txhdr->rts_dur_fb = hdr->duration_id;
34075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	}
34175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
34275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	/* Magic cookie */
34375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	txhdr->cookie = cpu_to_le16(cookie);
34475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
34575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	/* Apply the bitfields */
34675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	txhdr->mac_ctl = cpu_to_le32(mac_ctl);
34775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	txhdr->phy_ctl = cpu_to_le16(phy_ctl);
34875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger}
34975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
35075388acd0cd827dc1498043daa7d1c760902cd67Larry Fingervoid b43legacy_generate_txhdr(struct b43legacy_wldev *dev,
35175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			      u8 *txhdr,
35275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			      const unsigned char *fragment_data,
35375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			      unsigned int fragment_len,
35475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			      const struct ieee80211_tx_control *txctl,
35575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			      u16 cookie)
35675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger{
35775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	generate_txhdr_fw3(dev, (struct b43legacy_txhdr_fw3 *)txhdr,
35875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			   fragment_data, fragment_len,
35975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			   txctl, cookie);
36075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger}
36175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
36275388acd0cd827dc1498043daa7d1c760902cd67Larry Fingerstatic s8 b43legacy_rssi_postprocess(struct b43legacy_wldev *dev,
36375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger				     u8 in_rssi, int ofdm,
36475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger				     int adjust_2053, int adjust_2050)
36575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger{
36675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	struct b43legacy_phy *phy = &dev->phy;
36775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	s32 tmp;
36875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
36975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	switch (phy->radio_ver) {
37075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	case 0x2050:
37175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		if (ofdm) {
37275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			tmp = in_rssi;
37375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			if (tmp > 127)
37475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger				tmp -= 256;
37575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			tmp *= 73;
37675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			tmp /= 64;
37775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			if (adjust_2050)
37875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger				tmp += 25;
37975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			else
38075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger				tmp -= 3;
38175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		} else {
38275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			if (dev->dev->bus->sprom.r1.boardflags_lo
38375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			    & B43legacy_BFL_RSSI) {
38475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger				if (in_rssi > 63)
38575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger					in_rssi = 63;
38675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger				tmp = phy->nrssi_lt[in_rssi];
38775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger				tmp = 31 - tmp;
38875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger				tmp *= -131;
38975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger				tmp /= 128;
39075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger				tmp -= 57;
39175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			} else {
39275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger				tmp = in_rssi;
39375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger				tmp = 31 - tmp;
39475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger				tmp *= -149;
39575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger				tmp /= 128;
39675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger				tmp -= 68;
39775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			}
39875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			if (phy->type == B43legacy_PHYTYPE_G &&
39975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			    adjust_2050)
40075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger				tmp += 25;
40175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		}
40275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		break;
40375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	case 0x2060:
40475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		if (in_rssi > 127)
40575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			tmp = in_rssi - 256;
40675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		else
40775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			tmp = in_rssi;
40875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		break;
40975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	default:
41075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		tmp = in_rssi;
41175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		tmp -= 11;
41275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		tmp *= 103;
41375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		tmp /= 64;
41475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		if (adjust_2053)
41575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			tmp -= 109;
41675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		else
41775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			tmp -= 83;
41875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	}
41975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
42075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	return (s8)tmp;
42175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger}
42275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
42375388acd0cd827dc1498043daa7d1c760902cd67Larry Fingervoid b43legacy_rx(struct b43legacy_wldev *dev,
42475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		  struct sk_buff *skb,
42575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		  const void *_rxhdr)
42675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger{
42775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	struct ieee80211_rx_status status;
42875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	struct b43legacy_plcp_hdr6 *plcp;
42975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	struct ieee80211_hdr *wlhdr;
43075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	const struct b43legacy_rxhdr_fw3 *rxhdr = _rxhdr;
43175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	u16 fctl;
43275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	u16 phystat0;
43375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	u16 phystat3;
43475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	u16 chanstat;
43575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	u16 mactime;
43675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	u32 macstat;
43775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	u16 chanid;
43875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	u8 jssi;
43975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	int padding;
44075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
44175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	memset(&status, 0, sizeof(status));
44275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
44375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	/* Get metadata about the frame from the header. */
44475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	phystat0 = le16_to_cpu(rxhdr->phy_status0);
44575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	phystat3 = le16_to_cpu(rxhdr->phy_status3);
44675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	jssi = rxhdr->jssi;
44775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	macstat = le16_to_cpu(rxhdr->mac_status);
44875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	mactime = le16_to_cpu(rxhdr->mac_time);
44975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	chanstat = le16_to_cpu(rxhdr->channel);
45075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
45175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	if (macstat & B43legacy_RX_MAC_FCSERR)
45275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		dev->wl->ieee_stats.dot11FCSErrorCount++;
45375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
45475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	/* Skip PLCP and padding */
45575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	padding = (macstat & B43legacy_RX_MAC_PADDING) ? 2 : 0;
45675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	if (unlikely(skb->len < (sizeof(struct b43legacy_plcp_hdr6) +
45775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	    padding))) {
45875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		b43legacydbg(dev->wl, "RX: Packet size underrun (1)\n");
45975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		goto drop;
46075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	}
46175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	plcp = (struct b43legacy_plcp_hdr6 *)(skb->data + padding);
46275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	skb_pull(skb, sizeof(struct b43legacy_plcp_hdr6) + padding);
46375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	/* The skb contains the Wireless Header + payload data now */
46475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	if (unlikely(skb->len < (2+2+6/*minimum hdr*/ + FCS_LEN))) {
46575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		b43legacydbg(dev->wl, "RX: Packet size underrun (2)\n");
46675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		goto drop;
46775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	}
46875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	wlhdr = (struct ieee80211_hdr *)(skb->data);
46975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	fctl = le16_to_cpu(wlhdr->frame_control);
47075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
47175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	if ((macstat & B43legacy_RX_MAC_DEC) &&
47275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	    !(macstat & B43legacy_RX_MAC_DECERR)) {
47375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		unsigned int keyidx;
47475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		int wlhdr_len;
47575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		int iv_len;
47675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		int icv_len;
47775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
47875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		keyidx = ((macstat & B43legacy_RX_MAC_KEYIDX)
47975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			  >> B43legacy_RX_MAC_KEYIDX_SHIFT);
48075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		/* We must adjust the key index here. We want the "physical"
48175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		 * key index, but the ucode passed it slightly different.
48275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		 */
48375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		keyidx = b43legacy_kidx_to_raw(dev, keyidx);
48475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		B43legacy_WARN_ON(keyidx >= dev->max_nr_keys);
48575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
48675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		if (dev->key[keyidx].algorithm != B43legacy_SEC_ALGO_NONE) {
48775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			/* Remove PROTECTED flag to mark it as decrypted. */
48875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			B43legacy_WARN_ON(!(fctl & IEEE80211_FCTL_PROTECTED));
48975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			fctl &= ~IEEE80211_FCTL_PROTECTED;
49075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			wlhdr->frame_control = cpu_to_le16(fctl);
49175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
49275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			wlhdr_len = ieee80211_get_hdrlen(fctl);
49375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			if (unlikely(skb->len < (wlhdr_len + 3))) {
49475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger				b43legacydbg(dev->wl, "RX: Packet size"
49575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger					     " underrun3\n");
49675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger				goto drop;
49775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			}
49875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			if (skb->data[wlhdr_len + 3] & (1 << 5)) {
49975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger				/* The Ext-IV Bit is set in the "KeyID"
50075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger				 * octet of the IV.
50175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger				 */
50275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger				iv_len = 8;
50375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger				icv_len = 8;
50475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			} else {
50575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger				iv_len = 4;
50675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger				icv_len = 4;
50775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			}
50875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			if (unlikely(skb->len < (wlhdr_len + iv_len +
50975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			    icv_len))) {
51075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger				b43legacydbg(dev->wl, "RX: Packet size"
51175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger					     " underrun4\n");
51275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger				goto drop;
51375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			}
51475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			/* Remove the IV */
51575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			memmove(skb->data + iv_len, skb->data, wlhdr_len);
51675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			skb_pull(skb, iv_len);
51775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			/* Remove the ICV */
51875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			skb_trim(skb, skb->len - icv_len);
51975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
52075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			status.flag |= RX_FLAG_DECRYPTED;
52175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		}
52275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	}
52375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
52475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	status.ssi = b43legacy_rssi_postprocess(dev, jssi,
52575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger				      (phystat0 & B43legacy_RX_PHYST0_OFDM),
52675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger				      (phystat0 & B43legacy_RX_PHYST0_GAINCTL),
52775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger				      (phystat3 & B43legacy_RX_PHYST3_TRSTATE));
52875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	status.noise = dev->stats.link_noise;
52975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	status.signal = (jssi * 100) / B43legacy_RX_MAX_SSI;
53075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	if (phystat0 & B43legacy_RX_PHYST0_OFDM)
53175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		status.rate = b43legacy_plcp_get_bitrate_ofdm(plcp);
53275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	else
53375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		status.rate = b43legacy_plcp_get_bitrate_cck(plcp);
53475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	status.antenna = !!(phystat0 & B43legacy_RX_PHYST0_ANT);
53575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	status.mactime = mactime;
53603bffc1341c757e4b15a5a6058ad624e28b4801eJohannes Berg	status.flag |= RX_FLAG_TSFT;
53775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
53875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	chanid = (chanstat & B43legacy_RX_CHAN_ID) >>
53975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		  B43legacy_RX_CHAN_ID_SHIFT;
54075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	switch (chanstat & B43legacy_RX_CHAN_PHYTYPE) {
54175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	case B43legacy_PHYTYPE_B:
54275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		status.phymode = MODE_IEEE80211B;
54375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		status.freq = chanid + 2400;
54475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		status.channel = b43legacy_freq_to_channel_bg(chanid + 2400);
54575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		break;
54675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	case B43legacy_PHYTYPE_G:
54775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		status.phymode = MODE_IEEE80211G;
54875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		status.freq = chanid + 2400;
54975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		status.channel = b43legacy_freq_to_channel_bg(chanid + 2400);
55075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		break;
55175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	default:
55275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		b43legacywarn(dev->wl, "Unexpected value for chanstat (0x%X)\n",
55375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		       chanstat);
55475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	}
55575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
55675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	dev->stats.last_rx = jiffies;
55775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	ieee80211_rx_irqsafe(dev->wl->hw, skb, &status);
55875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
55975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	return;
56075388acd0cd827dc1498043daa7d1c760902cd67Larry Fingerdrop:
56175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	b43legacydbg(dev->wl, "RX: Packet dropped\n");
56275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	dev_kfree_skb_any(skb);
56375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger}
56475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
56575388acd0cd827dc1498043daa7d1c760902cd67Larry Fingervoid b43legacy_handle_txstatus(struct b43legacy_wldev *dev,
56675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			     const struct b43legacy_txstatus *status)
56775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger{
56875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	b43legacy_debugfs_log_txstat(dev, status);
56975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
57075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	if (status->intermediate)
57175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		return;
57275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	if (status->for_ampdu)
57375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		return;
57475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	if (!status->acked)
57575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		dev->wl->ieee_stats.dot11ACKFailureCount++;
57675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	if (status->rts_count) {
57775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		if (status->rts_count == 0xF) /* FIXME */
57875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			dev->wl->ieee_stats.dot11RTSFailureCount++;
57975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		else
58075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			dev->wl->ieee_stats.dot11RTSSuccessCount++;
58175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	}
58275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
58375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	if (b43legacy_using_pio(dev))
58475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		b43legacy_pio_handle_txstatus(dev, status);
58575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	else
58675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		b43legacy_dma_handle_txstatus(dev, status);
58775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger}
58875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
58975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger/* Handle TX status report as received through DMA/PIO queues */
59075388acd0cd827dc1498043daa7d1c760902cd67Larry Fingervoid b43legacy_handle_hwtxstatus(struct b43legacy_wldev *dev,
59175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger				 const struct b43legacy_hwtxstatus *hw)
59275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger{
59375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	struct b43legacy_txstatus status;
59475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	u8 tmp;
59575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
59675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	status.cookie = le16_to_cpu(hw->cookie);
59775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	status.seq = le16_to_cpu(hw->seq);
59875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	status.phy_stat = hw->phy_stat;
59975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	tmp = hw->count;
60075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	status.frame_count = (tmp >> 4);
60175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	status.rts_count = (tmp & 0x0F);
60275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	tmp = hw->flags;
60375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	status.supp_reason = ((tmp & 0x1C) >> 2);
60475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	status.pm_indicated = !!(tmp & 0x80);
60575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	status.intermediate = !!(tmp & 0x40);
60675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	status.for_ampdu = !!(tmp & 0x20);
60775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	status.acked = !!(tmp & 0x02);
60875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
60975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	b43legacy_handle_txstatus(dev, &status);
61075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger}
61175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
61275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger/* Stop any TX operation on the device (suspend the hardware queues) */
61375388acd0cd827dc1498043daa7d1c760902cd67Larry Fingervoid b43legacy_tx_suspend(struct b43legacy_wldev *dev)
61475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger{
61575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	if (b43legacy_using_pio(dev))
61675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		b43legacy_pio_freeze_txqueues(dev);
61775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	else
61875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		b43legacy_dma_tx_suspend(dev);
61975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger}
62075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
62175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger/* Resume any TX operation on the device (resume the hardware queues) */
62275388acd0cd827dc1498043daa7d1c760902cd67Larry Fingervoid b43legacy_tx_resume(struct b43legacy_wldev *dev)
62375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger{
62475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	if (b43legacy_using_pio(dev))
62575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		b43legacy_pio_thaw_txqueues(dev);
62675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	else
62775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		b43legacy_dma_tx_resume(dev);
62875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger}
62975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
63075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger/* Initialize the QoS parameters */
63175388acd0cd827dc1498043daa7d1c760902cd67Larry Fingervoid b43legacy_qos_init(struct b43legacy_wldev *dev)
63275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger{
63375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	/* FIXME: This function must probably be called from the mac80211
63475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	 * config callback. */
63575388acd0cd827dc1498043daa7d1c760902cd67Larry Fingerreturn;
63675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
63775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	b43legacy_hf_write(dev, b43legacy_hf_read(dev) | B43legacy_HF_EDCF);
63875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	/* FIXME kill magic */
63975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	b43legacy_write16(dev, 0x688,
64075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			  b43legacy_read16(dev, 0x688) | 0x4);
64175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
64275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
64375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	/*TODO: We might need some stack support here to get the values. */
64475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger}
645