18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci Broadcom B43 wireless driver 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci Transmission (TX/RX) related functions. 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci Copyright (C) 2005 Martin Langer <martin-langer@gmx.de> 98c2ecf20Sopenharmony_ci Copyright (C) 2005 Stefano Brivio <stefano.brivio@polimi.it> 108c2ecf20Sopenharmony_ci Copyright (C) 2005, 2006 Michael Buesch <m@bues.ch> 118c2ecf20Sopenharmony_ci Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org> 128c2ecf20Sopenharmony_ci Copyright (C) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci*/ 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include "xmit.h" 188c2ecf20Sopenharmony_ci#include "phy_common.h" 198c2ecf20Sopenharmony_ci#include "dma.h" 208c2ecf20Sopenharmony_ci#include "pio.h" 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_cistatic const struct b43_tx_legacy_rate_phy_ctl_entry b43_tx_legacy_rate_phy_ctl[] = { 238c2ecf20Sopenharmony_ci { B43_CCK_RATE_1MB, 0x0, 0x0 }, 248c2ecf20Sopenharmony_ci { B43_CCK_RATE_2MB, 0x0, 0x1 }, 258c2ecf20Sopenharmony_ci { B43_CCK_RATE_5MB, 0x0, 0x2 }, 268c2ecf20Sopenharmony_ci { B43_CCK_RATE_11MB, 0x0, 0x3 }, 278c2ecf20Sopenharmony_ci { B43_OFDM_RATE_6MB, B43_TXH_PHY1_CRATE_1_2, B43_TXH_PHY1_MODUL_BPSK }, 288c2ecf20Sopenharmony_ci { B43_OFDM_RATE_9MB, B43_TXH_PHY1_CRATE_3_4, B43_TXH_PHY1_MODUL_BPSK }, 298c2ecf20Sopenharmony_ci { B43_OFDM_RATE_12MB, B43_TXH_PHY1_CRATE_1_2, B43_TXH_PHY1_MODUL_QPSK }, 308c2ecf20Sopenharmony_ci { B43_OFDM_RATE_18MB, B43_TXH_PHY1_CRATE_3_4, B43_TXH_PHY1_MODUL_QPSK }, 318c2ecf20Sopenharmony_ci { B43_OFDM_RATE_24MB, B43_TXH_PHY1_CRATE_1_2, B43_TXH_PHY1_MODUL_QAM16 }, 328c2ecf20Sopenharmony_ci { B43_OFDM_RATE_36MB, B43_TXH_PHY1_CRATE_3_4, B43_TXH_PHY1_MODUL_QAM16 }, 338c2ecf20Sopenharmony_ci { B43_OFDM_RATE_48MB, B43_TXH_PHY1_CRATE_2_3, B43_TXH_PHY1_MODUL_QAM64 }, 348c2ecf20Sopenharmony_ci { B43_OFDM_RATE_54MB, B43_TXH_PHY1_CRATE_3_4, B43_TXH_PHY1_MODUL_QAM64 }, 358c2ecf20Sopenharmony_ci}; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic const struct b43_tx_legacy_rate_phy_ctl_entry * 388c2ecf20Sopenharmony_cib43_tx_legacy_rate_phy_ctl_ent(u8 bitrate) 398c2ecf20Sopenharmony_ci{ 408c2ecf20Sopenharmony_ci const struct b43_tx_legacy_rate_phy_ctl_entry *e; 418c2ecf20Sopenharmony_ci unsigned int i; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(b43_tx_legacy_rate_phy_ctl); i++) { 448c2ecf20Sopenharmony_ci e = &(b43_tx_legacy_rate_phy_ctl[i]); 458c2ecf20Sopenharmony_ci if (e->bitrate == bitrate) 468c2ecf20Sopenharmony_ci return e; 478c2ecf20Sopenharmony_ci } 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci B43_WARN_ON(1); 508c2ecf20Sopenharmony_ci return NULL; 518c2ecf20Sopenharmony_ci} 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci/* Extract the bitrate index out of a CCK PLCP header. */ 548c2ecf20Sopenharmony_cistatic int b43_plcp_get_bitrate_idx_cck(struct b43_plcp_hdr6 *plcp) 558c2ecf20Sopenharmony_ci{ 568c2ecf20Sopenharmony_ci switch (plcp->raw[0]) { 578c2ecf20Sopenharmony_ci case 0x0A: 588c2ecf20Sopenharmony_ci return 0; 598c2ecf20Sopenharmony_ci case 0x14: 608c2ecf20Sopenharmony_ci return 1; 618c2ecf20Sopenharmony_ci case 0x37: 628c2ecf20Sopenharmony_ci return 2; 638c2ecf20Sopenharmony_ci case 0x6E: 648c2ecf20Sopenharmony_ci return 3; 658c2ecf20Sopenharmony_ci } 668c2ecf20Sopenharmony_ci return -1; 678c2ecf20Sopenharmony_ci} 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci/* Extract the bitrate index out of an OFDM PLCP header. */ 708c2ecf20Sopenharmony_cistatic int b43_plcp_get_bitrate_idx_ofdm(struct b43_plcp_hdr6 *plcp, bool ghz5) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci /* For 2 GHz band first OFDM rate is at index 4, see main.c */ 738c2ecf20Sopenharmony_ci int base = ghz5 ? 0 : 4; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci switch (plcp->raw[0] & 0xF) { 768c2ecf20Sopenharmony_ci case 0xB: 778c2ecf20Sopenharmony_ci return base + 0; 788c2ecf20Sopenharmony_ci case 0xF: 798c2ecf20Sopenharmony_ci return base + 1; 808c2ecf20Sopenharmony_ci case 0xA: 818c2ecf20Sopenharmony_ci return base + 2; 828c2ecf20Sopenharmony_ci case 0xE: 838c2ecf20Sopenharmony_ci return base + 3; 848c2ecf20Sopenharmony_ci case 0x9: 858c2ecf20Sopenharmony_ci return base + 4; 868c2ecf20Sopenharmony_ci case 0xD: 878c2ecf20Sopenharmony_ci return base + 5; 888c2ecf20Sopenharmony_ci case 0x8: 898c2ecf20Sopenharmony_ci return base + 6; 908c2ecf20Sopenharmony_ci case 0xC: 918c2ecf20Sopenharmony_ci return base + 7; 928c2ecf20Sopenharmony_ci } 938c2ecf20Sopenharmony_ci return -1; 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ciu8 b43_plcp_get_ratecode_cck(const u8 bitrate) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci switch (bitrate) { 998c2ecf20Sopenharmony_ci case B43_CCK_RATE_1MB: 1008c2ecf20Sopenharmony_ci return 0x0A; 1018c2ecf20Sopenharmony_ci case B43_CCK_RATE_2MB: 1028c2ecf20Sopenharmony_ci return 0x14; 1038c2ecf20Sopenharmony_ci case B43_CCK_RATE_5MB: 1048c2ecf20Sopenharmony_ci return 0x37; 1058c2ecf20Sopenharmony_ci case B43_CCK_RATE_11MB: 1068c2ecf20Sopenharmony_ci return 0x6E; 1078c2ecf20Sopenharmony_ci } 1088c2ecf20Sopenharmony_ci B43_WARN_ON(1); 1098c2ecf20Sopenharmony_ci return 0; 1108c2ecf20Sopenharmony_ci} 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ciu8 b43_plcp_get_ratecode_ofdm(const u8 bitrate) 1138c2ecf20Sopenharmony_ci{ 1148c2ecf20Sopenharmony_ci switch (bitrate) { 1158c2ecf20Sopenharmony_ci case B43_OFDM_RATE_6MB: 1168c2ecf20Sopenharmony_ci return 0xB; 1178c2ecf20Sopenharmony_ci case B43_OFDM_RATE_9MB: 1188c2ecf20Sopenharmony_ci return 0xF; 1198c2ecf20Sopenharmony_ci case B43_OFDM_RATE_12MB: 1208c2ecf20Sopenharmony_ci return 0xA; 1218c2ecf20Sopenharmony_ci case B43_OFDM_RATE_18MB: 1228c2ecf20Sopenharmony_ci return 0xE; 1238c2ecf20Sopenharmony_ci case B43_OFDM_RATE_24MB: 1248c2ecf20Sopenharmony_ci return 0x9; 1258c2ecf20Sopenharmony_ci case B43_OFDM_RATE_36MB: 1268c2ecf20Sopenharmony_ci return 0xD; 1278c2ecf20Sopenharmony_ci case B43_OFDM_RATE_48MB: 1288c2ecf20Sopenharmony_ci return 0x8; 1298c2ecf20Sopenharmony_ci case B43_OFDM_RATE_54MB: 1308c2ecf20Sopenharmony_ci return 0xC; 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci B43_WARN_ON(1); 1338c2ecf20Sopenharmony_ci return 0; 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_civoid b43_generate_plcp_hdr(struct b43_plcp_hdr4 *plcp, 1378c2ecf20Sopenharmony_ci const u16 octets, const u8 bitrate) 1388c2ecf20Sopenharmony_ci{ 1398c2ecf20Sopenharmony_ci __u8 *raw = plcp->raw; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci if (b43_is_ofdm_rate(bitrate)) { 1428c2ecf20Sopenharmony_ci u32 d; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci d = b43_plcp_get_ratecode_ofdm(bitrate); 1458c2ecf20Sopenharmony_ci B43_WARN_ON(octets & 0xF000); 1468c2ecf20Sopenharmony_ci d |= (octets << 5); 1478c2ecf20Sopenharmony_ci plcp->data = cpu_to_le32(d); 1488c2ecf20Sopenharmony_ci } else { 1498c2ecf20Sopenharmony_ci u32 plen; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci plen = octets * 16 / bitrate; 1528c2ecf20Sopenharmony_ci if ((octets * 16 % bitrate) > 0) { 1538c2ecf20Sopenharmony_ci plen++; 1548c2ecf20Sopenharmony_ci if ((bitrate == B43_CCK_RATE_11MB) 1558c2ecf20Sopenharmony_ci && ((octets * 8 % 11) < 4)) { 1568c2ecf20Sopenharmony_ci raw[1] = 0x84; 1578c2ecf20Sopenharmony_ci } else 1588c2ecf20Sopenharmony_ci raw[1] = 0x04; 1598c2ecf20Sopenharmony_ci } else 1608c2ecf20Sopenharmony_ci raw[1] = 0x04; 1618c2ecf20Sopenharmony_ci plcp->data |= cpu_to_le32(plen << 16); 1628c2ecf20Sopenharmony_ci raw[0] = b43_plcp_get_ratecode_cck(bitrate); 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci/* TODO: verify if needed for SSLPN or LCN */ 1678c2ecf20Sopenharmony_cistatic u16 b43_generate_tx_phy_ctl1(struct b43_wldev *dev, u8 bitrate) 1688c2ecf20Sopenharmony_ci{ 1698c2ecf20Sopenharmony_ci const struct b43_phy *phy = &dev->phy; 1708c2ecf20Sopenharmony_ci const struct b43_tx_legacy_rate_phy_ctl_entry *e; 1718c2ecf20Sopenharmony_ci u16 control = 0; 1728c2ecf20Sopenharmony_ci u16 bw; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci if (phy->type == B43_PHYTYPE_LP) 1758c2ecf20Sopenharmony_ci bw = B43_TXH_PHY1_BW_20; 1768c2ecf20Sopenharmony_ci else /* FIXME */ 1778c2ecf20Sopenharmony_ci bw = B43_TXH_PHY1_BW_20; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci if (0) { /* FIXME: MIMO */ 1808c2ecf20Sopenharmony_ci } else if (b43_is_cck_rate(bitrate) && phy->type != B43_PHYTYPE_LP) { 1818c2ecf20Sopenharmony_ci control = bw; 1828c2ecf20Sopenharmony_ci } else { 1838c2ecf20Sopenharmony_ci control = bw; 1848c2ecf20Sopenharmony_ci e = b43_tx_legacy_rate_phy_ctl_ent(bitrate); 1858c2ecf20Sopenharmony_ci if (e) { 1868c2ecf20Sopenharmony_ci control |= e->coding_rate; 1878c2ecf20Sopenharmony_ci control |= e->modulation; 1888c2ecf20Sopenharmony_ci } 1898c2ecf20Sopenharmony_ci control |= B43_TXH_PHY1_MODE_SISO; 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci return control; 1938c2ecf20Sopenharmony_ci} 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_cistatic u8 b43_calc_fallback_rate(u8 bitrate, int gmode) 1968c2ecf20Sopenharmony_ci{ 1978c2ecf20Sopenharmony_ci switch (bitrate) { 1988c2ecf20Sopenharmony_ci case B43_CCK_RATE_1MB: 1998c2ecf20Sopenharmony_ci return B43_CCK_RATE_1MB; 2008c2ecf20Sopenharmony_ci case B43_CCK_RATE_2MB: 2018c2ecf20Sopenharmony_ci return B43_CCK_RATE_1MB; 2028c2ecf20Sopenharmony_ci case B43_CCK_RATE_5MB: 2038c2ecf20Sopenharmony_ci return B43_CCK_RATE_2MB; 2048c2ecf20Sopenharmony_ci case B43_CCK_RATE_11MB: 2058c2ecf20Sopenharmony_ci return B43_CCK_RATE_5MB; 2068c2ecf20Sopenharmony_ci /* 2078c2ecf20Sopenharmony_ci * Don't just fallback to CCK; it may be in 5GHz operation 2088c2ecf20Sopenharmony_ci * and falling back to CCK won't work out very well. 2098c2ecf20Sopenharmony_ci */ 2108c2ecf20Sopenharmony_ci case B43_OFDM_RATE_6MB: 2118c2ecf20Sopenharmony_ci if (gmode) 2128c2ecf20Sopenharmony_ci return B43_CCK_RATE_5MB; 2138c2ecf20Sopenharmony_ci else 2148c2ecf20Sopenharmony_ci return B43_OFDM_RATE_6MB; 2158c2ecf20Sopenharmony_ci case B43_OFDM_RATE_9MB: 2168c2ecf20Sopenharmony_ci return B43_OFDM_RATE_6MB; 2178c2ecf20Sopenharmony_ci case B43_OFDM_RATE_12MB: 2188c2ecf20Sopenharmony_ci return B43_OFDM_RATE_9MB; 2198c2ecf20Sopenharmony_ci case B43_OFDM_RATE_18MB: 2208c2ecf20Sopenharmony_ci return B43_OFDM_RATE_12MB; 2218c2ecf20Sopenharmony_ci case B43_OFDM_RATE_24MB: 2228c2ecf20Sopenharmony_ci return B43_OFDM_RATE_18MB; 2238c2ecf20Sopenharmony_ci case B43_OFDM_RATE_36MB: 2248c2ecf20Sopenharmony_ci return B43_OFDM_RATE_24MB; 2258c2ecf20Sopenharmony_ci case B43_OFDM_RATE_48MB: 2268c2ecf20Sopenharmony_ci return B43_OFDM_RATE_36MB; 2278c2ecf20Sopenharmony_ci case B43_OFDM_RATE_54MB: 2288c2ecf20Sopenharmony_ci return B43_OFDM_RATE_48MB; 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci B43_WARN_ON(1); 2318c2ecf20Sopenharmony_ci return 0; 2328c2ecf20Sopenharmony_ci} 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci/* Generate a TX data header. */ 2358c2ecf20Sopenharmony_ciint b43_generate_txhdr(struct b43_wldev *dev, 2368c2ecf20Sopenharmony_ci u8 *_txhdr, 2378c2ecf20Sopenharmony_ci struct sk_buff *skb_frag, 2388c2ecf20Sopenharmony_ci struct ieee80211_tx_info *info, 2398c2ecf20Sopenharmony_ci u16 cookie) 2408c2ecf20Sopenharmony_ci{ 2418c2ecf20Sopenharmony_ci const unsigned char *fragment_data = skb_frag->data; 2428c2ecf20Sopenharmony_ci unsigned int fragment_len = skb_frag->len; 2438c2ecf20Sopenharmony_ci struct b43_txhdr *txhdr = (struct b43_txhdr *)_txhdr; 2448c2ecf20Sopenharmony_ci const struct b43_phy *phy = &dev->phy; 2458c2ecf20Sopenharmony_ci const struct ieee80211_hdr *wlhdr = 2468c2ecf20Sopenharmony_ci (const struct ieee80211_hdr *)fragment_data; 2478c2ecf20Sopenharmony_ci int use_encryption = !!info->control.hw_key; 2488c2ecf20Sopenharmony_ci __le16 fctl = wlhdr->frame_control; 2498c2ecf20Sopenharmony_ci struct ieee80211_rate *fbrate; 2508c2ecf20Sopenharmony_ci u8 rate, rate_fb; 2518c2ecf20Sopenharmony_ci int rate_ofdm, rate_fb_ofdm; 2528c2ecf20Sopenharmony_ci unsigned int plcp_fragment_len; 2538c2ecf20Sopenharmony_ci u32 mac_ctl = 0; 2548c2ecf20Sopenharmony_ci u16 phy_ctl = 0; 2558c2ecf20Sopenharmony_ci bool fill_phy_ctl1 = (phy->type == B43_PHYTYPE_LP || 2568c2ecf20Sopenharmony_ci phy->type == B43_PHYTYPE_N || 2578c2ecf20Sopenharmony_ci phy->type == B43_PHYTYPE_HT); 2588c2ecf20Sopenharmony_ci u8 extra_ft = 0; 2598c2ecf20Sopenharmony_ci struct ieee80211_rate *txrate; 2608c2ecf20Sopenharmony_ci struct ieee80211_tx_rate *rates; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci memset(txhdr, 0, sizeof(*txhdr)); 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci txrate = ieee80211_get_tx_rate(dev->wl->hw, info); 2658c2ecf20Sopenharmony_ci rate = txrate ? txrate->hw_value : B43_CCK_RATE_1MB; 2668c2ecf20Sopenharmony_ci rate_ofdm = b43_is_ofdm_rate(rate); 2678c2ecf20Sopenharmony_ci fbrate = ieee80211_get_alt_retry_rate(dev->wl->hw, info, 0) ? : txrate; 2688c2ecf20Sopenharmony_ci rate_fb = fbrate->hw_value; 2698c2ecf20Sopenharmony_ci rate_fb_ofdm = b43_is_ofdm_rate(rate_fb); 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci if (rate_ofdm) 2728c2ecf20Sopenharmony_ci txhdr->phy_rate = b43_plcp_get_ratecode_ofdm(rate); 2738c2ecf20Sopenharmony_ci else 2748c2ecf20Sopenharmony_ci txhdr->phy_rate = b43_plcp_get_ratecode_cck(rate); 2758c2ecf20Sopenharmony_ci txhdr->mac_frame_ctl = wlhdr->frame_control; 2768c2ecf20Sopenharmony_ci memcpy(txhdr->tx_receiver, wlhdr->addr1, ETH_ALEN); 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci /* Calculate duration for fallback rate */ 2798c2ecf20Sopenharmony_ci if ((rate_fb == rate) || 2808c2ecf20Sopenharmony_ci (wlhdr->duration_id & cpu_to_le16(0x8000)) || 2818c2ecf20Sopenharmony_ci (wlhdr->duration_id == cpu_to_le16(0))) { 2828c2ecf20Sopenharmony_ci /* If the fallback rate equals the normal rate or the 2838c2ecf20Sopenharmony_ci * dur_id field contains an AID, CFP magic or 0, 2848c2ecf20Sopenharmony_ci * use the original dur_id field. */ 2858c2ecf20Sopenharmony_ci txhdr->dur_fb = wlhdr->duration_id; 2868c2ecf20Sopenharmony_ci } else { 2878c2ecf20Sopenharmony_ci txhdr->dur_fb = ieee80211_generic_frame_duration( 2888c2ecf20Sopenharmony_ci dev->wl->hw, info->control.vif, info->band, 2898c2ecf20Sopenharmony_ci fragment_len, fbrate); 2908c2ecf20Sopenharmony_ci } 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci plcp_fragment_len = fragment_len + FCS_LEN; 2938c2ecf20Sopenharmony_ci if (use_encryption) { 2948c2ecf20Sopenharmony_ci u8 key_idx = info->control.hw_key->hw_key_idx; 2958c2ecf20Sopenharmony_ci struct b43_key *key; 2968c2ecf20Sopenharmony_ci int wlhdr_len; 2978c2ecf20Sopenharmony_ci size_t iv_len; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci B43_WARN_ON(key_idx >= ARRAY_SIZE(dev->key)); 3008c2ecf20Sopenharmony_ci key = &(dev->key[key_idx]); 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci if (unlikely(!key->keyconf)) { 3038c2ecf20Sopenharmony_ci /* This key is invalid. This might only happen 3048c2ecf20Sopenharmony_ci * in a short timeframe after machine resume before 3058c2ecf20Sopenharmony_ci * we were able to reconfigure keys. 3068c2ecf20Sopenharmony_ci * Drop this packet completely. Do not transmit it 3078c2ecf20Sopenharmony_ci * unencrypted to avoid leaking information. */ 3088c2ecf20Sopenharmony_ci return -ENOKEY; 3098c2ecf20Sopenharmony_ci } 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci /* Hardware appends ICV. */ 3128c2ecf20Sopenharmony_ci plcp_fragment_len += info->control.hw_key->icv_len; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci key_idx = b43_kidx_to_fw(dev, key_idx); 3158c2ecf20Sopenharmony_ci mac_ctl |= (key_idx << B43_TXH_MAC_KEYIDX_SHIFT) & 3168c2ecf20Sopenharmony_ci B43_TXH_MAC_KEYIDX; 3178c2ecf20Sopenharmony_ci mac_ctl |= (key->algorithm << B43_TXH_MAC_KEYALG_SHIFT) & 3188c2ecf20Sopenharmony_ci B43_TXH_MAC_KEYALG; 3198c2ecf20Sopenharmony_ci wlhdr_len = ieee80211_hdrlen(fctl); 3208c2ecf20Sopenharmony_ci if (key->algorithm == B43_SEC_ALGO_TKIP) { 3218c2ecf20Sopenharmony_ci u16 phase1key[5]; 3228c2ecf20Sopenharmony_ci int i; 3238c2ecf20Sopenharmony_ci /* we give the phase1key and iv16 here, the key is stored in 3248c2ecf20Sopenharmony_ci * shm. With that the hardware can do phase 2 and encryption. 3258c2ecf20Sopenharmony_ci */ 3268c2ecf20Sopenharmony_ci ieee80211_get_tkip_p1k(info->control.hw_key, skb_frag, phase1key); 3278c2ecf20Sopenharmony_ci /* phase1key is in host endian. Copy to little-endian txhdr->iv. */ 3288c2ecf20Sopenharmony_ci for (i = 0; i < 5; i++) { 3298c2ecf20Sopenharmony_ci txhdr->iv[i * 2 + 0] = phase1key[i]; 3308c2ecf20Sopenharmony_ci txhdr->iv[i * 2 + 1] = phase1key[i] >> 8; 3318c2ecf20Sopenharmony_ci } 3328c2ecf20Sopenharmony_ci /* iv16 */ 3338c2ecf20Sopenharmony_ci memcpy(txhdr->iv + 10, ((u8 *) wlhdr) + wlhdr_len, 3); 3348c2ecf20Sopenharmony_ci } else { 3358c2ecf20Sopenharmony_ci iv_len = min_t(size_t, info->control.hw_key->iv_len, 3368c2ecf20Sopenharmony_ci ARRAY_SIZE(txhdr->iv)); 3378c2ecf20Sopenharmony_ci memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len); 3388c2ecf20Sopenharmony_ci } 3398c2ecf20Sopenharmony_ci } 3408c2ecf20Sopenharmony_ci switch (dev->fw.hdr_format) { 3418c2ecf20Sopenharmony_ci case B43_FW_HDR_598: 3428c2ecf20Sopenharmony_ci b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->format_598.plcp), 3438c2ecf20Sopenharmony_ci plcp_fragment_len, rate); 3448c2ecf20Sopenharmony_ci break; 3458c2ecf20Sopenharmony_ci case B43_FW_HDR_351: 3468c2ecf20Sopenharmony_ci b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->format_351.plcp), 3478c2ecf20Sopenharmony_ci plcp_fragment_len, rate); 3488c2ecf20Sopenharmony_ci break; 3498c2ecf20Sopenharmony_ci case B43_FW_HDR_410: 3508c2ecf20Sopenharmony_ci b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->format_410.plcp), 3518c2ecf20Sopenharmony_ci plcp_fragment_len, rate); 3528c2ecf20Sopenharmony_ci break; 3538c2ecf20Sopenharmony_ci } 3548c2ecf20Sopenharmony_ci b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->plcp_fb), 3558c2ecf20Sopenharmony_ci plcp_fragment_len, rate_fb); 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci /* Extra Frame Types */ 3588c2ecf20Sopenharmony_ci if (rate_fb_ofdm) 3598c2ecf20Sopenharmony_ci extra_ft |= B43_TXH_EFT_FB_OFDM; 3608c2ecf20Sopenharmony_ci else 3618c2ecf20Sopenharmony_ci extra_ft |= B43_TXH_EFT_FB_CCK; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci /* Set channel radio code. Note that the micrcode ORs 0x100 to 3648c2ecf20Sopenharmony_ci * this value before comparing it to the value in SHM, if this 3658c2ecf20Sopenharmony_ci * is a 5Ghz packet. 3668c2ecf20Sopenharmony_ci */ 3678c2ecf20Sopenharmony_ci txhdr->chan_radio_code = phy->channel; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci /* PHY TX Control word */ 3708c2ecf20Sopenharmony_ci if (rate_ofdm) 3718c2ecf20Sopenharmony_ci phy_ctl |= B43_TXH_PHY_ENC_OFDM; 3728c2ecf20Sopenharmony_ci else 3738c2ecf20Sopenharmony_ci phy_ctl |= B43_TXH_PHY_ENC_CCK; 3748c2ecf20Sopenharmony_ci if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) 3758c2ecf20Sopenharmony_ci phy_ctl |= B43_TXH_PHY_SHORTPRMBL; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci switch (b43_ieee80211_antenna_sanitize(dev, 0)) { 3788c2ecf20Sopenharmony_ci case 0: /* Default */ 3798c2ecf20Sopenharmony_ci phy_ctl |= B43_TXH_PHY_ANT01AUTO; 3808c2ecf20Sopenharmony_ci break; 3818c2ecf20Sopenharmony_ci case 1: /* Antenna 0 */ 3828c2ecf20Sopenharmony_ci phy_ctl |= B43_TXH_PHY_ANT0; 3838c2ecf20Sopenharmony_ci break; 3848c2ecf20Sopenharmony_ci case 2: /* Antenna 1 */ 3858c2ecf20Sopenharmony_ci phy_ctl |= B43_TXH_PHY_ANT1; 3868c2ecf20Sopenharmony_ci break; 3878c2ecf20Sopenharmony_ci case 3: /* Antenna 2 */ 3888c2ecf20Sopenharmony_ci phy_ctl |= B43_TXH_PHY_ANT2; 3898c2ecf20Sopenharmony_ci break; 3908c2ecf20Sopenharmony_ci case 4: /* Antenna 3 */ 3918c2ecf20Sopenharmony_ci phy_ctl |= B43_TXH_PHY_ANT3; 3928c2ecf20Sopenharmony_ci break; 3938c2ecf20Sopenharmony_ci default: 3948c2ecf20Sopenharmony_ci B43_WARN_ON(1); 3958c2ecf20Sopenharmony_ci } 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci rates = info->control.rates; 3988c2ecf20Sopenharmony_ci /* MAC control */ 3998c2ecf20Sopenharmony_ci if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) 4008c2ecf20Sopenharmony_ci mac_ctl |= B43_TXH_MAC_ACK; 4018c2ecf20Sopenharmony_ci /* use hardware sequence counter as the non-TID counter */ 4028c2ecf20Sopenharmony_ci if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) 4038c2ecf20Sopenharmony_ci mac_ctl |= B43_TXH_MAC_HWSEQ; 4048c2ecf20Sopenharmony_ci if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) 4058c2ecf20Sopenharmony_ci mac_ctl |= B43_TXH_MAC_STMSDU; 4068c2ecf20Sopenharmony_ci if (!phy->gmode) 4078c2ecf20Sopenharmony_ci mac_ctl |= B43_TXH_MAC_5GHZ; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci /* Overwrite rates[0].count to make the retry calculation 4108c2ecf20Sopenharmony_ci * in the tx status easier. need the actual retry limit to 4118c2ecf20Sopenharmony_ci * detect whether the fallback rate was used. 4128c2ecf20Sopenharmony_ci */ 4138c2ecf20Sopenharmony_ci if ((rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) || 4148c2ecf20Sopenharmony_ci (rates[0].count <= dev->wl->hw->conf.long_frame_max_tx_count)) { 4158c2ecf20Sopenharmony_ci rates[0].count = dev->wl->hw->conf.long_frame_max_tx_count; 4168c2ecf20Sopenharmony_ci mac_ctl |= B43_TXH_MAC_LONGFRAME; 4178c2ecf20Sopenharmony_ci } else { 4188c2ecf20Sopenharmony_ci rates[0].count = dev->wl->hw->conf.short_frame_max_tx_count; 4198c2ecf20Sopenharmony_ci } 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci /* Generate the RTS or CTS-to-self frame */ 4228c2ecf20Sopenharmony_ci if ((rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) || 4238c2ecf20Sopenharmony_ci (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)) { 4248c2ecf20Sopenharmony_ci unsigned int len; 4258c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr; 4268c2ecf20Sopenharmony_ci int rts_rate, rts_rate_fb; 4278c2ecf20Sopenharmony_ci int rts_rate_ofdm, rts_rate_fb_ofdm; 4288c2ecf20Sopenharmony_ci struct b43_plcp_hdr6 *plcp; 4298c2ecf20Sopenharmony_ci struct ieee80211_rate *rts_cts_rate; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci rts_cts_rate = ieee80211_get_rts_cts_rate(dev->wl->hw, info); 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci rts_rate = rts_cts_rate ? rts_cts_rate->hw_value : B43_CCK_RATE_1MB; 4348c2ecf20Sopenharmony_ci rts_rate_ofdm = b43_is_ofdm_rate(rts_rate); 4358c2ecf20Sopenharmony_ci rts_rate_fb = b43_calc_fallback_rate(rts_rate, phy->gmode); 4368c2ecf20Sopenharmony_ci rts_rate_fb_ofdm = b43_is_ofdm_rate(rts_rate_fb); 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci if (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { 4398c2ecf20Sopenharmony_ci struct ieee80211_cts *cts; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci switch (dev->fw.hdr_format) { 4428c2ecf20Sopenharmony_ci case B43_FW_HDR_598: 4438c2ecf20Sopenharmony_ci cts = (struct ieee80211_cts *) 4448c2ecf20Sopenharmony_ci (txhdr->format_598.rts_frame); 4458c2ecf20Sopenharmony_ci break; 4468c2ecf20Sopenharmony_ci case B43_FW_HDR_351: 4478c2ecf20Sopenharmony_ci cts = (struct ieee80211_cts *) 4488c2ecf20Sopenharmony_ci (txhdr->format_351.rts_frame); 4498c2ecf20Sopenharmony_ci break; 4508c2ecf20Sopenharmony_ci case B43_FW_HDR_410: 4518c2ecf20Sopenharmony_ci cts = (struct ieee80211_cts *) 4528c2ecf20Sopenharmony_ci (txhdr->format_410.rts_frame); 4538c2ecf20Sopenharmony_ci break; 4548c2ecf20Sopenharmony_ci } 4558c2ecf20Sopenharmony_ci ieee80211_ctstoself_get(dev->wl->hw, info->control.vif, 4568c2ecf20Sopenharmony_ci fragment_data, fragment_len, 4578c2ecf20Sopenharmony_ci info, cts); 4588c2ecf20Sopenharmony_ci mac_ctl |= B43_TXH_MAC_SENDCTS; 4598c2ecf20Sopenharmony_ci len = sizeof(struct ieee80211_cts); 4608c2ecf20Sopenharmony_ci } else { 4618c2ecf20Sopenharmony_ci struct ieee80211_rts *rts; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci switch (dev->fw.hdr_format) { 4648c2ecf20Sopenharmony_ci case B43_FW_HDR_598: 4658c2ecf20Sopenharmony_ci rts = (struct ieee80211_rts *) 4668c2ecf20Sopenharmony_ci (txhdr->format_598.rts_frame); 4678c2ecf20Sopenharmony_ci break; 4688c2ecf20Sopenharmony_ci case B43_FW_HDR_351: 4698c2ecf20Sopenharmony_ci rts = (struct ieee80211_rts *) 4708c2ecf20Sopenharmony_ci (txhdr->format_351.rts_frame); 4718c2ecf20Sopenharmony_ci break; 4728c2ecf20Sopenharmony_ci case B43_FW_HDR_410: 4738c2ecf20Sopenharmony_ci rts = (struct ieee80211_rts *) 4748c2ecf20Sopenharmony_ci (txhdr->format_410.rts_frame); 4758c2ecf20Sopenharmony_ci break; 4768c2ecf20Sopenharmony_ci } 4778c2ecf20Sopenharmony_ci ieee80211_rts_get(dev->wl->hw, info->control.vif, 4788c2ecf20Sopenharmony_ci fragment_data, fragment_len, 4798c2ecf20Sopenharmony_ci info, rts); 4808c2ecf20Sopenharmony_ci mac_ctl |= B43_TXH_MAC_SENDRTS; 4818c2ecf20Sopenharmony_ci len = sizeof(struct ieee80211_rts); 4828c2ecf20Sopenharmony_ci } 4838c2ecf20Sopenharmony_ci len += FCS_LEN; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci /* Generate the PLCP headers for the RTS/CTS frame */ 4868c2ecf20Sopenharmony_ci switch (dev->fw.hdr_format) { 4878c2ecf20Sopenharmony_ci case B43_FW_HDR_598: 4888c2ecf20Sopenharmony_ci plcp = &txhdr->format_598.rts_plcp; 4898c2ecf20Sopenharmony_ci break; 4908c2ecf20Sopenharmony_ci case B43_FW_HDR_351: 4918c2ecf20Sopenharmony_ci plcp = &txhdr->format_351.rts_plcp; 4928c2ecf20Sopenharmony_ci break; 4938c2ecf20Sopenharmony_ci case B43_FW_HDR_410: 4948c2ecf20Sopenharmony_ci plcp = &txhdr->format_410.rts_plcp; 4958c2ecf20Sopenharmony_ci break; 4968c2ecf20Sopenharmony_ci } 4978c2ecf20Sopenharmony_ci b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)plcp, 4988c2ecf20Sopenharmony_ci len, rts_rate); 4998c2ecf20Sopenharmony_ci plcp = &txhdr->rts_plcp_fb; 5008c2ecf20Sopenharmony_ci b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)plcp, 5018c2ecf20Sopenharmony_ci len, rts_rate_fb); 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci switch (dev->fw.hdr_format) { 5048c2ecf20Sopenharmony_ci case B43_FW_HDR_598: 5058c2ecf20Sopenharmony_ci hdr = (struct ieee80211_hdr *) 5068c2ecf20Sopenharmony_ci (&txhdr->format_598.rts_frame); 5078c2ecf20Sopenharmony_ci break; 5088c2ecf20Sopenharmony_ci case B43_FW_HDR_351: 5098c2ecf20Sopenharmony_ci hdr = (struct ieee80211_hdr *) 5108c2ecf20Sopenharmony_ci (&txhdr->format_351.rts_frame); 5118c2ecf20Sopenharmony_ci break; 5128c2ecf20Sopenharmony_ci case B43_FW_HDR_410: 5138c2ecf20Sopenharmony_ci hdr = (struct ieee80211_hdr *) 5148c2ecf20Sopenharmony_ci (&txhdr->format_410.rts_frame); 5158c2ecf20Sopenharmony_ci break; 5168c2ecf20Sopenharmony_ci } 5178c2ecf20Sopenharmony_ci txhdr->rts_dur_fb = hdr->duration_id; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci if (rts_rate_ofdm) { 5208c2ecf20Sopenharmony_ci extra_ft |= B43_TXH_EFT_RTS_OFDM; 5218c2ecf20Sopenharmony_ci txhdr->phy_rate_rts = 5228c2ecf20Sopenharmony_ci b43_plcp_get_ratecode_ofdm(rts_rate); 5238c2ecf20Sopenharmony_ci } else { 5248c2ecf20Sopenharmony_ci extra_ft |= B43_TXH_EFT_RTS_CCK; 5258c2ecf20Sopenharmony_ci txhdr->phy_rate_rts = 5268c2ecf20Sopenharmony_ci b43_plcp_get_ratecode_cck(rts_rate); 5278c2ecf20Sopenharmony_ci } 5288c2ecf20Sopenharmony_ci if (rts_rate_fb_ofdm) 5298c2ecf20Sopenharmony_ci extra_ft |= B43_TXH_EFT_RTSFB_OFDM; 5308c2ecf20Sopenharmony_ci else 5318c2ecf20Sopenharmony_ci extra_ft |= B43_TXH_EFT_RTSFB_CCK; 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci if (rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS && 5348c2ecf20Sopenharmony_ci fill_phy_ctl1) { 5358c2ecf20Sopenharmony_ci txhdr->phy_ctl1_rts = cpu_to_le16( 5368c2ecf20Sopenharmony_ci b43_generate_tx_phy_ctl1(dev, rts_rate)); 5378c2ecf20Sopenharmony_ci txhdr->phy_ctl1_rts_fb = cpu_to_le16( 5388c2ecf20Sopenharmony_ci b43_generate_tx_phy_ctl1(dev, rts_rate_fb)); 5398c2ecf20Sopenharmony_ci } 5408c2ecf20Sopenharmony_ci } 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci /* Magic cookie */ 5438c2ecf20Sopenharmony_ci switch (dev->fw.hdr_format) { 5448c2ecf20Sopenharmony_ci case B43_FW_HDR_598: 5458c2ecf20Sopenharmony_ci txhdr->format_598.cookie = cpu_to_le16(cookie); 5468c2ecf20Sopenharmony_ci break; 5478c2ecf20Sopenharmony_ci case B43_FW_HDR_351: 5488c2ecf20Sopenharmony_ci txhdr->format_351.cookie = cpu_to_le16(cookie); 5498c2ecf20Sopenharmony_ci break; 5508c2ecf20Sopenharmony_ci case B43_FW_HDR_410: 5518c2ecf20Sopenharmony_ci txhdr->format_410.cookie = cpu_to_le16(cookie); 5528c2ecf20Sopenharmony_ci break; 5538c2ecf20Sopenharmony_ci } 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci if (fill_phy_ctl1) { 5568c2ecf20Sopenharmony_ci txhdr->phy_ctl1 = 5578c2ecf20Sopenharmony_ci cpu_to_le16(b43_generate_tx_phy_ctl1(dev, rate)); 5588c2ecf20Sopenharmony_ci txhdr->phy_ctl1_fb = 5598c2ecf20Sopenharmony_ci cpu_to_le16(b43_generate_tx_phy_ctl1(dev, rate_fb)); 5608c2ecf20Sopenharmony_ci } 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci /* Apply the bitfields */ 5638c2ecf20Sopenharmony_ci txhdr->mac_ctl = cpu_to_le32(mac_ctl); 5648c2ecf20Sopenharmony_ci txhdr->phy_ctl = cpu_to_le16(phy_ctl); 5658c2ecf20Sopenharmony_ci txhdr->extra_ft = extra_ft; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci return 0; 5688c2ecf20Sopenharmony_ci} 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_cistatic s8 b43_rssi_postprocess(struct b43_wldev *dev, 5718c2ecf20Sopenharmony_ci u8 in_rssi, int ofdm, 5728c2ecf20Sopenharmony_ci int adjust_2053, int adjust_2050) 5738c2ecf20Sopenharmony_ci{ 5748c2ecf20Sopenharmony_ci struct b43_phy *phy = &dev->phy; 5758c2ecf20Sopenharmony_ci struct b43_phy_g *gphy = phy->g; 5768c2ecf20Sopenharmony_ci s32 tmp; 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci switch (phy->radio_ver) { 5798c2ecf20Sopenharmony_ci case 0x2050: 5808c2ecf20Sopenharmony_ci if (ofdm) { 5818c2ecf20Sopenharmony_ci tmp = in_rssi; 5828c2ecf20Sopenharmony_ci if (tmp > 127) 5838c2ecf20Sopenharmony_ci tmp -= 256; 5848c2ecf20Sopenharmony_ci tmp *= 73; 5858c2ecf20Sopenharmony_ci tmp /= 64; 5868c2ecf20Sopenharmony_ci if (adjust_2050) 5878c2ecf20Sopenharmony_ci tmp += 25; 5888c2ecf20Sopenharmony_ci else 5898c2ecf20Sopenharmony_ci tmp -= 3; 5908c2ecf20Sopenharmony_ci } else { 5918c2ecf20Sopenharmony_ci if (dev->dev->bus_sprom-> 5928c2ecf20Sopenharmony_ci boardflags_lo & B43_BFL_RSSI) { 5938c2ecf20Sopenharmony_ci if (in_rssi > 63) 5948c2ecf20Sopenharmony_ci in_rssi = 63; 5958c2ecf20Sopenharmony_ci B43_WARN_ON(phy->type != B43_PHYTYPE_G); 5968c2ecf20Sopenharmony_ci tmp = gphy->nrssi_lt[in_rssi]; 5978c2ecf20Sopenharmony_ci tmp = 31 - tmp; 5988c2ecf20Sopenharmony_ci tmp *= -131; 5998c2ecf20Sopenharmony_ci tmp /= 128; 6008c2ecf20Sopenharmony_ci tmp -= 57; 6018c2ecf20Sopenharmony_ci } else { 6028c2ecf20Sopenharmony_ci tmp = in_rssi; 6038c2ecf20Sopenharmony_ci tmp = 31 - tmp; 6048c2ecf20Sopenharmony_ci tmp *= -149; 6058c2ecf20Sopenharmony_ci tmp /= 128; 6068c2ecf20Sopenharmony_ci tmp -= 68; 6078c2ecf20Sopenharmony_ci } 6088c2ecf20Sopenharmony_ci if (phy->type == B43_PHYTYPE_G && adjust_2050) 6098c2ecf20Sopenharmony_ci tmp += 25; 6108c2ecf20Sopenharmony_ci } 6118c2ecf20Sopenharmony_ci break; 6128c2ecf20Sopenharmony_ci case 0x2060: 6138c2ecf20Sopenharmony_ci if (in_rssi > 127) 6148c2ecf20Sopenharmony_ci tmp = in_rssi - 256; 6158c2ecf20Sopenharmony_ci else 6168c2ecf20Sopenharmony_ci tmp = in_rssi; 6178c2ecf20Sopenharmony_ci break; 6188c2ecf20Sopenharmony_ci default: 6198c2ecf20Sopenharmony_ci tmp = in_rssi; 6208c2ecf20Sopenharmony_ci tmp -= 11; 6218c2ecf20Sopenharmony_ci tmp *= 103; 6228c2ecf20Sopenharmony_ci tmp /= 64; 6238c2ecf20Sopenharmony_ci if (adjust_2053) 6248c2ecf20Sopenharmony_ci tmp -= 109; 6258c2ecf20Sopenharmony_ci else 6268c2ecf20Sopenharmony_ci tmp -= 83; 6278c2ecf20Sopenharmony_ci } 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci return (s8) tmp; 6308c2ecf20Sopenharmony_ci} 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_civoid b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) 6338c2ecf20Sopenharmony_ci{ 6348c2ecf20Sopenharmony_ci struct ieee80211_rx_status status; 6358c2ecf20Sopenharmony_ci struct b43_plcp_hdr6 *plcp; 6368c2ecf20Sopenharmony_ci struct ieee80211_hdr *wlhdr; 6378c2ecf20Sopenharmony_ci const struct b43_rxhdr_fw4 *rxhdr = _rxhdr; 6388c2ecf20Sopenharmony_ci __le16 fctl; 6398c2ecf20Sopenharmony_ci u16 phystat0, phystat3; 6408c2ecf20Sopenharmony_ci u16 chanstat, mactime; 6418c2ecf20Sopenharmony_ci u32 macstat; 6428c2ecf20Sopenharmony_ci u16 chanid; 6438c2ecf20Sopenharmony_ci int padding, rate_idx; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci memset(&status, 0, sizeof(status)); 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci /* Get metadata about the frame from the header. */ 6488c2ecf20Sopenharmony_ci phystat0 = le16_to_cpu(rxhdr->phy_status0); 6498c2ecf20Sopenharmony_ci phystat3 = le16_to_cpu(rxhdr->phy_status3); 6508c2ecf20Sopenharmony_ci switch (dev->fw.hdr_format) { 6518c2ecf20Sopenharmony_ci case B43_FW_HDR_598: 6528c2ecf20Sopenharmony_ci macstat = le32_to_cpu(rxhdr->format_598.mac_status); 6538c2ecf20Sopenharmony_ci mactime = le16_to_cpu(rxhdr->format_598.mac_time); 6548c2ecf20Sopenharmony_ci chanstat = le16_to_cpu(rxhdr->format_598.channel); 6558c2ecf20Sopenharmony_ci break; 6568c2ecf20Sopenharmony_ci case B43_FW_HDR_410: 6578c2ecf20Sopenharmony_ci case B43_FW_HDR_351: 6588c2ecf20Sopenharmony_ci macstat = le32_to_cpu(rxhdr->format_351.mac_status); 6598c2ecf20Sopenharmony_ci mactime = le16_to_cpu(rxhdr->format_351.mac_time); 6608c2ecf20Sopenharmony_ci chanstat = le16_to_cpu(rxhdr->format_351.channel); 6618c2ecf20Sopenharmony_ci break; 6628c2ecf20Sopenharmony_ci } 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci if (unlikely(macstat & B43_RX_MAC_FCSERR)) { 6658c2ecf20Sopenharmony_ci dev->wl->ieee_stats.dot11FCSErrorCount++; 6668c2ecf20Sopenharmony_ci status.flag |= RX_FLAG_FAILED_FCS_CRC; 6678c2ecf20Sopenharmony_ci } 6688c2ecf20Sopenharmony_ci if (unlikely(phystat0 & (B43_RX_PHYST0_PLCPHCF | B43_RX_PHYST0_PLCPFV))) 6698c2ecf20Sopenharmony_ci status.flag |= RX_FLAG_FAILED_PLCP_CRC; 6708c2ecf20Sopenharmony_ci if (phystat0 & B43_RX_PHYST0_SHORTPRMBL) 6718c2ecf20Sopenharmony_ci status.enc_flags |= RX_ENC_FLAG_SHORTPRE; 6728c2ecf20Sopenharmony_ci if (macstat & B43_RX_MAC_DECERR) { 6738c2ecf20Sopenharmony_ci /* Decryption with the given key failed. 6748c2ecf20Sopenharmony_ci * Drop the packet. We also won't be able to decrypt it with 6758c2ecf20Sopenharmony_ci * the key in software. */ 6768c2ecf20Sopenharmony_ci goto drop; 6778c2ecf20Sopenharmony_ci } 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci /* Skip PLCP and padding */ 6808c2ecf20Sopenharmony_ci padding = (macstat & B43_RX_MAC_PADDING) ? 2 : 0; 6818c2ecf20Sopenharmony_ci if (unlikely(skb->len < (sizeof(struct b43_plcp_hdr6) + padding))) { 6828c2ecf20Sopenharmony_ci b43dbg(dev->wl, "RX: Packet size underrun (1)\n"); 6838c2ecf20Sopenharmony_ci goto drop; 6848c2ecf20Sopenharmony_ci } 6858c2ecf20Sopenharmony_ci plcp = (struct b43_plcp_hdr6 *)(skb->data + padding); 6868c2ecf20Sopenharmony_ci skb_pull(skb, sizeof(struct b43_plcp_hdr6) + padding); 6878c2ecf20Sopenharmony_ci /* The skb contains the Wireless Header + payload data now */ 6888c2ecf20Sopenharmony_ci if (unlikely(skb->len < (2 + 2 + 6 /*minimum hdr */ + FCS_LEN))) { 6898c2ecf20Sopenharmony_ci b43dbg(dev->wl, "RX: Packet size underrun (2)\n"); 6908c2ecf20Sopenharmony_ci goto drop; 6918c2ecf20Sopenharmony_ci } 6928c2ecf20Sopenharmony_ci wlhdr = (struct ieee80211_hdr *)(skb->data); 6938c2ecf20Sopenharmony_ci fctl = wlhdr->frame_control; 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci if (macstat & B43_RX_MAC_DEC) { 6968c2ecf20Sopenharmony_ci unsigned int keyidx; 6978c2ecf20Sopenharmony_ci int wlhdr_len; 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci keyidx = ((macstat & B43_RX_MAC_KEYIDX) 7008c2ecf20Sopenharmony_ci >> B43_RX_MAC_KEYIDX_SHIFT); 7018c2ecf20Sopenharmony_ci /* We must adjust the key index here. We want the "physical" 7028c2ecf20Sopenharmony_ci * key index, but the ucode passed it slightly different. 7038c2ecf20Sopenharmony_ci */ 7048c2ecf20Sopenharmony_ci keyidx = b43_kidx_to_raw(dev, keyidx); 7058c2ecf20Sopenharmony_ci B43_WARN_ON(keyidx >= ARRAY_SIZE(dev->key)); 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci if (dev->key[keyidx].algorithm != B43_SEC_ALGO_NONE) { 7088c2ecf20Sopenharmony_ci wlhdr_len = ieee80211_hdrlen(fctl); 7098c2ecf20Sopenharmony_ci if (unlikely(skb->len < (wlhdr_len + 3))) { 7108c2ecf20Sopenharmony_ci b43dbg(dev->wl, 7118c2ecf20Sopenharmony_ci "RX: Packet size underrun (3)\n"); 7128c2ecf20Sopenharmony_ci goto drop; 7138c2ecf20Sopenharmony_ci } 7148c2ecf20Sopenharmony_ci status.flag |= RX_FLAG_DECRYPTED; 7158c2ecf20Sopenharmony_ci } 7168c2ecf20Sopenharmony_ci } 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci /* Link quality statistics */ 7198c2ecf20Sopenharmony_ci switch (chanstat & B43_RX_CHAN_PHYTYPE) { 7208c2ecf20Sopenharmony_ci case B43_PHYTYPE_HT: 7218c2ecf20Sopenharmony_ci /* TODO: is max the right choice? */ 7228c2ecf20Sopenharmony_ci status.signal = max_t(__s8, 7238c2ecf20Sopenharmony_ci max(rxhdr->phy_ht_power0, rxhdr->phy_ht_power1), 7248c2ecf20Sopenharmony_ci rxhdr->phy_ht_power2); 7258c2ecf20Sopenharmony_ci break; 7268c2ecf20Sopenharmony_ci case B43_PHYTYPE_N: 7278c2ecf20Sopenharmony_ci /* Broadcom has code for min and avg, but always uses max */ 7288c2ecf20Sopenharmony_ci if (rxhdr->power0 == 16 || rxhdr->power0 == 32) 7298c2ecf20Sopenharmony_ci status.signal = max(rxhdr->power1, rxhdr->power2); 7308c2ecf20Sopenharmony_ci else 7318c2ecf20Sopenharmony_ci status.signal = max(rxhdr->power0, rxhdr->power1); 7328c2ecf20Sopenharmony_ci break; 7338c2ecf20Sopenharmony_ci case B43_PHYTYPE_B: 7348c2ecf20Sopenharmony_ci case B43_PHYTYPE_G: 7358c2ecf20Sopenharmony_ci case B43_PHYTYPE_LP: 7368c2ecf20Sopenharmony_ci status.signal = b43_rssi_postprocess(dev, rxhdr->jssi, 7378c2ecf20Sopenharmony_ci (phystat0 & B43_RX_PHYST0_OFDM), 7388c2ecf20Sopenharmony_ci (phystat0 & B43_RX_PHYST0_GAINCTL), 7398c2ecf20Sopenharmony_ci (phystat3 & B43_RX_PHYST3_TRSTATE)); 7408c2ecf20Sopenharmony_ci break; 7418c2ecf20Sopenharmony_ci } 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci if (phystat0 & B43_RX_PHYST0_OFDM) 7448c2ecf20Sopenharmony_ci rate_idx = b43_plcp_get_bitrate_idx_ofdm(plcp, 7458c2ecf20Sopenharmony_ci !!(chanstat & B43_RX_CHAN_5GHZ)); 7468c2ecf20Sopenharmony_ci else 7478c2ecf20Sopenharmony_ci rate_idx = b43_plcp_get_bitrate_idx_cck(plcp); 7488c2ecf20Sopenharmony_ci if (unlikely(rate_idx == -1)) { 7498c2ecf20Sopenharmony_ci /* PLCP seems to be corrupted. 7508c2ecf20Sopenharmony_ci * Drop the frame, if we are not interested in corrupted frames. */ 7518c2ecf20Sopenharmony_ci if (!(dev->wl->filter_flags & FIF_PLCPFAIL)) 7528c2ecf20Sopenharmony_ci goto drop; 7538c2ecf20Sopenharmony_ci } 7548c2ecf20Sopenharmony_ci status.rate_idx = rate_idx; 7558c2ecf20Sopenharmony_ci status.antenna = !!(phystat0 & B43_RX_PHYST0_ANT); 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci /* 7588c2ecf20Sopenharmony_ci * All frames on monitor interfaces and beacons always need a full 7598c2ecf20Sopenharmony_ci * 64-bit timestamp. Monitor interfaces need it for diagnostic 7608c2ecf20Sopenharmony_ci * purposes and beacons for IBSS merging. 7618c2ecf20Sopenharmony_ci * This code assumes we get to process the packet within 16 bits 7628c2ecf20Sopenharmony_ci * of timestamp, i.e. about 65 milliseconds after the PHY received 7638c2ecf20Sopenharmony_ci * the first symbol. 7648c2ecf20Sopenharmony_ci */ 7658c2ecf20Sopenharmony_ci if (ieee80211_is_beacon(fctl) || dev->wl->radiotap_enabled) { 7668c2ecf20Sopenharmony_ci u16 low_mactime_now; 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci b43_tsf_read(dev, &status.mactime); 7698c2ecf20Sopenharmony_ci low_mactime_now = status.mactime; 7708c2ecf20Sopenharmony_ci status.mactime = status.mactime & ~0xFFFFULL; 7718c2ecf20Sopenharmony_ci status.mactime += mactime; 7728c2ecf20Sopenharmony_ci if (low_mactime_now <= mactime) 7738c2ecf20Sopenharmony_ci status.mactime -= 0x10000; 7748c2ecf20Sopenharmony_ci status.flag |= RX_FLAG_MACTIME_START; 7758c2ecf20Sopenharmony_ci } 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci chanid = (chanstat & B43_RX_CHAN_ID) >> B43_RX_CHAN_ID_SHIFT; 7788c2ecf20Sopenharmony_ci switch (chanstat & B43_RX_CHAN_PHYTYPE) { 7798c2ecf20Sopenharmony_ci case B43_PHYTYPE_G: 7808c2ecf20Sopenharmony_ci status.band = NL80211_BAND_2GHZ; 7818c2ecf20Sopenharmony_ci /* Somewhere between 478.104 and 508.1084 firmware for G-PHY 7828c2ecf20Sopenharmony_ci * has been modified to be compatible with N-PHY and others. 7838c2ecf20Sopenharmony_ci */ 7848c2ecf20Sopenharmony_ci if (dev->fw.rev >= 508) 7858c2ecf20Sopenharmony_ci status.freq = ieee80211_channel_to_frequency(chanid, status.band); 7868c2ecf20Sopenharmony_ci else 7878c2ecf20Sopenharmony_ci status.freq = chanid + 2400; 7888c2ecf20Sopenharmony_ci break; 7898c2ecf20Sopenharmony_ci case B43_PHYTYPE_N: 7908c2ecf20Sopenharmony_ci case B43_PHYTYPE_LP: 7918c2ecf20Sopenharmony_ci case B43_PHYTYPE_HT: 7928c2ecf20Sopenharmony_ci /* chanid is the SHM channel cookie. Which is the plain 7938c2ecf20Sopenharmony_ci * channel number in b43. */ 7948c2ecf20Sopenharmony_ci if (chanstat & B43_RX_CHAN_5GHZ) 7958c2ecf20Sopenharmony_ci status.band = NL80211_BAND_5GHZ; 7968c2ecf20Sopenharmony_ci else 7978c2ecf20Sopenharmony_ci status.band = NL80211_BAND_2GHZ; 7988c2ecf20Sopenharmony_ci status.freq = 7998c2ecf20Sopenharmony_ci ieee80211_channel_to_frequency(chanid, status.band); 8008c2ecf20Sopenharmony_ci break; 8018c2ecf20Sopenharmony_ci default: 8028c2ecf20Sopenharmony_ci B43_WARN_ON(1); 8038c2ecf20Sopenharmony_ci goto drop; 8048c2ecf20Sopenharmony_ci } 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); 8078c2ecf20Sopenharmony_ci ieee80211_rx_ni(dev->wl->hw, skb); 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci#if B43_DEBUG 8108c2ecf20Sopenharmony_ci dev->rx_count++; 8118c2ecf20Sopenharmony_ci#endif 8128c2ecf20Sopenharmony_ci return; 8138c2ecf20Sopenharmony_cidrop: 8148c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 8158c2ecf20Sopenharmony_ci} 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_civoid b43_handle_txstatus(struct b43_wldev *dev, 8188c2ecf20Sopenharmony_ci const struct b43_txstatus *status) 8198c2ecf20Sopenharmony_ci{ 8208c2ecf20Sopenharmony_ci b43_debugfs_log_txstat(dev, status); 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci if (status->intermediate) 8238c2ecf20Sopenharmony_ci return; 8248c2ecf20Sopenharmony_ci if (status->for_ampdu) 8258c2ecf20Sopenharmony_ci return; 8268c2ecf20Sopenharmony_ci if (!status->acked) 8278c2ecf20Sopenharmony_ci dev->wl->ieee_stats.dot11ACKFailureCount++; 8288c2ecf20Sopenharmony_ci if (status->rts_count) { 8298c2ecf20Sopenharmony_ci if (status->rts_count == 0xF) //FIXME 8308c2ecf20Sopenharmony_ci dev->wl->ieee_stats.dot11RTSFailureCount++; 8318c2ecf20Sopenharmony_ci else 8328c2ecf20Sopenharmony_ci dev->wl->ieee_stats.dot11RTSSuccessCount++; 8338c2ecf20Sopenharmony_ci } 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci if (b43_using_pio_transfers(dev)) 8368c2ecf20Sopenharmony_ci b43_pio_handle_txstatus(dev, status); 8378c2ecf20Sopenharmony_ci else 8388c2ecf20Sopenharmony_ci b43_dma_handle_txstatus(dev, status); 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci b43_phy_txpower_check(dev, 0); 8418c2ecf20Sopenharmony_ci} 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci/* Fill out the mac80211 TXstatus report based on the b43-specific 8448c2ecf20Sopenharmony_ci * txstatus report data. This returns a boolean whether the frame was 8458c2ecf20Sopenharmony_ci * successfully transmitted. */ 8468c2ecf20Sopenharmony_cibool b43_fill_txstatus_report(struct b43_wldev *dev, 8478c2ecf20Sopenharmony_ci struct ieee80211_tx_info *report, 8488c2ecf20Sopenharmony_ci const struct b43_txstatus *status) 8498c2ecf20Sopenharmony_ci{ 8508c2ecf20Sopenharmony_ci bool frame_success = true; 8518c2ecf20Sopenharmony_ci int retry_limit; 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci /* preserve the confiured retry limit before clearing the status 8548c2ecf20Sopenharmony_ci * The xmit function has overwritten the rc's value with the actual 8558c2ecf20Sopenharmony_ci * retry limit done by the hardware */ 8568c2ecf20Sopenharmony_ci retry_limit = report->status.rates[0].count; 8578c2ecf20Sopenharmony_ci ieee80211_tx_info_clear_status(report); 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci if (status->acked) { 8608c2ecf20Sopenharmony_ci /* The frame was ACKed. */ 8618c2ecf20Sopenharmony_ci report->flags |= IEEE80211_TX_STAT_ACK; 8628c2ecf20Sopenharmony_ci } else { 8638c2ecf20Sopenharmony_ci /* The frame was not ACKed... */ 8648c2ecf20Sopenharmony_ci if (!(report->flags & IEEE80211_TX_CTL_NO_ACK)) { 8658c2ecf20Sopenharmony_ci /* ...but we expected an ACK. */ 8668c2ecf20Sopenharmony_ci frame_success = false; 8678c2ecf20Sopenharmony_ci } 8688c2ecf20Sopenharmony_ci } 8698c2ecf20Sopenharmony_ci if (status->frame_count == 0) { 8708c2ecf20Sopenharmony_ci /* The frame was not transmitted at all. */ 8718c2ecf20Sopenharmony_ci report->status.rates[0].count = 0; 8728c2ecf20Sopenharmony_ci } else if (status->rts_count > dev->wl->hw->conf.short_frame_max_tx_count) { 8738c2ecf20Sopenharmony_ci /* 8748c2ecf20Sopenharmony_ci * If the short retries (RTS, not data frame) have exceeded 8758c2ecf20Sopenharmony_ci * the limit, the hw will not have tried the selected rate, 8768c2ecf20Sopenharmony_ci * but will have used the fallback rate instead. 8778c2ecf20Sopenharmony_ci * Don't let the rate control count attempts for the selected 8788c2ecf20Sopenharmony_ci * rate in this case, otherwise the statistics will be off. 8798c2ecf20Sopenharmony_ci */ 8808c2ecf20Sopenharmony_ci report->status.rates[0].count = 0; 8818c2ecf20Sopenharmony_ci report->status.rates[1].count = status->frame_count; 8828c2ecf20Sopenharmony_ci } else { 8838c2ecf20Sopenharmony_ci if (status->frame_count > retry_limit) { 8848c2ecf20Sopenharmony_ci report->status.rates[0].count = retry_limit; 8858c2ecf20Sopenharmony_ci report->status.rates[1].count = status->frame_count - 8868c2ecf20Sopenharmony_ci retry_limit; 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci } else { 8898c2ecf20Sopenharmony_ci report->status.rates[0].count = status->frame_count; 8908c2ecf20Sopenharmony_ci report->status.rates[1].idx = -1; 8918c2ecf20Sopenharmony_ci } 8928c2ecf20Sopenharmony_ci } 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci return frame_success; 8958c2ecf20Sopenharmony_ci} 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci/* Stop any TX operation on the device (suspend the hardware queues) */ 8988c2ecf20Sopenharmony_civoid b43_tx_suspend(struct b43_wldev *dev) 8998c2ecf20Sopenharmony_ci{ 9008c2ecf20Sopenharmony_ci if (b43_using_pio_transfers(dev)) 9018c2ecf20Sopenharmony_ci b43_pio_tx_suspend(dev); 9028c2ecf20Sopenharmony_ci else 9038c2ecf20Sopenharmony_ci b43_dma_tx_suspend(dev); 9048c2ecf20Sopenharmony_ci} 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci/* Resume any TX operation on the device (resume the hardware queues) */ 9078c2ecf20Sopenharmony_civoid b43_tx_resume(struct b43_wldev *dev) 9088c2ecf20Sopenharmony_ci{ 9098c2ecf20Sopenharmony_ci if (b43_using_pio_transfers(dev)) 9108c2ecf20Sopenharmony_ci b43_pio_tx_resume(dev); 9118c2ecf20Sopenharmony_ci else 9128c2ecf20Sopenharmony_ci b43_dma_tx_resume(dev); 9138c2ecf20Sopenharmony_ci} 914