#include <Copyright.h>

/********************************************************************************
* gtBrgFdb.c
*
* DESCRIPTION:
*       API definitions for Multiple Forwarding Databases 
*
* DEPENDENCIES:
*
* FILE REVISION NUMBER:
*       $Revision: 9 $
*******************************************************************************/

#include <msApi.h>
#include <gtSem.h>
#include <gtHwCntl.h>
#include <gtDrvSwRegs.h>

/****************************************************************************/
/* Forward function declaration.                                            */
/****************************************************************************/
static GT_STATUS atuOperationPerform
(
    IN      GT_QD_DEV           *dev,
    IN      GT_ATU_OPERATION    atuOp,
    INOUT    GT_EXTRA_OP_DATA    *opData,
    INOUT     GT_ATU_ENTRY        *atuEntry
);

static GT_STATUS atuStateAppToDev
(
    IN  GT_QD_DEV    *dev,
    IN  GT_BOOL        unicast,
    IN  GT_U32        state,
    OUT GT_U32        *newOne
);

static GT_STATUS atuStateDevToApp
(
    IN  GT_QD_DEV    *dev,
    IN  GT_BOOL        unicast,
    IN  GT_U32        state,
    OUT GT_U32        *newOne
);

static GT_STATUS atuGetStats
(
    IN  GT_QD_DEV    *dev,
    IN  GT_ATU_STAT    *atuStat,
    OUT GT_U32        *count
);


/*******************************************************************************
* gfdbSetPortAtuLearnLimit
*
* DESCRIPTION:
*       Port's auto learning limit. When the limit is non-zero value, the number
*        of MAC addresses that can be learned on this port are limited to the value
*        specified in this API. When the learn limit has been reached any frame 
*        that ingresses this port with a source MAC address not already in the 
*        address database that is associated with this port will be discarded. 
*        Normal auto-learning will resume on the port as soon as the number of 
*        active unicast MAC addresses associated to this port is less than the 
*        learn limit.
*        CPU directed ATU Load, Purge, or Move will not have any effect on the 
*        learn limit.
*        This feature is disabled when the limit is zero.
*        The following care is needed when enabling this feature:
*            1) dsable learning on the ports
*            2) flush all non-static addresses in the ATU
*            3) define the desired limit for the ports
*            4) re-enable learing on the ports
*
* INPUTS:
*       port  - logical port number
*       limit - auto learning limit ( 0 ~ 255 )
*                                              
* OUTPUTS:
*       None.
*
* RETURNS:
*       GT_OK   - on success
*       GT_FAIL - on error
*        GT_BAD_PARAM - if limit > 0xFF
*       GT_NOT_SUPPORTED - if current device does not support this feature.
*
* COMMENTS:
*       None.
*
* GalTis:
*
*******************************************************************************/
GT_STATUS gfdbSetPortAtuLearnLimit
(
    IN  GT_QD_DEV     *dev,
    IN  GT_LPORT      port,
    IN  GT_U32       limit
)
{
    GT_U16          data, mask;
    GT_STATUS       retVal;         /* Functions return value.      */
    GT_U8           hwPort;         /* the physical port number     */

    DBG_INFO(("gfdbSetPortAtuLearnLimit Called.\n"));

    /* translate LPORT to hardware port */
    hwPort = GT_LPORT_2_PORT(port);

    /* Check device if it has fixed ATU Size. */
    if (!IS_IN_DEV_GROUP(dev,DEV_ATU_LIMIT))
    {
        return GT_NOT_SUPPORTED;
    }

    if (limit > 0xFF)
    {
        DBG_INFO(("Bad Parameter\n"));
        return GT_BAD_PARAM;
    }

    mask = 0x80FF;

    if (IS_IN_DEV_GROUP(dev,DEV_ATU_LIMIT_READ))
        mask |= 0x1000;

    data = (GT_U16) limit;

    /* Set the learn limit bits.                  */
    retVal = hwSetPortRegBits(dev,hwPort, QD_REG_PORT_ATU_CONTROL, mask, data);
    if(retVal != GT_OK)
    {
        DBG_INFO(("Failed.\n"));
        return retVal;
    }

    DBG_INFO(("OK.\n"));
    return GT_OK;
}


/*******************************************************************************
* gfdbGetPortAtuLearnLimit
*
* DESCRIPTION:
*      Port's auto learning limit. When the limit is non-zero value, the number
*        of MAC addresses that can be learned on this port are limited to the value
*        specified in this API. When the learn limit has been reached any frame 
*        that ingresses this port with a source MAC address not already in the 
*        address database that is associated with this port will be discarded. 
*        Normal auto-learning will resume on the port as soon as the number of 
*        active unicast MAC addresses associated to this port is less than the 
*        learn limit.
*        CPU directed ATU Load, Purge, or Move will not have any effect on the 
*        learn limit.
*        This feature is disabled when the limit is zero.
*        The following care is needed when enabling this feature:
*            1) dsable learning on the ports
*            2) flush all non-static addresses in the ATU
*            3) define the desired limit for the ports
*            4) re-enable learing on the ports
*
* INPUTS:
*        port  - logical port number
*                                              
* OUTPUTS:
*        limit - auto learning limit ( 0 ~ 255 )
*
* RETURNS:
*        GT_OK   - on success
*        GT_FAIL - on error
*        GT_BAD_PARAM - if limit > 0xFF
*        GT_NOT_SUPPORTED - if current device does not support this feature.
*
* COMMENTS:
*       None.
*
*******************************************************************************/
GT_STATUS gfdbGetPortAtuLearnLimit
(
    IN  GT_QD_DEV     *dev,
    IN  GT_LPORT      port,
    OUT GT_U32       *limit
)
{
    GT_U16          data, mask;
    GT_STATUS       retVal;         /* Functions return value.      */
    GT_U8           hwPort;         /* the physical port number     */

    DBG_INFO(("gfdbGetPortAtuLearnLimit Called.\n"));

    /* translate LPORT to hardware port */
    hwPort = GT_LPORT_2_PORT(port);

    /* Check device if it has fixed ATU Size. */
    if (!IS_IN_DEV_GROUP(dev,DEV_ATU_LIMIT_READ))
    {
        return GT_NOT_SUPPORTED;
    }

    mask = 0x9000;
    data = (GT_U16) 0x1000;

    /* Set the learn limit bits.                  */
    retVal = hwSetPortRegBits(dev,hwPort, QD_REG_PORT_ATU_CONTROL, mask, data);
    if(retVal != GT_OK)
    {
        DBG_INFO(("Failed.\n"));
        return retVal;
    }

    /* Get the ReadLearnLimit bit. */
    retVal = hwGetPortRegField(dev,hwPort, QD_REG_PORT_ATU_CONTROL, 0, 8, &data);
    if(retVal != GT_OK)
    {
        DBG_INFO(("Failed.\n"));
        return retVal;
    }

    *limit = (GT_U32)data;

    DBG_INFO(("OK.\n"));
    return GT_OK;
}



/*******************************************************************************
* gfdbGetPortAtuLearnCnt
*
* DESCRIPTION:
*       Read the current number of active unicast MAC addresses associated with 
*        the given port. This counter (LearnCnt) is held at zero if learn limit
*        (gfdbSetPortAtuLearnLimit API) is set to zero.
*
* INPUTS:
*       port  - logical port number
*                                              
* OUTPUTS:
*       count - current auto learning count
*
* RETURNS:
*       GT_OK   - on success
*       GT_FAIL - on error
*       GT_NOT_SUPPORTED - if current device does not support this feature.
*
* COMMENTS:
*       None.
*
* GalTis:
*
*******************************************************************************/
GT_STATUS gfdbGetPortAtuLearnCnt
(
    IN  GT_QD_DEV     *dev,
    IN  GT_LPORT      port,
    IN  GT_U32       *count
)
{
    GT_U16          data;
    GT_STATUS       retVal;         /* Functions return value.      */
    GT_U8           hwPort;         /* the physical port number     */

    DBG_INFO(("gfdbGetPortAtuLearnCnt Called.\n"));

    /* translate LPORT to hardware port */
    hwPort = GT_LPORT_2_PORT(port);

    /* Check device if this feature is supported. */
    if (!IS_IN_DEV_GROUP(dev,DEV_ATU_LIMIT))
    {
        return GT_NOT_SUPPORTED;
    }

    /* Get the ReadLearnCnt bit. */
    retVal = hwGetPortRegField(dev,hwPort, QD_REG_PORT_ATU_CONTROL, 15, 1, &data);
    if(retVal != GT_OK)
    {
        DBG_INFO(("Failed.\n"));
        return retVal;
    }

    if(data == 0)
    {
        /* Set the ReadLearnCnt bit. */
        retVal = hwSetPortRegField(dev,hwPort, QD_REG_PORT_ATU_CONTROL, 15, 1, 1);
        if(retVal != GT_OK)
        {
            DBG_INFO(("Failed.\n"));
            return retVal;
        }
    }

    /* Get the LearnCnt bits. */
    retVal = hwGetPortRegField(dev,hwPort, QD_REG_PORT_ATU_CONTROL, 0, 8, &data);
    if(retVal != GT_OK)
    {
        DBG_INFO(("Failed.\n"));
        return retVal;
    }

    *count = (GT_U32)data;

    DBG_INFO(("OK.\n"));
    return GT_OK;
}


/*******************************************************************************
* gfdbGetAtuAllCount
*
* DESCRIPTION:
*       Counts all entries in the Address Translation Unit.
*
* INPUTS:
*       None.
*
* OUTPUTS:
*       count - number of valid entries.
*
* RETURNS:
*       GT_OK      - on success
*       GT_FAIL    - on error
*       GT_NOT_SUPPORTED - if current device does not support this feature.
*
* COMMENTS:
*       None
*
*******************************************************************************/
GT_STATUS gfdbGetAtuAllCount
(
    IN  GT_QD_DEV     *dev,
    OUT GT_U32         *count
)
{
    GT_U32          dbNum, maxDbNum, numOfEntries;
    GT_STATUS       retVal;
    GT_ATU_ENTRY    entry;
    GT_ATU_STAT        atuStat;

    DBG_INFO(("gfdbGetAtuAllCount Called.\n"));

    if(IS_IN_DEV_GROUP(dev,DEV_ATU_STATS))
    {
        atuStat.op = GT_ATU_STATS_ALL;
        return atuGetStats(dev,&atuStat,count);
    }

    numOfEntries = 0;
    
    if (IS_IN_DEV_GROUP(dev,DEV_DBNUM_FULL))
        maxDbNum = 16;
    else if(IS_IN_DEV_GROUP(dev,DEV_DBNUM_64))
        maxDbNum = 64;
    else if(IS_IN_DEV_GROUP(dev,DEV_DBNUM_256))
        maxDbNum = 256;
    else if(IS_IN_DEV_GROUP(dev,DEV_DBNUM_4096))
        maxDbNum = 4096;
    else
        maxDbNum = 1;

    for(dbNum=0; dbNum<maxDbNum; dbNum++)
    {
        entry.DBNum = (GT_U16)dbNum;

        if(IS_IN_DEV_GROUP(dev,DEV_BROADCAST_INVALID))
            gtMemSet(entry.macAddr.arEther,0,sizeof(GT_ETHERADDR));
        else
            gtMemSet(entry.macAddr.arEther,0xFF,sizeof(GT_ETHERADDR));

        while(1)
        {
            retVal = atuOperationPerform(dev,GET_NEXT_ENTRY,NULL,&entry);
            if(retVal != GT_OK)
            {
                DBG_INFO(("Failed.\n"));
                return retVal;
            }

            if(IS_BROADCAST_MAC(entry.macAddr))
            {
                if(IS_IN_DEV_GROUP(dev,DEV_BROADCAST_INVALID))
                    break;
                else if(entry.entryState.ucEntryState == 0)
                    break;
                numOfEntries++;
                break;
            }

            numOfEntries++;
        }
    }

    *count = numOfEntries;
    DBG_INFO(("OK.\n"));
    return GT_OK;
}


