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