162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci  Broadcom B43 wireless driver
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci  Transmission (TX/RX) related functions.
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci  Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
962306a36Sopenharmony_ci  Copyright (C) 2005 Stefano Brivio <stefano.brivio@polimi.it>
1062306a36Sopenharmony_ci  Copyright (C) 2005, 2006 Michael Buesch <m@bues.ch>
1162306a36Sopenharmony_ci  Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
1262306a36Sopenharmony_ci  Copyright (C) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci*/
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include "xmit.h"
1862306a36Sopenharmony_ci#include "phy_common.h"
1962306a36Sopenharmony_ci#include "dma.h"
2062306a36Sopenharmony_ci#include "pio.h"
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_cistatic const struct b43_tx_legacy_rate_phy_ctl_entry b43_tx_legacy_rate_phy_ctl[] = {
2362306a36Sopenharmony_ci	{ B43_CCK_RATE_1MB,	0x0,			0x0 },
2462306a36Sopenharmony_ci	{ B43_CCK_RATE_2MB,	0x0,			0x1 },
2562306a36Sopenharmony_ci	{ B43_CCK_RATE_5MB,	0x0,			0x2 },
2662306a36Sopenharmony_ci	{ B43_CCK_RATE_11MB,	0x0,			0x3 },
2762306a36Sopenharmony_ci	{ B43_OFDM_RATE_6MB,	B43_TXH_PHY1_CRATE_1_2,	B43_TXH_PHY1_MODUL_BPSK },
2862306a36Sopenharmony_ci	{ B43_OFDM_RATE_9MB,	B43_TXH_PHY1_CRATE_3_4,	B43_TXH_PHY1_MODUL_BPSK },
2962306a36Sopenharmony_ci	{ B43_OFDM_RATE_12MB,	B43_TXH_PHY1_CRATE_1_2,	B43_TXH_PHY1_MODUL_QPSK },
3062306a36Sopenharmony_ci	{ B43_OFDM_RATE_18MB,	B43_TXH_PHY1_CRATE_3_4,	B43_TXH_PHY1_MODUL_QPSK },
3162306a36Sopenharmony_ci	{ B43_OFDM_RATE_24MB,	B43_TXH_PHY1_CRATE_1_2,	B43_TXH_PHY1_MODUL_QAM16 },
3262306a36Sopenharmony_ci	{ B43_OFDM_RATE_36MB,	B43_TXH_PHY1_CRATE_3_4,	B43_TXH_PHY1_MODUL_QAM16 },
3362306a36Sopenharmony_ci	{ B43_OFDM_RATE_48MB,	B43_TXH_PHY1_CRATE_2_3,	B43_TXH_PHY1_MODUL_QAM64 },
3462306a36Sopenharmony_ci	{ B43_OFDM_RATE_54MB,	B43_TXH_PHY1_CRATE_3_4,	B43_TXH_PHY1_MODUL_QAM64 },
3562306a36Sopenharmony_ci};
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_cistatic const struct b43_tx_legacy_rate_phy_ctl_entry *
3862306a36Sopenharmony_cib43_tx_legacy_rate_phy_ctl_ent(u8 bitrate)
3962306a36Sopenharmony_ci{
4062306a36Sopenharmony_ci	const struct b43_tx_legacy_rate_phy_ctl_entry *e;
4162306a36Sopenharmony_ci	unsigned int i;
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(b43_tx_legacy_rate_phy_ctl); i++) {
4462306a36Sopenharmony_ci		e = &(b43_tx_legacy_rate_phy_ctl[i]);
4562306a36Sopenharmony_ci		if (e->bitrate == bitrate)
4662306a36Sopenharmony_ci			return e;
4762306a36Sopenharmony_ci	}
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	B43_WARN_ON(1);
5062306a36Sopenharmony_ci	return NULL;
5162306a36Sopenharmony_ci}
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci/* Extract the bitrate index out of a CCK PLCP header. */
5462306a36Sopenharmony_cistatic int b43_plcp_get_bitrate_idx_cck(struct b43_plcp_hdr6 *plcp)
5562306a36Sopenharmony_ci{
5662306a36Sopenharmony_ci	switch (plcp->raw[0]) {
5762306a36Sopenharmony_ci	case 0x0A:
5862306a36Sopenharmony_ci		return 0;
5962306a36Sopenharmony_ci	case 0x14:
6062306a36Sopenharmony_ci		return 1;
6162306a36Sopenharmony_ci	case 0x37:
6262306a36Sopenharmony_ci		return 2;
6362306a36Sopenharmony_ci	case 0x6E:
6462306a36Sopenharmony_ci		return 3;
6562306a36Sopenharmony_ci	}
6662306a36Sopenharmony_ci	return -1;
6762306a36Sopenharmony_ci}
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci/* Extract the bitrate index out of an OFDM PLCP header. */
7062306a36Sopenharmony_cistatic int b43_plcp_get_bitrate_idx_ofdm(struct b43_plcp_hdr6 *plcp, bool ghz5)
7162306a36Sopenharmony_ci{
7262306a36Sopenharmony_ci	/* For 2 GHz band first OFDM rate is at index 4, see main.c */
7362306a36Sopenharmony_ci	int base = ghz5 ? 0 : 4;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	switch (plcp->raw[0] & 0xF) {
7662306a36Sopenharmony_ci	case 0xB:
7762306a36Sopenharmony_ci		return base + 0;
7862306a36Sopenharmony_ci	case 0xF:
7962306a36Sopenharmony_ci		return base + 1;
8062306a36Sopenharmony_ci	case 0xA:
8162306a36Sopenharmony_ci		return base + 2;
8262306a36Sopenharmony_ci	case 0xE:
8362306a36Sopenharmony_ci		return base + 3;
8462306a36Sopenharmony_ci	case 0x9:
8562306a36Sopenharmony_ci		return base + 4;
8662306a36Sopenharmony_ci	case 0xD:
8762306a36Sopenharmony_ci		return base + 5;
8862306a36Sopenharmony_ci	case 0x8:
8962306a36Sopenharmony_ci		return base + 6;
9062306a36Sopenharmony_ci	case 0xC:
9162306a36Sopenharmony_ci		return base + 7;
9262306a36Sopenharmony_ci	}
9362306a36Sopenharmony_ci	return -1;
9462306a36Sopenharmony_ci}
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ciu8 b43_plcp_get_ratecode_cck(const u8 bitrate)
9762306a36Sopenharmony_ci{
9862306a36Sopenharmony_ci	switch (bitrate) {
9962306a36Sopenharmony_ci	case B43_CCK_RATE_1MB:
10062306a36Sopenharmony_ci		return 0x0A;
10162306a36Sopenharmony_ci	case B43_CCK_RATE_2MB:
10262306a36Sopenharmony_ci		return 0x14;
10362306a36Sopenharmony_ci	case B43_CCK_RATE_5MB:
10462306a36Sopenharmony_ci		return 0x37;
10562306a36Sopenharmony_ci	case B43_CCK_RATE_11MB:
10662306a36Sopenharmony_ci		return 0x6E;
10762306a36Sopenharmony_ci	}
10862306a36Sopenharmony_ci	B43_WARN_ON(1);
10962306a36Sopenharmony_ci	return 0;
11062306a36Sopenharmony_ci}
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ciu8 b43_plcp_get_ratecode_ofdm(const u8 bitrate)
11362306a36Sopenharmony_ci{
11462306a36Sopenharmony_ci	switch (bitrate) {
11562306a36Sopenharmony_ci	case B43_OFDM_RATE_6MB:
11662306a36Sopenharmony_ci		return 0xB;
11762306a36Sopenharmony_ci	case B43_OFDM_RATE_9MB:
11862306a36Sopenharmony_ci		return 0xF;
11962306a36Sopenharmony_ci	case B43_OFDM_RATE_12MB:
12062306a36Sopenharmony_ci		return 0xA;
12162306a36Sopenharmony_ci	case B43_OFDM_RATE_18MB:
12262306a36Sopenharmony_ci		return 0xE;
12362306a36Sopenharmony_ci	case B43_OFDM_RATE_24MB:
12462306a36Sopenharmony_ci		return 0x9;
12562306a36Sopenharmony_ci	case B43_OFDM_RATE_36MB:
12662306a36Sopenharmony_ci		return 0xD;
12762306a36Sopenharmony_ci	case B43_OFDM_RATE_48MB:
12862306a36Sopenharmony_ci		return 0x8;
12962306a36Sopenharmony_ci	case B43_OFDM_RATE_54MB:
13062306a36Sopenharmony_ci		return 0xC;
13162306a36Sopenharmony_ci	}
13262306a36Sopenharmony_ci	B43_WARN_ON(1);
13362306a36Sopenharmony_ci	return 0;
13462306a36Sopenharmony_ci}
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_civoid b43_generate_plcp_hdr(struct b43_plcp_hdr4 *plcp,
13762306a36Sopenharmony_ci			   const u16 octets, const u8 bitrate)
13862306a36Sopenharmony_ci{
13962306a36Sopenharmony_ci	__u8 *raw = plcp->raw;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	if (b43_is_ofdm_rate(bitrate)) {
14262306a36Sopenharmony_ci		u32 d;
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci		d = b43_plcp_get_ratecode_ofdm(bitrate);
14562306a36Sopenharmony_ci		B43_WARN_ON(octets & 0xF000);
14662306a36Sopenharmony_ci		d |= (octets << 5);
14762306a36Sopenharmony_ci		plcp->data = cpu_to_le32(d);
14862306a36Sopenharmony_ci	} else {
14962306a36Sopenharmony_ci		u32 plen;
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci		plen = octets * 16 / bitrate;
15262306a36Sopenharmony_ci		if ((octets * 16 % bitrate) > 0) {
15362306a36Sopenharmony_ci			plen++;
15462306a36Sopenharmony_ci			if ((bitrate == B43_CCK_RATE_11MB)
15562306a36Sopenharmony_ci			    && ((octets * 8 % 11) < 4)) {
15662306a36Sopenharmony_ci				raw[1] = 0x84;
15762306a36Sopenharmony_ci			} else
15862306a36Sopenharmony_ci				raw[1] = 0x04;
15962306a36Sopenharmony_ci		} else
16062306a36Sopenharmony_ci			raw[1] = 0x04;
16162306a36Sopenharmony_ci		plcp->data |= cpu_to_le32(plen << 16);
16262306a36Sopenharmony_ci		raw[0] = b43_plcp_get_ratecode_cck(bitrate);
16362306a36Sopenharmony_ci	}
16462306a36Sopenharmony_ci}
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci/* TODO: verify if needed for SSLPN or LCN  */
16762306a36Sopenharmony_cistatic u16 b43_generate_tx_phy_ctl1(struct b43_wldev *dev, u8 bitrate)
16862306a36Sopenharmony_ci{
16962306a36Sopenharmony_ci	const struct b43_phy *phy = &dev->phy;
17062306a36Sopenharmony_ci	const struct b43_tx_legacy_rate_phy_ctl_entry *e;
17162306a36Sopenharmony_ci	u16 control = 0;
17262306a36Sopenharmony_ci	u16 bw;
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	if (phy->type == B43_PHYTYPE_LP)
17562306a36Sopenharmony_ci		bw = B43_TXH_PHY1_BW_20;
17662306a36Sopenharmony_ci	else /* FIXME */
17762306a36Sopenharmony_ci		bw = B43_TXH_PHY1_BW_20;
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	if (0) { /* FIXME: MIMO */
18062306a36Sopenharmony_ci	} else if (b43_is_cck_rate(bitrate) && phy->type != B43_PHYTYPE_LP) {
18162306a36Sopenharmony_ci		control = bw;
18262306a36Sopenharmony_ci	} else {
18362306a36Sopenharmony_ci		control = bw;
18462306a36Sopenharmony_ci		e = b43_tx_legacy_rate_phy_ctl_ent(bitrate);
18562306a36Sopenharmony_ci		if (e) {
18662306a36Sopenharmony_ci			control |= e->coding_rate;
18762306a36Sopenharmony_ci			control |= e->modulation;
18862306a36Sopenharmony_ci		}
18962306a36Sopenharmony_ci		control |= B43_TXH_PHY1_MODE_SISO;
19062306a36Sopenharmony_ci	}
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	return control;
19362306a36Sopenharmony_ci}
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_cistatic u8 b43_calc_fallback_rate(u8 bitrate, int gmode)
19662306a36Sopenharmony_ci{
19762306a36Sopenharmony_ci	switch (bitrate) {
19862306a36Sopenharmony_ci	case B43_CCK_RATE_1MB:
19962306a36Sopenharmony_ci		return B43_CCK_RATE_1MB;
20062306a36Sopenharmony_ci	case B43_CCK_RATE_2MB:
20162306a36Sopenharmony_ci		return B43_CCK_RATE_1MB;
20262306a36Sopenharmony_ci	case B43_CCK_RATE_5MB:
20362306a36Sopenharmony_ci		return B43_CCK_RATE_2MB;
20462306a36Sopenharmony_ci	case B43_CCK_RATE_11MB:
20562306a36Sopenharmony_ci		return B43_CCK_RATE_5MB;
20662306a36Sopenharmony_ci	/*
20762306a36Sopenharmony_ci	 * Don't just fallback to CCK; it may be in 5GHz operation
20862306a36Sopenharmony_ci	 * and falling back to CCK won't work out very well.
20962306a36Sopenharmony_ci	 */
21062306a36Sopenharmony_ci	case B43_OFDM_RATE_6MB:
21162306a36Sopenharmony_ci		if (gmode)
21262306a36Sopenharmony_ci			return B43_CCK_RATE_5MB;
21362306a36Sopenharmony_ci		else
21462306a36Sopenharmony_ci			return B43_OFDM_RATE_6MB;
21562306a36Sopenharmony_ci	case B43_OFDM_RATE_9MB:
21662306a36Sopenharmony_ci		return B43_OFDM_RATE_6MB;
21762306a36Sopenharmony_ci	case B43_OFDM_RATE_12MB:
21862306a36Sopenharmony_ci		return B43_OFDM_RATE_9MB;
21962306a36Sopenharmony_ci	case B43_OFDM_RATE_18MB:
22062306a36Sopenharmony_ci		return B43_OFDM_RATE_12MB;
22162306a36Sopenharmony_ci	case B43_OFDM_RATE_24MB:
22262306a36Sopenharmony_ci		return B43_OFDM_RATE_18MB;
22362306a36Sopenharmony_ci	case B43_OFDM_RATE_36MB:
22462306a36Sopenharmony_ci		return B43_OFDM_RATE_24MB;
22562306a36Sopenharmony_ci	case B43_OFDM_RATE_48MB:
22662306a36Sopenharmony_ci		return B43_OFDM_RATE_36MB;
22762306a36Sopenharmony_ci	case B43_OFDM_RATE_54MB:
22862306a36Sopenharmony_ci		return B43_OFDM_RATE_48MB;
22962306a36Sopenharmony_ci	}
23062306a36Sopenharmony_ci	B43_WARN_ON(1);
23162306a36Sopenharmony_ci	return 0;
23262306a36Sopenharmony_ci}
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci/* Generate a TX data header. */
23562306a36Sopenharmony_ciint b43_generate_txhdr(struct b43_wldev *dev,
23662306a36Sopenharmony_ci		       u8 *_txhdr,
23762306a36Sopenharmony_ci		       struct sk_buff *skb_frag,
23862306a36Sopenharmony_ci		       struct ieee80211_tx_info *info,
23962306a36Sopenharmony_ci		       u16 cookie)
24062306a36Sopenharmony_ci{
24162306a36Sopenharmony_ci	const unsigned char *fragment_data = skb_frag->data;
24262306a36Sopenharmony_ci	unsigned int fragment_len = skb_frag->len;
24362306a36Sopenharmony_ci	struct b43_txhdr *txhdr = (struct b43_txhdr *)_txhdr;
24462306a36Sopenharmony_ci	const struct b43_phy *phy = &dev->phy;
24562306a36Sopenharmony_ci	const struct ieee80211_hdr *wlhdr =
24662306a36Sopenharmony_ci	    (const struct ieee80211_hdr *)fragment_data;
24762306a36Sopenharmony_ci	int use_encryption = !!info->control.hw_key;
24862306a36Sopenharmony_ci	__le16 fctl = wlhdr->frame_control;
24962306a36Sopenharmony_ci	struct ieee80211_rate *fbrate;
25062306a36Sopenharmony_ci	u8 rate, rate_fb;
25162306a36Sopenharmony_ci	int rate_ofdm, rate_fb_ofdm;
25262306a36Sopenharmony_ci	unsigned int plcp_fragment_len;
25362306a36Sopenharmony_ci	u32 mac_ctl = 0;
25462306a36Sopenharmony_ci	u16 phy_ctl = 0;
25562306a36Sopenharmony_ci	bool fill_phy_ctl1 = (phy->type == B43_PHYTYPE_LP ||
25662306a36Sopenharmony_ci			      phy->type == B43_PHYTYPE_N ||
25762306a36Sopenharmony_ci			      phy->type == B43_PHYTYPE_HT);
25862306a36Sopenharmony_ci	u8 extra_ft = 0;
25962306a36Sopenharmony_ci	struct ieee80211_rate *txrate;
26062306a36Sopenharmony_ci	struct ieee80211_tx_rate *rates;
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	memset(txhdr, 0, sizeof(*txhdr));
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	txrate = ieee80211_get_tx_rate(dev->wl->hw, info);
26562306a36Sopenharmony_ci	rate = txrate ? txrate->hw_value : B43_CCK_RATE_1MB;
26662306a36Sopenharmony_ci	rate_ofdm = b43_is_ofdm_rate(rate);
26762306a36Sopenharmony_ci	fbrate = ieee80211_get_alt_retry_rate(dev->wl->hw, info, 0) ? : txrate;
26862306a36Sopenharmony_ci	rate_fb = fbrate->hw_value;
26962306a36Sopenharmony_ci	rate_fb_ofdm = b43_is_ofdm_rate(rate_fb);
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	if (rate_ofdm)
27262306a36Sopenharmony_ci		txhdr->phy_rate = b43_plcp_get_ratecode_ofdm(rate);
27362306a36Sopenharmony_ci	else
27462306a36Sopenharmony_ci		txhdr->phy_rate = b43_plcp_get_ratecode_cck(rate);
27562306a36Sopenharmony_ci	txhdr->mac_frame_ctl = wlhdr->frame_control;
27662306a36Sopenharmony_ci	memcpy(txhdr->tx_receiver, wlhdr->addr1, ETH_ALEN);
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	/* Calculate duration for fallback rate */
27962306a36Sopenharmony_ci	if ((rate_fb == rate) ||
28062306a36Sopenharmony_ci	    (wlhdr->duration_id & cpu_to_le16(0x8000)) ||
28162306a36Sopenharmony_ci	    (wlhdr->duration_id == cpu_to_le16(0))) {
28262306a36Sopenharmony_ci		/* If the fallback rate equals the normal rate or the
28362306a36Sopenharmony_ci		 * dur_id field contains an AID, CFP magic or 0,
28462306a36Sopenharmony_ci		 * use the original dur_id field. */
28562306a36Sopenharmony_ci		txhdr->dur_fb = wlhdr->duration_id;
28662306a36Sopenharmony_ci	} else {
28762306a36Sopenharmony_ci		txhdr->dur_fb = ieee80211_generic_frame_duration(
28862306a36Sopenharmony_ci			dev->wl->hw, info->control.vif, info->band,
28962306a36Sopenharmony_ci			fragment_len, fbrate);
29062306a36Sopenharmony_ci	}
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	plcp_fragment_len = fragment_len + FCS_LEN;
29362306a36Sopenharmony_ci	if (use_encryption) {
29462306a36Sopenharmony_ci		u8 key_idx = info->control.hw_key->hw_key_idx;
29562306a36Sopenharmony_ci		struct b43_key *key;
29662306a36Sopenharmony_ci		int wlhdr_len;
29762306a36Sopenharmony_ci		size_t iv_len;
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci		B43_WARN_ON(key_idx >= ARRAY_SIZE(dev->key));
30062306a36Sopenharmony_ci		key = &(dev->key[key_idx]);
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci		if (unlikely(!key->keyconf)) {
30362306a36Sopenharmony_ci			/* This key is invalid. This might only happen
30462306a36Sopenharmony_ci			 * in a short timeframe after machine resume before
30562306a36Sopenharmony_ci			 * we were able to reconfigure keys.
30662306a36Sopenharmony_ci			 * Drop this packet completely. Do not transmit it
30762306a36Sopenharmony_ci			 * unencrypted to avoid leaking information. */
30862306a36Sopenharmony_ci			return -ENOKEY;
30962306a36Sopenharmony_ci		}
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci		/* Hardware appends ICV. */
31262306a36Sopenharmony_ci		plcp_fragment_len += info->control.hw_key->icv_len;
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci		key_idx = b43_kidx_to_fw(dev, key_idx);
31562306a36Sopenharmony_ci		mac_ctl |= (key_idx << B43_TXH_MAC_KEYIDX_SHIFT) &
31662306a36Sopenharmony_ci			   B43_TXH_MAC_KEYIDX;
31762306a36Sopenharmony_ci		mac_ctl |= (key->algorithm << B43_TXH_MAC_KEYALG_SHIFT) &
31862306a36Sopenharmony_ci			   B43_TXH_MAC_KEYALG;
31962306a36Sopenharmony_ci		wlhdr_len = ieee80211_hdrlen(fctl);
32062306a36Sopenharmony_ci		if (key->algorithm == B43_SEC_ALGO_TKIP) {
32162306a36Sopenharmony_ci			u16 phase1key[5];
32262306a36Sopenharmony_ci			int i;
32362306a36Sopenharmony_ci			/* we give the phase1key and iv16 here, the key is stored in
32462306a36Sopenharmony_ci			 * shm. With that the hardware can do phase 2 and encryption.
32562306a36Sopenharmony_ci			 */
32662306a36Sopenharmony_ci			ieee80211_get_tkip_p1k(info->control.hw_key, skb_frag, phase1key);
32762306a36Sopenharmony_ci			/* phase1key is in host endian. Copy to little-endian txhdr->iv. */
32862306a36Sopenharmony_ci			for (i = 0; i < 5; i++) {
32962306a36Sopenharmony_ci				txhdr->iv[i * 2 + 0] = phase1key[i];
33062306a36Sopenharmony_ci				txhdr->iv[i * 2 + 1] = phase1key[i] >> 8;
33162306a36Sopenharmony_ci			}
33262306a36Sopenharmony_ci			/* iv16 */
33362306a36Sopenharmony_ci			memcpy(txhdr->iv + 10, ((u8 *) wlhdr) + wlhdr_len, 3);
33462306a36Sopenharmony_ci		} else {
33562306a36Sopenharmony_ci			iv_len = min_t(size_t, info->control.hw_key->iv_len,
33662306a36Sopenharmony_ci				     ARRAY_SIZE(txhdr->iv));
33762306a36Sopenharmony_ci			memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len);
33862306a36Sopenharmony_ci		}
33962306a36Sopenharmony_ci	}
34062306a36Sopenharmony_ci	switch (dev->fw.hdr_format) {
34162306a36Sopenharmony_ci	case B43_FW_HDR_598:
34262306a36Sopenharmony_ci		b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->format_598.plcp),
34362306a36Sopenharmony_ci				      plcp_fragment_len, rate);
34462306a36Sopenharmony_ci		break;
34562306a36Sopenharmony_ci	case B43_FW_HDR_351:
34662306a36Sopenharmony_ci		b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->format_351.plcp),
34762306a36Sopenharmony_ci				      plcp_fragment_len, rate);
34862306a36Sopenharmony_ci		break;
34962306a36Sopenharmony_ci	case B43_FW_HDR_410:
35062306a36Sopenharmony_ci		b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->format_410.plcp),
35162306a36Sopenharmony_ci				      plcp_fragment_len, rate);
35262306a36Sopenharmony_ci		break;
35362306a36Sopenharmony_ci	}
35462306a36Sopenharmony_ci	b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->plcp_fb),
35562306a36Sopenharmony_ci			      plcp_fragment_len, rate_fb);
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	/* Extra Frame Types */
35862306a36Sopenharmony_ci	if (rate_fb_ofdm)
35962306a36Sopenharmony_ci		extra_ft |= B43_TXH_EFT_FB_OFDM;
36062306a36Sopenharmony_ci	else
36162306a36Sopenharmony_ci		extra_ft |= B43_TXH_EFT_FB_CCK;
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	/* Set channel radio code. Note that the micrcode ORs 0x100 to
36462306a36Sopenharmony_ci	 * this value before comparing it to the value in SHM, if this
36562306a36Sopenharmony_ci	 * is a 5Ghz packet.
36662306a36Sopenharmony_ci	 */
36762306a36Sopenharmony_ci	txhdr->chan_radio_code = phy->channel;
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	/* PHY TX Control word */
37062306a36Sopenharmony_ci	if (rate_ofdm)
37162306a36Sopenharmony_ci		phy_ctl |= B43_TXH_PHY_ENC_OFDM;
37262306a36Sopenharmony_ci	else
37362306a36Sopenharmony_ci		phy_ctl |= B43_TXH_PHY_ENC_CCK;
37462306a36Sopenharmony_ci	if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
37562306a36Sopenharmony_ci		phy_ctl |= B43_TXH_PHY_SHORTPRMBL;
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	switch (b43_ieee80211_antenna_sanitize(dev, 0)) {
37862306a36Sopenharmony_ci	case 0: /* Default */
37962306a36Sopenharmony_ci		phy_ctl |= B43_TXH_PHY_ANT01AUTO;
38062306a36Sopenharmony_ci		break;
38162306a36Sopenharmony_ci	case 1: /* Antenna 0 */
38262306a36Sopenharmony_ci		phy_ctl |= B43_TXH_PHY_ANT0;
38362306a36Sopenharmony_ci		break;
38462306a36Sopenharmony_ci	case 2: /* Antenna 1 */
38562306a36Sopenharmony_ci		phy_ctl |= B43_TXH_PHY_ANT1;
38662306a36Sopenharmony_ci		break;
38762306a36Sopenharmony_ci	case 3: /* Antenna 2 */
38862306a36Sopenharmony_ci		phy_ctl |= B43_TXH_PHY_ANT2;
38962306a36Sopenharmony_ci		break;
39062306a36Sopenharmony_ci	case 4: /* Antenna 3 */
39162306a36Sopenharmony_ci		phy_ctl |= B43_TXH_PHY_ANT3;
39262306a36Sopenharmony_ci		break;
39362306a36Sopenharmony_ci	default:
39462306a36Sopenharmony_ci		B43_WARN_ON(1);
39562306a36Sopenharmony_ci	}
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	rates = info->control.rates;
39862306a36Sopenharmony_ci	/* MAC control */
39962306a36Sopenharmony_ci	if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
40062306a36Sopenharmony_ci		mac_ctl |= B43_TXH_MAC_ACK;
40162306a36Sopenharmony_ci	/* use hardware sequence counter as the non-TID counter */
40262306a36Sopenharmony_ci	if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)
40362306a36Sopenharmony_ci		mac_ctl |= B43_TXH_MAC_HWSEQ;
40462306a36Sopenharmony_ci	if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
40562306a36Sopenharmony_ci		mac_ctl |= B43_TXH_MAC_STMSDU;
40662306a36Sopenharmony_ci	if (!phy->gmode)
40762306a36Sopenharmony_ci		mac_ctl |= B43_TXH_MAC_5GHZ;
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	/* Overwrite rates[0].count to make the retry calculation
41062306a36Sopenharmony_ci	 * in the tx status easier. need the actual retry limit to
41162306a36Sopenharmony_ci	 * detect whether the fallback rate was used.
41262306a36Sopenharmony_ci	 */
41362306a36Sopenharmony_ci	if ((rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) ||
41462306a36Sopenharmony_ci	    (rates[0].count <= dev->wl->hw->conf.long_frame_max_tx_count)) {
41562306a36Sopenharmony_ci		rates[0].count = dev->wl->hw->conf.long_frame_max_tx_count;
41662306a36Sopenharmony_ci		mac_ctl |= B43_TXH_MAC_LONGFRAME;
41762306a36Sopenharmony_ci	} else {
41862306a36Sopenharmony_ci		rates[0].count = dev->wl->hw->conf.short_frame_max_tx_count;
41962306a36Sopenharmony_ci	}
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	/* Generate the RTS or CTS-to-self frame */
42262306a36Sopenharmony_ci	if ((rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) ||
42362306a36Sopenharmony_ci	    (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)) {
42462306a36Sopenharmony_ci		unsigned int len;
42562306a36Sopenharmony_ci		struct ieee80211_hdr *hdr;
42662306a36Sopenharmony_ci		int rts_rate, rts_rate_fb;
42762306a36Sopenharmony_ci		int rts_rate_ofdm, rts_rate_fb_ofdm;
42862306a36Sopenharmony_ci		struct b43_plcp_hdr6 *plcp;
42962306a36Sopenharmony_ci		struct ieee80211_rate *rts_cts_rate;
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci		rts_cts_rate = ieee80211_get_rts_cts_rate(dev->wl->hw, info);
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci		rts_rate = rts_cts_rate ? rts_cts_rate->hw_value : B43_CCK_RATE_1MB;
43462306a36Sopenharmony_ci		rts_rate_ofdm = b43_is_ofdm_rate(rts_rate);
43562306a36Sopenharmony_ci		rts_rate_fb = b43_calc_fallback_rate(rts_rate, phy->gmode);
43662306a36Sopenharmony_ci		rts_rate_fb_ofdm = b43_is_ofdm_rate(rts_rate_fb);
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci		if (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
43962306a36Sopenharmony_ci			struct ieee80211_cts *cts;
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci			switch (dev->fw.hdr_format) {
44262306a36Sopenharmony_ci			case B43_FW_HDR_598:
44362306a36Sopenharmony_ci				cts = (struct ieee80211_cts *)
44462306a36Sopenharmony_ci					(txhdr->format_598.rts_frame);
44562306a36Sopenharmony_ci				break;
44662306a36Sopenharmony_ci			case B43_FW_HDR_351:
44762306a36Sopenharmony_ci				cts = (struct ieee80211_cts *)
44862306a36Sopenharmony_ci					(txhdr->format_351.rts_frame);
44962306a36Sopenharmony_ci				break;
45062306a36Sopenharmony_ci			case B43_FW_HDR_410:
45162306a36Sopenharmony_ci				cts = (struct ieee80211_cts *)
45262306a36Sopenharmony_ci					(txhdr->format_410.rts_frame);
45362306a36Sopenharmony_ci				break;
45462306a36Sopenharmony_ci			}
45562306a36Sopenharmony_ci			ieee80211_ctstoself_get(dev->wl->hw, info->control.vif,
45662306a36Sopenharmony_ci						fragment_data, fragment_len,
45762306a36Sopenharmony_ci						info, cts);
45862306a36Sopenharmony_ci			mac_ctl |= B43_TXH_MAC_SENDCTS;
45962306a36Sopenharmony_ci			len = sizeof(struct ieee80211_cts);
46062306a36Sopenharmony_ci		} else {
46162306a36Sopenharmony_ci			struct ieee80211_rts *rts;
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci			switch (dev->fw.hdr_format) {
46462306a36Sopenharmony_ci			case B43_FW_HDR_598:
46562306a36Sopenharmony_ci				rts = (struct ieee80211_rts *)
46662306a36Sopenharmony_ci					(txhdr->format_598.rts_frame);
46762306a36Sopenharmony_ci				break;
46862306a36Sopenharmony_ci			case B43_FW_HDR_351:
46962306a36Sopenharmony_ci				rts = (struct ieee80211_rts *)
47062306a36Sopenharmony_ci					(txhdr->format_351.rts_frame);
47162306a36Sopenharmony_ci				break;
47262306a36Sopenharmony_ci			case B43_FW_HDR_410:
47362306a36Sopenharmony_ci				rts = (struct ieee80211_rts *)
47462306a36Sopenharmony_ci					(txhdr->format_410.rts_frame);
47562306a36Sopenharmony_ci				break;
47662306a36Sopenharmony_ci			}
47762306a36Sopenharmony_ci			ieee80211_rts_get(dev->wl->hw, info->control.vif,
47862306a36Sopenharmony_ci					  fragment_data, fragment_len,
47962306a36Sopenharmony_ci					  info, rts);
48062306a36Sopenharmony_ci			mac_ctl |= B43_TXH_MAC_SENDRTS;
48162306a36Sopenharmony_ci			len = sizeof(struct ieee80211_rts);
48262306a36Sopenharmony_ci		}
48362306a36Sopenharmony_ci		len += FCS_LEN;
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci		/* Generate the PLCP headers for the RTS/CTS frame */
48662306a36Sopenharmony_ci		switch (dev->fw.hdr_format) {
48762306a36Sopenharmony_ci		case B43_FW_HDR_598:
48862306a36Sopenharmony_ci			plcp = &txhdr->format_598.rts_plcp;
48962306a36Sopenharmony_ci			break;
49062306a36Sopenharmony_ci		case B43_FW_HDR_351:
49162306a36Sopenharmony_ci			plcp = &txhdr->format_351.rts_plcp;
49262306a36Sopenharmony_ci			break;
49362306a36Sopenharmony_ci		case B43_FW_HDR_410:
49462306a36Sopenharmony_ci			plcp = &txhdr->format_410.rts_plcp;
49562306a36Sopenharmony_ci			break;
49662306a36Sopenharmony_ci		}
49762306a36Sopenharmony_ci		b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)plcp,
49862306a36Sopenharmony_ci				      len, rts_rate);
49962306a36Sopenharmony_ci		plcp = &txhdr->rts_plcp_fb;
50062306a36Sopenharmony_ci		b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)plcp,
50162306a36Sopenharmony_ci				      len, rts_rate_fb);
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci		switch (dev->fw.hdr_format) {
50462306a36Sopenharmony_ci		case B43_FW_HDR_598:
50562306a36Sopenharmony_ci			hdr = (struct ieee80211_hdr *)
50662306a36Sopenharmony_ci				(&txhdr->format_598.rts_frame);
50762306a36Sopenharmony_ci			break;
50862306a36Sopenharmony_ci		case B43_FW_HDR_351:
50962306a36Sopenharmony_ci			hdr = (struct ieee80211_hdr *)
51062306a36Sopenharmony_ci				(&txhdr->format_351.rts_frame);
51162306a36Sopenharmony_ci			break;
51262306a36Sopenharmony_ci		case B43_FW_HDR_410:
51362306a36Sopenharmony_ci			hdr = (struct ieee80211_hdr *)
51462306a36Sopenharmony_ci				(&txhdr->format_410.rts_frame);
51562306a36Sopenharmony_ci			break;
51662306a36Sopenharmony_ci		}
51762306a36Sopenharmony_ci		txhdr->rts_dur_fb = hdr->duration_id;
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci		if (rts_rate_ofdm) {
52062306a36Sopenharmony_ci			extra_ft |= B43_TXH_EFT_RTS_OFDM;
52162306a36Sopenharmony_ci			txhdr->phy_rate_rts =
52262306a36Sopenharmony_ci			    b43_plcp_get_ratecode_ofdm(rts_rate);
52362306a36Sopenharmony_ci		} else {
52462306a36Sopenharmony_ci			extra_ft |= B43_TXH_EFT_RTS_CCK;
52562306a36Sopenharmony_ci			txhdr->phy_rate_rts =
52662306a36Sopenharmony_ci			    b43_plcp_get_ratecode_cck(rts_rate);
52762306a36Sopenharmony_ci		}
52862306a36Sopenharmony_ci		if (rts_rate_fb_ofdm)
52962306a36Sopenharmony_ci			extra_ft |= B43_TXH_EFT_RTSFB_OFDM;
53062306a36Sopenharmony_ci		else
53162306a36Sopenharmony_ci			extra_ft |= B43_TXH_EFT_RTSFB_CCK;
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci		if (rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS &&
53462306a36Sopenharmony_ci		    fill_phy_ctl1) {
53562306a36Sopenharmony_ci			txhdr->phy_ctl1_rts = cpu_to_le16(
53662306a36Sopenharmony_ci				b43_generate_tx_phy_ctl1(dev, rts_rate));
53762306a36Sopenharmony_ci			txhdr->phy_ctl1_rts_fb = cpu_to_le16(
53862306a36Sopenharmony_ci				b43_generate_tx_phy_ctl1(dev, rts_rate_fb));
53962306a36Sopenharmony_ci		}
54062306a36Sopenharmony_ci	}
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	/* Magic cookie */
54362306a36Sopenharmony_ci	switch (dev->fw.hdr_format) {
54462306a36Sopenharmony_ci	case B43_FW_HDR_598:
54562306a36Sopenharmony_ci		txhdr->format_598.cookie = cpu_to_le16(cookie);
54662306a36Sopenharmony_ci		break;
54762306a36Sopenharmony_ci	case B43_FW_HDR_351:
54862306a36Sopenharmony_ci		txhdr->format_351.cookie = cpu_to_le16(cookie);
54962306a36Sopenharmony_ci		break;
55062306a36Sopenharmony_ci	case B43_FW_HDR_410:
55162306a36Sopenharmony_ci		txhdr->format_410.cookie = cpu_to_le16(cookie);
55262306a36Sopenharmony_ci		break;
55362306a36Sopenharmony_ci	}
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	if (fill_phy_ctl1) {
55662306a36Sopenharmony_ci		txhdr->phy_ctl1 =
55762306a36Sopenharmony_ci			cpu_to_le16(b43_generate_tx_phy_ctl1(dev, rate));
55862306a36Sopenharmony_ci		txhdr->phy_ctl1_fb =
55962306a36Sopenharmony_ci			cpu_to_le16(b43_generate_tx_phy_ctl1(dev, rate_fb));
56062306a36Sopenharmony_ci	}
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci	/* Apply the bitfields */
56362306a36Sopenharmony_ci	txhdr->mac_ctl = cpu_to_le32(mac_ctl);
56462306a36Sopenharmony_ci	txhdr->phy_ctl = cpu_to_le16(phy_ctl);
56562306a36Sopenharmony_ci	txhdr->extra_ft = extra_ft;
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	return 0;
56862306a36Sopenharmony_ci}
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_cistatic s8 b43_rssi_postprocess(struct b43_wldev *dev,
57162306a36Sopenharmony_ci			       u8 in_rssi, int ofdm,
57262306a36Sopenharmony_ci			       int adjust_2053, int adjust_2050)
57362306a36Sopenharmony_ci{
57462306a36Sopenharmony_ci	struct b43_phy *phy = &dev->phy;
57562306a36Sopenharmony_ci	struct b43_phy_g *gphy = phy->g;
57662306a36Sopenharmony_ci	s32 tmp;
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci	switch (phy->radio_ver) {
57962306a36Sopenharmony_ci	case 0x2050:
58062306a36Sopenharmony_ci		if (ofdm) {
58162306a36Sopenharmony_ci			tmp = in_rssi;
58262306a36Sopenharmony_ci			if (tmp > 127)
58362306a36Sopenharmony_ci				tmp -= 256;
58462306a36Sopenharmony_ci			tmp *= 73;
58562306a36Sopenharmony_ci			tmp /= 64;
58662306a36Sopenharmony_ci			if (adjust_2050)
58762306a36Sopenharmony_ci				tmp += 25;
58862306a36Sopenharmony_ci			else
58962306a36Sopenharmony_ci				tmp -= 3;
59062306a36Sopenharmony_ci		} else {
59162306a36Sopenharmony_ci			if (dev->dev->bus_sprom->
59262306a36Sopenharmony_ci			    boardflags_lo & B43_BFL_RSSI) {
59362306a36Sopenharmony_ci				if (in_rssi > 63)
59462306a36Sopenharmony_ci					in_rssi = 63;
59562306a36Sopenharmony_ci				B43_WARN_ON(phy->type != B43_PHYTYPE_G);
59662306a36Sopenharmony_ci				tmp = gphy->nrssi_lt[in_rssi];
59762306a36Sopenharmony_ci				tmp = 31 - tmp;
59862306a36Sopenharmony_ci				tmp *= -131;
59962306a36Sopenharmony_ci				tmp /= 128;
60062306a36Sopenharmony_ci				tmp -= 57;
60162306a36Sopenharmony_ci			} else {
60262306a36Sopenharmony_ci				tmp = in_rssi;
60362306a36Sopenharmony_ci				tmp = 31 - tmp;
60462306a36Sopenharmony_ci				tmp *= -149;
60562306a36Sopenharmony_ci				tmp /= 128;
60662306a36Sopenharmony_ci				tmp -= 68;
60762306a36Sopenharmony_ci			}
60862306a36Sopenharmony_ci			if (phy->type == B43_PHYTYPE_G && adjust_2050)
60962306a36Sopenharmony_ci				tmp += 25;
61062306a36Sopenharmony_ci		}
61162306a36Sopenharmony_ci		break;
61262306a36Sopenharmony_ci	case 0x2060:
61362306a36Sopenharmony_ci		if (in_rssi > 127)
61462306a36Sopenharmony_ci			tmp = in_rssi - 256;
61562306a36Sopenharmony_ci		else
61662306a36Sopenharmony_ci			tmp = in_rssi;
61762306a36Sopenharmony_ci		break;
61862306a36Sopenharmony_ci	default:
61962306a36Sopenharmony_ci		tmp = in_rssi;
62062306a36Sopenharmony_ci		tmp -= 11;
62162306a36Sopenharmony_ci		tmp *= 103;
62262306a36Sopenharmony_ci		tmp /= 64;
62362306a36Sopenharmony_ci		if (adjust_2053)
62462306a36Sopenharmony_ci			tmp -= 109;
62562306a36Sopenharmony_ci		else
62662306a36Sopenharmony_ci			tmp -= 83;
62762306a36Sopenharmony_ci	}
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci	return (s8) tmp;
63062306a36Sopenharmony_ci}
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_civoid b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
63362306a36Sopenharmony_ci{
63462306a36Sopenharmony_ci	struct ieee80211_rx_status status;
63562306a36Sopenharmony_ci	struct b43_plcp_hdr6 *plcp;
63662306a36Sopenharmony_ci	struct ieee80211_hdr *wlhdr;
63762306a36Sopenharmony_ci	const struct b43_rxhdr_fw4 *rxhdr = _rxhdr;
63862306a36Sopenharmony_ci	__le16 fctl;
63962306a36Sopenharmony_ci	u16 phystat0, phystat3;
64062306a36Sopenharmony_ci	u16 chanstat, mactime;
64162306a36Sopenharmony_ci	u32 macstat;
64262306a36Sopenharmony_ci	u16 chanid;
64362306a36Sopenharmony_ci	int padding, rate_idx;
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci	memset(&status, 0, sizeof(status));
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci	/* Get metadata about the frame from the header. */
64862306a36Sopenharmony_ci	phystat0 = le16_to_cpu(rxhdr->phy_status0);
64962306a36Sopenharmony_ci	phystat3 = le16_to_cpu(rxhdr->phy_status3);
65062306a36Sopenharmony_ci	switch (dev->fw.hdr_format) {
65162306a36Sopenharmony_ci	case B43_FW_HDR_598:
65262306a36Sopenharmony_ci		macstat = le32_to_cpu(rxhdr->format_598.mac_status);
65362306a36Sopenharmony_ci		mactime = le16_to_cpu(rxhdr->format_598.mac_time);
65462306a36Sopenharmony_ci		chanstat = le16_to_cpu(rxhdr->format_598.channel);
65562306a36Sopenharmony_ci		break;
65662306a36Sopenharmony_ci	case B43_FW_HDR_410:
65762306a36Sopenharmony_ci	case B43_FW_HDR_351:
65862306a36Sopenharmony_ci		macstat = le32_to_cpu(rxhdr->format_351.mac_status);
65962306a36Sopenharmony_ci		mactime = le16_to_cpu(rxhdr->format_351.mac_time);
66062306a36Sopenharmony_ci		chanstat = le16_to_cpu(rxhdr->format_351.channel);
66162306a36Sopenharmony_ci		break;
66262306a36Sopenharmony_ci	}
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	if (unlikely(macstat & B43_RX_MAC_FCSERR)) {
66562306a36Sopenharmony_ci		dev->wl->ieee_stats.dot11FCSErrorCount++;
66662306a36Sopenharmony_ci		status.flag |= RX_FLAG_FAILED_FCS_CRC;
66762306a36Sopenharmony_ci	}
66862306a36Sopenharmony_ci	if (unlikely(phystat0 & (B43_RX_PHYST0_PLCPHCF | B43_RX_PHYST0_PLCPFV)))
66962306a36Sopenharmony_ci		status.flag |= RX_FLAG_FAILED_PLCP_CRC;
67062306a36Sopenharmony_ci	if (phystat0 & B43_RX_PHYST0_SHORTPRMBL)
67162306a36Sopenharmony_ci		status.enc_flags |= RX_ENC_FLAG_SHORTPRE;
67262306a36Sopenharmony_ci	if (macstat & B43_RX_MAC_DECERR) {
67362306a36Sopenharmony_ci		/* Decryption with the given key failed.
67462306a36Sopenharmony_ci		 * Drop the packet. We also won't be able to decrypt it with
67562306a36Sopenharmony_ci		 * the key in software. */
67662306a36Sopenharmony_ci		goto drop;
67762306a36Sopenharmony_ci	}
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci	/* Skip PLCP and padding */
68062306a36Sopenharmony_ci	padding = (macstat & B43_RX_MAC_PADDING) ? 2 : 0;
68162306a36Sopenharmony_ci	if (unlikely(skb->len < (sizeof(struct b43_plcp_hdr6) + padding))) {
68262306a36Sopenharmony_ci		b43dbg(dev->wl, "RX: Packet size underrun (1)\n");
68362306a36Sopenharmony_ci		goto drop;
68462306a36Sopenharmony_ci	}
68562306a36Sopenharmony_ci	plcp = (struct b43_plcp_hdr6 *)(skb->data + padding);
68662306a36Sopenharmony_ci	skb_pull(skb, sizeof(struct b43_plcp_hdr6) + padding);
68762306a36Sopenharmony_ci	/* The skb contains the Wireless Header + payload data now */
68862306a36Sopenharmony_ci	if (unlikely(skb->len < (2 + 2 + 6 /*minimum hdr */  + FCS_LEN))) {
68962306a36Sopenharmony_ci		b43dbg(dev->wl, "RX: Packet size underrun (2)\n");
69062306a36Sopenharmony_ci		goto drop;
69162306a36Sopenharmony_ci	}
69262306a36Sopenharmony_ci	wlhdr = (struct ieee80211_hdr *)(skb->data);
69362306a36Sopenharmony_ci	fctl = wlhdr->frame_control;
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci	if (macstat & B43_RX_MAC_DEC) {
69662306a36Sopenharmony_ci		unsigned int keyidx;
69762306a36Sopenharmony_ci		int wlhdr_len;
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci		keyidx = ((macstat & B43_RX_MAC_KEYIDX)
70062306a36Sopenharmony_ci			  >> B43_RX_MAC_KEYIDX_SHIFT);
70162306a36Sopenharmony_ci		/* We must adjust the key index here. We want the "physical"
70262306a36Sopenharmony_ci		 * key index, but the ucode passed it slightly different.
70362306a36Sopenharmony_ci		 */
70462306a36Sopenharmony_ci		keyidx = b43_kidx_to_raw(dev, keyidx);
70562306a36Sopenharmony_ci		B43_WARN_ON(keyidx >= ARRAY_SIZE(dev->key));
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci		if (dev->key[keyidx].algorithm != B43_SEC_ALGO_NONE) {
70862306a36Sopenharmony_ci			wlhdr_len = ieee80211_hdrlen(fctl);
70962306a36Sopenharmony_ci			if (unlikely(skb->len < (wlhdr_len + 3))) {
71062306a36Sopenharmony_ci				b43dbg(dev->wl,
71162306a36Sopenharmony_ci				       "RX: Packet size underrun (3)\n");
71262306a36Sopenharmony_ci				goto drop;
71362306a36Sopenharmony_ci			}
71462306a36Sopenharmony_ci			status.flag |= RX_FLAG_DECRYPTED;
71562306a36Sopenharmony_ci		}
71662306a36Sopenharmony_ci	}
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci	/* Link quality statistics */
71962306a36Sopenharmony_ci	switch (chanstat & B43_RX_CHAN_PHYTYPE) {
72062306a36Sopenharmony_ci	case B43_PHYTYPE_HT:
72162306a36Sopenharmony_ci		/* TODO: is max the right choice? */
72262306a36Sopenharmony_ci		status.signal = max_t(__s8,
72362306a36Sopenharmony_ci			max(rxhdr->phy_ht_power0, rxhdr->phy_ht_power1),
72462306a36Sopenharmony_ci			rxhdr->phy_ht_power2);
72562306a36Sopenharmony_ci		break;
72662306a36Sopenharmony_ci	case B43_PHYTYPE_N:
72762306a36Sopenharmony_ci		/* Broadcom has code for min and avg, but always uses max */
72862306a36Sopenharmony_ci		if (rxhdr->power0 == 16 || rxhdr->power0 == 32)
72962306a36Sopenharmony_ci			status.signal = max(rxhdr->power1, rxhdr->power2);
73062306a36Sopenharmony_ci		else
73162306a36Sopenharmony_ci			status.signal = max(rxhdr->power0, rxhdr->power1);
73262306a36Sopenharmony_ci		break;
73362306a36Sopenharmony_ci	case B43_PHYTYPE_B:
73462306a36Sopenharmony_ci	case B43_PHYTYPE_G:
73562306a36Sopenharmony_ci	case B43_PHYTYPE_LP:
73662306a36Sopenharmony_ci		status.signal = b43_rssi_postprocess(dev, rxhdr->jssi,
73762306a36Sopenharmony_ci						  (phystat0 & B43_RX_PHYST0_OFDM),
73862306a36Sopenharmony_ci						  (phystat0 & B43_RX_PHYST0_GAINCTL),
73962306a36Sopenharmony_ci						  (phystat3 & B43_RX_PHYST3_TRSTATE));
74062306a36Sopenharmony_ci		break;
74162306a36Sopenharmony_ci	}
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci	if (phystat0 & B43_RX_PHYST0_OFDM)
74462306a36Sopenharmony_ci		rate_idx = b43_plcp_get_bitrate_idx_ofdm(plcp,
74562306a36Sopenharmony_ci					!!(chanstat & B43_RX_CHAN_5GHZ));
74662306a36Sopenharmony_ci	else
74762306a36Sopenharmony_ci		rate_idx = b43_plcp_get_bitrate_idx_cck(plcp);
74862306a36Sopenharmony_ci	if (unlikely(rate_idx == -1)) {
74962306a36Sopenharmony_ci		/* PLCP seems to be corrupted.
75062306a36Sopenharmony_ci		 * Drop the frame, if we are not interested in corrupted frames. */
75162306a36Sopenharmony_ci		if (!(dev->wl->filter_flags & FIF_PLCPFAIL))
75262306a36Sopenharmony_ci			goto drop;
75362306a36Sopenharmony_ci	}
75462306a36Sopenharmony_ci	status.rate_idx = rate_idx;
75562306a36Sopenharmony_ci	status.antenna = !!(phystat0 & B43_RX_PHYST0_ANT);
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci	/*
75862306a36Sopenharmony_ci	 * All frames on monitor interfaces and beacons always need a full
75962306a36Sopenharmony_ci	 * 64-bit timestamp. Monitor interfaces need it for diagnostic
76062306a36Sopenharmony_ci	 * purposes and beacons for IBSS merging.
76162306a36Sopenharmony_ci	 * This code assumes we get to process the packet within 16 bits
76262306a36Sopenharmony_ci	 * of timestamp, i.e. about 65 milliseconds after the PHY received
76362306a36Sopenharmony_ci	 * the first symbol.
76462306a36Sopenharmony_ci	 */
76562306a36Sopenharmony_ci	if (ieee80211_is_beacon(fctl) || dev->wl->radiotap_enabled) {
76662306a36Sopenharmony_ci		u16 low_mactime_now;
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci		b43_tsf_read(dev, &status.mactime);
76962306a36Sopenharmony_ci		low_mactime_now = status.mactime;
77062306a36Sopenharmony_ci		status.mactime = status.mactime & ~0xFFFFULL;
77162306a36Sopenharmony_ci		status.mactime += mactime;
77262306a36Sopenharmony_ci		if (low_mactime_now <= mactime)
77362306a36Sopenharmony_ci			status.mactime -= 0x10000;
77462306a36Sopenharmony_ci		status.flag |= RX_FLAG_MACTIME_START;
77562306a36Sopenharmony_ci	}
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci	chanid = (chanstat & B43_RX_CHAN_ID) >> B43_RX_CHAN_ID_SHIFT;
77862306a36Sopenharmony_ci	switch (chanstat & B43_RX_CHAN_PHYTYPE) {
77962306a36Sopenharmony_ci	case B43_PHYTYPE_G:
78062306a36Sopenharmony_ci		status.band = NL80211_BAND_2GHZ;
78162306a36Sopenharmony_ci		/* Somewhere between 478.104 and 508.1084 firmware for G-PHY
78262306a36Sopenharmony_ci		 * has been modified to be compatible with N-PHY and others.
78362306a36Sopenharmony_ci		 */
78462306a36Sopenharmony_ci		if (dev->fw.rev >= 508)
78562306a36Sopenharmony_ci			status.freq = ieee80211_channel_to_frequency(chanid, status.band);
78662306a36Sopenharmony_ci		else
78762306a36Sopenharmony_ci			status.freq = chanid + 2400;
78862306a36Sopenharmony_ci		break;
78962306a36Sopenharmony_ci	case B43_PHYTYPE_N:
79062306a36Sopenharmony_ci	case B43_PHYTYPE_LP:
79162306a36Sopenharmony_ci	case B43_PHYTYPE_HT:
79262306a36Sopenharmony_ci		/* chanid is the SHM channel cookie. Which is the plain
79362306a36Sopenharmony_ci		 * channel number in b43. */
79462306a36Sopenharmony_ci		if (chanstat & B43_RX_CHAN_5GHZ)
79562306a36Sopenharmony_ci			status.band = NL80211_BAND_5GHZ;
79662306a36Sopenharmony_ci		else
79762306a36Sopenharmony_ci			status.band = NL80211_BAND_2GHZ;
79862306a36Sopenharmony_ci		status.freq =
79962306a36Sopenharmony_ci			ieee80211_channel_to_frequency(chanid, status.band);
80062306a36Sopenharmony_ci		break;
80162306a36Sopenharmony_ci	default:
80262306a36Sopenharmony_ci		B43_WARN_ON(1);
80362306a36Sopenharmony_ci		goto drop;
80462306a36Sopenharmony_ci	}
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_ci	memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
80762306a36Sopenharmony_ci	ieee80211_rx_ni(dev->wl->hw, skb);
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci#if B43_DEBUG
81062306a36Sopenharmony_ci	dev->rx_count++;
81162306a36Sopenharmony_ci#endif
81262306a36Sopenharmony_ci	return;
81362306a36Sopenharmony_cidrop:
81462306a36Sopenharmony_ci	dev_kfree_skb_any(skb);
81562306a36Sopenharmony_ci}
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_civoid b43_handle_txstatus(struct b43_wldev *dev,
81862306a36Sopenharmony_ci			 const struct b43_txstatus *status)
81962306a36Sopenharmony_ci{
82062306a36Sopenharmony_ci	b43_debugfs_log_txstat(dev, status);
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_ci	if (status->intermediate)
82362306a36Sopenharmony_ci		return;
82462306a36Sopenharmony_ci	if (status->for_ampdu)
82562306a36Sopenharmony_ci		return;
82662306a36Sopenharmony_ci	if (!status->acked)
82762306a36Sopenharmony_ci		dev->wl->ieee_stats.dot11ACKFailureCount++;
82862306a36Sopenharmony_ci	if (status->rts_count) {
82962306a36Sopenharmony_ci		if (status->rts_count == 0xF)	//FIXME
83062306a36Sopenharmony_ci			dev->wl->ieee_stats.dot11RTSFailureCount++;
83162306a36Sopenharmony_ci		else
83262306a36Sopenharmony_ci			dev->wl->ieee_stats.dot11RTSSuccessCount++;
83362306a36Sopenharmony_ci	}
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_ci	if (b43_using_pio_transfers(dev))
83662306a36Sopenharmony_ci		b43_pio_handle_txstatus(dev, status);
83762306a36Sopenharmony_ci	else
83862306a36Sopenharmony_ci		b43_dma_handle_txstatus(dev, status);
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci	b43_phy_txpower_check(dev, 0);
84162306a36Sopenharmony_ci}
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci/* Fill out the mac80211 TXstatus report based on the b43-specific
84462306a36Sopenharmony_ci * txstatus report data. This returns a boolean whether the frame was
84562306a36Sopenharmony_ci * successfully transmitted. */
84662306a36Sopenharmony_cibool b43_fill_txstatus_report(struct b43_wldev *dev,
84762306a36Sopenharmony_ci			      struct ieee80211_tx_info *report,
84862306a36Sopenharmony_ci			      const struct b43_txstatus *status)
84962306a36Sopenharmony_ci{
85062306a36Sopenharmony_ci	bool frame_success = true;
85162306a36Sopenharmony_ci	int retry_limit;
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci	/* preserve the confiured retry limit before clearing the status
85462306a36Sopenharmony_ci	 * The xmit function has overwritten the rc's value with the actual
85562306a36Sopenharmony_ci	 * retry limit done by the hardware */
85662306a36Sopenharmony_ci	retry_limit = report->status.rates[0].count;
85762306a36Sopenharmony_ci	ieee80211_tx_info_clear_status(report);
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ci	if (status->acked) {
86062306a36Sopenharmony_ci		/* The frame was ACKed. */
86162306a36Sopenharmony_ci		report->flags |= IEEE80211_TX_STAT_ACK;
86262306a36Sopenharmony_ci	} else {
86362306a36Sopenharmony_ci		/* The frame was not ACKed... */
86462306a36Sopenharmony_ci		if (!(report->flags & IEEE80211_TX_CTL_NO_ACK)) {
86562306a36Sopenharmony_ci			/* ...but we expected an ACK. */
86662306a36Sopenharmony_ci			frame_success = false;
86762306a36Sopenharmony_ci		}
86862306a36Sopenharmony_ci	}
86962306a36Sopenharmony_ci	if (status->frame_count == 0) {
87062306a36Sopenharmony_ci		/* The frame was not transmitted at all. */
87162306a36Sopenharmony_ci		report->status.rates[0].count = 0;
87262306a36Sopenharmony_ci	} else if (status->rts_count > dev->wl->hw->conf.short_frame_max_tx_count) {
87362306a36Sopenharmony_ci		/*
87462306a36Sopenharmony_ci		 * If the short retries (RTS, not data frame) have exceeded
87562306a36Sopenharmony_ci		 * the limit, the hw will not have tried the selected rate,
87662306a36Sopenharmony_ci		 * but will have used the fallback rate instead.
87762306a36Sopenharmony_ci		 * Don't let the rate control count attempts for the selected
87862306a36Sopenharmony_ci		 * rate in this case, otherwise the statistics will be off.
87962306a36Sopenharmony_ci		 */
88062306a36Sopenharmony_ci		report->status.rates[0].count = 0;
88162306a36Sopenharmony_ci		report->status.rates[1].count = status->frame_count;
88262306a36Sopenharmony_ci	} else {
88362306a36Sopenharmony_ci		if (status->frame_count > retry_limit) {
88462306a36Sopenharmony_ci			report->status.rates[0].count = retry_limit;
88562306a36Sopenharmony_ci			report->status.rates[1].count = status->frame_count -
88662306a36Sopenharmony_ci					retry_limit;
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci		} else {
88962306a36Sopenharmony_ci			report->status.rates[0].count = status->frame_count;
89062306a36Sopenharmony_ci			report->status.rates[1].idx = -1;
89162306a36Sopenharmony_ci		}
89262306a36Sopenharmony_ci	}
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_ci	return frame_success;
89562306a36Sopenharmony_ci}
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_ci/* Stop any TX operation on the device (suspend the hardware queues) */
89862306a36Sopenharmony_civoid b43_tx_suspend(struct b43_wldev *dev)
89962306a36Sopenharmony_ci{
90062306a36Sopenharmony_ci	if (b43_using_pio_transfers(dev))
90162306a36Sopenharmony_ci		b43_pio_tx_suspend(dev);
90262306a36Sopenharmony_ci	else
90362306a36Sopenharmony_ci		b43_dma_tx_suspend(dev);
90462306a36Sopenharmony_ci}
90562306a36Sopenharmony_ci
90662306a36Sopenharmony_ci/* Resume any TX operation on the device (resume the hardware queues) */
90762306a36Sopenharmony_civoid b43_tx_resume(struct b43_wldev *dev)
90862306a36Sopenharmony_ci{
90962306a36Sopenharmony_ci	if (b43_using_pio_transfers(dev))
91062306a36Sopenharmony_ci		b43_pio_tx_resume(dev);
91162306a36Sopenharmony_ci	else
91262306a36Sopenharmony_ci		b43_dma_tx_resume(dev);
91362306a36Sopenharmony_ci}
914