|  | /** | 
|  | * @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; | 
|  | } |