2 * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
3 * Copyright (c) 2002-2006 Atheros Communications, Inc.
5 * Permission to use, copy, modify, and/or 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.
17 * $Id: ar5211_xmit.c,v 1.1.1.1 2008/12/11 04:46:34 alc Exp $
22 #include "ah_internal.h"
25 #include "ar5211/ar5211.h"
26 #include "ar5211/ar5211reg.h"
27 #include "ar5211/ar5211desc.h"
30 * Update Tx FIFO trigger level.
32 * Set bIncTrigLevel to TRUE to increase the trigger level.
33 * Set bIncTrigLevel to FALSE to decrease the trigger level.
35 * Returns TRUE if the trigger level was updated
38 ar5211UpdateTxTrigLevel(struct ath_hal
*ah
, HAL_BOOL bIncTrigLevel
)
40 uint32_t curTrigLevel
, txcfg
;
41 HAL_INT ints
= ar5211GetInterrupts(ah
);
44 * Disable chip interrupts. This is because halUpdateTxTrigLevel
45 * is called from both ISR and non-ISR contexts.
47 ar5211SetInterrupts(ah
, ints
&~ HAL_INT_GLOBAL
);
48 txcfg
= OS_REG_READ(ah
, AR_TXCFG
);
49 curTrigLevel
= (txcfg
& AR_TXCFG_FTRIG_M
) >> AR_TXCFG_FTRIG_S
;
51 /* increase the trigger level */
52 curTrigLevel
= curTrigLevel
+
53 ((MAX_TX_FIFO_THRESHOLD
- curTrigLevel
) / 2);
55 /* decrease the trigger level if not already at the minimum */
56 if (curTrigLevel
> MIN_TX_FIFO_THRESHOLD
) {
57 /* decrease the trigger level */
60 /* no update to the trigger level */
61 /* re-enable chip interrupts */
62 ar5211SetInterrupts(ah
, ints
);
66 /* Update the trigger level */
67 OS_REG_WRITE(ah
, AR_TXCFG
, (txcfg
&~ AR_TXCFG_FTRIG_M
) |
68 ((curTrigLevel
<< AR_TXCFG_FTRIG_S
) & AR_TXCFG_FTRIG_M
));
69 /* re-enable chip interrupts */
70 ar5211SetInterrupts(ah
, ints
);
75 * Set the properties of the tx queue with the parameters
76 * from qInfo. The queue must previously have been setup
77 * with a call to ar5211SetupTxQueue.
80 ar5211SetTxQueueProps(struct ath_hal
*ah
, int q
, const HAL_TXQ_INFO
*qInfo
)
82 struct ath_hal_5211
*ahp
= AH5211(ah
);
84 if (q
>= HAL_NUM_TX_QUEUES
) {
85 HALDEBUG(ah
, HAL_DEBUG_ANY
, "%s: invalid queue num %u\n",
89 return ath_hal_setTxQProps(ah
, &ahp
->ah_txq
[q
], qInfo
);
93 * Return the properties for the specified tx queue.
96 ar5211GetTxQueueProps(struct ath_hal
*ah
, int q
, HAL_TXQ_INFO
*qInfo
)
98 struct ath_hal_5211
*ahp
= AH5211(ah
);
100 if (q
>= HAL_NUM_TX_QUEUES
) {
101 HALDEBUG(ah
, HAL_DEBUG_ANY
, "%s: invalid queue num %u\n",
105 return ath_hal_getTxQProps(ah
, qInfo
, &ahp
->ah_txq
[q
]);
109 * Allocate and initialize a tx DCU/QCU combination.
112 ar5211SetupTxQueue(struct ath_hal
*ah
, HAL_TX_QUEUE type
,
113 const HAL_TXQ_INFO
*qInfo
)
115 struct ath_hal_5211
*ahp
= AH5211(ah
);
116 HAL_TX_QUEUE_INFO
*qi
;
120 case HAL_TX_QUEUE_BEACON
:
123 case HAL_TX_QUEUE_CAB
:
126 case HAL_TX_QUEUE_DATA
:
128 if (ahp
->ah_txq
[q
].tqi_type
!= HAL_TX_QUEUE_INACTIVE
)
132 HALDEBUG(ah
, HAL_DEBUG_ANY
, "%s: bad tx queue type %u\n",
137 HALDEBUG(ah
, HAL_DEBUG_TXQUEUE
, "%s: queue %u\n", __func__
, q
);
139 qi
= &ahp
->ah_txq
[q
];
140 if (qi
->tqi_type
!= HAL_TX_QUEUE_INACTIVE
) {
141 HALDEBUG(ah
, HAL_DEBUG_ANY
, "%s: tx queue %u already active\n",
145 OS_MEMZERO(qi
, sizeof(HAL_TX_QUEUE_INFO
));
147 if (qInfo
== AH_NULL
) {
148 /* by default enable OK+ERR+DESC+URN interrupts */
150 HAL_TXQ_TXOKINT_ENABLE
151 | HAL_TXQ_TXERRINT_ENABLE
152 | HAL_TXQ_TXDESCINT_ENABLE
153 | HAL_TXQ_TXURNINT_ENABLE
155 qi
->tqi_aifs
= INIT_AIFS
;
156 qi
->tqi_cwmin
= HAL_TXQ_USEDEFAULT
; /* NB: do at reset */
157 qi
->tqi_cwmax
= INIT_CWMAX
;
158 qi
->tqi_shretry
= INIT_SH_RETRY
;
159 qi
->tqi_lgretry
= INIT_LG_RETRY
;
161 (void) ar5211SetTxQueueProps(ah
, q
, qInfo
);
166 * Update the h/w interrupt registers to reflect a tx q's configuration.
169 setTxQInterrupts(struct ath_hal
*ah
, HAL_TX_QUEUE_INFO
*qi
)
171 struct ath_hal_5211
*ahp
= AH5211(ah
);
173 HALDEBUG(ah
, HAL_DEBUG_TXQUEUE
,
174 "%s: tx ok 0x%x err 0x%x desc 0x%x eol 0x%x urn 0x%x\n", __func__
175 , ahp
->ah_txOkInterruptMask
176 , ahp
->ah_txErrInterruptMask
177 , ahp
->ah_txDescInterruptMask
178 , ahp
->ah_txEolInterruptMask
179 , ahp
->ah_txUrnInterruptMask
182 OS_REG_WRITE(ah
, AR_IMR_S0
,
183 SM(ahp
->ah_txOkInterruptMask
, AR_IMR_S0_QCU_TXOK
)
184 | SM(ahp
->ah_txDescInterruptMask
, AR_IMR_S0_QCU_TXDESC
)
186 OS_REG_WRITE(ah
, AR_IMR_S1
,
187 SM(ahp
->ah_txErrInterruptMask
, AR_IMR_S1_QCU_TXERR
)
188 | SM(ahp
->ah_txEolInterruptMask
, AR_IMR_S1_QCU_TXEOL
)
190 OS_REG_RMW_FIELD(ah
, AR_IMR_S2
,
191 AR_IMR_S2_QCU_TXURN
, ahp
->ah_txUrnInterruptMask
);
196 * Free a tx DCU/QCU combination.
199 ar5211ReleaseTxQueue(struct ath_hal
*ah
, u_int q
)
201 struct ath_hal_5211
*ahp
= AH5211(ah
);
202 HAL_TX_QUEUE_INFO
*qi
;
204 if (q
>= HAL_NUM_TX_QUEUES
) {
205 HALDEBUG(ah
, HAL_DEBUG_ANY
, "%s: invalid queue num %u\n",
209 qi
= &ahp
->ah_txq
[q
];
210 if (qi
->tqi_type
== HAL_TX_QUEUE_INACTIVE
) {
211 HALDEBUG(ah
, HAL_DEBUG_TXQUEUE
, "%s: inactive queue %u\n",
216 HALDEBUG(ah
, HAL_DEBUG_TXQUEUE
, "%s: release queue %u\n", __func__
, q
);
218 qi
->tqi_type
= HAL_TX_QUEUE_INACTIVE
;
219 ahp
->ah_txOkInterruptMask
&= ~(1 << q
);
220 ahp
->ah_txErrInterruptMask
&= ~(1 << q
);
221 ahp
->ah_txDescInterruptMask
&= ~(1 << q
);
222 ahp
->ah_txEolInterruptMask
&= ~(1 << q
);
223 ahp
->ah_txUrnInterruptMask
&= ~(1 << q
);
224 setTxQInterrupts(ah
, qi
);
230 * Set the retry, aifs, cwmin/max, readyTime regs for specified queue
233 ar5211ResetTxQueue(struct ath_hal
*ah
, u_int q
)
235 struct ath_hal_5211
*ahp
= AH5211(ah
);
236 HAL_CHANNEL_INTERNAL
*chan
= AH_PRIVATE(ah
)->ah_curchan
;
237 HAL_TX_QUEUE_INFO
*qi
;
238 uint32_t cwMin
, chanCwMin
, value
;
240 if (q
>= HAL_NUM_TX_QUEUES
) {
241 HALDEBUG(ah
, HAL_DEBUG_ANY
, "%s: invalid queue num %u\n",
245 qi
= &ahp
->ah_txq
[q
];
246 if (qi
->tqi_type
== HAL_TX_QUEUE_INACTIVE
) {
247 HALDEBUG(ah
, HAL_DEBUG_TXQUEUE
, "%s: inactive queue %u\n",
249 return AH_TRUE
; /* XXX??? */
252 if (qi
->tqi_cwmin
== HAL_TXQ_USEDEFAULT
) {
254 * Select cwmin according to channel type.
255 * NB: chan can be NULL during attach
257 if (chan
&& IS_CHAN_B(chan
))
258 chanCwMin
= INIT_CWMIN_11B
;
260 chanCwMin
= INIT_CWMIN
;
261 /* make sure that the CWmin is of the form (2^n - 1) */
262 for (cwMin
= 1; cwMin
< chanCwMin
; cwMin
= (cwMin
<< 1) | 1)
265 cwMin
= qi
->tqi_cwmin
;
267 /* set cwMin/Max and AIFS values */
268 OS_REG_WRITE(ah
, AR_DLCL_IFS(q
),
269 SM(cwMin
, AR_D_LCL_IFS_CWMIN
)
270 | SM(qi
->tqi_cwmax
, AR_D_LCL_IFS_CWMAX
)
271 | SM(qi
->tqi_aifs
, AR_D_LCL_IFS_AIFS
));
273 /* Set retry limit values */
274 OS_REG_WRITE(ah
, AR_DRETRY_LIMIT(q
),
275 SM(INIT_SSH_RETRY
, AR_D_RETRY_LIMIT_STA_SH
)
276 | SM(INIT_SLG_RETRY
, AR_D_RETRY_LIMIT_STA_LG
)
277 | SM(qi
->tqi_lgretry
, AR_D_RETRY_LIMIT_FR_LG
)
278 | SM(qi
->tqi_shretry
, AR_D_RETRY_LIMIT_FR_SH
)
281 /* enable early termination on the QCU */
282 OS_REG_WRITE(ah
, AR_QMISC(q
), AR_Q_MISC_DCU_EARLY_TERM_REQ
);
284 if (AH_PRIVATE(ah
)->ah_macVersion
< AR_SREV_VERSION_OAHU
) {
285 /* Configure DCU to use the global sequence count */
286 OS_REG_WRITE(ah
, AR_DMISC(q
), AR5311_D_MISC_SEQ_NUM_CONTROL
);
288 /* multiqueue support */
289 if (qi
->tqi_cbrPeriod
) {
290 OS_REG_WRITE(ah
, AR_QCBRCFG(q
),
291 SM(qi
->tqi_cbrPeriod
,AR_Q_CBRCFG_CBR_INTERVAL
)
292 | SM(qi
->tqi_cbrOverflowLimit
, AR_Q_CBRCFG_CBR_OVF_THRESH
));
293 OS_REG_WRITE(ah
, AR_QMISC(q
),
294 OS_REG_READ(ah
, AR_QMISC(q
)) |
296 (qi
->tqi_cbrOverflowLimit
?
297 AR_Q_MISC_CBR_EXP_CNTR_LIMIT
: 0));
299 if (qi
->tqi_readyTime
) {
300 OS_REG_WRITE(ah
, AR_QRDYTIMECFG(q
),
301 SM(qi
->tqi_readyTime
, AR_Q_RDYTIMECFG_INT
) |
304 if (qi
->tqi_burstTime
) {
305 OS_REG_WRITE(ah
, AR_DCHNTIME(q
),
306 SM(qi
->tqi_burstTime
, AR_D_CHNTIME_DUR
) |
308 if (qi
->tqi_qflags
& HAL_TXQ_RDYTIME_EXP_POLICY_ENABLE
) {
309 OS_REG_WRITE(ah
, AR_QMISC(q
),
310 OS_REG_READ(ah
, AR_QMISC(q
)) |
311 AR_Q_MISC_RDYTIME_EXP_POLICY
);
315 if (qi
->tqi_qflags
& HAL_TXQ_BACKOFF_DISABLE
) {
316 OS_REG_WRITE(ah
, AR_DMISC(q
),
317 OS_REG_READ(ah
, AR_DMISC(q
)) |
318 AR_D_MISC_POST_FR_BKOFF_DIS
);
320 if (qi
->tqi_qflags
& HAL_TXQ_FRAG_BURST_BACKOFF_ENABLE
) {
321 OS_REG_WRITE(ah
, AR_DMISC(q
),
322 OS_REG_READ(ah
, AR_DMISC(q
)) |
323 AR_D_MISC_FRAG_BKOFF_EN
);
325 switch (qi
->tqi_type
) {
326 case HAL_TX_QUEUE_BEACON
:
327 /* Configure QCU for beacons */
328 OS_REG_WRITE(ah
, AR_QMISC(q
),
329 OS_REG_READ(ah
, AR_QMISC(q
))
330 | AR_Q_MISC_FSP_DBA_GATED
331 | AR_Q_MISC_BEACON_USE
332 | AR_Q_MISC_CBR_INCR_DIS1
);
333 /* Configure DCU for beacons */
334 value
= (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL
<< AR_D_MISC_ARB_LOCKOUT_CNTRL_S
)
335 | AR_D_MISC_BEACON_USE
| AR_D_MISC_POST_FR_BKOFF_DIS
;
336 if (AH_PRIVATE(ah
)->ah_macVersion
< AR_SREV_VERSION_OAHU
)
337 value
|= AR5311_D_MISC_SEQ_NUM_CONTROL
;
338 OS_REG_WRITE(ah
, AR_DMISC(q
), value
);
340 case HAL_TX_QUEUE_CAB
:
341 /* Configure QCU for CAB (Crap After Beacon) frames */
342 OS_REG_WRITE(ah
, AR_QMISC(q
),
343 OS_REG_READ(ah
, AR_QMISC(q
))
344 | AR_Q_MISC_FSP_DBA_GATED
| AR_Q_MISC_CBR_INCR_DIS1
345 | AR_Q_MISC_CBR_INCR_DIS0
| AR_Q_MISC_RDYTIME_EXP_POLICY
);
347 value
= (ahp
->ah_beaconInterval
348 - (ath_hal_sw_beacon_response_time
- ath_hal_dma_beacon_response_time
)
349 - ath_hal_additional_swba_backoff
) * 1024;
350 OS_REG_WRITE(ah
, AR_QRDYTIMECFG(q
), value
| AR_Q_RDYTIMECFG_EN
);
352 /* Configure DCU for CAB */
353 value
= (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL
<< AR_D_MISC_ARB_LOCKOUT_CNTRL_S
);
354 if (AH_PRIVATE(ah
)->ah_macVersion
< AR_SREV_VERSION_OAHU
)
355 value
|= AR5311_D_MISC_SEQ_NUM_CONTROL
;
356 OS_REG_WRITE(ah
, AR_QMISC(q
), value
);
359 /* NB: silence compiler */
364 * Always update the secondary interrupt mask registers - this
365 * could be a new queue getting enabled in a running system or
366 * hw getting re-initialized during a reset!
368 * Since we don't differentiate between tx interrupts corresponding
369 * to individual queues - secondary tx mask regs are always unmasked;
370 * tx interrupts are enabled/disabled for all queues collectively
371 * using the primary mask reg
373 if (qi
->tqi_qflags
& HAL_TXQ_TXOKINT_ENABLE
)
374 ahp
->ah_txOkInterruptMask
|= 1 << q
;
376 ahp
->ah_txOkInterruptMask
&= ~(1 << q
);
377 if (qi
->tqi_qflags
& HAL_TXQ_TXERRINT_ENABLE
)
378 ahp
->ah_txErrInterruptMask
|= 1 << q
;
380 ahp
->ah_txErrInterruptMask
&= ~(1 << q
);
381 if (qi
->tqi_qflags
& HAL_TXQ_TXDESCINT_ENABLE
)
382 ahp
->ah_txDescInterruptMask
|= 1 << q
;
384 ahp
->ah_txDescInterruptMask
&= ~(1 << q
);
385 if (qi
->tqi_qflags
& HAL_TXQ_TXEOLINT_ENABLE
)
386 ahp
->ah_txEolInterruptMask
|= 1 << q
;
388 ahp
->ah_txEolInterruptMask
&= ~(1 << q
);
389 if (qi
->tqi_qflags
& HAL_TXQ_TXURNINT_ENABLE
)
390 ahp
->ah_txUrnInterruptMask
|= 1 << q
;
392 ahp
->ah_txUrnInterruptMask
&= ~(1 << q
);
393 setTxQInterrupts(ah
, qi
);
399 * Get the TXDP for the specified data queue.
402 ar5211GetTxDP(struct ath_hal
*ah
, u_int q
)
404 HALASSERT(q
< HAL_NUM_TX_QUEUES
);
405 return OS_REG_READ(ah
, AR_QTXDP(q
));
409 * Set the TxDP for the specified tx queue.
412 ar5211SetTxDP(struct ath_hal
*ah
, u_int q
, uint32_t txdp
)
414 HALASSERT(q
< HAL_NUM_TX_QUEUES
);
415 HALASSERT(AH5211(ah
)->ah_txq
[q
].tqi_type
!= HAL_TX_QUEUE_INACTIVE
);
418 * Make sure that TXE is deasserted before setting the TXDP. If TXE
419 * is still asserted, setting TXDP will have no effect.
421 HALASSERT((OS_REG_READ(ah
, AR_Q_TXE
) & (1 << q
)) == 0);
423 OS_REG_WRITE(ah
, AR_QTXDP(q
), txdp
);
429 * Set Transmit Enable bits for the specified queues.
432 ar5211StartTxDma(struct ath_hal
*ah
, u_int q
)
434 HALASSERT(q
< HAL_NUM_TX_QUEUES
);
435 HALASSERT(AH5211(ah
)->ah_txq
[q
].tqi_type
!= HAL_TX_QUEUE_INACTIVE
);
437 /* Check that queue is not already active */
438 HALASSERT((OS_REG_READ(ah
, AR_Q_TXD
) & (1<<q
)) == 0);
440 HALDEBUG(ah
, HAL_DEBUG_TXQUEUE
, "%s: queue %u\n", __func__
, q
);
442 /* Check to be sure we're not enabling a q that has its TXD bit set. */
443 HALASSERT((OS_REG_READ(ah
, AR_Q_TXD
) & (1 << q
)) == 0);
445 OS_REG_WRITE(ah
, AR_Q_TXE
, 1 << q
);
450 * Return the number of frames pending on the specified queue.
453 ar5211NumTxPending(struct ath_hal
*ah
, u_int q
)
457 HALASSERT(q
< HAL_NUM_TX_QUEUES
);
458 HALASSERT(AH5211(ah
)->ah_txq
[q
].tqi_type
!= HAL_TX_QUEUE_INACTIVE
);
460 n
= OS_REG_READ(ah
, AR_QSTS(q
)) & AR_Q_STS_PEND_FR_CNT_M
;
462 * Pending frame count (PFC) can momentarily go to zero
463 * while TXE remains asserted. In other words a PFC of
464 * zero is not sufficient to say that the queue has stopped.
466 if (n
== 0 && (OS_REG_READ(ah
, AR_Q_TXE
) & (1<<q
)))
467 n
= 1; /* arbitrarily pick 1 */
472 * Stop transmit on the specified queue
475 ar5211StopTxDma(struct ath_hal
*ah
, u_int q
)
479 HALASSERT(q
< HAL_NUM_TX_QUEUES
);
480 HALASSERT(AH5211(ah
)->ah_txq
[q
].tqi_type
!= HAL_TX_QUEUE_INACTIVE
);
482 OS_REG_WRITE(ah
, AR_Q_TXD
, 1<<q
);
483 for (i
= 0; i
< 10000; i
++) {
484 if (ar5211NumTxPending(ah
, q
) == 0)
488 OS_REG_WRITE(ah
, AR_Q_TXD
, 0);
494 * Descriptor Access Functions
497 #define VALID_PKT_TYPES \
498 ((1<<HAL_PKT_TYPE_NORMAL)|(1<<HAL_PKT_TYPE_ATIM)|\
499 (1<<HAL_PKT_TYPE_PSPOLL)|(1<<HAL_PKT_TYPE_PROBE_RESP)|\
500 (1<<HAL_PKT_TYPE_BEACON))
501 #define isValidPktType(_t) ((1<<(_t)) & VALID_PKT_TYPES)
502 #define VALID_TX_RATES \
503 ((1<<0x0b)|(1<<0x0f)|(1<<0x0a)|(1<<0x0e)|(1<<0x09)|(1<<0x0d)|\
504 (1<<0x08)|(1<<0x0c)|(1<<0x1b)|(1<<0x1a)|(1<<0x1e)|(1<<0x19)|\
505 (1<<0x1d)|(1<<0x18)|(1<<0x1c))
506 #define isValidTxRate(_r) ((1<<(_r)) & VALID_TX_RATES)
509 ar5211SetupTxDesc(struct ath_hal
*ah
, struct ath_desc
*ds
,
514 u_int txRate0
, u_int txTries0
,
519 u_int rtsctsDuration
,
524 struct ar5211_desc
*ads
= AR5211DESC(ds
);
528 (void) rtsctsRate
; (void) rtsctsDuration
;
530 HALASSERT(txTries0
!= 0);
531 HALASSERT(isValidPktType(type
));
532 HALASSERT(isValidTxRate(txRate0
));
533 /* XXX validate antMode */
535 ads
->ds_ctl0
= (pktLen
& AR_FrameLen
)
536 | (txRate0
<< AR_XmitRate_S
)
537 | (antMode
<< AR_AntModeXmit_S
)
538 | (flags
& HAL_TXDESC_CLRDMASK
? AR_ClearDestMask
: 0)
539 | (flags
& HAL_TXDESC_INTREQ
? AR_TxInterReq
: 0)
540 | (flags
& HAL_TXDESC_RTSENA
? AR_RTSCTSEnable
: 0)
541 | (flags
& HAL_TXDESC_VEOL
? AR_VEOL
: 0)
543 ads
->ds_ctl1
= (type
<< 26)
544 | (flags
& HAL_TXDESC_NOACK
? AR_NoAck
: 0)
547 if (keyIx
!= HAL_TXKEYIX_INVALID
) {
549 (keyIx
<< AR_EncryptKeyIdx_S
) & AR_EncryptKeyIdx
;
550 ads
->ds_ctl0
|= AR_EncryptKeyValid
;
557 ar5211SetupXTxDesc(struct ath_hal
*ah
, struct ath_desc
*ds
,
558 u_int txRate1
, u_int txTries1
,
559 u_int txRate2
, u_int txTries2
,
560 u_int txRate3
, u_int txTries3
)
562 (void) ah
; (void) ds
;
563 (void) txRate1
; (void) txTries1
;
564 (void) txRate2
; (void) txTries2
;
565 (void) txRate3
; (void) txTries3
;
570 ar5211IntrReqTxDesc(struct ath_hal
*ah
, struct ath_desc
*ds
)
572 struct ar5211_desc
*ads
= AR5211DESC(ds
);
574 ads
->ds_ctl0
|= AR_TxInterReq
;
578 ar5211FillTxDesc(struct ath_hal
*ah
, struct ath_desc
*ds
,
579 u_int segLen
, HAL_BOOL firstSeg
, HAL_BOOL lastSeg
,
580 const struct ath_desc
*ds0
)
582 struct ar5211_desc
*ads
= AR5211DESC(ds
);
584 HALASSERT((segLen
&~ AR_BufLen
) == 0);
588 * First descriptor, don't clobber xmit control data
589 * setup by ar5211SetupTxDesc.
591 ads
->ds_ctl1
|= segLen
| (lastSeg
? 0 : AR_More
);
592 } else if (lastSeg
) { /* !firstSeg && lastSeg */
594 * Last descriptor in a multi-descriptor frame,
595 * copy the transmit parameters from the first
596 * frame for processing on completion.
598 ads
->ds_ctl0
= AR5211DESC_CONST(ds0
)->ds_ctl0
;
599 ads
->ds_ctl1
= segLen
;
600 } else { /* !firstSeg && !lastSeg */
602 * Intermediate descriptor in a multi-descriptor frame.
605 ads
->ds_ctl1
= segLen
| AR_More
;
607 ads
->ds_status0
= ads
->ds_status1
= 0;
612 * Processing of HW TX descriptor.
615 ar5211ProcTxDesc(struct ath_hal
*ah
,
616 struct ath_desc
*ds
, struct ath_tx_status
*ts
)
618 struct ar5211_desc
*ads
= AR5211DESC(ds
);
620 if ((ads
->ds_status1
& AR_Done
) == 0)
621 return HAL_EINPROGRESS
;
623 /* Update software copies of the HW status */
624 ts
->ts_seqnum
= MS(ads
->ds_status1
, AR_SeqNum
);
625 ts
->ts_tstamp
= MS(ads
->ds_status0
, AR_SendTimestamp
);
627 if ((ads
->ds_status0
& AR_FrmXmitOK
) == 0) {
628 if (ads
->ds_status0
& AR_ExcessiveRetries
)
629 ts
->ts_status
|= HAL_TXERR_XRETRY
;
630 if (ads
->ds_status0
& AR_Filtered
)
631 ts
->ts_status
|= HAL_TXERR_FILT
;
632 if (ads
->ds_status0
& AR_FIFOUnderrun
)
633 ts
->ts_status
|= HAL_TXERR_FIFO
;
635 ts
->ts_rate
= MS(ads
->ds_ctl0
, AR_XmitRate
);
636 ts
->ts_rssi
= MS(ads
->ds_status1
, AR_AckSigStrength
);
637 ts
->ts_shortretry
= MS(ads
->ds_status0
, AR_ShortRetryCnt
);
638 ts
->ts_longretry
= MS(ads
->ds_status0
, AR_LongRetryCnt
);
639 ts
->ts_virtcol
= MS(ads
->ds_status0
, AR_VirtCollCnt
);
640 ts
->ts_antenna
= 0; /* NB: don't know */
643 * NB: the number of retries is one less than it should be.
644 * Also, 0 retries and 1 retry are both reported as 0 retries.
646 if (ts
->ts_shortretry
> 0)
648 if (ts
->ts_longretry
> 0)
655 * Determine which tx queues need interrupt servicing.
659 ar5211GetTxIntrQueue(struct ath_hal
*ah
, uint32_t *txqs
)