/*******************************************************************************
* gfdbGetAtuAllCountInDBNum
*
* DESCRIPTION:
*       Counts all entries in the defined FID (or DBNum).
*
* INPUTS:
*       dbNum - 
*
* OUTPUTS:
*       count - number of valid entries in FID (or DBNum).
*
* RETURNS:
*       GT_OK      - on success
*       GT_FAIL    - on error
*       GT_NOT_SUPPORTED - if current device does not support this feature.
*
* COMMENTS:
*       None
*
*******************************************************************************/
GT_STATUS gfdbGetAtuAllCountInDBNum
(
    IN  GT_QD_DEV     *dev,
    IN  GT_U32         dbNum,
    OUT GT_U32         *count
)
{
    GT_U32          numOfEntries;
    GT_STATUS       retVal;
    GT_ATU_ENTRY    entry;
    GT_ATU_STAT        atuStat;

    DBG_INFO(("gfdbGetAtuAllCountInDBNum Called.\n"));

    if(IS_IN_DEV_GROUP(dev,DEV_ATU_STATS))
    {
        atuStat.op = GT_ATU_STATS_ALL_FID;
        atuStat.DBNum = dbNum;
        return atuGetStats(dev,&atuStat,count);
    }

    numOfEntries = 0;
    
    entry.DBNum = (GT_U16)dbNum;

    if(IS_IN_DEV_GROUP(dev,DEV_BROADCAST_INVALID))
        gtMemSet(entry.macAddr.arEther,0,sizeof(GT_ETHERADDR));
    else
        gtMemSet(entry.macAddr.arEther,0xFF,sizeof(GT_ETHERADDR));

    while(1)
    {
        retVal = atuOperationPerform(dev,GET_NEXT_ENTRY,NULL,&entry);
        if(retVal != GT_OK)
        {
            DBG_INFO(("Failed.\n"));
            return retVal;
        }

        if(IS_BROADCAST_MAC(entry.macAddr))
        {
            if(IS_IN_DEV_GROUP(dev,DEV_BROADCAST_INVALID))
                break;
            else if(entry.entryState.ucEntryState == 0)
                break;
            numOfEntries++;
            break;
        }

        numOfEntries++;
    }

    *count = numOfEntries;
    DBG_INFO(("OK.\n"));
    return GT_OK;
}


/*******************************************************************************
* gfdbGetAtuDynamicCountInDBNum
*
* DESCRIPTION:
*       Counts all non-static entries in the defined FID (or DBNum).
*
* INPUTS:
*       dbNum - 
*
* OUTPUTS:
*       count - number of valid non-static entries in FID (or DBNum).
*
* RETURNS:
*       GT_OK      - on success
*       GT_FAIL    - on error
*       GT_NOT_SUPPORTED - if current device does not support this feature.
*
* COMMENTS:
*       None
*
*******************************************************************************/
GT_STATUS gfdbGetAtuDynamicCountInDBNum
(
    IN  GT_QD_DEV     *dev,
    IN  GT_U32         dbNum,
    OUT GT_U32         *count
)
{
    GT_U32          numOfEntries, tmpState;
    GT_STATUS       retVal;
    GT_ATU_ENTRY    entry;
    GT_ATU_UC_STATE    state;
    GT_ATU_STAT        atuStat;

    DBG_INFO(("gfdbGetAtuDynamicCountInDBNum Called.\n"));

    if(IS_IN_DEV_GROUP(dev,DEV_ATU_STATS))
    {
        atuStat.op = GT_ATU_STATS_NON_STATIC_FID;
        atuStat.DBNum = dbNum;
        return atuGetStats(dev,&atuStat,count);
    }

    numOfEntries = 0;
    
    entry.DBNum = (GT_U16)dbNum;

    if(IS_IN_DEV_GROUP(dev,DEV_BROADCAST_INVALID))
        gtMemSet(entry.macAddr.arEther,0,sizeof(GT_ETHERADDR));
    else
        gtMemSet(entry.macAddr.arEther,0xFF,sizeof(GT_ETHERADDR));

    while(1)
    {
        retVal = atuOperationPerform(dev,GET_NEXT_ENTRY,NULL,&entry);
        if(retVal != GT_OK)
        {
            DBG_INFO(("Failed.\n"));
            return retVal;
        }

        if(IS_BROADCAST_MAC(entry.macAddr))
            break;

        if(IS_MULTICAST_MAC(entry.macAddr))
        {
            continue;
        }

        atuStateDevToApp(dev,GT_TRUE,entry.entryState.ucEntryState,&tmpState);
        state = (GT_ATU_UC_STATE)tmpState;
        if (state == GT_UC_DYNAMIC)
        {
            numOfEntries++;
        }
    }
    
    *count = numOfEntries;
    DBG_INFO(("OK.\n"));
    return GT_OK;
}



/*******************************************************************************
* gfdbSetAtuSize
*
* DESCRIPTION:
*       Sets the Mac address table size.
*
* INPUTS:
*       size    - Mac address table size.
*
* OUTPUTS:
*       None.
*
* RETURNS:
*       GT_OK   - on success
*       GT_FAIL - on error
*
* COMMENTS:
*       None.
*
* GalTis:
*
*******************************************************************************/
GT_STATUS gfdbSetAtuSize
(
    IN GT_QD_DEV    *dev,
    IN ATU_SIZE     size
)
{
    GT_U16          data;
    GT_STATUS       retVal;         /* Functions return value.      */

    DBG_INFO(("gfdbSetAtuSize Called.\n"));

    switch(size)
    {
        case ATU_SIZE_256:
            if (IS_IN_DEV_GROUP(dev,DEV_ATU_256_2048))
                data = 0;
            else
                return GT_NOT_SUPPORTED;
            break;
        case ATU_SIZE_512:
        case ATU_SIZE_1024:
        case ATU_SIZE_2048:
            if (IS_IN_DEV_GROUP(dev,DEV_ATU_256_2048))
                data = (GT_U16)size;
            else
                data = (GT_U16)size - 1;
            break;

        case ATU_SIZE_4096:
            if ((IS_IN_DEV_GROUP(dev,DEV_ATU_256_2048))||(IS_IN_DEV_GROUP(dev,DEV_ATU_562_2048)))
                return GT_NOT_SUPPORTED;
            else
                data = 3;
            break;
        default:
            return GT_NOT_SUPPORTED;
    }
    
    /* Check device if it has fixed ATU Size. */
    if (IS_IN_DEV_GROUP(dev,DEV_ATU_SIZE_FIXED))
    {
        return GT_NOT_SUPPORTED;
    }

    /* Set the Software reset bit.                  */
    retVal = hwSetGlobalRegField(dev,QD_REG_ATU_CONTROL,12,2,data);
    if(retVal != GT_OK)
    {
        DBG_INFO(("Failed.\n"));
        return retVal;
    }

    /* Make sure the reset operation is completed.  */
#ifdef GT_RMGMT_ACCESS 
    /*    if (IS_IN_DEV_GROUP(dev,DEV_RMGMT)) */
    {
      HW_DEV_REG_ACCESS regAccess;

      regAccess.entries = 1;
  
      regAccess.rw_reg_list[0].cmd = HW_REG_WAIT_TILL_1;
      regAccess.rw_reg_list[0].addr = CALC_SMI_DEV_ADDR(dev, 0, GLOBAL_REG_ACCESS);
      regAccess.rw_reg_list[0].reg = QD_REG_GLOBAL_STATUS;
      regAccess.rw_reg_list[0].data = 11;

      retVal = hwAccessMultiRegs(dev, &regAccess);
      if(retVal != GT_OK)
      {
        gtSemGive(dev,dev->atuRegsSem);
        return retVal;
      }
    }
#else
    {
    data = 0;
    while(data == 0)
    {
        retVal = hwGetGlobalRegField(dev,QD_REG_GLOBAL_STATUS,11,1,&data);
        if(retVal != GT_OK)
        {
            DBG_INFO(("Failed.\n"));
            return retVal;
        }
    }
    }
#endif

    DBG_INFO(("OK.\n"));
    return GT_OK;
}


/*******************************************************************************
* gfdbGetAgingTimeRange
*
* DESCRIPTION:
*       Gets the maximal and minimum age times that the hardware can support.
*
* INPUTS:
*       None.
*
* OUTPUTS:
*       maxTimeout - max aging time in secounds.
*       minTimeout - min aging time in secounds.
*
* RETURNS:
*       GT_OK           - on success
*       GT_BAD_PARAM    - on bad parameter
*       GT_FAIL         - on error
*
* COMMENTS:
*       None.
*
* GalTis:
*
*******************************************************************************/
GT_STATUS gfdbGetAgingTimeRange
(
    IN GT_QD_DEV    *dev,
    OUT GT_U32 *maxTimeout,
    OUT GT_U32 *minTimeout
)
{
    DBG_INFO(("gfdbGetAgingTimeRange Called.\n"));
    if((maxTimeout == NULL) || (minTimeout == NULL))
    {
        DBG_INFO(("Failed.\n"));
        return GT_BAD_PARAM;
    }

    if (IS_IN_DEV_GROUP(dev,DEV_ATU_15SEC_AGING))
    {
        *minTimeout = 15;
        *maxTimeout = 3825;
    }
    else
    {
        *minTimeout = 16;
        *maxTimeout = 4080;
    }
    DBG_INFO(("OK.\n"));
    return GT_OK;
}


/*******************************************************************************
* gfdbGetAgingTimeout
*
* DESCRIPTION:
*       Gets the timeout period in seconds for aging out dynamically learned
*       forwarding information. The returned value may not be the same as the value
*        programmed with <gfdbSetAgingTimeout>. Please refer to the description of
*        <gfdbSetAgingTimeout>.
*
* INPUTS:
*       None.
*
* OUTPUTS:
*       timeout - aging time in seconds.
*
* RETURNS:
*       GT_OK           - on success
*       GT_FAIL         - on error
*
* COMMENTS:
*       None.
*
* GalTis:
*
*******************************************************************************/
GT_STATUS gfdbGetAgingTimeout
(
    IN  GT_QD_DEV    *dev,
    OUT GT_U32       *timeout
)
{
    GT_STATUS       retVal;         /* Functions return value.      */
    GT_U16          data;           /* The register's read data.    */
    GT_U16            timeBase;

    DBG_INFO(("gfdbGetAgingTimeout Called.\n"));
 
    if (IS_IN_DEV_GROUP(dev,DEV_ATU_15SEC_AGING))
        timeBase = 15;
    else
        timeBase = 16;

    /* Get the Time Out value.              */
    retVal = hwGetGlobalRegField(dev,QD_REG_ATU_CONTROL,4,8,&data);
    if(retVal != GT_OK)
    {
        DBG_INFO(("Failed.\n"));
        return retVal;
    }

    *timeout = data*timeBase;

    DBG_INFO(("OK.\n"));
    return GT_OK;
}


/*******************************************************************************
* gfdbSetAgingTimeout
*
* DESCRIPTION:
*       Sets the timeout period in seconds for aging out dynamically learned
*       forwarding information. The standard recommends 300 sec.
*        Supported aging timeout values are multiple of time-base, where time-base
*        is either 15 or 16 seconds, depending on the Switch device. For example,
*        88E6063 uses time-base 16, and so supported aging timeouts are 0,16,32,
*        48,..., and 4080. If unsupported timeout value (bigger than 16) is used, 
*        the value will be rounded to the nearest supported value smaller than the 
*        given timeout. If the given timeout is less than 16, minimum timeout value
*        16 will be used instead. E.g.) 35 becomes 32 and 5 becomes 16.
*        <gfdbGetAgingTimeRange> function can be used to find the time-base.
*
* INPUTS:
*       timeout - aging time in seconds.
*
* OUTPUTS:
*       None.
*
* RETURNS:
*       GT_OK           - on success
*       GT_FAIL         - on error
*
* COMMENTS:
*       None.
*
* GalTis:
*
*******************************************************************************/
GT_STATUS gfdbSetAgingTimeout
(
    IN GT_QD_DEV    *dev,
    IN GT_U32 timeout
)
{
    GT_STATUS       retVal;         /* Functions return value.      */
    GT_U16          data;           /* The register's read data.    */
    GT_U16            timeBase;

    DBG_INFO(("gfdbSetAgingTimeout Called.\n"));
 
    if (IS_IN_DEV_GROUP(dev,DEV_ATU_15SEC_AGING))
        timeBase = 15;
    else
        timeBase = 16;

    if((timeout < timeBase) && (timeout != 0))
    {    
        data = 1;
    }
    else
    {
        data = (GT_U16)(timeout/timeBase);
       if (data & 0xFF00)
            data = 0xFF;
    }

    /* Set the Time Out value.              */
    retVal = hwSetGlobalRegField(dev,QD_REG_ATU_CONTROL,4,8,data);
    if(retVal != GT_OK)
    {
        DBG_INFO(("Failed.\n"));
        return retVal;
    }

    DBG_INFO(("OK.\n"));
    return GT_OK;
}


