| [2] | 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 | |
|---|
| 268 | BDBG_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 */ |
|---|
| 281 | typedef struct BINT_P_Callback *BINT_P_CallbackHandle; |
|---|
| 282 | |
|---|
| 283 | /* |
|---|
| 284 | Summary: |
|---|
| 285 | This structure defines the head element for creating |
|---|
| 286 | a linked list. |
|---|
| 287 | */ |
|---|
| 288 | typedef struct BINT_P_cblHead BINT_P_cblHead; |
|---|
| 289 | BLST_SQ_HEAD(BINT_P_cblHead, BINT_P_Callback); |
|---|
| 290 | |
|---|
| 291 | /* |
|---|
| 292 | Summary: |
|---|
| 293 | This strcuture defines a single element in the |
|---|
| 294 | hash table used in the InterruptInterface. |
|---|
| 295 | |
|---|
| 296 | Description: |
|---|
| 297 | One and only instance of this structure will exist for each L2 interrupt bit. |
|---|
| 298 | */ |
|---|
| 299 | typedef 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 | /* |
|---|
| 311 | Summary: |
|---|
| 312 | This structure defines the head element for creating |
|---|
| 313 | a linked list. |
|---|
| 314 | */ |
|---|
| 315 | typedef struct BINT_P_L2Head BINT_P_L2Head; |
|---|
| 316 | BLST_SQ_HEAD(BINT_P_L2Head, BINT_P_L2Int); |
|---|
| 317 | |
|---|
| 318 | /* |
|---|
| 319 | Summary: |
|---|
| 320 | This structure defines the a callback handle/context. It includes |
|---|
| 321 | doubly linked list support. |
|---|
| 322 | |
|---|
| 323 | Description: |
|---|
| 324 | One of these structures exists for each callback created. There |
|---|
| 325 | may be multiple callbacks assigned for a single interrupt. |
|---|
| 326 | */ |
|---|
| 327 | typedef 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 | |
|---|
| 345 | BDBG_OBJECT_ID(BINT); |
|---|
| 346 | |
|---|
| 347 | typedef 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 */ |
|---|
| 376 | static 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 | |
|---|
| 394 | BERR_Code BINT_P_Stats_ComputeStats( BINT_CallbackHandle cbHandle, uint32_t ulStart, uint32_t ulEnd ); |
|---|
| 395 | uint32_t BINT_P_GetElapsedTime( uint32_t ulTimerStart, uint32_t ulTimerEnd ); |
|---|
| 396 | |
|---|
| 397 | BERR_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 | |
|---|
| 478 | error: |
|---|
| 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 | |
|---|
| 494 | BERR_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 | /** |
|---|
| 532 | BINT_Isr is the main inner loop of the entire refsw architecture. |
|---|
| 533 | Optimization of every line of code matters greatly. |
|---|
| 534 | **/ |
|---|
| 535 | void 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 |
|---|
| 692 | BERR_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 | } |
|---|
| 697 | BERR_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 |
|---|
| 699 | BERR_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 | } |
|---|
| 703 | BERR_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 | |
|---|
| 837 | done: |
|---|
| 838 | BINT_UNLOCK(intHandle); |
|---|
| 839 | return rc; |
|---|
| 840 | } |
|---|
| 841 | |
|---|
| 842 | BERR_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 | |
|---|
| 869 | BERR_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 | |
|---|
| 880 | BERR_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 | |
|---|
| 909 | BERR_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 | |
|---|
| 920 | BERR_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 | |
|---|
| 949 | BERR_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 | |
|---|
| 960 | BERR_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 | |
|---|
| 977 | BERR_Code BINT_TriggerInterruptByHandle( BINT_CallbackHandle cbHandle ) |
|---|
| 978 | { |
|---|
| 979 | return BINT_TriggerInterruptByHandle_isr( cbHandle ); |
|---|
| 980 | } |
|---|
| 981 | |
|---|
| 982 | BERR_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) |
|---|
| 1001 | void 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 |
|---|
| 1034 | void 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 | |
|---|
| 1058 | BINT_CallbackHandle BINT_GetCallbackFirst( BINT_Handle intHandle ) |
|---|
| 1059 | { |
|---|
| 1060 | return BLST_SQ_FIRST(&(intHandle->allCbList)); |
|---|
| 1061 | } |
|---|
| 1062 | |
|---|
| 1063 | BINT_CallbackHandle BINT_GetCallbackNext( BINT_CallbackHandle cbHandle ) |
|---|
| 1064 | { |
|---|
| 1065 | return BLST_SQ_NEXT(cbHandle, allCbLink); |
|---|
| 1066 | } |
|---|
| 1067 | |
|---|
| 1068 | BERR_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 | |
|---|
| 1080 | BERR_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 | |
|---|
| 1092 | BERR_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 | |
|---|
| 1157 | BERR_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 | |
|---|
| 1172 | BERR_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 | |
|---|
| 1192 | BERR_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 | |
|---|
| 1217 | BERR_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 | |
|---|
| 1250 | BERR_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 */ |
|---|
| 1271 | uint32_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 | |
|---|
| 1290 | BERR_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 | |
|---|
| 1376 | void 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 | |
|---|