18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org> 38c2ecf20Sopenharmony_ci * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com> 48c2ecf20Sopenharmony_ci * Copyright (c) 2007-2008 Pavel Roskin <proski@gnu.org> 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Permission to use, copy, modify, and distribute this software for any 78c2ecf20Sopenharmony_ci * purpose with or without fee is hereby granted, provided that the above 88c2ecf20Sopenharmony_ci * copyright notice and this permission notice appear in all copies. 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 118c2ecf20Sopenharmony_ci * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 128c2ecf20Sopenharmony_ci * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 138c2ecf20Sopenharmony_ci * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 148c2ecf20Sopenharmony_ci * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 158c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 168c2ecf20Sopenharmony_ci * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci */ 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci/******************************\ 218c2ecf20Sopenharmony_ci Hardware Descriptor Functions 228c2ecf20Sopenharmony_ci\******************************/ 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#include "ath5k.h" 278c2ecf20Sopenharmony_ci#include "reg.h" 288c2ecf20Sopenharmony_ci#include "debug.h" 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci/** 328c2ecf20Sopenharmony_ci * DOC: Hardware descriptor functions 338c2ecf20Sopenharmony_ci * 348c2ecf20Sopenharmony_ci * Here we handle the processing of the low-level hw descriptors 358c2ecf20Sopenharmony_ci * that hw reads and writes via DMA for each TX and RX attempt (that means 368c2ecf20Sopenharmony_ci * we can also have descriptors for failed TX/RX tries). We have two kind of 378c2ecf20Sopenharmony_ci * descriptors for RX and TX, control descriptors tell the hw how to send or 388c2ecf20Sopenharmony_ci * receive a packet where to read/write it from/to etc and status descriptors 398c2ecf20Sopenharmony_ci * that contain information about how the packet was sent or received (errors 408c2ecf20Sopenharmony_ci * included). 418c2ecf20Sopenharmony_ci * 428c2ecf20Sopenharmony_ci * Descriptor format is not exactly the same for each MAC chip version so we 438c2ecf20Sopenharmony_ci * have function pointers on &struct ath5k_hw we initialize at runtime based on 448c2ecf20Sopenharmony_ci * the chip used. 458c2ecf20Sopenharmony_ci */ 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci/************************\ 498c2ecf20Sopenharmony_ci* TX Control descriptors * 508c2ecf20Sopenharmony_ci\************************/ 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci/** 538c2ecf20Sopenharmony_ci * ath5k_hw_setup_2word_tx_desc() - Initialize a 2-word tx control descriptor 548c2ecf20Sopenharmony_ci * @ah: The &struct ath5k_hw 558c2ecf20Sopenharmony_ci * @desc: The &struct ath5k_desc 568c2ecf20Sopenharmony_ci * @pkt_len: Frame length in bytes 578c2ecf20Sopenharmony_ci * @hdr_len: Header length in bytes (only used on AR5210) 588c2ecf20Sopenharmony_ci * @padsize: Any padding we've added to the frame length 598c2ecf20Sopenharmony_ci * @type: One of enum ath5k_pkt_type 608c2ecf20Sopenharmony_ci * @tx_power: Tx power in 0.5dB steps 618c2ecf20Sopenharmony_ci * @tx_rate0: HW idx for transmission rate 628c2ecf20Sopenharmony_ci * @tx_tries0: Max number of retransmissions 638c2ecf20Sopenharmony_ci * @key_index: Index on key table to use for encryption 648c2ecf20Sopenharmony_ci * @antenna_mode: Which antenna to use (0 for auto) 658c2ecf20Sopenharmony_ci * @flags: One of AR5K_TXDESC_* flags (desc.h) 668c2ecf20Sopenharmony_ci * @rtscts_rate: HW idx for RTS/CTS transmission rate 678c2ecf20Sopenharmony_ci * @rtscts_duration: What to put on duration field on the header of RTS/CTS 688c2ecf20Sopenharmony_ci * 698c2ecf20Sopenharmony_ci * Internal function to initialize a 2-Word TX control descriptor 708c2ecf20Sopenharmony_ci * found on AR5210 and AR5211 MACs chips. 718c2ecf20Sopenharmony_ci * 728c2ecf20Sopenharmony_ci * Returns 0 on success or -EINVAL on false input 738c2ecf20Sopenharmony_ci */ 748c2ecf20Sopenharmony_cistatic int 758c2ecf20Sopenharmony_ciath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, 768c2ecf20Sopenharmony_ci struct ath5k_desc *desc, 778c2ecf20Sopenharmony_ci unsigned int pkt_len, unsigned int hdr_len, 788c2ecf20Sopenharmony_ci int padsize, 798c2ecf20Sopenharmony_ci enum ath5k_pkt_type type, 808c2ecf20Sopenharmony_ci unsigned int tx_power, 818c2ecf20Sopenharmony_ci unsigned int tx_rate0, unsigned int tx_tries0, 828c2ecf20Sopenharmony_ci unsigned int key_index, 838c2ecf20Sopenharmony_ci unsigned int antenna_mode, 848c2ecf20Sopenharmony_ci unsigned int flags, 858c2ecf20Sopenharmony_ci unsigned int rtscts_rate, unsigned int rtscts_duration) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci u32 frame_type; 888c2ecf20Sopenharmony_ci struct ath5k_hw_2w_tx_ctl *tx_ctl; 898c2ecf20Sopenharmony_ci unsigned int frame_len; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci tx_ctl = &desc->ud.ds_tx5210.tx_ctl; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci /* 948c2ecf20Sopenharmony_ci * Validate input 958c2ecf20Sopenharmony_ci * - Zero retries don't make sense. 968c2ecf20Sopenharmony_ci * - A zero rate will put the HW into a mode where it continuously sends 978c2ecf20Sopenharmony_ci * noise on the channel, so it is important to avoid this. 988c2ecf20Sopenharmony_ci */ 998c2ecf20Sopenharmony_ci if (unlikely(tx_tries0 == 0)) { 1008c2ecf20Sopenharmony_ci ATH5K_ERR(ah, "zero retries\n"); 1018c2ecf20Sopenharmony_ci WARN_ON(1); 1028c2ecf20Sopenharmony_ci return -EINVAL; 1038c2ecf20Sopenharmony_ci } 1048c2ecf20Sopenharmony_ci if (unlikely(tx_rate0 == 0)) { 1058c2ecf20Sopenharmony_ci ATH5K_ERR(ah, "zero rate\n"); 1068c2ecf20Sopenharmony_ci WARN_ON(1); 1078c2ecf20Sopenharmony_ci return -EINVAL; 1088c2ecf20Sopenharmony_ci } 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci /* Clear descriptor */ 1118c2ecf20Sopenharmony_ci memset(&desc->ud.ds_tx5210, 0, sizeof(struct ath5k_hw_5210_tx_desc)); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci /* Setup control descriptor */ 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci /* Verify and set frame length */ 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci /* remove padding we might have added before */ 1188c2ecf20Sopenharmony_ci frame_len = pkt_len - padsize + FCS_LEN; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci if (frame_len & ~AR5K_2W_TX_DESC_CTL0_FRAME_LEN) 1218c2ecf20Sopenharmony_ci return -EINVAL; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci tx_ctl->tx_control_0 = frame_len & AR5K_2W_TX_DESC_CTL0_FRAME_LEN; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci /* Verify and set buffer length */ 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci /* NB: beacon's BufLen must be a multiple of 4 bytes */ 1288c2ecf20Sopenharmony_ci if (type == AR5K_PKT_TYPE_BEACON) 1298c2ecf20Sopenharmony_ci pkt_len = roundup(pkt_len, 4); 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci if (pkt_len & ~AR5K_2W_TX_DESC_CTL1_BUF_LEN) 1328c2ecf20Sopenharmony_ci return -EINVAL; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci tx_ctl->tx_control_1 = pkt_len & AR5K_2W_TX_DESC_CTL1_BUF_LEN; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci /* 1378c2ecf20Sopenharmony_ci * Verify and set header length (only 5210) 1388c2ecf20Sopenharmony_ci */ 1398c2ecf20Sopenharmony_ci if (ah->ah_version == AR5K_AR5210) { 1408c2ecf20Sopenharmony_ci if (hdr_len & ~AR5K_2W_TX_DESC_CTL0_HEADER_LEN_5210) 1418c2ecf20Sopenharmony_ci return -EINVAL; 1428c2ecf20Sopenharmony_ci tx_ctl->tx_control_0 |= 1438c2ecf20Sopenharmony_ci AR5K_REG_SM(hdr_len, AR5K_2W_TX_DESC_CTL0_HEADER_LEN_5210); 1448c2ecf20Sopenharmony_ci } 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci /*Differences between 5210-5211*/ 1478c2ecf20Sopenharmony_ci if (ah->ah_version == AR5K_AR5210) { 1488c2ecf20Sopenharmony_ci switch (type) { 1498c2ecf20Sopenharmony_ci case AR5K_PKT_TYPE_BEACON: 1508c2ecf20Sopenharmony_ci case AR5K_PKT_TYPE_PROBE_RESP: 1518c2ecf20Sopenharmony_ci frame_type = AR5K_AR5210_TX_DESC_FRAME_TYPE_NO_DELAY; 1528c2ecf20Sopenharmony_ci break; 1538c2ecf20Sopenharmony_ci case AR5K_PKT_TYPE_PIFS: 1548c2ecf20Sopenharmony_ci frame_type = AR5K_AR5210_TX_DESC_FRAME_TYPE_PIFS; 1558c2ecf20Sopenharmony_ci break; 1568c2ecf20Sopenharmony_ci default: 1578c2ecf20Sopenharmony_ci frame_type = type; 1588c2ecf20Sopenharmony_ci break; 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci tx_ctl->tx_control_0 |= 1628c2ecf20Sopenharmony_ci AR5K_REG_SM(frame_type, AR5K_2W_TX_DESC_CTL0_FRAME_TYPE_5210) | 1638c2ecf20Sopenharmony_ci AR5K_REG_SM(tx_rate0, AR5K_2W_TX_DESC_CTL0_XMIT_RATE); 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci } else { 1668c2ecf20Sopenharmony_ci tx_ctl->tx_control_0 |= 1678c2ecf20Sopenharmony_ci AR5K_REG_SM(tx_rate0, AR5K_2W_TX_DESC_CTL0_XMIT_RATE) | 1688c2ecf20Sopenharmony_ci AR5K_REG_SM(antenna_mode, 1698c2ecf20Sopenharmony_ci AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT); 1708c2ecf20Sopenharmony_ci tx_ctl->tx_control_1 |= 1718c2ecf20Sopenharmony_ci AR5K_REG_SM(type, AR5K_2W_TX_DESC_CTL1_FRAME_TYPE_5211); 1728c2ecf20Sopenharmony_ci } 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci#define _TX_FLAGS(_c, _flag) \ 1758c2ecf20Sopenharmony_ci if (flags & AR5K_TXDESC_##_flag) { \ 1768c2ecf20Sopenharmony_ci tx_ctl->tx_control_##_c |= \ 1778c2ecf20Sopenharmony_ci AR5K_2W_TX_DESC_CTL##_c##_##_flag; \ 1788c2ecf20Sopenharmony_ci } 1798c2ecf20Sopenharmony_ci#define _TX_FLAGS_5211(_c, _flag) \ 1808c2ecf20Sopenharmony_ci if (flags & AR5K_TXDESC_##_flag) { \ 1818c2ecf20Sopenharmony_ci tx_ctl->tx_control_##_c |= \ 1828c2ecf20Sopenharmony_ci AR5K_2W_TX_DESC_CTL##_c##_##_flag##_5211; \ 1838c2ecf20Sopenharmony_ci } 1848c2ecf20Sopenharmony_ci _TX_FLAGS(0, CLRDMASK); 1858c2ecf20Sopenharmony_ci _TX_FLAGS(0, INTREQ); 1868c2ecf20Sopenharmony_ci _TX_FLAGS(0, RTSENA); 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci if (ah->ah_version == AR5K_AR5211) { 1898c2ecf20Sopenharmony_ci _TX_FLAGS_5211(0, VEOL); 1908c2ecf20Sopenharmony_ci _TX_FLAGS_5211(1, NOACK); 1918c2ecf20Sopenharmony_ci } 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci#undef _TX_FLAGS 1948c2ecf20Sopenharmony_ci#undef _TX_FLAGS_5211 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci /* 1978c2ecf20Sopenharmony_ci * WEP crap 1988c2ecf20Sopenharmony_ci */ 1998c2ecf20Sopenharmony_ci if (key_index != AR5K_TXKEYIX_INVALID) { 2008c2ecf20Sopenharmony_ci tx_ctl->tx_control_0 |= 2018c2ecf20Sopenharmony_ci AR5K_2W_TX_DESC_CTL0_ENCRYPT_KEY_VALID; 2028c2ecf20Sopenharmony_ci tx_ctl->tx_control_1 |= 2038c2ecf20Sopenharmony_ci AR5K_REG_SM(key_index, 2048c2ecf20Sopenharmony_ci AR5K_2W_TX_DESC_CTL1_ENC_KEY_IDX); 2058c2ecf20Sopenharmony_ci } 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci /* 2088c2ecf20Sopenharmony_ci * RTS/CTS Duration [5210 ?] 2098c2ecf20Sopenharmony_ci */ 2108c2ecf20Sopenharmony_ci if ((ah->ah_version == AR5K_AR5210) && 2118c2ecf20Sopenharmony_ci (flags & (AR5K_TXDESC_RTSENA | AR5K_TXDESC_CTSENA))) 2128c2ecf20Sopenharmony_ci tx_ctl->tx_control_1 |= rtscts_duration & 2138c2ecf20Sopenharmony_ci AR5K_2W_TX_DESC_CTL1_RTS_DURATION_5210; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci return 0; 2168c2ecf20Sopenharmony_ci} 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci/** 2198c2ecf20Sopenharmony_ci * ath5k_hw_setup_4word_tx_desc() - Initialize a 4-word tx control descriptor 2208c2ecf20Sopenharmony_ci * @ah: The &struct ath5k_hw 2218c2ecf20Sopenharmony_ci * @desc: The &struct ath5k_desc 2228c2ecf20Sopenharmony_ci * @pkt_len: Frame length in bytes 2238c2ecf20Sopenharmony_ci * @hdr_len: Header length in bytes (only used on AR5210) 2248c2ecf20Sopenharmony_ci * @padsize: Any padding we've added to the frame length 2258c2ecf20Sopenharmony_ci * @type: One of enum ath5k_pkt_type 2268c2ecf20Sopenharmony_ci * @tx_power: Tx power in 0.5dB steps 2278c2ecf20Sopenharmony_ci * @tx_rate0: HW idx for transmission rate 2288c2ecf20Sopenharmony_ci * @tx_tries0: Max number of retransmissions 2298c2ecf20Sopenharmony_ci * @key_index: Index on key table to use for encryption 2308c2ecf20Sopenharmony_ci * @antenna_mode: Which antenna to use (0 for auto) 2318c2ecf20Sopenharmony_ci * @flags: One of AR5K_TXDESC_* flags (desc.h) 2328c2ecf20Sopenharmony_ci * @rtscts_rate: HW idx for RTS/CTS transmission rate 2338c2ecf20Sopenharmony_ci * @rtscts_duration: What to put on duration field on the header of RTS/CTS 2348c2ecf20Sopenharmony_ci * 2358c2ecf20Sopenharmony_ci * Internal function to initialize a 4-Word TX control descriptor 2368c2ecf20Sopenharmony_ci * found on AR5212 and later MACs chips. 2378c2ecf20Sopenharmony_ci * 2388c2ecf20Sopenharmony_ci * Returns 0 on success or -EINVAL on false input 2398c2ecf20Sopenharmony_ci */ 2408c2ecf20Sopenharmony_cistatic int 2418c2ecf20Sopenharmony_ciath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, 2428c2ecf20Sopenharmony_ci struct ath5k_desc *desc, 2438c2ecf20Sopenharmony_ci unsigned int pkt_len, unsigned int hdr_len, 2448c2ecf20Sopenharmony_ci int padsize, 2458c2ecf20Sopenharmony_ci enum ath5k_pkt_type type, 2468c2ecf20Sopenharmony_ci unsigned int tx_power, 2478c2ecf20Sopenharmony_ci unsigned int tx_rate0, unsigned int tx_tries0, 2488c2ecf20Sopenharmony_ci unsigned int key_index, 2498c2ecf20Sopenharmony_ci unsigned int antenna_mode, 2508c2ecf20Sopenharmony_ci unsigned int flags, 2518c2ecf20Sopenharmony_ci unsigned int rtscts_rate, unsigned int rtscts_duration) 2528c2ecf20Sopenharmony_ci{ 2538c2ecf20Sopenharmony_ci struct ath5k_hw_4w_tx_ctl *tx_ctl; 2548c2ecf20Sopenharmony_ci unsigned int frame_len; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci /* 2578c2ecf20Sopenharmony_ci * Use local variables for these to reduce load/store access on 2588c2ecf20Sopenharmony_ci * uncached memory 2598c2ecf20Sopenharmony_ci */ 2608c2ecf20Sopenharmony_ci u32 txctl0 = 0, txctl1 = 0, txctl2 = 0, txctl3 = 0; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci tx_ctl = &desc->ud.ds_tx5212.tx_ctl; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci /* 2658c2ecf20Sopenharmony_ci * Validate input 2668c2ecf20Sopenharmony_ci * - Zero retries don't make sense. 2678c2ecf20Sopenharmony_ci * - A zero rate will put the HW into a mode where it continuously sends 2688c2ecf20Sopenharmony_ci * noise on the channel, so it is important to avoid this. 2698c2ecf20Sopenharmony_ci */ 2708c2ecf20Sopenharmony_ci if (unlikely(tx_tries0 == 0)) { 2718c2ecf20Sopenharmony_ci ATH5K_ERR(ah, "zero retries\n"); 2728c2ecf20Sopenharmony_ci WARN_ON(1); 2738c2ecf20Sopenharmony_ci return -EINVAL; 2748c2ecf20Sopenharmony_ci } 2758c2ecf20Sopenharmony_ci if (unlikely(tx_rate0 == 0)) { 2768c2ecf20Sopenharmony_ci ATH5K_ERR(ah, "zero rate\n"); 2778c2ecf20Sopenharmony_ci WARN_ON(1); 2788c2ecf20Sopenharmony_ci return -EINVAL; 2798c2ecf20Sopenharmony_ci } 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci tx_power += ah->ah_txpower.txp_offset; 2828c2ecf20Sopenharmony_ci if (tx_power > AR5K_TUNE_MAX_TXPOWER) 2838c2ecf20Sopenharmony_ci tx_power = AR5K_TUNE_MAX_TXPOWER; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci /* Clear descriptor status area */ 2868c2ecf20Sopenharmony_ci memset(&desc->ud.ds_tx5212.tx_stat, 0, 2878c2ecf20Sopenharmony_ci sizeof(desc->ud.ds_tx5212.tx_stat)); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci /* Setup control descriptor */ 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci /* Verify and set frame length */ 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci /* remove padding we might have added before */ 2948c2ecf20Sopenharmony_ci frame_len = pkt_len - padsize + FCS_LEN; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci if (frame_len & ~AR5K_4W_TX_DESC_CTL0_FRAME_LEN) 2978c2ecf20Sopenharmony_ci return -EINVAL; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci txctl0 = frame_len & AR5K_4W_TX_DESC_CTL0_FRAME_LEN; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci /* Verify and set buffer length */ 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci /* NB: beacon's BufLen must be a multiple of 4 bytes */ 3048c2ecf20Sopenharmony_ci if (type == AR5K_PKT_TYPE_BEACON) 3058c2ecf20Sopenharmony_ci pkt_len = roundup(pkt_len, 4); 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci if (pkt_len & ~AR5K_4W_TX_DESC_CTL1_BUF_LEN) 3088c2ecf20Sopenharmony_ci return -EINVAL; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci txctl1 = pkt_len & AR5K_4W_TX_DESC_CTL1_BUF_LEN; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci txctl0 |= AR5K_REG_SM(tx_power, AR5K_4W_TX_DESC_CTL0_XMIT_POWER) | 3138c2ecf20Sopenharmony_ci AR5K_REG_SM(antenna_mode, AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT); 3148c2ecf20Sopenharmony_ci txctl1 |= AR5K_REG_SM(type, AR5K_4W_TX_DESC_CTL1_FRAME_TYPE); 3158c2ecf20Sopenharmony_ci txctl2 = AR5K_REG_SM(tx_tries0, AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0); 3168c2ecf20Sopenharmony_ci txctl3 = tx_rate0 & AR5K_4W_TX_DESC_CTL3_XMIT_RATE0; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci#define _TX_FLAGS(_c, _flag) \ 3198c2ecf20Sopenharmony_ci if (flags & AR5K_TXDESC_##_flag) { \ 3208c2ecf20Sopenharmony_ci txctl##_c |= AR5K_4W_TX_DESC_CTL##_c##_##_flag; \ 3218c2ecf20Sopenharmony_ci } 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci _TX_FLAGS(0, CLRDMASK); 3248c2ecf20Sopenharmony_ci _TX_FLAGS(0, VEOL); 3258c2ecf20Sopenharmony_ci _TX_FLAGS(0, INTREQ); 3268c2ecf20Sopenharmony_ci _TX_FLAGS(0, RTSENA); 3278c2ecf20Sopenharmony_ci _TX_FLAGS(0, CTSENA); 3288c2ecf20Sopenharmony_ci _TX_FLAGS(1, NOACK); 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci#undef _TX_FLAGS 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci /* 3338c2ecf20Sopenharmony_ci * WEP crap 3348c2ecf20Sopenharmony_ci */ 3358c2ecf20Sopenharmony_ci if (key_index != AR5K_TXKEYIX_INVALID) { 3368c2ecf20Sopenharmony_ci txctl0 |= AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID; 3378c2ecf20Sopenharmony_ci txctl1 |= AR5K_REG_SM(key_index, 3388c2ecf20Sopenharmony_ci AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_IDX); 3398c2ecf20Sopenharmony_ci } 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci /* 3428c2ecf20Sopenharmony_ci * RTS/CTS 3438c2ecf20Sopenharmony_ci */ 3448c2ecf20Sopenharmony_ci if (flags & (AR5K_TXDESC_RTSENA | AR5K_TXDESC_CTSENA)) { 3458c2ecf20Sopenharmony_ci if ((flags & AR5K_TXDESC_RTSENA) && 3468c2ecf20Sopenharmony_ci (flags & AR5K_TXDESC_CTSENA)) 3478c2ecf20Sopenharmony_ci return -EINVAL; 3488c2ecf20Sopenharmony_ci txctl2 |= rtscts_duration & AR5K_4W_TX_DESC_CTL2_RTS_DURATION; 3498c2ecf20Sopenharmony_ci txctl3 |= AR5K_REG_SM(rtscts_rate, 3508c2ecf20Sopenharmony_ci AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE); 3518c2ecf20Sopenharmony_ci } 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci tx_ctl->tx_control_0 = txctl0; 3548c2ecf20Sopenharmony_ci tx_ctl->tx_control_1 = txctl1; 3558c2ecf20Sopenharmony_ci tx_ctl->tx_control_2 = txctl2; 3568c2ecf20Sopenharmony_ci tx_ctl->tx_control_3 = txctl3; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci return 0; 3598c2ecf20Sopenharmony_ci} 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci/** 3628c2ecf20Sopenharmony_ci * ath5k_hw_setup_mrr_tx_desc() - Initialize an MRR tx control descriptor 3638c2ecf20Sopenharmony_ci * @ah: The &struct ath5k_hw 3648c2ecf20Sopenharmony_ci * @desc: The &struct ath5k_desc 3658c2ecf20Sopenharmony_ci * @tx_rate1: HW idx for rate used on transmission series 1 3668c2ecf20Sopenharmony_ci * @tx_tries1: Max number of retransmissions for transmission series 1 3678c2ecf20Sopenharmony_ci * @tx_rate2: HW idx for rate used on transmission series 2 3688c2ecf20Sopenharmony_ci * @tx_tries2: Max number of retransmissions for transmission series 2 3698c2ecf20Sopenharmony_ci * @tx_rate3: HW idx for rate used on transmission series 3 3708c2ecf20Sopenharmony_ci * @tx_tries3: Max number of retransmissions for transmission series 3 3718c2ecf20Sopenharmony_ci * 3728c2ecf20Sopenharmony_ci * Multi rate retry (MRR) tx control descriptors are available only on AR5212 3738c2ecf20Sopenharmony_ci * MACs, they are part of the normal 4-word tx control descriptor (see above) 3748c2ecf20Sopenharmony_ci * but we handle them through a separate function for better abstraction. 3758c2ecf20Sopenharmony_ci * 3768c2ecf20Sopenharmony_ci * Returns 0 on success or -EINVAL on invalid input 3778c2ecf20Sopenharmony_ci */ 3788c2ecf20Sopenharmony_ciint 3798c2ecf20Sopenharmony_ciath5k_hw_setup_mrr_tx_desc(struct ath5k_hw *ah, 3808c2ecf20Sopenharmony_ci struct ath5k_desc *desc, 3818c2ecf20Sopenharmony_ci u_int tx_rate1, u_int tx_tries1, 3828c2ecf20Sopenharmony_ci u_int tx_rate2, u_int tx_tries2, 3838c2ecf20Sopenharmony_ci u_int tx_rate3, u_int tx_tries3) 3848c2ecf20Sopenharmony_ci{ 3858c2ecf20Sopenharmony_ci struct ath5k_hw_4w_tx_ctl *tx_ctl; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci /* no mrr support for cards older than 5212 */ 3888c2ecf20Sopenharmony_ci if (ah->ah_version < AR5K_AR5212) 3898c2ecf20Sopenharmony_ci return 0; 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci /* 3928c2ecf20Sopenharmony_ci * Rates can be 0 as long as the retry count is 0 too. 3938c2ecf20Sopenharmony_ci * A zero rate and nonzero retry count will put the HW into a mode where 3948c2ecf20Sopenharmony_ci * it continuously sends noise on the channel, so it is important to 3958c2ecf20Sopenharmony_ci * avoid this. 3968c2ecf20Sopenharmony_ci */ 3978c2ecf20Sopenharmony_ci if (unlikely((tx_rate1 == 0 && tx_tries1 != 0) || 3988c2ecf20Sopenharmony_ci (tx_rate2 == 0 && tx_tries2 != 0) || 3998c2ecf20Sopenharmony_ci (tx_rate3 == 0 && tx_tries3 != 0))) { 4008c2ecf20Sopenharmony_ci ATH5K_ERR(ah, "zero rate\n"); 4018c2ecf20Sopenharmony_ci WARN_ON(1); 4028c2ecf20Sopenharmony_ci return -EINVAL; 4038c2ecf20Sopenharmony_ci } 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci if (ah->ah_version == AR5K_AR5212) { 4068c2ecf20Sopenharmony_ci tx_ctl = &desc->ud.ds_tx5212.tx_ctl; 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci#define _XTX_TRIES(_n) \ 4098c2ecf20Sopenharmony_ci if (tx_tries##_n) { \ 4108c2ecf20Sopenharmony_ci tx_ctl->tx_control_2 |= \ 4118c2ecf20Sopenharmony_ci AR5K_REG_SM(tx_tries##_n, \ 4128c2ecf20Sopenharmony_ci AR5K_4W_TX_DESC_CTL2_XMIT_TRIES##_n); \ 4138c2ecf20Sopenharmony_ci tx_ctl->tx_control_3 |= \ 4148c2ecf20Sopenharmony_ci AR5K_REG_SM(tx_rate##_n, \ 4158c2ecf20Sopenharmony_ci AR5K_4W_TX_DESC_CTL3_XMIT_RATE##_n); \ 4168c2ecf20Sopenharmony_ci } 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci _XTX_TRIES(1); 4198c2ecf20Sopenharmony_ci _XTX_TRIES(2); 4208c2ecf20Sopenharmony_ci _XTX_TRIES(3); 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci#undef _XTX_TRIES 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci return 1; 4258c2ecf20Sopenharmony_ci } 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci return 0; 4288c2ecf20Sopenharmony_ci} 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci/***********************\ 4328c2ecf20Sopenharmony_ci* TX Status descriptors * 4338c2ecf20Sopenharmony_ci\***********************/ 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci/** 4368c2ecf20Sopenharmony_ci * ath5k_hw_proc_2word_tx_status() - Process a tx status descriptor on 5210/1 4378c2ecf20Sopenharmony_ci * @ah: The &struct ath5k_hw 4388c2ecf20Sopenharmony_ci * @desc: The &struct ath5k_desc 4398c2ecf20Sopenharmony_ci * @ts: The &struct ath5k_tx_status 4408c2ecf20Sopenharmony_ci */ 4418c2ecf20Sopenharmony_cistatic int 4428c2ecf20Sopenharmony_ciath5k_hw_proc_2word_tx_status(struct ath5k_hw *ah, 4438c2ecf20Sopenharmony_ci struct ath5k_desc *desc, 4448c2ecf20Sopenharmony_ci struct ath5k_tx_status *ts) 4458c2ecf20Sopenharmony_ci{ 4468c2ecf20Sopenharmony_ci struct ath5k_hw_tx_status *tx_status; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci tx_status = &desc->ud.ds_tx5210.tx_stat; 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci /* No frame has been send or error */ 4518c2ecf20Sopenharmony_ci if (unlikely((tx_status->tx_status_1 & AR5K_DESC_TX_STATUS1_DONE) == 0)) 4528c2ecf20Sopenharmony_ci return -EINPROGRESS; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci /* 4558c2ecf20Sopenharmony_ci * Get descriptor status 4568c2ecf20Sopenharmony_ci */ 4578c2ecf20Sopenharmony_ci ts->ts_tstamp = AR5K_REG_MS(tx_status->tx_status_0, 4588c2ecf20Sopenharmony_ci AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP); 4598c2ecf20Sopenharmony_ci ts->ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0, 4608c2ecf20Sopenharmony_ci AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT); 4618c2ecf20Sopenharmony_ci ts->ts_final_retry = AR5K_REG_MS(tx_status->tx_status_0, 4628c2ecf20Sopenharmony_ci AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT); 4638c2ecf20Sopenharmony_ci /*TODO: ts->ts_virtcol + test*/ 4648c2ecf20Sopenharmony_ci ts->ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1, 4658c2ecf20Sopenharmony_ci AR5K_DESC_TX_STATUS1_SEQ_NUM); 4668c2ecf20Sopenharmony_ci ts->ts_rssi = AR5K_REG_MS(tx_status->tx_status_1, 4678c2ecf20Sopenharmony_ci AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH); 4688c2ecf20Sopenharmony_ci ts->ts_antenna = 1; 4698c2ecf20Sopenharmony_ci ts->ts_status = 0; 4708c2ecf20Sopenharmony_ci ts->ts_final_idx = 0; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci if (!(tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK)) { 4738c2ecf20Sopenharmony_ci if (tx_status->tx_status_0 & 4748c2ecf20Sopenharmony_ci AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES) 4758c2ecf20Sopenharmony_ci ts->ts_status |= AR5K_TXERR_XRETRY; 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN) 4788c2ecf20Sopenharmony_ci ts->ts_status |= AR5K_TXERR_FIFO; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FILTERED) 4818c2ecf20Sopenharmony_ci ts->ts_status |= AR5K_TXERR_FILT; 4828c2ecf20Sopenharmony_ci } 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci return 0; 4858c2ecf20Sopenharmony_ci} 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci/** 4888c2ecf20Sopenharmony_ci * ath5k_hw_proc_4word_tx_status() - Process a tx status descriptor on 5212 4898c2ecf20Sopenharmony_ci * @ah: The &struct ath5k_hw 4908c2ecf20Sopenharmony_ci * @desc: The &struct ath5k_desc 4918c2ecf20Sopenharmony_ci * @ts: The &struct ath5k_tx_status 4928c2ecf20Sopenharmony_ci */ 4938c2ecf20Sopenharmony_cistatic int 4948c2ecf20Sopenharmony_ciath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah, 4958c2ecf20Sopenharmony_ci struct ath5k_desc *desc, 4968c2ecf20Sopenharmony_ci struct ath5k_tx_status *ts) 4978c2ecf20Sopenharmony_ci{ 4988c2ecf20Sopenharmony_ci struct ath5k_hw_tx_status *tx_status; 4998c2ecf20Sopenharmony_ci u32 txstat0, txstat1; 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci tx_status = &desc->ud.ds_tx5212.tx_stat; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci txstat1 = READ_ONCE(tx_status->tx_status_1); 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci /* No frame has been send or error */ 5068c2ecf20Sopenharmony_ci if (unlikely(!(txstat1 & AR5K_DESC_TX_STATUS1_DONE))) 5078c2ecf20Sopenharmony_ci return -EINPROGRESS; 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci txstat0 = READ_ONCE(tx_status->tx_status_0); 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci /* 5128c2ecf20Sopenharmony_ci * Get descriptor status 5138c2ecf20Sopenharmony_ci */ 5148c2ecf20Sopenharmony_ci ts->ts_tstamp = AR5K_REG_MS(txstat0, 5158c2ecf20Sopenharmony_ci AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP); 5168c2ecf20Sopenharmony_ci ts->ts_shortretry = AR5K_REG_MS(txstat0, 5178c2ecf20Sopenharmony_ci AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT); 5188c2ecf20Sopenharmony_ci ts->ts_final_retry = AR5K_REG_MS(txstat0, 5198c2ecf20Sopenharmony_ci AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT); 5208c2ecf20Sopenharmony_ci ts->ts_seqnum = AR5K_REG_MS(txstat1, 5218c2ecf20Sopenharmony_ci AR5K_DESC_TX_STATUS1_SEQ_NUM); 5228c2ecf20Sopenharmony_ci ts->ts_rssi = AR5K_REG_MS(txstat1, 5238c2ecf20Sopenharmony_ci AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH); 5248c2ecf20Sopenharmony_ci ts->ts_antenna = (txstat1 & 5258c2ecf20Sopenharmony_ci AR5K_DESC_TX_STATUS1_XMIT_ANTENNA_5212) ? 2 : 1; 5268c2ecf20Sopenharmony_ci ts->ts_status = 0; 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci ts->ts_final_idx = AR5K_REG_MS(txstat1, 5298c2ecf20Sopenharmony_ci AR5K_DESC_TX_STATUS1_FINAL_TS_IX_5212); 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci /* TX error */ 5328c2ecf20Sopenharmony_ci if (!(txstat0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK)) { 5338c2ecf20Sopenharmony_ci if (txstat0 & AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES) 5348c2ecf20Sopenharmony_ci ts->ts_status |= AR5K_TXERR_XRETRY; 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci if (txstat0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN) 5378c2ecf20Sopenharmony_ci ts->ts_status |= AR5K_TXERR_FIFO; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci if (txstat0 & AR5K_DESC_TX_STATUS0_FILTERED) 5408c2ecf20Sopenharmony_ci ts->ts_status |= AR5K_TXERR_FILT; 5418c2ecf20Sopenharmony_ci } 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci return 0; 5448c2ecf20Sopenharmony_ci} 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci/****************\ 5488c2ecf20Sopenharmony_ci* RX Descriptors * 5498c2ecf20Sopenharmony_ci\****************/ 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci/** 5528c2ecf20Sopenharmony_ci * ath5k_hw_setup_rx_desc() - Initialize an rx control descriptor 5538c2ecf20Sopenharmony_ci * @ah: The &struct ath5k_hw 5548c2ecf20Sopenharmony_ci * @desc: The &struct ath5k_desc 5558c2ecf20Sopenharmony_ci * @size: RX buffer length in bytes 5568c2ecf20Sopenharmony_ci * @flags: One of AR5K_RXDESC_* flags 5578c2ecf20Sopenharmony_ci */ 5588c2ecf20Sopenharmony_ciint 5598c2ecf20Sopenharmony_ciath5k_hw_setup_rx_desc(struct ath5k_hw *ah, 5608c2ecf20Sopenharmony_ci struct ath5k_desc *desc, 5618c2ecf20Sopenharmony_ci u32 size, unsigned int flags) 5628c2ecf20Sopenharmony_ci{ 5638c2ecf20Sopenharmony_ci struct ath5k_hw_rx_ctl *rx_ctl; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci rx_ctl = &desc->ud.ds_rx.rx_ctl; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci /* 5688c2ecf20Sopenharmony_ci * Clear the descriptor 5698c2ecf20Sopenharmony_ci * If we don't clean the status descriptor, 5708c2ecf20Sopenharmony_ci * while scanning we get too many results, 5718c2ecf20Sopenharmony_ci * most of them virtual, after some secs 5728c2ecf20Sopenharmony_ci * of scanning system hangs. M.F. 5738c2ecf20Sopenharmony_ci */ 5748c2ecf20Sopenharmony_ci memset(&desc->ud.ds_rx, 0, sizeof(struct ath5k_hw_all_rx_desc)); 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci if (unlikely(size & ~AR5K_DESC_RX_CTL1_BUF_LEN)) 5778c2ecf20Sopenharmony_ci return -EINVAL; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci /* Setup descriptor */ 5808c2ecf20Sopenharmony_ci rx_ctl->rx_control_1 = size & AR5K_DESC_RX_CTL1_BUF_LEN; 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci if (flags & AR5K_RXDESC_INTREQ) 5838c2ecf20Sopenharmony_ci rx_ctl->rx_control_1 |= AR5K_DESC_RX_CTL1_INTREQ; 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci return 0; 5868c2ecf20Sopenharmony_ci} 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci/** 5898c2ecf20Sopenharmony_ci * ath5k_hw_proc_5210_rx_status() - Process the rx status descriptor on 5210/1 5908c2ecf20Sopenharmony_ci * @ah: The &struct ath5k_hw 5918c2ecf20Sopenharmony_ci * @desc: The &struct ath5k_desc 5928c2ecf20Sopenharmony_ci * @rs: The &struct ath5k_rx_status 5938c2ecf20Sopenharmony_ci * 5948c2ecf20Sopenharmony_ci * Internal function used to process an RX status descriptor 5958c2ecf20Sopenharmony_ci * on AR5210/5211 MAC. 5968c2ecf20Sopenharmony_ci * 5978c2ecf20Sopenharmony_ci * Returns 0 on success or -EINPROGRESS in case we haven't received the who;e 5988c2ecf20Sopenharmony_ci * frame yet. 5998c2ecf20Sopenharmony_ci */ 6008c2ecf20Sopenharmony_cistatic int 6018c2ecf20Sopenharmony_ciath5k_hw_proc_5210_rx_status(struct ath5k_hw *ah, 6028c2ecf20Sopenharmony_ci struct ath5k_desc *desc, 6038c2ecf20Sopenharmony_ci struct ath5k_rx_status *rs) 6048c2ecf20Sopenharmony_ci{ 6058c2ecf20Sopenharmony_ci struct ath5k_hw_rx_status *rx_status; 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci rx_status = &desc->ud.ds_rx.rx_stat; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci /* No frame received / not ready */ 6108c2ecf20Sopenharmony_ci if (unlikely(!(rx_status->rx_status_1 & 6118c2ecf20Sopenharmony_ci AR5K_5210_RX_DESC_STATUS1_DONE))) 6128c2ecf20Sopenharmony_ci return -EINPROGRESS; 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci memset(rs, 0, sizeof(struct ath5k_rx_status)); 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci /* 6178c2ecf20Sopenharmony_ci * Frame receive status 6188c2ecf20Sopenharmony_ci */ 6198c2ecf20Sopenharmony_ci rs->rs_datalen = rx_status->rx_status_0 & 6208c2ecf20Sopenharmony_ci AR5K_5210_RX_DESC_STATUS0_DATA_LEN; 6218c2ecf20Sopenharmony_ci rs->rs_rssi = AR5K_REG_MS(rx_status->rx_status_0, 6228c2ecf20Sopenharmony_ci AR5K_5210_RX_DESC_STATUS0_RECEIVE_SIGNAL); 6238c2ecf20Sopenharmony_ci rs->rs_rate = AR5K_REG_MS(rx_status->rx_status_0, 6248c2ecf20Sopenharmony_ci AR5K_5210_RX_DESC_STATUS0_RECEIVE_RATE); 6258c2ecf20Sopenharmony_ci rs->rs_more = !!(rx_status->rx_status_0 & 6268c2ecf20Sopenharmony_ci AR5K_5210_RX_DESC_STATUS0_MORE); 6278c2ecf20Sopenharmony_ci /* TODO: this timestamp is 13 bit, later on we assume 15 bit! 6288c2ecf20Sopenharmony_ci * also the HAL code for 5210 says the timestamp is bits [10..22] of the 6298c2ecf20Sopenharmony_ci * TSF, and extends the timestamp here to 15 bit. 6308c2ecf20Sopenharmony_ci * we need to check on 5210... 6318c2ecf20Sopenharmony_ci */ 6328c2ecf20Sopenharmony_ci rs->rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1, 6338c2ecf20Sopenharmony_ci AR5K_5210_RX_DESC_STATUS1_RECEIVE_TIMESTAMP); 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci if (ah->ah_version == AR5K_AR5211) 6368c2ecf20Sopenharmony_ci rs->rs_antenna = AR5K_REG_MS(rx_status->rx_status_0, 6378c2ecf20Sopenharmony_ci AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANT_5211); 6388c2ecf20Sopenharmony_ci else 6398c2ecf20Sopenharmony_ci rs->rs_antenna = (rx_status->rx_status_0 & 6408c2ecf20Sopenharmony_ci AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANT_5210) 6418c2ecf20Sopenharmony_ci ? 2 : 1; 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci /* 6448c2ecf20Sopenharmony_ci * Key table status 6458c2ecf20Sopenharmony_ci */ 6468c2ecf20Sopenharmony_ci if (rx_status->rx_status_1 & AR5K_5210_RX_DESC_STATUS1_KEY_INDEX_VALID) 6478c2ecf20Sopenharmony_ci rs->rs_keyix = AR5K_REG_MS(rx_status->rx_status_1, 6488c2ecf20Sopenharmony_ci AR5K_5210_RX_DESC_STATUS1_KEY_INDEX); 6498c2ecf20Sopenharmony_ci else 6508c2ecf20Sopenharmony_ci rs->rs_keyix = AR5K_RXKEYIX_INVALID; 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci /* 6538c2ecf20Sopenharmony_ci * Receive/descriptor errors 6548c2ecf20Sopenharmony_ci */ 6558c2ecf20Sopenharmony_ci if (!(rx_status->rx_status_1 & 6568c2ecf20Sopenharmony_ci AR5K_5210_RX_DESC_STATUS1_FRAME_RECEIVE_OK)) { 6578c2ecf20Sopenharmony_ci if (rx_status->rx_status_1 & 6588c2ecf20Sopenharmony_ci AR5K_5210_RX_DESC_STATUS1_CRC_ERROR) 6598c2ecf20Sopenharmony_ci rs->rs_status |= AR5K_RXERR_CRC; 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci /* only on 5210 */ 6628c2ecf20Sopenharmony_ci if ((ah->ah_version == AR5K_AR5210) && 6638c2ecf20Sopenharmony_ci (rx_status->rx_status_1 & 6648c2ecf20Sopenharmony_ci AR5K_5210_RX_DESC_STATUS1_FIFO_OVERRUN_5210)) 6658c2ecf20Sopenharmony_ci rs->rs_status |= AR5K_RXERR_FIFO; 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci if (rx_status->rx_status_1 & 6688c2ecf20Sopenharmony_ci AR5K_5210_RX_DESC_STATUS1_PHY_ERROR) { 6698c2ecf20Sopenharmony_ci rs->rs_status |= AR5K_RXERR_PHY; 6708c2ecf20Sopenharmony_ci rs->rs_phyerr = AR5K_REG_MS(rx_status->rx_status_1, 6718c2ecf20Sopenharmony_ci AR5K_5210_RX_DESC_STATUS1_PHY_ERROR); 6728c2ecf20Sopenharmony_ci } 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci if (rx_status->rx_status_1 & 6758c2ecf20Sopenharmony_ci AR5K_5210_RX_DESC_STATUS1_DECRYPT_CRC_ERROR) 6768c2ecf20Sopenharmony_ci rs->rs_status |= AR5K_RXERR_DECRYPT; 6778c2ecf20Sopenharmony_ci } 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci return 0; 6808c2ecf20Sopenharmony_ci} 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci/** 6838c2ecf20Sopenharmony_ci * ath5k_hw_proc_5212_rx_status() - Process the rx status descriptor on 5212 6848c2ecf20Sopenharmony_ci * @ah: The &struct ath5k_hw 6858c2ecf20Sopenharmony_ci * @desc: The &struct ath5k_desc 6868c2ecf20Sopenharmony_ci * @rs: The &struct ath5k_rx_status 6878c2ecf20Sopenharmony_ci * 6888c2ecf20Sopenharmony_ci * Internal function used to process an RX status descriptor 6898c2ecf20Sopenharmony_ci * on AR5212 and later MAC. 6908c2ecf20Sopenharmony_ci * 6918c2ecf20Sopenharmony_ci * Returns 0 on success or -EINPROGRESS in case we haven't received the who;e 6928c2ecf20Sopenharmony_ci * frame yet. 6938c2ecf20Sopenharmony_ci */ 6948c2ecf20Sopenharmony_cistatic int 6958c2ecf20Sopenharmony_ciath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah, 6968c2ecf20Sopenharmony_ci struct ath5k_desc *desc, 6978c2ecf20Sopenharmony_ci struct ath5k_rx_status *rs) 6988c2ecf20Sopenharmony_ci{ 6998c2ecf20Sopenharmony_ci struct ath5k_hw_rx_status *rx_status; 7008c2ecf20Sopenharmony_ci u32 rxstat0, rxstat1; 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci rx_status = &desc->ud.ds_rx.rx_stat; 7038c2ecf20Sopenharmony_ci rxstat1 = READ_ONCE(rx_status->rx_status_1); 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci /* No frame received / not ready */ 7068c2ecf20Sopenharmony_ci if (unlikely(!(rxstat1 & AR5K_5212_RX_DESC_STATUS1_DONE))) 7078c2ecf20Sopenharmony_ci return -EINPROGRESS; 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci memset(rs, 0, sizeof(struct ath5k_rx_status)); 7108c2ecf20Sopenharmony_ci rxstat0 = READ_ONCE(rx_status->rx_status_0); 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci /* 7138c2ecf20Sopenharmony_ci * Frame receive status 7148c2ecf20Sopenharmony_ci */ 7158c2ecf20Sopenharmony_ci rs->rs_datalen = rxstat0 & AR5K_5212_RX_DESC_STATUS0_DATA_LEN; 7168c2ecf20Sopenharmony_ci rs->rs_rssi = AR5K_REG_MS(rxstat0, 7178c2ecf20Sopenharmony_ci AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL); 7188c2ecf20Sopenharmony_ci rs->rs_rate = AR5K_REG_MS(rxstat0, 7198c2ecf20Sopenharmony_ci AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE); 7208c2ecf20Sopenharmony_ci rs->rs_antenna = AR5K_REG_MS(rxstat0, 7218c2ecf20Sopenharmony_ci AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA); 7228c2ecf20Sopenharmony_ci rs->rs_more = !!(rxstat0 & AR5K_5212_RX_DESC_STATUS0_MORE); 7238c2ecf20Sopenharmony_ci rs->rs_tstamp = AR5K_REG_MS(rxstat1, 7248c2ecf20Sopenharmony_ci AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP); 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci /* 7278c2ecf20Sopenharmony_ci * Key table status 7288c2ecf20Sopenharmony_ci */ 7298c2ecf20Sopenharmony_ci if (rxstat1 & AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_VALID) 7308c2ecf20Sopenharmony_ci rs->rs_keyix = AR5K_REG_MS(rxstat1, 7318c2ecf20Sopenharmony_ci AR5K_5212_RX_DESC_STATUS1_KEY_INDEX); 7328c2ecf20Sopenharmony_ci else 7338c2ecf20Sopenharmony_ci rs->rs_keyix = AR5K_RXKEYIX_INVALID; 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci /* 7368c2ecf20Sopenharmony_ci * Receive/descriptor errors 7378c2ecf20Sopenharmony_ci */ 7388c2ecf20Sopenharmony_ci if (!(rxstat1 & AR5K_5212_RX_DESC_STATUS1_FRAME_RECEIVE_OK)) { 7398c2ecf20Sopenharmony_ci if (rxstat1 & AR5K_5212_RX_DESC_STATUS1_CRC_ERROR) 7408c2ecf20Sopenharmony_ci rs->rs_status |= AR5K_RXERR_CRC; 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci if (rxstat1 & AR5K_5212_RX_DESC_STATUS1_PHY_ERROR) { 7438c2ecf20Sopenharmony_ci rs->rs_status |= AR5K_RXERR_PHY; 7448c2ecf20Sopenharmony_ci rs->rs_phyerr = AR5K_REG_MS(rxstat1, 7458c2ecf20Sopenharmony_ci AR5K_5212_RX_DESC_STATUS1_PHY_ERROR_CODE); 7468c2ecf20Sopenharmony_ci if (!ah->ah_capabilities.cap_has_phyerr_counters) 7478c2ecf20Sopenharmony_ci ath5k_ani_phy_error_report(ah, rs->rs_phyerr); 7488c2ecf20Sopenharmony_ci } 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci if (rxstat1 & AR5K_5212_RX_DESC_STATUS1_DECRYPT_CRC_ERROR) 7518c2ecf20Sopenharmony_ci rs->rs_status |= AR5K_RXERR_DECRYPT; 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci if (rxstat1 & AR5K_5212_RX_DESC_STATUS1_MIC_ERROR) 7548c2ecf20Sopenharmony_ci rs->rs_status |= AR5K_RXERR_MIC; 7558c2ecf20Sopenharmony_ci } 7568c2ecf20Sopenharmony_ci return 0; 7578c2ecf20Sopenharmony_ci} 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci/********\ 7618c2ecf20Sopenharmony_ci* Attach * 7628c2ecf20Sopenharmony_ci\********/ 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci/** 7658c2ecf20Sopenharmony_ci * ath5k_hw_init_desc_functions() - Init function pointers inside ah 7668c2ecf20Sopenharmony_ci * @ah: The &struct ath5k_hw 7678c2ecf20Sopenharmony_ci * 7688c2ecf20Sopenharmony_ci * Maps the internal descriptor functions to the function pointers on ah, used 7698c2ecf20Sopenharmony_ci * from above. This is used as an abstraction layer to handle the various chips 7708c2ecf20Sopenharmony_ci * the same way. 7718c2ecf20Sopenharmony_ci */ 7728c2ecf20Sopenharmony_ciint 7738c2ecf20Sopenharmony_ciath5k_hw_init_desc_functions(struct ath5k_hw *ah) 7748c2ecf20Sopenharmony_ci{ 7758c2ecf20Sopenharmony_ci if (ah->ah_version == AR5K_AR5212) { 7768c2ecf20Sopenharmony_ci ah->ah_setup_tx_desc = ath5k_hw_setup_4word_tx_desc; 7778c2ecf20Sopenharmony_ci ah->ah_proc_tx_desc = ath5k_hw_proc_4word_tx_status; 7788c2ecf20Sopenharmony_ci ah->ah_proc_rx_desc = ath5k_hw_proc_5212_rx_status; 7798c2ecf20Sopenharmony_ci } else if (ah->ah_version <= AR5K_AR5211) { 7808c2ecf20Sopenharmony_ci ah->ah_setup_tx_desc = ath5k_hw_setup_2word_tx_desc; 7818c2ecf20Sopenharmony_ci ah->ah_proc_tx_desc = ath5k_hw_proc_2word_tx_status; 7828c2ecf20Sopenharmony_ci ah->ah_proc_rx_desc = ath5k_hw_proc_5210_rx_status; 7838c2ecf20Sopenharmony_ci } else 7848c2ecf20Sopenharmony_ci return -ENOTSUPP; 7858c2ecf20Sopenharmony_ci return 0; 7868c2ecf20Sopenharmony_ci} 787