1/*
2 * CmdMBox.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/** \file  CmdMBox.c
36 *  \brief Handle the wlan hardware command mailbox
37 *
38 *  \see CmdMBox.h, CmdMBox_api.h, CmdQueue.c
39 */
40
41#define __FILE_ID__  FILE_ID_101
42#include "tidef.h"
43#include "osApi.h"
44#include "timer.h"
45#include "report.h"
46#include "FwEvent_api.h"
47#include "CmdMBox_api.h"
48#include "CmdMBox.h"
49#include "CmdQueue_api.h"
50#include "TWDriverInternal.h"
51#include "TwIf.h"
52
53/*****************************************************************************
54 **         Internal functions definitions                                  **
55 *****************************************************************************/
56
57/*
58 * \brief	Handle cmdMbox timeout.
59 *
60 * \param  hCmdMbox  - Handle to CmdMbox
61 * \return TI_OK
62 *
63 * \par Description
64 * Call fErrorCb() to handle the error.
65 *
66 * \sa cmdMbox_SendCommand
67 */
68static void cmdMbox_TimeOut (TI_HANDLE hCmdMbox, TI_BOOL bTwdInitOccured);
69static void cmdMbox_ConfigHwCb (TI_HANDLE hCmdMbox, TTxnStruct *pTxn);
70
71/*
72 * \brief	Create the mailbox object
73 *
74 * \param  hOs  - OS module object handle
75 * \return Handle to the created object
76 *
77 * \par Description
78 * Calling this function creates a CmdMbox object
79 *
80 * \sa cmdMbox_Destroy
81 */
82TI_HANDLE cmdMbox_Create (TI_HANDLE hOs)
83{
84    TCmdMbox   *pCmdMbox;
85
86    pCmdMbox = os_memoryAlloc (hOs, sizeof (TCmdMbox));
87    if (pCmdMbox == NULL)
88    {
89        WLAN_OS_REPORT (("FATAL ERROR: cmdMbox_Create(): Error Creating CmdMbox - Aborting\n"));
90        return NULL;
91    }
92
93    /* reset control module control block */
94    os_memoryZero (hOs, pCmdMbox, sizeof (TCmdMbox));
95    pCmdMbox->hOs = hOs;
96
97    return pCmdMbox;
98}
99
100
101/*
102 * \brief	Destroys the mailbox object
103 *
104 * \param  hCmdMbox  - The object to free
105 * \return TI_OK
106 *
107 * \par Description
108 * Calling this function destroys a CmdMbox object
109 *
110 * \sa cmdMbox_Create
111 */
112TI_STATUS cmdMbox_Destroy (TI_HANDLE hCmdMbox)
113{
114    TCmdMbox   *pCmdMbox = (TCmdMbox *)hCmdMbox;
115
116    /* free timer */
117    if (pCmdMbox->hCmdMboxTimer)
118    {
119        tmr_DestroyTimer (pCmdMbox->hCmdMboxTimer);
120    }
121
122    /* free context */
123    os_memoryFree (pCmdMbox->hOs, pCmdMbox, sizeof (TCmdMbox));
124
125    return TI_OK;
126}
127
128
129/*
130 * \brief	Configure the CmdMbox object
131 *
132 * \param  hCmdMbox  - Handle to CmdMbox
133 * \param  hReport  - Handle to report module
134 * \param  hTwIf  - Handle to TwIf
135 * \param  hTimer  - Handle to os timer
136 * \param  hCmdQueue  - Handle to CmdQueue
137 * \param  fErrorCb  - Handle to error handling function
138 * \return TI_OK on success or TI_NOK on failure
139 *
140 * \par Description
141 *
142 * \sa
143 */
144TI_STATUS cmdMbox_Init (TI_HANDLE hCmdMbox,
145                          TI_HANDLE             hReport,
146                        TI_HANDLE hTwIf,
147                          TI_HANDLE             hTimer,
148                        TI_HANDLE hCmdQueue,
149                          TCmdMboxErrorCb       fErrorCb)
150{
151    TCmdMbox   *pCmdMbox = (TCmdMbox *)hCmdMbox;
152
153    pCmdMbox->hCmdQueue = hCmdQueue;
154    pCmdMbox->hTwIf = hTwIf;
155    pCmdMbox->hReport = hReport;
156    pCmdMbox->hCmdMboxTimer = hTimer;
157
158    pCmdMbox->uFwAddr = 0;
159    pCmdMbox->uReadLen = 0;
160    pCmdMbox->uWriteLen = 0;
161    pCmdMbox->bCmdInProgress = TI_FALSE;
162    pCmdMbox->fErrorCb = fErrorCb;
163
164	/* allocate OS timer memory */
165    pCmdMbox->hCmdMboxTimer = tmr_CreateTimer (hTimer);
166	if (pCmdMbox->hCmdMboxTimer == NULL)
167	{
168        TRACE0(pCmdMbox->hReport, REPORT_SEVERITY_ERROR, "cmdMbox_Init(): Failed to create hCmdMboxTimer!\n");
169		return TI_NOK;
170	}
171
172    return TI_OK;
173}
174
175
176/*
177 * \brief	Send the Command to the Mailbox
178 *
179 * \param  hCmdMbox  - Handle to CmdMbox
180 * \param  cmdType  -
181 * \param  pParamsBuf  - The buffer that will be written to the mailbox
182 * \param  uWriteLen  - Length of data to write to the mailbox
183 * \param  uReadLen  - Length of data to read from the mailbox (when the result is received)
184 * \return TI_PENDING
185 *
186 * \par Description
187 * Copy the buffer given to a local struct, update the write & read lengths
188 * and send to the FW's mailbox.
189 *
190 *       ------------------------------------------------------
191 *      | CmdMbox Header | Cmd Header    | Command parameters |
192 *      ------------------------------------------------------
193 *      | ID   | Status  | Type | Length | Command parameters |
194 *      ------------------------------------------------------
195 *       16bit   16bit    16bit   16bit
196 *
197 * \sa cmdMbox_CommandComplete
198 */
199TI_STATUS cmdMbox_SendCommand       (TI_HANDLE hCmdMbox, Command_e cmdType, TI_UINT8* pParamsBuf, TI_UINT32 uWriteLen, TI_UINT32 uReadLen)
200{
201    TCmdMbox   *pCmdMbox = (TCmdMbox *)hCmdMbox;
202    TTxnStruct *pCmdTxn = (TTxnStruct*)&pCmdMbox->aCmdTxn[0].tTxnStruct;
203    TTxnStruct *pRegTxn = (TTxnStruct*)&pCmdMbox->aRegTxn[0].tTxnStruct;
204    Command_t  *pCmd = (Command_t*)&pCmdMbox->aCmdTxn[0].tCmdMbox;
205
206
207    if (pCmdMbox->bCmdInProgress)
208    {
209        TRACE0(pCmdMbox->hReport, REPORT_SEVERITY_ERROR, "cmdMbox_SendCommand(): Trying to send Cmd while other Cmd is still in progres!\n");
210        return TI_NOK;
211    }
212
213    /* Add the CMDMBOX_HEADER_LEN to the read length, used when reading the result later on */
214    pCmdMbox->uReadLen = uReadLen + CMDMBOX_HEADER_LEN;
215    /* Prepare the Cmd Hw template */
216    pCmd->cmdID = cmdType;
217    pCmd->cmdStatus = TI_OK;
218    os_memoryCopy (pCmdMbox->hOs, (void *)pCmd->parameters, (void *)pParamsBuf, uWriteLen);
219
220    /* Add the CMDMBOX_HEADER_LEN to the write length */
221    pCmdMbox->uWriteLen = uWriteLen + CMDMBOX_HEADER_LEN;
222
223    /* Must make sure that the length is multiple of 32 bit */
224    if (pCmdMbox->uWriteLen & 0x3)
225    {
226        TRACE1(pCmdMbox->hReport, REPORT_SEVERITY_WARNING, "cmdMbox_SendCommand(): Command length isn't 32bit aligned! CmdId=%d\n", pCmd->cmdID);
227        pCmdMbox->uWriteLen = (pCmdMbox->uWriteLen + 4) & 0xFFFFFFFC;
228    }
229
230    /* no other command can start the send process  till bCmdInProgress will return to TI_FALSE*/
231    pCmdMbox->bCmdInProgress = TI_TRUE;
232
233    /* Build the command TxnStruct */
234    TXN_PARAM_SET(pCmdTxn, TXN_LOW_PRIORITY, TXN_FUNC_ID_WLAN, TXN_DIRECTION_WRITE, TXN_INC_ADDR)
235    BUILD_TTxnStruct(pCmdTxn, pCmdMbox->uFwAddr, pCmd, pCmdMbox->uWriteLen, NULL, NULL)
236    /* Send the command */
237    twIf_Transact(pCmdMbox->hTwIf, pCmdTxn);
238
239    /* Build the trig TxnStruct */
240    pCmdMbox->aRegTxn[0].uRegister = INTR_TRIG_CMD;
241    TXN_PARAM_SET(pRegTxn, TXN_LOW_PRIORITY, TXN_FUNC_ID_WLAN, TXN_DIRECTION_WRITE, TXN_INC_ADDR)
242    BUILD_TTxnStruct(pRegTxn, ACX_REG_INTERRUPT_TRIG, &(pCmdMbox->aRegTxn[0].uRegister), REGISTER_SIZE, NULL, NULL)
243
244    /* start the CmdMbox timer */
245    tmr_StartTimer (pCmdMbox->hCmdMboxTimer, cmdMbox_TimeOut, hCmdMbox, CMDMBOX_WAIT_TIMEOUT, TI_FALSE);
246
247    /* Send the FW trigger */
248    twIf_Transact(pCmdMbox->hTwIf, pRegTxn);
249
250
251    return TXN_STATUS_PENDING;
252}
253
254
255/*
256 * \brief	Read the command's result
257 *
258 * \param  hCmdMbox  - Handle to CmdMbox
259 * \return void
260 *
261 * \par Description
262 * This function is called from FwEvent module uppon receiving command complete interrupt.
263 * It issues a read transaction from the mailbox with a CB.
264 *
265 * \sa cmdMbox_SendCommand, cmdMbox_TransferComplete
266 */
267void cmdMbox_CommandComplete (TI_HANDLE hCmdMbox)
268{
269    TCmdMbox   *pCmdMbox = (TCmdMbox *)hCmdMbox;
270    TTxnStruct *pCmdTxn = (TTxnStruct*)&pCmdMbox->aCmdTxn[1].tTxnStruct;
271    Command_t  *pCmd = (Command_t*)&pCmdMbox->aCmdTxn[1].tCmdMbox;
272    ETxnStatus  rc;
273
274    /* stop the CmdMbox timer */
275    tmr_StopTimer(pCmdMbox->hCmdMboxTimer);
276
277    /* Build the command TxnStruct */
278    TXN_PARAM_SET(pCmdTxn, TXN_LOW_PRIORITY, TXN_FUNC_ID_WLAN, TXN_DIRECTION_READ, TXN_INC_ADDR)
279    /* Applying a CB in case of an async read */
280    BUILD_TTxnStruct(pCmdTxn, pCmdMbox->uFwAddr, pCmd, pCmdMbox->uReadLen,(TTxnDoneCb)cmdMbox_TransferComplete, hCmdMbox)
281    /* Send the command */
282    rc = twIf_Transact(pCmdMbox->hTwIf, pCmdTxn);
283
284    /* In case of a sync read, call the CB directly */
285    if (rc == TXN_STATUS_COMPLETE)
286    {
287        cmdMbox_TransferComplete(hCmdMbox);
288    }
289}
290
291
292/*
293 * \brief	Calls the cmdQueue_ResultReceived.
294 *
295 * \param  hCmdMbox  - Handle to CmdMbox
296 * \return TI_OK
297 *
298 * \par Description
299 * This function is called from cmdMbox_CommandComplete on a sync read, or from TwIf as a CB on an async read.
300 * It calls cmdQueue_ResultReceived to continue the result handling procces & switch the bCmdInProgress flag to TI_FALSE,
301 * meaning other commands can be sent to the FW.
302 *
303 * \sa cmdMbox_SendCommand, cmdMbox_TransferComplete
304 */
305TI_STATUS cmdMbox_TransferComplete(TI_HANDLE hCmdMbox)
306{
307    TCmdMbox   *pCmdMbox = (TCmdMbox *)hCmdMbox;
308
309    /* Other commands can be sent to the FW */
310    pCmdMbox->bCmdInProgress = TI_FALSE;
311
312    cmdQueue_ResultReceived(pCmdMbox->hCmdQueue);
313
314    return TI_OK;
315}
316
317
318/*
319 * \brief	Handle cmdMbox timeout.
320 *
321 * \param  hCmdMbox  - Handle to CmdMbox
322 * \return TI_OK
323 *
324 * \par Description
325 * Call fErrorCb() to handle the error.
326 *
327 * \sa cmdMbox_SendCommand
328 */
329static void cmdMbox_TimeOut (TI_HANDLE hCmdMbox, TI_BOOL bTwdInitOccured)
330{
331    TCmdMbox   *pCmdMbox = (TCmdMbox *)hCmdMbox;
332    Command_t  *pCmd = (Command_t*)&pCmdMbox->aCmdTxn[0].tCmdMbox;
333
334    TRACE0(pCmdMbox->hReport, REPORT_SEVERITY_ERROR , "cmdMbox_TimeOut: Timeout occured in CmdMbox\n");
335
336    /* Call error CB */
337    if (pCmdMbox->fErrorCb != NULL)
338    {
339        pCmdMbox->fErrorCb (pCmdMbox->hCmdQueue,
340                            (TI_UINT32)pCmd->cmdID,
341                            CMD_STATUS_TIMEOUT,
342                            (void *)pCmd->parameters);
343    }
344}
345
346
347/*
348 * \brief	configure the mailbox address.
349 *
350 * \param  hCmdMbox  - Handle to CmdMbox
351 * \param  fCb  - Pointer to the CB
352 * \param  hCb  - Cb's handle
353 * \return TI_OK or TI_PENDING
354 *
355 * \par Description
356 * Called from HwInit to read the command mailbox address.
357 *
358 * \sa
359 */
360TI_STATUS cmdMbox_ConfigHw (TI_HANDLE hCmdMbox, fnotify_t fCb, TI_HANDLE hCb)
361{
362    TCmdMbox   *pCmdMbox = (TCmdMbox *)hCmdMbox;
363    TTxnStruct *pRegTxn = (TTxnStruct*)&pCmdMbox->aRegTxn[1].tTxnStruct;
364    TI_STATUS   rc;
365
366    pCmdMbox->fCb = fCb;
367    pCmdMbox->hCb = hCb;
368    /* Build the command TxnStruct */
369    TXN_PARAM_SET(pRegTxn, TXN_LOW_PRIORITY, TXN_FUNC_ID_WLAN, TXN_DIRECTION_READ, TXN_INC_ADDR)
370    BUILD_TTxnStruct(pRegTxn, REG_COMMAND_MAILBOX_PTR, &(pCmdMbox->aRegTxn[1].uRegister), REGISTER_SIZE,(TTxnDoneCb)cmdMbox_ConfigHwCb, hCmdMbox)
371    /* Get the command mailbox address */
372    rc = twIf_Transact(pCmdMbox->hTwIf, pRegTxn);
373    if (rc == TXN_STATUS_COMPLETE)
374    {
375        pCmdMbox->uFwAddr = pCmdMbox->aRegTxn[1].uRegister;
376    }
377
378    return rc;
379}
380
381
382/*
383 * \brief	Cb to cmdMbox_ConfigHw
384 *
385 * \param  hCmdMbox  - Handle to CmdMbox
386 * \return TI_OK
387 *
388 * \par Description
389 *
390 * \sa
391 */
392static void cmdMbox_ConfigHwCb (TI_HANDLE hCmdMbox, TTxnStruct *pTxn)
393{
394    TCmdMbox   *pCmdMbox = (TCmdMbox *)hCmdMbox;
395
396    pCmdMbox->uFwAddr = pCmdMbox->aRegTxn[1].uRegister;
397
398    /* Call back the original State Machine */
399    pCmdMbox->fCb(pCmdMbox->hCb, TI_OK);
400}
401
402
403/*
404 * \brief	Restart the module upon driver stop or restart
405 *
406 * \param  hCmdMbox  - Handle to CmdMbox
407 * \return TI_OK
408 *
409 * \par Description
410 *
411 * \sa
412 */
413TI_STATUS cmdMbox_Restart (TI_HANDLE hCmdMbox)
414{
415    TCmdMbox   *pCmdMbox = (TCmdMbox *)hCmdMbox;
416
417    /* Stop the timeout timer if running and reset the state */
418    tmr_StopTimer (pCmdMbox->hCmdMboxTimer);
419    pCmdMbox->bCmdInProgress = TI_FALSE;
420    pCmdMbox->uReadLen       = 0;
421    pCmdMbox->uWriteLen      = 0;
422
423    return TI_OK;
424}
425
426
427/*
428 * \brief	Return the latest command status
429 *
430 * \param  hCmdMbox  - Handle to CmdMbox
431 * \return TI_OK or TI_NOK
432 *
433 * \par Description
434 *
435 * \sa
436 */
437TI_STATUS cmdMbox_GetStatus (TI_HANDLE hCmdMbox, CommandStatus_e *cmdStatus)
438{
439    TCmdMbox   *pCmdMbox = (TCmdMbox *)hCmdMbox;
440    Command_t  *pCmd = (Command_t*)&pCmdMbox->aCmdTxn[1].tCmdMbox;
441    TI_STATUS   status;
442
443    status = (pCmd->cmdStatus == CMD_STATUS_SUCCESS) ? TI_OK : TI_NOK;
444    TRACE2(pCmdMbox->hReport, REPORT_SEVERITY_INFORMATION , "cmdMbox_GetStatus: TI_STATUS = (%d) <= pCmdMbox->tCmdMbox.cmdStatus = %d\n", status, pCmd->cmdStatus);
445    *cmdStatus = pCmd->cmdStatus;
446    return status;
447}
448
449/*
450 * \brief	Return the MBox address
451 *
452 * \param  hCmdMbox  - Handle to CmdMbox
453 * \return MBox address
454 *
455 * \par Description
456 *
457 * \sa
458 */
459TI_UINT32 cmdMbox_GetMboxAddress (TI_HANDLE hCmdMbox)
460{
461    TCmdMbox *pCmdMbox = (TCmdMbox *)hCmdMbox;
462
463    return pCmdMbox->uFwAddr;
464}
465
466
467/*
468 * \brief	Return the Command parameters buffer
469 *
470 * \param  hCmdMbox  - Handle to CmdMbox
471 * \param  pParamBuf  - Holds the returned buffer
472 * \return
473 *
474 * \par Description
475 * Copying the command's data to pParamBuf
476 *
477 * \sa
478 */
479void cmdMbox_GetCmdParams (TI_HANDLE hCmdMbox, TI_UINT8* pParamBuf)
480{
481    TCmdMbox *pCmdMbox = (TCmdMbox *)hCmdMbox;
482    Command_t  *pCmd = (Command_t*)&pCmdMbox->aCmdTxn[1].tCmdMbox;
483
484    /*
485     * Copy the results to the caller buffer:
486     * We need to copy only the data without the cmdMbox header,
487     * otherwise we will overflow the pParambuf
488     */
489    os_memoryCopy (pCmdMbox->hOs,
490                   (void *)pParamBuf,
491                   (void *)pCmd->parameters,
492                   pCmdMbox->uReadLen - CMDMBOX_HEADER_LEN);
493
494}
495
496
497#ifdef TI_DBG
498
499void cmdMbox_PrintInfo(TI_HANDLE hCmdMbox)
500{
501#ifdef REPORT_LOG
502    TCmdMbox *pCmdMbox = (TCmdMbox *)hCmdMbox;
503
504    WLAN_OS_REPORT(("Print cmdMbox module info\n"));
505    WLAN_OS_REPORT(("=========================\n"));
506    WLAN_OS_REPORT(("bCmdInProgress = %d\n", pCmdMbox->bCmdInProgress));
507#endif
508}
509
510#endif  /* TI_DBG */
511
512
513