2 * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
3 * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
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.
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.
19 /********************************************\
20 Queue Control Unit, DFS Control Unit Functions
21 \********************************************/
29 * Get properties for a transmit queue
31 int ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue,
32 struct ath5k_txq_info *queue_info)
34 memcpy(queue_info, &ah->ah_txq[queue], sizeof(struct ath5k_txq_info));
39 * Make sure cw is a power of 2 minus 1 and smaller than 1024
41 static u16 ath5k_cw_validate(u16 cw_req)
44 cw_req = min(cw_req, (u16)1023);
53 * Set properties for a transmit queue
55 int ath5k_hw_set_tx_queueprops(struct ath5k_hw *ah, int queue,
56 const struct ath5k_txq_info *qinfo)
58 struct ath5k_txq_info *qi;
60 AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
62 qi = &ah->ah_txq[queue];
64 if (qi->tqi_type == AR5K_TX_QUEUE_INACTIVE)
67 /* copy and validate values */
68 qi->tqi_type = qinfo->tqi_type;
69 qi->tqi_subtype = qinfo->tqi_subtype;
70 qi->tqi_flags = qinfo->tqi_flags;
72 * According to the docs: Although the AIFS field is 8 bit wide,
73 * the maximum supported value is 0xFC. Setting it higher than that
74 * will cause the DCU to hang.
76 qi->tqi_aifs = min(qinfo->tqi_aifs, (u8)0xFC);
77 qi->tqi_cw_min = ath5k_cw_validate(qinfo->tqi_cw_min);
78 qi->tqi_cw_max = ath5k_cw_validate(qinfo->tqi_cw_max);
79 qi->tqi_cbr_period = qinfo->tqi_cbr_period;
80 qi->tqi_cbr_overflow_limit = qinfo->tqi_cbr_overflow_limit;
81 qi->tqi_burst_time = qinfo->tqi_burst_time;
82 qi->tqi_ready_time = qinfo->tqi_ready_time;
84 /*XXX: Is this supported on 5210 ?*/
85 /*XXX: Is this correct for AR5K_WME_AC_VI,VO ???*/
86 if ((qinfo->tqi_type == AR5K_TX_QUEUE_DATA &&
87 ((qinfo->tqi_subtype == AR5K_WME_AC_VI) ||
88 (qinfo->tqi_subtype == AR5K_WME_AC_VO))) ||
89 qinfo->tqi_type == AR5K_TX_QUEUE_UAPSD)
90 qi->tqi_flags |= AR5K_TXQ_FLAG_POST_FR_BKOFF_DIS;
96 * Initialize a transmit queue
98 int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type,
99 struct ath5k_txq_info *queue_info)
107 /*5210 only has 2 queues*/
108 if (ah->ah_version == AR5K_AR5210) {
109 switch (queue_type) {
110 case AR5K_TX_QUEUE_DATA:
111 queue = AR5K_TX_QUEUE_ID_NOQCU_DATA;
113 case AR5K_TX_QUEUE_BEACON:
114 case AR5K_TX_QUEUE_CAB:
115 queue = AR5K_TX_QUEUE_ID_NOQCU_BEACON;
121 switch (queue_type) {
122 case AR5K_TX_QUEUE_DATA:
123 for (queue = AR5K_TX_QUEUE_ID_DATA_MIN;
124 ah->ah_txq[queue].tqi_type !=
125 AR5K_TX_QUEUE_INACTIVE; queue++) {
127 if (queue > AR5K_TX_QUEUE_ID_DATA_MAX)
131 case AR5K_TX_QUEUE_UAPSD:
132 queue = AR5K_TX_QUEUE_ID_UAPSD;
134 case AR5K_TX_QUEUE_BEACON:
135 queue = AR5K_TX_QUEUE_ID_BEACON;
137 case AR5K_TX_QUEUE_CAB:
138 queue = AR5K_TX_QUEUE_ID_CAB;
140 case AR5K_TX_QUEUE_XR_DATA:
141 if (ah->ah_version != AR5K_AR5212)
143 "XR data queues only supported in"
145 queue = AR5K_TX_QUEUE_ID_XR_DATA;
153 * Setup internal queue structure
155 memset(&ah->ah_txq[queue], 0, sizeof(struct ath5k_txq_info));
156 ah->ah_txq[queue].tqi_type = queue_type;
158 if (queue_info != NULL) {
159 queue_info->tqi_type = queue_type;
160 ret = ath5k_hw_set_tx_queueprops(ah, queue, queue_info);
166 * We use ah_txq_status to hold a temp value for
167 * the Secondary interrupt mask registers on 5211+
168 * check out ath5k_hw_reset_tx_queue
170 AR5K_Q_ENABLE_BITS(ah->ah_txq_status, queue);
176 * Get number of pending frames
177 * for a specific queue [5211+]
179 u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue)
182 AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
184 /* Return if queue is declared inactive */
185 if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE)
188 /* XXX: How about AR5K_CFG_TXCNT ? */
189 if (ah->ah_version == AR5K_AR5210)
192 pending = ath5k_hw_reg_read(ah, AR5K_QUEUE_STATUS(queue));
193 pending &= AR5K_QCU_STS_FRMPENDCNT;
195 /* It's possible to have no frames pending even if TXE
196 * is set. To indicate that q has not stopped return
198 if (!pending && AR5K_REG_READ_Q(ah, AR5K_QCU_TXE, queue))
205 * Set a transmit queue inactive
207 void ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue)
209 if (WARN_ON(queue >= ah->ah_capabilities.cap_queues.q_tx_num))
212 /* This queue will be skipped in further operations */
213 ah->ah_txq[queue].tqi_type = AR5K_TX_QUEUE_INACTIVE;
215 AR5K_Q_DISABLE_BITS(ah->ah_txq_status, queue);
219 * Set DFS properties for a transmit queue on DCU
221 int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
223 u32 retry_lg, retry_sh;
224 struct ath5k_txq_info *tq = &ah->ah_txq[queue];
226 AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
228 tq = &ah->ah_txq[queue];
230 if (tq->tqi_type == AR5K_TX_QUEUE_INACTIVE)
233 if (ah->ah_version == AR5K_AR5210) {
234 /* Only handle data queues, others will be ignored */
235 if (tq->tqi_type != AR5K_TX_QUEUE_DATA)
239 ath5k_hw_reg_write(ah, ah->ah_turbo ?
240 AR5K_INIT_SLOT_TIME_TURBO : AR5K_INIT_SLOT_TIME,
242 /* Set ACK_CTS timeout */
243 ath5k_hw_reg_write(ah, ah->ah_turbo ?
244 AR5K_INIT_ACK_CTS_TIMEOUT_TURBO :
245 AR5K_INIT_ACK_CTS_TIMEOUT, AR5K_SLOT_TIME);
246 /* Set Transmit Latency */
247 ath5k_hw_reg_write(ah, ah->ah_turbo ?
248 AR5K_INIT_TRANSMIT_LATENCY_TURBO :
249 AR5K_INIT_TRANSMIT_LATENCY, AR5K_USEC_5210);
253 ath5k_hw_reg_write(ah, ((AR5K_INIT_SIFS_TURBO +
254 tq->tqi_aifs * AR5K_INIT_SLOT_TIME_TURBO) <<
255 AR5K_IFS0_DIFS_S) | AR5K_INIT_SIFS_TURBO,
258 ath5k_hw_reg_write(ah, ((AR5K_INIT_SIFS +
259 tq->tqi_aifs * AR5K_INIT_SLOT_TIME) <<
261 AR5K_INIT_SIFS, AR5K_IFS0);
265 ath5k_hw_reg_write(ah, ah->ah_turbo ?
266 AR5K_INIT_PROTO_TIME_CNTRL_TURBO :
267 AR5K_INIT_PROTO_TIME_CNTRL, AR5K_IFS1);
268 /* Set AR5K_PHY_SETTLING */
269 ath5k_hw_reg_write(ah, ah->ah_turbo ?
270 (ath5k_hw_reg_read(ah, AR5K_PHY_SETTLING) & ~0x7F)
272 (ath5k_hw_reg_read(ah, AR5K_PHY_SETTLING) & ~0x7F)
275 /* Set Frame Control Register */
276 ath5k_hw_reg_write(ah, ah->ah_turbo ?
277 (AR5K_PHY_FRAME_CTL_INI | AR5K_PHY_TURBO_MODE |
278 AR5K_PHY_TURBO_SHORT | 0x2020) :
279 (AR5K_PHY_FRAME_CTL_INI | 0x1020),
280 AR5K_PHY_FRAME_CTL_5210);
284 * Calculate and set retry limits
286 if (ah->ah_software_retry) {
287 /* XXX Need to test this */
288 retry_lg = ah->ah_limit_tx_retries;
289 retry_sh = retry_lg = retry_lg > AR5K_DCU_RETRY_LMT_SH_RETRY ?
290 AR5K_DCU_RETRY_LMT_SH_RETRY : retry_lg;
292 retry_lg = AR5K_INIT_LG_RETRY;
293 retry_sh = AR5K_INIT_SH_RETRY;
296 /*No QCU/DCU [5210]*/
297 if (ah->ah_version == AR5K_AR5210) {
298 ath5k_hw_reg_write(ah,
299 (tq->tqi_cw_min << AR5K_NODCU_RETRY_LMT_CW_MIN_S)
300 | AR5K_REG_SM(AR5K_INIT_SLG_RETRY,
301 AR5K_NODCU_RETRY_LMT_SLG_RETRY)
302 | AR5K_REG_SM(AR5K_INIT_SSH_RETRY,
303 AR5K_NODCU_RETRY_LMT_SSH_RETRY)
304 | AR5K_REG_SM(retry_lg, AR5K_NODCU_RETRY_LMT_LG_RETRY)
305 | AR5K_REG_SM(retry_sh, AR5K_NODCU_RETRY_LMT_SH_RETRY),
306 AR5K_NODCU_RETRY_LMT);
309 ath5k_hw_reg_write(ah,
310 AR5K_REG_SM(AR5K_INIT_SLG_RETRY,
311 AR5K_DCU_RETRY_LMT_SLG_RETRY) |
312 AR5K_REG_SM(AR5K_INIT_SSH_RETRY,
313 AR5K_DCU_RETRY_LMT_SSH_RETRY) |
314 AR5K_REG_SM(retry_lg, AR5K_DCU_RETRY_LMT_LG_RETRY) |
315 AR5K_REG_SM(retry_sh, AR5K_DCU_RETRY_LMT_SH_RETRY),
316 AR5K_QUEUE_DFS_RETRY_LIMIT(queue));
318 /*===Rest is also for QCU/DCU only [5211+]===*/
321 * Set contention window (cw_min/cw_max)
322 * and arbitrated interframe space (aifs)...
324 ath5k_hw_reg_write(ah,
325 AR5K_REG_SM(tq->tqi_cw_min, AR5K_DCU_LCL_IFS_CW_MIN) |
326 AR5K_REG_SM(tq->tqi_cw_max, AR5K_DCU_LCL_IFS_CW_MAX) |
327 AR5K_REG_SM(tq->tqi_aifs, AR5K_DCU_LCL_IFS_AIFS),
328 AR5K_QUEUE_DFS_LOCAL_IFS(queue));
333 /* Enable DCU early termination for this queue */
334 AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
335 AR5K_QCU_MISC_DCU_EARLY);
337 /* Enable DCU to wait for next fragment from QCU */
338 AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
339 AR5K_DCU_MISC_FRAG_WAIT);
341 /* On Maui and Spirit use the global seqnum on DCU */
342 if (ah->ah_mac_version < AR5K_SREV_AR5211)
343 AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
344 AR5K_DCU_MISC_SEQNUM_CTL);
346 if (tq->tqi_cbr_period) {
347 ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_cbr_period,
348 AR5K_QCU_CBRCFG_INTVAL) |
349 AR5K_REG_SM(tq->tqi_cbr_overflow_limit,
350 AR5K_QCU_CBRCFG_ORN_THRES),
351 AR5K_QUEUE_CBRCFG(queue));
352 AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
353 AR5K_QCU_MISC_FRSHED_CBR);
354 if (tq->tqi_cbr_overflow_limit)
355 AR5K_REG_ENABLE_BITS(ah,
356 AR5K_QUEUE_MISC(queue),
357 AR5K_QCU_MISC_CBR_THRES_ENABLE);
360 if (tq->tqi_ready_time &&
361 (tq->tqi_type != AR5K_TX_QUEUE_CAB))
362 ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_ready_time,
363 AR5K_QCU_RDYTIMECFG_INTVAL) |
364 AR5K_QCU_RDYTIMECFG_ENABLE,
365 AR5K_QUEUE_RDYTIMECFG(queue));
367 if (tq->tqi_burst_time) {
368 ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_burst_time,
369 AR5K_DCU_CHAN_TIME_DUR) |
370 AR5K_DCU_CHAN_TIME_ENABLE,
371 AR5K_QUEUE_DFS_CHANNEL_TIME(queue));
374 & AR5K_TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE)
375 AR5K_REG_ENABLE_BITS(ah,
376 AR5K_QUEUE_MISC(queue),
377 AR5K_QCU_MISC_RDY_VEOL_POLICY);
380 if (tq->tqi_flags & AR5K_TXQ_FLAG_BACKOFF_DISABLE)
381 ath5k_hw_reg_write(ah, AR5K_DCU_MISC_POST_FR_BKOFF_DIS,
382 AR5K_QUEUE_DFS_MISC(queue));
384 if (tq->tqi_flags & AR5K_TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE)
385 ath5k_hw_reg_write(ah, AR5K_DCU_MISC_BACKOFF_FRAG,
386 AR5K_QUEUE_DFS_MISC(queue));
389 * Set registers by queue type
391 switch (tq->tqi_type) {
392 case AR5K_TX_QUEUE_BEACON:
393 AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
394 AR5K_QCU_MISC_FRSHED_DBA_GT |
395 AR5K_QCU_MISC_CBREXP_BCN_DIS |
396 AR5K_QCU_MISC_BCN_ENABLE);
398 AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
399 (AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL <<
400 AR5K_DCU_MISC_ARBLOCK_CTL_S) |
401 AR5K_DCU_MISC_ARBLOCK_IGNORE |
402 AR5K_DCU_MISC_POST_FR_BKOFF_DIS |
403 AR5K_DCU_MISC_BCN_ENABLE);
406 case AR5K_TX_QUEUE_CAB:
407 /* XXX: use BCN_SENT_GT, if we can figure out how */
408 AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
409 AR5K_QCU_MISC_FRSHED_DBA_GT |
410 AR5K_QCU_MISC_CBREXP_DIS |
411 AR5K_QCU_MISC_CBREXP_BCN_DIS);
413 ath5k_hw_reg_write(ah, ((tq->tqi_ready_time -
414 (AR5K_TUNE_SW_BEACON_RESP -
415 AR5K_TUNE_DMA_BEACON_RESP) -
416 AR5K_TUNE_ADDITIONAL_SWBA_BACKOFF) * 1024) |
417 AR5K_QCU_RDYTIMECFG_ENABLE,
418 AR5K_QUEUE_RDYTIMECFG(queue));
420 AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
421 (AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL <<
422 AR5K_DCU_MISC_ARBLOCK_CTL_S));
425 case AR5K_TX_QUEUE_UAPSD:
426 AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
427 AR5K_QCU_MISC_CBREXP_DIS);
430 case AR5K_TX_QUEUE_DATA:
435 /* TODO: Handle frame compression */
438 * Enable interrupts for this tx queue
439 * in the secondary interrupt mask registers
441 if (tq->tqi_flags & AR5K_TXQ_FLAG_TXOKINT_ENABLE)
442 AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txok, queue);
444 if (tq->tqi_flags & AR5K_TXQ_FLAG_TXERRINT_ENABLE)
445 AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txerr, queue);
447 if (tq->tqi_flags & AR5K_TXQ_FLAG_TXURNINT_ENABLE)
448 AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txurn, queue);
450 if (tq->tqi_flags & AR5K_TXQ_FLAG_TXDESCINT_ENABLE)
451 AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txdesc, queue);
453 if (tq->tqi_flags & AR5K_TXQ_FLAG_TXEOLINT_ENABLE)
454 AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txeol, queue);
456 if (tq->tqi_flags & AR5K_TXQ_FLAG_CBRORNINT_ENABLE)
457 AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_cbrorn, queue);
459 if (tq->tqi_flags & AR5K_TXQ_FLAG_CBRURNINT_ENABLE)
460 AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_cbrurn, queue);
462 if (tq->tqi_flags & AR5K_TXQ_FLAG_QTRIGINT_ENABLE)
463 AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_qtrig, queue);
465 if (tq->tqi_flags & AR5K_TXQ_FLAG_TXNOFRMINT_ENABLE)
466 AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_nofrm, queue);
468 /* Update secondary interrupt mask registers */
470 /* Filter out inactive queues */
471 ah->ah_txq_imr_txok &= ah->ah_txq_status;
472 ah->ah_txq_imr_txerr &= ah->ah_txq_status;
473 ah->ah_txq_imr_txurn &= ah->ah_txq_status;
474 ah->ah_txq_imr_txdesc &= ah->ah_txq_status;
475 ah->ah_txq_imr_txeol &= ah->ah_txq_status;
476 ah->ah_txq_imr_cbrorn &= ah->ah_txq_status;
477 ah->ah_txq_imr_cbrurn &= ah->ah_txq_status;
478 ah->ah_txq_imr_qtrig &= ah->ah_txq_status;
479 ah->ah_txq_imr_nofrm &= ah->ah_txq_status;
481 ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txok,
482 AR5K_SIMR0_QCU_TXOK) |
483 AR5K_REG_SM(ah->ah_txq_imr_txdesc,
484 AR5K_SIMR0_QCU_TXDESC), AR5K_SIMR0);
485 ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txerr,
486 AR5K_SIMR1_QCU_TXERR) |
487 AR5K_REG_SM(ah->ah_txq_imr_txeol,
488 AR5K_SIMR1_QCU_TXEOL), AR5K_SIMR1);
489 /* Update simr2 but don't overwrite rest simr2 settings */
490 AR5K_REG_DISABLE_BITS(ah, AR5K_SIMR2, AR5K_SIMR2_QCU_TXURN);
491 AR5K_REG_ENABLE_BITS(ah, AR5K_SIMR2,
492 AR5K_REG_SM(ah->ah_txq_imr_txurn,
493 AR5K_SIMR2_QCU_TXURN));
494 ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_cbrorn,
495 AR5K_SIMR3_QCBRORN) |
496 AR5K_REG_SM(ah->ah_txq_imr_cbrurn,
497 AR5K_SIMR3_QCBRURN), AR5K_SIMR3);
498 ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_qtrig,
499 AR5K_SIMR4_QTRIG), AR5K_SIMR4);
500 /* Set TXNOFRM_QCU for the queues with TXNOFRM enabled */
501 ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_nofrm,
502 AR5K_TXNOFRM_QCU), AR5K_TXNOFRM);
503 /* No queue has TXNOFRM enabled, disable the interrupt
504 * by setting AR5K_TXNOFRM to zero */
505 if (ah->ah_txq_imr_nofrm == 0)
506 ath5k_hw_reg_write(ah, 0, AR5K_TXNOFRM);
508 /* Set QCU mask for this DCU to save power */
509 AR5K_REG_WRITE_Q(ah, AR5K_QUEUE_QCUMASK(queue), queue);
516 * Set slot time on DCU
518 int ath5k_hw_set_slot_time(struct ath5k_hw *ah, unsigned int slot_time)
520 u32 slot_time_clock = ath5k_hw_htoclock(ah, slot_time);
522 if (slot_time < 6 || slot_time_clock > AR5K_SLOT_TIME_MAX)
525 if (ah->ah_version == AR5K_AR5210)
526 ath5k_hw_reg_write(ah, slot_time_clock, AR5K_SLOT_TIME);
528 ath5k_hw_reg_write(ah, slot_time_clock, AR5K_DCU_GBL_IFS_SLOT);