summaryrefslogtreecommitdiff
path: root/drivers/net/npe/IxEthAccMac.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/npe/IxEthAccMac.c')
-rw-r--r--drivers/net/npe/IxEthAccMac.c2641
1 files changed, 2641 insertions, 0 deletions
diff --git a/drivers/net/npe/IxEthAccMac.c b/drivers/net/npe/IxEthAccMac.c
new file mode 100644
index 0000000..369ee91
--- /dev/null
+++ b/drivers/net/npe/IxEthAccMac.c
@@ -0,0 +1,2641 @@
+/**
+ * @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
+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]);
+ }
+}