| /** | |
| * @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]); | |
| } | |
| } |