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:  ETxnStatus
255 ***************************************************************************/
256ETxnStatus 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 ****************************************************************************/
305static 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 ***************************************************************************/
355static 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	{
377TRACE2(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 ****************************************************************************/
409void 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 ****************************************************************************/
435void 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 ****************************************************************************/
454void 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