1 /******************************************************************************* 2 *Copyright (c) 2014 PMC-Sierra, Inc. All rights reserved. 3 * 4 *Redistribution and use in source and binary forms, with or without modification, are permitted provided 5 *that the following conditions are met: 6 *1. Redistributions of source code must retain the above copyright notice, this list of conditions and the 7 *following disclaimer. 8 *2. Redistributions in binary form must reproduce the above copyright notice, 9 *this list of conditions and the following disclaimer in the documentation and/or other materials provided 10 *with the distribution. 11 * 12 *THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED 13 *WARRANTIES,INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 14 *FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 15 *FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 16 *NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 17 *BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 18 *LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 19 *SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE 20 21 ********************************************************************************/ 22 /*******************************************************************************/ 23 /*! \file satimer.c 24 * \brief The file implements the timerTick function 25 * 26 */ 27 /******************************************************************************/ 28 #include <sys/cdefs.h> 29 __FBSDID("$FreeBSD$"); 30 #include <dev/pms/config.h> 31 32 #include <dev/pms/RefTisa/sallsdk/spc/saglobal.h> 33 #ifdef SA_FW_TEST_BUNCH_STARTS 34 void mpiMsgProduceBunch( agsaLLRoot_t *saRoot); 35 #endif /* SA_FW_TEST_BUNCH_STARTS */ 36 37 #ifdef SA_ENABLE_TRACE_FUNCTIONS 38 #ifdef siTraceFileID 39 #undef siTraceFileID 40 #endif 41 #define siTraceFileID 'P' 42 #endif 43 44 /******************************************************************************/ 45 /*! \brief TimerTick 46 * 47 * TimerTick 48 * 49 * \param agRoot handles for this instance of SAS/SATA hardware 50 * 51 * \return -void- 52 */ 53 /*******************************************************************************/ 54 GLOBAL void saTimerTick( 55 agsaRoot_t *agRoot 56 ) 57 { 58 agsaLLRoot_t *saRoot = (agsaLLRoot_t *)(agRoot->sdkData); 59 agsaTimerDesc_t *pTimer; 60 bit32 Event; 61 void * pParm; 62 63 if(agNULL == saRoot) 64 { 65 SA_DBG1(("saTimerTick:agNULL == saRoot \n")); 66 return; 67 } 68 69 /* (1) Acquire timer list lock */ 70 ossaSingleThreadedEnter(agRoot, LL_TIMER_LOCK); 71 72 /* (2) Find the timers are timeout */ 73 pTimer = (agsaTimerDesc_t *) saLlistGetHead(&(saRoot->validTimers)); 74 while ( agNULL != pTimer ) 75 { 76 /* (2.1) Find the first timer is timeout */ 77 if ( pTimer->timeoutTick == saRoot->timeTick ) 78 { 79 /* (2.1.1) remove the timer from valid timer list */ 80 saLlistRemove(&(saRoot->validTimers), &(pTimer->linkNode)); 81 /* (2.1.2) Invalid timer */ 82 pTimer->valid = agFALSE; 83 /* (2.1.3) Get timer event and param */ 84 Event = pTimer->Event; 85 pParm = pTimer->pParm; 86 /* (2.1.4) Release timer list lock */ 87 ossaSingleThreadedLeave(agRoot, LL_TIMER_LOCK); 88 89 /* (2.1.5) Timer Callback */ 90 pTimer->pfnTimeout(agRoot, Event, pParm); 91 92 /* (2.1.6) Acquire timer list lock again */ 93 ossaSingleThreadedEnter(agRoot, LL_TIMER_LOCK); 94 /* (2.1.7) return the timer to free timer list */ 95 saLlistAdd(&(saRoot->freeTimers), &(pTimer->linkNode)); 96 } 97 /* (2.2) the first timer is not timeout */ 98 else 99 { 100 break; 101 } 102 pTimer = (agsaTimerDesc_t *) saLlistGetHead(&(saRoot->validTimers)); 103 } 104 105 /* (3) increment timeTick */ 106 saRoot->timeTick ++; 107 108 if( saRoot->ResetFailed ) 109 { 110 SA_DBG1(("saTimerTick: siChipResetV saRoot->ResetFailed\n")); 111 } 112 113 #ifdef SA_FW_TEST_BUNCH_STARTS 114 if (saRoot->BunchStarts_Enable && 115 saRoot->BunchStarts_Pending) 116 { 117 SA_DBG3(("saTimerTick: mpiMsgProduceBunch\n")); 118 mpiMsgProduceBunch( saRoot); 119 } 120 #endif /* SA_FW_TEST_BUNCH_STARTS */ 121 122 123 #ifdef SA_FW_TEST_INTERRUPT_REASSERT 124 125 if(1) 126 { 127 mpiOCQueue_t *circularQ; 128 int i; 129 SA_DBG4(("saTimerTick:SA_FW_TEST_INTERRUPT_REASSERT\n")); 130 for ( i = 0; i < saRoot->QueueConfig.numOutboundQueues; i++ ) 131 { 132 circularQ = &saRoot->outboundQueue[i]; 133 OSSA_READ_LE_32(circularQ->agRoot, &circularQ->producerIdx, circularQ->piPointer, 0); 134 if(circularQ->producerIdx != circularQ->consumerIdx) 135 { 136 if( saRoot->OldCi[i] == circularQ->consumerIdx && saRoot->OldPi[i] >= circularQ->producerIdx) 137 { 138 agsaEchoCmd_t payload; 139 payload.tag = 0xF0; 140 payload.payload[0]= 0x0; 141 if( ++saRoot->OldFlag[i] > 1 ) 142 { 143 saRoot->CheckAll++; 144 } 145 SA_DBG1(("saTimerTick:Q %d (%d) PI 0x%03x CI 0x%03x (%d) CheckAll %d %d\n",i, 146 saRoot->OldFlag[i], 147 circularQ->producerIdx, 148 circularQ->consumerIdx, 149 (circularQ->producerIdx > circularQ->consumerIdx ? (circularQ->producerIdx - circularQ->consumerIdx) : (circularQ->numElements - circularQ->consumerIdx ) + circularQ->producerIdx), 150 saRoot->CheckAll, 151 saRoot->sysIntsActive )); 152 153 if(smIS64bInt(agRoot)) 154 { 155 SA_DBG1(("saTimerTick:CheckAll %d ODR 0x%08X%08X ODMR 0x%08X%08X our Int %x\n", 156 saRoot->CheckAll, 157 ossaHwRegReadExt(agRoot, 0, V_Outbound_Doorbell_Set_RegisterU), 158 ossaHwRegReadExt(agRoot, 0, V_Outbound_Doorbell_Set_Register), 159 ossaHwRegReadExt(agRoot, 0, V_Outbound_Doorbell_Mask_Set_RegisterU), 160 ossaHwRegReadExt(agRoot, 0, V_Outbound_Doorbell_Mask_Set_Register), 161 saRoot->OurInterrupt(agRoot,i) 162 )); 163 } 164 else 165 { 166 SA_DBG1(("saTimerTick:CheckAll %d ODR 0x%08X ODMR 0x%08X our Int %x\n", 167 saRoot->CheckAll, 168 siHalRegReadExt(agRoot, GEN_MSGU_ODR, V_Outbound_Doorbell_Set_Register), 169 siHalRegReadExt(agRoot, GEN_MSGU_ODMR, V_Outbound_Doorbell_Mask_Set_Register), 170 saRoot->OurInterrupt(agRoot,i) 171 )); 172 } 173 174 175 if( saRoot->CheckAll > 1) 176 { 177 saEchoCommand(agRoot,agNULL, ((i << 16) & 0xFFFF0000 ), (void *)&payload); 178 } 179 180 } 181 else 182 { 183 saRoot->OldFlag[i] = 0; 184 } 185 186 saRoot->OldPi[i] = circularQ->producerIdx; 187 saRoot->OldCi[i] = circularQ->consumerIdx; 188 189 } 190 } 191 } 192 #endif /* SA_FW_TEST_INTERRUPT_REASSERT */ 193 194 /* (4) Release timer list lock */ 195 ossaSingleThreadedLeave(agRoot, LL_TIMER_LOCK); 196 #ifdef SA_FW_TEST_INTERRUPT_REASSERT 197 if(saRoot->CheckAll ) 198 { 199 int a; 200 for(a=0; a < 32; a++ ) 201 { 202 if (saRoot->interruptVecIndexBitMap[a] & (1 << a)) 203 { 204 SA_DBG1(("saTimerTick DI %d\n",a)); 205 saSystemInterruptsEnable ( agRoot, a ); 206 207 } 208 } 209 } 210 #endif /* SA_FW_TEST_INTERRUPT_REASSERT */ 211 } 212 213 /******************************************************************************/ 214 /*! \brief add a timer 215 * 216 * add a timer 217 * 218 * \param agRoot handles for this instance of SAS/SATA hardware 219 * \param pTimer the pointer to the timer being added 220 * \param timeout the timeout ticks from now 221 * \param pfnTimeout callback function when time is out 222 * \param Event the Event code passed to callback function 223 * \param pParm the pointer to parameter passed to callback function 224 * 225 * \return If the timer is added successfully 226 * - \e AGSA_RC_SUCCESS timer is added successfully 227 * - \e AGSA_RC_FAILURE cannot add new timer, run out of resource 228 */ 229 /*******************************************************************************/ 230 GLOBAL agsaTimerDesc_t *siTimerAdd( 231 agsaRoot_t *agRoot, 232 bit32 timeout, 233 agsaCallback_t pfnTimeout, 234 bit32 Event, 235 void * pParm 236 ) 237 { 238 agsaLLRoot_t *saRoot = (agsaLLRoot_t *)(agRoot->sdkData); 239 agsaTimerDesc_t *pTimer; 240 agsaTimerDesc_t *pValidTimer; 241 242 smTraceFuncEnter(hpDBG_VERY_LOUD, "Ta"); 243 /* (1) Acquire timer list lock */ 244 ossaSingleThreadedEnter(agRoot, LL_TIMER_LOCK); 245 246 /* (2) Get a free timer */ 247 pTimer = (agsaTimerDesc_t *) saLlistGetHead(&(saRoot->freeTimers)); 248 249 /* (3) If the timer is availble */ 250 if ( agNULL != pTimer ) 251 { 252 saLlistRemove(&(saRoot->freeTimers), &(pTimer->linkNode)); 253 254 /* (3.1) Setup timer */ 255 saLlinkInitialize(&(pTimer->linkNode)); 256 /*--------------------------------------** 257 ** the timeout shall greater than 0 ** 258 **--------------------------------------*/ 259 if ( 0 == timeout ) 260 { 261 timeout = timeout + 1; 262 } 263 pTimer->valid = agTRUE; 264 pTimer->timeoutTick = saRoot->timeTick + timeout; 265 pTimer->pfnTimeout = pfnTimeout; 266 pTimer->Event = Event; 267 pTimer->pParm = pParm; 268 269 /* (3.2) Add timer the timer to valid timer list */ 270 pValidTimer = (agsaTimerDesc_t *) saLlistGetHead(&(saRoot->validTimers)); 271 /* (3.3) for each timer in the valid timer list */ 272 while ( agNULL != pValidTimer ) 273 { 274 /* (3.3.1) If the timeoutTick is not wrapped around */ 275 if ( pTimer->timeoutTick > saRoot->timeTick ) 276 { 277 /* (3.3.1.1) If validTimer wrapped around */ 278 if ( pValidTimer->timeoutTick < saRoot->timeTick ) 279 { 280 saLlistInsert(&(saRoot->validTimers), &(pValidTimer->linkNode), &(pTimer->linkNode)); 281 break; 282 } 283 /* (3.3.1.2) If validTimer is not wrapped around */ 284 else 285 { 286 if ( pValidTimer->timeoutTick > pTimer->timeoutTick ) 287 { 288 saLlistInsert(&(saRoot->validTimers), &(pValidTimer->linkNode), &(pTimer->linkNode)); 289 break; 290 } 291 } 292 } 293 /* (3.3.2) If the timeoutTick is wrapped around */ 294 else 295 { 296 /* (3.3.2.1) If validTimer is wrapped around */ 297 if ( pValidTimer->timeoutTick < saRoot->timeTick ) 298 { 299 if ( pValidTimer->timeoutTick > pTimer->timeoutTick ) 300 { 301 saLlistInsert(&(saRoot->validTimers), &(pValidTimer->linkNode), &(pTimer->linkNode)); 302 break; 303 } 304 } 305 } 306 /* (3.3.3) Continue to the next valid timer */ 307 pValidTimer = (agsaTimerDesc_t *) saLlistGetNext(&(saRoot->validTimers), &(pValidTimer->linkNode)); 308 } 309 310 /* (3.4) No timers in the validtimer list is greater than this timer */ 311 if ( agNULL == pValidTimer ) 312 { 313 saLlistAdd(&(saRoot->validTimers), &(pTimer->linkNode)); 314 } 315 } 316 317 /* (4) Release timer list lock */ 318 ossaSingleThreadedLeave(agRoot, LL_TIMER_LOCK); 319 smTraceFuncExit(hpDBG_VERY_LOUD, 'a', "Ta"); 320 321 return pTimer; 322 } 323 324 /******************************************************************************/ 325 /*! \brief remove a valid timer 326 * 327 * remove a timer 328 * 329 * \param agRoot handles for this instance of SAS/SATA hardware 330 * \param pTimer the timer to be removed 331 * 332 * \return -void- 333 */ 334 /*******************************************************************************/ 335 GLOBAL void siTimerRemove( 336 agsaRoot_t *agRoot, 337 agsaTimerDesc_t *pTimer 338 ) 339 { 340 agsaLLRoot_t *saRoot = (agsaLLRoot_t *)(agRoot->sdkData); 341 342 /* (1) Acquire timer list lock */ 343 smTraceFuncEnter(hpDBG_VERY_LOUD,"Tb"); 344 ossaSingleThreadedEnter(agRoot, LL_TIMER_LOCK); 345 346 /* (2) If the timer is still valid */ 347 if ( agTRUE == pTimer->valid ) 348 { 349 /* (2.1) remove from the valid timer list */ 350 saLlistRemove(&(saRoot->validTimers), &(pTimer->linkNode)); 351 /* (2.2) Invalid the timer */ 352 pTimer->valid = agFALSE; 353 /* (2.3) return the timer to the free timer list */ 354 saLlistAdd(&(saRoot->freeTimers), &(pTimer->linkNode)); 355 } 356 /* (3) Release timer list lock */ 357 ossaSingleThreadedLeave(agRoot, LL_TIMER_LOCK); 358 smTraceFuncExit(hpDBG_VERY_LOUD, 'a', "Tb"); 359 360 return; 361 } 362 363 /******************************************************************************/ 364 /*! \brief remove all valid timer 365 * 366 * remove all timer 367 * 368 * \param agRoot handles for this instance of SAS/SATA hardware 369 * 370 * \return -void- 371 */ 372 /*******************************************************************************/ 373 GLOBAL void siTimerRemoveAll( 374 agsaRoot_t *agRoot 375 ) 376 { 377 agsaLLRoot_t *saRoot = (agsaLLRoot_t *)(agRoot->sdkData); 378 agsaTimerDesc_t *pTimer; 379 380 smTraceFuncEnter(hpDBG_VERY_LOUD,"Tc"); 381 382 /* (1) Acquire timer list lock */ 383 ossaSingleThreadedEnter(agRoot, LL_TIMER_LOCK); 384 385 /* (2) Get a valid timer */ 386 pTimer = (agsaTimerDesc_t *) saLlistGetHead(&(saRoot->validTimers)); 387 388 /* (3) If the timer is valid */ 389 while ( agNULL != pTimer ) 390 { 391 /* (3.1) remove from the valid timer list */ 392 saLlistRemove(&(saRoot->validTimers), &(pTimer->linkNode)); 393 394 /* (3.2) Invalid timer */ 395 pTimer->valid = agFALSE; 396 397 /* (3.3) return the timer to the free timer list */ 398 saLlistAdd(&(saRoot->freeTimers), &(pTimer->linkNode)); 399 400 /* (3.4) get next valid timer */ 401 pTimer = (agsaTimerDesc_t *) saLlistGetHead(&(saRoot->validTimers)); 402 } 403 404 /* (4) Release timer list lock */ 405 ossaSingleThreadedLeave(agRoot, LL_TIMER_LOCK); 406 407 smTraceFuncExit(hpDBG_VERY_LOUD, 'a', "Tc"); 408 409 return; 410 } 411