1203c4805SLuis R. Rodriguez /* 2203c4805SLuis R. Rodriguez * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org> 3203c4805SLuis R. Rodriguez * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com> 4203c4805SLuis R. Rodriguez * Copyright (c) 2007-2008 Pavel Roskin <proski@gnu.org> 5203c4805SLuis R. Rodriguez * 6203c4805SLuis R. Rodriguez * Permission to use, copy, modify, and distribute this software for any 7203c4805SLuis R. Rodriguez * purpose with or without fee is hereby granted, provided that the above 8203c4805SLuis R. Rodriguez * copyright notice and this permission notice appear in all copies. 9203c4805SLuis R. Rodriguez * 10203c4805SLuis R. Rodriguez * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11203c4805SLuis R. Rodriguez * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12203c4805SLuis R. Rodriguez * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13203c4805SLuis R. Rodriguez * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14203c4805SLuis R. Rodriguez * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15203c4805SLuis R. Rodriguez * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16203c4805SLuis R. Rodriguez * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17203c4805SLuis R. Rodriguez * 18203c4805SLuis R. Rodriguez */ 19203c4805SLuis R. Rodriguez 20203c4805SLuis R. Rodriguez /******************************\ 21203c4805SLuis R. Rodriguez Hardware Descriptor Functions 22203c4805SLuis R. Rodriguez \******************************/ 23203c4805SLuis R. Rodriguez 24203c4805SLuis R. Rodriguez #include "ath5k.h" 25203c4805SLuis R. Rodriguez #include "reg.h" 26203c4805SLuis R. Rodriguez #include "debug.h" 27203c4805SLuis R. Rodriguez #include "base.h" 28203c4805SLuis R. Rodriguez 29203c4805SLuis R. Rodriguez /* 30203c4805SLuis R. Rodriguez * TX Descriptors 31203c4805SLuis R. Rodriguez */ 32203c4805SLuis R. Rodriguez 33203c4805SLuis R. Rodriguez /* 34203c4805SLuis R. Rodriguez * Initialize the 2-word tx control descriptor on 5210/5211 35203c4805SLuis R. Rodriguez */ 36203c4805SLuis R. Rodriguez static int 37203c4805SLuis R. Rodriguez ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, 388127fbdcSBenoit Papillault unsigned int pkt_len, unsigned int hdr_len, int padsize, 398127fbdcSBenoit Papillault enum ath5k_pkt_type type, 40203c4805SLuis R. Rodriguez unsigned int tx_power, unsigned int tx_rate0, unsigned int tx_tries0, 41203c4805SLuis R. Rodriguez unsigned int key_index, unsigned int antenna_mode, unsigned int flags, 42203c4805SLuis R. Rodriguez unsigned int rtscts_rate, unsigned int rtscts_duration) 43203c4805SLuis R. Rodriguez { 44203c4805SLuis R. Rodriguez u32 frame_type; 45203c4805SLuis R. Rodriguez struct ath5k_hw_2w_tx_ctl *tx_ctl; 46203c4805SLuis R. Rodriguez unsigned int frame_len; 47203c4805SLuis R. Rodriguez 48203c4805SLuis R. Rodriguez tx_ctl = &desc->ud.ds_tx5210.tx_ctl; 49203c4805SLuis R. Rodriguez 50203c4805SLuis R. Rodriguez /* 51203c4805SLuis R. Rodriguez * Validate input 52203c4805SLuis R. Rodriguez * - Zero retries don't make sense. 53203c4805SLuis R. Rodriguez * - A zero rate will put the HW into a mode where it continously sends 54203c4805SLuis R. Rodriguez * noise on the channel, so it is important to avoid this. 55203c4805SLuis R. Rodriguez */ 56203c4805SLuis R. Rodriguez if (unlikely(tx_tries0 == 0)) { 57203c4805SLuis R. Rodriguez ATH5K_ERR(ah->ah_sc, "zero retries\n"); 58203c4805SLuis R. Rodriguez WARN_ON(1); 59203c4805SLuis R. Rodriguez return -EINVAL; 60203c4805SLuis R. Rodriguez } 61203c4805SLuis R. Rodriguez if (unlikely(tx_rate0 == 0)) { 62203c4805SLuis R. Rodriguez ATH5K_ERR(ah->ah_sc, "zero rate\n"); 63203c4805SLuis R. Rodriguez WARN_ON(1); 64203c4805SLuis R. Rodriguez return -EINVAL; 65203c4805SLuis R. Rodriguez } 66203c4805SLuis R. Rodriguez 67203c4805SLuis R. Rodriguez /* Clear descriptor */ 68203c4805SLuis R. Rodriguez memset(&desc->ud.ds_tx5210, 0, sizeof(struct ath5k_hw_5210_tx_desc)); 69203c4805SLuis R. Rodriguez 70203c4805SLuis R. Rodriguez /* Setup control descriptor */ 71203c4805SLuis R. Rodriguez 72203c4805SLuis R. Rodriguez /* Verify and set frame length */ 73203c4805SLuis R. Rodriguez 74203c4805SLuis R. Rodriguez /* remove padding we might have added before */ 758127fbdcSBenoit Papillault frame_len = pkt_len - padsize + FCS_LEN; 76203c4805SLuis R. Rodriguez 77203c4805SLuis R. Rodriguez if (frame_len & ~AR5K_2W_TX_DESC_CTL0_FRAME_LEN) 78203c4805SLuis R. Rodriguez return -EINVAL; 79203c4805SLuis R. Rodriguez 80203c4805SLuis R. Rodriguez tx_ctl->tx_control_0 = frame_len & AR5K_2W_TX_DESC_CTL0_FRAME_LEN; 81203c4805SLuis R. Rodriguez 82203c4805SLuis R. Rodriguez /* Verify and set buffer length */ 83203c4805SLuis R. Rodriguez 84203c4805SLuis R. Rodriguez /* NB: beacon's BufLen must be a multiple of 4 bytes */ 85203c4805SLuis R. Rodriguez if (type == AR5K_PKT_TYPE_BEACON) 86203c4805SLuis R. Rodriguez pkt_len = roundup(pkt_len, 4); 87203c4805SLuis R. Rodriguez 88203c4805SLuis R. Rodriguez if (pkt_len & ~AR5K_2W_TX_DESC_CTL1_BUF_LEN) 89203c4805SLuis R. Rodriguez return -EINVAL; 90203c4805SLuis R. Rodriguez 91203c4805SLuis R. Rodriguez tx_ctl->tx_control_1 = pkt_len & AR5K_2W_TX_DESC_CTL1_BUF_LEN; 92203c4805SLuis R. Rodriguez 93203c4805SLuis R. Rodriguez /* 941884a367SBruno Randolf * Verify and set header length (only 5210) 95203c4805SLuis R. Rodriguez */ 96203c4805SLuis R. Rodriguez if (ah->ah_version == AR5K_AR5210) { 9703417bc6SBruno Randolf if (hdr_len & ~AR5K_2W_TX_DESC_CTL0_HEADER_LEN_5210) 98203c4805SLuis R. Rodriguez return -EINVAL; 99203c4805SLuis R. Rodriguez tx_ctl->tx_control_0 |= 10003417bc6SBruno Randolf AR5K_REG_SM(hdr_len, AR5K_2W_TX_DESC_CTL0_HEADER_LEN_5210); 101203c4805SLuis R. Rodriguez } 102203c4805SLuis R. Rodriguez 1038127fbdcSBenoit Papillault /*Differences between 5210-5211*/ 104203c4805SLuis R. Rodriguez if (ah->ah_version == AR5K_AR5210) { 105203c4805SLuis R. Rodriguez switch (type) { 106203c4805SLuis R. Rodriguez case AR5K_PKT_TYPE_BEACON: 107203c4805SLuis R. Rodriguez case AR5K_PKT_TYPE_PROBE_RESP: 108203c4805SLuis R. Rodriguez frame_type = AR5K_AR5210_TX_DESC_FRAME_TYPE_NO_DELAY; 109203c4805SLuis R. Rodriguez case AR5K_PKT_TYPE_PIFS: 110203c4805SLuis R. Rodriguez frame_type = AR5K_AR5210_TX_DESC_FRAME_TYPE_PIFS; 111203c4805SLuis R. Rodriguez default: 1122237e928SBruno Randolf frame_type = type; 113203c4805SLuis R. Rodriguez } 114203c4805SLuis R. Rodriguez 115203c4805SLuis R. Rodriguez tx_ctl->tx_control_0 |= 11603417bc6SBruno Randolf AR5K_REG_SM(frame_type, AR5K_2W_TX_DESC_CTL0_FRAME_TYPE_5210) | 117203c4805SLuis R. Rodriguez AR5K_REG_SM(tx_rate0, AR5K_2W_TX_DESC_CTL0_XMIT_RATE); 118203c4805SLuis R. Rodriguez 119203c4805SLuis R. Rodriguez } else { 120203c4805SLuis R. Rodriguez tx_ctl->tx_control_0 |= 121203c4805SLuis R. Rodriguez AR5K_REG_SM(tx_rate0, AR5K_2W_TX_DESC_CTL0_XMIT_RATE) | 122203c4805SLuis R. Rodriguez AR5K_REG_SM(antenna_mode, 123203c4805SLuis R. Rodriguez AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT); 124203c4805SLuis R. Rodriguez tx_ctl->tx_control_1 |= 12503417bc6SBruno Randolf AR5K_REG_SM(type, AR5K_2W_TX_DESC_CTL1_FRAME_TYPE_5211); 126203c4805SLuis R. Rodriguez } 1271884a367SBruno Randolf 128203c4805SLuis R. Rodriguez #define _TX_FLAGS(_c, _flag) \ 129203c4805SLuis R. Rodriguez if (flags & AR5K_TXDESC_##_flag) { \ 130203c4805SLuis R. Rodriguez tx_ctl->tx_control_##_c |= \ 131203c4805SLuis R. Rodriguez AR5K_2W_TX_DESC_CTL##_c##_##_flag; \ 132203c4805SLuis R. Rodriguez } 1331884a367SBruno Randolf #define _TX_FLAGS_5211(_c, _flag) \ 1341884a367SBruno Randolf if (flags & AR5K_TXDESC_##_flag) { \ 1351884a367SBruno Randolf tx_ctl->tx_control_##_c |= \ 1361884a367SBruno Randolf AR5K_2W_TX_DESC_CTL##_c##_##_flag##_5211; \ 1371884a367SBruno Randolf } 138203c4805SLuis R. Rodriguez _TX_FLAGS(0, CLRDMASK); 139203c4805SLuis R. Rodriguez _TX_FLAGS(0, INTREQ); 140203c4805SLuis R. Rodriguez _TX_FLAGS(0, RTSENA); 1411884a367SBruno Randolf 1421884a367SBruno Randolf if (ah->ah_version == AR5K_AR5211) { 1431884a367SBruno Randolf _TX_FLAGS_5211(0, VEOL); 1441884a367SBruno Randolf _TX_FLAGS_5211(1, NOACK); 1451884a367SBruno Randolf } 146203c4805SLuis R. Rodriguez 147203c4805SLuis R. Rodriguez #undef _TX_FLAGS 1481884a367SBruno Randolf #undef _TX_FLAGS_5211 149203c4805SLuis R. Rodriguez 150203c4805SLuis R. Rodriguez /* 151203c4805SLuis R. Rodriguez * WEP crap 152203c4805SLuis R. Rodriguez */ 153203c4805SLuis R. Rodriguez if (key_index != AR5K_TXKEYIX_INVALID) { 154203c4805SLuis R. Rodriguez tx_ctl->tx_control_0 |= 155203c4805SLuis R. Rodriguez AR5K_2W_TX_DESC_CTL0_ENCRYPT_KEY_VALID; 156203c4805SLuis R. Rodriguez tx_ctl->tx_control_1 |= 157203c4805SLuis R. Rodriguez AR5K_REG_SM(key_index, 15803417bc6SBruno Randolf AR5K_2W_TX_DESC_CTL1_ENC_KEY_IDX); 159203c4805SLuis R. Rodriguez } 160203c4805SLuis R. Rodriguez 161203c4805SLuis R. Rodriguez /* 162203c4805SLuis R. Rodriguez * RTS/CTS Duration [5210 ?] 163203c4805SLuis R. Rodriguez */ 164203c4805SLuis R. Rodriguez if ((ah->ah_version == AR5K_AR5210) && 165203c4805SLuis R. Rodriguez (flags & (AR5K_TXDESC_RTSENA | AR5K_TXDESC_CTSENA))) 166203c4805SLuis R. Rodriguez tx_ctl->tx_control_1 |= rtscts_duration & 16703417bc6SBruno Randolf AR5K_2W_TX_DESC_CTL1_RTS_DURATION_5210; 168203c4805SLuis R. Rodriguez 169203c4805SLuis R. Rodriguez return 0; 170203c4805SLuis R. Rodriguez } 171203c4805SLuis R. Rodriguez 172203c4805SLuis R. Rodriguez /* 173203c4805SLuis R. Rodriguez * Initialize the 4-word tx control descriptor on 5212 174203c4805SLuis R. Rodriguez */ 175203c4805SLuis R. Rodriguez static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, 176203c4805SLuis R. Rodriguez struct ath5k_desc *desc, unsigned int pkt_len, unsigned int hdr_len, 1778127fbdcSBenoit Papillault int padsize, 178203c4805SLuis R. Rodriguez enum ath5k_pkt_type type, unsigned int tx_power, unsigned int tx_rate0, 179203c4805SLuis R. Rodriguez unsigned int tx_tries0, unsigned int key_index, 180203c4805SLuis R. Rodriguez unsigned int antenna_mode, unsigned int flags, 181203c4805SLuis R. Rodriguez unsigned int rtscts_rate, 182203c4805SLuis R. Rodriguez unsigned int rtscts_duration) 183203c4805SLuis R. Rodriguez { 184203c4805SLuis R. Rodriguez struct ath5k_hw_4w_tx_ctl *tx_ctl; 185203c4805SLuis R. Rodriguez unsigned int frame_len; 186203c4805SLuis R. Rodriguez 187203c4805SLuis R. Rodriguez tx_ctl = &desc->ud.ds_tx5212.tx_ctl; 188203c4805SLuis R. Rodriguez 189203c4805SLuis R. Rodriguez /* 190203c4805SLuis R. Rodriguez * Validate input 191203c4805SLuis R. Rodriguez * - Zero retries don't make sense. 192203c4805SLuis R. Rodriguez * - A zero rate will put the HW into a mode where it continously sends 193203c4805SLuis R. Rodriguez * noise on the channel, so it is important to avoid this. 194203c4805SLuis R. Rodriguez */ 195203c4805SLuis R. Rodriguez if (unlikely(tx_tries0 == 0)) { 196203c4805SLuis R. Rodriguez ATH5K_ERR(ah->ah_sc, "zero retries\n"); 197203c4805SLuis R. Rodriguez WARN_ON(1); 198203c4805SLuis R. Rodriguez return -EINVAL; 199203c4805SLuis R. Rodriguez } 200203c4805SLuis R. Rodriguez if (unlikely(tx_rate0 == 0)) { 201203c4805SLuis R. Rodriguez ATH5K_ERR(ah->ah_sc, "zero rate\n"); 202203c4805SLuis R. Rodriguez WARN_ON(1); 203203c4805SLuis R. Rodriguez return -EINVAL; 204203c4805SLuis R. Rodriguez } 205203c4805SLuis R. Rodriguez 206203c4805SLuis R. Rodriguez tx_power += ah->ah_txpower.txp_offset; 207203c4805SLuis R. Rodriguez if (tx_power > AR5K_TUNE_MAX_TXPOWER) 208203c4805SLuis R. Rodriguez tx_power = AR5K_TUNE_MAX_TXPOWER; 209203c4805SLuis R. Rodriguez 210203c4805SLuis R. Rodriguez /* Clear descriptor */ 211203c4805SLuis R. Rodriguez memset(&desc->ud.ds_tx5212, 0, sizeof(struct ath5k_hw_5212_tx_desc)); 212203c4805SLuis R. Rodriguez 213203c4805SLuis R. Rodriguez /* Setup control descriptor */ 214203c4805SLuis R. Rodriguez 215203c4805SLuis R. Rodriguez /* Verify and set frame length */ 216203c4805SLuis R. Rodriguez 217203c4805SLuis R. Rodriguez /* remove padding we might have added before */ 2188127fbdcSBenoit Papillault frame_len = pkt_len - padsize + FCS_LEN; 219203c4805SLuis R. Rodriguez 220203c4805SLuis R. Rodriguez if (frame_len & ~AR5K_4W_TX_DESC_CTL0_FRAME_LEN) 221203c4805SLuis R. Rodriguez return -EINVAL; 222203c4805SLuis R. Rodriguez 223203c4805SLuis R. Rodriguez tx_ctl->tx_control_0 = frame_len & AR5K_4W_TX_DESC_CTL0_FRAME_LEN; 224203c4805SLuis R. Rodriguez 225203c4805SLuis R. Rodriguez /* Verify and set buffer length */ 226203c4805SLuis R. Rodriguez 227203c4805SLuis R. Rodriguez /* NB: beacon's BufLen must be a multiple of 4 bytes */ 228203c4805SLuis R. Rodriguez if (type == AR5K_PKT_TYPE_BEACON) 229203c4805SLuis R. Rodriguez pkt_len = roundup(pkt_len, 4); 230203c4805SLuis R. Rodriguez 231203c4805SLuis R. Rodriguez if (pkt_len & ~AR5K_4W_TX_DESC_CTL1_BUF_LEN) 232203c4805SLuis R. Rodriguez return -EINVAL; 233203c4805SLuis R. Rodriguez 234203c4805SLuis R. Rodriguez tx_ctl->tx_control_1 = pkt_len & AR5K_4W_TX_DESC_CTL1_BUF_LEN; 235203c4805SLuis R. Rodriguez 236203c4805SLuis R. Rodriguez tx_ctl->tx_control_0 |= 237203c4805SLuis R. Rodriguez AR5K_REG_SM(tx_power, AR5K_4W_TX_DESC_CTL0_XMIT_POWER) | 238203c4805SLuis R. Rodriguez AR5K_REG_SM(antenna_mode, AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT); 239203c4805SLuis R. Rodriguez tx_ctl->tx_control_1 |= AR5K_REG_SM(type, 240203c4805SLuis R. Rodriguez AR5K_4W_TX_DESC_CTL1_FRAME_TYPE); 241e9f08381SAndrew Blaich tx_ctl->tx_control_2 = AR5K_REG_SM(tx_tries0, 242203c4805SLuis R. Rodriguez AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0); 243203c4805SLuis R. Rodriguez tx_ctl->tx_control_3 = tx_rate0 & AR5K_4W_TX_DESC_CTL3_XMIT_RATE0; 244203c4805SLuis R. Rodriguez 245203c4805SLuis R. Rodriguez #define _TX_FLAGS(_c, _flag) \ 246203c4805SLuis R. Rodriguez if (flags & AR5K_TXDESC_##_flag) { \ 247203c4805SLuis R. Rodriguez tx_ctl->tx_control_##_c |= \ 248203c4805SLuis R. Rodriguez AR5K_4W_TX_DESC_CTL##_c##_##_flag; \ 249203c4805SLuis R. Rodriguez } 250203c4805SLuis R. Rodriguez 251203c4805SLuis R. Rodriguez _TX_FLAGS(0, CLRDMASK); 252203c4805SLuis R. Rodriguez _TX_FLAGS(0, VEOL); 253203c4805SLuis R. Rodriguez _TX_FLAGS(0, INTREQ); 254203c4805SLuis R. Rodriguez _TX_FLAGS(0, RTSENA); 255203c4805SLuis R. Rodriguez _TX_FLAGS(0, CTSENA); 256203c4805SLuis R. Rodriguez _TX_FLAGS(1, NOACK); 257203c4805SLuis R. Rodriguez 258203c4805SLuis R. Rodriguez #undef _TX_FLAGS 259203c4805SLuis R. Rodriguez 260203c4805SLuis R. Rodriguez /* 261203c4805SLuis R. Rodriguez * WEP crap 262203c4805SLuis R. Rodriguez */ 263203c4805SLuis R. Rodriguez if (key_index != AR5K_TXKEYIX_INVALID) { 264203c4805SLuis R. Rodriguez tx_ctl->tx_control_0 |= AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID; 265203c4805SLuis R. Rodriguez tx_ctl->tx_control_1 |= AR5K_REG_SM(key_index, 26603417bc6SBruno Randolf AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_IDX); 267203c4805SLuis R. Rodriguez } 268203c4805SLuis R. Rodriguez 269203c4805SLuis R. Rodriguez /* 270203c4805SLuis R. Rodriguez * RTS/CTS 271203c4805SLuis R. Rodriguez */ 272203c4805SLuis R. Rodriguez if (flags & (AR5K_TXDESC_RTSENA | AR5K_TXDESC_CTSENA)) { 273203c4805SLuis R. Rodriguez if ((flags & AR5K_TXDESC_RTSENA) && 274203c4805SLuis R. Rodriguez (flags & AR5K_TXDESC_CTSENA)) 275203c4805SLuis R. Rodriguez return -EINVAL; 276203c4805SLuis R. Rodriguez tx_ctl->tx_control_2 |= rtscts_duration & 277203c4805SLuis R. Rodriguez AR5K_4W_TX_DESC_CTL2_RTS_DURATION; 278203c4805SLuis R. Rodriguez tx_ctl->tx_control_3 |= AR5K_REG_SM(rtscts_rate, 279203c4805SLuis R. Rodriguez AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE); 280203c4805SLuis R. Rodriguez } 281203c4805SLuis R. Rodriguez 282203c4805SLuis R. Rodriguez return 0; 283203c4805SLuis R. Rodriguez } 284203c4805SLuis R. Rodriguez 285203c4805SLuis R. Rodriguez /* 286203c4805SLuis R. Rodriguez * Initialize a 4-word multi rate retry tx control descriptor on 5212 287203c4805SLuis R. Rodriguez */ 288a6668193SBruno Randolf int 289203c4805SLuis R. Rodriguez ath5k_hw_setup_mrr_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, 290203c4805SLuis R. Rodriguez unsigned int tx_rate1, u_int tx_tries1, u_int tx_rate2, 291203c4805SLuis R. Rodriguez u_int tx_tries2, unsigned int tx_rate3, u_int tx_tries3) 292203c4805SLuis R. Rodriguez { 293203c4805SLuis R. Rodriguez struct ath5k_hw_4w_tx_ctl *tx_ctl; 294203c4805SLuis R. Rodriguez 295a6668193SBruno Randolf /* no mrr support for cards older than 5212 */ 296a6668193SBruno Randolf if (ah->ah_version < AR5K_AR5212) 297a6668193SBruno Randolf return 0; 298a6668193SBruno Randolf 299203c4805SLuis R. Rodriguez /* 300203c4805SLuis R. Rodriguez * Rates can be 0 as long as the retry count is 0 too. 301203c4805SLuis R. Rodriguez * A zero rate and nonzero retry count will put the HW into a mode where 302203c4805SLuis R. Rodriguez * it continously sends noise on the channel, so it is important to 303203c4805SLuis R. Rodriguez * avoid this. 304203c4805SLuis R. Rodriguez */ 305203c4805SLuis R. Rodriguez if (unlikely((tx_rate1 == 0 && tx_tries1 != 0) || 306203c4805SLuis R. Rodriguez (tx_rate2 == 0 && tx_tries2 != 0) || 307203c4805SLuis R. Rodriguez (tx_rate3 == 0 && tx_tries3 != 0))) { 308203c4805SLuis R. Rodriguez ATH5K_ERR(ah->ah_sc, "zero rate\n"); 309203c4805SLuis R. Rodriguez WARN_ON(1); 310203c4805SLuis R. Rodriguez return -EINVAL; 311203c4805SLuis R. Rodriguez } 312203c4805SLuis R. Rodriguez 313203c4805SLuis R. Rodriguez if (ah->ah_version == AR5K_AR5212) { 314203c4805SLuis R. Rodriguez tx_ctl = &desc->ud.ds_tx5212.tx_ctl; 315203c4805SLuis R. Rodriguez 316203c4805SLuis R. Rodriguez #define _XTX_TRIES(_n) \ 317203c4805SLuis R. Rodriguez if (tx_tries##_n) { \ 318203c4805SLuis R. Rodriguez tx_ctl->tx_control_2 |= \ 319203c4805SLuis R. Rodriguez AR5K_REG_SM(tx_tries##_n, \ 320203c4805SLuis R. Rodriguez AR5K_4W_TX_DESC_CTL2_XMIT_TRIES##_n); \ 321203c4805SLuis R. Rodriguez tx_ctl->tx_control_3 |= \ 322203c4805SLuis R. Rodriguez AR5K_REG_SM(tx_rate##_n, \ 323203c4805SLuis R. Rodriguez AR5K_4W_TX_DESC_CTL3_XMIT_RATE##_n); \ 324203c4805SLuis R. Rodriguez } 325203c4805SLuis R. Rodriguez 326203c4805SLuis R. Rodriguez _XTX_TRIES(1); 327203c4805SLuis R. Rodriguez _XTX_TRIES(2); 328203c4805SLuis R. Rodriguez _XTX_TRIES(3); 329203c4805SLuis R. Rodriguez 330203c4805SLuis R. Rodriguez #undef _XTX_TRIES 331203c4805SLuis R. Rodriguez 332203c4805SLuis R. Rodriguez return 1; 333203c4805SLuis R. Rodriguez } 334203c4805SLuis R. Rodriguez 335203c4805SLuis R. Rodriguez return 0; 336203c4805SLuis R. Rodriguez } 337203c4805SLuis R. Rodriguez 338203c4805SLuis R. Rodriguez /* 339203c4805SLuis R. Rodriguez * Proccess the tx status descriptor on 5210/5211 340203c4805SLuis R. Rodriguez */ 341203c4805SLuis R. Rodriguez static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *ah, 342203c4805SLuis R. Rodriguez struct ath5k_desc *desc, struct ath5k_tx_status *ts) 343203c4805SLuis R. Rodriguez { 344203c4805SLuis R. Rodriguez struct ath5k_hw_2w_tx_ctl *tx_ctl; 345203c4805SLuis R. Rodriguez struct ath5k_hw_tx_status *tx_status; 346203c4805SLuis R. Rodriguez 347203c4805SLuis R. Rodriguez tx_ctl = &desc->ud.ds_tx5210.tx_ctl; 348203c4805SLuis R. Rodriguez tx_status = &desc->ud.ds_tx5210.tx_stat; 349203c4805SLuis R. Rodriguez 350203c4805SLuis R. Rodriguez /* No frame has been send or error */ 351203c4805SLuis R. Rodriguez if (unlikely((tx_status->tx_status_1 & AR5K_DESC_TX_STATUS1_DONE) == 0)) 352203c4805SLuis R. Rodriguez return -EINPROGRESS; 353203c4805SLuis R. Rodriguez 354203c4805SLuis R. Rodriguez /* 355203c4805SLuis R. Rodriguez * Get descriptor status 356203c4805SLuis R. Rodriguez */ 357203c4805SLuis R. Rodriguez ts->ts_tstamp = AR5K_REG_MS(tx_status->tx_status_0, 358203c4805SLuis R. Rodriguez AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP); 359203c4805SLuis R. Rodriguez ts->ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0, 360203c4805SLuis R. Rodriguez AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT); 361203c4805SLuis R. Rodriguez ts->ts_longretry = AR5K_REG_MS(tx_status->tx_status_0, 362203c4805SLuis R. Rodriguez AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT); 363203c4805SLuis R. Rodriguez /*TODO: ts->ts_virtcol + test*/ 364203c4805SLuis R. Rodriguez ts->ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1, 365203c4805SLuis R. Rodriguez AR5K_DESC_TX_STATUS1_SEQ_NUM); 366203c4805SLuis R. Rodriguez ts->ts_rssi = AR5K_REG_MS(tx_status->tx_status_1, 367203c4805SLuis R. Rodriguez AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH); 368203c4805SLuis R. Rodriguez ts->ts_antenna = 1; 369203c4805SLuis R. Rodriguez ts->ts_status = 0; 370203c4805SLuis R. Rodriguez ts->ts_rate[0] = AR5K_REG_MS(tx_ctl->tx_control_0, 371203c4805SLuis R. Rodriguez AR5K_2W_TX_DESC_CTL0_XMIT_RATE); 372203c4805SLuis R. Rodriguez ts->ts_retry[0] = ts->ts_longretry; 373203c4805SLuis R. Rodriguez ts->ts_final_idx = 0; 374203c4805SLuis R. Rodriguez 375203c4805SLuis R. Rodriguez if (!(tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK)) { 376203c4805SLuis R. Rodriguez if (tx_status->tx_status_0 & 377203c4805SLuis R. Rodriguez AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES) 378203c4805SLuis R. Rodriguez ts->ts_status |= AR5K_TXERR_XRETRY; 379203c4805SLuis R. Rodriguez 380203c4805SLuis R. Rodriguez if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN) 381203c4805SLuis R. Rodriguez ts->ts_status |= AR5K_TXERR_FIFO; 382203c4805SLuis R. Rodriguez 383203c4805SLuis R. Rodriguez if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FILTERED) 384203c4805SLuis R. Rodriguez ts->ts_status |= AR5K_TXERR_FILT; 385203c4805SLuis R. Rodriguez } 386203c4805SLuis R. Rodriguez 387203c4805SLuis R. Rodriguez return 0; 388203c4805SLuis R. Rodriguez } 389203c4805SLuis R. Rodriguez 390203c4805SLuis R. Rodriguez /* 391203c4805SLuis R. Rodriguez * Proccess a tx status descriptor on 5212 392203c4805SLuis R. Rodriguez */ 393203c4805SLuis R. Rodriguez static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah, 394203c4805SLuis R. Rodriguez struct ath5k_desc *desc, struct ath5k_tx_status *ts) 395203c4805SLuis R. Rodriguez { 396203c4805SLuis R. Rodriguez struct ath5k_hw_4w_tx_ctl *tx_ctl; 397203c4805SLuis R. Rodriguez struct ath5k_hw_tx_status *tx_status; 398203c4805SLuis R. Rodriguez 399203c4805SLuis R. Rodriguez tx_ctl = &desc->ud.ds_tx5212.tx_ctl; 400203c4805SLuis R. Rodriguez tx_status = &desc->ud.ds_tx5212.tx_stat; 401203c4805SLuis R. Rodriguez 402203c4805SLuis R. Rodriguez /* No frame has been send or error */ 403203c4805SLuis R. Rodriguez if (unlikely(!(tx_status->tx_status_1 & AR5K_DESC_TX_STATUS1_DONE))) 404203c4805SLuis R. Rodriguez return -EINPROGRESS; 405203c4805SLuis R. Rodriguez 406203c4805SLuis R. Rodriguez /* 407203c4805SLuis R. Rodriguez * Get descriptor status 408203c4805SLuis R. Rodriguez */ 409203c4805SLuis R. Rodriguez ts->ts_tstamp = AR5K_REG_MS(tx_status->tx_status_0, 410203c4805SLuis R. Rodriguez AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP); 411203c4805SLuis R. Rodriguez ts->ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0, 412203c4805SLuis R. Rodriguez AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT); 413203c4805SLuis R. Rodriguez ts->ts_longretry = AR5K_REG_MS(tx_status->tx_status_0, 414203c4805SLuis R. Rodriguez AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT); 415203c4805SLuis R. Rodriguez ts->ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1, 416203c4805SLuis R. Rodriguez AR5K_DESC_TX_STATUS1_SEQ_NUM); 417203c4805SLuis R. Rodriguez ts->ts_rssi = AR5K_REG_MS(tx_status->tx_status_1, 418203c4805SLuis R. Rodriguez AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH); 419203c4805SLuis R. Rodriguez ts->ts_antenna = (tx_status->tx_status_1 & 42003417bc6SBruno Randolf AR5K_DESC_TX_STATUS1_XMIT_ANTENNA_5212) ? 2 : 1; 421203c4805SLuis R. Rodriguez ts->ts_status = 0; 422203c4805SLuis R. Rodriguez 423203c4805SLuis R. Rodriguez ts->ts_final_idx = AR5K_REG_MS(tx_status->tx_status_1, 42403417bc6SBruno Randolf AR5K_DESC_TX_STATUS1_FINAL_TS_IX_5212); 425203c4805SLuis R. Rodriguez 426203c4805SLuis R. Rodriguez /* The longretry counter has the number of un-acked retries 427203c4805SLuis R. Rodriguez * for the final rate. To get the total number of retries 428203c4805SLuis R. Rodriguez * we have to add the retry counters for the other rates 429203c4805SLuis R. Rodriguez * as well 430203c4805SLuis R. Rodriguez */ 431203c4805SLuis R. Rodriguez ts->ts_retry[ts->ts_final_idx] = ts->ts_longretry; 432203c4805SLuis R. Rodriguez switch (ts->ts_final_idx) { 433203c4805SLuis R. Rodriguez case 3: 434203c4805SLuis R. Rodriguez ts->ts_rate[3] = AR5K_REG_MS(tx_ctl->tx_control_3, 435203c4805SLuis R. Rodriguez AR5K_4W_TX_DESC_CTL3_XMIT_RATE3); 436203c4805SLuis R. Rodriguez 437203c4805SLuis R. Rodriguez ts->ts_retry[2] = AR5K_REG_MS(tx_ctl->tx_control_2, 438203c4805SLuis R. Rodriguez AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2); 439203c4805SLuis R. Rodriguez ts->ts_longretry += ts->ts_retry[2]; 440203c4805SLuis R. Rodriguez /* fall through */ 441203c4805SLuis R. Rodriguez case 2: 442203c4805SLuis R. Rodriguez ts->ts_rate[2] = AR5K_REG_MS(tx_ctl->tx_control_3, 443203c4805SLuis R. Rodriguez AR5K_4W_TX_DESC_CTL3_XMIT_RATE2); 444203c4805SLuis R. Rodriguez 445203c4805SLuis R. Rodriguez ts->ts_retry[1] = AR5K_REG_MS(tx_ctl->tx_control_2, 446203c4805SLuis R. Rodriguez AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1); 447203c4805SLuis R. Rodriguez ts->ts_longretry += ts->ts_retry[1]; 448203c4805SLuis R. Rodriguez /* fall through */ 449203c4805SLuis R. Rodriguez case 1: 450203c4805SLuis R. Rodriguez ts->ts_rate[1] = AR5K_REG_MS(tx_ctl->tx_control_3, 451203c4805SLuis R. Rodriguez AR5K_4W_TX_DESC_CTL3_XMIT_RATE1); 452203c4805SLuis R. Rodriguez 453203c4805SLuis R. Rodriguez ts->ts_retry[0] = AR5K_REG_MS(tx_ctl->tx_control_2, 454203c4805SLuis R. Rodriguez AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1); 455203c4805SLuis R. Rodriguez ts->ts_longretry += ts->ts_retry[0]; 456203c4805SLuis R. Rodriguez /* fall through */ 457203c4805SLuis R. Rodriguez case 0: 458203c4805SLuis R. Rodriguez ts->ts_rate[0] = tx_ctl->tx_control_3 & 459203c4805SLuis R. Rodriguez AR5K_4W_TX_DESC_CTL3_XMIT_RATE0; 460203c4805SLuis R. Rodriguez break; 461203c4805SLuis R. Rodriguez } 462203c4805SLuis R. Rodriguez 463203c4805SLuis R. Rodriguez /* TX error */ 464203c4805SLuis R. Rodriguez if (!(tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK)) { 465203c4805SLuis R. Rodriguez if (tx_status->tx_status_0 & 466203c4805SLuis R. Rodriguez AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES) 467203c4805SLuis R. Rodriguez ts->ts_status |= AR5K_TXERR_XRETRY; 468203c4805SLuis R. Rodriguez 469203c4805SLuis R. Rodriguez if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN) 470203c4805SLuis R. Rodriguez ts->ts_status |= AR5K_TXERR_FIFO; 471203c4805SLuis R. Rodriguez 472203c4805SLuis R. Rodriguez if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FILTERED) 473203c4805SLuis R. Rodriguez ts->ts_status |= AR5K_TXERR_FILT; 474203c4805SLuis R. Rodriguez } 475203c4805SLuis R. Rodriguez 476203c4805SLuis R. Rodriguez return 0; 477203c4805SLuis R. Rodriguez } 478203c4805SLuis R. Rodriguez 479203c4805SLuis R. Rodriguez /* 480203c4805SLuis R. Rodriguez * RX Descriptors 481203c4805SLuis R. Rodriguez */ 482203c4805SLuis R. Rodriguez 483203c4805SLuis R. Rodriguez /* 484203c4805SLuis R. Rodriguez * Initialize an rx control descriptor 485203c4805SLuis R. Rodriguez */ 486a6668193SBruno Randolf int ath5k_hw_setup_rx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, 487203c4805SLuis R. Rodriguez u32 size, unsigned int flags) 488203c4805SLuis R. Rodriguez { 489203c4805SLuis R. Rodriguez struct ath5k_hw_rx_ctl *rx_ctl; 490203c4805SLuis R. Rodriguez 491203c4805SLuis R. Rodriguez rx_ctl = &desc->ud.ds_rx.rx_ctl; 492203c4805SLuis R. Rodriguez 493203c4805SLuis R. Rodriguez /* 494203c4805SLuis R. Rodriguez * Clear the descriptor 495203c4805SLuis R. Rodriguez * If we don't clean the status descriptor, 496203c4805SLuis R. Rodriguez * while scanning we get too many results, 497203c4805SLuis R. Rodriguez * most of them virtual, after some secs 498203c4805SLuis R. Rodriguez * of scanning system hangs. M.F. 499203c4805SLuis R. Rodriguez */ 500203c4805SLuis R. Rodriguez memset(&desc->ud.ds_rx, 0, sizeof(struct ath5k_hw_all_rx_desc)); 501203c4805SLuis R. Rodriguez 5028786123bSBruno Randolf if (unlikely(size & ~AR5K_DESC_RX_CTL1_BUF_LEN)) 5038786123bSBruno Randolf return -EINVAL; 5048786123bSBruno Randolf 505203c4805SLuis R. Rodriguez /* Setup descriptor */ 506203c4805SLuis R. Rodriguez rx_ctl->rx_control_1 = size & AR5K_DESC_RX_CTL1_BUF_LEN; 507203c4805SLuis R. Rodriguez 508203c4805SLuis R. Rodriguez if (flags & AR5K_RXDESC_INTREQ) 509203c4805SLuis R. Rodriguez rx_ctl->rx_control_1 |= AR5K_DESC_RX_CTL1_INTREQ; 510203c4805SLuis R. Rodriguez 511203c4805SLuis R. Rodriguez return 0; 512203c4805SLuis R. Rodriguez } 513203c4805SLuis R. Rodriguez 514203c4805SLuis R. Rodriguez /* 515203c4805SLuis R. Rodriguez * Proccess the rx status descriptor on 5210/5211 516203c4805SLuis R. Rodriguez */ 517203c4805SLuis R. Rodriguez static int ath5k_hw_proc_5210_rx_status(struct ath5k_hw *ah, 518203c4805SLuis R. Rodriguez struct ath5k_desc *desc, struct ath5k_rx_status *rs) 519203c4805SLuis R. Rodriguez { 520203c4805SLuis R. Rodriguez struct ath5k_hw_rx_status *rx_status; 521203c4805SLuis R. Rodriguez 52262412a8fSBruno Randolf rx_status = &desc->ud.ds_rx.rx_stat; 523203c4805SLuis R. Rodriguez 524203c4805SLuis R. Rodriguez /* No frame received / not ready */ 525203c4805SLuis R. Rodriguez if (unlikely(!(rx_status->rx_status_1 & 526203c4805SLuis R. Rodriguez AR5K_5210_RX_DESC_STATUS1_DONE))) 527203c4805SLuis R. Rodriguez return -EINPROGRESS; 528203c4805SLuis R. Rodriguez 5298786123bSBruno Randolf memset(rs, 0, sizeof(struct ath5k_rx_status)); 5308786123bSBruno Randolf 531203c4805SLuis R. Rodriguez /* 532203c4805SLuis R. Rodriguez * Frame receive status 533203c4805SLuis R. Rodriguez */ 534203c4805SLuis R. Rodriguez rs->rs_datalen = rx_status->rx_status_0 & 535203c4805SLuis R. Rodriguez AR5K_5210_RX_DESC_STATUS0_DATA_LEN; 536203c4805SLuis R. Rodriguez rs->rs_rssi = AR5K_REG_MS(rx_status->rx_status_0, 537203c4805SLuis R. Rodriguez AR5K_5210_RX_DESC_STATUS0_RECEIVE_SIGNAL); 538203c4805SLuis R. Rodriguez rs->rs_rate = AR5K_REG_MS(rx_status->rx_status_0, 539203c4805SLuis R. Rodriguez AR5K_5210_RX_DESC_STATUS0_RECEIVE_RATE); 540203c4805SLuis R. Rodriguez rs->rs_more = !!(rx_status->rx_status_0 & 541203c4805SLuis R. Rodriguez AR5K_5210_RX_DESC_STATUS0_MORE); 5428786123bSBruno Randolf /* TODO: this timestamp is 13 bit, later on we assume 15 bit! 5438786123bSBruno Randolf * also the HAL code for 5210 says the timestamp is bits [10..22] of the 5448786123bSBruno Randolf * TSF, and extends the timestamp here to 15 bit. 5458786123bSBruno Randolf * we need to check on 5210... 5468786123bSBruno Randolf */ 547203c4805SLuis R. Rodriguez rs->rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1, 548203c4805SLuis R. Rodriguez AR5K_5210_RX_DESC_STATUS1_RECEIVE_TIMESTAMP); 5491884a367SBruno Randolf 5501884a367SBruno Randolf if (ah->ah_version == AR5K_AR5211) 5511884a367SBruno Randolf rs->rs_antenna = AR5K_REG_MS(rx_status->rx_status_0, 5521884a367SBruno Randolf AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANT_5211); 5531884a367SBruno Randolf else 5541884a367SBruno Randolf rs->rs_antenna = (rx_status->rx_status_0 & 5551884a367SBruno Randolf AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANT_5210) 5561884a367SBruno Randolf ? 2 : 1; 5571884a367SBruno Randolf 558203c4805SLuis R. Rodriguez /* 559203c4805SLuis R. Rodriguez * Key table status 560203c4805SLuis R. Rodriguez */ 561203c4805SLuis R. Rodriguez if (rx_status->rx_status_1 & AR5K_5210_RX_DESC_STATUS1_KEY_INDEX_VALID) 562203c4805SLuis R. Rodriguez rs->rs_keyix = AR5K_REG_MS(rx_status->rx_status_1, 563203c4805SLuis R. Rodriguez AR5K_5210_RX_DESC_STATUS1_KEY_INDEX); 564203c4805SLuis R. Rodriguez else 565203c4805SLuis R. Rodriguez rs->rs_keyix = AR5K_RXKEYIX_INVALID; 566203c4805SLuis R. Rodriguez 567203c4805SLuis R. Rodriguez /* 568203c4805SLuis R. Rodriguez * Receive/descriptor errors 569203c4805SLuis R. Rodriguez */ 570203c4805SLuis R. Rodriguez if (!(rx_status->rx_status_1 & 571203c4805SLuis R. Rodriguez AR5K_5210_RX_DESC_STATUS1_FRAME_RECEIVE_OK)) { 572203c4805SLuis R. Rodriguez if (rx_status->rx_status_1 & 573203c4805SLuis R. Rodriguez AR5K_5210_RX_DESC_STATUS1_CRC_ERROR) 574203c4805SLuis R. Rodriguez rs->rs_status |= AR5K_RXERR_CRC; 575203c4805SLuis R. Rodriguez 5768786123bSBruno Randolf /* only on 5210 */ 5778786123bSBruno Randolf if ((ah->ah_version == AR5K_AR5210) && 5788786123bSBruno Randolf (rx_status->rx_status_1 & 5798786123bSBruno Randolf AR5K_5210_RX_DESC_STATUS1_FIFO_OVERRUN_5210)) 580203c4805SLuis R. Rodriguez rs->rs_status |= AR5K_RXERR_FIFO; 581203c4805SLuis R. Rodriguez 582203c4805SLuis R. Rodriguez if (rx_status->rx_status_1 & 583203c4805SLuis R. Rodriguez AR5K_5210_RX_DESC_STATUS1_PHY_ERROR) { 584203c4805SLuis R. Rodriguez rs->rs_status |= AR5K_RXERR_PHY; 5858786123bSBruno Randolf rs->rs_phyerr = AR5K_REG_MS(rx_status->rx_status_1, 586203c4805SLuis R. Rodriguez AR5K_5210_RX_DESC_STATUS1_PHY_ERROR); 587203c4805SLuis R. Rodriguez } 588203c4805SLuis R. Rodriguez 589203c4805SLuis R. Rodriguez if (rx_status->rx_status_1 & 590203c4805SLuis R. Rodriguez AR5K_5210_RX_DESC_STATUS1_DECRYPT_CRC_ERROR) 591203c4805SLuis R. Rodriguez rs->rs_status |= AR5K_RXERR_DECRYPT; 592203c4805SLuis R. Rodriguez } 593203c4805SLuis R. Rodriguez 594203c4805SLuis R. Rodriguez return 0; 595203c4805SLuis R. Rodriguez } 596203c4805SLuis R. Rodriguez 597203c4805SLuis R. Rodriguez /* 598203c4805SLuis R. Rodriguez * Proccess the rx status descriptor on 5212 599203c4805SLuis R. Rodriguez */ 600203c4805SLuis R. Rodriguez static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah, 6012847109fSBruno Randolf struct ath5k_desc *desc, 6022847109fSBruno Randolf struct ath5k_rx_status *rs) 603203c4805SLuis R. Rodriguez { 604203c4805SLuis R. Rodriguez struct ath5k_hw_rx_status *rx_status; 605203c4805SLuis R. Rodriguez 60662412a8fSBruno Randolf rx_status = &desc->ud.ds_rx.rx_stat; 607203c4805SLuis R. Rodriguez 608203c4805SLuis R. Rodriguez /* No frame received / not ready */ 609203c4805SLuis R. Rodriguez if (unlikely(!(rx_status->rx_status_1 & 610203c4805SLuis R. Rodriguez AR5K_5212_RX_DESC_STATUS1_DONE))) 611203c4805SLuis R. Rodriguez return -EINPROGRESS; 612203c4805SLuis R. Rodriguez 6138786123bSBruno Randolf memset(rs, 0, sizeof(struct ath5k_rx_status)); 6148786123bSBruno Randolf 615203c4805SLuis R. Rodriguez /* 616203c4805SLuis R. Rodriguez * Frame receive status 617203c4805SLuis R. Rodriguez */ 618203c4805SLuis R. Rodriguez rs->rs_datalen = rx_status->rx_status_0 & 619203c4805SLuis R. Rodriguez AR5K_5212_RX_DESC_STATUS0_DATA_LEN; 620203c4805SLuis R. Rodriguez rs->rs_rssi = AR5K_REG_MS(rx_status->rx_status_0, 621203c4805SLuis R. Rodriguez AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL); 622203c4805SLuis R. Rodriguez rs->rs_rate = AR5K_REG_MS(rx_status->rx_status_0, 623203c4805SLuis R. Rodriguez AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE); 624203c4805SLuis R. Rodriguez rs->rs_antenna = AR5K_REG_MS(rx_status->rx_status_0, 625203c4805SLuis R. Rodriguez AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA); 626203c4805SLuis R. Rodriguez rs->rs_more = !!(rx_status->rx_status_0 & 627203c4805SLuis R. Rodriguez AR5K_5212_RX_DESC_STATUS0_MORE); 628203c4805SLuis R. Rodriguez rs->rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1, 629203c4805SLuis R. Rodriguez AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP); 630203c4805SLuis R. Rodriguez 631203c4805SLuis R. Rodriguez /* 632203c4805SLuis R. Rodriguez * Key table status 633203c4805SLuis R. Rodriguez */ 634203c4805SLuis R. Rodriguez if (rx_status->rx_status_1 & AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_VALID) 635203c4805SLuis R. Rodriguez rs->rs_keyix = AR5K_REG_MS(rx_status->rx_status_1, 636203c4805SLuis R. Rodriguez AR5K_5212_RX_DESC_STATUS1_KEY_INDEX); 637203c4805SLuis R. Rodriguez else 638203c4805SLuis R. Rodriguez rs->rs_keyix = AR5K_RXKEYIX_INVALID; 639203c4805SLuis R. Rodriguez 640203c4805SLuis R. Rodriguez /* 641203c4805SLuis R. Rodriguez * Receive/descriptor errors 642203c4805SLuis R. Rodriguez */ 643203c4805SLuis R. Rodriguez if (!(rx_status->rx_status_1 & 644203c4805SLuis R. Rodriguez AR5K_5212_RX_DESC_STATUS1_FRAME_RECEIVE_OK)) { 645203c4805SLuis R. Rodriguez if (rx_status->rx_status_1 & 646203c4805SLuis R. Rodriguez AR5K_5212_RX_DESC_STATUS1_CRC_ERROR) 647203c4805SLuis R. Rodriguez rs->rs_status |= AR5K_RXERR_CRC; 648203c4805SLuis R. Rodriguez 649203c4805SLuis R. Rodriguez if (rx_status->rx_status_1 & 650203c4805SLuis R. Rodriguez AR5K_5212_RX_DESC_STATUS1_PHY_ERROR) { 651203c4805SLuis R. Rodriguez rs->rs_status |= AR5K_RXERR_PHY; 6528786123bSBruno Randolf rs->rs_phyerr = AR5K_REG_MS(rx_status->rx_status_1, 65362412a8fSBruno Randolf AR5K_5212_RX_DESC_STATUS1_PHY_ERROR_CODE); 6546a0076e0SBruno Randolf if (!ah->ah_capabilities.cap_has_phyerr_counters) 6552111ac0dSBruno Randolf ath5k_ani_phy_error_report(ah, rs->rs_phyerr); 656203c4805SLuis R. Rodriguez } 657203c4805SLuis R. Rodriguez 658203c4805SLuis R. Rodriguez if (rx_status->rx_status_1 & 659203c4805SLuis R. Rodriguez AR5K_5212_RX_DESC_STATUS1_DECRYPT_CRC_ERROR) 660203c4805SLuis R. Rodriguez rs->rs_status |= AR5K_RXERR_DECRYPT; 661203c4805SLuis R. Rodriguez 662203c4805SLuis R. Rodriguez if (rx_status->rx_status_1 & 663203c4805SLuis R. Rodriguez AR5K_5212_RX_DESC_STATUS1_MIC_ERROR) 664203c4805SLuis R. Rodriguez rs->rs_status |= AR5K_RXERR_MIC; 665203c4805SLuis R. Rodriguez } 666203c4805SLuis R. Rodriguez return 0; 667203c4805SLuis R. Rodriguez } 668203c4805SLuis R. Rodriguez 669203c4805SLuis R. Rodriguez /* 670203c4805SLuis R. Rodriguez * Init function pointers inside ath5k_hw struct 671203c4805SLuis R. Rodriguez */ 672203c4805SLuis R. Rodriguez int ath5k_hw_init_desc_functions(struct ath5k_hw *ah) 673203c4805SLuis R. Rodriguez { 674203c4805SLuis R. Rodriguez if (ah->ah_version == AR5K_AR5212) { 675203c4805SLuis R. Rodriguez ah->ah_setup_tx_desc = ath5k_hw_setup_4word_tx_desc; 676203c4805SLuis R. Rodriguez ah->ah_proc_tx_desc = ath5k_hw_proc_4word_tx_status; 677203c4805SLuis R. Rodriguez ah->ah_proc_rx_desc = ath5k_hw_proc_5212_rx_status; 678a6668193SBruno Randolf } else if (ah->ah_version <= AR5K_AR5211) { 679a6668193SBruno Randolf ah->ah_setup_tx_desc = ath5k_hw_setup_2word_tx_desc; 680a6668193SBruno Randolf ah->ah_proc_tx_desc = ath5k_hw_proc_2word_tx_status; 681203c4805SLuis R. Rodriguez ah->ah_proc_rx_desc = ath5k_hw_proc_5210_rx_status; 682a6668193SBruno Randolf } else 683a6668193SBruno Randolf return -ENOTSUPP; 684203c4805SLuis R. Rodriguez return 0; 685203c4805SLuis R. Rodriguez } 686