1 /* 2 * CmdMBox.c 3 * 4 * Copyright(c) 1998 - 2010 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 */ 68 static void cmdMbox_TimeOut (TI_HANDLE hCmdMbox, TI_BOOL bTwdInitOccured); 69 static 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 */ 82 TI_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 */ 112 TI_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 */ 144 TI_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 157 pCmdMbox->uFwAddr = 0; 158 pCmdMbox->uReadLen = 0; 159 pCmdMbox->uWriteLen = 0; 160 pCmdMbox->bCmdInProgress = TI_FALSE; 161 pCmdMbox->fErrorCb = fErrorCb; 162 163 /* allocate OS timer memory */ 164 pCmdMbox->hCmdMboxTimer = tmr_CreateTimer (hTimer); 165 if (pCmdMbox->hCmdMboxTimer == NULL) 166 { 167 TRACE0(pCmdMbox->hReport, REPORT_SEVERITY_ERROR, "cmdMbox_Init(): Failed to create hCmdMboxTimer!\n"); 168 return TI_NOK; 169 } 170 171 return TI_OK; 172 } 173 174 175 /* 176 * \brief Send the Command to the Mailbox 177 * 178 * \param hCmdMbox - Handle to CmdMbox 179 * \param cmdType - 180 * \param pParamsBuf - The buffer that will be written to the mailbox 181 * \param uWriteLen - Length of data to write to the mailbox 182 * \param uReadLen - Length of data to read from the mailbox (when the result is received) 183 * \return TI_PENDING 184 * 185 * \par Description 186 * Copy the buffer given to a local struct, update the write & read lengths 187 * and send to the FW's mailbox. 188 * 189 * ------------------------------------------------------ 190 * | CmdMbox Header | Cmd Header | Command parameters | 191 * ------------------------------------------------------ 192 * | ID | Status | Type | Length | Command parameters | 193 * ------------------------------------------------------ 194 * 16bit 16bit 16bit 16bit 195 * 196 * \sa cmdMbox_CommandComplete 197 */ 198 TI_STATUS cmdMbox_SendCommand (TI_HANDLE hCmdMbox, Command_e cmdType, TI_UINT8* pParamsBuf, TI_UINT32 uWriteLen, TI_UINT32 uReadLen) 199 { 200 TCmdMbox *pCmdMbox = (TCmdMbox *)hCmdMbox; 201 TTxnStruct *pCmdTxn = (TTxnStruct*)&pCmdMbox->aCmdTxn[0].tTxnStruct; 202 TTxnStruct *pRegTxn = (TTxnStruct*)&pCmdMbox->aRegTxn[0].tTxnStruct; 203 Command_t *pCmd = (Command_t*)&pCmdMbox->aCmdTxn[0].tCmdMbox; 204 205 206 if (pCmdMbox->bCmdInProgress) 207 { 208 TRACE0(pCmdMbox->hReport, REPORT_SEVERITY_ERROR, "cmdMbox_SendCommand(): Trying to send Cmd while other Cmd is still in progres!\n"); 209 return TI_NOK; 210 } 211 212 /* Add the CMDMBOX_HEADER_LEN to the read length, used when reading the result later on */ 213 pCmdMbox->uReadLen = uReadLen + CMDMBOX_HEADER_LEN; 214 /* Prepare the Cmd Hw template */ 215 pCmd->cmdID = cmdType; 216 pCmd->cmdStatus = TI_OK; 217 os_memoryCopy (pCmdMbox->hOs, (void *)pCmd->parameters, (void *)pParamsBuf, uWriteLen); 218 219 /* Add the CMDMBOX_HEADER_LEN to the write length */ 220 pCmdMbox->uWriteLen = uWriteLen + CMDMBOX_HEADER_LEN; 221 222 /* Must make sure that the length is multiple of 32 bit */ 223 if (pCmdMbox->uWriteLen & 0x3) 224 { 225 TRACE1(pCmdMbox->hReport, REPORT_SEVERITY_WARNING, "cmdMbox_SendCommand(): Command length isn't 32bit aligned! CmdId=%d\n", pCmd->cmdID); 226 pCmdMbox->uWriteLen = (pCmdMbox->uWriteLen + 4) & 0xFFFFFFFC; 227 } 228 229 /* no other command can start the send process till bCmdInProgress will return to TI_FALSE*/ 230 pCmdMbox->bCmdInProgress = TI_TRUE; 231 232 /* Build the command TxnStruct */ 233 TXN_PARAM_SET(pCmdTxn, TXN_LOW_PRIORITY, TXN_FUNC_ID_WLAN, TXN_DIRECTION_WRITE, TXN_INC_ADDR) 234 BUILD_TTxnStruct(pCmdTxn, pCmdMbox->uFwAddr, pCmd, pCmdMbox->uWriteLen, NULL, NULL) 235 /* Send the command */ 236 twIf_Transact(pCmdMbox->hTwIf, pCmdTxn); 237 238 /* Build the trig TxnStruct */ 239 pCmdMbox->aRegTxn[0].uRegister = INTR_TRIG_CMD; 240 TXN_PARAM_SET(pRegTxn, TXN_LOW_PRIORITY, TXN_FUNC_ID_WLAN, TXN_DIRECTION_WRITE, TXN_INC_ADDR) 241 BUILD_TTxnStruct(pRegTxn, ACX_REG_INTERRUPT_TRIG, &(pCmdMbox->aRegTxn[0].uRegister), REGISTER_SIZE, NULL, NULL) 242 243 /* start the CmdMbox timer */ 244 tmr_StartTimer (pCmdMbox->hCmdMboxTimer, cmdMbox_TimeOut, hCmdMbox, CMDMBOX_WAIT_TIMEOUT, TI_FALSE); 245 246 /* Send the FW trigger */ 247 twIf_Transact(pCmdMbox->hTwIf, pRegTxn); 248 249 250 return TXN_STATUS_PENDING; 251 } 252 253 254 /* 255 * \brief Read the command's result 256 * 257 * \param hCmdMbox - Handle to CmdMbox 258 * \return void 259 * 260 * \par Description 261 * This function is called from FwEvent module uppon receiving command complete interrupt. 262 * It issues a read transaction from the mailbox with a CB. 263 * 264 * \sa cmdMbox_SendCommand, cmdMbox_TransferComplete 265 */ 266 ETxnStatus cmdMbox_CommandComplete (TI_HANDLE hCmdMbox) 267 { 268 TCmdMbox *pCmdMbox = (TCmdMbox *)hCmdMbox; 269 TTxnStruct *pCmdTxn = (TTxnStruct*)&pCmdMbox->aCmdTxn[1].tTxnStruct; 270 Command_t *pCmd = (Command_t*)&pCmdMbox->aCmdTxn[1].tCmdMbox; 271 ETxnStatus rc; 272 273 /* stop the CmdMbox timer */ 274 tmr_StopTimer(pCmdMbox->hCmdMboxTimer); 275 276 /* Build the command TxnStruct */ 277 TXN_PARAM_SET(pCmdTxn, TXN_LOW_PRIORITY, TXN_FUNC_ID_WLAN, TXN_DIRECTION_READ, TXN_INC_ADDR) 278 /* Applying a CB in case of an async read */ 279 BUILD_TTxnStruct(pCmdTxn, pCmdMbox->uFwAddr, pCmd, pCmdMbox->uReadLen,(TTxnDoneCb)cmdMbox_TransferComplete, hCmdMbox) 280 /* Send the command */ 281 rc = twIf_Transact(pCmdMbox->hTwIf, pCmdTxn); 282 283 /* In case of a sync read, call the CB directly */ 284 if (rc == TXN_STATUS_COMPLETE) 285 { 286 cmdMbox_TransferComplete(hCmdMbox); 287 } 288 289 return TXN_STATUS_COMPLETE; 290 } 291 292 293 /* 294 * \brief Calls the cmdQueue_ResultReceived. 295 * 296 * \param hCmdMbox - Handle to CmdMbox 297 * \return TI_OK 298 * 299 * \par Description 300 * This function is called from cmdMbox_CommandComplete on a sync read, or from TwIf as a CB on an async read. 301 * It calls cmdQueue_ResultReceived to continue the result handling procces & switch the bCmdInProgress flag to TI_FALSE, 302 * meaning other commands can be sent to the FW. 303 * 304 * \sa cmdMbox_SendCommand, cmdMbox_TransferComplete 305 */ 306 TI_STATUS cmdMbox_TransferComplete(TI_HANDLE hCmdMbox) 307 { 308 TCmdMbox *pCmdMbox = (TCmdMbox *)hCmdMbox; 309 310 /* Other commands can be sent to the FW */ 311 pCmdMbox->bCmdInProgress = TI_FALSE; 312 313 cmdQueue_ResultReceived(pCmdMbox->hCmdQueue); 314 315 return TI_OK; 316 } 317 318 319 /* 320 * \brief Handle cmdMbox timeout. 321 * 322 * \param hCmdMbox - Handle to CmdMbox 323 * \return TI_OK 324 * 325 * \par Description 326 * Call fErrorCb() to handle the error. 327 * 328 * \sa cmdMbox_SendCommand 329 */ 330 static void cmdMbox_TimeOut (TI_HANDLE hCmdMbox, TI_BOOL bTwdInitOccured) 331 { 332 TCmdMbox *pCmdMbox = (TCmdMbox *)hCmdMbox; 333 Command_t *pCmd = (Command_t*)&pCmdMbox->aCmdTxn[0].tCmdMbox; 334 335 TRACE0(pCmdMbox->hReport, REPORT_SEVERITY_ERROR , "cmdMbox_TimeOut: Timeout occured in CmdMbox\n"); 336 337 /* Call error CB */ 338 if (pCmdMbox->fErrorCb != NULL) 339 { 340 pCmdMbox->fErrorCb (pCmdMbox->hCmdQueue, 341 (TI_UINT32)pCmd->cmdID, 342 CMD_STATUS_TIMEOUT, 343 (void *)pCmd->parameters); 344 } 345 } 346 347 348 /* 349 * \brief configure the mailbox address. 350 * 351 * \param hCmdMbox - Handle to CmdMbox 352 * \param fCb - Pointer to the CB 353 * \param hCb - Cb's handle 354 * \return TI_OK or TI_PENDING 355 * 356 * \par Description 357 * Called from HwInit to read the command mailbox address. 358 * 359 * \sa 360 */ 361 TI_STATUS cmdMbox_ConfigHw (TI_HANDLE hCmdMbox, fnotify_t fCb, TI_HANDLE hCb) 362 { 363 TCmdMbox *pCmdMbox = (TCmdMbox *)hCmdMbox; 364 TTxnStruct *pRegTxn = (TTxnStruct*)&pCmdMbox->aRegTxn[1].tTxnStruct; 365 TI_STATUS rc; 366 367 pCmdMbox->fCb = fCb; 368 pCmdMbox->hCb = hCb; 369 /* Build the command TxnStruct */ 370 TXN_PARAM_SET(pRegTxn, TXN_LOW_PRIORITY, TXN_FUNC_ID_WLAN, TXN_DIRECTION_READ, TXN_INC_ADDR) 371 BUILD_TTxnStruct(pRegTxn, REG_COMMAND_MAILBOX_PTR, &(pCmdMbox->aRegTxn[1].uRegister), REGISTER_SIZE,(TTxnDoneCb)cmdMbox_ConfigHwCb, hCmdMbox) 372 /* Get the command mailbox address */ 373 rc = twIf_Transact(pCmdMbox->hTwIf, pRegTxn); 374 if (rc == TXN_STATUS_COMPLETE) 375 { 376 pCmdMbox->uFwAddr = pCmdMbox->aRegTxn[1].uRegister; 377 } 378 379 return rc; 380 } 381 382 383 /* 384 * \brief Cb to cmdMbox_ConfigHw 385 * 386 * \param hCmdMbox - Handle to CmdMbox 387 * \return TI_OK 388 * 389 * \par Description 390 * 391 * \sa 392 */ 393 static void cmdMbox_ConfigHwCb (TI_HANDLE hCmdMbox, TTxnStruct *pTxn) 394 { 395 TCmdMbox *pCmdMbox = (TCmdMbox *)hCmdMbox; 396 397 pCmdMbox->uFwAddr = pCmdMbox->aRegTxn[1].uRegister; 398 399 /* Call back the original State Machine */ 400 pCmdMbox->fCb(pCmdMbox->hCb, TI_OK); 401 } 402 403 404 /* 405 * \brief Restart the module upon driver stop or restart 406 * 407 * \param hCmdMbox - Handle to CmdMbox 408 * \return TI_OK 409 * 410 * \par Description 411 * 412 * \sa 413 */ 414 TI_STATUS cmdMbox_Restart (TI_HANDLE hCmdMbox) 415 { 416 TCmdMbox *pCmdMbox = (TCmdMbox *)hCmdMbox; 417 418 /* Stop the timeout timer if running and reset the state */ 419 tmr_StopTimer (pCmdMbox->hCmdMboxTimer); 420 pCmdMbox->bCmdInProgress = TI_FALSE; 421 pCmdMbox->uReadLen = 0; 422 pCmdMbox->uWriteLen = 0; 423 424 return TI_OK; 425 } 426 427 428 /* 429 * \brief Return the latest command status 430 * 431 * \param hCmdMbox - Handle to CmdMbox 432 * \return TI_OK or TI_NOK 433 * 434 * \par Description 435 * 436 * \sa 437 */ 438 TI_STATUS cmdMbox_GetStatus (TI_HANDLE hCmdMbox, CommandStatus_e *cmdStatus) 439 { 440 TCmdMbox *pCmdMbox = (TCmdMbox *)hCmdMbox; 441 Command_t *pCmd = (Command_t*)&pCmdMbox->aCmdTxn[1].tCmdMbox; 442 TI_STATUS status; 443 444 status = (pCmd->cmdStatus == CMD_STATUS_SUCCESS) ? TI_OK : TI_NOK; 445 TRACE2(pCmdMbox->hReport, REPORT_SEVERITY_INFORMATION , "cmdMbox_GetStatus: TI_STATUS = (%d) <= pCmdMbox->tCmdMbox.cmdStatus = %d\n", status, pCmd->cmdStatus); 446 *cmdStatus = pCmd->cmdStatus; 447 return status; 448 } 449 450 /* 451 * \brief Return the MBox address 452 * 453 * \param hCmdMbox - Handle to CmdMbox 454 * \return MBox address 455 * 456 * \par Description 457 * 458 * \sa 459 */ 460 TI_UINT32 cmdMbox_GetMboxAddress (TI_HANDLE hCmdMbox) 461 { 462 TCmdMbox *pCmdMbox = (TCmdMbox *)hCmdMbox; 463 464 return pCmdMbox->uFwAddr; 465 } 466 467 468 /* 469 * \brief Return the Command parameters buffer 470 * 471 * \param hCmdMbox - Handle to CmdMbox 472 * \param pParamBuf - Holds the returned buffer 473 * \return 474 * 475 * \par Description 476 * Copying the command's data to pParamBuf 477 * 478 * \sa 479 */ 480 void cmdMbox_GetCmdParams (TI_HANDLE hCmdMbox, TI_UINT8* pParamBuf) 481 { 482 TCmdMbox *pCmdMbox = (TCmdMbox *)hCmdMbox; 483 Command_t *pCmd = (Command_t*)&pCmdMbox->aCmdTxn[1].tCmdMbox; 484 485 /* 486 * Copy the results to the caller buffer: 487 * We need to copy only the data without the cmdMbox header, 488 * otherwise we will overflow the pParambuf 489 */ 490 os_memoryCopy (pCmdMbox->hOs, 491 (void *)pParamBuf, 492 (void *)pCmd->parameters, 493 pCmdMbox->uReadLen - CMDMBOX_HEADER_LEN); 494 495 } 496 497 498 #ifdef TI_DBG 499 500 void cmdMbox_PrintInfo(TI_HANDLE hCmdMbox) 501 { 502 #ifdef REPORT_LOG 503 TCmdMbox *pCmdMbox = (TCmdMbox *)hCmdMbox; 504 505 WLAN_OS_REPORT(("Print cmdMbox module info\n")); 506 WLAN_OS_REPORT(("=========================\n")); 507 WLAN_OS_REPORT(("bCmdInProgress = %d\n", pCmdMbox->bCmdInProgress)); 508 #endif 509 } 510 511 #endif /* TI_DBG */ 512 513 514