📄 ixqmgrdispatcher.c
字号:
/* 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 intixQMgrCountLeadingZeros(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 */voidixQMgrDispatcherLoopGet (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; } }}voidixQMgrDispatcherLoopRunA0 (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}voidixQMgrDispatcherLoopRunB0 (IxQMgrDispatchGroup group){ UINT32 intRegVal; /* Interrupt reg val */ UINT32 intRegValSav; /* Saved 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); /* save to write back after processing queues */ intRegValSav = intRegVal; /* The sequence in which we process queues and write back the * interrupt register depends on whether or not sticky interrupts * are in use. If sticky interrupts are enabled, that means that the * interrupt status won't be cleared until after the queues are processed * and the queue status bits are updated. If interrupts are not sticky, * the interrupt register has to be written back immediately, before processing * the queues in case new queue status changes occur during processing. */ if(!stickyEnabled) { /* not sticky, write back now */ ixQMgrAqmIfQInterruptRegWrite (group, intRegValSav); } /* No queue has interrupt register set */ if (intRegVal != 0) { /* 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 */ if(stickyEnabled) { /* Write back saved register to clear the interrupt */ ixQMgrAqmIfQInterruptRegWrite (group, intRegValSav); } } /* End of intRegVal != 0 */#ifndef NDEBUG /* Update statistics */ dispatcherStats.loopRunCnt++;#endif /* Rebuild the priority table if needed */ if (rebuildTable)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -