| /** | 
 |  * @file    IxQMgrDispatcher.c | 
 |  * | 
 |  * @author Intel Corporation | 
 |  * @date    20-Dec-2001 | 
 |  *     | 
 |  * @brief   This file contains the implementation of the Dispatcher sub component | 
 |  * | 
 |  *  | 
 |  * @par | 
 |  * IXP400 SW Release version 2.0 | 
 |  *  | 
 |  * -- Copyright Notice -- | 
 |  *  | 
 |  * @par | 
 |  * Copyright 2001-2005, Intel Corporation. | 
 |  * All rights reserved. | 
 |  *  | 
 |  * @par | 
 |  * Redistribution and use in source and binary forms, with or without | 
 |  * modification, are permitted provided that the following conditions | 
 |  * are met: | 
 |  * 1. Redistributions of source code must retain the above copyright | 
 |  *    notice, this list of conditions and the following disclaimer. | 
 |  * 2. Redistributions in binary form must reproduce the above copyright | 
 |  *    notice, this list of conditions and the following disclaimer in the | 
 |  *    documentation and/or other materials provided with the distribution. | 
 |  * 3. Neither the name of the Intel Corporation nor the names of its contributors | 
 |  *    may be used to endorse or promote products derived from this software | 
 |  *    without specific prior written permission. | 
 |  *  | 
 |  * @par | 
 |  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' | 
 |  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 
 |  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 
 |  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE | 
 |  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 
 |  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 
 |  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 
 |  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 
 |  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 
 |  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 
 |  * SUCH DAMAGE. | 
 |  *  | 
 |  * @par | 
 |  * -- End of Copyright Notice -- | 
 | */ | 
 |  | 
 | /* | 
 |  * User defined include files. | 
 |  */ | 
 | #include "IxQMgr.h" | 
 | #include "IxQMgrAqmIf_p.h" | 
 | #include "IxQMgrQCfg_p.h" | 
 | #include "IxQMgrDispatcher_p.h" | 
 | #include "IxQMgrLog_p.h" | 
 | #include "IxQMgrDefines_p.h" | 
 | #include "IxFeatureCtrl.h" | 
 | #include "IxOsal.h" | 
 |  | 
 |  | 
 |  | 
 | /* | 
 |  * #defines and macros used in this file. | 
 |  */ | 
 |  | 
 |  | 
 | /* | 
 |  * This constant is used to indicate the number of priority levels supported | 
 |  */ | 
 | #define IX_QMGR_NUM_PRIORITY_LEVELS 3 | 
 |  | 
 | /*  | 
 |  * This constant is used to set the size of the array of status words | 
 |  */ | 
 | #define MAX_Q_STATUS_WORDS      4 | 
 |  | 
 | /* | 
 |  * This macro is used to check if a given priority is valid | 
 |  */ | 
 | #define IX_QMGR_DISPATCHER_PRIORITY_CHECK(priority) \ | 
 | (((priority) >= IX_QMGR_Q_PRIORITY_0) && ((priority) <= IX_QMGR_Q_PRIORITY_2)) | 
 |  | 
 | /* | 
 |  * This macto is used to check that a given interrupt source is valid | 
 |  */ | 
 | #define IX_QMGR_DISPATCHER_SOURCE_ID_CHECK(srcSel) \ | 
 | (((srcSel) >= IX_QMGR_Q_SOURCE_ID_E) && ((srcSel) <= IX_QMGR_Q_SOURCE_ID_NOT_F)) | 
 |  | 
 | /* | 
 |  * Number of times a dummy callback is called before logging a trace | 
 |  * message | 
 |  */ | 
 | #define LOG_THROTTLE_COUNT 1000000 | 
 |  | 
 | /* Priority tables limits */ | 
 | #define IX_QMGR_MIN_LOW_QUE_PRIORITY_TABLE_INDEX (0) | 
 | #define IX_QMGR_MID_LOW_QUE_PRIORITY_TABLE_INDEX (16) | 
 | #define IX_QMGR_MAX_LOW_QUE_PRIORITY_TABLE_INDEX (31) | 
 | #define IX_QMGR_MIN_UPP_QUE_PRIORITY_TABLE_INDEX (32) | 
 | #define IX_QMGR_MID_UPP_QUE_PRIORITY_TABLE_INDEX (48) | 
 | #define IX_QMGR_MAX_UPP_QUE_PRIORITY_TABLE_INDEX (63) | 
 |   | 
 | /* | 
 |  * This macro is used to check if a given callback type is valid | 
 |  */ | 
 | #define IX_QMGR_DISPATCHER_CALLBACK_TYPE_CHECK(type) \ | 
 |             (((type) >= IX_QMGR_TYPE_REALTIME_OTHER) && \ | 
 |             ((type) <= IX_QMGR_TYPE_REALTIME_SPORADIC)) | 
 |  | 
 | /*  | 
 |  * define max index in lower queue to use in loops  | 
 |  */ | 
 | #define IX_QMGR_MAX_LOW_QUE_TABLE_INDEX (31) | 
 |  | 
 | /* | 
 |  * Typedefs whose scope is limited to this file. | 
 |  */ | 
 |  | 
 | /* | 
 |  * Information on a queue needed by the Dispatcher | 
 |  */ | 
 | typedef struct  | 
 | { | 
 |     IxQMgrCallback callback;       /* Notification callback                  */ | 
 |     IxQMgrCallbackId callbackId;   /* Notification callback identifier       */ | 
 |     unsigned dummyCallbackCount;   /* Number of times runs of dummy callback */ | 
 |     IxQMgrPriority priority;       /* Dispatch priority                      */ | 
 |     unsigned int statusWordOffset; /* Offset to the status word to check     */ | 
 |     UINT32 statusMask;             /* Status mask                            */     | 
 |     UINT32 statusCheckValue;       /* Status check value                     */ | 
 |     UINT32 intRegCheckMask;	   /* Interrupt register check mask          */ | 
 | } IxQMgrQInfo; | 
 |  | 
 | /* | 
 |  * Variable declarations global to this file. Externs are followed by | 
 |  * statics. | 
 |  */ | 
 |  | 
 | /*  | 
 |  * Flag to keep record of what dispatcher set in featureCtrl when ixQMgrInit() | 
 |  * is called. This is needed because it is possible that a client might | 
 |  * change whether the live lock prevention dispatcher is used between | 
 |  * calls to ixQMgrInit() and ixQMgrDispatcherLoopGet().  | 
 |  */ | 
 | PRIVATE IX_STATUS ixQMgrOrigB0Dispatcher = IX_FEATURE_CTRL_COMPONENT_ENABLED; | 
 |  | 
 | /*  | 
 |  * keep record of Q types - not in IxQMgrQInfo for performance as | 
 |  * it is only used with ixQMgrDispatcherLoopRunB0LLP() | 
 |  */ | 
 | PRIVATE IxQMgrType ixQMgrQTypes[IX_QMGR_MAX_NUM_QUEUES]; | 
 |  | 
 | /* | 
 |  * This array contains a list of queue identifiers ordered by priority. The table | 
 |  * is split logically between queue identifiers 0-31 and 32-63. | 
 |  */ | 
 | static IxQMgrQId priorityTable[IX_QMGR_MAX_NUM_QUEUES]; | 
 |  | 
 | /* | 
 |  * This flag indicates to the dispatcher that the priority table needs to be rebuilt. | 
 |  */ | 
 | static BOOL rebuildTable = FALSE; | 
 |  | 
 | /* Dispatcher statistics */ | 
 | static IxQMgrDispatcherStats dispatcherStats; | 
 |  | 
 | /* Table of queue information */ | 
 | static IxQMgrQInfo dispatchQInfo[IX_QMGR_MAX_NUM_QUEUES]; | 
 |  | 
 | /* Masks use to identify the first queues in the priority tables  | 
 | *  when comparing with the interrupt register | 
 | */ | 
 | static unsigned int lowPriorityTableFirstHalfMask; | 
 | static unsigned int uppPriorityTableFirstHalfMask; | 
 |  | 
 | /* | 
 |  * Static function prototypes | 
 |  */ | 
 |  | 
 | /* | 
 |  * This function is the default callback for all queues | 
 |  */ | 
 | PRIVATE void | 
 | dummyCallback (IxQMgrQId qId,	       | 
 | 	       IxQMgrCallbackId cbId); | 
 |  | 
 | PRIVATE void | 
 | ixQMgrDispatcherReBuildPriorityTable (void); | 
 |  | 
 | /* | 
 |  * Function definitions. | 
 |  */ | 
 | void | 
 | ixQMgrDispatcherInit (void) | 
 | { | 
 |     int i; | 
 |     IxFeatureCtrlProductId productId = 0; | 
 |     IxFeatureCtrlDeviceId deviceId = 0; | 
 |     BOOL stickyIntSilicon = TRUE;  | 
 |  | 
 |     /* Set default priorities */ | 
 |     for (i=0; i< IX_QMGR_MAX_NUM_QUEUES; i++) | 
 |     { | 
 | 	dispatchQInfo[i].callback = dummyCallback; | 
 | 	dispatchQInfo[i].callbackId = 0; | 
 | 	dispatchQInfo[i].dummyCallbackCount = 0; | 
 | 	dispatchQInfo[i].priority = IX_QMGR_Q_PRIORITY_2; | 
 | 	dispatchQInfo[i].statusWordOffset = 0; | 
 | 	dispatchQInfo[i].statusCheckValue = 0; | 
 | 	dispatchQInfo[i].statusMask = 0;   | 
 |         /*  | 
 | 	 * There are two interrupt registers, 32 bits each. One for the lower | 
 | 	 * queues(0-31) and one for the upper queues(32-63). Therefore need to | 
 | 	 * mod by 32 i.e the min upper queue identifier. | 
 | 	 */ | 
 | 	dispatchQInfo[i].intRegCheckMask = (1<<(i%(IX_QMGR_MIN_QUEUPP_QID))); | 
 |  | 
 |         /*  | 
 |          * Set the Q types - will only be used with livelock  | 
 |          */ | 
 |         ixQMgrQTypes[i] = IX_QMGR_TYPE_REALTIME_OTHER; | 
 |  | 
 | 	/* Reset queue statistics */ | 
 | 	dispatcherStats.queueStats[i].callbackCnt = 0; | 
 | 	dispatcherStats.queueStats[i].priorityChangeCnt = 0; | 
 | 	dispatcherStats.queueStats[i].intNoCallbackCnt = 0; | 
 | 	dispatcherStats.queueStats[i].intLostCallbackCnt = 0; | 
 |         dispatcherStats.queueStats[i].notificationEnabled = FALSE; | 
 |         dispatcherStats.queueStats[i].srcSel = 0; | 
 |  | 
 |     } | 
 |  | 
 |     /* Priority table. Order the table from queue 0 to 63 */ | 
 |     ixQMgrDispatcherReBuildPriorityTable(); | 
 |  | 
 |     /* Reset statistics */ | 
 |     dispatcherStats.loopRunCnt = 0; | 
 |  | 
 |     /* Get the device ID for the underlying silicon */ | 
 |     deviceId = ixFeatureCtrlDeviceRead(); | 
 |      | 
 |     /* Get the product ID for the underlying silicon */ | 
 |     productId = ixFeatureCtrlProductIdRead(); | 
 |  | 
 |     /*  | 
 |      * Check featureCtrl to see if Livelock prevention is required  | 
 |      */ | 
 |     ixQMgrOrigB0Dispatcher = ixFeatureCtrlSwConfigurationCheck(  | 
 |                                  IX_FEATURECTRL_ORIGB0_DISPATCHER); | 
 |  | 
 |     /* | 
 |      * Check if the silicon supports the sticky interrupt feature. | 
 |      * IF (IXP42X AND A0) -> No sticky interrupt feature supported  | 
 |      */ | 
 |     if ((IX_FEATURE_CTRL_DEVICE_TYPE_IXP42X ==  | 
 |         (IX_FEATURE_CTRL_DEVICE_TYPE_MASK & deviceId)) && | 
 |         (IX_FEATURE_CTRL_SILICON_TYPE_A0 ==  | 
 |         (IX_FEATURE_CTRL_SILICON_STEPPING_MASK & productId)))  | 
 |     { | 
 |        stickyIntSilicon = FALSE; | 
 |     } | 
 |  | 
 |     /* | 
 |      * IF user wants livelock prev option AND silicon supports sticky interrupt  | 
 |      * feature -> enable the sticky interrupt bit | 
 |      */ | 
 |     if ((IX_FEATURE_CTRL_SWCONFIG_DISABLED == ixQMgrOrigB0Dispatcher) && | 
 |          stickyIntSilicon)   | 
 |     { | 
 |         ixQMgrStickyInterruptRegEnable(); | 
 |     } | 
 | } | 
 |  | 
 | IX_STATUS | 
 | ixQMgrDispatcherPrioritySet (IxQMgrQId qId, | 
 | 			     IxQMgrPriority priority) | 
 | {    | 
 |     int ixQMgrLockKey; | 
 |  | 
 |     if (!ixQMgrQIsConfigured(qId)) | 
 |     { | 
 | 	return IX_QMGR_Q_NOT_CONFIGURED; | 
 |     } | 
 |      | 
 |     if (!IX_QMGR_DISPATCHER_PRIORITY_CHECK(priority)) | 
 |     { | 
 | 	return IX_QMGR_Q_INVALID_PRIORITY; | 
 |     } | 
 |  | 
 |     ixQMgrLockKey = ixOsalIrqLock(); | 
 |      | 
 |     /* Change priority */ | 
 |     dispatchQInfo[qId].priority = priority; | 
 |     /* Set flag */ | 
 |     rebuildTable = TRUE; | 
 |  | 
 |     ixOsalIrqUnlock(ixQMgrLockKey); | 
 |  | 
 | #ifndef NDEBUG | 
 |     /* Update statistics */ | 
 |     dispatcherStats.queueStats[qId].priorityChangeCnt++; | 
 | #endif | 
 |  | 
 |     return IX_SUCCESS; | 
 | } | 
 |  | 
 | IX_STATUS | 
 | ixQMgrNotificationCallbackSet (IxQMgrQId qId, | 
 | 			       IxQMgrCallback callback, | 
 | 			       IxQMgrCallbackId callbackId) | 
 | { | 
 |     if (!ixQMgrQIsConfigured(qId)) | 
 |     { | 
 | 	return IX_QMGR_Q_NOT_CONFIGURED; | 
 |     } | 
 |  | 
 |     if (NULL == callback) | 
 |     { | 
 | 	/* Reset to dummy callback */ | 
 | 	dispatchQInfo[qId].callback = dummyCallback; | 
 | 	dispatchQInfo[qId].dummyCallbackCount = 0; | 
 | 	dispatchQInfo[qId].callbackId = 0; | 
 |     } | 
 |     else  | 
 |     { | 
 | 	dispatchQInfo[qId].callback = callback; | 
 | 	dispatchQInfo[qId].callbackId = callbackId; | 
 |     } | 
 |  | 
 |     return IX_SUCCESS; | 
 | } | 
 |  | 
 | IX_STATUS | 
 | ixQMgrNotificationEnable (IxQMgrQId qId,  | 
 | 			  IxQMgrSourceId srcSel) | 
 | { | 
 |     IxQMgrQStatus qStatusOnEntry;/* The queue status on entry/exit */ | 
 |     IxQMgrQStatus qStatusOnExit; /* to this function               */ | 
 |     int ixQMgrLockKey; | 
 |  | 
 | #ifndef NDEBUG | 
 |     if (!ixQMgrQIsConfigured (qId)) | 
 |     { | 
 | 	return IX_QMGR_Q_NOT_CONFIGURED; | 
 |     } | 
 |  | 
 |     if ((qId < IX_QMGR_MIN_QUEUPP_QID) && | 
 |        !IX_QMGR_DISPATCHER_SOURCE_ID_CHECK(srcSel)) | 
 |     { | 
 | 	/* QId 0-31 source id invalid */ | 
 | 	return IX_QMGR_INVALID_INT_SOURCE_ID; | 
 |     } | 
 |  | 
 |     if ((IX_QMGR_Q_SOURCE_ID_NE != srcSel) && | 
 | 	(qId >= IX_QMGR_MIN_QUEUPP_QID)) | 
 |     { | 
 | 	/* | 
 | 	 * For queues 32-63 the interrupt source is fixed to the Nearly | 
 | 	 * Empty status flag and therefore should have a srcSel of NE. | 
 | 	 */ | 
 | 	return IX_QMGR_INVALID_INT_SOURCE_ID; | 
 |     } | 
 | #endif | 
 |  | 
 | #ifndef NDEBUG | 
 |     dispatcherStats.queueStats[qId].notificationEnabled = TRUE; | 
 |     dispatcherStats.queueStats[qId].srcSel = srcSel; | 
 | #endif | 
 |  | 
 |     /* Get the current queue status */ | 
 |     ixQMgrAqmIfQueStatRead (qId, &qStatusOnEntry); | 
 |    | 
 |     /*  | 
 |      * Enabling interrupts results in Read-Modify-Write | 
 |      * so need critical section | 
 |      */ | 
 |  | 
 |     ixQMgrLockKey = ixOsalIrqLock(); | 
 |  | 
 |     /* Calculate the checkMask and checkValue for this q */ | 
 |     ixQMgrAqmIfQStatusCheckValsCalc (qId, | 
 | 				     srcSel, | 
 | 				     &dispatchQInfo[qId].statusWordOffset, | 
 | 				     &dispatchQInfo[qId].statusCheckValue, | 
 | 				     &dispatchQInfo[qId].statusMask); | 
 |  | 
 |  | 
 |     /* Set the interupt source is this queue is in the range 0-31 */ | 
 |     if (qId < IX_QMGR_MIN_QUEUPP_QID) | 
 |     { | 
 | 	ixQMgrAqmIfIntSrcSelWrite (qId, srcSel); | 
 |     } | 
 |  | 
 |     /* Enable the interrupt */ | 
 |     ixQMgrAqmIfQInterruptEnable (qId); | 
 |  | 
 |     ixOsalIrqUnlock(ixQMgrLockKey); | 
 |      | 
 |     /* Get the current queue status */ | 
 |     ixQMgrAqmIfQueStatRead (qId, &qStatusOnExit); | 
 |    | 
 |     /* If the status has changed return a warning */ | 
 |     if (qStatusOnEntry != qStatusOnExit) | 
 |     { | 
 | 	return IX_QMGR_WARNING; | 
 |     } | 
 |      | 
 |     return IX_SUCCESS; | 
 | } | 
 |  | 
 |  | 
 | IX_STATUS | 
 | ixQMgrNotificationDisable (IxQMgrQId qId) | 
 | { | 
 |     int ixQMgrLockKey; | 
 |  | 
 | #ifndef NDEBUG | 
 |     /* Validate parameters */ | 
 |     if (!ixQMgrQIsConfigured (qId)) | 
 |     { | 
 | 	return IX_QMGR_Q_NOT_CONFIGURED; | 
 |     } | 
 | #endif | 
 |    | 
 |     /*  | 
 |      * Enabling interrupts results in Read-Modify-Write | 
 |      * so need critical section | 
 |      */ | 
 | #ifndef NDEBUG | 
 |     dispatcherStats.queueStats[qId].notificationEnabled = FALSE; | 
 | #endif | 
 |  | 
 |     ixQMgrLockKey = ixOsalIrqLock(); | 
 |  | 
 |     ixQMgrAqmIfQInterruptDisable (qId); | 
 |      | 
 |     ixOsalIrqUnlock(ixQMgrLockKey); | 
 |  | 
 |     return IX_SUCCESS;     | 
 | } | 
 |  | 
 | void  | 
 | ixQMgrStickyInterruptRegEnable(void) | 
 | { | 
 |  /* Use Aqm If function to set Interrupt Register0 Bit-3 */  | 
 |  ixQMgrAqmIfIntSrcSelReg0Bit3Set ();    | 
 | } | 
 |  | 
 | #if !defined __XSCALE__ || defined __linux | 
 |  | 
 | /* Count the number of leading zero bits in a word, | 
 |  * and return the same value than the CLZ instruction. | 
 |  * | 
 |  * word (in)    return value (out) | 
 |  * 0x80000000   0 | 
 |  * 0x40000000   1 | 
 |  * ,,,          ,,, | 
 |  * 0x00000002   30 | 
 |  * 0x00000001   31 | 
 |  * 0x00000000   32 | 
 |  * | 
 |  * The C version of this function is used as a replacement  | 
 |  * for system not providing the equivalent of the CLZ  | 
 |  * assembly language instruction. | 
 |  * | 
 |  * Note that this version is big-endian | 
 |  */ | 
 | unsigned int | 
 | ixQMgrCountLeadingZeros(UINT32 word) | 
 | { | 
 |   unsigned int leadingZerosCount = 0; | 
 |  | 
 |   if (word == 0) | 
 |   { | 
 |       return 32; | 
 |   } | 
 |   /* search the first bit set by testing the MSB and shifting the input word */ | 
 |   while ((word & 0x80000000) == 0) | 
 |   { | 
 |       word <<= 1; | 
 |       leadingZerosCount++; | 
 |   } | 
 |   return leadingZerosCount; | 
 | } | 
 | #endif /* not  __XSCALE__ or __linux */ | 
 |  | 
 | void | 
 | ixQMgrDispatcherLoopGet (IxQMgrDispatcherFuncPtr *qDispatcherFuncPtr) | 
 | { | 
 |   IxFeatureCtrlProductId productId = 0; | 
 |   IxFeatureCtrlDeviceId deviceId = 0; | 
 |    | 
 |   /* Get the device ID for the underlying silicon */ | 
 |   deviceId = ixFeatureCtrlDeviceRead(); | 
 |  | 
 |   /* Get the product ID for the underlying silicon */ | 
 |   productId = ixFeatureCtrlProductIdRead (); | 
 |  | 
 |   /* IF (IXP42X AND A0 silicon) -> use ixQMgrDispatcherLoopRunA0 */ | 
 |   if ((IX_FEATURE_CTRL_DEVICE_TYPE_IXP42X == | 
 |       (IX_FEATURE_CTRL_DEVICE_TYPE_MASK & deviceId)) && | 
 |       (IX_FEATURE_CTRL_SILICON_TYPE_A0 ==   | 
 |       (IX_FEATURE_CTRL_SILICON_STEPPING_MASK & productId)))   | 
 |   { | 
 |     /*For IXP42X A0 silicon */ | 
 |     *qDispatcherFuncPtr = &ixQMgrDispatcherLoopRunA0 ; | 
 |   }  | 
 |   else /*For IXP42X B0 or IXP46X silicon*/  | 
 |   {  | 
 |     if (IX_FEATURE_CTRL_SWCONFIG_ENABLED == ixQMgrOrigB0Dispatcher) | 
 |     { | 
 |         /* Default for IXP42X B0 and IXP46X silicon */ | 
 |         *qDispatcherFuncPtr = &ixQMgrDispatcherLoopRunB0; | 
 |     } | 
 |     else  | 
 |     { | 
 |         /* FeatureCtrl indicated that livelock dispatcher be used */ | 
 |         *qDispatcherFuncPtr = &ixQMgrDispatcherLoopRunB0LLP; | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | void | 
 | ixQMgrDispatcherLoopRunA0 (IxQMgrDispatchGroup group) | 
 | { | 
 |     UINT32 intRegVal;                /* Interrupt reg val */ | 
 |     UINT32 intRegValAfterWrite;      /* Interrupt reg val after writing back */ | 
 |     UINT32 intRegCheckMask;          /* Mask for checking interrupt bits */ | 
 |     UINT32 qStatusWordsB4Write[MAX_Q_STATUS_WORDS];  /* Status b4 interrupt write */ | 
 |     UINT32 qStatusWordsAfterWrite[MAX_Q_STATUS_WORDS]; /* Status after interrupt write */ | 
 |     IxQMgrQInfo *currDispatchQInfo; | 
 |     BOOL statusChangeFlag; | 
 |  | 
 |     int priorityTableIndex;/* Priority table index */ | 
 |     int qIndex;            /* Current queue being processed */ | 
 |     int endIndex;          /* Index of last queue to process */ | 
 |  | 
 | #ifndef NDEBUG | 
 |     IX_OSAL_ASSERT((group == IX_QMGR_QUEUPP_GROUP) ||  | 
 | 	      (group == IX_QMGR_QUELOW_GROUP)); | 
 | #endif | 
 |  | 
 |     /* Read Q status registers before interrupt status read/write */ | 
 |     ixQMgrAqmIfQStatusRegsRead (group, qStatusWordsB4Write); | 
 |  | 
 |     /* Read the interrupt register */ | 
 |     ixQMgrAqmIfQInterruptRegRead (group, &intRegVal); | 
 |  | 
 |     /* No bit set : nothing to process (the reaminder of the algorithm is | 
 |     * based on the fact that the interrupt register value contains at | 
 |     * least one bit set | 
 |     */ | 
 |     if (intRegVal == 0)  | 
 |     { | 
 | #ifndef NDEBUG | 
 | 	/* Update statistics */ | 
 | 	dispatcherStats.loopRunCnt++; | 
 | #endif | 
 |  | 
 | 	/* Rebuild the priority table if needed */ | 
 | 	if (rebuildTable) | 
 | 	{ | 
 | 	    ixQMgrDispatcherReBuildPriorityTable (); | 
 | 	} | 
 |  | 
 | 	return; | 
 |     } | 
 |     | 
 |     /* Write it back to clear the interrupt */ | 
 |     ixQMgrAqmIfQInterruptRegWrite (group, intRegVal); | 
 |  | 
 |     /* Read Q status registers after interrupt status read/write */ | 
 |     ixQMgrAqmIfQStatusRegsRead (group, qStatusWordsAfterWrite); | 
 |   | 
 |     /* get the first queue Id from the interrupt register value */ | 
 |     qIndex = (BITS_PER_WORD - 1) - ixQMgrCountLeadingZeros(intRegVal); | 
 |  | 
 |     /* check if any change occured during hw register modifications */  | 
 |     if (IX_QMGR_QUELOW_GROUP == group) | 
 |     { | 
 | 	statusChangeFlag =  | 
 | 	    (qStatusWordsB4Write[0] != qStatusWordsAfterWrite[0]) || | 
 | 	    (qStatusWordsB4Write[1] != qStatusWordsAfterWrite[1]) || | 
 | 	    (qStatusWordsB4Write[2] != qStatusWordsAfterWrite[2]) || | 
 | 	    (qStatusWordsB4Write[3] != qStatusWordsAfterWrite[3]); | 
 |     } | 
 |     else | 
 |     { | 
 | 	statusChangeFlag =  | 
 | 	    (qStatusWordsB4Write[0] != qStatusWordsAfterWrite[0]); | 
 | 	/* Set the queue range based on the queue group to proccess */ | 
 | 	qIndex += IX_QMGR_MIN_QUEUPP_QID; | 
 |     } | 
 |  | 
 |     if (statusChangeFlag == FALSE) | 
 |     { | 
 | 	/* check if the interrupt register contains  | 
 | 	 * only 1 bit set (happy day scenario) | 
 | 	 */ | 
 | 	currDispatchQInfo = &dispatchQInfo[qIndex]; | 
 | 	if (intRegVal == currDispatchQInfo->intRegCheckMask) | 
 | 	{ | 
 | 	    /* only 1 queue event triggered a notification * | 
 | 	     * Call the callback function for this queue  | 
 | 	     */ | 
 | 	    currDispatchQInfo->callback (qIndex, | 
 | 					 currDispatchQInfo->callbackId);   | 
 | #ifndef NDEBUG | 
 | 	    /* Update statistics */ | 
 | 	    dispatcherStats.queueStats[qIndex].callbackCnt++; | 
 | #endif | 
 | 	} | 
 | 	else  | 
 | 	{ | 
 | 	    /* the event is triggered by more than 1 queue,  | 
 | 	     * the queue search will be starting from the beginning | 
 | 	     * or the middle of the priority table | 
 | 	     * | 
 | 	     * the serach will end when all the bits of the interrupt | 
 | 	     * register are cleared. There is no need to maintain | 
 | 	     * a seperate value and test it at each iteration. | 
 | 	     */ | 
 | 	    if (IX_QMGR_QUELOW_GROUP == group) | 
 | 	    { | 
 | 		/* check if any bit related to queues in the first | 
 | 		 * half of the priority table is set | 
 | 		 */ | 
 | 		if (intRegVal & lowPriorityTableFirstHalfMask) | 
 | 		{ | 
 | 		    priorityTableIndex = IX_QMGR_MIN_LOW_QUE_PRIORITY_TABLE_INDEX; | 
 | 		} | 
 | 		else | 
 | 		{ | 
 | 		    priorityTableIndex = IX_QMGR_MID_LOW_QUE_PRIORITY_TABLE_INDEX; | 
 | 		} | 
 | 	    } | 
 | 	    else  | 
 | 	    { | 
 | 		/* check if any bit related to queues in the first | 
 | 		 * half of the priority table is set | 
 | 		 */ | 
 | 		if (intRegVal & uppPriorityTableFirstHalfMask) | 
 | 		{ | 
 | 		    priorityTableIndex = IX_QMGR_MIN_UPP_QUE_PRIORITY_TABLE_INDEX; | 
 | 		} | 
 | 		else | 
 | 		{ | 
 | 		    priorityTableIndex = IX_QMGR_MID_UPP_QUE_PRIORITY_TABLE_INDEX; | 
 | 		} | 
 | 	    } | 
 | 	     | 
 | 	    /* iterate following the priority table until all the bits  | 
 | 	     * of the interrupt register are cleared. | 
 | 	     */ | 
 | 	    do | 
 | 	    { | 
 | 		qIndex = priorityTable[priorityTableIndex++]; | 
 | 		currDispatchQInfo = &dispatchQInfo[qIndex]; | 
 | 		intRegCheckMask = currDispatchQInfo->intRegCheckMask; | 
 | 		 | 
 | 		/* If this queue caused this interrupt to be raised */ | 
 | 		if (intRegVal & intRegCheckMask) | 
 | 		{ | 
 | 		    /* Call the callback function for this queue */ | 
 | 		    currDispatchQInfo->callback (qIndex, | 
 | 						 currDispatchQInfo->callbackId); | 
 | #ifndef NDEBUG | 
 | 		    /* Update statistics */ | 
 | 		    dispatcherStats.queueStats[qIndex].callbackCnt++; | 
 | #endif | 
 | 		     | 
 | 		    /* Clear the interrupt register bit */ | 
 | 		    intRegVal &= ~intRegCheckMask; | 
 | 		} | 
 | 	    } | 
 | 	    while(intRegVal); | 
 | 	} | 
 |     } | 
 |     else | 
 |     { | 
 |     /* A change in queue status occured during the hw interrupt | 
 |      * register update. To maintain the interrupt consistency, it | 
 |      * is necessary to iterate through all queues of the queue group. | 
 |      */ | 
 |  | 
 |     /* Read interrupt status again */ | 
 |     ixQMgrAqmIfQInterruptRegRead (group, &intRegValAfterWrite); | 
 |  | 
 |     if (IX_QMGR_QUELOW_GROUP == group) | 
 |     { | 
 | 	priorityTableIndex = IX_QMGR_MIN_LOW_QUE_PRIORITY_TABLE_INDEX; | 
 | 	endIndex = IX_QMGR_MAX_LOW_QUE_PRIORITY_TABLE_INDEX; | 
 |     } | 
 |     else | 
 |     { | 
 | 	priorityTableIndex = IX_QMGR_MIN_UPP_QUE_PRIORITY_TABLE_INDEX; | 
 | 	endIndex = IX_QMGR_MAX_UPP_QUE_PRIORITY_TABLE_INDEX; | 
 |     } | 
 |  | 
 |     for ( ; priorityTableIndex<=endIndex; priorityTableIndex++) | 
 |     { | 
 | 	qIndex = priorityTable[priorityTableIndex]; | 
 | 	currDispatchQInfo = &dispatchQInfo[qIndex]; | 
 | 	intRegCheckMask = currDispatchQInfo->intRegCheckMask; | 
 |  | 
 | 	/* If this queue caused this interrupt to be raised */ | 
 | 	if (intRegVal & intRegCheckMask) | 
 | 	{   | 
 | 	    /* Call the callback function for this queue */ | 
 | 	    currDispatchQInfo->callback (qIndex, | 
 | 					 currDispatchQInfo->callbackId); | 
 | #ifndef NDEBUG | 
 | 	    /* Update statistics */ | 
 | 	    dispatcherStats.queueStats[qIndex].callbackCnt++; | 
 | #endif | 
 | 	     | 
 | 	} /* if (intRegVal .. */ | 
 |  | 
 | 	/*  | 
 | 	 * If interrupt bit is set in intRegValAfterWrite don't | 
 | 	 * proceed as this will be caught in next interrupt | 
 | 	 */ | 
 | 	else if ((intRegValAfterWrite & intRegCheckMask) == 0) | 
 | 	{ | 
 | 	    /* Check if an interrupt was lost for this Q */ | 
 | 	    if (ixQMgrAqmIfQStatusCheck(qStatusWordsB4Write, | 
 | 					qStatusWordsAfterWrite, | 
 | 					currDispatchQInfo->statusWordOffset, | 
 | 					currDispatchQInfo->statusCheckValue, | 
 | 					currDispatchQInfo->statusMask)) | 
 | 	    { | 
 | 		/* Call the callback function for this queue */ | 
 | 		currDispatchQInfo->callback (qIndex,  | 
 | 					     dispatchQInfo[qIndex].callbackId);                  | 
 | #ifndef NDEBUG | 
 | 		/* Update statistics */ | 
 | 		dispatcherStats.queueStats[qIndex].callbackCnt++; | 
 | 		dispatcherStats.queueStats[qIndex].intLostCallbackCnt++; | 
 | #endif | 
 | 	    } /* if ixQMgrAqmIfQStatusCheck(.. */ | 
 | 	} /* else if ((intRegValAfterWrite ... */ | 
 |     } /* for (priorityTableIndex=0 ... */ | 
 |     } | 
 |  | 
 |     /* Rebuild the priority table if needed */ | 
 |     if (rebuildTable) | 
 |     { | 
 | 	ixQMgrDispatcherReBuildPriorityTable (); | 
 |     } | 
 |  | 
 | #ifndef NDEBUG | 
 |     /* Update statistics */ | 
 |     dispatcherStats.loopRunCnt++; | 
 | #endif | 
 | } | 
 |  | 
 |  | 
 |  | 
 | void | 
 | ixQMgrDispatcherLoopRunB0 (IxQMgrDispatchGroup group) | 
 | { | 
 |     UINT32 intRegVal;                /* Interrupt reg val */ | 
 |     UINT32 intRegCheckMask;          /* Mask for checking interrupt bits */ | 
 |     IxQMgrQInfo *currDispatchQInfo; | 
 |  | 
 |  | 
 |     int priorityTableIndex; /* Priority table index */ | 
 |     int qIndex;             /* Current queue being processed */ | 
 |  | 
 | #ifndef NDEBUG | 
 |     IX_OSAL_ASSERT((group == IX_QMGR_QUEUPP_GROUP) || | 
 |               (group == IX_QMGR_QUELOW_GROUP)); | 
 |     IX_OSAL_ASSERT((group == IX_QMGR_QUEUPP_GROUP) ||  | 
 | 	      (group == IX_QMGR_QUELOW_GROUP)); | 
 | #endif | 
 |  | 
 |     /* Read the interrupt register */ | 
 |     ixQMgrAqmIfQInterruptRegRead (group, &intRegVal); | 
 |  | 
 |  | 
 |     /* No queue has interrupt register set */ | 
 |     if (intRegVal != 0) | 
 |     { | 
 |  | 
 |             /* Write it back to clear the interrupt */ | 
 |             ixQMgrAqmIfQInterruptRegWrite (group, intRegVal); | 
 |  | 
 |             /* get the first queue Id from the interrupt register value */ | 
 |             qIndex = (BITS_PER_WORD - 1) - ixQMgrCountLeadingZeros(intRegVal); | 
 |  | 
 |             if (IX_QMGR_QUEUPP_GROUP == group) | 
 |             { | 
 |                 /* Set the queue range based on the queue group to proccess */ | 
 |                 qIndex += IX_QMGR_MIN_QUEUPP_QID; | 
 |             } | 
 |  | 
 |             /* check if the interrupt register contains | 
 |              * only 1 bit set | 
 |              * For example: | 
 |              *                                        intRegVal = 0x0010 | 
 |              *               currDispatchQInfo->intRegCheckMask = 0x0010 | 
 |              *    intRegVal == currDispatchQInfo->intRegCheckMask is TRUE. | 
 |              */ | 
 |              currDispatchQInfo = &dispatchQInfo[qIndex]; | 
 |              if (intRegVal == currDispatchQInfo->intRegCheckMask) | 
 |              { | 
 |                 /* only 1 queue event triggered a notification * | 
 |                  * Call the callback function for this queue | 
 |                  */ | 
 |                 currDispatchQInfo->callback (qIndex, | 
 |                                      currDispatchQInfo->callbackId); | 
 | #ifndef NDEBUG | 
 |                 /* Update statistics */ | 
 |                 dispatcherStats.queueStats[qIndex].callbackCnt++; | 
 | #endif | 
 |              } | 
 |              else | 
 |              { | 
 |                  /* the event is triggered by more than 1 queue, | 
 |                   * the queue search will be starting from the beginning | 
 |                   * or the middle of the priority table | 
 |                   * | 
 |                   * the serach will end when all the bits of the interrupt | 
 |                   * register are cleared. There is no need to maintain | 
 |                   * a seperate value and test it at each iteration. | 
 |                   */ | 
 |                  if (IX_QMGR_QUELOW_GROUP == group) | 
 |                  { | 
 |                      /* check if any bit related to queues in the first | 
 |                       * half of the priority table is set | 
 |                       */ | 
 |                      if (intRegVal & lowPriorityTableFirstHalfMask) | 
 |                      { | 
 |                          priorityTableIndex = IX_QMGR_MIN_LOW_QUE_PRIORITY_TABLE_INDEX; | 
 |                      } | 
 |                      else | 
 |                      { | 
 |                          priorityTableIndex = IX_QMGR_MID_LOW_QUE_PRIORITY_TABLE_INDEX; | 
 |                      } | 
 |                  } | 
 |                 else | 
 |                  { | 
 |                      /* check if any bit related to queues in the first | 
 |                       * half of the priority table is set | 
 |                       */ | 
 |                      if (intRegVal & uppPriorityTableFirstHalfMask) | 
 |                      { | 
 |                          priorityTableIndex = IX_QMGR_MIN_UPP_QUE_PRIORITY_TABLE_INDEX; | 
 |                      } | 
 |                      else | 
 |                      { | 
 |                          priorityTableIndex = IX_QMGR_MID_UPP_QUE_PRIORITY_TABLE_INDEX; | 
 |                      } | 
 |                  } | 
 |  | 
 |                  /* iterate following the priority table until all the bits | 
 |                   * of the interrupt register are cleared. | 
 |                   */ | 
 |                  do | 
 |                  { | 
 |                      qIndex = priorityTable[priorityTableIndex++]; | 
 |                      currDispatchQInfo = &dispatchQInfo[qIndex]; | 
 |                      intRegCheckMask = currDispatchQInfo->intRegCheckMask; | 
 |  | 
 |                      /* If this queue caused this interrupt to be raised */ | 
 |                      if (intRegVal & intRegCheckMask) | 
 |                      { | 
 |                          /* Call the callback function for this queue */ | 
 |                          currDispatchQInfo->callback (qIndex, | 
 |                                               currDispatchQInfo->callbackId); | 
 | #ifndef NDEBUG | 
 |                          /* Update statistics */ | 
 |                          dispatcherStats.queueStats[qIndex].callbackCnt++; | 
 | #endif | 
 |  | 
 |                          /* Clear the interrupt register bit */ | 
 |                          intRegVal &= ~intRegCheckMask; | 
 |                      } | 
 |                   } | 
 |                   while(intRegVal); | 
 |              } /*End of intRegVal == currDispatchQInfo->intRegCheckMask */ | 
 |      } /* End of intRegVal != 0 */ | 
 |  | 
 | #ifndef NDEBUG | 
 |     /* Update statistics */ | 
 |     dispatcherStats.loopRunCnt++; | 
 | #endif | 
 |  | 
 |     /* Rebuild the priority table if needed */ | 
 |     if (rebuildTable) | 
 |     { | 
 |         ixQMgrDispatcherReBuildPriorityTable (); | 
 |     } | 
 | } | 
 |  | 
 | void | 
 | ixQMgrDispatcherLoopRunB0LLP (IxQMgrDispatchGroup group) | 
 | { | 
 |     UINT32 intRegVal =0;                /* Interrupt reg val */ | 
 |     UINT32 intRegCheckMask;          /* Mask for checking interrupt bits */ | 
 |     IxQMgrQInfo *currDispatchQInfo; | 
 |  | 
 |     int priorityTableIndex; /* Priority table index */ | 
 |     int qIndex;             /* Current queue being processed */ | 
 |  | 
 |     UINT32 intRegValCopy = 0; | 
 |     UINT32 intEnableRegVal = 0; | 
 |     UINT8 i = 0; | 
 |  | 
 | #ifndef NDEBUG | 
 |     IX_OSAL_ASSERT((group == IX_QMGR_QUEUPP_GROUP) || | 
 |               (group == IX_QMGR_QUELOW_GROUP)); | 
 | #endif | 
 |  | 
 |     /* Read the interrupt register */ | 
 |     ixQMgrAqmIfQInterruptRegRead (group, &intRegVal); | 
 |  | 
 |     /*  | 
 |      * mask any interrupts that are not enabled  | 
 |      */ | 
 |     ixQMgrAqmIfQInterruptEnableRegRead (group, &intEnableRegVal); | 
 |     intRegVal &= intEnableRegVal; | 
 |  | 
 |     /* No queue has interrupt register set */ | 
 |     if (intRegVal != 0) | 
 |     { | 
 |         if (IX_QMGR_QUELOW_GROUP == group) | 
 |         { | 
 |             /* | 
 |              * As the sticky bit is set, the interrupt register will  | 
 |              * not clear if write back at this point because the condition | 
 |              * has not been cleared. Take a copy and write back later after | 
 |              * the condition has been cleared | 
 |              */ | 
 |             intRegValCopy = intRegVal; | 
 |         } | 
 |         else | 
 |         { | 
 |             /* no sticky for upper Q's, so write back now */ | 
 |             ixQMgrAqmIfQInterruptRegWrite (group, intRegVal); | 
 |         } | 
 |  | 
 |         /* get the first queue Id from the interrupt register value */ | 
 |         qIndex = (BITS_PER_WORD - 1) - ixQMgrCountLeadingZeros(intRegVal); | 
 |  | 
 |         if (IX_QMGR_QUEUPP_GROUP == group) | 
 |         { | 
 |             /* Set the queue range based on the queue group to proccess */ | 
 |             qIndex += IX_QMGR_MIN_QUEUPP_QID; | 
 |         } | 
 |  | 
 |         /* check if the interrupt register contains | 
 |         * only 1 bit set | 
 |         * For example: | 
 |         *                                        intRegVal = 0x0010 | 
 |         *               currDispatchQInfo->intRegCheckMask = 0x0010 | 
 |         *    intRegVal == currDispatchQInfo->intRegCheckMask is TRUE. | 
 |         */ | 
 |         currDispatchQInfo = &dispatchQInfo[qIndex]; | 
 |         if (intRegVal == currDispatchQInfo->intRegCheckMask) | 
 |         { | 
 |  | 
 |             /*  | 
 |              * check if Q type periodic -  only lower queues can | 
 |              * have there type set to periodic  | 
 |              */ | 
 |             if (IX_QMGR_TYPE_REALTIME_PERIODIC == ixQMgrQTypes[qIndex]) | 
 |             { | 
 |                 /*  | 
 |                  * Disable the notifications on any sporadics  | 
 |                  */ | 
 |                 for (i=0; i <= IX_QMGR_MAX_LOW_QUE_TABLE_INDEX; i++) | 
 |                 { | 
 |                     if (IX_QMGR_TYPE_REALTIME_SPORADIC == ixQMgrQTypes[i]) | 
 |                     { | 
 |                         ixQMgrNotificationDisable(i); | 
 | #ifndef NDEBUG | 
 |                         /* Update statistics */ | 
 |                         dispatcherStats.queueStats[i].disableCount++; | 
 | #endif | 
 |                     } | 
 |                 } | 
 |             } | 
 |  | 
 |             currDispatchQInfo->callback (qIndex, | 
 |                                          currDispatchQInfo->callbackId); | 
 | #ifndef NDEBUG | 
 |             /* Update statistics */ | 
 |             dispatcherStats.queueStats[qIndex].callbackCnt++; | 
 | #endif | 
 |         } | 
 |         else | 
 |         { | 
 |             /* the event is triggered by more than 1 queue, | 
 |             * the queue search will be starting from the beginning | 
 |             * or the middle of the priority table | 
 |             * | 
 |             * the serach will end when all the bits of the interrupt | 
 |             * register are cleared. There is no need to maintain | 
 |             * a seperate value and test it at each iteration. | 
 |             */ | 
 |             if (IX_QMGR_QUELOW_GROUP == group) | 
 |             { | 
 |                 /* check if any bit related to queues in the first | 
 |                  * half of the priority table is set | 
 |                  */ | 
 |                 if (intRegVal & lowPriorityTableFirstHalfMask) | 
 |                 { | 
 |                     priorityTableIndex = | 
 |                                        IX_QMGR_MIN_LOW_QUE_PRIORITY_TABLE_INDEX; | 
 |                 } | 
 |                 else | 
 |                 { | 
 |                     priorityTableIndex = | 
 |                                        IX_QMGR_MID_LOW_QUE_PRIORITY_TABLE_INDEX; | 
 |                 } | 
 |             } | 
 |             else | 
 |             { | 
 |                 /* check if any bit related to queues in the first | 
 |                  * half of the priority table is set | 
 |                  */ | 
 |                 if (intRegVal & uppPriorityTableFirstHalfMask) | 
 |                 { | 
 |                     priorityTableIndex = | 
 |                                        IX_QMGR_MIN_UPP_QUE_PRIORITY_TABLE_INDEX; | 
 |                 } | 
 |                 else | 
 |                 { | 
 |                     priorityTableIndex = | 
 |                                        IX_QMGR_MID_UPP_QUE_PRIORITY_TABLE_INDEX; | 
 |                 } | 
 |             } | 
 |  | 
 |             /* iterate following the priority table until all the bits | 
 |              * of the interrupt register are cleared. | 
 |              */ | 
 |             do | 
 |             { | 
 |                 qIndex = priorityTable[priorityTableIndex++]; | 
 |                 currDispatchQInfo = &dispatchQInfo[qIndex]; | 
 |                 intRegCheckMask = currDispatchQInfo->intRegCheckMask; | 
 |  | 
 |                 /* If this queue caused this interrupt to be raised */ | 
 |                 if (intRegVal & intRegCheckMask) | 
 |                 { | 
 |                     /*  | 
 |                      * check if Q type periodic - only lower queues can | 
 |                      * have there type set to periodic. There can only be one | 
 |                      * periodic queue, so the sporadics are only disabled once. | 
 |                      */ | 
 |                     if (IX_QMGR_TYPE_REALTIME_PERIODIC == ixQMgrQTypes[qIndex]) | 
 |                     { | 
 |                         /*  | 
 |                          * Disable the notifications on any sporadics  | 
 |                          */ | 
 |                         for (i=0; i <= IX_QMGR_MAX_LOW_QUE_TABLE_INDEX; i++) | 
 |                         { | 
 |                             if (IX_QMGR_TYPE_REALTIME_SPORADIC ==  | 
 |                                     ixQMgrQTypes[i]) | 
 |                             { | 
 |                                 ixQMgrNotificationDisable(i); | 
 |                                 /*  | 
 |                                  * remove from intRegVal as we don't want  | 
 |                                  * to service any sporadics now | 
 |                                  */ | 
 |                                 intRegVal &= ~dispatchQInfo[i].intRegCheckMask; | 
 | #ifndef NDEBUG | 
 |                                 /* Update statistics */ | 
 |                                 dispatcherStats.queueStats[i].disableCount++; | 
 | #endif | 
 |                             } | 
 |                         } | 
 |                     } | 
 |  | 
 |                     currDispatchQInfo->callback (qIndex, | 
 |                                                  currDispatchQInfo->callbackId); | 
 | #ifndef NDEBUG | 
 |                     /* Update statistics */ | 
 |                     dispatcherStats.queueStats[qIndex].callbackCnt++; | 
 | #endif | 
 |                     /* Clear the interrupt register bit */ | 
 |                     intRegVal &= ~intRegCheckMask; | 
 |                 } | 
 |             } | 
 |             while(intRegVal); | 
 |         } /*End of intRegVal == currDispatchQInfo->intRegCheckMask */ | 
 |     } /* End of intRegVal != 0 */ | 
 |  | 
 | #ifndef NDEBUG | 
 |     /* Update statistics */ | 
 |     dispatcherStats.loopRunCnt++; | 
 | #endif | 
 |  | 
 |     if ((intRegValCopy != 0) && (IX_QMGR_QUELOW_GROUP == group)) | 
 |     { | 
 |         /*  | 
 |          * lower groups (therefore sticky) AND at least one enabled interrupt | 
 |          * Write back to clear the interrupt  | 
 |          */ | 
 |         ixQMgrAqmIfQInterruptRegWrite (IX_QMGR_QUELOW_GROUP, intRegValCopy); | 
 |     } | 
 |  | 
 |     /* Rebuild the priority table if needed */ | 
 |     if (rebuildTable) | 
 |     { | 
 |         ixQMgrDispatcherReBuildPriorityTable (); | 
 |     } | 
 | } | 
 |  | 
 | PRIVATE void | 
 | ixQMgrDispatcherReBuildPriorityTable (void) | 
 | { | 
 |     UINT32 qIndex; | 
 |     UINT32 priority; | 
 |     int lowQuePriorityTableIndex = IX_QMGR_MIN_LOW_QUE_PRIORITY_TABLE_INDEX; | 
 |     int uppQuePriorityTableIndex = IX_QMGR_MIN_UPP_QUE_PRIORITY_TABLE_INDEX; | 
 |  | 
 |     /* Reset the rebuild flag */ | 
 |     rebuildTable = FALSE; | 
 |  | 
 |     /* initialize the mak used to identify the queues in the first half | 
 |      * of the priority table | 
 |      */ | 
 |     lowPriorityTableFirstHalfMask = 0; | 
 |     uppPriorityTableFirstHalfMask = 0; | 
 |      | 
 |     /* For each priority level */ | 
 |     for(priority=0; priority<IX_QMGR_NUM_PRIORITY_LEVELS; priority++) | 
 |     { | 
 | 	/* Foreach low queue in this priority */ | 
 | 	for(qIndex=0; qIndex<IX_QMGR_MIN_QUEUPP_QID; qIndex++) | 
 | 	{ | 
 | 	    if (dispatchQInfo[qIndex].priority == priority) | 
 | 	    {  | 
 | 		/* build the priority table bitmask which match the | 
 | 		 * queues of the first half of the priority table  | 
 | 		 */ | 
 | 		if (lowQuePriorityTableIndex < IX_QMGR_MID_LOW_QUE_PRIORITY_TABLE_INDEX)  | 
 | 		{ | 
 | 		    lowPriorityTableFirstHalfMask |= dispatchQInfo[qIndex].intRegCheckMask; | 
 | 		} | 
 | 		/* build the priority table */ | 
 | 		priorityTable[lowQuePriorityTableIndex++] = qIndex; | 
 | 	    } | 
 | 	} | 
 | 	/* Foreach upp queue */ | 
 | 	for(qIndex=IX_QMGR_MIN_QUEUPP_QID; qIndex<=IX_QMGR_MAX_QID; qIndex++) | 
 | 	{ | 
 | 	    if (dispatchQInfo[qIndex].priority == priority) | 
 | 	    { | 
 | 		/* build the priority table bitmask which match the | 
 | 		 * queues of the first half of the priority table  | 
 | 		 */ | 
 | 		if (uppQuePriorityTableIndex < IX_QMGR_MID_UPP_QUE_PRIORITY_TABLE_INDEX)  | 
 | 		{ | 
 | 		    uppPriorityTableFirstHalfMask |= dispatchQInfo[qIndex].intRegCheckMask; | 
 | 		} | 
 | 		/* build the priority table */ | 
 | 		priorityTable[uppQuePriorityTableIndex++] = qIndex; | 
 | 	    } | 
 | 	} | 
 |     } | 
 | } | 
 |  | 
 | IxQMgrDispatcherStats* | 
 | ixQMgrDispatcherStatsGet (void) | 
 | { | 
 |     return &dispatcherStats; | 
 | } | 
 |  | 
 | PRIVATE void | 
 | dummyCallback (IxQMgrQId qId, | 
 | 	       IxQMgrCallbackId cbId) | 
 | { | 
 |     /* Throttle the trace message */ | 
 |     if ((dispatchQInfo[qId].dummyCallbackCount % LOG_THROTTLE_COUNT) == 0) | 
 |     { | 
 | 	IX_QMGR_LOG_WARNING2("--> dummyCallback: qId (%d), callbackId (%d)\n",qId,cbId); | 
 |     } | 
 |     dispatchQInfo[qId].dummyCallbackCount++; | 
 |  | 
 | #ifndef NDEBUG | 
 |     /* Update statistcs */ | 
 |     dispatcherStats.queueStats[qId].intNoCallbackCnt++; | 
 | #endif | 
 | } | 
 | void | 
 | ixQMgrLLPShow (int resetStats) | 
 | { | 
 | #ifndef NDEBUG | 
 |     UINT8 i = 0; | 
 |     IxQMgrQInfo *q; | 
 |     UINT32 intEnableRegVal = 0; | 
 |  | 
 |     printf ("Livelock statistics are printed on the fly.\n"); | 
 |     printf ("qId Type     EnableCnt DisableCnt IntEnableState Callbacks\n"); | 
 |     printf ("=== ======== ========= ========== ============== =========\n"); | 
 |  | 
 |     for (i=0; i<= IX_QMGR_MAX_LOW_QUE_TABLE_INDEX; i++) | 
 |     { | 
 |         q = &dispatchQInfo[i]; | 
 |  | 
 |         if (ixQMgrQTypes[i] != IX_QMGR_TYPE_REALTIME_OTHER) | 
 |         { | 
 |             printf (" %2d ", i); | 
 |  | 
 |             if (ixQMgrQTypes[i] == IX_QMGR_TYPE_REALTIME_SPORADIC) | 
 |             { | 
 |                 printf ("Sporadic"); | 
 |             } | 
 |             else | 
 |             { | 
 |                 printf ("Periodic"); | 
 |             } | 
 |  | 
 |             | 
 |             ixQMgrAqmIfQInterruptEnableRegRead (IX_QMGR_QUELOW_GROUP,  | 
 |                                                     &intEnableRegVal); | 
 |             	 | 
 |  | 
 | 	    intEnableRegVal &= dispatchQInfo[i].intRegCheckMask; | 
 |             intEnableRegVal = intEnableRegVal >> i; | 
 |  | 
 |             printf (" %10d %10d %10d %10d\n", | 
 |                     dispatcherStats.queueStats[i].enableCount, | 
 |                     dispatcherStats.queueStats[i].disableCount, | 
 |                     intEnableRegVal, | 
 |                     dispatcherStats.queueStats[i].callbackCnt); | 
 |  | 
 |             if (resetStats) | 
 |             { | 
 |                 dispatcherStats.queueStats[i].enableCount = | 
 |                 dispatcherStats.queueStats[i].disableCount =  | 
 |                 dispatcherStats.queueStats[i].callbackCnt = 0; | 
 |             } | 
 |         } | 
 |     } | 
 | #else | 
 |     IX_QMGR_LOG0("Livelock Prevention statistics are only collected in debug mode\n"); | 
 | #endif | 
 | } | 
 |  | 
 | void | 
 | ixQMgrPeriodicDone (void) | 
 | { | 
 |     UINT32 i = 0; | 
 |     UINT32 ixQMgrLockKey = 0; | 
 |  | 
 |     /*  | 
 |      * for the lower queues | 
 |      */ | 
 |     for (i=0; i <= IX_QMGR_MAX_LOW_QUE_TABLE_INDEX; i++) | 
 |     { | 
 |         /* | 
 |          * check for sporadics  | 
 |          */ | 
 |         if (IX_QMGR_TYPE_REALTIME_SPORADIC == ixQMgrQTypes[i]) | 
 |         { | 
 |              /*  | 
 |               * enable any sporadics  | 
 |               */ | 
 |              ixQMgrLockKey = ixOsalIrqLock(); | 
 |              ixQMgrAqmIfQInterruptEnable(i); | 
 |              ixOsalIrqUnlock(ixQMgrLockKey); | 
 | #ifndef NDEBUG | 
 |              /*  | 
 |               * Update statistics  | 
 |               */ | 
 |              dispatcherStats.queueStats[i].enableCount++; | 
 |              dispatcherStats.queueStats[i].notificationEnabled = TRUE; | 
 | #endif | 
 |         } | 
 |     } | 
 | } | 
 | IX_STATUS | 
 | ixQMgrCallbackTypeSet (IxQMgrQId qId,  | 
 |                        IxQMgrType type) | 
 | { | 
 |     UINT32 ixQMgrLockKey = 0; | 
 |     IxQMgrType ixQMgrOldType =0; | 
 |  | 
 | #ifndef NDEBUG | 
 |     if (!ixQMgrQIsConfigured(qId)) | 
 |     { | 
 |         return IX_QMGR_Q_NOT_CONFIGURED; | 
 |     } | 
 |     if (qId >= IX_QMGR_MIN_QUEUPP_QID) | 
 |     { | 
 |         return IX_QMGR_PARAMETER_ERROR; | 
 |     } | 
 |     if(!IX_QMGR_DISPATCHER_CALLBACK_TYPE_CHECK(type)) | 
 |     { | 
 |         return IX_QMGR_PARAMETER_ERROR; | 
 |     } | 
 | #endif | 
 |  | 
 |     ixQMgrOldType = ixQMgrQTypes[qId]; | 
 |     ixQMgrQTypes[qId] = type; | 
 |  | 
 |     /* | 
 |      * check if Q has been changed from type SPORADIC | 
 |      */ | 
 |     if (IX_QMGR_TYPE_REALTIME_SPORADIC == ixQMgrOldType) | 
 |     { | 
 |        /*  | 
 |         * previously Q was a SPORADIC, this means that LLP | 
 |         * might have had it disabled. enable it now. | 
 |         */ | 
 |        ixQMgrLockKey = ixOsalIrqLock(); | 
 |        ixQMgrAqmIfQInterruptEnable(qId); | 
 |        ixOsalIrqUnlock(ixQMgrLockKey); | 
 |  | 
 | #ifndef NDEBUG | 
 |        /*  | 
 |         * Update statistics  | 
 |         */ | 
 |        dispatcherStats.queueStats[qId].enableCount++; | 
 | #endif | 
 |     } | 
 |  | 
 |     return IX_SUCCESS; | 
 | } | 
 |  | 
 | IX_STATUS | 
 | ixQMgrCallbackTypeGet (IxQMgrQId qId,  | 
 |                        IxQMgrType *type) | 
 | { | 
 | #ifndef NDEBUG | 
 |     if (!ixQMgrQIsConfigured(qId)) | 
 |     { | 
 |         return IX_QMGR_Q_NOT_CONFIGURED; | 
 |     } | 
 |     if (qId >= IX_QMGR_MIN_QUEUPP_QID) | 
 |     { | 
 |         return IX_QMGR_PARAMETER_ERROR; | 
 |     } | 
 |     if(type == NULL) | 
 |     { | 
 |          return IX_QMGR_PARAMETER_ERROR; | 
 |     } | 
 | #endif | 
 |  | 
 |     *type = ixQMgrQTypes[qId]; | 
 |     return IX_SUCCESS; | 
 | } |