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