/******************************************************************************* *Copyright (c) 2014 PMC-Sierra, Inc. All rights reserved. * *Redistribution and use in source and binary forms, with or without modification, are permitted provided *that the following conditions are met: *1. Redistributions of source code must retain the above copyright notice, this list of conditions and the *following disclaimer. *2. Redistributions in binary form must reproduce the above copyright notice, *this list of conditions and the following disclaimer in the documentation and/or other materials provided *with the distribution. * *THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED *WARRANTIES,INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE *FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT *NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR *BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT *LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE ********************************************************************************/ /*******************************************************************************/ /*! \file satimer.c * \brief The file implements the timerTick function * */ /******************************************************************************/ #include __FBSDID("$FreeBSD$"); #include #include #ifdef SA_FW_TEST_BUNCH_STARTS void mpiMsgProduceBunch( agsaLLRoot_t *saRoot); #endif /* SA_FW_TEST_BUNCH_STARTS */ #ifdef SA_ENABLE_TRACE_FUNCTIONS #ifdef siTraceFileID #undef siTraceFileID #endif #define siTraceFileID 'P' #endif /******************************************************************************/ /*! \brief TimerTick * * TimerTick * * \param agRoot handles for this instance of SAS/SATA hardware * * \return -void- */ /*******************************************************************************/ GLOBAL void saTimerTick( agsaRoot_t *agRoot ) { agsaLLRoot_t *saRoot = (agsaLLRoot_t *)(agRoot->sdkData); agsaTimerDesc_t *pTimer; bit32 Event; void * pParm; if(agNULL == saRoot) { SA_DBG1(("saTimerTick:agNULL == saRoot \n")); return; } /* (1) Acquire timer list lock */ ossaSingleThreadedEnter(agRoot, LL_TIMER_LOCK); /* (2) Find the timers are timeout */ pTimer = (agsaTimerDesc_t *) saLlistGetHead(&(saRoot->validTimers)); while ( agNULL != pTimer ) { /* (2.1) Find the first timer is timeout */ if ( pTimer->timeoutTick == saRoot->timeTick ) { /* (2.1.1) remove the timer from valid timer list */ saLlistRemove(&(saRoot->validTimers), &(pTimer->linkNode)); /* (2.1.2) Invalid timer */ pTimer->valid = agFALSE; /* (2.1.3) Get timer event and param */ Event = pTimer->Event; pParm = pTimer->pParm; /* (2.1.4) Release timer list lock */ ossaSingleThreadedLeave(agRoot, LL_TIMER_LOCK); /* (2.1.5) Timer Callback */ pTimer->pfnTimeout(agRoot, Event, pParm); /* (2.1.6) Acquire timer list lock again */ ossaSingleThreadedEnter(agRoot, LL_TIMER_LOCK); /* (2.1.7) return the timer to free timer list */ saLlistAdd(&(saRoot->freeTimers), &(pTimer->linkNode)); } /* (2.2) the first timer is not timeout */ else { break; } pTimer = (agsaTimerDesc_t *) saLlistGetHead(&(saRoot->validTimers)); } /* (3) increment timeTick */ saRoot->timeTick ++; if( saRoot->ResetFailed ) { SA_DBG1(("saTimerTick: siChipResetV saRoot->ResetFailed\n")); } #ifdef SA_FW_TEST_BUNCH_STARTS if (saRoot->BunchStarts_Enable && saRoot->BunchStarts_Pending) { SA_DBG3(("saTimerTick: mpiMsgProduceBunch\n")); mpiMsgProduceBunch( saRoot); } #endif /* SA_FW_TEST_BUNCH_STARTS */ #ifdef SA_FW_TEST_INTERRUPT_REASSERT if(1) { mpiOCQueue_t *circularQ; int i; SA_DBG4(("saTimerTick:SA_FW_TEST_INTERRUPT_REASSERT\n")); for ( i = 0; i < saRoot->QueueConfig.numOutboundQueues; i++ ) { circularQ = &saRoot->outboundQueue[i]; OSSA_READ_LE_32(circularQ->agRoot, &circularQ->producerIdx, circularQ->piPointer, 0); if(circularQ->producerIdx != circularQ->consumerIdx) { if( saRoot->OldCi[i] == circularQ->consumerIdx && saRoot->OldPi[i] >= circularQ->producerIdx) { agsaEchoCmd_t payload; payload.tag = 0xF0; payload.payload[0]= 0x0; if( ++saRoot->OldFlag[i] > 1 ) { saRoot->CheckAll++; } SA_DBG1(("saTimerTick:Q %d (%d) PI 0x%03x CI 0x%03x (%d) CheckAll %d %d\n",i, saRoot->OldFlag[i], circularQ->producerIdx, circularQ->consumerIdx, (circularQ->producerIdx > circularQ->consumerIdx ? (circularQ->producerIdx - circularQ->consumerIdx) : (circularQ->numElements - circularQ->consumerIdx ) + circularQ->producerIdx), saRoot->CheckAll, saRoot->sysIntsActive )); if(smIS64bInt(agRoot)) { SA_DBG1(("saTimerTick:CheckAll %d ODR 0x%08X%08X ODMR 0x%08X%08X our Int %x\n", saRoot->CheckAll, ossaHwRegReadExt(agRoot, 0, V_Outbound_Doorbell_Set_RegisterU), ossaHwRegReadExt(agRoot, 0, V_Outbound_Doorbell_Set_Register), ossaHwRegReadExt(agRoot, 0, V_Outbound_Doorbell_Mask_Set_RegisterU), ossaHwRegReadExt(agRoot, 0, V_Outbound_Doorbell_Mask_Set_Register), saRoot->OurInterrupt(agRoot,i) )); } else { SA_DBG1(("saTimerTick:CheckAll %d ODR 0x%08X ODMR 0x%08X our Int %x\n", saRoot->CheckAll, siHalRegReadExt(agRoot, GEN_MSGU_ODR, V_Outbound_Doorbell_Set_Register), siHalRegReadExt(agRoot, GEN_MSGU_ODMR, V_Outbound_Doorbell_Mask_Set_Register), saRoot->OurInterrupt(agRoot,i) )); } if( saRoot->CheckAll > 1) { saEchoCommand(agRoot,agNULL, ((i << 16) & 0xFFFF0000 ), (void *)&payload); } } else { saRoot->OldFlag[i] = 0; } saRoot->OldPi[i] = circularQ->producerIdx; saRoot->OldCi[i] = circularQ->consumerIdx; } } } #endif /* SA_FW_TEST_INTERRUPT_REASSERT */ /* (4) Release timer list lock */ ossaSingleThreadedLeave(agRoot, LL_TIMER_LOCK); #ifdef SA_FW_TEST_INTERRUPT_REASSERT if(saRoot->CheckAll ) { int a; for(a=0; a < 32; a++ ) { if (saRoot->interruptVecIndexBitMap[a] & (1 << a)) { SA_DBG1(("saTimerTick DI %d\n",a)); saSystemInterruptsEnable ( agRoot, a ); } } } #endif /* SA_FW_TEST_INTERRUPT_REASSERT */ } /******************************************************************************/ /*! \brief add a timer * * add a timer * * \param agRoot handles for this instance of SAS/SATA hardware * \param pTimer the pointer to the timer being added * \param timeout the timeout ticks from now * \param pfnTimeout callback function when time is out * \param Event the Event code passed to callback function * \param pParm the pointer to parameter passed to callback function * * \return If the timer is added successfully * - \e AGSA_RC_SUCCESS timer is added successfully * - \e AGSA_RC_FAILURE cannot add new timer, run out of resource */ /*******************************************************************************/ GLOBAL agsaTimerDesc_t *siTimerAdd( agsaRoot_t *agRoot, bit32 timeout, agsaCallback_t pfnTimeout, bit32 Event, void * pParm ) { agsaLLRoot_t *saRoot = (agsaLLRoot_t *)(agRoot->sdkData); agsaTimerDesc_t *pTimer; agsaTimerDesc_t *pValidTimer; smTraceFuncEnter(hpDBG_VERY_LOUD, "Ta"); /* (1) Acquire timer list lock */ ossaSingleThreadedEnter(agRoot, LL_TIMER_LOCK); /* (2) Get a free timer */ pTimer = (agsaTimerDesc_t *) saLlistGetHead(&(saRoot->freeTimers)); /* (3) If the timer is availble */ if ( agNULL != pTimer ) { saLlistRemove(&(saRoot->freeTimers), &(pTimer->linkNode)); /* (3.1) Setup timer */ saLlinkInitialize(&(pTimer->linkNode)); /*--------------------------------------** ** the timeout shall greater than 0 ** **--------------------------------------*/ if ( 0 == timeout ) { timeout = timeout + 1; } pTimer->valid = agTRUE; pTimer->timeoutTick = saRoot->timeTick + timeout; pTimer->pfnTimeout = pfnTimeout; pTimer->Event = Event; pTimer->pParm = pParm; /* (3.2) Add timer the timer to valid timer list */ pValidTimer = (agsaTimerDesc_t *) saLlistGetHead(&(saRoot->validTimers)); /* (3.3) for each timer in the valid timer list */ while ( agNULL != pValidTimer ) { /* (3.3.1) If the timeoutTick is not wrapped around */ if ( pTimer->timeoutTick > saRoot->timeTick ) { /* (3.3.1.1) If validTimer wrapped around */ if ( pValidTimer->timeoutTick < saRoot->timeTick ) { saLlistInsert(&(saRoot->validTimers), &(pValidTimer->linkNode), &(pTimer->linkNode)); break; } /* (3.3.1.2) If validTimer is not wrapped around */ else { if ( pValidTimer->timeoutTick > pTimer->timeoutTick ) { saLlistInsert(&(saRoot->validTimers), &(pValidTimer->linkNode), &(pTimer->linkNode)); break; } } } /* (3.3.2) If the timeoutTick is wrapped around */ else { /* (3.3.2.1) If validTimer is wrapped around */ if ( pValidTimer->timeoutTick < saRoot->timeTick ) { if ( pValidTimer->timeoutTick > pTimer->timeoutTick ) { saLlistInsert(&(saRoot->validTimers), &(pValidTimer->linkNode), &(pTimer->linkNode)); break; } } } /* (3.3.3) Continue to the next valid timer */ pValidTimer = (agsaTimerDesc_t *) saLlistGetNext(&(saRoot->validTimers), &(pValidTimer->linkNode)); } /* (3.4) No timers in the validtimer list is greater than this timer */ if ( agNULL == pValidTimer ) { saLlistAdd(&(saRoot->validTimers), &(pTimer->linkNode)); } } /* (4) Release timer list lock */ ossaSingleThreadedLeave(agRoot, LL_TIMER_LOCK); smTraceFuncExit(hpDBG_VERY_LOUD, 'a', "Ta"); return pTimer; } /******************************************************************************/ /*! \brief remove a valid timer * * remove a timer * * \param agRoot handles for this instance of SAS/SATA hardware * \param pTimer the timer to be removed * * \return -void- */ /*******************************************************************************/ GLOBAL void siTimerRemove( agsaRoot_t *agRoot, agsaTimerDesc_t *pTimer ) { agsaLLRoot_t *saRoot = (agsaLLRoot_t *)(agRoot->sdkData); /* (1) Acquire timer list lock */ smTraceFuncEnter(hpDBG_VERY_LOUD,"Tb"); ossaSingleThreadedEnter(agRoot, LL_TIMER_LOCK); /* (2) If the timer is still valid */ if ( agTRUE == pTimer->valid ) { /* (2.1) remove from the valid timer list */ saLlistRemove(&(saRoot->validTimers), &(pTimer->linkNode)); /* (2.2) Invalid the timer */ pTimer->valid = agFALSE; /* (2.3) return the timer to the free timer list */ saLlistAdd(&(saRoot->freeTimers), &(pTimer->linkNode)); } /* (3) Release timer list lock */ ossaSingleThreadedLeave(agRoot, LL_TIMER_LOCK); smTraceFuncExit(hpDBG_VERY_LOUD, 'a', "Tb"); return; } /******************************************************************************/ /*! \brief remove all valid timer * * remove all timer * * \param agRoot handles for this instance of SAS/SATA hardware * * \return -void- */ /*******************************************************************************/ GLOBAL void siTimerRemoveAll( agsaRoot_t *agRoot ) { agsaLLRoot_t *saRoot = (agsaLLRoot_t *)(agRoot->sdkData); agsaTimerDesc_t *pTimer; smTraceFuncEnter(hpDBG_VERY_LOUD,"Tc"); /* (1) Acquire timer list lock */ ossaSingleThreadedEnter(agRoot, LL_TIMER_LOCK); /* (2) Get a valid timer */ pTimer = (agsaTimerDesc_t *) saLlistGetHead(&(saRoot->validTimers)); /* (3) If the timer is valid */ while ( agNULL != pTimer ) { /* (3.1) remove from the valid timer list */ saLlistRemove(&(saRoot->validTimers), &(pTimer->linkNode)); /* (3.2) Invalid timer */ pTimer->valid = agFALSE; /* (3.3) return the timer to the free timer list */ saLlistAdd(&(saRoot->freeTimers), &(pTimer->linkNode)); /* (3.4) get next valid timer */ pTimer = (agsaTimerDesc_t *) saLlistGetHead(&(saRoot->validTimers)); } /* (4) Release timer list lock */ ossaSingleThreadedLeave(agRoot, LL_TIMER_LOCK); smTraceFuncExit(hpDBG_VERY_LOUD, 'a', "Tc"); return; }