2 * @file IxQMgrDispatcher.c
4 * @author Intel Corporation
7 * @brief This file contains the implementation of the Dispatcher sub component
11 * IXP400 SW Release version 2.0
13 * -- Copyright Notice --
16 * Copyright 2001-2005, Intel Corporation.
17 * All rights reserved.
20 * SPDX-License-Identifier: BSD-3-Clause
22 * -- End of Copyright Notice --
26 * User defined include files.
29 #include "IxQMgrAqmIf_p.h"
30 #include "IxQMgrQCfg_p.h"
31 #include "IxQMgrDispatcher_p.h"
32 #include "IxQMgrLog_p.h"
33 #include "IxQMgrDefines_p.h"
34 #include "IxFeatureCtrl.h"
40 * #defines and macros used in this file.
45 * This constant is used to indicate the number of priority levels supported
47 #define IX_QMGR_NUM_PRIORITY_LEVELS 3
50 * This constant is used to set the size of the array of status words
52 #define MAX_Q_STATUS_WORDS 4
55 * This macro is used to check if a given priority is valid
57 #define IX_QMGR_DISPATCHER_PRIORITY_CHECK(priority) \
58 (((priority) >= IX_QMGR_Q_PRIORITY_0) && ((priority) <= IX_QMGR_Q_PRIORITY_2))
61 * This macto is used to check that a given interrupt source is valid
63 #define IX_QMGR_DISPATCHER_SOURCE_ID_CHECK(srcSel) \
64 (((srcSel) >= IX_QMGR_Q_SOURCE_ID_E) && ((srcSel) <= IX_QMGR_Q_SOURCE_ID_NOT_F))
67 * Number of times a dummy callback is called before logging a trace
70 #define LOG_THROTTLE_COUNT 1000000
72 /* Priority tables limits */
73 #define IX_QMGR_MIN_LOW_QUE_PRIORITY_TABLE_INDEX (0)
74 #define IX_QMGR_MID_LOW_QUE_PRIORITY_TABLE_INDEX (16)
75 #define IX_QMGR_MAX_LOW_QUE_PRIORITY_TABLE_INDEX (31)
76 #define IX_QMGR_MIN_UPP_QUE_PRIORITY_TABLE_INDEX (32)
77 #define IX_QMGR_MID_UPP_QUE_PRIORITY_TABLE_INDEX (48)
78 #define IX_QMGR_MAX_UPP_QUE_PRIORITY_TABLE_INDEX (63)
81 * This macro is used to check if a given callback type is valid
83 #define IX_QMGR_DISPATCHER_CALLBACK_TYPE_CHECK(type) \
84 (((type) >= IX_QMGR_TYPE_REALTIME_OTHER) && \
85 ((type) <= IX_QMGR_TYPE_REALTIME_SPORADIC))
88 * define max index in lower queue to use in loops
90 #define IX_QMGR_MAX_LOW_QUE_TABLE_INDEX (31)
93 * Typedefs whose scope is limited to this file.
97 * Information on a queue needed by the Dispatcher
101 IxQMgrCallback callback; /* Notification callback */
102 IxQMgrCallbackId callbackId; /* Notification callback identifier */
103 unsigned dummyCallbackCount; /* Number of times runs of dummy callback */
104 IxQMgrPriority priority; /* Dispatch priority */
105 unsigned int statusWordOffset; /* Offset to the status word to check */
106 UINT32 statusMask; /* Status mask */
107 UINT32 statusCheckValue; /* Status check value */
108 UINT32 intRegCheckMask; /* Interrupt register check mask */
112 * Variable declarations global to this file. Externs are followed by
117 * Flag to keep record of what dispatcher set in featureCtrl when ixQMgrInit()
118 * is called. This is needed because it is possible that a client might
119 * change whether the live lock prevention dispatcher is used between
120 * calls to ixQMgrInit() and ixQMgrDispatcherLoopGet().
122 PRIVATE IX_STATUS ixQMgrOrigB0Dispatcher = IX_FEATURE_CTRL_COMPONENT_ENABLED;
125 * keep record of Q types - not in IxQMgrQInfo for performance as
126 * it is only used with ixQMgrDispatcherLoopRunB0LLP()
128 PRIVATE IxQMgrType ixQMgrQTypes[IX_QMGR_MAX_NUM_QUEUES];
131 * This array contains a list of queue identifiers ordered by priority. The table
132 * is split logically between queue identifiers 0-31 and 32-63.
134 static IxQMgrQId priorityTable[IX_QMGR_MAX_NUM_QUEUES];
137 * This flag indicates to the dispatcher that the priority table needs to be rebuilt.
139 static BOOL rebuildTable = false;
141 /* Dispatcher statistics */
142 static IxQMgrDispatcherStats dispatcherStats;
144 /* Table of queue information */
145 static IxQMgrQInfo dispatchQInfo[IX_QMGR_MAX_NUM_QUEUES];
147 /* Masks use to identify the first queues in the priority tables
148 * when comparing with the interrupt register
150 static unsigned int lowPriorityTableFirstHalfMask;
151 static unsigned int uppPriorityTableFirstHalfMask;
154 * Static function prototypes
158 * This function is the default callback for all queues
161 dummyCallback (IxQMgrQId qId,
162 IxQMgrCallbackId cbId);
165 ixQMgrDispatcherReBuildPriorityTable (void);
168 * Function definitions.
171 ixQMgrDispatcherInit (void)
174 IxFeatureCtrlProductId productId = 0;
175 IxFeatureCtrlDeviceId deviceId = 0;
176 BOOL stickyIntSilicon = true;
178 /* Set default priorities */
179 for (i=0; i< IX_QMGR_MAX_NUM_QUEUES; i++)
181 dispatchQInfo[i].callback = dummyCallback;
182 dispatchQInfo[i].callbackId = 0;
183 dispatchQInfo[i].dummyCallbackCount = 0;
184 dispatchQInfo[i].priority = IX_QMGR_Q_PRIORITY_2;
185 dispatchQInfo[i].statusWordOffset = 0;
186 dispatchQInfo[i].statusCheckValue = 0;
187 dispatchQInfo[i].statusMask = 0;
189 * There are two interrupt registers, 32 bits each. One for the lower
190 * queues(0-31) and one for the upper queues(32-63). Therefore need to
191 * mod by 32 i.e the min upper queue identifier.
193 dispatchQInfo[i].intRegCheckMask = (1<<(i%(IX_QMGR_MIN_QUEUPP_QID)));
196 * Set the Q types - will only be used with livelock
198 ixQMgrQTypes[i] = IX_QMGR_TYPE_REALTIME_OTHER;
200 /* Reset queue statistics */
201 dispatcherStats.queueStats[i].callbackCnt = 0;
202 dispatcherStats.queueStats[i].priorityChangeCnt = 0;
203 dispatcherStats.queueStats[i].intNoCallbackCnt = 0;
204 dispatcherStats.queueStats[i].intLostCallbackCnt = 0;
205 dispatcherStats.queueStats[i].notificationEnabled = false;
206 dispatcherStats.queueStats[i].srcSel = 0;
210 /* Priority table. Order the table from queue 0 to 63 */
211 ixQMgrDispatcherReBuildPriorityTable();
213 /* Reset statistics */
214 dispatcherStats.loopRunCnt = 0;
216 /* Get the device ID for the underlying silicon */
217 deviceId = ixFeatureCtrlDeviceRead();
219 /* Get the product ID for the underlying silicon */
220 productId = ixFeatureCtrlProductIdRead();
223 * Check featureCtrl to see if Livelock prevention is required
225 ixQMgrOrigB0Dispatcher = ixFeatureCtrlSwConfigurationCheck(
226 IX_FEATURECTRL_ORIGB0_DISPATCHER);
229 * Check if the silicon supports the sticky interrupt feature.
230 * IF (IXP42X AND A0) -> No sticky interrupt feature supported
232 if ((IX_FEATURE_CTRL_DEVICE_TYPE_IXP42X ==
233 (IX_FEATURE_CTRL_DEVICE_TYPE_MASK & deviceId)) &&
234 (IX_FEATURE_CTRL_SILICON_TYPE_A0 ==
235 (IX_FEATURE_CTRL_SILICON_STEPPING_MASK & productId)))
237 stickyIntSilicon = false;
241 * IF user wants livelock prev option AND silicon supports sticky interrupt
242 * feature -> enable the sticky interrupt bit
244 if ((IX_FEATURE_CTRL_SWCONFIG_DISABLED == ixQMgrOrigB0Dispatcher) &&
247 ixQMgrStickyInterruptRegEnable();
252 ixQMgrDispatcherPrioritySet (IxQMgrQId qId,
253 IxQMgrPriority priority)
257 if (!ixQMgrQIsConfigured(qId))
259 return IX_QMGR_Q_NOT_CONFIGURED;
262 if (!IX_QMGR_DISPATCHER_PRIORITY_CHECK(priority))
264 return IX_QMGR_Q_INVALID_PRIORITY;
267 ixQMgrLockKey = ixOsalIrqLock();
269 /* Change priority */
270 dispatchQInfo[qId].priority = priority;
274 ixOsalIrqUnlock(ixQMgrLockKey);
277 /* Update statistics */
278 dispatcherStats.queueStats[qId].priorityChangeCnt++;
285 ixQMgrNotificationCallbackSet (IxQMgrQId qId,
286 IxQMgrCallback callback,
287 IxQMgrCallbackId callbackId)
289 if (!ixQMgrQIsConfigured(qId))
291 return IX_QMGR_Q_NOT_CONFIGURED;
294 if (NULL == callback)
296 /* Reset to dummy callback */
297 dispatchQInfo[qId].callback = dummyCallback;
298 dispatchQInfo[qId].dummyCallbackCount = 0;
299 dispatchQInfo[qId].callbackId = 0;
303 dispatchQInfo[qId].callback = callback;
304 dispatchQInfo[qId].callbackId = callbackId;
311 ixQMgrNotificationEnable (IxQMgrQId qId,
312 IxQMgrSourceId srcSel)
314 IxQMgrQStatus qStatusOnEntry;/* The queue status on entry/exit */
315 IxQMgrQStatus qStatusOnExit; /* to this function */
319 if (!ixQMgrQIsConfigured (qId))
321 return IX_QMGR_Q_NOT_CONFIGURED;
324 if ((qId < IX_QMGR_MIN_QUEUPP_QID) &&
325 !IX_QMGR_DISPATCHER_SOURCE_ID_CHECK(srcSel))
327 /* QId 0-31 source id invalid */
328 return IX_QMGR_INVALID_INT_SOURCE_ID;
331 if ((IX_QMGR_Q_SOURCE_ID_NE != srcSel) &&
332 (qId >= IX_QMGR_MIN_QUEUPP_QID))
335 * For queues 32-63 the interrupt source is fixed to the Nearly
336 * Empty status flag and therefore should have a srcSel of NE.
338 return IX_QMGR_INVALID_INT_SOURCE_ID;
343 dispatcherStats.queueStats[qId].notificationEnabled = true;
344 dispatcherStats.queueStats[qId].srcSel = srcSel;
347 /* Get the current queue status */
348 ixQMgrAqmIfQueStatRead (qId, &qStatusOnEntry);
351 * Enabling interrupts results in Read-Modify-Write
352 * so need critical section
355 ixQMgrLockKey = ixOsalIrqLock();
357 /* Calculate the checkMask and checkValue for this q */
358 ixQMgrAqmIfQStatusCheckValsCalc (qId,
360 &dispatchQInfo[qId].statusWordOffset,
361 &dispatchQInfo[qId].statusCheckValue,
362 &dispatchQInfo[qId].statusMask);
365 /* Set the interrupt source is this queue is in the range 0-31 */
366 if (qId < IX_QMGR_MIN_QUEUPP_QID)
368 ixQMgrAqmIfIntSrcSelWrite (qId, srcSel);
371 /* Enable the interrupt */
372 ixQMgrAqmIfQInterruptEnable (qId);
374 ixOsalIrqUnlock(ixQMgrLockKey);
376 /* Get the current queue status */
377 ixQMgrAqmIfQueStatRead (qId, &qStatusOnExit);
379 /* If the status has changed return a warning */
380 if (qStatusOnEntry != qStatusOnExit)
382 return IX_QMGR_WARNING;
390 ixQMgrNotificationDisable (IxQMgrQId qId)
395 /* Validate parameters */
396 if (!ixQMgrQIsConfigured (qId))
398 return IX_QMGR_Q_NOT_CONFIGURED;
403 * Enabling interrupts results in Read-Modify-Write
404 * so need critical section
407 dispatcherStats.queueStats[qId].notificationEnabled = false;
410 ixQMgrLockKey = ixOsalIrqLock();
412 ixQMgrAqmIfQInterruptDisable (qId);
414 ixOsalIrqUnlock(ixQMgrLockKey);
420 ixQMgrStickyInterruptRegEnable(void)
422 /* Use Aqm If function to set Interrupt Register0 Bit-3 */
423 ixQMgrAqmIfIntSrcSelReg0Bit3Set ();
426 #if !defined __XSCALE__ || defined __linux
428 /* Count the number of leading zero bits in a word,
429 * and return the same value than the CLZ instruction.
431 * word (in) return value (out)
439 * The C version of this function is used as a replacement
440 * for system not providing the equivalent of the CLZ
441 * assembly language instruction.
443 * Note that this version is big-endian
446 ixQMgrCountLeadingZeros(UINT32 word)
448 unsigned int leadingZerosCount = 0;
454 /* search the first bit set by testing the MSB and shifting the input word */
455 while ((word & 0x80000000) == 0)
460 return leadingZerosCount;
462 #endif /* not __XSCALE__ or __linux */
465 ixQMgrDispatcherLoopGet (IxQMgrDispatcherFuncPtr *qDispatcherFuncPtr)
467 IxFeatureCtrlProductId productId = 0;
468 IxFeatureCtrlDeviceId deviceId = 0;
470 /* Get the device ID for the underlying silicon */
471 deviceId = ixFeatureCtrlDeviceRead();
473 /* Get the product ID for the underlying silicon */
474 productId = ixFeatureCtrlProductIdRead ();
476 /* IF (IXP42X AND A0 silicon) -> use ixQMgrDispatcherLoopRunA0 */
477 if ((IX_FEATURE_CTRL_DEVICE_TYPE_IXP42X ==
478 (IX_FEATURE_CTRL_DEVICE_TYPE_MASK & deviceId)) &&
479 (IX_FEATURE_CTRL_SILICON_TYPE_A0 ==
480 (IX_FEATURE_CTRL_SILICON_STEPPING_MASK & productId)))
482 /*For IXP42X A0 silicon */
483 *qDispatcherFuncPtr = &ixQMgrDispatcherLoopRunA0 ;
485 else /*For IXP42X B0 or IXP46X silicon*/
487 if (IX_FEATURE_CTRL_SWCONFIG_ENABLED == ixQMgrOrigB0Dispatcher)
489 /* Default for IXP42X B0 and IXP46X silicon */
490 *qDispatcherFuncPtr = &ixQMgrDispatcherLoopRunB0;
494 /* FeatureCtrl indicated that livelock dispatcher be used */
495 *qDispatcherFuncPtr = &ixQMgrDispatcherLoopRunB0LLP;
501 ixQMgrDispatcherLoopRunA0 (IxQMgrDispatchGroup group)
503 UINT32 intRegVal; /* Interrupt reg val */
504 UINT32 intRegValAfterWrite; /* Interrupt reg val after writing back */
505 UINT32 intRegCheckMask; /* Mask for checking interrupt bits */
506 UINT32 qStatusWordsB4Write[MAX_Q_STATUS_WORDS]; /* Status b4 interrupt write */
507 UINT32 qStatusWordsAfterWrite[MAX_Q_STATUS_WORDS]; /* Status after interrupt write */
508 IxQMgrQInfo *currDispatchQInfo;
509 BOOL statusChangeFlag;
511 int priorityTableIndex;/* Priority table index */
512 int qIndex; /* Current queue being processed */
513 int endIndex; /* Index of last queue to process */
516 IX_OSAL_ASSERT((group == IX_QMGR_QUEUPP_GROUP) ||
517 (group == IX_QMGR_QUELOW_GROUP));
520 /* Read Q status registers before interrupt status read/write */
521 ixQMgrAqmIfQStatusRegsRead (group, qStatusWordsB4Write);
523 /* Read the interrupt register */
524 ixQMgrAqmIfQInterruptRegRead (group, &intRegVal);
526 /* No bit set : nothing to process (the reaminder of the algorithm is
527 * based on the fact that the interrupt register value contains at
533 /* Update statistics */
534 dispatcherStats.loopRunCnt++;
537 /* Rebuild the priority table if needed */
540 ixQMgrDispatcherReBuildPriorityTable ();
546 /* Write it back to clear the interrupt */
547 ixQMgrAqmIfQInterruptRegWrite (group, intRegVal);
549 /* Read Q status registers after interrupt status read/write */
550 ixQMgrAqmIfQStatusRegsRead (group, qStatusWordsAfterWrite);
552 /* get the first queue Id from the interrupt register value */
553 qIndex = (BITS_PER_WORD - 1) - ixQMgrCountLeadingZeros(intRegVal);
555 /* check if any change occured during hw register modifications */
556 if (IX_QMGR_QUELOW_GROUP == group)
559 (qStatusWordsB4Write[0] != qStatusWordsAfterWrite[0]) ||
560 (qStatusWordsB4Write[1] != qStatusWordsAfterWrite[1]) ||
561 (qStatusWordsB4Write[2] != qStatusWordsAfterWrite[2]) ||
562 (qStatusWordsB4Write[3] != qStatusWordsAfterWrite[3]);
567 (qStatusWordsB4Write[0] != qStatusWordsAfterWrite[0]);
568 /* Set the queue range based on the queue group to proccess */
569 qIndex += IX_QMGR_MIN_QUEUPP_QID;
572 if (statusChangeFlag == false)
574 /* check if the interrupt register contains
575 * only 1 bit set (happy day scenario)
577 currDispatchQInfo = &dispatchQInfo[qIndex];
578 if (intRegVal == currDispatchQInfo->intRegCheckMask)
580 /* only 1 queue event triggered a notification *
581 * Call the callback function for this queue
583 currDispatchQInfo->callback (qIndex,
584 currDispatchQInfo->callbackId);
586 /* Update statistics */
587 dispatcherStats.queueStats[qIndex].callbackCnt++;
592 /* the event is triggered by more than 1 queue,
593 * the queue search will be starting from the beginning
594 * or the middle of the priority table
596 * the serach will end when all the bits of the interrupt
597 * register are cleared. There is no need to maintain
598 * a seperate value and test it at each iteration.
600 if (IX_QMGR_QUELOW_GROUP == group)
602 /* check if any bit related to queues in the first
603 * half of the priority table is set
605 if (intRegVal & lowPriorityTableFirstHalfMask)
607 priorityTableIndex = IX_QMGR_MIN_LOW_QUE_PRIORITY_TABLE_INDEX;
611 priorityTableIndex = IX_QMGR_MID_LOW_QUE_PRIORITY_TABLE_INDEX;
616 /* check if any bit related to queues in the first
617 * half of the priority table is set
619 if (intRegVal & uppPriorityTableFirstHalfMask)
621 priorityTableIndex = IX_QMGR_MIN_UPP_QUE_PRIORITY_TABLE_INDEX;
625 priorityTableIndex = IX_QMGR_MID_UPP_QUE_PRIORITY_TABLE_INDEX;
629 /* iterate following the priority table until all the bits
630 * of the interrupt register are cleared.
634 qIndex = priorityTable[priorityTableIndex++];
635 currDispatchQInfo = &dispatchQInfo[qIndex];
636 intRegCheckMask = currDispatchQInfo->intRegCheckMask;
638 /* If this queue caused this interrupt to be raised */
639 if (intRegVal & intRegCheckMask)
641 /* Call the callback function for this queue */
642 currDispatchQInfo->callback (qIndex,
643 currDispatchQInfo->callbackId);
645 /* Update statistics */
646 dispatcherStats.queueStats[qIndex].callbackCnt++;
649 /* Clear the interrupt register bit */
650 intRegVal &= ~intRegCheckMask;
658 /* A change in queue status occured during the hw interrupt
659 * register update. To maintain the interrupt consistency, it
660 * is necessary to iterate through all queues of the queue group.
663 /* Read interrupt status again */
664 ixQMgrAqmIfQInterruptRegRead (group, &intRegValAfterWrite);
666 if (IX_QMGR_QUELOW_GROUP == group)
668 priorityTableIndex = IX_QMGR_MIN_LOW_QUE_PRIORITY_TABLE_INDEX;
669 endIndex = IX_QMGR_MAX_LOW_QUE_PRIORITY_TABLE_INDEX;
673 priorityTableIndex = IX_QMGR_MIN_UPP_QUE_PRIORITY_TABLE_INDEX;
674 endIndex = IX_QMGR_MAX_UPP_QUE_PRIORITY_TABLE_INDEX;
677 for ( ; priorityTableIndex<=endIndex; priorityTableIndex++)
679 qIndex = priorityTable[priorityTableIndex];
680 currDispatchQInfo = &dispatchQInfo[qIndex];
681 intRegCheckMask = currDispatchQInfo->intRegCheckMask;
683 /* If this queue caused this interrupt to be raised */
684 if (intRegVal & intRegCheckMask)
686 /* Call the callback function for this queue */
687 currDispatchQInfo->callback (qIndex,
688 currDispatchQInfo->callbackId);
690 /* Update statistics */
691 dispatcherStats.queueStats[qIndex].callbackCnt++;
694 } /* if (intRegVal .. */
697 * If interrupt bit is set in intRegValAfterWrite don't
698 * proceed as this will be caught in next interrupt
700 else if ((intRegValAfterWrite & intRegCheckMask) == 0)
702 /* Check if an interrupt was lost for this Q */
703 if (ixQMgrAqmIfQStatusCheck(qStatusWordsB4Write,
704 qStatusWordsAfterWrite,
705 currDispatchQInfo->statusWordOffset,
706 currDispatchQInfo->statusCheckValue,
707 currDispatchQInfo->statusMask))
709 /* Call the callback function for this queue */
710 currDispatchQInfo->callback (qIndex,
711 dispatchQInfo[qIndex].callbackId);
713 /* Update statistics */
714 dispatcherStats.queueStats[qIndex].callbackCnt++;
715 dispatcherStats.queueStats[qIndex].intLostCallbackCnt++;
717 } /* if ixQMgrAqmIfQStatusCheck(.. */
718 } /* else if ((intRegValAfterWrite ... */
719 } /* for (priorityTableIndex=0 ... */
722 /* Rebuild the priority table if needed */
725 ixQMgrDispatcherReBuildPriorityTable ();
729 /* Update statistics */
730 dispatcherStats.loopRunCnt++;
737 ixQMgrDispatcherLoopRunB0 (IxQMgrDispatchGroup group)
739 UINT32 intRegVal; /* Interrupt reg val */
740 UINT32 intRegCheckMask; /* Mask for checking interrupt bits */
741 IxQMgrQInfo *currDispatchQInfo;
744 int priorityTableIndex; /* Priority table index */
745 int qIndex; /* Current queue being processed */
748 IX_OSAL_ASSERT((group == IX_QMGR_QUEUPP_GROUP) ||
749 (group == IX_QMGR_QUELOW_GROUP));
750 IX_OSAL_ASSERT((group == IX_QMGR_QUEUPP_GROUP) ||
751 (group == IX_QMGR_QUELOW_GROUP));
754 /* Read the interrupt register */
755 ixQMgrAqmIfQInterruptRegRead (group, &intRegVal);
758 /* No queue has interrupt register set */
762 /* Write it back to clear the interrupt */
763 ixQMgrAqmIfQInterruptRegWrite (group, intRegVal);
765 /* get the first queue Id from the interrupt register value */
766 qIndex = (BITS_PER_WORD - 1) - ixQMgrCountLeadingZeros(intRegVal);
768 if (IX_QMGR_QUEUPP_GROUP == group)
770 /* Set the queue range based on the queue group to proccess */
771 qIndex += IX_QMGR_MIN_QUEUPP_QID;
774 /* check if the interrupt register contains
778 * currDispatchQInfo->intRegCheckMask = 0x0010
779 * intRegVal == currDispatchQInfo->intRegCheckMask is true.
781 currDispatchQInfo = &dispatchQInfo[qIndex];
782 if (intRegVal == currDispatchQInfo->intRegCheckMask)
784 /* only 1 queue event triggered a notification *
785 * Call the callback function for this queue
787 currDispatchQInfo->callback (qIndex,
788 currDispatchQInfo->callbackId);
790 /* Update statistics */
791 dispatcherStats.queueStats[qIndex].callbackCnt++;
796 /* the event is triggered by more than 1 queue,
797 * the queue search will be starting from the beginning
798 * or the middle of the priority table
800 * the serach will end when all the bits of the interrupt
801 * register are cleared. There is no need to maintain
802 * a seperate value and test it at each iteration.
804 if (IX_QMGR_QUELOW_GROUP == group)
806 /* check if any bit related to queues in the first
807 * half of the priority table is set
809 if (intRegVal & lowPriorityTableFirstHalfMask)
811 priorityTableIndex = IX_QMGR_MIN_LOW_QUE_PRIORITY_TABLE_INDEX;
815 priorityTableIndex = IX_QMGR_MID_LOW_QUE_PRIORITY_TABLE_INDEX;
820 /* check if any bit related to queues in the first
821 * half of the priority table is set
823 if (intRegVal & uppPriorityTableFirstHalfMask)
825 priorityTableIndex = IX_QMGR_MIN_UPP_QUE_PRIORITY_TABLE_INDEX;
829 priorityTableIndex = IX_QMGR_MID_UPP_QUE_PRIORITY_TABLE_INDEX;
833 /* iterate following the priority table until all the bits
834 * of the interrupt register are cleared.
838 qIndex = priorityTable[priorityTableIndex++];
839 currDispatchQInfo = &dispatchQInfo[qIndex];
840 intRegCheckMask = currDispatchQInfo->intRegCheckMask;
842 /* If this queue caused this interrupt to be raised */
843 if (intRegVal & intRegCheckMask)
845 /* Call the callback function for this queue */
846 currDispatchQInfo->callback (qIndex,
847 currDispatchQInfo->callbackId);
849 /* Update statistics */
850 dispatcherStats.queueStats[qIndex].callbackCnt++;
853 /* Clear the interrupt register bit */
854 intRegVal &= ~intRegCheckMask;
858 } /*End of intRegVal == currDispatchQInfo->intRegCheckMask */
859 } /* End of intRegVal != 0 */
862 /* Update statistics */
863 dispatcherStats.loopRunCnt++;
866 /* Rebuild the priority table if needed */
869 ixQMgrDispatcherReBuildPriorityTable ();
874 ixQMgrDispatcherLoopRunB0LLP (IxQMgrDispatchGroup group)
876 UINT32 intRegVal =0; /* Interrupt reg val */
877 UINT32 intRegCheckMask; /* Mask for checking interrupt bits */
878 IxQMgrQInfo *currDispatchQInfo;
880 int priorityTableIndex; /* Priority table index */
881 int qIndex; /* Current queue being processed */
883 UINT32 intRegValCopy = 0;
884 UINT32 intEnableRegVal = 0;
888 IX_OSAL_ASSERT((group == IX_QMGR_QUEUPP_GROUP) ||
889 (group == IX_QMGR_QUELOW_GROUP));
892 /* Read the interrupt register */
893 ixQMgrAqmIfQInterruptRegRead (group, &intRegVal);
896 * mask any interrupts that are not enabled
898 ixQMgrAqmIfQInterruptEnableRegRead (group, &intEnableRegVal);
899 intRegVal &= intEnableRegVal;
901 /* No queue has interrupt register set */
904 if (IX_QMGR_QUELOW_GROUP == group)
907 * As the sticky bit is set, the interrupt register will
908 * not clear if write back at this point because the condition
909 * has not been cleared. Take a copy and write back later after
910 * the condition has been cleared
912 intRegValCopy = intRegVal;
916 /* no sticky for upper Q's, so write back now */
917 ixQMgrAqmIfQInterruptRegWrite (group, intRegVal);
920 /* get the first queue Id from the interrupt register value */
921 qIndex = (BITS_PER_WORD - 1) - ixQMgrCountLeadingZeros(intRegVal);
923 if (IX_QMGR_QUEUPP_GROUP == group)
925 /* Set the queue range based on the queue group to proccess */
926 qIndex += IX_QMGR_MIN_QUEUPP_QID;
929 /* check if the interrupt register contains
933 * currDispatchQInfo->intRegCheckMask = 0x0010
934 * intRegVal == currDispatchQInfo->intRegCheckMask is true.
936 currDispatchQInfo = &dispatchQInfo[qIndex];
937 if (intRegVal == currDispatchQInfo->intRegCheckMask)
941 * check if Q type periodic - only lower queues can
942 * have there type set to periodic
944 if (IX_QMGR_TYPE_REALTIME_PERIODIC == ixQMgrQTypes[qIndex])
947 * Disable the notifications on any sporadics
949 for (i=0; i <= IX_QMGR_MAX_LOW_QUE_TABLE_INDEX; i++)
951 if (IX_QMGR_TYPE_REALTIME_SPORADIC == ixQMgrQTypes[i])
953 ixQMgrNotificationDisable(i);
955 /* Update statistics */
956 dispatcherStats.queueStats[i].disableCount++;
962 currDispatchQInfo->callback (qIndex,
963 currDispatchQInfo->callbackId);
965 /* Update statistics */
966 dispatcherStats.queueStats[qIndex].callbackCnt++;
971 /* the event is triggered by more than 1 queue,
972 * the queue search will be starting from the beginning
973 * or the middle of the priority table
975 * the serach will end when all the bits of the interrupt
976 * register are cleared. There is no need to maintain
977 * a seperate value and test it at each iteration.
979 if (IX_QMGR_QUELOW_GROUP == group)
981 /* check if any bit related to queues in the first
982 * half of the priority table is set
984 if (intRegVal & lowPriorityTableFirstHalfMask)
987 IX_QMGR_MIN_LOW_QUE_PRIORITY_TABLE_INDEX;
992 IX_QMGR_MID_LOW_QUE_PRIORITY_TABLE_INDEX;
997 /* check if any bit related to queues in the first
998 * half of the priority table is set
1000 if (intRegVal & uppPriorityTableFirstHalfMask)
1002 priorityTableIndex =
1003 IX_QMGR_MIN_UPP_QUE_PRIORITY_TABLE_INDEX;
1007 priorityTableIndex =
1008 IX_QMGR_MID_UPP_QUE_PRIORITY_TABLE_INDEX;
1012 /* iterate following the priority table until all the bits
1013 * of the interrupt register are cleared.
1017 qIndex = priorityTable[priorityTableIndex++];
1018 currDispatchQInfo = &dispatchQInfo[qIndex];
1019 intRegCheckMask = currDispatchQInfo->intRegCheckMask;
1021 /* If this queue caused this interrupt to be raised */
1022 if (intRegVal & intRegCheckMask)
1025 * check if Q type periodic - only lower queues can
1026 * have there type set to periodic. There can only be one
1027 * periodic queue, so the sporadics are only disabled once.
1029 if (IX_QMGR_TYPE_REALTIME_PERIODIC == ixQMgrQTypes[qIndex])
1032 * Disable the notifications on any sporadics
1034 for (i=0; i <= IX_QMGR_MAX_LOW_QUE_TABLE_INDEX; i++)
1036 if (IX_QMGR_TYPE_REALTIME_SPORADIC ==
1039 ixQMgrNotificationDisable(i);
1041 * remove from intRegVal as we don't want
1042 * to service any sporadics now
1044 intRegVal &= ~dispatchQInfo[i].intRegCheckMask;
1046 /* Update statistics */
1047 dispatcherStats.queueStats[i].disableCount++;
1053 currDispatchQInfo->callback (qIndex,
1054 currDispatchQInfo->callbackId);
1056 /* Update statistics */
1057 dispatcherStats.queueStats[qIndex].callbackCnt++;
1059 /* Clear the interrupt register bit */
1060 intRegVal &= ~intRegCheckMask;
1064 } /*End of intRegVal == currDispatchQInfo->intRegCheckMask */
1065 } /* End of intRegVal != 0 */
1068 /* Update statistics */
1069 dispatcherStats.loopRunCnt++;
1072 if ((intRegValCopy != 0) && (IX_QMGR_QUELOW_GROUP == group))
1075 * lower groups (therefore sticky) AND at least one enabled interrupt
1076 * Write back to clear the interrupt
1078 ixQMgrAqmIfQInterruptRegWrite (IX_QMGR_QUELOW_GROUP, intRegValCopy);
1081 /* Rebuild the priority table if needed */
1084 ixQMgrDispatcherReBuildPriorityTable ();
1089 ixQMgrDispatcherReBuildPriorityTable (void)
1093 int lowQuePriorityTableIndex = IX_QMGR_MIN_LOW_QUE_PRIORITY_TABLE_INDEX;
1094 int uppQuePriorityTableIndex = IX_QMGR_MIN_UPP_QUE_PRIORITY_TABLE_INDEX;
1096 /* Reset the rebuild flag */
1097 rebuildTable = false;
1099 /* initialize the mak used to identify the queues in the first half
1100 * of the priority table
1102 lowPriorityTableFirstHalfMask = 0;
1103 uppPriorityTableFirstHalfMask = 0;
1105 /* For each priority level */
1106 for(priority=0; priority<IX_QMGR_NUM_PRIORITY_LEVELS; priority++)
1108 /* Foreach low queue in this priority */
1109 for(qIndex=0; qIndex<IX_QMGR_MIN_QUEUPP_QID; qIndex++)
1111 if (dispatchQInfo[qIndex].priority == priority)
1113 /* build the priority table bitmask which match the
1114 * queues of the first half of the priority table
1116 if (lowQuePriorityTableIndex < IX_QMGR_MID_LOW_QUE_PRIORITY_TABLE_INDEX)
1118 lowPriorityTableFirstHalfMask |= dispatchQInfo[qIndex].intRegCheckMask;
1120 /* build the priority table */
1121 priorityTable[lowQuePriorityTableIndex++] = qIndex;
1124 /* Foreach upp queue */
1125 for(qIndex=IX_QMGR_MIN_QUEUPP_QID; qIndex<=IX_QMGR_MAX_QID; qIndex++)
1127 if (dispatchQInfo[qIndex].priority == priority)
1129 /* build the priority table bitmask which match the
1130 * queues of the first half of the priority table
1132 if (uppQuePriorityTableIndex < IX_QMGR_MID_UPP_QUE_PRIORITY_TABLE_INDEX)
1134 uppPriorityTableFirstHalfMask |= dispatchQInfo[qIndex].intRegCheckMask;
1136 /* build the priority table */
1137 priorityTable[uppQuePriorityTableIndex++] = qIndex;
1143 IxQMgrDispatcherStats*
1144 ixQMgrDispatcherStatsGet (void)
1146 return &dispatcherStats;
1150 dummyCallback (IxQMgrQId qId,
1151 IxQMgrCallbackId cbId)
1153 /* Throttle the trace message */
1154 if ((dispatchQInfo[qId].dummyCallbackCount % LOG_THROTTLE_COUNT) == 0)
1156 IX_QMGR_LOG_WARNING2("--> dummyCallback: qId (%d), callbackId (%d)\n",qId,cbId);
1158 dispatchQInfo[qId].dummyCallbackCount++;
1161 /* Update statistcs */
1162 dispatcherStats.queueStats[qId].intNoCallbackCnt++;
1166 ixQMgrLLPShow (int resetStats)
1170 UINT32 intEnableRegVal = 0;
1172 printf ("Livelock statistics are printed on the fly.\n");
1173 printf ("qId Type EnableCnt DisableCnt IntEnableState Callbacks\n");
1174 printf ("=== ======== ========= ========== ============== =========\n");
1176 for (i=0; i<= IX_QMGR_MAX_LOW_QUE_TABLE_INDEX; i++)
1178 if (ixQMgrQTypes[i] != IX_QMGR_TYPE_REALTIME_OTHER)
1180 printf (" %2d ", i);
1182 if (ixQMgrQTypes[i] == IX_QMGR_TYPE_REALTIME_SPORADIC)
1184 printf ("Sporadic");
1188 printf ("Periodic");
1192 ixQMgrAqmIfQInterruptEnableRegRead (IX_QMGR_QUELOW_GROUP,
1196 intEnableRegVal &= dispatchQInfo[i].intRegCheckMask;
1197 intEnableRegVal = intEnableRegVal >> i;
1199 printf (" %10d %10d %10d %10d\n",
1200 dispatcherStats.queueStats[i].enableCount,
1201 dispatcherStats.queueStats[i].disableCount,
1203 dispatcherStats.queueStats[i].callbackCnt);
1207 dispatcherStats.queueStats[i].enableCount =
1208 dispatcherStats.queueStats[i].disableCount =
1209 dispatcherStats.queueStats[i].callbackCnt = 0;
1214 IX_QMGR_LOG0("Livelock Prevention statistics are only collected in debug mode\n");
1219 ixQMgrPeriodicDone (void)
1222 UINT32 ixQMgrLockKey = 0;
1225 * for the lower queues
1227 for (i=0; i <= IX_QMGR_MAX_LOW_QUE_TABLE_INDEX; i++)
1230 * check for sporadics
1232 if (IX_QMGR_TYPE_REALTIME_SPORADIC == ixQMgrQTypes[i])
1235 * enable any sporadics
1237 ixQMgrLockKey = ixOsalIrqLock();
1238 ixQMgrAqmIfQInterruptEnable(i);
1239 ixOsalIrqUnlock(ixQMgrLockKey);
1244 dispatcherStats.queueStats[i].enableCount++;
1245 dispatcherStats.queueStats[i].notificationEnabled = true;
1251 ixQMgrCallbackTypeSet (IxQMgrQId qId,
1254 UINT32 ixQMgrLockKey = 0;
1255 IxQMgrType ixQMgrOldType =0;
1258 if (!ixQMgrQIsConfigured(qId))
1260 return IX_QMGR_Q_NOT_CONFIGURED;
1262 if (qId >= IX_QMGR_MIN_QUEUPP_QID)
1264 return IX_QMGR_PARAMETER_ERROR;
1266 if(!IX_QMGR_DISPATCHER_CALLBACK_TYPE_CHECK(type))
1268 return IX_QMGR_PARAMETER_ERROR;
1272 ixQMgrOldType = ixQMgrQTypes[qId];
1273 ixQMgrQTypes[qId] = type;
1276 * check if Q has been changed from type SPORADIC
1278 if (IX_QMGR_TYPE_REALTIME_SPORADIC == ixQMgrOldType)
1281 * previously Q was a SPORADIC, this means that LLP
1282 * might have had it disabled. enable it now.
1284 ixQMgrLockKey = ixOsalIrqLock();
1285 ixQMgrAqmIfQInterruptEnable(qId);
1286 ixOsalIrqUnlock(ixQMgrLockKey);
1292 dispatcherStats.queueStats[qId].enableCount++;
1300 ixQMgrCallbackTypeGet (IxQMgrQId qId,
1304 if (!ixQMgrQIsConfigured(qId))
1306 return IX_QMGR_Q_NOT_CONFIGURED;
1308 if (qId >= IX_QMGR_MIN_QUEUPP_QID)
1310 return IX_QMGR_PARAMETER_ERROR;
1314 return IX_QMGR_PARAMETER_ERROR;
1318 *type = ixQMgrQTypes[qId];