Logo Search packages:      
Sourcecode: u-boot-linaro version File versions  Download package

IxEthAccMac.c

Go to the documentation of this file.
/**
 * @file IxEthAccMac.c
 *
 * @author Intel Corporation
 * @date
 *
 * @brief  MAC control functions
 *
 * Design Notes:
 *
 * @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 --
 */

#include "IxOsal.h"
#include "IxNpeMh.h"
#ifdef CONFIG_IXP425_COMPONENT_ETHDB
#include "IxEthDB.h"
#endif
#include "IxEthDBPortDefs.h"
#include "IxEthNpe.h"
#include "IxEthAcc.h"
#include "IxEthAccDataPlane_p.h"
#include "IxEthAcc_p.h"
#include "IxEthAccMac_p.h"

/* Maximum number of retries during ixEthAccPortDisable, which
 * is approximately 10 seconds
*/
#define IX_ETH_ACC_MAX_RETRY 500

/* Maximum number of retries during ixEthAccPortDisable when expecting
 * timeout
 */
#define IX_ETH_ACC_MAX_RETRY_TIMEOUT 5

#define IX_ETH_ACC_VALIDATE_PORT_ID(portId) \
    do                                                           \
    {                                                            \
        if(!IX_ETH_ACC_IS_PORT_VALID(portId))   \
        {                                                        \
          return IX_ETH_ACC_INVALID_PORT;                      \
        }                                                        \
    } while(0)

PUBLIC IxEthAccMacState ixEthAccMacState[IX_ETH_ACC_NUMBER_OF_PORTS];

PRIVATE UINT32 ixEthAccMacBase[IX_ETH_ACC_NUMBER_OF_PORTS];

/*Forward function declarations*/
PRIVATE void
ixEthAccPortDisableRx (IxEthAccPortId portId,
                   IX_OSAL_MBUF * mBufPtr,
                   BOOL useMultiBufferCallback);

PRIVATE void
ixEthAccPortDisableRxAndReplenish (IxEthAccPortId portId,
                           IX_OSAL_MBUF * mBufPtr,
                           BOOL useMultiBufferCallback);

PRIVATE void
ixEthAccPortDisableTxDone (UINT32 cbTag,
                     IX_OSAL_MBUF *mbuf);

PRIVATE void
ixEthAccPortDisableTxDoneAndSubmit (UINT32 cbTag,
                            IX_OSAL_MBUF *mbuf);

PRIVATE void
ixEthAccPortDisableRxCallback (UINT32 cbTag,
                         IX_OSAL_MBUF * mBufPtr,
                         UINT32 learnedPortId);

PRIVATE void
ixEthAccPortDisableMultiBufferRxCallback (UINT32 cbTag,
                                IX_OSAL_MBUF **mBufPtr);

PRIVATE IxEthAccStatus
ixEthAccPortDisableTryTransmit(UINT32 portId);

PRIVATE IxEthAccStatus
ixEthAccPortDisableTryReplenish(UINT32 portId);

PRIVATE IxEthAccStatus
ixEthAccPortMulticastMacAddressGet (IxEthAccPortId portId,
                            IxEthAccMacAddr *macAddr);

PRIVATE IxEthAccStatus
ixEthAccPortMulticastMacFilterGet (IxEthAccPortId portId,
                           IxEthAccMacAddr *macAddr);

PRIVATE void
ixEthAccMacNpeStatsMessageCallback (IxNpeMhNpeId npeId,
                            IxNpeMhMessage msg);

PRIVATE void
ixEthAccMacNpeStatsResetMessageCallback (IxNpeMhNpeId npeId,
                               IxNpeMhMessage msg);

PRIVATE void
ixEthAccNpeLoopbackMessageCallback (IxNpeMhNpeId npeId,
                            IxNpeMhMessage msg);

PRIVATE void
ixEthAccMulticastAddressSet(IxEthAccPortId portId);

PRIVATE BOOL
ixEthAccMacEqual(IxEthAccMacAddr *macAddr1,
             IxEthAccMacAddr *macAddr2);

PRIVATE void
ixEthAccMacPrint(IxEthAccMacAddr *m);

PRIVATE void
ixEthAccMacStateUpdate(IxEthAccPortId portId);

IxEthAccStatus
ixEthAccMacMemInit(void)
{
    ixEthAccMacBase[IX_ETH_PORT_1] =
      (UINT32) IX_OSAL_MEM_MAP(IX_ETH_ACC_MAC_0_BASE,
                         IX_OSAL_IXP400_ETHA_MAP_SIZE);
    ixEthAccMacBase[IX_ETH_PORT_2] =
      (UINT32) IX_OSAL_MEM_MAP(IX_ETH_ACC_MAC_1_BASE,
                         IX_OSAL_IXP400_ETHB_MAP_SIZE);
#ifdef __ixp46X
    ixEthAccMacBase[IX_ETH_PORT_3] =
      (UINT32) IX_OSAL_MEM_MAP(IX_ETH_ACC_MAC_2_BASE,
                         IX_OSAL_IXP400_ETH_NPEA_MAP_SIZE);
    if (ixEthAccMacBase[IX_ETH_PORT_3] == 0)
    {
      ixOsalLog(IX_OSAL_LOG_LVL_FATAL,
              IX_OSAL_LOG_DEV_STDOUT,
              "EthAcc: Could not map MAC I/O memory\n",
              0, 0, 0, 0, 0 ,0);

      return IX_ETH_ACC_FAIL;
    }
#endif

    if (ixEthAccMacBase[IX_ETH_PORT_1] == 0
      || ixEthAccMacBase[IX_ETH_PORT_2] == 0)
    {
      ixOsalLog(IX_OSAL_LOG_LVL_FATAL,
              IX_OSAL_LOG_DEV_STDOUT,
              "EthAcc: Could not map MAC I/O memory\n",
              0, 0, 0, 0, 0 ,0);

      return IX_ETH_ACC_FAIL;
    }

    return IX_ETH_ACC_SUCCESS;
}

void
ixEthAccMacUnload(void)
{
    IX_OSAL_MEM_UNMAP(ixEthAccMacBase[IX_ETH_PORT_1]);
    IX_OSAL_MEM_UNMAP(ixEthAccMacBase[IX_ETH_PORT_2]);
#ifdef __ixp46X
    IX_OSAL_MEM_UNMAP(ixEthAccMacBase[IX_ETH_PORT_3]);
    ixEthAccMacBase[IX_ETH_PORT_3] = 0;
#endif
    ixEthAccMacBase[IX_ETH_PORT_2] = 0;
    ixEthAccMacBase[IX_ETH_PORT_1] = 0;
}

IxEthAccStatus
ixEthAccPortEnablePriv(IxEthAccPortId portId)
{
    IX_ETH_ACC_VALIDATE_PORT_ID(portId);

    if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId))
    {
        IX_ETH_ACC_WARNING_LOG("EthAcc: Unavailable Eth %d: Cannot enable port.\n",(INT32)portId,0,0,0,0,0);
        return IX_ETH_ACC_SUCCESS ;
    }

    if (!IX_ETH_IS_PORT_INITIALIZED(portId))
    {
        printf("EthAcc: (Mac) cannot enable port %d, port not initialized\n", portId);
      return (IX_ETH_ACC_PORT_UNINITIALIZED);
    }

    if (ixEthAccPortData[portId].ixEthAccTxData.txBufferDoneCallbackFn == NULL)
    {
        /* TxDone callback not registered */
        printf("EthAcc: (Mac) cannot enable port %d, TxDone callback not registered\n", portId);
      return (IX_ETH_ACC_PORT_UNINITIALIZED);
    }

    if ((ixEthAccPortData[portId].ixEthAccRxData.rxCallbackFn == NULL)
      && (ixEthAccPortData[portId].ixEthAccRxData.rxMultiBufferCallbackFn == NULL))
    {
        /* Receive callback not registered */
        printf("EthAcc: (Mac) cannot enable port %d, Rx callback not registered\n", portId);
      return (IX_ETH_ACC_PORT_UNINITIALIZED);
    }

    if(!ixEthAccMacState[portId].initDone)
    {
        printf("EthAcc: (Mac) cannot enable port %d, MAC address not set\n", portId);
      return (IX_ETH_ACC_MAC_UNINITIALIZED);
    }

    /* if the state is being set to what it is already at, do nothing*/
    if (ixEthAccMacState[portId].enabled)
    {
        return IX_ETH_ACC_SUCCESS;
    }

#ifdef CONFIG_IXP425_COMPONENT_ETHDB
    /* enable ethernet database for this port */
    if (ixEthDBPortEnable(portId) != IX_ETH_DB_SUCCESS)
    {
        printf("EthAcc: (Mac) cannot enable port %d, EthDB failure\n", portId);
        return IX_ETH_ACC_FAIL;
    }
#endif

    /* set the MAC core registers */
    REG_WRITE(ixEthAccMacBase[portId],
            IX_ETH_ACC_MAC_TX_CNTRL2,
            IX_ETH_ACC_TX_CNTRL2_RETRIES_MASK);

    REG_WRITE(ixEthAccMacBase[portId],
            IX_ETH_ACC_MAC_RANDOM_SEED,
            IX_ETH_ACC_RANDOM_SEED_DEFAULT);

    REG_WRITE(ixEthAccMacBase[portId],
            IX_ETH_ACC_MAC_THRESH_P_EMPTY,
            IX_ETH_ACC_MAC_THRESH_P_EMPTY_DEFAULT);

    REG_WRITE(ixEthAccMacBase[portId],
            IX_ETH_ACC_MAC_THRESH_P_FULL,
            IX_ETH_ACC_MAC_THRESH_P_FULL_DEFAULT);

    REG_WRITE(ixEthAccMacBase[portId],
            IX_ETH_ACC_MAC_TX_DEFER,
            IX_ETH_ACC_MAC_TX_DEFER_DEFAULT);

    REG_WRITE(ixEthAccMacBase[portId],
            IX_ETH_ACC_MAC_TX_TWO_DEFER_1,
            IX_ETH_ACC_MAC_TX_TWO_DEFER_1_DEFAULT);

    REG_WRITE(ixEthAccMacBase[portId],
            IX_ETH_ACC_MAC_TX_TWO_DEFER_2,
            IX_ETH_ACC_MAC_TX_TWO_DEFER_2_DEFAULT);

    REG_WRITE(ixEthAccMacBase[portId],
            IX_ETH_ACC_MAC_SLOT_TIME,
            IX_ETH_ACC_MAC_SLOT_TIME_DEFAULT);

    REG_WRITE(ixEthAccMacBase[portId],
            IX_ETH_ACC_MAC_INT_CLK_THRESH,
            IX_ETH_ACC_MAC_INT_CLK_THRESH_DEFAULT);

    REG_WRITE(ixEthAccMacBase[portId],
            IX_ETH_ACC_MAC_BUF_SIZE_TX,
            IX_ETH_ACC_MAC_BUF_SIZE_TX_DEFAULT);

    REG_WRITE(ixEthAccMacBase[portId],
            IX_ETH_ACC_MAC_TX_CNTRL1,
            IX_ETH_ACC_TX_CNTRL1_DEFAULT);

    REG_WRITE(ixEthAccMacBase[portId],
            IX_ETH_ACC_MAC_RX_CNTRL1,
            IX_ETH_ACC_RX_CNTRL1_DEFAULT);

    /* set the global state */
    ixEthAccMacState[portId].portDisableState = ACTIVE;
    ixEthAccMacState[portId].enabled = TRUE;

    /* rewrite the setup (including mac filtering) depending
     * on current options
     */
    ixEthAccMacStateUpdate(portId);

    return IX_ETH_ACC_SUCCESS;
}

/*
 * PortDisable local variables. They contain the intermediate steps
 * while the port is being disabled and the buffers being drained out
 * of the NPE.
 */
typedef void (*IxEthAccPortDisableRx)(IxEthAccPortId portId,
                              IX_OSAL_MBUF * mBufPtr,
                              BOOL useMultiBufferCallback);
static IxEthAccPortRxCallback
ixEthAccPortDisableFn[IX_ETH_ACC_NUMBER_OF_PORTS];
static IxEthAccPortMultiBufferRxCallback
ixEthAccPortDisableMultiBufferFn[IX_ETH_ACC_NUMBER_OF_PORTS];
static IxEthAccPortDisableRx
ixEthAccPortDisableRxTable[IX_ETH_ACC_NUMBER_OF_PORTS];
static UINT32
ixEthAccPortDisableCbTag[IX_ETH_ACC_NUMBER_OF_PORTS];
static UINT32
ixEthAccPortDisableMultiBufferCbTag[IX_ETH_ACC_NUMBER_OF_PORTS];