/*******************************************************************************
* gfdbGetLearn2All
*
* DESCRIPTION:
*        When more than one Marvell device is used to form a single 'switch', it
*        may be desirable for all devices in the 'switch' to learn any address this 
*        device learns. When this bit is set to a one all other devices in the 
*        'switch' learn the same addresses this device learns. When this bit is 
*        cleared to a zero, only the devices that actually receive frames will learn
*        from those frames. This mode typically supports more active MAC addresses 
*        at one time as each device in the switch does not need to learn addresses 
*        it may nerver use.
*
* INPUTS:
*        None.
*
* OUTPUTS:
*        mode  - GT_TRUE if Learn2All is enabled, GT_FALSE otherwise
*
* RETURNS:
*        GT_OK           - on success
*        GT_FAIL         - on error
*        GT_NOT_SUPPORTED - if current device does not support this feature.
*
* COMMENTS:
*        None.
*
*
*******************************************************************************/
GT_STATUS gfdbGetLearn2All
(
    IN  GT_QD_DEV    *dev,
    OUT GT_BOOL     *mode
)
{
    GT_STATUS       retVal;         /* Functions return value.      */
    GT_U16          data;           /* to keep the read valve       */

    DBG_INFO(("gprtGetLearn2All Called.\n"));

    /* check if the given Switch supports this feature. */
    if ((!IS_IN_DEV_GROUP(dev,DEV_88E6093_FAMILY)) ||
        (IS_IN_DEV_GROUP(dev,DEV_88EC000_FAMILY)) ||
        (IS_IN_DEV_GROUP(dev,DEV_88ESPANNAK_FAMILY)))
    {
        DBG_INFO(("GT_NOT_SUPPORTED\n"));
        return GT_NOT_SUPPORTED;
    }

    /* Get the Learn2All. */
    retVal = hwGetGlobalRegField(dev,QD_REG_ATU_CONTROL, 3, 1, &data);

    BIT_2_BOOL(data, *mode);

    if(retVal != GT_OK)
    {
        DBG_INFO(("Failed.\n"));
    }
    else
    {
        DBG_INFO(("OK.\n"));
    }

    return retVal;
}

/*******************************************************************************
* gfdbSetLearn2All
*
* DESCRIPTION:
*        Enable or disable Learn2All mode.
*
* INPUTS:
*        mode - GT_TRUE to set Learn2All, GT_FALSE otherwise
*
* OUTPUTS:
*        None.
*
* RETURNS:
*        GT_OK   - on success
*        GT_FAIL - on error
*        GT_NOT_SUPPORTED - if current device does not support this feature.
*
* COMMENTS: 
*
* GalTis:
*
*******************************************************************************/
GT_STATUS gfdbSetLearn2All
(
    IN GT_QD_DEV    *dev,
    IN GT_BOOL        mode
)
{
    GT_U16          data;           /* Used to poll the SWReset bit */
    GT_STATUS       retVal;         /* Functions return value.      */

    DBG_INFO(("gprtSetLearn2All Called.\n"));

    /* check if the given Switch supports this feature. */
    if ((!IS_IN_DEV_GROUP(dev,DEV_88E6093_FAMILY)) ||
        (IS_IN_DEV_GROUP(dev,DEV_88EC000_FAMILY)) ||
        (IS_IN_DEV_GROUP(dev,DEV_88ESPANNAK_FAMILY)))
    {
        DBG_INFO(("GT_NOT_SUPPORTED\n"));
        return GT_NOT_SUPPORTED;
    }

    /* translate BOOL to binary */
    BOOL_2_BIT(mode, data);

    /* Set Learn2All. */
    retVal = hwSetGlobalRegField(dev,QD_REG_ATU_CONTROL, 3, 1, data);

    if(retVal != GT_OK)
    {
        DBG_INFO(("Failed.\n"));
    }
    else
    {
        DBG_INFO(("OK.\n"));
    }
    return retVal;
}


/*******************************************************************************
* gfdbGetMacAvb
*
* DESCRIPTION:
*        ATU MAC entry in AVB mode.
*        When enabled, ATU entries operate in AVB mode:
*
*        GT_ATU_UC_STATE - support
*            GT_UC_NO_PRI_STATIC_AVB_ENTRY, and 
*            GT_UC_STATIC_AVB_ENTRY
*
*        GT_ATU_MC_STATE - support
*            GT_MC_STATIC_AVB_ENTRY, and
*            GT_MC_PRIO_STATIC_AVB_ENTRY
*
*        When disabled, ATU entries operate in non-AVB mode:
*
*        GT_ATU_UC_STATE - support
*            GT_UC_NO_PRI_STATIC_NRL, and 
*            GT_UC_STATIC_NRL
*
*        GT_ATU_MC_STATE - support
*            GT_MC_STATIC_UNLIMITED_RATE, and
*            GT_MC_PRIO_STATIC_UNLIMITED_RATE
*
* INPUTS:
*        None.
*
* OUTPUTS:
*        mode  - GT_TRUE if MacAvb is enabled, GT_FALSE otherwise
*
* RETURNS:
*        GT_OK           - on success
*        GT_FAIL         - on error
*        GT_NOT_SUPPORTED - if current device does not support this feature.
*
* COMMENTS:
*        None.
*
*
*******************************************************************************/
GT_STATUS gfdbGetMacAvb
(
    IN  GT_QD_DEV    *dev,
    OUT GT_BOOL     *mode
)
{
    GT_STATUS       retVal;         /* Functions return value.      */
    GT_U16          data;           /* to keep the read valve       */

    DBG_INFO(("gfdbGetMacAvb Called.\n"));

    /* check if the given Switch supports this feature. */
    if (!IS_IN_DEV_GROUP(dev,DEV_MAC_AVB))
    {
        DBG_INFO(("GT_NOT_SUPPORTED\n"));
        return GT_NOT_SUPPORTED;
    }

    /* Get the bit. */
    retVal = hwGetGlobalRegField(dev,QD_REG_ATU_CONTROL, 15, 1, &data);

    BIT_2_BOOL(data, *mode);

    if(retVal != GT_OK)
    {
        DBG_INFO(("Failed.\n"));
    }
    else
    {
        DBG_INFO(("OK.\n"));
    }

    return retVal;
}

/*******************************************************************************
* gfdbSetMacAvb
*
* DESCRIPTION:
*        ATU MAC entry in AVB mode.
*        When enabled, ATU entries operate in AVB mode:
*
*        GT_ATU_UC_STATE - support
*            GT_UC_NO_PRI_STATIC_AVB_ENTRY, and 
*            GT_UC_STATIC_AVB_ENTRY
*
*        GT_ATU_MC_STATE - support
*            GT_MC_STATIC_AVB_ENTRY, and
*            GT_MC_PRIO_STATIC_AVB_ENTRY
*
*        When disabled, ATU entries operate in non-AVB mode:
*
*        GT_ATU_UC_STATE - support
*            GT_UC_NO_PRI_STATIC_NRL, and 
*            GT_UC_STATIC_NRL
*
*        GT_ATU_MC_STATE - support
*            GT_MC_STATIC_UNLIMITED_RATE, and
*            GT_MC_PRIO_STATIC_UNLIMITED_RATE
*
* INPUTS:
*        mode - GT_TRUE to enable MacAvb, GT_FALSE otherwise
*
* OUTPUTS:
*        None.
*
* RETURNS:
*        GT_OK   - on success
*        GT_FAIL - on error
*        GT_NOT_SUPPORTED - if current device does not support this feature.
*
* COMMENTS: 
*
*******************************************************************************/
GT_STATUS gfdbSetMacAvb
(
    IN GT_QD_DEV    *dev,
    IN GT_BOOL        mode
)
{
    GT_U16          data;           /* Used to poll the SWReset bit */
    GT_STATUS       retVal;         /* Functions return value.      */

    DBG_INFO(("gprtSetMacAvb Called.\n"));

    /* check if the given Switch supports this feature. */
    if (!IS_IN_DEV_GROUP(dev,DEV_MAC_AVB))
    {
        DBG_INFO(("GT_NOT_SUPPORTED\n"));
        return GT_NOT_SUPPORTED;
    }

    /* translate BOOL to binary */
    BOOL_2_BIT(mode, data);

    /* Set the bit */
    retVal = hwSetGlobalRegField(dev,QD_REG_ATU_CONTROL, 15, 1, data);

    if(retVal != GT_OK)
    {
        DBG_INFO(("Failed.\n"));
    }
    else
    {
        DBG_INFO(("OK.\n"));
    }
    return retVal;
}


/*******************************************************************************
* gfdbGetAtuDynamicCount
*
* DESCRIPTION:
*       Gets the current number of dynamic unicast (non-static) entries in this
*       Filtering Database.
*
* INPUTS:
*       None.
*
* OUTPUTS:
*       numDynEntries - number of dynamic entries.
*
* RETURNS:
*       GT_OK      - on success
*       GT_FAIL    - on error
*       GT_NO_SUCH - vlan does not exist.
*
* COMMENTS:
*       None
*
* GalTis:
*
*******************************************************************************/
GT_STATUS gfdbGetAtuDynamicCount
(
    IN  GT_QD_DEV     *dev,
    OUT GT_U32         *numDynEntries
)
{
    GT_U32          dbNum, maxDbNum, numOfEntries, tmpState;
    GT_STATUS       retVal;
    GT_ATU_ENTRY    entry;
    GT_ATU_UC_STATE    state;
    GT_ATU_STAT        atuStat;

    DBG_INFO(("gfdbGetAtuDynamicCount Called.\n"));

    if(IS_IN_DEV_GROUP(dev,DEV_ATU_STATS))
    {
        atuStat.op = GT_ATU_STATS_NON_STATIC;
        return atuGetStats(dev,&atuStat,numDynEntries);
    }

    numOfEntries = 0;
    
    if (IS_IN_DEV_GROUP(dev,DEV_DBNUM_FULL))
        maxDbNum = 16;
    else if(IS_IN_DEV_GROUP(dev,DEV_DBNUM_64))
        maxDbNum = 64;
    else if(IS_IN_DEV_GROUP(dev,DEV_DBNUM_256))
        maxDbNum = 256;
    else if(IS_IN_DEV_GROUP(dev,DEV_DBNUM_4096))
        maxDbNum = 4096;
    else
        maxDbNum = 1;

    for(dbNum=0; dbNum<maxDbNum; dbNum++)
    {
        entry.DBNum = (GT_U16)dbNum;

        if(IS_IN_DEV_GROUP(dev,DEV_BROADCAST_INVALID))
            gtMemSet(entry.macAddr.arEther,0,sizeof(GT_ETHERADDR));
        else
            gtMemSet(entry.macAddr.arEther,0xFF,sizeof(GT_ETHERADDR));

        while(1)
        {
            retVal = atuOperationPerform(dev,GET_NEXT_ENTRY,NULL,&entry);
            if(retVal != GT_OK)
            {
                DBG_INFO(("Failed.\n"));
                return retVal;
            }

            if(IS_BROADCAST_MAC(entry.macAddr))
                break;

            if(IS_MULTICAST_MAC(entry.macAddr))
            {
                continue;
            }

            atuStateDevToApp(dev,GT_TRUE,(GT_U32)entry.entryState.ucEntryState,&tmpState);
            state = (GT_ATU_UC_STATE)tmpState;
            if (state == GT_UC_DYNAMIC)
            {
                numOfEntries++;
            }
        }
    }

    *numDynEntries = numOfEntries;
    DBG_INFO(("OK.\n"));
    return GT_OK;
}


/*******************************************************************************
* gfdbGetAtuEntryFirst
*
* DESCRIPTION:
*       Gets first lexicographic MAC address entry from the ATU.
*
* INPUTS:
*       None.
*
* OUTPUTS:
*       atuEntry - match Address translate unit entry.
*
* RETURNS:
*       GT_OK      - on success
*       GT_FAIL    - on error
*       GT_NO_SUCH - table is empty.
*
* COMMENTS:
*       Search starts from Mac[00:00:00:00:00:00]
*
*        DBNum in atuEntry - 
*            ATU MAC Address Database number. If multiple address 
*            databases are not being used, DBNum should be zero.
*            If multiple address databases are being used, this value
*            should be set to the desired address database number.
*
*******************************************************************************/
GT_STATUS gfdbGetAtuEntryFirst
(
    IN GT_QD_DEV    *dev,
    OUT GT_ATU_ENTRY    *atuEntry
)
{
    GT_STATUS       retVal;
    GT_ATU_ENTRY    entry;
    GT_U32 data;

    DBG_INFO(("gfdbGetAtuEntryFirst Called.\n"));

    if(IS_IN_DEV_GROUP(dev,DEV_BROADCAST_INVALID))
        gtMemSet(entry.macAddr.arEther,0,sizeof(GT_ETHERADDR));
    else
        gtMemSet(entry.macAddr.arEther,0xFF,sizeof(GT_ETHERADDR));

    entry.DBNum = atuEntry->DBNum;

    DBG_INFO(("DBNum : %i\n",entry.DBNum));

    retVal = atuOperationPerform(dev,GET_NEXT_ENTRY,NULL,&entry);
    if(retVal != GT_OK)
    {
        DBG_INFO(("Failed (atuOperationPerform returned GT_FAIL).\n"));
        return retVal;
    }

    if(IS_BROADCAST_MAC(entry.macAddr))
    {
        if(IS_IN_DEV_GROUP(dev,DEV_BROADCAST_INVALID))
        {
            DBG_INFO(("Failed (Invalid Mac).\n"));
            return GT_NO_SUCH;
        }
        else if(entry.entryState.ucEntryState == 0)
        {
            DBG_INFO(("Failed (Invalid Mac).\n"));
            return GT_NO_SUCH;
        }
    }

    gtMemCpy(atuEntry->macAddr.arEther,entry.macAddr.arEther,6);
    atuEntry->portVec   = GT_PORTVEC_2_LPORTVEC(entry.portVec);
    atuEntry->prio      = entry.prio;
    atuEntry->trunkMember = entry.trunkMember;
    atuEntry->exPrio.useMacFPri = entry.exPrio.useMacFPri;
    atuEntry->exPrio.macFPri = entry.exPrio.macFPri;
    atuEntry->exPrio.macQPri = entry.exPrio.macQPri;

    if(IS_MULTICAST_MAC(entry.macAddr))
    {
        if(dev->deviceId == GT_88E6051)
        {
            DBG_INFO(("Failed.\n"));
            return GT_FAIL;
        }

        atuStateDevToApp(dev,GT_FALSE,entry.entryState.ucEntryState,
                        &data);
        atuEntry->entryState.mcEntryState = data;
    }
    else
    {
        atuStateDevToApp(dev,GT_TRUE,entry.entryState.ucEntryState,
                        &data);
        atuEntry->entryState.ucEntryState = data;
    }

    DBG_INFO(("OK.\n"));
    return GT_OK;
}



