|
1 /* |
|
2 * TwIf.c |
|
3 * |
|
4 * Copyright(c) 1998 - 2010 Texas Instruments. All rights reserved. |
|
5 * All rights reserved. |
|
6 * |
|
7 * This program and the accompanying materials are made available under the |
|
8 * terms of the Eclipse Public License v1.0 or BSD License which accompanies |
|
9 * this distribution. The Eclipse Public License is available at |
|
10 * http://www.eclipse.org/legal/epl-v10.html and the BSD License is as below. |
|
11 * |
|
12 * Redistribution and use in source and binary forms, with or without |
|
13 * modification, are permitted provided that the following conditions |
|
14 * are met: |
|
15 * |
|
16 * * Redistributions of source code must retain the above copyright |
|
17 * notice, this list of conditions and the following disclaimer. |
|
18 * * Redistributions in binary form must reproduce the above copyright |
|
19 * notice, this list of conditions and the following disclaimer in |
|
20 * the documentation and/or other materials provided with the |
|
21 * distribution. |
|
22 * * Neither the name Texas Instruments nor the names of its |
|
23 * contributors may be used to endorse or promote products derived |
|
24 * from this software without specific prior written permission. |
|
25 * |
|
26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
27 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
28 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
29 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|
30 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
31 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
32 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
33 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|
34 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
35 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|
36 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
37 */ |
|
38 |
|
39 |
|
40 /** \file TwIf.c |
|
41 * \brief The TWD bottom API towards the Txn-Queue. |
|
42 * |
|
43 * The TwIf module is the lowest WLAN-specific layer and presents a common interface to all Xfer modules. |
|
44 * As such, it is responsible for the common functionalities related to device access, which includes: |
|
45 * - transactions submission |
|
46 * - interface power control |
|
47 * - address translation (paging) when needed (depends on bus attributes). |
|
48 * The TwIf has no OS, platform or bus type dependencies. |
|
49 * |
|
50 * \see TwIf.h, TxnQueue.c, TxnQueue.h |
|
51 */ |
|
52 |
|
53 #define __FILE_ID__ FILE_ID_121 |
|
54 #include "tidef.h" |
|
55 #include "report.h" |
|
56 #include "context.h" |
|
57 #include "TxnDefs.h" |
|
58 #include "TxnQueue.h" |
|
59 #include "TwIf.h" |
|
60 #include "TWDriver.h" |
|
61 |
|
62 |
|
63 /************************************************************************ |
|
64 * Defines |
|
65 ************************************************************************/ |
|
66 #define TXN_DONE_QUE_SIZE 64 /* TxnDone-queue size */ |
|
67 |
|
68 /* Values to write to the ELP register for sleep/awake */ |
|
69 #define ELP_CTRL_REG_SLEEP 0 |
|
70 #define ELP_CTRL_REG_AWAKE 1 |
|
71 |
|
72 /* |
|
73 * Device interface-control registers addresses (at the end ot the 17-bit address space): |
|
74 */ |
|
75 #define PARTITION_REGISTERS_ADDR (0x1FFC0) /* Four 32 bit register: */ |
|
76 /* Memory region size (0x1FFC0) */ |
|
77 /* Memory region base address (0x1FFC4) */ |
|
78 /* Registers region size (0x1FFC8) */ |
|
79 /* Registers region base address (0x1FFCC) */ |
|
80 |
|
81 #define ELP_CTRL_REG_ADDR (0x1FFFC) /* ELP control register address */ |
|
82 |
|
83 |
|
84 |
|
85 /************************************************************************ |
|
86 * Types |
|
87 ************************************************************************/ |
|
88 |
|
89 /* TwIf SM States */ |
|
90 typedef enum |
|
91 { |
|
92 SM_STATE_AWAKE, /* HW is awake and Txn-Queue is running */ |
|
93 SM_STATE_SLEEP, /* HW is asleep and Txn-Queue is stopped */ |
|
94 SM_STATE_WAIT_HW /* Waiting for HW to wake up (after triggering it), Txn-Queue is stopped */ |
|
95 } ESmState; |
|
96 |
|
97 /* TwIf SM Events */ |
|
98 typedef enum |
|
99 { |
|
100 SM_EVENT_START, /* Need to wake up the device to handle transactions */ |
|
101 SM_EVENT_HW_AVAILABLE, /* The device woke up */ |
|
102 SM_EVENT_SLEEP /* Need to let the device go to sleep */ |
|
103 } ESmEvent; |
|
104 |
|
105 /* The addresses partitioning configuration Txn data */ |
|
106 typedef struct |
|
107 { |
|
108 TI_UINT32 uMemSize; /* The HW memory region size. */ |
|
109 TI_UINT32 uMemAddr; /* The HW memory region address. */ |
|
110 TI_UINT32 uRegSize; /* The HW registers region size. */ |
|
111 TI_UINT32 uRegAddr; /* The HW registers region address. */ |
|
112 |
|
113 } TPartitionTxnData; |
|
114 |
|
115 /* The addresses partitioning configuration Txn */ |
|
116 typedef struct |
|
117 { |
|
118 TTxnStruct tHdr; /* The generic transaction structure */ |
|
119 TI_UINT8 *pData; /* The addresses partitioning configuration data */ |
|
120 |
|
121 } TPartitionTxn; |
|
122 |
|
123 /* The addresses partitioning configuration Txn */ |
|
124 typedef struct |
|
125 { |
|
126 TTxnStruct tHdr; /* The generic transaction structure */ |
|
127 TI_UINT8 *pData; /* The addresses partitioning configuration data for one register */ |
|
128 |
|
129 } TPartitionRegTxn; |
|
130 |
|
131 /* The addresses partitioning configuration Txn */ |
|
132 typedef struct |
|
133 { |
|
134 TTxnStruct tHdr; /* The generic transaction structure */ |
|
135 TI_UINT8 uElpData; /* The value to write to the ELP register */ |
|
136 |
|
137 } TElpTxn; |
|
138 |
|
139 /* The TwIf module Object */ |
|
140 typedef struct _TTwIfObj |
|
141 { |
|
142 /* Other modules handles */ |
|
143 TI_HANDLE hOs; |
|
144 TI_HANDLE hReport; |
|
145 TI_HANDLE hContext; |
|
146 TI_HANDLE hTxnQ; |
|
147 |
|
148 ESmState eState; /* SM current state */ |
|
149 TI_HANDLE hTxnDoneQueue; /* Queue for completed transactions not reported yet to the upper layer */ |
|
150 TI_UINT32 uContextId; /* The ID allocated to this module on registration to context module */ |
|
151 TFailureEventCb fErrCb; /* The upper layer CB function for error handling */ |
|
152 TI_HANDLE hErrCb; /* The CB function handle */ |
|
153 TRecoveryCb fRecoveryCb; /* The upper layer CB for restart complete */ |
|
154 TI_HANDLE hRecoveryCb; /* The CB function handle */ |
|
155 TI_UINT32 uAwakeReqCount; /* Increment on awake requests and decrement on sleep requests */ |
|
156 TI_UINT32 uPendingTxnCount;/* Count pending transactions (sent to TxnQ and not completed yet) */ |
|
157 TElpTxn tElpTxnSleep; /* Transaction structure for writing sleep to ELP register */ |
|
158 TElpTxn tElpTxnAwake; /* Transaction structure for writing awake to ELP register */ |
|
159 |
|
160 /* HW Addresses partitioning */ |
|
161 TI_UINT32 uMemAddr1; /* The HW memory region start address. */ |
|
162 TI_UINT32 uMemSize1; /* The HW memory region end address. */ |
|
163 TI_UINT32 uMemAddr2; /* The HW registers region start address. */ |
|
164 TI_UINT32 uMemSize2; /* The HW registers region end address. */ |
|
165 TI_UINT32 uMemAddr3; /* The INT Status registers region start address. */ |
|
166 TI_UINT32 uMemSize3; /* The INT Status registers region end address. */ |
|
167 TI_UINT32 uMemAddr4; /* The FW Status mem registers region start address. */ |
|
168 |
|
169 |
|
170 #ifdef TI_DBG |
|
171 /* Debug counters */ |
|
172 TI_UINT32 uDbgCountAwake; /* Count calls to twIf_Awake */ |
|
173 TI_UINT32 uDbgCountSleep; /* Count calls to twIf_Sleep */ |
|
174 TI_UINT32 uDbgCountTxn; /* Count calls to twIf_SendTransaction (including TwIf internal Txns) */ |
|
175 TI_UINT32 uDbgCountTxnPending; /* Count transactions that returned PENDING */ |
|
176 TI_UINT32 uDbgCountTxnComplete;/* Count transactions that returned COMPLETE */ |
|
177 TI_UINT32 uDbgCountTxnDoneCb; /* Count calls to twIf_TxnDoneCb */ |
|
178 #endif |
|
179 |
|
180 } TTwIfObj; |
|
181 |
|
182 |
|
183 /************************************************************************ |
|
184 * Internal functions prototypes |
|
185 ************************************************************************/ |
|
186 static void twIf_WriteElpReg (TTwIfObj *pTwIf, TI_UINT32 uValue); |
|
187 static void twIf_PartitionTxnDoneCb (TI_HANDLE hTwIf, void *hTxn); |
|
188 static ETxnStatus twIf_SendTransaction (TTwIfObj *pTwIf, TTxnStruct *pTxn); |
|
189 static void twIf_HandleSmEvent (TTwIfObj *pTwIf, ESmEvent eEvent); |
|
190 static void twIf_TxnDoneCb (TI_HANDLE hTwIf, TTxnStruct *pTxn); |
|
191 static void twIf_HandleTxnDone (TI_HANDLE hTwIf); |
|
192 static void twIf_ClearTxnDoneQueue (TI_HANDLE hTwIf); |
|
193 |
|
194 |
|
195 |
|
196 /************************************************************************ |
|
197 * |
|
198 * Module functions implementation |
|
199 * |
|
200 ************************************************************************/ |
|
201 |
|
202 /** |
|
203 * \fn twIf_Create |
|
204 * \brief Create the module |
|
205 * |
|
206 * Allocate and clear the module's object. |
|
207 * |
|
208 * \note |
|
209 * \param hOs - Handle to Os Abstraction Layer |
|
210 * \return Handle of the allocated object, NULL if allocation failed |
|
211 * \sa twIf_Destroy |
|
212 */ |
|
213 TI_HANDLE twIf_Create (TI_HANDLE hOs) |
|
214 { |
|
215 TI_HANDLE hTwIf; |
|
216 TTwIfObj *pTwIf; |
|
217 |
|
218 hTwIf = os_memoryAlloc (hOs, sizeof(TTwIfObj),MemoryNormal); |
|
219 if (hTwIf == NULL) |
|
220 return NULL; |
|
221 |
|
222 pTwIf = (TTwIfObj *)hTwIf; |
|
223 |
|
224 os_memoryZero (hOs, hTwIf, sizeof(TTwIfObj)); |
|
225 |
|
226 pTwIf->hOs = hOs; |
|
227 |
|
228 return pTwIf; |
|
229 } |
|
230 |
|
231 |
|
232 /** |
|
233 * \fn twIf_Destroy |
|
234 * \brief Destroy the module. |
|
235 * |
|
236 * Unregister from TxnQ and free the TxnDone-queue and the module's object. |
|
237 * |
|
238 * \note |
|
239 * \param The module's object |
|
240 * \return TI_OK on success or TI_NOK on failure |
|
241 * \sa twIf_Create |
|
242 */ |
|
243 TI_STATUS twIf_Destroy (TI_HANDLE hTwIf) |
|
244 { |
|
245 TTwIfObj *pTwIf = (TTwIfObj*)hTwIf; |
|
246 |
|
247 if (pTwIf) |
|
248 { |
|
249 txnQ_Close (pTwIf->hTxnQ, TXN_FUNC_ID_WLAN); |
|
250 que_Destroy (pTwIf->hTxnDoneQueue); |
|
251 os_memoryFree (pTwIf->hOs, pTwIf, sizeof(TTwIfObj)); |
|
252 } |
|
253 return TI_OK; |
|
254 } |
|
255 |
|
256 |
|
257 /** |
|
258 * \fn twIf_Init |
|
259 * \brief Init module |
|
260 * |
|
261 * - Init required handles and module variables |
|
262 * - Create the TxnDone-queue |
|
263 * - Register to TxnQ |
|
264 * - Register to context module |
|
265 * |
|
266 * \note |
|
267 * \param hTwIf - The module's object |
|
268 * \param hReport - Handle to report module |
|
269 * \param hContext - Handle to context module |
|
270 * \param hTxnQ - Handle to TxnQ module |
|
271 * \return void |
|
272 * \sa |
|
273 */ |
|
274 void twIf_Init (TI_HANDLE hTwIf, TI_HANDLE hReport, TI_HANDLE hContext, TI_HANDLE hTxnQ, TRecoveryCb fRecoveryCb, TI_HANDLE hRecoveryCb) |
|
275 { |
|
276 TTwIfObj *pTwIf = (TTwIfObj*)hTwIf; |
|
277 TI_UINT32 uNodeHeaderOffset; |
|
278 TTxnStruct *pTxnHdr; /* The ELP transactions header (as used in the TxnQ API) */ |
|
279 |
|
280 pTwIf->hReport = hReport; |
|
281 pTwIf->hContext = hContext; |
|
282 pTwIf->hTxnQ = hTxnQ; |
|
283 pTwIf->fRecoveryCb = fRecoveryCb; |
|
284 pTwIf->hRecoveryCb = hRecoveryCb; |
|
285 |
|
286 /* Prepare ELP sleep transaction */ |
|
287 pTwIf->tElpTxnSleep.uElpData = ELP_CTRL_REG_SLEEP; |
|
288 pTxnHdr = &(pTwIf->tElpTxnSleep.tHdr); |
|
289 TXN_PARAM_SET(pTxnHdr, TXN_LOW_PRIORITY, TXN_FUNC_ID_WLAN, TXN_DIRECTION_WRITE, TXN_INC_ADDR) |
|
290 TXN_PARAM_SET_MORE(pTxnHdr, 0); /* Sleep is the last transaction! */ |
|
291 /* NOTE: Function id for single step will be replaced to 0 by the bus driver */ |
|
292 TXN_PARAM_SET_SINGLE_STEP(pTxnHdr, 1); /* ELP write is always single step (TxnQ is topped)! */ |
|
293 BUILD_TTxnStruct(pTxnHdr, ELP_CTRL_REG_ADDR, &(pTwIf->tElpTxnSleep.uElpData), sizeof(TI_UINT8), NULL, NULL) |
|
294 |
|
295 /* Prepare ELP awake transaction */ |
|
296 pTwIf->tElpTxnAwake.uElpData = ELP_CTRL_REG_AWAKE; |
|
297 pTxnHdr = &(pTwIf->tElpTxnAwake.tHdr); |
|
298 TXN_PARAM_SET(pTxnHdr, TXN_LOW_PRIORITY, TXN_FUNC_ID_WLAN, TXN_DIRECTION_WRITE, TXN_INC_ADDR) |
|
299 TXN_PARAM_SET_MORE(pTxnHdr, 1); |
|
300 /* NOTE: Function id for single step will be replaced to 0 by the bus driver */ |
|
301 TXN_PARAM_SET_SINGLE_STEP(pTxnHdr, 1); /* ELP write is always single step (TxnQ is topped)! */ |
|
302 BUILD_TTxnStruct(pTxnHdr, ELP_CTRL_REG_ADDR, &(pTwIf->tElpTxnAwake.uElpData), sizeof(TI_UINT8), NULL, NULL) |
|
303 |
|
304 /* Create the TxnDone queue. */ |
|
305 uNodeHeaderOffset = TI_FIELD_OFFSET(TTxnStruct, tTxnQNode); |
|
306 pTwIf->hTxnDoneQueue = que_Create (pTwIf->hOs, pTwIf->hReport, TXN_DONE_QUE_SIZE, uNodeHeaderOffset); |
|
307 if (pTwIf->hTxnDoneQueue == NULL) |
|
308 { |
|
309 TRACE0(pTwIf->hReport, REPORT_SEVERITY_ERROR, "twIf_Init: TxnDone queue creation failed!\n"); |
|
310 } |
|
311 |
|
312 /* Register to the context engine and get the client ID */ |
|
313 pTwIf->uContextId = context_RegisterClient (pTwIf->hContext, |
|
314 twIf_HandleTxnDone, |
|
315 hTwIf, |
|
316 TI_TRUE, |
|
317 "TWIF", |
|
318 sizeof("TWIF")); |
|
319 |
|
320 /* Register to TxnQ */ |
|
321 txnQ_Open (pTwIf->hTxnQ, TXN_FUNC_ID_WLAN, TXN_NUM_PRIORITYS, (TTxnQueueDoneCb)twIf_TxnDoneCb, hTwIf); |
|
322 |
|
323 /* Restart TwIf and TxnQ modules */ |
|
324 twIf_Restart (hTwIf); |
|
325 } |
|
326 |
|
327 |
|
328 /** |
|
329 * \fn twIf_Restart |
|
330 * \brief Restart module upon driver stop or recovery |
|
331 * |
|
332 * Called upon driver stop command or upon recovery. |
|
333 * Calls txnQ_Restart to clear the WLAN queues and call the TxnDone CB on each tansaction. |
|
334 * If no transaction in progress, the queues are cleared immediately. |
|
335 * If a transaction is in progress, it is done upon TxnDone. |
|
336 * The status in transactions that were dropped due to restart is TXN_STATUS_RECOVERY, |
|
337 * and its originator (Xfer module) handles it if required (if its CB was written in the Txn). |
|
338 * |
|
339 * \note |
|
340 * \param hTwIf - The module's object |
|
341 * \return COMPLETE if the WLAN queues were restarted, PENDING if waiting for TxnDone to restart queues |
|
342 * \sa |
|
343 */ |
|
344 ETxnStatus twIf_Restart (TI_HANDLE hTwIf) |
|
345 { |
|
346 TTwIfObj *pTwIf = (TTwIfObj*) hTwIf; |
|
347 |
|
348 pTwIf->eState = SM_STATE_SLEEP; |
|
349 pTwIf->uAwakeReqCount = 0; |
|
350 |
|
351 pTwIf->uPendingTxnCount = 0; |
|
352 |
|
353 /* Clear done queue */ |
|
354 twIf_ClearTxnDoneQueue(hTwIf); |
|
355 |
|
356 /* Restart WLAN queues and return result (COMPLETE or PENDINF if completed in TxnDone context) */ |
|
357 return txnQ_Restart (pTwIf->hTxnQ, TXN_FUNC_ID_WLAN); |
|
358 } |
|
359 |
|
360 |
|
361 /** |
|
362 * \fn twIf_RegisterErrCb |
|
363 * \brief Register Error CB |
|
364 * |
|
365 * Register upper layer (health monitor) CB for bus error |
|
366 * |
|
367 * \note |
|
368 * \param hTwIf - The module's object |
|
369 * \param fErrCb - The upper layer CB function for error handling |
|
370 * \param hErrCb - The CB function handle |
|
371 * \return void |
|
372 * \sa |
|
373 */ |
|
374 void twIf_RegisterErrCb (TI_HANDLE hTwIf, void *fErrCb, TI_HANDLE hErrCb) |
|
375 { |
|
376 TTwIfObj *pTwIf = (TTwIfObj*) hTwIf; |
|
377 |
|
378 /* Save upper layer (health monitor) CB for bus error */ |
|
379 pTwIf->fErrCb = (TFailureEventCb)fErrCb; |
|
380 pTwIf->hErrCb = hErrCb; |
|
381 } |
|
382 |
|
383 |
|
384 /** |
|
385 * \fn twIf_WriteElpReg |
|
386 * \brief write ELP register |
|
387 * |
|
388 * \note |
|
389 * \param pTwIf - The module's object |
|
390 * \param uValue - ELP_CTRL_REG_SLEEP or ELP_CTRL_REG_AWAKE |
|
391 * \return void |
|
392 * \sa |
|
393 */ |
|
394 static void twIf_WriteElpReg (TTwIfObj *pTwIf, TI_UINT32 uValue) |
|
395 { |
|
396 TRACE1(pTwIf->hReport, REPORT_SEVERITY_INFORMATION, "twIf_WriteElpReg: ELP Txn data = 0x%x\n", uValue); |
|
397 |
|
398 /* Send ELP (awake or sleep) transaction to TxnQ */ |
|
399 if (uValue == ELP_CTRL_REG_AWAKE) |
|
400 { |
|
401 txnQ_Transact (pTwIf->hTxnQ, &(pTwIf->tElpTxnAwake.tHdr)); |
|
402 } |
|
403 else |
|
404 { |
|
405 txnQ_Transact (pTwIf->hTxnQ, &(pTwIf->tElpTxnSleep.tHdr)); |
|
406 } |
|
407 } |
|
408 |
|
409 |
|
410 /** |
|
411 * \fn twIf_SetPartition |
|
412 * \brief Set HW addresses partition |
|
413 * |
|
414 * Called by the HwInit module to set the HW address ranges for download or working access. |
|
415 * Generate and configure the bus access address mapping table. |
|
416 * The partition is split between register (fixed partition of 24KB size, exists in all modes), |
|
417 * and memory (dynamically changed during init and gets constant value in run-time, 104KB size). |
|
418 * The TwIf configures the memory mapping table on the device by issuing write transaction to |
|
419 * table address (note that the TxnQ and bus driver see this as a regular transaction). |
|
420 * |
|
421 * \note In future versions, a specific bus may not support partitioning (as in wUART), |
|
422 * In this case the HwInit module shall not call this function (will learn the bus |
|
423 * configuration from the INI file). |
|
424 * |
|
425 * \param hTwIf - The module's object |
|
426 * \param uMemAddr - The memory partition base address |
|
427 * \param uMemSize - The memory partition size |
|
428 * \param uRegAddr - The registers partition base address |
|
429 * \param uRegSize - The register partition size |
|
430 * \return void |
|
431 * \sa |
|
432 */ |
|
433 |
|
434 void twIf_SetPartition (TI_HANDLE hTwIf, |
|
435 TPartition *pPartition) |
|
436 { |
|
437 TTwIfObj *pTwIf = (TTwIfObj*) hTwIf; |
|
438 TPartitionRegTxn *pPartitionRegTxn;/* The partition transaction structure for one register */ |
|
439 TTxnStruct *pTxnHdr; /* The partition transaction header (as used in the TxnQ API) */ |
|
440 ETxnStatus eStatus; |
|
441 int i; |
|
442 |
|
443 /* Save partition information for translation and validation. */ |
|
444 pTwIf->uMemAddr1 = pPartition[0].uMemAdrr; |
|
445 pTwIf->uMemSize1 = pPartition[0].uMemSize; |
|
446 pTwIf->uMemAddr2 = pPartition[1].uMemAdrr; |
|
447 pTwIf->uMemSize2 = pPartition[1].uMemSize; |
|
448 pTwIf->uMemAddr3 = pPartition[2].uMemAdrr; |
|
449 pTwIf->uMemSize3 = pPartition[2].uMemSize; |
|
450 pTwIf->uMemAddr4 = pPartition[3].uMemAdrr; |
|
451 |
|
452 /* Allocate memory for the current 4 partition transactions */ |
|
453 pPartitionRegTxn = (TPartitionRegTxn *) os_memoryAlloc (pTwIf->hOs, 7*sizeof(TPartitionRegTxn),MemoryNormal); |
|
454 /* Zero the allocated memory to be certain that unused fields will be initialized */ |
|
455 os_memoryZero (pTwIf->hOs, pPartitionRegTxn, 7*sizeof(TPartitionRegTxn)); |
|
456 pTxnHdr = &(pPartitionRegTxn->tHdr); |
|
457 |
|
458 for (i = 0; i < 7; i++) |
|
459 { |
|
460 pPartitionRegTxn[i].pData = os_memoryAlloc (pTwIf->hOs, sizeof(TI_UINT32) + WSPI_PAD_LEN_READ, MemoryDMA); |
|
461 os_memoryZero (pTwIf->hOs, pPartitionRegTxn[i].pData, sizeof(TI_UINT32) + WSPI_PAD_LEN_READ); |
|
462 pPartitionRegTxn[i].pData += WSPI_PAD_LEN_READ; |
|
463 } |
|
464 |
|
465 |
|
466 /* Prepare partition transaction data */ |
|
467 *((TI_UINT32*)(pPartitionRegTxn[0].pData)) = ENDIAN_HANDLE_LONG(pTwIf->uMemAddr1); |
|
468 *((TI_UINT32*)(pPartitionRegTxn[1].pData)) = ENDIAN_HANDLE_LONG(pTwIf->uMemSize1); |
|
469 *((TI_UINT32*)(pPartitionRegTxn[2].pData)) = ENDIAN_HANDLE_LONG(pTwIf->uMemAddr2); |
|
470 *((TI_UINT32*)(pPartitionRegTxn[3].pData)) = ENDIAN_HANDLE_LONG(pTwIf->uMemSize2); |
|
471 *((TI_UINT32*)(pPartitionRegTxn[4].pData)) = ENDIAN_HANDLE_LONG(pTwIf->uMemAddr3); |
|
472 *((TI_UINT32*)(pPartitionRegTxn[5].pData)) = ENDIAN_HANDLE_LONG(pTwIf->uMemSize3); |
|
473 *((TI_UINT32*)(pPartitionRegTxn[6].pData)) = ENDIAN_HANDLE_LONG(pTwIf->uMemAddr4); |
|
474 |
|
475 |
|
476 /* Prepare partition Txn header */ |
|
477 for (i=0; i<7; i++) |
|
478 { |
|
479 pTxnHdr = &(pPartitionRegTxn[i].tHdr); |
|
480 TXN_PARAM_SET(pTxnHdr, TXN_LOW_PRIORITY, TXN_FUNC_ID_WLAN, TXN_DIRECTION_WRITE, TXN_INC_ADDR) |
|
481 TXN_PARAM_SET_MORE(pTxnHdr, 1); |
|
482 TXN_PARAM_SET_SINGLE_STEP(pTxnHdr, 0); |
|
483 } |
|
484 |
|
485 |
|
486 /* Memory address */ |
|
487 pTxnHdr = &(pPartitionRegTxn[0].tHdr); |
|
488 BUILD_TTxnStruct(pTxnHdr, PARTITION_REGISTERS_ADDR+4, pPartitionRegTxn[0].pData, REGISTER_SIZE, 0, 0) |
|
489 twIf_SendTransaction (pTwIf, pTxnHdr); |
|
490 |
|
491 /* Memory size */ |
|
492 pTxnHdr = &(pPartitionRegTxn[1].tHdr); |
|
493 BUILD_TTxnStruct(pTxnHdr, PARTITION_REGISTERS_ADDR+0, pPartitionRegTxn[1].pData, REGISTER_SIZE, 0, 0) |
|
494 twIf_SendTransaction (pTwIf, pTxnHdr); |
|
495 |
|
496 /* Registers address */ |
|
497 pTxnHdr = &(pPartitionRegTxn[2].tHdr); |
|
498 BUILD_TTxnStruct(pTxnHdr, PARTITION_REGISTERS_ADDR+12, pPartitionRegTxn[2].pData, REGISTER_SIZE, 0, 0) |
|
499 twIf_SendTransaction (pTwIf, pTxnHdr); |
|
500 |
|
501 /* Registers size */ |
|
502 pTxnHdr = &(pPartitionRegTxn[3].tHdr); |
|
503 BUILD_TTxnStruct(pTxnHdr, PARTITION_REGISTERS_ADDR+8, pPartitionRegTxn[3].pData, REGISTER_SIZE, 0, 0) |
|
504 eStatus = twIf_SendTransaction (pTwIf, pTxnHdr); |
|
505 |
|
506 |
|
507 /* Registers address */ |
|
508 pTxnHdr = &(pPartitionRegTxn[4].tHdr); |
|
509 BUILD_TTxnStruct(pTxnHdr, PARTITION_REGISTERS_ADDR+20, pPartitionRegTxn[4].pData, REGISTER_SIZE, 0, 0) |
|
510 twIf_SendTransaction (pTwIf, pTxnHdr); |
|
511 |
|
512 /* Registers size */ |
|
513 pTxnHdr = &(pPartitionRegTxn[5].tHdr); |
|
514 BUILD_TTxnStruct(pTxnHdr, PARTITION_REGISTERS_ADDR+16, pPartitionRegTxn[5].pData, REGISTER_SIZE, 0, 0) |
|
515 eStatus = twIf_SendTransaction (pTwIf, pTxnHdr); |
|
516 |
|
517 /* Registers address */ |
|
518 pTxnHdr = &(pPartitionRegTxn[6].tHdr); |
|
519 BUILD_TTxnStruct(pTxnHdr, PARTITION_REGISTERS_ADDR+24, pPartitionRegTxn[6].pData, REGISTER_SIZE, twIf_PartitionTxnDoneCb, pTwIf) |
|
520 twIf_SendTransaction (pTwIf, pTxnHdr); |
|
521 |
|
522 /* If the transaction is done, free the allocated memory (otherwise freed in the partition CB) */ |
|
523 if (eStatus != TXN_STATUS_PENDING) |
|
524 { |
|
525 for (i = 0; i < 7; i++) |
|
526 { |
|
527 os_memoryFree (pTwIf->hOs, pPartitionRegTxn[i].pData - WSPI_PAD_LEN_READ, sizeof(TI_UINT32) + WSPI_PAD_LEN_READ); |
|
528 } |
|
529 /* Release the memory for the 4 partition transactions */ |
|
530 os_memoryFree (pTwIf->hOs, pPartitionRegTxn, 7 * sizeof(TPartitionRegTxn)); |
|
531 } |
|
532 } |
|
533 |
|
534 |
|
535 static void twIf_PartitionTxnDoneCb (TI_HANDLE hTwIf, void *hTxn) |
|
536 { |
|
537 TTwIfObj *pTwIf = (TTwIfObj*) hTwIf; |
|
538 TPartitionRegTxn *pPartitionTxn; |
|
539 int i; |
|
540 |
|
541 pPartitionTxn = (TPartitionRegTxn *)((char *)hTxn - (6 * sizeof(TPartitionRegTxn))); |
|
542 |
|
543 /* Free the partition transaction buffer after completed (see transaction above) */ |
|
544 for (i = 0; i < 7; i++) |
|
545 { |
|
546 os_memoryFree (pTwIf->hOs, pPartitionTxn[i].pData - WSPI_PAD_LEN_READ, sizeof(TI_UINT32) + WSPI_PAD_LEN_READ); |
|
547 } |
|
548 os_memoryFree (pTwIf->hOs, |
|
549 (char *)hTxn - (6 * sizeof(TPartitionRegTxn)), /* Move back to the first Txn start */ |
|
550 7 * sizeof(TPartitionRegTxn)); |
|
551 } |
|
552 |
|
553 |
|
554 /** |
|
555 * \fn twIf_Awake |
|
556 * \brief Request to keep the device awake |
|
557 * |
|
558 * Used by the Xfer modules to request to keep the device awake until twIf_Sleep() is called. |
|
559 * Each call to this function increments AwakeReq counter. Once the device is awake (upon transaction), |
|
560 * the TwIf SM keeps it awake as long as this counter is not zero. |
|
561 * |
|
562 * \note |
|
563 * \param hTwIf - The module's object |
|
564 * \return void |
|
565 * \sa twIf_Sleep |
|
566 */ |
|
567 void twIf_Awake (TI_HANDLE hTwIf) |
|
568 { |
|
569 TTwIfObj *pTwIf = (TTwIfObj*) hTwIf; |
|
570 |
|
571 /* Increment awake requests counter */ |
|
572 pTwIf->uAwakeReqCount++; |
|
573 |
|
574 #ifdef TI_DBG |
|
575 pTwIf->uDbgCountAwake++; |
|
576 TRACE1(pTwIf->hReport, REPORT_SEVERITY_INFORMATION, "twIf_Awake: uAwakeReqCount = %d\n", pTwIf->uAwakeReqCount); |
|
577 #endif |
|
578 } |
|
579 |
|
580 |
|
581 /** |
|
582 * \fn twIf_Sleep |
|
583 * \brief Remove request to keep the device awake |
|
584 * |
|
585 * Each call to this function decrements AwakeReq counter. |
|
586 * Once this counter is zeroed, if the TxnQ is empty (no WLAN transactions), the TwIf SM is |
|
587 * invoked to stop the TxnQ and enable the device to sleep (write 0 to ELP register). |
|
588 * |
|
589 * \note |
|
590 * \param hTwIf - The module's object |
|
591 * \return void |
|
592 * \sa twIf_Awake |
|
593 */ |
|
594 void twIf_Sleep (TI_HANDLE hTwIf) |
|
595 { |
|
596 TTwIfObj *pTwIf = (TTwIfObj*) hTwIf; |
|
597 |
|
598 /* Decrement awake requests counter */ |
|
599 if (pTwIf->uAwakeReqCount > 0) /* in case of redundant call after recovery */ |
|
600 { |
|
601 pTwIf->uAwakeReqCount--; |
|
602 } |
|
603 |
|
604 #ifdef TI_DBG |
|
605 pTwIf->uDbgCountSleep++; |
|
606 TRACE1(pTwIf->hReport, REPORT_SEVERITY_INFORMATION, "twIf_Sleep: uAwakeReqCount = %d\n", pTwIf->uAwakeReqCount); |
|
607 #endif |
|
608 |
|
609 /* If Awake not required and no pending transactions in TxnQ, issue Sleep event to SM */ |
|
610 if ((pTwIf->uAwakeReqCount == 0) && (pTwIf->uPendingTxnCount == 0)) |
|
611 { |
|
612 twIf_HandleSmEvent (pTwIf, SM_EVENT_SLEEP); |
|
613 } |
|
614 } |
|
615 |
|
616 |
|
617 /** |
|
618 * \fn twIf_HwAvailable |
|
619 * \brief The device is awake |
|
620 * |
|
621 * This is an indication from the FwEvent that the device is awake. |
|
622 * Issue HW_AVAILABLE event to the SM. |
|
623 * |
|
624 * \note |
|
625 * \param hTwIf - The module's object |
|
626 * \return void |
|
627 * \sa |
|
628 */ |
|
629 void twIf_HwAvailable (TI_HANDLE hTwIf) |
|
630 { |
|
631 TTwIfObj *pTwIf = (TTwIfObj*) hTwIf; |
|
632 |
|
633 TRACE0(pTwIf->hReport, REPORT_SEVERITY_INFORMATION, "twIf_HwAvailable: HW is Available\n"); |
|
634 |
|
635 /* Issue HW_AVAILABLE event to the SM */ |
|
636 twIf_HandleSmEvent (pTwIf, SM_EVENT_HW_AVAILABLE); |
|
637 } |
|
638 |
|
639 |
|
640 /** |
|
641 * \fn twIf_Transact |
|
642 * \brief Issue a transaction |
|
643 * |
|
644 * This method is used by the Xfer modules to issue all transaction types. |
|
645 * Translate HW address according to bus partition and call twIf_SendTransaction(). |
|
646 * |
|
647 * \note |
|
648 * \param hTwIf - The module's object |
|
649 * \param pTxn - The transaction object |
|
650 * \return COMPLETE if the transaction was completed in this context, PENDING if not, ERROR if failed |
|
651 * \sa twIf_SendTransaction |
|
652 */ |
|
653 ETxnStatus twIf_Transact (TI_HANDLE hTwIf, TTxnStruct *pTxn) |
|
654 { |
|
655 TTwIfObj *pTwIf = (TTwIfObj*)hTwIf; |
|
656 |
|
657 /* Translate HW address for registers region */ |
|
658 if ((pTxn->uHwAddr >= pTwIf->uMemAddr2) && (pTxn->uHwAddr <= pTwIf->uMemAddr2 + pTwIf->uMemSize2)) |
|
659 { |
|
660 pTxn->uHwAddr = pTxn->uHwAddr - pTwIf->uMemAddr2 + pTwIf->uMemSize1; |
|
661 } |
|
662 /* Translate HW address for memory region */ |
|
663 else |
|
664 { |
|
665 pTxn->uHwAddr = pTxn->uHwAddr - pTwIf->uMemAddr1; |
|
666 } |
|
667 |
|
668 /* Regular transaction are not the last and are not single step (only ELP write is) */ |
|
669 TXN_PARAM_SET_MORE(pTxn, 1); |
|
670 TXN_PARAM_SET_SINGLE_STEP(pTxn, 0); |
|
671 |
|
672 /* Send the transaction to the TxnQ and update the SM if needed. */ |
|
673 return twIf_SendTransaction (pTwIf, pTxn); |
|
674 } |
|
675 |
|
676 ETxnStatus twIf_TransactReadFWStatus (TI_HANDLE hTwIf, TTxnStruct *pTxn) |
|
677 { |
|
678 TTwIfObj *pTwIf = (TTwIfObj*)hTwIf; |
|
679 |
|
680 /* Regular transaction are not the last and are not single step (only ELP write is) */ |
|
681 TXN_PARAM_SET_MORE(pTxn, 1); |
|
682 TXN_PARAM_SET_SINGLE_STEP(pTxn, 0); |
|
683 |
|
684 /* Send the transaction to the TxnQ and update the SM if needed. */ |
|
685 return twIf_SendTransaction (pTwIf, pTxn); |
|
686 } |
|
687 |
|
688 |
|
689 /** |
|
690 * \fn twIf_SendTransaction |
|
691 * \brief Send a transaction to the device |
|
692 * |
|
693 * This method is used by the Xfer modules and the TwIf to send all transaction types to the device. |
|
694 * Send the transaction to the TxnQ and update the SM if needed. |
|
695 * |
|
696 * \note |
|
697 * \param pTwIf - The module's object |
|
698 * \param pTxn - The transaction object |
|
699 * \return COMPLETE if the transaction was completed in this context, PENDING if not, ERROR if failed |
|
700 * \sa |
|
701 */ |
|
702 static ETxnStatus twIf_SendTransaction (TTwIfObj *pTwIf, TTxnStruct *pTxn) |
|
703 { |
|
704 ETxnStatus eStatus; |
|
705 |
|
706 #ifdef TI_DBG |
|
707 /* Verify that the Txn HW-Address is 4-bytes aligned |
|
708 - in QOS it should be 2 bytes aligned */ |
|
709 if (pTxn->uHwAddr & 0x3) |
|
710 { |
|
711 TRACE2(pTwIf->hReport, REPORT_SEVERITY_WARNING, "twIf_SendTransaction: Unaligned HwAddr! might be QOS: HwAddr=0x%x, Params=0x%x\n", pTxn->uHwAddr, pTxn->uTxnParams); |
|
712 } |
|
713 /* Verify that the host addresses lengths are 4-bytes aligned */ |
|
714 if ((pTxn->aLen[0] & 0x3) || (pTxn->aLen[1] & 0x3)) |
|
715 { |
|
716 TRACE6(pTwIf->hReport, REPORT_SEVERITY_WARNING, "twIf_SendTransaction: Unaligned Length! might be QOS: Len0=%d, Len1=%d, Len2=%d, Len3=%d, Params=0x%x, HwAddr=0x%x\n", pTxn->aLen[0], pTxn->aLen[1], pTxn->aLen[2], pTxn->aLen[3], pTxn->uTxnParams, pTxn->uHwAddr); |
|
717 |
|
718 } |
|
719 /* |
|
720 * Note: We may add other checks here, like length 2 & 3 and host addresses alignment. |
|
721 * Note that the host address for read transaction may be unaligned (for Rx-Xfer QoS packets) |
|
722 */ |
|
723 #endif |
|
724 |
|
725 |
|
726 /* Send transaction to TxnQ */ |
|
727 eStatus = txnQ_Transact(pTwIf->hTxnQ, pTxn); |
|
728 |
|
729 #ifdef TI_DBG |
|
730 pTwIf->uDbgCountTxn++; |
|
731 if (eStatus == TXN_STATUS_COMPLETE) { pTwIf->uDbgCountTxnComplete++; } |
|
732 else if (eStatus == TXN_STATUS_PENDING ) { pTwIf->uDbgCountTxnPending++; } |
|
733 TRACE8(pTwIf->hReport, REPORT_SEVERITY_INFORMATION, "twIf_SendTransaction: Status = %d, Params=0x%x, HwAddr=0x%x, Len0=%d, Len1=%d, Len2=%d, Len3=%d, Data0=%x \n", eStatus, pTxn->uTxnParams, pTxn->uHwAddr, pTxn->aLen[0], pTxn->aLen[1], pTxn->aLen[2], pTxn->aLen[3], *((TI_UINT32*)pTxn->aBuf[0])); |
|
734 #endif |
|
735 |
|
736 /* If Txn status is PENDING, increment pending Txn counter and issue Start event to the SM */ |
|
737 if (eStatus == TXN_STATUS_PENDING) |
|
738 { |
|
739 pTwIf->uPendingTxnCount++; |
|
740 twIf_HandleSmEvent (pTwIf, SM_EVENT_START); |
|
741 } |
|
742 |
|
743 /* Else (COMPLETE or ERROR) */ |
|
744 else |
|
745 { |
|
746 /* If Awake not required and no pending transactions in TxnQ, issue Sleep event to SM */ |
|
747 if ((pTwIf->uAwakeReqCount == 0) && (pTwIf->uPendingTxnCount == 0)) |
|
748 { |
|
749 twIf_HandleSmEvent (pTwIf, SM_EVENT_SLEEP); |
|
750 } |
|
751 |
|
752 /* If Txn failed and error CB available, call it to initiate recovery */ |
|
753 if (eStatus == TXN_STATUS_ERROR) |
|
754 { |
|
755 TRACE6(pTwIf->hReport, REPORT_SEVERITY_ERROR, "twIf_SendTransaction: Txn failed!! Params=0x%x, HwAddr=0x%x, Len0=%d, Len1=%d, Len2=%d, Len3=%d\n", pTxn->uTxnParams, pTxn->uHwAddr, pTxn->aLen[0], pTxn->aLen[1], pTxn->aLen[2], pTxn->aLen[3]); |
|
756 |
|
757 if (pTwIf->fErrCb) |
|
758 { |
|
759 pTwIf->fErrCb (pTwIf->hErrCb, BUS_FAILURE); |
|
760 } |
|
761 } |
|
762 } |
|
763 |
|
764 /* Return the Txn status (COMPLETE if completed in this context, PENDING if not, ERROR if failed) */ |
|
765 return eStatus; |
|
766 } |
|
767 |
|
768 |
|
769 /** |
|
770 * \fn twIf_HandleSmEvent |
|
771 * \brief The TwIf SM implementation |
|
772 * |
|
773 * Handle SM event. |
|
774 * Control the device awake/sleep states and the TxnQ run/stop states according to the event. |
|
775 * |
|
776 * \note |
|
777 * \param hTwIf - The module's object |
|
778 * \return void |
|
779 * \sa |
|
780 */ |
|
781 static void twIf_HandleSmEvent (TTwIfObj *pTwIf, ESmEvent eEvent) |
|
782 { |
|
783 ESmState eState = pTwIf->eState; /* The state before handling the event */ |
|
784 |
|
785 /* Switch by current state and handle event */ |
|
786 switch (eState) |
|
787 { |
|
788 case SM_STATE_AWAKE: |
|
789 /* SLEEP event: AWAKE ==> SLEEP, stop TxnQ and set ELP reg to sleep */ |
|
790 if (eEvent == SM_EVENT_SLEEP) |
|
791 { |
|
792 pTwIf->eState = SM_STATE_SLEEP; |
|
793 txnQ_Stop (pTwIf->hTxnQ, TXN_FUNC_ID_WLAN); |
|
794 twIf_WriteElpReg (pTwIf, ELP_CTRL_REG_SLEEP); |
|
795 } |
|
796 break; |
|
797 case SM_STATE_SLEEP: |
|
798 /* START event: SLEEP ==> WAIT_HW, set ELP reg to wake-up */ |
|
799 if (eEvent == SM_EVENT_START) |
|
800 { |
|
801 pTwIf->eState = SM_STATE_WAIT_HW; |
|
802 twIf_WriteElpReg (pTwIf, ELP_CTRL_REG_AWAKE); |
|
803 } |
|
804 /* HW_AVAILABLE event: SLEEP ==> AWAKE, set ELP reg to wake-up and run TxnQ */ |
|
805 else if (eEvent == SM_EVENT_HW_AVAILABLE) |
|
806 { |
|
807 pTwIf->eState = SM_STATE_AWAKE; |
|
808 twIf_WriteElpReg (pTwIf, ELP_CTRL_REG_AWAKE); |
|
809 txnQ_Run (pTwIf->hTxnQ, TXN_FUNC_ID_WLAN); |
|
810 } |
|
811 break; |
|
812 case SM_STATE_WAIT_HW: |
|
813 /* HW_AVAILABLE event: WAIT_HW ==> AWAKE, run TxnQ */ |
|
814 if (eEvent == SM_EVENT_HW_AVAILABLE) |
|
815 { |
|
816 pTwIf->eState = SM_STATE_AWAKE; |
|
817 txnQ_Run (pTwIf->hTxnQ, TXN_FUNC_ID_WLAN); |
|
818 } |
|
819 break; |
|
820 } |
|
821 |
|
822 TRACE3(pTwIf->hReport, REPORT_SEVERITY_INFORMATION, "twIf_HandleSmEvent: <currentState = %d, event = %d> --> nextState = %d\n", eState, eEvent, pTwIf->eState); |
|
823 } |
|
824 |
|
825 |
|
826 /** |
|
827 * \fn twIf_TxnDoneCb |
|
828 * \brief Transaction completion CB |
|
829 * |
|
830 * This callback is called by the TxnQ upon transaction completion, unless is was completed in |
|
831 * the original context where it was issued. |
|
832 * It may be called from bus driver external context (TxnDone ISR) or from WLAN driver context. |
|
833 * |
|
834 * \note |
|
835 * \param hTwIf - The module's object |
|
836 * \param pTxn - The completed transaction object |
|
837 * \return void |
|
838 * \sa twIf_HandleTxnDone |
|
839 */ |
|
840 static void twIf_TxnDoneCb (TI_HANDLE hTwIf, TTxnStruct *pTxn) |
|
841 { |
|
842 TTwIfObj *pTwIf = (TTwIfObj*)hTwIf; |
|
843 |
|
844 #ifdef TI_DBG |
|
845 pTwIf->uDbgCountTxnDoneCb++; |
|
846 TRACE6(pTwIf->hReport, REPORT_SEVERITY_INFORMATION, "twIf_TxnDoneCb: Params=0x%x, HwAddr=0x%x, Len0=%d, Len1=%d, Len2=%d, Len3=%d\n", pTxn->uTxnParams, pTxn->uHwAddr, pTxn->aLen[0], pTxn->aLen[1], pTxn->aLen[2], pTxn->aLen[3]); |
|
847 #endif |
|
848 |
|
849 /* In case of recovery flag, Call directly restart callback */ |
|
850 if (TXN_PARAM_GET_STATUS(pTxn) == TXN_PARAM_STATUS_RECOVERY) |
|
851 { |
|
852 if (pTwIf->fRecoveryCb) |
|
853 { |
|
854 TRACE0(pTwIf->hReport, REPORT_SEVERITY_INFORMATION, "twIf_TxnDoneCb: call RecoveryCb\n"); |
|
855 pTwIf->fRecoveryCb(pTwIf->hRecoveryCb); |
|
856 return; |
|
857 } |
|
858 } |
|
859 |
|
860 /* If the completed Txn is ELP, nothing to do (not counted) so exit */ |
|
861 if (TXN_PARAM_GET_SINGLE_STEP(pTxn)) |
|
862 { |
|
863 return; |
|
864 } |
|
865 |
|
866 if (pTxn->fTxnDoneCb) |
|
867 { |
|
868 /* In critical section, enqueue the completed transaction in the TxnDoneQ. */ |
|
869 que_Enqueue (pTwIf->hTxnDoneQueue, (TI_HANDLE)pTxn); |
|
870 } |
|
871 else |
|
872 { |
|
873 /* Decrement pending Txn counter, It's value will be checked in twIf_HandleTxnDone() */ |
|
874 if (pTwIf->uPendingTxnCount > 0) /* in case of callback on recovery after restart */ |
|
875 { |
|
876 pTwIf->uPendingTxnCount--; |
|
877 } |
|
878 } |
|
879 |
|
880 /* Request schedule to continue handling in driver context (will call twIf_HandleTxnDone()) */ |
|
881 context_RequestSchedule (pTwIf->hContext, pTwIf->uContextId); |
|
882 } |
|
883 |
|
884 |
|
885 /** |
|
886 * \fn twIf_HandleTxnDone |
|
887 * \brief Completed transactions handler |
|
888 * |
|
889 * The completed transactions handler, called upon TxnDone event, either from the context engine |
|
890 * or directly from twIf_TxnDoneCb() if we are already in the WLAN driver's context. |
|
891 * Dequeue all completed transactions in critical section, and call their callbacks if available. |
|
892 * If awake is not required and no pending transactions in TxnQ, issue Sleep event to SM. |
|
893 * |
|
894 * \note |
|
895 * \param hTwIf - The module's object |
|
896 * \return void |
|
897 * \sa |
|
898 */ |
|
899 static void twIf_HandleTxnDone (TI_HANDLE hTwIf) |
|
900 { |
|
901 TTwIfObj *pTwIf = (TTwIfObj*)hTwIf; |
|
902 TTxnStruct *pTxn; |
|
903 |
|
904 /* Loop while there are completed transactions to handle */ |
|
905 while (1) |
|
906 { |
|
907 /* In critical section, dequeue completed transaction from the TxnDoneQ. */ |
|
908 CONTEXT_ENTER_CRITICAL_SECTION (pTwIf->hContext); |
|
909 pTxn = (TTxnStruct *) que_Dequeue (pTwIf->hTxnDoneQueue); |
|
910 CONTEXT_LEAVE_CRITICAL_SECTION (pTwIf->hContext); |
|
911 |
|
912 /* If no more transactions to handle, exit */ |
|
913 if (pTxn != NULL) |
|
914 { |
|
915 /* Decrement pending Txn counter */ |
|
916 if (pTwIf->uPendingTxnCount > 0) /* in case of callback on recovery after restart */ |
|
917 { |
|
918 pTwIf->uPendingTxnCount--; |
|
919 } |
|
920 |
|
921 TRACE4(pTwIf->hReport, REPORT_SEVERITY_INFORMATION, "twIf_HandleTxnDone: Completed-Txn: Params=0x%x, HwAddr=0x%x, Len0=%d, fTxnDoneCb=0x%x\n", pTxn->uTxnParams, pTxn->uHwAddr, pTxn->aLen[0], pTxn->fTxnDoneCb); |
|
922 |
|
923 /* If Txn failed and error CB available, call it to initiate recovery */ |
|
924 if (TXN_PARAM_GET_STATUS(pTxn) == TXN_PARAM_STATUS_ERROR) |
|
925 { |
|
926 TRACE6(pTwIf->hReport, REPORT_SEVERITY_ERROR, "twIf_HandleTxnDone: Txn failed!! Params=0x%x, HwAddr=0x%x, Len0=%d, Len1=%d, Len2=%d, Len3=%d\n", pTxn->uTxnParams, pTxn->uHwAddr, pTxn->aLen[0], pTxn->aLen[1], pTxn->aLen[2], pTxn->aLen[3]); |
|
927 |
|
928 if (pTwIf->fErrCb) |
|
929 { |
|
930 pTwIf->fErrCb (pTwIf->hErrCb, BUS_FAILURE); |
|
931 } |
|
932 /* in error do not continue */ |
|
933 return; |
|
934 } |
|
935 |
|
936 /* If Txn specific CB available, call it (may free Txn resources and issue new Txns) */ |
|
937 if (pTxn->fTxnDoneCb != NULL) |
|
938 { |
|
939 ((TTxnDoneCb)(pTxn->fTxnDoneCb)) (pTxn->hCbHandle, pTxn); |
|
940 } |
|
941 } |
|
942 |
|
943 /*If uPendingTxnCount == 0 and awake not required, issue Sleep event to SM */ |
|
944 if ((pTwIf->uAwakeReqCount == 0) && (pTwIf->uPendingTxnCount == 0)) |
|
945 { |
|
946 twIf_HandleSmEvent (pTwIf, SM_EVENT_SLEEP); |
|
947 } |
|
948 |
|
949 if (pTxn == NULL) |
|
950 { |
|
951 return; |
|
952 } |
|
953 } |
|
954 } |
|
955 |
|
956 /** |
|
957 * \fn twIf_ClearTxnDoneQueue |
|
958 * \brief Clean the DoneQueue |
|
959 * |
|
960 * Clear the specified done queue - don't call the callbacks. |
|
961 * |
|
962 * \note |
|
963 * \param hTwIf - The module's object |
|
964 * \return void |
|
965 * \sa |
|
966 */ |
|
967 static void twIf_ClearTxnDoneQueue (TI_HANDLE hTwIf) |
|
968 { |
|
969 TTwIfObj *pTwIf = (TTwIfObj*)hTwIf; |
|
970 TTxnStruct *pTxn; |
|
971 |
|
972 /* Loop while there are completed transactions to handle */ |
|
973 while (1) |
|
974 { |
|
975 /* In critical section, dequeue completed transaction from the TxnDoneQ. */ |
|
976 CONTEXT_ENTER_CRITICAL_SECTION (pTwIf->hContext); |
|
977 pTxn = (TTxnStruct *) que_Dequeue (pTwIf->hTxnDoneQueue); |
|
978 CONTEXT_LEAVE_CRITICAL_SECTION (pTwIf->hContext); |
|
979 |
|
980 /* If no more transactions to handle, exit */ |
|
981 if (pTxn != NULL) |
|
982 { |
|
983 /* Decrement pending Txn counter */ |
|
984 if (pTwIf->uPendingTxnCount > 0) /* in case of callback on recovery after restart */ |
|
985 { |
|
986 pTwIf->uPendingTxnCount--; |
|
987 } |
|
988 |
|
989 /* |
|
990 * Drop on Recovery |
|
991 * do not call pTxn->fTxnDoneCb (pTxn->hCbHandle, pTxn) callback |
|
992 */ |
|
993 } |
|
994 |
|
995 if (pTxn == NULL) |
|
996 { |
|
997 return; |
|
998 } |
|
999 } |
|
1000 } |
|
1001 TI_BOOL twIf_isValidMemoryAddr(TI_HANDLE hTwIf, TI_UINT32 Address, TI_UINT32 Length) |
|
1002 { |
|
1003 TTwIfObj *pTwIf = (TTwIfObj*)hTwIf; |
|
1004 |
|
1005 if ((Address >= pTwIf->uMemAddr1) && |
|
1006 (Address + Length < pTwIf->uMemAddr1 + pTwIf->uMemSize1 )) |
|
1007 return TI_TRUE; |
|
1008 |
|
1009 return TI_FALSE; |
|
1010 } |
|
1011 |
|
1012 TI_BOOL twIf_isValidRegAddr(TI_HANDLE hTwIf, TI_UINT32 Address, TI_UINT32 Length) |
|
1013 { |
|
1014 TTwIfObj *pTwIf = (TTwIfObj*)hTwIf; |
|
1015 |
|
1016 if ((Address >= pTwIf->uMemAddr2 ) && |
|
1017 ( Address < pTwIf->uMemAddr2 + pTwIf->uMemSize2 )) |
|
1018 return TI_TRUE; |
|
1019 |
|
1020 return TI_FALSE; |
|
1021 } |
|
1022 |
|
1023 /******************************************************************************* |
|
1024 * DEBUG FUNCTIONS IMPLEMENTATION * |
|
1025 ********************************************************************************/ |
|
1026 |
|
1027 #ifdef TI_DBG |
|
1028 |
|
1029 /** |
|
1030 * \fn twIf_PrintModuleInfo |
|
1031 * \brief Print module's parameters (debug) |
|
1032 * |
|
1033 * This function prints the module's parameters. |
|
1034 * |
|
1035 * \note |
|
1036 * \param hTwIf - The module's object |
|
1037 * \return void |
|
1038 * \sa |
|
1039 */ |
|
1040 void twIf_PrintModuleInfo (TI_HANDLE hTwIf) |
|
1041 { |
|
1042 TTwIfObj *pTwIf = (TTwIfObj*)hTwIf; |
|
1043 |
|
1044 WLAN_OS_REPORT(("-------------- TwIf Module Info-- ------------------------\n")); |
|
1045 WLAN_OS_REPORT(("==========================================================\n")); |
|
1046 WLAN_OS_REPORT(("eSmState = %d\n", pTwIf->eState )); |
|
1047 WLAN_OS_REPORT(("uContextId = %d\n", pTwIf->uContextId )); |
|
1048 WLAN_OS_REPORT(("fErrCb = %d\n", pTwIf->fErrCb )); |
|
1049 WLAN_OS_REPORT(("hErrCb = %d\n", pTwIf->hErrCb )); |
|
1050 WLAN_OS_REPORT(("uAwakeReqCount = %d\n", pTwIf->uAwakeReqCount )); |
|
1051 WLAN_OS_REPORT(("uPendingTxnCount = %d\n", pTwIf->uPendingTxnCount )); |
|
1052 WLAN_OS_REPORT(("uMemAddr = 0x%x\n", pTwIf->uMemAddr1 )); |
|
1053 WLAN_OS_REPORT(("uMemSize = 0x%x\n", pTwIf->uMemSize1 )); |
|
1054 WLAN_OS_REPORT(("uRegAddr = 0x%x\n", pTwIf->uMemAddr2 )); |
|
1055 WLAN_OS_REPORT(("uRegSize = 0x%x\n", pTwIf->uMemSize2 )); |
|
1056 WLAN_OS_REPORT(("uFWStatuSize = 0x%x\n", pTwIf->uMemSize3 )); |
|
1057 WLAN_OS_REPORT(("uFWStatuAddr = 0x%x\n", pTwIf->uMemSize3 )); |
|
1058 WLAN_OS_REPORT(("uFWMemAddr = 0x%x\n", pTwIf->uMemAddr4 )); |
|
1059 WLAN_OS_REPORT(("uDbgCountAwake = %d\n", pTwIf->uDbgCountAwake )); |
|
1060 WLAN_OS_REPORT(("uDbgCountSleep = %d\n", pTwIf->uDbgCountSleep )); |
|
1061 WLAN_OS_REPORT(("uDbgCountTxn = %d\n", pTwIf->uDbgCountTxn )); |
|
1062 WLAN_OS_REPORT(("uDbgCountTxnPending = %d\n", pTwIf->uDbgCountTxnPending )); |
|
1063 WLAN_OS_REPORT(("uDbgCountTxnComplete = %d\n", pTwIf->uDbgCountTxnComplete )); |
|
1064 WLAN_OS_REPORT(("uDbgCountTxnDone = %d\n", pTwIf->uDbgCountTxnDoneCb )); |
|
1065 WLAN_OS_REPORT(("==========================================================\n\n")); |
|
1066 } |
|
1067 |
|
1068 |
|
1069 void twIf_PrintQueues (TI_HANDLE hTwIf) |
|
1070 { |
|
1071 TTwIfObj *pTwIf = (TTwIfObj*)hTwIf; |
|
1072 |
|
1073 txnQ_PrintQueues(pTwIf->hTxnQ); |
|
1074 } |
|
1075 |
|
1076 |
|
1077 #endif /* TI_DBG */ |
|
1078 |
|
1079 |
|
1080 |
|
1081 |