static IxEthAccPortTxDoneCallback
ixEthAccPortDisableTxDoneFn[IX_ETH_ACC_NUMBER_OF_PORTS];
static UINT32
ixEthAccPortDisableTxDoneCbTag[IX_ETH_ACC_NUMBER_OF_PORTS];

static UINT32
ixEthAccPortDisableUserBufferCount[IX_ETH_ACC_NUMBER_OF_PORTS];

/*
 * PortDisable private callbacks functions. They handle the user
 * traffic, and the special buffers (one for tx, one for rx) used
 * in portDisable.
 */
PRIVATE void
ixEthAccPortDisableTxDone(UINT32 cbTag,
                    IX_OSAL_MBUF *mbuf)
{
    IxEthAccPortId portId = (IxEthAccPortId)cbTag;
    volatile IxEthAccPortDisableState *txState = &ixEthAccMacState[portId].txState;

    /* check for the special mbuf used in portDisable */
    if (mbuf == ixEthAccMacState[portId].portDisableTxMbufPtr)
    {
        *txState = TRANSMIT_DONE;
    }
    else
    {
      /* increment the count of user traffic during portDisable */
      ixEthAccPortDisableUserBufferCount[portId]++;

       /* call client TxDone function */
        ixEthAccPortDisableTxDoneFn[portId](ixEthAccPortDisableTxDoneCbTag[portId], mbuf);
    }
}

PRIVATE IxEthAccStatus
ixEthAccPortDisableTryTransmit(UINT32 portId)
{
    int key;
    IxEthAccStatus status = IX_ETH_ACC_SUCCESS;
    volatile IxEthAccPortDisableState *txState = &ixEthAccMacState[portId].txState;
    /* transmit the special buffer again if it is transmitted
     * and update the txState
     * This section is protected because the portDisable context
     * run an identical code, so the system keeps transmitting at the
     * maximum rate.
     */
    key = ixOsalIrqLock();
    if (*txState == TRANSMIT_DONE)
    {
      IX_OSAL_MBUF *mbufTxPtr = ixEthAccMacState[portId].portDisableTxMbufPtr;
      *txState = TRANSMIT;
      status = ixEthAccPortTxFrameSubmit(portId,
                                 mbufTxPtr,
                                 IX_ETH_ACC_TX_DEFAULT_PRIORITY);
    }
    ixOsalIrqUnlock(key);

    return status;
}

PRIVATE void
ixEthAccPortDisableTxDoneAndSubmit(UINT32 cbTag,
                           IX_OSAL_MBUF *mbuf)
{
    IxEthAccPortId portId = (IxEthAccPortId)cbTag;

    /* call the callback which forwards the traffic to the client */
    ixEthAccPortDisableTxDone(cbTag, mbuf);

    /* try to transmit the buffer used in portDisable
     * if seen in TxDone
     */
    ixEthAccPortDisableTryTransmit(portId);
}

PRIVATE void
ixEthAccPortDisableRx (IxEthAccPortId portId,
                   IX_OSAL_MBUF * mBufPtr,
                   BOOL useMultiBufferCallback)
{
    volatile IxEthAccPortDisableState *rxState = &ixEthAccMacState[portId].rxState;
    IX_OSAL_MBUF *mNextPtr;

    while (mBufPtr)
    {
      mNextPtr = IX_OSAL_MBUF_NEXT_BUFFER_IN_PKT_PTR(mBufPtr);
      IX_OSAL_MBUF_NEXT_BUFFER_IN_PKT_PTR(mBufPtr) = NULL;

      /* check for the special mbuf used in portDisable */
      if (mBufPtr == ixEthAccMacState[portId].portDisableRxMbufPtr)
      {
            *rxState = RECEIVE;
      }
      else
      {
          /* increment the count of user traffic during portDisable */
          ixEthAccPortDisableUserBufferCount[portId]++;

          /* reset the received payload length during portDisable */
          IX_OSAL_MBUF_MLEN(mBufPtr)    = 0;
          IX_OSAL_MBUF_PKT_LEN(mBufPtr) = 0;

          if (useMultiBufferCallback)
          {
            /* call the user callback with one unchained
             * buffer, without payload. A small array is built
             * to be used as a parameter (the user callback expects
             * to receive an array ended by a NULL pointer.
             */
            IX_OSAL_MBUF *mBufPtrArray[2];

            mBufPtrArray[0] = mBufPtr;
            mBufPtrArray[1] = NULL;
            ixEthAccPortDisableMultiBufferFn[portId](
                   ixEthAccPortDisableMultiBufferCbTag[portId],
                   mBufPtrArray);
          }
          else
          {
            /* call the user callback with a unchained
             * buffer, without payload and the destination port is
             * unknown.
             */
            ixEthAccPortDisableFn[portId](
                  ixEthAccPortDisableCbTag[portId],
                  mBufPtr,
                  IX_ETH_DB_UNKNOWN_PORT /* port not found */);
          }
        }

        mBufPtr = mNextPtr;
    }
}

PRIVATE IxEthAccStatus
ixEthAccPortDisableTryReplenish(UINT32 portId)
{
    int key;
    IxEthAccStatus status = IX_ETH_ACC_SUCCESS;
    volatile IxEthAccPortDisableState *rxState = &ixEthAccMacState[portId].rxState;
    /* replenish with the special buffer again if it is received
     * and update the rxState
     * This section is protected because the portDisable context
     * run an identical code, so the system keeps replenishing at the
     * maximum rate.
     */
    key = ixOsalIrqLock();
    if (*rxState == RECEIVE)
    {
      IX_OSAL_MBUF *mbufRxPtr = ixEthAccMacState[portId].portDisableRxMbufPtr;
      *rxState = REPLENISH;
      IX_OSAL_MBUF_MLEN(mbufRxPtr) = IX_ETHACC_RX_MBUF_MIN_SIZE;
      status = ixEthAccPortRxFreeReplenish(portId, mbufRxPtr);
    }
    ixOsalIrqUnlock(key);

    return status;
}

PRIVATE void
ixEthAccPortDisableRxAndReplenish (IxEthAccPortId portId,
                           IX_OSAL_MBUF * mBufPtr,
                           BOOL useMultiBufferCallback)
{
    /* call the callback which forwards the traffic to the client */
    ixEthAccPortDisableRx(portId, mBufPtr, useMultiBufferCallback);

    /* try to replenish with the buffer used in portDisable
     * if seen in Rx
     */
    ixEthAccPortDisableTryReplenish(portId);
}

PRIVATE void
ixEthAccPortDisableRxCallback (UINT32 cbTag,
                         IX_OSAL_MBUF * mBufPtr,
                         UINT32 learnedPortId)
{
    IxEthAccPortId portId = (IxEthAccPortId)cbTag;

    /* call the portDisable receive callback */
   (ixEthAccPortDisableRxTable[portId])(portId, mBufPtr, FALSE);
}

PRIVATE void
ixEthAccPortDisableMultiBufferRxCallback (UINT32 cbTag,
                                IX_OSAL_MBUF **mBufPtr)
{
    IxEthAccPortId portId = (IxEthAccPortId)cbTag;

    while (*mBufPtr)
    {
      /* call the portDisable receive callback with one buffer at a time */
      (ixEthAccPortDisableRxTable[portId])(portId, *mBufPtr++, TRUE);
    }
}

IxEthAccStatus
ixEthAccPortDisablePriv(IxEthAccPortId portId)
{
    IxEthAccStatus status = IX_ETH_ACC_SUCCESS;
    int key;
    int retry, retryTimeout;
    volatile IxEthAccPortDisableState *state = &ixEthAccMacState[portId].portDisableState;
    volatile IxEthAccPortDisableState *rxState = &ixEthAccMacState[portId].rxState;
    volatile IxEthAccPortDisableState *txState = &ixEthAccMacState[portId].txState;

    IX_ETH_ACC_VALIDATE_PORT_ID(portId);

    if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId))
    {
        IX_ETH_ACC_WARNING_LOG("EthAcc: Unavailable Eth %d: Cannot disable port.\n",(INT32)portId,0,0,0,0,0);
        return IX_ETH_ACC_SUCCESS ;
    }

    if (!IX_ETH_IS_PORT_INITIALIZED(portId))
    {
      return (IX_ETH_ACC_PORT_UNINITIALIZED);
    }

    /* if the state is being set to what it is already at, do nothing */
    if (!ixEthAccMacState[portId].enabled)
    {
        return IX_ETH_ACC_SUCCESS;
    }

    *state = DISABLED;

    /* disable MAC receive first */
    ixEthAccPortRxDisablePriv(portId);

#ifdef CONFIG_IXP425_COMPONENT_ETHDB
    /* disable ethernet database for this port - It is done now to avoid
     * issuing ELT maintenance after requesting 'port disable' in an NPE
     */
    if (ixEthDBPortDisable(portId) != IX_ETH_DB_SUCCESS)
    {
      status = IX_ETH_ACC_FAIL;
        IX_ETH_ACC_FATAL_LOG("ixEthAccPortDisable: failed to disable EthDB for this port\n", 0, 0, 0, 0, 0, 0);
    }
