1 /**************************************************************************** 2 **+-----------------------------------------------------------------------+** 3 **| |** 4 **| Copyright(c) 1998 - 2008 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 /* */ 38 /* MODULE: ElpCtrl.c */ 39 /* PURPOSE: ELP controller implementation module */ 40 /* */ 41 /**********************************************************************************/ 42 #include "osApi.h" 43 #include "whalBus_Api.h" 44 #include "fsm.h" 45 #include "TNETWIF.h" 46 #include "whalHwAccess.h" 47 #include "ElpCtrl.h" 48 /* #include <linux/timer.h> */ 49 50 /* Healthy timer timeout in milliseconds */ 51 #define ELPCTRL_TIMER_TIMEOUT 100 52 53 54 typedef enum 55 { 56 ELPS_AWAKE, 57 ELPS_ASLEEP, 58 ELPS_WAKING_UP_WRITE, 59 ELPS_WAKING_UP_READ, 60 ELPS_WAKING_UP_MUX 61 62 } elpCtrl_State_e; 63 64 65 typedef struct _elpCtrl_t 66 { 67 TI_HANDLE hOs; 68 TI_HANDLE hTNETWIF; 69 TI_HANDLE hTNETWArb; 70 71 TNETWIF_callback_t fCb; 72 elpCtrl_Mode_e mode; 73 elpCtrl_State_e state; 74 UINT32 uElpRegister; 75 BOOL bExitWakeUpSeq; 76 BOOL bMuxBackNeeded; 77 BOOL bSynch; 78 TI_STATUS eReturnValue; 79 80 failureEventCB_t fFail; /* upper layer failure event callback. 81 * called when the scan command has been timer expiry */ 82 TI_HANDLE hFail; /* object parameter passed to the fFail 83 * when it is called */ 84 TI_HANDLE hTimer; 85 86 } elpCtrl_t; 87 88 /**************************************************************************** 89 * elpCtrl_TimerTimeout() 90 **************************************************************************** 91 * DESCRIPTION: 92 * 93 * INPUTS: hElpCtrl - the handle to the ElpCtrl module. 94 * 95 * OUTPUT: 96 * 97 * RETURNS: OK 98 ****************************************************************************/ 99 void elpCtrl_TimerTimeout (TI_HANDLE hElpCtrl) 100 { 101 elpCtrl_t *pElpCtrl = (elpCtrl_t*)hElpCtrl; 102 103 /* 104 * Error Reporting and Recovery 105 * This Timeout means that we failed to wake up the FW 106 * so the only way out of it is to restart the device - by recovery 107 */ 108 /* WLAN_OS_REPORT (("elpCtrl_TimerTimeout - ELP timeout timer expired! %lu\n", jiffies)); */ 109 WLAN_OS_REPORT (("elpCtrl_TimerTimeout - ELP timeout timer expired!\n")); 110 111 if (pElpCtrl->fFail) 112 pElpCtrl->fFail (pElpCtrl->hFail, HW_AWAKE_FAILURE); 113 } 114 115 /**************************************************************************** 116 * elpCtrl_Create() 117 **************************************************************************** 118 * DESCRIPTION: 119 * 120 * INPUTS: hOs - the handle to the OS layer 121 * hReport - the handle to the report module 122 * 123 * 124 * OUTPUT: the context of the ElpCtrl module 125 * 126 * RETURNS: the context of the ElpCtrl module (NULL if error) 127 ****************************************************************************/ 128 TI_HANDLE elpCtrl_Create (TI_HANDLE hOs) 129 { 130 elpCtrl_t *pElpCtrl; 131 132 /* Create context */ 133 pElpCtrl = os_memoryAlloc (hOs, sizeof(elpCtrl_t)); 134 if (pElpCtrl == NULL) 135 { 136 WLAN_OS_REPORT (("%s: Error allocating object\n", __FUNCTION__)); 137 return NULL; 138 } 139 os_memoryZero (hOs, pElpCtrl, sizeof(elpCtrl_t)); 140 141 pElpCtrl->hOs = hOs; 142 143 /* Create timer */ 144 pElpCtrl->hTimer = os_timerCreate (hOs, elpCtrl_TimerTimeout, pElpCtrl); 145 if (pElpCtrl->hTimer == NULL) 146 { 147 WLAN_OS_REPORT (("%s: Error in creating timer\n", __FUNCTION__)); 148 elpCtrl_Destroy (pElpCtrl); 149 return NULL; 150 } 151 152 return pElpCtrl; 153 } 154 155 156 /**************************************************************************** 157 * elpCtrl_Destroy() 158 **************************************************************************** 159 * DESCRIPTION: 160 * 161 * INPUTS: hElpCtrl - the handle to the ElpCtrl module. 162 * 163 * 164 * OUTPUT: 165 * 166 * RETURNS: OK 167 ****************************************************************************/ 168 int elpCtrl_Destroy (TI_HANDLE hElpCtrl) 169 { 170 elpCtrl_t *pElpCtrl = (elpCtrl_t*)hElpCtrl; 171 172 if (pElpCtrl) 173 { 174 if (NULL != pElpCtrl->hTimer) 175 { 176 os_timerDestroy (pElpCtrl->hOs, pElpCtrl->hTimer); 177 } 178 179 os_memoryFree (pElpCtrl->hOs, pElpCtrl, sizeof(elpCtrl_t)); 180 } 181 182 return OK; 183 } 184 185 186 /**************************************************************************** 187 * elpCtrl_Configure() 188 **************************************************************************** 189 * DESCRIPTION: 190 * 191 * INPUTS: hElpCtrl - the handle to the ElpCtrl module 192 * hTNETWIF - the handle to the TNETWIF module 193 * fCb - ELP asynchronous operation default callback 194 * 195 * OUTPUT: 196 * 197 * RETURNS: ELPCTRL_COMPLETE - if succeeded (sync.) 198 * ELPCTRL_PENDING - if succeeded (async.) 199 * ELPCTRL_ERROR - if failed 200 ****************************************************************************/ 201 int elpCtrl_Configure (TI_HANDLE hElpCtrl, TI_HANDLE hTNETWIF, TNETWIF_callback_t fCb) 202 { 203 elpCtrl_t *pElpCtrl = (elpCtrl_t*)hElpCtrl; 204 205 pElpCtrl->state = ELPS_AWAKE; 206 pElpCtrl->mode = ELPCTRL_MODE_KEEP_AWAKE; 207 pElpCtrl->hTNETWIF = hTNETWIF; 208 pElpCtrl->hTNETWArb = ((TNETWIF_t *)hTNETWIF)->hTNETWArb; 209 pElpCtrl->fCb = fCb; 210 pElpCtrl->bMuxBackNeeded = FALSE; 211 return ELPCTRL_COMPLETE; 212 } 213 214 /**************************************************************************** 215 * elpCtrl_wakeUpSeqSM() 216 **************************************************************************** 217 * DESCRIPTION: SM for handling Synch & Asynch wake up sequence. 218 * The flow of the SM is by that order: 219 * WRITE (wake up) -> READ (elp) -> if awake - exit. else WRITE (mux) 220 * 221 * OUTPUT: 222 * 223 * RETURNS: 224 ****************************************************************************/ 225 static void elpCtrl_wakeUpSeqSM (TI_HANDLE hElpCtrl, UINT8 module_id, TI_STATUS status) 226 { 227 elpCtrl_t *pElpCtrl = (elpCtrl_t*)hElpCtrl; 228 229 /* Check if Arbiter announced that interrupt occurred (i.e. no need for wake up sequence) */ 230 if (pElpCtrl->bExitWakeUpSeq) 231 { 232 /* Fw is up - we should imitate TXN_COMPLETE to announce that we are done */ 233 pElpCtrl->state = ELPS_AWAKE; 234 /* set TXN_COMPLETE to ArbiterSM - Note: It could only happen in Asynch IF */ 235 pElpCtrl->fCb (pElpCtrl->hTNETWArb, DEFAULT_MODULE_ID, OK); 236 return; 237 } 238 239 pElpCtrl->eReturnValue = OK; 240 241 /* 242 * This while loop will continue till the exit or when waiting for the CB due to 243 * memory transfer operation pending for DMA to complete 244 */ 245 while (TNETWIF_PENDING != pElpCtrl->eReturnValue) 246 { 247 switch(pElpCtrl->state) 248 { 249 case ELPS_ASLEEP: 250 251 pElpCtrl->state = ELPS_WAKING_UP_WRITE; 252 pElpCtrl->eReturnValue = TNETWIF_WriteELPOpt (pElpCtrl->hTNETWIF, 253 ELPCTRL_WAKE_UP, 254 DEFAULT_MODULE_ID, 255 elpCtrl_wakeUpSeqSM, 256 hElpCtrl, 257 TRUE); 258 break; 259 260 261 case ELPS_WAKING_UP_WRITE: 262 263 pElpCtrl->state = ELPS_WAKING_UP_READ; 264 pElpCtrl->eReturnValue = TNETWIF_ReadELPOpt (pElpCtrl->hTNETWIF, 265 (UINT8*)&pElpCtrl->uElpRegister, 266 DEFAULT_MODULE_ID, 267 elpCtrl_wakeUpSeqSM, 268 hElpCtrl, 269 TRUE); 270 break; 271 272 case ELPS_WAKING_UP_READ: 273 274 /* Check whether Muxing is needed */ 275 if (pElpCtrl->uElpRegister & ELPCTRL_WLAN_READY) 276 { 277 /* Fw is up, but no WLAN_READY interrupt will occur (since we disabled the mux) */ 278 pElpCtrl->state = ELPS_AWAKE; 279 /* 280 * set TXN_COMPLETE to ArbiterSM only if we are not working in synchronize IF 281 * In synch IF we set the TXN_COMPLETE at the end of this function 282 */ 283 if ( !pElpCtrl->bSynch) 284 { 285 pElpCtrl->fCb (pElpCtrl->hTNETWArb, DEFAULT_MODULE_ID, OK); 286 } 287 } 288 else /* Fw is asleep - Mux to WLAN_READY and let arbiter wait for interrupt */ 289 { 290 pElpCtrl->state = ELPS_WAKING_UP_MUX; 291 pElpCtrl->bMuxBackNeeded = TRUE; 292 #ifdef DM_USE_WORKQUEUE 293 /* printk("TI: %s:\t%lu - start timeout 1000 ms\n", __FUNCTION__, jiffies); */ 294 os_timerStart (pElpCtrl->hOs, pElpCtrl->hTimer, ELPCTRL_TIMER_TIMEOUT * 10, FALSE); 295 #else 296 os_timerStart (pElpCtrl->hOs, pElpCtrl->hTimer, ELPCTRL_TIMER_TIMEOUT, FALSE); 297 #endif 298 /* 299 * Mux to WLAN_READY and let the Arbiter wait for Txn complete 300 */ 301 pElpCtrl->eReturnValue = TNETWIF_WriteELPOpt (pElpCtrl->hTNETWIF, 302 ELPCTRL_WAKE_UP_WLAN_READY, 303 DEFAULT_MODULE_ID, 304 pElpCtrl->fCb, 305 pElpCtrl->hTNETWArb, 306 TRUE); 307 if(TNETWIF_PENDING == pElpCtrl->eReturnValue) 308 { 309 /* If we are here then we are not using Synch IF */ 310 pElpCtrl->bSynch = FALSE; 311 } 312 313 /* The previous states was async and now it sync */ 314 if((TNETWIF_COMPLETE == pElpCtrl->eReturnValue) && (pElpCtrl->bSynch == FALSE)) 315 { 316 pElpCtrl->fCb (pElpCtrl->hTNETWArb, DEFAULT_MODULE_ID, OK); 317 } 318 } 319 320 return; 321 322 default: 323 324 WLAN_OS_REPORT(("Error: %s state = %d\n", __FUNCTION__, pElpCtrl->state)); 325 326 } 327 } 328 /* If we are here then we are not using Synch IF */ 329 pElpCtrl->bSynch = FALSE; 330 } 331 332 /**************************************************************************** 333 * elpCtrl_Wake() 334 **************************************************************************** 335 * DESCRIPTION: 336 * 337 * INPUTS: hElpCtrl - the handle to the ElpCtrl module 338 * bHwAvail - TRUE if HW is available 339 * 340 * OUTPUT: 341 * 342 * RETURNS: TNETWIF_COMPLETE | TNETWIF_PENDING 343 ****************************************************************************/ 344 int elpCtrl_Wake (TI_HANDLE hElpCtrl, BOOL bHwAvail) 345 { 346 elpCtrl_t *pElpCtrl = (elpCtrl_t*)hElpCtrl; 347 int rc = ELPCTRL_AWAKE; 348 349 if (pElpCtrl->state == ELPS_ASLEEP) 350 { 351 if (bHwAvail == FALSE) 352 { 353 /* 354 * Wake up the FW without mux. The mux will be done only if the FW is asleep. This is done due to a race 355 * condition in the Fw, which causes 2 interrupts in the driver - one of them is not needed 356 */ 357 pElpCtrl->bExitWakeUpSeq = FALSE; 358 pElpCtrl->bSynch = TRUE; 359 360 elpCtrl_wakeUpSeqSM (hElpCtrl, DEFAULT_MODULE_ID, OK); 361 362 /* 363 * In Synch IF we send won't send TXN_COMPLETE from elpCtrl so we should 364 * indicate the arbiter to roll forward its SM. 365 */ 366 rc = ((pElpCtrl->bSynch) ? ELPCTRL_WLAN_RDY_COMPLETE : ELPCTRL_COMPLETE); 367 } 368 else 369 { 370 pElpCtrl->state = ELPS_AWAKE; 371 372 if (TNETWIF_WriteELPOpt (pElpCtrl->hTNETWIF, 373 ELPCTRL_WAKE_UP, 374 DEFAULT_MODULE_ID, 375 pElpCtrl->fCb, 376 pElpCtrl->hTNETWArb, 377 TRUE) == TNETWIF_COMPLETE) 378 { 379 rc = ELPCTRL_WLAN_RDY_COMPLETE; 380 } 381 else 382 { 383 rc = ELPCTRL_WLAN_RDY; 384 } 385 } 386 } 387 388 return rc; 389 } 390 391 392 /**************************************************************************** 393 * elpCtrl_Sleep() 394 **************************************************************************** 395 * DESCRIPTION: 396 * 397 * INPUTS: hElpCtrl - the handle to the ElpCtrl module. 398 * 399 * OUTPUT: 400 * 401 * RETURNS: TNETWIF_PENDING | TNETWIF_COMPLETE 402 ****************************************************************************/ 403 int elpCtrl_Sleep (TI_HANDLE hElpCtrl) 404 { 405 elpCtrl_t *pElpCtrl = (elpCtrl_t*)hElpCtrl; 406 int rc = TNETWIF_COMPLETE; 407 408 if (pElpCtrl->state == ELPS_AWAKE && pElpCtrl->mode == ELPCTRL_MODE_NORMAL) 409 { 410 pElpCtrl->state = ELPS_ASLEEP; 411 412 /* IRQ_SRC(0) WLAN_WUP(0) - 'more' flag is FALSE since the HW is going to sleep */ 413 rc = TNETWIF_WriteELPOpt (pElpCtrl->hTNETWIF, 414 ELPCTRL_SLEEP, 415 DEFAULT_MODULE_ID, 416 pElpCtrl->fCb, 417 pElpCtrl->hTNETWArb, 418 FALSE); 419 } 420 421 return rc; 422 } 423 424 425 /**************************************************************************** 426 * elpCtrl_Unmux() 427 **************************************************************************** 428 * DESCRIPTION: 429 * 430 * INPUTS: hElpCtrl - the handle to the ElpCtrl module. 431 * 432 * OUTPUT: 433 * 434 * RETURNS: TNETWIF_PENDING | TNETWIF_COMPLETE 435 ****************************************************************************/ 436 int elpCtrl_UnMux (TI_HANDLE hElpCtrl) 437 { 438 elpCtrl_t *pElpCtrl = (elpCtrl_t*)hElpCtrl; 439 int rc = (pElpCtrl->bMuxBackNeeded ? OK : NOK); 440 441 442 pElpCtrl->bMuxBackNeeded = FALSE; 443 444 return rc; 445 } 446 447 /**************************************************************************** 448 * elpCtrl_ReceivedIRQ() 449 **************************************************************************** 450 * DESCRIPTION: 451 * 452 * INPUTS: hElpCtrl - the handle to the ElpCtrl module. 453 * 454 * OUTPUT: 455 * 456 * RETURNS: TNETWIF_PENDING | TNETWIF_COMPLETE 457 ****************************************************************************/ 458 void elpCtrl_ReceivedIRQ (TI_HANDLE hElpCtrl) 459 { 460 elpCtrl_t *pElpCtrl = (elpCtrl_t*)hElpCtrl; 461 462 if (pElpCtrl->state == ELPS_WAKING_UP_MUX) 463 { 464 pElpCtrl->state = ELPS_AWAKE; 465 /* printk("TI: %s:\t%lu - stop timeout\n", __FUNCTION__, jiffies); */ 466 os_timerStop (pElpCtrl->hOs, pElpCtrl->hTimer); 467 } 468 469 return; 470 } 471 472 /**************************************************************************** 473 * elpCtrl_Mode() 474 **************************************************************************** 475 * DESCRIPTION: 476 * 477 * INPUTS: hElpCtrl - the handle to the ElpCtrl module. 478 * 479 * 480 * OUTPUT: 481 * 482 * RETURNS: ELPCTRL_COMPLETE 483 ****************************************************************************/ 484 int elpCtrl_Mode (TI_HANDLE hElpCtrl, elpCtrl_Mode_e mode) 485 { 486 elpCtrl_t *pElpCtrl = (elpCtrl_t*)hElpCtrl; 487 488 pElpCtrl->mode = mode; 489 490 return ELPCTRL_COMPLETE; 491 } 492 493 /**************************************************************************** 494 * elpCtrl_isIRQComing() 495 **************************************************************************** 496 * DESCRIPTION: Check if IRQ is about to come from Fw - depending on the ELP state 497 * 498 * INPUTS: hElpCtrl - the handle to the ElpCtrl module. 499 * 500 * 501 * OUTPUT: 502 * 503 * RETURNS: TRUE - IRQ will arrive from WLAN_READY. FALSE - Otherwise 504 ****************************************************************************/ 505 BOOL elpCtrl_isIRQComing (TI_HANDLE hElpCtrl) 506 { 507 elpCtrl_t *pElpCtrl = (elpCtrl_t*)hElpCtrl; 508 509 return (pElpCtrl->state == ELPS_WAKING_UP_MUX ? TRUE : FALSE); 510 } 511 512 /**************************************************************************** 513 * elpCtrl_exitWakeUpSeq() 514 **************************************************************************** 515 * DESCRIPTION: Mark that exit from wake up sequence is needed and return if 516 * wake up is already over. 517 * 518 * INPUTS: hElpCtrl - the handle to the ElpCtrl module. 519 * 520 * 521 * OUTPUT: bExitWakeUpSeq = TRUE 522 * 523 * RETURNS: TRUE - IRQ will arrive from WLAN_READY. FALSE - Otherwise 524 ****************************************************************************/ 525 elpCtrl_e elpCtrl_exitWakeUpSeq (TI_HANDLE hElpCtrl) 526 { 527 elpCtrl_t *pElpCtrl = (elpCtrl_t*)hElpCtrl; 528 529 if (pElpCtrl->state == ELPS_AWAKE) 530 { /* We are already awake */ 531 return ELPCTRL_AWAKE; 532 } 533 else /* Still in wake up sequence */ 534 { 535 pElpCtrl->bExitWakeUpSeq = TRUE; 536 return ELPCTRL_ASLEEP; 537 } 538 } 539 540 /**************************************************************************************** 541 * elpCtrl_RegisterFailureEventCB * 542 **************************************************************************************** 543 DESCRIPTION: Registers a failure event callback for Hw available 544 545 INPUT: - hElpCtrl - handle to the Elp Ctrl object. 546 - fCb - the failure event callback function.\n 547 - hCb - handle to the object passed to the failure event callback function. 548 549 OUTPUT: 550 551 RETURN: void. 552 ****************************************************************************************/ 553 554 void elpCtrl_RegisterFailureEventCB (TI_HANDLE hElpCtrl, void *fCb, TI_HANDLE hCb) 555 { 556 elpCtrl_t *pElpCtrl = (elpCtrl_t*)hElpCtrl; 557 558 pElpCtrl->fFail = (failureEventCB_t)fCb; 559 pElpCtrl->hFail = hCb; 560 } 561 562 /**************************************************************************** 563 * elpCtrl_Stop() 564 **************************************************************************** 565 * DESCRIPTION: Stop ElpCtrl module before Recovery. 566 * Move to "open": MODE_KEEP_AWAKE + STATE_ON 567 * 568 * INPUTS: hElpCtrl - the handle to the ElpCtrl module. 569 * 570 * OUTPUT: 571 * 572 * RETURNS: OK 573 ****************************************************************************/ 574 int elpCtrl_Stop(TI_HANDLE hElpCtrl) 575 { 576 elpCtrl_t *pElpCtrl = (elpCtrl_t*)hElpCtrl; 577 578 /* set the init state */ 579 pElpCtrl->mode = ELPCTRL_MODE_KEEP_AWAKE; 580 pElpCtrl->state = ELPS_AWAKE; 581 582 /* printk("TI: %s:\t%lu - stop timeout\n", __FUNCTION__, jiffies); */ 583 os_timerStop (pElpCtrl->hOs, pElpCtrl->hTimer); 584 585 return OK; 586 } 587 588 /**************************************************************************** 589 * elpCtrl_Start() 590 **************************************************************************** 591 * DESCRIPTION: Stop ElpCtrl module before Recovery. 592 * Move to "open": MODE_KEEP_AWAKE + STATE_ON 593 * 594 * INPUTS: hElpCtrl - the handle to the ElpCtrl module. 595 * 596 * OUTPUT: 597 * 598 * RETURNS: OK 599 ****************************************************************************/ 600 int elpCtrl_Start(TI_HANDLE hElpCtrl) 601 { 602 elpCtrl_t *pElpCtrl = (elpCtrl_t*)hElpCtrl; 603 604 /* Set: SCR = 1 and WUP = 1. The pattern is 101 */ 605 /* NOTE: no callback needed */ 606 /* IRQ_SRC(1) WLAN_WUP(1)*/ 607 TNETWIF_WriteELPOpt (pElpCtrl->hTNETWIF, 608 ELPCTRL_WAKE_UP, 609 DEFAULT_MODULE_ID, 610 NULL, 611 NULL, 612 TRUE); 613 614 615 return OK; 616 } 617 618