/*******************************************************************************
* gfdbGetAtuEntryNext
*
* DESCRIPTION:
*       Gets next lexicographic MAC address from the specified Mac Addr.
*
* INPUTS:
*       atuEntry - the Mac Address to start the search.
*
* OUTPUTS:
*       atuEntry - match Address translate unit entry.
*
* RETURNS:
*       GT_OK      - on success.
*       GT_FAIL    - on error or entry does not exist.
*       GT_NO_SUCH - no more entries.
*
* COMMENTS:
*       Search starts from atu.macAddr[xx:xx:xx:xx:xx:xx] specified by the
*       user.
*
*        DBNum in atuEntry - 
*            ATU MAC Address Database number. If multiple address 
*            databases are not being used, DBNum should be zero.
*            If multiple address databases are being used, this value
*            should be set to the desired address database number.
*
*******************************************************************************/
GT_STATUS gfdbGetAtuEntryNext
(
    IN GT_QD_DEV    *dev,
    INOUT GT_ATU_ENTRY  *atuEntry
)
{
    GT_STATUS       retVal;
    GT_ATU_ENTRY    entry;
    GT_U32 data;

    DBG_INFO(("gfdbGetAtuEntryNext Called.\n"));

    if(IS_BROADCAST_MAC(atuEntry->macAddr))
    {
           return GT_NO_SUCH;
    }

    gtMemCpy(entry.macAddr.arEther,atuEntry->macAddr.arEther,6);

    entry.DBNum = atuEntry->DBNum;
    DBG_INFO(("DBNum : %i\n",entry.DBNum));

    retVal = atuOperationPerform(dev,GET_NEXT_ENTRY,NULL,&entry);
    if(retVal != GT_OK)
    {
        DBG_INFO(("Failed (atuOperationPerform returned GT_FAIL).\n"));
        return retVal;
    }

    if(IS_BROADCAST_MAC(entry.macAddr))
    {
        if(IS_IN_DEV_GROUP(dev,DEV_BROADCAST_INVALID))
        {
            DBG_INFO(("Failed (Invalid Mac).\n"));
            return GT_NO_SUCH;
        }
        else if(entry.entryState.ucEntryState == 0)
        {
            DBG_INFO(("Failed (Invalid Mac).\n"));
            return GT_NO_SUCH;
        }
    }

    gtMemCpy(atuEntry->macAddr.arEther,entry.macAddr.arEther,6);
    atuEntry->portVec   = GT_PORTVEC_2_LPORTVEC(entry.portVec);
    atuEntry->prio      = entry.prio;
    atuEntry->trunkMember = entry.trunkMember;
    atuEntry->exPrio.useMacFPri = entry.exPrio.useMacFPri;
    atuEntry->exPrio.macFPri = entry.exPrio.macFPri;
    atuEntry->exPrio.macQPri = entry.exPrio.macQPri;

    if(IS_MULTICAST_MAC(entry.macAddr))
    {
        if(dev->deviceId == GT_88E6051)
        {
            DBG_INFO(("Failed.\n"));
            return GT_FAIL;
        }

        atuStateDevToApp(dev,GT_FALSE,(GT_U32)entry.entryState.ucEntryState,
                        &data);
        atuEntry->entryState.mcEntryState = data;
    }
    else
    {
        atuStateDevToApp(dev,GT_TRUE,(GT_U32)entry.entryState.ucEntryState,
                        &data);
        atuEntry->entryState.ucEntryState = data;
    }

    DBG_INFO(("OK.\n"));
    return GT_OK;
}



/*******************************************************************************
* gfdbFindAtuMacEntry
*
* DESCRIPTION:
*       Find FDB entry for specific MAC address from the ATU.
*
* INPUTS:
*       atuEntry - the Mac address to search.
*
* OUTPUTS:
*       found    - GT_TRUE, if the appropriate entry exists.
*       atuEntry - the entry parameters.
*
* RETURNS:
*       GT_OK      - on success.
*       GT_FAIL    - on error or entry does not exist.
*       GT_NO_SUCH - no more entries.
*       GT_BAD_PARAM    - on bad parameter
*
* COMMENTS:
*        DBNum in atuEntry - 
*            ATU MAC Address Database number. If multiple address 
*            databases are not being used, DBNum should be zero.
*            If multiple address databases are being used, this value
*            should be set to the desired address database number.
*
*******************************************************************************/
GT_STATUS gfdbFindAtuMacEntry
(
    IN GT_QD_DEV    *dev,
    INOUT GT_ATU_ENTRY  *atuEntry,
    OUT GT_BOOL         *found
)
{
    GT_STATUS       retVal;
    GT_ATU_ENTRY    entry;
    int           i;
    GT_U32 data;

    DBG_INFO(("gfdbFindAtuMacEntry Called.\n"));
    *found = GT_FALSE;
    gtMemCpy(entry.macAddr.arEther,atuEntry->macAddr.arEther,6);
    entry.DBNum = atuEntry->DBNum;
    /* Decrement 1 from mac address.    */
    for(i=5; i >= 0; i--)
    {
        if(entry.macAddr.arEther[i] != 0)
        {
            entry.macAddr.arEther[i] -= 1;
            break;
        }
        else
            entry.macAddr.arEther[i] = 0xFF;
    }

    /* Check if the given mac equals zero   */
    if((i == -1) && IS_IN_DEV_GROUP(dev,DEV_BROADCAST_INVALID))
    {
        DBG_INFO(("Address should not be all zeros.\n"));
        return GT_BAD_PARAM;
    }

    retVal = atuOperationPerform(dev,GET_NEXT_ENTRY,NULL,&entry);
    if(retVal != GT_OK)
    {
        DBG_INFO(("Failed.\n"));
        return retVal;
    }

    if(IS_BROADCAST_MAC(entry.macAddr))
    {
        if(IS_IN_DEV_GROUP(dev,DEV_BROADCAST_INVALID))
        {
            DBG_INFO(("Failed (Broadcast addr is not valid).\n"));
            return GT_NO_SUCH;
        }
        else if(entry.entryState.ucEntryState == 0)
        {
            DBG_INFO(("Failed (Invalid Mac).\n"));
            return GT_NO_SUCH;
        }
    }
    if(gtMemCmp((char*)atuEntry->macAddr.arEther,(char*)entry.macAddr.arEther,ETHERNET_HEADER_SIZE))
    {
#ifdef __KERNELL__
      DBG_INFO(("@@@@@@@@@@@@@  error gfdbFindAtuMacEntry:check: %02x:%02x:%02x:%02x:%02x:%02x get: %02x:%02x:%02x:%02x:%02x:%02x\n",
      atuEntry->macAddr.arEther[0], 
      atuEntry->macAddr.arEther[1], 
      atuEntry->macAddr.arEther[2], 
      atuEntry->macAddr.arEther[3], 
      atuEntry->macAddr.arEther[4], 
      atuEntry->macAddr.arEther[5], 
      entry.macAddr.arEther[0],
      entry.macAddr.arEther[1],
      entry.macAddr.arEther[2],
      entry.macAddr.arEther[3],
      entry.macAddr.arEther[4],
      entry.macAddr.arEther[5]
      ));
#endif
        DBG_INFO(("Failed.\n"));
        return GT_NO_SUCH;
    }

    atuEntry->portVec   = GT_PORTVEC_2_LPORTVEC(entry.portVec);
    atuEntry->prio      = entry.prio;
    atuEntry->trunkMember = entry.trunkMember;
    atuEntry->exPrio.useMacFPri = entry.exPrio.useMacFPri;
    atuEntry->exPrio.macFPri = entry.exPrio.macFPri;
    atuEntry->exPrio.macQPri = entry.exPrio.macQPri;

    if(IS_MULTICAST_MAC(entry.macAddr))
    {
        if(dev->deviceId == GT_88E6051)
        {
            DBG_INFO(("Failed.\n"));
            return GT_FAIL;
        }

        atuStateDevToApp(dev,GT_FALSE,(GT_U32)entry.entryState.ucEntryState,
                        &data);
        atuEntry->entryState.mcEntryState = data;
    }
    else
    {
        atuStateDevToApp(dev,GT_TRUE,(GT_U32)entry.entryState.ucEntryState,
                        &data);
        atuEntry->entryState.ucEntryState = data;
    }

    *found = GT_TRUE;
    DBG_INFO(("OK.\n"));
    return GT_OK;
}



/*******************************************************************************
* gfdbFlush
*
* DESCRIPTION:
*       This routine flush all or unblocked addresses from the MAC Address
*       Table.
*
* INPUTS:
*       flushCmd - the flush operation type.
*
* OUTPUTS:
*       None
*
* RETURNS:
*       GT_OK           - on success
*       GT_FAIL         - on error
*       GT_NO_RESOURCE  - failed to allocate a t2c struct
*
* COMMENTS:
*
* GalTis:
*
*******************************************************************************/
GT_STATUS gfdbFlush
(
    IN GT_QD_DEV    *dev,
    IN GT_FLUSH_CMD flushCmd
)
{
    GT_STATUS       retVal;
    GT_ATU_ENTRY    entry;

    DBG_INFO(("gfdbFlush Called.\n"));
    /* check if device supports this feature */
    if (!IS_IN_DEV_GROUP(dev,DEV_STATIC_ADDR))
    {
        DBG_INFO(("GT_NOT_SUPPORTED\n"));
        return GT_NOT_SUPPORTED;
    }

    entry.DBNum = 0;
    entry.entryState.ucEntryState = 0;

    if(flushCmd == GT_FLUSH_ALL)
        retVal = atuOperationPerform(dev,FLUSH_ALL,NULL,&entry);
    else
        retVal = atuOperationPerform(dev,FLUSH_UNLOCKED,NULL,&entry);

    if(retVal != GT_OK)
    {
        DBG_INFO(("Failed.\n"));
        return retVal;
    }

    DBG_INFO(("OK.\n"));
    return GT_OK;
}


/*******************************************************************************
* gfdbFlushInDB
*
* DESCRIPTION:
*       This routine flush all or unblocked addresses from the particular
*       ATU Database (DBNum). If multiple address databases are being used, this
*        API can be used to flush entries in a particular DBNum database.
*
* INPUTS:
*       flushCmd - the flush operation type.
*        DBNum     - ATU MAC Address Database Number. 
*
* OUTPUTS:
*       None
*
* RETURNS:
*       GT_OK           - on success
*       GT_FAIL         - on error
*       GT_NOT_SUPPORTED- if current device does not support this feature.
*
* COMMENTS:
*
* GalTis:
*
*******************************************************************************/
GT_STATUS gfdbFlushInDB
(
    IN GT_QD_DEV    *dev,
    IN GT_FLUSH_CMD flushCmd,
    IN GT_U32 DBNum
)
{
    GT_STATUS       retVal;
    GT_ATU_ENTRY    entry;

    DBG_INFO(("gfdbFlushInDB Called.\n"));
    DBG_INFO(("gfdbFush: dev=%x, dev->atuRegsSem=%d \n",dev, dev->atuRegsSem));

    /* check if device supports this feature */
    if ((!IS_IN_DEV_GROUP(dev,DEV_DBNUM_FULL)) && 
        (!IS_IN_DEV_GROUP(dev,DEV_DBNUM_64)) && 
        (!IS_IN_DEV_GROUP(dev,DEV_DBNUM_4096)) && 
        (!IS_IN_DEV_GROUP(dev,DEV_DBNUM_256)))
    {
        DBG_INFO(("GT_NOT_SUPPORTED\n"));
        return GT_NOT_SUPPORTED;
    }

    entry.DBNum = (GT_U16)DBNum;
    entry.entryState.ucEntryState = 0;

    if(flushCmd == GT_FLUSH_ALL)
        retVal = atuOperationPerform(dev,FLUSH_ALL_IN_DB,NULL,&entry);
    else
        retVal = atuOperationPerform(dev,FLUSH_UNLOCKED_IN_DB,NULL,&entry);

    if(retVal != GT_OK)
    {
        DBG_INFO(("Failed.\n"));
        return retVal;
    }

    DBG_INFO(("OK.\n"));
    return GT_OK;
}


