xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/ath/ath5k/desc.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
3*4882a593Smuzhiyun  * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
4*4882a593Smuzhiyun  * Copyright (c) 2007-2008 Pavel Roskin <proski@gnu.org>
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * Permission to use, copy, modify, and distribute this software for any
7*4882a593Smuzhiyun  * purpose with or without fee is hereby granted, provided that the above
8*4882a593Smuzhiyun  * copyright notice and this permission notice appear in all copies.
9*4882a593Smuzhiyun  *
10*4882a593Smuzhiyun  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11*4882a593Smuzhiyun  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12*4882a593Smuzhiyun  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13*4882a593Smuzhiyun  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14*4882a593Smuzhiyun  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15*4882a593Smuzhiyun  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16*4882a593Smuzhiyun  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*4882a593Smuzhiyun  *
18*4882a593Smuzhiyun  */
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun /******************************\
21*4882a593Smuzhiyun  Hardware Descriptor Functions
22*4882a593Smuzhiyun \******************************/
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun #include "ath5k.h"
27*4882a593Smuzhiyun #include "reg.h"
28*4882a593Smuzhiyun #include "debug.h"
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun /**
32*4882a593Smuzhiyun  * DOC: Hardware descriptor functions
33*4882a593Smuzhiyun  *
34*4882a593Smuzhiyun  * Here we handle the processing of the low-level hw descriptors
35*4882a593Smuzhiyun  * that hw reads and writes via DMA for each TX and RX attempt (that means
36*4882a593Smuzhiyun  * we can also have descriptors for failed TX/RX tries). We have two kind of
37*4882a593Smuzhiyun  * descriptors for RX and TX, control descriptors tell the hw how to send or
38*4882a593Smuzhiyun  * receive a packet where to read/write it from/to etc and status descriptors
39*4882a593Smuzhiyun  * that contain information about how the packet was sent or received (errors
40*4882a593Smuzhiyun  * included).
41*4882a593Smuzhiyun  *
42*4882a593Smuzhiyun  * Descriptor format is not exactly the same for each MAC chip version so we
43*4882a593Smuzhiyun  * have function pointers on &struct ath5k_hw we initialize at runtime based on
44*4882a593Smuzhiyun  * the chip used.
45*4882a593Smuzhiyun  */
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun /************************\
49*4882a593Smuzhiyun * TX Control descriptors *
50*4882a593Smuzhiyun \************************/
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun /**
53*4882a593Smuzhiyun  * ath5k_hw_setup_2word_tx_desc() - Initialize a 2-word tx control descriptor
54*4882a593Smuzhiyun  * @ah: The &struct ath5k_hw
55*4882a593Smuzhiyun  * @desc: The &struct ath5k_desc
56*4882a593Smuzhiyun  * @pkt_len: Frame length in bytes
57*4882a593Smuzhiyun  * @hdr_len: Header length in bytes (only used on AR5210)
58*4882a593Smuzhiyun  * @padsize: Any padding we've added to the frame length
59*4882a593Smuzhiyun  * @type: One of enum ath5k_pkt_type
60*4882a593Smuzhiyun  * @tx_power: Tx power in 0.5dB steps
61*4882a593Smuzhiyun  * @tx_rate0: HW idx for transmission rate
62*4882a593Smuzhiyun  * @tx_tries0: Max number of retransmissions
63*4882a593Smuzhiyun  * @key_index: Index on key table to use for encryption
64*4882a593Smuzhiyun  * @antenna_mode: Which antenna to use (0 for auto)
65*4882a593Smuzhiyun  * @flags: One of AR5K_TXDESC_* flags (desc.h)
66*4882a593Smuzhiyun  * @rtscts_rate: HW idx for RTS/CTS transmission rate
67*4882a593Smuzhiyun  * @rtscts_duration: What to put on duration field on the header of RTS/CTS
68*4882a593Smuzhiyun  *
69*4882a593Smuzhiyun  * Internal function to initialize a 2-Word TX control descriptor
70*4882a593Smuzhiyun  * found on AR5210 and AR5211 MACs chips.
71*4882a593Smuzhiyun  *
72*4882a593Smuzhiyun  * Returns 0 on success or -EINVAL on false input
73*4882a593Smuzhiyun  */
74*4882a593Smuzhiyun static int
ath5k_hw_setup_2word_tx_desc(struct ath5k_hw * ah,struct ath5k_desc * desc,unsigned int pkt_len,unsigned int hdr_len,int padsize,enum ath5k_pkt_type type,unsigned int tx_power,unsigned int tx_rate0,unsigned int tx_tries0,unsigned int key_index,unsigned int antenna_mode,unsigned int flags,unsigned int rtscts_rate,unsigned int rtscts_duration)75*4882a593Smuzhiyun ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah,
76*4882a593Smuzhiyun 			struct ath5k_desc *desc,
77*4882a593Smuzhiyun 			unsigned int pkt_len, unsigned int hdr_len,
78*4882a593Smuzhiyun 			int padsize,
79*4882a593Smuzhiyun 			enum ath5k_pkt_type type,
80*4882a593Smuzhiyun 			unsigned int tx_power,
81*4882a593Smuzhiyun 			unsigned int tx_rate0, unsigned int tx_tries0,
82*4882a593Smuzhiyun 			unsigned int key_index,
83*4882a593Smuzhiyun 			unsigned int antenna_mode,
84*4882a593Smuzhiyun 			unsigned int flags,
85*4882a593Smuzhiyun 			unsigned int rtscts_rate, unsigned int rtscts_duration)
86*4882a593Smuzhiyun {
87*4882a593Smuzhiyun 	u32 frame_type;
88*4882a593Smuzhiyun 	struct ath5k_hw_2w_tx_ctl *tx_ctl;
89*4882a593Smuzhiyun 	unsigned int frame_len;
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun 	tx_ctl = &desc->ud.ds_tx5210.tx_ctl;
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun 	/*
94*4882a593Smuzhiyun 	 * Validate input
95*4882a593Smuzhiyun 	 * - Zero retries don't make sense.
96*4882a593Smuzhiyun 	 * - A zero rate will put the HW into a mode where it continuously sends
97*4882a593Smuzhiyun 	 *   noise on the channel, so it is important to avoid this.
98*4882a593Smuzhiyun 	 */
99*4882a593Smuzhiyun 	if (unlikely(tx_tries0 == 0)) {
100*4882a593Smuzhiyun 		ATH5K_ERR(ah, "zero retries\n");
101*4882a593Smuzhiyun 		WARN_ON(1);
102*4882a593Smuzhiyun 		return -EINVAL;
103*4882a593Smuzhiyun 	}
104*4882a593Smuzhiyun 	if (unlikely(tx_rate0 == 0)) {
105*4882a593Smuzhiyun 		ATH5K_ERR(ah, "zero rate\n");
106*4882a593Smuzhiyun 		WARN_ON(1);
107*4882a593Smuzhiyun 		return -EINVAL;
108*4882a593Smuzhiyun 	}
109*4882a593Smuzhiyun 
110*4882a593Smuzhiyun 	/* Clear descriptor */
111*4882a593Smuzhiyun 	memset(&desc->ud.ds_tx5210, 0, sizeof(struct ath5k_hw_5210_tx_desc));
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun 	/* Setup control descriptor */
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun 	/* Verify and set frame length */
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun 	/* remove padding we might have added before */
118*4882a593Smuzhiyun 	frame_len = pkt_len - padsize + FCS_LEN;
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun 	if (frame_len & ~AR5K_2W_TX_DESC_CTL0_FRAME_LEN)
121*4882a593Smuzhiyun 		return -EINVAL;
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun 	tx_ctl->tx_control_0 = frame_len & AR5K_2W_TX_DESC_CTL0_FRAME_LEN;
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun 	/* Verify and set buffer length */
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun 	/* NB: beacon's BufLen must be a multiple of 4 bytes */
128*4882a593Smuzhiyun 	if (type == AR5K_PKT_TYPE_BEACON)
129*4882a593Smuzhiyun 		pkt_len = roundup(pkt_len, 4);
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun 	if (pkt_len & ~AR5K_2W_TX_DESC_CTL1_BUF_LEN)
132*4882a593Smuzhiyun 		return -EINVAL;
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun 	tx_ctl->tx_control_1 = pkt_len & AR5K_2W_TX_DESC_CTL1_BUF_LEN;
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun 	/*
137*4882a593Smuzhiyun 	 * Verify and set header length (only 5210)
138*4882a593Smuzhiyun 	 */
139*4882a593Smuzhiyun 	if (ah->ah_version == AR5K_AR5210) {
140*4882a593Smuzhiyun 		if (hdr_len & ~AR5K_2W_TX_DESC_CTL0_HEADER_LEN_5210)
141*4882a593Smuzhiyun 			return -EINVAL;
142*4882a593Smuzhiyun 		tx_ctl->tx_control_0 |=
143*4882a593Smuzhiyun 			AR5K_REG_SM(hdr_len, AR5K_2W_TX_DESC_CTL0_HEADER_LEN_5210);
144*4882a593Smuzhiyun 	}
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun 	/*Differences between 5210-5211*/
147*4882a593Smuzhiyun 	if (ah->ah_version == AR5K_AR5210) {
148*4882a593Smuzhiyun 		switch (type) {
149*4882a593Smuzhiyun 		case AR5K_PKT_TYPE_BEACON:
150*4882a593Smuzhiyun 		case AR5K_PKT_TYPE_PROBE_RESP:
151*4882a593Smuzhiyun 			frame_type = AR5K_AR5210_TX_DESC_FRAME_TYPE_NO_DELAY;
152*4882a593Smuzhiyun 			break;
153*4882a593Smuzhiyun 		case AR5K_PKT_TYPE_PIFS:
154*4882a593Smuzhiyun 			frame_type = AR5K_AR5210_TX_DESC_FRAME_TYPE_PIFS;
155*4882a593Smuzhiyun 			break;
156*4882a593Smuzhiyun 		default:
157*4882a593Smuzhiyun 			frame_type = type;
158*4882a593Smuzhiyun 			break;
159*4882a593Smuzhiyun 		}
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun 		tx_ctl->tx_control_0 |=
162*4882a593Smuzhiyun 		AR5K_REG_SM(frame_type, AR5K_2W_TX_DESC_CTL0_FRAME_TYPE_5210) |
163*4882a593Smuzhiyun 		AR5K_REG_SM(tx_rate0, AR5K_2W_TX_DESC_CTL0_XMIT_RATE);
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun 	} else {
166*4882a593Smuzhiyun 		tx_ctl->tx_control_0 |=
167*4882a593Smuzhiyun 			AR5K_REG_SM(tx_rate0, AR5K_2W_TX_DESC_CTL0_XMIT_RATE) |
168*4882a593Smuzhiyun 			AR5K_REG_SM(antenna_mode,
169*4882a593Smuzhiyun 				AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT);
170*4882a593Smuzhiyun 		tx_ctl->tx_control_1 |=
171*4882a593Smuzhiyun 			AR5K_REG_SM(type, AR5K_2W_TX_DESC_CTL1_FRAME_TYPE_5211);
172*4882a593Smuzhiyun 	}
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun #define _TX_FLAGS(_c, _flag)					\
175*4882a593Smuzhiyun 	if (flags & AR5K_TXDESC_##_flag) {			\
176*4882a593Smuzhiyun 		tx_ctl->tx_control_##_c |=			\
177*4882a593Smuzhiyun 			AR5K_2W_TX_DESC_CTL##_c##_##_flag;	\
178*4882a593Smuzhiyun 	}
179*4882a593Smuzhiyun #define _TX_FLAGS_5211(_c, _flag)					\
180*4882a593Smuzhiyun 	if (flags & AR5K_TXDESC_##_flag) {				\
181*4882a593Smuzhiyun 		tx_ctl->tx_control_##_c |=				\
182*4882a593Smuzhiyun 			AR5K_2W_TX_DESC_CTL##_c##_##_flag##_5211;	\
183*4882a593Smuzhiyun 	}
184*4882a593Smuzhiyun 	_TX_FLAGS(0, CLRDMASK);
185*4882a593Smuzhiyun 	_TX_FLAGS(0, INTREQ);
186*4882a593Smuzhiyun 	_TX_FLAGS(0, RTSENA);
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun 	if (ah->ah_version == AR5K_AR5211) {
189*4882a593Smuzhiyun 		_TX_FLAGS_5211(0, VEOL);
190*4882a593Smuzhiyun 		_TX_FLAGS_5211(1, NOACK);
191*4882a593Smuzhiyun 	}
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun #undef _TX_FLAGS
194*4882a593Smuzhiyun #undef _TX_FLAGS_5211
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun 	/*
197*4882a593Smuzhiyun 	 * WEP crap
198*4882a593Smuzhiyun 	 */
199*4882a593Smuzhiyun 	if (key_index != AR5K_TXKEYIX_INVALID) {
200*4882a593Smuzhiyun 		tx_ctl->tx_control_0 |=
201*4882a593Smuzhiyun 			AR5K_2W_TX_DESC_CTL0_ENCRYPT_KEY_VALID;
202*4882a593Smuzhiyun 		tx_ctl->tx_control_1 |=
203*4882a593Smuzhiyun 			AR5K_REG_SM(key_index,
204*4882a593Smuzhiyun 			AR5K_2W_TX_DESC_CTL1_ENC_KEY_IDX);
205*4882a593Smuzhiyun 	}
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun 	/*
208*4882a593Smuzhiyun 	 * RTS/CTS Duration [5210 ?]
209*4882a593Smuzhiyun 	 */
210*4882a593Smuzhiyun 	if ((ah->ah_version == AR5K_AR5210) &&
211*4882a593Smuzhiyun 			(flags & (AR5K_TXDESC_RTSENA | AR5K_TXDESC_CTSENA)))
212*4882a593Smuzhiyun 		tx_ctl->tx_control_1 |= rtscts_duration &
213*4882a593Smuzhiyun 				AR5K_2W_TX_DESC_CTL1_RTS_DURATION_5210;
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun 	return 0;
216*4882a593Smuzhiyun }
217*4882a593Smuzhiyun 
218*4882a593Smuzhiyun /**
219*4882a593Smuzhiyun  * ath5k_hw_setup_4word_tx_desc() - Initialize a 4-word tx control descriptor
220*4882a593Smuzhiyun  * @ah: The &struct ath5k_hw
221*4882a593Smuzhiyun  * @desc: The &struct ath5k_desc
222*4882a593Smuzhiyun  * @pkt_len: Frame length in bytes
223*4882a593Smuzhiyun  * @hdr_len: Header length in bytes (only used on AR5210)
224*4882a593Smuzhiyun  * @padsize: Any padding we've added to the frame length
225*4882a593Smuzhiyun  * @type: One of enum ath5k_pkt_type
226*4882a593Smuzhiyun  * @tx_power: Tx power in 0.5dB steps
227*4882a593Smuzhiyun  * @tx_rate0: HW idx for transmission rate
228*4882a593Smuzhiyun  * @tx_tries0: Max number of retransmissions
229*4882a593Smuzhiyun  * @key_index: Index on key table to use for encryption
230*4882a593Smuzhiyun  * @antenna_mode: Which antenna to use (0 for auto)
231*4882a593Smuzhiyun  * @flags: One of AR5K_TXDESC_* flags (desc.h)
232*4882a593Smuzhiyun  * @rtscts_rate: HW idx for RTS/CTS transmission rate
233*4882a593Smuzhiyun  * @rtscts_duration: What to put on duration field on the header of RTS/CTS
234*4882a593Smuzhiyun  *
235*4882a593Smuzhiyun  * Internal function to initialize a 4-Word TX control descriptor
236*4882a593Smuzhiyun  * found on AR5212 and later MACs chips.
237*4882a593Smuzhiyun  *
238*4882a593Smuzhiyun  * Returns 0 on success or -EINVAL on false input
239*4882a593Smuzhiyun  */
240*4882a593Smuzhiyun static int
ath5k_hw_setup_4word_tx_desc(struct ath5k_hw * ah,struct ath5k_desc * desc,unsigned int pkt_len,unsigned int hdr_len,int padsize,enum ath5k_pkt_type type,unsigned int tx_power,unsigned int tx_rate0,unsigned int tx_tries0,unsigned int key_index,unsigned int antenna_mode,unsigned int flags,unsigned int rtscts_rate,unsigned int rtscts_duration)241*4882a593Smuzhiyun ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah,
242*4882a593Smuzhiyun 			struct ath5k_desc *desc,
243*4882a593Smuzhiyun 			unsigned int pkt_len, unsigned int hdr_len,
244*4882a593Smuzhiyun 			int padsize,
245*4882a593Smuzhiyun 			enum ath5k_pkt_type type,
246*4882a593Smuzhiyun 			unsigned int tx_power,
247*4882a593Smuzhiyun 			unsigned int tx_rate0, unsigned int tx_tries0,
248*4882a593Smuzhiyun 			unsigned int key_index,
249*4882a593Smuzhiyun 			unsigned int antenna_mode,
250*4882a593Smuzhiyun 			unsigned int flags,
251*4882a593Smuzhiyun 			unsigned int rtscts_rate, unsigned int rtscts_duration)
252*4882a593Smuzhiyun {
253*4882a593Smuzhiyun 	struct ath5k_hw_4w_tx_ctl *tx_ctl;
254*4882a593Smuzhiyun 	unsigned int frame_len;
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun 	/*
257*4882a593Smuzhiyun 	 * Use local variables for these to reduce load/store access on
258*4882a593Smuzhiyun 	 * uncached memory
259*4882a593Smuzhiyun 	 */
260*4882a593Smuzhiyun 	u32 txctl0 = 0, txctl1 = 0, txctl2 = 0, txctl3 = 0;
261*4882a593Smuzhiyun 
262*4882a593Smuzhiyun 	tx_ctl = &desc->ud.ds_tx5212.tx_ctl;
263*4882a593Smuzhiyun 
264*4882a593Smuzhiyun 	/*
265*4882a593Smuzhiyun 	 * Validate input
266*4882a593Smuzhiyun 	 * - Zero retries don't make sense.
267*4882a593Smuzhiyun 	 * - A zero rate will put the HW into a mode where it continuously sends
268*4882a593Smuzhiyun 	 *   noise on the channel, so it is important to avoid this.
269*4882a593Smuzhiyun 	 */
270*4882a593Smuzhiyun 	if (unlikely(tx_tries0 == 0)) {
271*4882a593Smuzhiyun 		ATH5K_ERR(ah, "zero retries\n");
272*4882a593Smuzhiyun 		WARN_ON(1);
273*4882a593Smuzhiyun 		return -EINVAL;
274*4882a593Smuzhiyun 	}
275*4882a593Smuzhiyun 	if (unlikely(tx_rate0 == 0)) {
276*4882a593Smuzhiyun 		ATH5K_ERR(ah, "zero rate\n");
277*4882a593Smuzhiyun 		WARN_ON(1);
278*4882a593Smuzhiyun 		return -EINVAL;
279*4882a593Smuzhiyun 	}
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun 	tx_power += ah->ah_txpower.txp_offset;
282*4882a593Smuzhiyun 	if (tx_power > AR5K_TUNE_MAX_TXPOWER)
283*4882a593Smuzhiyun 		tx_power = AR5K_TUNE_MAX_TXPOWER;
284*4882a593Smuzhiyun 
285*4882a593Smuzhiyun 	/* Clear descriptor status area */
286*4882a593Smuzhiyun 	memset(&desc->ud.ds_tx5212.tx_stat, 0,
287*4882a593Smuzhiyun 	       sizeof(desc->ud.ds_tx5212.tx_stat));
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun 	/* Setup control descriptor */
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun 	/* Verify and set frame length */
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun 	/* remove padding we might have added before */
294*4882a593Smuzhiyun 	frame_len = pkt_len - padsize + FCS_LEN;
295*4882a593Smuzhiyun 
296*4882a593Smuzhiyun 	if (frame_len & ~AR5K_4W_TX_DESC_CTL0_FRAME_LEN)
297*4882a593Smuzhiyun 		return -EINVAL;
298*4882a593Smuzhiyun 
299*4882a593Smuzhiyun 	txctl0 = frame_len & AR5K_4W_TX_DESC_CTL0_FRAME_LEN;
300*4882a593Smuzhiyun 
301*4882a593Smuzhiyun 	/* Verify and set buffer length */
302*4882a593Smuzhiyun 
303*4882a593Smuzhiyun 	/* NB: beacon's BufLen must be a multiple of 4 bytes */
304*4882a593Smuzhiyun 	if (type == AR5K_PKT_TYPE_BEACON)
305*4882a593Smuzhiyun 		pkt_len = roundup(pkt_len, 4);
306*4882a593Smuzhiyun 
307*4882a593Smuzhiyun 	if (pkt_len & ~AR5K_4W_TX_DESC_CTL1_BUF_LEN)
308*4882a593Smuzhiyun 		return -EINVAL;
309*4882a593Smuzhiyun 
310*4882a593Smuzhiyun 	txctl1 = pkt_len & AR5K_4W_TX_DESC_CTL1_BUF_LEN;
311*4882a593Smuzhiyun 
312*4882a593Smuzhiyun 	txctl0 |= AR5K_REG_SM(tx_power, AR5K_4W_TX_DESC_CTL0_XMIT_POWER) |
313*4882a593Smuzhiyun 		  AR5K_REG_SM(antenna_mode, AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT);
314*4882a593Smuzhiyun 	txctl1 |= AR5K_REG_SM(type, AR5K_4W_TX_DESC_CTL1_FRAME_TYPE);
315*4882a593Smuzhiyun 	txctl2 = AR5K_REG_SM(tx_tries0, AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0);
316*4882a593Smuzhiyun 	txctl3 = tx_rate0 & AR5K_4W_TX_DESC_CTL3_XMIT_RATE0;
317*4882a593Smuzhiyun 
318*4882a593Smuzhiyun #define _TX_FLAGS(_c, _flag)					\
319*4882a593Smuzhiyun 	if (flags & AR5K_TXDESC_##_flag) {			\
320*4882a593Smuzhiyun 		txctl##_c |= AR5K_4W_TX_DESC_CTL##_c##_##_flag;	\
321*4882a593Smuzhiyun 	}
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun 	_TX_FLAGS(0, CLRDMASK);
324*4882a593Smuzhiyun 	_TX_FLAGS(0, VEOL);
325*4882a593Smuzhiyun 	_TX_FLAGS(0, INTREQ);
326*4882a593Smuzhiyun 	_TX_FLAGS(0, RTSENA);
327*4882a593Smuzhiyun 	_TX_FLAGS(0, CTSENA);
328*4882a593Smuzhiyun 	_TX_FLAGS(1, NOACK);
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun #undef _TX_FLAGS
331*4882a593Smuzhiyun 
332*4882a593Smuzhiyun 	/*
333*4882a593Smuzhiyun 	 * WEP crap
334*4882a593Smuzhiyun 	 */
335*4882a593Smuzhiyun 	if (key_index != AR5K_TXKEYIX_INVALID) {
336*4882a593Smuzhiyun 		txctl0 |= AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID;
337*4882a593Smuzhiyun 		txctl1 |= AR5K_REG_SM(key_index,
338*4882a593Smuzhiyun 				AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_IDX);
339*4882a593Smuzhiyun 	}
340*4882a593Smuzhiyun 
341*4882a593Smuzhiyun 	/*
342*4882a593Smuzhiyun 	 * RTS/CTS
343*4882a593Smuzhiyun 	 */
344*4882a593Smuzhiyun 	if (flags & (AR5K_TXDESC_RTSENA | AR5K_TXDESC_CTSENA)) {
345*4882a593Smuzhiyun 		if ((flags & AR5K_TXDESC_RTSENA) &&
346*4882a593Smuzhiyun 				(flags & AR5K_TXDESC_CTSENA))
347*4882a593Smuzhiyun 			return -EINVAL;
348*4882a593Smuzhiyun 		txctl2 |= rtscts_duration & AR5K_4W_TX_DESC_CTL2_RTS_DURATION;
349*4882a593Smuzhiyun 		txctl3 |= AR5K_REG_SM(rtscts_rate,
350*4882a593Smuzhiyun 				AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE);
351*4882a593Smuzhiyun 	}
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun 	tx_ctl->tx_control_0 = txctl0;
354*4882a593Smuzhiyun 	tx_ctl->tx_control_1 = txctl1;
355*4882a593Smuzhiyun 	tx_ctl->tx_control_2 = txctl2;
356*4882a593Smuzhiyun 	tx_ctl->tx_control_3 = txctl3;
357*4882a593Smuzhiyun 
358*4882a593Smuzhiyun 	return 0;
359*4882a593Smuzhiyun }
360*4882a593Smuzhiyun 
361*4882a593Smuzhiyun /**
362*4882a593Smuzhiyun  * ath5k_hw_setup_mrr_tx_desc() - Initialize an MRR tx control descriptor
363*4882a593Smuzhiyun  * @ah: The &struct ath5k_hw
364*4882a593Smuzhiyun  * @desc: The &struct ath5k_desc
365*4882a593Smuzhiyun  * @tx_rate1: HW idx for rate used on transmission series 1
366*4882a593Smuzhiyun  * @tx_tries1: Max number of retransmissions for transmission series 1
367*4882a593Smuzhiyun  * @tx_rate2: HW idx for rate used on transmission series 2
368*4882a593Smuzhiyun  * @tx_tries2: Max number of retransmissions for transmission series 2
369*4882a593Smuzhiyun  * @tx_rate3: HW idx for rate used on transmission series 3
370*4882a593Smuzhiyun  * @tx_tries3: Max number of retransmissions for transmission series 3
371*4882a593Smuzhiyun  *
372*4882a593Smuzhiyun  * Multi rate retry (MRR) tx control descriptors are available only on AR5212
373*4882a593Smuzhiyun  * MACs, they are part of the normal 4-word tx control descriptor (see above)
374*4882a593Smuzhiyun  * but we handle them through a separate function for better abstraction.
375*4882a593Smuzhiyun  *
376*4882a593Smuzhiyun  * Returns 0 on success or -EINVAL on invalid input
377*4882a593Smuzhiyun  */
378*4882a593Smuzhiyun int
ath5k_hw_setup_mrr_tx_desc(struct ath5k_hw * ah,struct ath5k_desc * desc,u_int tx_rate1,u_int tx_tries1,u_int tx_rate2,u_int tx_tries2,u_int tx_rate3,u_int tx_tries3)379*4882a593Smuzhiyun ath5k_hw_setup_mrr_tx_desc(struct ath5k_hw *ah,
380*4882a593Smuzhiyun 			struct ath5k_desc *desc,
381*4882a593Smuzhiyun 			u_int tx_rate1, u_int tx_tries1,
382*4882a593Smuzhiyun 			u_int tx_rate2, u_int tx_tries2,
383*4882a593Smuzhiyun 			u_int tx_rate3, u_int tx_tries3)
384*4882a593Smuzhiyun {
385*4882a593Smuzhiyun 	struct ath5k_hw_4w_tx_ctl *tx_ctl;
386*4882a593Smuzhiyun 
387*4882a593Smuzhiyun 	/* no mrr support for cards older than 5212 */
388*4882a593Smuzhiyun 	if (ah->ah_version < AR5K_AR5212)
389*4882a593Smuzhiyun 		return 0;
390*4882a593Smuzhiyun 
391*4882a593Smuzhiyun 	/*
392*4882a593Smuzhiyun 	 * Rates can be 0 as long as the retry count is 0 too.
393*4882a593Smuzhiyun 	 * A zero rate and nonzero retry count will put the HW into a mode where
394*4882a593Smuzhiyun 	 * it continuously sends noise on the channel, so it is important to
395*4882a593Smuzhiyun 	 * avoid this.
396*4882a593Smuzhiyun 	 */
397*4882a593Smuzhiyun 	if (unlikely((tx_rate1 == 0 && tx_tries1 != 0) ||
398*4882a593Smuzhiyun 		     (tx_rate2 == 0 && tx_tries2 != 0) ||
399*4882a593Smuzhiyun 		     (tx_rate3 == 0 && tx_tries3 != 0))) {
400*4882a593Smuzhiyun 		ATH5K_ERR(ah, "zero rate\n");
401*4882a593Smuzhiyun 		WARN_ON(1);
402*4882a593Smuzhiyun 		return -EINVAL;
403*4882a593Smuzhiyun 	}
404*4882a593Smuzhiyun 
405*4882a593Smuzhiyun 	if (ah->ah_version == AR5K_AR5212) {
406*4882a593Smuzhiyun 		tx_ctl = &desc->ud.ds_tx5212.tx_ctl;
407*4882a593Smuzhiyun 
408*4882a593Smuzhiyun #define _XTX_TRIES(_n)							\
409*4882a593Smuzhiyun 	if (tx_tries##_n) {						\
410*4882a593Smuzhiyun 		tx_ctl->tx_control_2 |=					\
411*4882a593Smuzhiyun 		    AR5K_REG_SM(tx_tries##_n,				\
412*4882a593Smuzhiyun 		    AR5K_4W_TX_DESC_CTL2_XMIT_TRIES##_n);		\
413*4882a593Smuzhiyun 		tx_ctl->tx_control_3 |=					\
414*4882a593Smuzhiyun 		    AR5K_REG_SM(tx_rate##_n,				\
415*4882a593Smuzhiyun 		    AR5K_4W_TX_DESC_CTL3_XMIT_RATE##_n);		\
416*4882a593Smuzhiyun 	}
417*4882a593Smuzhiyun 
418*4882a593Smuzhiyun 		_XTX_TRIES(1);
419*4882a593Smuzhiyun 		_XTX_TRIES(2);
420*4882a593Smuzhiyun 		_XTX_TRIES(3);
421*4882a593Smuzhiyun 
422*4882a593Smuzhiyun #undef _XTX_TRIES
423*4882a593Smuzhiyun 
424*4882a593Smuzhiyun 		return 1;
425*4882a593Smuzhiyun 	}
426*4882a593Smuzhiyun 
427*4882a593Smuzhiyun 	return 0;
428*4882a593Smuzhiyun }
429*4882a593Smuzhiyun 
430*4882a593Smuzhiyun 
431*4882a593Smuzhiyun /***********************\
432*4882a593Smuzhiyun * TX Status descriptors *
433*4882a593Smuzhiyun \***********************/
434*4882a593Smuzhiyun 
435*4882a593Smuzhiyun /**
436*4882a593Smuzhiyun  * ath5k_hw_proc_2word_tx_status() - Process a tx status descriptor on 5210/1
437*4882a593Smuzhiyun  * @ah: The &struct ath5k_hw
438*4882a593Smuzhiyun  * @desc: The &struct ath5k_desc
439*4882a593Smuzhiyun  * @ts: The &struct ath5k_tx_status
440*4882a593Smuzhiyun  */
441*4882a593Smuzhiyun static int
ath5k_hw_proc_2word_tx_status(struct ath5k_hw * ah,struct ath5k_desc * desc,struct ath5k_tx_status * ts)442*4882a593Smuzhiyun ath5k_hw_proc_2word_tx_status(struct ath5k_hw *ah,
443*4882a593Smuzhiyun 				struct ath5k_desc *desc,
444*4882a593Smuzhiyun 				struct ath5k_tx_status *ts)
445*4882a593Smuzhiyun {
446*4882a593Smuzhiyun 	struct ath5k_hw_tx_status *tx_status;
447*4882a593Smuzhiyun 
448*4882a593Smuzhiyun 	tx_status = &desc->ud.ds_tx5210.tx_stat;
449*4882a593Smuzhiyun 
450*4882a593Smuzhiyun 	/* No frame has been send or error */
451*4882a593Smuzhiyun 	if (unlikely((tx_status->tx_status_1 & AR5K_DESC_TX_STATUS1_DONE) == 0))
452*4882a593Smuzhiyun 		return -EINPROGRESS;
453*4882a593Smuzhiyun 
454*4882a593Smuzhiyun 	/*
455*4882a593Smuzhiyun 	 * Get descriptor status
456*4882a593Smuzhiyun 	 */
457*4882a593Smuzhiyun 	ts->ts_tstamp = AR5K_REG_MS(tx_status->tx_status_0,
458*4882a593Smuzhiyun 		AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP);
459*4882a593Smuzhiyun 	ts->ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0,
460*4882a593Smuzhiyun 		AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT);
461*4882a593Smuzhiyun 	ts->ts_final_retry = AR5K_REG_MS(tx_status->tx_status_0,
462*4882a593Smuzhiyun 		AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT);
463*4882a593Smuzhiyun 	/*TODO: ts->ts_virtcol + test*/
464*4882a593Smuzhiyun 	ts->ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1,
465*4882a593Smuzhiyun 		AR5K_DESC_TX_STATUS1_SEQ_NUM);
466*4882a593Smuzhiyun 	ts->ts_rssi = AR5K_REG_MS(tx_status->tx_status_1,
467*4882a593Smuzhiyun 		AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH);
468*4882a593Smuzhiyun 	ts->ts_antenna = 1;
469*4882a593Smuzhiyun 	ts->ts_status = 0;
470*4882a593Smuzhiyun 	ts->ts_final_idx = 0;
471*4882a593Smuzhiyun 
472*4882a593Smuzhiyun 	if (!(tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK)) {
473*4882a593Smuzhiyun 		if (tx_status->tx_status_0 &
474*4882a593Smuzhiyun 				AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES)
475*4882a593Smuzhiyun 			ts->ts_status |= AR5K_TXERR_XRETRY;
476*4882a593Smuzhiyun 
477*4882a593Smuzhiyun 		if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN)
478*4882a593Smuzhiyun 			ts->ts_status |= AR5K_TXERR_FIFO;
479*4882a593Smuzhiyun 
480*4882a593Smuzhiyun 		if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FILTERED)
481*4882a593Smuzhiyun 			ts->ts_status |= AR5K_TXERR_FILT;
482*4882a593Smuzhiyun 	}
483*4882a593Smuzhiyun 
484*4882a593Smuzhiyun 	return 0;
485*4882a593Smuzhiyun }
486*4882a593Smuzhiyun 
487*4882a593Smuzhiyun /**
488*4882a593Smuzhiyun  * ath5k_hw_proc_4word_tx_status() - Process a tx status descriptor on 5212
489*4882a593Smuzhiyun  * @ah: The &struct ath5k_hw
490*4882a593Smuzhiyun  * @desc: The &struct ath5k_desc
491*4882a593Smuzhiyun  * @ts: The &struct ath5k_tx_status
492*4882a593Smuzhiyun  */
493*4882a593Smuzhiyun static int
ath5k_hw_proc_4word_tx_status(struct ath5k_hw * ah,struct ath5k_desc * desc,struct ath5k_tx_status * ts)494*4882a593Smuzhiyun ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah,
495*4882a593Smuzhiyun 				struct ath5k_desc *desc,
496*4882a593Smuzhiyun 				struct ath5k_tx_status *ts)
497*4882a593Smuzhiyun {
498*4882a593Smuzhiyun 	struct ath5k_hw_tx_status *tx_status;
499*4882a593Smuzhiyun 	u32 txstat0, txstat1;
500*4882a593Smuzhiyun 
501*4882a593Smuzhiyun 	tx_status = &desc->ud.ds_tx5212.tx_stat;
502*4882a593Smuzhiyun 
503*4882a593Smuzhiyun 	txstat1 = READ_ONCE(tx_status->tx_status_1);
504*4882a593Smuzhiyun 
505*4882a593Smuzhiyun 	/* No frame has been send or error */
506*4882a593Smuzhiyun 	if (unlikely(!(txstat1 & AR5K_DESC_TX_STATUS1_DONE)))
507*4882a593Smuzhiyun 		return -EINPROGRESS;
508*4882a593Smuzhiyun 
509*4882a593Smuzhiyun 	txstat0 = READ_ONCE(tx_status->tx_status_0);
510*4882a593Smuzhiyun 
511*4882a593Smuzhiyun 	/*
512*4882a593Smuzhiyun 	 * Get descriptor status
513*4882a593Smuzhiyun 	 */
514*4882a593Smuzhiyun 	ts->ts_tstamp = AR5K_REG_MS(txstat0,
515*4882a593Smuzhiyun 		AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP);
516*4882a593Smuzhiyun 	ts->ts_shortretry = AR5K_REG_MS(txstat0,
517*4882a593Smuzhiyun 		AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT);
518*4882a593Smuzhiyun 	ts->ts_final_retry = AR5K_REG_MS(txstat0,
519*4882a593Smuzhiyun 		AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT);
520*4882a593Smuzhiyun 	ts->ts_seqnum = AR5K_REG_MS(txstat1,
521*4882a593Smuzhiyun 		AR5K_DESC_TX_STATUS1_SEQ_NUM);
522*4882a593Smuzhiyun 	ts->ts_rssi = AR5K_REG_MS(txstat1,
523*4882a593Smuzhiyun 		AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH);
524*4882a593Smuzhiyun 	ts->ts_antenna = (txstat1 &
525*4882a593Smuzhiyun 		AR5K_DESC_TX_STATUS1_XMIT_ANTENNA_5212) ? 2 : 1;
526*4882a593Smuzhiyun 	ts->ts_status = 0;
527*4882a593Smuzhiyun 
528*4882a593Smuzhiyun 	ts->ts_final_idx = AR5K_REG_MS(txstat1,
529*4882a593Smuzhiyun 			AR5K_DESC_TX_STATUS1_FINAL_TS_IX_5212);
530*4882a593Smuzhiyun 
531*4882a593Smuzhiyun 	/* TX error */
532*4882a593Smuzhiyun 	if (!(txstat0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK)) {
533*4882a593Smuzhiyun 		if (txstat0 & AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES)
534*4882a593Smuzhiyun 			ts->ts_status |= AR5K_TXERR_XRETRY;
535*4882a593Smuzhiyun 
536*4882a593Smuzhiyun 		if (txstat0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN)
537*4882a593Smuzhiyun 			ts->ts_status |= AR5K_TXERR_FIFO;
538*4882a593Smuzhiyun 
539*4882a593Smuzhiyun 		if (txstat0 & AR5K_DESC_TX_STATUS0_FILTERED)
540*4882a593Smuzhiyun 			ts->ts_status |= AR5K_TXERR_FILT;
541*4882a593Smuzhiyun 	}
542*4882a593Smuzhiyun 
543*4882a593Smuzhiyun 	return 0;
544*4882a593Smuzhiyun }
545*4882a593Smuzhiyun 
546*4882a593Smuzhiyun 
547*4882a593Smuzhiyun /****************\
548*4882a593Smuzhiyun * RX Descriptors *
549*4882a593Smuzhiyun \****************/
550*4882a593Smuzhiyun 
551*4882a593Smuzhiyun /**
552*4882a593Smuzhiyun  * ath5k_hw_setup_rx_desc() - Initialize an rx control descriptor
553*4882a593Smuzhiyun  * @ah: The &struct ath5k_hw
554*4882a593Smuzhiyun  * @desc: The &struct ath5k_desc
555*4882a593Smuzhiyun  * @size: RX buffer length in bytes
556*4882a593Smuzhiyun  * @flags: One of AR5K_RXDESC_* flags
557*4882a593Smuzhiyun  */
558*4882a593Smuzhiyun int
ath5k_hw_setup_rx_desc(struct ath5k_hw * ah,struct ath5k_desc * desc,u32 size,unsigned int flags)559*4882a593Smuzhiyun ath5k_hw_setup_rx_desc(struct ath5k_hw *ah,
560*4882a593Smuzhiyun 			struct ath5k_desc *desc,
561*4882a593Smuzhiyun 			u32 size, unsigned int flags)
562*4882a593Smuzhiyun {
563*4882a593Smuzhiyun 	struct ath5k_hw_rx_ctl *rx_ctl;
564*4882a593Smuzhiyun 
565*4882a593Smuzhiyun 	rx_ctl = &desc->ud.ds_rx.rx_ctl;
566*4882a593Smuzhiyun 
567*4882a593Smuzhiyun 	/*
568*4882a593Smuzhiyun 	 * Clear the descriptor
569*4882a593Smuzhiyun 	 * If we don't clean the status descriptor,
570*4882a593Smuzhiyun 	 * while scanning we get too many results,
571*4882a593Smuzhiyun 	 * most of them virtual, after some secs
572*4882a593Smuzhiyun 	 * of scanning system hangs. M.F.
573*4882a593Smuzhiyun 	*/
574*4882a593Smuzhiyun 	memset(&desc->ud.ds_rx, 0, sizeof(struct ath5k_hw_all_rx_desc));
575*4882a593Smuzhiyun 
576*4882a593Smuzhiyun 	if (unlikely(size & ~AR5K_DESC_RX_CTL1_BUF_LEN))
577*4882a593Smuzhiyun 		return -EINVAL;
578*4882a593Smuzhiyun 
579*4882a593Smuzhiyun 	/* Setup descriptor */
580*4882a593Smuzhiyun 	rx_ctl->rx_control_1 = size & AR5K_DESC_RX_CTL1_BUF_LEN;
581*4882a593Smuzhiyun 
582*4882a593Smuzhiyun 	if (flags & AR5K_RXDESC_INTREQ)
583*4882a593Smuzhiyun 		rx_ctl->rx_control_1 |= AR5K_DESC_RX_CTL1_INTREQ;
584*4882a593Smuzhiyun 
585*4882a593Smuzhiyun 	return 0;
586*4882a593Smuzhiyun }
587*4882a593Smuzhiyun 
588*4882a593Smuzhiyun /**
589*4882a593Smuzhiyun  * ath5k_hw_proc_5210_rx_status() - Process the rx status descriptor on 5210/1
590*4882a593Smuzhiyun  * @ah: The &struct ath5k_hw
591*4882a593Smuzhiyun  * @desc: The &struct ath5k_desc
592*4882a593Smuzhiyun  * @rs: The &struct ath5k_rx_status
593*4882a593Smuzhiyun  *
594*4882a593Smuzhiyun  * Internal function used to process an RX status descriptor
595*4882a593Smuzhiyun  * on AR5210/5211 MAC.
596*4882a593Smuzhiyun  *
597*4882a593Smuzhiyun  * Returns 0 on success or -EINPROGRESS in case we haven't received the who;e
598*4882a593Smuzhiyun  * frame yet.
599*4882a593Smuzhiyun  */
600*4882a593Smuzhiyun static int
ath5k_hw_proc_5210_rx_status(struct ath5k_hw * ah,struct ath5k_desc * desc,struct ath5k_rx_status * rs)601*4882a593Smuzhiyun ath5k_hw_proc_5210_rx_status(struct ath5k_hw *ah,
602*4882a593Smuzhiyun 				struct ath5k_desc *desc,
603*4882a593Smuzhiyun 				struct ath5k_rx_status *rs)
604*4882a593Smuzhiyun {
605*4882a593Smuzhiyun 	struct ath5k_hw_rx_status *rx_status;
606*4882a593Smuzhiyun 
607*4882a593Smuzhiyun 	rx_status = &desc->ud.ds_rx.rx_stat;
608*4882a593Smuzhiyun 
609*4882a593Smuzhiyun 	/* No frame received / not ready */
610*4882a593Smuzhiyun 	if (unlikely(!(rx_status->rx_status_1 &
611*4882a593Smuzhiyun 			AR5K_5210_RX_DESC_STATUS1_DONE)))
612*4882a593Smuzhiyun 		return -EINPROGRESS;
613*4882a593Smuzhiyun 
614*4882a593Smuzhiyun 	memset(rs, 0, sizeof(struct ath5k_rx_status));
615*4882a593Smuzhiyun 
616*4882a593Smuzhiyun 	/*
617*4882a593Smuzhiyun 	 * Frame receive status
618*4882a593Smuzhiyun 	 */
619*4882a593Smuzhiyun 	rs->rs_datalen = rx_status->rx_status_0 &
620*4882a593Smuzhiyun 		AR5K_5210_RX_DESC_STATUS0_DATA_LEN;
621*4882a593Smuzhiyun 	rs->rs_rssi = AR5K_REG_MS(rx_status->rx_status_0,
622*4882a593Smuzhiyun 		AR5K_5210_RX_DESC_STATUS0_RECEIVE_SIGNAL);
623*4882a593Smuzhiyun 	rs->rs_rate = AR5K_REG_MS(rx_status->rx_status_0,
624*4882a593Smuzhiyun 		AR5K_5210_RX_DESC_STATUS0_RECEIVE_RATE);
625*4882a593Smuzhiyun 	rs->rs_more = !!(rx_status->rx_status_0 &
626*4882a593Smuzhiyun 		AR5K_5210_RX_DESC_STATUS0_MORE);
627*4882a593Smuzhiyun 	/* TODO: this timestamp is 13 bit, later on we assume 15 bit!
628*4882a593Smuzhiyun 	 * also the HAL code for 5210 says the timestamp is bits [10..22] of the
629*4882a593Smuzhiyun 	 * TSF, and extends the timestamp here to 15 bit.
630*4882a593Smuzhiyun 	 * we need to check on 5210...
631*4882a593Smuzhiyun 	 */
632*4882a593Smuzhiyun 	rs->rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1,
633*4882a593Smuzhiyun 		AR5K_5210_RX_DESC_STATUS1_RECEIVE_TIMESTAMP);
634*4882a593Smuzhiyun 
635*4882a593Smuzhiyun 	if (ah->ah_version == AR5K_AR5211)
636*4882a593Smuzhiyun 		rs->rs_antenna = AR5K_REG_MS(rx_status->rx_status_0,
637*4882a593Smuzhiyun 				AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANT_5211);
638*4882a593Smuzhiyun 	else
639*4882a593Smuzhiyun 		rs->rs_antenna = (rx_status->rx_status_0 &
640*4882a593Smuzhiyun 				AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANT_5210)
641*4882a593Smuzhiyun 				? 2 : 1;
642*4882a593Smuzhiyun 
643*4882a593Smuzhiyun 	/*
644*4882a593Smuzhiyun 	 * Key table status
645*4882a593Smuzhiyun 	 */
646*4882a593Smuzhiyun 	if (rx_status->rx_status_1 & AR5K_5210_RX_DESC_STATUS1_KEY_INDEX_VALID)
647*4882a593Smuzhiyun 		rs->rs_keyix = AR5K_REG_MS(rx_status->rx_status_1,
648*4882a593Smuzhiyun 			AR5K_5210_RX_DESC_STATUS1_KEY_INDEX);
649*4882a593Smuzhiyun 	else
650*4882a593Smuzhiyun 		rs->rs_keyix = AR5K_RXKEYIX_INVALID;
651*4882a593Smuzhiyun 
652*4882a593Smuzhiyun 	/*
653*4882a593Smuzhiyun 	 * Receive/descriptor errors
654*4882a593Smuzhiyun 	 */
655*4882a593Smuzhiyun 	if (!(rx_status->rx_status_1 &
656*4882a593Smuzhiyun 			AR5K_5210_RX_DESC_STATUS1_FRAME_RECEIVE_OK)) {
657*4882a593Smuzhiyun 		if (rx_status->rx_status_1 &
658*4882a593Smuzhiyun 				AR5K_5210_RX_DESC_STATUS1_CRC_ERROR)
659*4882a593Smuzhiyun 			rs->rs_status |= AR5K_RXERR_CRC;
660*4882a593Smuzhiyun 
661*4882a593Smuzhiyun 		/* only on 5210 */
662*4882a593Smuzhiyun 		if ((ah->ah_version == AR5K_AR5210) &&
663*4882a593Smuzhiyun 		    (rx_status->rx_status_1 &
664*4882a593Smuzhiyun 				AR5K_5210_RX_DESC_STATUS1_FIFO_OVERRUN_5210))
665*4882a593Smuzhiyun 			rs->rs_status |= AR5K_RXERR_FIFO;
666*4882a593Smuzhiyun 
667*4882a593Smuzhiyun 		if (rx_status->rx_status_1 &
668*4882a593Smuzhiyun 				AR5K_5210_RX_DESC_STATUS1_PHY_ERROR) {
669*4882a593Smuzhiyun 			rs->rs_status |= AR5K_RXERR_PHY;
670*4882a593Smuzhiyun 			rs->rs_phyerr = AR5K_REG_MS(rx_status->rx_status_1,
671*4882a593Smuzhiyun 				AR5K_5210_RX_DESC_STATUS1_PHY_ERROR);
672*4882a593Smuzhiyun 		}
673*4882a593Smuzhiyun 
674*4882a593Smuzhiyun 		if (rx_status->rx_status_1 &
675*4882a593Smuzhiyun 				AR5K_5210_RX_DESC_STATUS1_DECRYPT_CRC_ERROR)
676*4882a593Smuzhiyun 			rs->rs_status |= AR5K_RXERR_DECRYPT;
677*4882a593Smuzhiyun 	}
678*4882a593Smuzhiyun 
679*4882a593Smuzhiyun 	return 0;
680*4882a593Smuzhiyun }
681*4882a593Smuzhiyun 
682*4882a593Smuzhiyun /**
683*4882a593Smuzhiyun  * ath5k_hw_proc_5212_rx_status() - Process the rx status descriptor on 5212
684*4882a593Smuzhiyun  * @ah: The &struct ath5k_hw
685*4882a593Smuzhiyun  * @desc: The &struct ath5k_desc
686*4882a593Smuzhiyun  * @rs: The &struct ath5k_rx_status
687*4882a593Smuzhiyun  *
688*4882a593Smuzhiyun  * Internal function used to process an RX status descriptor
689*4882a593Smuzhiyun  * on AR5212 and later MAC.
690*4882a593Smuzhiyun  *
691*4882a593Smuzhiyun  * Returns 0 on success or -EINPROGRESS in case we haven't received the who;e
692*4882a593Smuzhiyun  * frame yet.
693*4882a593Smuzhiyun  */
694*4882a593Smuzhiyun static int
ath5k_hw_proc_5212_rx_status(struct ath5k_hw * ah,struct ath5k_desc * desc,struct ath5k_rx_status * rs)695*4882a593Smuzhiyun ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah,
696*4882a593Smuzhiyun 				struct ath5k_desc *desc,
697*4882a593Smuzhiyun 				struct ath5k_rx_status *rs)
698*4882a593Smuzhiyun {
699*4882a593Smuzhiyun 	struct ath5k_hw_rx_status *rx_status;
700*4882a593Smuzhiyun 	u32 rxstat0, rxstat1;
701*4882a593Smuzhiyun 
702*4882a593Smuzhiyun 	rx_status = &desc->ud.ds_rx.rx_stat;
703*4882a593Smuzhiyun 	rxstat1 = READ_ONCE(rx_status->rx_status_1);
704*4882a593Smuzhiyun 
705*4882a593Smuzhiyun 	/* No frame received / not ready */
706*4882a593Smuzhiyun 	if (unlikely(!(rxstat1 & AR5K_5212_RX_DESC_STATUS1_DONE)))
707*4882a593Smuzhiyun 		return -EINPROGRESS;
708*4882a593Smuzhiyun 
709*4882a593Smuzhiyun 	memset(rs, 0, sizeof(struct ath5k_rx_status));
710*4882a593Smuzhiyun 	rxstat0 = READ_ONCE(rx_status->rx_status_0);
711*4882a593Smuzhiyun 
712*4882a593Smuzhiyun 	/*
713*4882a593Smuzhiyun 	 * Frame receive status
714*4882a593Smuzhiyun 	 */
715*4882a593Smuzhiyun 	rs->rs_datalen = rxstat0 & AR5K_5212_RX_DESC_STATUS0_DATA_LEN;
716*4882a593Smuzhiyun 	rs->rs_rssi = AR5K_REG_MS(rxstat0,
717*4882a593Smuzhiyun 		AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL);
718*4882a593Smuzhiyun 	rs->rs_rate = AR5K_REG_MS(rxstat0,
719*4882a593Smuzhiyun 		AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE);
720*4882a593Smuzhiyun 	rs->rs_antenna = AR5K_REG_MS(rxstat0,
721*4882a593Smuzhiyun 		AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA);
722*4882a593Smuzhiyun 	rs->rs_more = !!(rxstat0 & AR5K_5212_RX_DESC_STATUS0_MORE);
723*4882a593Smuzhiyun 	rs->rs_tstamp = AR5K_REG_MS(rxstat1,
724*4882a593Smuzhiyun 		AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP);
725*4882a593Smuzhiyun 
726*4882a593Smuzhiyun 	/*
727*4882a593Smuzhiyun 	 * Key table status
728*4882a593Smuzhiyun 	 */
729*4882a593Smuzhiyun 	if (rxstat1 & AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_VALID)
730*4882a593Smuzhiyun 		rs->rs_keyix = AR5K_REG_MS(rxstat1,
731*4882a593Smuzhiyun 					   AR5K_5212_RX_DESC_STATUS1_KEY_INDEX);
732*4882a593Smuzhiyun 	else
733*4882a593Smuzhiyun 		rs->rs_keyix = AR5K_RXKEYIX_INVALID;
734*4882a593Smuzhiyun 
735*4882a593Smuzhiyun 	/*
736*4882a593Smuzhiyun 	 * Receive/descriptor errors
737*4882a593Smuzhiyun 	 */
738*4882a593Smuzhiyun 	if (!(rxstat1 & AR5K_5212_RX_DESC_STATUS1_FRAME_RECEIVE_OK)) {
739*4882a593Smuzhiyun 		if (rxstat1 & AR5K_5212_RX_DESC_STATUS1_CRC_ERROR)
740*4882a593Smuzhiyun 			rs->rs_status |= AR5K_RXERR_CRC;
741*4882a593Smuzhiyun 
742*4882a593Smuzhiyun 		if (rxstat1 & AR5K_5212_RX_DESC_STATUS1_PHY_ERROR) {
743*4882a593Smuzhiyun 			rs->rs_status |= AR5K_RXERR_PHY;
744*4882a593Smuzhiyun 			rs->rs_phyerr = AR5K_REG_MS(rxstat1,
745*4882a593Smuzhiyun 				AR5K_5212_RX_DESC_STATUS1_PHY_ERROR_CODE);
746*4882a593Smuzhiyun 			if (!ah->ah_capabilities.cap_has_phyerr_counters)
747*4882a593Smuzhiyun 				ath5k_ani_phy_error_report(ah, rs->rs_phyerr);
748*4882a593Smuzhiyun 		}
749*4882a593Smuzhiyun 
750*4882a593Smuzhiyun 		if (rxstat1 & AR5K_5212_RX_DESC_STATUS1_DECRYPT_CRC_ERROR)
751*4882a593Smuzhiyun 			rs->rs_status |= AR5K_RXERR_DECRYPT;
752*4882a593Smuzhiyun 
753*4882a593Smuzhiyun 		if (rxstat1 & AR5K_5212_RX_DESC_STATUS1_MIC_ERROR)
754*4882a593Smuzhiyun 			rs->rs_status |= AR5K_RXERR_MIC;
755*4882a593Smuzhiyun 	}
756*4882a593Smuzhiyun 	return 0;
757*4882a593Smuzhiyun }
758*4882a593Smuzhiyun 
759*4882a593Smuzhiyun 
760*4882a593Smuzhiyun /********\
761*4882a593Smuzhiyun * Attach *
762*4882a593Smuzhiyun \********/
763*4882a593Smuzhiyun 
764*4882a593Smuzhiyun /**
765*4882a593Smuzhiyun  * ath5k_hw_init_desc_functions() - Init function pointers inside ah
766*4882a593Smuzhiyun  * @ah: The &struct ath5k_hw
767*4882a593Smuzhiyun  *
768*4882a593Smuzhiyun  * Maps the internal descriptor functions to the function pointers on ah, used
769*4882a593Smuzhiyun  * from above. This is used as an abstraction layer to handle the various chips
770*4882a593Smuzhiyun  * the same way.
771*4882a593Smuzhiyun  */
772*4882a593Smuzhiyun int
ath5k_hw_init_desc_functions(struct ath5k_hw * ah)773*4882a593Smuzhiyun ath5k_hw_init_desc_functions(struct ath5k_hw *ah)
774*4882a593Smuzhiyun {
775*4882a593Smuzhiyun 	if (ah->ah_version == AR5K_AR5212) {
776*4882a593Smuzhiyun 		ah->ah_setup_tx_desc = ath5k_hw_setup_4word_tx_desc;
777*4882a593Smuzhiyun 		ah->ah_proc_tx_desc = ath5k_hw_proc_4word_tx_status;
778*4882a593Smuzhiyun 		ah->ah_proc_rx_desc = ath5k_hw_proc_5212_rx_status;
779*4882a593Smuzhiyun 	} else if (ah->ah_version <= AR5K_AR5211) {
780*4882a593Smuzhiyun 		ah->ah_setup_tx_desc = ath5k_hw_setup_2word_tx_desc;
781*4882a593Smuzhiyun 		ah->ah_proc_tx_desc = ath5k_hw_proc_2word_tx_status;
782*4882a593Smuzhiyun 		ah->ah_proc_rx_desc = ath5k_hw_proc_5210_rx_status;
783*4882a593Smuzhiyun 	} else
784*4882a593Smuzhiyun 		return -ENOTSUPP;
785*4882a593Smuzhiyun 	return 0;
786*4882a593Smuzhiyun }
787