1 /****************************************************************************
2 **+-----------------------------------------------------------------------+**
3 **| |**
4 **| Copyright(c) 1998 - 2008 Texas Instruments. All rights reserved. |**
5 **| All rights reserved. |**
6 **| |**
7 **| Redistribution and use in source and binary forms, with or without |**
8 **| modification, are permitted provided that the following conditions |**
9 **| are met: |**
10 **| |**
11 **| * Redistributions of source code must retain the above copyright |**
12 **| notice, this list of conditions and the following disclaimer. |**
13 **| * Redistributions in binary form must reproduce the above copyright |**
14 **| notice, this list of conditions and the following disclaimer in |**
15 **| the documentation and/or other materials provided with the |**
16 **| distribution. |**
17 **| * Neither the name Texas Instruments nor the names of its |**
18 **| contributors may be used to endorse or promote products derived |**
19 **| from this software without specific prior written permission. |**
20 **| |**
21 **| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |**
22 **| "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |**
23 **| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |**
24 **| A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |**
25 **| OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |**
26 **| SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |**
27 **| LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |**
28 **| DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |**
29 **| THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |**
30 **| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |**
31 **| OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |**
32 **| |**
33 **+-----------------------------------------------------------------------+**
34 ****************************************************************************/
35
36 /****************************************************************************
37 *
38 * MODULE: txXfer.c
39 *
40 * PURPOSE: Handle Tx frame transfer to the firmware in slave double-buffer scheme.
41 *
42 * DESCRIPTION:
43 * ============
44 * This module gets the upper driver's Tx packets after FW resources were
45 * allocated for it, and handles its transfer to the FW double-buffer.
46 * It can handle two packets at a time, thus providing a pipe-line behavior.
47 * It is planned to start an asynchronous copy of one packet to the FW,
48 * and immediately indicate the upper layer to start handling the next
49 * packet transmission in parallel.
50 *
51 ****************************************************************************/
52
53 #include "osTIType.h"
54 #include "paramIn.h"
55 #include "commonTypes.h"
56 #include "TNETWIF.h"
57 #include "whalCommon.h"
58 #include "whalHwDefs.h"
59 #include "txXfer_api.h"
60 #include "txXfer.h" /* Local definitions */
61
62
63 /****************************************************************************
64 * txXfer_Create()
65 ****************************************************************************
66 * DESCRIPTION: Create the Xfer module object
67 *
68 * INPUTS: None
69 *
70 * OUTPUT: None
71 *
72 * RETURNS: The Created object
73 ****************************************************************************/
txXfer_Create(TI_HANDLE hOs)74 TI_HANDLE txXfer_Create(TI_HANDLE hOs)
75 {
76 txXferObj_t *pTxXfer;
77
78 pTxXfer = os_memoryAlloc(hOs, sizeof(txXferObj_t));
79 if (pTxXfer == NULL)
80 {
81 return NULL;
82 }
83
84 os_memoryZero(hOs, pTxXfer, sizeof(txXferObj_t));
85
86 pTxXfer->hOs = hOs;
87
88 return (TI_HANDLE)pTxXfer;
89 }
90
91
92 /****************************************************************************
93 * txXfer_Destroy()
94 ****************************************************************************
95 * DESCRIPTION: Destroy the Xfer module object
96 *
97 * INPUTS: hTxXfer - The object to free
98 *
99 * OUTPUT: None
100 *
101 * RETURNS: OK or NOK
102 ****************************************************************************/
txXfer_Destroy(TI_HANDLE hTxXfer)103 TI_STATUS txXfer_Destroy(TI_HANDLE hTxXfer)
104 {
105 txXferObj_t *pTxXfer = (txXferObj_t *)hTxXfer;
106
107 if (pTxXfer)
108 {
109 os_memoryFree(pTxXfer->hOs, pTxXfer, sizeof(txXferObj_t));
110 }
111
112 return OK;
113 }
114
115
116 /****************************************************************************
117 * txXfer_init()
118 ****************************************************************************
119 DESCRIPTION:
120 ============
121 Initialize the Xfer module.
122 ****************************************************************************/
txXfer_init(TI_HANDLE hTxXfer,TI_HANDLE hReport,TI_HANDLE hTNETWIF,TI_HANDLE hTxResult)123 TI_STATUS txXfer_init(TI_HANDLE hTxXfer, TI_HANDLE hReport, TI_HANDLE hTNETWIF, TI_HANDLE hTxResult)
124 {
125 txXferObj_t *pTxXfer = (txXferObj_t *)hTxXfer;
126
127 pTxXfer->hReport = hReport;
128 pTxXfer->hTNETWIF = hTNETWIF;
129 pTxXfer->hTxResult = hTxResult;
130 pTxXfer->sendPacketTransferCB = NULL;
131 pTxXfer->sendPacketDebugCB = NULL;
132
133 return txXfer_restart(pTxXfer);
134 }
135
136 /****************************************************************************
137 * txXfer_config()
138 ****************************************************************************
139 * DESCRIPTION:
140 * Configures the TX XFER module with initialization parameters.
141 *
142 * INPUTS:
143 * hTxXfer The object
144 * pInitParams initialization parameters values
145 *
146 * OUTPUT: None
147 *
148 * RETURNS: None
149 ****************************************************************************/
txXfer_config(TI_HANDLE hTxXfer,TnetwDrv_InitParams_t * pInitParams)150 void txXfer_config(TI_HANDLE hTxXfer, TnetwDrv_InitParams_t *pInitParams)
151 {
152 txXferObj_t *pTxXfer = (txXferObj_t *)hTxXfer;
153
154 pTxXfer->timeToTxStuckMs = pInitParams->txXferInitParams.timeToTxStuckMs;
155 }
156
157
158 /****************************************************************************
159 * txXfer_setHwInfo()
160 ****************************************************************************
161 * DESCRIPTION:
162 * Called after the HW configuration upon init or recovery.
163 * Store the HW addresses of the Double Buffer and the Tx-status.
164 *
165 * INPUTS:
166 * hTxXfer The object
167 * pDataPathParams Pointer to the Double Buffer Address
168 *
169 * OUTPUT: None
170 *
171 * RETURNS: None
172 ****************************************************************************/
txXfer_setHwInfo(TI_HANDLE hTxXfer,ACXDataPathParamsResp_t * pDataPathParams)173 void txXfer_setHwInfo(TI_HANDLE hTxXfer, ACXDataPathParamsResp_t *pDataPathParams)
174 {
175 txXferObj_t *pTxXfer = (txXferObj_t *)hTxXfer;
176
177 pTxXfer->dblBufAddr[0] = pDataPathParams->txPacketRingAddr;
178 pTxXfer->dblBufAddr[1] = pDataPathParams->txPacketRingAddr + pDataPathParams->txPacketRingChunkSize;
179 pTxXfer->txPathStatusAddr = pDataPathParams->txControlAddr;
180
181 /* Print of the Tx double buffer address */
182 WLAN_REPORT_INFORMATION(pTxXfer->hReport, TNETW_XFER_MODULE_LOG,
183 ("TX DOUBLE BUFFER Addresses: Buf_0 = 0x%x, Buf_1 = 0x%x\n",
184 pTxXfer->dblBufAddr[0], pTxXfer->dblBufAddr[1]));
185 }
186
187
188
189
190
191 /****************************************************************************
192 * txXfer_restart()
193 ****************************************************************************
194 DESCRIPTION:
195 ============
196 Restarts the Xfer module.
197 Should be called upon init and recovery!!
198 ****************************************************************************/
txXfer_restart(TI_HANDLE hTxXfer)199 TI_STATUS txXfer_restart(TI_HANDLE hTxXfer)
200 {
201 txXferObj_t *pTxXfer = (txXferObj_t *)hTxXfer;
202
203 /* Initialize module variables. */
204 pTxXfer->txXferState = TX_XFER_STATE_IDLE;
205 pTxXfer->numBufferedPkts = 0;
206 pTxXfer->xferDonePostponed = FALSE;
207 pTxXfer->bRecovery = FALSE;
208 pTxXfer->dataInCount = 0;
209 pTxXfer->hwStatusReadLoopCount = 0;
210
211 return OK;
212 }
213
214
215
216
217 /****************************************************************************
218 * txXfer_sendPacket()
219 ****************************************************************************
220 * DESCRIPTION:
221 ============
222 Handle sent packet according to the number of packets already in the Xfer buffers:
223 If no buffered pkts:
224 If in IDLE state, update state to WAIT_BUS and request the bus.
225 Return SEND_PACKET_SUCCESS.
226 If one buffered pkt, just buffer the request and return SEND_PACKET_PENDING (can't get more).
227 If two buffered pkts, return SEND_PACKET_ERROR (not expected to get more packets).
228 ****************************************************************************/
txXfer_sendPacket(TI_HANDLE hTxXfer,txCtrlBlkEntry_t * pPktCtrlBlk)229 systemStatus_e txXfer_sendPacket(TI_HANDLE hTxXfer, txCtrlBlkEntry_t *pPktCtrlBlk)
230 {
231 txXferObj_t *pTxXfer = (txXferObj_t *)hTxXfer;
232 TI_STATUS tnetwifStatus;
233
234 #ifdef TI_DBG
235 pTxXfer->sendPacketCount++;
236 #endif
237
238 /* Handle sent packet according to the number of packets already in the Xfer buffers. */
239 switch(pTxXfer->numBufferedPkts)
240 {
241
242 /* No buffered pkts. */
243 case 0:
244
245 pTxXfer->numBufferedPkts = 1;
246 pTxXfer->pPktCtrlBlk[0] = pPktCtrlBlk; /* Save the first pkt Ctrl-Blk pointer. */
247
248 /* If in IDLE state, update state to WAIT_BUS and request the bus. */
249 if (pTxXfer->txXferState == TX_XFER_STATE_IDLE)
250 {
251 WLAN_REPORT_INFORMATION(pTxXfer->hReport, TNETW_XFER_MODULE_LOG,
252 ("txXfer_sendPacket(): First Pkt, IDLE-STATE, Start Bus-Wait\n"));
253
254 /* Note: Update the Xfer-SM state before calling the TNETWIF because it will call the
255 SM immediately if the bus is available. */
256 pTxXfer->txXferState = TX_XFER_STATE_WAIT_BUS;
257
258 /* Set to detect if the Xfer proces is completed in this context (returns XFER_DONE). */
259 pTxXfer->syncXferIndication = TRUE;
260
261 tnetwifStatus = TNETWIF_Start(pTxXfer->hTNETWIF, TX_XFER_MODULE_ID, pTxXfer, xferStateMachine);
262
263 if (pTxXfer->bRecovery)
264 return SEND_PACKET_RECOVERY;
265
266 #ifdef TI_DBG
267 if (tnetwifStatus == TNETWIF_COMPLETE)
268 {
269 pTxXfer->busStartSyncCount++;
270 }
271 else if (tnetwifStatus == TNETWIF_PENDING)
272 {
273 pTxXfer->busStartAsyncCount++;
274 }
275 else
276 {
277 WLAN_REPORT_ERROR(pTxXfer->hReport, TNETW_XFER_MODULE_LOG,
278 ("txXfer_sendPacket(): TNETWIF_Start returned error=%d\n", tnetwifStatus));
279 }
280 #endif
281
282 /* If the Xfer was completed in this context (Synchronous), return XFER_DONE. */
283 /* Note: In this case xferDone callback will not be called! */
284 if (pTxXfer->syncXferIndication)
285 {
286 pTxXfer->syncXferIndication = FALSE;
287
288 if (tnetwifStatus == TNETWIF_COMPLETE) /* The SM was called from the Start function. */
289 {
290 #ifdef TI_DBG
291 pTxXfer->xferDoneSyncCount++;
292 WLAN_REPORT_INFORMATION(pTxXfer->hReport, TNETW_XFER_MODULE_LOG,
293 ("txXfer_sendPacket(): Xfer Completed in upper driver context\n"));
294 #endif
295 return SEND_PACKET_XFER_DONE; /* Xfer can get another packet. */
296 }
297 }
298 }
299 else
300 {
301 WLAN_REPORT_INFORMATION(pTxXfer->hReport, TNETW_XFER_MODULE_LOG,
302 ("txXfer_sendPacket(): First Pkt, not IDLE-STATE, XferState=%d\n", pTxXfer->txXferState));
303 }
304
305 /* If the Xfer wasn't completed in this context (Asynchronous), return SUCCESS
306 (xferDone callback will be called). */
307 return SEND_PACKET_SUCCESS; /* Xfer can get another packet. */
308
309
310
311 /* If one buffered pkt, just buffer the request and return SEND_PACKET_PENDING (can't get more). */
312 case 1:
313
314 if (pTxXfer->bRecovery)
315 {
316 return SEND_PACKET_RECOVERY;
317 }
318
319 else
320 {
321 WLAN_REPORT_INFORMATION (pTxXfer->hReport, TNETW_XFER_MODULE_LOG,
322 ("txXfer_sendPacket(): Second Pkt Buffered, XferState=%d\n", pTxXfer->txXferState));
323
324 pTxXfer->numBufferedPkts = 2; /* We now have two packets handled in the Xfer. */
325 pTxXfer->pPktCtrlBlk[1] = pPktCtrlBlk; /* Save the second pkt Ctrl-Blk pointer. */
326
327 return SEND_PACKET_PENDING; /* Xfer can't get further packets. */
328 }
329
330
331 /* If two buffered pkts, return SEND_PACKET_ERROR (not expected to get more packets). */
332 default:
333
334 WLAN_REPORT_ERROR(pTxXfer->hReport, TNETW_XFER_MODULE_LOG,
335 ("txXfer_sendPacket(): Two Pkts Allready Buffered, XferState=%d, xferDonePostponed=%d, numPkts=%d\n",
336 pTxXfer->txXferState, pTxXfer->xferDonePostponed, pTxXfer->numBufferedPkts));
337
338 return SEND_PACKET_ERROR;
339 }
340 }
341
342
343 #define MAX_RECOVERY_LOOPS 1000
344
345
346 /****************************************************************************
347 * xferStateMachine()
348 ****************************************************************************
349 * DESCRIPTION:
350 ============
351 This is the Xfer process state machine.
352 It handles the transfer of packets sent by the upper driver to the HW via TNETWIF.
353
354 The SM supports both Sync and Async accesses to the HW.
355 It loops and progresses from state to state as long as the HW is accessed synchronously.
356 Once the access is Asynchronous (TNETWIF_PENDING), it exits and is called later
357 by the TNETWIF when the HW is ready.
358 That's why it uses only unspecified-mode accesses (e.g. TNETWIF_ReadMemOpt) which
359 selects either Sync or Async automatically according to the platform.
360
361 When the SM is active (not in IDLE state), it has either one or two packets buffered.
362 This enables (in Async access) pipeline behavior, where one packet is transfered to
363 the HW, and the other is being processed from the upper driver to the Xfer in parallel.
364
365
366 The SM steps are:
367 =================
368
369 Event: Send-Pkt Bus-Ready HW-Buffer-Ready Xfer-Done Trigger-Done
370 | | | | |
371 V V V V V
372 State: IDLE ----> WAIT_BUS ----> WAIT_HW_BUFFER ----> WAIT_XFER_DONE ----> WAIT_TRIGGER_DONE ----> IDLE
373 | |
374 | |
375 <---------<---------<---------<---------<---------<----------
376 Pending-Packet (*)
377
378 (*) When a packet transfer is finished but another packet is already waiting in the Xfer
379 for processing, the Xfer will postpone the Xfer-Done indication of the first packet
380 until it has started the second one's transfer to the HW.
381 It will request "Bus Restart" in order to prevent nesting and enable bus allocation
382 to other tasks.
383
384 ****************************************************************************/
xferStateMachine(TI_HANDLE hTxXfer,UINT8 module_id,TI_STATUS status)385 static void xferStateMachine(TI_HANDLE hTxXfer, UINT8 module_id, TI_STATUS status)
386 {
387 txXferObj_t *pTxXfer = (txXferObj_t *)hTxXfer;
388 TI_STATUS tnetwifStatus;
389
390 #ifdef TI_DBG
391 if (hTxXfer == NULL)
392 {
393 WLAN_REPORT_ERROR(pTxXfer->hReport, TNETW_XFER_MODULE_LOG,
394 ("xferStateMachine(): **** Called with NULL handle!! ****\n"));
395 return;
396 }
397 #endif
398
399 /*
400 * Loop through the states sequence as long as the process is synchronous.
401 * Exit when finished or if an Asynchronous process is required. In this case
402 * the SM process will be resumed later (called back by TNETWIF).
403 */
404 while (1)
405 {
406 switch (pTxXfer->txXferState)
407 {
408
409 case TX_XFER_STATE_WAIT_BUS:
410
411 /* Call debug callback */
412 if (pTxXfer->sendPacketDebugCB)
413 {
414 pTxXfer->sendPacketDebugCB (pTxXfer->sendPacketDebugHandle,
415 pTxXfer->pPktCtrlBlk[0],
416 pTxXfer->txXferState);
417 }
418
419 /* We now own the bus, so request to read HW-Tx-Status and go to WAIT_HW_BUFFER state. */
420 pTxXfer->txXferState = TX_XFER_STATE_WAIT_HW_BUFFER;
421
422 /* also mark the time at which the first attemot is done */
423 pTxXfer->TimeStampFirstHwBufferRead = os_timeStampMs( pTxXfer->hOs );
424
425 tnetwifStatus = TNETWIF_ReadMemOpt (pTxXfer->hTNETWIF,
426 pTxXfer->txPathStatusAddr,
427 PADREAD (&pTxXfer->hwTxPathStatusRead),
428 sizeof(UINT32),
429 TX_XFER_MODULE_ID,
430 xferStateMachine,
431 pTxXfer);
432
433 break;
434
435
436
437 case TX_XFER_STATE_WAIT_HW_BUFFER:
438
439 /* Call debug callback */
440 if (pTxXfer->sendPacketDebugCB)
441 {
442 pTxXfer->sendPacketDebugCB (pTxXfer->sendPacketDebugHandle,
443 pTxXfer->pPktCtrlBlk[0],
444 pTxXfer->txXferState);
445 }
446
447 /* We now have the HW-Tx-Status read, so check if there are HW buffers available. */
448 if (hwBuffersOccupied(pTxXfer) < DP_TX_PACKET_RING_CHUNK_NUM)
449 {
450 /* Handle actual packet transfer to HW buffer. */
451 tnetwifStatus = transferPacket(pTxXfer);
452
453 pTxXfer->txXferState = TX_XFER_STATE_WAIT_XFER_DONE;
454
455 /*
456 * If we've postponed the Xfer-Done callback of the previous transfered
457 * packet, call it now in parallel with the Xfer of the current packet.
458 * Note that all variables are updated before calling the XferDone, since
459 * it may be used to send another packet.
460 * The current transfered packet pointer is moved to the first buffer.
461 */
462 if (pTxXfer->xferDonePostponed)
463 {
464 txCtrlBlkEntry_t *pPostponedPktCtrlBlk = pTxXfer->pPktCtrlBlk[0];
465 pTxXfer->numBufferedPkts = 1;
466 pTxXfer->pPktCtrlBlk[0] = pTxXfer->pPktCtrlBlk[1];
467 pTxXfer->xferDonePostponed = FALSE;
468 pTxXfer->sendPacketTransferCB(pTxXfer->sendPacketTransferHandle, pPostponedPktCtrlBlk);
469 #ifdef TI_DBG
470 pTxXfer->xferDoneCallCBCount++;
471 #endif
472 }
473 pTxXfer->hwStatusReadLoopCount = 0;
474 #ifdef TI_DBG
475 pTxXfer->hwBufferReadCount++;
476 #endif
477 }
478
479 /* If HW buffer isn't available, try reading the status again (loop on same state). */
480 else
481 {
482 tnetwifStatus = TNETWIF_ReadMemOpt (pTxXfer->hTNETWIF,
483 pTxXfer->txPathStatusAddr,
484 PADREAD (&pTxXfer->hwTxPathStatusRead),
485 sizeof(UINT32),
486 TX_XFER_MODULE_ID,
487 xferStateMachine,
488 pTxXfer);
489
490 #ifdef TI_DBG
491 /* For Debug: Update counters */
492 pTxXfer->hwBufferFullCount++;
493 pTxXfer->hwBufferReadCount++;
494 #endif
495 /* Detect endless loop and perform recovery if needed */
496 pTxXfer->hwStatusReadLoopCount++;
497 if (os_timeStampMs (pTxXfer->hOs) - pTxXfer->TimeStampFirstHwBufferRead >
498 pTxXfer->timeToTxStuckMs)
499 {
500 WLAN_REPORT_ERROR(pTxXfer->hReport, TNETW_XFER_MODULE_LOG,
501 ("xferStateMachine(): Looping too long for Tx-Status, LastTxStatus=%d\n",
502 pTxXfer->hwTxPathStatusRead));
503 WLAN_REPORT_ERROR(pTxXfer->hReport, TNETW_XFER_MODULE_LOG,
504 ("Loop count=%d, First time stamp:%d, current time stamp:%d\n",
505 pTxXfer->hwStatusReadLoopCount, pTxXfer->TimeStampFirstHwBufferRead,
506 os_timeStampMs( pTxXfer->hOs )) );
507
508 #ifdef USE_RECOVERY
509 pTxXfer->bRecovery = TRUE;
510 /* Error Reporting - if after a configurable interval we could not
511 transfer data a recovery will be called */
512 if (pTxXfer->failureEventFunc)
513 {
514 pTxXfer->failureEventFunc(pTxXfer->failureEventObj, TX_STUCK);
515 }
516
517 return;
518 #endif
519 }
520 }
521
522 break;
523
524 case TX_XFER_STATE_WAIT_XFER_DONE:
525
526 /* Call debug callback */
527 if (pTxXfer->sendPacketDebugCB)
528 {
529 pTxXfer->sendPacketDebugCB (pTxXfer->sendPacketDebugHandle,
530 pTxXfer->pPktCtrlBlk[0],
531 pTxXfer->txXferState);
532 }
533
534 /* Now the last packet transfer to the HW is finished, so we issue a trigger to the FW. */
535
536 {
537 UINT32 txInterruptRegAddress;
538 UINT32 txInterruptRegData;
539
540 /* Set the Tx-interrupt address and value according to the
541 HW buffer used for the last transfer. */
542 if (pTxXfer->dataInCount & 0x1)
543 {
544 txInterruptRegAddress = ACX_REG_INTERRUPT_TRIG_H;
545 txInterruptRegData = INTR_TRIG_TX_PROC1;
546 }
547 else
548 {
549 txInterruptRegAddress = ACX_REG_INTERRUPT_TRIG;
550 txInterruptRegData = INTR_TRIG_TX_PROC0;
551 }
552
553 /* Call debug callback */
554 if (pTxXfer->sendPacketDebugCB)
555 {
556 pTxXfer->sendPacketDebugCB (pTxXfer->sendPacketDebugHandle,
557 pTxXfer->pPktCtrlBlk[0],
558 0);
559 }
560
561 /* Issue the Tx interrupt trigger to the FW. */
562 tnetwifStatus = TNETWIF_WriteRegOpt(pTxXfer->hTNETWIF,
563 txInterruptRegAddress,
564 txInterruptRegData,
565 TX_XFER_MODULE_ID,
566 xferStateMachine,
567 pTxXfer);
568
569 /* Increment the transfered packets counter modulo 16 (as FW data-out counter). */
570 pTxXfer->dataInCount = (pTxXfer->dataInCount + 1) & TX_STATUS_DATA_OUT_COUNT_MASK;
571
572 pTxXfer->txXferState = TX_XFER_STATE_WAIT_TRIGGER_DONE;
573 }
574
575 break;
576
577 case TX_XFER_STATE_WAIT_TRIGGER_DONE:
578
579 /* Call debug callback */
580 if (pTxXfer->sendPacketDebugCB)
581 {
582 pTxXfer->sendPacketDebugCB (pTxXfer->sendPacketDebugHandle,
583 pTxXfer->pPktCtrlBlk[0],
584 pTxXfer->txXferState);
585 }
586
587 /* Now the HW Tx trigger is done so we can continue to the next packet if waiting. */
588
589 /* If we don't have another packet pending for transfer. */
590 if (pTxXfer->numBufferedPkts == 1)
591 {
592 pTxXfer->numBufferedPkts = 0;
593
594 /*
595 * Call the XferDone callback, but only if we are not in the original
596 * SendPacket context (i.e. completely synchronous).
597 * This is to avoid nesting, since the callback may start another SendPacket.
598 */
599 if (!pTxXfer->syncXferIndication)
600 {
601 #ifdef TI_DBG
602 pTxXfer->xferDoneCallCBCount++;
603 WLAN_REPORT_INFORMATION(pTxXfer->hReport, TNETW_XFER_MODULE_LOG,
604 ("sendPacketTransferCB: CB_Func=0x%x, CB_Handle=0x%x\n",
605 pTxXfer->sendPacketTransferCB, pTxXfer->sendPacketTransferHandle));
606 #endif
607 pTxXfer->sendPacketTransferCB(pTxXfer->sendPacketTransferHandle, pTxXfer->pPktCtrlBlk[0]);
608 }
609
610 /* If still no packet was sent, release bus (Finish), set IDLE state and exit. */
611 if (pTxXfer->numBufferedPkts == 0)
612 {
613 pTxXfer->txXferState = TX_XFER_STATE_IDLE;
614 TNETWIF_Finish (pTxXfer->hTNETWIF, TX_XFER_MODULE_ID, pTxXfer, NULL);
615
616 WLAN_REPORT_INFORMATION(pTxXfer->hReport, TNETW_XFER_MODULE_LOG,
617 ("txXferSM Finished -> IDLE: NumPkts=%d, XferDonePostponed=%d, SyncIndication=%d\n",
618 pTxXfer->numBufferedPkts, pTxXfer->xferDonePostponed, pTxXfer->syncXferIndication));
619
620 return; /************ Exit State Machine (back to IDLE) ************/
621 }
622
623 /*
624 * A new packet was sent (in XferDone callback), so request the bus again using Restart.
625 * This will call the SM later, and start the process again from WAIT_BUS state.
626 */
627 else
628 {
629 pTxXfer->txXferState = TX_XFER_STATE_WAIT_BUS;
630 tnetwifStatus = TNETWIF_Restart(pTxXfer->hTNETWIF, TX_XFER_MODULE_ID, pTxXfer, xferStateMachine);
631 #ifdef TI_DBG
632 pTxXfer->busRestartCount++;
633 #endif
634 }
635 }
636
637 /*
638 * We have another packet pending.
639 * So to enable parallel processing, we postpone the XferDone callback (just set flag).
640 * Thus, we'll start first the new packet transfer and only than call the postponed
641 * XferDone (see WAIT_HW_BUFFER state), which may start another SendPacket in
642 * parallel to the HW transfer.
643 * Note that we request the bus again using Restart (to avoid nesting or bus starvation).
644 * This will call the SM later, and start the process again from WAIT_BUS state.
645 */
646 else
647 {
648 pTxXfer->xferDonePostponed = TRUE;
649 pTxXfer->txXferState = TX_XFER_STATE_WAIT_BUS;
650 tnetwifStatus = TNETWIF_Restart(pTxXfer->hTNETWIF, TX_XFER_MODULE_ID, pTxXfer, xferStateMachine);
651 #ifdef TI_DBG
652 pTxXfer->busRestartCount++;
653 pTxXfer->xferDonePostponeCount++;
654 #endif
655 }
656
657 break;
658
659
660
661 default:
662 WLAN_REPORT_ERROR(pTxXfer->hReport, TNETW_XFER_MODULE_LOG,
663 ("xferStateMachine(): Unexpected state, txXferState=%d, NumPkts=%d\n",
664 pTxXfer->txXferState, pTxXfer->numBufferedPkts));
665
666 return;
667
668 } /* switch (pTxXfer->txXferState) */
669
670 WLAN_REPORT_INFORMATION(pTxXfer->hReport, TNETW_XFER_MODULE_LOG,
671 ("txXferSM(): SmState=%d, NumPkts=%d, XferDonePostponed=%d, TnetwIfStatus=%d, SyncIndication=%d, HwTxStatus=0x%x, DataInCount=0x%x\n",
672 pTxXfer->txXferState, pTxXfer->numBufferedPkts, pTxXfer->xferDonePostponed,
673 tnetwifStatus, pTxXfer->syncXferIndication, pTxXfer->hwTxPathStatusRead, pTxXfer->dataInCount));
674
675 /*
676 * If the last HW access request was pended, exit the SM (Asynchronous process).
677 * The SM will be called back when the HW access is done.
678 * Also reset the Sync flag to notify that the Xfer wasn't completed in the SendPacket context.
679 */
680 if (tnetwifStatus == TNETWIF_PENDING)
681 {
682 pTxXfer->syncXferIndication = FALSE;
683
684 return; /********** Exit State Machine (to be called back by TNETWIF) **********/
685 }
686
687 #ifdef TI_DBG
688 else if (tnetwifStatus == TNETWIF_ERROR)
689 {
690 WLAN_REPORT_ERROR(pTxXfer->hReport, TNETW_XFER_MODULE_LOG,
691 ("txXferSM TNETWIF_ERROR: SmState=%d, NumPkts=%d, XferDonePostponed=%d, TnetwIfStatus=%d, SyncIndication=%d, HwTxStatus=0x%x, DataInCount=0x%x\n",
692 pTxXfer->txXferState, pTxXfer->numBufferedPkts, pTxXfer->xferDonePostponed,
693 tnetwifStatus, pTxXfer->syncXferIndication, pTxXfer->hwTxPathStatusRead, pTxXfer->dataInCount));
694 return;
695 }
696 #endif
697
698 } /* while (1) */
699
700 }
701
702
703
704
705 /****************************************************************************
706 * hwBuffersOccupied()
707 ****************************************************************************
708 * DESCRIPTION:
709 ============
710 Return the number of occupied buffers in the HW Tx double buffer, based on
711 the last read of the HW Tx path status.
712 ****************************************************************************/
hwBuffersOccupied(txXferObj_t * pTxXfer)713 static UINT32 hwBuffersOccupied(txXferObj_t *pTxXfer)
714 {
715 UINT32 dataOutCount = pTxXfer->hwTxPathStatusRead & TX_STATUS_DATA_OUT_COUNT_MASK;
716
717 /* Return the difference between the packets transfered to the double buffer (by host)
718 and the packets copied from it (by FW). The else is for counter wrap around. */
719
720 if (pTxXfer->dataInCount >= dataOutCount)
721 {
722 return pTxXfer->dataInCount - dataOutCount;
723 }
724 else
725 {
726 return pTxXfer->dataInCount + TX_STATUS_DATA_OUT_COUNT_MASK + 1 - dataOutCount;
727 }
728 }
729
730
731
732
733 /****************************************************************************
734 * transferPacket()
735 ****************************************************************************
736 * DESCRIPTION:
737 ============
738 Handle the current packet transfer to the HW Tx double buffer.
739 Return the transfer status:
740 TNETWIF_COMPLETE - if completed, i.e. Synchronous mode.
741 TNETWIF_PENDING - if pending, i.e. Asynchronous mode (callback function will be called).
742
743
744 If the packet was pending during disconnect, notify the TxResult to issue Tx-Complete,
745 and return TNETWIF_COMPLETE, since we don't transfer it to the FW.
746
747 ****************************************************************************/
transferPacket(txXferObj_t * pTxXfer)748 static TI_STATUS transferPacket(txXferObj_t *pTxXfer)
749 {
750 UINT16 XferLength; /* The actual length of the transfer. */
751 txCtrlBlkEntry_t *pPktCtrlBlk; /* The packet control block pointer. */
752 TI_STATUS status;
753
754 /* Get the current packet control-block pointer. If we've postponed the last packet Xfer-Done (i.e.
755 was transfered but still buffered) than our current packet is the second one. */
756 pPktCtrlBlk = pTxXfer->pPktCtrlBlk[ ((pTxXfer->xferDonePostponed) ? 1 : 0) ];
757
758 /* Get the packet length, add descriptor length and align upward to 32 bit. */
759 XferLength = (pPktCtrlBlk->txDescriptor.length + sizeof(DbTescriptor) + ALIGN_32BIT_MASK) & ~ALIGN_32BIT_MASK;
760
761 /* Initiate the packet transfer. The status indicates if Sync or Async mode was used!! */
762 status = TNETWIF_WriteMemOpt (pTxXfer->hTNETWIF,
763 pTxXfer->dblBufAddr[pTxXfer->dataInCount & 0x1],
764 (UINT8 *)(pPktCtrlBlk->txPktParams.pFrame),
765 XferLength,
766 TX_XFER_MODULE_ID,
767 xferStateMachine,
768 pTxXfer);
769
770 #ifdef TI_DBG
771 WLAN_REPORT_INFORMATION(pTxXfer->hReport, TNETW_XFER_MODULE_LOG,
772 ("transferPacket(): Status=%d, XferLength=%d, DataInCount=0x%x, pPktCtrlBlk=0x%x, dbgPktSeqNum=%d, Expiry=%d\n",
773 status, XferLength, pTxXfer->dataInCount, pPktCtrlBlk, pPktCtrlBlk->txPktParams.dbgPktSeqNum,
774 pPktCtrlBlk->txDescriptor.expiryTime));
775
776 if (status == TNETWIF_COMPLETE)
777 {
778 pTxXfer->pktTransferSyncCount++;
779 }
780 else if (status == TNETWIF_PENDING)
781 {
782 pTxXfer->pktTransferAsyncCount++;
783 }
784 else
785 {
786 WLAN_REPORT_ERROR(pTxXfer->hReport, TNETW_XFER_MODULE_LOG,
787 ("transferPacket - TNETWIF_ERROR: Status=%d, XferLength=%d, DataInCount=0x%x, pPktCtrlBlk=0x%x, dbgPktSeqNum=%d, Expiry=%d\n",
788 status, XferLength, pTxXfer->dataInCount, pPktCtrlBlk, pPktCtrlBlk->txPktParams.dbgPktSeqNum,
789 pPktCtrlBlk->txDescriptor.expiryTime));
790 }
791 #endif
792
793 /* Return the transfer status:
794 TNETWIF_COMPLETE - if completed, i.e. Synchronous mode.
795 TNETWIF_PENDING - if pending, i.e. Asynchronous mode (callback function will be called).
796 */
797 return status;
798 }
799
800
801
802
803 /****************************************************************************
804 * txXfer_RegisterCB()
805 ****************************************************************************
806 * DESCRIPTION: Register the upper driver Xfer callback functions.
807 ****************************************************************************/
txXfer_RegisterCB(TI_HANDLE hTxXfer,tiUINT32 CallBackID,void * CBFunc,TI_HANDLE CBObj)808 void txXfer_RegisterCB(TI_HANDLE hTxXfer, tiUINT32 CallBackID, void *CBFunc, TI_HANDLE CBObj)
809 {
810 txXferObj_t* pTxXfer = (txXferObj_t*)hTxXfer;
811
812 WLAN_REPORT_INFORMATION(pTxXfer->hReport, TNETW_XFER_MODULE_LOG,
813 ("txXfer_RegisterCB(): CallBackID=%d, CBFunc=0x%x, CBObj=0x%x\n", CallBackID, CBFunc, CBObj));
814
815 switch(CallBackID)
816 {
817 /* Set Transfer-Done callback */
818 case TX_XFER_SEND_PKT_TRANSFER:
819 pTxXfer->sendPacketTransferCB = (SendPacketTranferCB_t)CBFunc;
820 pTxXfer->sendPacketTransferHandle = CBObj;
821 break;
822
823 case TX_XFER_SEND_PKT_DEBUG:
824 pTxXfer->sendPacketDebugCB = (SendPacketDebugCB_t)CBFunc;
825 pTxXfer->sendPacketDebugHandle = CBObj;
826 break;
827
828 default:
829 WLAN_REPORT_ERROR(pTxXfer->hReport, TNETW_XFER_MODULE_LOG, ("txXfer_RegisterCB - Illegal value\n"));
830 break;
831 }
832 }
833
834
835
836 /****************************************************************************************
837 * txXfer_RegisterFailureEventCB *
838 ****************************************************************************************
839 DESCRIPTION: Registers a failure event callback for scan error notifications.
840
841
842 INPUT: - hTxXfer - handle to the xfer object.
843 - failureEventCB - the failure event callback function.\n
844 - hFailureEventObj - handle to the object passed to the failure event callback function.
845
846 OUTPUT:
847 RETURN: void.
848 ****************************************************************************************/
849
txXfer_RegisterFailureEventCB(TI_HANDLE hTxXfer,void * failureEventCB,TI_HANDLE hFailureEventObj)850 void txXfer_RegisterFailureEventCB( TI_HANDLE hTxXfer,
851 void * failureEventCB, TI_HANDLE hFailureEventObj )
852 {
853 txXferObj_t *pTxXfer = (txXferObj_t *)hTxXfer;
854
855 pTxXfer->failureEventFunc = (failureEventCB_t)failureEventCB;
856 pTxXfer->failureEventObj = hFailureEventObj;
857 }
858
859 /****************************************************************************
860 * txXfer_printInfo()
861 ****************************************************************************
862 * DESCRIPTION: Print the txXfer object main fields.
863 ****************************************************************************/
txXfer_printInfo(TI_HANDLE hTxXfer)864 void txXfer_printInfo(TI_HANDLE hTxXfer)
865 {
866 #ifdef TI_DBG
867 txXferObj_t *pTxXfer = (txXferObj_t *)hTxXfer;
868
869 WLAN_OS_REPORT(("Tx-Xfer Module Information:\n"));
870 WLAN_OS_REPORT(("===========================\n"));
871
872 switch (pTxXfer->txXferState)
873 {
874 case TX_XFER_STATE_IDLE:
875 WLAN_OS_REPORT(("State = IDLE\n"));
876 break;
877
878 case TX_XFER_STATE_WAIT_BUS:
879 WLAN_OS_REPORT(("State = WAIT_BUS\n"));
880 break;
881
882 case TX_XFER_STATE_WAIT_HW_BUFFER:
883 WLAN_OS_REPORT(("State = WAIT_HW_BUFFER\n"));
884 break;
885
886 case TX_XFER_STATE_WAIT_XFER_DONE:
887 WLAN_OS_REPORT(("State = WAIT_XFER_DONE\n"));
888 break;
889
890 case TX_XFER_STATE_WAIT_TRIGGER_DONE:
891 WLAN_OS_REPORT(("State = WAIT_TRIGGER_DONE\n"));
892 break;
893
894 default:
895 WLAN_OS_REPORT(("State = UNKNOWN !!\n"));
896 break;
897 }
898
899 WLAN_OS_REPORT(("numBufferedPkts = %d\n", pTxXfer->numBufferedPkts));
900 WLAN_OS_REPORT(("xferDonePostponed = %d\n", pTxXfer->xferDonePostponed));
901 WLAN_OS_REPORT(("syncXferIndication = %d\n", pTxXfer->syncXferIndication));
902 WLAN_OS_REPORT(("pPktCtrlBlk[0] = 0x%x\n", pTxXfer->pPktCtrlBlk[0]));
903 WLAN_OS_REPORT(("pPktCtrlBlk[1] = 0x%x\n", pTxXfer->pPktCtrlBlk[1]));
904 WLAN_OS_REPORT(("hwTxPathStatusRead = 0x%x\n", pTxXfer->hwTxPathStatusRead));
905 WLAN_OS_REPORT(("dataInCount = 0x%x\n", pTxXfer->dataInCount));
906 WLAN_OS_REPORT(("txPathStatusAddr = 0x%x\n", pTxXfer->txPathStatusAddr));
907 WLAN_OS_REPORT(("dblBufAddr[0] = 0x%x\n", pTxXfer->dblBufAddr[0]));
908 WLAN_OS_REPORT(("dblBufAddr[1] = 0x%x\n\n", pTxXfer->dblBufAddr[1]));
909
910 WLAN_OS_REPORT(("hwBufferReadCount = %d\n", pTxXfer->hwBufferReadCount));
911 WLAN_OS_REPORT(("hwBufferFullCount = %d\n", pTxXfer->hwBufferFullCount));
912 WLAN_OS_REPORT(("sendPacketCount = %d\n", pTxXfer->sendPacketCount));
913 WLAN_OS_REPORT(("busStartSyncCount = %d\n", pTxXfer->busStartSyncCount));
914 WLAN_OS_REPORT(("busStartAsyncCount = %d\n", pTxXfer->busStartAsyncCount));
915 WLAN_OS_REPORT(("pktTransferSyncCount = %d\n", pTxXfer->pktTransferSyncCount));
916 WLAN_OS_REPORT(("pktTransferAsyncCount = %d\n", pTxXfer->pktTransferAsyncCount));
917 WLAN_OS_REPORT(("busRestartCount = %d\n", pTxXfer->busRestartCount));
918 WLAN_OS_REPORT(("xferDonePostponeCount = %d\n", pTxXfer->xferDonePostponeCount));
919 WLAN_OS_REPORT(("xferDoneSyncCount = %d\n", pTxXfer->xferDoneSyncCount));
920 WLAN_OS_REPORT(("xferDoneCallCBCount = %d\n", pTxXfer->xferDoneCallCBCount));
921 #endif /* TI_DBG */
922 }
923