#endif

    /* enter the critical section */
    key = ixOsalIrqLock();

    /* swap the Rx and TxDone callbacks */
    ixEthAccPortDisableFn[portId]            = ixEthAccPortData[portId].ixEthAccRxData.rxCallbackFn;
    ixEthAccPortDisableMultiBufferFn[portId] = ixEthAccPortData[portId].ixEthAccRxData.rxMultiBufferCallbackFn;
    ixEthAccPortDisableCbTag[portId]         = ixEthAccPortData[portId].ixEthAccRxData.rxCallbackTag;
    ixEthAccPortDisableMultiBufferCbTag[portId] = ixEthAccPortData[portId].ixEthAccRxData.rxMultiBufferCallbackTag;
    ixEthAccPortDisableTxDoneFn[portId]      = ixEthAccPortData[portId].ixEthAccTxData.txBufferDoneCallbackFn;
    ixEthAccPortDisableTxDoneCbTag[portId]   = ixEthAccPortData[portId].ixEthAccTxData.txCallbackTag;
    ixEthAccPortDisableRxTable[portId]       =  ixEthAccPortDisableRx;

    /* register temporary callbacks */
    ixEthAccPortData[portId].ixEthAccRxData.rxCallbackFn            = ixEthAccPortDisableRxCallback;
    ixEthAccPortData[portId].ixEthAccRxData.rxCallbackTag           = portId;

    ixEthAccPortData[portId].ixEthAccRxData.rxMultiBufferCallbackFn = ixEthAccPortDisableMultiBufferRxCallback;
    ixEthAccPortData[portId].ixEthAccRxData.rxMultiBufferCallbackTag = portId;

    ixEthAccPortData[portId].ixEthAccTxData.txBufferDoneCallbackFn  = ixEthAccPortDisableTxDone;
    ixEthAccPortData[portId].ixEthAccTxData.txCallbackTag           = portId;

    /* initialise the Rx state and Tx states */
    *txState = TRANSMIT_DONE;
    *rxState = RECEIVE;

    /* exit the critical section */
    ixOsalIrqUnlock(key);

    /* enable a NPE loopback */
    if (ixEthAccNpeLoopbackEnablePriv(portId) != IX_ETH_ACC_SUCCESS)
    {
      status = IX_ETH_ACC_FAIL;
    }

    if (status == IX_ETH_ACC_SUCCESS)
    {
      retry = 0;

      /* Step 1 : Drain Tx traffic and TxDone queues :
       *
       * Transmit and replenish at least once with the
       * special buffers until both of them are seen
       * in the callback hook
       *
       * (the receive callback keeps replenishing, so once we see
       * the special Tx buffer, we can be sure that Tx drain is complete)
       */
      ixEthAccPortDisableRxTable[portId]
          =  ixEthAccPortDisableRxAndReplenish;
      ixEthAccPortData[portId].ixEthAccTxData.txBufferDoneCallbackFn
          = ixEthAccPortDisableTxDone;

      do
      {
          /* keep replenishing */
          status = ixEthAccPortDisableTryReplenish(portId);
          if (status == IX_ETH_ACC_SUCCESS)
          {
            /* keep transmitting */
            status = ixEthAccPortDisableTryTransmit(portId);
          }
          if (status == IX_ETH_ACC_SUCCESS)
          {
            /* wait for some traffic being processed */
            ixOsalSleep(IX_ETH_ACC_PORT_DISABLE_DELAY_MSECS);
          }
      }
      while ((status == IX_ETH_ACC_SUCCESS)
             && (retry++ < IX_ETH_ACC_MAX_RETRY)
             && (*txState == TRANSMIT));

      /* Step 2 : Drain Rx traffic, RxFree and Rx queues :
       *
       * Transmit and replenish at least once with the
       * special buffers until both of them are seen
       * in the callback hook
       * (the transmit callback keeps transmitting, and when we see
       * the special Rx buffer, we can be sure that rxFree drain
       * is complete)
       *
       * The nested loop helps to retry if the user was keeping
       * replenishing or transmitting during portDisable.
       *
       * The 2 nested loops ensure more retries if user traffic is
       * seen during portDisable : the user should not replenish
       * or transmit while portDisable is running. However, because of
       * the queueing possibilities in ethAcc dataplane, it is possible
       * that a lot of traffic is left in the queues (e.g. when
       * transmitting over a low speed link) and therefore, more
       * retries are allowed to help flushing the buffers out.
       */
      ixEthAccPortDisableRxTable[portId]
          =  ixEthAccPortDisableRx;
      ixEthAccPortData[portId].ixEthAccTxData.txBufferDoneCallbackFn
          = ixEthAccPortDisableTxDoneAndSubmit;

      do
      {
          do
          {
            ixEthAccPortDisableUserBufferCount[portId] = 0;

            /* keep replenishing */
            status = ixEthAccPortDisableTryReplenish(portId);
            if (status == IX_ETH_ACC_SUCCESS)
            {
                /* keep transmitting */
                status = ixEthAccPortDisableTryTransmit(portId);
            }
            if (status == IX_ETH_ACC_SUCCESS)
            {
                /* wait for some traffic being processed */
                ixOsalSleep(IX_ETH_ACC_PORT_DISABLE_DELAY_MSECS);
            }
          }
          while ((status == IX_ETH_ACC_SUCCESS)
               && (retry++ < IX_ETH_ACC_MAX_RETRY)
               && ((ixEthAccPortDisableUserBufferCount[portId] != 0)
                   || (*rxState == REPLENISH)));

          /* After the first iteration, change the receive callbacks,
           * to process only 1 buffer at a time
           */
          ixEthAccPortDisableRxTable[portId]
            = ixEthAccPortDisableRx;
          ixEthAccPortData[portId].ixEthAccTxData.txBufferDoneCallbackFn
            = ixEthAccPortDisableTxDone;

          /* repeat the whole process while user traffic is seen in TxDone
           *
           * The conditions to stop the loop are
           * - Xscale has both Rx and Tx special buffers
           *   (txState = transmit, rxState = receive)
           * - any error in txSubmit or rxReplenish
           * - no user traffic seen
           * - an excessive amount of retries
           */
      }
      while ((status == IX_ETH_ACC_SUCCESS)
             && (retry < IX_ETH_ACC_MAX_RETRY)
             && (*txState == TRANSMIT));

      /* check the loop exit conditions. The NPE should not hold
       * the special buffers.
       */
      if ((*rxState == REPLENISH) || (*txState == TRANSMIT))
      {
          status = IX_ETH_ACC_FAIL;
      }

      if (status == IX_ETH_ACC_SUCCESS)
      {
          /* Step 3 : Replenish without transmitting until a timeout
           * occurs, in order to drain the internal NPE fifos
           *
           * we can expect a few frames srill held
           * in the NPE.
           *
           * The 2 nested loops take care about the NPE dropping traffic
           * (including loopback traffic) when the Rx queue is full.
           *
           * The timeout value is very conservative
           * since the loopback used keeps replenishhing.
           *
           */
          do
          {
            ixEthAccPortDisableRxTable[portId] = ixEthAccPortDisableRxAndReplenish;
            ixEthAccPortDisableUserBufferCount[portId] = 0;
            retryTimeout = 0;
            do
            {
                /* keep replenishing */
                status = ixEthAccPortDisableTryReplenish(portId);
                if (status == IX_ETH_ACC_SUCCESS)
                {
                  /* wait for some traffic being processed */
                  ixOsalSleep(IX_ETH_ACC_PORT_DISABLE_DELAY_MSECS);
                }
            }
            while ((status == IX_ETH_ACC_SUCCESS)
                   && (retryTimeout++ < IX_ETH_ACC_MAX_RETRY_TIMEOUT));

            /* Step 4 : Transmit once. Stop replenish
             *
             * After the Rx timeout, we are sure that the NPE does not
             * hold any frame in its internal NPE fifos.
             *
             * At this point, the NPE still holds the last rxFree buffer.
             * By transmitting a single frame, this should unblock the
             * last rxFree buffer. This code just transmit once and
             * wait for both frames seen in TxDone and in rxFree.
             *
             */
            ixEthAccPortDisableRxTable[portId] =  ixEthAccPortDisableRx;
            status = ixEthAccPortDisableTryTransmit(portId);

            /* the NPE should immediatelyt release
             * the last Rx buffer and the last transmitted buffer
             * unless the last Tx frame was dropped (rx queue full)
             */
            if (status == IX_ETH_ACC_SUCCESS)
            {
                retryTimeout = 0;
                do
                {
                  ixOsalSleep(IX_ETH_ACC_PORT_DISABLE_DELAY_MSECS);
                }
                while ((*rxState == REPLENISH)
                     && (retryTimeout++ < IX_ETH_ACC_MAX_RETRY_TIMEOUT));
            }

            /* the NPE may have dropped the traffic because of Rx
             * queue being full. This code ensures that the last
             * Tx and Rx frames are both received.
             */
          }
          while ((status == IX_ETH_ACC_SUCCESS)
               && (retry++ < IX_ETH_ACC_MAX_RETRY)
               && ((*txState == TRANSMIT)
                   || (*rxState == REPLENISH)
                   || (ixEthAccPortDisableUserBufferCount[portId] != 0)));

          /* Step 5 : check the final states : the NPE has
           * no buffer left, nor in Tx , nor in Rx directions.
           */
          if ((*rxState == REPLENISH) || (*txState == TRANSMIT))
          {
            status = IX_ETH_ACC_FAIL;
          }
      }

        /* now all the buffers are drained, disable NPE loopback
       * This is done regardless of the logic to drain the queues and
       * the internal buffers held by the NPE.
       */
      if (ixEthAccNpeLoopbackDisablePriv(portId) != IX_ETH_ACC_SUCCESS)
      {
          status = IX_ETH_ACC_FAIL;
      }
    }

    /* disable MAC Tx and Rx services */
    ixEthAccMacState[portId].enabled = FALSE;
    ixEthAccMacStateUpdate(portId);

    /* restore the Rx and TxDone callbacks (within a critical section) */
    key = ixOsalIrqLock();

    ixEthAccPortData[portId].ixEthAccRxData.rxCallbackFn            = ixEthAccPortDisableFn[portId];
    ixEthAccPortData[portId].ixEthAccRxData.rxCallbackTag           = ixEthAccPortDisableCbTag[portId];
    ixEthAccPortData[portId].ixEthAccRxData.rxMultiBufferCallbackFn = ixEthAccPortDisableMultiBufferFn[portId];
    ixEthAccPortData[portId].ixEthAccRxData.rxMultiBufferCallbackTag = ixEthAccPortDisableMultiBufferCbTag[portId];
    ixEthAccPortData[portId].ixEthAccTxData.txBufferDoneCallbackFn  = ixEthAccPortDisableTxDoneFn[portId];
    ixEthAccPortData[portId].ixEthAccTxData.txCallbackTag           = ixEthAccPortDisableTxDoneCbTag[portId];

    ixOsalIrqUnlock(key);

    /* the MAC core rx/tx disable may left the MAC hardware in an
     * unpredictable state. A hw reset is executed before resetting
     * all the MAC parameters to a known value.
     */
    REG_WRITE(ixEthAccMacBase[portId],
            IX_ETH_ACC_MAC_CORE_CNTRL,
            IX_ETH_ACC_CORE_RESET);

    ixOsalSleep(IX_ETH_ACC_MAC_RESET_DELAY);

    /* rewrite all parameters to their current value */
    ixEthAccMacStateUpdate(portId);

    REG_WRITE(ixEthAccMacBase[portId],
            IX_ETH_ACC_MAC_INT_CLK_THRESH,
            IX_ETH_ACC_MAC_INT_CLK_THRESH_DEFAULT);

    REG_WRITE(ixEthAccMacBase[portId],
            IX_ETH_ACC_MAC_CORE_CNTRL,
            IX_ETH_ACC_CORE_MDC_EN);

    return status;
}

IxEthAccStatus
ixEthAccPortEnabledQueryPriv(IxEthAccPortId portId, BOOL *enabled)
{
    IX_ETH_ACC_VALIDATE_PORT_ID(portId);

    if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId))
    {
        IX_ETH_ACC_WARNING_LOG("EthAcc: Unavailable Eth %d: Cannot enable port.\n",(INT32)portId,0,0,0,0,0);

        /* Since Eth NPE is not available, port must be disabled */
        *enabled = FALSE ;
        return IX_ETH_ACC_SUCCESS ;
    }

    if (!IX_ETH_IS_PORT_INITIALIZED(portId))
    {
        /* Since Eth NPE is not available, port must be disabled */
        *enabled = FALSE ;
      return (IX_ETH_ACC_PORT_UNINITIALIZED);
    }

    *enabled = ixEthAccMacState[portId].enabled;

    return IX_ETH_ACC_SUCCESS;
}

IxEthAccStatus
ixEthAccPortMacResetPriv(IxEthAccPortId portId)
{
    IX_ETH_ACC_VALIDATE_PORT_ID(portId);

    if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId))
    {
        IX_ETH_ACC_WARNING_LOG("EthAcc: Eth %d: Cannot reset Ethernet coprocessor.\n",(INT32)portId,0,0,0,0,0);
        return IX_ETH_ACC_SUCCESS ;
    }

    if (!IX_ETH_IS_PORT_INITIALIZED(portId))
    {
      return (IX_ETH_ACC_PORT_UNINITIALIZED);
    }

    REG_WRITE(ixEthAccMacBase[portId],
            IX_ETH_ACC_MAC_CORE_CNTRL,
            IX_ETH_ACC_CORE_RESET);

    ixOsalSleep(IX_ETH_ACC_MAC_RESET_DELAY);

    /* rewrite all parameters to their current value */
    ixEthAccMacStateUpdate(portId);

    REG_WRITE(ixEthAccMacBase[portId],
            IX_ETH_ACC_MAC_INT_CLK_THRESH,
            IX_ETH_ACC_MAC_INT_CLK_THRESH_DEFAULT);

    REG_WRITE(ixEthAccMacBase[portId],
            IX_ETH_ACC_MAC_CORE_CNTRL,
            IX_ETH_ACC_CORE_MDC_EN);

    return IX_ETH_ACC_SUCCESS;
}

IxEthAccStatus
ixEthAccPortLoopbackEnable(IxEthAccPortId portId)
{
    UINT32 regval;

    /* Turn off promiscuous mode */
    IX_ETH_ACC_VALIDATE_PORT_ID(portId);

    if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId))
    {
        IX_ETH_ACC_WARNING_LOG("EthAcc: Eth %d: Cannot enable loopback.\n",(INT32)portId,0,0,0,0,0);
        return IX_ETH_ACC_SUCCESS ;
    }

    if (!IX_ETH_IS_PORT_INITIALIZED(portId))
    {
      return (IX_ETH_ACC_PORT_UNINITIALIZED);
    }

    /* read register */
    REG_READ(ixEthAccMacBase[portId],
           IX_ETH_ACC_MAC_RX_CNTRL1,
           regval);

    /* update register */
    REG_WRITE(ixEthAccMacBase[portId],
            IX_ETH_ACC_MAC_RX_CNTRL1,
            regval | IX_ETH_ACC_RX_CNTRL1_LOOP_EN);

    return IX_ETH_ACC_SUCCESS;
}

PRIVATE void
ixEthAccNpeLoopbackMessageCallback (IxNpeMhNpeId npeId,
                            IxNpeMhMessage msg)
{
    IxEthAccPortId portId = IX_ETH_ACC_NPE_TO_PORT_ID(npeId);

#ifndef NDEBUG
    /* Prudent to at least check the port is within range */
    if (portId >= IX_ETH_ACC_NUMBER_OF_PORTS)
    {
      IX_ETH_ACC_FATAL_LOG("IXETHACC:ixEthAccPortDisableMessageCallback: Illegal port: %u\n",
            (UINT32) portId, 0, 0, 0, 0, 0);

      return;
    }
#endif

    /* unlock message reception mutex */
    ixOsalMutexUnlock(&ixEthAccMacState[portId].npeLoopbackMessageLock);
}

