1285809Sscottl/*******************************************************************************
2285809Sscottl*Copyright (c) 2014 PMC-Sierra, Inc.  All rights reserved.
3285809Sscottl*
4285809Sscottl*Redistribution and use in source and binary forms, with or without modification, are permitted provided
5285809Sscottl*that the following conditions are met:
6285809Sscottl*1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
7285809Sscottl*following disclaimer.
8285809Sscottl*2. Redistributions in binary form must reproduce the above copyright notice,
9285809Sscottl*this list of conditions and the following disclaimer in the documentation and/or other materials provided
10285809Sscottl*with the distribution.
11285809Sscottl*
12285809Sscottl*THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED
13285809Sscottl*WARRANTIES,INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
14285809Sscottl*FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
15285809Sscottl*FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
16285809Sscottl*NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
17285809Sscottl*BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
18285809Sscottl*LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
19285809Sscottl*SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
20285809Sscottl
21285809Sscottl********************************************************************************/
22285809Sscottl/*******************************************************************************/
23285809Sscottl/*! \file satimer.c
24285809Sscottl *  \brief The file implements the timerTick function
25285809Sscottl *
26285809Sscottl */
27285809Sscottl/******************************************************************************/
28285809Sscottl#include <sys/cdefs.h>
29285809Sscottl__FBSDID("$FreeBSD$");
30285809Sscottl#include <dev/pms/config.h>
31285809Sscottl
32285809Sscottl#include <dev/pms/RefTisa/sallsdk/spc/saglobal.h>
33285809Sscottl#ifdef SA_FW_TEST_BUNCH_STARTS
34285809Sscottlvoid mpiMsgProduceBunch(  agsaLLRoot_t  *saRoot);
35285809Sscottl#endif /* SA_FW_TEST_BUNCH_STARTS */
36285809Sscottl
37285809Sscottl#ifdef SA_ENABLE_TRACE_FUNCTIONS
38285809Sscottl#ifdef siTraceFileID
39285809Sscottl#undef siTraceFileID
40285809Sscottl#endif
41285809Sscottl#define siTraceFileID 'P'
42285809Sscottl#endif
43285809Sscottl
44285809Sscottl/******************************************************************************/
45285809Sscottl/*! \brief TimerTick
46285809Sscottl *
47285809Sscottl *  TimerTick
48285809Sscottl *
49285809Sscottl *  \param agRoot handles for this instance of SAS/SATA hardware
50285809Sscottl *
51285809Sscottl *  \return -void-
52285809Sscottl */
53285809Sscottl/*******************************************************************************/
54285809SscottlGLOBAL void saTimerTick(
55285809Sscottl  agsaRoot_t  *agRoot
56285809Sscottl  )
57285809Sscottl{
58285809Sscottl  agsaLLRoot_t    *saRoot = (agsaLLRoot_t *)(agRoot->sdkData);
59285809Sscottl  agsaTimerDesc_t *pTimer;
60285809Sscottl  bit32           Event;
61285809Sscottl  void *          pParm;
62285809Sscottl
63285809Sscottl  if(agNULL ==  saRoot)
64285809Sscottl  {
65285809Sscottl    SA_DBG1(("saTimerTick:agNULL ==  saRoot \n"));
66285809Sscottl    return;
67285809Sscottl  }
68285809Sscottl
69285809Sscottl  /* (1) Acquire timer list lock */
70285809Sscottl  ossaSingleThreadedEnter(agRoot, LL_TIMER_LOCK);
71285809Sscottl
72285809Sscottl  /* (2) Find the timers are timeout */
73285809Sscottl  pTimer = (agsaTimerDesc_t *) saLlistGetHead(&(saRoot->validTimers));
74285809Sscottl  while ( agNULL != pTimer )
75285809Sscottl  {
76285809Sscottl    /* (2.1) Find the first timer is timeout */
77285809Sscottl    if ( pTimer->timeoutTick == saRoot->timeTick )
78285809Sscottl    {
79285809Sscottl      /* (2.1.1) remove the timer from valid timer list */
80285809Sscottl      saLlistRemove(&(saRoot->validTimers), &(pTimer->linkNode));
81285809Sscottl      /* (2.1.2) Invalid timer */
82285809Sscottl      pTimer->valid = agFALSE;
83285809Sscottl      /* (2.1.3) Get timer event and param */
84285809Sscottl      Event = pTimer->Event;
85285809Sscottl      pParm = pTimer->pParm;
86285809Sscottl      /* (2.1.4) Release timer list lock */
87285809Sscottl      ossaSingleThreadedLeave(agRoot, LL_TIMER_LOCK);
88285809Sscottl
89285809Sscottl      /* (2.1.5) Timer Callback */
90285809Sscottl      pTimer->pfnTimeout(agRoot, Event, pParm);
91285809Sscottl
92285809Sscottl      /* (2.1.6) Acquire timer list lock again */
93285809Sscottl      ossaSingleThreadedEnter(agRoot, LL_TIMER_LOCK);
94285809Sscottl      /* (2.1.7) return the timer to free timer list */
95285809Sscottl      saLlistAdd(&(saRoot->freeTimers), &(pTimer->linkNode));
96285809Sscottl    }
97285809Sscottl    /* (2.2) the first timer is not timeout */
98285809Sscottl    else
99285809Sscottl    {
100285809Sscottl      break;
101285809Sscottl    }
102285809Sscottl    pTimer = (agsaTimerDesc_t *) saLlistGetHead(&(saRoot->validTimers));
103285809Sscottl  }
104285809Sscottl
105285809Sscottl  /* (3) increment timeTick */
106285809Sscottl  saRoot->timeTick ++;
107285809Sscottl
108285809Sscottl  if( saRoot->ResetFailed )
109285809Sscottl  {
110285809Sscottl    SA_DBG1(("saTimerTick: siChipResetV saRoot->ResetFailed\n"));
111285809Sscottl  }
112285809Sscottl
113285809Sscottl#ifdef SA_FW_TEST_BUNCH_STARTS
114285809Sscottl  if (saRoot->BunchStarts_Enable &&
115285809Sscottl      saRoot->BunchStarts_Pending)
116285809Sscottl  {
117285809Sscottl      SA_DBG3(("saTimerTick: mpiMsgProduceBunch\n"));
118285809Sscottl      mpiMsgProduceBunch(  saRoot);
119285809Sscottl  }
120285809Sscottl#endif /* SA_FW_TEST_BUNCH_STARTS */
121285809Sscottl
122285809Sscottl
123285809Sscottl#ifdef SA_FW_TEST_INTERRUPT_REASSERT
124285809Sscottl
125285809Sscottl  if(1)
126285809Sscottl  {
127285809Sscottl    mpiOCQueue_t         *circularQ;
128285809Sscottl    int i;
129285809Sscottl    SA_DBG4(("saTimerTick:SA_FW_TEST_INTERRUPT_REASSERT\n"));
130285809Sscottl    for ( i = 0; i < saRoot->QueueConfig.numOutboundQueues; i++ )
131285809Sscottl    {
132285809Sscottl      circularQ = &saRoot->outboundQueue[i];
133285809Sscottl      OSSA_READ_LE_32(circularQ->agRoot, &circularQ->producerIdx, circularQ->piPointer, 0);
134285809Sscottl      if(circularQ->producerIdx != circularQ->consumerIdx)
135285809Sscottl      {
136285809Sscottl        if( saRoot->OldCi[i] == circularQ->consumerIdx && saRoot->OldPi[i] >= circularQ->producerIdx)
137285809Sscottl        {
138285809Sscottl          agsaEchoCmd_t       payload;
139285809Sscottl          payload.tag = 0xF0;
140285809Sscottl          payload.payload[0]= 0x0;
141285809Sscottl          if( ++saRoot->OldFlag[i] > 1 )
142285809Sscottl          {
143285809Sscottl            saRoot->CheckAll++;
144285809Sscottl          }
145285809Sscottl          SA_DBG1(("saTimerTick:Q %d (%d) PI 0x%03x CI 0x%03x (%d) CheckAll %d %d\n",i,
146285809Sscottl            saRoot->OldFlag[i],
147285809Sscottl            circularQ->producerIdx,
148285809Sscottl            circularQ->consumerIdx,
149285809Sscottl            (circularQ->producerIdx > circularQ->consumerIdx ? (circularQ->producerIdx - circularQ->consumerIdx) :   (circularQ->numElements -  circularQ->consumerIdx ) + circularQ->producerIdx),
150285809Sscottl            saRoot->CheckAll,
151285809Sscottl            saRoot->sysIntsActive ));
152285809Sscottl
153285809Sscottl          if(smIS64bInt(agRoot))
154285809Sscottl          {
155285809Sscottl            SA_DBG1(("saTimerTick:CheckAll %d ODR 0x%08X%08X ODMR 0x%08X%08X our Int %x\n",
156285809Sscottl              saRoot->CheckAll,
157285809Sscottl              ossaHwRegReadExt(agRoot, 0, V_Outbound_Doorbell_Set_RegisterU),
158285809Sscottl              ossaHwRegReadExt(agRoot, 0, V_Outbound_Doorbell_Set_Register),
159285809Sscottl              ossaHwRegReadExt(agRoot, 0, V_Outbound_Doorbell_Mask_Set_RegisterU),
160285809Sscottl              ossaHwRegReadExt(agRoot, 0, V_Outbound_Doorbell_Mask_Set_Register),
161285809Sscottl              saRoot->OurInterrupt(agRoot,i)
162285809Sscottl              ));
163285809Sscottl          }
164285809Sscottl          else
165285809Sscottl          {
166285809Sscottl            SA_DBG1(("saTimerTick:CheckAll %d ODR 0x%08X ODMR 0x%08X our Int %x\n",
167285809Sscottl              saRoot->CheckAll,
168285809Sscottl              siHalRegReadExt(agRoot, GEN_MSGU_ODR,  V_Outbound_Doorbell_Set_Register),
169285809Sscottl              siHalRegReadExt(agRoot, GEN_MSGU_ODMR, V_Outbound_Doorbell_Mask_Set_Register),
170285809Sscottl              saRoot->OurInterrupt(agRoot,i)
171285809Sscottl              ));
172285809Sscottl          }
173285809Sscottl
174285809Sscottl
175285809Sscottl          if( saRoot->CheckAll > 1)
176285809Sscottl          {
177285809Sscottl            saEchoCommand(agRoot,agNULL, ((i << 16) & 0xFFFF0000 ), (void *)&payload);
178285809Sscottl          }
179285809Sscottl
180285809Sscottl        }
181285809Sscottl        else
182285809Sscottl        {
183285809Sscottl          saRoot->OldFlag[i] = 0;
184285809Sscottl        }
185285809Sscottl
186285809Sscottl        saRoot->OldPi[i] = circularQ->producerIdx;
187285809Sscottl        saRoot->OldCi[i] = circularQ->consumerIdx;
188285809Sscottl
189285809Sscottl      }
190285809Sscottl    }
191285809Sscottl  }
192285809Sscottl#endif /* SA_FW_TEST_INTERRUPT_REASSERT */
193285809Sscottl
194285809Sscottl  /* (4) Release timer list lock */
195285809Sscottl  ossaSingleThreadedLeave(agRoot, LL_TIMER_LOCK);
196285809Sscottl#ifdef SA_FW_TEST_INTERRUPT_REASSERT
197285809Sscottl  if(saRoot->CheckAll )
198285809Sscottl  {
199285809Sscottl    int a;
200285809Sscottl    for(a=0; a < 32; a++ )
201285809Sscottl    {
202285809Sscottl      if (saRoot->interruptVecIndexBitMap[a] & (1 << a))
203285809Sscottl      {
204285809Sscottl        SA_DBG1(("saTimerTick DI %d\n",a));
205285809Sscottl        saSystemInterruptsEnable  ( agRoot, a );
206285809Sscottl
207285809Sscottl      }
208285809Sscottl    }
209285809Sscottl  }
210285809Sscottl#endif /* SA_FW_TEST_INTERRUPT_REASSERT */
211285809Sscottl}
212285809Sscottl
213285809Sscottl/******************************************************************************/
214285809Sscottl/*! \brief add a timer
215285809Sscottl *
216285809Sscottl *  add a timer
217285809Sscottl *
218285809Sscottl *  \param agRoot       handles for this instance of SAS/SATA hardware
219285809Sscottl *  \param pTimer       the pointer to the timer being added
220285809Sscottl *  \param timeout      the timeout ticks from now
221285809Sscottl *  \param pfnTimeout   callback function when time is out
222285809Sscottl *  \param Event        the Event code passed to callback function
223285809Sscottl *  \param pParm        the pointer to parameter passed to callback function
224285809Sscottl *
225285809Sscottl *  \return If the timer is added successfully
226285809Sscottl *          - \e AGSA_RC_SUCCESS timer is added successfully
227285809Sscottl *          - \e AGSA_RC_FAILURE cannot add new timer, run out of resource
228285809Sscottl */
229285809Sscottl/*******************************************************************************/
230285809SscottlGLOBAL agsaTimerDesc_t *siTimerAdd(
231285809Sscottl  agsaRoot_t      *agRoot,
232285809Sscottl  bit32           timeout,
233285809Sscottl  agsaCallback_t  pfnTimeout,
234285809Sscottl  bit32           Event,
235285809Sscottl  void *          pParm
236285809Sscottl  )
237285809Sscottl{
238285809Sscottl  agsaLLRoot_t    *saRoot = (agsaLLRoot_t *)(agRoot->sdkData);
239285809Sscottl  agsaTimerDesc_t *pTimer;
240285809Sscottl  agsaTimerDesc_t *pValidTimer;
241285809Sscottl
242285809Sscottl  smTraceFuncEnter(hpDBG_VERY_LOUD, "Ta");
243285809Sscottl  /* (1) Acquire timer list lock */
244285809Sscottl  ossaSingleThreadedEnter(agRoot, LL_TIMER_LOCK);
245285809Sscottl
246285809Sscottl  /* (2) Get a free timer */
247285809Sscottl  pTimer = (agsaTimerDesc_t *) saLlistGetHead(&(saRoot->freeTimers));
248285809Sscottl
249285809Sscottl  /* (3) If the timer is availble  */
250285809Sscottl  if ( agNULL != pTimer )
251285809Sscottl  {
252285809Sscottl    saLlistRemove(&(saRoot->freeTimers), &(pTimer->linkNode));
253285809Sscottl
254285809Sscottl    /* (3.1) Setup timer */
255285809Sscottl    saLlinkInitialize(&(pTimer->linkNode));
256285809Sscottl    /*--------------------------------------**
257285809Sscottl    ** the timeout shall greater than 0 **
258285809Sscottl    **--------------------------------------*/
259285809Sscottl    if ( 0 == timeout )
260285809Sscottl    {
261285809Sscottl      timeout = timeout + 1;
262285809Sscottl    }
263285809Sscottl    pTimer->valid = agTRUE;
264285809Sscottl    pTimer->timeoutTick = saRoot->timeTick + timeout;
265285809Sscottl    pTimer->pfnTimeout = pfnTimeout;
266285809Sscottl    pTimer->Event = Event;
267285809Sscottl    pTimer->pParm = pParm;
268285809Sscottl
269285809Sscottl    /* (3.2) Add timer the timer to valid timer list */
270285809Sscottl    pValidTimer = (agsaTimerDesc_t *) saLlistGetHead(&(saRoot->validTimers));
271285809Sscottl    /* (3.3) for each timer in the valid timer list */
272285809Sscottl    while ( agNULL != pValidTimer )
273285809Sscottl    {
274285809Sscottl      /* (3.3.1) If the timeoutTick is not wrapped around */
275285809Sscottl      if ( pTimer->timeoutTick > saRoot->timeTick )
276285809Sscottl      {
277285809Sscottl        /* (3.3.1.1) If validTimer wrapped around */
278285809Sscottl        if ( pValidTimer->timeoutTick < saRoot->timeTick )
279285809Sscottl        {
280285809Sscottl          saLlistInsert(&(saRoot->validTimers), &(pValidTimer->linkNode), &(pTimer->linkNode));
281285809Sscottl          break;
282285809Sscottl        }
283285809Sscottl        /* (3.3.1.2) If validTimer is not wrapped around */
284285809Sscottl        else
285285809Sscottl        {
286285809Sscottl          if ( pValidTimer->timeoutTick > pTimer->timeoutTick )
287285809Sscottl          {
288285809Sscottl            saLlistInsert(&(saRoot->validTimers), &(pValidTimer->linkNode), &(pTimer->linkNode));
289285809Sscottl            break;
290285809Sscottl          }
291285809Sscottl        }
292285809Sscottl      }
293285809Sscottl      /* (3.3.2) If the timeoutTick is wrapped around */
294285809Sscottl      else
295285809Sscottl      {
296285809Sscottl        /* (3.3.2.1) If validTimer is wrapped around */
297285809Sscottl        if ( pValidTimer->timeoutTick < saRoot->timeTick )
298285809Sscottl        {
299285809Sscottl          if ( pValidTimer->timeoutTick > pTimer->timeoutTick )
300285809Sscottl          {
301285809Sscottl            saLlistInsert(&(saRoot->validTimers), &(pValidTimer->linkNode), &(pTimer->linkNode));
302285809Sscottl            break;
303285809Sscottl          }
304285809Sscottl        }
305285809Sscottl      }
306285809Sscottl      /* (3.3.3) Continue to the next valid timer */
307285809Sscottl      pValidTimer = (agsaTimerDesc_t *) saLlistGetNext(&(saRoot->validTimers), &(pValidTimer->linkNode));
308285809Sscottl    }
309285809Sscottl
310285809Sscottl    /* (3.4) No timers in the validtimer list is greater than this timer */
311285809Sscottl    if ( agNULL == pValidTimer )
312285809Sscottl    {
313285809Sscottl      saLlistAdd(&(saRoot->validTimers), &(pTimer->linkNode));
314285809Sscottl    }
315285809Sscottl  }
316285809Sscottl
317285809Sscottl  /* (4) Release timer list lock */
318285809Sscottl  ossaSingleThreadedLeave(agRoot, LL_TIMER_LOCK);
319285809Sscottl  smTraceFuncExit(hpDBG_VERY_LOUD, 'a', "Ta");
320285809Sscottl
321285809Sscottl  return pTimer;
322285809Sscottl}
323285809Sscottl
324285809Sscottl/******************************************************************************/
325285809Sscottl/*! \brief remove a valid timer
326285809Sscottl *
327285809Sscottl *  remove a timer
328285809Sscottl *
329285809Sscottl *  \param agRoot       handles for this instance of SAS/SATA hardware
330285809Sscottl *  \param pTimer       the timer to be removed
331285809Sscottl *
332285809Sscottl *  \return -void-
333285809Sscottl */
334285809Sscottl/*******************************************************************************/
335285809SscottlGLOBAL void siTimerRemove(
336285809Sscottl  agsaRoot_t      *agRoot,
337285809Sscottl  agsaTimerDesc_t *pTimer
338285809Sscottl  )
339285809Sscottl{
340285809Sscottl  agsaLLRoot_t    *saRoot = (agsaLLRoot_t *)(agRoot->sdkData);
341285809Sscottl
342285809Sscottl  /* (1) Acquire timer list lock */
343285809Sscottl  smTraceFuncEnter(hpDBG_VERY_LOUD,"Tb");
344285809Sscottl  ossaSingleThreadedEnter(agRoot, LL_TIMER_LOCK);
345285809Sscottl
346285809Sscottl  /* (2) If the timer is still valid */
347285809Sscottl  if ( agTRUE == pTimer->valid )
348285809Sscottl  {
349285809Sscottl    /* (2.1) remove from the valid timer list */
350285809Sscottl    saLlistRemove(&(saRoot->validTimers), &(pTimer->linkNode));
351285809Sscottl    /* (2.2) Invalid the timer */
352285809Sscottl    pTimer->valid = agFALSE;
353285809Sscottl    /* (2.3) return the timer to the free timer list */
354285809Sscottl    saLlistAdd(&(saRoot->freeTimers), &(pTimer->linkNode));
355285809Sscottl  }
356285809Sscottl  /* (3) Release timer list lock */
357285809Sscottl  ossaSingleThreadedLeave(agRoot, LL_TIMER_LOCK);
358285809Sscottl  smTraceFuncExit(hpDBG_VERY_LOUD, 'a', "Tb");
359285809Sscottl
360285809Sscottl  return;
361285809Sscottl}
362285809Sscottl
363285809Sscottl/******************************************************************************/
364285809Sscottl/*! \brief remove all valid timer
365285809Sscottl *
366285809Sscottl *  remove all timer
367285809Sscottl *
368285809Sscottl *  \param agRoot       handles for this instance of SAS/SATA hardware
369285809Sscottl *
370285809Sscottl *  \return -void-
371285809Sscottl */
372285809Sscottl/*******************************************************************************/
373285809SscottlGLOBAL void siTimerRemoveAll(
374285809Sscottl  agsaRoot_t      *agRoot
375285809Sscottl  )
376285809Sscottl{
377285809Sscottl  agsaLLRoot_t    *saRoot = (agsaLLRoot_t *)(agRoot->sdkData);
378285809Sscottl  agsaTimerDesc_t *pTimer;
379285809Sscottl
380285809Sscottl  smTraceFuncEnter(hpDBG_VERY_LOUD,"Tc");
381285809Sscottl
382285809Sscottl  /* (1) Acquire timer list lock */
383285809Sscottl  ossaSingleThreadedEnter(agRoot, LL_TIMER_LOCK);
384285809Sscottl
385285809Sscottl  /* (2) Get a valid timer */
386285809Sscottl  pTimer = (agsaTimerDesc_t *) saLlistGetHead(&(saRoot->validTimers));
387285809Sscottl
388285809Sscottl  /* (3) If the timer is valid  */
389285809Sscottl  while ( agNULL != pTimer )
390285809Sscottl  {
391285809Sscottl    /* (3.1) remove from the valid timer list */
392285809Sscottl    saLlistRemove(&(saRoot->validTimers), &(pTimer->linkNode));
393285809Sscottl
394285809Sscottl    /* (3.2) Invalid timer */
395285809Sscottl    pTimer->valid = agFALSE;
396285809Sscottl
397285809Sscottl    /* (3.3) return the timer to the free timer list */
398285809Sscottl    saLlistAdd(&(saRoot->freeTimers), &(pTimer->linkNode));
399285809Sscottl
400285809Sscottl    /* (3.4) get next valid timer */
401285809Sscottl    pTimer = (agsaTimerDesc_t *) saLlistGetHead(&(saRoot->validTimers));
402285809Sscottl  }
403285809Sscottl
404285809Sscottl  /* (4) Release timer list lock */
405285809Sscottl  ossaSingleThreadedLeave(agRoot, LL_TIMER_LOCK);
406285809Sscottl
407285809Sscottl  smTraceFuncExit(hpDBG_VERY_LOUD, 'a', "Tc");
408285809Sscottl
409285809Sscottl  return;
410285809Sscottl}
411