mirror of
				https://source.denx.de/u-boot/u-boot.git
				synced 2025-11-04 02:11:25 +01:00 
			
		
		
		
	Signed-off-by: Marek Vasut <marex@denx.de> Cc: Bryan Hundven <bryanhundven@gmail.com> Cc: Michael Schwingen <rincewind@discworld.dascon.de> Cc: Wolfgang Denk <wd@denx.de> Cc: Albert Aribaud <albert.u.boot@aribaud.net> Cc: U-Boot DM <u-boot-dm@lists.denx.de> Cc: Joe Hershberger <joe.hershberger@ni.com>
		
			
				
	
	
		
			1345 lines
		
	
	
		
			40 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1345 lines
		
	
	
		
			40 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/**
 | 
						|
 * @file    IxQMgrDispatcher.c
 | 
						|
 *
 | 
						|
 * @author Intel Corporation
 | 
						|
 * @date    20-Dec-2001
 | 
						|
 *    
 | 
						|
 * @brief   This file contains the implementation of the Dispatcher sub component
 | 
						|
 *
 | 
						|
 * 
 | 
						|
 * @par
 | 
						|
 * IXP400 SW Release version 2.0
 | 
						|
 * 
 | 
						|
 * -- Copyright Notice --
 | 
						|
 * 
 | 
						|
 * @par
 | 
						|
 * Copyright 2001-2005, Intel Corporation.
 | 
						|
 * All rights reserved.
 | 
						|
 * 
 | 
						|
 * @par
 | 
						|
 * Redistribution and use in source and binary forms, with or without
 | 
						|
 * modification, are permitted provided that the following conditions
 | 
						|
 * are met:
 | 
						|
 * 1. Redistributions of source code must retain the above copyright
 | 
						|
 *    notice, this list of conditions and the following disclaimer.
 | 
						|
 * 2. Redistributions in binary form must reproduce the above copyright
 | 
						|
 *    notice, this list of conditions and the following disclaimer in the
 | 
						|
 *    documentation and/or other materials provided with the distribution.
 | 
						|
 * 3. Neither the name of the Intel Corporation nor the names of its contributors
 | 
						|
 *    may be used to endorse or promote products derived from this software
 | 
						|
 *    without specific prior written permission.
 | 
						|
 * 
 | 
						|
 * @par
 | 
						|
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
 | 
						|
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | 
						|
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
						|
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
 | 
						|
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 | 
						|
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 | 
						|
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 | 
						|
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 | 
						|
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 | 
						|
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 | 
						|
 * SUCH DAMAGE.
 | 
						|
 * 
 | 
						|
 * @par
 | 
						|
 * -- End of Copyright Notice --
 | 
						|
*/
 | 
						|
 | 
						|
/*
 | 
						|
 * User defined include files.
 | 
						|
 */
 | 
						|
#include "IxQMgr.h"
 | 
						|
#include "IxQMgrAqmIf_p.h"
 | 
						|
#include "IxQMgrQCfg_p.h"
 | 
						|
#include "IxQMgrDispatcher_p.h"
 | 
						|
#include "IxQMgrLog_p.h"
 | 
						|
#include "IxQMgrDefines_p.h"
 | 
						|
#include "IxFeatureCtrl.h"
 | 
						|
#include "IxOsal.h"
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * #defines and macros used in this file.
 | 
						|
 */
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * This constant is used to indicate the number of priority levels supported
 | 
						|
 */
 | 
						|
#define IX_QMGR_NUM_PRIORITY_LEVELS 3
 | 
						|
 | 
						|
/* 
 | 
						|
 * This constant is used to set the size of the array of status words
 | 
						|
 */
 | 
						|
#define MAX_Q_STATUS_WORDS      4
 | 
						|
 | 
						|
/*
 | 
						|
 * This macro is used to check if a given priority is valid
 | 
						|
 */
 | 
						|
#define IX_QMGR_DISPATCHER_PRIORITY_CHECK(priority) \
 | 
						|
(((priority) >= IX_QMGR_Q_PRIORITY_0) && ((priority) <= IX_QMGR_Q_PRIORITY_2))
 | 
						|
 | 
						|
/*
 | 
						|
 * This macto is used to check that a given interrupt source is valid
 | 
						|
 */
 | 
						|
#define IX_QMGR_DISPATCHER_SOURCE_ID_CHECK(srcSel) \
 | 
						|
(((srcSel) >= IX_QMGR_Q_SOURCE_ID_E) && ((srcSel) <= IX_QMGR_Q_SOURCE_ID_NOT_F))
 | 
						|
 | 
						|
/*
 | 
						|
 * Number of times a dummy callback is called before logging a trace
 | 
						|
 * message
 | 
						|
 */
 | 
						|
#define LOG_THROTTLE_COUNT 1000000
 | 
						|
 | 
						|
/* Priority tables limits */
 | 
						|
#define IX_QMGR_MIN_LOW_QUE_PRIORITY_TABLE_INDEX (0)
 | 
						|
#define IX_QMGR_MID_LOW_QUE_PRIORITY_TABLE_INDEX (16)
 | 
						|
#define IX_QMGR_MAX_LOW_QUE_PRIORITY_TABLE_INDEX (31)
 | 
						|
#define IX_QMGR_MIN_UPP_QUE_PRIORITY_TABLE_INDEX (32)
 | 
						|
#define IX_QMGR_MID_UPP_QUE_PRIORITY_TABLE_INDEX (48)
 | 
						|
#define IX_QMGR_MAX_UPP_QUE_PRIORITY_TABLE_INDEX (63)
 | 
						|
 
 | 
						|
/*
 | 
						|
 * This macro is used to check if a given callback type is valid
 | 
						|
 */
 | 
						|
#define IX_QMGR_DISPATCHER_CALLBACK_TYPE_CHECK(type) \
 | 
						|
            (((type) >= IX_QMGR_TYPE_REALTIME_OTHER) && \
 | 
						|
            ((type) <= IX_QMGR_TYPE_REALTIME_SPORADIC))
 | 
						|
 | 
						|
/* 
 | 
						|
 * define max index in lower queue to use in loops 
 | 
						|
 */
 | 
						|
#define IX_QMGR_MAX_LOW_QUE_TABLE_INDEX (31)
 | 
						|
 | 
						|
/*
 | 
						|
 * Typedefs whose scope is limited to this file.
 | 
						|
 */
 | 
						|
 | 
						|
/*
 | 
						|
 * Information on a queue needed by the Dispatcher
 | 
						|
 */
 | 
						|
typedef struct 
 | 
						|
{
 | 
						|
    IxQMgrCallback callback;       /* Notification callback                  */
 | 
						|
    IxQMgrCallbackId callbackId;   /* Notification callback identifier       */
 | 
						|
    unsigned dummyCallbackCount;   /* Number of times runs of dummy callback */
 | 
						|
    IxQMgrPriority priority;       /* Dispatch priority                      */
 | 
						|
    unsigned int statusWordOffset; /* Offset to the status word to check     */
 | 
						|
    UINT32 statusMask;             /* Status mask                            */    
 | 
						|
    UINT32 statusCheckValue;       /* Status check value                     */
 | 
						|
    UINT32 intRegCheckMask;	   /* Interrupt register check mask          */
 | 
						|
} IxQMgrQInfo;
 | 
						|
 | 
						|
/*
 | 
						|
 * Variable declarations global to this file. Externs are followed by
 | 
						|
 * statics.
 | 
						|
 */
 | 
						|
 | 
						|
/* 
 | 
						|
 * Flag to keep record of what dispatcher set in featureCtrl when ixQMgrInit()
 | 
						|
 * is called. This is needed because it is possible that a client might
 | 
						|
 * change whether the live lock prevention dispatcher is used between
 | 
						|
 * calls to ixQMgrInit() and ixQMgrDispatcherLoopGet(). 
 | 
						|
 */
 | 
						|
PRIVATE IX_STATUS ixQMgrOrigB0Dispatcher = IX_FEATURE_CTRL_COMPONENT_ENABLED;
 | 
						|
 | 
						|
/* 
 | 
						|
 * keep record of Q types - not in IxQMgrQInfo for performance as
 | 
						|
 * it is only used with ixQMgrDispatcherLoopRunB0LLP()
 | 
						|
 */
 | 
						|
PRIVATE IxQMgrType ixQMgrQTypes[IX_QMGR_MAX_NUM_QUEUES];
 | 
						|
 | 
						|
