162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
362306a36Sopenharmony_ci * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
462306a36Sopenharmony_ci * Copyright (c) 2007-2008 Pavel Roskin <proski@gnu.org>
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Permission to use, copy, modify, and distribute this software for any
762306a36Sopenharmony_ci * purpose with or without fee is hereby granted, provided that the above
862306a36Sopenharmony_ci * copyright notice and this permission notice appear in all copies.
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1162306a36Sopenharmony_ci * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1262306a36Sopenharmony_ci * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1362306a36Sopenharmony_ci * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1462306a36Sopenharmony_ci * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1562306a36Sopenharmony_ci * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1662306a36Sopenharmony_ci * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1762306a36Sopenharmony_ci *
1862306a36Sopenharmony_ci */
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci/******************************\
2162306a36Sopenharmony_ci Hardware Descriptor Functions
2262306a36Sopenharmony_ci\******************************/
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#include "ath5k.h"
2762306a36Sopenharmony_ci#include "reg.h"
2862306a36Sopenharmony_ci#include "debug.h"
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci/**
3262306a36Sopenharmony_ci * DOC: Hardware descriptor functions
3362306a36Sopenharmony_ci *
3462306a36Sopenharmony_ci * Here we handle the processing of the low-level hw descriptors
3562306a36Sopenharmony_ci * that hw reads and writes via DMA for each TX and RX attempt (that means
3662306a36Sopenharmony_ci * we can also have descriptors for failed TX/RX tries). We have two kind of
3762306a36Sopenharmony_ci * descriptors for RX and TX, control descriptors tell the hw how to send or
3862306a36Sopenharmony_ci * receive a packet where to read/write it from/to etc and status descriptors
3962306a36Sopenharmony_ci * that contain information about how the packet was sent or received (errors
4062306a36Sopenharmony_ci * included).
4162306a36Sopenharmony_ci *
4262306a36Sopenharmony_ci * Descriptor format is not exactly the same for each MAC chip version so we
4362306a36Sopenharmony_ci * have function pointers on &struct ath5k_hw we initialize at runtime based on
4462306a36Sopenharmony_ci * the chip used.
4562306a36Sopenharmony_ci */
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci/************************\
4962306a36Sopenharmony_ci* TX Control descriptors *
5062306a36Sopenharmony_ci\************************/
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci/**
5362306a36Sopenharmony_ci * ath5k_hw_setup_2word_tx_desc() - Initialize a 2-word tx control descriptor
5462306a36Sopenharmony_ci * @ah: The &struct ath5k_hw
5562306a36Sopenharmony_ci * @desc: The &struct ath5k_desc
5662306a36Sopenharmony_ci * @pkt_len: Frame length in bytes
5762306a36Sopenharmony_ci * @hdr_len: Header length in bytes (only used on AR5210)
5862306a36Sopenharmony_ci * @padsize: Any padding we've added to the frame length
5962306a36Sopenharmony_ci * @type: One of enum ath5k_pkt_type
6062306a36Sopenharmony_ci * @tx_power: Tx power in 0.5dB steps
6162306a36Sopenharmony_ci * @tx_rate0: HW idx for transmission rate
6262306a36Sopenharmony_ci * @tx_tries0: Max number of retransmissions
6362306a36Sopenharmony_ci * @key_index: Index on key table to use for encryption
6462306a36Sopenharmony_ci * @antenna_mode: Which antenna to use (0 for auto)
6562306a36Sopenharmony_ci * @flags: One of AR5K_TXDESC_* flags (desc.h)
6662306a36Sopenharmony_ci * @rtscts_rate: HW idx for RTS/CTS transmission rate
6762306a36Sopenharmony_ci * @rtscts_duration: What to put on duration field on the header of RTS/CTS
6862306a36Sopenharmony_ci *
6962306a36Sopenharmony_ci * Internal function to initialize a 2-Word TX control descriptor
7062306a36Sopenharmony_ci * found on AR5210 and AR5211 MACs chips.
7162306a36Sopenharmony_ci *
7262306a36Sopenharmony_ci * Returns 0 on success or -EINVAL on false input
7362306a36Sopenharmony_ci */
7462306a36Sopenharmony_cistatic int
7562306a36Sopenharmony_ciath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah,
7662306a36Sopenharmony_ci			struct ath5k_desc *desc,
7762306a36Sopenharmony_ci			unsigned int pkt_len, unsigned int hdr_len,
7862306a36Sopenharmony_ci			int padsize,
7962306a36Sopenharmony_ci			enum ath5k_pkt_type type,
8062306a36Sopenharmony_ci			unsigned int tx_power,
8162306a36Sopenharmony_ci			unsigned int tx_rate0, unsigned int tx_tries0,
8262306a36Sopenharmony_ci			unsigned int key_index,
8362306a36Sopenharmony_ci			unsigned int antenna_mode,
8462306a36Sopenharmony_ci			unsigned int flags,
8562306a36Sopenharmony_ci			unsigned int rtscts_rate, unsigned int rtscts_duration)
8662306a36Sopenharmony_ci{
8762306a36Sopenharmony_ci	u32 frame_type;
8862306a36Sopenharmony_ci	struct ath5k_hw_2w_tx_ctl *tx_ctl;
8962306a36Sopenharmony_ci	unsigned int frame_len;
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	tx_ctl = &desc->ud.ds_tx5210.tx_ctl;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	/*
9462306a36Sopenharmony_ci	 * Validate input
9562306a36Sopenharmony_ci	 * - Zero retries don't make sense.
9662306a36Sopenharmony_ci	 * - A zero rate will put the HW into a mode where it continuously sends
9762306a36Sopenharmony_ci	 *   noise on the channel, so it is important to avoid this.
9862306a36Sopenharmony_ci	 */
9962306a36Sopenharmony_ci	if (unlikely(tx_tries0 == 0)) {
10062306a36Sopenharmony_ci		ATH5K_ERR(ah, "zero retries\n");
10162306a36Sopenharmony_ci		WARN_ON(1);
10262306a36Sopenharmony_ci		return -EINVAL;
10362306a36Sopenharmony_ci	}
10462306a36Sopenharmony_ci	if (unlikely(tx_rate0 == 0)) {
10562306a36Sopenharmony_ci		ATH5K_ERR(ah, "zero rate\n");
10662306a36Sopenharmony_ci		WARN_ON(1);
10762306a36Sopenharmony_ci		return -EINVAL;
10862306a36Sopenharmony_ci	}
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	/* Clear descriptor */
11162306a36Sopenharmony_ci	memset(&desc->ud.ds_tx5210, 0, sizeof(struct ath5k_hw_5210_tx_desc));
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	/* Setup control descriptor */
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	/* Verify and set frame length */
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	/* remove padding we might have added before */
11862306a36Sopenharmony_ci	frame_len = pkt_len - padsize + FCS_LEN;
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	if (frame_len & ~AR5K_2W_TX_DESC_CTL0_FRAME_LEN)
12162306a36Sopenharmony_ci		return -EINVAL;
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	tx_ctl->tx_control_0 = frame_len & AR5K_2W_TX_DESC_CTL0_FRAME_LEN;
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	/* Verify and set buffer length */
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	/* NB: beacon's BufLen must be a multiple of 4 bytes */
12862306a36Sopenharmony_ci	if (type == AR5K_PKT_TYPE_BEACON)
12962306a36Sopenharmony_ci		pkt_len = roundup(pkt_len, 4);
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	if (pkt_len & ~AR5K_2W_TX_DESC_CTL1_BUF_LEN)
13262306a36Sopenharmony_ci		return -EINVAL;
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	tx_ctl->tx_control_1 = pkt_len & AR5K_2W_TX_DESC_CTL1_BUF_LEN;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	/*
13762306a36Sopenharmony_ci	 * Verify and set header length (only 5210)
13862306a36Sopenharmony_ci	 */
13962306a36Sopenharmony_ci	if (ah->ah_version == AR5K_AR5210) {
14062306a36Sopenharmony_ci		if (hdr_len & ~AR5K_2W_TX_DESC_CTL0_HEADER_LEN_5210)
14162306a36Sopenharmony_ci			return -EINVAL;
14262306a36Sopenharmony_ci		tx_ctl->tx_control_0 |=
14362306a36Sopenharmony_ci			AR5K_REG_SM(hdr_len, AR5K_2W_TX_DESC_CTL0_HEADER_LEN_5210);
14462306a36Sopenharmony_ci	}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	/*Differences between 5210-5211*/
14762306a36Sopenharmony_ci	if (ah->ah_version == AR5K_AR5210) {
14862306a36Sopenharmony_ci		switch (type) {
14962306a36Sopenharmony_ci		case AR5K_PKT_TYPE_BEACON:
15062306a36Sopenharmony_ci		case AR5K_PKT_TYPE_PROBE_RESP:
15162306a36Sopenharmony_ci			frame_type = AR5K_AR5210_TX_DESC_FRAME_TYPE_NO_DELAY;
15262306a36Sopenharmony_ci			break;
15362306a36Sopenharmony_ci		case AR5K_PKT_TYPE_PIFS:
15462306a36Sopenharmony_ci			frame_type = AR5K_AR5210_TX_DESC_FRAME_TYPE_PIFS;
15562306a36Sopenharmony_ci			break;
15662306a36Sopenharmony_ci		default:
15762306a36Sopenharmony_ci			frame_type = type;
15862306a36Sopenharmony_ci			break;
15962306a36Sopenharmony_ci		}
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci		tx_ctl->tx_control_0 |=
16262306a36Sopenharmony_ci		AR5K_REG_SM(frame_type, AR5K_2W_TX_DESC_CTL0_FRAME_TYPE_5210) |
16362306a36Sopenharmony_ci		AR5K_REG_SM(tx_rate0, AR5K_2W_TX_DESC_CTL0_XMIT_RATE);
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	} else {
16662306a36Sopenharmony_ci		tx_ctl->tx_control_0 |=
16762306a36Sopenharmony_ci			AR5K_REG_SM(tx_rate0, AR5K_2W_TX_DESC_CTL0_XMIT_RATE) |
16862306a36Sopenharmony_ci			AR5K_REG_SM(antenna_mode,
16962306a36Sopenharmony_ci				AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT);
17062306a36Sopenharmony_ci		tx_ctl->tx_control_1 |=
17162306a36Sopenharmony_ci			AR5K_REG_SM(type, AR5K_2W_TX_DESC_CTL1_FRAME_TYPE_5211);
17262306a36Sopenharmony_ci	}
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci#define _TX_FLAGS(_c, _flag)					\
17562306a36Sopenharmony_ci	if (flags & AR5K_TXDESC_##_flag) {			\
17662306a36Sopenharmony_ci		tx_ctl->tx_control_##_c |=			\
17762306a36Sopenharmony_ci			AR5K_2W_TX_DESC_CTL##_c##_##_flag;	\
17862306a36Sopenharmony_ci	}
17962306a36Sopenharmony_ci#define _TX_FLAGS_5211(_c, _flag)					\
18062306a36Sopenharmony_ci	if (flags & AR5K_TXDESC_##_flag) {				\
18162306a36Sopenharmony_ci		tx_ctl->tx_control_##_c |=				\
18262306a36Sopenharmony_ci			AR5K_2W_TX_DESC_CTL##_c##_##_flag##_5211;	\
18362306a36Sopenharmony_ci	}
18462306a36Sopenharmony_ci	_TX_FLAGS(0, CLRDMASK);
18562306a36Sopenharmony_ci	_TX_FLAGS(0, INTREQ);
18662306a36Sopenharmony_ci	_TX_FLAGS(0, RTSENA);
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	if (ah->ah_version == AR5K_AR5211) {
18962306a36Sopenharmony_ci		_TX_FLAGS_5211(0, VEOL);
19062306a36Sopenharmony_ci		_TX_FLAGS_5211(1, NOACK);
19162306a36Sopenharmony_ci	}
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci#undef _TX_FLAGS
19462306a36Sopenharmony_ci#undef _TX_FLAGS_5211
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	/*
19762306a36Sopenharmony_ci	 * WEP crap
19862306a36Sopenharmony_ci	 */
19962306a36Sopenharmony_ci	if (key_index != AR5K_TXKEYIX_INVALID) {
20062306a36Sopenharmony_ci		tx_ctl->tx_control_0 |=
20162306a36Sopenharmony_ci			AR5K_2W_TX_DESC_CTL0_ENCRYPT_KEY_VALID;
20262306a36Sopenharmony_ci		tx_ctl->tx_control_1 |=
20362306a36Sopenharmony_ci			AR5K_REG_SM(key_index,
20462306a36Sopenharmony_ci			AR5K_2W_TX_DESC_CTL1_ENC_KEY_IDX);
20562306a36Sopenharmony_ci	}
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	/*
20862306a36Sopenharmony_ci	 * RTS/CTS Duration [5210 ?]
20962306a36Sopenharmony_ci	 */
21062306a36Sopenharmony_ci	if ((ah->ah_version == AR5K_AR5210) &&
21162306a36Sopenharmony_ci			(flags & (AR5K_TXDESC_RTSENA | AR5K_TXDESC_CTSENA)))
21262306a36Sopenharmony_ci		tx_ctl->tx_control_1 |= rtscts_duration &
21362306a36Sopenharmony_ci				AR5K_2W_TX_DESC_CTL1_RTS_DURATION_5210;
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	return 0;
21662306a36Sopenharmony_ci}
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci/**
21962306a36Sopenharmony_ci * ath5k_hw_setup_4word_tx_desc() - Initialize a 4-word tx control descriptor
22062306a36Sopenharmony_ci * @ah: The &struct ath5k_hw
22162306a36Sopenharmony_ci * @desc: The &struct ath5k_desc
22262306a36Sopenharmony_ci * @pkt_len: Frame length in bytes
22362306a36Sopenharmony_ci * @hdr_len: Header length in bytes (only used on AR5210)
22462306a36Sopenharmony_ci * @padsize: Any padding we've added to the frame length
22562306a36Sopenharmony_ci * @type: One of enum ath5k_pkt_type
22662306a36Sopenharmony_ci * @tx_power: Tx power in 0.5dB steps
22762306a36Sopenharmony_ci * @tx_rate0: HW idx for transmission rate
22862306a36Sopenharmony_ci * @tx_tries0: Max number of retransmissions
22962306a36Sopenharmony_ci * @key_index: Index on key table to use for encryption
23062306a36Sopenharmony_ci * @antenna_mode: Which antenna to use (0 for auto)
23162306a36Sopenharmony_ci * @flags: One of AR5K_TXDESC_* flags (desc.h)
23262306a36Sopenharmony_ci * @rtscts_rate: HW idx for RTS/CTS transmission rate
23362306a36Sopenharmony_ci * @rtscts_duration: What to put on duration field on the header of RTS/CTS
23462306a36Sopenharmony_ci *
23562306a36Sopenharmony_ci * Internal function to initialize a 4-Word TX control descriptor
23662306a36Sopenharmony_ci * found on AR5212 and later MACs chips.
23762306a36Sopenharmony_ci *
23862306a36Sopenharmony_ci * Returns 0 on success or -EINVAL on false input
23962306a36Sopenharmony_ci */
24062306a36Sopenharmony_cistatic int
24162306a36Sopenharmony_ciath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah,
24262306a36Sopenharmony_ci			struct ath5k_desc *desc,
24362306a36Sopenharmony_ci			unsigned int pkt_len, unsigned int hdr_len,
24462306a36Sopenharmony_ci			int padsize,
24562306a36Sopenharmony_ci			enum ath5k_pkt_type type,
24662306a36Sopenharmony_ci			unsigned int tx_power,
24762306a36Sopenharmony_ci			unsigned int tx_rate0, unsigned int tx_tries0,
24862306a36Sopenharmony_ci			unsigned int key_index,
24962306a36Sopenharmony_ci			unsigned int antenna_mode,
25062306a36Sopenharmony_ci			unsigned int flags,
25162306a36Sopenharmony_ci			unsigned int rtscts_rate, unsigned int rtscts_duration)
25262306a36Sopenharmony_ci{
25362306a36Sopenharmony_ci	struct ath5k_hw_4w_tx_ctl *tx_ctl;
25462306a36Sopenharmony_ci	unsigned int frame_len;
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	/*
25762306a36Sopenharmony_ci	 * Use local variables for these to reduce load/store access on
25862306a36Sopenharmony_ci	 * uncached memory
25962306a36Sopenharmony_ci	 */
26062306a36Sopenharmony_ci	u32 txctl0 = 0, txctl1 = 0, txctl2 = 0, txctl3 = 0;
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	tx_ctl = &desc->ud.ds_tx5212.tx_ctl;
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	/*
26562306a36Sopenharmony_ci	 * Validate input
26662306a36Sopenharmony_ci	 * - Zero retries don't make sense.
26762306a36Sopenharmony_ci	 * - A zero rate will put the HW into a mode where it continuously sends
26862306a36Sopenharmony_ci	 *   noise on the channel, so it is important to avoid this.
26962306a36Sopenharmony_ci	 */
27062306a36Sopenharmony_ci	if (unlikely(tx_tries0 == 0)) {
27162306a36Sopenharmony_ci		ATH5K_ERR(ah, "zero retries\n");
27262306a36Sopenharmony_ci		WARN_ON(1);
27362306a36Sopenharmony_ci		return -EINVAL;
27462306a36Sopenharmony_ci	}
27562306a36Sopenharmony_ci	if (unlikely(tx_rate0 == 0)) {
27662306a36Sopenharmony_ci		ATH5K_ERR(ah, "zero rate\n");
27762306a36Sopenharmony_ci		WARN_ON(1);
27862306a36Sopenharmony_ci		return -EINVAL;
27962306a36Sopenharmony_ci	}
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	tx_power += ah->ah_txpower.txp_offset;
28262306a36Sopenharmony_ci	if (tx_power > AR5K_TUNE_MAX_TXPOWER)
28362306a36Sopenharmony_ci		tx_power = AR5K_TUNE_MAX_TXPOWER;
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	/* Clear descriptor status area */
28662306a36Sopenharmony_ci	memset(&desc->ud.ds_tx5212.tx_stat, 0,
28762306a36Sopenharmony_ci	       sizeof(desc->ud.ds_tx5212.tx_stat));
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	/* Setup control descriptor */
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	/* Verify and set frame length */
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	/* remove padding we might have added before */
29462306a36Sopenharmony_ci	frame_len = pkt_len - padsize + FCS_LEN;
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	if (frame_len & ~AR5K_4W_TX_DESC_CTL0_FRAME_LEN)
29762306a36Sopenharmony_ci		return -EINVAL;
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	txctl0 = frame_len & AR5K_4W_TX_DESC_CTL0_FRAME_LEN;
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	/* Verify and set buffer length */
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	/* NB: beacon's BufLen must be a multiple of 4 bytes */
30462306a36Sopenharmony_ci	if (type == AR5K_PKT_TYPE_BEACON)
30562306a36Sopenharmony_ci		pkt_len = roundup(pkt_len, 4);
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	if (pkt_len & ~AR5K_4W_TX_DESC_CTL1_BUF_LEN)
30862306a36Sopenharmony_ci		return -EINVAL;
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	txctl1 = pkt_len & AR5K_4W_TX_DESC_CTL1_BUF_LEN;
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	txctl0 |= AR5K_REG_SM(tx_power, AR5K_4W_TX_DESC_CTL0_XMIT_POWER) |
31362306a36Sopenharmony_ci		  AR5K_REG_SM(antenna_mode, AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT);
31462306a36Sopenharmony_ci	txctl1 |= AR5K_REG_SM(type, AR5K_4W_TX_DESC_CTL1_FRAME_TYPE);
31562306a36Sopenharmony_ci	txctl2 = AR5K_REG_SM(tx_tries0, AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0);
31662306a36Sopenharmony_ci	txctl3 = tx_rate0 & AR5K_4W_TX_DESC_CTL3_XMIT_RATE0;
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci#define _TX_FLAGS(_c, _flag)					\
31962306a36Sopenharmony_ci	if (flags & AR5K_TXDESC_##_flag) {			\
32062306a36Sopenharmony_ci		txctl##_c |= AR5K_4W_TX_DESC_CTL##_c##_##_flag;	\
32162306a36Sopenharmony_ci	}
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	_TX_FLAGS(0, CLRDMASK);
32462306a36Sopenharmony_ci	_TX_FLAGS(0, VEOL);
32562306a36Sopenharmony_ci	_TX_FLAGS(0, INTREQ);
32662306a36Sopenharmony_ci	_TX_FLAGS(0, RTSENA);
32762306a36Sopenharmony_ci	_TX_FLAGS(0, CTSENA);
32862306a36Sopenharmony_ci	_TX_FLAGS(1, NOACK);
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci#undef _TX_FLAGS
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	/*
33362306a36Sopenharmony_ci	 * WEP crap
33462306a36Sopenharmony_ci	 */
33562306a36Sopenharmony_ci	if (key_index != AR5K_TXKEYIX_INVALID) {
33662306a36Sopenharmony_ci		txctl0 |= AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID;
33762306a36Sopenharmony_ci		txctl1 |= AR5K_REG_SM(key_index,
33862306a36Sopenharmony_ci				AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_IDX);
33962306a36Sopenharmony_ci	}
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	/*
34262306a36Sopenharmony_ci	 * RTS/CTS
34362306a36Sopenharmony_ci	 */
34462306a36Sopenharmony_ci	if (flags & (AR5K_TXDESC_RTSENA | AR5K_TXDESC_CTSENA)) {
34562306a36Sopenharmony_ci		if ((flags & AR5K_TXDESC_RTSENA) &&
34662306a36Sopenharmony_ci				(flags & AR5K_TXDESC_CTSENA))
34762306a36Sopenharmony_ci			return -EINVAL;
34862306a36Sopenharmony_ci		txctl2 |= rtscts_duration & AR5K_4W_TX_DESC_CTL2_RTS_DURATION;
34962306a36Sopenharmony_ci		txctl3 |= AR5K_REG_SM(rtscts_rate,
35062306a36Sopenharmony_ci				AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE);
35162306a36Sopenharmony_ci	}
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	tx_ctl->tx_control_0 = txctl0;
35462306a36Sopenharmony_ci	tx_ctl->tx_control_1 = txctl1;
35562306a36Sopenharmony_ci	tx_ctl->tx_control_2 = txctl2;
35662306a36Sopenharmony_ci	tx_ctl->tx_control_3 = txctl3;
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	return 0;
35962306a36Sopenharmony_ci}
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci/**
36262306a36Sopenharmony_ci * ath5k_hw_setup_mrr_tx_desc() - Initialize an MRR tx control descriptor
36362306a36Sopenharmony_ci * @ah: The &struct ath5k_hw
36462306a36Sopenharmony_ci * @desc: The &struct ath5k_desc
36562306a36Sopenharmony_ci * @tx_rate1: HW idx for rate used on transmission series 1
36662306a36Sopenharmony_ci * @tx_tries1: Max number of retransmissions for transmission series 1
36762306a36Sopenharmony_ci * @tx_rate2: HW idx for rate used on transmission series 2
36862306a36Sopenharmony_ci * @tx_tries2: Max number of retransmissions for transmission series 2
36962306a36Sopenharmony_ci * @tx_rate3: HW idx for rate used on transmission series 3
37062306a36Sopenharmony_ci * @tx_tries3: Max number of retransmissions for transmission series 3
37162306a36Sopenharmony_ci *
37262306a36Sopenharmony_ci * Multi rate retry (MRR) tx control descriptors are available only on AR5212
37362306a36Sopenharmony_ci * MACs, they are part of the normal 4-word tx control descriptor (see above)
37462306a36Sopenharmony_ci * but we handle them through a separate function for better abstraction.
37562306a36Sopenharmony_ci *
37662306a36Sopenharmony_ci * Returns 0 on success or -EINVAL on invalid input
37762306a36Sopenharmony_ci */
37862306a36Sopenharmony_ciint
37962306a36Sopenharmony_ciath5k_hw_setup_mrr_tx_desc(struct ath5k_hw *ah,
38062306a36Sopenharmony_ci			struct ath5k_desc *desc,
38162306a36Sopenharmony_ci			u_int tx_rate1, u_int tx_tries1,
38262306a36Sopenharmony_ci			u_int tx_rate2, u_int tx_tries2,
38362306a36Sopenharmony_ci			u_int tx_rate3, u_int tx_tries3)
38462306a36Sopenharmony_ci{
38562306a36Sopenharmony_ci	struct ath5k_hw_4w_tx_ctl *tx_ctl;
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	/* no mrr support for cards older than 5212 */
38862306a36Sopenharmony_ci	if (ah->ah_version < AR5K_AR5212)
38962306a36Sopenharmony_ci		return 0;
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	/*
39262306a36Sopenharmony_ci	 * Rates can be 0 as long as the retry count is 0 too.
39362306a36Sopenharmony_ci	 * A zero rate and nonzero retry count will put the HW into a mode where
39462306a36Sopenharmony_ci	 * it continuously sends noise on the channel, so it is important to
39562306a36Sopenharmony_ci	 * avoid this.
39662306a36Sopenharmony_ci	 */
39762306a36Sopenharmony_ci	if (unlikely((tx_rate1 == 0 && tx_tries1 != 0) ||
39862306a36Sopenharmony_ci		     (tx_rate2 == 0 && tx_tries2 != 0) ||
39962306a36Sopenharmony_ci		     (tx_rate3 == 0 && tx_tries3 != 0))) {
40062306a36Sopenharmony_ci		ATH5K_ERR(ah, "zero rate\n");
40162306a36Sopenharmony_ci		WARN_ON(1);
40262306a36Sopenharmony_ci		return -EINVAL;
40362306a36Sopenharmony_ci	}
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	if (ah->ah_version == AR5K_AR5212) {
40662306a36Sopenharmony_ci		tx_ctl = &desc->ud.ds_tx5212.tx_ctl;
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci#define _XTX_TRIES(_n)							\
40962306a36Sopenharmony_ci	if (tx_tries##_n) {						\
41062306a36Sopenharmony_ci		tx_ctl->tx_control_2 |=					\
41162306a36Sopenharmony_ci		    AR5K_REG_SM(tx_tries##_n,				\
41262306a36Sopenharmony_ci		    AR5K_4W_TX_DESC_CTL2_XMIT_TRIES##_n);		\
41362306a36Sopenharmony_ci		tx_ctl->tx_control_3 |=					\
41462306a36Sopenharmony_ci		    AR5K_REG_SM(tx_rate##_n,				\
41562306a36Sopenharmony_ci		    AR5K_4W_TX_DESC_CTL3_XMIT_RATE##_n);		\
41662306a36Sopenharmony_ci	}
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci		_XTX_TRIES(1);
41962306a36Sopenharmony_ci		_XTX_TRIES(2);
42062306a36Sopenharmony_ci		_XTX_TRIES(3);
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci#undef _XTX_TRIES
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci		return 1;
42562306a36Sopenharmony_ci	}
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	return 0;
42862306a36Sopenharmony_ci}
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci/***********************\
43262306a36Sopenharmony_ci* TX Status descriptors *
43362306a36Sopenharmony_ci\***********************/
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci/**
43662306a36Sopenharmony_ci * ath5k_hw_proc_2word_tx_status() - Process a tx status descriptor on 5210/1
43762306a36Sopenharmony_ci * @ah: The &struct ath5k_hw
43862306a36Sopenharmony_ci * @desc: The &struct ath5k_desc
43962306a36Sopenharmony_ci * @ts: The &struct ath5k_tx_status
44062306a36Sopenharmony_ci */
44162306a36Sopenharmony_cistatic int
44262306a36Sopenharmony_ciath5k_hw_proc_2word_tx_status(struct ath5k_hw *ah,
44362306a36Sopenharmony_ci				struct ath5k_desc *desc,
44462306a36Sopenharmony_ci				struct ath5k_tx_status *ts)
44562306a36Sopenharmony_ci{
44662306a36Sopenharmony_ci	struct ath5k_hw_tx_status *tx_status;
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	tx_status = &desc->ud.ds_tx5210.tx_stat;
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	/* No frame has been send or error */
45162306a36Sopenharmony_ci	if (unlikely((tx_status->tx_status_1 & AR5K_DESC_TX_STATUS1_DONE) == 0))
45262306a36Sopenharmony_ci		return -EINPROGRESS;
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	/*
45562306a36Sopenharmony_ci	 * Get descriptor status
45662306a36Sopenharmony_ci	 */
45762306a36Sopenharmony_ci	ts->ts_tstamp = AR5K_REG_MS(tx_status->tx_status_0,
45862306a36Sopenharmony_ci		AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP);
45962306a36Sopenharmony_ci	ts->ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0,
46062306a36Sopenharmony_ci		AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT);
46162306a36Sopenharmony_ci	ts->ts_final_retry = AR5K_REG_MS(tx_status->tx_status_0,
46262306a36Sopenharmony_ci		AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT);
46362306a36Sopenharmony_ci	/*TODO: ts->ts_virtcol + test*/
46462306a36Sopenharmony_ci	ts->ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1,
46562306a36Sopenharmony_ci		AR5K_DESC_TX_STATUS1_SEQ_NUM);
46662306a36Sopenharmony_ci	ts->ts_rssi = AR5K_REG_MS(tx_status->tx_status_1,
46762306a36Sopenharmony_ci		AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH);
46862306a36Sopenharmony_ci	ts->ts_antenna = 1;
46962306a36Sopenharmony_ci	ts->ts_status = 0;
47062306a36Sopenharmony_ci	ts->ts_final_idx = 0;
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	if (!(tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK)) {
47362306a36Sopenharmony_ci		if (tx_status->tx_status_0 &
47462306a36Sopenharmony_ci				AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES)
47562306a36Sopenharmony_ci			ts->ts_status |= AR5K_TXERR_XRETRY;
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci		if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN)
47862306a36Sopenharmony_ci			ts->ts_status |= AR5K_TXERR_FIFO;
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci		if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FILTERED)
48162306a36Sopenharmony_ci			ts->ts_status |= AR5K_TXERR_FILT;
48262306a36Sopenharmony_ci	}
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	return 0;
48562306a36Sopenharmony_ci}
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci/**
48862306a36Sopenharmony_ci * ath5k_hw_proc_4word_tx_status() - Process a tx status descriptor on 5212
48962306a36Sopenharmony_ci * @ah: The &struct ath5k_hw
49062306a36Sopenharmony_ci * @desc: The &struct ath5k_desc
49162306a36Sopenharmony_ci * @ts: The &struct ath5k_tx_status
49262306a36Sopenharmony_ci */
49362306a36Sopenharmony_cistatic int
49462306a36Sopenharmony_ciath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah,
49562306a36Sopenharmony_ci				struct ath5k_desc *desc,
49662306a36Sopenharmony_ci				struct ath5k_tx_status *ts)
49762306a36Sopenharmony_ci{
49862306a36Sopenharmony_ci	struct ath5k_hw_tx_status *tx_status;
49962306a36Sopenharmony_ci	u32 txstat0, txstat1;
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	tx_status = &desc->ud.ds_tx5212.tx_stat;
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci	txstat1 = READ_ONCE(tx_status->tx_status_1);
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	/* No frame has been send or error */
50662306a36Sopenharmony_ci	if (unlikely(!(txstat1 & AR5K_DESC_TX_STATUS1_DONE)))
50762306a36Sopenharmony_ci		return -EINPROGRESS;
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	txstat0 = READ_ONCE(tx_status->tx_status_0);
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	/*
51262306a36Sopenharmony_ci	 * Get descriptor status
51362306a36Sopenharmony_ci	 */
51462306a36Sopenharmony_ci	ts->ts_tstamp = AR5K_REG_MS(txstat0,
51562306a36Sopenharmony_ci		AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP);
51662306a36Sopenharmony_ci	ts->ts_shortretry = AR5K_REG_MS(txstat0,
51762306a36Sopenharmony_ci		AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT);
51862306a36Sopenharmony_ci	ts->ts_final_retry = AR5K_REG_MS(txstat0,
51962306a36Sopenharmony_ci		AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT);
52062306a36Sopenharmony_ci	ts->ts_seqnum = AR5K_REG_MS(txstat1,
52162306a36Sopenharmony_ci		AR5K_DESC_TX_STATUS1_SEQ_NUM);
52262306a36Sopenharmony_ci	ts->ts_rssi = AR5K_REG_MS(txstat1,
52362306a36Sopenharmony_ci		AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH);
52462306a36Sopenharmony_ci	ts->ts_antenna = (txstat1 &
52562306a36Sopenharmony_ci		AR5K_DESC_TX_STATUS1_XMIT_ANTENNA_5212) ? 2 : 1;
52662306a36Sopenharmony_ci	ts->ts_status = 0;
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	ts->ts_final_idx = AR5K_REG_MS(txstat1,
52962306a36Sopenharmony_ci			AR5K_DESC_TX_STATUS1_FINAL_TS_IX_5212);
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	/* TX error */
53262306a36Sopenharmony_ci	if (!(txstat0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK)) {
53362306a36Sopenharmony_ci		if (txstat0 & AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES)
53462306a36Sopenharmony_ci			ts->ts_status |= AR5K_TXERR_XRETRY;
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci		if (txstat0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN)
53762306a36Sopenharmony_ci			ts->ts_status |= AR5K_TXERR_FIFO;
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci		if (txstat0 & AR5K_DESC_TX_STATUS0_FILTERED)
54062306a36Sopenharmony_ci			ts->ts_status |= AR5K_TXERR_FILT;
54162306a36Sopenharmony_ci	}
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	return 0;
54462306a36Sopenharmony_ci}
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci/****************\
54862306a36Sopenharmony_ci* RX Descriptors *
54962306a36Sopenharmony_ci\****************/
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci/**
55262306a36Sopenharmony_ci * ath5k_hw_setup_rx_desc() - Initialize an rx control descriptor
55362306a36Sopenharmony_ci * @ah: The &struct ath5k_hw
55462306a36Sopenharmony_ci * @desc: The &struct ath5k_desc
55562306a36Sopenharmony_ci * @size: RX buffer length in bytes
55662306a36Sopenharmony_ci * @flags: One of AR5K_RXDESC_* flags
55762306a36Sopenharmony_ci */
55862306a36Sopenharmony_ciint
55962306a36Sopenharmony_ciath5k_hw_setup_rx_desc(struct ath5k_hw *ah,
56062306a36Sopenharmony_ci			struct ath5k_desc *desc,
56162306a36Sopenharmony_ci			u32 size, unsigned int flags)
56262306a36Sopenharmony_ci{
56362306a36Sopenharmony_ci	struct ath5k_hw_rx_ctl *rx_ctl;
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	rx_ctl = &desc->ud.ds_rx.rx_ctl;
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	/*
56862306a36Sopenharmony_ci	 * Clear the descriptor
56962306a36Sopenharmony_ci	 * If we don't clean the status descriptor,
57062306a36Sopenharmony_ci	 * while scanning we get too many results,
57162306a36Sopenharmony_ci	 * most of them virtual, after some secs
57262306a36Sopenharmony_ci	 * of scanning system hangs. M.F.
57362306a36Sopenharmony_ci	*/
57462306a36Sopenharmony_ci	memset(&desc->ud.ds_rx, 0, sizeof(struct ath5k_hw_all_rx_desc));
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	if (unlikely(size & ~AR5K_DESC_RX_CTL1_BUF_LEN))
57762306a36Sopenharmony_ci		return -EINVAL;
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci	/* Setup descriptor */
58062306a36Sopenharmony_ci	rx_ctl->rx_control_1 = size & AR5K_DESC_RX_CTL1_BUF_LEN;
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	if (flags & AR5K_RXDESC_INTREQ)
58362306a36Sopenharmony_ci		rx_ctl->rx_control_1 |= AR5K_DESC_RX_CTL1_INTREQ;
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci	return 0;
58662306a36Sopenharmony_ci}
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci/**
58962306a36Sopenharmony_ci * ath5k_hw_proc_5210_rx_status() - Process the rx status descriptor on 5210/1
59062306a36Sopenharmony_ci * @ah: The &struct ath5k_hw
59162306a36Sopenharmony_ci * @desc: The &struct ath5k_desc
59262306a36Sopenharmony_ci * @rs: The &struct ath5k_rx_status
59362306a36Sopenharmony_ci *
59462306a36Sopenharmony_ci * Internal function used to process an RX status descriptor
59562306a36Sopenharmony_ci * on AR5210/5211 MAC.
59662306a36Sopenharmony_ci *
59762306a36Sopenharmony_ci * Returns 0 on success or -EINPROGRESS in case we haven't received the who;e
59862306a36Sopenharmony_ci * frame yet.
59962306a36Sopenharmony_ci */
60062306a36Sopenharmony_cistatic int
60162306a36Sopenharmony_ciath5k_hw_proc_5210_rx_status(struct ath5k_hw *ah,
60262306a36Sopenharmony_ci				struct ath5k_desc *desc,
60362306a36Sopenharmony_ci				struct ath5k_rx_status *rs)
60462306a36Sopenharmony_ci{
60562306a36Sopenharmony_ci	struct ath5k_hw_rx_status *rx_status;
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci	rx_status = &desc->ud.ds_rx.rx_stat;
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	/* No frame received / not ready */
61062306a36Sopenharmony_ci	if (unlikely(!(rx_status->rx_status_1 &
61162306a36Sopenharmony_ci			AR5K_5210_RX_DESC_STATUS1_DONE)))
61262306a36Sopenharmony_ci		return -EINPROGRESS;
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci	memset(rs, 0, sizeof(struct ath5k_rx_status));
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	/*
61762306a36Sopenharmony_ci	 * Frame receive status
61862306a36Sopenharmony_ci	 */
61962306a36Sopenharmony_ci	rs->rs_datalen = rx_status->rx_status_0 &
62062306a36Sopenharmony_ci		AR5K_5210_RX_DESC_STATUS0_DATA_LEN;
62162306a36Sopenharmony_ci	rs->rs_rssi = AR5K_REG_MS(rx_status->rx_status_0,
62262306a36Sopenharmony_ci		AR5K_5210_RX_DESC_STATUS0_RECEIVE_SIGNAL);
62362306a36Sopenharmony_ci	rs->rs_rate = AR5K_REG_MS(rx_status->rx_status_0,
62462306a36Sopenharmony_ci		AR5K_5210_RX_DESC_STATUS0_RECEIVE_RATE);
62562306a36Sopenharmony_ci	rs->rs_more = !!(rx_status->rx_status_0 &
62662306a36Sopenharmony_ci		AR5K_5210_RX_DESC_STATUS0_MORE);
62762306a36Sopenharmony_ci	/* TODO: this timestamp is 13 bit, later on we assume 15 bit!
62862306a36Sopenharmony_ci	 * also the HAL code for 5210 says the timestamp is bits [10..22] of the
62962306a36Sopenharmony_ci	 * TSF, and extends the timestamp here to 15 bit.
63062306a36Sopenharmony_ci	 * we need to check on 5210...
63162306a36Sopenharmony_ci	 */
63262306a36Sopenharmony_ci	rs->rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1,
63362306a36Sopenharmony_ci		AR5K_5210_RX_DESC_STATUS1_RECEIVE_TIMESTAMP);
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	if (ah->ah_version == AR5K_AR5211)
63662306a36Sopenharmony_ci		rs->rs_antenna = AR5K_REG_MS(rx_status->rx_status_0,
63762306a36Sopenharmony_ci				AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANT_5211);
63862306a36Sopenharmony_ci	else
63962306a36Sopenharmony_ci		rs->rs_antenna = (rx_status->rx_status_0 &
64062306a36Sopenharmony_ci				AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANT_5210)
64162306a36Sopenharmony_ci				? 2 : 1;
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	/*
64462306a36Sopenharmony_ci	 * Key table status
64562306a36Sopenharmony_ci	 */
64662306a36Sopenharmony_ci	if (rx_status->rx_status_1 & AR5K_5210_RX_DESC_STATUS1_KEY_INDEX_VALID)
64762306a36Sopenharmony_ci		rs->rs_keyix = AR5K_REG_MS(rx_status->rx_status_1,
64862306a36Sopenharmony_ci			AR5K_5210_RX_DESC_STATUS1_KEY_INDEX);
64962306a36Sopenharmony_ci	else
65062306a36Sopenharmony_ci		rs->rs_keyix = AR5K_RXKEYIX_INVALID;
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci	/*
65362306a36Sopenharmony_ci	 * Receive/descriptor errors
65462306a36Sopenharmony_ci	 */
65562306a36Sopenharmony_ci	if (!(rx_status->rx_status_1 &
65662306a36Sopenharmony_ci			AR5K_5210_RX_DESC_STATUS1_FRAME_RECEIVE_OK)) {
65762306a36Sopenharmony_ci		if (rx_status->rx_status_1 &
65862306a36Sopenharmony_ci				AR5K_5210_RX_DESC_STATUS1_CRC_ERROR)
65962306a36Sopenharmony_ci			rs->rs_status |= AR5K_RXERR_CRC;
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci		/* only on 5210 */
66262306a36Sopenharmony_ci		if ((ah->ah_version == AR5K_AR5210) &&
66362306a36Sopenharmony_ci		    (rx_status->rx_status_1 &
66462306a36Sopenharmony_ci				AR5K_5210_RX_DESC_STATUS1_FIFO_OVERRUN_5210))
66562306a36Sopenharmony_ci			rs->rs_status |= AR5K_RXERR_FIFO;
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci		if (rx_status->rx_status_1 &
66862306a36Sopenharmony_ci				AR5K_5210_RX_DESC_STATUS1_PHY_ERROR) {
66962306a36Sopenharmony_ci			rs->rs_status |= AR5K_RXERR_PHY;
67062306a36Sopenharmony_ci			rs->rs_phyerr = AR5K_REG_MS(rx_status->rx_status_1,
67162306a36Sopenharmony_ci				AR5K_5210_RX_DESC_STATUS1_PHY_ERROR);
67262306a36Sopenharmony_ci		}
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci		if (rx_status->rx_status_1 &
67562306a36Sopenharmony_ci				AR5K_5210_RX_DESC_STATUS1_DECRYPT_CRC_ERROR)
67662306a36Sopenharmony_ci			rs->rs_status |= AR5K_RXERR_DECRYPT;
67762306a36Sopenharmony_ci	}
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci	return 0;
68062306a36Sopenharmony_ci}
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci/**
68362306a36Sopenharmony_ci * ath5k_hw_proc_5212_rx_status() - Process the rx status descriptor on 5212
68462306a36Sopenharmony_ci * @ah: The &struct ath5k_hw
68562306a36Sopenharmony_ci * @desc: The &struct ath5k_desc
68662306a36Sopenharmony_ci * @rs: The &struct ath5k_rx_status
68762306a36Sopenharmony_ci *
68862306a36Sopenharmony_ci * Internal function used to process an RX status descriptor
68962306a36Sopenharmony_ci * on AR5212 and later MAC.
69062306a36Sopenharmony_ci *
69162306a36Sopenharmony_ci * Returns 0 on success or -EINPROGRESS in case we haven't received the who;e
69262306a36Sopenharmony_ci * frame yet.
69362306a36Sopenharmony_ci */
69462306a36Sopenharmony_cistatic int
69562306a36Sopenharmony_ciath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah,
69662306a36Sopenharmony_ci				struct ath5k_desc *desc,
69762306a36Sopenharmony_ci				struct ath5k_rx_status *rs)
69862306a36Sopenharmony_ci{
69962306a36Sopenharmony_ci	struct ath5k_hw_rx_status *rx_status;
70062306a36Sopenharmony_ci	u32 rxstat0, rxstat1;
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci	rx_status = &desc->ud.ds_rx.rx_stat;
70362306a36Sopenharmony_ci	rxstat1 = READ_ONCE(rx_status->rx_status_1);
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci	/* No frame received / not ready */
70662306a36Sopenharmony_ci	if (unlikely(!(rxstat1 & AR5K_5212_RX_DESC_STATUS1_DONE)))
70762306a36Sopenharmony_ci		return -EINPROGRESS;
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci	memset(rs, 0, sizeof(struct ath5k_rx_status));
71062306a36Sopenharmony_ci	rxstat0 = READ_ONCE(rx_status->rx_status_0);
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci	/*
71362306a36Sopenharmony_ci	 * Frame receive status
71462306a36Sopenharmony_ci	 */
71562306a36Sopenharmony_ci	rs->rs_datalen = rxstat0 & AR5K_5212_RX_DESC_STATUS0_DATA_LEN;
71662306a36Sopenharmony_ci	rs->rs_rssi = AR5K_REG_MS(rxstat0,
71762306a36Sopenharmony_ci		AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL);
71862306a36Sopenharmony_ci	rs->rs_rate = AR5K_REG_MS(rxstat0,
71962306a36Sopenharmony_ci		AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE);
72062306a36Sopenharmony_ci	rs->rs_antenna = AR5K_REG_MS(rxstat0,
72162306a36Sopenharmony_ci		AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA);
72262306a36Sopenharmony_ci	rs->rs_more = !!(rxstat0 & AR5K_5212_RX_DESC_STATUS0_MORE);
72362306a36Sopenharmony_ci	rs->rs_tstamp = AR5K_REG_MS(rxstat1,
72462306a36Sopenharmony_ci		AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP);
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci	/*
72762306a36Sopenharmony_ci	 * Key table status
72862306a36Sopenharmony_ci	 */
72962306a36Sopenharmony_ci	if (rxstat1 & AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_VALID)
73062306a36Sopenharmony_ci		rs->rs_keyix = AR5K_REG_MS(rxstat1,
73162306a36Sopenharmony_ci					   AR5K_5212_RX_DESC_STATUS1_KEY_INDEX);
73262306a36Sopenharmony_ci	else
73362306a36Sopenharmony_ci		rs->rs_keyix = AR5K_RXKEYIX_INVALID;
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci	/*
73662306a36Sopenharmony_ci	 * Receive/descriptor errors
73762306a36Sopenharmony_ci	 */
73862306a36Sopenharmony_ci	if (!(rxstat1 & AR5K_5212_RX_DESC_STATUS1_FRAME_RECEIVE_OK)) {
73962306a36Sopenharmony_ci		if (rxstat1 & AR5K_5212_RX_DESC_STATUS1_CRC_ERROR)
74062306a36Sopenharmony_ci			rs->rs_status |= AR5K_RXERR_CRC;
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci		if (rxstat1 & AR5K_5212_RX_DESC_STATUS1_PHY_ERROR) {
74362306a36Sopenharmony_ci			rs->rs_status |= AR5K_RXERR_PHY;
74462306a36Sopenharmony_ci			rs->rs_phyerr = AR5K_REG_MS(rxstat1,
74562306a36Sopenharmony_ci				AR5K_5212_RX_DESC_STATUS1_PHY_ERROR_CODE);
74662306a36Sopenharmony_ci			if (!ah->ah_capabilities.cap_has_phyerr_counters)
74762306a36Sopenharmony_ci				ath5k_ani_phy_error_report(ah, rs->rs_phyerr);
74862306a36Sopenharmony_ci		}
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci		if (rxstat1 & AR5K_5212_RX_DESC_STATUS1_DECRYPT_CRC_ERROR)
75162306a36Sopenharmony_ci			rs->rs_status |= AR5K_RXERR_DECRYPT;
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_ci		if (rxstat1 & AR5K_5212_RX_DESC_STATUS1_MIC_ERROR)
75462306a36Sopenharmony_ci			rs->rs_status |= AR5K_RXERR_MIC;
75562306a36Sopenharmony_ci	}
75662306a36Sopenharmony_ci	return 0;
75762306a36Sopenharmony_ci}
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ci/********\
76162306a36Sopenharmony_ci* Attach *
76262306a36Sopenharmony_ci\********/
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_ci/**
76562306a36Sopenharmony_ci * ath5k_hw_init_desc_functions() - Init function pointers inside ah
76662306a36Sopenharmony_ci * @ah: The &struct ath5k_hw
76762306a36Sopenharmony_ci *
76862306a36Sopenharmony_ci * Maps the internal descriptor functions to the function pointers on ah, used
76962306a36Sopenharmony_ci * from above. This is used as an abstraction layer to handle the various chips
77062306a36Sopenharmony_ci * the same way.
77162306a36Sopenharmony_ci */
77262306a36Sopenharmony_ciint
77362306a36Sopenharmony_ciath5k_hw_init_desc_functions(struct ath5k_hw *ah)
77462306a36Sopenharmony_ci{
77562306a36Sopenharmony_ci	if (ah->ah_version == AR5K_AR5212) {
77662306a36Sopenharmony_ci		ah->ah_setup_tx_desc = ath5k_hw_setup_4word_tx_desc;
77762306a36Sopenharmony_ci		ah->ah_proc_tx_desc = ath5k_hw_proc_4word_tx_status;
77862306a36Sopenharmony_ci		ah->ah_proc_rx_desc = ath5k_hw_proc_5212_rx_status;
77962306a36Sopenharmony_ci	} else if (ah->ah_version <= AR5K_AR5211) {
78062306a36Sopenharmony_ci		ah->ah_setup_tx_desc = ath5k_hw_setup_2word_tx_desc;
78162306a36Sopenharmony_ci		ah->ah_proc_tx_desc = ath5k_hw_proc_2word_tx_status;
78262306a36Sopenharmony_ci		ah->ah_proc_rx_desc = ath5k_hw_proc_5210_rx_status;
78362306a36Sopenharmony_ci	} else
78462306a36Sopenharmony_ci		return -ENOTSUPP;
78562306a36Sopenharmony_ci	return 0;
78662306a36Sopenharmony_ci}
787