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