/*
 | 
						|
 * This array contains a list of queue identifiers ordered by priority. The table
 | 
						|
 * is split logically between queue identifiers 0-31 and 32-63.
 | 
						|
 */
 | 
						|
static IxQMgrQId priorityTable[IX_QMGR_MAX_NUM_QUEUES];
 | 
						|
 | 
						|
/*
 | 
						|
 * This flag indicates to the dispatcher that the priority table needs to be rebuilt.
 | 
						|
 */
 | 
						|
static BOOL rebuildTable = FALSE;
 | 
						|
 | 
						|
/* Dispatcher statistics */
 | 
						|
static IxQMgrDispatcherStats dispatcherStats;
 | 
						|
 | 
						|
/* Table of queue information */
 | 
						|
static IxQMgrQInfo dispatchQInfo[IX_QMGR_MAX_NUM_QUEUES];
 | 
						|
 | 
						|
/* Masks use to identify the first queues in the priority tables 
 | 
						|
*  when comparing with the interrupt register
 | 
						|
*/
 | 
						|
static unsigned int lowPriorityTableFirstHalfMask;
 | 
						|
static unsigned int uppPriorityTableFirstHalfMask;
 | 
						|
 | 
						|
/*
 | 
						|
 * Static function prototypes
 | 
						|
 */
 | 
						|
 | 
						|
/*
 | 
						|
 * This function is the default callback for all queues
 | 
						|
 */
 | 
						|
PRIVATE void
 | 
						|
dummyCallback (IxQMgrQId qId,	      
 | 
						|
	       IxQMgrCallbackId cbId);
 | 
						|
 | 
						|
PRIVATE void
 | 
						|
ixQMgrDispatcherReBuildPriorityTable (void);
 | 
						|
 | 
						|
/*
 | 
						|
 * Function definitions.
 | 
						|
 */
 | 
						|
void
 | 
						|