/*******************************************************************************
* gfdbMove
*
* DESCRIPTION:
*       This routine moves all or unblocked addresses from a port to another.
*
* INPUTS:
*         moveCmd  - the move operation type.
*        moveFrom - port where moving from
*        moveTo   - port where moving to
*
* OUTPUTS:
*       None
*
* RETURNS:
*       GT_OK           - on success
*       GT_FAIL         - on error
*       GT_NOT_SUPPORTED - if current device does not support this feature.
*
* COMMENTS:
*
* GalTis:
*
*******************************************************************************/
GT_STATUS gfdbMove
(
    IN GT_QD_DEV    *dev,
    IN GT_MOVE_CMD  moveCmd,
    IN GT_LPORT        moveFrom,
    IN GT_LPORT        moveTo
)
{
    GT_STATUS       retVal;
    GT_ATU_ENTRY    entry;
    GT_EXTRA_OP_DATA    opData;

    DBG_INFO(("gfdbMove Called.\n"));

    /* Only Gigabit Switch supports this status. */
    if (!IS_IN_DEV_GROUP(dev,DEV_802_1W))
    {
        DBG_INFO(("GT_NOT_SUPPORTED\n"));
        return GT_NOT_SUPPORTED;
    }

    entry.DBNum = 0;
    entry.entryState.ucEntryState = 0xF;
    if (moveTo == 0xF)
        opData.moveTo = moveTo;
    else
        opData.moveTo = (GT_U32)GT_LPORT_2_PORT(moveTo);
    opData.moveFrom = (GT_U32)GT_LPORT_2_PORT(moveFrom);

    if((opData.moveTo == 0xFF) || (opData.moveFrom == 0xFF))
        return GT_BAD_PARAM;

    if(moveCmd == GT_MOVE_ALL)
        retVal = atuOperationPerform(dev,FLUSH_ALL,&opData,&entry);
    else
        retVal = atuOperationPerform(dev,FLUSH_UNLOCKED,&opData,&entry);

    if(retVal != GT_OK)
    {
        DBG_INFO(("Failed.\n"));
        return retVal;
    }

    DBG_INFO(("OK.\n"));
    return GT_OK;
}


/*******************************************************************************
* gfdbMoveInDB
*
* DESCRIPTION:
*       This routine move all or unblocked addresses which are in the particular
*       ATU Database (DBNum) from a port to another.
*
* INPUTS:
*       moveCmd  - the move operation type.
*        DBNum     - ATU MAC Address Database Number.
*        moveFrom - port where moving from
*        moveTo   - port where moving to
*
* OUTPUTS:
*       None
*
* RETURNS:
*       GT_OK           - on success
*       GT_FAIL         - on error
*       GT_NOT_SUPPORTED- if current device does not support this feature.
*
* COMMENTS:
*
* GalTis:
*
*******************************************************************************/
GT_STATUS gfdbMoveInDB
(
    IN GT_QD_DEV    *dev,
    IN GT_MOVE_CMD     moveCmd,
    IN GT_U32         DBNum,
    IN GT_LPORT        moveFrom,
    IN GT_LPORT        moveTo
)
{
    GT_STATUS       retVal;
    GT_ATU_ENTRY    entry;
    GT_EXTRA_OP_DATA    opData;

    DBG_INFO(("gfdbMoveInDB Called.\n"));

    /* Only Gigabit Switch supports this status. */
    if (!IS_IN_DEV_GROUP(dev,DEV_802_1W))
    {
        DBG_INFO(("GT_NOT_SUPPORTED\n"));
        return GT_NOT_SUPPORTED;
    }

    entry.DBNum = (GT_U16)DBNum;
    entry.entryState.ucEntryState = 0xF;

    if (moveTo == 0xF)
        opData.moveTo = moveTo;
    else
        opData.moveTo = (GT_U32)GT_LPORT_2_PORT(moveTo);
    opData.moveFrom = (GT_U32)GT_LPORT_2_PORT(moveFrom);

    if((opData.moveTo == 0xFF) || (opData.moveFrom == 0xFF))
        return GT_BAD_PARAM;

    if(moveCmd == GT_MOVE_ALL)
        retVal = atuOperationPerform(dev,FLUSH_ALL_IN_DB,&opData,&entry);
    else
        retVal = atuOperationPerform(dev,FLUSH_UNLOCKED_IN_DB,&opData,&entry);

    if(retVal != GT_OK)
    {
        DBG_INFO(("Failed.\n"));
        return retVal;
    }

    DBG_INFO(("OK.\n"));
    return GT_OK;
}


/*******************************************************************************
* gfdbRemovePort
*
* DESCRIPTION:
*       This routine deassociages all or unblocked addresses from a port.
*
* INPUTS:
*       moveCmd - the move operation type.
*       port - the logical port number.
*
* OUTPUTS:
*       None
*
* RETURNS:
*       GT_OK           - on success
*       GT_FAIL         - on error
*       GT_NOT_SUPPORTED - if current device does not support this feature.
*
* COMMENTS:
*
* GalTis:
*
*******************************************************************************/
GT_STATUS gfdbRemovePort
(
    IN GT_QD_DEV    *dev,
    IN GT_MOVE_CMD     moveCmd,
    IN GT_LPORT        port
)
{
    DBG_INFO(("gfdbRemovePort Called.\n"));

    return gfdbMove(dev,moveCmd,port,(GT_LPORT)0xF);
}


/*******************************************************************************
* gfdbRemovePortInDB
*
* DESCRIPTION:
*       This routine deassociages all or unblocked addresses from a port in the
*       particular ATU Database (DBNum).
*
* INPUTS:
*       moveCmd  - the move operation type.
*       port - the logical port number.
*        DBNum     - ATU MAC Address Database Number.
*
* OUTPUTS:
*       None
*
* RETURNS:
*       GT_OK           - on success
*       GT_FAIL         - on error
*       GT_NOT_SUPPORTED- if current device does not support this feature.
*
* COMMENTS:
*
* GalTis:
*
*******************************************************************************/
GT_STATUS gfdbRemovePortInDB
(
    IN GT_QD_DEV    *dev,
    IN GT_MOVE_CMD     moveCmd,
    IN GT_LPORT        port,
    IN GT_U32         DBNum
)
{
    DBG_INFO(("gfdbRemovePortInDB Called.\n"));

    return gfdbMoveInDB(dev,moveCmd,DBNum,port,(GT_LPORT)0xF);
}


/*******************************************************************************
* gfdbAddMacEntry
*
* DESCRIPTION:
*       Creates the new entry in MAC address table.
*
* INPUTS:
*       macEntry    - mac address entry to insert to the ATU.
*
* OUTPUTS:
*       None
*
* RETURNS:
*       GT_OK          - on success
*       GT_FAIL        - on error
*       GT_BAD_PARAM   - on invalid port vector
*
* COMMENTS:
*        DBNum in atuEntry - 
*            ATU MAC Address Database number. If multiple address 
*            databases are not being used, DBNum should be zero.
*            If multiple address databases are being used, this value
*            should be set to the desired address database number.
*
* GalTis:
*
*******************************************************************************/
GT_STATUS gfdbAddMacEntry
(
    IN GT_QD_DEV    *dev,
    IN GT_ATU_ENTRY *macEntry
)
{
    GT_STATUS       retVal;
    GT_ATU_ENTRY    entry;
    GT_U32 data;

    DBG_INFO(("gfdbAddMacEntry Called.\n"));
    /* check if device supports this feature */
    if (!IS_IN_DEV_GROUP(dev,DEV_STATIC_ADDR))
    {
        DBG_INFO(("GT_NOT_SUPPORTED\n"));
        return GT_NOT_SUPPORTED;
    }

    gtMemCpy(entry.macAddr.arEther,macEntry->macAddr.arEther,6);
    entry.DBNum        = macEntry->DBNum;
    entry.portVec     = GT_LPORTVEC_2_PORTVEC(macEntry->portVec);
    if(entry.portVec == GT_INVALID_PORT_VEC)
    {
        return GT_BAD_PARAM;
    }

    if(IS_IN_DEV_GROUP(dev,DEV_ATU_EXT_PRI))
    {
        if(IS_IN_DEV_GROUP(dev,DEV_FQPRI_IN_TABLE))
        {
            entry.exPrio.useMacFPri = macEntry->exPrio.useMacFPri;
            entry.exPrio.macFPri = macEntry->exPrio.macFPri;
            entry.exPrio.macQPri = macEntry->exPrio.macQPri;
        }
        else
        {
            entry.exPrio.useMacFPri = 0;
            entry.exPrio.macFPri = macEntry->exPrio.macQPri;
            entry.exPrio.macQPri = macEntry->exPrio.macQPri;
        }
        entry.prio        = 0;
    }
    else
    {
        entry.exPrio.useMacFPri = 0;
        entry.exPrio.macFPri = 0;
        entry.exPrio.macQPri = 0;
        entry.prio        = macEntry->prio;
    }

    if (IS_IN_DEV_GROUP(dev,DEV_TRUNK))
    {
        entry.trunkMember = macEntry->trunkMember;
    }
    else
    {
        entry.trunkMember = GT_FALSE;
    }

    if(IS_MULTICAST_MAC(entry.macAddr))
    {
        atuStateAppToDev(dev,GT_FALSE,(GT_U32)macEntry->entryState.mcEntryState,
                        &data);
        entry.entryState.ucEntryState = data;
    }
    else
    {
        atuStateAppToDev(dev,GT_TRUE,(GT_U32)macEntry->entryState.ucEntryState,
                        &data);
        entry.entryState.ucEntryState = data;
    }

    if (entry.entryState.ucEntryState == 0)
    {
        DBG_INFO(("Entry State should not be ZERO.\n"));
        return GT_BAD_PARAM;
    }

    retVal = atuOperationPerform(dev,LOAD_PURGE_ENTRY,NULL,&entry);
    if(retVal != GT_OK)
    {
        DBG_INFO(("Failed.\n"));
        return retVal;
    }

    DBG_INFO(("OK.\n"));
    return GT_OK;
}

/*******************************************************************************
* gfdbDelMacEntry
*
* DESCRIPTION:
*       Deletes MAC address entry. If DBNum or FID is used, gfdbDelAtuEntry API
*        would be the better choice to delete an entry in ATU.
*
* INPUTS:
*       macAddress - mac address.
*
* OUTPUTS:
*       None.
*
* RETURNS:
*       GT_OK           - on success
*       GT_FAIL         - on error
*       GT_NO_RESOURCE  - failed to allocate a t2c struct
*       GT_NO_SUCH      - if specified address entry does not exist
*
* COMMENTS:
*
*******************************************************************************/
GT_STATUS gfdbDelMacEntry
(
    IN GT_QD_DEV    *dev,
    IN GT_ETHERADDR  *macAddress
)
{
    GT_STATUS retVal;
    GT_ATU_ENTRY    entry;

    DBG_INFO(("gfdbDelMacEntry Called.\n"));
    /* check if device supports this feature */
    if (!IS_IN_DEV_GROUP(dev,DEV_STATIC_ADDR))
    {
        DBG_INFO(("GT_NOT_SUPPORTED\n"));
        return GT_NOT_SUPPORTED;
    }

    gtMemCpy(entry.macAddr.arEther,macAddress->arEther,6);
    entry.DBNum = 0;
    entry.prio = 0;
    entry.portVec = 0;
    entry.entryState.ucEntryState = 0;
    entry.trunkMember = GT_FALSE;
    entry.exPrio.useMacFPri = GT_FALSE;
    entry.exPrio.macFPri = 0;
    entry.exPrio.macQPri = 0;

    retVal = atuOperationPerform(dev,LOAD_PURGE_ENTRY,NULL,&entry);
    if(retVal != GT_OK)
    {
        DBG_INFO(("Failed.\n"));
        return retVal;
    }
    DBG_INFO(("OK.\n"));
    return GT_OK;
}


