• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * txResult.c
3  *
4  * Copyright(c) 1998 - 2009 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  *   MODULE:  txResult.c
38  *
39  *   PURPOSE:  Handle packets Tx results upon Tx-complete from the FW.
40  *
41  *   DESCRIPTION:
42  *   ============
43  *      This module is called upon Tx-complete from FW.
44  *      It retrieves the transmitted packets results from the FW TxResult table and
45  *        calls the upper layer callback function for each packet with its results.
46  *
47  ****************************************************************************/
48 
49 #define __FILE_ID__  FILE_ID_107
50 #include "tidef.h"
51 #include "osApi.h"
52 #include "report.h"
53 #include "TwIf.h"
54 #include "txCtrlBlk_api.h"
55 #include "txResult_api.h"
56 #include "TWDriver.h"
57 #include "FwEvent_api.h"
58 
59 
60 
61 #define TX_RESULT_QUEUE_DEPTH_MASK  (TRQ_DEPTH - 1)
62 
63 #if (TX_RESULT_QUEUE_DEPTH_MASK & TRQ_DEPTH)
64     #error  TRQ_DEPTH should be a power of 2 !!
65 #endif
66 
67 
68 /* Callback function definition for Tx sendPacketComplete */
69 typedef void (* TSendPacketCompleteCb)(TI_HANDLE hCbObj, TxResultDescriptor_t *pTxResultInfo);
70 
71 /* Tx-Result SM states */
72 typedef enum
73 {
74     TX_RESULT_STATE_IDLE,
75     TX_RESULT_STATE_READING
76 } ETxResultState;
77 
78 /* The host Tx-results counter write transaction structure. */
79 typedef struct
80 {
81     TTxnStruct tTxnStruct;
82     TI_UINT32  uCounter;
83 } THostCounterWriteTxn;
84 
85 /* The Tx-results counters and table read transaction structure. */
86 typedef struct
87 {
88     TTxnStruct          tTxnStruct;
89     TxResultInterface_t tTxResultInfo;
90 } TResultsInfoReadTxn;
91 
92 /* The TxResult module object. */
93 typedef struct
94 {
95     TI_HANDLE               hOs;
96     TI_HANDLE               hReport;
97     TI_HANDLE               hTwIf;
98 
99     TI_UINT32               uTxResultInfoAddr;       /* The HW Tx-Result Table address */
100     TI_UINT32               uTxResultHostCounterAddr;/* The Tx-Result host counter address in SRAM */
101     TI_UINT32               uHostResultsCounter;     /* Number of results read by host from queue since FW-init (updated to FW) */
102     ETxResultState          eState;                  /* Current eState of SM */
103     TSendPacketCompleteCb   fSendPacketCompleteCb;   /* Tx-Complete callback function */
104     TI_HANDLE               hSendPacketCompleteHndl; /* Tx-Complete callback function handle */
105     THostCounterWriteTxn    tHostCounterWriteTxn;    /* The structure used for writing host results counter to FW */
106     TResultsInfoReadTxn     tResultsInfoReadTxn;     /* The structure used for reading Tx-results counters and table from  FW */
107 #ifdef TI_DBG
108     TI_UINT32               uInterruptsCounter;         /* Count number of Tx-results */
109 #endif
110 
111 } TTxResultObj;
112 
113 
114 static void txResult_Restart (TTxResultObj *pTxResult);
115 static void txResult_HandleNewResults (TTxResultObj *pTxResult);
116 static void txResult_StateMachine (TI_HANDLE hTxResult);
117 
118 
119 
120 /****************************************************************************
121  *                      txResult_Create()
122  ****************************************************************************
123  * DESCRIPTION: Create the Tx-Result object
124  *
125  * INPUTS:  hOs
126  *
127  * OUTPUT:  None
128  *
129  * RETURNS: The Created object
130  ****************************************************************************/
txResult_Create(TI_HANDLE hOs)131 TI_HANDLE txResult_Create(TI_HANDLE hOs)
132 {
133     TTxResultObj *pTxResult;
134 
135     pTxResult = os_memoryAlloc(hOs, sizeof(TTxResultObj));
136     if (pTxResult == NULL)
137         return NULL;
138 
139     os_memoryZero(hOs, pTxResult, sizeof(TTxResultObj));
140 
141     pTxResult->hOs = hOs;
142 
143     return( (TI_HANDLE)pTxResult );
144 }
145 
146 
147 /****************************************************************************
148  *                      txResult_Destroy()
149  ****************************************************************************
150  * DESCRIPTION: Destroy the Tx-Result object
151  *
152  * INPUTS:  hTxResult - The object to free
153  *
154  * OUTPUT:  None
155  *
156  * RETURNS: TI_OK or TI_NOK
157  ****************************************************************************/
txResult_Destroy(TI_HANDLE hTxResult)158 TI_STATUS txResult_Destroy(TI_HANDLE hTxResult)
159 {
160     TTxResultObj *pTxResult = (TTxResultObj *)hTxResult;
161 
162     if (pTxResult)
163         os_memoryFree(pTxResult->hOs, pTxResult, sizeof(TTxResultObj));
164 
165     return TI_OK;
166 }
167 
168 
169 /****************************************************************************
170  *               txResult_Init()
171  ****************************************************************************
172    DESCRIPTION:
173    ============
174      Initialize the txResult module.
175  ****************************************************************************/
txResult_Init(TI_HANDLE hTxResult,TI_HANDLE hReport,TI_HANDLE hTwIf)176 TI_STATUS txResult_Init(TI_HANDLE hTxResult, TI_HANDLE hReport, TI_HANDLE hTwIf)
177 {
178     TTxResultObj *pTxResult = (TTxResultObj *)hTxResult;
179     TTxnStruct   *pTxn;
180 
181     pTxResult->hReport    = hReport;
182     pTxResult->hTwIf      = hTwIf;
183 
184     /* Prepare Host-Results-Counter write transaction (HwAddr is filled before each transaction) */
185     pTxn = &pTxResult->tHostCounterWriteTxn.tTxnStruct;
186     TXN_PARAM_SET(pTxn, TXN_LOW_PRIORITY, TXN_FUNC_ID_WLAN, TXN_DIRECTION_WRITE, TXN_INC_ADDR)
187     BUILD_TTxnStruct(pTxn, 0, &pTxResult->tHostCounterWriteTxn.uCounter, REGISTER_SIZE, NULL, NULL)
188 
189     /* Prepare Tx-Result counter and table read transaction (HwAddr is filled before each transaction) */
190     pTxn = &pTxResult->tResultsInfoReadTxn.tTxnStruct;
191     TXN_PARAM_SET(pTxn, TXN_LOW_PRIORITY, TXN_FUNC_ID_WLAN, TXN_DIRECTION_READ, TXN_INC_ADDR)
192     BUILD_TTxnStruct(pTxn,
193                      0,
194                      &pTxResult->tResultsInfoReadTxn.tTxResultInfo,
195                      sizeof(TxResultInterface_t),
196                      (TTxnDoneCb)txResult_StateMachine,
197                      hTxResult)
198 
199     txResult_Restart (pTxResult);
200 
201     return TI_OK;
202 }
203 
204 
205 /****************************************************************************
206  *               txResult_Restart()
207  ****************************************************************************
208    DESCRIPTION:
209    ============
210      Restarts the Tx-Result module.
211      Called upon init and recovery.
212      Shouldn't be called upon disconnect, since the FW provides Tx-Complete
213        for all pending packets in FW!!
214  ****************************************************************************/
txResult_Restart(TTxResultObj * pTxResult)215 static void txResult_Restart (TTxResultObj *pTxResult)
216 {
217 	pTxResult->uHostResultsCounter = 0;
218     pTxResult->eState = TX_RESULT_STATE_IDLE;
219 }
220 
221 
222 /****************************************************************************
223  *                      txResult_setHwInfo()
224  ****************************************************************************
225  * DESCRIPTION:
226  *      Called after the HW configuration upon init or recovery.
227  *      Store the Tx-result table HW address.
228  ****************************************************************************/
txResult_setHwInfo(TI_HANDLE hTxResult,TDmaParams * pDmaParams)229 void  txResult_setHwInfo(TI_HANDLE hTxResult, TDmaParams *pDmaParams)
230 {
231     TTxResultObj *pTxResult = (TTxResultObj *)hTxResult;
232 
233     pTxResult->uTxResultInfoAddr = (TI_UINT32)(pDmaParams->fwTxResultInterface);
234 	pTxResult->uTxResultHostCounterAddr = pTxResult->uTxResultInfoAddr +
235 		TI_FIELD_OFFSET(TxResultControl_t, TxResultHostCounter);
236 
237     txResult_Restart (pTxResult);
238 }
239 
240 
241 /****************************************************************************
242  *                      txResult_TxCmpltIntrCb()
243  ****************************************************************************
244  * DESCRIPTION:
245  * ============
246  *  Called upon DATA interrupt from the FW.
247  *  If new Tx results are available, start handling them.
248  *
249  * INPUTS:  hTxResult - the txResult object handle.
250  *          pFwStatus - The FW status registers read by the FwEvent
251  *
252  * OUTPUT:  None
253  *
254  * RETURNS:  ETxnStatus
255  ***************************************************************************/
txResult_TxCmpltIntrCb(TI_HANDLE hTxResult,FwStatus_t * pFwStatus)256 ETxnStatus txResult_TxCmpltIntrCb (TI_HANDLE hTxResult, FwStatus_t *pFwStatus)
257 {
258     TTxResultObj   *pTxResult = (TTxResultObj *)hTxResult;
259     TI_UINT32      uTempCounters;
260     FwStatCntrs_t  *pFwStatusCounters;
261 
262 #ifdef TI_DBG
263     pTxResult->uInterruptsCounter++;
264 
265     if (pTxResult->eState != TX_RESULT_STATE_IDLE)
266     {
267         TRACE1(pTxResult->hReport, REPORT_SEVERITY_INFORMATION, ": called in eState %d, so exit\n", pTxResult->eState);
268         return TXN_STATUS_COMPLETE;
269     }
270 #endif
271 
272     /* If no new results - exit (may happen since Data interrupt is common to all Tx&Rx events) */
273     uTempCounters = ENDIAN_HANDLE_LONG(pFwStatus->counters);
274     pFwStatusCounters = (FwStatCntrs_t *)&uTempCounters;
275     if (pFwStatusCounters->txResultsCntr == (TI_UINT8)pTxResult->uHostResultsCounter)
276     {
277         TRACE0(pTxResult->hReport, REPORT_SEVERITY_INFORMATION, ": No new Tx results\n");
278         return TXN_STATUS_COMPLETE;
279     }
280 
281     /* Call the SM to handle the new Tx results */
282     txResult_StateMachine (hTxResult);
283     return TXN_STATUS_COMPLETE;
284 }
285 
286 
287 /****************************************************************************
288  *                      txResult_StateMachine()
289  ****************************************************************************
290  * DESCRIPTION:
291  *
292  *  The main SM of the module. Called in IDLE eState by txResult_TxCmpltIntrCb() on
293  *      Data interrupt from the FW.
294  *  If no new results - exit (may happen since Data interrupt is common to all Tx&Rx events)
295  *  Read all Tx-Result cyclic table.
296  *  Go over the new Tx-results and call the upper layer callback function for each packet result.
297  *  At the end - write the new host counter to the FW.
298  *
299  * INPUTS:
300  *
301  * OUTPUT:
302  *
303  * RETURNS: None
304  ****************************************************************************/
txResult_StateMachine(TI_HANDLE hTxResult)305 static void txResult_StateMachine (TI_HANDLE hTxResult)
306 {
307     TTxResultObj *pTxResult  = (TTxResultObj *)hTxResult;
308 	ETxnStatus   eTwifStatus = TXN_STATUS_COMPLETE;  /* Last bus operation status: Complete (Sync) or Pending (Async). */
309     TTxnStruct   *pTxn       = &(pTxResult->tResultsInfoReadTxn.tTxnStruct);
310 
311     /* Loop while processing is completed in current context (sync), or until fully completed */
312     while (eTwifStatus == TXN_STATUS_COMPLETE)
313     {
314         TRACE2(pTxResult->hReport, REPORT_SEVERITY_INFORMATION, ": eState = %d, eTwifStatus = %d\n", pTxResult->eState, eTwifStatus);
315 
316         switch(pTxResult->eState)
317         {
318         case TX_RESULT_STATE_IDLE:
319             /* Read Tx-Result queue and counters. */
320             pTxn->uHwAddr = pTxResult->uTxResultInfoAddr;
321             eTwifStatus = twIf_Transact (pTxResult->hTwIf, pTxn);
322 
323             pTxResult->eState = TX_RESULT_STATE_READING;
324             break;
325 
326         case TX_RESULT_STATE_READING:
327             /* Process new Tx results, call upper layers to handle them and update host-index in the FW. */
328             txResult_HandleNewResults (pTxResult);
329             pTxResult->eState = TX_RESULT_STATE_IDLE;
330             return;  /*********  Exit after all processing is finished  **********/
331 
332         default:
333             TRACE1(pTxResult->hReport, REPORT_SEVERITY_ERROR, ": Unknown eState = %d\n", pTxResult->eState);
334             return;
335         }
336     }
337 
338     if (eTwifStatus == TXN_STATUS_ERROR)
339     {
340         TRACE2(pTxResult->hReport, REPORT_SEVERITY_ERROR, ": returning ERROR in eState %d, eTwifStatus=%d !!!\n", pTxResult->eState, eTwifStatus);
341     }
342 }
343 
344 
345 /****************************************************************************
346  *                      txResult_HandleNewResults()
347  ****************************************************************************
348  * DESCRIPTION:
349  * ============
350  *	We now have the Tx Result table info from the FW so do as follows:
351  *	1.	Find the number of new results (FW counter minus host counter), and if 0 exit.
352  *  2.	Call the upper layers callback per Tx result.
353  *	3.	Update Host-Counter to be equal to the FW-Counter, and write it to the FW.
354  ***************************************************************************/
txResult_HandleNewResults(TTxResultObj * pTxResult)355 static void txResult_HandleNewResults (TTxResultObj *pTxResult)
356 {
357 	TI_UINT32 uNumNewResults;    /* The number of new Tx-Result entries to be processed. */
358 	TI_UINT32 uFwResultsCounter; /* The FW current results counter (accumulated). */
359 	TI_UINT32 uTableIndex;
360 	TI_UINT32 i;
361 	TxResultDescriptor_t *pCurrentResult;
362     TTxnStruct *pTxn = &(pTxResult->tHostCounterWriteTxn.tTxnStruct);
363 
364 	/* The uFwResultsCounter is the accumulated number of Tx-Results provided by the FW, and the
365 	 *   uHostResultsCounter is the accumulated number of Tx-Results processed by the host.
366 	 * The delta is the number of new Tx-results in the queue, waiting for host processing.
367 	 * Since the difference is always a small positive number, a simple subtraction is good
368 	 *   also for wrap around case.
369 	 */
370 	uFwResultsCounter = ENDIAN_HANDLE_LONG(pTxResult->tResultsInfoReadTxn.tTxResultInfo.TxResultControl.TxResultFwCounter);
371 	uNumNewResults = uFwResultsCounter - pTxResult->uHostResultsCounter;
372 
373 #ifdef TI_DBG
374 	/* Verify there are new entries (was already checked in txResult_TxCmpltIntrCb) */
375 	if (uNumNewResults == 0)
376 	{
377 TRACE2(pTxResult->hReport, REPORT_SEVERITY_WARNING, ": No New Results although indicated by FwStatus!!  HostCount=%d, FwCount=%d\n", pTxResult->uHostResultsCounter, uFwResultsCounter);
378 		return;
379 	}
380 #endif
381 
382 	/* Update host results-counter in FW to be equal to the FW counter (all new results were processed). */
383 	pTxResult->tHostCounterWriteTxn.uCounter = ENDIAN_HANDLE_LONG(uFwResultsCounter);
384     pTxn->uHwAddr = pTxResult->uTxResultHostCounterAddr;
385     twIf_Transact(pTxResult->hTwIf, pTxn);
386 
387     TRACE3(pTxResult->hReport, REPORT_SEVERITY_INFORMATION, ": NumResults=%d, OriginalHostCount=%d, FwCount=%d\n", uNumNewResults, pTxResult->uHostResultsCounter, uFwResultsCounter);
388 
389 	/* Loop over all new Tx-results and call Tx-complete callback with current entry pointer. */
390     /* NOTE: THIS SHOULD COME LAST because it may lead to driver-stop process!! */
391 	for (i = 0; i < uNumNewResults; i++)
392 	{
393 		uTableIndex = pTxResult->uHostResultsCounter & TX_RESULT_QUEUE_DEPTH_MASK;
394 		pCurrentResult = &(pTxResult->tResultsInfoReadTxn.tTxResultInfo.TxResultQueue[uTableIndex]);
395         pTxResult->uHostResultsCounter++;
396 
397         TRACE1(pTxResult->hReport, REPORT_SEVERITY_INFORMATION , ": call upper layer CB, Status = %d\n", pCurrentResult->status);
398 
399 		pTxResult->fSendPacketCompleteCb (pTxResult->hSendPacketCompleteHndl, pCurrentResult);
400 	}
401 }
402 
403 
404 /****************************************************************************
405  *                      txResult_RegisterCb()
406  ****************************************************************************
407  * DESCRIPTION:  Register the upper driver Tx-Result callback functions.
408  ****************************************************************************/
txResult_RegisterCb(TI_HANDLE hTxResult,TI_UINT32 uCallBackId,void * CBFunc,TI_HANDLE hCbObj)409 void txResult_RegisterCb (TI_HANDLE hTxResult, TI_UINT32 uCallBackId, void *CBFunc, TI_HANDLE hCbObj)
410 {
411     TTxResultObj* pTxResult = (TTxResultObj*)hTxResult;
412 
413     switch (uCallBackId)
414     {
415         /* Set Tx-Complete callback */
416         case TWD_INT_SEND_PACKET_COMPLETE:
417             pTxResult->fSendPacketCompleteCb   = (TSendPacketCompleteCb)CBFunc;
418             pTxResult->hSendPacketCompleteHndl = hCbObj;
419             break;
420 
421         default:
422             TRACE0(pTxResult->hReport, REPORT_SEVERITY_ERROR, ": Illegal value\n");
423             return;
424     }
425 }
426 
427 
428 #ifdef TI_DBG      /*  Debug Functions   */
429 
430 /****************************************************************************
431  *                      txResult_PrintInfo()
432  ****************************************************************************
433  * DESCRIPTION:  Prints TX result debug information.
434  ****************************************************************************/
txResult_PrintInfo(TI_HANDLE hTxResult)435 void txResult_PrintInfo (TI_HANDLE hTxResult)
436 {
437 #ifdef REPORT_LOG
438     TTxResultObj* pTxResult = (TTxResultObj*)hTxResult;
439 
440     WLAN_OS_REPORT(("Tx-Result Module Information:\n"));
441     WLAN_OS_REPORT(("=============================\n"));
442     WLAN_OS_REPORT(("uInterruptsCounter:     %d\n", pTxResult->uInterruptsCounter));
443     WLAN_OS_REPORT(("uHostResultsCounter:    %d\n", pTxResult->uHostResultsCounter));
444     WLAN_OS_REPORT(("=============================\n"));
445 #endif
446 }
447 
448 
449 /****************************************************************************
450  *                      txResult_ClearInfo()
451  ****************************************************************************
452  * DESCRIPTION:  Clears TX result debug information.
453  ****************************************************************************/
txResult_ClearInfo(TI_HANDLE hTxResult)454 void txResult_ClearInfo (TI_HANDLE hTxResult)
455 {
456     TTxResultObj* pTxResult = (TTxResultObj*)hTxResult;
457 
458     pTxResult->uInterruptsCounter = 0;
459 }
460 
461 #endif  /* TI_DBG */
462 
463 
464