Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/dev/ath/ath_hal/ar5211/ar5211_xmit.c
39566 views
1
/*-
2
* SPDX-License-Identifier: ISC
3
*
4
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
5
* Copyright (c) 2002-2006 Atheros Communications, Inc.
6
*
7
* Permission to use, copy, modify, and/or distribute this software for any
8
* purpose with or without fee is hereby granted, provided that the above
9
* copyright notice and this permission notice appear in all copies.
10
*
11
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18
*/
19
#include "opt_ah.h"
20
21
#include "ah.h"
22
#include "ah_internal.h"
23
#include "ah_desc.h"
24
25
#include "ar5211/ar5211.h"
26
#include "ar5211/ar5211reg.h"
27
#include "ar5211/ar5211desc.h"
28
29
/*
30
* Update Tx FIFO trigger level.
31
*
32
* Set bIncTrigLevel to TRUE to increase the trigger level.
33
* Set bIncTrigLevel to FALSE to decrease the trigger level.
34
*
35
* Returns TRUE if the trigger level was updated
36
*/
37
HAL_BOOL
38
ar5211UpdateTxTrigLevel(struct ath_hal *ah, HAL_BOOL bIncTrigLevel)
39
{
40
uint32_t curTrigLevel, txcfg;
41
HAL_INT ints = ar5211GetInterrupts(ah);
42
43
/*
44
* Disable chip interrupts. This is because halUpdateTxTrigLevel
45
* is called from both ISR and non-ISR contexts.
46
*/
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;
50
if (bIncTrigLevel){
51
/* increase the trigger level */
52
curTrigLevel = curTrigLevel +
53
((MAX_TX_FIFO_THRESHOLD - curTrigLevel) / 2);
54
} else {
55
/* decrease the trigger level if not already at the minimum */
56
if (curTrigLevel > MIN_TX_FIFO_THRESHOLD) {
57
/* decrease the trigger level */
58
curTrigLevel--;
59
} else {
60
/* no update to the trigger level */
61
/* re-enable chip interrupts */
62
ar5211SetInterrupts(ah, ints);
63
return AH_FALSE;
64
}
65
}
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);
71
return AH_TRUE;
72
}
73
74
/*
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.
78
*/
79
HAL_BOOL
80
ar5211SetTxQueueProps(struct ath_hal *ah, int q, const HAL_TXQ_INFO *qInfo)
81
{
82
struct ath_hal_5211 *ahp = AH5211(ah);
83
84
if (q >= HAL_NUM_TX_QUEUES) {
85
HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n",
86
__func__, q);
87
return AH_FALSE;
88
}
89
return ath_hal_setTxQProps(ah, &ahp->ah_txq[q], qInfo);
90
}
91
92
/*
93
* Return the properties for the specified tx queue.
94
*/
95
HAL_BOOL
96
ar5211GetTxQueueProps(struct ath_hal *ah, int q, HAL_TXQ_INFO *qInfo)
97
{
98
struct ath_hal_5211 *ahp = AH5211(ah);
99
100
if (q >= HAL_NUM_TX_QUEUES) {
101
HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n",
102
__func__, q);
103
return AH_FALSE;
104
}
105
return ath_hal_getTxQProps(ah, qInfo, &ahp->ah_txq[q]);
106
}
107
108
/*
109
* Allocate and initialize a tx DCU/QCU combination.
110
*/
111
int
112
ar5211SetupTxQueue(struct ath_hal *ah, HAL_TX_QUEUE type,
113
const HAL_TXQ_INFO *qInfo)
114
{
115
struct ath_hal_5211 *ahp = AH5211(ah);
116
HAL_TX_QUEUE_INFO *qi;
117
int q;
118
119
switch (type) {
120
case HAL_TX_QUEUE_BEACON:
121
q = 9;
122
break;
123
case HAL_TX_QUEUE_CAB:
124
q = 8;
125
break;
126
case HAL_TX_QUEUE_DATA:
127
q = 0;
128
if (ahp->ah_txq[q].tqi_type != HAL_TX_QUEUE_INACTIVE)
129
return q;
130
break;
131
default:
132
HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad tx queue type %u\n",
133
__func__, type);
134
return -1;
135
}
136
137
HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: queue %u\n", __func__, q);
138
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",
142
__func__, q);
143
return -1;
144
}
145
OS_MEMZERO(qi, sizeof(HAL_TX_QUEUE_INFO));
146
qi->tqi_type = type;
147
if (qInfo == AH_NULL) {
148
/* by default enable OK+ERR+DESC+URN interrupts */
149
qi->tqi_qflags =
150
HAL_TXQ_TXOKINT_ENABLE
151
| HAL_TXQ_TXERRINT_ENABLE
152
| HAL_TXQ_TXDESCINT_ENABLE
153
| HAL_TXQ_TXURNINT_ENABLE
154
;
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;
160
} else
161
(void) ar5211SetTxQueueProps(ah, q, qInfo);
162
return q;
163
}
164
165
/*
166
* Update the h/w interrupt registers to reflect a tx q's configuration.
167
*/
168
static void
169
setTxQInterrupts(struct ath_hal *ah, HAL_TX_QUEUE_INFO *qi)
170
{
171
struct ath_hal_5211 *ahp = AH5211(ah);
172
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
180
);
181
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)
185
);
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)
189
);
190
OS_REG_RMW_FIELD(ah, AR_IMR_S2,
191
AR_IMR_S2_QCU_TXURN, ahp->ah_txUrnInterruptMask);
192
}
193
194
/*
195
* Free a tx DCU/QCU combination.
196
*/
197
HAL_BOOL
198
ar5211ReleaseTxQueue(struct ath_hal *ah, u_int q)
199
{
200
struct ath_hal_5211 *ahp = AH5211(ah);
201
HAL_TX_QUEUE_INFO *qi;
202
203
if (q >= HAL_NUM_TX_QUEUES) {
204
HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n",
205
__func__, q);
206
return AH_FALSE;
207
}
208
qi = &ahp->ah_txq[q];
209
if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) {
210
HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: inactive queue %u\n",
211
__func__, q);
212
return AH_FALSE;
213
}
214
215
HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: release queue %u\n", __func__, q);
216
217
qi->tqi_type = HAL_TX_QUEUE_INACTIVE;
218
ahp->ah_txOkInterruptMask &= ~(1 << q);
219
ahp->ah_txErrInterruptMask &= ~(1 << q);
220
ahp->ah_txDescInterruptMask &= ~(1 << q);
221
ahp->ah_txEolInterruptMask &= ~(1 << q);
222
ahp->ah_txUrnInterruptMask &= ~(1 << q);
223
setTxQInterrupts(ah, qi);
224
225
return AH_TRUE;
226
}
227
228
/*
229
* Set the retry, aifs, cwmin/max, readyTime regs for specified queue
230
*/
231
HAL_BOOL
232
ar5211ResetTxQueue(struct ath_hal *ah, u_int q)
233
{
234
struct ath_hal_5211 *ahp = AH5211(ah);
235
const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan;
236
HAL_TX_QUEUE_INFO *qi;
237
uint32_t cwMin, chanCwMin, value;
238
239
if (q >= HAL_NUM_TX_QUEUES) {
240
HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n",
241
__func__, q);
242
return AH_FALSE;
243
}
244
qi = &ahp->ah_txq[q];
245
if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) {
246
HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: inactive queue %u\n",
247
__func__, q);
248
return AH_TRUE; /* XXX??? */
249
}
250
251
if (qi->tqi_cwmin == HAL_TXQ_USEDEFAULT) {
252
/*
253
* Select cwmin according to channel type.
254
* NB: chan can be NULL during attach
255
*/
256
if (chan && IEEE80211_IS_CHAN_B(chan))
257
chanCwMin = INIT_CWMIN_11B;
258
else
259
chanCwMin = INIT_CWMIN;
260
/* make sure that the CWmin is of the form (2^n - 1) */
261
for (cwMin = 1; cwMin < chanCwMin; cwMin = (cwMin << 1) | 1)
262
;
263
} else
264
cwMin = qi->tqi_cwmin;
265
266
/* set cwMin/Max and AIFS values */
267
OS_REG_WRITE(ah, AR_DLCL_IFS(q),
268
SM(cwMin, AR_D_LCL_IFS_CWMIN)
269
| SM(qi->tqi_cwmax, AR_D_LCL_IFS_CWMAX)
270
| SM(qi->tqi_aifs, AR_D_LCL_IFS_AIFS));
271
272
/* Set retry limit values */
273
OS_REG_WRITE(ah, AR_DRETRY_LIMIT(q),
274
SM(INIT_SSH_RETRY, AR_D_RETRY_LIMIT_STA_SH)
275
| SM(INIT_SLG_RETRY, AR_D_RETRY_LIMIT_STA_LG)
276
| SM(qi->tqi_lgretry, AR_D_RETRY_LIMIT_FR_LG)
277
| SM(qi->tqi_shretry, AR_D_RETRY_LIMIT_FR_SH)
278
);
279
280
/* enable early termination on the QCU */
281
OS_REG_WRITE(ah, AR_QMISC(q), AR_Q_MISC_DCU_EARLY_TERM_REQ);
282
283
if (AH_PRIVATE(ah)->ah_macVersion < AR_SREV_VERSION_OAHU) {
284
/* Configure DCU to use the global sequence count */
285
OS_REG_WRITE(ah, AR_DMISC(q), AR5311_D_MISC_SEQ_NUM_CONTROL);
286
}
287
/* multiqueue support */
288
if (qi->tqi_cbrPeriod) {
289
OS_REG_WRITE(ah, AR_QCBRCFG(q),
290
SM(qi->tqi_cbrPeriod,AR_Q_CBRCFG_CBR_INTERVAL)
291
| SM(qi->tqi_cbrOverflowLimit, AR_Q_CBRCFG_CBR_OVF_THRESH));
292
OS_REG_WRITE(ah, AR_QMISC(q),
293
OS_REG_READ(ah, AR_QMISC(q)) |
294
AR_Q_MISC_FSP_CBR |
295
(qi->tqi_cbrOverflowLimit ?
296
AR_Q_MISC_CBR_EXP_CNTR_LIMIT : 0));
297
}
298
if (qi->tqi_readyTime) {
299
OS_REG_WRITE(ah, AR_QRDYTIMECFG(q),
300
SM(qi->tqi_readyTime, AR_Q_RDYTIMECFG_INT) |
301
AR_Q_RDYTIMECFG_EN);
302
}
303
if (qi->tqi_burstTime) {
304
OS_REG_WRITE(ah, AR_DCHNTIME(q),
305
SM(qi->tqi_burstTime, AR_D_CHNTIME_DUR) |
306
AR_D_CHNTIME_EN);
307
if (qi->tqi_qflags & HAL_TXQ_RDYTIME_EXP_POLICY_ENABLE) {
308
OS_REG_WRITE(ah, AR_QMISC(q),
309
OS_REG_READ(ah, AR_QMISC(q)) |
310
AR_Q_MISC_RDYTIME_EXP_POLICY);
311
}
312
}
313
314
if (qi->tqi_qflags & HAL_TXQ_BACKOFF_DISABLE) {
315
OS_REG_WRITE(ah, AR_DMISC(q),
316
OS_REG_READ(ah, AR_DMISC(q)) |
317
AR_D_MISC_POST_FR_BKOFF_DIS);
318
}
319
if (qi->tqi_qflags & HAL_TXQ_FRAG_BURST_BACKOFF_ENABLE) {
320
OS_REG_WRITE(ah, AR_DMISC(q),
321
OS_REG_READ(ah, AR_DMISC(q)) |
322
AR_D_MISC_FRAG_BKOFF_EN);
323
}
324
switch (qi->tqi_type) {
325
case HAL_TX_QUEUE_BEACON:
326
/* Configure QCU for beacons */
327
OS_REG_WRITE(ah, AR_QMISC(q),
328
OS_REG_READ(ah, AR_QMISC(q))
329
| AR_Q_MISC_FSP_DBA_GATED
330
| AR_Q_MISC_BEACON_USE
331
| AR_Q_MISC_CBR_INCR_DIS1);
332
/* Configure DCU for beacons */
333
value = (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL << AR_D_MISC_ARB_LOCKOUT_CNTRL_S)
334
| AR_D_MISC_BEACON_USE | AR_D_MISC_POST_FR_BKOFF_DIS;
335
if (AH_PRIVATE(ah)->ah_macVersion < AR_SREV_VERSION_OAHU)
336
value |= AR5311_D_MISC_SEQ_NUM_CONTROL;
337
OS_REG_WRITE(ah, AR_DMISC(q), value);
338
break;
339
case HAL_TX_QUEUE_CAB:
340
/* Configure QCU for CAB (Crap After Beacon) frames */
341
OS_REG_WRITE(ah, AR_QMISC(q),
342
OS_REG_READ(ah, AR_QMISC(q))
343
| AR_Q_MISC_FSP_DBA_GATED | AR_Q_MISC_CBR_INCR_DIS1
344
| AR_Q_MISC_CBR_INCR_DIS0 | AR_Q_MISC_RDYTIME_EXP_POLICY);
345
346
value = (ahp->ah_beaconInterval
347
- (ah->ah_config.ah_sw_beacon_response_time
348
- ah->ah_config.ah_dma_beacon_response_time)
349
- ah->ah_config.ah_additional_swba_backoff) * 1024;
350
OS_REG_WRITE(ah, AR_QRDYTIMECFG(q), value | AR_Q_RDYTIMECFG_EN);
351
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);
357
break;
358
default:
359
/* NB: silence compiler */
360
break;
361
}
362
363
/*
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!
367
*
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
372
*/
373
if (qi->tqi_qflags & HAL_TXQ_TXOKINT_ENABLE)
374
ahp->ah_txOkInterruptMask |= 1 << q;
375
else
376
ahp->ah_txOkInterruptMask &= ~(1 << q);
377
if (qi->tqi_qflags & HAL_TXQ_TXERRINT_ENABLE)
378
ahp->ah_txErrInterruptMask |= 1 << q;
379
else
380
ahp->ah_txErrInterruptMask &= ~(1 << q);
381
if (qi->tqi_qflags & HAL_TXQ_TXDESCINT_ENABLE)
382
ahp->ah_txDescInterruptMask |= 1 << q;
383
else
384
ahp->ah_txDescInterruptMask &= ~(1 << q);
385
if (qi->tqi_qflags & HAL_TXQ_TXEOLINT_ENABLE)
386
ahp->ah_txEolInterruptMask |= 1 << q;
387
else
388
ahp->ah_txEolInterruptMask &= ~(1 << q);
389
if (qi->tqi_qflags & HAL_TXQ_TXURNINT_ENABLE)
390
ahp->ah_txUrnInterruptMask |= 1 << q;
391
else
392
ahp->ah_txUrnInterruptMask &= ~(1 << q);
393
setTxQInterrupts(ah, qi);
394
395
return AH_TRUE;
396
}
397
398
/*
399
* Get the TXDP for the specified data queue.
400
*/
401
uint32_t
402
ar5211GetTxDP(struct ath_hal *ah, u_int q)
403
{
404
HALASSERT(q < HAL_NUM_TX_QUEUES);
405
return OS_REG_READ(ah, AR_QTXDP(q));
406
}
407
408
/*
409
* Set the TxDP for the specified tx queue.
410
*/
411
HAL_BOOL
412
ar5211SetTxDP(struct ath_hal *ah, u_int q, uint32_t txdp)
413
{
414
HALASSERT(q < HAL_NUM_TX_QUEUES);
415
HALASSERT(AH5211(ah)->ah_txq[q].tqi_type != HAL_TX_QUEUE_INACTIVE);
416
417
/*
418
* Make sure that TXE is deasserted before setting the TXDP. If TXE
419
* is still asserted, setting TXDP will have no effect.
420
*/
421
HALASSERT((OS_REG_READ(ah, AR_Q_TXE) & (1 << q)) == 0);
422
423
OS_REG_WRITE(ah, AR_QTXDP(q), txdp);
424
425
return AH_TRUE;
426
}
427
428
/*
429
* Set Transmit Enable bits for the specified queues.
430
*/
431
HAL_BOOL
432
ar5211StartTxDma(struct ath_hal *ah, u_int q)
433
{
434
HALASSERT(q < HAL_NUM_TX_QUEUES);
435
HALASSERT(AH5211(ah)->ah_txq[q].tqi_type != HAL_TX_QUEUE_INACTIVE);
436
437
/* Check that queue is not already active */
438
HALASSERT((OS_REG_READ(ah, AR_Q_TXD) & (1<<q)) == 0);
439
440
HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: queue %u\n", __func__, q);
441
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);
444
445
OS_REG_WRITE(ah, AR_Q_TXE, 1 << q);
446
return AH_TRUE;
447
}
448
449
/*
450
* Return the number of frames pending on the specified queue.
451
*/
452
uint32_t
453
ar5211NumTxPending(struct ath_hal *ah, u_int q)
454
{
455
uint32_t n;
456
457
HALASSERT(q < HAL_NUM_TX_QUEUES);
458
HALASSERT(AH5211(ah)->ah_txq[q].tqi_type != HAL_TX_QUEUE_INACTIVE);
459
460
n = OS_REG_READ(ah, AR_QSTS(q)) & AR_Q_STS_PEND_FR_CNT_M;
461
/*
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.
465
*/
466
if (n == 0 && (OS_REG_READ(ah, AR_Q_TXE) & (1<<q)))
467
n = 1; /* arbitrarily pick 1 */
468
return n;
469
}
470
471
/*
472
* Stop transmit on the specified queue
473
*/
474
HAL_BOOL
475
ar5211StopTxDma(struct ath_hal *ah, u_int q)
476
{
477
int i;
478
479
HALASSERT(q < HAL_NUM_TX_QUEUES);
480
HALASSERT(AH5211(ah)->ah_txq[q].tqi_type != HAL_TX_QUEUE_INACTIVE);
481
482
OS_REG_WRITE(ah, AR_Q_TXD, 1<<q);
483
for (i = 0; i < 10000; i++) {
484
if (ar5211NumTxPending(ah, q) == 0)
485
break;
486
OS_DELAY(10);
487
}
488
OS_REG_WRITE(ah, AR_Q_TXD, 0);
489
490
return (i < 10000);
491
}
492
493
/*
494
* Descriptor Access Functions
495
*/
496
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)
507
508
HAL_BOOL
509
ar5211SetupTxDesc(struct ath_hal *ah, struct ath_desc *ds,
510
u_int pktLen,
511
u_int hdrLen,
512
HAL_PKT_TYPE type,
513
u_int txPower,
514
u_int txRate0, u_int txTries0,
515
u_int keyIx,
516
u_int antMode,
517
u_int flags,
518
u_int rtsctsRate,
519
u_int rtsctsDuration,
520
u_int compicvLen,
521
u_int compivLen,
522
u_int comp)
523
{
524
struct ar5211_desc *ads = AR5211DESC(ds);
525
526
(void) hdrLen;
527
(void) txPower;
528
(void) rtsctsRate; (void) rtsctsDuration;
529
530
HALASSERT(txTries0 != 0);
531
HALASSERT(isValidPktType(type));
532
HALASSERT(isValidTxRate(txRate0));
533
/* XXX validate antMode */
534
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)
542
;
543
ads->ds_ctl1 = (type << 26)
544
| (flags & HAL_TXDESC_NOACK ? AR_NoAck : 0)
545
;
546
547
if (keyIx != HAL_TXKEYIX_INVALID) {
548
ads->ds_ctl1 |=
549
(keyIx << AR_EncryptKeyIdx_S) & AR_EncryptKeyIdx;
550
ads->ds_ctl0 |= AR_EncryptKeyValid;
551
}
552
return AH_TRUE;
553
#undef RATE
554
}
555
556
HAL_BOOL
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)
561
{
562
(void) ah; (void) ds;
563
(void) txRate1; (void) txTries1;
564
(void) txRate2; (void) txTries2;
565
(void) txRate3; (void) txTries3;
566
return AH_FALSE;
567
}
568
569
void
570
ar5211IntrReqTxDesc(struct ath_hal *ah, struct ath_desc *ds)
571
{
572
struct ar5211_desc *ads = AR5211DESC(ds);
573
574
ads->ds_ctl0 |= AR_TxInterReq;
575
}
576
577
HAL_BOOL
578
ar5211FillTxDesc(struct ath_hal *ah, struct ath_desc *ds,
579
HAL_DMA_ADDR *bufAddrList, uint32_t *segLenList, u_int qcuId,
580
u_int descId, HAL_BOOL firstSeg, HAL_BOOL lastSeg,
581
const struct ath_desc *ds0)
582
{
583
struct ar5211_desc *ads = AR5211DESC(ds);
584
uint32_t segLen = segLenList[0];
585
586
ds->ds_data = bufAddrList[0];
587
588
HALASSERT((segLen &~ AR_BufLen) == 0);
589
590
if (firstSeg) {
591
/*
592
* First descriptor, don't clobber xmit control data
593
* setup by ar5211SetupTxDesc.
594
*/
595
ads->ds_ctl1 |= segLen | (lastSeg ? 0 : AR_More);
596
} else if (lastSeg) { /* !firstSeg && lastSeg */
597
/*
598
* Last descriptor in a multi-descriptor frame,
599
* copy the transmit parameters from the first
600
* frame for processing on completion.
601
*/
602
ads->ds_ctl0 = AR5211DESC_CONST(ds0)->ds_ctl0;
603
ads->ds_ctl1 = segLen;
604
} else { /* !firstSeg && !lastSeg */
605
/*
606
* Intermediate descriptor in a multi-descriptor frame.
607
*/
608
ads->ds_ctl0 = 0;
609
ads->ds_ctl1 = segLen | AR_More;
610
}
611
ads->ds_status0 = ads->ds_status1 = 0;
612
return AH_TRUE;
613
}
614
615
/*
616
* Processing of HW TX descriptor.
617
*/
618
HAL_STATUS
619
ar5211ProcTxDesc(struct ath_hal *ah,
620
struct ath_desc *ds, struct ath_tx_status *ts)
621
{
622
struct ar5211_desc *ads = AR5211DESC(ds);
623
624
if ((ads->ds_status1 & AR_Done) == 0)
625
return HAL_EINPROGRESS;
626
627
/* Update software copies of the HW status */
628
ts->ts_seqnum = MS(ads->ds_status1, AR_SeqNum);
629
ts->ts_tstamp = MS(ads->ds_status0, AR_SendTimestamp);
630
ts->ts_status = 0;
631
if ((ads->ds_status0 & AR_FrmXmitOK) == 0) {
632
if (ads->ds_status0 & AR_ExcessiveRetries)
633
ts->ts_status |= HAL_TXERR_XRETRY;
634
if (ads->ds_status0 & AR_Filtered)
635
ts->ts_status |= HAL_TXERR_FILT;
636
if (ads->ds_status0 & AR_FIFOUnderrun)
637
ts->ts_status |= HAL_TXERR_FIFO;
638
}
639
ts->ts_rate = MS(ads->ds_ctl0, AR_XmitRate);
640
ts->ts_rssi = MS(ads->ds_status1, AR_AckSigStrength);
641
ts->ts_shortretry = MS(ads->ds_status0, AR_ShortRetryCnt);
642
ts->ts_longretry = MS(ads->ds_status0, AR_LongRetryCnt);
643
ts->ts_virtcol = MS(ads->ds_status0, AR_VirtCollCnt);
644
ts->ts_antenna = 0; /* NB: don't know */
645
ts->ts_finaltsi = 0;
646
/*
647
* NB: the number of retries is one less than it should be.
648
* Also, 0 retries and 1 retry are both reported as 0 retries.
649
*/
650
if (ts->ts_shortretry > 0)
651
ts->ts_shortretry++;
652
if (ts->ts_longretry > 0)
653
ts->ts_longretry++;
654
655
return HAL_OK;
656
}
657
658
/*
659
* Determine which tx queues need interrupt servicing.
660
* STUB.
661
*/
662
void
663
ar5211GetTxIntrQueue(struct ath_hal *ah, uint32_t *txqs)
664
{
665
return;
666
}
667
668
/*
669
* Retrieve the rate table from the given TX completion descriptor
670
*/
671
HAL_BOOL
672
ar5211GetTxCompletionRates(struct ath_hal *ah, const struct ath_desc *ds0, int *rates, int *tries)
673
{
674
return AH_FALSE;
675
}
676
677
void
678
ar5211SetTxDescLink(struct ath_hal *ah, void *ds, uint32_t link)
679
{
680
struct ar5211_desc *ads = AR5211DESC(ds);
681
682
ads->ds_link = link;
683
}
684
685
void
686
ar5211GetTxDescLink(struct ath_hal *ah, void *ds, uint32_t *link)
687
{
688
struct ar5211_desc *ads = AR5211DESC(ds);
689
690
*link = ads->ds_link;
691
}
692
693
void
694
ar5211GetTxDescLinkPtr(struct ath_hal *ah, void *ds, uint32_t **linkptr)
695
{
696
struct ar5211_desc *ads = AR5211DESC(ds);
697
698
*linkptr = &ads->ds_link;
699
}
700
701