ixQMgrDispatcherInit (void)
 | 
						|
{
 | 
						|
    int i;
 | 
						|
    IxFeatureCtrlProductId productId = 0;
 | 
						|
    IxFeatureCtrlDeviceId deviceId = 0;
 | 
						|
    BOOL stickyIntSilicon = TRUE; 
 | 
						|
 | 
						|
    /* Set default priorities */
 | 
						|
    for (i=0; i< IX_QMGR_MAX_NUM_QUEUES; i++)
 | 
						|
    {
 | 
						|
	dispatchQInfo[i].callback = dummyCallback;
 | 
						|
	dispatchQInfo[i].callbackId = 0;
 | 
						|
	dispatchQInfo[i].dummyCallbackCount = 0;
 | 
						|
	dispatchQInfo[i].priority = IX_QMGR_Q_PRIORITY_2;
 | 
						|
	dispatchQInfo[i].statusWordOffset = 0;
 | 
						|
	dispatchQInfo[i].statusCheckValue = 0;
 | 
						|
	dispatchQInfo[i].statusMask = 0;  
 | 
						|
        /* 
 | 
						|
	 * There are two interrupt registers, 32 bits each. One for the lower
 | 
						|
	 * queues(0-31) and one for the upper queues(32-63). Therefore need to
 | 
						|
	 * mod by 32 i.e the min upper queue identifier.
 | 
						|
	 */
 | 
						|
	dispatchQInfo[i].intRegCheckMask = (1<<(i%(IX_QMGR_MIN_QUEUPP_QID)));
 | 
						|
 | 
						|
        /* 
 | 
						|
         * Set the Q types - will only be used with livelock 
 | 
						|
         */
 | 
						|
        ixQMgrQTypes[i] = IX_QMGR_TYPE_REALTIME_OTHER;
 | 
						|
 | 
						|
	/* Reset queue statistics */
 | 
						|
	dispatcherStats.queueStats[i].callbackCnt = 0;
 | 
						|
	dispatcherStats.queueStats[i].priorityChangeCnt = 0;
 | 
						|
	dispatcherStats.queueStats[i].intNoCallbackCnt = 0;
 | 
						|
	dispatcherStats.queueStats[i].intLostCallbackCnt = 0;
 | 
						|
        dispatcherStats.queueStats[i].notificationEnabled = FALSE;
 | 
						|
        dispatcherStats.queueStats[i].srcSel = 0;
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
    /* Priority table. Order the table from queue 0 to 63 */
 | 
						|
    ixQMgrDispatcherReBuildPriorityTable();
 | 
						|
 | 
						|
    /* Reset statistics */
 | 
						|
    dispatcherStats.loopRunCnt = 0;
 | 
						|
 | 
						|
    /* Get the device ID for the underlying silicon */
 | 
						|
    deviceId = ixFeatureCtrlDeviceRead();
 | 
						|
    
 | 
						|
    /* Get the product ID for the underlying silicon */
 | 
						|
    productId = ixFeatureCtrlProductIdRead();
 | 
						|
 | 
						|
    /* 
 | 
						|
     * Check featureCtrl to see if Livelock prevention is required 
 | 
						|
     */
 | 
						|
    ixQMgrOrigB0Dispatcher = ixFeatureCtrlSwConfigurationCheck( 
 | 
						|
                                 IX_FEATURECTRL_ORIGB0_DISPATCHER);
 | 
						|
 | 
						|
    /*
 | 
						|
     * Check if the silicon supports the sticky interrupt feature.
 | 
						|
     * IF (IXP42X AND A0) -> No sticky interrupt feature supported 
 | 
						|
     */
 | 
						|
    if ((IX_FEATURE_CTRL_DEVICE_TYPE_IXP42X == 
 | 
						|
        (IX_FEATURE_CTRL_DEVICE_TYPE_MASK & deviceId)) &&
 | 
						|
        (IX_FEATURE_CTRL_SILICON_TYPE_A0 == 
 | 
						|
        (IX_FEATURE_CTRL_SILICON_STEPPING_MASK & productId))) 
 | 
						|
    {
 | 
						|
       stickyIntSilicon = FALSE;
 | 
						|
    }
 | 
						|
 | 
						|
    /*
 | 
						|
     * IF user wants livelock prev option AND silicon supports sticky interrupt 
 | 
						|
     * feature -> enable the sticky interrupt bit
 | 
						|
     */
 | 
						|
    if ((IX_FEATURE_CTRL_SWCONFIG_DISABLED == ixQMgrOrigB0Dispatcher) &&
 | 
						|
         stickyIntSilicon)  
 | 
						|
    {
 | 
						|
        ixQMgrStickyInterruptRegEnable();
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
IX_STATUS
 | 
						|
ixQMgrDispatcherPrioritySet (IxQMgrQId qId,
 | 
						|
			     IxQMgrPriority priority)
 | 
						|
{   
 | 
						|
    int ixQMgrLockKey;
 | 
						|
 | 
						|
    if (!ixQMgrQIsConfigured(qId))
 | 
						|
    {
 | 
						|
	return IX_QMGR_Q_NOT_CONFIGURED;
 | 
						|
    }
 | 
						|
    
 | 
						|
    if (!IX_QMGR_DISPATCHER_PRIORITY_CHECK(priority))
 | 
						|
    {
 | 
						|
	return IX_QMGR_Q_INVALID_PRIORITY;
 | 
						|
    }
 | 
						|
 | 
						|
    ixQMgrLockKey = ixOsalIrqLock();
 | 
						|
    
 | 
						|
    /* Change priority */
 | 
						|
    dispatchQInfo[qId].priority = priority;
 | 
						|
    /* Set flag */
 | 
						|
    rebuildTable = TRUE;
 | 
						|
 | 
						|
    ixOsalIrqUnlock(ixQMgrLockKey);
 | 
						|
 | 
						|
#ifndef NDEBUG
 | 
						|
    /* Update statistics */
 | 
						|
    dispatcherStats.queueStats[qId].priorityChangeCnt++;
 | 
						|
#endif
 | 
						|
 | 
						|
    return IX_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
IX_STATUS
 | 
						|
ixQMgrNotificationCallbackSet (IxQMgrQId qId,
 | 
						|
			       IxQMgrCallback callback,
 | 
						|
			       IxQMgrCallbackId callbackId)
 | 
						|
{
 | 
						|
    if (!ixQMgrQIsConfigured(qId))
 | 
						|
    {
 | 
						|
	return IX_QMGR_Q_NOT_CONFIGURED;
 | 
						|
    }
 | 
						|
 | 
						|
    if (NULL == callback)
 | 
						|
    {
 | 
						|
	/* Reset to dummy callback */
 | 
						|
	dispatchQInfo[qId].callback = dummyCallback;
 | 
						|
	dispatchQInfo[qId].dummyCallbackCount = 0;
 | 
						|
	dispatchQInfo[qId].callbackId = 0;
 | 
						|
    }
 | 
						|
    else 
 | 
						|
    {
 | 
						|
	dispatchQInfo[qId].callback = callback;
 | 
						|
	dispatchQInfo[qId].callbackId = callbackId;
 | 
						|
    }
 | 
						|
 | 
						|
    return IX_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
IX_STATUS
 | 
						|
ixQMgrNotificationEnable (IxQMgrQId qId, 
 | 
						|
			  IxQMgrSourceId srcSel)
 | 
						|
{
 | 
						|
    IxQMgrQStatus qStatusOnEntry;/* The queue status on entry/exit */
 | 
						|
    IxQMgrQStatus qStatusOnExit; /* to this function               */
 | 
						|
    int ixQMgrLockKey;
 | 
						|
 | 
						|
#ifndef NDEBUG
 | 
						|
    if (!ixQMgrQIsConfigured (qId))
 | 
						|
    {
 | 
						|
	return IX_QMGR_Q_NOT_CONFIGURED;
 | 
						|
    }
 | 
						|
 | 
						|
    if ((qId < IX_QMGR_MIN_QUEUPP_QID) &&
 | 
						|
       !IX_QMGR_DISPATCHER_SOURCE_ID_CHECK(srcSel))
 | 
						|
    {
 | 
						|
	/* QId 0-31 source id invalid */
 | 
						|
	return IX_QMGR_INVALID_INT_SOURCE_ID;
 | 
						|
    }
 | 
						|
 | 
						|
    if ((IX_QMGR_Q_SOURCE_ID_NE != srcSel) &&
 | 
						|
	(qId >= IX_QMGR_MIN_QUEUPP_QID))
 | 
						|
    {
 | 
						|
	/*
 | 
						|
	 * For queues 32-63 the interrupt source is fixed to the Nearly
 | 
						|
	 * Empty status flag and therefore should have a srcSel of NE.
 | 
						|
	 */
 | 
						|
	return IX_QMGR_INVALID_INT_SOURCE_ID;
 | 
						|
    }
 | 
						|
#endif
 | 
						|
 | 
						|
#ifndef NDEBUG
 | 
						|
    dispatcherStats.queueStats[qId].notificationEnabled = TRUE;
 | 
						|
    dispatcherStats.queueStats[qId].srcSel = srcSel;
 | 
						|
#endif
 | 
						|
 | 
						|
    /* Get the current queue status */
 | 
						|
    ixQMgrAqmIfQueStatRead (qId, &qStatusOnEntry);
 | 
						|
  
 | 
						|
    /* 
 | 
						|
     * Enabling interrupts results in Read-Modify-Write
 | 
						|
     * so need critical section
 | 
						|
     */
 | 
						|
 | 
						|
    ixQMgrLockKey = ixOsalIrqLock();
 | 
						|
 | 
						|
    /* Calculate the checkMask and checkValue for this q */
 | 
						|
    ixQMgrAqmIfQStatusCheckValsCalc (qId,
 | 
						|
				     srcSel,
 | 
						|
				     &dispatchQInfo[qId].statusWordOffset,
 | 
						|
				     &dispatchQInfo[qId].statusCheckValue,
 | 
						|
				     &dispatchQInfo[qId].statusMask);
 | 
						|
 | 
						|
 | 
						|
    /* Set the interrupt source is this queue is in the range 0-31 */
 | 
						|
    if (qId < IX_QMGR_MIN_QUEUPP_QID)
 | 
						|
    {
 | 
						|
	ixQMgrAqmIfIntSrcSelWrite (qId, srcSel);
 | 
						|
    }
 | 
						|
 | 
						|
    /* Enable the interrupt */
 | 
						|
    ixQMgrAqmIfQInterruptEnable (qId);
 | 
						|
 | 
						|
    ixOsalIrqUnlock(ixQMgrLockKey);
 | 
						|
    
 | 
						|
    /* Get the current queue status */
 | 
						|
    ixQMgrAqmIfQueStatRead (qId, &qStatusOnExit);
 | 
						|
  
 | 
						|
    /* If the status has changed return a warning */
 | 
						|
    if (qStatusOnEntry != qStatusOnExit)
 | 
						|
    {
 | 
						|
	return IX_QMGR_WARNING;
 | 
						|
    }
 | 
						|
    
 | 
						|
    return IX_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
IX_STATUS
 | 
						|
ixQMgrNotificationDisable (IxQMgrQId qId)
 | 
						|
{
 | 
						|
    int ixQMgrLockKey;
 | 
						|
 | 
						|
#ifndef NDEBUG
 | 
						|
    /* Validate parameters */
 | 
						|
    if (!ixQMgrQIsConfigured (qId))
 | 
						|
    {
 | 
						|
	return IX_QMGR_Q_NOT_CONFIGURED;
 | 
						|
    }
 | 
						|
#endif
 | 
						|
  
 | 
						|
    /* 
 | 
						|
     * Enabling interrupts results in Read-Modify-Write
 | 
						|
     * so need critical section
 | 
						|
     */
 | 
						|
#ifndef NDEBUG
 | 
						|
    dispatcherStats.queueStats[qId].notificationEnabled = FALSE;
 | 
						|
#endif
 | 
						|
 | 
						|
    ixQMgrLockKey = ixOsalIrqLock();
 | 
						|
 | 
						|
    ixQMgrAqmIfQInterruptDisable (qId);
 | 
						|
    
 | 
						|
    ixOsalIrqUnlock(ixQMgrLockKey);
 | 
						|
 | 
						|
    return IX_SUCCESS;    
 | 
						|
}
 | 
						|
 | 
						|
void 
 | 
						|
ixQMgrStickyInterruptRegEnable(void)
 | 
						|
{
 | 
						|
 /* Use Aqm If function to set Interrupt Register0 Bit-3 */ 
 | 
						|
 ixQMgrAqmIfIntSrcSelReg0Bit3Set ();   
 | 
						|
}
 | 
						|
 | 
						|
#if !defined __XSCALE__ || defined __linux
 | 
						|
 | 
						|
/* Count the number of leading zero bits in a word,
 | 
						|
 * and return the same value than the CLZ instruction.
 | 
						|
 *
 | 
						|
 * word (in)    return value (out)
 | 
						|
 * 0x80000000   0
 | 
						|
 * 0x40000000   1
 | 
						|
 * ,,,          ,,,
 | 
						|
 * 0x00000002   30
 | 
						|
 * 0x00000001   31
 | 
						|
 * 0x00000000   32
 | 
						|
 *
 | 
						|
 * The C version of this function is used as a replacement 
 | 
						|
 * for system not providing the equivalent of the CLZ 
 | 
						|
 * assembly language instruction.
 | 
						|
 *
 | 
						|
 * Note that this version is big-endian
 | 
						|
 */
 | 
						|
unsigned int
 | 
						|
ixQMgrCountLeadingZeros(UINT32 word)
 | 
						|
{
 | 
						|
  unsigned int leadingZerosCount = 0;
 | 
						|
 | 
						|
  if (word == 0)
 | 
						|
  {
 | 
						|
      return 32;
 | 
						|
  }
 | 
						|
  /* search the first bit set by testing the MSB and shifting the input word */
 | 
						|
  while ((word & 0x80000000) == 0)
 | 
						|
  {
 | 
						|
      word <<= 1;
 | 
						|
      leadingZerosCount++;
 | 
						|
  }
 | 
						|
  return leadingZerosCount;
 | 
						|
}
 | 
						|
#endif /* not  __XSCALE__ or __linux */
 | 
						|
 | 
						|
void
 | 
						|
ixQMgrDispatcherLoopGet (IxQMgrDispatcherFuncPtr *qDispatcherFuncPtr)
 | 
						|
{
 | 
						|
  IxFeatureCtrlProductId productId = 0;
 | 
						|
  IxFeatureCtrlDeviceId deviceId = 0;
 | 
						|
  
 | 
						|
  /* Get the device ID for the underlying silicon */
 | 
						|
  deviceId = ixFeatureCtrlDeviceRead();
 | 
						|
 | 
						|
  /* Get the product ID for the underlying silicon */
 | 
						|
  productId = ixFeatureCtrlProductIdRead ();
 | 
						|
 | 
						|
  /* IF (IXP42X AND A0 silicon) -> use ixQMgrDispatcherLoopRunA0 */
 | 
						|
  if ((IX_FEATURE_CTRL_DEVICE_TYPE_IXP42X ==
 | 
						|
      (IX_FEATURE_CTRL_DEVICE_TYPE_MASK & deviceId)) &&
 | 
						|
      (IX_FEATURE_CTRL_SILICON_TYPE_A0 ==  
 | 
						|
      (IX_FEATURE_CTRL_SILICON_STEPPING_MASK & productId)))  
 | 
						|
  {
 | 
						|
    /*For IXP42X A0 silicon */
 | 
						|
    *qDispatcherFuncPtr = &ixQMgrDispatcherLoopRunA0 ;
 | 
						|
  } 
 | 
						|
  else /*For IXP42X B0 or IXP46X silicon*/ 
 | 
						|
  { 
 | 
						|
    if (IX_FEATURE_CTRL_SWCONFIG_ENABLED == ixQMgrOrigB0Dispatcher)
 | 
						|
    {
 | 
						|
        /* Default for IXP42X B0 and IXP46X silicon */
 | 
						|
        *qDispatcherFuncPtr = &ixQMgrDispatcherLoopRunB0;
 | 
						|
    }
 | 
						|
    else 
 | 
						|
    {
 | 
						|
        /* FeatureCtrl indicated that livelock dispatcher be used */
 | 
						|
        *qDispatcherFuncPtr = &ixQMgrDispatcherLoopRunB0LLP;
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
ixQMgrDispatcherLoopRunA0 (IxQMgrDispatchGroup group)
 | 
						|
{
 | 
						|
    UINT32 intRegVal;                /* Interrupt reg val */
 | 
						|
    UINT32 intRegValAfterWrite;      /* Interrupt reg val after writing back */
 | 
						|
    UINT32 intRegCheckMask;          /* Mask for checking interrupt bits */
 | 
						|
    UINT32 qStatusWordsB4Write[MAX_Q_STATUS_WORDS];  /* Status b4 interrupt write */
 | 
						|
    UINT32 qStatusWordsAfterWrite[MAX_Q_STATUS_WORDS]; /* Status after interrupt write */
 | 
						|
    IxQMgrQInfo *currDispatchQInfo;
 | 
						|
    BOOL statusChangeFlag;
 | 
						|
 | 
						|
    int priorityTableIndex;/* Priority table index */
 | 
						|
    int qIndex;            /* Current queue being processed */
 | 
						|
    int endIndex;          /* Index of last queue to process */
 | 
						|
 | 
						|
#ifndef NDEBUG
 | 
						|
    IX_OSAL_ASSERT((group == IX_QMGR_QUEUPP_GROUP) || 
 | 
						|
	      (group == IX_QMGR_QUELOW_GROUP));
 | 
						|
#endif
 | 
						|
 | 
						|
    /* Read Q status registers before interrupt status read/write */
 | 
						|
    ixQMgrAqmIfQStatusRegsRead (group, qStatusWordsB4Write);
 | 
						|
 | 
						|
    /* Read the interrupt register */
 | 
						|
    ixQMgrAqmIfQInterruptRegRead (group, &intRegVal);
 | 
						|
 | 
						|
    /* No bit set : nothing to process (the reaminder of the algorithm is
 | 
						|
    * based on the fact that the interrupt register value contains at
 | 
						|
    * least one bit set
 | 
						|
    */
 | 
						|
    if (intRegVal == 0) 
 | 
						|
    {
 | 
						|
#ifndef NDEBUG
 | 
						|
	/* Update statistics */
 | 
						|
	dispatcherStats.loopRunCnt++;
 | 
						|
#endif
 | 
						|
 | 
						|
	/* Rebuild the priority table if needed */
 | 
						|
	if (rebuildTable)
 | 
						|
	{
 | 
						|
	    ixQMgrDispatcherReBuildPriorityTable ();
 | 
						|
	}
 | 
						|
 | 
						|
	return;
 | 
						|
    }
 | 
						|
   
 | 
						|
    /* Write it back to clear the interrupt */
 | 
						|
    ixQMgrAqmIfQInterruptRegWrite (group, intRegVal);
 | 
						|
 | 
						|
    /* Read Q status registers after interrupt status read/write */
 | 
						|
    ixQMgrAqmIfQStatusRegsRead (group, qStatusWordsAfterWrite);
 | 
						|
 
 | 
						|
    /* get the first queue Id from the interrupt register value */
 | 
						|
    qIndex = (BITS_PER_WORD - 1) - ixQMgrCountLeadingZeros(intRegVal);
 | 
						|
 | 
						|
    /* check if any change occured during hw register modifications */ 
 | 
						|
    if (IX_QMGR_QUELOW_GROUP == group)
 | 
						|
    {
 | 
						|
	statusChangeFlag = 
 | 
						|
	    (qStatusWordsB4Write[0] != qStatusWordsAfterWrite[0]) ||
 | 
						|
	    (qStatusWordsB4Write[1] != qStatusWordsAfterWrite[1]) ||
 | 
						|
	    (qStatusWordsB4Write[2] != qStatusWordsAfterWrite[2]) ||
 | 
						|
	    (qStatusWordsB4Write[3] != qStatusWordsAfterWrite[3]);
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
	statusChangeFlag = 
 | 
						|
	    (qStatusWordsB4Write[0] != qStatusWordsAfterWrite[0]);
 | 
						|
	/* Set the queue range based on the queue group to proccess */
 | 
						|
	qIndex += IX_QMGR_MIN_QUEUPP_QID;
 | 
						|
    }
 | 
						|
 | 
						|
    if (statusChangeFlag == FALSE)
 | 
						|
    {
 | 
						|
	/* check if the interrupt register contains 
 | 
						|
	 * only 1 bit set (happy day scenario)
 | 
						|
	 */
 | 
						|
	currDispatchQInfo = &dispatchQInfo[qIndex];
 | 
						|
	if (intRegVal == currDispatchQInfo->intRegCheckMask)
 | 
						|
	{
 | 
						|
	    /* only 1 queue event triggered a notification *
 | 
						|
	     * Call the callback function for this queue 
 | 
						|
	     */
 | 
						|
	    currDispatchQInfo->callback (qIndex,
 | 
						|
					 currDispatchQInfo->callbackId);  
 | 
						|
#ifndef NDEBUG
 | 
						|
	    /* Update statistics */
 | 
						|
	    dispatcherStats.queueStats[qIndex].callbackCnt++;
 | 
						|
#endif
 | 
						|
	}
 | 
						|
	else 
 | 
						|
	{
 | 
						|
	    /* the event is triggered by more than 1 queue, 
 | 
						|
	     * the queue search will be starting from the beginning
 | 
						|
	     * or the middle of the priority table
 | 
						|
	     *
 | 
						|
	     * the serach will end when all the bits of the interrupt
 | 
						|
	     * register are cleared. There is no need to maintain
 | 
						|
	     * a seperate value and test it at each iteration.
 | 
						|
	     */
 | 
						|
	    if (IX_QMGR_QUELOW_GROUP == group)
 | 
						|
	    {
 | 
						|
		/* check if any bit related to queues in the first
 | 
						|
		 * half of the priority table is set
 | 
						|
		 */
 | 
						|
		if (intRegVal & lowPriorityTableFirstHalfMask)
 | 
						|
		{
 | 
						|
		    priorityTableIndex = IX_QMGR_MIN_LOW_QUE_PRIORITY_TABLE_INDEX;
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
		    priorityTableIndex = IX_QMGR_MID_LOW_QUE_PRIORITY_TABLE_INDEX;
 | 
						|
		}
 | 
						|
	    }
 | 
						|
	    else 
 | 
						|
	    {
 | 
						|
		/* check if any bit related to queues in the first
 | 
						|
		 * half of the priority table is set
 | 
						|
		 */
 | 
						|
		if (intRegVal & uppPriorityTableFirstHalfMask)
 | 
						|
		{
 | 
						|
		    priorityTableIndex = IX_QMGR_MIN_UPP_QUE_PRIORITY_TABLE_INDEX;
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
		    priorityTableIndex = IX_QMGR_MID_UPP_QUE_PRIORITY_TABLE_INDEX;
 | 
						|
		}
 | 
						|
	    }
 | 
						|
	    
 | 
						|
	    /* iterate following the priority table until all the bits 
 | 
						|
	     * of the interrupt register are cleared.
 | 
						|
	     */
 | 
						|
	    do
 | 
						|
	    {
 | 
						|
		qIndex = priorityTable[priorityTableIndex++];
 | 
						|
		currDispatchQInfo = &dispatchQInfo[qIndex];
 | 
						|
		intRegCheckMask = currDispatchQInfo->intRegCheckMask;
 | 
						|
		
 | 
						|
		/* If this queue caused this interrupt to be raised */
 | 
						|
		if (intRegVal & intRegCheckMask)
 | 
						|
		{
 | 
						|
		    /* Call the callback function for this queue */
 | 
						|
		    currDispatchQInfo->callback (qIndex,
 | 
						|
						 currDispatchQInfo->callbackId);
 | 
						|
#ifndef NDEBUG
 | 
						|
		    /* Update statistics */
 | 
						|
		    dispatcherStats.queueStats[qIndex].callbackCnt++;
 | 
						|
#endif
 | 
						|
		    
 | 
						|
		    /* Clear the interrupt register bit */
 | 
						|
		    intRegVal &= ~intRegCheckMask;
 | 
						|
		}
 | 
						|
	    }
 | 
						|
	    while(intRegVal);
 | 
						|
	}
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
    /* A change in queue status occured during the hw interrupt
 | 
						|
     * register update. To maintain the interrupt consistency, it
 | 
						|
     * is necessary to iterate through all queues of the queue group.
 | 
						|
     */
 | 
						|
 | 
						|
    /* Read interrupt status again */
 | 
						|
    ixQMgrAqmIfQInterruptRegRead (group, &intRegValAfterWrite);
 | 
						|
 | 
						|
    if (IX_QMGR_QUELOW_GROUP == group)
 | 
						|
    {
 | 
						|
	priorityTableIndex = IX_QMGR_MIN_LOW_QUE_PRIORITY_TABLE_INDEX;
 | 
						|
	endIndex = IX_QMGR_MAX_LOW_QUE_PRIORITY_TABLE_INDEX;
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
	priorityTableIndex = IX_QMGR_MIN_UPP_QUE_PRIORITY_TABLE_INDEX;
 | 
						|
	endIndex = IX_QMGR_MAX_UPP_QUE_PRIORITY_TABLE_INDEX;
 | 
						|
    }
 | 
						|
 | 
						|
    for ( ; priorityTableIndex<=endIndex; priorityTableIndex++)
 | 
						|
    {
 | 
						|
	qIndex = priorityTable[priorityTableIndex];
 | 
						|
	currDispatchQInfo = &dispatchQInfo[qIndex];
 | 
						|
	intRegCheckMask = currDispatchQInfo->intRegCheckMask;
 | 
						|
 | 
						|
	/* If this queue caused this interrupt to be raised */
 | 
						|
	if (intRegVal & intRegCheckMask)
 | 
						|
	{  
 | 
						|
	    /* Call the callback function for this queue */
 | 
						|
	    currDispatchQInfo->callback (qIndex,
 | 
						|
					 currDispatchQInfo->callbackId);
 | 
						|
#ifndef NDEBUG
 | 
						|
	    /* Update statistics */
 | 
						|
	    dispatcherStats.queueStats[qIndex].callbackCnt++;
 | 
						|
#endif
 | 
						|
	    
 | 
						|
	} /* if (intRegVal .. */
 | 
						|
 | 
						|
	/* 
 | 
						|
	 * If interrupt bit is set in intRegValAfterWrite don't
 | 
						|
	 * proceed as this will be caught in next interrupt
 | 
						|
	 */
 | 
						|
	else if ((intRegValAfterWrite & intRegCheckMask) == 0)
 | 
						|
	{
 | 
						|
	    /* Check if an interrupt was lost for this Q */
 | 
						|
	    if (ixQMgrAqmIfQStatusCheck(qStatusWordsB4Write,
 | 
						|
					qStatusWordsAfterWrite,
 | 
						|
					currDispatchQInfo->statusWordOffset,
 | 
						|
					currDispatchQInfo->statusCheckValue,
 | 
						|
					currDispatchQInfo->statusMask))
 | 
						|
	    {
 | 
						|
		/* Call the callback function for this queue */
 | 
						|
		currDispatchQInfo->callback (qIndex, 
 | 
						|
					     dispatchQInfo[qIndex].callbackId);                 
 | 
						|
#ifndef NDEBUG
 | 
						|
		/* Update statistics */
 | 
						|
		dispatcherStats.queueStats[qIndex].callbackCnt++;
 | 
						|
		dispatcherStats.queueStats[qIndex].intLostCallbackCnt++;
 | 
						|
#endif
 | 
						|
	    } /* if ixQMgrAqmIfQStatusCheck(.. */
 | 
						|
	} /* else if ((intRegValAfterWrite ... */
 | 
						|
    } /* for (priorityTableIndex=0 ... */
 | 
						|
    }
 | 
						|
 | 
						|
    /* Rebuild the priority table if needed */
 | 
						|
    if (rebuildTable)
 | 
						|
    {
 | 
						|
	ixQMgrDispatcherReBuildPriorityTable ();
 | 
						|
    }
 | 
						|
 | 
						|
#ifndef NDEBUG
 | 
						|
    /* Update statistics */
 | 
						|
    dispatcherStats.loopRunCnt++;
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
void
 | 
						|
ixQMgrDispatcherLoopRunB0 (IxQMgrDispatchGroup group)
 | 
						|
{
 | 
						|
    UINT32 intRegVal;                /* Interrupt reg val */
 | 
						|
    UINT32 intRegCheckMask;          /* Mask for checking interrupt bits */
 | 
						|
    IxQMgrQInfo *currDispatchQInfo;
 | 
						|
 | 
						|
 | 
						|
    int priorityTableIndex; /* Priority table index */
 | 
						|
    int qIndex;             /* Current queue being processed */
 | 
						|
 | 
						|
#ifndef NDEBUG
 | 
						|
    IX_OSAL_ASSERT((group == IX_QMGR_QUEUPP_GROUP) ||
 | 
						|
              (group == IX_QMGR_QUELOW_GROUP));
 | 
						|
    IX_OSAL_ASSERT((group == IX_QMGR_QUEUPP_GROUP) || 
 | 
						|
	      (group == IX_QMGR_QUELOW_GROUP));
 | 
						|
#endif
 | 
						|
 | 
						|
    /* Read the interrupt register */
 | 
						|
    ixQMgrAqmIfQInterruptRegRead (group, &intRegVal);
 | 
						|
 | 
						|
 | 
						|
    /* No queue has interrupt register set */
 | 
						|
    if (intRegVal != 0)
 | 
						|
    {
 | 
						|
 | 
						|
            /* Write it back to clear the interrupt */
 | 
						|
            ixQMgrAqmIfQInterruptRegWrite (group, intRegVal);
 | 
						|
 | 
						|
            /* get the first queue Id from the interrupt register value */
 | 
						|
            qIndex = (BITS_PER_WORD - 1) - ixQMgrCountLeadingZeros(intRegVal);
 | 
						|
 | 
						|
            if (IX_QMGR_QUEUPP_GROUP == group)
 | 
						|
            {
 | 
						|
                /* Set the queue range based on the queue group to proccess */
 | 
						|
                qIndex += IX_QMGR_MIN_QUEUPP_QID;
 | 
						|
            }
 | 
						|
 | 
						|
            /* check if the interrupt register contains
 | 
						|
             * only 1 bit set
 | 
						|
             * For example:
 | 
						|
             *                                        intRegVal = 0x0010
 | 
						|
             *               currDispatchQInfo->intRegCheckMask = 0x0010
 | 
						|
             *    intRegVal == currDispatchQInfo->intRegCheckMask is TRUE.
 | 
						|
             */
 | 
						|
             currDispatchQInfo = &dispatchQInfo[qIndex];
 | 
						|
             if (intRegVal == currDispatchQInfo->intRegCheckMask)
 | 
						|
             {
 | 
						|
                /* only 1 queue event triggered a notification *
 | 
						|
                 * Call the callback function for this queue
 | 
						|
                 */
 | 
						|
                currDispatchQInfo->callback (qIndex,
 | 
						|
                                     currDispatchQInfo->callbackId);
 | 
						|
#ifndef NDEBUG
 | 
						|
                /* Update statistics */
 | 
						|
                dispatcherStats.queueStats[qIndex].callbackCnt++;
 | 
						|
#endif
 | 
						|
             }
 | 
						|
             else
 | 
						|
             {
 | 
						|
                 /* the event is triggered by more than 1 queue,
 | 
						|
                  * the queue search will be starting from the beginning
 | 
						|
                  * or the middle of the priority table
 | 
						|
                  *
 | 
						|
                  * the serach will end when all the bits of the interrupt
 | 
						|
                  * register are cleared. There is no need to maintain
 | 
						|
                  * a seperate value and test it at each iteration.
 | 
						|
                  */
 | 
						|
                 if (IX_QMGR_QUELOW_GROUP == group)
 | 
						|
                 {
 | 
						|
                     /* check if any bit related to queues in the first
 | 
						|
                      * half of the priority table is set
 | 
						|
                      */
 | 
						|
                     if (intRegVal & lowPriorityTableFirstHalfMask)
 | 
						|
                     {
 | 
						|
                         priorityTableIndex = IX_QMGR_MIN_LOW_QUE_PRIORITY_TABLE_INDEX;
 | 
						|
                     }
 | 
						|
                     else
 | 
						|
                     {
 | 
						|
                         priorityTableIndex = IX_QMGR_MID_LOW_QUE_PRIORITY_TABLE_INDEX;
 | 
						|
                     }
 | 
						|
                 }
 | 
						|
                else
 | 
						|
                 {
 | 
						|
                     /* check if any bit related to queues in the first
 | 
						|
                      * half of the priority table is set
 | 
						|
                      */
 | 
						|
                     if (intRegVal & uppPriorityTableFirstHalfMask)
 | 
						|
                     {
 | 
						|
                         priorityTableIndex = IX_QMGR_MIN_UPP_QUE_PRIORITY_TABLE_INDEX;
 | 
						|
                     }
 | 
						|
                     else
 | 
						|
                     {
 | 
						|
                         priorityTableIndex = IX_QMGR_MID_UPP_QUE_PRIORITY_TABLE_INDEX;
 | 
						|
                     }
 | 
						|
                 }
 | 
						|
 | 
						|
                 /* iterate following the priority table until all the bits
 | 
						|
                  * of the interrupt register are cleared.
 | 
						|
                  */
 | 
						|
                 do
 | 
						|
                 {
 | 
						|
                     qIndex = priorityTable[priorityTableIndex++];
 | 
						|
                     currDispatchQInfo = &dispatchQInfo[qIndex];
 | 
						|
                     intRegCheckMask = currDispatchQInfo->intRegCheckMask;
 | 
						|
 | 
						|
                     /* If this queue caused this interrupt to be raised */
 | 
						|
                     if (intRegVal & intRegCheckMask)
 | 
						|
                     {
 | 
						|
                         /* Call the callback function for this queue */
 | 
						|
                         currDispatchQInfo->callback (qIndex,
 | 
						|
                                              currDispatchQInfo->callbackId);
 | 
						|
#ifndef NDEBUG
 | 
						|
                         /* Update statistics */
 | 
						|
                         dispatcherStats.queueStats[qIndex].callbackCnt++;
 | 
						|
#endif
 | 
						|
 | 
						|
                         /* Clear the interrupt register bit */
 | 
						|
                         intRegVal &= ~intRegCheckMask;
 | 
						|
                     }
 | 
						|
                  }
 | 
						|
                  while(intRegVal);
 | 
						|
             } /*End of intRegVal == currDispatchQInfo->intRegCheckMask */
 | 
						|
     } /* End of intRegVal != 0 */
 | 
						|
 | 
						|
#ifndef NDEBUG
 | 
						|
    /* Update statistics */
 | 
						|
    dispatcherStats.loopRunCnt++;
 | 
						|
#endif
 | 
						|
 | 
						|
    /* Rebuild the priority table if needed */
 | 
						|
    if (rebuildTable)
 | 
						|
    {
 | 
						|
        ixQMgrDispatcherReBuildPriorityTable ();
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
ixQMgrDispatcherLoopRunB0LLP (IxQMgrDispatchGroup group)
 | 
						|
{
 | 
						|
    UINT32 intRegVal =0;                /* Interrupt reg val */
 | 
						|
    UINT32 intRegCheckMask;          /* Mask for checking interrupt bits */
 | 
						|
    IxQMgrQInfo *currDispatchQInfo;
 | 
						|
 | 
						|
    int priorityTableIndex; /* Priority table index */
 | 
						|
    int qIndex;             /* Current queue being processed */
 | 
						|
 | 
						|
    UINT32 intRegValCopy = 0;
 | 
						|
    UINT32 intEnableRegVal = 0;
 | 
						|
    UINT8 i = 0;
 | 
						|
 | 
						|
#ifndef NDEBUG
 | 
						|
    IX_OSAL_ASSERT((group == IX_QMGR_QUEUPP_GROUP) ||
 | 
						|
              (group == IX_QMGR_QUELOW_GROUP));
 | 
						|
#endif
 | 
						|
 | 
						|
    /* Read the interrupt register */
 | 
						|
    ixQMgrAqmIfQInterruptRegRead (group, &intRegVal);
 | 
						|
 | 
						|
    /* 
 | 
						|
     * mask any interrupts that are not enabled 
 | 
						|
     */
 | 
						|
    ixQMgrAqmIfQInterruptEnableRegRead (group, &intEnableRegVal);
 | 
						|
    intRegVal &= intEnableRegVal;
 | 
						|
 | 
						|
    /* No queue has interrupt register set */
 | 
						|
    if (intRegVal != 0)
 | 
						|
    {
 | 
						|
        if (IX_QMGR_QUELOW_GROUP == group)
 | 
						|
        {
 | 
						|
            /*
 | 
						|
             * As the sticky bit is set, the interrupt register will 
 | 
						|
             * not clear if write back at this point because the condition
 | 
						|
             * has not been cleared. Take a copy and write back later after
 | 
						|
             * the condition has been cleared
 | 
						|
             */
 | 
						|
            intRegValCopy = intRegVal;
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            /* no sticky for upper Q's, so write back now */
 | 
						|
            ixQMgrAqmIfQInterruptRegWrite (group, intRegVal);
 | 
						|
        }
 | 
						|
 | 
						|
        /* get the first queue Id from the interrupt register value */
 | 
						|
        qIndex = (BITS_PER_WORD - 1) - ixQMgrCountLeadingZeros(intRegVal);
 | 
						|
 | 
						|
        if (IX_QMGR_QUEUPP_GROUP == group)
 | 
						|
        {
 | 
						|
            /* Set the queue range based on the queue group to proccess */
 | 
						|
            qIndex += IX_QMGR_MIN_QUEUPP_QID;
 | 
						|
        }
 | 
						|
 | 
						|
        /* check if the interrupt register contains
 | 
						|
        * only 1 bit set
 | 
						|
        * For example:
 | 
						|
        *                                        intRegVal = 0x0010
 | 
						|
        *               currDispatchQInfo->intRegCheckMask = 0x0010
 | 
						|
        *    intRegVal == currDispatchQInfo->intRegCheckMask is TRUE.
 | 
						|
        */
 | 
						|
        currDispatchQInfo = &dispatchQInfo[qIndex];
 | 
						|
        if (intRegVal == currDispatchQInfo->intRegCheckMask)
 | 
						|
        {
 | 
						|
 | 
						|
            /* 
 | 
						|
             * check if Q type periodic -  only lower queues can
 | 
						|
             * have there type set to periodic 
 | 
						|
             */
 | 
						|
            if (IX_QMGR_TYPE_REALTIME_PERIODIC == ixQMgrQTypes[qIndex])
 | 
						|
            {
 | 
						|
                /* 
 | 
						|
                 * Disable the notifications on any sporadics 
 | 
						|
                 */
 | 
						|
                for (i=0; i <= IX_QMGR_MAX_LOW_QUE_TABLE_INDEX; i++)
 | 
						|
                {
 | 
						|
                    if (IX_QMGR_TYPE_REALTIME_SPORADIC == ixQMgrQTypes[i])
 | 
						|
                    {
 | 
						|
                        ixQMgrNotificationDisable(i);
 | 
						|
#ifndef NDEBUG
 | 
						|
                        /* Update statistics */
 | 
						|
                        dispatcherStats.queueStats[i].disableCount++;
 | 
						|
#endif
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            currDispatchQInfo->callback (qIndex,
 | 
						|
                                         currDispatchQInfo->callbackId);
 | 
						|
#ifndef NDEBUG
 | 
						|
            /* Update statistics */
 | 
						|
            dispatcherStats.queueStats[qIndex].callbackCnt++;
 | 
						|
#endif
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            /* the event is triggered by more than 1 queue,
 | 
						|
            * the queue search will be starting from the beginning
 | 
						|
            * or the middle of the priority table
 | 
						|
            *
 | 
						|
            * the serach will end when all the bits of the interrupt
 | 
						|
            * register are cleared. There is no need to maintain
 | 
						|
            * a seperate value and test it at each iteration.
 | 
						|
            */
 | 
						|
            if (IX_QMGR_QUELOW_GROUP == group)
 | 
						|
            {
 | 
						|
                /* check if any bit related to queues in the first
 | 
						|
                 * half of the priority table is set
 | 
						|
                 */
 | 
						|
                if (intRegVal & lowPriorityTableFirstHalfMask)
 | 
						|
                {
 | 
						|
                    priorityTableIndex =
 | 
						|
                                       IX_QMGR_MIN_LOW_QUE_PRIORITY_TABLE_INDEX;
 | 
						|
                }
 | 
						|
                else
 | 
						|
                {
 | 
						|
                    priorityTableIndex =
 | 
						|
                                       IX_QMGR_MID_LOW_QUE_PRIORITY_TABLE_INDEX;
 | 
						|
                }
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                /* check if any bit related to queues in the first
 | 
						|
                 * half of the priority table is set
 | 
						|
                 */
 | 
						|
                if (intRegVal & uppPriorityTableFirstHalfMask)
 | 
						|
                {
 | 
						|
                    priorityTableIndex =
 | 
						|
                                       IX_QMGR_MIN_UPP_QUE_PRIORITY_TABLE_INDEX;
 | 
						|
                }
 | 
						|
                else
 | 
						|
                {
 | 
						|
                    priorityTableIndex =
 | 
						|
                                       IX_QMGR_MID_UPP_QUE_PRIORITY_TABLE_INDEX;
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            /* iterate following the priority table until all the bits
 | 
						|
             * of the interrupt register are cleared.
 | 
						|
             */
 | 
						|
            do
 | 
						|
            {
 | 
						|
                qIndex = priorityTable[priorityTableIndex++];
 | 
						|
                currDispatchQInfo = &dispatchQInfo[qIndex];
 | 
						|
                intRegCheckMask = currDispatchQInfo->intRegCheckMask;
 | 
						|
 | 
						|
                /* If this queue caused this interrupt to be raised */
 | 
						|
                if (intRegVal & intRegCheckMask)
 | 
						|
                {
 | 
						|
                    /* 
 | 
						|
                     * check if Q type periodic - only lower queues can
 | 
						|
                     * have there type set to periodic. There can only be one
 | 
						|
                     * periodic queue, so the sporadics are only disabled once.
 | 
						|
                     */
 | 
						|
                    if (IX_QMGR_TYPE_REALTIME_PERIODIC == ixQMgrQTypes[qIndex])
 | 
						|
                    {
 | 
						|
                        /* 
 | 
						|
                         * Disable the notifications on any sporadics 
 | 
						|
                         */
 | 
						|
                        for (i=0; i <= IX_QMGR_MAX_LOW_QUE_TABLE_INDEX; i++)
 | 
						|
                        {
 | 
						|
                            if (IX_QMGR_TYPE_REALTIME_SPORADIC == 
 | 
						|
                                    ixQMgrQTypes[i])
 | 
						|
                            {
 | 
						|
                                ixQMgrNotificationDisable(i);
 | 
						|
                                /* 
 | 
						|
                                 * remove from intRegVal as we don't want 
 | 
						|
                                 * to service any sporadics now
 | 
						|
                                 */
 | 
						|
                                intRegVal &= ~dispatchQInfo[i].intRegCheckMask;
 | 
						|
#ifndef NDEBUG
 | 
						|
                                /* Update statistics */
 | 
						|
                                dispatcherStats.queueStats[i].disableCount++;
 | 
						|
#endif
 | 
						|
                            }
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
 | 
						|
                    currDispatchQInfo->callback (qIndex,
 | 
						|
                                                 currDispatchQInfo->callbackId);
 | 
						|
#ifndef NDEBUG
 | 
						|
                    /* Update statistics */
 | 
						|
                    dispatcherStats.queueStats[qIndex].callbackCnt++;
 | 
						|
#endif
 | 
						|
                    /* Clear the interrupt register bit */
 | 
						|
                    intRegVal &= ~intRegCheckMask;
 | 
						|
                }
 | 
						|
            }
 | 
						|
            while(intRegVal);
 | 
						|
        } /*End of intRegVal == currDispatchQInfo->intRegCheckMask */
 | 
						|
    } /* End of intRegVal != 0 */
 | 
						|
 | 
						|
#ifndef NDEBUG
 | 
						|
    /* Update statistics */
 | 
						|
    dispatcherStats.loopRunCnt++;
 | 
						|
#endif
 | 
						|
 | 
						|
    if ((intRegValCopy != 0) && (IX_QMGR_QUELOW_GROUP == group))
 | 
						|
    {
 | 
						|
        /* 
 | 
						|
         * lower groups (therefore sticky) AND at least one enabled interrupt
 | 
						|
         * Write back to clear the interrupt 
 | 
						|
         */
 | 
						|
        ixQMgrAqmIfQInterruptRegWrite (IX_QMGR_QUELOW_GROUP, intRegValCopy);
 | 
						|
    }
 | 
						|
 | 
						|
    /* Rebuild the priority table if needed */
 | 
						|
    if (rebuildTable)
 | 
						|
    {
 | 
						|
        ixQMgrDispatcherReBuildPriorityTable ();
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
PRIVATE void
 | 
						|
ixQMgrDispatcherReBuildPriorityTable (void)
 | 
						|
{
 | 
						|
    UINT32 qIndex;
 | 
						|
    UINT32 priority;
 | 
						|
    int lowQuePriorityTableIndex = IX_QMGR_MIN_LOW_QUE_PRIORITY_TABLE_INDEX;
 | 
						|
    int uppQuePriorityTableIndex = IX_QMGR_MIN_UPP_QUE_PRIORITY_TABLE_INDEX;
 | 
						|
 | 
						|
    /* Reset the rebuild flag */
 | 
						|
    rebuildTable = FALSE;
 | 
						|
 | 
						|
    /* initialize the mak used to identify the queues in the first half
 | 
						|
     * of the priority table
 | 
						|
     */
 | 
						|
    lowPriorityTableFirstHalfMask = 0;
 | 
						|
    uppPriorityTableFirstHalfMask = 0;
 | 
						|
    
 | 
						|
    /* For each priority level */
 | 
						|
    for(priority=0; priority<IX_QMGR_NUM_PRIORITY_LEVELS; priority++)
 | 
						|
    {
 | 
						|
	/* Foreach low queue in this priority */
 | 
						|
	for(qIndex=0; qIndex<IX_QMGR_MIN_QUEUPP_QID; qIndex++)
 | 
						|
	{
 | 
						|
	    if (dispatchQInfo[qIndex].priority == priority)
 | 
						|
	    { 
 | 
						|
		/* build the priority table bitmask which match the
 | 
						|
		 * queues of the first half of the priority table 
 | 
						|
		 */
 | 
						|
		if (lowQuePriorityTableIndex < IX_QMGR_MID_LOW_QUE_PRIORITY_TABLE_INDEX) 
 | 
						|
		{
 | 
						|
		    lowPriorityTableFirstHalfMask |= dispatchQInfo[qIndex].intRegCheckMask;
 | 
						|
		}
 | 
						|
		/* build the priority table */
 | 
						|
		priorityTable[lowQuePriorityTableIndex++] = qIndex;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
	/* Foreach upp queue */
 | 
						|
	for(qIndex=IX_QMGR_MIN_QUEUPP_QID; qIndex<=IX_QMGR_MAX_QID; qIndex++)
 | 
						|
	{
 | 
						|
	    if (dispatchQInfo[qIndex].priority == priority)
 | 
						|
	    {
 | 
						|
		/* build the priority table bitmask which match the
 | 
						|
		 * queues of the first half of the priority table 
 | 
						|
		 */
 | 
						|
		if (uppQuePriorityTableIndex < IX_QMGR_MID_UPP_QUE_PRIORITY_TABLE_INDEX) 
 | 
						|
		{
 | 
						|
		    uppPriorityTableFirstHalfMask |= dispatchQInfo[qIndex].intRegCheckMask;
 | 
						|
		}
 | 
						|
		/* build the priority table */
 | 
						|
		priorityTable[uppQuePriorityTableIndex++] = qIndex;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
IxQMgrDispatcherStats*
 | 
						|
ixQMgrDispatcherStatsGet (void)
 | 
						|
{
 | 
						|
    return &dispatcherStats;
 | 
						|
}
 | 
						|
 | 
						|
PRIVATE void
 | 
						|
dummyCallback (IxQMgrQId qId,
 | 
						|
	       IxQMgrCallbackId cbId)
 | 
						|
{
 | 
						|
    /* Throttle the trace message */
 | 
						|
    if ((dispatchQInfo[qId].dummyCallbackCount % LOG_THROTTLE_COUNT) == 0)
 | 
						|
    {
 | 
						|
	IX_QMGR_LOG_WARNING2("--> dummyCallback: qId (%d), callbackId (%d)\n",qId,cbId);
 | 
						|
    }
 | 
						|
    dispatchQInfo[qId].dummyCallbackCount++;
 | 
						|
 | 
						|
#ifndef NDEBUG
 | 
						|
    /* Update statistcs */
 | 
						|
    dispatcherStats.queueStats[qId].intNoCallbackCnt++;
 | 
						|
#endif
 | 
						|
}
 | 
						|
void
 | 
						|
ixQMgrLLPShow (int resetStats)
 | 
						|
{
 | 
						|
#ifndef NDEBUG
 | 
						|
    UINT8 i = 0;
 | 
						|
    UINT32 intEnableRegVal = 0;
 | 
						|
 | 
						|
    printf ("Livelock statistics are printed on the fly.\n");
 | 
						|
    printf ("qId Type     EnableCnt DisableCnt IntEnableState Callbacks\n");
 | 
						|
    printf ("=== ======== ========= ========== ============== =========\n");
 | 
						|
 | 
						|
    for (i=0; i<= IX_QMGR_MAX_LOW_QUE_TABLE_INDEX; i++)
 | 
						|
    {
 | 
						|
        if (ixQMgrQTypes[i] != IX_QMGR_TYPE_REALTIME_OTHER)
 | 
						|
        {
 | 
						|
            printf (" %2d ", i);
 | 
						|
 | 
						|
            if (ixQMgrQTypes[i] == IX_QMGR_TYPE_REALTIME_SPORADIC)
 | 
						|
            {
 | 
						|
                printf ("Sporadic");
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                printf ("Periodic");
 | 
						|
            }
 | 
						|
 | 
						|
           
 | 
						|
            ixQMgrAqmIfQInterruptEnableRegRead (IX_QMGR_QUELOW_GROUP, 
 | 
						|
                                                    &intEnableRegVal);
 | 
						|
            	
 | 
						|
 | 
						|
	    intEnableRegVal &= dispatchQInfo[i].intRegCheckMask;
 | 
						|
            intEnableRegVal = intEnableRegVal >> i;
 | 
						|
 | 
						|
            printf (" %10d %10d %10d %10d\n",
 | 
						|
                    dispatcherStats.queueStats[i].enableCount,
 | 
						|
                    dispatcherStats.queueStats[i].disableCount,
 | 
						|
                    intEnableRegVal,
 | 
						|
                    dispatcherStats.queueStats[i].callbackCnt);
 | 
						|
 | 
						|
            if (resetStats)
 | 
						|
            {
 | 
						|
                dispatcherStats.queueStats[i].enableCount =
 | 
						|
                dispatcherStats.queueStats[i].disableCount = 
 | 
						|
                dispatcherStats.queueStats[i].callbackCnt = 0;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
#else
 | 
						|
    IX_QMGR_LOG0("Livelock Prevention statistics are only collected in debug mode\n");
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
ixQMgrPeriodicDone (void)
 | 
						|
{
 | 
						|
    UINT32 i = 0;
 | 
						|
    UINT32 ixQMgrLockKey = 0;
 | 
						|
 | 
						|
    /* 
 | 
						|
     * for the lower queues
 | 
						|
     */
 | 
						|
    for (i=0; i <= IX_QMGR_MAX_LOW_QUE_TABLE_INDEX; i++)
 | 
						|
    {
 | 
						|
        /*
 | 
						|
         * check for sporadics 
 | 
						|
         */
 | 
						|
        if (IX_QMGR_TYPE_REALTIME_SPORADIC == ixQMgrQTypes[i])
 | 
						|
        {
 | 
						|
             /* 
 | 
						|
              * enable any sporadics 
 | 
						|
              */
 | 
						|
             ixQMgrLockKey = ixOsalIrqLock();
 | 
						|
             ixQMgrAqmIfQInterruptEnable(i);
 | 
						|
             ixOsalIrqUnlock(ixQMgrLockKey);
 | 
						|
#ifndef NDEBUG
 | 
						|
             /* 
 | 
						|
              * Update statistics 
 | 
						|
              */
 | 
						|
             dispatcherStats.queueStats[i].enableCount++;
 | 
						|
             dispatcherStats.queueStats[i].notificationEnabled = TRUE;
 | 
						|
#endif
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
IX_STATUS
 | 
						|
ixQMgrCallbackTypeSet (IxQMgrQId qId, 
 | 
						|
                       IxQMgrType type)
 | 
						|
{
 | 
						|
    UINT32 ixQMgrLockKey = 0;
 | 
						|
    IxQMgrType ixQMgrOldType =0;
 | 
						|
 | 
						|
#ifndef NDEBUG
 | 
						|
    if (!ixQMgrQIsConfigured(qId))
 | 
						|
    {
 | 
						|
        return IX_QMGR_Q_NOT_CONFIGURED;
 | 
						|
    }
 | 
						|
    if (qId >= IX_QMGR_MIN_QUEUPP_QID)
 | 
						|
    {
 | 
						|
        return IX_QMGR_PARAMETER_ERROR;
 | 
						|
    }
 | 
						|
    if(!IX_QMGR_DISPATCHER_CALLBACK_TYPE_CHECK(type))
 | 
						|
    {
 | 
						|
        return IX_QMGR_PARAMETER_ERROR;
 | 
						|
    }
 | 
						|
#endif
 | 
						|
 | 
						|
    ixQMgrOldType = ixQMgrQTypes[qId];
 | 
						|
    ixQMgrQTypes[qId] = type;
 | 
						|
 | 
						|
    /*
 | 
						|
     * check if Q has been changed from type SPORADIC
 | 
						|
     */
 | 
						|
    if (IX_QMGR_TYPE_REALTIME_SPORADIC == ixQMgrOldType)
 | 
						|
    {
 | 
						|
       /* 
 | 
						|
        * previously Q was a SPORADIC, this means that LLP
 | 
						|
        * might have had it disabled. enable it now.
 | 
						|
        */
 | 
						|
       ixQMgrLockKey = ixOsalIrqLock();
 | 
						|
       ixQMgrAqmIfQInterruptEnable(qId);
 | 
						|
       ixOsalIrqUnlock(ixQMgrLockKey);
 | 
						|
 | 
						|
#ifndef NDEBUG
 | 
						|
       /* 
 | 
						|
        * Update statistics 
 | 
						|
        */
 | 
						|
       dispatcherStats.queueStats[qId].enableCount++;
 | 
						|
#endif
 | 
						|
    }
 | 
						|
 | 
						|
    return IX_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
IX_STATUS
 | 
						|
ixQMgrCallbackTypeGet (IxQMgrQId qId, 
 | 
						|
                       IxQMgrType *type)
 | 
						|
{
 | 
						|
#ifndef NDEBUG
 | 
						|
    if (!ixQMgrQIsConfigured(qId))
 | 
						|
    {
 | 
						|
        return IX_QMGR_Q_NOT_CONFIGURED;
 | 
						|
    }
 | 
						|
    if (qId >= IX_QMGR_MIN_QUEUPP_QID)
 | 
						|
    {
 | 
						|
        return IX_QMGR_PARAMETER_ERROR;
 | 
						|
    }
 | 
						|
    if(type == NULL)
 | 
						|
    {
 | 
						|
         return IX_QMGR_PARAMETER_ERROR;
 | 
						|
    }
 | 
						|
#endif
 | 
						|
 | 
						|
    *type = ixQMgrQTypes[qId];
 | 
						|
    return IX_SUCCESS;
 | 
						|
}
 |