source: svn/trunk/newcon3bcm2_21bu/magnum/basemodules/int/bint.c @ 55

Last change on this file since 55 was 2, checked in by jglee, 11 years ago

first commit

  • Property svn:executable set to *
File size: 46.7 KB
Line 
1/***************************************************************************
2 *     Copyright (c) 2003-2011, Broadcom Corporation
3 *     All Rights Reserved
4 *     Confidential Property of Broadcom Corporation
5 *
6 *  THIS SOFTWARE MAY ONLY BE USED SUBJECT TO AN EXECUTED SOFTWARE LICENSE
7 *  AGREEMENT  BETWEEN THE USER AND BROADCOM.  YOU HAVE NO RIGHT TO USE OR
8 *  EXPLOIT THIS MATERIAL EXCEPT SUBJECT TO THE TERMS OF SUCH AN AGREEMENT.
9 *
10 * $brcm_Workfile: bint.c $
11 * $brcm_Revision: Hydra_Software_Devel/66 $
12 * $brcm_Date: 3/1/11 12:27p $
13 *
14 * Module Description:
15 *
16 * Revision History:
17 *
18 * $brcm_Log: /magnum/basemodules/int/bint.c $
19 *
20 * Hydra_Software_Devel/66   3/1/11 12:27p jtna
21 * SW7420-972: add comment about needing BCHP_PWR around BINT_Open
22 *
23 * Hydra_Software_Devel/65   2/7/11 11:06a erickson
24 * SW7340-249: clarify need for re-enabling L2's in BINT_Isr
25 *
26 * Hydra_Software_Devel/64   8/9/10 9:49a pntruong
27 * SW3548-2526: Tighten the use of _isr function.
28 *
29 * Hydra_Software_Devel/63   8/2/10 1:33p erickson
30 * SW7420-880: use BDBG_OBJECT to protect INT. do not BDBG_OBJECT_ASSERT
31 * in BINT_Isr because it's a critical inner loop.
32 *
33 * Hydra_Software_Devel/62   10/15/09 12:50p erickson
34 * SW7405-3221: add BDBG_MSG for callback->StatInfo if available. clear
35 * stats on every timer. default off.
36 *
37 * Hydra_Software_Devel/61   7/24/09 6:11p pntruong
38 * PR55861: Further refactored the new int macro.
39 *
40 * Hydra_Software_Devel/61   7/24/09 6:09p pntruong
41 * PR55861: Further refactored the new int macro.
42 *
43 * Hydra_Software_Devel/61   7/24/09 6:05p pntruong
44 * PR55861: Further refactored the new int macro to ease porting of new
45 * chips.
46 *
47 * Hydra_Software_Devel/60   7/24/09 2:24p mward
48 * PR55545: Add 7125 to BINT_NEW_INT_MODEL list.
49 *
50 * Hydra_Software_Devel/59   7/10/09 4:40p erickson
51 * PR56517: add #ifndef BINT_OPEN_BYPASS_L2INIT option for power standby
52 * driver
53 *
54 * Hydra_Software_Devel/58   4/23/09 10:56a jhaberf
55 * PR53796: Adding BCM35130 support.
56 *
57 * Hydra_Software_Devel/57   4/8/09 4:23p vsilyaev
58 * PR 54015: Don't include bkni_multi.h into the bdbg.h. All thread-aware
59 * modules should include explicitly bkni_multi.h
60 *
61 * Hydra_Software_Devel/56   1/31/09 1:55a jrubio
62 * PR51629: add 7336 support
63 *
64 * Hydra_Software_Devel/55   12/3/08 9:25p nickh
65 * PR49691: Enable interrupt support for 7420 for new user mode driver
66 *
67 * Hydra_Software_Devel/54   9/29/08 4:54p rpan
68 * PR47411: Enable interrupt support for 3548/3556 for new user mode
69 * driver.
70 *
71 * Hydra_Software_Devel/53   9/2/08 10:46a erickson
72 * PR46415: added goto so we don't skip BINT_UNLOCK
73 *
74 * Hydra_Software_Devel/52   7/30/08 4:04p vishk
75 * PR45177: uintptr_t is now defined in linux 2.6.18-5.1 header files
76 *
77 * Hydra_Software_Devel/51   4/25/08 10:27a vsilyaev
78 * PR 41896: Added support to reentrant configuration
79 *
80 * Hydra_Software_Devel/PR41896/1   4/17/08 6:49p vsilyaev
81 * PR 41896: Added support to reentrant configuration
82 *
83 * Hydra_Software_Devel/50   11/28/07 11:47a katrep
84 * PR37430: fixed compiler error.
85 *
86 * Hydra_Software_Devel/49   11/28/07 10:58a katrep
87 * PR37430: Extended interrupt interface to 128 bits for 7405,7325,7335
88 *
89 * Hydra_Software_Devel/48   7/30/07 1:45p vsilyaev
90 * PR 33617: Added BINT_P_CreateCallback_Tag symbol for release build
91 *
92 * Hydra_Software_Devel/47   7/24/07 10:41a jgarrett
93 * PR 33363: Revising check for missing interrupt
94 *
95 * Hydra_Software_Devel/46   2/15/07 12:01p erickson
96 * PR26657: optimized BINT_Isr. added BINT_IS_STANDARD to allow standard
97 * interrupts to be processed inside bint.c.
98 *
99 * Hydra_Software_Devel/45   2/9/07 5:23p albertl
100 * PR24115:  Added warning messages for long executing interrupts and
101 * runaway interrupts with adjustable compile time thresholds.
102 *
103 * Hydra_Software_Devel/43   5/25/06 4:13p albertl
104 * PR21392:  BINT_Stats functions now split off into bint_stats.h to solve
105 * BTMR circular dependency.
106 *
107 * Hydra_Software_Devel/42   5/24/06 6:56p albertl
108 * PR21392:  Changed BINT stats tracking to use timers from TMR module.
109 * Added BINT_Stats_Enable and BINT_Stats_Disable.
110 *
111 * Hydra_Software_Devel/41   2/15/06 5:30p vsilyaev
112 * PR 19693: Added support for acquiring interrupt rate
113 *
114 * Hydra_Software_Devel/40   6/30/05 4:36p hongtaoz
115 * PR15921: keep L2 handle's enable count consistent with number of
116 * enabled callbacks;
117 *
118 * Hydra_Software_Devel/39   4/13/05 5:49p albertl
119 * PR10596:  Added parenthesis to conditionals in BINT_Stats_AddBin.
120 *
121 * Hydra_Software_Devel/38   4/13/05 5:16p albertl
122 * PR10596:  Fixed error checking.  Moved bDefaultBins to
123 * BINT_Stats_CallbackStats.
124 *
125 * Hydra_Software_Devel/37   4/11/05 5:30p albertl
126 * PR10596:  Added BINT_Stats_DestroyBins and BINT_Stats_Reset.
127 * Implemented default bin configuration.
128 *
129 * Hydra_Software_Devel/36   4/7/05 4:17p albertl
130 * PR10596:  Changed BINT_STATS_TRACK to BINT_STATS_ENABLE.  Added warning
131 * message for calling BINT_Stats_Get without enabling stats tracking.
132 *
133 * Hydra_Software_Devel/35   4/6/05 2:29p albertl
134 * PR10596:  pReadTimer and pGetElapsedTime function pointers now checked
135 * before executing.  Removed unnecessary #ifdef BINT_STATS_TRACK cases
136 * for better readability.
137 *
138 * Hydra_Software_Devel/34   4/5/05 7:12p albertl
139 * PR10596:  Added new statistics tracking functionality.
140 *
141 * Hydra_Software_Devel/33   9/2/04 1:29p marcusk
142 * PR12445: Check usage count before unmasking an interrupt.
143 *
144 * Hydra_Software_Devel/32   8/31/04 12:17p marcusk
145 * PR12445: Updated to unmask interrupts required to support shared L1
146 * between GFX and Softmodem
147 *
148 * Hydra_Software_Devel/31   8/11/04 1:57p marcusk
149 * PR12255: UPdated to allow BINT_ClearCallback() to always clear
150 * callback.
151 *
152 * Hydra_Software_Devel/30   8/9/04 5:12p marcusk
153 * PR12233: UPdated so that disabling a callback that is already disabled
154 * does nothing.
155 *
156 * Hydra_Software_Devel/29   5/24/04 3:01p marcusk
157 * PR10666: Mergedown from B0
158 *
159 * Hydra_Software_Devel/Refsw_Devel_7038_B0/2   4/19/04 11:52a marcusk
160 * PR10666: No longer clear previous interrupts when enabling a callback.
161 *
162 * Hydra_Software_Devel/28   4/16/04 5:12p marcusk
163 * PR10666: Partially merged functionality from B0 specific branch.  Full
164 * merge will occur once B0 is released.
165 *
166 * Hydra_Software_Devel/Refsw_Devel_7038_B0/2   4/16/04 4:55p marcusk
167 * PR10666: Do not clear interrupts when enabling and added
168 * BINT_ClearCallback() routines.
169 *
170 * Hydra_Software_Devel/27   4/2/04 12:12p marcusk
171 * PR10462: Removed while loop when processing interrupts.
172 *
173 * Hydra_Software_Devel/26   3/5/04 10:41a marcusk
174 * PR9994: Updated to check both interrupt register and offset when
175 * creating a callback.
176 *
177 * Hydra_Software_Devel/25   2/3/04 8:38p vsilyaev
178 * PR 9606: Clear all managed L2 interrupts.
179 *
180 * Hydra_Software_Devel/24   1/9/04 12:00p marcusk
181 * PR9241: Updated to insert on tail rather than on head.
182 *
183 * Hydra_Software_Devel/23   1/6/04 9:45a marcusk
184 * PR9117: Properly look up interrupt ignore mask during isr() routine.
185 *
186 * Hydra_Software_Devel/22   1/5/04 4:26p marcusk
187 * PR9117: Updated to support PI provided L2 interrupt handler (for
188 * transport message and overflow interrupts).  Updated documentation.
189 *
190 * Hydra_Software_Devel/21   12/30/03 12:02p dlwin
191 * PR 9117: Fixed a problem with creating Callback for UPG interrupts.
192 *
193 * Hydra_Software_Devel/20   12/29/03 4:16p marcusk
194 * PR9117: Updated with changes required to support interrupt ids rather
195 * than strings.
196 *
197 * Hydra_Software_Devel/19   12/23/03 11:13a marcusk
198 * PR8985: No longer assert since this causes problems with the UPG
199 * interrupts.
200 *
201 * Hydra_Software_Devel/18   12/18/03 2:55p marcusk
202 * PR8985: Updated to assert if somebody is messing with the interrupt
203 * mask.
204 *
205 * Hydra_Software_Devel/17   12/18/03 2:37p marcusk
206 * PR8985: Removed bint_priv.h since it is no longer needed.
207 *
208 * Hydra_Software_Devel/16   12/18/03 2:08p marcusk
209 * PR8985: Refactored to use single ISR() routine. Removed reserved names.
210 * Placed all platform specific defines in bint_plat.h
211 *
212 * Hydra_Software_Devel/15   12/1/03 4:51p jasonh
213 * Added interrupt clear when callback is enabled.
214 *
215 * Hydra_Software_Devel/14   11/24/03 3:27p marcusk
216 * PR 8719: Clear and mask all managed interrupts at open time.
217 *
218 * Hydra_Software_Devel/13   9/16/03 10:30a marcusk
219 * Updated to comply with DocJet requirements. Fixes for PR8055.
220 *
221 * Hydra_Software_Devel/12   8/26/03 10:43a marcusk
222 * Removed default settings (they are not valid)
223 *
224 * Hydra_Software_Devel/11   8/22/03 3:00p erickson
225 * added BINT_GetDefaultSettings
226 *
227 * Hydra_Software_Devel/10   6/18/03 3:26p dlwin
228 * Added support to allow for more general implementation of Interrupt
229 * manager.
230 *
231 * Hydra_Software_Devel/9   4/2/03 10:38a marcusk
232 * Updated to support flag to specify if the interrupt can be triggered by
233 * the CPU.
234 *
235 * Hydra_Software_Devel/7   3/31/03 4:07p marcusk
236 * Detect interrupts that get enabled outside the interrupt interface
237 * module.
238 *
239 * Hydra_Software_Devel/6   3/31/03 8:57a marcusk
240 * Updated out of memory error returns.
241 *
242 * Hydra_Software_Devel/5   3/31/03 8:45a marcusk
243 * Fixed a small bug when all 32 bits of an L2 interrupt register is used.
244 *
245 * Hydra_Software_Devel/4   3/28/03 10:22a marcusk
246 * Fixed many bugs. Updated to trace when returning errors. Added support
247 * for unit test environment (without hardware).
248 *
249 * Hydra_Software_Devel/3   3/25/03 4:08p marcusk
250 * Updated some comments.
251 *
252 * Hydra_Software_Devel/2   3/21/03 6:29p marcusk
253 * Initial version (that compiles).
254 *
255 * Hydra_Software_Devel/1   3/21/03 5:51p marcusk
256 * In development.
257 *
258 ***************************************************************************/
259#include "bstd.h"
260#include "bint_plat.h"  /* include other interrupt interface headers */
261#include "bint_stats.h"
262#include "bkni.h"
263#include "bkni_multi.h"
264#include "blst_squeue.h"
265#include "bchp.h"
266#include "btmr.h"
267
268BDBG_MODULE(int);
269
270#define BINT_REENTRANT  1
271#define BINT_NON_REENTRANT      0
272
273#ifndef BINT_REENTRANT_CONFIG
274#define BINT_REENTRANT_CONFIG   BINT_REENTRANT
275#endif
276
277
278#define BINT_P_ComputeIndex( L1Shift, Hash ) (Hash[L1Shift])
279
280/* Dummy typedef to alloc circular dependencies between structures */
281typedef struct BINT_P_Callback *BINT_P_CallbackHandle;
282
283/*
284Summary:
285This structure defines the head element for creating
286a linked list.
287*/
288typedef struct BINT_P_cblHead BINT_P_cblHead;
289BLST_SQ_HEAD(BINT_P_cblHead, BINT_P_Callback);
290
291/*
292Summary:
293This strcuture defines a single element in the
294hash table used in the InterruptInterface.
295
296Description:
297One and only instance of this structure will exist for each L2 interrupt bit.
298*/
299typedef struct BINT_P_L2Int
300{
301    BLST_SQ_ENTRY(BINT_P_L2Int) link; /* doubly-linked list support */
302    BINT_Handle intHandle; /* handle to the main InterruptInterface */
303    int intMapIndex; /* Index into the interrupt map */
304    BINT_Id intId; /* Interrupt ID (contains L2 base and L2 shift) */
305    int enableCount; /* Number of callbacks that are enabled for this interrupt */
306    BINT_P_cblHead callbackList; /* list of callbacks associated with this interrupt */
307    unsigned count;     /* number of times when L2 interrupt was fired */
308} BINT_P_L2Int, *BINT_P_L2Handle;
309
310/*
311Summary:
312This structure defines the head element for creating
313a linked list.
314*/
315typedef struct BINT_P_L2Head BINT_P_L2Head;
316BLST_SQ_HEAD(BINT_P_L2Head, BINT_P_L2Int);
317
318/*
319Summary:
320This structure defines the a callback handle/context.  It includes
321doubly linked list support.
322
323Description:
324One of these structures exists for each callback created.  There
325may be multiple callbacks assigned for a single interrupt.
326*/
327typedef struct BINT_P_Callback
328{
329    BLST_SQ_ENTRY(BINT_P_Callback) link; /* doubly-linked list support */
330    BLST_SQ_ENTRY(BINT_P_Callback) allCbLink; /* links all callbacks created for traversing */
331    BINT_P_L2Handle L2Handle; /* L2 handle for this interrupt */
332    BINT_CallbackFunc func; /* function to call when the interrupt triggers */
333    void * pParm1; /* returned when callback is executed */
334    int parm2; /* returned when callback is executed */
335    bool enabled; /* false: callback will never be executed, true: callback will be executed when interrupt triggers */
336
337    uint32_t ulStartTime;
338
339    unsigned count; /* number of times when callback interrupt was fired */
340    const char *callbackName; /* callback name saved for the debug builds */
341
342    BINT_Stats_CallbackStats StatInfo;
343} BINT_P_Callback;
344
345BDBG_OBJECT_ID(BINT);
346
347typedef struct BINT_P_Context
348{
349    BDBG_OBJECT(BINT)
350#if BINT_REENTRANT_CONFIG==BINT_REENTRANT
351    BKNI_MutexHandle lock;
352#define BINT_LOCK(h) BKNI_AcquireMutex((h)->lock)
353#define BINT_UNLOCK(h) BKNI_ReleaseMutex((h)->lock)
354#else
355#define BINT_LOCK(h)
356#define BINT_UNLOCK(h)
357#endif
358    BINT_P_L2Head IntArray[BINT_P_L1_SIZE]; /* Array of L2 interrupt lists (one list per L1 interrupt). NULL if not used. */
359    const BINT_P_IntMap *pIntMap; /* ptr to the interrupt map, REQUIRED */
360    int callbackCount; /* Number of callbacks installed in InterruptInterface */
361    unsigned numInts; /* Number of L2 interrupts managed by this instance of the InterruptInterface */
362    BREG_Handle regHandle; /* regHandle for accessing interrupt registers */
363    BINT_SetIntFunc pSetInt; /* ptr to Set Interrupt, NULL if none */
364    BINT_ClearIntFunc pClearInt; /* ptr to Clear Interrupt, NULL if none */
365    BINT_SetMaskFunc pSetMask; /* ptr to Set Interrupt Mask, REQUIRED */
366    BINT_ClearMaskFunc pClearMask; /* ptr to Clear Interrupt Mask, REQUIRED */
367    BINT_ReadStatusFunc pReadStatus; /* ptr to Read Status, REQUIRED */
368    BINT_ReadMaskFunc pReadMask; /* ptr to Read Mask, REQUIRED */
369    BINT_P_cblHead allCbList; /* list of all callbacks registered */
370    BINT_Settings settings; /* BINT_Settings */
371    BTMR_TimerHandle hTimer; /* timer used for stats tracking */
372    bool bStatsEnable; /* enables stats tracking */
373} BINT_P_Context;
374
375/* Default bin configuration */
376static const BINT_Stats_CallbackBin g_aDefaultBins[] =
377{
378    /* range min, range max, bin hit count */
379    {  0,         50,        0 },
380    {  51,        100,       0 },
381    {  101,       200,       0 },
382    {  201,       500,       0 },
383    {  501,       1000,      0 },
384    {  1000,      2500,      0 },
385    {  2501,      10000,     0 },
386    {  10001,     50000,     0 },
387    {  50001,     100000,    0 },
388    {  100001,    500000,    0 },
389};
390
391#define BINT_P_STATS_DEFAULT_BINS_NUM \
392    (sizeof (g_aDefaultBins) / sizeof (BINT_Stats_CallbackBin))
393
394BERR_Code BINT_P_Stats_ComputeStats( BINT_CallbackHandle cbHandle, uint32_t ulStart, uint32_t ulEnd );
395uint32_t BINT_P_GetElapsedTime( uint32_t ulTimerStart, uint32_t ulTimerEnd );
396
397BERR_Code BINT_Open( BINT_Handle *pHandle, BREG_Handle regHandle, const BINT_Settings *pDefSettings )
398{
399    int i;
400    BERR_Code rc = BERR_SUCCESS;
401
402    *pHandle = (BINT_Handle) BKNI_Malloc( sizeof( BINT_P_Context ) );
403    if( *pHandle == NULL )
404    {
405        rc = BERR_TRACE(BERR_OUT_OF_SYSTEM_MEMORY);
406        goto error;
407    }
408
409    BKNI_Memset( *pHandle, 0, sizeof( BINT_P_Context ) );
410    BDBG_OBJECT_SET(*pHandle, BINT);
411
412#if BINT_REENTRANT_CONFIG==BINT_REENTRANT
413    rc = BKNI_CreateMutex(&(*pHandle)->lock);
414    if(rc!=BERR_SUCCESS)
415    {
416        rc=BERR_TRACE(rc);
417        goto error;
418    }
419#endif
420
421    (*pHandle)->numInts = 0;
422    (*pHandle)->callbackCount = 0;
423    (*pHandle)->pIntMap = pDefSettings->pIntMap;
424    (*pHandle)->pSetInt = pDefSettings->pSetInt;
425    (*pHandle)->pClearInt = pDefSettings->pClearInt;
426    (*pHandle)->pSetMask = pDefSettings->pSetMask;
427    (*pHandle)->pClearMask = pDefSettings->pClearMask;
428    (*pHandle)->pReadStatus = pDefSettings->pReadStatus;
429    (*pHandle)->pReadMask = pDefSettings->pReadMask;
430    (*pHandle)->settings = *pDefSettings;
431
432    (*pHandle)->hTimer = NULL;
433    (*pHandle)->bStatsEnable = false;
434
435    (*pHandle)->regHandle = regHandle;
436
437    if( (*pHandle)->pReadMask == NULL ||
438        (*pHandle)->pReadStatus == NULL ||
439        (*pHandle)->pSetMask == NULL ||
440        (*pHandle)->pClearMask == NULL )
441    {
442        BDBG_ERR(("Invalid function points passed into BINT_Open()"));
443        rc = BERR_TRACE(BERR_INVALID_PARAMETER);
444        BDBG_ASSERT(0);
445        goto error;
446    }
447
448    for( i=0; i<BINT_P_L1_SIZE; i++ )
449    {
450        BLST_SQ_INIT( &((*pHandle)->IntArray[i]) );
451    }
452
453    /* If your platform has BCHP_PWR-based power management, then the SW layer that is calling BINT_Open
454       must also acquire/release power around BINT_Open. Otherwise, you'll likely hit GISB errors below,
455       when registers are accessed without power to their respective 108M clocks.
456
457       See /rockford/appframework/src/common/appframework/framework.c or nexus_core.c for examples
458       on how to do this */
459       
460#ifndef BINT_OPEN_BYPASS_L2INIT
461    /* Clear all L2 interrupts */
462    for( i=0;;i++) {
463        unsigned bit;
464        const BINT_P_IntMap *L2Register = &(*pHandle)->pIntMap[i];
465        if (L2Register->L1Shift<0) {
466            break;
467        }
468        for(bit=0; bit<32; bit++) {
469            if ( (L2Register->L2InvalidMask&(1<<bit))==0) {
470                (*pHandle)->pSetMask((*pHandle)->regHandle, L2Register->L2RegOffset, bit);
471            }
472        }
473    }
474#endif
475
476    return rc;
477
478error:
479
480    if( (*pHandle) != NULL )
481    {
482#if BINT_REENTRANT_CONFIG==BINT_REENTRANT
483        if((*pHandle)->lock)
484        {
485            BKNI_DestroyMutex((*pHandle)->lock);
486        }
487#endif
488        BKNI_Free( (*pHandle) );
489    }
490
491    return rc;
492}
493
494BERR_Code BINT_Close( BINT_Handle intHandle )
495{
496    int L1Shift;
497    BINT_P_L2Handle L2Handle;
498    BINT_CallbackHandle cbHandle;
499
500    BDBG_OBJECT_ASSERT(intHandle, BINT);
501    BDBG_ASSERT ( intHandle->bStatsEnable == false );
502
503    for(L1Shift=0; L1Shift<BINT_P_L1_SIZE; L1Shift++ )
504    {
505        for(L2Handle=BLST_SQ_FIRST(&(intHandle->IntArray[L1Shift])); L2Handle ; L2Handle=BLST_SQ_FIRST(&(intHandle->IntArray[L1Shift])))
506        {
507            for(cbHandle=BLST_SQ_FIRST(&(L2Handle->callbackList)); cbHandle ; cbHandle=BLST_SQ_FIRST(&(L2Handle->callbackList)))
508            {
509                BINT_DestroyCallback(cbHandle);
510            }
511
512            BKNI_EnterCriticalSection();
513            BLST_SQ_REMOVE_HEAD(&(intHandle->IntArray[L1Shift]), link);
514            BKNI_LeaveCriticalSection();
515            BKNI_Free( L2Handle );
516        }
517    }
518
519    if( intHandle->callbackCount != 0 )
520        return BERR_UNKNOWN;
521
522#if BINT_REENTRANT_CONFIG==BINT_REENTRANT
523    BKNI_DestroyMutex(intHandle->lock);
524#endif
525    BDBG_OBJECT_DESTROY(intHandle, BINT);
526    BKNI_Free( intHandle );
527
528    return BERR_SUCCESS;
529}
530
531/**
532BINT_Isr is the main inner loop of the entire refsw architecture.
533Optimization of every line of code matters greatly.
534**/
535void BINT_Isr( BINT_Handle intHandle, int L1Shift )
536{
537    BINT_P_Callback *cbHandle;
538    uint32_t intStatus = 0;
539    BINT_P_L2Handle L2Handle;
540    /* Optimization: Dereference this pointers once */
541    BINT_ClearIntFunc pClearInt = intHandle->pClearInt;
542    BINT_ClearMaskFunc pClearMask = intHandle->pClearMask;
543    BINT_ReadStatusFunc pReadStatus = intHandle->pReadStatus;
544    BREG_Handle regHandle = intHandle->regHandle;
545#ifdef BINT_STATS_ENABLE
546    bool bStatsEnable = intHandle->bStatsEnable;
547#endif
548    /* Optimization: The IntArray is sorted by L2Reg. Therefore we can remember the value of the
549    previous status read. If we have the same L2Reg, avoid the extra read. */
550    uint32_t prevStatusReg = 0;
551
552#if 0
553/* for performance, this ASSERT is compiled out. you can temporarily enable for debug. */
554    BDBG_OBJECT_ASSERT(intHandle, BINT);
555#endif
556
557    for( L2Handle=BLST_SQ_FIRST(&(intHandle->IntArray[L1Shift])) ; L2Handle ; L2Handle=BLST_SQ_NEXT(L2Handle, link))
558    {
559        /* Optimization: Dereference once */
560        int intId = L2Handle->intId;
561        uint32_t L2BaseRegister = BCHP_INT_ID_GET_REG( intId );
562        uint32_t L2Shift = BCHP_INT_ID_GET_SHIFT( intId );
563        const BINT_P_IntMap *L2Register = &intHandle->pIntMap[L2Handle->intMapIndex];
564
565        /* DumpInfo accounting */
566        L2Handle->count++;
567
568/* BINT_IS_STANDARD assumes these offsets from L1BaseRegister are correct. */
569#define BINT_P_STD_STATUS       0x00
570#define BINT_P_STD_CLEAR        0x08
571#define BINT_P_STD_MASK_CLEAR   0x14
572        /* Standard registers can be handled internal to bint.c which results in dramatic performance improvement.
573        Each chip must set BINT_IS_STANDARD as appropriate. */
574        if (L2Register->L1Shift & BINT_IS_STANDARD)
575        {
576            if (L2BaseRegister != prevStatusReg) {
577                intStatus = BREG_Read32_isr(regHandle, L2BaseRegister); /* read status */
578                prevStatusReg = L2BaseRegister;
579            }
580
581            /* find any interrupts that are triggered and enabled */
582            if( (intStatus & (1ul<<L2Shift)) && L2Handle->enableCount )
583            {
584                BREG_Write32_isr(regHandle, L2BaseRegister + BINT_P_STD_CLEAR, 1<<L2Shift); /* clear status */
585
586                /* Call all callbacks that are enabled */
587                for(cbHandle=BLST_SQ_FIRST(&(L2Handle->callbackList)); cbHandle ; cbHandle=BLST_SQ_NEXT(cbHandle, link))
588                {
589                    if( cbHandle->enabled )
590                    {
591                        (*cbHandle->func)( cbHandle->pParm1, cbHandle->parm2 );
592                        cbHandle->count++;
593                    }
594                }
595                if( L2Handle->enableCount )
596                {
597                    /* Shared L1 interrupts require that the L2 be masked in bcmdriver.ko, so BINT unmasks
598                    here to reverse that. For unshared L1's, this is harmless. */
599                    BREG_Write32_isr(regHandle, L2BaseRegister + BINT_P_STD_MASK_CLEAR, 1<<L2Shift);
600                }
601            }
602        }
603        else {
604            if( L2Register->L2InvalidMask==BINT_DONT_PROCESS_L2 )
605            {
606                /*
607                If the L2InvalidMask is BINT_DONT_PROCESS_L2 that means that the interrupt interface
608                does not process the L2 interrupts for this L1 shift.  Instead a separate L2
609                isr routine should be installed as the callback for the specified L1
610                shift that will handle this interrupt.
611                */
612                cbHandle=BLST_SQ_FIRST(&(L2Handle->callbackList));
613                (*cbHandle->func)( cbHandle->pParm1, cbHandle->parm2 );
614            }
615            else
616            {
617                /*
618                Read the status and mask each time we obtain a new L2Handle.  This is to handle L1 interrupts
619                that map to multiple L2 interrupt registers (the L2 register offset is stored in the L2 handle).
620                */
621#if 0
622                /* PR 27936 - this is optimal code, but is causes problems with I2C (aka BSC). This is likely a bug
623                in the I2C PI. */
624                if (L2BaseRegister != prevStatusReg) {
625                    intStatus = (*pReadStatus)( regHandle, L2BaseRegister);
626                    prevStatusReg = L2BaseRegister;
627                }
628#else
629                intStatus = (*pReadStatus)( regHandle, L2BaseRegister);
630#endif
631
632                /* find any interrupts that are triggered and enabled */
633                if( (intStatus & (1ul<<L2Shift)) && L2Handle->enableCount )
634                {
635                    /* Since L2 interrupts are edge triggered they must be cleared before processing!! */
636                    if(pClearInt)
637                    {
638                        (*pClearInt)( regHandle, L2BaseRegister, L2Shift);
639                    }
640
641                    /* Call all callbacks that are enabled */
642                    for(cbHandle=BLST_SQ_FIRST(&(L2Handle->callbackList)); cbHandle ; cbHandle=BLST_SQ_NEXT(cbHandle, link))
643                    {
644                        if( cbHandle->enabled )
645                        {
646#ifdef BINT_STATS_ENABLE
647                            uint32_t ulStart, ulEnd = 0;
648                            BERR_Code rc;
649
650                            if (bStatsEnable)
651                            {
652                                rc = BTMR_ReadTimer_isr(intHandle->hTimer, &ulStart);
653                                if (rc != BERR_SUCCESS)
654                                {
655                                    BDBG_WRN(("Error reading timer for statistics."));
656                                }
657                            }
658
659                            (*cbHandle->func)( cbHandle->pParm1, cbHandle->parm2 );
660
661                            if (bStatsEnable)
662                            {
663                                rc = BTMR_ReadTimer_isr(intHandle->hTimer, &ulEnd);
664                                if (rc != BERR_SUCCESS)
665                                {
666                                    BDBG_WRN(("Error reading timer for statistics."));
667                                }
668
669                                BINT_P_Stats_ComputeStats( cbHandle, ulStart, ulEnd );
670                            }
671#else
672                            (*cbHandle->func)( cbHandle->pParm1, cbHandle->parm2 );
673#endif /* BINT_STATS_ENABLE */
674                            cbHandle->count++;
675                        }
676                    }
677
678                    if( L2Handle->enableCount )
679                    {
680                        /* Shared L1 interrupts require that the L2 be masked in bcmdriver.ko, so BINT unmasks
681                        here to reverse that. For unshared L1's, this is harmless. */
682                        (*pClearMask)( regHandle, L2BaseRegister, L2Shift);
683                    }
684                }
685            }
686        }
687    }
688}
689
690#if BDBG_DEBUG_BUILD
691#undef BINT_CreateCallback
692BERR_Code BINT_CreateCallback( BINT_CallbackHandle *pCbHandle, BINT_Handle intHandle, BINT_Id intId, BINT_CallbackFunc func, void * pParm1, int parm2 )
693{
694    BDBG_WRN(("BINT_CallbackFunc shall be never called in the debug builds"));
695    return BINT_P_CreateCallback_Tag(pCbHandle, intHandle, intId, func, pParm1, parm2, "");
696}
697BERR_Code BINT_P_CreateCallback_Tag( BINT_CallbackHandle *pCbHandle, BINT_Handle intHandle, BINT_Id intId, BINT_CallbackFunc func, void * pParm1, int parm2, const char *callbackName)
698#else
699BERR_Code BINT_P_CreateCallback_Tag( BINT_CallbackHandle *pCbHandle, BINT_Handle intHandle, BINT_Id intId, BINT_CallbackFunc func, void * pParm1, int parm2)
700{
701    return BINT_CreateCallback(pCbHandle, intHandle, intId, func, pParm1, parm2);
702}
703BERR_Code BINT_CreateCallback( BINT_CallbackHandle *pCbHandle, BINT_Handle intHandle, BINT_Id intId, BINT_CallbackFunc func, void * pParm1, int parm2 )
704#endif
705{
706    uint32_t L2Reg = BCHP_INT_ID_GET_REG(intId);
707    uint32_t L2Shift = BCHP_INT_ID_GET_SHIFT(intId);
708    int intMapIndex, L1Shift;
709    BINT_P_L2Handle L2Handle;
710    BINT_P_L2Handle SameL2RegHandle = NULL;
711    BERR_Code rc;
712
713    BDBG_OBJECT_ASSERT(intHandle, BINT);
714    BINT_LOCK(intHandle);
715
716    /* We must find the L1 interrupt associated with this L2 interrupt by looking through our interrupt map */
717    for( intMapIndex=0; intHandle->pIntMap[intMapIndex].L1Shift != -1; intMapIndex++ )
718    {
719        /*
720        We must find the matching L2 register offset and ensure that the specified L2 interrupt is actually
721        handled by the specified L1->L2 mapping.  This is because some wacky L2 interrupt registers actually map to
722        multiple L1 interrupts (i.e. 8 bits of the L2 register map to L1=X, while the other bits map to L1=Y).
723        This also properly handles multiple L2 interrupt registers that are mapped to a single L1 bit.
724
725        Also, if the L2InvalidMask is BINT_DONT_PROCESS_L2 for this register it means that the interrupt interface
726        does not handle the L2 interrupts.  Rather it should just create the first callback associated with that
727        L1 interrupt shift.
728        */
729        if( (intHandle->pIntMap[intMapIndex].L2RegOffset == L2Reg) &&
730            ( !((1ul<<L2Shift)&intHandle->pIntMap[intMapIndex].L2InvalidMask) || (intHandle->pIntMap[intMapIndex].L2InvalidMask==BINT_DONT_PROCESS_L2) ))
731        {
732            break;
733        }
734    }
735
736    L1Shift = intHandle->pIntMap[intMapIndex].L1Shift;
737    if( L1Shift == -1 )
738    {
739        rc = BERR_TRACE(BERR_INVALID_PARAMETER);
740        goto done;
741    }
742
743    L1Shift &= ~BINT_IS_STANDARD;
744
745    /* Determine if we need to allocate a new L2 interrupt context */
746    for(L2Handle=BLST_SQ_FIRST(&(intHandle->IntArray[L1Shift])); L2Handle ; L2Handle=BLST_SQ_NEXT(L2Handle, link))
747    {
748        if( BCHP_INT_ID_GET_REG( L2Handle->intId ) == L2Reg && BCHP_INT_ID_GET_SHIFT( L2Handle->intId ) == L2Shift )
749        {
750            break;
751        }
752        else if( BCHP_INT_ID_GET_REG( L2Handle->intId ) == L2Reg )
753        {
754            /* Optimization: Remember if we share the same L2, but not the same L2Shift.
755            This makes the IntArray sorted by L2 register. This allows us to avoid extra BREG_Read32 calls in BINT_Isr. */
756            SameL2RegHandle = L2Handle;
757        }
758    }
759    if( L2Handle == NULL )
760    {
761        /* We need to create a new L2 element to manage this interrupt bit */
762        L2Handle = (BINT_P_L2Int *) BKNI_Malloc( sizeof(BINT_P_L2Int) );
763        if( L2Handle == NULL )
764        {
765            rc = BERR_TRACE(BERR_INVALID_PARAMETER);
766            goto done;
767        }
768        BLST_SQ_INIT( &(L2Handle->callbackList) );
769        L2Handle->enableCount = 0;
770        L2Handle->intId = intId;
771        L2Handle->intHandle = intHandle;
772        L2Handle->intMapIndex = intMapIndex;
773        L2Handle->count = 0;
774
775        BKNI_EnterCriticalSection();
776        if (SameL2RegHandle) {
777            BLST_SQ_INSERT_AFTER(&(intHandle->IntArray[L1Shift]), SameL2RegHandle, L2Handle, link);
778        }
779        else {
780            BLST_SQ_INSERT_TAIL(&(intHandle->IntArray[L1Shift]), L2Handle, link);
781        }
782        BKNI_LeaveCriticalSection();
783
784        intHandle->numInts++;
785
786        /* clear previous status */
787        if( intHandle->pClearInt != NULL )
788        {
789            intHandle->pClearInt( intHandle->regHandle, BCHP_INT_ID_GET_REG(intId), BCHP_INT_ID_GET_SHIFT(intId) );
790        }
791    }
792
793    *pCbHandle = (BINT_CallbackHandle) BKNI_Malloc( sizeof(BINT_P_Callback) );
794    if( *pCbHandle == NULL )
795    {
796        rc = BERR_TRACE(BERR_OUT_OF_SYSTEM_MEMORY);
797        goto done;
798    }
799
800    BKNI_Memset( *pCbHandle, 0, sizeof(BINT_P_Callback) );
801
802    (*pCbHandle)->func = func;
803    (*pCbHandle)->pParm1 = pParm1;
804    (*pCbHandle)->parm2 = parm2;
805    (*pCbHandle)->L2Handle = L2Handle;
806
807    (*pCbHandle)->StatInfo.ulTimeMin = UINT32_MAX;
808    (*pCbHandle)->StatInfo.ulTimeMax = 0;
809    (*pCbHandle)->StatInfo.ulTimeAvg = 0;
810    (*pCbHandle)->StatInfo.ulCbHitCount = 0;
811    (*pCbHandle)->StatInfo.ulTimeStampStartIdx = 0;
812
813    BKNI_Memset((*pCbHandle)->StatInfo.aulTimeStamp, 0, sizeof(uint32_t) * BINT_P_STATS_RECENT_CB_HIT_COUNT);
814
815    /* set up default bins */
816    (*pCbHandle)->StatInfo.ulActiveBins = BINT_P_STATS_DEFAULT_BINS_NUM;
817    BKNI_Memcpy((*pCbHandle)->StatInfo.aBinInfo, g_aDefaultBins,
818                sizeof(g_aDefaultBins));
819
820    (*pCbHandle)->StatInfo.bDefaultBins = true;
821
822    BKNI_EnterCriticalSection();
823    BLST_SQ_INSERT_TAIL(&(L2Handle->callbackList), *pCbHandle, link);
824    BLST_SQ_INSERT_TAIL(&(intHandle->allCbList), *pCbHandle, allCbLink);
825    BKNI_LeaveCriticalSection();
826
827    (*pCbHandle)->count = 0;
828#if BDBG_DEBUG_BUILD
829    (*pCbHandle)->callbackName = callbackName;
830#else
831    (*pCbHandle)->callbackName = NULL;
832#endif
833
834    intHandle->callbackCount++;
835    rc = BERR_SUCCESS;
836
837done:
838    BINT_UNLOCK(intHandle);
839    return rc;
840}
841
842BERR_Code BINT_DestroyCallback( BINT_CallbackHandle cbHandle )
843{
844    BINT_P_Context *intHandle;
845
846    BDBG_ASSERT( cbHandle != NULL );
847
848    intHandle = cbHandle->L2Handle->intHandle;
849    BINT_LOCK(intHandle);
850
851    if( cbHandle->enabled == true )
852    {
853        BINT_DisableCallback(cbHandle );
854    }
855
856    BKNI_EnterCriticalSection();
857    BLST_SQ_REMOVE(&(cbHandle->L2Handle->callbackList), cbHandle, BINT_P_Callback, link);
858    BLST_SQ_REMOVE(&(intHandle->allCbList), cbHandle, BINT_P_Callback, allCbLink);
859    BKNI_LeaveCriticalSection();
860
861
862    BKNI_Free( cbHandle );
863    intHandle->callbackCount--;
864    BINT_UNLOCK(intHandle);
865
866    return BERR_SUCCESS;
867}
868
869BERR_Code BINT_EnableCallback( BINT_CallbackHandle cbHandle )
870{
871    BERR_Code rc;
872
873    BKNI_EnterCriticalSection();
874    rc = BINT_EnableCallback_isr( cbHandle );
875    BKNI_LeaveCriticalSection();
876
877    return rc;
878}
879
880BERR_Code BINT_EnableCallback_isr( BINT_CallbackHandle cbHandle )
881{
882    BINT_P_Context *intHandle;
883
884    BDBG_ASSERT( cbHandle != NULL );
885
886    /* If enabled, we are already done... */
887    if( cbHandle->enabled )
888    {
889        return BERR_SUCCESS;
890    }
891
892    intHandle = cbHandle->L2Handle->intHandle;
893
894    /* Flag callback as enabled so that we execute it if we get an interrupt immediately after it is unmasked */
895    cbHandle->enabled = true;
896
897    cbHandle->L2Handle->enableCount++;
898    if( cbHandle->L2Handle->enableCount == 1 )
899    {
900        if( intHandle->pClearMask != NULL )
901        {
902            intHandle->pClearMask( intHandle->regHandle, BCHP_INT_ID_GET_REG(cbHandle->L2Handle->intId), BCHP_INT_ID_GET_SHIFT(cbHandle->L2Handle->intId) );
903        }
904    }
905
906    return BERR_SUCCESS;
907}
908
909BERR_Code BINT_DisableCallback( BINT_CallbackHandle cbHandle )
910{
911    BERR_Code rc;
912
913    BKNI_EnterCriticalSection();
914    rc = BINT_DisableCallback_isr( cbHandle );
915    BKNI_LeaveCriticalSection();
916
917    return rc;
918}
919
920BERR_Code BINT_DisableCallback_isr( BINT_CallbackHandle cbHandle )
921{
922    BINT_P_Context *intHandle;
923
924    BDBG_ASSERT( cbHandle != NULL );
925
926    /* If not enabled, we are already done... */
927    if( cbHandle->enabled == false )
928    {
929        return BERR_SUCCESS;
930    }
931
932    intHandle = cbHandle->L2Handle->intHandle;
933
934    cbHandle->L2Handle->enableCount--;
935    if( cbHandle->L2Handle->enableCount == 0 )
936    {
937        if( intHandle->pSetMask != NULL )
938        {
939            intHandle->pSetMask( intHandle->regHandle, BCHP_INT_ID_GET_REG(cbHandle->L2Handle->intId), BCHP_INT_ID_GET_SHIFT(cbHandle->L2Handle->intId) );
940        }
941    }
942
943    /* Flag callback as disabled only after it is masked so that we can execute if we get an interrupt */
944    cbHandle->enabled = false;
945
946    return BERR_SUCCESS;
947}
948
949BERR_Code BINT_ClearCallback( BINT_CallbackHandle cbHandle )
950{
951    BERR_Code rc;
952
953    BKNI_EnterCriticalSection();
954    rc = BINT_ClearCallback_isr( cbHandle );
955    BKNI_LeaveCriticalSection();
956
957    return rc;
958}
959
960BERR_Code BINT_ClearCallback_isr( BINT_CallbackHandle cbHandle )
961{
962    BERR_Code rc = BERR_SUCCESS;
963    BINT_P_Context *intHandle;
964
965    BDBG_ASSERT( cbHandle != NULL );
966
967    intHandle = cbHandle->L2Handle->intHandle;
968
969    if( intHandle->pClearInt != NULL )
970    {
971        intHandle->pClearInt( intHandle->regHandle, BCHP_INT_ID_GET_REG(cbHandle->L2Handle->intId), BCHP_INT_ID_GET_SHIFT(cbHandle->L2Handle->intId) );
972    }
973
974    return rc;
975}
976
977BERR_Code BINT_TriggerInterruptByHandle( BINT_CallbackHandle cbHandle )
978{
979    return BINT_TriggerInterruptByHandle_isr( cbHandle );
980}
981
982BERR_Code BINT_TriggerInterruptByHandle_isr( BINT_CallbackHandle cbHandle )
983{
984    BINT_P_Context *intHandle;
985    BDBG_ASSERT( cbHandle != NULL );
986
987    intHandle = cbHandle->L2Handle->intHandle;
988
989    if( intHandle->pSetInt == NULL )
990    {
991        return BERR_TRACE(BERR_INVALID_PARAMETER);
992    }
993    else
994    {
995        intHandle->pSetInt( intHandle->regHandle, BCHP_INT_ID_GET_REG(cbHandle->L2Handle->intId), BCHP_INT_ID_GET_SHIFT(cbHandle->L2Handle->intId) );
996    }
997    return BERR_SUCCESS;
998}
999
1000#if (BINT_NEW_INT_MODEL)
1001void BINT_GetL1BitMask(BINT_Handle intHandle, uint32_t   BitMask[BINT_MAX_INTC_SIZE])
1002{
1003    int i;
1004
1005    BDBG_OBJECT_ASSERT(intHandle, BINT);
1006
1007    for(i=0;i<BINT_MAX_INTC_SIZE;i++)
1008    {
1009        BitMask[i]=0;
1010    }
1011
1012    for( i=0; intHandle->pIntMap[i].L1Shift != -1; i++ )
1013    {
1014        int L1Shift = intHandle->pIntMap[i].L1Shift&~BINT_IS_STANDARD;
1015        if(L1Shift >= 96)
1016        {
1017            BitMask[3] |= 1ul<<(L1Shift-96);
1018        }
1019        else if(L1Shift >= 64 && L1Shift < 96)
1020        {
1021            BitMask[2] |= 1ul<<(L1Shift-64);
1022        }
1023        else if( L1Shift >= 32 && L1Shift < 64 )
1024        {
1025            BitMask[1] |= 1ul<<(L1Shift-32);
1026        }
1027        else
1028        {
1029            BitMask[0] |= 1ul<<L1Shift;
1030        }
1031    }
1032}
1033#else
1034void BINT_GetL1BitMask( BINT_Handle intHandle, uint32_t *pBitMaskLo, uint32_t *pBitMaskHi )
1035{
1036    int i;
1037
1038    BDBG_OBJECT_ASSERT(intHandle, BINT);
1039
1040    *pBitMaskLo = 0;
1041    *pBitMaskHi = 0;
1042
1043    for( i=0; intHandle->pIntMap[i].L1Shift != -1; i++ )
1044    {
1045        int L1Shift = intHandle->pIntMap[i].L1Shift&~BINT_IS_STANDARD;
1046        if( L1Shift >= 32 )
1047        {
1048            *pBitMaskHi |= 1ul<<(L1Shift-32);
1049        }
1050        else
1051        {
1052            *pBitMaskLo |= 1ul<<L1Shift;
1053        }
1054    }
1055}
1056#endif
1057
1058BINT_CallbackHandle BINT_GetCallbackFirst( BINT_Handle intHandle )
1059{
1060    return BLST_SQ_FIRST(&(intHandle->allCbList));
1061}
1062
1063BINT_CallbackHandle BINT_GetCallbackNext( BINT_CallbackHandle cbHandle )
1064{
1065    return BLST_SQ_NEXT(cbHandle, allCbLink);
1066}
1067
1068BERR_Code BINT_GetInterruptId( BINT_CallbackHandle cbHandle, BINT_Id *pIntId )
1069{
1070    if (( cbHandle == NULL ) || ( pIntId == NULL ))
1071    {
1072        return BERR_TRACE(BERR_INVALID_PARAMETER);
1073    }
1074
1075    *pIntId = cbHandle->L2Handle->intId;
1076
1077    return BERR_SUCCESS;
1078}
1079
1080BERR_Code BINT_GetCallbackStatus( BINT_CallbackHandle cbHandle, bool *pbEnabled)
1081{
1082    if ( cbHandle == NULL )
1083    {
1084        return BERR_TRACE(BERR_INVALID_PARAMETER);
1085    }
1086
1087    *pbEnabled = cbHandle->enabled;
1088
1089    return BERR_SUCCESS;
1090}
1091
1092BERR_Code BINT_Stats_AddBin( BINT_CallbackHandle cbHandle, uint32_t ulRangeMin, uint32_t ulRangeMax )
1093{
1094    uint32_t ulActiveBins;
1095    BINT_Stats_CallbackBin *pCurBinInfo = NULL;
1096    BINT_Stats_CallbackBin aTmpBinInfo[BINT_P_STATS_BIN_MAX];
1097    uint16_t i = 0;
1098
1099
1100    if (( cbHandle == NULL ) ||
1101        ( ulRangeMin > ulRangeMax))
1102    {
1103        return BERR_TRACE(BERR_INVALID_PARAMETER);
1104    }
1105
1106    if ( cbHandle->StatInfo.bDefaultBins )
1107    {
1108        BINT_Stats_DestroyBins(cbHandle);
1109        cbHandle->StatInfo.bDefaultBins = false;
1110    }
1111
1112    ulActiveBins = cbHandle->StatInfo.ulActiveBins;
1113
1114    if ( ulActiveBins == BINT_P_STATS_BIN_MAX )
1115    {
1116        return BERR_TRACE(BERR_INVALID_PARAMETER);
1117    }
1118
1119    for (i = 0; i <= ulActiveBins; i++)
1120    {
1121        pCurBinInfo = &(cbHandle->StatInfo.aBinInfo[i]);
1122
1123        /* check for range overlap with current bin */
1124        if (( ulActiveBins > 0 ) &&
1125            ((( ulRangeMin >= pCurBinInfo->ulBinRangeMin ) &&
1126              ( ulRangeMin <= pCurBinInfo->ulBinRangeMax )) ||
1127             (( ulRangeMax >= pCurBinInfo->ulBinRangeMin ) &&
1128              ( ulRangeMax <= pCurBinInfo->ulBinRangeMax ))))
1129        {
1130            return BERR_TRACE(BERR_INVALID_PARAMETER);
1131        }
1132
1133        /* check for bin insertion here */
1134        if ( ulRangeMax < pCurBinInfo->ulBinRangeMin )
1135        {
1136            /* shift bins for insertion */
1137            uint32_t ulBinCopyNum = ulActiveBins - i;
1138            BKNI_Memcpy(aTmpBinInfo, pCurBinInfo, sizeof(BINT_Stats_CallbackBin) * ulBinCopyNum);
1139            BKNI_Memcpy(pCurBinInfo + 1, aTmpBinInfo, sizeof(BINT_Stats_CallbackBin) * ulBinCopyNum);
1140        }
1141
1142        /* set bin */
1143        if (( ulRangeMax < pCurBinInfo->ulBinRangeMin ) || (i == ulActiveBins))
1144        {
1145            pCurBinInfo->ulBinRangeMin = ulRangeMin;
1146            pCurBinInfo->ulBinRangeMax = ulRangeMax;
1147            pCurBinInfo->ulBinHitCount = 0;
1148
1149            cbHandle->StatInfo.ulActiveBins++;
1150            break;
1151        }
1152    }
1153
1154    return BERR_SUCCESS;
1155}
1156
1157BERR_Code BINT_Stats_DestroyBins( BINT_CallbackHandle cbHandle )
1158{
1159    if ( cbHandle == NULL )
1160    {
1161        return BERR_TRACE(BERR_INVALID_PARAMETER);
1162    }
1163
1164    cbHandle->StatInfo.ulActiveBins = 0;
1165
1166    BKNI_Memset(cbHandle->StatInfo.aBinInfo, 0,
1167                sizeof(BINT_Stats_CallbackBin) * BINT_P_STATS_BIN_MAX);
1168
1169    return BERR_SUCCESS;
1170}
1171
1172BERR_Code BINT_Stats_Get( BINT_CallbackHandle cbHandle, BINT_Stats_CallbackStats **ppCbStats )
1173{
1174    BINT_P_Context *intHandle;
1175
1176    if ( cbHandle == NULL )
1177    {
1178        return BERR_TRACE(BERR_INVALID_PARAMETER);
1179    }
1180
1181    intHandle = cbHandle->L2Handle->intHandle;
1182
1183#ifndef BINT_STATS_ENABLE
1184    BDBG_WRN(("Stats tracking not enabled in compile."));
1185#endif /* BINT_STATS_ENABLE */
1186
1187    *ppCbStats = &(cbHandle->StatInfo);
1188
1189    return BERR_SUCCESS;
1190}
1191
1192BERR_Code BINT_Stats_Reset( BINT_CallbackHandle cbHandle )
1193{
1194    uint16_t i;
1195    BINT_Stats_CallbackStats *pStatInfo = &(cbHandle->StatInfo);
1196
1197    if ( cbHandle == NULL )
1198    {
1199        return BERR_TRACE(BERR_INVALID_PARAMETER);
1200    }
1201
1202    BKNI_EnterCriticalSection();
1203    pStatInfo->ulTimeMin = UINT32_MAX;
1204    pStatInfo->ulTimeMax = 0;
1205    pStatInfo->ulTimeAvg = 0;
1206    pStatInfo->ulCbHitCount = 0;
1207
1208    for (i = 0; i < pStatInfo->ulActiveBins; i++)
1209    {
1210        pStatInfo->aBinInfo[i].ulBinHitCount = 0;
1211    }
1212    BKNI_LeaveCriticalSection();
1213
1214    return BERR_SUCCESS;
1215}
1216
1217BERR_Code BINT_Stats_Enable( BINT_Handle intHandle, BTMR_Handle hTmrHandle )
1218{
1219    BERR_Code rc = BERR_SUCCESS;
1220    BTMR_TimerHandle hTimer = NULL;
1221
1222    BTMR_Settings stSettings = { BTMR_Type_eSharedFreeRun,
1223                                 NULL,
1224                                 NULL,
1225                                 0,
1226                                 false };
1227
1228    if ( intHandle == NULL )
1229    {
1230        return BERR_TRACE(BERR_INVALID_PARAMETER);
1231    }
1232
1233    if ( intHandle->bStatsEnable == true )
1234    {
1235        return BERR_TRACE(BINT_STATS_ERR_ALREADY_ENABLED);
1236    }
1237
1238    rc = BTMR_CreateTimer( hTmrHandle, &hTimer, &stSettings );
1239    if (rc != BERR_SUCCESS)
1240    {
1241        return rc;
1242    }
1243
1244    intHandle->hTimer = hTimer;
1245    intHandle->bStatsEnable = true;
1246
1247    return BERR_SUCCESS;
1248}
1249
1250BERR_Code BINT_Stats_Disable( BINT_Handle intHandle )
1251{
1252    if ( intHandle == NULL )
1253    {
1254        return BERR_TRACE(BERR_INVALID_PARAMETER);
1255    }
1256
1257    if ( intHandle->bStatsEnable == false )
1258    {
1259        return BERR_TRACE(BINT_STATS_ERR_ALREADY_DISABLED);
1260    }
1261
1262    BDBG_ASSERT( intHandle->hTimer != NULL );
1263    BTMR_DestroyTimer(intHandle->hTimer);
1264
1265    intHandle->bStatsEnable = false;
1266
1267    return BERR_SUCCESS;
1268}
1269
1270/* returns elapsed time in microseconds */
1271uint32_t BINT_P_GetElapsedTime( uint32_t ulTimerStart, uint32_t ulTimerEnd )
1272{
1273    uint32_t ulTimerMax;
1274    uint32_t ulTimerElapsed;
1275
1276    ulTimerMax = BTMR_ReadTimerMax();
1277
1278    if (ulTimerEnd < ulTimerStart)
1279    {
1280        ulTimerElapsed = ((ulTimerMax - ulTimerStart) + ulTimerEnd);
1281    }
1282    else
1283    {
1284        ulTimerElapsed = (ulTimerEnd - ulTimerStart);
1285    }
1286
1287    return ulTimerElapsed;
1288}
1289
1290BERR_Code BINT_P_Stats_ComputeStats( BINT_CallbackHandle cbHandle, uint32_t ulStart, uint32_t ulEnd )
1291{
1292    uint16_t i;
1293    uint32_t ulSampleNum = BINT_P_STATS_SAMPLE_MAX;
1294    uint32_t ulElapsedTime = BINT_P_GetElapsedTime( ulStart, ulEnd );
1295    BINT_Stats_CallbackStats *pStatInfo = &(cbHandle->StatInfo);
1296
1297    pStatInfo->ulCbHitCount++;
1298
1299
1300    /* calculate min, max and average times */
1301    if ( ulElapsedTime < pStatInfo->ulTimeMin)
1302    {
1303        pStatInfo->ulTimeMin = ulElapsedTime;
1304    }
1305
1306    if ( ulElapsedTime > pStatInfo->ulTimeMax)
1307    {
1308        pStatInfo->ulTimeMax = ulElapsedTime;
1309    }
1310
1311    if (ulSampleNum > pStatInfo->ulCbHitCount)
1312    {
1313        ulSampleNum = pStatInfo->ulCbHitCount;
1314    }
1315
1316    pStatInfo->ulTimeAvg = ((pStatInfo->ulTimeAvg * (ulSampleNum - 1)) +
1317                                  ulElapsedTime) / ulSampleNum;
1318    pStatInfo->aulTimeStamp[pStatInfo->ulTimeStampStartIdx] = ulStart;
1319
1320    /* check for callbacks that take too long */
1321    if (ulElapsedTime > BINT_P_STATS_EXECUTION_TIME_MAX_THRESHOLD)
1322    {
1323        BDBG_WRN(("BINT_Isr(%s) took %d msec",
1324        cbHandle->L2Handle->intHandle->pIntMap[cbHandle->L2Handle->intMapIndex].L2Name,
1325        ulElapsedTime/1000));
1326    }
1327
1328    /* check for runaway interrupts */
1329    if (ulSampleNum >= BINT_P_STATS_RECENT_CB_HIT_COUNT)
1330    {
1331        uint32_t ulTotalPeriod, ulAvgPeriod;
1332        uint32_t ulTimeStampEndIdx;
1333
1334        if (pStatInfo->ulTimeStampStartIdx == BINT_P_STATS_RECENT_CB_HIT_COUNT - 1)
1335        {
1336            ulTimeStampEndIdx = 0;
1337        }
1338        else
1339        {
1340            ulTimeStampEndIdx = pStatInfo->ulTimeStampStartIdx + 1;
1341        }
1342
1343        ulTotalPeriod = BINT_P_GetElapsedTime(pStatInfo->aulTimeStamp[ulTimeStampEndIdx],
1344                                              pStatInfo->aulTimeStamp[pStatInfo->ulTimeStampStartIdx]);
1345
1346        ulAvgPeriod = ulTotalPeriod / BINT_P_STATS_RECENT_CB_HIT_COUNT;
1347
1348#if 0
1349/* Commenting out this code because some interrupts fire faster than this for a period of time. */
1350        if (ulAvgPeriod < BINT_P_STATS_AVG_PERIOD_MIN_THRESHOLD)
1351        {
1352            BDBG_WRN(("BINT_Isr(%s) overflow, %d msec between hits",
1353            cbHandle->L2Handle->intHandle->pIntMap[cbHandle->L2Handle->intMapIndex].L2Name,
1354            ulAvgPeriod/1000));
1355        }
1356#endif
1357
1358        pStatInfo->ulTimeStampStartIdx++;
1359        pStatInfo->ulTimeStampStartIdx = pStatInfo->ulTimeStampStartIdx % BINT_P_STATS_RECENT_CB_HIT_COUNT;
1360    }
1361
1362    /* mark bin according to elapsed time */
1363    for (i = 0; i < pStatInfo->ulActiveBins; i++)
1364    {
1365        if ((ulElapsedTime >= pStatInfo->aBinInfo[i].ulBinRangeMin) &&
1366            (ulElapsedTime <= pStatInfo->aBinInfo[i].ulBinRangeMax))
1367        {
1368            pStatInfo->aBinInfo[i].ulBinHitCount++;
1369            break;
1370        }
1371    }
1372
1373    return BERR_SUCCESS;
1374}
1375
1376void BINT_DumpInfo(BINT_Handle intHandle)
1377{
1378    BINT_P_L2Handle L2Handle;
1379    int L1Shift, i;
1380    BINT_CallbackHandle callback;
1381    bool l1_head, l2_head, int_head;
1382
1383    BDBG_OBJECT_ASSERT(intHandle, BINT);
1384    BINT_LOCK(intHandle);
1385
1386    for(i=0,int_head=false; intHandle->pIntMap[i].L1Shift != -1; i++) {
1387        L1Shift = intHandle->pIntMap[i].L1Shift&~BINT_IS_STANDARD;
1388        for(l1_head=false,L2Handle=BLST_SQ_FIRST(&(intHandle->IntArray[L1Shift])); L2Handle ; L2Handle=BLST_SQ_NEXT(L2Handle, link)) {
1389            if (!L2Handle->count) {
1390                continue;
1391            }
1392            if (!int_head) {
1393                BDBG_MSG(("------[%s dump]--------", intHandle->settings.name?intHandle->settings.name:"XXX"));
1394                int_head=true;
1395            }
1396            if(!l1_head) {
1397                BDBG_MSG((" %#x:%s", (unsigned)L1Shift, intHandle->pIntMap[i].L2Name?intHandle->pIntMap[i].L2Name:""));
1398                l1_head=true;
1399            }
1400            for(l2_head=false,callback=BLST_SQ_FIRST(&L2Handle->callbackList); callback; callback=BLST_SQ_NEXT(callback, link)) {
1401                if (!callback->count) {
1402                    continue;
1403                }
1404                if (!l2_head) {
1405                    BDBG_MSG(("   %#x:%u %s[%#x]:(%#x,%#x) %u %s", BCHP_INT_ID_GET_REG(L2Handle->intId), BCHP_INT_ID_GET_SHIFT(L2Handle->intId), callback->callbackName, (unsigned)callback->func, (unsigned)callback->pParm1, (unsigned)callback->parm2, callback->count, callback->enabled?"":"disabled"));
1406                    l2_head=true;
1407                } else {
1408                    BDBG_MSG(("   >>> %s[%#x]:(%#x,%#x) %u %s", callback->callbackName, (unsigned)callback->func, (unsigned)callback->pParm1, (unsigned)callback->parm2, callback->count, callback->enabled?"":"disabled"));
1409                }
1410#if 0
1411#ifdef BINT_STATS_ENABLE
1412                if (intHandle->bStatsEnable) {
1413                    BDBG_MSG(("     elapsed: min %d, max %d, avg %d (usec)",
1414                        callback->StatInfo.ulTimeMin, callback->StatInfo.ulTimeMax, callback->StatInfo.ulTimeAvg));
1415                    callback->StatInfo.ulTimeMin = 0;
1416                    callback->StatInfo.ulTimeMax = 0;
1417                    callback->StatInfo.ulTimeAvg = 0;
1418                    callback->StatInfo.ulCbHitCount = 0;
1419                }
1420#endif
1421#endif
1422                callback->count=0;
1423            }
1424            L2Handle->count=0;
1425        }
1426    }
1427    BINT_UNLOCK(intHandle);
1428    return;
1429}
1430
Note: See TracBrowser for help on using the repository browser.