1 | /* |
2 | * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting |
3 | * Copyright (c) 2002-2004 Atheros Communications, Inc. |
4 | * |
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. |
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 | * $Id: ar5210_xmit.c,v 1.1.1.1 2008/12/11 04:46:29 alc Exp $ |
18 | */ |
19 | #include "opt_ah.h" |
20 | |
21 | #include "ah.h" |
22 | #include "ah_internal.h" |
23 | #include "ah_desc.h" |
24 | |
25 | #include "ar5210/ar5210.h" |
26 | #include "ar5210/ar5210reg.h" |
27 | #include "ar5210/ar5210phy.h" |
28 | #include "ar5210/ar5210desc.h" |
29 | |
30 | /* |
31 | * Set the properties of the tx queue with the parameters |
32 | * from qInfo. The queue must previously have been setup |
33 | * with a call to ar5210SetupTxQueue. |
34 | */ |
35 | HAL_BOOL |
36 | ar5210SetTxQueueProps(struct ath_hal *ah, int q, const HAL_TXQ_INFO *qInfo) |
37 | { |
38 | struct ath_hal_5210 *ahp = AH5210(ah); |
39 | |
40 | if (q >= HAL_NUM_TX_QUEUES) { |
41 | HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n" , |
42 | __func__, q); |
43 | return AH_FALSE; |
44 | } |
45 | return ath_hal_setTxQProps(ah, &ahp->ah_txq[q], qInfo); |
46 | } |
47 | |
48 | /* |
49 | * Return the properties for the specified tx queue. |
50 | */ |
51 | HAL_BOOL |
52 | ar5210GetTxQueueProps(struct ath_hal *ah, int q, HAL_TXQ_INFO *qInfo) |
53 | { |
54 | struct ath_hal_5210 *ahp = AH5210(ah); |
55 | |
56 | if (q >= HAL_NUM_TX_QUEUES) { |
57 | HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n" , |
58 | __func__, q); |
59 | return AH_FALSE; |
60 | } |
61 | return ath_hal_getTxQProps(ah, qInfo, &ahp->ah_txq[q]); |
62 | } |
63 | |
64 | /* |
65 | * Allocate and initialize a tx DCU/QCU combination. |
66 | */ |
67 | int |
68 | ar5210SetupTxQueue(struct ath_hal *ah, HAL_TX_QUEUE type, |
69 | const HAL_TXQ_INFO *qInfo) |
70 | { |
71 | struct ath_hal_5210 *ahp = AH5210(ah); |
72 | HAL_TX_QUEUE_INFO *qi; |
73 | int q; |
74 | |
75 | switch (type) { |
76 | case HAL_TX_QUEUE_BEACON: |
77 | q = 2; |
78 | break; |
79 | case HAL_TX_QUEUE_CAB: |
80 | q = 1; |
81 | break; |
82 | case HAL_TX_QUEUE_DATA: |
83 | q = 0; |
84 | break; |
85 | default: |
86 | HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad tx queue type %u\n" , |
87 | __func__, type); |
88 | return -1; |
89 | } |
90 | |
91 | HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: queue %u\n" , __func__, q); |
92 | |
93 | qi = &ahp->ah_txq[q]; |
94 | if (qi->tqi_type != HAL_TX_QUEUE_INACTIVE) { |
95 | HALDEBUG(ah, HAL_DEBUG_ANY, "%s: tx queue %u already active\n" , |
96 | __func__, q); |
97 | return -1; |
98 | } |
99 | OS_MEMZERO(qi, sizeof(HAL_TX_QUEUE_INFO)); |
100 | qi->tqi_type = type; |
101 | if (qInfo == AH_NULL) { |
102 | /* by default enable OK+ERR+DESC+URN interrupts */ |
103 | qi->tqi_qflags = |
104 | HAL_TXQ_TXOKINT_ENABLE |
105 | | HAL_TXQ_TXERRINT_ENABLE |
106 | | HAL_TXQ_TXDESCINT_ENABLE |
107 | | HAL_TXQ_TXURNINT_ENABLE |
108 | ; |
109 | qi->tqi_aifs = INIT_AIFS; |
110 | qi->tqi_cwmin = HAL_TXQ_USEDEFAULT; /* NB: do at reset */ |
111 | qi->tqi_shretry = INIT_SH_RETRY; |
112 | qi->tqi_lgretry = INIT_LG_RETRY; |
113 | } else |
114 | (void) ar5210SetTxQueueProps(ah, q, qInfo); |
115 | /* NB: must be followed by ar5210ResetTxQueue */ |
116 | return q; |
117 | } |
118 | |
119 | /* |
120 | * Free a tx DCU/QCU combination. |
121 | */ |
122 | HAL_BOOL |
123 | ar5210ReleaseTxQueue(struct ath_hal *ah, u_int q) |
124 | { |
125 | struct ath_hal_5210 *ahp = AH5210(ah); |
126 | HAL_TX_QUEUE_INFO *qi; |
127 | |
128 | if (q >= HAL_NUM_TX_QUEUES) { |
129 | HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n" , |
130 | __func__, q); |
131 | return AH_FALSE; |
132 | } |
133 | qi = &ahp->ah_txq[q]; |
134 | if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) { |
135 | HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: inactive queue %u\n" , |
136 | __func__, q); |
137 | return AH_FALSE; |
138 | } |
139 | |
140 | HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: release queue %u\n" , __func__, q); |
141 | |
142 | qi->tqi_type = HAL_TX_QUEUE_INACTIVE; |
143 | ahp->ah_txOkInterruptMask &= ~(1 << q); |
144 | ahp->ah_txErrInterruptMask &= ~(1 << q); |
145 | ahp->ah_txDescInterruptMask &= ~(1 << q); |
146 | ahp->ah_txEolInterruptMask &= ~(1 << q); |
147 | ahp->ah_txUrnInterruptMask &= ~(1 << q); |
148 | |
149 | return AH_TRUE; |
150 | #undef N |
151 | } |
152 | |
153 | HAL_BOOL |
154 | ar5210ResetTxQueue(struct ath_hal *ah, u_int q) |
155 | { |
156 | struct ath_hal_5210 *ahp = AH5210(ah); |
157 | HAL_CHANNEL_INTERNAL *chan = AH_PRIVATE(ah)->ah_curchan; |
158 | HAL_TX_QUEUE_INFO *qi; |
159 | uint32_t cwMin; |
160 | |
161 | if (q >= HAL_NUM_TX_QUEUES) { |
162 | HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n" , |
163 | __func__, q); |
164 | return AH_FALSE; |
165 | } |
166 | qi = &ahp->ah_txq[q]; |
167 | if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) { |
168 | HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: inactive queue %u\n" , |
169 | __func__, q); |
170 | return AH_FALSE; |
171 | } |
172 | |
173 | /* |
174 | * Ignore any non-data queue(s). |
175 | */ |
176 | if (qi->tqi_type != HAL_TX_QUEUE_DATA) |
177 | return AH_TRUE; |
178 | |
179 | /* Set turbo mode / base mode parameters on or off */ |
180 | if (IS_CHAN_TURBO(chan)) { |
181 | OS_REG_WRITE(ah, AR_SLOT_TIME, INIT_SLOT_TIME_TURBO); |
182 | OS_REG_WRITE(ah, AR_TIME_OUT, INIT_ACK_CTS_TIMEOUT_TURBO); |
183 | OS_REG_WRITE(ah, AR_USEC, INIT_TRANSMIT_LATENCY_TURBO); |
184 | OS_REG_WRITE(ah, AR_IFS0, |
185 | ((INIT_SIFS_TURBO + qi->tqi_aifs * INIT_SLOT_TIME_TURBO) |
186 | << AR_IFS0_DIFS_S) |
187 | | INIT_SIFS_TURBO); |
188 | OS_REG_WRITE(ah, AR_IFS1, INIT_PROTO_TIME_CNTRL_TURBO); |
189 | OS_REG_WRITE(ah, AR_PHY(17), |
190 | (OS_REG_READ(ah, AR_PHY(17)) & ~0x7F) | 0x38); |
191 | OS_REG_WRITE(ah, AR_PHY_FRCTL, |
192 | AR_PHY_SERVICE_ERR | AR_PHY_TXURN_ERR | |
193 | AR_PHY_ILLLEN_ERR | AR_PHY_ILLRATE_ERR | |
194 | AR_PHY_PARITY_ERR | AR_PHY_TIMING_ERR | |
195 | 0x2020 | |
196 | AR_PHY_TURBO_MODE | AR_PHY_TURBO_SHORT); |
197 | } else { |
198 | OS_REG_WRITE(ah, AR_SLOT_TIME, INIT_SLOT_TIME); |
199 | OS_REG_WRITE(ah, AR_TIME_OUT, INIT_ACK_CTS_TIMEOUT); |
200 | OS_REG_WRITE(ah, AR_USEC, INIT_TRANSMIT_LATENCY); |
201 | OS_REG_WRITE(ah, AR_IFS0, |
202 | ((INIT_SIFS + qi->tqi_aifs * INIT_SLOT_TIME) |
203 | << AR_IFS0_DIFS_S) |
204 | | INIT_SIFS); |
205 | OS_REG_WRITE(ah, AR_IFS1, INIT_PROTO_TIME_CNTRL); |
206 | OS_REG_WRITE(ah, AR_PHY(17), |
207 | (OS_REG_READ(ah, AR_PHY(17)) & ~0x7F) | 0x1C); |
208 | OS_REG_WRITE(ah, AR_PHY_FRCTL, |
209 | AR_PHY_SERVICE_ERR | AR_PHY_TXURN_ERR | |
210 | AR_PHY_ILLLEN_ERR | AR_PHY_ILLRATE_ERR | |
211 | AR_PHY_PARITY_ERR | AR_PHY_TIMING_ERR | 0x1020); |
212 | } |
213 | |
214 | if (qi->tqi_cwmin == HAL_TXQ_USEDEFAULT) |
215 | cwMin = INIT_CWMIN; |
216 | else |
217 | cwMin = qi->tqi_cwmin; |
218 | |
219 | /* Set cwmin and retry limit values */ |
220 | OS_REG_WRITE(ah, AR_RETRY_LMT, |
221 | (cwMin << AR_RETRY_LMT_CW_MIN_S) |
222 | | SM(INIT_SLG_RETRY, AR_RETRY_LMT_SLG_RETRY) |
223 | | SM(INIT_SSH_RETRY, AR_RETRY_LMT_SSH_RETRY) |
224 | | SM(qi->tqi_lgretry, AR_RETRY_LMT_LG_RETRY) |
225 | | SM(qi->tqi_shretry, AR_RETRY_LMT_SH_RETRY) |
226 | ); |
227 | |
228 | if (qi->tqi_qflags & HAL_TXQ_TXOKINT_ENABLE) |
229 | ahp->ah_txOkInterruptMask |= 1 << q; |
230 | else |
231 | ahp->ah_txOkInterruptMask &= ~(1 << q); |
232 | if (qi->tqi_qflags & HAL_TXQ_TXERRINT_ENABLE) |
233 | ahp->ah_txErrInterruptMask |= 1 << q; |
234 | else |
235 | ahp->ah_txErrInterruptMask &= ~(1 << q); |
236 | if (qi->tqi_qflags & HAL_TXQ_TXDESCINT_ENABLE) |
237 | ahp->ah_txDescInterruptMask |= 1 << q; |
238 | else |
239 | ahp->ah_txDescInterruptMask &= ~(1 << q); |
240 | if (qi->tqi_qflags & HAL_TXQ_TXEOLINT_ENABLE) |
241 | ahp->ah_txEolInterruptMask |= 1 << q; |
242 | else |
243 | ahp->ah_txEolInterruptMask &= ~(1 << q); |
244 | if (qi->tqi_qflags & HAL_TXQ_TXURNINT_ENABLE) |
245 | ahp->ah_txUrnInterruptMask |= 1 << q; |
246 | else |
247 | ahp->ah_txUrnInterruptMask &= ~(1 << q); |
248 | |
249 | return AH_TRUE; |
250 | } |
251 | |
252 | /* |
253 | * Get the TXDP for the "main" data queue. Needs to be extended |
254 | * for multiple Q functionality |
255 | */ |
256 | uint32_t |
257 | ar5210GetTxDP(struct ath_hal *ah, u_int q) |
258 | { |
259 | struct ath_hal_5210 *ahp = AH5210(ah); |
260 | HAL_TX_QUEUE_INFO *qi; |
261 | |
262 | HALASSERT(q < HAL_NUM_TX_QUEUES); |
263 | |
264 | qi = &ahp->ah_txq[q]; |
265 | switch (qi->tqi_type) { |
266 | case HAL_TX_QUEUE_DATA: |
267 | return OS_REG_READ(ah, AR_TXDP0); |
268 | case HAL_TX_QUEUE_INACTIVE: |
269 | HALDEBUG(ah, HAL_DEBUG_ANY, "%s: inactive queue %u\n" , |
270 | __func__, q); |
271 | /* fall thru... */ |
272 | default: |
273 | break; |
274 | } |
275 | return 0xffffffff; |
276 | } |
277 | |
278 | /* |
279 | * Set the TxDP for the "main" data queue. |
280 | */ |
281 | HAL_BOOL |
282 | ar5210SetTxDP(struct ath_hal *ah, u_int q, uint32_t txdp) |
283 | { |
284 | struct ath_hal_5210 *ahp = AH5210(ah); |
285 | HAL_TX_QUEUE_INFO *qi; |
286 | |
287 | HALASSERT(q < HAL_NUM_TX_QUEUES); |
288 | |
289 | HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: queue %u 0x%x\n" , |
290 | __func__, q, txdp); |
291 | qi = &ahp->ah_txq[q]; |
292 | switch (qi->tqi_type) { |
293 | case HAL_TX_QUEUE_DATA: |
294 | #ifdef AH_DEBUG |
295 | /* |
296 | * Make sure that TXE is deasserted before setting the |
297 | * TXDP. If TXE is still asserted, setting TXDP will |
298 | * have no effect. |
299 | */ |
300 | if (OS_REG_READ(ah, AR_CR) & AR_CR_TXE0) |
301 | ath_hal_printf(ah, "%s: TXE asserted; AR_CR=0x%x\n" , |
302 | __func__, OS_REG_READ(ah, AR_CR)); |
303 | #endif |
304 | OS_REG_WRITE(ah, AR_TXDP0, txdp); |
305 | break; |
306 | case HAL_TX_QUEUE_BEACON: |
307 | case HAL_TX_QUEUE_CAB: |
308 | OS_REG_WRITE(ah, AR_TXDP1, txdp); |
309 | break; |
310 | case HAL_TX_QUEUE_INACTIVE: |
311 | HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: inactive queue %u\n" , |
312 | __func__, q); |
313 | /* fall thru... */ |
314 | default: |
315 | return AH_FALSE; |
316 | } |
317 | return AH_TRUE; |
318 | } |
319 | |
320 | /* |
321 | * Update Tx FIFO trigger level. |
322 | * |
323 | * Set bIncTrigLevel to TRUE to increase the trigger level. |
324 | * Set bIncTrigLevel to FALSE to decrease the trigger level. |
325 | * |
326 | * Returns TRUE if the trigger level was updated |
327 | */ |
328 | HAL_BOOL |
329 | ar5210UpdateTxTrigLevel(struct ath_hal *ah, HAL_BOOL bIncTrigLevel) |
330 | { |
331 | uint32_t curTrigLevel; |
332 | HAL_INT ints = ar5210GetInterrupts(ah); |
333 | |
334 | /* |
335 | * Disable chip interrupts. This is because halUpdateTxTrigLevel |
336 | * is called from both ISR and non-ISR contexts. |
337 | */ |
338 | (void) ar5210SetInterrupts(ah, ints &~ HAL_INT_GLOBAL); |
339 | curTrigLevel = OS_REG_READ(ah, AR_TRIG_LEV); |
340 | if (bIncTrigLevel){ |
341 | /* increase the trigger level */ |
342 | curTrigLevel = curTrigLevel + |
343 | ((MAX_TX_FIFO_THRESHOLD - curTrigLevel) / 2); |
344 | } else { |
345 | /* decrease the trigger level if not already at the minimum */ |
346 | if (curTrigLevel > MIN_TX_FIFO_THRESHOLD) { |
347 | /* decrease the trigger level */ |
348 | curTrigLevel--; |
349 | } else { |
350 | /* no update to the trigger level */ |
351 | /* re-enable chip interrupts */ |
352 | ar5210SetInterrupts(ah, ints); |
353 | return AH_FALSE; |
354 | } |
355 | } |
356 | /* Update the trigger level */ |
357 | OS_REG_WRITE(ah, AR_TRIG_LEV, curTrigLevel); |
358 | /* re-enable chip interrupts */ |
359 | ar5210SetInterrupts(ah, ints); |
360 | return AH_TRUE; |
361 | } |
362 | |
363 | /* |
364 | * Set Transmit Enable bits for the specified queues. |
365 | */ |
366 | HAL_BOOL |
367 | ar5210StartTxDma(struct ath_hal *ah, u_int q) |
368 | { |
369 | struct ath_hal_5210 *ahp = AH5210(ah); |
370 | HAL_TX_QUEUE_INFO *qi; |
371 | |
372 | HALASSERT(q < HAL_NUM_TX_QUEUES); |
373 | |
374 | HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: queue %u\n" , __func__, q); |
375 | qi = &ahp->ah_txq[q]; |
376 | switch (qi->tqi_type) { |
377 | case HAL_TX_QUEUE_DATA: |
378 | OS_REG_WRITE(ah, AR_CR, AR_CR_TXE0); |
379 | break; |
380 | case HAL_TX_QUEUE_CAB: |
381 | OS_REG_WRITE(ah, AR_CR, AR_CR_TXE1); /* enable altq xmit */ |
382 | OS_REG_WRITE(ah, AR_BCR, |
383 | AR_BCR_TQ1V | AR_BCR_BDMAE | AR_BCR_TQ1FV); |
384 | break; |
385 | case HAL_TX_QUEUE_BEACON: |
386 | /* XXX add CR_BCR_BCMD if IBSS mode */ |
387 | OS_REG_WRITE(ah, AR_BCR, AR_BCR_TQ1V | AR_BCR_BDMAE); |
388 | break; |
389 | case HAL_TX_QUEUE_INACTIVE: |
390 | HALDEBUG(ah, HAL_DEBUG_ANY, "%s: inactive queue %u\n" , |
391 | __func__, q); |
392 | /* fal thru... */ |
393 | default: |
394 | return AH_FALSE; |
395 | } |
396 | return AH_TRUE; |
397 | } |
398 | |
399 | uint32_t |
400 | ar5210NumTxPending(struct ath_hal *ah, u_int q) |
401 | { |
402 | struct ath_hal_5210 *ahp = AH5210(ah); |
403 | HAL_TX_QUEUE_INFO *qi; |
404 | uint32_t v; |
405 | |
406 | HALASSERT(q < HAL_NUM_TX_QUEUES); |
407 | |
408 | HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: queue %u\n" , __func__, q); |
409 | qi = &ahp->ah_txq[q]; |
410 | switch (qi->tqi_type) { |
411 | case HAL_TX_QUEUE_DATA: |
412 | v = OS_REG_READ(ah, AR_CFG); |
413 | return MS(v, AR_CFG_TXCNT); |
414 | case HAL_TX_QUEUE_INACTIVE: |
415 | HALDEBUG(ah, HAL_DEBUG_ANY, "%s: inactive queue %u\n" , |
416 | __func__, q); |
417 | /* fall thru... */ |
418 | default: |
419 | break; |
420 | } |
421 | return 0; |
422 | } |
423 | |
424 | /* |
425 | * Stop transmit on the specified queue |
426 | */ |
427 | HAL_BOOL |
428 | ar5210StopTxDma(struct ath_hal *ah, u_int q) |
429 | { |
430 | struct ath_hal_5210 *ahp = AH5210(ah); |
431 | HAL_TX_QUEUE_INFO *qi; |
432 | |
433 | HALASSERT(q < HAL_NUM_TX_QUEUES); |
434 | |
435 | HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: queue %u\n" , __func__, q); |
436 | qi = &ahp->ah_txq[q]; |
437 | switch (qi->tqi_type) { |
438 | case HAL_TX_QUEUE_DATA: { |
439 | int i; |
440 | OS_REG_WRITE(ah, AR_CR, AR_CR_TXD0); |
441 | for (i = 0; i < 1000; i++) { |
442 | if ((OS_REG_READ(ah, AR_CFG) & AR_CFG_TXCNT) == 0) |
443 | break; |
444 | OS_DELAY(10); |
445 | } |
446 | OS_REG_WRITE(ah, AR_CR, 0); |
447 | return (i < 1000); |
448 | } |
449 | case HAL_TX_QUEUE_BEACON: |
450 | return ath_hal_wait(ah, AR_BSR, AR_BSR_TXQ1F, 0); |
451 | case HAL_TX_QUEUE_INACTIVE: |
452 | HALDEBUG(ah, HAL_DEBUG_ANY, "%s: inactive queue %u\n" , |
453 | __func__, q); |
454 | /* fall thru... */ |
455 | default: |
456 | break; |
457 | } |
458 | return AH_FALSE; |
459 | } |
460 | |
461 | /* |
462 | * Descriptor Access Functions |
463 | */ |
464 | |
465 | #define VALID_PKT_TYPES \ |
466 | ((1<<HAL_PKT_TYPE_NORMAL)|(1<<HAL_PKT_TYPE_ATIM)|\ |
467 | (1<<HAL_PKT_TYPE_PSPOLL)|(1<<HAL_PKT_TYPE_PROBE_RESP)|\ |
468 | (1<<HAL_PKT_TYPE_BEACON)) |
469 | #define isValidPktType(_t) ((1<<(_t)) & VALID_PKT_TYPES) |
470 | #define VALID_TX_RATES \ |
471 | ((1<<0x0b)|(1<<0x0f)|(1<<0x0a)|(1<<0x0e)|(1<<0x09)|(1<<0x0d)|\ |
472 | (1<<0x08)|(1<<0x0c)|(1<<0x1b)|(1<<0x1a)|(1<<0x1e)|(1<<0x19)|\ |
473 | (1<<0x1d)|(1<<0x18)|(1<<0x1c)) |
474 | #define isValidTxRate(_r) ((1<<(_r)) & VALID_TX_RATES) |
475 | |
476 | HAL_BOOL |
477 | ar5210SetupTxDesc(struct ath_hal *ah, struct ath_desc *ds, |
478 | u_int pktLen, |
479 | u_int hdrLen, |
480 | HAL_PKT_TYPE type, |
481 | u_int txPower, |
482 | u_int txRate0, u_int txTries0, |
483 | u_int keyIx, |
484 | u_int antMode, |
485 | u_int flags, |
486 | u_int rtsctsRate, |
487 | u_int rtsctsDuration, |
488 | u_int compicvLen, |
489 | u_int compivLen, |
490 | u_int comp) |
491 | { |
492 | struct ar5210_desc *ads = AR5210DESC(ds); |
493 | uint32_t frtype; |
494 | |
495 | (void) txPower; |
496 | (void) rtsctsDuration; |
497 | |
498 | HALASSERT(txTries0 != 0); |
499 | HALASSERT(isValidPktType(type)); |
500 | HALASSERT(isValidTxRate(txRate0)); |
501 | |
502 | if (type == HAL_PKT_TYPE_BEACON || type == HAL_PKT_TYPE_PROBE_RESP) |
503 | frtype = AR_Frm_NoDelay; |
504 | else |
505 | frtype = type << 26; |
506 | ads->ds_ctl0 = (pktLen & AR_FrameLen) |
507 | | (txRate0 << AR_XmitRate_S) |
508 | | ((hdrLen << AR_HdrLen_S) & AR_HdrLen) |
509 | | frtype |
510 | | (flags & HAL_TXDESC_CLRDMASK ? AR_ClearDestMask : 0) |
511 | | (flags & HAL_TXDESC_INTREQ ? AR_TxInterReq : 0) |
512 | | (antMode ? AR_AntModeXmit : 0) |
513 | ; |
514 | if (keyIx != HAL_TXKEYIX_INVALID) { |
515 | ads->ds_ctl1 = (keyIx << AR_EncryptKeyIdx_S) & AR_EncryptKeyIdx; |
516 | ads->ds_ctl0 |= AR_EncryptKeyValid; |
517 | } else |
518 | ads->ds_ctl1 = 0; |
519 | if (flags & HAL_TXDESC_RTSENA) { |
520 | ads->ds_ctl0 |= AR_RTSCTSEnable; |
521 | ads->ds_ctl1 |= rtsctsDuration & AR_RTSDuration; |
522 | } |
523 | return AH_TRUE; |
524 | } |
525 | |
526 | HAL_BOOL |
527 | ar5210SetupXTxDesc(struct ath_hal *ah, struct ath_desc *ds, |
528 | u_int txRate1, u_int txTries1, |
529 | u_int txRate2, u_int txTries2, |
530 | u_int txRate3, u_int txTries3) |
531 | { |
532 | (void) ah; (void) ds; |
533 | (void) txRate1; (void) txTries1; |
534 | (void) txRate2; (void) txTries2; |
535 | (void) txRate3; (void) txTries3; |
536 | return AH_FALSE; |
537 | } |
538 | |
539 | void |
540 | ar5210IntrReqTxDesc(struct ath_hal *ah, struct ath_desc *ds) |
541 | { |
542 | struct ar5210_desc *ads = AR5210DESC(ds); |
543 | |
544 | ads->ds_ctl0 |= AR_TxInterReq; |
545 | } |
546 | |
547 | HAL_BOOL |
548 | ar5210FillTxDesc(struct ath_hal *ah, struct ath_desc *ds, |
549 | u_int segLen, HAL_BOOL firstSeg, HAL_BOOL lastSeg, |
550 | const struct ath_desc *ds0) |
551 | { |
552 | struct ar5210_desc *ads = AR5210DESC(ds); |
553 | |
554 | HALASSERT((segLen &~ AR_BufLen) == 0); |
555 | |
556 | if (firstSeg) { |
557 | /* |
558 | * First descriptor, don't clobber xmit control data |
559 | * setup by ar5210SetupTxDesc. |
560 | */ |
561 | ads->ds_ctl1 |= segLen | (lastSeg ? 0 : AR_More); |
562 | } else if (lastSeg) { /* !firstSeg && lastSeg */ |
563 | /* |
564 | * Last descriptor in a multi-descriptor frame, |
565 | * copy the transmit parameters from the first |
566 | * frame for processing on completion. |
567 | */ |
568 | ads->ds_ctl0 = AR5210DESC_CONST(ds0)->ds_ctl0; |
569 | ads->ds_ctl1 = segLen; |
570 | } else { /* !firstSeg && !lastSeg */ |
571 | /* |
572 | * Intermediate descriptor in a multi-descriptor frame. |
573 | */ |
574 | ads->ds_ctl0 = 0; |
575 | ads->ds_ctl1 = segLen | AR_More; |
576 | } |
577 | ads->ds_status0 = ads->ds_status1 = 0; |
578 | return AH_TRUE; |
579 | } |
580 | |
581 | /* |
582 | * Processing of HW TX descriptor. |
583 | */ |
584 | HAL_STATUS |
585 | ar5210ProcTxDesc(struct ath_hal *ah, |
586 | struct ath_desc *ds, struct ath_tx_status *ts) |
587 | { |
588 | struct ar5210_desc *ads = AR5210DESC(ds); |
589 | |
590 | if ((ads->ds_status1 & AR_Done) == 0) |
591 | return HAL_EINPROGRESS; |
592 | |
593 | /* Update software copies of the HW status */ |
594 | ts->ts_seqnum = ads->ds_status1 & AR_SeqNum; |
595 | ts->ts_tstamp = MS(ads->ds_status0, AR_SendTimestamp); |
596 | ts->ts_status = 0; |
597 | if ((ads->ds_status0 & AR_FrmXmitOK) == 0) { |
598 | if (ads->ds_status0 & AR_ExcessiveRetries) |
599 | ts->ts_status |= HAL_TXERR_XRETRY; |
600 | if (ads->ds_status0 & AR_Filtered) |
601 | ts->ts_status |= HAL_TXERR_FILT; |
602 | if (ads->ds_status0 & AR_FIFOUnderrun) |
603 | ts->ts_status |= HAL_TXERR_FIFO; |
604 | } |
605 | ts->ts_rate = MS(ads->ds_ctl0, AR_XmitRate); |
606 | ts->ts_rssi = MS(ads->ds_status1, AR_AckSigStrength); |
607 | ts->ts_shortretry = MS(ads->ds_status0, AR_ShortRetryCnt); |
608 | ts->ts_longretry = MS(ads->ds_status0, AR_LongRetryCnt); |
609 | ts->ts_antenna = 0; /* NB: don't know */ |
610 | ts->ts_finaltsi = 0; |
611 | |
612 | return HAL_OK; |
613 | } |
614 | |
615 | /* |
616 | * Determine which tx queues need interrupt servicing. |
617 | * STUB. |
618 | */ |
619 | void |
620 | ar5210GetTxIntrQueue(struct ath_hal *ah, uint32_t *txqs) |
621 | { |
622 | return; |
623 | } |
624 | |