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