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 * Redistribution and use in source and binary forms, with or without
21 * modification, are permitted provided that the following conditions
23 * 1. Redistributions of source code must retain the above copyright
24 * notice, this list of conditions and the following disclaimer.
25 * 2. Redistributions in binary form must reproduce the above copyright
26 * notice, this list of conditions and the following disclaimer in the
27 * documentation and/or other materials provided with the distribution.
28 * 3. Neither the name of the Intel Corporation nor the names of its contributors
29 * may be used to endorse or promote products derived from this software
30 * without specific prior written permission.
33 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
34 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
35 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
36 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
37 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
38 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
39 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
40 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
41 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
42 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46 * -- End of Copyright Notice --
50 * User defined include files.
53 #include "IxQMgrAqmIf_p.h"
54 #include "IxQMgrQCfg_p.h"
55 #include "IxQMgrDispatcher_p.h"
56 #include "IxQMgrLog_p.h"
57 #include "IxQMgrDefines_p.h"
58 #include "IxFeatureCtrl.h"
64 * #defines and macros used in this file.
69 * This constant is used to indicate the number of priority levels supported
71 #define IX_QMGR_NUM_PRIORITY_LEVELS 3
74 * This constant is used to set the size of the array of status words
76 #define MAX_Q_STATUS_WORDS 4
79 * This macro is used to check if a given priority is valid
81 #define IX_QMGR_DISPATCHER_PRIORITY_CHECK(priority) \
82 (((priority) >= IX_QMGR_Q_PRIORITY_0) && ((priority) <= IX_QMGR_Q_PRIORITY_2))
85 * This macto is used to check that a given interrupt source is valid
87 #define IX_QMGR_DISPATCHER_SOURCE_ID_CHECK(srcSel) \
88 (((srcSel) >= IX_QMGR_Q_SOURCE_ID_E) && ((srcSel) <= IX_QMGR_Q_SOURCE_ID_NOT_F))
91 * Number of times a dummy callback is called before logging a trace
94 #define LOG_THROTTLE_COUNT 1000000
96 /* Priority tables limits */
97 #define IX_QMGR_MIN_LOW_QUE_PRIORITY_TABLE_INDEX (0)
98 #define IX_QMGR_MID_LOW_QUE_PRIORITY_TABLE_INDEX (16)
99 #define IX_QMGR_MAX_LOW_QUE_PRIORITY_TABLE_INDEX (31)
100 #define IX_QMGR_MIN_UPP_QUE_PRIORITY_TABLE_INDEX (32)
101 #define IX_QMGR_MID_UPP_QUE_PRIORITY_TABLE_INDEX (48)
102 #define IX_QMGR_MAX_UPP_QUE_PRIORITY_TABLE_INDEX (63)
105 * This macro is used to check if a given callback type is valid
107 #define IX_QMGR_DISPATCHER_CALLBACK_TYPE_CHECK(type) \
108 (((type) >= IX_QMGR_TYPE_REALTIME_OTHER) && \
109 ((type) <= IX_QMGR_TYPE_REALTIME_SPORADIC))
112 * define max index in lower queue to use in loops
114 #define IX_QMGR_MAX_LOW_QUE_TABLE_INDEX (31)
117 * Typedefs whose scope is limited to this file.
121 * Information on a queue needed by the Dispatcher
125 IxQMgrCallback callback; /* Notification callback */
126 IxQMgrCallbackId callbackId; /* Notification callback identifier */
127 unsigned dummyCallbackCount; /* Number of times runs of dummy callback */
128 IxQMgrPriority priority; /* Dispatch priority */
129 unsigned int statusWordOffset; /* Offset to the status word to check */
130 UINT32 statusMask; /* Status mask */
131 UINT32 statusCheckValue; /* Status check value */
132 UINT32 intRegCheckMask; /* Interrupt register check mask */
136 * Variable declarations global to this file. Externs are followed by
141 * Flag to keep record of what dispatcher set in featureCtrl when ixQMgrInit()
142 * is called. This is needed because it is possible that a client might
143 * change whether the live lock prevention dispatcher is used between
144 * calls to ixQMgrInit() and ixQMgrDispatcherLoopGet().
146 PRIVATE IX_STATUS ixQMgrOrigB0Dispatcher = IX_FEATURE_CTRL_COMPONENT_ENABLED;
149 * keep record of Q types - not in IxQMgrQInfo for performance as
150 * it is only used with ixQMgrDispatcherLoopRunB0LLP()
152 PRIVATE IxQMgrType ixQMgrQTypes[IX_QMGR_MAX_NUM_QUEUES];
155 * This array contains a list of queue identifiers ordered by priority. The table
156 * is split logically between queue identifiers 0-31 and 32-63.
158 static IxQMgrQId priorityTable[IX_QMGR_MAX_NUM_QUEUES];
161 * This flag indicates to the dispatcher that the priority table needs to be rebuilt.
163 static BOOL rebuildTable = FALSE;
165 /* Dispatcher statistics */
166 static IxQMgrDispatcherStats dispatcherStats;
168 /* Table of queue information */
169 static IxQMgrQInfo dispatchQInfo[IX_QMGR_MAX_NUM_QUEUES];
171 /* Masks use to identify the first queues in the priority tables
172 * when comparing with the interrupt register
174 static unsigned int lowPriorityTableFirstHalfMask;
175 static unsigned int uppPriorityTableFirstHalfMask;
178 * Static function prototypes
182 * This function is the default callback for all queues
185 dummyCallback (IxQMgrQId qId,
186 IxQMgrCallbackId cbId);
189 ixQMgrDispatcherReBuildPriorityTable (void);
192 * Function definitions.
195 ixQMgrDispatcherInit (void)
198 IxFeatureCtrlProductId productId = 0;
199 IxFeatureCtrlDeviceId deviceId = 0;
200 BOOL stickyIntSilicon = TRUE;
202 /* Set default priorities */
203 for (i=0; i< IX_QMGR_MAX_NUM_QUEUES; i++)
205 dispatchQInfo[i].callback = dummyCallback;
206 dispatchQInfo[i].callbackId = 0;
207 dispatchQInfo[i].dummyCallbackCount = 0;
208 dispatchQInfo[i].priority = IX_QMGR_Q_PRIORITY_2;
209 dispatchQInfo[i].statusWordOffset = 0;
210 dispatchQInfo[i].statusCheckValue = 0;
211 dispatchQInfo[i].statusMask = 0;
213 * There are two interrupt registers, 32 bits each. One for the lower
214 * queues(0-31) and one for the upper queues(32-63). Therefore need to
215 * mod by 32 i.e the min upper queue identifier.
217 dispatchQInfo[i].intRegCheckMask = (1<<(i%(IX_QMGR_MIN_QUEUPP_QID)));
220 * Set the Q types - will only be used with livelock
222 ixQMgrQTypes[i] = IX_QMGR_TYPE_REALTIME_OTHER;
224 /* Reset queue statistics */
225 dispatcherStats.queueStats[i].callbackCnt = 0;
226 dispatcherStats.queueStats[i].priorityChangeCnt = 0;
227 dispatcherStats.queueStats[i].intNoCallbackCnt = 0;
228 dispatcherStats.queueStats[i].intLostCallbackCnt = 0;
229 dispatcherStats.queueStats[i].notificationEnabled = FALSE;
230 dispatcherStats.queueStats[i].srcSel = 0;
234 /* Priority table. Order the table from queue 0 to 63 */
235 ixQMgrDispatcherReBuildPriorityTable();
237 /* Reset statistics */
238 dispatcherStats.loopRunCnt = 0;
240 /* Get the device ID for the underlying silicon */
241 deviceId = ixFeatureCtrlDeviceRead();
243 /* Get the product ID for the underlying silicon */
244 productId = ixFeatureCtrlProductIdRead();
247 * Check featureCtrl to see if Livelock prevention is required
249 ixQMgrOrigB0Dispatcher = ixFeatureCtrlSwConfigurationCheck(
250 IX_FEATURECTRL_ORIGB0_DISPATCHER);
253 * Check if the silicon supports the sticky interrupt feature.
254 * IF (IXP42X AND A0) -> No sticky interrupt feature supported
256 if ((IX_FEATURE_CTRL_DEVICE_TYPE_IXP42X ==
257 (IX_FEATURE_CTRL_DEVICE_TYPE_MASK & deviceId)) &&
258 (IX_FEATURE_CTRL_SILICON_TYPE_A0 ==
259 (IX_FEATURE_CTRL_SILICON_STEPPING_MASK & productId)))
261 stickyIntSilicon = FALSE;
265 * IF user wants livelock prev option AND silicon supports sticky interrupt
266 * feature -> enable the sticky interrupt bit
268 if ((IX_FEATURE_CTRL_SWCONFIG_DISABLED == ixQMgrOrigB0Dispatcher) &&
271 ixQMgrStickyInterruptRegEnable();
276 ixQMgrDispatcherPrioritySet (IxQMgrQId qId,
277 IxQMgrPriority priority)
281 if (!ixQMgrQIsConfigured(qId))
283 return IX_QMGR_Q_NOT_CONFIGURED;
286 if (!IX_QMGR_DISPATCHER_PRIORITY_CHECK(priority))
288 return IX_QMGR_Q_INVALID_PRIORITY;
291 ixQMgrLockKey = ixOsalIrqLock();
293 /* Change priority */
294 dispatchQInfo[qId].priority = priority;
298 ixOsalIrqUnlock(ixQMgrLockKey);
301 /* Update statistics */
302 dispatcherStats.queueStats[qId].priorityChangeCnt++;
309 ixQMgrNotificationCallbackSet (IxQMgrQId qId,
310 IxQMgrCallback callback,
311 IxQMgrCallbackId callbackId)
313 if (!ixQMgrQIsConfigured(qId))
315 return IX_QMGR_Q_NOT_CONFIGURED;
318 if (NULL == callback)
320 /* Reset to dummy callback */
321 dispatchQInfo[qId].callback = dummyCallback;
322 dispatchQInfo[qId].dummyCallbackCount = 0;
323 dispatchQInfo[qId].callbackId = 0;
327 dispatchQInfo[qId].callback = callback;
328 dispatchQInfo[qId].callbackId = callbackId;
335 ixQMgrNotificationEnable (IxQMgrQId qId,
336 IxQMgrSourceId srcSel)
338 IxQMgrQStatus qStatusOnEntry;/* The queue status on entry/exit */
339 IxQMgrQStatus qStatusOnExit; /* to this function */
343 if (!ixQMgrQIsConfigured (qId))
345 return IX_QMGR_Q_NOT_CONFIGURED;
348 if ((qId < IX_QMGR_MIN_QUEUPP_QID) &&
349 !IX_QMGR_DISPATCHER_SOURCE_ID_CHECK(srcSel))
351 /* QId 0-31 source id invalid */
352 return IX_QMGR_INVALID_INT_SOURCE_ID;
355 if ((IX_QMGR_Q_SOURCE_ID_NE != srcSel) &&
356 (qId >= IX_QMGR_MIN_QUEUPP_QID))
359 * For queues 32-63 the interrupt source is fixed to the Nearly
360 * Empty status flag and therefore should have a srcSel of NE.
362 return IX_QMGR_INVALID_INT_SOURCE_ID;
367 dispatcherStats.queueStats[qId].notificationEnabled = TRUE;
368 dispatcherStats.queueStats[qId].srcSel = srcSel;
371 /* Get the current queue status */
372 ixQMgrAqmIfQueStatRead (qId, &qStatusOnEntry);
375 * Enabling interrupts results in Read-Modify-Write
376 * so need critical section
379 ixQMgrLockKey = ixOsalIrqLock();
381 /* Calculate the checkMask and checkValue for this q */
382 ixQMgrAqmIfQStatusCheckValsCalc (qId,
384 &dispatchQInfo[qId].statusWordOffset,
385 &dispatchQInfo[qId].statusCheckValue,
386 &dispatchQInfo[qId].statusMask);
389 /* Set the interupt source is this queue is in the range 0-31 */
390 if (qId < IX_QMGR_MIN_QUEUPP_QID)
392 ixQMgrAqmIfIntSrcSelWrite (qId, srcSel);
395 /* Enable the interrupt */
396 ixQMgrAqmIfQInterruptEnable (qId);
398 ixOsalIrqUnlock(ixQMgrLockKey);
400 /* Get the current queue status */
401 ixQMgrAqmIfQueStatRead (qId, &qStatusOnExit);
403 /* If the status has changed return a warning */
404 if (qStatusOnEntry != qStatusOnExit)
406 return IX_QMGR_WARNING;
414 ixQMgrNotificationDisable (IxQMgrQId qId)
419 /* Validate parameters */
420 if (!ixQMgrQIsConfigured (qId))
422 return IX_QMGR_Q_NOT_CONFIGURED;
427 * Enabling interrupts results in Read-Modify-Write
428 * so need critical section
431 dispatcherStats.queueStats[qId].notificationEnabled = FALSE;
434 ixQMgrLockKey = ixOsalIrqLock();
436 ixQMgrAqmIfQInterruptDisable (qId);
438 ixOsalIrqUnlock(ixQMgrLockKey);
444 ixQMgrStickyInterruptRegEnable(void)
446 /* Use Aqm If function to set Interrupt Register0 Bit-3 */
447 ixQMgrAqmIfIntSrcSelReg0Bit3Set ();
450 #if !defined __XSCALE__ || defined __linux
452 /* Count the number of leading zero bits in a word,
453 * and return the same value than the CLZ instruction.
455 * word (in) return value (out)
463 * The C version of this function is used as a replacement
464 * for system not providing the equivalent of the CLZ
465 * assembly language instruction.
467 * Note that this version is big-endian
470 ixQMgrCountLeadingZeros(UINT32 word)
472 unsigned int leadingZerosCount = 0;
478 /* search the first bit set by testing the MSB and shifting the input word */
479 while ((word & 0x80000000) == 0)
484 return leadingZerosCount;
486 #endif /* not __XSCALE__ or __linux */
489 ixQMgrDispatcherLoopGet (IxQMgrDispatcherFuncPtr *qDispatcherFuncPtr)
491 IxFeatureCtrlProductId productId = 0;
492 IxFeatureCtrlDeviceId deviceId = 0;
494 /* Get the device ID for the underlying silicon */
495 deviceId = ixFeatureCtrlDeviceRead();
497 /* Get the product ID for the underlying silicon */
498 productId = ixFeatureCtrlProductIdRead ();
500 /* IF (IXP42X AND A0 silicon) -> use ixQMgrDispatcherLoopRunA0 */
501 if ((IX_FEATURE_CTRL_DEVICE_TYPE_IXP42X ==
502 (IX_FEATURE_CTRL_DEVICE_TYPE_MASK & deviceId)) &&
503 (IX_FEATURE_CTRL_SILICON_TYPE_A0 ==
504 (IX_FEATURE_CTRL_SILICON_STEPPING_MASK & productId)))
506 /*For IXP42X A0 silicon */
507 *qDispatcherFuncPtr = &ixQMgrDispatcherLoopRunA0 ;
509 else /*For IXP42X B0 or IXP46X silicon*/
511 if (IX_FEATURE_CTRL_SWCONFIG_ENABLED == ixQMgrOrigB0Dispatcher)
513 /* Default for IXP42X B0 and IXP46X silicon */
514 *qDispatcherFuncPtr = &ixQMgrDispatcherLoopRunB0;
518 /* FeatureCtrl indicated that livelock dispatcher be used */
519 *qDispatcherFuncPtr = &ixQMgrDispatcherLoopRunB0LLP;
525 ixQMgrDispatcherLoopRunA0 (IxQMgrDispatchGroup group)
527 UINT32 intRegVal; /* Interrupt reg val */
528 UINT32 intRegValAfterWrite; /* Interrupt reg val after writing back */
529 UINT32 intRegCheckMask; /* Mask for checking interrupt bits */
530 UINT32 qStatusWordsB4Write[MAX_Q_STATUS_WORDS]; /* Status b4 interrupt write */
531 UINT32 qStatusWordsAfterWrite[MAX_Q_STATUS_WORDS]; /* Status after interrupt write */
532 IxQMgrQInfo *currDispatchQInfo;
533 BOOL statusChangeFlag;
535 int priorityTableIndex;/* Priority table index */
536 int qIndex; /* Current queue being processed */
537 int endIndex; /* Index of last queue to process */
540 IX_OSAL_ASSERT((group == IX_QMGR_QUEUPP_GROUP) ||
541 (group == IX_QMGR_QUELOW_GROUP));
544 /* Read Q status registers before interrupt status read/write */
545 ixQMgrAqmIfQStatusRegsRead (group, qStatusWordsB4Write);
547 /* Read the interrupt register */
548 ixQMgrAqmIfQInterruptRegRead (group, &intRegVal);
550 /* No bit set : nothing to process (the reaminder of the algorithm is
551 * based on the fact that the interrupt register value contains at
557 /* Update statistics */
558 dispatcherStats.loopRunCnt++;
561 /* Rebuild the priority table if needed */
564 ixQMgrDispatcherReBuildPriorityTable ();
570 /* Write it back to clear the interrupt */
571 ixQMgrAqmIfQInterruptRegWrite (group, intRegVal);
573 /* Read Q status registers after interrupt status read/write */
574 ixQMgrAqmIfQStatusRegsRead (group, qStatusWordsAfterWrite);
576 /* get the first queue Id from the interrupt register value */
577 qIndex = (BITS_PER_WORD - 1) - ixQMgrCountLeadingZeros(intRegVal);
579 /* check if any change occured during hw register modifications */
580 if (IX_QMGR_QUELOW_GROUP == group)
583 (qStatusWordsB4Write[0] != qStatusWordsAfterWrite[0]) ||
584 (qStatusWordsB4Write[1] != qStatusWordsAfterWrite[1]) ||
585 (qStatusWordsB4Write[2] != qStatusWordsAfterWrite[2]) ||
586 (qStatusWordsB4Write[3] != qStatusWordsAfterWrite[3]);
591 (qStatusWordsB4Write[0] != qStatusWordsAfterWrite[0]);
592 /* Set the queue range based on the queue group to proccess */
593 qIndex += IX_QMGR_MIN_QUEUPP_QID;
596 if (statusChangeFlag == FALSE)
598 /* check if the interrupt register contains
599 * only 1 bit set (happy day scenario)
601 currDispatchQInfo = &dispatchQInfo[qIndex];
602 if (intRegVal == currDispatchQInfo->intRegCheckMask)
604 /* only 1 queue event triggered a notification *
605 * Call the callback function for this queue
607 currDispatchQInfo->callback (qIndex,
608 currDispatchQInfo->callbackId);
610 /* Update statistics */
611 dispatcherStats.queueStats[qIndex].callbackCnt++;
616 /* the event is triggered by more than 1 queue,
617 * the queue search will be starting from the beginning
618 * or the middle of the priority table
620 * the serach will end when all the bits of the interrupt
621 * register are cleared. There is no need to maintain
622 * a seperate value and test it at each iteration.
624 if (IX_QMGR_QUELOW_GROUP == group)
626 /* check if any bit related to queues in the first
627 * half of the priority table is set
629 if (intRegVal & lowPriorityTableFirstHalfMask)
631 priorityTableIndex = IX_QMGR_MIN_LOW_QUE_PRIORITY_TABLE_INDEX;
635 priorityTableIndex = IX_QMGR_MID_LOW_QUE_PRIORITY_TABLE_INDEX;
640 /* check if any bit related to queues in the first
641 * half of the priority table is set
643 if (intRegVal & uppPriorityTableFirstHalfMask)
645 priorityTableIndex = IX_QMGR_MIN_UPP_QUE_PRIORITY_TABLE_INDEX;
649 priorityTableIndex = IX_QMGR_MID_UPP_QUE_PRIORITY_TABLE_INDEX;
653 /* iterate following the priority table until all the bits
654 * of the interrupt register are cleared.
658 qIndex = priorityTable[priorityTableIndex++];
659 currDispatchQInfo = &dispatchQInfo[qIndex];
660 intRegCheckMask = currDispatchQInfo->intRegCheckMask;
662 /* If this queue caused this interrupt to be raised */
663 if (intRegVal & intRegCheckMask)
665 /* Call the callback function for this queue */
666 currDispatchQInfo->callback (qIndex,
667 currDispatchQInfo->callbackId);
669 /* Update statistics */
670 dispatcherStats.queueStats[qIndex].callbackCnt++;
673 /* Clear the interrupt register bit */
674 intRegVal &= ~intRegCheckMask;
682 /* A change in queue status occured during the hw interrupt
683 * register update. To maintain the interrupt consistency, it
684 * is necessary to iterate through all queues of the queue group.
687 /* Read interrupt status again */
688 ixQMgrAqmIfQInterruptRegRead (group, &intRegValAfterWrite);
690 if (IX_QMGR_QUELOW_GROUP == group)
692 priorityTableIndex = IX_QMGR_MIN_LOW_QUE_PRIORITY_TABLE_INDEX;
693 endIndex = IX_QMGR_MAX_LOW_QUE_PRIORITY_TABLE_INDEX;
697 priorityTableIndex = IX_QMGR_MIN_UPP_QUE_PRIORITY_TABLE_INDEX;
698 endIndex = IX_QMGR_MAX_UPP_QUE_PRIORITY_TABLE_INDEX;
701 for ( ; priorityTableIndex<=endIndex; priorityTableIndex++)
703 qIndex = priorityTable[priorityTableIndex];
704 currDispatchQInfo = &dispatchQInfo[qIndex];
705 intRegCheckMask = currDispatchQInfo->intRegCheckMask;
707 /* If this queue caused this interrupt to be raised */
708 if (intRegVal & intRegCheckMask)
710 /* Call the callback function for this queue */
711 currDispatchQInfo->callback (qIndex,
712 currDispatchQInfo->callbackId);
714 /* Update statistics */
715 dispatcherStats.queueStats[qIndex].callbackCnt++;
718 } /* if (intRegVal .. */
721 * If interrupt bit is set in intRegValAfterWrite don't
722 * proceed as this will be caught in next interrupt
724 else if ((intRegValAfterWrite & intRegCheckMask) == 0)
726 /* Check if an interrupt was lost for this Q */
727 if (ixQMgrAqmIfQStatusCheck(qStatusWordsB4Write,
728 qStatusWordsAfterWrite,
729 currDispatchQInfo->statusWordOffset,
730 currDispatchQInfo->statusCheckValue,
731 currDispatchQInfo->statusMask))
733 /* Call the callback function for this queue */
734 currDispatchQInfo->callback (qIndex,
735 dispatchQInfo[qIndex].callbackId);
737 /* Update statistics */
738 dispatcherStats.queueStats[qIndex].callbackCnt++;
739 dispatcherStats.queueStats[qIndex].intLostCallbackCnt++;
741 } /* if ixQMgrAqmIfQStatusCheck(.. */
742 } /* else if ((intRegValAfterWrite ... */
743 } /* for (priorityTableIndex=0 ... */
746 /* Rebuild the priority table if needed */
749 ixQMgrDispatcherReBuildPriorityTable ();
753 /* Update statistics */
754 dispatcherStats.loopRunCnt++;
761 ixQMgrDispatcherLoopRunB0 (IxQMgrDispatchGroup group)
763 UINT32 intRegVal; /* Interrupt reg val */
764 UINT32 intRegCheckMask; /* Mask for checking interrupt bits */
765 IxQMgrQInfo *currDispatchQInfo;
768 int priorityTableIndex; /* Priority table index */
769 int qIndex; /* Current queue being processed */
772 IX_OSAL_ASSERT((group == IX_QMGR_QUEUPP_GROUP) ||
773 (group == IX_QMGR_QUELOW_GROUP));
774 IX_OSAL_ASSERT((group == IX_QMGR_QUEUPP_GROUP) ||
775 (group == IX_QMGR_QUELOW_GROUP));
778 /* Read the interrupt register */
779 ixQMgrAqmIfQInterruptRegRead (group, &intRegVal);
782 /* No queue has interrupt register set */
786 /* Write it back to clear the interrupt */
787 ixQMgrAqmIfQInterruptRegWrite (group, intRegVal);
789 /* get the first queue Id from the interrupt register value */
790 qIndex = (BITS_PER_WORD - 1) - ixQMgrCountLeadingZeros(intRegVal);
792 if (IX_QMGR_QUEUPP_GROUP == group)
794 /* Set the queue range based on the queue group to proccess */
795 qIndex += IX_QMGR_MIN_QUEUPP_QID;
798 /* check if the interrupt register contains
802 * currDispatchQInfo->intRegCheckMask = 0x0010
803 * intRegVal == currDispatchQInfo->intRegCheckMask is TRUE.
805 currDispatchQInfo = &dispatchQInfo[qIndex];
806 if (intRegVal == currDispatchQInfo->intRegCheckMask)
808 /* only 1 queue event triggered a notification *
809 * Call the callback function for this queue
811 currDispatchQInfo->callback (qIndex,
812 currDispatchQInfo->callbackId);
814 /* Update statistics */
815 dispatcherStats.queueStats[qIndex].callbackCnt++;
820 /* the event is triggered by more than 1 queue,
821 * the queue search will be starting from the beginning
822 * or the middle of the priority table
824 * the serach will end when all the bits of the interrupt
825 * register are cleared. There is no need to maintain
826 * a seperate value and test it at each iteration.
828 if (IX_QMGR_QUELOW_GROUP == group)
830 /* check if any bit related to queues in the first
831 * half of the priority table is set
833 if (intRegVal & lowPriorityTableFirstHalfMask)
835 priorityTableIndex = IX_QMGR_MIN_LOW_QUE_PRIORITY_TABLE_INDEX;
839 priorityTableIndex = IX_QMGR_MID_LOW_QUE_PRIORITY_TABLE_INDEX;
844 /* check if any bit related to queues in the first
845 * half of the priority table is set
847 if (intRegVal & uppPriorityTableFirstHalfMask)
849 priorityTableIndex = IX_QMGR_MIN_UPP_QUE_PRIORITY_TABLE_INDEX;
853 priorityTableIndex = IX_QMGR_MID_UPP_QUE_PRIORITY_TABLE_INDEX;
857 /* iterate following the priority table until all the bits
858 * of the interrupt register are cleared.
862 qIndex = priorityTable[priorityTableIndex++];
863 currDispatchQInfo = &dispatchQInfo[qIndex];
864 intRegCheckMask = currDispatchQInfo->intRegCheckMask;
866 /* If this queue caused this interrupt to be raised */
867 if (intRegVal & intRegCheckMask)
869 /* Call the callback function for this queue */
870 currDispatchQInfo->callback (qIndex,
871 currDispatchQInfo->callbackId);
873 /* Update statistics */
874 dispatcherStats.queueStats[qIndex].callbackCnt++;
877 /* Clear the interrupt register bit */
878 intRegVal &= ~intRegCheckMask;
882 } /*End of intRegVal == currDispatchQInfo->intRegCheckMask */
883 } /* End of intRegVal != 0 */
886 /* Update statistics */
887 dispatcherStats.loopRunCnt++;
890 /* Rebuild the priority table if needed */
893 ixQMgrDispatcherReBuildPriorityTable ();
898 ixQMgrDispatcherLoopRunB0LLP (IxQMgrDispatchGroup group)
900 UINT32 intRegVal =0; /* Interrupt reg val */
901 UINT32 intRegCheckMask; /* Mask for checking interrupt bits */
902 IxQMgrQInfo *currDispatchQInfo;
904 int priorityTableIndex; /* Priority table index */
905 int qIndex; /* Current queue being processed */
907 UINT32 intRegValCopy = 0;
908 UINT32 intEnableRegVal = 0;
912 IX_OSAL_ASSERT((group == IX_QMGR_QUEUPP_GROUP) ||
913 (group == IX_QMGR_QUELOW_GROUP));
916 /* Read the interrupt register */
917 ixQMgrAqmIfQInterruptRegRead (group, &intRegVal);
920 * mask any interrupts that are not enabled
922 ixQMgrAqmIfQInterruptEnableRegRead (group, &intEnableRegVal);
923 intRegVal &= intEnableRegVal;
925 /* No queue has interrupt register set */
928 if (IX_QMGR_QUELOW_GROUP == group)
931 * As the sticky bit is set, the interrupt register will
932 * not clear if write back at this point because the condition
933 * has not been cleared. Take a copy and write back later after
934 * the condition has been cleared
936 intRegValCopy = intRegVal;
940 /* no sticky for upper Q's, so write back now */
941 ixQMgrAqmIfQInterruptRegWrite (group, intRegVal);
944 /* get the first queue Id from the interrupt register value */
945 qIndex = (BITS_PER_WORD - 1) - ixQMgrCountLeadingZeros(intRegVal);
947 if (IX_QMGR_QUEUPP_GROUP == group)
949 /* Set the queue range based on the queue group to proccess */
950 qIndex += IX_QMGR_MIN_QUEUPP_QID;
953 /* check if the interrupt register contains
957 * currDispatchQInfo->intRegCheckMask = 0x0010
958 * intRegVal == currDispatchQInfo->intRegCheckMask is TRUE.
960 currDispatchQInfo = &dispatchQInfo[qIndex];
961 if (intRegVal == currDispatchQInfo->intRegCheckMask)
965 * check if Q type periodic - only lower queues can
966 * have there type set to periodic
968 if (IX_QMGR_TYPE_REALTIME_PERIODIC == ixQMgrQTypes[qIndex])
971 * Disable the notifications on any sporadics
973 for (i=0; i <= IX_QMGR_MAX_LOW_QUE_TABLE_INDEX; i++)
975 if (IX_QMGR_TYPE_REALTIME_SPORADIC == ixQMgrQTypes[i])
977 ixQMgrNotificationDisable(i);
979 /* Update statistics */
980 dispatcherStats.queueStats[i].disableCount++;
986 currDispatchQInfo->callback (qIndex,
987 currDispatchQInfo->callbackId);
989 /* Update statistics */
990 dispatcherStats.queueStats[qIndex].callbackCnt++;
995 /* the event is triggered by more than 1 queue,
996 * the queue search will be starting from the beginning
997 * or the middle of the priority table
999 * the serach will end when all the bits of the interrupt
1000 * register are cleared. There is no need to maintain
1001 * a seperate value and test it at each iteration.
1003 if (IX_QMGR_QUELOW_GROUP == group)
1005 /* check if any bit related to queues in the first
1006 * half of the priority table is set
1008 if (intRegVal & lowPriorityTableFirstHalfMask)
1010 priorityTableIndex =
1011 IX_QMGR_MIN_LOW_QUE_PRIORITY_TABLE_INDEX;
1015 priorityTableIndex =
1016 IX_QMGR_MID_LOW_QUE_PRIORITY_TABLE_INDEX;
1021 /* check if any bit related to queues in the first
1022 * half of the priority table is set
1024 if (intRegVal & uppPriorityTableFirstHalfMask)
1026 priorityTableIndex =
1027 IX_QMGR_MIN_UPP_QUE_PRIORITY_TABLE_INDEX;
1031 priorityTableIndex =
1032 IX_QMGR_MID_UPP_QUE_PRIORITY_TABLE_INDEX;
1036 /* iterate following the priority table until all the bits
1037 * of the interrupt register are cleared.
1041 qIndex = priorityTable[priorityTableIndex++];
1042 currDispatchQInfo = &dispatchQInfo[qIndex];
1043 intRegCheckMask = currDispatchQInfo->intRegCheckMask;
1045 /* If this queue caused this interrupt to be raised */
1046 if (intRegVal & intRegCheckMask)
1049 * check if Q type periodic - only lower queues can
1050 * have there type set to periodic. There can only be one
1051 * periodic queue, so the sporadics are only disabled once.
1053 if (IX_QMGR_TYPE_REALTIME_PERIODIC == ixQMgrQTypes[qIndex])
1056 * Disable the notifications on any sporadics
1058 for (i=0; i <= IX_QMGR_MAX_LOW_QUE_TABLE_INDEX; i++)
1060 if (IX_QMGR_TYPE_REALTIME_SPORADIC ==
1063 ixQMgrNotificationDisable(i);
1065 * remove from intRegVal as we don't want
1066 * to service any sporadics now
1068 intRegVal &= ~dispatchQInfo[i].intRegCheckMask;
1070 /* Update statistics */
1071 dispatcherStats.queueStats[i].disableCount++;
1077 currDispatchQInfo->callback (qIndex,
1078 currDispatchQInfo->callbackId);
1080 /* Update statistics */
1081 dispatcherStats.queueStats[qIndex].callbackCnt++;
1083 /* Clear the interrupt register bit */
1084 intRegVal &= ~intRegCheckMask;
1088 } /*End of intRegVal == currDispatchQInfo->intRegCheckMask */
1089 } /* End of intRegVal != 0 */
1092 /* Update statistics */
1093 dispatcherStats.loopRunCnt++;
1096 if ((intRegValCopy != 0) && (IX_QMGR_QUELOW_GROUP == group))
1099 * lower groups (therefore sticky) AND at least one enabled interrupt
1100 * Write back to clear the interrupt
1102 ixQMgrAqmIfQInterruptRegWrite (IX_QMGR_QUELOW_GROUP, intRegValCopy);
1105 /* Rebuild the priority table if needed */
1108 ixQMgrDispatcherReBuildPriorityTable ();
1113 ixQMgrDispatcherReBuildPriorityTable (void)
1117 int lowQuePriorityTableIndex = IX_QMGR_MIN_LOW_QUE_PRIORITY_TABLE_INDEX;
1118 int uppQuePriorityTableIndex = IX_QMGR_MIN_UPP_QUE_PRIORITY_TABLE_INDEX;
1120 /* Reset the rebuild flag */
1121 rebuildTable = FALSE;
1123 /* initialize the mak used to identify the queues in the first half
1124 * of the priority table
1126 lowPriorityTableFirstHalfMask = 0;
1127 uppPriorityTableFirstHalfMask = 0;
1129 /* For each priority level */
1130 for(priority=0; priority<IX_QMGR_NUM_PRIORITY_LEVELS; priority++)
1132 /* Foreach low queue in this priority */
1133 for(qIndex=0; qIndex<IX_QMGR_MIN_QUEUPP_QID; qIndex++)
1135 if (dispatchQInfo[qIndex].priority == priority)
1137 /* build the priority table bitmask which match the
1138 * queues of the first half of the priority table
1140 if (lowQuePriorityTableIndex < IX_QMGR_MID_LOW_QUE_PRIORITY_TABLE_INDEX)
1142 lowPriorityTableFirstHalfMask |= dispatchQInfo[qIndex].intRegCheckMask;
1144 /* build the priority table */
1145 priorityTable[lowQuePriorityTableIndex++] = qIndex;
1148 /* Foreach upp queue */
1149 for(qIndex=IX_QMGR_MIN_QUEUPP_QID; qIndex<=IX_QMGR_MAX_QID; qIndex++)
1151 if (dispatchQInfo[qIndex].priority == priority)
1153 /* build the priority table bitmask which match the
1154 * queues of the first half of the priority table
1156 if (uppQuePriorityTableIndex < IX_QMGR_MID_UPP_QUE_PRIORITY_TABLE_INDEX)
1158 uppPriorityTableFirstHalfMask |= dispatchQInfo[qIndex].intRegCheckMask;
1160 /* build the priority table */
1161 priorityTable[uppQuePriorityTableIndex++] = qIndex;
1167 IxQMgrDispatcherStats*
1168 ixQMgrDispatcherStatsGet (void)
1170 return &dispatcherStats;
1174 dummyCallback (IxQMgrQId qId,
1175 IxQMgrCallbackId cbId)
1177 /* Throttle the trace message */
1178 if ((dispatchQInfo[qId].dummyCallbackCount % LOG_THROTTLE_COUNT) == 0)
1180 IX_QMGR_LOG_WARNING2("--> dummyCallback: qId (%d), callbackId (%d)\n",qId,cbId);
1182 dispatchQInfo[qId].dummyCallbackCount++;
1185 /* Update statistcs */
1186 dispatcherStats.queueStats[qId].intNoCallbackCnt++;
1190 ixQMgrLLPShow (int resetStats)
1195 UINT32 intEnableRegVal = 0;
1197 printf ("Livelock statistics are printed on the fly.\n");
1198 printf ("qId Type EnableCnt DisableCnt IntEnableState Callbacks\n");
1199 printf ("=== ======== ========= ========== ============== =========\n");
1201 for (i=0; i<= IX_QMGR_MAX_LOW_QUE_TABLE_INDEX; i++)
1203 q = &dispatchQInfo[i];
1205 if (ixQMgrQTypes[i] != IX_QMGR_TYPE_REALTIME_OTHER)
1207 printf (" %2d ", i);
1209 if (ixQMgrQTypes[i] == IX_QMGR_TYPE_REALTIME_SPORADIC)
1211 printf ("Sporadic");
1215 printf ("Periodic");
1219 ixQMgrAqmIfQInterruptEnableRegRead (IX_QMGR_QUELOW_GROUP,
1223 intEnableRegVal &= dispatchQInfo[i].intRegCheckMask;
1224 intEnableRegVal = intEnableRegVal >> i;
1226 printf (" %10d %10d %10d %10d\n",
1227 dispatcherStats.queueStats[i].enableCount,
1228 dispatcherStats.queueStats[i].disableCount,
1230 dispatcherStats.queueStats[i].callbackCnt);
1234 dispatcherStats.queueStats[i].enableCount =
1235 dispatcherStats.queueStats[i].disableCount =
1236 dispatcherStats.queueStats[i].callbackCnt = 0;
1241 IX_QMGR_LOG0("Livelock Prevention statistics are only collected in debug mode\n");
1246 ixQMgrPeriodicDone (void)
1249 UINT32 ixQMgrLockKey = 0;
1252 * for the lower queues
1254 for (i=0; i <= IX_QMGR_MAX_LOW_QUE_TABLE_INDEX; i++)
1257 * check for sporadics
1259 if (IX_QMGR_TYPE_REALTIME_SPORADIC == ixQMgrQTypes[i])
1262 * enable any sporadics
1264 ixQMgrLockKey = ixOsalIrqLock();
1265 ixQMgrAqmIfQInterruptEnable(i);
1266 ixOsalIrqUnlock(ixQMgrLockKey);
1271 dispatcherStats.queueStats[i].enableCount++;
1272 dispatcherStats.queueStats[i].notificationEnabled = TRUE;
1278 ixQMgrCallbackTypeSet (IxQMgrQId qId,
1281 UINT32 ixQMgrLockKey = 0;
1282 IxQMgrType ixQMgrOldType =0;
1285 if (!ixQMgrQIsConfigured(qId))
1287 return IX_QMGR_Q_NOT_CONFIGURED;
1289 if (qId >= IX_QMGR_MIN_QUEUPP_QID)
1291 return IX_QMGR_PARAMETER_ERROR;
1293 if(!IX_QMGR_DISPATCHER_CALLBACK_TYPE_CHECK(type))
1295 return IX_QMGR_PARAMETER_ERROR;
1299 ixQMgrOldType = ixQMgrQTypes[qId];
1300 ixQMgrQTypes[qId] = type;
1303 * check if Q has been changed from type SPORADIC
1305 if (IX_QMGR_TYPE_REALTIME_SPORADIC == ixQMgrOldType)
1308 * previously Q was a SPORADIC, this means that LLP
1309 * might have had it disabled. enable it now.
1311 ixQMgrLockKey = ixOsalIrqLock();
1312 ixQMgrAqmIfQInterruptEnable(qId);
1313 ixOsalIrqUnlock(ixQMgrLockKey);
1319 dispatcherStats.queueStats[qId].enableCount++;
1327 ixQMgrCallbackTypeGet (IxQMgrQId qId,
1331 if (!ixQMgrQIsConfigured(qId))
1333 return IX_QMGR_Q_NOT_CONFIGURED;
1335 if (qId >= IX_QMGR_MIN_QUEUPP_QID)
1337 return IX_QMGR_PARAMETER_ERROR;
1341 return IX_QMGR_PARAMETER_ERROR;
1345 *type = ixQMgrQTypes[qId];