blob: 65113448d27b7a732a4dd0efde1d28d8b78a0fdc [file] [log] [blame]
/**
* @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
* SPDX-License-Identifier: BSD-3-Clause
* @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
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
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
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
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]);
}
}