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 */
69typedef void (* TSendPacketCompleteCb)(TI_HANDLE hCbObj, TxResultDescriptor_t *pTxResultInfo);
70
71/* Tx-Result SM states */
72typedef enum
73{
74    TX_RESULT_STATE_IDLE,
75    TX_RESULT_STATE_READING
76} ETxResultState;
77
78/* The host Tx-results counter write transaction structure. */
79typedef struct
80{
81    TTxnStruct tTxnStruct;
82    TI_UINT32  uCounter;
83} THostCounterWriteTxn;
84
85/* The Tx-results counters and table read transaction structure. */
86typedef struct
87{
88    TTxnStruct          tTxnStruct;
89    TxResultInterface_t tTxResultInfo;
90} TResultsInfoReadTxn;
91
92/* The TxResult module object. */
93typedef 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
114static void txResult_Restart (TTxResultObj *pTxResult);
115static void txResult_HandleNewResults (TTxResultObj *pTxResult);
116static 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 ****************************************************************************/
131TI_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 ****************************************************************************/
158TI_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 ****************************************************************************/
176TI_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 ****************************************************************************/
215static 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 ****************************************************************************/
229void  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: void
255 ***************************************************************************/
256void 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;
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;
279    }
280
281    /* Call the SM to handle the new Tx results */
282    txResult_StateMachine (hTxResult);
283}
284
285
286/****************************************************************************
287 *                      txResult_StateMachine()
288 ****************************************************************************
289 * DESCRIPTION:
290 *
291 *  The main SM of the module. Called in IDLE eState by txResult_TxCmpltIntrCb() on
292 *      Data interrupt from the FW.
293 *  If no new results - exit (may happen since Data interrupt is common to all Tx&Rx events)
294 *  Read all Tx-Result cyclic table.
295 *  Go over the new Tx-results and call the upper layer callback function for each packet result.
296 *  At the end - write the new host counter to the FW.
297 *
298 * INPUTS:
299 *
300 * OUTPUT:
301 *
302 * RETURNS: None
303 ****************************************************************************/
304static void txResult_StateMachine (TI_HANDLE hTxResult)
305{
306    TTxResultObj *pTxResult  = (TTxResultObj *)hTxResult;
307	ETxnStatus   eTwifStatus = TXN_STATUS_COMPLETE;  /* Last bus operation status: Complete (Sync) or Pending (Async). */
308    TTxnStruct   *pTxn       = &(pTxResult->tResultsInfoReadTxn.tTxnStruct);
309
310    /* Loop while processing is completed in current context (sync), or until fully completed */
311    while (eTwifStatus == TXN_STATUS_COMPLETE)
312    {
313        TRACE2(pTxResult->hReport, REPORT_SEVERITY_INFORMATION, ": eState = %d, eTwifStatus = %d\n", pTxResult->eState, eTwifStatus);
314
315        switch(pTxResult->eState)
316        {
317        case TX_RESULT_STATE_IDLE:
318            /* Read Tx-Result queue and counters. */
319            pTxn->uHwAddr = pTxResult->uTxResultInfoAddr;
320            eTwifStatus = twIf_Transact (pTxResult->hTwIf, pTxn);
321
322            pTxResult->eState = TX_RESULT_STATE_READING;
323            break;
324
325        case TX_RESULT_STATE_READING:
326            /* Process new Tx results, call upper layers to handle them and update host-index in the FW. */
327            txResult_HandleNewResults (pTxResult);
328            pTxResult->eState = TX_RESULT_STATE_IDLE;
329            return;  /*********  Exit after all processing is finished  **********/
330
331        default:
332            TRACE1(pTxResult->hReport, REPORT_SEVERITY_ERROR, ": Unknown eState = %d\n", pTxResult->eState);
333            return;
334        }
335    }
336
337    if (eTwifStatus == TXN_STATUS_ERROR)
338    {
339        TRACE2(pTxResult->hReport, REPORT_SEVERITY_ERROR, ": returning ERROR in eState %d, eTwifStatus=%d !!!\n", pTxResult->eState, eTwifStatus);
340    }
341}
342
343
344/****************************************************************************
345 *                      txResult_HandleNewResults()
346 ****************************************************************************
347 * DESCRIPTION:
348 * ============
349 *	We now have the Tx Result table info from the FW so do as follows:
350 *	1.	Find the number of new results (FW counter minus host counter), and if 0 exit.
351 *  2.	Call the upper layers callback per Tx result.
352 *	3.	Update Host-Counter to be equal to the FW-Counter, and write it to the FW.
353 ***************************************************************************/
354static void txResult_HandleNewResults (TTxResultObj *pTxResult)
355{
356	TI_UINT32 uNumNewResults;    /* The number of new Tx-Result entries to be processed. */
357	TI_UINT32 uFwResultsCounter; /* The FW current results counter (accumulated). */
358	TI_UINT32 uTableIndex;
359	TI_UINT32 i;
360	TxResultDescriptor_t *pCurrentResult;
361    TTxnStruct *pTxn = &(pTxResult->tHostCounterWriteTxn.tTxnStruct);
362
363	/* The uFwResultsCounter is the accumulated number of Tx-Results provided by the FW, and the
364	 *   uHostResultsCounter is the accumulated number of Tx-Results processed by the host.
365	 * The delta is the number of new Tx-results in the queue, waiting for host processing.
366	 * Since the difference is always a small positive number, a simple subtraction is good
367	 *   also for wrap around case.
368	 */
369	uFwResultsCounter = ENDIAN_HANDLE_LONG(pTxResult->tResultsInfoReadTxn.tTxResultInfo.TxResultControl.TxResultFwCounter);
370	uNumNewResults = uFwResultsCounter - pTxResult->uHostResultsCounter;
371
372#ifdef TI_DBG
373	/* Verify there are new entries (was already checked in txResult_TxCmpltIntrCb) */
374	if (uNumNewResults == 0)
375	{
376TRACE2(pTxResult->hReport, REPORT_SEVERITY_WARNING, ": No New Results although indicated by FwStatus!!  HostCount=%d, FwCount=%d\n", pTxResult->uHostResultsCounter, uFwResultsCounter);
377		return;
378	}
379#endif
380
381	/* Update host results-counter in FW to be equal to the FW counter (all new results were processed). */
382	pTxResult->tHostCounterWriteTxn.uCounter = ENDIAN_HANDLE_LONG(uFwResultsCounter);
383    pTxn->uHwAddr = pTxResult->uTxResultHostCounterAddr;
384    twIf_Transact(pTxResult->hTwIf, pTxn);
385
386    TRACE3(pTxResult->hReport, REPORT_SEVERITY_INFORMATION, ": NumResults=%d, OriginalHostCount=%d, FwCount=%d\n", uNumNewResults, pTxResult->uHostResultsCounter, uFwResultsCounter);
387
388	/* Loop over all new Tx-results and call Tx-complete callback with current entry pointer. */
389    /* NOTE: THIS SHOULD COME LAST because it may lead to driver-stop process!! */
390	for (i = 0; i < uNumNewResults; i++)
391	{
392		uTableIndex = pTxResult->uHostResultsCounter & TX_RESULT_QUEUE_DEPTH_MASK;
393		pCurrentResult = &(pTxResult->tResultsInfoReadTxn.tTxResultInfo.TxResultQueue[uTableIndex]);
394        pTxResult->uHostResultsCounter++;
395
396        TRACE1(pTxResult->hReport, REPORT_SEVERITY_INFORMATION , ": call upper layer CB, Status = %d\n", pCurrentResult->status);
397
398		pTxResult->fSendPacketCompleteCb (pTxResult->hSendPacketCompleteHndl, pCurrentResult);
399	}
400}
401
402
403/****************************************************************************
404 *                      txResult_RegisterCb()
405 ****************************************************************************
406 * DESCRIPTION:  Register the upper driver Tx-Result callback functions.
407 ****************************************************************************/
408void txResult_RegisterCb (TI_HANDLE hTxResult, TI_UINT32 uCallBackId, void *CBFunc, TI_HANDLE hCbObj)
409{
410    TTxResultObj* pTxResult = (TTxResultObj*)hTxResult;
411
412    switch (uCallBackId)
413    {
414        /* Set Tx-Complete callback */
415        case TWD_INT_SEND_PACKET_COMPLETE:
416            pTxResult->fSendPacketCompleteCb   = (TSendPacketCompleteCb)CBFunc;
417            pTxResult->hSendPacketCompleteHndl = hCbObj;
418            break;
419
420        default:
421            TRACE0(pTxResult->hReport, REPORT_SEVERITY_ERROR, ": Illegal value\n");
422            return;
423    }
424}
425
426
427#ifdef TI_DBG      /*  Debug Functions   */
428
429/****************************************************************************
430 *                      txResult_PrintInfo()
431 ****************************************************************************
432 * DESCRIPTION:  Prints TX result debug information.
433 ****************************************************************************/
434void txResult_PrintInfo (TI_HANDLE hTxResult)
435{
436#ifdef REPORT_LOG
437    TTxResultObj* pTxResult = (TTxResultObj*)hTxResult;
438
439    WLAN_OS_REPORT(("Tx-Result Module Information:\n"));
440    WLAN_OS_REPORT(("=============================\n"));
441    WLAN_OS_REPORT(("uInterruptsCounter:     %d\n", pTxResult->uInterruptsCounter));
442    WLAN_OS_REPORT(("uHostResultsCounter:    %d\n", pTxResult->uHostResultsCounter));
443    WLAN_OS_REPORT(("=============================\n"));
444#endif
445}
446
447
448/****************************************************************************
449 *                      txResult_ClearInfo()
450 ****************************************************************************
451 * DESCRIPTION:  Clears TX result debug information.
452 ****************************************************************************/
453void txResult_ClearInfo (TI_HANDLE hTxResult)
454{
455    TTxResultObj* pTxResult = (TTxResultObj*)hTxResult;
456
457    pTxResult->uInterruptsCounter = 0;
458}
459
460#endif  /* TI_DBG */
461
462
463