• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6/drivers/net/wireless/ath/ath5k/
1/*
2 * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
3 * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 *
17 */
18
19/********************************************\
20Queue Control Unit, DFS Control Unit Functions
21\********************************************/
22
23#include "ath5k.h"
24#include "reg.h"
25#include "debug.h"
26#include "base.h"
27
28/*
29 * Get properties for a transmit queue
30 */
31int ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue,
32		struct ath5k_txq_info *queue_info)
33{
34	memcpy(queue_info, &ah->ah_txq[queue], sizeof(struct ath5k_txq_info));
35	return 0;
36}
37
38/*
39 * Set properties for a transmit queue
40 */
41int ath5k_hw_set_tx_queueprops(struct ath5k_hw *ah, int queue,
42				const struct ath5k_txq_info *queue_info)
43{
44	AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
45
46	if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE)
47		return -EIO;
48
49	memcpy(&ah->ah_txq[queue], queue_info, sizeof(struct ath5k_txq_info));
50
51	if ((queue_info->tqi_type == AR5K_TX_QUEUE_DATA &&
52			((queue_info->tqi_subtype == AR5K_WME_AC_VI) ||
53			(queue_info->tqi_subtype == AR5K_WME_AC_VO))) ||
54			queue_info->tqi_type == AR5K_TX_QUEUE_UAPSD)
55		ah->ah_txq[queue].tqi_flags |= AR5K_TXQ_FLAG_POST_FR_BKOFF_DIS;
56
57	return 0;
58}
59
60/*
61 * Initialize a transmit queue
62 */
63int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type,
64		struct ath5k_txq_info *queue_info)
65{
66	unsigned int queue;
67	int ret;
68
69	/*
70	 * Get queue by type
71	 */
72	/*5210 only has 2 queues*/
73	if (ah->ah_version == AR5K_AR5210) {
74		switch (queue_type) {
75		case AR5K_TX_QUEUE_DATA:
76			queue = AR5K_TX_QUEUE_ID_NOQCU_DATA;
77			break;
78		case AR5K_TX_QUEUE_BEACON:
79		case AR5K_TX_QUEUE_CAB:
80			queue = AR5K_TX_QUEUE_ID_NOQCU_BEACON;
81			break;
82		default:
83			return -EINVAL;
84		}
85	} else {
86		switch (queue_type) {
87		case AR5K_TX_QUEUE_DATA:
88			for (queue = AR5K_TX_QUEUE_ID_DATA_MIN;
89				ah->ah_txq[queue].tqi_type !=
90				AR5K_TX_QUEUE_INACTIVE; queue++) {
91
92				if (queue > AR5K_TX_QUEUE_ID_DATA_MAX)
93					return -EINVAL;
94			}
95			break;
96		case AR5K_TX_QUEUE_UAPSD:
97			queue = AR5K_TX_QUEUE_ID_UAPSD;
98			break;
99		case AR5K_TX_QUEUE_BEACON:
100			queue = AR5K_TX_QUEUE_ID_BEACON;
101			break;
102		case AR5K_TX_QUEUE_CAB:
103			queue = AR5K_TX_QUEUE_ID_CAB;
104			break;
105		case AR5K_TX_QUEUE_XR_DATA:
106			if (ah->ah_version != AR5K_AR5212)
107				ATH5K_ERR(ah->ah_sc,
108					"XR data queues only supported in"
109					" 5212!\n");
110			queue = AR5K_TX_QUEUE_ID_XR_DATA;
111			break;
112		default:
113			return -EINVAL;
114		}
115	}
116
117	/*
118	 * Setup internal queue structure
119	 */
120	memset(&ah->ah_txq[queue], 0, sizeof(struct ath5k_txq_info));
121	ah->ah_txq[queue].tqi_type = queue_type;
122
123	if (queue_info != NULL) {
124		queue_info->tqi_type = queue_type;
125		ret = ath5k_hw_set_tx_queueprops(ah, queue, queue_info);
126		if (ret)
127			return ret;
128	}
129
130	/*
131	 * We use ah_txq_status to hold a temp value for
132	 * the Secondary interrupt mask registers on 5211+
133	 * check out ath5k_hw_reset_tx_queue
134	 */
135	AR5K_Q_ENABLE_BITS(ah->ah_txq_status, queue);
136
137	return queue;
138}
139
140/*
141 * Get number of pending frames
142 * for a specific queue [5211+]
143 */
144u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue)
145{
146	u32 pending;
147	AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
148
149	/* Return if queue is declared inactive */
150	if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE)
151		return false;
152
153	if (ah->ah_version == AR5K_AR5210)
154		return false;
155
156	pending = ath5k_hw_reg_read(ah, AR5K_QUEUE_STATUS(queue));
157	pending &= AR5K_QCU_STS_FRMPENDCNT;
158
159	/* It's possible to have no frames pending even if TXE
160	 * is set. To indicate that q has not stopped return
161	 * true */
162	if (!pending && AR5K_REG_READ_Q(ah, AR5K_QCU_TXE, queue))
163		return true;
164
165	return pending;
166}
167
168/*
169 * Set a transmit queue inactive
170 */
171void ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue)
172{
173	if (WARN_ON(queue >= ah->ah_capabilities.cap_queues.q_tx_num))
174		return;
175
176	/* This queue will be skipped in further operations */
177	ah->ah_txq[queue].tqi_type = AR5K_TX_QUEUE_INACTIVE;
178	/*For SIMR setup*/
179	AR5K_Q_DISABLE_BITS(ah->ah_txq_status, queue);
180}
181
182/*
183 * Set DFS properties for a transmit queue on DCU
184 */
185int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
186{
187	u32 cw_min, cw_max, retry_lg, retry_sh;
188	struct ath5k_txq_info *tq = &ah->ah_txq[queue];
189
190	AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
191
192	tq = &ah->ah_txq[queue];
193
194	if (tq->tqi_type == AR5K_TX_QUEUE_INACTIVE)
195		return 0;
196
197	if (ah->ah_version == AR5K_AR5210) {
198		/* Only handle data queues, others will be ignored */
199		if (tq->tqi_type != AR5K_TX_QUEUE_DATA)
200			return 0;
201
202		/* Set Slot time */
203		ath5k_hw_reg_write(ah, ah->ah_turbo ?
204			AR5K_INIT_SLOT_TIME_TURBO : AR5K_INIT_SLOT_TIME,
205			AR5K_SLOT_TIME);
206		/* Set ACK_CTS timeout */
207		ath5k_hw_reg_write(ah, ah->ah_turbo ?
208			AR5K_INIT_ACK_CTS_TIMEOUT_TURBO :
209			AR5K_INIT_ACK_CTS_TIMEOUT, AR5K_SLOT_TIME);
210		/* Set Transmit Latency */
211		ath5k_hw_reg_write(ah, ah->ah_turbo ?
212			AR5K_INIT_TRANSMIT_LATENCY_TURBO :
213			AR5K_INIT_TRANSMIT_LATENCY, AR5K_USEC_5210);
214
215		/* Set IFS0 */
216		if (ah->ah_turbo) {
217			 ath5k_hw_reg_write(ah, ((AR5K_INIT_SIFS_TURBO +
218				(ah->ah_aifs + tq->tqi_aifs) *
219				AR5K_INIT_SLOT_TIME_TURBO) <<
220				AR5K_IFS0_DIFS_S) | AR5K_INIT_SIFS_TURBO,
221				AR5K_IFS0);
222		} else {
223			ath5k_hw_reg_write(ah, ((AR5K_INIT_SIFS +
224				(ah->ah_aifs + tq->tqi_aifs) *
225				AR5K_INIT_SLOT_TIME) << AR5K_IFS0_DIFS_S) |
226				AR5K_INIT_SIFS, AR5K_IFS0);
227		}
228
229		/* Set IFS1 */
230		ath5k_hw_reg_write(ah, ah->ah_turbo ?
231			AR5K_INIT_PROTO_TIME_CNTRL_TURBO :
232			AR5K_INIT_PROTO_TIME_CNTRL, AR5K_IFS1);
233		/* Set AR5K_PHY_SETTLING */
234		ath5k_hw_reg_write(ah, ah->ah_turbo ?
235			(ath5k_hw_reg_read(ah, AR5K_PHY_SETTLING) & ~0x7F)
236			| 0x38 :
237			(ath5k_hw_reg_read(ah, AR5K_PHY_SETTLING) & ~0x7F)
238			| 0x1C,
239			AR5K_PHY_SETTLING);
240		/* Set Frame Control Register */
241		ath5k_hw_reg_write(ah, ah->ah_turbo ?
242			(AR5K_PHY_FRAME_CTL_INI | AR5K_PHY_TURBO_MODE |
243			AR5K_PHY_TURBO_SHORT | 0x2020) :
244			(AR5K_PHY_FRAME_CTL_INI | 0x1020),
245			AR5K_PHY_FRAME_CTL_5210);
246	}
247
248	/*
249	 * Calculate cwmin/max by channel mode
250	 */
251	cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN;
252	cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX;
253	ah->ah_aifs = AR5K_TUNE_AIFS;
254	/*XR is only supported on 5212*/
255	if (IS_CHAN_XR(ah->ah_current_channel) &&
256			ah->ah_version == AR5K_AR5212) {
257		cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN_XR;
258		cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX_XR;
259		ah->ah_aifs = AR5K_TUNE_AIFS_XR;
260	/*B mode is not supported on 5210*/
261	} else if (IS_CHAN_B(ah->ah_current_channel) &&
262			ah->ah_version != AR5K_AR5210) {
263		cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN_11B;
264		cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX_11B;
265		ah->ah_aifs = AR5K_TUNE_AIFS_11B;
266	}
267
268	cw_min = 1;
269	while (cw_min < ah->ah_cw_min)
270		cw_min = (cw_min << 1) | 1;
271
272	cw_min = tq->tqi_cw_min < 0 ? (cw_min >> (-tq->tqi_cw_min)) :
273		((cw_min << tq->tqi_cw_min) + (1 << tq->tqi_cw_min) - 1);
274	cw_max = tq->tqi_cw_max < 0 ? (cw_max >> (-tq->tqi_cw_max)) :
275		((cw_max << tq->tqi_cw_max) + (1 << tq->tqi_cw_max) - 1);
276
277	/*
278	 * Calculate and set retry limits
279	 */
280	if (ah->ah_software_retry) {
281		retry_lg = ah->ah_limit_tx_retries;
282		retry_sh = retry_lg = retry_lg > AR5K_DCU_RETRY_LMT_SH_RETRY ?
283			AR5K_DCU_RETRY_LMT_SH_RETRY : retry_lg;
284	} else {
285		retry_lg = AR5K_INIT_LG_RETRY;
286		retry_sh = AR5K_INIT_SH_RETRY;
287	}
288
289	/*No QCU/DCU [5210]*/
290	if (ah->ah_version == AR5K_AR5210) {
291		ath5k_hw_reg_write(ah,
292			(cw_min << AR5K_NODCU_RETRY_LMT_CW_MIN_S)
293			| AR5K_REG_SM(AR5K_INIT_SLG_RETRY,
294				AR5K_NODCU_RETRY_LMT_SLG_RETRY)
295			| AR5K_REG_SM(AR5K_INIT_SSH_RETRY,
296				AR5K_NODCU_RETRY_LMT_SSH_RETRY)
297			| AR5K_REG_SM(retry_lg, AR5K_NODCU_RETRY_LMT_LG_RETRY)
298			| AR5K_REG_SM(retry_sh, AR5K_NODCU_RETRY_LMT_SH_RETRY),
299			AR5K_NODCU_RETRY_LMT);
300	} else {
301		/*QCU/DCU [5211+]*/
302		ath5k_hw_reg_write(ah,
303			AR5K_REG_SM(AR5K_INIT_SLG_RETRY,
304				AR5K_DCU_RETRY_LMT_SLG_RETRY) |
305			AR5K_REG_SM(AR5K_INIT_SSH_RETRY,
306				AR5K_DCU_RETRY_LMT_SSH_RETRY) |
307			AR5K_REG_SM(retry_lg, AR5K_DCU_RETRY_LMT_LG_RETRY) |
308			AR5K_REG_SM(retry_sh, AR5K_DCU_RETRY_LMT_SH_RETRY),
309			AR5K_QUEUE_DFS_RETRY_LIMIT(queue));
310
311	/*===Rest is also for QCU/DCU only [5211+]===*/
312
313		/*
314		 * Set initial content window (cw_min/cw_max)
315		 * and arbitrated interframe space (aifs)...
316		 */
317		ath5k_hw_reg_write(ah,
318			AR5K_REG_SM(cw_min, AR5K_DCU_LCL_IFS_CW_MIN) |
319			AR5K_REG_SM(cw_max, AR5K_DCU_LCL_IFS_CW_MAX) |
320			AR5K_REG_SM(ah->ah_aifs + tq->tqi_aifs,
321				AR5K_DCU_LCL_IFS_AIFS),
322			AR5K_QUEUE_DFS_LOCAL_IFS(queue));
323
324		/*
325		 * Set misc registers
326		 */
327		/* Enable DCU early termination for this queue */
328		AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
329					AR5K_QCU_MISC_DCU_EARLY);
330
331		/* Enable DCU to wait for next fragment from QCU */
332		AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
333					AR5K_DCU_MISC_FRAG_WAIT);
334
335		/* On Maui and Spirit use the global seqnum on DCU */
336		if (ah->ah_mac_version < AR5K_SREV_AR5211)
337			AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
338						AR5K_DCU_MISC_SEQNUM_CTL);
339
340		if (tq->tqi_cbr_period) {
341			ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_cbr_period,
342				AR5K_QCU_CBRCFG_INTVAL) |
343				AR5K_REG_SM(tq->tqi_cbr_overflow_limit,
344				AR5K_QCU_CBRCFG_ORN_THRES),
345				AR5K_QUEUE_CBRCFG(queue));
346			AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
347				AR5K_QCU_MISC_FRSHED_CBR);
348			if (tq->tqi_cbr_overflow_limit)
349				AR5K_REG_ENABLE_BITS(ah,
350					AR5K_QUEUE_MISC(queue),
351					AR5K_QCU_MISC_CBR_THRES_ENABLE);
352		}
353
354		if (tq->tqi_ready_time &&
355		(tq->tqi_type != AR5K_TX_QUEUE_CAB))
356			ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_ready_time,
357				AR5K_QCU_RDYTIMECFG_INTVAL) |
358				AR5K_QCU_RDYTIMECFG_ENABLE,
359				AR5K_QUEUE_RDYTIMECFG(queue));
360
361		if (tq->tqi_burst_time) {
362			ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_burst_time,
363				AR5K_DCU_CHAN_TIME_DUR) |
364				AR5K_DCU_CHAN_TIME_ENABLE,
365				AR5K_QUEUE_DFS_CHANNEL_TIME(queue));
366
367			if (tq->tqi_flags
368			& AR5K_TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE)
369				AR5K_REG_ENABLE_BITS(ah,
370					AR5K_QUEUE_MISC(queue),
371					AR5K_QCU_MISC_RDY_VEOL_POLICY);
372		}
373
374		if (tq->tqi_flags & AR5K_TXQ_FLAG_BACKOFF_DISABLE)
375			ath5k_hw_reg_write(ah, AR5K_DCU_MISC_POST_FR_BKOFF_DIS,
376				AR5K_QUEUE_DFS_MISC(queue));
377
378		if (tq->tqi_flags & AR5K_TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE)
379			ath5k_hw_reg_write(ah, AR5K_DCU_MISC_BACKOFF_FRAG,
380				AR5K_QUEUE_DFS_MISC(queue));
381
382		/*
383		 * Set registers by queue type
384		 */
385		switch (tq->tqi_type) {
386		case AR5K_TX_QUEUE_BEACON:
387			AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
388				AR5K_QCU_MISC_FRSHED_DBA_GT |
389				AR5K_QCU_MISC_CBREXP_BCN_DIS |
390				AR5K_QCU_MISC_BCN_ENABLE);
391
392			AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
393				(AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL <<
394				AR5K_DCU_MISC_ARBLOCK_CTL_S) |
395				AR5K_DCU_MISC_ARBLOCK_IGNORE |
396				AR5K_DCU_MISC_POST_FR_BKOFF_DIS |
397				AR5K_DCU_MISC_BCN_ENABLE);
398			break;
399
400		case AR5K_TX_QUEUE_CAB:
401			AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
402				AR5K_QCU_MISC_FRSHED_DBA_GT |
403				AR5K_QCU_MISC_CBREXP_DIS |
404				AR5K_QCU_MISC_CBREXP_BCN_DIS);
405
406			ath5k_hw_reg_write(ah, ((tq->tqi_ready_time -
407				(AR5K_TUNE_SW_BEACON_RESP -
408				AR5K_TUNE_DMA_BEACON_RESP) -
409				AR5K_TUNE_ADDITIONAL_SWBA_BACKOFF) * 1024) |
410				AR5K_QCU_RDYTIMECFG_ENABLE,
411				AR5K_QUEUE_RDYTIMECFG(queue));
412
413			AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
414				(AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL <<
415				AR5K_DCU_MISC_ARBLOCK_CTL_S));
416			break;
417
418		case AR5K_TX_QUEUE_UAPSD:
419			AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
420				AR5K_QCU_MISC_CBREXP_DIS);
421			break;
422
423		case AR5K_TX_QUEUE_DATA:
424		default:
425			break;
426		}
427
428		/* TODO: Handle frame compression */
429
430		/*
431		 * Enable interrupts for this tx queue
432		 * in the secondary interrupt mask registers
433		 */
434		if (tq->tqi_flags & AR5K_TXQ_FLAG_TXOKINT_ENABLE)
435			AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txok, queue);
436
437		if (tq->tqi_flags & AR5K_TXQ_FLAG_TXERRINT_ENABLE)
438			AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txerr, queue);
439
440		if (tq->tqi_flags & AR5K_TXQ_FLAG_TXURNINT_ENABLE)
441			AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txurn, queue);
442
443		if (tq->tqi_flags & AR5K_TXQ_FLAG_TXDESCINT_ENABLE)
444			AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txdesc, queue);
445
446		if (tq->tqi_flags & AR5K_TXQ_FLAG_TXEOLINT_ENABLE)
447			AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txeol, queue);
448
449		if (tq->tqi_flags & AR5K_TXQ_FLAG_CBRORNINT_ENABLE)
450			AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_cbrorn, queue);
451
452		if (tq->tqi_flags & AR5K_TXQ_FLAG_CBRURNINT_ENABLE)
453			AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_cbrurn, queue);
454
455		if (tq->tqi_flags & AR5K_TXQ_FLAG_QTRIGINT_ENABLE)
456			AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_qtrig, queue);
457
458		if (tq->tqi_flags & AR5K_TXQ_FLAG_TXNOFRMINT_ENABLE)
459			AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_nofrm, queue);
460
461		/* Update secondary interrupt mask registers */
462
463		/* Filter out inactive queues */
464		ah->ah_txq_imr_txok &= ah->ah_txq_status;
465		ah->ah_txq_imr_txerr &= ah->ah_txq_status;
466		ah->ah_txq_imr_txurn &= ah->ah_txq_status;
467		ah->ah_txq_imr_txdesc &= ah->ah_txq_status;
468		ah->ah_txq_imr_txeol &= ah->ah_txq_status;
469		ah->ah_txq_imr_cbrorn &= ah->ah_txq_status;
470		ah->ah_txq_imr_cbrurn &= ah->ah_txq_status;
471		ah->ah_txq_imr_qtrig &= ah->ah_txq_status;
472		ah->ah_txq_imr_nofrm &= ah->ah_txq_status;
473
474		ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txok,
475			AR5K_SIMR0_QCU_TXOK) |
476			AR5K_REG_SM(ah->ah_txq_imr_txdesc,
477			AR5K_SIMR0_QCU_TXDESC), AR5K_SIMR0);
478		ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txerr,
479			AR5K_SIMR1_QCU_TXERR) |
480			AR5K_REG_SM(ah->ah_txq_imr_txeol,
481			AR5K_SIMR1_QCU_TXEOL), AR5K_SIMR1);
482		/* Update simr2 but don't overwrite rest simr2 settings */
483		AR5K_REG_DISABLE_BITS(ah, AR5K_SIMR2, AR5K_SIMR2_QCU_TXURN);
484		AR5K_REG_ENABLE_BITS(ah, AR5K_SIMR2,
485			AR5K_REG_SM(ah->ah_txq_imr_txurn,
486			AR5K_SIMR2_QCU_TXURN));
487		ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_cbrorn,
488			AR5K_SIMR3_QCBRORN) |
489			AR5K_REG_SM(ah->ah_txq_imr_cbrurn,
490			AR5K_SIMR3_QCBRURN), AR5K_SIMR3);
491		ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_qtrig,
492			AR5K_SIMR4_QTRIG), AR5K_SIMR4);
493		/* Set TXNOFRM_QCU for the queues with TXNOFRM enabled */
494		ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_nofrm,
495			AR5K_TXNOFRM_QCU), AR5K_TXNOFRM);
496		/* No queue has TXNOFRM enabled, disable the interrupt
497		 * by setting AR5K_TXNOFRM to zero */
498		if (ah->ah_txq_imr_nofrm == 0)
499			ath5k_hw_reg_write(ah, 0, AR5K_TXNOFRM);
500
501		/* Set QCU mask for this DCU to save power */
502		AR5K_REG_WRITE_Q(ah, AR5K_QUEUE_QCUMASK(queue), queue);
503	}
504
505	return 0;
506}
507
508/*
509 * Set slot time on DCU
510 */
511int ath5k_hw_set_slot_time(struct ath5k_hw *ah, unsigned int slot_time)
512{
513	u32 slot_time_clock = ath5k_hw_htoclock(ah, slot_time);
514
515	if (slot_time < 6 || slot_time_clock > AR5K_SLOT_TIME_MAX)
516		return -EINVAL;
517
518	if (ah->ah_version == AR5K_AR5210)
519		ath5k_hw_reg_write(ah, slot_time_clock, AR5K_SLOT_TIME);
520	else
521		ath5k_hw_reg_write(ah, slot_time_clock, AR5K_DCU_GBL_IFS_SLOT);
522
523	return 0;
524}
525