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
];