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