xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/ath/ath5k/qcu.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  *
5*4882a593Smuzhiyun  * Permission to use, copy, modify, and distribute this software for any
6*4882a593Smuzhiyun  * purpose with or without fee is hereby granted, provided that the above
7*4882a593Smuzhiyun  * copyright notice and this permission notice appear in all copies.
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10*4882a593Smuzhiyun  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11*4882a593Smuzhiyun  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12*4882a593Smuzhiyun  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13*4882a593Smuzhiyun  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14*4882a593Smuzhiyun  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15*4882a593Smuzhiyun  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16*4882a593Smuzhiyun  *
17*4882a593Smuzhiyun  */
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun /********************************************\
20*4882a593Smuzhiyun Queue Control Unit, DCF Control Unit Functions
21*4882a593Smuzhiyun \********************************************/
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun #include "ath5k.h"
26*4882a593Smuzhiyun #include "reg.h"
27*4882a593Smuzhiyun #include "debug.h"
28*4882a593Smuzhiyun #include <linux/log2.h>
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun /**
31*4882a593Smuzhiyun  * DOC: Queue Control Unit (QCU)/DCF Control Unit (DCU) functions
32*4882a593Smuzhiyun  *
33*4882a593Smuzhiyun  * Here we setup parameters for the 12 available TX queues. Note that
34*4882a593Smuzhiyun  * on the various registers we can usually only map the first 10 of them so
35*4882a593Smuzhiyun  * basically we have 10 queues to play with. Each queue has a matching
36*4882a593Smuzhiyun  * QCU that controls when the queue will get triggered and multiple QCUs
37*4882a593Smuzhiyun  * can be mapped to a single DCU that controls the various DFS parameters
38*4882a593Smuzhiyun  * for the various queues. In our setup we have a 1:1 mapping between QCUs
39*4882a593Smuzhiyun  * and DCUs allowing us to have different DFS settings for each queue.
40*4882a593Smuzhiyun  *
41*4882a593Smuzhiyun  * When a frame goes into a TX queue, QCU decides when it'll trigger a
42*4882a593Smuzhiyun  * transmission based on various criteria (such as how many data we have inside
43*4882a593Smuzhiyun  * it's buffer or -if it's a beacon queue- if it's time to fire up the queue
44*4882a593Smuzhiyun  * based on TSF etc), DCU adds backoff, IFSes etc and then a scheduler
45*4882a593Smuzhiyun  * (arbitrator) decides the priority of each QCU based on it's configuration
46*4882a593Smuzhiyun  * (e.g. beacons are always transmitted when they leave DCU bypassing all other
47*4882a593Smuzhiyun  * frames from other queues waiting to be transmitted). After a frame leaves
48*4882a593Smuzhiyun  * the DCU it goes to PCU for further processing and then to PHY for
49*4882a593Smuzhiyun  * the actual transmission.
50*4882a593Smuzhiyun  */
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun /******************\
54*4882a593Smuzhiyun * Helper functions *
55*4882a593Smuzhiyun \******************/
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun /**
58*4882a593Smuzhiyun  * ath5k_hw_num_tx_pending() - Get number of pending frames for a  given queue
59*4882a593Smuzhiyun  * @ah: The &struct ath5k_hw
60*4882a593Smuzhiyun  * @queue: One of enum ath5k_tx_queue_id
61*4882a593Smuzhiyun  */
62*4882a593Smuzhiyun u32
ath5k_hw_num_tx_pending(struct ath5k_hw * ah,unsigned int queue)63*4882a593Smuzhiyun ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue)
64*4882a593Smuzhiyun {
65*4882a593Smuzhiyun 	u32 pending;
66*4882a593Smuzhiyun 	AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun 	/* Return if queue is declared inactive */
69*4882a593Smuzhiyun 	if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE)
70*4882a593Smuzhiyun 		return false;
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun 	/* XXX: How about AR5K_CFG_TXCNT ? */
73*4882a593Smuzhiyun 	if (ah->ah_version == AR5K_AR5210)
74*4882a593Smuzhiyun 		return false;
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun 	pending = ath5k_hw_reg_read(ah, AR5K_QUEUE_STATUS(queue));
77*4882a593Smuzhiyun 	pending &= AR5K_QCU_STS_FRMPENDCNT;
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun 	/* It's possible to have no frames pending even if TXE
80*4882a593Smuzhiyun 	 * is set. To indicate that q has not stopped return
81*4882a593Smuzhiyun 	 * true */
82*4882a593Smuzhiyun 	if (!pending && AR5K_REG_READ_Q(ah, AR5K_QCU_TXE, queue))
83*4882a593Smuzhiyun 		return true;
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun 	return pending;
86*4882a593Smuzhiyun }
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun /**
89*4882a593Smuzhiyun  * ath5k_hw_release_tx_queue() - Set a transmit queue inactive
90*4882a593Smuzhiyun  * @ah: The &struct ath5k_hw
91*4882a593Smuzhiyun  * @queue: One of enum ath5k_tx_queue_id
92*4882a593Smuzhiyun  */
93*4882a593Smuzhiyun void
ath5k_hw_release_tx_queue(struct ath5k_hw * ah,unsigned int queue)94*4882a593Smuzhiyun ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue)
95*4882a593Smuzhiyun {
96*4882a593Smuzhiyun 	if (WARN_ON(queue >= ah->ah_capabilities.cap_queues.q_tx_num))
97*4882a593Smuzhiyun 		return;
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun 	/* This queue will be skipped in further operations */
100*4882a593Smuzhiyun 	ah->ah_txq[queue].tqi_type = AR5K_TX_QUEUE_INACTIVE;
101*4882a593Smuzhiyun 	/*For SIMR setup*/
102*4882a593Smuzhiyun 	AR5K_Q_DISABLE_BITS(ah->ah_txq_status, queue);
103*4882a593Smuzhiyun }
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun /**
106*4882a593Smuzhiyun  * ath5k_cw_validate() - Make sure the given cw is valid
107*4882a593Smuzhiyun  * @cw_req: The contention window value to check
108*4882a593Smuzhiyun  *
109*4882a593Smuzhiyun  * Make sure cw is a power of 2 minus 1 and smaller than 1024
110*4882a593Smuzhiyun  */
111*4882a593Smuzhiyun static u16
ath5k_cw_validate(u16 cw_req)112*4882a593Smuzhiyun ath5k_cw_validate(u16 cw_req)
113*4882a593Smuzhiyun {
114*4882a593Smuzhiyun 	cw_req = min(cw_req, (u16)1023);
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun 	/* Check if cw_req + 1 a power of 2 */
117*4882a593Smuzhiyun 	if (is_power_of_2(cw_req + 1))
118*4882a593Smuzhiyun 		return cw_req;
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun 	/* Check if cw_req is a power of 2 */
121*4882a593Smuzhiyun 	if (is_power_of_2(cw_req))
122*4882a593Smuzhiyun 		return cw_req - 1;
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun 	/* If none of the above is correct
125*4882a593Smuzhiyun 	 * find the closest power of 2 */
126*4882a593Smuzhiyun 	cw_req = (u16) roundup_pow_of_two(cw_req) - 1;
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun 	return cw_req;
129*4882a593Smuzhiyun }
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun /**
132*4882a593Smuzhiyun  * ath5k_hw_get_tx_queueprops() - Get properties for a transmit queue
133*4882a593Smuzhiyun  * @ah: The &struct ath5k_hw
134*4882a593Smuzhiyun  * @queue: One of enum ath5k_tx_queue_id
135*4882a593Smuzhiyun  * @queue_info: The &struct ath5k_txq_info to fill
136*4882a593Smuzhiyun  */
137*4882a593Smuzhiyun int
ath5k_hw_get_tx_queueprops(struct ath5k_hw * ah,int queue,struct ath5k_txq_info * queue_info)138*4882a593Smuzhiyun ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue,
139*4882a593Smuzhiyun 		struct ath5k_txq_info *queue_info)
140*4882a593Smuzhiyun {
141*4882a593Smuzhiyun 	memcpy(queue_info, &ah->ah_txq[queue], sizeof(struct ath5k_txq_info));
142*4882a593Smuzhiyun 	return 0;
143*4882a593Smuzhiyun }
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun /**
146*4882a593Smuzhiyun  * ath5k_hw_set_tx_queueprops() - Set properties for a transmit queue
147*4882a593Smuzhiyun  * @ah: The &struct ath5k_hw
148*4882a593Smuzhiyun  * @queue: One of enum ath5k_tx_queue_id
149*4882a593Smuzhiyun  * @qinfo: The &struct ath5k_txq_info to use
150*4882a593Smuzhiyun  *
151*4882a593Smuzhiyun  * Returns 0 on success or -EIO if queue is inactive
152*4882a593Smuzhiyun  */
153*4882a593Smuzhiyun int
ath5k_hw_set_tx_queueprops(struct ath5k_hw * ah,int queue,const struct ath5k_txq_info * qinfo)154*4882a593Smuzhiyun ath5k_hw_set_tx_queueprops(struct ath5k_hw *ah, int queue,
155*4882a593Smuzhiyun 				const struct ath5k_txq_info *qinfo)
156*4882a593Smuzhiyun {
157*4882a593Smuzhiyun 	struct ath5k_txq_info *qi;
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 	AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun 	qi = &ah->ah_txq[queue];
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun 	if (qi->tqi_type == AR5K_TX_QUEUE_INACTIVE)
164*4882a593Smuzhiyun 		return -EIO;
165*4882a593Smuzhiyun 
166*4882a593Smuzhiyun 	/* copy and validate values */
167*4882a593Smuzhiyun 	qi->tqi_type = qinfo->tqi_type;
168*4882a593Smuzhiyun 	qi->tqi_subtype = qinfo->tqi_subtype;
169*4882a593Smuzhiyun 	qi->tqi_flags = qinfo->tqi_flags;
170*4882a593Smuzhiyun 	/*
171*4882a593Smuzhiyun 	 * According to the docs: Although the AIFS field is 8 bit wide,
172*4882a593Smuzhiyun 	 * the maximum supported value is 0xFC. Setting it higher than that
173*4882a593Smuzhiyun 	 * will cause the DCU to hang.
174*4882a593Smuzhiyun 	 */
175*4882a593Smuzhiyun 	qi->tqi_aifs = min(qinfo->tqi_aifs, (u8)0xFC);
176*4882a593Smuzhiyun 	qi->tqi_cw_min = ath5k_cw_validate(qinfo->tqi_cw_min);
177*4882a593Smuzhiyun 	qi->tqi_cw_max = ath5k_cw_validate(qinfo->tqi_cw_max);
178*4882a593Smuzhiyun 	qi->tqi_cbr_period = qinfo->tqi_cbr_period;
179*4882a593Smuzhiyun 	qi->tqi_cbr_overflow_limit = qinfo->tqi_cbr_overflow_limit;
180*4882a593Smuzhiyun 	qi->tqi_burst_time = qinfo->tqi_burst_time;
181*4882a593Smuzhiyun 	qi->tqi_ready_time = qinfo->tqi_ready_time;
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun 	/*XXX: Is this supported on 5210 ?*/
184*4882a593Smuzhiyun 	/*XXX: Is this correct for AR5K_WME_AC_VI,VO ???*/
185*4882a593Smuzhiyun 	if ((qinfo->tqi_type == AR5K_TX_QUEUE_DATA &&
186*4882a593Smuzhiyun 		((qinfo->tqi_subtype == AR5K_WME_AC_VI) ||
187*4882a593Smuzhiyun 		 (qinfo->tqi_subtype == AR5K_WME_AC_VO))) ||
188*4882a593Smuzhiyun 	     qinfo->tqi_type == AR5K_TX_QUEUE_UAPSD)
189*4882a593Smuzhiyun 		qi->tqi_flags |= AR5K_TXQ_FLAG_POST_FR_BKOFF_DIS;
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun 	return 0;
192*4882a593Smuzhiyun }
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun /**
195*4882a593Smuzhiyun  * ath5k_hw_setup_tx_queue() - Initialize a transmit queue
196*4882a593Smuzhiyun  * @ah: The &struct ath5k_hw
197*4882a593Smuzhiyun  * @queue_type: One of enum ath5k_tx_queue
198*4882a593Smuzhiyun  * @queue_info: The &struct ath5k_txq_info to use
199*4882a593Smuzhiyun  *
200*4882a593Smuzhiyun  * Returns 0 on success, -EINVAL on invalid arguments
201*4882a593Smuzhiyun  */
202*4882a593Smuzhiyun int
ath5k_hw_setup_tx_queue(struct ath5k_hw * ah,enum ath5k_tx_queue queue_type,struct ath5k_txq_info * queue_info)203*4882a593Smuzhiyun ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type,
204*4882a593Smuzhiyun 		struct ath5k_txq_info *queue_info)
205*4882a593Smuzhiyun {
206*4882a593Smuzhiyun 	unsigned int queue;
207*4882a593Smuzhiyun 	int ret;
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun 	/*
210*4882a593Smuzhiyun 	 * Get queue by type
211*4882a593Smuzhiyun 	 */
212*4882a593Smuzhiyun 	/* 5210 only has 2 queues */
213*4882a593Smuzhiyun 	if (ah->ah_capabilities.cap_queues.q_tx_num == 2) {
214*4882a593Smuzhiyun 		switch (queue_type) {
215*4882a593Smuzhiyun 		case AR5K_TX_QUEUE_DATA:
216*4882a593Smuzhiyun 			queue = AR5K_TX_QUEUE_ID_NOQCU_DATA;
217*4882a593Smuzhiyun 			break;
218*4882a593Smuzhiyun 		case AR5K_TX_QUEUE_BEACON:
219*4882a593Smuzhiyun 		case AR5K_TX_QUEUE_CAB:
220*4882a593Smuzhiyun 			queue = AR5K_TX_QUEUE_ID_NOQCU_BEACON;
221*4882a593Smuzhiyun 			break;
222*4882a593Smuzhiyun 		default:
223*4882a593Smuzhiyun 			return -EINVAL;
224*4882a593Smuzhiyun 		}
225*4882a593Smuzhiyun 	} else {
226*4882a593Smuzhiyun 		switch (queue_type) {
227*4882a593Smuzhiyun 		case AR5K_TX_QUEUE_DATA:
228*4882a593Smuzhiyun 			queue = queue_info->tqi_subtype;
229*4882a593Smuzhiyun 			break;
230*4882a593Smuzhiyun 		case AR5K_TX_QUEUE_UAPSD:
231*4882a593Smuzhiyun 			queue = AR5K_TX_QUEUE_ID_UAPSD;
232*4882a593Smuzhiyun 			break;
233*4882a593Smuzhiyun 		case AR5K_TX_QUEUE_BEACON:
234*4882a593Smuzhiyun 			queue = AR5K_TX_QUEUE_ID_BEACON;
235*4882a593Smuzhiyun 			break;
236*4882a593Smuzhiyun 		case AR5K_TX_QUEUE_CAB:
237*4882a593Smuzhiyun 			queue = AR5K_TX_QUEUE_ID_CAB;
238*4882a593Smuzhiyun 			break;
239*4882a593Smuzhiyun 		default:
240*4882a593Smuzhiyun 			return -EINVAL;
241*4882a593Smuzhiyun 		}
242*4882a593Smuzhiyun 	}
243*4882a593Smuzhiyun 
244*4882a593Smuzhiyun 	/*
245*4882a593Smuzhiyun 	 * Setup internal queue structure
246*4882a593Smuzhiyun 	 */
247*4882a593Smuzhiyun 	memset(&ah->ah_txq[queue], 0, sizeof(struct ath5k_txq_info));
248*4882a593Smuzhiyun 	ah->ah_txq[queue].tqi_type = queue_type;
249*4882a593Smuzhiyun 
250*4882a593Smuzhiyun 	if (queue_info != NULL) {
251*4882a593Smuzhiyun 		queue_info->tqi_type = queue_type;
252*4882a593Smuzhiyun 		ret = ath5k_hw_set_tx_queueprops(ah, queue, queue_info);
253*4882a593Smuzhiyun 		if (ret)
254*4882a593Smuzhiyun 			return ret;
255*4882a593Smuzhiyun 	}
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun 	/*
258*4882a593Smuzhiyun 	 * We use ah_txq_status to hold a temp value for
259*4882a593Smuzhiyun 	 * the Secondary interrupt mask registers on 5211+
260*4882a593Smuzhiyun 	 * check out ath5k_hw_reset_tx_queue
261*4882a593Smuzhiyun 	 */
262*4882a593Smuzhiyun 	AR5K_Q_ENABLE_BITS(ah->ah_txq_status, queue);
263*4882a593Smuzhiyun 
264*4882a593Smuzhiyun 	return queue;
265*4882a593Smuzhiyun }
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun 
268*4882a593Smuzhiyun /*******************************\
269*4882a593Smuzhiyun * Single QCU/DCU initialization *
270*4882a593Smuzhiyun \*******************************/
271*4882a593Smuzhiyun 
272*4882a593Smuzhiyun /**
273*4882a593Smuzhiyun  * ath5k_hw_set_tx_retry_limits() - Set tx retry limits on DCU
274*4882a593Smuzhiyun  * @ah: The &struct ath5k_hw
275*4882a593Smuzhiyun  * @queue: One of enum ath5k_tx_queue_id
276*4882a593Smuzhiyun  *
277*4882a593Smuzhiyun  * This function is used when initializing a queue, to set
278*4882a593Smuzhiyun  * retry limits based on ah->ah_retry_* and the chipset used.
279*4882a593Smuzhiyun  */
280*4882a593Smuzhiyun void
ath5k_hw_set_tx_retry_limits(struct ath5k_hw * ah,unsigned int queue)281*4882a593Smuzhiyun ath5k_hw_set_tx_retry_limits(struct ath5k_hw *ah,
282*4882a593Smuzhiyun 				  unsigned int queue)
283*4882a593Smuzhiyun {
284*4882a593Smuzhiyun 	/* Single data queue on AR5210 */
285*4882a593Smuzhiyun 	if (ah->ah_version == AR5K_AR5210) {
286*4882a593Smuzhiyun 		struct ath5k_txq_info *tq = &ah->ah_txq[queue];
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun 		if (queue > 0)
289*4882a593Smuzhiyun 			return;
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun 		ath5k_hw_reg_write(ah,
292*4882a593Smuzhiyun 			(tq->tqi_cw_min << AR5K_NODCU_RETRY_LMT_CW_MIN_S)
293*4882a593Smuzhiyun 			| AR5K_REG_SM(ah->ah_retry_long,
294*4882a593Smuzhiyun 				      AR5K_NODCU_RETRY_LMT_SLG_RETRY)
295*4882a593Smuzhiyun 			| AR5K_REG_SM(ah->ah_retry_short,
296*4882a593Smuzhiyun 				      AR5K_NODCU_RETRY_LMT_SSH_RETRY)
297*4882a593Smuzhiyun 			| AR5K_REG_SM(ah->ah_retry_long,
298*4882a593Smuzhiyun 				      AR5K_NODCU_RETRY_LMT_LG_RETRY)
299*4882a593Smuzhiyun 			| AR5K_REG_SM(ah->ah_retry_short,
300*4882a593Smuzhiyun 				      AR5K_NODCU_RETRY_LMT_SH_RETRY),
301*4882a593Smuzhiyun 			AR5K_NODCU_RETRY_LMT);
302*4882a593Smuzhiyun 	/* DCU on AR5211+ */
303*4882a593Smuzhiyun 	} else {
304*4882a593Smuzhiyun 		ath5k_hw_reg_write(ah,
305*4882a593Smuzhiyun 			AR5K_REG_SM(ah->ah_retry_long,
306*4882a593Smuzhiyun 				    AR5K_DCU_RETRY_LMT_RTS)
307*4882a593Smuzhiyun 			| AR5K_REG_SM(ah->ah_retry_long,
308*4882a593Smuzhiyun 				      AR5K_DCU_RETRY_LMT_STA_RTS)
309*4882a593Smuzhiyun 			| AR5K_REG_SM(max(ah->ah_retry_long, ah->ah_retry_short),
310*4882a593Smuzhiyun 				      AR5K_DCU_RETRY_LMT_STA_DATA),
311*4882a593Smuzhiyun 			AR5K_QUEUE_DFS_RETRY_LIMIT(queue));
312*4882a593Smuzhiyun 	}
313*4882a593Smuzhiyun }
314*4882a593Smuzhiyun 
315*4882a593Smuzhiyun /**
316*4882a593Smuzhiyun  * ath5k_hw_reset_tx_queue() - Initialize a single hw queue
317*4882a593Smuzhiyun  * @ah: The &struct ath5k_hw
318*4882a593Smuzhiyun  * @queue: One of enum ath5k_tx_queue_id
319*4882a593Smuzhiyun  *
320*4882a593Smuzhiyun  * Set DCF properties for the given transmit queue on DCU
321*4882a593Smuzhiyun  * and configures all queue-specific parameters.
322*4882a593Smuzhiyun  */
323*4882a593Smuzhiyun int
ath5k_hw_reset_tx_queue(struct ath5k_hw * ah,unsigned int queue)324*4882a593Smuzhiyun ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
325*4882a593Smuzhiyun {
326*4882a593Smuzhiyun 	struct ath5k_txq_info *tq = &ah->ah_txq[queue];
327*4882a593Smuzhiyun 
328*4882a593Smuzhiyun 	AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun 	/* Skip if queue inactive or if we are on AR5210
331*4882a593Smuzhiyun 	 * that doesn't have QCU/DCU */
332*4882a593Smuzhiyun 	if ((ah->ah_version == AR5K_AR5210) ||
333*4882a593Smuzhiyun 	(tq->tqi_type == AR5K_TX_QUEUE_INACTIVE))
334*4882a593Smuzhiyun 		return 0;
335*4882a593Smuzhiyun 
336*4882a593Smuzhiyun 	/*
337*4882a593Smuzhiyun 	 * Set contention window (cw_min/cw_max)
338*4882a593Smuzhiyun 	 * and arbitrated interframe space (aifs)...
339*4882a593Smuzhiyun 	 */
340*4882a593Smuzhiyun 	ath5k_hw_reg_write(ah,
341*4882a593Smuzhiyun 		AR5K_REG_SM(tq->tqi_cw_min, AR5K_DCU_LCL_IFS_CW_MIN) |
342*4882a593Smuzhiyun 		AR5K_REG_SM(tq->tqi_cw_max, AR5K_DCU_LCL_IFS_CW_MAX) |
343*4882a593Smuzhiyun 		AR5K_REG_SM(tq->tqi_aifs, AR5K_DCU_LCL_IFS_AIFS),
344*4882a593Smuzhiyun 		AR5K_QUEUE_DFS_LOCAL_IFS(queue));
345*4882a593Smuzhiyun 
346*4882a593Smuzhiyun 	/*
347*4882a593Smuzhiyun 	 * Set tx retry limits for this queue
348*4882a593Smuzhiyun 	 */
349*4882a593Smuzhiyun 	ath5k_hw_set_tx_retry_limits(ah, queue);
350*4882a593Smuzhiyun 
351*4882a593Smuzhiyun 
352*4882a593Smuzhiyun 	/*
353*4882a593Smuzhiyun 	 * Set misc registers
354*4882a593Smuzhiyun 	 */
355*4882a593Smuzhiyun 
356*4882a593Smuzhiyun 	/* Enable DCU to wait for next fragment from QCU */
357*4882a593Smuzhiyun 	AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
358*4882a593Smuzhiyun 				AR5K_DCU_MISC_FRAG_WAIT);
359*4882a593Smuzhiyun 
360*4882a593Smuzhiyun 	/* On Maui and Spirit use the global seqnum on DCU */
361*4882a593Smuzhiyun 	if (ah->ah_mac_version < AR5K_SREV_AR5211)
362*4882a593Smuzhiyun 		AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
363*4882a593Smuzhiyun 					AR5K_DCU_MISC_SEQNUM_CTL);
364*4882a593Smuzhiyun 
365*4882a593Smuzhiyun 	/* Constant bit rate period */
366*4882a593Smuzhiyun 	if (tq->tqi_cbr_period) {
367*4882a593Smuzhiyun 		ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_cbr_period,
368*4882a593Smuzhiyun 					AR5K_QCU_CBRCFG_INTVAL) |
369*4882a593Smuzhiyun 					AR5K_REG_SM(tq->tqi_cbr_overflow_limit,
370*4882a593Smuzhiyun 					AR5K_QCU_CBRCFG_ORN_THRES),
371*4882a593Smuzhiyun 					AR5K_QUEUE_CBRCFG(queue));
372*4882a593Smuzhiyun 
373*4882a593Smuzhiyun 		AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
374*4882a593Smuzhiyun 					AR5K_QCU_MISC_FRSHED_CBR);
375*4882a593Smuzhiyun 
376*4882a593Smuzhiyun 		if (tq->tqi_cbr_overflow_limit)
377*4882a593Smuzhiyun 			AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
378*4882a593Smuzhiyun 					AR5K_QCU_MISC_CBR_THRES_ENABLE);
379*4882a593Smuzhiyun 	}
380*4882a593Smuzhiyun 
381*4882a593Smuzhiyun 	/* Ready time interval */
382*4882a593Smuzhiyun 	if (tq->tqi_ready_time && (tq->tqi_type != AR5K_TX_QUEUE_CAB))
383*4882a593Smuzhiyun 		ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_ready_time,
384*4882a593Smuzhiyun 					AR5K_QCU_RDYTIMECFG_INTVAL) |
385*4882a593Smuzhiyun 					AR5K_QCU_RDYTIMECFG_ENABLE,
386*4882a593Smuzhiyun 					AR5K_QUEUE_RDYTIMECFG(queue));
387*4882a593Smuzhiyun 
388*4882a593Smuzhiyun 	if (tq->tqi_burst_time) {
389*4882a593Smuzhiyun 		ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_burst_time,
390*4882a593Smuzhiyun 					AR5K_DCU_CHAN_TIME_DUR) |
391*4882a593Smuzhiyun 					AR5K_DCU_CHAN_TIME_ENABLE,
392*4882a593Smuzhiyun 					AR5K_QUEUE_DFS_CHANNEL_TIME(queue));
393*4882a593Smuzhiyun 
394*4882a593Smuzhiyun 		if (tq->tqi_flags & AR5K_TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE)
395*4882a593Smuzhiyun 			AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
396*4882a593Smuzhiyun 					AR5K_QCU_MISC_RDY_VEOL_POLICY);
397*4882a593Smuzhiyun 	}
398*4882a593Smuzhiyun 
399*4882a593Smuzhiyun 	/* Enable/disable Post frame backoff */
400*4882a593Smuzhiyun 	if (tq->tqi_flags & AR5K_TXQ_FLAG_BACKOFF_DISABLE)
401*4882a593Smuzhiyun 		ath5k_hw_reg_write(ah, AR5K_DCU_MISC_POST_FR_BKOFF_DIS,
402*4882a593Smuzhiyun 					AR5K_QUEUE_DFS_MISC(queue));
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun 	/* Enable/disable fragmentation burst backoff */
405*4882a593Smuzhiyun 	if (tq->tqi_flags & AR5K_TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE)
406*4882a593Smuzhiyun 		ath5k_hw_reg_write(ah, AR5K_DCU_MISC_BACKOFF_FRAG,
407*4882a593Smuzhiyun 					AR5K_QUEUE_DFS_MISC(queue));
408*4882a593Smuzhiyun 
409*4882a593Smuzhiyun 	/*
410*4882a593Smuzhiyun 	 * Set registers by queue type
411*4882a593Smuzhiyun 	 */
412*4882a593Smuzhiyun 	switch (tq->tqi_type) {
413*4882a593Smuzhiyun 	case AR5K_TX_QUEUE_BEACON:
414*4882a593Smuzhiyun 		AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
415*4882a593Smuzhiyun 				AR5K_QCU_MISC_FRSHED_DBA_GT |
416*4882a593Smuzhiyun 				AR5K_QCU_MISC_CBREXP_BCN_DIS |
417*4882a593Smuzhiyun 				AR5K_QCU_MISC_BCN_ENABLE);
418*4882a593Smuzhiyun 
419*4882a593Smuzhiyun 		AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
420*4882a593Smuzhiyun 				(AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL <<
421*4882a593Smuzhiyun 				AR5K_DCU_MISC_ARBLOCK_CTL_S) |
422*4882a593Smuzhiyun 				AR5K_DCU_MISC_ARBLOCK_IGNORE |
423*4882a593Smuzhiyun 				AR5K_DCU_MISC_POST_FR_BKOFF_DIS |
424*4882a593Smuzhiyun 				AR5K_DCU_MISC_BCN_ENABLE);
425*4882a593Smuzhiyun 		break;
426*4882a593Smuzhiyun 
427*4882a593Smuzhiyun 	case AR5K_TX_QUEUE_CAB:
428*4882a593Smuzhiyun 		/* XXX: use BCN_SENT_GT, if we can figure out how */
429*4882a593Smuzhiyun 		AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
430*4882a593Smuzhiyun 					AR5K_QCU_MISC_FRSHED_DBA_GT |
431*4882a593Smuzhiyun 					AR5K_QCU_MISC_CBREXP_DIS |
432*4882a593Smuzhiyun 					AR5K_QCU_MISC_CBREXP_BCN_DIS);
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun 		ath5k_hw_reg_write(ah, ((tq->tqi_ready_time -
435*4882a593Smuzhiyun 					(AR5K_TUNE_SW_BEACON_RESP -
436*4882a593Smuzhiyun 					AR5K_TUNE_DMA_BEACON_RESP) -
437*4882a593Smuzhiyun 				AR5K_TUNE_ADDITIONAL_SWBA_BACKOFF) * 1024) |
438*4882a593Smuzhiyun 					AR5K_QCU_RDYTIMECFG_ENABLE,
439*4882a593Smuzhiyun 					AR5K_QUEUE_RDYTIMECFG(queue));
440*4882a593Smuzhiyun 
441*4882a593Smuzhiyun 		AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
442*4882a593Smuzhiyun 					(AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL <<
443*4882a593Smuzhiyun 					AR5K_DCU_MISC_ARBLOCK_CTL_S));
444*4882a593Smuzhiyun 		break;
445*4882a593Smuzhiyun 
446*4882a593Smuzhiyun 	case AR5K_TX_QUEUE_UAPSD:
447*4882a593Smuzhiyun 		AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
448*4882a593Smuzhiyun 					AR5K_QCU_MISC_CBREXP_DIS);
449*4882a593Smuzhiyun 		break;
450*4882a593Smuzhiyun 
451*4882a593Smuzhiyun 	case AR5K_TX_QUEUE_DATA:
452*4882a593Smuzhiyun 	default:
453*4882a593Smuzhiyun 			break;
454*4882a593Smuzhiyun 	}
455*4882a593Smuzhiyun 
456*4882a593Smuzhiyun 	/* TODO: Handle frame compression */
457*4882a593Smuzhiyun 
458*4882a593Smuzhiyun 	/*
459*4882a593Smuzhiyun 	 * Enable interrupts for this tx queue
460*4882a593Smuzhiyun 	 * in the secondary interrupt mask registers
461*4882a593Smuzhiyun 	 */
462*4882a593Smuzhiyun 	if (tq->tqi_flags & AR5K_TXQ_FLAG_TXOKINT_ENABLE)
463*4882a593Smuzhiyun 		AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txok, queue);
464*4882a593Smuzhiyun 
465*4882a593Smuzhiyun 	if (tq->tqi_flags & AR5K_TXQ_FLAG_TXERRINT_ENABLE)
466*4882a593Smuzhiyun 		AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txerr, queue);
467*4882a593Smuzhiyun 
468*4882a593Smuzhiyun 	if (tq->tqi_flags & AR5K_TXQ_FLAG_TXURNINT_ENABLE)
469*4882a593Smuzhiyun 		AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txurn, queue);
470*4882a593Smuzhiyun 
471*4882a593Smuzhiyun 	if (tq->tqi_flags & AR5K_TXQ_FLAG_TXDESCINT_ENABLE)
472*4882a593Smuzhiyun 		AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txdesc, queue);
473*4882a593Smuzhiyun 
474*4882a593Smuzhiyun 	if (tq->tqi_flags & AR5K_TXQ_FLAG_TXEOLINT_ENABLE)
475*4882a593Smuzhiyun 		AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txeol, queue);
476*4882a593Smuzhiyun 
477*4882a593Smuzhiyun 	if (tq->tqi_flags & AR5K_TXQ_FLAG_CBRORNINT_ENABLE)
478*4882a593Smuzhiyun 		AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_cbrorn, queue);
479*4882a593Smuzhiyun 
480*4882a593Smuzhiyun 	if (tq->tqi_flags & AR5K_TXQ_FLAG_CBRURNINT_ENABLE)
481*4882a593Smuzhiyun 		AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_cbrurn, queue);
482*4882a593Smuzhiyun 
483*4882a593Smuzhiyun 	if (tq->tqi_flags & AR5K_TXQ_FLAG_QTRIGINT_ENABLE)
484*4882a593Smuzhiyun 		AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_qtrig, queue);
485*4882a593Smuzhiyun 
486*4882a593Smuzhiyun 	if (tq->tqi_flags & AR5K_TXQ_FLAG_TXNOFRMINT_ENABLE)
487*4882a593Smuzhiyun 		AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_nofrm, queue);
488*4882a593Smuzhiyun 
489*4882a593Smuzhiyun 	/* Update secondary interrupt mask registers */
490*4882a593Smuzhiyun 
491*4882a593Smuzhiyun 	/* Filter out inactive queues */
492*4882a593Smuzhiyun 	ah->ah_txq_imr_txok &= ah->ah_txq_status;
493*4882a593Smuzhiyun 	ah->ah_txq_imr_txerr &= ah->ah_txq_status;
494*4882a593Smuzhiyun 	ah->ah_txq_imr_txurn &= ah->ah_txq_status;
495*4882a593Smuzhiyun 	ah->ah_txq_imr_txdesc &= ah->ah_txq_status;
496*4882a593Smuzhiyun 	ah->ah_txq_imr_txeol &= ah->ah_txq_status;
497*4882a593Smuzhiyun 	ah->ah_txq_imr_cbrorn &= ah->ah_txq_status;
498*4882a593Smuzhiyun 	ah->ah_txq_imr_cbrurn &= ah->ah_txq_status;
499*4882a593Smuzhiyun 	ah->ah_txq_imr_qtrig &= ah->ah_txq_status;
500*4882a593Smuzhiyun 	ah->ah_txq_imr_nofrm &= ah->ah_txq_status;
501*4882a593Smuzhiyun 
502*4882a593Smuzhiyun 	ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txok,
503*4882a593Smuzhiyun 					AR5K_SIMR0_QCU_TXOK) |
504*4882a593Smuzhiyun 					AR5K_REG_SM(ah->ah_txq_imr_txdesc,
505*4882a593Smuzhiyun 					AR5K_SIMR0_QCU_TXDESC),
506*4882a593Smuzhiyun 					AR5K_SIMR0);
507*4882a593Smuzhiyun 
508*4882a593Smuzhiyun 	ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txerr,
509*4882a593Smuzhiyun 					AR5K_SIMR1_QCU_TXERR) |
510*4882a593Smuzhiyun 					AR5K_REG_SM(ah->ah_txq_imr_txeol,
511*4882a593Smuzhiyun 					AR5K_SIMR1_QCU_TXEOL),
512*4882a593Smuzhiyun 					AR5K_SIMR1);
513*4882a593Smuzhiyun 
514*4882a593Smuzhiyun 	/* Update SIMR2 but don't overwrite rest simr2 settings */
515*4882a593Smuzhiyun 	AR5K_REG_DISABLE_BITS(ah, AR5K_SIMR2, AR5K_SIMR2_QCU_TXURN);
516*4882a593Smuzhiyun 	AR5K_REG_ENABLE_BITS(ah, AR5K_SIMR2,
517*4882a593Smuzhiyun 				AR5K_REG_SM(ah->ah_txq_imr_txurn,
518*4882a593Smuzhiyun 				AR5K_SIMR2_QCU_TXURN));
519*4882a593Smuzhiyun 
520*4882a593Smuzhiyun 	ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_cbrorn,
521*4882a593Smuzhiyun 				AR5K_SIMR3_QCBRORN) |
522*4882a593Smuzhiyun 				AR5K_REG_SM(ah->ah_txq_imr_cbrurn,
523*4882a593Smuzhiyun 				AR5K_SIMR3_QCBRURN),
524*4882a593Smuzhiyun 				AR5K_SIMR3);
525*4882a593Smuzhiyun 
526*4882a593Smuzhiyun 	ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_qtrig,
527*4882a593Smuzhiyun 				AR5K_SIMR4_QTRIG), AR5K_SIMR4);
528*4882a593Smuzhiyun 
529*4882a593Smuzhiyun 	/* Set TXNOFRM_QCU for the queues with TXNOFRM enabled */
530*4882a593Smuzhiyun 	ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_nofrm,
531*4882a593Smuzhiyun 				AR5K_TXNOFRM_QCU), AR5K_TXNOFRM);
532*4882a593Smuzhiyun 
533*4882a593Smuzhiyun 	/* No queue has TXNOFRM enabled, disable the interrupt
534*4882a593Smuzhiyun 	 * by setting AR5K_TXNOFRM to zero */
535*4882a593Smuzhiyun 	if (ah->ah_txq_imr_nofrm == 0)
536*4882a593Smuzhiyun 		ath5k_hw_reg_write(ah, 0, AR5K_TXNOFRM);
537*4882a593Smuzhiyun 
538*4882a593Smuzhiyun 	/* Set QCU mask for this DCU to save power */
539*4882a593Smuzhiyun 	AR5K_REG_WRITE_Q(ah, AR5K_QUEUE_QCUMASK(queue), queue);
540*4882a593Smuzhiyun 
541*4882a593Smuzhiyun 	return 0;
542*4882a593Smuzhiyun }
543*4882a593Smuzhiyun 
544*4882a593Smuzhiyun 
545*4882a593Smuzhiyun /**************************\
546*4882a593Smuzhiyun * Global QCU/DCU functions *
547*4882a593Smuzhiyun \**************************/
548*4882a593Smuzhiyun 
549*4882a593Smuzhiyun /**
550*4882a593Smuzhiyun  * ath5k_hw_set_ifs_intervals()  - Set global inter-frame spaces on DCU
551*4882a593Smuzhiyun  * @ah: The &struct ath5k_hw
552*4882a593Smuzhiyun  * @slot_time: Slot time in us
553*4882a593Smuzhiyun  *
554*4882a593Smuzhiyun  * Sets the global IFS intervals on DCU (also works on AR5210) for
555*4882a593Smuzhiyun  * the given slot time and the current bwmode.
556*4882a593Smuzhiyun  */
ath5k_hw_set_ifs_intervals(struct ath5k_hw * ah,unsigned int slot_time)557*4882a593Smuzhiyun int ath5k_hw_set_ifs_intervals(struct ath5k_hw *ah, unsigned int slot_time)
558*4882a593Smuzhiyun {
559*4882a593Smuzhiyun 	struct ieee80211_channel *channel = ah->ah_current_channel;
560*4882a593Smuzhiyun 	enum nl80211_band band;
561*4882a593Smuzhiyun 	struct ieee80211_supported_band *sband;
562*4882a593Smuzhiyun 	struct ieee80211_rate *rate;
563*4882a593Smuzhiyun 	u32 ack_tx_time, eifs, eifs_clock, sifs, sifs_clock;
564*4882a593Smuzhiyun 	u32 slot_time_clock = ath5k_hw_htoclock(ah, slot_time);
565*4882a593Smuzhiyun 	u32 rate_flags, i;
566*4882a593Smuzhiyun 
567*4882a593Smuzhiyun 	if (slot_time < 6 || slot_time_clock > AR5K_SLOT_TIME_MAX)
568*4882a593Smuzhiyun 		return -EINVAL;
569*4882a593Smuzhiyun 
570*4882a593Smuzhiyun 	sifs = ath5k_hw_get_default_sifs(ah);
571*4882a593Smuzhiyun 	sifs_clock = ath5k_hw_htoclock(ah, sifs - 2);
572*4882a593Smuzhiyun 
573*4882a593Smuzhiyun 	/* EIFS
574*4882a593Smuzhiyun 	 * Txtime of ack at lowest rate + SIFS + DIFS
575*4882a593Smuzhiyun 	 * (DIFS = SIFS + 2 * Slot time)
576*4882a593Smuzhiyun 	 *
577*4882a593Smuzhiyun 	 * Note: HAL has some predefined values for EIFS
578*4882a593Smuzhiyun 	 * Turbo:   (37 + 2 * 6)
579*4882a593Smuzhiyun 	 * Default: (74 + 2 * 9)
580*4882a593Smuzhiyun 	 * Half:    (149 + 2 * 13)
581*4882a593Smuzhiyun 	 * Quarter: (298 + 2 * 21)
582*4882a593Smuzhiyun 	 *
583*4882a593Smuzhiyun 	 * (74 + 2 * 6) for AR5210 default and turbo !
584*4882a593Smuzhiyun 	 *
585*4882a593Smuzhiyun 	 * According to the formula we have
586*4882a593Smuzhiyun 	 * ack_tx_time = 25 for turbo and
587*4882a593Smuzhiyun 	 * ack_tx_time = 42.5 * clock multiplier
588*4882a593Smuzhiyun 	 * for default/half/quarter.
589*4882a593Smuzhiyun 	 *
590*4882a593Smuzhiyun 	 * This can't be right, 42 is what we would get
591*4882a593Smuzhiyun 	 * from ath5k_hw_get_frame_dur_for_bwmode or
592*4882a593Smuzhiyun 	 * ieee80211_generic_frame_duration for zero frame
593*4882a593Smuzhiyun 	 * length and without SIFS !
594*4882a593Smuzhiyun 	 *
595*4882a593Smuzhiyun 	 * Also we have different lowest rate for 802.11a
596*4882a593Smuzhiyun 	 */
597*4882a593Smuzhiyun 	if (channel->band == NL80211_BAND_5GHZ)
598*4882a593Smuzhiyun 		band = NL80211_BAND_5GHZ;
599*4882a593Smuzhiyun 	else
600*4882a593Smuzhiyun 		band = NL80211_BAND_2GHZ;
601*4882a593Smuzhiyun 
602*4882a593Smuzhiyun 	switch (ah->ah_bwmode) {
603*4882a593Smuzhiyun 	case AR5K_BWMODE_5MHZ:
604*4882a593Smuzhiyun 		rate_flags = IEEE80211_RATE_SUPPORTS_5MHZ;
605*4882a593Smuzhiyun 		break;
606*4882a593Smuzhiyun 	case AR5K_BWMODE_10MHZ:
607*4882a593Smuzhiyun 		rate_flags = IEEE80211_RATE_SUPPORTS_10MHZ;
608*4882a593Smuzhiyun 		break;
609*4882a593Smuzhiyun 	default:
610*4882a593Smuzhiyun 		rate_flags = 0;
611*4882a593Smuzhiyun 		break;
612*4882a593Smuzhiyun 	}
613*4882a593Smuzhiyun 	sband = &ah->sbands[band];
614*4882a593Smuzhiyun 	rate = NULL;
615*4882a593Smuzhiyun 	for (i = 0; i < sband->n_bitrates; i++) {
616*4882a593Smuzhiyun 		if ((rate_flags & sband->bitrates[i].flags) != rate_flags)
617*4882a593Smuzhiyun 			continue;
618*4882a593Smuzhiyun 		rate = &sband->bitrates[i];
619*4882a593Smuzhiyun 		break;
620*4882a593Smuzhiyun 	}
621*4882a593Smuzhiyun 	if (WARN_ON(!rate))
622*4882a593Smuzhiyun 		return -EINVAL;
623*4882a593Smuzhiyun 
624*4882a593Smuzhiyun 	ack_tx_time = ath5k_hw_get_frame_duration(ah, band, 10, rate, false);
625*4882a593Smuzhiyun 
626*4882a593Smuzhiyun 	/* ack_tx_time includes an SIFS already */
627*4882a593Smuzhiyun 	eifs = ack_tx_time + sifs + 2 * slot_time;
628*4882a593Smuzhiyun 	eifs_clock = ath5k_hw_htoclock(ah, eifs);
629*4882a593Smuzhiyun 
630*4882a593Smuzhiyun 	/* Set IFS settings on AR5210 */
631*4882a593Smuzhiyun 	if (ah->ah_version == AR5K_AR5210) {
632*4882a593Smuzhiyun 		u32 pifs, pifs_clock, difs, difs_clock;
633*4882a593Smuzhiyun 
634*4882a593Smuzhiyun 		/* Set slot time */
635*4882a593Smuzhiyun 		ath5k_hw_reg_write(ah, slot_time_clock, AR5K_SLOT_TIME);
636*4882a593Smuzhiyun 
637*4882a593Smuzhiyun 		/* Set EIFS */
638*4882a593Smuzhiyun 		eifs_clock = AR5K_REG_SM(eifs_clock, AR5K_IFS1_EIFS);
639*4882a593Smuzhiyun 
640*4882a593Smuzhiyun 		/* PIFS = Slot time + SIFS */
641*4882a593Smuzhiyun 		pifs = slot_time + sifs;
642*4882a593Smuzhiyun 		pifs_clock = ath5k_hw_htoclock(ah, pifs);
643*4882a593Smuzhiyun 		pifs_clock = AR5K_REG_SM(pifs_clock, AR5K_IFS1_PIFS);
644*4882a593Smuzhiyun 
645*4882a593Smuzhiyun 		/* DIFS = SIFS + 2 * Slot time */
646*4882a593Smuzhiyun 		difs = sifs + 2 * slot_time;
647*4882a593Smuzhiyun 		difs_clock = ath5k_hw_htoclock(ah, difs);
648*4882a593Smuzhiyun 
649*4882a593Smuzhiyun 		/* Set SIFS/DIFS */
650*4882a593Smuzhiyun 		ath5k_hw_reg_write(ah, (difs_clock <<
651*4882a593Smuzhiyun 				AR5K_IFS0_DIFS_S) | sifs_clock,
652*4882a593Smuzhiyun 				AR5K_IFS0);
653*4882a593Smuzhiyun 
654*4882a593Smuzhiyun 		/* Set PIFS/EIFS and preserve AR5K_INIT_CARR_SENSE_EN */
655*4882a593Smuzhiyun 		ath5k_hw_reg_write(ah, pifs_clock | eifs_clock |
656*4882a593Smuzhiyun 				(AR5K_INIT_CARR_SENSE_EN << AR5K_IFS1_CS_EN_S),
657*4882a593Smuzhiyun 				AR5K_IFS1);
658*4882a593Smuzhiyun 
659*4882a593Smuzhiyun 		return 0;
660*4882a593Smuzhiyun 	}
661*4882a593Smuzhiyun 
662*4882a593Smuzhiyun 	/* Set IFS slot time */
663*4882a593Smuzhiyun 	ath5k_hw_reg_write(ah, slot_time_clock, AR5K_DCU_GBL_IFS_SLOT);
664*4882a593Smuzhiyun 
665*4882a593Smuzhiyun 	/* Set EIFS interval */
666*4882a593Smuzhiyun 	ath5k_hw_reg_write(ah, eifs_clock, AR5K_DCU_GBL_IFS_EIFS);
667*4882a593Smuzhiyun 
668*4882a593Smuzhiyun 	/* Set SIFS interval in usecs */
669*4882a593Smuzhiyun 	AR5K_REG_WRITE_BITS(ah, AR5K_DCU_GBL_IFS_MISC,
670*4882a593Smuzhiyun 				AR5K_DCU_GBL_IFS_MISC_SIFS_DUR_USEC,
671*4882a593Smuzhiyun 				sifs);
672*4882a593Smuzhiyun 
673*4882a593Smuzhiyun 	/* Set SIFS interval in clock cycles */
674*4882a593Smuzhiyun 	ath5k_hw_reg_write(ah, sifs_clock, AR5K_DCU_GBL_IFS_SIFS);
675*4882a593Smuzhiyun 
676*4882a593Smuzhiyun 	return 0;
677*4882a593Smuzhiyun }
678*4882a593Smuzhiyun 
679*4882a593Smuzhiyun 
680*4882a593Smuzhiyun /**
681*4882a593Smuzhiyun  * ath5k_hw_init_queues() - Initialize tx queues
682*4882a593Smuzhiyun  * @ah: The &struct ath5k_hw
683*4882a593Smuzhiyun  *
684*4882a593Smuzhiyun  * Initializes all tx queues based on information on
685*4882a593Smuzhiyun  * ah->ah_txq* set by the driver
686*4882a593Smuzhiyun  */
687*4882a593Smuzhiyun int
ath5k_hw_init_queues(struct ath5k_hw * ah)688*4882a593Smuzhiyun ath5k_hw_init_queues(struct ath5k_hw *ah)
689*4882a593Smuzhiyun {
690*4882a593Smuzhiyun 	int i, ret;
691*4882a593Smuzhiyun 
692*4882a593Smuzhiyun 	/* TODO: HW Compression support for data queues */
693*4882a593Smuzhiyun 	/* TODO: Burst prefetch for data queues */
694*4882a593Smuzhiyun 
695*4882a593Smuzhiyun 	/*
696*4882a593Smuzhiyun 	 * Reset queues and start beacon timers at the end of the reset routine
697*4882a593Smuzhiyun 	 * This also sets QCU mask on each DCU for 1:1 qcu to dcu mapping
698*4882a593Smuzhiyun 	 * Note: If we want we can assign multiple qcus on one dcu.
699*4882a593Smuzhiyun 	 */
700*4882a593Smuzhiyun 	if (ah->ah_version != AR5K_AR5210)
701*4882a593Smuzhiyun 		for (i = 0; i < ah->ah_capabilities.cap_queues.q_tx_num; i++) {
702*4882a593Smuzhiyun 			ret = ath5k_hw_reset_tx_queue(ah, i);
703*4882a593Smuzhiyun 			if (ret) {
704*4882a593Smuzhiyun 				ATH5K_ERR(ah,
705*4882a593Smuzhiyun 					"failed to reset TX queue #%d\n", i);
706*4882a593Smuzhiyun 				return ret;
707*4882a593Smuzhiyun 			}
708*4882a593Smuzhiyun 		}
709*4882a593Smuzhiyun 	else
710*4882a593Smuzhiyun 		/* No QCU/DCU on AR5210, just set tx
711*4882a593Smuzhiyun 		 * retry limits. We set IFS parameters
712*4882a593Smuzhiyun 		 * on ath5k_hw_set_ifs_intervals */
713*4882a593Smuzhiyun 		ath5k_hw_set_tx_retry_limits(ah, 0);
714*4882a593Smuzhiyun 
715*4882a593Smuzhiyun 	/* Set the turbo flag when operating on 40MHz */
716*4882a593Smuzhiyun 	if (ah->ah_bwmode == AR5K_BWMODE_40MHZ)
717*4882a593Smuzhiyun 		AR5K_REG_ENABLE_BITS(ah, AR5K_DCU_GBL_IFS_MISC,
718*4882a593Smuzhiyun 				AR5K_DCU_GBL_IFS_MISC_TURBO_MODE);
719*4882a593Smuzhiyun 
720*4882a593Smuzhiyun 	/* If we didn't set IFS timings through
721*4882a593Smuzhiyun 	 * ath5k_hw_set_coverage_class make sure
722*4882a593Smuzhiyun 	 * we set them here */
723*4882a593Smuzhiyun 	if (!ah->ah_coverage_class) {
724*4882a593Smuzhiyun 		unsigned int slot_time = ath5k_hw_get_default_slottime(ah);
725*4882a593Smuzhiyun 		ath5k_hw_set_ifs_intervals(ah, slot_time);
726*4882a593Smuzhiyun 	}
727*4882a593Smuzhiyun 
728*4882a593Smuzhiyun 	return 0;
729*4882a593Smuzhiyun }
730