IxEthAccStatus
ixEthAccNpeLoopbackEnablePriv(IxEthAccPortId portId)
{
    IX_STATUS npeMhStatus;
    IxNpeMhMessage message;
    IxEthAccStatus status = IX_ETH_ACC_SUCCESS;

    /* Turn off promiscuous mode */
    IX_ETH_ACC_VALIDATE_PORT_ID(portId);

    if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId))
    {
        IX_ETH_ACC_WARNING_LOG("EthAcc: Eth %d: Cannot enable NPE loopback.\n",(INT32)portId,0,0,0,0,0);
        return IX_ETH_ACC_SUCCESS ;
    }

    if (!IX_ETH_IS_PORT_INITIALIZED(portId))
    {
      return (IX_ETH_ACC_PORT_UNINITIALIZED);
    }

    /* enable NPE loopback (lsb of the message contains the value 1) */
    message.data[0] = (IX_ETHNPE_SETLOOPBACK_MODE << IX_ETH_ACC_MAC_MSGID_SHL)
      | 0x01;
    message.data[1] = 0;

    npeMhStatus = ixNpeMhMessageWithResponseSend(IX_ETH_ACC_PORT_TO_NPE_ID(portId),
            message,
            IX_ETHNPE_SETLOOPBACK_MODE_ACK,
            ixEthAccNpeLoopbackMessageCallback,
            IX_NPEMH_SEND_RETRIES_DEFAULT);

    if (npeMhStatus != IX_SUCCESS)
    {
        status = IX_ETH_ACC_FAIL;
    }
    else
    {
      /* wait for NPE loopbackEnable response */
        if (ixOsalMutexLock(&ixEthAccMacState[portId]. npeLoopbackMessageLock,
                      IX_ETH_ACC_PORT_DISABLE_DELAY_MSECS)
          != IX_SUCCESS)
        {
            status = IX_ETH_ACC_FAIL;
        }
    }

    return status;
}

IxEthAccStatus
ixEthAccPortTxEnablePriv(IxEthAccPortId portId)
{
    UINT32 regval;

    /* Turn off promiscuous mode */
    IX_ETH_ACC_VALIDATE_PORT_ID(portId);

    if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId))
    {
        IX_ETH_ACC_WARNING_LOG("EthAcc: Eth %d: Cannot enable TX.\n",(INT32)portId,0,0,0,0,0);
        return IX_ETH_ACC_SUCCESS ;
    }

    if (!IX_ETH_IS_PORT_INITIALIZED(portId))
    {
      return (IX_ETH_ACC_PORT_UNINITIALIZED);
    }

    /* read register */
    REG_READ(ixEthAccMacBase[portId],
           IX_ETH_ACC_MAC_TX_CNTRL1,
           regval);

    /* update register */
    REG_WRITE(ixEthAccMacBase[portId],
            IX_ETH_ACC_MAC_TX_CNTRL1,
            regval | IX_ETH_ACC_TX_CNTRL1_TX_EN);

    return IX_ETH_ACC_SUCCESS;
}

IxEthAccStatus
ixEthAccPortRxEnablePriv(IxEthAccPortId portId)
{
    UINT32 regval;

    /* Turn off promiscuous mode */
    IX_ETH_ACC_VALIDATE_PORT_ID(portId);

    if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId))
    {
        IX_ETH_ACC_WARNING_LOG("EthAcc: Eth %d: Cannot enable RX.\n",(INT32)portId,0,0,0,0,0);
        return IX_ETH_ACC_SUCCESS ;
    }

    if (!IX_ETH_IS_PORT_INITIALIZED(portId))
    {
      return (IX_ETH_ACC_PORT_UNINITIALIZED);
    }

    /* read register */
    REG_READ(ixEthAccMacBase[portId],
           IX_ETH_ACC_MAC_RX_CNTRL1,
           regval);

    /* update register */
    REG_WRITE(ixEthAccMacBase[portId],
            IX_ETH_ACC_MAC_RX_CNTRL1,
            regval | IX_ETH_ACC_RX_CNTRL1_RX_EN);

    return IX_ETH_ACC_SUCCESS;
}

IxEthAccStatus
ixEthAccPortLoopbackDisable(IxEthAccPortId portId)
{
    UINT32 regval;

    IX_ETH_ACC_VALIDATE_PORT_ID(portId);

    if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId))
    {
        IX_ETH_ACC_WARNING_LOG("EthAcc: Eth %d: Cannot disable loopback.\n",(INT32)portId,0,0,0,0,0);
        return IX_ETH_ACC_SUCCESS ;
    }

    if (!IX_ETH_IS_PORT_INITIALIZED(portId))
    {
      return (IX_ETH_ACC_PORT_UNINITIALIZED);
    }

    /*disable MAC loopabck */
    REG_READ(ixEthAccMacBase[portId],
           IX_ETH_ACC_MAC_RX_CNTRL1,
           regval);

    REG_WRITE(ixEthAccMacBase[portId],
            IX_ETH_ACC_MAC_RX_CNTRL1,
            (regval & ~IX_ETH_ACC_RX_CNTRL1_LOOP_EN));

    return IX_ETH_ACC_SUCCESS;
}

IxEthAccStatus
ixEthAccNpeLoopbackDisablePriv(IxEthAccPortId portId)
{
    IX_STATUS npeMhStatus;
    IxNpeMhMessage message;
    IxEthAccStatus status = IX_ETH_ACC_SUCCESS;

    /* Turn off promiscuous mode */
    IX_ETH_ACC_VALIDATE_PORT_ID(portId);

    if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId))
    {
        IX_ETH_ACC_WARNING_LOG("EthAcc: Eth %d: Cannot enable NPE loopback.\n",(INT32)portId,0,0,0,0,0);
        return IX_ETH_ACC_SUCCESS ;
    }

    if (!IX_ETH_IS_PORT_INITIALIZED(portId))
    {
      return (IX_ETH_ACC_PORT_UNINITIALIZED);
    }

    /* disable NPE loopback (lsb of the message contains the value 0) */
    message.data[0] = (IX_ETHNPE_SETLOOPBACK_MODE << IX_ETH_ACC_MAC_MSGID_SHL);
    message.data[1] = 0;

    npeMhStatus = ixNpeMhMessageWithResponseSend(IX_ETH_ACC_PORT_TO_NPE_ID(portId),
            message,
            IX_ETHNPE_SETLOOPBACK_MODE_ACK,
            ixEthAccNpeLoopbackMessageCallback,
            IX_NPEMH_SEND_RETRIES_DEFAULT);

    if (npeMhStatus != IX_SUCCESS)
    {
        status = IX_ETH_ACC_FAIL;
    }
    else
    {
      /* wait for NPE loopbackEnable response */
        if (ixOsalMutexLock(&ixEthAccMacState[portId].npeLoopbackMessageLock,
                      IX_ETH_ACC_PORT_DISABLE_DELAY_MSECS)
          != IX_SUCCESS)
        {
            status = IX_ETH_ACC_FAIL;
        }
    }

    return status;
}

IxEthAccStatus
ixEthAccPortTxDisablePriv(IxEthAccPortId portId)
{
    UINT32 regval;

    /* Turn off promiscuous mode */
    IX_ETH_ACC_VALIDATE_PORT_ID(portId);

    if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId))
    {
        IX_ETH_ACC_WARNING_LOG("EthAcc: Eth %d: Cannot disable TX.\n", (INT32)portId,0,0,0,0,0);
        return IX_ETH_ACC_SUCCESS ;
    }

    if (!IX_ETH_IS_PORT_INITIALIZED(portId))
    {
      return (IX_ETH_ACC_PORT_UNINITIALIZED);
    }

    /* read register */
    REG_READ(ixEthAccMacBase[portId],
           IX_ETH_ACC_MAC_TX_CNTRL1,
           regval);

    /* update register */
    REG_WRITE(ixEthAccMacBase[portId],
            IX_ETH_ACC_MAC_TX_CNTRL1,
            (regval & ~IX_ETH_ACC_TX_CNTRL1_TX_EN));

    return IX_ETH_ACC_SUCCESS;
}

IxEthAccStatus
ixEthAccPortRxDisablePriv(IxEthAccPortId portId)
{
    UINT32 regval;

    /* Turn off promiscuous mode */
    IX_ETH_ACC_VALIDATE_PORT_ID(portId);

    if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId))
    {
        IX_ETH_ACC_WARNING_LOG("EthAcc: Eth %d: Cannot disable RX.\n", (INT32)portId,0,0,0,0,0);
        return IX_ETH_ACC_SUCCESS ;
    }

    if (!IX_ETH_IS_PORT_INITIALIZED(portId))
    {
      return (IX_ETH_ACC_PORT_UNINITIALIZED);
    }

    /* read register */
    REG_READ(ixEthAccMacBase[portId],
           IX_ETH_ACC_MAC_RX_CNTRL1,
           regval);

    /* update register */
    REG_WRITE(ixEthAccMacBase[portId],
            IX_ETH_ACC_MAC_RX_CNTRL1,
            (regval & ~IX_ETH_ACC_RX_CNTRL1_RX_EN));

    return IX_ETH_ACC_SUCCESS;
}

IxEthAccStatus
ixEthAccPortPromiscuousModeClearPriv(IxEthAccPortId portId)
{
    UINT32 regval;

    /* Turn off promiscuous mode */
    IX_ETH_ACC_VALIDATE_PORT_ID(portId);

    if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId))
    {
        IX_ETH_ACC_WARNING_LOG("EthAcc: Unavailable Eth %d: Cannot clear promiscuous mode.\n",(INT32)portId,0,0,0,0,0);
        return IX_ETH_ACC_SUCCESS ;
    }

    if (!IX_ETH_IS_PORT_INITIALIZED(portId))
    {
      return (IX_ETH_ACC_PORT_UNINITIALIZED);
    }

    /*set bit 5 of Rx control 1 - enable address filtering*/
    REG_READ(ixEthAccMacBase[portId],
           IX_ETH_ACC_MAC_RX_CNTRL1,
           regval);

    REG_WRITE(ixEthAccMacBase[portId],
            IX_ETH_ACC_MAC_RX_CNTRL1,
            regval | IX_ETH_ACC_RX_CNTRL1_ADDR_FLTR_EN);

    ixEthAccMacState[portId].promiscuous = FALSE;

    ixEthAccMulticastAddressSet(portId);

    return IX_ETH_ACC_SUCCESS;
}

IxEthAccStatus
ixEthAccPortPromiscuousModeSetPriv(IxEthAccPortId portId)
{
    UINT32 regval;

    IX_ETH_ACC_VALIDATE_PORT_ID(portId);

    if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId))
    {
        IX_ETH_ACC_WARNING_LOG("EthAcc: Unavailable Eth %d: Cannot set promiscuous mode.\n",(INT32)portId,0,0,0,0,0);
        return IX_ETH_ACC_SUCCESS ;
    }

    if (!IX_ETH_IS_PORT_INITIALIZED(portId))
    {
      return (IX_ETH_ACC_PORT_UNINITIALIZED);
    }

    /*
     * Set bit 5 of Rx control 1 - We enable address filtering even in
     * promiscuous mode because we want the MAC to set the appropriate
     * bits in m_flags which doesn't happen if we turn off filtering.
     */
    REG_READ(ixEthAccMacBase[portId],
           IX_ETH_ACC_MAC_RX_CNTRL1,
           regval);

    REG_WRITE(ixEthAccMacBase[portId],
            IX_ETH_ACC_MAC_RX_CNTRL1,
            regval | IX_ETH_ACC_RX_CNTRL1_ADDR_FLTR_EN);

    ixEthAccMacState[portId].promiscuous = TRUE;

    ixEthAccMulticastAddressSet(portId);

    return IX_ETH_ACC_SUCCESS;
}

IxEthAccStatus
ixEthAccPortUnicastMacAddressSetPriv (IxEthAccPortId portId,
                          IxEthAccMacAddr *macAddr)
{
    UINT32 i;

    IX_ETH_ACC_VALIDATE_PORT_ID(portId);

    if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId))
    {
        IX_ETH_ACC_WARNING_LOG("EthAcc: Unavailable Eth %d: Cannot set Unicast Mac Address.\n",(INT32)portId,0,0,0,0,0);
        return IX_ETH_ACC_SUCCESS ;
    }

    if (!IX_ETH_IS_PORT_INITIALIZED(portId))
    {
      return (IX_ETH_ACC_PORT_UNINITIALIZED);
    }


    if (macAddr == NULL)
    {
      return IX_ETH_ACC_FAIL;
    }

    if ( macAddr->macAddress[0] & IX_ETH_ACC_ETH_MAC_BCAST_MCAST_BIT )
    {
      /* This is a multicast/broadcast address cant set it ! */
      return IX_ETH_ACC_FAIL;
    }

    if ( macAddr->macAddress[0] == 0 &&
       macAddr->macAddress[1] == 0 &&
       macAddr->macAddress[2] == 0 &&
       macAddr->macAddress[3] == 0 &&
       macAddr->macAddress[4] == 0 &&
       macAddr->macAddress[5] == 0  )
    {
      /* This is an invalid mac address cant set it ! */
      return IX_ETH_ACC_FAIL;
    }

