• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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