]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - drivers/net/npe/IxQMgrDispatcher.c
Merge branch 'u-boot-imx/master' into 'u-boot-arm/master'
[karo-tx-uboot.git] / drivers / net / npe / IxQMgrDispatcher.c
1 /**
2  * @file    IxQMgrDispatcher.c
3  *
4  * @author Intel Corporation
5  * @date    20-Dec-2001
6  *    
7  * @brief   This file contains the implementation of the Dispatcher sub component
8  *
9  * 
10  * @par
11  * IXP400 SW Release version 2.0
12  * 
13  * -- Copyright Notice --
14  * 
15  * @par
16  * Copyright 2001-2005, Intel Corporation.
17  * All rights reserved.
18  * 
19  * @par
20  * Redistribution and use in source and binary forms, with or without
21  * modification, are permitted provided that the following conditions
22  * are met:
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.
31  * 
32  * @par
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
43  * SUCH DAMAGE.
44  * 
45  * @par
46  * -- End of Copyright Notice --
47 */
48
49 /*
50  * User defined include files.
51  */
52 #include "IxQMgr.h"
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"
59 #include "IxOsal.h"
60
61
62
63 /*
64  * #defines and macros used in this file.
65  */
66
67
68 /*
69  * This constant is used to indicate the number of priority levels supported
70  */
71 #define IX_QMGR_NUM_PRIORITY_LEVELS 3
72
73 /* 
74  * This constant is used to set the size of the array of status words
75  */
76 #define MAX_Q_STATUS_WORDS      4
77
78 /*
79  * This macro is used to check if a given priority is valid
80  */
81 #define IX_QMGR_DISPATCHER_PRIORITY_CHECK(priority) \
82 (((priority) >= IX_QMGR_Q_PRIORITY_0) && ((priority) <= IX_QMGR_Q_PRIORITY_2))
83
84 /*
85  * This macto is used to check that a given interrupt source is valid
86  */
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))
89
90 /*
91  * Number of times a dummy callback is called before logging a trace
92  * message
93  */
94 #define LOG_THROTTLE_COUNT 1000000
95
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)
103  
104 /*
105  * This macro is used to check if a given callback type is valid
106  */
107 #define IX_QMGR_DISPATCHER_CALLBACK_TYPE_CHECK(type) \
108             (((type) >= IX_QMGR_TYPE_REALTIME_OTHER) && \
109             ((type) <= IX_QMGR_TYPE_REALTIME_SPORADIC))
110
111 /* 
112  * define max index in lower queue to use in loops 
113  */
114 #define IX_QMGR_MAX_LOW_QUE_TABLE_INDEX (31)
115
116 /*
117  * Typedefs whose scope is limited to this file.
118  */
119
120 /*
121  * Information on a queue needed by the Dispatcher
122  */
123 typedef struct 
124 {
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          */
133 } IxQMgrQInfo;
134
135 /*
136  * Variable declarations global to this file. Externs are followed by
137  * statics.
138  */
139
140 /* 
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(). 
145  */
146 PRIVATE IX_STATUS ixQMgrOrigB0Dispatcher = IX_FEATURE_CTRL_COMPONENT_ENABLED;
147
148 /* 
149  * keep record of Q types - not in IxQMgrQInfo for performance as
150  * it is only used with ixQMgrDispatcherLoopRunB0LLP()
151  */
152 PRIVATE IxQMgrType ixQMgrQTypes[IX_QMGR_MAX_NUM_QUEUES];
153
154 /*
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.
157  */
158 static IxQMgrQId priorityTable[IX_QMGR_MAX_NUM_QUEUES];
159
160 /*
161  * This flag indicates to the dispatcher that the priority table needs to be rebuilt.
162  */
163 static BOOL rebuildTable = false;
164
165 /* Dispatcher statistics */
166 static IxQMgrDispatcherStats dispatcherStats;
167
168 /* Table of queue information */
169 static IxQMgrQInfo dispatchQInfo[IX_QMGR_MAX_NUM_QUEUES];
170
171 /* Masks use to identify the first queues in the priority tables 
172 *  when comparing with the interrupt register
173 */
174 static unsigned int lowPriorityTableFirstHalfMask;
175 static unsigned int uppPriorityTableFirstHalfMask;
176
177 /*
178  * Static function prototypes
179  */
180
181 /*
182  * This function is the default callback for all queues
183  */
184 PRIVATE void
185 dummyCallback (IxQMgrQId qId,         
186                IxQMgrCallbackId cbId);
187
188 PRIVATE void
189 ixQMgrDispatcherReBuildPriorityTable (void);
190
191 /*
192  * Function definitions.
193  */
194 void
195 ixQMgrDispatcherInit (void)
196 {
197     int i;
198     IxFeatureCtrlProductId productId = 0;
199     IxFeatureCtrlDeviceId deviceId = 0;
200     BOOL stickyIntSilicon = true;
201
202     /* Set default priorities */
203     for (i=0; i< IX_QMGR_MAX_NUM_QUEUES; i++)
204     {
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;  
212         /* 
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.
216          */
217         dispatchQInfo[i].intRegCheckMask = (1<<(i%(IX_QMGR_MIN_QUEUPP_QID)));
218
219         /* 
220          * Set the Q types - will only be used with livelock 
221          */
222         ixQMgrQTypes[i] = IX_QMGR_TYPE_REALTIME_OTHER;
223
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;
231
232     }
233
234     /* Priority table. Order the table from queue 0 to 63 */
235     ixQMgrDispatcherReBuildPriorityTable();
236
237     /* Reset statistics */
238     dispatcherStats.loopRunCnt = 0;
239
240     /* Get the device ID for the underlying silicon */
241     deviceId = ixFeatureCtrlDeviceRead();
242     
243     /* Get the product ID for the underlying silicon */
244     productId = ixFeatureCtrlProductIdRead();
245
246     /* 
247      * Check featureCtrl to see if Livelock prevention is required 
248      */
249     ixQMgrOrigB0Dispatcher = ixFeatureCtrlSwConfigurationCheck( 
250                                  IX_FEATURECTRL_ORIGB0_DISPATCHER);
251
252     /*
253      * Check if the silicon supports the sticky interrupt feature.
254      * IF (IXP42X AND A0) -> No sticky interrupt feature supported 
255      */
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))) 
260     {
261        stickyIntSilicon = false;
262     }
263
264     /*
265      * IF user wants livelock prev option AND silicon supports sticky interrupt 
266      * feature -> enable the sticky interrupt bit
267      */
268     if ((IX_FEATURE_CTRL_SWCONFIG_DISABLED == ixQMgrOrigB0Dispatcher) &&
269          stickyIntSilicon)  
270     {
271         ixQMgrStickyInterruptRegEnable();
272     }
273 }
274
275 IX_STATUS
276 ixQMgrDispatcherPrioritySet (IxQMgrQId qId,
277                              IxQMgrPriority priority)
278 {   
279     int ixQMgrLockKey;
280
281     if (!ixQMgrQIsConfigured(qId))
282     {
283         return IX_QMGR_Q_NOT_CONFIGURED;
284     }
285     
286     if (!IX_QMGR_DISPATCHER_PRIORITY_CHECK(priority))
287     {
288         return IX_QMGR_Q_INVALID_PRIORITY;
289     }
290
291     ixQMgrLockKey = ixOsalIrqLock();
292     
293     /* Change priority */
294     dispatchQInfo[qId].priority = priority;
295     /* Set flag */
296     rebuildTable = true;
297
298     ixOsalIrqUnlock(ixQMgrLockKey);
299
300 #ifndef NDEBUG
301     /* Update statistics */
302     dispatcherStats.queueStats[qId].priorityChangeCnt++;
303 #endif
304
305     return IX_SUCCESS;
306 }
307
308 IX_STATUS
309 ixQMgrNotificationCallbackSet (IxQMgrQId qId,
310                                IxQMgrCallback callback,
311                                IxQMgrCallbackId callbackId)
312 {
313     if (!ixQMgrQIsConfigured(qId))
314     {
315         return IX_QMGR_Q_NOT_CONFIGURED;
316     }
317
318     if (NULL == callback)
319     {
320         /* Reset to dummy callback */
321         dispatchQInfo[qId].callback = dummyCallback;
322         dispatchQInfo[qId].dummyCallbackCount = 0;
323         dispatchQInfo[qId].callbackId = 0;
324     }
325     else 
326     {
327         dispatchQInfo[qId].callback = callback;
328         dispatchQInfo[qId].callbackId = callbackId;
329     }
330
331     return IX_SUCCESS;
332 }
333
334 IX_STATUS
335 ixQMgrNotificationEnable (IxQMgrQId qId, 
336                           IxQMgrSourceId srcSel)
337 {
338     IxQMgrQStatus qStatusOnEntry;/* The queue status on entry/exit */
339     IxQMgrQStatus qStatusOnExit; /* to this function               */
340     int ixQMgrLockKey;
341
342 #ifndef NDEBUG
343     if (!ixQMgrQIsConfigured (qId))
344     {
345         return IX_QMGR_Q_NOT_CONFIGURED;
346     }
347
348     if ((qId < IX_QMGR_MIN_QUEUPP_QID) &&
349        !IX_QMGR_DISPATCHER_SOURCE_ID_CHECK(srcSel))
350     {
351         /* QId 0-31 source id invalid */
352         return IX_QMGR_INVALID_INT_SOURCE_ID;
353     }
354
355     if ((IX_QMGR_Q_SOURCE_ID_NE != srcSel) &&
356         (qId >= IX_QMGR_MIN_QUEUPP_QID))
357     {
358         /*
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.
361          */
362         return IX_QMGR_INVALID_INT_SOURCE_ID;
363     }
364 #endif
365
366 #ifndef NDEBUG
367     dispatcherStats.queueStats[qId].notificationEnabled = true;
368     dispatcherStats.queueStats[qId].srcSel = srcSel;
369 #endif
370
371     /* Get the current queue status */
372     ixQMgrAqmIfQueStatRead (qId, &qStatusOnEntry);
373   
374     /* 
375      * Enabling interrupts results in Read-Modify-Write
376      * so need critical section
377      */
378
379     ixQMgrLockKey = ixOsalIrqLock();
380
381     /* Calculate the checkMask and checkValue for this q */
382     ixQMgrAqmIfQStatusCheckValsCalc (qId,
383                                      srcSel,
384                                      &dispatchQInfo[qId].statusWordOffset,
385                                      &dispatchQInfo[qId].statusCheckValue,
386                                      &dispatchQInfo[qId].statusMask);
387
388
389     /* Set the interrupt source is this queue is in the range 0-31 */
390     if (qId < IX_QMGR_MIN_QUEUPP_QID)
391     {
392         ixQMgrAqmIfIntSrcSelWrite (qId, srcSel);
393     }
394
395     /* Enable the interrupt */
396     ixQMgrAqmIfQInterruptEnable (qId);
397
398     ixOsalIrqUnlock(ixQMgrLockKey);
399     
400     /* Get the current queue status */
401     ixQMgrAqmIfQueStatRead (qId, &qStatusOnExit);
402   
403     /* If the status has changed return a warning */
404     if (qStatusOnEntry != qStatusOnExit)
405     {
406         return IX_QMGR_WARNING;
407     }
408     
409     return IX_SUCCESS;
410 }
411
412
413 IX_STATUS
414 ixQMgrNotificationDisable (IxQMgrQId qId)
415 {
416     int ixQMgrLockKey;
417
418 #ifndef NDEBUG
419     /* Validate parameters */
420     if (!ixQMgrQIsConfigured (qId))
421     {
422         return IX_QMGR_Q_NOT_CONFIGURED;
423     }
424 #endif
425   
426     /* 
427      * Enabling interrupts results in Read-Modify-Write
428      * so need critical section
429      */
430 #ifndef NDEBUG
431     dispatcherStats.queueStats[qId].notificationEnabled = false;
432 #endif
433
434     ixQMgrLockKey = ixOsalIrqLock();
435
436     ixQMgrAqmIfQInterruptDisable (qId);
437     
438     ixOsalIrqUnlock(ixQMgrLockKey);
439
440     return IX_SUCCESS;    
441 }
442
443 void 
444 ixQMgrStickyInterruptRegEnable(void)
445 {
446  /* Use Aqm If function to set Interrupt Register0 Bit-3 */ 
447  ixQMgrAqmIfIntSrcSelReg0Bit3Set ();   
448 }
449
450 #if !defined __XSCALE__ || defined __linux
451
452 /* Count the number of leading zero bits in a word,
453  * and return the same value than the CLZ instruction.
454  *
455  * word (in)    return value (out)
456  * 0x80000000   0
457  * 0x40000000   1
458  * ,,,          ,,,
459  * 0x00000002   30
460  * 0x00000001   31
461  * 0x00000000   32
462  *
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.
466  *
467  * Note that this version is big-endian
468  */
469 unsigned int
470 ixQMgrCountLeadingZeros(UINT32 word)
471 {
472   unsigned int leadingZerosCount = 0;
473
474   if (word == 0)
475   {
476       return 32;
477   }
478   /* search the first bit set by testing the MSB and shifting the input word */
479   while ((word & 0x80000000) == 0)
480   {
481       word <<= 1;
482       leadingZerosCount++;
483   }
484   return leadingZerosCount;
485 }
486 #endif /* not  __XSCALE__ or __linux */
487
488 void
489 ixQMgrDispatcherLoopGet (IxQMgrDispatcherFuncPtr *qDispatcherFuncPtr)
490 {
491   IxFeatureCtrlProductId productId = 0;
492   IxFeatureCtrlDeviceId deviceId = 0;
493   
494   /* Get the device ID for the underlying silicon */
495   deviceId = ixFeatureCtrlDeviceRead();
496
497   /* Get the product ID for the underlying silicon */
498   productId = ixFeatureCtrlProductIdRead ();
499
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)))  
505   {
506     /*For IXP42X A0 silicon */
507     *qDispatcherFuncPtr = &ixQMgrDispatcherLoopRunA0 ;
508   } 
509   else /*For IXP42X B0 or IXP46X silicon*/ 
510   { 
511     if (IX_FEATURE_CTRL_SWCONFIG_ENABLED == ixQMgrOrigB0Dispatcher)
512     {
513         /* Default for IXP42X B0 and IXP46X silicon */
514         *qDispatcherFuncPtr = &ixQMgrDispatcherLoopRunB0;
515     }
516     else 
517     {
518         /* FeatureCtrl indicated that livelock dispatcher be used */
519         *qDispatcherFuncPtr = &ixQMgrDispatcherLoopRunB0LLP;
520     }
521   }
522 }
523
524 void
525 ixQMgrDispatcherLoopRunA0 (IxQMgrDispatchGroup group)
526 {
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;
534
535     int priorityTableIndex;/* Priority table index */
536     int qIndex;            /* Current queue being processed */
537     int endIndex;          /* Index of last queue to process */
538
539 #ifndef NDEBUG
540     IX_OSAL_ASSERT((group == IX_QMGR_QUEUPP_GROUP) || 
541               (group == IX_QMGR_QUELOW_GROUP));
542 #endif
543
544     /* Read Q status registers before interrupt status read/write */
545     ixQMgrAqmIfQStatusRegsRead (group, qStatusWordsB4Write);
546
547     /* Read the interrupt register */
548     ixQMgrAqmIfQInterruptRegRead (group, &intRegVal);
549
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
552     * least one bit set
553     */
554     if (intRegVal == 0) 
555     {
556 #ifndef NDEBUG
557         /* Update statistics */
558         dispatcherStats.loopRunCnt++;
559 #endif
560
561         /* Rebuild the priority table if needed */
562         if (rebuildTable)
563         {
564             ixQMgrDispatcherReBuildPriorityTable ();
565         }
566
567         return;
568     }
569    
570     /* Write it back to clear the interrupt */
571     ixQMgrAqmIfQInterruptRegWrite (group, intRegVal);
572
573     /* Read Q status registers after interrupt status read/write */
574     ixQMgrAqmIfQStatusRegsRead (group, qStatusWordsAfterWrite);
575  
576     /* get the first queue Id from the interrupt register value */
577     qIndex = (BITS_PER_WORD - 1) - ixQMgrCountLeadingZeros(intRegVal);
578
579     /* check if any change occured during hw register modifications */ 
580     if (IX_QMGR_QUELOW_GROUP == group)
581     {
582         statusChangeFlag = 
583             (qStatusWordsB4Write[0] != qStatusWordsAfterWrite[0]) ||
584             (qStatusWordsB4Write[1] != qStatusWordsAfterWrite[1]) ||
585             (qStatusWordsB4Write[2] != qStatusWordsAfterWrite[2]) ||
586             (qStatusWordsB4Write[3] != qStatusWordsAfterWrite[3]);
587     }
588     else
589     {
590         statusChangeFlag = 
591             (qStatusWordsB4Write[0] != qStatusWordsAfterWrite[0]);
592         /* Set the queue range based on the queue group to proccess */
593         qIndex += IX_QMGR_MIN_QUEUPP_QID;
594     }
595
596     if (statusChangeFlag == false)
597     {
598         /* check if the interrupt register contains 
599          * only 1 bit set (happy day scenario)
600          */
601         currDispatchQInfo = &dispatchQInfo[qIndex];
602         if (intRegVal == currDispatchQInfo->intRegCheckMask)
603         {
604             /* only 1 queue event triggered a notification *
605              * Call the callback function for this queue 
606              */
607             currDispatchQInfo->callback (qIndex,
608                                          currDispatchQInfo->callbackId);  
609 #ifndef NDEBUG
610             /* Update statistics */
611             dispatcherStats.queueStats[qIndex].callbackCnt++;
612 #endif
613         }
614         else 
615         {
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
619              *
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.
623              */
624             if (IX_QMGR_QUELOW_GROUP == group)
625             {
626                 /* check if any bit related to queues in the first
627                  * half of the priority table is set
628                  */
629                 if (intRegVal & lowPriorityTableFirstHalfMask)
630                 {
631                     priorityTableIndex = IX_QMGR_MIN_LOW_QUE_PRIORITY_TABLE_INDEX;
632                 }
633                 else
634                 {
635                     priorityTableIndex = IX_QMGR_MID_LOW_QUE_PRIORITY_TABLE_INDEX;
636                 }
637             }
638             else 
639             {
640                 /* check if any bit related to queues in the first
641                  * half of the priority table is set
642                  */
643                 if (intRegVal & uppPriorityTableFirstHalfMask)
644                 {
645                     priorityTableIndex = IX_QMGR_MIN_UPP_QUE_PRIORITY_TABLE_INDEX;
646                 }
647                 else
648                 {
649                     priorityTableIndex = IX_QMGR_MID_UPP_QUE_PRIORITY_TABLE_INDEX;
650                 }
651             }
652             
653             /* iterate following the priority table until all the bits 
654              * of the interrupt register are cleared.
655              */
656             do
657             {
658                 qIndex = priorityTable[priorityTableIndex++];
659                 currDispatchQInfo = &dispatchQInfo[qIndex];
660                 intRegCheckMask = currDispatchQInfo->intRegCheckMask;
661                 
662                 /* If this queue caused this interrupt to be raised */
663                 if (intRegVal & intRegCheckMask)
664                 {
665                     /* Call the callback function for this queue */
666                     currDispatchQInfo->callback (qIndex,
667                                                  currDispatchQInfo->callbackId);
668 #ifndef NDEBUG
669                     /* Update statistics */
670                     dispatcherStats.queueStats[qIndex].callbackCnt++;
671 #endif
672                     
673                     /* Clear the interrupt register bit */
674                     intRegVal &= ~intRegCheckMask;
675                 }
676             }
677             while(intRegVal);
678         }
679     }
680     else
681     {
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.
685      */
686
687     /* Read interrupt status again */
688     ixQMgrAqmIfQInterruptRegRead (group, &intRegValAfterWrite);
689
690     if (IX_QMGR_QUELOW_GROUP == group)
691     {
692         priorityTableIndex = IX_QMGR_MIN_LOW_QUE_PRIORITY_TABLE_INDEX;
693         endIndex = IX_QMGR_MAX_LOW_QUE_PRIORITY_TABLE_INDEX;
694     }
695     else
696     {
697         priorityTableIndex = IX_QMGR_MIN_UPP_QUE_PRIORITY_TABLE_INDEX;
698         endIndex = IX_QMGR_MAX_UPP_QUE_PRIORITY_TABLE_INDEX;
699     }
700
701     for ( ; priorityTableIndex<=endIndex; priorityTableIndex++)
702     {
703         qIndex = priorityTable[priorityTableIndex];
704         currDispatchQInfo = &dispatchQInfo[qIndex];
705         intRegCheckMask = currDispatchQInfo->intRegCheckMask;
706
707         /* If this queue caused this interrupt to be raised */
708         if (intRegVal & intRegCheckMask)
709         {  
710             /* Call the callback function for this queue */
711             currDispatchQInfo->callback (qIndex,
712                                          currDispatchQInfo->callbackId);
713 #ifndef NDEBUG
714             /* Update statistics */
715             dispatcherStats.queueStats[qIndex].callbackCnt++;
716 #endif
717             
718         } /* if (intRegVal .. */
719
720         /* 
721          * If interrupt bit is set in intRegValAfterWrite don't
722          * proceed as this will be caught in next interrupt
723          */
724         else if ((intRegValAfterWrite & intRegCheckMask) == 0)
725         {
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))
732             {
733                 /* Call the callback function for this queue */
734                 currDispatchQInfo->callback (qIndex, 
735                                              dispatchQInfo[qIndex].callbackId);                 
736 #ifndef NDEBUG
737                 /* Update statistics */
738                 dispatcherStats.queueStats[qIndex].callbackCnt++;
739                 dispatcherStats.queueStats[qIndex].intLostCallbackCnt++;
740 #endif
741             } /* if ixQMgrAqmIfQStatusCheck(.. */
742         } /* else if ((intRegValAfterWrite ... */
743     } /* for (priorityTableIndex=0 ... */
744     }
745
746     /* Rebuild the priority table if needed */
747     if (rebuildTable)
748     {
749         ixQMgrDispatcherReBuildPriorityTable ();
750     }
751
752 #ifndef NDEBUG
753     /* Update statistics */
754     dispatcherStats.loopRunCnt++;
755 #endif
756 }
757
758
759
760 void
761 ixQMgrDispatcherLoopRunB0 (IxQMgrDispatchGroup group)
762 {
763     UINT32 intRegVal;                /* Interrupt reg val */
764     UINT32 intRegCheckMask;          /* Mask for checking interrupt bits */
765     IxQMgrQInfo *currDispatchQInfo;
766
767
768     int priorityTableIndex; /* Priority table index */
769     int qIndex;             /* Current queue being processed */
770
771 #ifndef NDEBUG
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));
776 #endif
777
778     /* Read the interrupt register */
779     ixQMgrAqmIfQInterruptRegRead (group, &intRegVal);
780
781
782     /* No queue has interrupt register set */
783     if (intRegVal != 0)
784     {
785
786             /* Write it back to clear the interrupt */
787             ixQMgrAqmIfQInterruptRegWrite (group, intRegVal);
788
789             /* get the first queue Id from the interrupt register value */
790             qIndex = (BITS_PER_WORD - 1) - ixQMgrCountLeadingZeros(intRegVal);
791
792             if (IX_QMGR_QUEUPP_GROUP == group)
793             {
794                 /* Set the queue range based on the queue group to proccess */
795                 qIndex += IX_QMGR_MIN_QUEUPP_QID;
796             }
797
798             /* check if the interrupt register contains
799              * only 1 bit set
800              * For example:
801              *                                        intRegVal = 0x0010
802              *               currDispatchQInfo->intRegCheckMask = 0x0010
803              *    intRegVal == currDispatchQInfo->intRegCheckMask is true.
804              */
805              currDispatchQInfo = &dispatchQInfo[qIndex];
806              if (intRegVal == currDispatchQInfo->intRegCheckMask)
807              {
808                 /* only 1 queue event triggered a notification *
809                  * Call the callback function for this queue
810                  */
811                 currDispatchQInfo->callback (qIndex,
812                                      currDispatchQInfo->callbackId);
813 #ifndef NDEBUG
814                 /* Update statistics */
815                 dispatcherStats.queueStats[qIndex].callbackCnt++;
816 #endif
817              }
818              else
819              {
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
823                   *
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.
827                   */
828                  if (IX_QMGR_QUELOW_GROUP == group)
829                  {
830                      /* check if any bit related to queues in the first
831                       * half of the priority table is set
832                       */
833                      if (intRegVal & lowPriorityTableFirstHalfMask)
834                      {
835                          priorityTableIndex = IX_QMGR_MIN_LOW_QUE_PRIORITY_TABLE_INDEX;
836                      }
837                      else
838                      {
839                          priorityTableIndex = IX_QMGR_MID_LOW_QUE_PRIORITY_TABLE_INDEX;
840                      }
841                  }
842                 else
843                  {
844                      /* check if any bit related to queues in the first
845                       * half of the priority table is set
846                       */
847                      if (intRegVal & uppPriorityTableFirstHalfMask)
848                      {
849                          priorityTableIndex = IX_QMGR_MIN_UPP_QUE_PRIORITY_TABLE_INDEX;
850                      }
851                      else
852                      {
853                          priorityTableIndex = IX_QMGR_MID_UPP_QUE_PRIORITY_TABLE_INDEX;
854                      }
855                  }
856
857                  /* iterate following the priority table until all the bits
858                   * of the interrupt register are cleared.
859                   */
860                  do
861                  {
862                      qIndex = priorityTable[priorityTableIndex++];
863                      currDispatchQInfo = &dispatchQInfo[qIndex];
864                      intRegCheckMask = currDispatchQInfo->intRegCheckMask;
865
866                      /* If this queue caused this interrupt to be raised */
867                      if (intRegVal & intRegCheckMask)
868                      {
869                          /* Call the callback function for this queue */
870                          currDispatchQInfo->callback (qIndex,
871                                               currDispatchQInfo->callbackId);
872 #ifndef NDEBUG
873                          /* Update statistics */
874                          dispatcherStats.queueStats[qIndex].callbackCnt++;
875 #endif
876
877                          /* Clear the interrupt register bit */
878                          intRegVal &= ~intRegCheckMask;
879                      }
880                   }
881                   while(intRegVal);
882              } /*End of intRegVal == currDispatchQInfo->intRegCheckMask */
883      } /* End of intRegVal != 0 */
884
885 #ifndef NDEBUG
886     /* Update statistics */
887     dispatcherStats.loopRunCnt++;
888 #endif
889
890     /* Rebuild the priority table if needed */
891     if (rebuildTable)
892     {
893         ixQMgrDispatcherReBuildPriorityTable ();
894     }
895 }
896
897 void
898 ixQMgrDispatcherLoopRunB0LLP (IxQMgrDispatchGroup group)
899 {
900     UINT32 intRegVal =0;                /* Interrupt reg val */
901     UINT32 intRegCheckMask;          /* Mask for checking interrupt bits */
902     IxQMgrQInfo *currDispatchQInfo;
903
904     int priorityTableIndex; /* Priority table index */
905     int qIndex;             /* Current queue being processed */
906
907     UINT32 intRegValCopy = 0;
908     UINT32 intEnableRegVal = 0;
909     UINT8 i = 0;
910
911 #ifndef NDEBUG
912     IX_OSAL_ASSERT((group == IX_QMGR_QUEUPP_GROUP) ||
913               (group == IX_QMGR_QUELOW_GROUP));
914 #endif
915
916     /* Read the interrupt register */
917     ixQMgrAqmIfQInterruptRegRead (group, &intRegVal);
918
919     /* 
920      * mask any interrupts that are not enabled 
921      */
922     ixQMgrAqmIfQInterruptEnableRegRead (group, &intEnableRegVal);
923     intRegVal &= intEnableRegVal;
924
925     /* No queue has interrupt register set */
926     if (intRegVal != 0)
927     {
928         if (IX_QMGR_QUELOW_GROUP == group)
929         {
930             /*
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
935              */
936             intRegValCopy = intRegVal;
937         }
938         else
939         {
940             /* no sticky for upper Q's, so write back now */
941             ixQMgrAqmIfQInterruptRegWrite (group, intRegVal);
942         }
943
944         /* get the first queue Id from the interrupt register value */
945         qIndex = (BITS_PER_WORD - 1) - ixQMgrCountLeadingZeros(intRegVal);
946
947         if (IX_QMGR_QUEUPP_GROUP == group)
948         {
949             /* Set the queue range based on the queue group to proccess */
950             qIndex += IX_QMGR_MIN_QUEUPP_QID;
951         }
952
953         /* check if the interrupt register contains
954         * only 1 bit set
955         * For example:
956         *                                        intRegVal = 0x0010
957         *               currDispatchQInfo->intRegCheckMask = 0x0010
958         *    intRegVal == currDispatchQInfo->intRegCheckMask is true.
959         */
960         currDispatchQInfo = &dispatchQInfo[qIndex];
961         if (intRegVal == currDispatchQInfo->intRegCheckMask)
962         {
963
964             /* 
965              * check if Q type periodic -  only lower queues can
966              * have there type set to periodic 
967              */
968             if (IX_QMGR_TYPE_REALTIME_PERIODIC == ixQMgrQTypes[qIndex])
969             {
970                 /* 
971                  * Disable the notifications on any sporadics 
972                  */
973                 for (i=0; i <= IX_QMGR_MAX_LOW_QUE_TABLE_INDEX; i++)
974                 {
975                     if (IX_QMGR_TYPE_REALTIME_SPORADIC == ixQMgrQTypes[i])
976                     {
977                         ixQMgrNotificationDisable(i);
978 #ifndef NDEBUG
979                         /* Update statistics */
980                         dispatcherStats.queueStats[i].disableCount++;
981 #endif
982                     }
983                 }
984             }
985
986             currDispatchQInfo->callback (qIndex,
987                                          currDispatchQInfo->callbackId);
988 #ifndef NDEBUG
989             /* Update statistics */
990             dispatcherStats.queueStats[qIndex].callbackCnt++;
991 #endif
992         }
993         else
994         {
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
998             *
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.
1002             */
1003             if (IX_QMGR_QUELOW_GROUP == group)
1004             {
1005                 /* check if any bit related to queues in the first
1006                  * half of the priority table is set
1007                  */
1008                 if (intRegVal & lowPriorityTableFirstHalfMask)
1009                 {
1010                     priorityTableIndex =
1011                                        IX_QMGR_MIN_LOW_QUE_PRIORITY_TABLE_INDEX;
1012                 }
1013                 else
1014                 {
1015                     priorityTableIndex =
1016                                        IX_QMGR_MID_LOW_QUE_PRIORITY_TABLE_INDEX;
1017                 }
1018             }
1019             else
1020             {
1021                 /* check if any bit related to queues in the first
1022                  * half of the priority table is set
1023                  */
1024                 if (intRegVal & uppPriorityTableFirstHalfMask)
1025                 {
1026                     priorityTableIndex =
1027                                        IX_QMGR_MIN_UPP_QUE_PRIORITY_TABLE_INDEX;
1028                 }
1029                 else
1030                 {
1031                     priorityTableIndex =
1032                                        IX_QMGR_MID_UPP_QUE_PRIORITY_TABLE_INDEX;
1033                 }
1034             }
1035
1036             /* iterate following the priority table until all the bits
1037              * of the interrupt register are cleared.
1038              */
1039             do
1040             {
1041                 qIndex = priorityTable[priorityTableIndex++];
1042                 currDispatchQInfo = &dispatchQInfo[qIndex];
1043                 intRegCheckMask = currDispatchQInfo->intRegCheckMask;
1044
1045                 /* If this queue caused this interrupt to be raised */
1046                 if (intRegVal & intRegCheckMask)
1047                 {
1048                     /* 
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.
1052                      */
1053                     if (IX_QMGR_TYPE_REALTIME_PERIODIC == ixQMgrQTypes[qIndex])
1054                     {
1055                         /* 
1056                          * Disable the notifications on any sporadics 
1057                          */
1058                         for (i=0; i <= IX_QMGR_MAX_LOW_QUE_TABLE_INDEX; i++)
1059                         {
1060                             if (IX_QMGR_TYPE_REALTIME_SPORADIC == 
1061                                     ixQMgrQTypes[i])
1062                             {
1063                                 ixQMgrNotificationDisable(i);
1064                                 /* 
1065                                  * remove from intRegVal as we don't want 
1066                                  * to service any sporadics now
1067                                  */
1068                                 intRegVal &= ~dispatchQInfo[i].intRegCheckMask;
1069 #ifndef NDEBUG
1070                                 /* Update statistics */
1071                                 dispatcherStats.queueStats[i].disableCount++;
1072 #endif
1073                             }
1074                         }
1075                     }
1076
1077                     currDispatchQInfo->callback (qIndex,
1078                                                  currDispatchQInfo->callbackId);
1079 #ifndef NDEBUG
1080                     /* Update statistics */
1081                     dispatcherStats.queueStats[qIndex].callbackCnt++;
1082 #endif
1083                     /* Clear the interrupt register bit */
1084                     intRegVal &= ~intRegCheckMask;
1085                 }
1086             }
1087             while(intRegVal);
1088         } /*End of intRegVal == currDispatchQInfo->intRegCheckMask */
1089     } /* End of intRegVal != 0 */
1090
1091 #ifndef NDEBUG
1092     /* Update statistics */
1093     dispatcherStats.loopRunCnt++;
1094 #endif
1095
1096     if ((intRegValCopy != 0) && (IX_QMGR_QUELOW_GROUP == group))
1097     {
1098         /* 
1099          * lower groups (therefore sticky) AND at least one enabled interrupt
1100          * Write back to clear the interrupt 
1101          */
1102         ixQMgrAqmIfQInterruptRegWrite (IX_QMGR_QUELOW_GROUP, intRegValCopy);
1103     }
1104
1105     /* Rebuild the priority table if needed */
1106     if (rebuildTable)
1107     {
1108         ixQMgrDispatcherReBuildPriorityTable ();
1109     }
1110 }
1111
1112 PRIVATE void
1113 ixQMgrDispatcherReBuildPriorityTable (void)
1114 {
1115     UINT32 qIndex;
1116     UINT32 priority;
1117     int lowQuePriorityTableIndex = IX_QMGR_MIN_LOW_QUE_PRIORITY_TABLE_INDEX;
1118     int uppQuePriorityTableIndex = IX_QMGR_MIN_UPP_QUE_PRIORITY_TABLE_INDEX;
1119
1120     /* Reset the rebuild flag */
1121     rebuildTable = false;
1122
1123     /* initialize the mak used to identify the queues in the first half
1124      * of the priority table
1125      */
1126     lowPriorityTableFirstHalfMask = 0;
1127     uppPriorityTableFirstHalfMask = 0;
1128     
1129     /* For each priority level */
1130     for(priority=0; priority<IX_QMGR_NUM_PRIORITY_LEVELS; priority++)
1131     {
1132         /* Foreach low queue in this priority */
1133         for(qIndex=0; qIndex<IX_QMGR_MIN_QUEUPP_QID; qIndex++)
1134         {
1135             if (dispatchQInfo[qIndex].priority == priority)
1136             { 
1137                 /* build the priority table bitmask which match the
1138                  * queues of the first half of the priority table 
1139                  */
1140                 if (lowQuePriorityTableIndex < IX_QMGR_MID_LOW_QUE_PRIORITY_TABLE_INDEX) 
1141                 {
1142                     lowPriorityTableFirstHalfMask |= dispatchQInfo[qIndex].intRegCheckMask;
1143                 }
1144                 /* build the priority table */
1145                 priorityTable[lowQuePriorityTableIndex++] = qIndex;
1146             }
1147         }
1148         /* Foreach upp queue */
1149         for(qIndex=IX_QMGR_MIN_QUEUPP_QID; qIndex<=IX_QMGR_MAX_QID; qIndex++)
1150         {
1151             if (dispatchQInfo[qIndex].priority == priority)
1152             {
1153                 /* build the priority table bitmask which match the
1154                  * queues of the first half of the priority table 
1155                  */
1156                 if (uppQuePriorityTableIndex < IX_QMGR_MID_UPP_QUE_PRIORITY_TABLE_INDEX) 
1157                 {
1158                     uppPriorityTableFirstHalfMask |= dispatchQInfo[qIndex].intRegCheckMask;
1159                 }
1160                 /* build the priority table */
1161                 priorityTable[uppQuePriorityTableIndex++] = qIndex;
1162             }
1163         }
1164     }
1165 }
1166
1167 IxQMgrDispatcherStats*
1168 ixQMgrDispatcherStatsGet (void)
1169 {
1170     return &dispatcherStats;
1171 }
1172
1173 PRIVATE void
1174 dummyCallback (IxQMgrQId qId,
1175                IxQMgrCallbackId cbId)
1176 {
1177     /* Throttle the trace message */
1178     if ((dispatchQInfo[qId].dummyCallbackCount % LOG_THROTTLE_COUNT) == 0)
1179     {
1180         IX_QMGR_LOG_WARNING2("--> dummyCallback: qId (%d), callbackId (%d)\n",qId,cbId);
1181     }
1182     dispatchQInfo[qId].dummyCallbackCount++;
1183
1184 #ifndef NDEBUG
1185     /* Update statistcs */
1186     dispatcherStats.queueStats[qId].intNoCallbackCnt++;
1187 #endif
1188 }
1189 void
1190 ixQMgrLLPShow (int resetStats)
1191 {
1192 #ifndef NDEBUG
1193     UINT8 i = 0;
1194     UINT32 intEnableRegVal = 0;
1195
1196     printf ("Livelock statistics are printed on the fly.\n");
1197     printf ("qId Type     EnableCnt DisableCnt IntEnableState Callbacks\n");
1198     printf ("=== ======== ========= ========== ============== =========\n");
1199
1200     for (i=0; i<= IX_QMGR_MAX_LOW_QUE_TABLE_INDEX; i++)
1201     {
1202         if (ixQMgrQTypes[i] != IX_QMGR_TYPE_REALTIME_OTHER)
1203         {
1204             printf (" %2d ", i);
1205
1206             if (ixQMgrQTypes[i] == IX_QMGR_TYPE_REALTIME_SPORADIC)
1207             {
1208                 printf ("Sporadic");
1209             }
1210             else
1211             {
1212                 printf ("Periodic");
1213             }
1214
1215            
1216             ixQMgrAqmIfQInterruptEnableRegRead (IX_QMGR_QUELOW_GROUP, 
1217                                                     &intEnableRegVal);
1218                 
1219
1220             intEnableRegVal &= dispatchQInfo[i].intRegCheckMask;
1221             intEnableRegVal = intEnableRegVal >> i;
1222
1223             printf (" %10d %10d %10d %10d\n",
1224                     dispatcherStats.queueStats[i].enableCount,
1225                     dispatcherStats.queueStats[i].disableCount,
1226                     intEnableRegVal,
1227                     dispatcherStats.queueStats[i].callbackCnt);
1228
1229             if (resetStats)
1230             {
1231                 dispatcherStats.queueStats[i].enableCount =
1232                 dispatcherStats.queueStats[i].disableCount = 
1233                 dispatcherStats.queueStats[i].callbackCnt = 0;
1234             }
1235         }
1236     }
1237 #else
1238     IX_QMGR_LOG0("Livelock Prevention statistics are only collected in debug mode\n");
1239 #endif
1240 }
1241
1242 void
1243 ixQMgrPeriodicDone (void)
1244 {
1245     UINT32 i = 0;
1246     UINT32 ixQMgrLockKey = 0;
1247
1248     /* 
1249      * for the lower queues
1250      */
1251     for (i=0; i <= IX_QMGR_MAX_LOW_QUE_TABLE_INDEX; i++)
1252     {
1253         /*
1254          * check for sporadics 
1255          */
1256         if (IX_QMGR_TYPE_REALTIME_SPORADIC == ixQMgrQTypes[i])
1257         {
1258              /* 
1259               * enable any sporadics 
1260               */
1261              ixQMgrLockKey = ixOsalIrqLock();
1262              ixQMgrAqmIfQInterruptEnable(i);
1263              ixOsalIrqUnlock(ixQMgrLockKey);
1264 #ifndef NDEBUG
1265              /* 
1266               * Update statistics 
1267               */
1268              dispatcherStats.queueStats[i].enableCount++;
1269              dispatcherStats.queueStats[i].notificationEnabled = true;
1270 #endif
1271         }
1272     }
1273 }
1274 IX_STATUS
1275 ixQMgrCallbackTypeSet (IxQMgrQId qId, 
1276                        IxQMgrType type)
1277 {
1278     UINT32 ixQMgrLockKey = 0;
1279     IxQMgrType ixQMgrOldType =0;
1280
1281 #ifndef NDEBUG
1282     if (!ixQMgrQIsConfigured(qId))
1283     {
1284         return IX_QMGR_Q_NOT_CONFIGURED;
1285     }
1286     if (qId >= IX_QMGR_MIN_QUEUPP_QID)
1287     {
1288         return IX_QMGR_PARAMETER_ERROR;
1289     }
1290     if(!IX_QMGR_DISPATCHER_CALLBACK_TYPE_CHECK(type))
1291     {
1292         return IX_QMGR_PARAMETER_ERROR;
1293     }
1294 #endif
1295
1296     ixQMgrOldType = ixQMgrQTypes[qId];
1297     ixQMgrQTypes[qId] = type;
1298
1299     /*
1300      * check if Q has been changed from type SPORADIC
1301      */
1302     if (IX_QMGR_TYPE_REALTIME_SPORADIC == ixQMgrOldType)
1303     {
1304        /* 
1305         * previously Q was a SPORADIC, this means that LLP
1306         * might have had it disabled. enable it now.
1307         */
1308        ixQMgrLockKey = ixOsalIrqLock();
1309        ixQMgrAqmIfQInterruptEnable(qId);
1310        ixOsalIrqUnlock(ixQMgrLockKey);
1311
1312 #ifndef NDEBUG
1313        /* 
1314         * Update statistics 
1315         */
1316        dispatcherStats.queueStats[qId].enableCount++;
1317 #endif
1318     }
1319
1320     return IX_SUCCESS;
1321 }
1322
1323 IX_STATUS
1324 ixQMgrCallbackTypeGet (IxQMgrQId qId, 
1325                        IxQMgrType *type)
1326 {
1327 #ifndef NDEBUG
1328     if (!ixQMgrQIsConfigured(qId))
1329     {
1330         return IX_QMGR_Q_NOT_CONFIGURED;
1331     }
1332     if (qId >= IX_QMGR_MIN_QUEUPP_QID)
1333     {
1334         return IX_QMGR_PARAMETER_ERROR;
1335     }
1336     if(type == NULL)
1337     {
1338          return IX_QMGR_PARAMETER_ERROR;
1339     }
1340 #endif
1341
1342     *type = ixQMgrQTypes[qId];
1343     return IX_SUCCESS;
1344 }