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
34void 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/*******************************************************************************/
54GLOBAL 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/*******************************************************************************/
230GLOBAL 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/*******************************************************************************/
335GLOBAL 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/*******************************************************************************/
373GLOBAL 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