#ifdef CONFIG_IXP425_COMPONENT_ETHDB
    /* update the MAC address in the ethernet database */
    if (ixEthDBPortAddressSet(portId, (IxEthDBMacAddr *) macAddr) != IX_ETH_DB_SUCCESS)
    {
        return IX_ETH_ACC_FAIL;
    }
#endif

    /*Set the Unicast MAC to the specified value*/
    for(i=0;i<IX_IEEE803_MAC_ADDRESS_SIZE;i++)
    {
      REG_WRITE(ixEthAccMacBase[portId],
              IX_ETH_ACC_MAC_UNI_ADDR_1 + i*sizeof(UINT32),
              macAddr->macAddress[i]);
    }
    ixEthAccMacState[portId].initDone = TRUE;

    return IX_ETH_ACC_SUCCESS;
}

IxEthAccStatus
ixEthAccPortUnicastMacAddressGetPriv (IxEthAccPortId portId,
                          IxEthAccMacAddr *macAddr)
{
    /*Return the current value of the Unicast MAC from h/w
      for the specified port*/
    UINT32 i;

    IX_ETH_ACC_VALIDATE_PORT_ID(portId);

    if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId))
    {
        IX_ETH_ACC_WARNING_LOG("EthAcc: Unavailable Eth %d: Cannot get Unicast Mac Address.\n",(INT32)portId,0,0,0,0,0);
        /* Since Eth Npe is unavailable, return invalid MAC Address = 00:00:00:00:00:00 */
        for(i=0;i<IX_IEEE803_MAC_ADDRESS_SIZE;i++)
        {
          macAddr->macAddress[i] = 0;
        }
        return IX_ETH_ACC_SUCCESS ;
    }

    if(!ixEthAccMacState[portId].initDone)
    {
      return (IX_ETH_ACC_MAC_UNINITIALIZED);
    }

    if (macAddr == NULL)
    {
      return IX_ETH_ACC_FAIL;
    }


    for(i=0;i<IX_IEEE803_MAC_ADDRESS_SIZE;i++)
    {
      REG_READ(ixEthAccMacBase[portId],
             IX_ETH_ACC_MAC_UNI_ADDR_1 + i*sizeof(UINT32),
             macAddr->macAddress[i]);
    }
    return IX_ETH_ACC_SUCCESS;
}

PRIVATE IxEthAccStatus
ixEthAccPortMulticastMacAddressGet (IxEthAccPortId portId,
                            IxEthAccMacAddr *macAddr)
{
    /*Return the current value of the Multicast MAC from h/w
      for the specified port*/
    UINT32 i;

    for(i=0;i<IX_IEEE803_MAC_ADDRESS_SIZE;i++)
    {

      REG_READ(ixEthAccMacBase[portId],
             IX_ETH_ACC_MAC_ADDR_1 + i*sizeof(UINT32),
             macAddr->macAddress[i]);
    }

    return IX_ETH_ACC_SUCCESS;
}

PRIVATE IxEthAccStatus
ixEthAccPortMulticastMacFilterGet (IxEthAccPortId portId,
                           IxEthAccMacAddr *macAddr)
{
    /*Return the current value of the Multicast MAC from h/w
      for the specified port*/
    UINT32 i;

    for(i=0;i<IX_IEEE803_MAC_ADDRESS_SIZE;i++)
    {

      REG_READ(ixEthAccMacBase[portId],
             IX_ETH_ACC_MAC_ADDR_MASK_1 + i*sizeof(UINT32),
             macAddr->macAddress[i]);
    }
    return IX_ETH_ACC_SUCCESS;
}

IxEthAccStatus
ixEthAccPortMulticastAddressJoinPriv (IxEthAccPortId portId,
                          IxEthAccMacAddr *macAddr)
{
    UINT32 i;
    IxEthAccMacAddr broadcastAddr = {{0xff,0xff,0xff,0xff,0xff,0xff}};

    /*Check that the port parameter is valid*/
    IX_ETH_ACC_VALIDATE_PORT_ID(portId);

    if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId))
    {
        IX_ETH_ACC_WARNING_LOG("EthAcc: Unavailable Eth %d: Cannot join Multicast Mac Address.\n",(INT32)portId,0,0,0,0,0);
        return IX_ETH_ACC_SUCCESS ;
    }

    if (!IX_ETH_IS_PORT_INITIALIZED(portId))
    {
      return (IX_ETH_ACC_PORT_UNINITIALIZED);
    }

    /*Check that the mac address is valid*/
    if(macAddr == NULL)
    {
      return IX_ETH_ACC_FAIL;
    }

    /* Check that this is a multicast address */
    if (!(macAddr->macAddress[0] & IX_ETH_ACC_ETH_MAC_BCAST_MCAST_BIT))
    {
      return IX_ETH_ACC_FAIL;
    }

    /* We don't add the Broadcast address */
    if(ixEthAccMacEqual(&broadcastAddr, macAddr))
    {
      return IX_ETH_ACC_FAIL;
    }

    for (i = 0;
       i<ixEthAccMacState[portId].mcastAddrIndex;
       i++)
    {
      /*Check if the current entry already match an existing matches*/
      if(ixEthAccMacEqual(&ixEthAccMacState[portId].mcastAddrsTable[i], macAddr))
      {
          /* Address found in the list and already configured,
           * return a success status
           */
          return IX_ETH_ACC_SUCCESS;
      }
    }

    /* check for availability at the end of the current table */
    if(ixEthAccMacState[portId].mcastAddrIndex >= IX_ETH_ACC_MAX_MULTICAST_ADDRESSES)
    {
      return IX_ETH_ACC_FAIL;
    }

    /*First add the address to the multicast table for the
      specified port*/
    i=ixEthAccMacState[portId].mcastAddrIndex;

    memcpy(&ixEthAccMacState[portId].mcastAddrsTable[i],
         &macAddr->macAddress,
         IX_IEEE803_MAC_ADDRESS_SIZE);

    /*Increment the index into the table, this must be done here
     as MulticastAddressSet below needs to know about the latest
     entry.
    */
    ixEthAccMacState[portId].mcastAddrIndex++;

    /*Then calculate the new value to be written to the address and
      address mask registers*/
    ixEthAccMulticastAddressSet(portId);

    return IX_ETH_ACC_SUCCESS;
}


IxEthAccStatus
ixEthAccPortMulticastAddressJoinAllPriv (IxEthAccPortId portId)
{
    IxEthAccMacAddr mcastMacAddr = {{0x1,0x0,0x0,0x0,0x0,0x0}};

    /*Check that the port parameter is valid*/
    IX_ETH_ACC_VALIDATE_PORT_ID(portId);

    if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId))
    {
        IX_ETH_ACC_WARNING_LOG("EthAcc: Unavailable Eth %d: Cannot join all Multicast Address.\n",(INT32)portId,0,0,0,0,0);
        return IX_ETH_ACC_SUCCESS ;
    }

    if (!IX_ETH_IS_PORT_INITIALIZED(portId))
    {
      return (IX_ETH_ACC_PORT_UNINITIALIZED);
    }

    /* remove all entries from the database and
    *  insert a multicast entry
    */
    memcpy(&ixEthAccMacState[portId].mcastAddrsTable[0],
         &mcastMacAddr.macAddress,
         IX_IEEE803_MAC_ADDRESS_SIZE);

    ixEthAccMacState[portId].mcastAddrIndex = 1;
    ixEthAccMacState[portId].joinAll = TRUE;

    ixEthAccMulticastAddressSet(portId);

    return IX_ETH_ACC_SUCCESS;
}

IxEthAccStatus
ixEthAccPortMulticastAddressLeavePriv (IxEthAccPortId portId,
                           IxEthAccMacAddr *macAddr)
{
    UINT32 i;
    IxEthAccMacAddr mcastMacAddr = {{0x1,0x0,0x0,0x0,0x0,0x0}};

    /*Check that the port parameter is valid*/
    IX_ETH_ACC_VALIDATE_PORT_ID(portId);

    if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId))
    {
        IX_ETH_ACC_WARNING_LOG("EthAcc: Unavailable Eth %d: Cannot leave Multicast Address.\n",(INT32)portId,0,0,0,0,0);
        return IX_ETH_ACC_SUCCESS ;
    }

    if (!IX_ETH_IS_PORT_INITIALIZED(portId))
    {
      return (IX_ETH_ACC_PORT_UNINITIALIZED);
    }

    /*Check that the mac address is valid*/
    if(macAddr == NULL)
    {
      return IX_ETH_ACC_FAIL;
    }
    /* Remove this mac address from the mask for the specified port
     * we copy down all entries above the blanked entry, and
     * decrement the index
     */
    i=0;

    while(i<ixEthAccMacState[portId].mcastAddrIndex)
    {
      /*Check if the current entry matches*/
      if(ixEthAccMacEqual(&ixEthAccMacState[portId].mcastAddrsTable[i],
                      macAddr))
      {
          if(ixEthAccMacEqual(macAddr, &mcastMacAddr))
          {
            ixEthAccMacState[portId].joinAll = FALSE;
          }
          /*Decrement the index into the multicast address table
            for the current port*/
          ixEthAccMacState[portId].mcastAddrIndex--;

          /*Copy down all entries above the current entry*/
          while(i<ixEthAccMacState[portId].mcastAddrIndex)
          {
            memcpy(&ixEthAccMacState[portId].mcastAddrsTable[i],
                   &ixEthAccMacState[portId].mcastAddrsTable[i+1],
                   IX_IEEE803_MAC_ADDRESS_SIZE);
                i++;
          }
          /*recalculate the mask and write it to the MAC*/
          ixEthAccMulticastAddressSet(portId);

          return IX_ETH_ACC_SUCCESS;
      }
      /* search the next entry */
      i++;
    }
    /* no matching entry found */
    return IX_ETH_ACC_NO_SUCH_ADDR;
}

IxEthAccStatus
ixEthAccPortMulticastAddressLeaveAllPriv (IxEthAccPortId portId)
{
    /*Check that the port parameter is valid*/
    IX_ETH_ACC_VALIDATE_PORT_ID(portId);

    if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId))
    {
        IX_ETH_ACC_WARNING_LOG("EthAcc: Unavailable Eth %d: Cannot leave all Multicast Address.\n",(INT32)portId,0,0,0,0,0);
        return IX_ETH_ACC_SUCCESS ;
    }

    if (!IX_ETH_IS_PORT_INITIALIZED(portId))
    {
      return (IX_ETH_ACC_PORT_UNINITIALIZED);
    }

    ixEthAccMacState[portId].mcastAddrIndex = 0;
    ixEthAccMacState[portId].joinAll = FALSE;

    ixEthAccMulticastAddressSet(portId);

    return IX_ETH_ACC_SUCCESS;
}


IxEthAccStatus
ixEthAccPortUnicastAddressShowPriv (IxEthAccPortId portId)
{
    IxEthAccMacAddr macAddr;

    IX_ETH_ACC_VALIDATE_PORT_ID(portId);

    if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId))
    {
        IX_ETH_ACC_WARNING_LOG("EthAcc: Unavailable Eth %d: Cannot show Unicast Address.\n",(INT32)portId,0,0,0,0,0);
        return IX_ETH_ACC_SUCCESS ;
    }

    if (!IX_ETH_IS_PORT_INITIALIZED(portId))
    {
      return (IX_ETH_ACC_PORT_UNINITIALIZED);
    }

    /*Get the MAC (UINICAST) address from hardware*/
    if(ixEthAccPortUnicastMacAddressGetPriv(portId, &macAddr) != IX_ETH_ACC_SUCCESS)
    {
        IX_ETH_ACC_WARNING_LOG("EthAcc: MAC address uninitialised port %u\n",
                         (INT32)portId,0,0,0,0,0);
      return IX_ETH_ACC_MAC_UNINITIALIZED;
    }

    /*print it out*/
    ixEthAccMacPrint(&macAddr);
    printf("\n");
    return IX_ETH_ACC_SUCCESS;
}



