/** * @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;imacAddress[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;imacAddress[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;imacAddress[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;imacAddress[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;imacAddress[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= 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= 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;imacAddress[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