/*******************************************************************************
* gfdbDelAtuEntry
*
* DESCRIPTION:
*       Deletes ATU entry.
*
* INPUTS:
*       atuEntry - the ATU entry to be deleted.
*
* OUTPUTS:
*       None.
*
* RETURNS:
*       GT_OK           - on success
*       GT_FAIL         - on error
*       GT_NO_RESOURCE  - failed to allocate a t2c struct
*       GT_NO_SUCH      - if specified address entry does not exist
*
* COMMENTS:
*        DBNum in atuEntry - 
*            ATU MAC Address Database number. If multiple address 
*            databases are not being used, DBNum should be zero.
*            If multiple address databases are being used, this value
*            should be set to the desired address database number.
*
*******************************************************************************/
GT_STATUS gfdbDelAtuEntry
(
    IN GT_QD_DEV    *dev,
    IN GT_ATU_ENTRY  *atuEntry
)
{
    GT_ATU_ENTRY    entry;
    GT_STATUS retVal;

    DBG_INFO(("gfdbDelAtuEntry Called.\n"));
    /* check if device supports this feature */
    if (!IS_IN_DEV_GROUP(dev,DEV_STATIC_ADDR))
    {
        DBG_INFO(("GT_NOT_SUPPORTED\n"));
        return GT_NOT_SUPPORTED;
    }

    gtMemCpy(entry.macAddr.arEther,atuEntry->macAddr.arEther,6);
    entry.DBNum = atuEntry->DBNum;
    entry.prio = 0;
    entry.portVec = 0;
    entry.entryState.ucEntryState = 0;
    entry.trunkMember = GT_FALSE;
    entry.exPrio.useMacFPri = GT_FALSE;
    entry.exPrio.macFPri = 0;
    entry.exPrio.macQPri = 0;

    retVal = atuOperationPerform(dev,LOAD_PURGE_ENTRY,NULL,&entry);
    if(retVal != GT_OK)
    {
        DBG_INFO(("Failed.\n"));
        return retVal;
    }
    DBG_INFO(("OK.\n"));
    return GT_OK;
}

/*******************************************************************************
* gfdbLearnEnable
*
* DESCRIPTION:
*       Enable/disable automatic learning of new source MAC addresses on port
*       ingress.
*
* INPUTS:
*       en - GT_TRUE for enable  or GT_FALSE otherwise
*
* OUTPUTS:
*       None
*
* RETURNS:
*       GT_OK   - on success
*       GT_FAIL - on error
*
* COMMENTS:
*
* GalTis:
*
*******************************************************************************/
GT_STATUS gfdbLearnEnable
(
    IN GT_QD_DEV    *dev,
    IN GT_BOOL  en
)
{
    GT_STATUS       retVal;         /* Functions return value.      */
    GT_U16          data;           /* Data to be set into the      */
                                    /* register.                    */
    GT_LPORT    port;
    GT_BOOL        mode;

    DBG_INFO(("gfdbLearnEnable Called.\n"));
    BOOL_2_BIT(en,data);
    data = 1 - data;

    if (IS_IN_DEV_GROUP(dev,DEV_GIGABIT_SWITCH))
    {
        mode = (en)?GT_FALSE:GT_TRUE;

        for (port=0; port<dev->numOfPorts; port++)
        {
            retVal = gprtSetLearnDisable(dev,port,mode);
            if(retVal != GT_OK)
            {
                DBG_INFO(("Failed.\n"));
                return retVal;
            }
        }
    }
    else
    {
        /* Set the Learn Enable bit.            */
        retVal = hwSetGlobalRegField(dev,QD_REG_ATU_CONTROL,14,1,data);
        if(retVal != GT_OK)
        {
            DBG_INFO(("Failed.\n"));
            return retVal;
        }
    }    
    DBG_INFO(("OK.\n"));
    return GT_OK;
}


/*******************************************************************************
* gfdbGetLearnEnable
*
* DESCRIPTION:
*       Get automatic learning status of new source MAC addresses on port ingress.
*
* INPUTS:
*       None
*
* OUTPUTS:
*       en - GT_TRUE if enabled  or GT_FALSE otherwise
*
* RETURNS:
*       GT_OK   - on success
*       GT_FAIL - on error
*        GT_NOT_SUPPORTED - if current device does not support this feature.
*
* COMMENTS:
*
* GalTis:
*
*******************************************************************************/
GT_STATUS gfdbGetLearnEnable
(
    IN GT_QD_DEV    *dev,
    OUT GT_BOOL  *en
)
{
    GT_STATUS       retVal;         /* Functions return value.      */
    GT_U16          data;           /* Data to be set into the      */
                                    /* register.                    */
    DBG_INFO(("gfdbGetLearnEnable Called.\n"));

    if (IS_IN_DEV_GROUP(dev,DEV_GIGABIT_SWITCH))
    {
        return GT_NOT_SUPPORTED;
    }
    else
    {
        /* Get the Learn Enable bit.            */
        retVal = hwGetGlobalRegField(dev,QD_REG_ATU_CONTROL,14,1,&data);
        if(retVal != GT_OK)
        {
            DBG_INFO(("Failed.\n"));
            return retVal;
        }
    }    

    data = 1 - data;
    BOOL_2_BIT(data, *en);

    DBG_INFO(("OK.\n"));
    return GT_OK;
}

/****************************************************************************/
/* Internal use functions.                                                  */
/****************************************************************************/

/*******************************************************************************
* gatuGetViolation
*
* DESCRIPTION:
*       Get ATU Violation data
*
* INPUTS:
*       None.
*
* OUTPUTS:
*       atuIntStatus - interrupt cause, source portID, and vid.
*
* RETURNS:
*       GT_OK           - on success
*       GT_FAIL         - on error
*       GT_NOT_SUPPORT  - if current device does not support this feature.
*
* COMMENTS:
*        This is an internal function. No user should call this function.
*
* GalTis:
*
*******************************************************************************/
GT_STATUS gatuGetViolation
(
    IN  GT_QD_DEV         *dev,
    OUT GT_ATU_INT_STATUS *atuIntStatus
)
{
    GT_U16              intCause;
    GT_STATUS           retVal;
    GT_ATU_ENTRY        entry;
    GT_EXTRA_OP_DATA    opData;
    GT_BOOL                found, ageInt;

    DBG_INFO(("gatuGetViolation Called.\n"));

    /* check which Violation occurred */
    retVal = hwGetGlobalRegField(dev,QD_REG_GLOBAL_STATUS,3,1,&intCause);
    if(retVal != GT_OK)
    {
        DBG_INFO(("ERROR to read ATU OPERATION Register.\n"));
        return retVal;
    }

    if (!intCause)
    {
        /* No Violation occurred. */
        atuIntStatus->atuIntCause = 0;
        return GT_OK;
    }

    entry.DBNum = 0;

    retVal = atuOperationPerform(dev,SERVICE_VIOLATIONS,&opData,&entry);
    if(retVal != GT_OK)
    {
        DBG_INFO(("Failed (atuOperationPerform returned GT_FAIL).\n"));
        return retVal;
    }

    gtMemCpy(atuIntStatus->macAddr.arEther,entry.macAddr.arEther,6);

    atuIntStatus->atuIntCause = (GT_U16)opData.intCause;
    atuIntStatus->spid = entry.entryState.ucEntryState;
    atuIntStatus->dbNum = qdShort2Char(entry.DBNum);

    if(atuIntStatus->spid != 0xF)
        atuIntStatus->spid = (GT_U8)GT_PORT_2_LPORT(atuIntStatus->spid);
            
    if (IS_IN_DEV_GROUP(dev,DEV_AGE_OUT_INT))
    {
        if (opData.intCause == GT_AGE_VIOLATION)
        {
            atuIntStatus->atuIntCause = GT_AGE_OUT_VIOLATION;
        }
        else if (opData.intCause == GT_MISS_VIOLATION)
        {
            /* check if it's AGE Violation */
            if((retVal = gsysGetAgeInt(dev, &ageInt)) != GT_OK)
                return retVal;

            if(ageInt)
            {
                gfdbFindAtuMacEntry(dev, &entry, &found);
                if ((found) && (entry.entryState.ucEntryState <= 4))
                    atuIntStatus->atuIntCause = GT_AGE_VIOLATION;
            }
            
        }
    }

    DBG_INFO(("OK.\n"));
    return GT_OK;
}