void
ixEthAccPortMulticastAddressShowPriv(IxEthAccPortId portId)
{
    IxEthAccMacAddr macAddr;
    UINT32 i;

    if(!IX_ETH_ACC_IS_PORT_VALID(portId))
    {
        return;
    }

    if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId))
    {
        IX_ETH_ACC_WARNING_LOG("EthAcc: Unavailable Eth %d: Cannot show Multicast Address.\n",(INT32)portId,0,0,0,0,0);
        return ;
    }

    if (!IX_ETH_IS_PORT_INITIALIZED(portId))
    {
      return;
    }

    printf("Multicast MAC: ");
    /*Get the MAC (MULTICAST) address from hardware*/
    ixEthAccPortMulticastMacAddressGet(portId, &macAddr);
    /*print it out*/
    ixEthAccMacPrint(&macAddr);
    /*Get the MAC (MULTICAST) filter from hardware*/
    ixEthAccPortMulticastMacFilterGet(portId, &macAddr);
    /*print it out*/
    printf(" ( ");
    ixEthAccMacPrint(&macAddr);
    printf(" )\n");
    printf("Constituent Addresses:\n");
    for(i=0;i<ixEthAccMacState[portId].mcastAddrIndex;i++)
    {
      ixEthAccMacPrint(&ixEthAccMacState[portId].mcastAddrsTable[i]);
      printf("\n");
    }
    return;
}

/*Set the duplex mode*/
IxEthAccStatus
ixEthAccPortDuplexModeSetPriv (IxEthAccPortId portId,
                     IxEthAccDuplexMode mode)
{
    UINT32 txregval;
    UINT32 rxregval;

    /*This is bit 1 of the transmit control reg, set to 1 for half
      duplex, 0 for full duplex*/
    IX_ETH_ACC_VALIDATE_PORT_ID(portId);

    if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId))
    {
        IX_ETH_ACC_WARNING_LOG("EthAcc: Unavailable Eth %d: Cannot set Duplex Mode.\n",(INT32)portId,0,0,0,0,0);
        return IX_ETH_ACC_SUCCESS ;
    }

    if (!IX_ETH_IS_PORT_INITIALIZED(portId))
    {
      return (IX_ETH_ACC_PORT_UNINITIALIZED);
    }

    REG_READ(ixEthAccMacBase[portId],
           IX_ETH_ACC_MAC_TX_CNTRL1,
           txregval);

    REG_READ(ixEthAccMacBase[portId],
           IX_ETH_ACC_MAC_RX_CNTRL1,
           rxregval);

    if (mode ==  IX_ETH_ACC_FULL_DUPLEX)
    {
      /*Clear half duplex bit in TX*/
      REG_WRITE(ixEthAccMacBase[portId],
              IX_ETH_ACC_MAC_TX_CNTRL1,
              txregval & ~IX_ETH_ACC_TX_CNTRL1_DUPLEX);

      /*We must set the pause enable in the receive logic when in
        full duplex mode*/
      REG_WRITE(ixEthAccMacBase[portId],
              IX_ETH_ACC_MAC_RX_CNTRL1,
              rxregval | IX_ETH_ACC_RX_CNTRL1_PAUSE_EN);
      ixEthAccMacState[portId].fullDuplex = TRUE;

    }
    else if (mode ==  IX_ETH_ACC_HALF_DUPLEX)
    {
      /*Set half duplex bit in TX*/
      REG_WRITE(ixEthAccMacBase[portId],
              IX_ETH_ACC_MAC_TX_CNTRL1,
              txregval | IX_ETH_ACC_TX_CNTRL1_DUPLEX);

      /*We must clear pause enable in the receive logic when in
        half duplex mode*/
      REG_WRITE(ixEthAccMacBase[portId],
              IX_ETH_ACC_MAC_RX_CNTRL1,
              rxregval & ~IX_ETH_ACC_RX_CNTRL1_PAUSE_EN);

      ixEthAccMacState[portId].fullDuplex = FALSE;
    }
    else
    {
      return IX_ETH_ACC_FAIL;
    }


    return IX_ETH_ACC_SUCCESS;

}



IxEthAccStatus
ixEthAccPortDuplexModeGetPriv (IxEthAccPortId portId,
                     IxEthAccDuplexMode *mode)
{
    /*Return the duplex mode for the specified port*/
    UINT32 regval;

    /*This is bit 1 of the transmit control reg, set to 1 for half
      duplex, 0 for full duplex*/
    IX_ETH_ACC_VALIDATE_PORT_ID(portId);

    if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId))
    {
        IX_ETH_ACC_WARNING_LOG("EthAcc: Unavailable Eth %d: Cannot get Duplex Mode.\n",(INT32)portId,0,0,0,0,0);
        /* return hald duplex */
        *mode = IX_ETH_ACC_HALF_DUPLEX ;
        return IX_ETH_ACC_SUCCESS ;
    }

    if (!IX_ETH_IS_PORT_INITIALIZED(portId))
    {
      return (IX_ETH_ACC_PORT_UNINITIALIZED);
    }

    if (mode == NULL)
    {
      return (IX_ETH_ACC_FAIL);
    }

    REG_READ(ixEthAccMacBase[portId],
           IX_ETH_ACC_MAC_TX_CNTRL1,
           regval);

    if( regval & IX_ETH_ACC_TX_CNTRL1_DUPLEX)
    {
      *mode = IX_ETH_ACC_HALF_DUPLEX;
    }
    else
    {
      *mode = IX_ETH_ACC_FULL_DUPLEX;
    }

    return IX_ETH_ACC_SUCCESS;
}



IxEthAccStatus
ixEthAccPortTxFrameAppendPaddingEnablePriv (IxEthAccPortId portId)
{
    UINT32 regval;
    /*Enable FCS computation by the MAC and appending to the
      frame*/

    IX_ETH_ACC_VALIDATE_PORT_ID(portId);

    if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId))
    {
        IX_ETH_ACC_WARNING_LOG("EthAcc: Unavailable Eth %d: Cannot enable Tx Frame Append Padding.\n",(INT32)portId,0,0,0,0,0);
        return IX_ETH_ACC_SUCCESS ;
    }

    if (!IX_ETH_IS_PORT_INITIALIZED(portId))
    {
      return (IX_ETH_ACC_PORT_UNINITIALIZED);
    }

    REG_READ(ixEthAccMacBase[portId],
           IX_ETH_ACC_MAC_TX_CNTRL1,
           regval);

    REG_WRITE(ixEthAccMacBase[portId],
            IX_ETH_ACC_MAC_TX_CNTRL1,
            regval |
            IX_ETH_ACC_TX_CNTRL1_PAD_EN);

    ixEthAccMacState[portId].txPADAppend = TRUE;
    return IX_ETH_ACC_SUCCESS;
}

IxEthAccStatus
ixEthAccPortTxFrameAppendPaddingDisablePriv (IxEthAccPortId portId)
{
    UINT32 regval;

    /*disable FCS computation and appending*/
    /*Set bit 4 of Tx control register one to zero*/
    IX_ETH_ACC_VALIDATE_PORT_ID(portId);

    if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId))
    {
        IX_ETH_ACC_WARNING_LOG("EthAcc: Unavailable Eth %d: Cannot disble Tx Frame Append Padding.\n",(INT32)portId,0,0,0,0,0);
        return IX_ETH_ACC_SUCCESS ;
    }

    if (!IX_ETH_IS_PORT_INITIALIZED(portId))
    {
      return (IX_ETH_ACC_PORT_UNINITIALIZED);
    }

    REG_READ(ixEthAccMacBase[portId],
           IX_ETH_ACC_MAC_TX_CNTRL1,
           regval);

    REG_WRITE(ixEthAccMacBase[portId],
            IX_ETH_ACC_MAC_TX_CNTRL1,
            regval & ~IX_ETH_ACC_TX_CNTRL1_PAD_EN);

    ixEthAccMacState[portId].txPADAppend = FALSE;
    return IX_ETH_ACC_SUCCESS;
}

IxEthAccStatus
ixEthAccPortTxFrameAppendFCSEnablePriv (IxEthAccPortId portId)
{
    UINT32 regval;

    /*Enable FCS computation by the MAC and appending to the
      frame*/

    IX_ETH_ACC_VALIDATE_PORT_ID(portId);

    if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId))
    {
        IX_ETH_ACC_WARNING_LOG("EthAcc: Unavailable Eth %d: Cannot enable Tx Frame Append FCS.\n",(INT32)portId,0,0,0,0,0);
        return IX_ETH_ACC_SUCCESS ;
    }

    if (!IX_ETH_IS_PORT_INITIALIZED(portId))
    {
      return (IX_ETH_ACC_PORT_UNINITIALIZED);
    }

    REG_READ(ixEthAccMacBase[portId],
           IX_ETH_ACC_MAC_TX_CNTRL1,
           regval);

    REG_WRITE(ixEthAccMacBase[portId],
            IX_ETH_ACC_MAC_TX_CNTRL1,
            regval | IX_ETH_ACC_TX_CNTRL1_FCS_EN);

    ixEthAccMacState[portId].txFCSAppend = TRUE;
    return IX_ETH_ACC_SUCCESS;
}

IxEthAccStatus
ixEthAccPortTxFrameAppendFCSDisablePriv (IxEthAccPortId portId)
{
    UINT32 regval;

    /*disable FCS computation and appending*/
    /*Set bit 4 of Tx control register one to zero*/
    IX_ETH_ACC_VALIDATE_PORT_ID(portId);

    if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId))
    {
        IX_ETH_ACC_WARNING_LOG("EthAcc: Unavailable Eth %d: Cannot disable Tx Frame Append FCS.\n",(INT32)portId,0,0,0,0,0);
        return IX_ETH_ACC_SUCCESS ;
    }

    if (!IX_ETH_IS_PORT_INITIALIZED(portId))
    {
      return (IX_ETH_ACC_PORT_UNINITIALIZED);
    }

    REG_READ(ixEthAccMacBase[portId],
           IX_ETH_ACC_MAC_TX_CNTRL1,
           regval);

    REG_WRITE(ixEthAccMacBase[portId],
            IX_ETH_ACC_MAC_TX_CNTRL1,
            regval & ~IX_ETH_ACC_TX_CNTRL1_FCS_EN);

    ixEthAccMacState[portId].txFCSAppend = FALSE;
    return IX_ETH_ACC_SUCCESS;
}

IxEthAccStatus
ixEthAccPortRxFrameAppendFCSEnablePriv (IxEthAccPortId portId)
{
    /*Set bit 2 of Rx control 1*/
    UINT32 regval;

    IX_ETH_ACC_VALIDATE_PORT_ID(portId);

    if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId))
    {
        IX_ETH_ACC_WARNING_LOG("EthAcc: Unavailable Eth %d: Cannot enable Rx Frame Append FCS.\n",(INT32)portId,0,0,0,0,0);
        return IX_ETH_ACC_SUCCESS ;
    }

    if (!IX_ETH_IS_PORT_INITIALIZED(portId))
    {
      return (IX_ETH_ACC_PORT_UNINITIALIZED);
    }

    REG_READ(ixEthAccMacBase[portId],
           IX_ETH_ACC_MAC_RX_CNTRL1,
           regval);

    REG_WRITE(ixEthAccMacBase[portId],
            IX_ETH_ACC_MAC_RX_CNTRL1,
            regval | IX_ETH_ACC_RX_CNTRL1_CRC_EN);

    ixEthAccMacState[portId].rxFCSAppend = TRUE;
    return IX_ETH_ACC_SUCCESS;
}

IxEthAccStatus
ixEthAccPortRxFrameAppendFCSDisablePriv (IxEthAccPortId portId)
{
    UINT32 regval;

    /*Clear bit 2 of Rx control 1*/
    IX_ETH_ACC_VALIDATE_PORT_ID(portId);

    if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId))
    {
        IX_ETH_ACC_WARNING_LOG("EthAcc: Unavailable Eth %d: Cannot disable Rx Frame Append FCS.\n",(INT32)portId,0,0,0,0,0);
        return IX_ETH_ACC_SUCCESS ;
    }

    if (!IX_ETH_IS_PORT_INITIALIZED(portId))
    {
      return (IX_ETH_ACC_PORT_UNINITIALIZED);
    }

    REG_READ(ixEthAccMacBase[portId],
           IX_ETH_ACC_MAC_RX_CNTRL1,
           regval);

    REG_WRITE(ixEthAccMacBase[portId],
            IX_ETH_ACC_MAC_RX_CNTRL1,
            regval & ~IX_ETH_ACC_RX_CNTRL1_CRC_EN);

    ixEthAccMacState[portId].rxFCSAppend = FALSE;
    return IX_ETH_ACC_SUCCESS;
}



PRIVATE void
ixEthAccMacNpeStatsMessageCallback (IxNpeMhNpeId npeId,
                            IxNpeMhMessage msg)
{
    IxEthAccPortId portId = IX_ETH_ACC_NPE_TO_PORT_ID(npeId);

#ifndef NDEBUG
    /* Prudent to at least check the port is within range */
    if (portId >= IX_ETH_ACC_NUMBER_OF_PORTS)
    {
      IX_ETH_ACC_FATAL_LOG(
     "IXETHACC:ixEthAccMacNpeStatsMessageCallback: Illegal port: %u\n",
     (UINT32)portId, 0, 0, 0, 0, 0);
      return;
    }
#endif

    /*Unblock Stats Get call*/
    ixOsalMutexUnlock(&ixEthAccMacState[portId].ackMIBStatsLock);

}

