aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath5k/qcu.c
diff options
context:
space:
mode:
authorNick Kossifidis <mick@madwifi.org>2008-08-29 15:45:39 -0400
committerJohn W. Linville <linville@tuxdriver.com>2008-09-05 16:15:24 -0400
commitc6e387a214f4b2c4bd48020409e366c133385d98 (patch)
tree11fd58fd71e113a62d05f6f191771ca3d7d544f0 /drivers/net/wireless/ath5k/qcu.c
parentfa9abe050d0a018b888fce61a4353afab17b0860 (diff)
ath5k: HW code cleanup
* No code changes... * Split hw.c to multiple files for better maintenance and add some documentation on each file code is going to grow soon (eeprom.c for example is going to get much stuff currently developed on ath_info) so it's better this way. * Rename following functions to maintain naming scheme: ah_setup_xtx_desc -> ah_setup_mrr_tx_desc (Because xtx doesn't say much, it's actually a multi-rate-retry tx descriptor) ath5k_hw_put_tx/rx_buf - > ath5k_hw_set_tx/rxdp ath5k_hw_get_tx/rx_buf -> ath5k_hw_get_tx/rxdp (We don't put any "buf" we set descriptor pointers on hw) ath5k_hw_tx_start -> ath5k_hw_start_tx_dma ath5k_hw_start_rx -> ath5k_hw_start_rx_dma ath5k_hw_stop_pcu_recv -> ath5k_hw_stop_rx_pcu (It's easier this way to identify them, we also have ath5k_hw_start_rx_pcu which completes the set) ath5k_hw_set_intr -> ath5k_hw_set_imr (As in get_isr we set imr here, not "intr") * Move ath5k_hw_setup_rx_desc on ah->ah_setup_rx_desc so we can include support for different rx descriptors in the future * Further cleanups so that checkpatch doesn't complain (only some > 80 col warnings for eeprom.h and reg.h as usual due to comments) Tested on 5211 and 5213 cards and works ok. Changes-licensed-under: ISC Signed-off-by: Nick Kossifidis <mickflemm@gmail.com> Acked-by: Luis R. Rodriguez <lrodriguez@atheros.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ath5k/qcu.c')
-rw-r--r--drivers/net/wireless/ath5k/qcu.c488
1 files changed, 488 insertions, 0 deletions
diff --git a/drivers/net/wireless/ath5k/qcu.c b/drivers/net/wireless/ath5k/qcu.c
new file mode 100644
index 00000000000..2e20f7816ca
--- /dev/null
+++ b/drivers/net/wireless/ath5k/qcu.c
@@ -0,0 +1,488 @@
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 ATH5K_TRACE(ah->ah_sc);
35 memcpy(queue_info, &ah->ah_txq[queue], sizeof(struct ath5k_txq_info));
36 return 0;
37}
38
39/*
40 * Set properties for a transmit queue
41 */
42int ath5k_hw_set_tx_queueprops(struct ath5k_hw *ah, int queue,
43 const struct ath5k_txq_info *queue_info)
44{
45 ATH5K_TRACE(ah->ah_sc);
46 AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
47
48 if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE)
49 return -EIO;
50
51 memcpy(&ah->ah_txq[queue], queue_info, sizeof(struct ath5k_txq_info));
52
53 /*XXX: Is this supported on 5210 ?*/
54 if ((queue_info->tqi_type == AR5K_TX_QUEUE_DATA &&
55 ((queue_info->tqi_subtype == AR5K_WME_AC_VI) ||
56 (queue_info->tqi_subtype == AR5K_WME_AC_VO))) ||
57 queue_info->tqi_type == AR5K_TX_QUEUE_UAPSD)
58 ah->ah_txq[queue].tqi_flags |= AR5K_TXQ_FLAG_POST_FR_BKOFF_DIS;
59
60 return 0;
61}
62
63/*
64 * Initialize a transmit queue
65 */
66int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type,
67 struct ath5k_txq_info *queue_info)
68{
69 unsigned int queue;
70 int ret;
71
72 ATH5K_TRACE(ah->ah_sc);
73
74 /*
75 * Get queue by type
76 */
77 /*5210 only has 2 queues*/
78 if (ah->ah_version == AR5K_AR5210) {
79 switch (queue_type) {
80 case AR5K_TX_QUEUE_DATA:
81 queue = AR5K_TX_QUEUE_ID_NOQCU_DATA;
82 break;
83 case AR5K_TX_QUEUE_BEACON:
84 case AR5K_TX_QUEUE_CAB:
85 queue = AR5K_TX_QUEUE_ID_NOQCU_BEACON;
86 break;
87 default:
88 return -EINVAL;
89 }
90 } else {
91 switch (queue_type) {
92 case AR5K_TX_QUEUE_DATA:
93 for (queue = AR5K_TX_QUEUE_ID_DATA_MIN;
94 ah->ah_txq[queue].tqi_type !=
95 AR5K_TX_QUEUE_INACTIVE; queue++) {
96
97 if (queue > AR5K_TX_QUEUE_ID_DATA_MAX)
98 return -EINVAL;
99 }
100 break;
101 case AR5K_TX_QUEUE_UAPSD:
102 queue = AR5K_TX_QUEUE_ID_UAPSD;
103 break;
104 case AR5K_TX_QUEUE_BEACON:
105 queue = AR5K_TX_QUEUE_ID_BEACON;
106 break;
107 case AR5K_TX_QUEUE_CAB:
108 queue = AR5K_TX_QUEUE_ID_CAB;
109 break;
110 case AR5K_TX_QUEUE_XR_DATA:
111 if (ah->ah_version != AR5K_AR5212)
112 ATH5K_ERR(ah->ah_sc,
113 "XR data queues only supported in"
114 " 5212!\n");
115 queue = AR5K_TX_QUEUE_ID_XR_DATA;
116 break;
117 default:
118 return -EINVAL;
119 }
120 }
121
122 /*
123 * Setup internal queue structure
124 */
125 memset(&ah->ah_txq[queue], 0, sizeof(struct ath5k_txq_info));
126 ah->ah_txq[queue].tqi_type = queue_type;
127
128 if (queue_info != NULL) {
129 queue_info->tqi_type = queue_type;
130 ret = ath5k_hw_set_tx_queueprops(ah, queue, queue_info);
131 if (ret)
132 return ret;
133 }
134
135 /*
136 * We use ah_txq_status to hold a temp value for
137 * the Secondary interrupt mask registers on 5211+
138 * check out ath5k_hw_reset_tx_queue
139 */
140 AR5K_Q_ENABLE_BITS(ah->ah_txq_status, queue);
141
142 return queue;
143}
144
145/*
146 * Get number of pending frames
147 * for a specific queue [5211+]
148 */
149u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue)
150{
151 ATH5K_TRACE(ah->ah_sc);
152 AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
153
154 /* Return if queue is declared inactive */
155 if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE)
156 return false;
157
158 /* XXX: How about AR5K_CFG_TXCNT ? */
159 if (ah->ah_version == AR5K_AR5210)
160 return false;
161
162 return AR5K_QUEUE_STATUS(queue) & AR5K_QCU_STS_FRMPENDCNT;
163}
164
165/*
166 * Set a transmit queue inactive
167 */
168void ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue)
169{
170 ATH5K_TRACE(ah->ah_sc);
171 if (WARN_ON(queue >= ah->ah_capabilities.cap_queues.q_tx_num))
172 return;
173
174 /* This queue will be skipped in further operations */
175 ah->ah_txq[queue].tqi_type = AR5K_TX_QUEUE_INACTIVE;
176 /*For SIMR setup*/
177 AR5K_Q_DISABLE_BITS(ah->ah_txq_status, queue);
178}
179
180/*
181 * Set DFS properties for a transmit queue on DCU
182 */
183int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
184{
185 u32 cw_min, cw_max, retry_lg, retry_sh;
186 struct ath5k_txq_info *tq = &ah->ah_txq[queue];
187
188 ATH5K_TRACE(ah->ah_sc);
189 AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
190
191 tq = &ah->ah_txq[queue];
192
193 if (tq->tqi_type == AR5K_TX_QUEUE_INACTIVE)
194 return 0;
195
196 if (ah->ah_version == AR5K_AR5210) {
197 /* Only handle data queues, others will be ignored */
198 if (tq->tqi_type != AR5K_TX_QUEUE_DATA)
199 return 0;
200
201 /* Set Slot time */
202 ath5k_hw_reg_write(ah, ah->ah_turbo ?
203 AR5K_INIT_SLOT_TIME_TURBO : AR5K_INIT_SLOT_TIME,
204 AR5K_SLOT_TIME);
205 /* Set ACK_CTS timeout */
206 ath5k_hw_reg_write(ah, ah->ah_turbo ?
207 AR5K_INIT_ACK_CTS_TIMEOUT_TURBO :
208 AR5K_INIT_ACK_CTS_TIMEOUT, AR5K_SLOT_TIME);
209 /* Set Transmit Latency */
210 ath5k_hw_reg_write(ah, ah->ah_turbo ?
211 AR5K_INIT_TRANSMIT_LATENCY_TURBO :
212 AR5K_INIT_TRANSMIT_LATENCY, AR5K_USEC_5210);
213
214 /* Set IFS0 */
215 if (ah->ah_turbo) {
216 ath5k_hw_reg_write(ah, ((AR5K_INIT_SIFS_TURBO +
217 (ah->ah_aifs + tq->tqi_aifs) *
218 AR5K_INIT_SLOT_TIME_TURBO) <<
219 AR5K_IFS0_DIFS_S) | AR5K_INIT_SIFS_TURBO,
220 AR5K_IFS0);
221 } else {
222 ath5k_hw_reg_write(ah, ((AR5K_INIT_SIFS +
223 (ah->ah_aifs + tq->tqi_aifs) *
224 AR5K_INIT_SLOT_TIME) << AR5K_IFS0_DIFS_S) |
225 AR5K_INIT_SIFS, AR5K_IFS0);
226 }
227
228 /* Set IFS1 */
229 ath5k_hw_reg_write(ah, ah->ah_turbo ?
230 AR5K_INIT_PROTO_TIME_CNTRL_TURBO :
231 AR5K_INIT_PROTO_TIME_CNTRL, AR5K_IFS1);
232 /* Set AR5K_PHY_SETTLING */
233 ath5k_hw_reg_write(ah, ah->ah_turbo ?
234 (ath5k_hw_reg_read(ah, AR5K_PHY_SETTLING) & ~0x7F)
235 | 0x38 :
236 (ath5k_hw_reg_read(ah, AR5K_PHY_SETTLING) & ~0x7F)
237 | 0x1C,
238 AR5K_PHY_SETTLING);
239 /* Set Frame Control Register */
240 ath5k_hw_reg_write(ah, ah->ah_turbo ?
241 (AR5K_PHY_FRAME_CTL_INI | AR5K_PHY_TURBO_MODE |
242 AR5K_PHY_TURBO_SHORT | 0x2020) :
243 (AR5K_PHY_FRAME_CTL_INI | 0x1020),
244 AR5K_PHY_FRAME_CTL_5210);
245 }
246
247 /*
248 * Calculate cwmin/max by channel mode
249 */
250 cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN;
251 cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX;
252 ah->ah_aifs = AR5K_TUNE_AIFS;
253 /*XR is only supported on 5212*/
254 if (IS_CHAN_XR(ah->ah_current_channel) &&
255 ah->ah_version == AR5K_AR5212) {
256 cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN_XR;
257 cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX_XR;
258 ah->ah_aifs = AR5K_TUNE_AIFS_XR;
259 /*B mode is not supported on 5210*/
260 } else if (IS_CHAN_B(ah->ah_current_channel) &&
261 ah->ah_version != AR5K_AR5210) {
262 cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN_11B;
263 cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX_11B;
264 ah->ah_aifs = AR5K_TUNE_AIFS_11B;
265 }
266
267 cw_min = 1;
268 while (cw_min < ah->ah_cw_min)
269 cw_min = (cw_min << 1) | 1;
270
271 cw_min = tq->tqi_cw_min < 0 ? (cw_min >> (-tq->tqi_cw_min)) :
272 ((cw_min << tq->tqi_cw_min) + (1 << tq->tqi_cw_min) - 1);
273 cw_max = tq->tqi_cw_max < 0 ? (cw_max >> (-tq->tqi_cw_max)) :
274 ((cw_max << tq->tqi_cw_max) + (1 << tq->tqi_cw_max) - 1);
275
276 /*
277 * Calculate and set retry limits
278 */
279 if (ah->ah_software_retry) {
280 /* XXX Need to test this */
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 ath5k_hw_reg_write(ah, AR5K_QCU_MISC_DCU_EARLY,
328 AR5K_QUEUE_MISC(queue));
329
330 if (tq->tqi_cbr_period) {
331 ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_cbr_period,
332 AR5K_QCU_CBRCFG_INTVAL) |
333 AR5K_REG_SM(tq->tqi_cbr_overflow_limit,
334 AR5K_QCU_CBRCFG_ORN_THRES),
335 AR5K_QUEUE_CBRCFG(queue));
336 AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
337 AR5K_QCU_MISC_FRSHED_CBR);
338 if (tq->tqi_cbr_overflow_limit)
339 AR5K_REG_ENABLE_BITS(ah,
340 AR5K_QUEUE_MISC(queue),
341 AR5K_QCU_MISC_CBR_THRES_ENABLE);
342 }
343
344 if (tq->tqi_ready_time)
345 ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_ready_time,
346 AR5K_QCU_RDYTIMECFG_INTVAL) |
347 AR5K_QCU_RDYTIMECFG_ENABLE,
348 AR5K_QUEUE_RDYTIMECFG(queue));
349
350 if (tq->tqi_burst_time) {
351 ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_burst_time,
352 AR5K_DCU_CHAN_TIME_DUR) |
353 AR5K_DCU_CHAN_TIME_ENABLE,
354 AR5K_QUEUE_DFS_CHANNEL_TIME(queue));
355
356 if (tq->tqi_flags
357 & AR5K_TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE)
358 AR5K_REG_ENABLE_BITS(ah,
359 AR5K_QUEUE_MISC(queue),
360 AR5K_QCU_MISC_RDY_VEOL_POLICY);
361 }
362
363 if (tq->tqi_flags & AR5K_TXQ_FLAG_BACKOFF_DISABLE)
364 ath5k_hw_reg_write(ah, AR5K_DCU_MISC_POST_FR_BKOFF_DIS,
365 AR5K_QUEUE_DFS_MISC(queue));
366
367 if (tq->tqi_flags & AR5K_TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE)
368 ath5k_hw_reg_write(ah, AR5K_DCU_MISC_BACKOFF_FRAG,
369 AR5K_QUEUE_DFS_MISC(queue));
370
371 /*
372 * Set registers by queue type
373 */
374 switch (tq->tqi_type) {
375 case AR5K_TX_QUEUE_BEACON:
376 AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
377 AR5K_QCU_MISC_FRSHED_DBA_GT |
378 AR5K_QCU_MISC_CBREXP_BCN |
379 AR5K_QCU_MISC_BCN_ENABLE);
380
381 AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
382 (AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL <<
383 AR5K_DCU_MISC_ARBLOCK_CTL_S) |
384 AR5K_DCU_MISC_POST_FR_BKOFF_DIS |
385 AR5K_DCU_MISC_BCN_ENABLE);
386
387 ath5k_hw_reg_write(ah, ((AR5K_TUNE_BEACON_INTERVAL -
388 (AR5K_TUNE_SW_BEACON_RESP -
389 AR5K_TUNE_DMA_BEACON_RESP) -
390 AR5K_TUNE_ADDITIONAL_SWBA_BACKOFF) * 1024) |
391 AR5K_QCU_RDYTIMECFG_ENABLE,
392 AR5K_QUEUE_RDYTIMECFG(queue));
393 break;
394
395 case AR5K_TX_QUEUE_CAB:
396 AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
397 AR5K_QCU_MISC_FRSHED_DBA_GT |
398 AR5K_QCU_MISC_CBREXP |
399 AR5K_QCU_MISC_CBREXP_BCN);
400
401 AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
402 (AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL <<
403 AR5K_DCU_MISC_ARBLOCK_CTL_S));
404 break;
405
406 case AR5K_TX_QUEUE_UAPSD:
407 AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
408 AR5K_QCU_MISC_CBREXP);
409 break;
410
411 case AR5K_TX_QUEUE_DATA:
412 default:
413 break;
414 }
415
416 /*
417 * Enable interrupts for this tx queue
418 * in the secondary interrupt mask registers
419 */
420 if (tq->tqi_flags & AR5K_TXQ_FLAG_TXOKINT_ENABLE)
421 AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txok, queue);
422
423 if (tq->tqi_flags & AR5K_TXQ_FLAG_TXERRINT_ENABLE)
424 AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txerr, queue);
425
426 if (tq->tqi_flags & AR5K_TXQ_FLAG_TXURNINT_ENABLE)
427 AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txurn, queue);
428
429 if (tq->tqi_flags & AR5K_TXQ_FLAG_TXDESCINT_ENABLE)
430 AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txdesc, queue);
431
432 if (tq->tqi_flags & AR5K_TXQ_FLAG_TXEOLINT_ENABLE)
433 AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txeol, queue);
434
435
436 /* Update secondary interrupt mask registers */
437 ah->ah_txq_imr_txok &= ah->ah_txq_status;
438 ah->ah_txq_imr_txerr &= ah->ah_txq_status;
439 ah->ah_txq_imr_txurn &= ah->ah_txq_status;
440 ah->ah_txq_imr_txdesc &= ah->ah_txq_status;
441 ah->ah_txq_imr_txeol &= ah->ah_txq_status;
442
443 ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txok,
444 AR5K_SIMR0_QCU_TXOK) |
445 AR5K_REG_SM(ah->ah_txq_imr_txdesc,
446 AR5K_SIMR0_QCU_TXDESC), AR5K_SIMR0);
447 ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txerr,
448 AR5K_SIMR1_QCU_TXERR) |
449 AR5K_REG_SM(ah->ah_txq_imr_txeol,
450 AR5K_SIMR1_QCU_TXEOL), AR5K_SIMR1);
451 ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txurn,
452 AR5K_SIMR2_QCU_TXURN), AR5K_SIMR2);
453 }
454
455 return 0;
456}
457
458/*
459 * Get slot time from DCU
460 */
461unsigned int ath5k_hw_get_slot_time(struct ath5k_hw *ah)
462{
463 ATH5K_TRACE(ah->ah_sc);
464 if (ah->ah_version == AR5K_AR5210)
465 return ath5k_hw_clocktoh(ath5k_hw_reg_read(ah,
466 AR5K_SLOT_TIME) & 0xffff, ah->ah_turbo);
467 else
468 return ath5k_hw_reg_read(ah, AR5K_DCU_GBL_IFS_SLOT) & 0xffff;
469}
470
471/*
472 * Set slot time on DCU
473 */
474int ath5k_hw_set_slot_time(struct ath5k_hw *ah, unsigned int slot_time)
475{
476 ATH5K_TRACE(ah->ah_sc);
477 if (slot_time < AR5K_SLOT_TIME_9 || slot_time > AR5K_SLOT_TIME_MAX)
478 return -EINVAL;
479
480 if (ah->ah_version == AR5K_AR5210)
481 ath5k_hw_reg_write(ah, ath5k_hw_htoclock(slot_time,
482 ah->ah_turbo), AR5K_SLOT_TIME);
483 else
484 ath5k_hw_reg_write(ah, slot_time, AR5K_DCU_GBL_IFS_SLOT);
485
486 return 0;
487}
488