/*******************************************************************************
* atuOperationPerform
*
* DESCRIPTION:
*       This function is used by all ATU control functions, and is responsible
*       to write the required operation into the ATU registers.
*
* INPUTS:
*       atuOp       - The ATU operation bits to be written into the ATU
*                     operation register.
*       DBNum       - ATU Database Number for CPU accesses
*       entryPri    - The EntryPri field in the ATU Data register.
*       portVec     - The portVec field in the ATU Data register.
*       entryState  - The EntryState field in the ATU Data register.
*       atuMac      - The Mac address to be written to the ATU Mac registers.
*
* OUTPUTS:
*       entryPri    - The EntryPri field in case the atuOp is GetNext.
*       portVec     - The portVec field in case the atuOp is GetNext.
*       entryState  - The EntryState field in case the atuOp is GetNext.
*       atuMac      - The returned Mac address in case the atuOp is GetNext.
*
* RETURNS:
*       GT_OK on success,
*       GT_FAIL otherwise.
*
* COMMENTS:
*       1.  if atuMac == NULL, nothing needs to be written to ATU Mac registers.
*
*******************************************************************************/
static GT_STATUS atuOperationPerform
(
    IN      GT_QD_DEV           *dev,
    IN      GT_ATU_OPERATION    atuOp,
    INOUT    GT_EXTRA_OP_DATA    *opData,
    INOUT     GT_ATU_ENTRY        *entry
)
{
    GT_STATUS       retVal;         /* Functions return value.      */
    GT_U16          data;           /* Data to be set into the      */
                                    /* register.                    */
    GT_U16          opcodeData;           /* Data to be set into the      */
                                    /* register.                    */
    GT_U8           i;
    GT_U16            portMask;

    gtSemTake(dev,dev->atuRegsSem,OS_WAIT_FOREVER);

    portMask = (1 << dev->maxPorts) - 1;

    /* Wait until the ATU in ready. */
#ifdef GT_RMGMT_ACCESS
    {
      HW_DEV_REG_ACCESS regAccess;

      regAccess.entries = 1;
  
      regAccess.rw_reg_list[0].cmd = HW_REG_WAIT_TILL_0;
      regAccess.rw_reg_list[0].addr = CALC_SMI_DEV_ADDR(dev, 0, GLOBAL_REG_ACCESS);
      regAccess.rw_reg_list[0].reg = QD_REG_ATU_OPERATION;
      regAccess.rw_reg_list[0].data = 15;
      retVal = hwAccessMultiRegs(dev, &regAccess);
      if(retVal != GT_OK)
      {
        gtSemGive(dev,dev->atuRegsSem);
        return retVal;
      }
    }
#else
    data = 1;
    while(data == 1)
    {
        retVal = hwGetGlobalRegField(dev,QD_REG_ATU_OPERATION,15,1,&data);
        if(retVal != GT_OK)
        {
            gtSemGive(dev,dev->atuRegsSem);
            return retVal;
        }
    }
#endif

    opcodeData = 0;

    switch (atuOp)
    {
        case LOAD_PURGE_ENTRY:
                if ((IS_IN_DEV_GROUP(dev,DEV_88E6093_FAMILY) &&
                    (!((IS_IN_DEV_GROUP(dev,DEV_88EC000_FAMILY))||
                       (IS_IN_DEV_GROUP(dev,DEV_88ESPANNAK_FAMILY))))) ||
                    IS_IN_DEV_GROUP(dev,DEV_TRUNK))
                {
                    if (IS_IN_DEV_GROUP(dev,DEV_TRUNK) && entry->trunkMember)
                    {
                        /* portVec represents trunk ID */
                        data = (GT_U16)( 0x8000 | (((entry->portVec) & 0xF) << 4) |
                             (((entry->entryState.ucEntryState) & 0xF)) );
                    }
                    else
                    {
                        data = (GT_U16)( (((entry->portVec) & portMask) << 4) |
                             (((entry->entryState.ucEntryState) & 0xF)) );
                    }
                    opcodeData |= (entry->prio & 0x7) << 8;
                }
                else if(IS_IN_DEV_GROUP(dev,DEV_ATU_EXT_PRI))
                {
                  if(IS_IN_DEV_GROUP(dev,DEV_MACPRI_IN_TABLE))
                  {
                    data = (GT_U16)( (((entry->portVec) & portMask) << 4) |
                             ((entry->entryState.ucEntryState) & 0xF) );
                    data |= ((entry->prio & 0x7) << 13);
                  }
                  else
                  {
                    data = (GT_U16)( (((entry->portVec) & portMask) << 4) |
                             (((entry->entryState.ucEntryState) & 0xF)) |
                             (((entry->exPrio.macQPri) & 0x3) << 14) );
                    if(entry->exPrio.useMacFPri == GT_TRUE)
                        data |= ((1 << 13) | ((entry->exPrio.macFPri & 0x7) << 10));
                  }
                }
                else
                {
                    data = (GT_U16)( (((entry->prio) & 0x3) << 14) | 
                            (((entry->portVec) & portMask) << 4) |
                            (((entry->entryState.ucEntryState) & 0xF)) );
                }
                retVal = hwWriteGlobalReg(dev,QD_REG_ATU_DATA_REG,data);
                if(retVal != GT_OK)
                {
                    gtSemGive(dev,dev->atuRegsSem);
                    return retVal;
                }
                /* pass thru */

        case GET_NEXT_ENTRY:
#ifdef GT_RMGMT_ACCESS
    {
      HW_DEV_REG_ACCESS regAccess;

      regAccess.entries = 3;
  
      for(i = 0; i < 3; i++)
      {
        data=(entry->macAddr.arEther[2*i] << 8)|(entry->macAddr.arEther[1 + 2*i]);
        regAccess.rw_reg_list[i].cmd = HW_REG_WRITE;
        regAccess.rw_reg_list[i].addr = CALC_SMI_DEV_ADDR(dev, 0, GLOBAL_REG_ACCESS);
        regAccess.rw_reg_list[i].reg = QD_REG_ATU_MAC_BASE+i;
        regAccess.rw_reg_list[i].data = data;
      }
      retVal = hwAccessMultiRegs(dev, &regAccess);
      if(retVal != GT_OK)
      {
        gtSemGive(dev,dev->atuRegsSem);
        return retVal;
      }
    }
#else
                for(i = 0; i < 3; i++)
                {
                    data=(entry->macAddr.arEther[2*i] << 8)|(entry->macAddr.arEther[1 + 2*i]);
                    retVal = hwWriteGlobalReg(dev,(GT_U8)(QD_REG_ATU_MAC_BASE+i),data);
                    if(retVal != GT_OK)
                    {
                        gtSemGive(dev,dev->atuRegsSem);
                        return retVal;
                    }
                }
#endif
                break;

        case FLUSH_ALL:
        case FLUSH_UNLOCKED:
        case FLUSH_ALL_IN_DB:
        case FLUSH_UNLOCKED_IN_DB:
                if (entry->entryState.ucEntryState == 0xF)
                {
                    data = (GT_U16)(0xF | ((opData->moveFrom & 0xF) << 4) | ((opData->moveTo & 0xF) << 8));
                }
                else
                {
                    data = 0;
                }
                retVal = hwWriteGlobalReg(dev,QD_REG_ATU_DATA_REG,data);
                   if(retVal != GT_OK)
                {
                       gtSemGive(dev,dev->atuRegsSem);
                    return retVal;
                   }
                break;

        case SERVICE_VIOLATIONS:

                break;

        default :
                return GT_FAIL;
    }

    /* Set DBNum */
    if(IS_IN_DEV_GROUP(dev,DEV_FID_REG))
    {
        retVal = hwSetGlobalRegField(dev,QD_REG_ATU_FID_REG,0,12,(GT_U16)(entry->DBNum & 0xFFF));
        if(retVal != GT_OK)
        {
            gtSemGive(dev,dev->atuRegsSem);
            return retVal;
        }
    }
    else if (IS_IN_DEV_GROUP(dev,DEV_DBNUM_256))
    {
        retVal = hwSetGlobalRegField(dev,QD_REG_ATU_CONTROL,12,4,(GT_U16)((entry->DBNum & 0xF0) >> 4));
        if(retVal != GT_OK)
        {
            gtSemGive(dev,dev->atuRegsSem);
            return retVal;
        }
    }
    else if (IS_IN_DEV_GROUP(dev,DEV_DBNUM_64))
    {
        opcodeData |= ((entry->DBNum & 0x30) << 4);    /* Op Reg bit 9:8 */
    }

    /* Set the ATU Operation register in addtion to DBNum setup  */

    if(IS_IN_DEV_GROUP(dev,DEV_FID_REG))
        opcodeData |= ((1 << 15) | (atuOp << 12));
    else
    {
        opcodeData |= ((1 << 15) | (atuOp << 12) | (entry->DBNum & 0xF));
    }

    retVal = hwWriteGlobalReg(dev,QD_REG_ATU_OPERATION,opcodeData);
    if(retVal != GT_OK)
    {
        gtSemGive(dev,dev->atuRegsSem);
        return retVal;
    }

    /* If the operation is to service violation operation wait for the response   */
    if(atuOp == SERVICE_VIOLATIONS)
    {
        /* Wait until the VTU in ready. */
#ifdef GT_RMGMT_ACCESS
        {
          HW_DEV_REG_ACCESS regAccess;

          regAccess.entries = 1;
  
          regAccess.rw_reg_list[0].cmd = HW_REG_WAIT_TILL_0;
          regAccess.rw_reg_list[0].addr = CALC_SMI_DEV_ADDR(dev, 0, GLOBAL_REG_ACCESS);
          regAccess.rw_reg_list[0].reg = QD_REG_ATU_OPERATION;
          regAccess.rw_reg_list[0].data = 15;
          retVal = hwAccessMultiRegs(dev, &regAccess);
          if(retVal != GT_OK)
          {
            gtSemGive(dev,dev->atuRegsSem);
          return retVal;
          }
        }
#else
        data = 1;
        while(data == 1)
        {
            retVal = hwGetGlobalRegField(dev,QD_REG_ATU_OPERATION,15,1,&data);
            if(retVal != GT_OK)
            {
                gtSemGive(dev,dev->atuRegsSem);
                return retVal;
            }
        }
#endif

        /* get the Interrupt Cause */
        retVal = hwGetGlobalRegField(dev,QD_REG_ATU_OPERATION,4,4,&data);
        if(retVal != GT_OK)
        {
            gtSemGive(dev,dev->atuRegsSem);
            return retVal;
        }
        if (!IS_IN_DEV_GROUP(dev,DEV_AGE_OUT_INT))
        {
            data &= 0x7;    /* only 3 bits are valid for non age_out_int group */
        }
    
        switch (data)
        {
            case 8:    /* Age Interrupt */
                opData->intCause = GT_AGE_VIOLATION;
                break;
            case 4:    /* Member Violation */
                opData->intCause = GT_MEMBER_VIOLATION;
                break;
            case 2:    /* Miss Violation */
                opData->intCause = GT_MISS_VIOLATION;
                break;
            case 1:    /* Full Violation */
                opData->intCause = GT_FULL_VIOLATION;
                break;
            default:
                opData->intCause = 0;
                gtSemGive(dev,dev->atuRegsSem);
                return GT_OK;
        }

        /* get the DBNum that was involved in the violation */

        entry->DBNum = 0;

        if(IS_IN_DEV_GROUP(dev,DEV_FID_REG))
        {
            retVal = hwGetGlobalRegField(dev,QD_REG_ATU_FID_REG,0,12,&data);
            if(retVal != GT_OK)
            {
                gtSemGive(dev,dev->atuRegsSem);
                return retVal;
            }
            entry->DBNum = (GT_U16)data;
        }
        else if (IS_IN_DEV_GROUP(dev,DEV_DBNUM_256))
        {
            retVal = hwGetGlobalRegField(dev,QD_REG_ATU_CONTROL,12,4,&data);
            if(retVal != GT_OK)
            {
                gtSemGive(dev,dev->atuRegsSem);
                return retVal;
            }
            entry->DBNum = (GT_U16)data << 4;
        }
        else if (IS_IN_DEV_GROUP(dev,DEV_DBNUM_64))
        {
            retVal = hwGetGlobalRegField(dev,QD_REG_ATU_OPERATION,8,2,&data);
            if(retVal != GT_OK)
            {
                gtSemGive(dev,dev->atuRegsSem);
                return retVal;
            }
            entry->DBNum = (GT_U16)data << 4;
        }

        if(!IS_IN_DEV_GROUP(dev,DEV_FID_REG))
        {
            retVal = hwGetGlobalRegField(dev,QD_REG_ATU_OPERATION,0,4,&data);
            if(retVal != GT_OK)
            {
                gtSemGive(dev,dev->atuRegsSem);
                return retVal;
            }

            entry->DBNum |= (GT_U8)(data & 0xF);
        }

        /* get the Source Port ID that was involved in the violation */

        retVal = hwReadGlobalReg(dev,QD_REG_ATU_DATA_REG,&data);
        if(retVal != GT_OK)
        {
            gtSemGive(dev,dev->atuRegsSem);
            return retVal;
        }

        entry->entryState.ucEntryState = data & 0xF;

        /* Get the Mac address  */
#ifdef GT_RMGMT_ACCESS
        {
          HW_DEV_REG_ACCESS regAccess;

          regAccess.entries = 3;
  
          for(i = 0; i < 3; i++)
          {
            regAccess.rw_reg_list[i].cmd = HW_REG_READ;
            regAccess.rw_reg_list[i].addr = CALC_SMI_DEV_ADDR(dev, 0, GLOBAL_REG_ACCESS);
            regAccess.rw_reg_list[i].reg = QD_REG_ATU_MAC_BASE+i;
            regAccess.rw_reg_list[i].data = 0;
          }
          retVal = hwAccessMultiRegs(dev, &regAccess);
          if(retVal != GT_OK)
          {
            gtSemGive(dev,dev->atuRegsSem);
            return retVal;
          }
          for(i = 0; i < 3; i++)
          {
            entry->macAddr.arEther[2*i] = qdLong2Char(regAccess.rw_reg_list[i].data >> 8);
            entry->macAddr.arEther[1 + 2*i] = qdLong2Char(regAccess.rw_reg_list[i].data & 0xFF);
          }
        }
#else
        for(i = 0; i < 3; i++)
        {
            retVal = hwReadGlobalReg(dev,(GT_U8)(QD_REG_ATU_MAC_BASE+i),&data);
            if(retVal != GT_OK)
            {
                gtSemGive(dev,dev->atuRegsSem);
                return retVal;
            }
            entry->macAddr.arEther[2*i] = data >> 8;
            entry->macAddr.arEther[1 + 2*i] = data & 0xFF;
        }
#endif


    } /* end of service violations */
    /* If the operation is a gen next operation wait for the response   */
    if(atuOp == GET_NEXT_ENTRY)
    {
        entry->trunkMember = GT_FALSE;
        entry->exPrio.useMacFPri = GT_FALSE;
        entry->exPrio.macFPri = 0;
        entry->exPrio.macQPri = 0;

        /* Wait until the ATU in ready. */
#ifdef GT_RMGMT_ACCESS
        {
          HW_DEV_REG_ACCESS regAccess;

          regAccess.entries = 5;
  
          regAccess.rw_reg_list[0].cmd = HW_REG_WAIT_TILL_0;
          regAccess.rw_reg_list[0].addr = CALC_SMI_DEV_ADDR(dev, 0, GLOBAL_REG_ACCESS);
          regAccess.rw_reg_list[0].reg = QD_REG_ATU_OPERATION;
          regAccess.rw_reg_list[0].data = 15;
  
          for(i = 1; i < 4; i++)
          {
            regAccess.rw_reg_list[i].cmd = HW_REG_READ;
            regAccess.rw_reg_list[i].addr = CALC_SMI_DEV_ADDR(dev, 0, GLOBAL_REG_ACCESS);
            regAccess.rw_reg_list[i].reg = QD_REG_ATU_MAC_BASE+i-1;
            regAccess.rw_reg_list[i].data = 0;
          }

          regAccess.rw_reg_list[4].cmd = HW_REG_READ;
          regAccess.rw_reg_list[4].addr = CALC_SMI_DEV_ADDR(dev, 0, GLOBAL_REG_ACCESS);
          regAccess.rw_reg_list[4].reg = QD_REG_ATU_DATA_REG;
          regAccess.rw_reg_list[4].data = 0;

          retVal = hwAccessMultiRegs(dev, &regAccess);
          if(retVal != GT_OK)
          {
            gtSemGive(dev,dev->atuRegsSem);
            return retVal;
          }
          for(i = 0; i < 3; i++)
          {
            entry->macAddr.arEther[2*i] = qdLong2Char(regAccess.rw_reg_list[i+1].data >> 8);
            entry->macAddr.arEther[1 + 2*i] = qdLong2Char(regAccess.rw_reg_list[i+1].data & 0xFF);
          }
          data = qdLong2Short(regAccess.rw_reg_list[4].data);
        }
#else
        data = 1;
        while(data == 1)
        {
            retVal = hwGetGlobalRegField(dev,QD_REG_ATU_OPERATION,15,1,&data);
            if(retVal != GT_OK)
            {
                gtSemGive(dev,dev->atuRegsSem);
                return retVal;
            }
        }

        /* Get the Mac address  */
        for(i = 0; i < 3; i++)
        {
            retVal = hwReadGlobalReg(dev,(GT_U8)(QD_REG_ATU_MAC_BASE+i),&data);
            if(retVal != GT_OK)
            {
                gtSemGive(dev,dev->atuRegsSem);
                return retVal;
            }
            entry->macAddr.arEther[2*i] = data >> 8;
            entry->macAddr.arEther[1 + 2*i] = data & 0xFF;
        }

        retVal = hwReadGlobalReg(dev,QD_REG_ATU_DATA_REG,&data);
        if(retVal != GT_OK)
        {
            gtSemGive(dev,dev->atuRegsSem);
            return retVal;
        }
#endif

        /* Get the Atu data register fields */
        if ((IS_IN_DEV_GROUP(dev,DEV_88E6093_FAMILY) &&
            (!((IS_IN_DEV_GROUP(dev,DEV_88EC000_FAMILY))||
               (IS_IN_DEV_GROUP(dev,DEV_88ESPANNAK_FAMILY))))) ||
            IS_IN_DEV_GROUP(dev,DEV_TRUNK))
        {
            if (IS_IN_DEV_GROUP(dev,DEV_TRUNK))
            {
                entry->trunkMember = (data & 0x8000)?GT_TRUE:GT_FALSE;
            }

            entry->portVec = (data >> 4) & portMask;
            entry->entryState.ucEntryState = data & 0xF;
            retVal = hwGetGlobalRegField(dev,QD_REG_ATU_OPERATION,8,3,&data);
            if(retVal != GT_OK)
            {
                gtSemGive(dev,dev->atuRegsSem);
                return retVal;
            }
            entry->prio = (GT_U8)data;
        }
        else if(IS_IN_DEV_GROUP(dev,DEV_ATU_EXT_PRI))
        {
          if(IS_IN_DEV_GROUP(dev,DEV_MACPRI_IN_TABLE))
          {
            entry->portVec = (data >> 4) & portMask;
            entry->entryState.ucEntryState = data & 0xF;
            entry->prio = (data >> 13) & 0x7;
            entry->exPrio.macFPri = entry->prio;
            entry->exPrio.macQPri = entry->prio; 
            entry->prio = 0;
            entry->exPrio.useMacFPri = GT_FALSE; /* doesn't care */
          }
          else
          {
            entry->prio = 0;
            entry->portVec = (data >> 4) & portMask;
            entry->entryState.ucEntryState = data & 0xF;
            entry->exPrio.useMacFPri = (data & 0x2000)?GT_TRUE:GT_FALSE;
            entry->exPrio.macFPri = (data >> 10) & 0x7;
            entry->exPrio.macQPri = data >> 14;
          }
        }
        else
        {
            entry->prio = data >> 14;
            entry->portVec = (data >> 4) & portMask;
            entry->entryState.ucEntryState = data & 0xF;
        }
    }

    gtSemGive(dev,dev->atuRegsSem);
    return GT_OK;
}