PRIVATE void
ixEthAccMibIIStatsEndianConvert (IxEthEthObjStats *retStats)
{
    /* endianness conversion */

    /* Rx stats */
    retStats->dot3StatsAlignmentErrors =
      IX_OSAL_SWAP_BE_SHARED_LONG(retStats->dot3StatsAlignmentErrors);
    retStats->dot3StatsFCSErrors =
      IX_OSAL_SWAP_BE_SHARED_LONG(retStats->dot3StatsFCSErrors);
    retStats->dot3StatsInternalMacReceiveErrors =
      IX_OSAL_SWAP_BE_SHARED_LONG(retStats->dot3StatsInternalMacReceiveErrors);
    retStats->RxOverrunDiscards =
      IX_OSAL_SWAP_BE_SHARED_LONG(retStats->RxOverrunDiscards);
    retStats->RxLearnedEntryDiscards =
      IX_OSAL_SWAP_BE_SHARED_LONG(retStats->RxLearnedEntryDiscards);
    retStats->RxLargeFramesDiscards =
      IX_OSAL_SWAP_BE_SHARED_LONG(retStats->RxLargeFramesDiscards);
    retStats->RxSTPBlockedDiscards =
      IX_OSAL_SWAP_BE_SHARED_LONG(retStats->RxSTPBlockedDiscards);
    retStats->RxVLANTypeFilterDiscards =
      IX_OSAL_SWAP_BE_SHARED_LONG(retStats->RxVLANTypeFilterDiscards);
    retStats->RxVLANIdFilterDiscards =
      IX_OSAL_SWAP_BE_SHARED_LONG(retStats->RxVLANIdFilterDiscards);
    retStats->RxInvalidSourceDiscards =
      IX_OSAL_SWAP_BE_SHARED_LONG(retStats->RxInvalidSourceDiscards);
    retStats->RxBlackListDiscards =
      IX_OSAL_SWAP_BE_SHARED_LONG(retStats->RxBlackListDiscards);
    retStats->RxWhiteListDiscards =
      IX_OSAL_SWAP_BE_SHARED_LONG(retStats->RxWhiteListDiscards);
    retStats->RxUnderflowEntryDiscards =
      IX_OSAL_SWAP_BE_SHARED_LONG(retStats->RxUnderflowEntryDiscards);

    /* Tx stats */
    retStats->dot3StatsSingleCollisionFrames =
      IX_OSAL_SWAP_BE_SHARED_LONG(retStats->dot3StatsSingleCollisionFrames);
    retStats->dot3StatsMultipleCollisionFrames =
      IX_OSAL_SWAP_BE_SHARED_LONG(retStats->dot3StatsMultipleCollisionFrames);
    retStats->dot3StatsDeferredTransmissions =
      IX_OSAL_SWAP_BE_SHARED_LONG(retStats->dot3StatsDeferredTransmissions);
    retStats->dot3StatsLateCollisions =
      IX_OSAL_SWAP_BE_SHARED_LONG(retStats->dot3StatsLateCollisions);
    retStats->dot3StatsExcessiveCollsions =
      IX_OSAL_SWAP_BE_SHARED_LONG(retStats->dot3StatsExcessiveCollsions);
    retStats->dot3StatsInternalMacTransmitErrors =
      IX_OSAL_SWAP_BE_SHARED_LONG(retStats->dot3StatsInternalMacTransmitErrors);
    retStats->dot3StatsCarrierSenseErrors =
      IX_OSAL_SWAP_BE_SHARED_LONG(retStats->dot3StatsCarrierSenseErrors);
    retStats->TxLargeFrameDiscards =
      IX_OSAL_SWAP_BE_SHARED_LONG(retStats->TxLargeFrameDiscards);
    retStats->TxVLANIdFilterDiscards =
      IX_OSAL_SWAP_BE_SHARED_LONG(retStats->TxVLANIdFilterDiscards);
}

IxEthAccStatus
02121 ixEthAccMibIIStatsGet (IxEthAccPortId portId,
                   IxEthEthObjStats *retStats )
{
    IxNpeMhMessage message;

    if (!IX_ETH_ACC_IS_SERVICE_INITIALIZED())
    {
        printf("EthAcc: ixEthAccMibIIStatsGet (Mac) EthAcc service is not initialized\n");
      return (IX_ETH_ACC_FAIL);
    }

    IX_ETH_ACC_VALIDATE_PORT_ID(portId);

    if (retStats == NULL)
    {
        printf("EthAcc: ixEthAccMibIIStatsGet (Mac) NULL argument\n");
      return (IX_ETH_ACC_FAIL);
    }

    if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId))
    {
        printf("EthAcc: ixEthAccMibIIStatsGet (Mac) NPE for port %d is not available\n", portId);

        IX_ETH_ACC_WARNING_LOG("EthAcc: Unavailable Eth %d: Cannot get MIB II Stats.\n",(INT32)portId,0,0,0,0,0);

        /* Return all zero stats */
        IX_ETH_ACC_MEMSET(retStats, 0, sizeof(IxEthEthObjStats));

        return IX_ETH_ACC_SUCCESS ;
    }

    if (!IX_ETH_IS_PORT_INITIALIZED(portId))
    {
        printf("EthAcc: ixEthAccMibIIStatsGet (Mac) port %d is not initialized\n", portId);
      return (IX_ETH_ACC_PORT_UNINITIALIZED);
    }

    IX_OSAL_CACHE_INVALIDATE(retStats, sizeof(IxEthEthObjStats));

    message.data[0] = IX_ETHNPE_GETSTATS << IX_ETH_ACC_MAC_MSGID_SHL;
    message.data[1] = (UINT32) IX_OSAL_MMU_VIRT_TO_PHYS(retStats);

    /* Permit only one task to request MIB statistics Get operation
       at a time */
    ixOsalMutexLock(&ixEthAccMacState[portId].MIBStatsGetAccessLock, IX_OSAL_WAIT_FOREVER);

    if(ixNpeMhMessageWithResponseSend(IX_ETH_ACC_PORT_TO_NPE_ID(portId),
                              message,
                              IX_ETHNPE_GETSTATS,
                              ixEthAccMacNpeStatsMessageCallback,
                              IX_NPEMH_SEND_RETRIES_DEFAULT)
       != IX_SUCCESS)
    {
      ixOsalMutexUnlock(&ixEthAccMacState[portId].MIBStatsGetAccessLock);

        printf("EthAcc: (Mac) StatsGet failed to send NPE message\n");

      return IX_ETH_ACC_FAIL;
    }

    /* Wait for callback invocation indicating response to
       this request - we need this mutex in order to ensure
       that the return from this function is synchronous */
    ixOsalMutexLock(&ixEthAccMacState[portId].ackMIBStatsLock, IX_ETH_ACC_MIB_STATS_DELAY_MSECS);

    /* Permit other tasks to perform MIB statistics Get operation */
    ixOsalMutexUnlock(&ixEthAccMacState[portId].MIBStatsGetAccessLock);

    ixEthAccMibIIStatsEndianConvert (retStats);

    return IX_ETH_ACC_SUCCESS;
}


PRIVATE void
ixEthAccMacNpeStatsResetMessageCallback (IxNpeMhNpeId npeId,
                               IxNpeMhMessage msg)
{
    IxEthAccPortId portId = IX_ETH_ACC_NPE_TO_PORT_ID(npeId);

#ifndef NDEBUG
    /* Prudent to at least check the port is within range */
    if (portId >= IX_ETH_ACC_NUMBER_OF_PORTS)
    {
      IX_ETH_ACC_FATAL_LOG(
     "IXETHACC:ixEthAccMacNpeStatsResetMessageCallback: Illegal port: %u\n",
     (UINT32)portId, 0, 0, 0, 0, 0);
      return;
    }
#endif

    /*Unblock Stats Get & reset call*/
    ixOsalMutexUnlock(&ixEthAccMacState[portId].ackMIBStatsResetLock);

}



IxEthAccStatus
02220 ixEthAccMibIIStatsGetClear (IxEthAccPortId portId,
                      IxEthEthObjStats *retStats)
{
    IxNpeMhMessage message;

    if (!IX_ETH_ACC_IS_SERVICE_INITIALIZED())
    {
        printf("EthAcc: ixEthAccMibIIStatsGetClear (Mac) EthAcc service is not initialized\n");
      return (IX_ETH_ACC_FAIL);
    }

    IX_ETH_ACC_VALIDATE_PORT_ID(portId);

    if (retStats == NULL)
    {
        printf("EthAcc: ixEthAccMibIIStatsGetClear (Mac) NULL argument\n");
      return (IX_ETH_ACC_FAIL);
    }

    if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId))
    {
        printf("EthAcc: ixEthAccMibIIStatsGetClear (Mac) NPE for port %d is not available\n", portId);

        IX_ETH_ACC_WARNING_LOG("EthAcc: Unavailable Eth %d: Cannot get and clear MIB II Stats.\n", (INT32)portId, 0, 0, 0, 0, 0);

        /* Return all zero stats */
        IX_ETH_ACC_MEMSET(retStats, 0, sizeof(IxEthEthObjStats));

        return IX_ETH_ACC_SUCCESS ;
    }

    if (!IX_ETH_IS_PORT_INITIALIZED(portId))
    {
        printf("EthAcc: ixEthAccMibIIStatsGetClear (Mac) port %d is not initialized\n", portId);
      return (IX_ETH_ACC_PORT_UNINITIALIZED);
    }

    IX_OSAL_CACHE_INVALIDATE(retStats, sizeof(IxEthEthObjStats));

    message.data[0] = IX_ETHNPE_RESETSTATS << IX_ETH_ACC_MAC_MSGID_SHL;
    message.data[1] = (UINT32) IX_OSAL_MMU_VIRT_TO_PHYS(retStats);

    /* Permit only one task to request MIB statistics Get-Reset operation at a time */
    ixOsalMutexLock(&ixEthAccMacState[portId].MIBStatsGetResetAccessLock, IX_OSAL_WAIT_FOREVER);

    if(ixNpeMhMessageWithResponseSend(IX_ETH_ACC_PORT_TO_NPE_ID(portId),
                              message,
                              IX_ETHNPE_RESETSTATS,
                              ixEthAccMacNpeStatsResetMessageCallback,
                              IX_NPEMH_SEND_RETRIES_DEFAULT)
       != IX_SUCCESS)
    {
      ixOsalMutexUnlock(&ixEthAccMacState[portId].MIBStatsGetResetAccessLock);

        printf("EthAcc: (Mac) ixEthAccMibIIStatsGetClear failed to send NPE message\n");

      return IX_ETH_ACC_FAIL;
    }

    /* Wait for callback invocation indicating response to this request */
    ixOsalMutexLock(&ixEthAccMacState[portId].ackMIBStatsResetLock, IX_ETH_ACC_MIB_STATS_DELAY_MSECS);

    /* permit other tasks to get and reset MIB stats*/
    ixOsalMutexUnlock(&ixEthAccMacState[portId].MIBStatsGetResetAccessLock);

    ixEthAccMibIIStatsEndianConvert(retStats);

    return IX_ETH_ACC_SUCCESS;
}

IxEthAccStatus
02291 ixEthAccMibIIStatsClear (IxEthAccPortId portId)
{
    static IxEthEthObjStats retStats;
    IxEthAccStatus status;

    if (!IX_ETH_ACC_IS_SERVICE_INITIALIZED())
    {
      return (IX_ETH_ACC_FAIL);
    }

    IX_ETH_ACC_VALIDATE_PORT_ID(portId);

    if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId))
    {
        IX_ETH_ACC_WARNING_LOG("EthAcc: Unavailable Eth %d: Cannot clear MIB II Stats.\n",(INT32)portId,0,0,0,0,0);
        return IX_ETH_ACC_SUCCESS ;
    }

    /* there is no reset operation without a corresponding Get */
    status = ixEthAccMibIIStatsGetClear(portId, &retStats);

    return status;
}

/* Initialize the ethernet MAC settings */
IxEthAccStatus
02317 ixEthAccMacInit(IxEthAccPortId portId)
{
    IX_OSAL_MBUF_POOL* portDisablePool;
    UINT8 *data;

    IX_ETH_ACC_VALIDATE_PORT_ID(portId);

    if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId))
    {
        IX_ETH_ACC_WARNING_LOG("EthAcc: Unavailable Eth %d: Cannot initialize Mac.\n",(INT32)portId,0,0,0,0,0);
        return IX_ETH_ACC_SUCCESS ;
    }

    if(ixEthAccMacState[portId].macInitialised == FALSE)
    {
      ixEthAccMacState[portId].fullDuplex  = TRUE;
      ixEthAccMacState[portId].rxFCSAppend = TRUE;
      ixEthAccMacState[portId].txFCSAppend = TRUE;
      ixEthAccMacState[portId].txPADAppend = TRUE;
      ixEthAccMacState[portId].enabled     = FALSE;
      ixEthAccMacState[portId].promiscuous = TRUE;
      ixEthAccMacState[portId].joinAll     = FALSE;
      ixEthAccMacState[portId].initDone    = FALSE;
      ixEthAccMacState[portId].macInitialised = TRUE;

        /* initialize MIB stats mutexes */
        ixOsalMutexInit(&ixEthAccMacState[portId].ackMIBStatsLock);
        ixOsalMutexLock(&ixEthAccMacState[portId].ackMIBStatsLock, IX_OSAL_WAIT_FOREVER);

        ixOsalMutexInit(&ixEthAccMacState[portId].ackMIBStatsResetLock);
        ixOsalMutexLock(&ixEthAccMacState[portId].ackMIBStatsResetLock, IX_OSAL_WAIT_FOREVER);

        ixOsalMutexInit(&ixEthAccMacState[portId].MIBStatsGetAccessLock);

        ixOsalMutexInit(&ixEthAccMacState[portId].MIBStatsGetResetAccessLock);

        ixOsalMutexInit(&ixEthAccMacState[portId].npeLoopbackMessageLock);

      ixEthAccMacState[portId].portDisableRxMbufPtr = NULL;
        ixEthAccMacState[portId].portDisableTxMbufPtr = NULL;

      portDisablePool = IX_OSAL_MBUF_POOL_INIT(2,
                    IX_ETHACC_RX_MBUF_MIN_SIZE,
                    "portDisable Pool");

        IX_OSAL_ENSURE(portDisablePool != NULL, "Failed to initialize PortDisable pool");

      ixEthAccMacState[portId].portDisableRxMbufPtr = IX_OSAL_MBUF_POOL_GET(portDisablePool);
        ixEthAccMacState[portId].portDisableTxMbufPtr = IX_OSAL_MBUF_POOL_GET(portDisablePool);

      IX_OSAL_ENSURE(ixEthAccMacState[portId].portDisableRxMbufPtr != NULL,
              "Pool allocation failed");
        IX_OSAL_ENSURE(ixEthAccMacState[portId].portDisableTxMbufPtr != NULL,
              "Pool allocation failed");
      /* fill the payload of the Rx mbuf used in portDisable */
        IX_OSAL_MBUF_MLEN(ixEthAccMacState[portId].portDisableRxMbufPtr) = IX_ETHACC_RX_MBUF_MIN_SIZE;

        memset(IX_OSAL_MBUF_MDATA(ixEthAccMacState[portId].portDisableRxMbufPtr),
             0xAA,
             IX_ETHACC_RX_MBUF_MIN_SIZE);

      /* fill the payload of the Tx mbuf used in portDisable (64 bytes) */
        IX_OSAL_MBUF_MLEN(ixEthAccMacState[portId].portDisableTxMbufPtr) = 64;
        IX_OSAL_MBUF_PKT_LEN(ixEthAccMacState[portId].portDisableTxMbufPtr) = 64;

        data = (UINT8 *) IX_OSAL_MBUF_MDATA(ixEthAccMacState[portId].portDisableTxMbufPtr);
        memset(data, 0xBB, 64);
        data[0] = 0x00; /* unicast destination MAC address */
        data[6] = 0x00; /* unicast source MAC address */
        data[12] = 0x08; /* typelength : IP frame */
        data[13] = 0x00; /* typelength : IP frame */

      IX_OSAL_CACHE_FLUSH(data, 64);
    }

    IX_OSAL_ASSERT (ixEthAccMacBase[portId] != 0);

    REG_WRITE(ixEthAccMacBase[portId],
            IX_ETH_ACC_MAC_CORE_CNTRL,
            IX_ETH_ACC_CORE_RESET);

    ixOsalSleep(IX_ETH_ACC_MAC_RESET_DELAY);

    REG_WRITE(ixEthAccMacBase[portId],
            IX_ETH_ACC_MAC_CORE_CNTRL,
            IX_ETH_ACC_CORE_MDC_EN);

    REG_WRITE(ixEthAccMacBase[portId],
            IX_ETH_ACC_MAC_INT_CLK_THRESH,
            IX_ETH_ACC_MAC_INT_CLK_THRESH_DEFAULT);

    ixEthAccMacStateUpdate(portId);

    return IX_ETH_ACC_SUCCESS;
}

/* PRIVATE Functions*/

PRIVATE void
ixEthAccMacStateUpdate(IxEthAccPortId portId)
{
    UINT32 regval;

    if ( ixEthAccMacState[portId].enabled == FALSE )
    {
      /*  Just disable both the transmitter and reciver in the MAC.  */
        REG_READ(ixEthAccMacBase[portId],
             IX_ETH_ACC_MAC_RX_CNTRL1,
             regval);
      REG_WRITE(ixEthAccMacBase[portId],
              IX_ETH_ACC_MAC_RX_CNTRL1,
              regval & ~IX_ETH_ACC_RX_CNTRL1_RX_EN);

        REG_READ(ixEthAccMacBase[portId],
             IX_ETH_ACC_MAC_TX_CNTRL1,
             regval);
      REG_WRITE(ixEthAccMacBase[portId],
              IX_ETH_ACC_MAC_TX_CNTRL1,
              regval & ~IX_ETH_ACC_TX_CNTRL1_TX_EN);
    }

    if(ixEthAccMacState[portId].fullDuplex)
    {
      ixEthAccPortDuplexModeSetPriv (portId, IX_ETH_ACC_FULL_DUPLEX);
    }
    else
    {
      ixEthAccPortDuplexModeSetPriv (portId, IX_ETH_ACC_HALF_DUPLEX);
    }

    if(ixEthAccMacState[portId].rxFCSAppend)
    {
      ixEthAccPortRxFrameAppendFCSEnablePriv (portId);
    }
    else
    {
      ixEthAccPortRxFrameAppendFCSDisablePriv (portId);
    }

    if(ixEthAccMacState[portId].txFCSAppend)
    {
      ixEthAccPortTxFrameAppendFCSEnablePriv (portId);
    }
    else
    {
      ixEthAccPortTxFrameAppendFCSDisablePriv (portId);
    }

    if(ixEthAccMacState[portId].txPADAppend)
    {
      ixEthAccPortTxFrameAppendPaddingEnablePriv (portId);
    }
    else
    {
      ixEthAccPortTxFrameAppendPaddingDisablePriv (portId);
    }

    if(ixEthAccMacState[portId].promiscuous)
    {
      ixEthAccPortPromiscuousModeSetPriv(portId);
    }
    else
    {
      ixEthAccPortPromiscuousModeClearPriv(portId);
    }

    if ( ixEthAccMacState[portId].enabled == TRUE )
    {
        /*   Enable both the transmitter and reciver in the MAC.  */
        REG_READ(ixEthAccMacBase[portId],
             IX_ETH_ACC_MAC_RX_CNTRL1,
             regval);
        REG_WRITE(ixEthAccMacBase[portId],
              IX_ETH_ACC_MAC_RX_CNTRL1,
              regval | IX_ETH_ACC_RX_CNTRL1_RX_EN);

        REG_READ(ixEthAccMacBase[portId],
             IX_ETH_ACC_MAC_TX_CNTRL1,
             regval);
      REG_WRITE(ixEthAccMacBase[portId],
              IX_ETH_ACC_MAC_TX_CNTRL1,
              regval | IX_ETH_ACC_TX_CNTRL1_TX_EN);
    }
}


PRIVATE BOOL
ixEthAccMacEqual(IxEthAccMacAddr *macAddr1,
             IxEthAccMacAddr *macAddr2)
{
    UINT32 i;
    for(i=0;i<IX_IEEE803_MAC_ADDRESS_SIZE; i++)
    {
      if(macAddr1->macAddress[i] != macAddr2->macAddress[i])
      {
          return FALSE;
      }
    }
    return TRUE;
}

PRIVATE void
ixEthAccMacPrint(IxEthAccMacAddr *m)
{
    printf("%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x",
         m->macAddress[0], m->macAddress[1],
         m->macAddress[2], m->macAddress[3],
         m->macAddress[4], m->macAddress[5]);
}

/* Set the multicast address and address mask registers
 *
 * A bit in the address mask register must be set if
 * all multicast addresses always have that bit set, or if
 * all multicast addresses always have that bit cleared.
 *
 * A bit in the address register must be set if all multicast
 * addresses have that bit set, otherwise, it should be cleared
 */

PRIVATE void
ixEthAccMulticastAddressSet(IxEthAccPortId portId)
{
    UINT32 i;
    UINT32 j;
    IxEthAccMacAddr addressMask;
    IxEthAccMacAddr address;
    IxEthAccMacAddr alwaysClearBits;
    IxEthAccMacAddr alwaysSetBits;

    /* calculate alwaysClearBits and alwaysSetBits:
     * alwaysClearBits is calculated by ORing all
     * multicast addresses, those bits that are always
     * clear are clear in the result
     *
     * alwaysSetBits is calculated by ANDing all
     * multicast addresses, those bits that are always set
     * are set in the result
     */

    if (ixEthAccMacState[portId].promiscuous == TRUE)
    {
      /* Promiscuous Mode is set, and filtering
       * allow all packets, and enable the mcast and
       * bcast detection.
       */
      memset(&addressMask.macAddress,
             0,
             IX_IEEE803_MAC_ADDRESS_SIZE);
      memset(&address.macAddress,
             0,
             IX_IEEE803_MAC_ADDRESS_SIZE);
    }
    else
    {
      if(ixEthAccMacState[portId].joinAll == TRUE)
      {
          /* Join all is set. The mask and address are
           * the multicast settings.
           */
          IxEthAccMacAddr macAddr = {{0x1,0x0,0x0,0x0,0x0,0x0}};

          memcpy(addressMask.macAddress,
               macAddr.macAddress,
               IX_IEEE803_MAC_ADDRESS_SIZE);
          memcpy(address.macAddress,
               macAddr.macAddress,
               IX_IEEE803_MAC_ADDRESS_SIZE);
      }
      else if(ixEthAccMacState[portId].mcastAddrIndex == 0)
      {
          /* No entry in the filtering database,
           * Promiscuous Mode is cleared, Broadcast filtering
           * is configured.
           */
          memset(addressMask.macAddress,
               IX_ETH_ACC_MAC_ALL_BITS_SET,
               IX_IEEE803_MAC_ADDRESS_SIZE);
          memset(address.macAddress,
               IX_ETH_ACC_MAC_ALL_BITS_SET,
               IX_IEEE803_MAC_ADDRESS_SIZE);
      }
      else
      {
          /* build a mask and an address which mix all entreis
           * from the list of multicast addresses
           */
          memset(alwaysClearBits.macAddress,
               0,
               IX_IEEE803_MAC_ADDRESS_SIZE);
          memset(alwaysSetBits.macAddress,
               IX_ETH_ACC_MAC_ALL_BITS_SET,
               IX_IEEE803_MAC_ADDRESS_SIZE);

          for(i=0;i<ixEthAccMacState[portId].mcastAddrIndex;i++)
          {
            for(j=0;j<IX_IEEE803_MAC_ADDRESS_SIZE;j++)
            {
                alwaysClearBits.macAddress[j] |=
                  ixEthAccMacState[portId].mcastAddrsTable[i].macAddress[j];
                alwaysSetBits.macAddress[j] &=
                  ixEthAccMacState[portId].mcastAddrsTable[i].macAddress[j];
            }
          }

          for(i=0;i<IX_IEEE803_MAC_ADDRESS_SIZE;i++)
          {
            addressMask.macAddress[i] = alwaysSetBits.macAddress[i]
                | ~alwaysClearBits.macAddress[i];
            address.macAddress[i] = alwaysSetBits.macAddress[i];
          }
      }
    }

    /*write the new addr filtering to h/w*/
    for(i=0;i<IX_IEEE803_MAC_ADDRESS_SIZE;i++)
    {
      REG_WRITE(ixEthAccMacBase[portId],
              IX_ETH_ACC_MAC_ADDR_MASK_1+i*sizeof(UINT32),
              addressMask.macAddress[i]);
      REG_WRITE(ixEthAccMacBase[portId],
              IX_ETH_ACC_MAC_ADDR_1+i*sizeof(UINT32),
              address.macAddress[i]);
    }
}

Generated by  Doxygen 1.6.0   Back to index