static GT_STATUS atuStateAppToDev
(
    IN  GT_QD_DEV    *dev,
    IN  GT_BOOL        unicast,
    IN  GT_U32        state,
    OUT GT_U32        *newOne
)
{
    GT_U32    newState;
    GT_STATUS    retVal = GT_OK;

    if(unicast)
    {
        switch ((GT_ATU_UC_STATE)state)
        {
            case GT_UC_INVALID:
                newState = state;
                break;

            case GT_UC_DYNAMIC:
                if (IS_IN_DEV_GROUP(dev,DEV_UC_7_DYNAMIC))
                {
                    newState = 7;
                }
                else
                {
                    newState = 0xE;
                }
                break;

            case GT_UC_NO_PRI_TO_CPU_STATIC_NRL:
                if (IS_IN_DEV_GROUP(dev,DEV_UC_NO_PRI_TO_CPU_STATIC_NRL))
                {
                    newState = state;
                }
                else
                {
                    newState = (GT_U32)GT_UC_STATIC;
                    retVal = GT_BAD_PARAM;
                }
                break;

            case GT_UC_TO_CPU_STATIC_NRL:
                if (IS_IN_DEV_GROUP(dev,DEV_UC_TO_CPU_STATIC_NRL))
                {
                    newState = state;
                }
                else
                {
                    newState = (GT_U32)GT_UC_STATIC;
                    retVal = GT_BAD_PARAM;
                }
                break;

            case GT_UC_NO_PRI_STATIC_NRL:
                if (IS_IN_DEV_GROUP(dev,DEV_UC_NO_PRI_STATIC_NRL))
                {
                    newState = state;
                }
                else
                {
                    newState = (GT_U32)GT_UC_STATIC;
                    retVal = GT_BAD_PARAM;
                }
                break;

            case GT_UC_STATIC_NRL:
                if (IS_IN_DEV_GROUP(dev,DEV_UC_STATIC_NRL))
                {
                    newState = state;
                }
                else
                {
                    newState = (GT_U32)GT_UC_STATIC;
                    retVal = GT_BAD_PARAM;
                }
                break;

            case GT_UC_NO_PRI_TO_CPU_STATIC:
                if (IS_IN_DEV_GROUP(dev,DEV_UC_NO_PRI_TO_CPU_STATIC))
                {
                    newState = state;
                }
                else
                {
                    newState = (GT_U32)GT_UC_STATIC;
                    retVal = GT_BAD_PARAM;
                }
                break;

            case GT_UC_TO_CPU_STATIC:
                if (IS_IN_DEV_GROUP(dev,DEV_UC_TO_CPU_STATIC))
                {
                    newState = state;
                }
                else
                {
                    newState = (GT_U32)GT_UC_STATIC;
                    retVal = GT_BAD_PARAM;
                }
                break;

            case GT_UC_NO_PRI_STATIC:
                if (IS_IN_DEV_GROUP(dev,DEV_UC_NO_PRI_STATIC))
                {
                    newState = state;
                }
                else
                {
                    newState = (GT_U32)GT_UC_STATIC;
                    retVal = GT_BAD_PARAM;
                }
                break;

            case GT_UC_STATIC:
                if (IS_IN_DEV_GROUP(dev,DEV_UC_STATIC))
                {
                    newState = state;
                }
                else
                {
                    newState = (GT_U32)GT_UC_STATIC;
                    retVal = GT_BAD_PARAM;
                }
                break;

            default:
                if (IS_IN_DEV_GROUP(dev,DEV_UC_7_DYNAMIC))
                {
                    newState = 7;
                }
                else
                {
                    newState = 0xE;
                }
                retVal = GT_BAD_PARAM;
                break;

        }
    }
    else
    {
        switch ((GT_ATU_UC_STATE)state)
        {
            case GT_MC_INVALID:
                newState = state;
                break;

            case GT_MC_MGM_STATIC_UNLIMITED_RATE:
                if (IS_IN_DEV_GROUP(dev,DEV_MC_MGM_STATIC_UNLIMITED_RATE))
                {
                    newState = state;
                }
                else
                {
                    newState = (GT_U32)GT_MC_STATIC;
                    retVal = GT_BAD_PARAM;
                }
                break;

            case GT_MC_STATIC_UNLIMITED_RATE:
                if (IS_IN_DEV_GROUP(dev,DEV_MC_STATIC_UNLIMITED_RATE))
                {
                    newState = state;
                }
                else
                {
                    newState = (GT_U32)GT_MC_STATIC;
                    retVal = GT_BAD_PARAM;
                }
                break;

            case GT_MC_MGM_STATIC:
                if (IS_IN_DEV_GROUP(dev,DEV_MC_MGM_STATIC))
                {
                    newState = state;
                }
                else
                {
                    newState = (GT_U32)GT_MC_STATIC;
                    retVal = GT_BAD_PARAM;
                }
                break;

            case GT_MC_STATIC:
                if (IS_IN_DEV_GROUP(dev,DEV_MC_STATIC))
                {
                    newState = state;
                }
                else
                {
                    newState = (GT_U32)GT_MC_STATIC;
                    retVal = GT_BAD_PARAM;
                }
                break;

            case GT_MC_PRIO_MGM_STATIC_UNLIMITED_RATE:
                if (IS_IN_DEV_GROUP(dev,DEV_MC_PRIO_MGM_STATIC_UNLIMITED_RATE))
                {
                    newState = state;
                }
                else
                {
                    newState = (GT_U32)GT_MC_STATIC;
                    retVal = GT_BAD_PARAM;
                }
                break;

            case GT_MC_PRIO_STATIC_UNLIMITED_RATE:
                if (IS_IN_DEV_GROUP(dev,DEV_MC_PRIO_STATIC_UNLIMITED_RATE))
                {
                    newState = state;
                }
                else
                {
                    newState = (GT_U32)GT_MC_STATIC;
                    retVal = GT_BAD_PARAM;
                }
                break;

            case GT_MC_PRIO_MGM_STATIC:
                if (IS_IN_DEV_GROUP(dev,DEV_MC_PRIO_MGM_STATIC))
                {
                    newState = state;
                }
                else
                {
                    newState = (GT_U32)GT_MC_STATIC;
                    retVal = GT_BAD_PARAM;
                }
                break;

            case GT_MC_PRIO_STATIC:
                if (IS_IN_DEV_GROUP(dev,DEV_MC_PRIO_STATIC))
                {
                    newState = state;
                }
                else
                {
                    newState = (GT_U32)GT_MC_STATIC;
                    retVal = GT_BAD_PARAM;
                }
                break;

            default:
                newState = (GT_U32)GT_MC_STATIC;
                retVal = GT_BAD_PARAM;
                break;

        }
    }
    
    *newOne = newState;
    return retVal;
}

static GT_STATUS atuStateDevToApp
(
    IN  GT_QD_DEV    *dev,
    IN  GT_BOOL        unicast,
    IN  GT_U32        state,
    OUT GT_U32        *newOne
)
{
    GT_U32    newState;
    GT_STATUS    retVal = GT_OK;

    if(unicast)
    {
        if (state == 0)
        {
            newState = (GT_U32)GT_UC_INVALID;
        }
        else if (state <= 7)
        {
            newState = (GT_U32)GT_UC_DYNAMIC;
        }
        else if ((state <= 0xE) && (!IS_IN_DEV_GROUP(dev,DEV_UC_7_DYNAMIC)))
        {
            newState = (GT_U32)GT_UC_DYNAMIC;
        }
        else
        {
            newState = state;
        }
    }
    else
    {
        newState = state;
    }

    *newOne = newState;
    return retVal;
}


static GT_STATUS atuGetStats
(
    IN  GT_QD_DEV    *dev,
    IN  GT_ATU_STAT    *atuStat,
    OUT GT_U32        *count
)
{
    GT_U32          numOfEntries, dbNum;
    GT_ATU_ENTRY    entry;
    GT_U16            data,mode,bin;
    GT_STATUS       retVal;

    DBG_INFO(("atuGetStats Called.\n"));

    switch (atuStat->op)
    {
        case GT_ATU_STATS_ALL:
        case GT_ATU_STATS_NON_STATIC:
            dbNum = 0;
            break;
        case GT_ATU_STATS_ALL_FID:
        case GT_ATU_STATS_NON_STATIC_FID:
            dbNum = atuStat->DBNum;
            break;
        default:
            return GT_FALSE;
    }

    numOfEntries = 0;
    mode = atuStat->op;

    for(bin=0; bin<4; bin++)
    {    
        data = (bin << 14) | (mode << 12);

        retVal = hwWriteGlobal2Reg(dev, QD_REG_ATU_STATS, data);
           if(retVal != GT_OK)
        {
               DBG_INFO(("Failed.\n"));
               return retVal;
        }
        
        entry.DBNum = (GT_U16)dbNum;
        gtMemSet(entry.macAddr.arEther,0,sizeof(GT_ETHERADDR));

        retVal = atuOperationPerform(dev,GET_NEXT_ENTRY,NULL,&entry);
           if(retVal == GT_FAIL)
        {
               DBG_INFO(("Failed.\n"));
               return retVal;
        }

        retVal = hwReadGlobal2Reg(dev, QD_REG_ATU_STATS, &data);
           if(retVal != GT_OK)
        {
               DBG_INFO(("Failed.\n"));
               return retVal;
        }
        
        numOfEntries += (data & 0xFFF);
    }

    *count = numOfEntries;

    return GT_OK;
}

