| /** |
| * @file IxEthAccMac.c |
| * |
| * @author Intel Corporation |
| * @date |
| * |
| * @brief MAC control functions |
| * |
| * Design Notes: |
| * |
| * @par |
| * IXP400 SW Release version 2.0 |
| * |
| * -- Copyright Notice -- |
| * |
| * @par |
| * Copyright 2001-2005, Intel Corporation. |
| * All rights reserved. |
| * |
| * @par |
| * SPDX-License-Identifier: BSD-3-Clause |
| * @par |
| * -- End of Copyright Notice -- |
| */ |
| |
| #include "IxOsal.h" |
| #include "IxNpeMh.h" |
| #ifdef CONFIG_IXP425_COMPONENT_ETHDB |
| #include "IxEthDB.h" |
| #endif |
| #include "IxEthDBPortDefs.h" |
| #include "IxEthNpe.h" |
| #include "IxEthAcc.h" |
| #include "IxEthAccDataPlane_p.h" |
| #include "IxEthAcc_p.h" |
| #include "IxEthAccMac_p.h" |
| |
| /* Maximum number of retries during ixEthAccPortDisable, which |
| * is approximately 10 seconds |
| */ |
| #define IX_ETH_ACC_MAX_RETRY 500 |
| |
| /* Maximum number of retries during ixEthAccPortDisable when expecting |
| * timeout |
| */ |
| #define IX_ETH_ACC_MAX_RETRY_TIMEOUT 5 |
| |
| #define IX_ETH_ACC_VALIDATE_PORT_ID(portId) \ |
| do \ |
| { \ |
| if(!IX_ETH_ACC_IS_PORT_VALID(portId)) \ |
| { \ |
| return IX_ETH_ACC_INVALID_PORT; \ |
| } \ |
| } while(0) |
| |
| PUBLIC IxEthAccMacState ixEthAccMacState[IX_ETH_ACC_NUMBER_OF_PORTS]; |
| |
| PRIVATE UINT32 ixEthAccMacBase[IX_ETH_ACC_NUMBER_OF_PORTS]; |
| |
| /*Forward function declarations*/ |
| PRIVATE void |
| ixEthAccPortDisableRx (IxEthAccPortId portId, |
| IX_OSAL_MBUF * mBufPtr, |
| BOOL useMultiBufferCallback); |
| |
| PRIVATE void |
| ixEthAccPortDisableRxAndReplenish (IxEthAccPortId portId, |
| IX_OSAL_MBUF * mBufPtr, |
| BOOL useMultiBufferCallback); |
| |
| PRIVATE void |
| ixEthAccPortDisableTxDone (UINT32 cbTag, |
| IX_OSAL_MBUF *mbuf); |
| |
| PRIVATE void |
| ixEthAccPortDisableTxDoneAndSubmit (UINT32 cbTag, |
| IX_OSAL_MBUF *mbuf); |
| |
| PRIVATE void |
| ixEthAccPortDisableRxCallback (UINT32 cbTag, |
| IX_OSAL_MBUF * mBufPtr, |
| UINT32 learnedPortId); |
| |
| PRIVATE void |
| ixEthAccPortDisableMultiBufferRxCallback (UINT32 cbTag, |
| IX_OSAL_MBUF **mBufPtr); |
| |
| PRIVATE IxEthAccStatus |
| ixEthAccPortDisableTryTransmit(UINT32 portId); |
| |
| PRIVATE IxEthAccStatus |
| ixEthAccPortDisableTryReplenish(UINT32 portId); |
| |
| PRIVATE IxEthAccStatus |
| ixEthAccPortMulticastMacAddressGet (IxEthAccPortId portId, |
| IxEthAccMacAddr *macAddr); |
| |
| PRIVATE IxEthAccStatus |
| ixEthAccPortMulticastMacFilterGet (IxEthAccPortId portId, |
| IxEthAccMacAddr *macAddr); |
| |
| PRIVATE void |
| ixEthAccMacNpeStatsMessageCallback (IxNpeMhNpeId npeId, |
| IxNpeMhMessage msg); |
| |
| PRIVATE void |
| ixEthAccMacNpeStatsResetMessageCallback (IxNpeMhNpeId npeId, |
| IxNpeMhMessage msg); |
| |
| PRIVATE void |
| ixEthAccNpeLoopbackMessageCallback (IxNpeMhNpeId npeId, |
| IxNpeMhMessage msg); |
| |
| PRIVATE void |
| ixEthAccMulticastAddressSet(IxEthAccPortId portId); |
| |
| PRIVATE BOOL |
| ixEthAccMacEqual(IxEthAccMacAddr *macAddr1, |
| IxEthAccMacAddr *macAddr2); |
| |
| PRIVATE void |
| ixEthAccMacPrint(IxEthAccMacAddr *m); |
| |
| PRIVATE void |
| ixEthAccMacStateUpdate(IxEthAccPortId portId); |
| |
| IxEthAccStatus |
| ixEthAccMacMemInit(void) |
| { |
| ixEthAccMacBase[IX_ETH_PORT_1] = |
| (UINT32) IX_OSAL_MEM_MAP(IX_ETH_ACC_MAC_0_BASE, |
| IX_OSAL_IXP400_ETHA_MAP_SIZE); |
| ixEthAccMacBase[IX_ETH_PORT_2] = |
| (UINT32) IX_OSAL_MEM_MAP(IX_ETH_ACC_MAC_1_BASE, |
| IX_OSAL_IXP400_ETHB_MAP_SIZE); |
| #ifdef __ixp46X |
| ixEthAccMacBase[IX_ETH_PORT_3] = |
| (UINT32) IX_OSAL_MEM_MAP(IX_ETH_ACC_MAC_2_BASE, |
| IX_OSAL_IXP400_ETH_NPEA_MAP_SIZE); |
| if (ixEthAccMacBase[IX_ETH_PORT_3] == 0) |
| { |
| ixOsalLog(IX_OSAL_LOG_LVL_FATAL, |
| IX_OSAL_LOG_DEV_STDOUT, |
| "EthAcc: Could not map MAC I/O memory\n", |
| 0, 0, 0, 0, 0 ,0); |
| |
| return IX_ETH_ACC_FAIL; |
| } |
| #endif |
| |
| if (ixEthAccMacBase[IX_ETH_PORT_1] == 0 |
| || ixEthAccMacBase[IX_ETH_PORT_2] == 0) |
| { |
| ixOsalLog(IX_OSAL_LOG_LVL_FATAL, |
| IX_OSAL_LOG_DEV_STDOUT, |
| "EthAcc: Could not map MAC I/O memory\n", |
| 0, 0, 0, 0, 0 ,0); |
| |
| return IX_ETH_ACC_FAIL; |
| } |
| |
| return IX_ETH_ACC_SUCCESS; |
| } |
| |
| void |
| ixEthAccMacUnload(void) |
| { |
| IX_OSAL_MEM_UNMAP(ixEthAccMacBase[IX_ETH_PORT_1]); |
| IX_OSAL_MEM_UNMAP(ixEthAccMacBase[IX_ETH_PORT_2]); |
| #ifdef __ixp46X |
| IX_OSAL_MEM_UNMAP(ixEthAccMacBase[IX_ETH_PORT_3]); |
| ixEthAccMacBase[IX_ETH_PORT_3] = 0; |
| #endif |
| ixEthAccMacBase[IX_ETH_PORT_2] = 0; |
| ixEthAccMacBase[IX_ETH_PORT_1] = 0; |
| } |
| |
| IxEthAccStatus |
| ixEthAccPortEnablePriv(IxEthAccPortId portId) |
| { |
| IX_ETH_ACC_VALIDATE_PORT_ID(portId); |
| |
| if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId)) |
| { |
| IX_ETH_ACC_WARNING_LOG("EthAcc: Unavailable Eth %d: Cannot enable port.\n",(INT32)portId,0,0,0,0,0); |
| return IX_ETH_ACC_SUCCESS ; |
| } |
| |
| if (!IX_ETH_IS_PORT_INITIALIZED(portId)) |
| { |
| printf("EthAcc: (Mac) cannot enable port %d, port not initialized\n", portId); |
| return (IX_ETH_ACC_PORT_UNINITIALIZED); |
| } |
| |
| if (ixEthAccPortData[portId].ixEthAccTxData.txBufferDoneCallbackFn == NULL) |
| { |
| /* TxDone callback not registered */ |
| printf("EthAcc: (Mac) cannot enable port %d, TxDone callback not registered\n", portId); |
| return (IX_ETH_ACC_PORT_UNINITIALIZED); |
| } |
| |
| if ((ixEthAccPortData[portId].ixEthAccRxData.rxCallbackFn == NULL) |
| && (ixEthAccPortData[portId].ixEthAccRxData.rxMultiBufferCallbackFn == NULL)) |
| { |
| /* Receive callback not registered */ |
| printf("EthAcc: (Mac) cannot enable port %d, Rx callback not registered\n", portId); |
| return (IX_ETH_ACC_PORT_UNINITIALIZED); |
| } |
| |
| if(!ixEthAccMacState[portId].initDone) |
| { |
| printf("EthAcc: (Mac) cannot enable port %d, MAC address not set\n", portId); |
| return (IX_ETH_ACC_MAC_UNINITIALIZED); |
| } |
| |
| /* if the state is being set to what it is already at, do nothing*/ |
| if (ixEthAccMacState[portId].enabled) |
| { |
| return IX_ETH_ACC_SUCCESS; |
| } |
| |
| #ifdef CONFIG_IXP425_COMPONENT_ETHDB |
| /* enable ethernet database for this port */ |
| if (ixEthDBPortEnable(portId) != IX_ETH_DB_SUCCESS) |
| { |
| printf("EthAcc: (Mac) cannot enable port %d, EthDB failure\n", portId); |
| return IX_ETH_ACC_FAIL; |
| } |
| #endif |
| |
| /* set the MAC core registers */ |
| REG_WRITE(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_TX_CNTRL2, |
| IX_ETH_ACC_TX_CNTRL2_RETRIES_MASK); |
| |
| REG_WRITE(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_RANDOM_SEED, |
| IX_ETH_ACC_RANDOM_SEED_DEFAULT); |
| |
| REG_WRITE(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_THRESH_P_EMPTY, |
| IX_ETH_ACC_MAC_THRESH_P_EMPTY_DEFAULT); |
| |
| REG_WRITE(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_THRESH_P_FULL, |
| IX_ETH_ACC_MAC_THRESH_P_FULL_DEFAULT); |
| |
| REG_WRITE(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_TX_DEFER, |
| IX_ETH_ACC_MAC_TX_DEFER_DEFAULT); |
| |
| REG_WRITE(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_TX_TWO_DEFER_1, |
| IX_ETH_ACC_MAC_TX_TWO_DEFER_1_DEFAULT); |
| |
| REG_WRITE(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_TX_TWO_DEFER_2, |
| IX_ETH_ACC_MAC_TX_TWO_DEFER_2_DEFAULT); |
| |
| REG_WRITE(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_SLOT_TIME, |
| IX_ETH_ACC_MAC_SLOT_TIME_DEFAULT); |
| |
| REG_WRITE(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_INT_CLK_THRESH, |
| IX_ETH_ACC_MAC_INT_CLK_THRESH_DEFAULT); |
| |
| REG_WRITE(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_BUF_SIZE_TX, |
| IX_ETH_ACC_MAC_BUF_SIZE_TX_DEFAULT); |
| |
| REG_WRITE(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_TX_CNTRL1, |
| IX_ETH_ACC_TX_CNTRL1_DEFAULT); |
| |
| REG_WRITE(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_RX_CNTRL1, |
| IX_ETH_ACC_RX_CNTRL1_DEFAULT); |
| |
| /* set the global state */ |
| ixEthAccMacState[portId].portDisableState = ACTIVE; |
| ixEthAccMacState[portId].enabled = true; |
| |
| /* rewrite the setup (including mac filtering) depending |
| * on current options |
| */ |
| ixEthAccMacStateUpdate(portId); |
| |
| return IX_ETH_ACC_SUCCESS; |
| } |
| |
| /* |
| * PortDisable local variables. They contain the intermediate steps |
| * while the port is being disabled and the buffers being drained out |
| * of the NPE. |
| */ |
| typedef void (*IxEthAccPortDisableRx)(IxEthAccPortId portId, |
| IX_OSAL_MBUF * mBufPtr, |
| BOOL useMultiBufferCallback); |
| static IxEthAccPortRxCallback |
| ixEthAccPortDisableFn[IX_ETH_ACC_NUMBER_OF_PORTS]; |
| static IxEthAccPortMultiBufferRxCallback |
| ixEthAccPortDisableMultiBufferFn[IX_ETH_ACC_NUMBER_OF_PORTS]; |
| static IxEthAccPortDisableRx |
| ixEthAccPortDisableRxTable[IX_ETH_ACC_NUMBER_OF_PORTS]; |
| static UINT32 |
| ixEthAccPortDisableCbTag[IX_ETH_ACC_NUMBER_OF_PORTS]; |
| static UINT32 |
| ixEthAccPortDisableMultiBufferCbTag[IX_ETH_ACC_NUMBER_OF_PORTS]; |
| |
| static IxEthAccPortTxDoneCallback |
| ixEthAccPortDisableTxDoneFn[IX_ETH_ACC_NUMBER_OF_PORTS]; |
| static UINT32 |
| ixEthAccPortDisableTxDoneCbTag[IX_ETH_ACC_NUMBER_OF_PORTS]; |
| |
| static UINT32 |
| ixEthAccPortDisableUserBufferCount[IX_ETH_ACC_NUMBER_OF_PORTS]; |
| |
| /* |
| * PortDisable private callbacks functions. They handle the user |
| * traffic, and the special buffers (one for tx, one for rx) used |
| * in portDisable. |
| */ |
| PRIVATE void |
| ixEthAccPortDisableTxDone(UINT32 cbTag, |
| IX_OSAL_MBUF *mbuf) |
| { |
| IxEthAccPortId portId = (IxEthAccPortId)cbTag; |
| volatile IxEthAccPortDisableState *txState = &ixEthAccMacState[portId].txState; |
| |
| /* check for the special mbuf used in portDisable */ |
| if (mbuf == ixEthAccMacState[portId].portDisableTxMbufPtr) |
| { |
| *txState = TRANSMIT_DONE; |
| } |
| else |
| { |
| /* increment the count of user traffic during portDisable */ |
| ixEthAccPortDisableUserBufferCount[portId]++; |
| |
| /* call client TxDone function */ |
| ixEthAccPortDisableTxDoneFn[portId](ixEthAccPortDisableTxDoneCbTag[portId], mbuf); |
| } |
| } |
| |
| PRIVATE IxEthAccStatus |
| ixEthAccPortDisableTryTransmit(UINT32 portId) |
| { |
| int key; |
| IxEthAccStatus status = IX_ETH_ACC_SUCCESS; |
| volatile IxEthAccPortDisableState *txState = &ixEthAccMacState[portId].txState; |
| /* transmit the special buffer again if it is transmitted |
| * and update the txState |
| * This section is protected because the portDisable context |
| * run an identical code, so the system keeps transmitting at the |
| * maximum rate. |
| */ |
| key = ixOsalIrqLock(); |
| if (*txState == TRANSMIT_DONE) |
| { |
| IX_OSAL_MBUF *mbufTxPtr = ixEthAccMacState[portId].portDisableTxMbufPtr; |
| *txState = TRANSMIT; |
| status = ixEthAccPortTxFrameSubmit(portId, |
| mbufTxPtr, |
| IX_ETH_ACC_TX_DEFAULT_PRIORITY); |
| } |
| ixOsalIrqUnlock(key); |
| |
| return status; |
| } |
| |
| PRIVATE void |
| ixEthAccPortDisableTxDoneAndSubmit(UINT32 cbTag, |
| IX_OSAL_MBUF *mbuf) |
| { |
| IxEthAccPortId portId = (IxEthAccPortId)cbTag; |
| |
| /* call the callback which forwards the traffic to the client */ |
| ixEthAccPortDisableTxDone(cbTag, mbuf); |
| |
| /* try to transmit the buffer used in portDisable |
| * if seen in TxDone |
| */ |
| ixEthAccPortDisableTryTransmit(portId); |
| } |
| |
| PRIVATE void |
| ixEthAccPortDisableRx (IxEthAccPortId portId, |
| IX_OSAL_MBUF * mBufPtr, |
| BOOL useMultiBufferCallback) |
| { |
| volatile IxEthAccPortDisableState *rxState = &ixEthAccMacState[portId].rxState; |
| IX_OSAL_MBUF *mNextPtr; |
| |
| while (mBufPtr) |
| { |
| mNextPtr = IX_OSAL_MBUF_NEXT_BUFFER_IN_PKT_PTR(mBufPtr); |
| IX_OSAL_MBUF_NEXT_BUFFER_IN_PKT_PTR(mBufPtr) = NULL; |
| |
| /* check for the special mbuf used in portDisable */ |
| if (mBufPtr == ixEthAccMacState[portId].portDisableRxMbufPtr) |
| { |
| *rxState = RECEIVE; |
| } |
| else |
| { |
| /* increment the count of user traffic during portDisable */ |
| ixEthAccPortDisableUserBufferCount[portId]++; |
| |
| /* reset the received payload length during portDisable */ |
| IX_OSAL_MBUF_MLEN(mBufPtr) = 0; |
| IX_OSAL_MBUF_PKT_LEN(mBufPtr) = 0; |
| |
| if (useMultiBufferCallback) |
| { |
| /* call the user callback with one unchained |
| * buffer, without payload. A small array is built |
| * to be used as a parameter (the user callback expects |
| * to receive an array ended by a NULL pointer. |
| */ |
| IX_OSAL_MBUF *mBufPtrArray[2]; |
| |
| mBufPtrArray[0] = mBufPtr; |
| mBufPtrArray[1] = NULL; |
| ixEthAccPortDisableMultiBufferFn[portId]( |
| ixEthAccPortDisableMultiBufferCbTag[portId], |
| mBufPtrArray); |
| } |
| else |
| { |
| /* call the user callback with a unchained |
| * buffer, without payload and the destination port is |
| * unknown. |
| */ |
| ixEthAccPortDisableFn[portId]( |
| ixEthAccPortDisableCbTag[portId], |
| mBufPtr, |
| IX_ETH_DB_UNKNOWN_PORT /* port not found */); |
| } |
| } |
| |
| mBufPtr = mNextPtr; |
| } |
| } |
| |
| PRIVATE IxEthAccStatus |
| ixEthAccPortDisableTryReplenish(UINT32 portId) |
| { |
| int key; |
| IxEthAccStatus status = IX_ETH_ACC_SUCCESS; |
| volatile IxEthAccPortDisableState *rxState = &ixEthAccMacState[portId].rxState; |
| /* replenish with the special buffer again if it is received |
| * and update the rxState |
| * This section is protected because the portDisable context |
| * run an identical code, so the system keeps replenishing at the |
| * maximum rate. |
| */ |
| key = ixOsalIrqLock(); |
| if (*rxState == RECEIVE) |
| { |
| IX_OSAL_MBUF *mbufRxPtr = ixEthAccMacState[portId].portDisableRxMbufPtr; |
| *rxState = REPLENISH; |
| IX_OSAL_MBUF_MLEN(mbufRxPtr) = IX_ETHACC_RX_MBUF_MIN_SIZE; |
| status = ixEthAccPortRxFreeReplenish(portId, mbufRxPtr); |
| } |
| ixOsalIrqUnlock(key); |
| |
| return status; |
| } |
| |
| PRIVATE void |
| ixEthAccPortDisableRxAndReplenish (IxEthAccPortId portId, |
| IX_OSAL_MBUF * mBufPtr, |
| BOOL useMultiBufferCallback) |
| { |
| /* call the callback which forwards the traffic to the client */ |
| ixEthAccPortDisableRx(portId, mBufPtr, useMultiBufferCallback); |
| |
| /* try to replenish with the buffer used in portDisable |
| * if seen in Rx |
| */ |
| ixEthAccPortDisableTryReplenish(portId); |
| } |
| |
| PRIVATE void |
| ixEthAccPortDisableRxCallback (UINT32 cbTag, |
| IX_OSAL_MBUF * mBufPtr, |
| UINT32 learnedPortId) |
| { |
| IxEthAccPortId portId = (IxEthAccPortId)cbTag; |
| |
| /* call the portDisable receive callback */ |
| (ixEthAccPortDisableRxTable[portId])(portId, mBufPtr, false); |
| } |
| |
| PRIVATE void |
| ixEthAccPortDisableMultiBufferRxCallback (UINT32 cbTag, |
| IX_OSAL_MBUF **mBufPtr) |
| { |
| IxEthAccPortId portId = (IxEthAccPortId)cbTag; |
| |
| while (*mBufPtr) |
| { |
| /* call the portDisable receive callback with one buffer at a time */ |
| (ixEthAccPortDisableRxTable[portId])(portId, *mBufPtr++, true); |
| } |
| } |
| |
| IxEthAccStatus |
| ixEthAccPortDisablePriv(IxEthAccPortId portId) |
| { |
| IxEthAccStatus status = IX_ETH_ACC_SUCCESS; |
| int key; |
| int retry, retryTimeout; |
| volatile IxEthAccPortDisableState *state = &ixEthAccMacState[portId].portDisableState; |
| volatile IxEthAccPortDisableState *rxState = &ixEthAccMacState[portId].rxState; |
| volatile IxEthAccPortDisableState *txState = &ixEthAccMacState[portId].txState; |
| |
| IX_ETH_ACC_VALIDATE_PORT_ID(portId); |
| |
| if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId)) |
| { |
| IX_ETH_ACC_WARNING_LOG("EthAcc: Unavailable Eth %d: Cannot disable port.\n",(INT32)portId,0,0,0,0,0); |
| return IX_ETH_ACC_SUCCESS ; |
| } |
| |
| if (!IX_ETH_IS_PORT_INITIALIZED(portId)) |
| { |
| return (IX_ETH_ACC_PORT_UNINITIALIZED); |
| } |
| |
| /* if the state is being set to what it is already at, do nothing */ |
| if (!ixEthAccMacState[portId].enabled) |
| { |
| return IX_ETH_ACC_SUCCESS; |
| } |
| |
| *state = DISABLED; |
| |
| /* disable MAC receive first */ |
| ixEthAccPortRxDisablePriv(portId); |
| |
| #ifdef CONFIG_IXP425_COMPONENT_ETHDB |
| /* disable ethernet database for this port - It is done now to avoid |
| * issuing ELT maintenance after requesting 'port disable' in an NPE |
| */ |
| if (ixEthDBPortDisable(portId) != IX_ETH_DB_SUCCESS) |
| { |
| status = IX_ETH_ACC_FAIL; |
| IX_ETH_ACC_FATAL_LOG("ixEthAccPortDisable: failed to disable EthDB for this port\n", 0, 0, 0, 0, 0, 0); |
| } |
| #endif |
| |
| /* enter the critical section */ |
| key = ixOsalIrqLock(); |
| |
| /* swap the Rx and TxDone callbacks */ |
| ixEthAccPortDisableFn[portId] = ixEthAccPortData[portId].ixEthAccRxData.rxCallbackFn; |
| ixEthAccPortDisableMultiBufferFn[portId] = ixEthAccPortData[portId].ixEthAccRxData.rxMultiBufferCallbackFn; |
| ixEthAccPortDisableCbTag[portId] = ixEthAccPortData[portId].ixEthAccRxData.rxCallbackTag; |
| ixEthAccPortDisableMultiBufferCbTag[portId] = ixEthAccPortData[portId].ixEthAccRxData.rxMultiBufferCallbackTag; |
| ixEthAccPortDisableTxDoneFn[portId] = ixEthAccPortData[portId].ixEthAccTxData.txBufferDoneCallbackFn; |
| ixEthAccPortDisableTxDoneCbTag[portId] = ixEthAccPortData[portId].ixEthAccTxData.txCallbackTag; |
| ixEthAccPortDisableRxTable[portId] = ixEthAccPortDisableRx; |
| |
| /* register temporary callbacks */ |
| ixEthAccPortData[portId].ixEthAccRxData.rxCallbackFn = ixEthAccPortDisableRxCallback; |
| ixEthAccPortData[portId].ixEthAccRxData.rxCallbackTag = portId; |
| |
| ixEthAccPortData[portId].ixEthAccRxData.rxMultiBufferCallbackFn = ixEthAccPortDisableMultiBufferRxCallback; |
| ixEthAccPortData[portId].ixEthAccRxData.rxMultiBufferCallbackTag = portId; |
| |
| ixEthAccPortData[portId].ixEthAccTxData.txBufferDoneCallbackFn = ixEthAccPortDisableTxDone; |
| ixEthAccPortData[portId].ixEthAccTxData.txCallbackTag = portId; |
| |
| /* initialise the Rx state and Tx states */ |
| *txState = TRANSMIT_DONE; |
| *rxState = RECEIVE; |
| |
| /* exit the critical section */ |
| ixOsalIrqUnlock(key); |
| |
| /* enable a NPE loopback */ |
| if (ixEthAccNpeLoopbackEnablePriv(portId) != IX_ETH_ACC_SUCCESS) |
| { |
| status = IX_ETH_ACC_FAIL; |
| } |
| |
| if (status == IX_ETH_ACC_SUCCESS) |
| { |
| retry = 0; |
| |
| /* Step 1 : Drain Tx traffic and TxDone queues : |
| * |
| * Transmit and replenish at least once with the |
| * special buffers until both of them are seen |
| * in the callback hook |
| * |
| * (the receive callback keeps replenishing, so once we see |
| * the special Tx buffer, we can be sure that Tx drain is complete) |
| */ |
| ixEthAccPortDisableRxTable[portId] |
| = ixEthAccPortDisableRxAndReplenish; |
| ixEthAccPortData[portId].ixEthAccTxData.txBufferDoneCallbackFn |
| = ixEthAccPortDisableTxDone; |
| |
| do |
| { |
| /* keep replenishing */ |
| status = ixEthAccPortDisableTryReplenish(portId); |
| if (status == IX_ETH_ACC_SUCCESS) |
| { |
| /* keep transmitting */ |
| status = ixEthAccPortDisableTryTransmit(portId); |
| } |
| if (status == IX_ETH_ACC_SUCCESS) |
| { |
| /* wait for some traffic being processed */ |
| ixOsalSleep(IX_ETH_ACC_PORT_DISABLE_DELAY_MSECS); |
| } |
| } |
| while ((status == IX_ETH_ACC_SUCCESS) |
| && (retry++ < IX_ETH_ACC_MAX_RETRY) |
| && (*txState == TRANSMIT)); |
| |
| /* Step 2 : Drain Rx traffic, RxFree and Rx queues : |
| * |
| * Transmit and replenish at least once with the |
| * special buffers until both of them are seen |
| * in the callback hook |
| * (the transmit callback keeps transmitting, and when we see |
| * the special Rx buffer, we can be sure that rxFree drain |
| * is complete) |
| * |
| * The nested loop helps to retry if the user was keeping |
| * replenishing or transmitting during portDisable. |
| * |
| * The 2 nested loops ensure more retries if user traffic is |
| * seen during portDisable : the user should not replenish |
| * or transmit while portDisable is running. However, because of |
| * the queueing possibilities in ethAcc dataplane, it is possible |
| * that a lot of traffic is left in the queues (e.g. when |
| * transmitting over a low speed link) and therefore, more |
| * retries are allowed to help flushing the buffers out. |
| */ |
| ixEthAccPortDisableRxTable[portId] |
| = ixEthAccPortDisableRx; |
| ixEthAccPortData[portId].ixEthAccTxData.txBufferDoneCallbackFn |
| = ixEthAccPortDisableTxDoneAndSubmit; |
| |
| do |
| { |
| do |
| { |
| ixEthAccPortDisableUserBufferCount[portId] = 0; |
| |
| /* keep replenishing */ |
| status = ixEthAccPortDisableTryReplenish(portId); |
| if (status == IX_ETH_ACC_SUCCESS) |
| { |
| /* keep transmitting */ |
| status = ixEthAccPortDisableTryTransmit(portId); |
| } |
| if (status == IX_ETH_ACC_SUCCESS) |
| { |
| /* wait for some traffic being processed */ |
| ixOsalSleep(IX_ETH_ACC_PORT_DISABLE_DELAY_MSECS); |
| } |
| } |
| while ((status == IX_ETH_ACC_SUCCESS) |
| && (retry++ < IX_ETH_ACC_MAX_RETRY) |
| && ((ixEthAccPortDisableUserBufferCount[portId] != 0) |
| || (*rxState == REPLENISH))); |
| |
| /* After the first iteration, change the receive callbacks, |
| * to process only 1 buffer at a time |
| */ |
| ixEthAccPortDisableRxTable[portId] |
| = ixEthAccPortDisableRx; |
| ixEthAccPortData[portId].ixEthAccTxData.txBufferDoneCallbackFn |
| = ixEthAccPortDisableTxDone; |
| |
| /* repeat the whole process while user traffic is seen in TxDone |
| * |
| * The conditions to stop the loop are |
| * - Xscale has both Rx and Tx special buffers |
| * (txState = transmit, rxState = receive) |
| * - any error in txSubmit or rxReplenish |
| * - no user traffic seen |
| * - an excessive amount of retries |
| */ |
| } |
| while ((status == IX_ETH_ACC_SUCCESS) |
| && (retry < IX_ETH_ACC_MAX_RETRY) |
| && (*txState == TRANSMIT)); |
| |
| /* check the loop exit conditions. The NPE should not hold |
| * the special buffers. |
| */ |
| if ((*rxState == REPLENISH) || (*txState == TRANSMIT)) |
| { |
| status = IX_ETH_ACC_FAIL; |
| } |
| |
| if (status == IX_ETH_ACC_SUCCESS) |
| { |
| /* Step 3 : Replenish without transmitting until a timeout |
| * occurs, in order to drain the internal NPE fifos |
| * |
| * we can expect a few frames srill held |
| * in the NPE. |
| * |
| * The 2 nested loops take care about the NPE dropping traffic |
| * (including loopback traffic) when the Rx queue is full. |
| * |
| * The timeout value is very conservative |
| * since the loopback used keeps replenishhing. |
| * |
| */ |
| do |
| { |
| ixEthAccPortDisableRxTable[portId] = ixEthAccPortDisableRxAndReplenish; |
| ixEthAccPortDisableUserBufferCount[portId] = 0; |
| retryTimeout = 0; |
| do |
| { |
| /* keep replenishing */ |
| status = ixEthAccPortDisableTryReplenish(portId); |
| if (status == IX_ETH_ACC_SUCCESS) |
| { |
| /* wait for some traffic being processed */ |
| ixOsalSleep(IX_ETH_ACC_PORT_DISABLE_DELAY_MSECS); |
| } |
| } |
| while ((status == IX_ETH_ACC_SUCCESS) |
| && (retryTimeout++ < IX_ETH_ACC_MAX_RETRY_TIMEOUT)); |
| |
| /* Step 4 : Transmit once. Stop replenish |
| * |
| * After the Rx timeout, we are sure that the NPE does not |
| * hold any frame in its internal NPE fifos. |
| * |
| * At this point, the NPE still holds the last rxFree buffer. |
| * By transmitting a single frame, this should unblock the |
| * last rxFree buffer. This code just transmit once and |
| * wait for both frames seen in TxDone and in rxFree. |
| * |
| */ |
| ixEthAccPortDisableRxTable[portId] = ixEthAccPortDisableRx; |
| status = ixEthAccPortDisableTryTransmit(portId); |
| |
| /* the NPE should immediatelyt release |
| * the last Rx buffer and the last transmitted buffer |
| * unless the last Tx frame was dropped (rx queue full) |
| */ |
| if (status == IX_ETH_ACC_SUCCESS) |
| { |
| retryTimeout = 0; |
| do |
| { |
| ixOsalSleep(IX_ETH_ACC_PORT_DISABLE_DELAY_MSECS); |
| } |
| while ((*rxState == REPLENISH) |
| && (retryTimeout++ < IX_ETH_ACC_MAX_RETRY_TIMEOUT)); |
| } |
| |
| /* the NPE may have dropped the traffic because of Rx |
| * queue being full. This code ensures that the last |
| * Tx and Rx frames are both received. |
| */ |
| } |
| while ((status == IX_ETH_ACC_SUCCESS) |
| && (retry++ < IX_ETH_ACC_MAX_RETRY) |
| && ((*txState == TRANSMIT) |
| || (*rxState == REPLENISH) |
| || (ixEthAccPortDisableUserBufferCount[portId] != 0))); |
| |
| /* Step 5 : check the final states : the NPE has |
| * no buffer left, nor in Tx , nor in Rx directions. |
| */ |
| if ((*rxState == REPLENISH) || (*txState == TRANSMIT)) |
| { |
| status = IX_ETH_ACC_FAIL; |
| } |
| } |
| |
| /* now all the buffers are drained, disable NPE loopback |
| * This is done regardless of the logic to drain the queues and |
| * the internal buffers held by the NPE. |
| */ |
| if (ixEthAccNpeLoopbackDisablePriv(portId) != IX_ETH_ACC_SUCCESS) |
| { |
| status = IX_ETH_ACC_FAIL; |
| } |
| } |
| |
| /* disable MAC Tx and Rx services */ |
| ixEthAccMacState[portId].enabled = false; |
| ixEthAccMacStateUpdate(portId); |
| |
| /* restore the Rx and TxDone callbacks (within a critical section) */ |
| key = ixOsalIrqLock(); |
| |
| ixEthAccPortData[portId].ixEthAccRxData.rxCallbackFn = ixEthAccPortDisableFn[portId]; |
| ixEthAccPortData[portId].ixEthAccRxData.rxCallbackTag = ixEthAccPortDisableCbTag[portId]; |
| ixEthAccPortData[portId].ixEthAccRxData.rxMultiBufferCallbackFn = ixEthAccPortDisableMultiBufferFn[portId]; |
| ixEthAccPortData[portId].ixEthAccRxData.rxMultiBufferCallbackTag = ixEthAccPortDisableMultiBufferCbTag[portId]; |
| ixEthAccPortData[portId].ixEthAccTxData.txBufferDoneCallbackFn = ixEthAccPortDisableTxDoneFn[portId]; |
| ixEthAccPortData[portId].ixEthAccTxData.txCallbackTag = ixEthAccPortDisableTxDoneCbTag[portId]; |
| |
| ixOsalIrqUnlock(key); |
| |
| /* the MAC core rx/tx disable may left the MAC hardware in an |
| * unpredictable state. A hw reset is executed before resetting |
| * all the MAC parameters to a known value. |
| */ |
| REG_WRITE(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_CORE_CNTRL, |
| IX_ETH_ACC_CORE_RESET); |
| |
| ixOsalSleep(IX_ETH_ACC_MAC_RESET_DELAY); |
| |
| /* rewrite all parameters to their current value */ |
| ixEthAccMacStateUpdate(portId); |
| |
| REG_WRITE(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_INT_CLK_THRESH, |
| IX_ETH_ACC_MAC_INT_CLK_THRESH_DEFAULT); |
| |
| REG_WRITE(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_CORE_CNTRL, |
| IX_ETH_ACC_CORE_MDC_EN); |
| |
| return status; |
| } |
| |
| IxEthAccStatus |
| ixEthAccPortEnabledQueryPriv(IxEthAccPortId portId, BOOL *enabled) |
| { |
| IX_ETH_ACC_VALIDATE_PORT_ID(portId); |
| |
| if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId)) |
| { |
| IX_ETH_ACC_WARNING_LOG("EthAcc: Unavailable Eth %d: Cannot enable port.\n",(INT32)portId,0,0,0,0,0); |
| |
| /* Since Eth NPE is not available, port must be disabled */ |
| *enabled = false ; |
| return IX_ETH_ACC_SUCCESS ; |
| } |
| |
| if (!IX_ETH_IS_PORT_INITIALIZED(portId)) |
| { |
| /* Since Eth NPE is not available, port must be disabled */ |
| *enabled = false ; |
| return (IX_ETH_ACC_PORT_UNINITIALIZED); |
| } |
| |
| *enabled = ixEthAccMacState[portId].enabled; |
| |
| return IX_ETH_ACC_SUCCESS; |
| } |
| |
| IxEthAccStatus |
| ixEthAccPortMacResetPriv(IxEthAccPortId portId) |
| { |
| IX_ETH_ACC_VALIDATE_PORT_ID(portId); |
| |
| if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId)) |
| { |
| IX_ETH_ACC_WARNING_LOG("EthAcc: Eth %d: Cannot reset Ethernet coprocessor.\n",(INT32)portId,0,0,0,0,0); |
| return IX_ETH_ACC_SUCCESS ; |
| } |
| |
| if (!IX_ETH_IS_PORT_INITIALIZED(portId)) |
| { |
| return (IX_ETH_ACC_PORT_UNINITIALIZED); |
| } |
| |
| REG_WRITE(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_CORE_CNTRL, |
| IX_ETH_ACC_CORE_RESET); |
| |
| ixOsalSleep(IX_ETH_ACC_MAC_RESET_DELAY); |
| |
| /* rewrite all parameters to their current value */ |
| ixEthAccMacStateUpdate(portId); |
| |
| REG_WRITE(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_INT_CLK_THRESH, |
| IX_ETH_ACC_MAC_INT_CLK_THRESH_DEFAULT); |
| |
| REG_WRITE(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_CORE_CNTRL, |
| IX_ETH_ACC_CORE_MDC_EN); |
| |
| return IX_ETH_ACC_SUCCESS; |
| } |
| |
| IxEthAccStatus |
| ixEthAccPortLoopbackEnable(IxEthAccPortId portId) |
| { |
| UINT32 regval; |
| |
| /* Turn off promiscuous mode */ |
| IX_ETH_ACC_VALIDATE_PORT_ID(portId); |
| |
| if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId)) |
| { |
| IX_ETH_ACC_WARNING_LOG("EthAcc: Eth %d: Cannot enable loopback.\n",(INT32)portId,0,0,0,0,0); |
| return IX_ETH_ACC_SUCCESS ; |
| } |
| |
| if (!IX_ETH_IS_PORT_INITIALIZED(portId)) |
| { |
| return (IX_ETH_ACC_PORT_UNINITIALIZED); |
| } |
| |
| /* read register */ |
| REG_READ(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_RX_CNTRL1, |
| regval); |
| |
| /* update register */ |
| REG_WRITE(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_RX_CNTRL1, |
| regval | IX_ETH_ACC_RX_CNTRL1_LOOP_EN); |
| |
| return IX_ETH_ACC_SUCCESS; |
| } |
| |
| PRIVATE void |
| ixEthAccNpeLoopbackMessageCallback (IxNpeMhNpeId npeId, |
| IxNpeMhMessage msg) |
| { |
| IxEthAccPortId portId = IX_ETH_ACC_NPE_TO_PORT_ID(npeId); |
| |
| #ifndef NDEBUG |
| /* Prudent to at least check the port is within range */ |
| if (portId >= IX_ETH_ACC_NUMBER_OF_PORTS) |
| { |
| IX_ETH_ACC_FATAL_LOG("IXETHACC:ixEthAccPortDisableMessageCallback: Illegal port: %u\n", |
| (UINT32) portId, 0, 0, 0, 0, 0); |
| |
| return; |
| } |
| #endif |
| |
| /* unlock message reception mutex */ |
| ixOsalMutexUnlock(&ixEthAccMacState[portId].npeLoopbackMessageLock); |
| } |
| |
| IxEthAccStatus |
| ixEthAccNpeLoopbackEnablePriv(IxEthAccPortId portId) |
| { |
| IX_STATUS npeMhStatus; |
| IxNpeMhMessage message; |
| IxEthAccStatus status = IX_ETH_ACC_SUCCESS; |
| |
| /* Turn off promiscuous mode */ |
| IX_ETH_ACC_VALIDATE_PORT_ID(portId); |
| |
| if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId)) |
| { |
| IX_ETH_ACC_WARNING_LOG("EthAcc: Eth %d: Cannot enable NPE loopback.\n",(INT32)portId,0,0,0,0,0); |
| return IX_ETH_ACC_SUCCESS ; |
| } |
| |
| if (!IX_ETH_IS_PORT_INITIALIZED(portId)) |
| { |
| return (IX_ETH_ACC_PORT_UNINITIALIZED); |
| } |
| |
| /* enable NPE loopback (lsb of the message contains the value 1) */ |
| message.data[0] = (IX_ETHNPE_SETLOOPBACK_MODE << IX_ETH_ACC_MAC_MSGID_SHL) |
| | 0x01; |
| message.data[1] = 0; |
| |
| npeMhStatus = ixNpeMhMessageWithResponseSend(IX_ETH_ACC_PORT_TO_NPE_ID(portId), |
| message, |
| IX_ETHNPE_SETLOOPBACK_MODE_ACK, |
| ixEthAccNpeLoopbackMessageCallback, |
| IX_NPEMH_SEND_RETRIES_DEFAULT); |
| |
| if (npeMhStatus != IX_SUCCESS) |
| { |
| status = IX_ETH_ACC_FAIL; |
| } |
| else |
| { |
| /* wait for NPE loopbackEnable response */ |
| if (ixOsalMutexLock(&ixEthAccMacState[portId]. npeLoopbackMessageLock, |
| IX_ETH_ACC_PORT_DISABLE_DELAY_MSECS) |
| != IX_SUCCESS) |
| { |
| status = IX_ETH_ACC_FAIL; |
| } |
| } |
| |
| return status; |
| } |
| |
| IxEthAccStatus |
| ixEthAccPortTxEnablePriv(IxEthAccPortId portId) |
| { |
| UINT32 regval; |
| |
| /* Turn off promiscuous mode */ |
| IX_ETH_ACC_VALIDATE_PORT_ID(portId); |
| |
| if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId)) |
| { |
| IX_ETH_ACC_WARNING_LOG("EthAcc: Eth %d: Cannot enable TX.\n",(INT32)portId,0,0,0,0,0); |
| return IX_ETH_ACC_SUCCESS ; |
| } |
| |
| if (!IX_ETH_IS_PORT_INITIALIZED(portId)) |
| { |
| return (IX_ETH_ACC_PORT_UNINITIALIZED); |
| } |
| |
| /* read register */ |
| REG_READ(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_TX_CNTRL1, |
| regval); |
| |
| /* update register */ |
| REG_WRITE(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_TX_CNTRL1, |
| regval | IX_ETH_ACC_TX_CNTRL1_TX_EN); |
| |
| return IX_ETH_ACC_SUCCESS; |
| } |
| |
| IxEthAccStatus |
| ixEthAccPortRxEnablePriv(IxEthAccPortId portId) |
| { |
| UINT32 regval; |
| |
| /* Turn off promiscuous mode */ |
| IX_ETH_ACC_VALIDATE_PORT_ID(portId); |
| |
| if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId)) |
| { |
| IX_ETH_ACC_WARNING_LOG("EthAcc: Eth %d: Cannot enable RX.\n",(INT32)portId,0,0,0,0,0); |
| return IX_ETH_ACC_SUCCESS ; |
| } |
| |
| if (!IX_ETH_IS_PORT_INITIALIZED(portId)) |
| { |
| return (IX_ETH_ACC_PORT_UNINITIALIZED); |
| } |
| |
| /* read register */ |
| REG_READ(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_RX_CNTRL1, |
| regval); |
| |
| /* update register */ |
| REG_WRITE(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_RX_CNTRL1, |
| regval | IX_ETH_ACC_RX_CNTRL1_RX_EN); |
| |
| return IX_ETH_ACC_SUCCESS; |
| } |
| |
| IxEthAccStatus |
| ixEthAccPortLoopbackDisable(IxEthAccPortId portId) |
| { |
| UINT32 regval; |
| |
| IX_ETH_ACC_VALIDATE_PORT_ID(portId); |
| |
| if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId)) |
| { |
| IX_ETH_ACC_WARNING_LOG("EthAcc: Eth %d: Cannot disable loopback.\n",(INT32)portId,0,0,0,0,0); |
| return IX_ETH_ACC_SUCCESS ; |
| } |
| |
| if (!IX_ETH_IS_PORT_INITIALIZED(portId)) |
| { |
| return (IX_ETH_ACC_PORT_UNINITIALIZED); |
| } |
| |
| /*disable MAC loopabck */ |
| REG_READ(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_RX_CNTRL1, |
| regval); |
| |
| REG_WRITE(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_RX_CNTRL1, |
| (regval & ~IX_ETH_ACC_RX_CNTRL1_LOOP_EN)); |
| |
| return IX_ETH_ACC_SUCCESS; |
| } |
| |
| IxEthAccStatus |
| ixEthAccNpeLoopbackDisablePriv(IxEthAccPortId portId) |
| { |
| IX_STATUS npeMhStatus; |
| IxNpeMhMessage message; |
| IxEthAccStatus status = IX_ETH_ACC_SUCCESS; |
| |
| /* Turn off promiscuous mode */ |
| IX_ETH_ACC_VALIDATE_PORT_ID(portId); |
| |
| if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId)) |
| { |
| IX_ETH_ACC_WARNING_LOG("EthAcc: Eth %d: Cannot enable NPE loopback.\n",(INT32)portId,0,0,0,0,0); |
| return IX_ETH_ACC_SUCCESS ; |
| } |
| |
| if (!IX_ETH_IS_PORT_INITIALIZED(portId)) |
| { |
| return (IX_ETH_ACC_PORT_UNINITIALIZED); |
| } |
| |
| /* disable NPE loopback (lsb of the message contains the value 0) */ |
| message.data[0] = (IX_ETHNPE_SETLOOPBACK_MODE << IX_ETH_ACC_MAC_MSGID_SHL); |
| message.data[1] = 0; |
| |
| npeMhStatus = ixNpeMhMessageWithResponseSend(IX_ETH_ACC_PORT_TO_NPE_ID(portId), |
| message, |
| IX_ETHNPE_SETLOOPBACK_MODE_ACK, |
| ixEthAccNpeLoopbackMessageCallback, |
| IX_NPEMH_SEND_RETRIES_DEFAULT); |
| |
| if (npeMhStatus != IX_SUCCESS) |
| { |
| status = IX_ETH_ACC_FAIL; |
| } |
| else |
| { |
| /* wait for NPE loopbackEnable response */ |
| if (ixOsalMutexLock(&ixEthAccMacState[portId].npeLoopbackMessageLock, |
| IX_ETH_ACC_PORT_DISABLE_DELAY_MSECS) |
| != IX_SUCCESS) |
| { |
| status = IX_ETH_ACC_FAIL; |
| } |
| } |
| |
| return status; |
| } |
| |
| IxEthAccStatus |
| ixEthAccPortTxDisablePriv(IxEthAccPortId portId) |
| { |
| UINT32 regval; |
| |
| /* Turn off promiscuous mode */ |
| IX_ETH_ACC_VALIDATE_PORT_ID(portId); |
| |
| if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId)) |
| { |
| IX_ETH_ACC_WARNING_LOG("EthAcc: Eth %d: Cannot disable TX.\n", (INT32)portId,0,0,0,0,0); |
| return IX_ETH_ACC_SUCCESS ; |
| } |
| |
| if (!IX_ETH_IS_PORT_INITIALIZED(portId)) |
| { |
| return (IX_ETH_ACC_PORT_UNINITIALIZED); |
| } |
| |
| /* read register */ |
| REG_READ(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_TX_CNTRL1, |
| regval); |
| |
| /* update register */ |
| REG_WRITE(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_TX_CNTRL1, |
| (regval & ~IX_ETH_ACC_TX_CNTRL1_TX_EN)); |
| |
| return IX_ETH_ACC_SUCCESS; |
| } |
| |
| IxEthAccStatus |
| ixEthAccPortRxDisablePriv(IxEthAccPortId portId) |
| { |
| UINT32 regval; |
| |
| /* Turn off promiscuous mode */ |
| IX_ETH_ACC_VALIDATE_PORT_ID(portId); |
| |
| if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId)) |
| { |
| IX_ETH_ACC_WARNING_LOG("EthAcc: Eth %d: Cannot disable RX.\n", (INT32)portId,0,0,0,0,0); |
| return IX_ETH_ACC_SUCCESS ; |
| } |
| |
| if (!IX_ETH_IS_PORT_INITIALIZED(portId)) |
| { |
| return (IX_ETH_ACC_PORT_UNINITIALIZED); |
| } |
| |
| /* read register */ |
| REG_READ(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_RX_CNTRL1, |
| regval); |
| |
| /* update register */ |
| REG_WRITE(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_RX_CNTRL1, |
| (regval & ~IX_ETH_ACC_RX_CNTRL1_RX_EN)); |
| |
| return IX_ETH_ACC_SUCCESS; |
| } |
| |
| IxEthAccStatus |
| ixEthAccPortPromiscuousModeClearPriv(IxEthAccPortId portId) |
| { |
| UINT32 regval; |
| |
| /* Turn off promiscuous mode */ |
| IX_ETH_ACC_VALIDATE_PORT_ID(portId); |
| |
| if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId)) |
| { |
| IX_ETH_ACC_WARNING_LOG("EthAcc: Unavailable Eth %d: Cannot clear promiscuous mode.\n",(INT32)portId,0,0,0,0,0); |
| return IX_ETH_ACC_SUCCESS ; |
| } |
| |
| if (!IX_ETH_IS_PORT_INITIALIZED(portId)) |
| { |
| return (IX_ETH_ACC_PORT_UNINITIALIZED); |
| } |
| |
| /*set bit 5 of Rx control 1 - enable address filtering*/ |
| REG_READ(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_RX_CNTRL1, |
| regval); |
| |
| REG_WRITE(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_RX_CNTRL1, |
| regval | IX_ETH_ACC_RX_CNTRL1_ADDR_FLTR_EN); |
| |
| ixEthAccMacState[portId].promiscuous = false; |
| |
| ixEthAccMulticastAddressSet(portId); |
| |
| return IX_ETH_ACC_SUCCESS; |
| } |
| |
| IxEthAccStatus |
| ixEthAccPortPromiscuousModeSetPriv(IxEthAccPortId portId) |
| { |
| UINT32 regval; |
| |
| IX_ETH_ACC_VALIDATE_PORT_ID(portId); |
| |
| if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId)) |
| { |
| IX_ETH_ACC_WARNING_LOG("EthAcc: Unavailable Eth %d: Cannot set promiscuous mode.\n",(INT32)portId,0,0,0,0,0); |
| return IX_ETH_ACC_SUCCESS ; |
| } |
| |
| if (!IX_ETH_IS_PORT_INITIALIZED(portId)) |
| { |
| return (IX_ETH_ACC_PORT_UNINITIALIZED); |
| } |
| |
| /* |
| * Set bit 5 of Rx control 1 - We enable address filtering even in |
| * promiscuous mode because we want the MAC to set the appropriate |
| * bits in m_flags which doesn't happen if we turn off filtering. |
| */ |
| REG_READ(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_RX_CNTRL1, |
| regval); |
| |
| REG_WRITE(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_RX_CNTRL1, |
| regval | IX_ETH_ACC_RX_CNTRL1_ADDR_FLTR_EN); |
| |
| ixEthAccMacState[portId].promiscuous = true; |
| |
| ixEthAccMulticastAddressSet(portId); |
| |
| return IX_ETH_ACC_SUCCESS; |
| } |
| |
| IxEthAccStatus |
| ixEthAccPortUnicastMacAddressSetPriv (IxEthAccPortId portId, |
| IxEthAccMacAddr *macAddr) |
| { |
| UINT32 i; |
| |
| IX_ETH_ACC_VALIDATE_PORT_ID(portId); |
| |
| if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId)) |
| { |
| IX_ETH_ACC_WARNING_LOG("EthAcc: Unavailable Eth %d: Cannot set Unicast Mac Address.\n",(INT32)portId,0,0,0,0,0); |
| return IX_ETH_ACC_SUCCESS ; |
| } |
| |
| if (!IX_ETH_IS_PORT_INITIALIZED(portId)) |
| { |
| return (IX_ETH_ACC_PORT_UNINITIALIZED); |
| } |
| |
| |
| if (macAddr == NULL) |
| { |
| return IX_ETH_ACC_FAIL; |
| } |
| |
| if ( macAddr->macAddress[0] & IX_ETH_ACC_ETH_MAC_BCAST_MCAST_BIT ) |
| { |
| /* This is a multicast/broadcast address cant set it ! */ |
| return IX_ETH_ACC_FAIL; |
| } |
| |
| if ( macAddr->macAddress[0] == 0 && |
| macAddr->macAddress[1] == 0 && |
| macAddr->macAddress[2] == 0 && |
| macAddr->macAddress[3] == 0 && |
| macAddr->macAddress[4] == 0 && |
| macAddr->macAddress[5] == 0 ) |
| { |
| /* This is an invalid mac address cant set it ! */ |
| return IX_ETH_ACC_FAIL; |
| } |
| |
| #ifdef CONFIG_IXP425_COMPONENT_ETHDB |
| /* update the MAC address in the ethernet database */ |
| if (ixEthDBPortAddressSet(portId, (IxEthDBMacAddr *) macAddr) != IX_ETH_DB_SUCCESS) |
| { |
| return IX_ETH_ACC_FAIL; |
| } |
| #endif |
| |
| /*Set the Unicast MAC to the specified value*/ |
| for(i=0;i<IX_IEEE803_MAC_ADDRESS_SIZE;i++) |
| { |
| REG_WRITE(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_UNI_ADDR_1 + i*sizeof(UINT32), |
| macAddr->macAddress[i]); |
| } |
| ixEthAccMacState[portId].initDone = true; |
| |
| return IX_ETH_ACC_SUCCESS; |
| } |
| |
| IxEthAccStatus |
| ixEthAccPortUnicastMacAddressGetPriv (IxEthAccPortId portId, |
| IxEthAccMacAddr *macAddr) |
| { |
| /*Return the current value of the Unicast MAC from h/w |
| for the specified port*/ |
| UINT32 i; |
| |
| IX_ETH_ACC_VALIDATE_PORT_ID(portId); |
| |
| if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId)) |
| { |
| IX_ETH_ACC_WARNING_LOG("EthAcc: Unavailable Eth %d: Cannot get Unicast Mac Address.\n",(INT32)portId,0,0,0,0,0); |
| /* Since Eth Npe is unavailable, return invalid MAC Address = 00:00:00:00:00:00 */ |
| for(i=0;i<IX_IEEE803_MAC_ADDRESS_SIZE;i++) |
| { |
| macAddr->macAddress[i] = 0; |
| } |
| return IX_ETH_ACC_SUCCESS ; |
| } |
| |
| if(!ixEthAccMacState[portId].initDone) |
| { |
| return (IX_ETH_ACC_MAC_UNINITIALIZED); |
| } |
| |
| if (macAddr == NULL) |
| { |
| return IX_ETH_ACC_FAIL; |
| } |
| |
| |
| for(i=0;i<IX_IEEE803_MAC_ADDRESS_SIZE;i++) |
| { |
| REG_READ(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_UNI_ADDR_1 + i*sizeof(UINT32), |
| macAddr->macAddress[i]); |
| } |
| return IX_ETH_ACC_SUCCESS; |
| } |
| |
| PRIVATE IxEthAccStatus |
| ixEthAccPortMulticastMacAddressGet (IxEthAccPortId portId, |
| IxEthAccMacAddr *macAddr) |
| { |
| /*Return the current value of the Multicast MAC from h/w |
| for the specified port*/ |
| UINT32 i; |
| |
| for(i=0;i<IX_IEEE803_MAC_ADDRESS_SIZE;i++) |
| { |
| |
| REG_READ(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_ADDR_1 + i*sizeof(UINT32), |
| macAddr->macAddress[i]); |
| } |
| |
| return IX_ETH_ACC_SUCCESS; |
| } |
| |
| PRIVATE IxEthAccStatus |
| ixEthAccPortMulticastMacFilterGet (IxEthAccPortId portId, |
| IxEthAccMacAddr *macAddr) |
| { |
| /*Return the current value of the Multicast MAC from h/w |
| for the specified port*/ |
| UINT32 i; |
| |
| for(i=0;i<IX_IEEE803_MAC_ADDRESS_SIZE;i++) |
| { |
| |
| REG_READ(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_ADDR_MASK_1 + i*sizeof(UINT32), |
| macAddr->macAddress[i]); |
| } |
| return IX_ETH_ACC_SUCCESS; |
| } |
| |
| IxEthAccStatus |
| ixEthAccPortMulticastAddressJoinPriv (IxEthAccPortId portId, |
| IxEthAccMacAddr *macAddr) |
| { |
| UINT32 i; |
| IxEthAccMacAddr broadcastAddr = {{0xff,0xff,0xff,0xff,0xff,0xff}}; |
| |
| /*Check that the port parameter is valid*/ |
| IX_ETH_ACC_VALIDATE_PORT_ID(portId); |
| |
| if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId)) |
| { |
| IX_ETH_ACC_WARNING_LOG("EthAcc: Unavailable Eth %d: Cannot join Multicast Mac Address.\n",(INT32)portId,0,0,0,0,0); |
| return IX_ETH_ACC_SUCCESS ; |
| } |
| |
| if (!IX_ETH_IS_PORT_INITIALIZED(portId)) |
| { |
| return (IX_ETH_ACC_PORT_UNINITIALIZED); |
| } |
| |
| /*Check that the mac address is valid*/ |
| if(macAddr == NULL) |
| { |
| return IX_ETH_ACC_FAIL; |
| } |
| |
| /* Check that this is a multicast address */ |
| if (!(macAddr->macAddress[0] & IX_ETH_ACC_ETH_MAC_BCAST_MCAST_BIT)) |
| { |
| return IX_ETH_ACC_FAIL; |
| } |
| |
| /* We don't add the Broadcast address */ |
| if(ixEthAccMacEqual(&broadcastAddr, macAddr)) |
| { |
| return IX_ETH_ACC_FAIL; |
| } |
| |
| for (i = 0; |
| i<ixEthAccMacState[portId].mcastAddrIndex; |
| i++) |
| { |
| /*Check if the current entry already match an existing matches*/ |
| if(ixEthAccMacEqual(&ixEthAccMacState[portId].mcastAddrsTable[i], macAddr)) |
| { |
| /* Address found in the list and already configured, |
| * return a success status |
| */ |
| return IX_ETH_ACC_SUCCESS; |
| } |
| } |
| |
| /* check for availability at the end of the current table */ |
| if(ixEthAccMacState[portId].mcastAddrIndex >= IX_ETH_ACC_MAX_MULTICAST_ADDRESSES) |
| { |
| return IX_ETH_ACC_FAIL; |
| } |
| |
| /*First add the address to the multicast table for the |
| specified port*/ |
| i=ixEthAccMacState[portId].mcastAddrIndex; |
| |
| memcpy(&ixEthAccMacState[portId].mcastAddrsTable[i], |
| &macAddr->macAddress, |
| IX_IEEE803_MAC_ADDRESS_SIZE); |
| |
| /*Increment the index into the table, this must be done here |
| as MulticastAddressSet below needs to know about the latest |
| entry. |
| */ |
| ixEthAccMacState[portId].mcastAddrIndex++; |
| |
| /*Then calculate the new value to be written to the address and |
| address mask registers*/ |
| ixEthAccMulticastAddressSet(portId); |
| |
| return IX_ETH_ACC_SUCCESS; |
| } |
| |
| |
| IxEthAccStatus |
| ixEthAccPortMulticastAddressJoinAllPriv (IxEthAccPortId portId) |
| { |
| IxEthAccMacAddr mcastMacAddr = {{0x1,0x0,0x0,0x0,0x0,0x0}}; |
| |
| /*Check that the port parameter is valid*/ |
| IX_ETH_ACC_VALIDATE_PORT_ID(portId); |
| |
| if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId)) |
| { |
| IX_ETH_ACC_WARNING_LOG("EthAcc: Unavailable Eth %d: Cannot join all Multicast Address.\n",(INT32)portId,0,0,0,0,0); |
| return IX_ETH_ACC_SUCCESS ; |
| } |
| |
| if (!IX_ETH_IS_PORT_INITIALIZED(portId)) |
| { |
| return (IX_ETH_ACC_PORT_UNINITIALIZED); |
| } |
| |
| /* remove all entries from the database and |
| * insert a multicast entry |
| */ |
| memcpy(&ixEthAccMacState[portId].mcastAddrsTable[0], |
| &mcastMacAddr.macAddress, |
| IX_IEEE803_MAC_ADDRESS_SIZE); |
| |
| ixEthAccMacState[portId].mcastAddrIndex = 1; |
| ixEthAccMacState[portId].joinAll = true; |
| |
| ixEthAccMulticastAddressSet(portId); |
| |
| return IX_ETH_ACC_SUCCESS; |
| } |
| |
| IxEthAccStatus |
| ixEthAccPortMulticastAddressLeavePriv (IxEthAccPortId portId, |
| IxEthAccMacAddr *macAddr) |
| { |
| UINT32 i; |
| IxEthAccMacAddr mcastMacAddr = {{0x1,0x0,0x0,0x0,0x0,0x0}}; |
| |
| /*Check that the port parameter is valid*/ |
| IX_ETH_ACC_VALIDATE_PORT_ID(portId); |
| |
| if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId)) |
| { |
| IX_ETH_ACC_WARNING_LOG("EthAcc: Unavailable Eth %d: Cannot leave Multicast Address.\n",(INT32)portId,0,0,0,0,0); |
| return IX_ETH_ACC_SUCCESS ; |
| } |
| |
| if (!IX_ETH_IS_PORT_INITIALIZED(portId)) |
| { |
| return (IX_ETH_ACC_PORT_UNINITIALIZED); |
| } |
| |
| /*Check that the mac address is valid*/ |
| if(macAddr == NULL) |
| { |
| return IX_ETH_ACC_FAIL; |
| } |
| /* Remove this mac address from the mask for the specified port |
| * we copy down all entries above the blanked entry, and |
| * decrement the index |
| */ |
| i=0; |
| |
| while(i<ixEthAccMacState[portId].mcastAddrIndex) |
| { |
| /*Check if the current entry matches*/ |
| if(ixEthAccMacEqual(&ixEthAccMacState[portId].mcastAddrsTable[i], |
| macAddr)) |
| { |
| if(ixEthAccMacEqual(macAddr, &mcastMacAddr)) |
| { |
| ixEthAccMacState[portId].joinAll = false; |
| } |
| /*Decrement the index into the multicast address table |
| for the current port*/ |
| ixEthAccMacState[portId].mcastAddrIndex--; |
| |
| /*Copy down all entries above the current entry*/ |
| while(i<ixEthAccMacState[portId].mcastAddrIndex) |
| { |
| memcpy(&ixEthAccMacState[portId].mcastAddrsTable[i], |
| &ixEthAccMacState[portId].mcastAddrsTable[i+1], |
| IX_IEEE803_MAC_ADDRESS_SIZE); |
| i++; |
| } |
| /*recalculate the mask and write it to the MAC*/ |
| ixEthAccMulticastAddressSet(portId); |
| |
| return IX_ETH_ACC_SUCCESS; |
| } |
| /* search the next entry */ |
| i++; |
| } |
| /* no matching entry found */ |
| return IX_ETH_ACC_NO_SUCH_ADDR; |
| } |
| |
| IxEthAccStatus |
| ixEthAccPortMulticastAddressLeaveAllPriv (IxEthAccPortId portId) |
| { |
| /*Check that the port parameter is valid*/ |
| IX_ETH_ACC_VALIDATE_PORT_ID(portId); |
| |
| if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId)) |
| { |
| IX_ETH_ACC_WARNING_LOG("EthAcc: Unavailable Eth %d: Cannot leave all Multicast Address.\n",(INT32)portId,0,0,0,0,0); |
| return IX_ETH_ACC_SUCCESS ; |
| } |
| |
| if (!IX_ETH_IS_PORT_INITIALIZED(portId)) |
| { |
| return (IX_ETH_ACC_PORT_UNINITIALIZED); |
| } |
| |
| ixEthAccMacState[portId].mcastAddrIndex = 0; |
| ixEthAccMacState[portId].joinAll = false; |
| |
| ixEthAccMulticastAddressSet(portId); |
| |
| return IX_ETH_ACC_SUCCESS; |
| } |
| |
| |
| IxEthAccStatus |
| ixEthAccPortUnicastAddressShowPriv (IxEthAccPortId portId) |
| { |
| IxEthAccMacAddr macAddr; |
| |
| IX_ETH_ACC_VALIDATE_PORT_ID(portId); |
| |
| if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId)) |
| { |
| IX_ETH_ACC_WARNING_LOG("EthAcc: Unavailable Eth %d: Cannot show Unicast Address.\n",(INT32)portId,0,0,0,0,0); |
| return IX_ETH_ACC_SUCCESS ; |
| } |
| |
| if (!IX_ETH_IS_PORT_INITIALIZED(portId)) |
| { |
| return (IX_ETH_ACC_PORT_UNINITIALIZED); |
| } |
| |
| /*Get the MAC (UINICAST) address from hardware*/ |
| if(ixEthAccPortUnicastMacAddressGetPriv(portId, &macAddr) != IX_ETH_ACC_SUCCESS) |
| { |
| IX_ETH_ACC_WARNING_LOG("EthAcc: MAC address uninitialised port %u\n", |
| (INT32)portId,0,0,0,0,0); |
| return IX_ETH_ACC_MAC_UNINITIALIZED; |
| } |
| |
| /*print it out*/ |
| ixEthAccMacPrint(&macAddr); |
| printf("\n"); |
| return IX_ETH_ACC_SUCCESS; |
| } |
| |
| |
| |
| void |
| ixEthAccPortMulticastAddressShowPriv(IxEthAccPortId portId) |
| { |
| IxEthAccMacAddr macAddr; |
| UINT32 i; |
| |
| if(!IX_ETH_ACC_IS_PORT_VALID(portId)) |
| { |
| return; |
| } |
| |
| if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId)) |
| { |
| IX_ETH_ACC_WARNING_LOG("EthAcc: Unavailable Eth %d: Cannot show Multicast Address.\n",(INT32)portId,0,0,0,0,0); |
| return ; |
| } |
| |
| if (!IX_ETH_IS_PORT_INITIALIZED(portId)) |
| { |
| return; |
| } |
| |
| printf("Multicast MAC: "); |
| /*Get the MAC (MULTICAST) address from hardware*/ |
| ixEthAccPortMulticastMacAddressGet(portId, &macAddr); |
| /*print it out*/ |
| ixEthAccMacPrint(&macAddr); |
| /*Get the MAC (MULTICAST) filter from hardware*/ |
| ixEthAccPortMulticastMacFilterGet(portId, &macAddr); |
| /*print it out*/ |
| printf(" ( "); |
| ixEthAccMacPrint(&macAddr); |
| printf(" )\n"); |
| printf("Constituent Addresses:\n"); |
| for(i=0;i<ixEthAccMacState[portId].mcastAddrIndex;i++) |
| { |
| ixEthAccMacPrint(&ixEthAccMacState[portId].mcastAddrsTable[i]); |
| printf("\n"); |
| } |
| return; |
| } |
| |
| /*Set the duplex mode*/ |
| IxEthAccStatus |
| ixEthAccPortDuplexModeSetPriv (IxEthAccPortId portId, |
| IxEthAccDuplexMode mode) |
| { |
| UINT32 txregval; |
| UINT32 rxregval; |
| |
| /*This is bit 1 of the transmit control reg, set to 1 for half |
| duplex, 0 for full duplex*/ |
| IX_ETH_ACC_VALIDATE_PORT_ID(portId); |
| |
| if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId)) |
| { |
| IX_ETH_ACC_WARNING_LOG("EthAcc: Unavailable Eth %d: Cannot set Duplex Mode.\n",(INT32)portId,0,0,0,0,0); |
| return IX_ETH_ACC_SUCCESS ; |
| } |
| |
| if (!IX_ETH_IS_PORT_INITIALIZED(portId)) |
| { |
| return (IX_ETH_ACC_PORT_UNINITIALIZED); |
| } |
| |
| REG_READ(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_TX_CNTRL1, |
| txregval); |
| |
| REG_READ(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_RX_CNTRL1, |
| rxregval); |
| |
| if (mode == IX_ETH_ACC_FULL_DUPLEX) |
| { |
| /*Clear half duplex bit in TX*/ |
| REG_WRITE(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_TX_CNTRL1, |
| txregval & ~IX_ETH_ACC_TX_CNTRL1_DUPLEX); |
| |
| /*We must set the pause enable in the receive logic when in |
| full duplex mode*/ |
| REG_WRITE(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_RX_CNTRL1, |
| rxregval | IX_ETH_ACC_RX_CNTRL1_PAUSE_EN); |
| ixEthAccMacState[portId].fullDuplex = true; |
| |
| } |
| else if (mode == IX_ETH_ACC_HALF_DUPLEX) |
| { |
| /*Set half duplex bit in TX*/ |
| REG_WRITE(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_TX_CNTRL1, |
| txregval | IX_ETH_ACC_TX_CNTRL1_DUPLEX); |
| |
| /*We must clear pause enable in the receive logic when in |
| half duplex mode*/ |
| REG_WRITE(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_RX_CNTRL1, |
| rxregval & ~IX_ETH_ACC_RX_CNTRL1_PAUSE_EN); |
| |
| ixEthAccMacState[portId].fullDuplex = false; |
| } |
| else |
| { |
| return IX_ETH_ACC_FAIL; |
| } |
| |
| |
| return IX_ETH_ACC_SUCCESS; |
| |
| } |
| |
| |
| |
| IxEthAccStatus |
| ixEthAccPortDuplexModeGetPriv (IxEthAccPortId portId, |
| IxEthAccDuplexMode *mode) |
| { |
| /*Return the duplex mode for the specified port*/ |
| UINT32 regval; |
| |
| /*This is bit 1 of the transmit control reg, set to 1 for half |
| duplex, 0 for full duplex*/ |
| IX_ETH_ACC_VALIDATE_PORT_ID(portId); |
| |
| if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId)) |
| { |
| IX_ETH_ACC_WARNING_LOG("EthAcc: Unavailable Eth %d: Cannot get Duplex Mode.\n",(INT32)portId,0,0,0,0,0); |
| /* return hald duplex */ |
| *mode = IX_ETH_ACC_HALF_DUPLEX ; |
| return IX_ETH_ACC_SUCCESS ; |
| } |
| |
| if (!IX_ETH_IS_PORT_INITIALIZED(portId)) |
| { |
| return (IX_ETH_ACC_PORT_UNINITIALIZED); |
| } |
| |
| if (mode == NULL) |
| { |
| return (IX_ETH_ACC_FAIL); |
| } |
| |
| REG_READ(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_TX_CNTRL1, |
| regval); |
| |
| if( regval & IX_ETH_ACC_TX_CNTRL1_DUPLEX) |
| { |
| *mode = IX_ETH_ACC_HALF_DUPLEX; |
| } |
| else |
| { |
| *mode = IX_ETH_ACC_FULL_DUPLEX; |
| } |
| |
| return IX_ETH_ACC_SUCCESS; |
| } |
| |
| |
| |
| IxEthAccStatus |
| ixEthAccPortTxFrameAppendPaddingEnablePriv (IxEthAccPortId portId) |
| { |
| UINT32 regval; |
| /*Enable FCS computation by the MAC and appending to the |
| frame*/ |
| |
| IX_ETH_ACC_VALIDATE_PORT_ID(portId); |
| |
| if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId)) |
| { |
| IX_ETH_ACC_WARNING_LOG("EthAcc: Unavailable Eth %d: Cannot enable Tx Frame Append Padding.\n",(INT32)portId,0,0,0,0,0); |
| return IX_ETH_ACC_SUCCESS ; |
| } |
| |
| if (!IX_ETH_IS_PORT_INITIALIZED(portId)) |
| { |
| return (IX_ETH_ACC_PORT_UNINITIALIZED); |
| } |
| |
| REG_READ(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_TX_CNTRL1, |
| regval); |
| |
| REG_WRITE(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_TX_CNTRL1, |
| regval | |
| IX_ETH_ACC_TX_CNTRL1_PAD_EN); |
| |
| ixEthAccMacState[portId].txPADAppend = true; |
| return IX_ETH_ACC_SUCCESS; |
| } |
| |
| IxEthAccStatus |
| ixEthAccPortTxFrameAppendPaddingDisablePriv (IxEthAccPortId portId) |
| { |
| UINT32 regval; |
| |
| /*disable FCS computation and appending*/ |
| /*Set bit 4 of Tx control register one to zero*/ |
| IX_ETH_ACC_VALIDATE_PORT_ID(portId); |
| |
| if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId)) |
| { |
| IX_ETH_ACC_WARNING_LOG("EthAcc: Unavailable Eth %d: Cannot disble Tx Frame Append Padding.\n",(INT32)portId,0,0,0,0,0); |
| return IX_ETH_ACC_SUCCESS ; |
| } |
| |
| if (!IX_ETH_IS_PORT_INITIALIZED(portId)) |
| { |
| return (IX_ETH_ACC_PORT_UNINITIALIZED); |
| } |
| |
| REG_READ(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_TX_CNTRL1, |
| regval); |
| |
| REG_WRITE(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_TX_CNTRL1, |
| regval & ~IX_ETH_ACC_TX_CNTRL1_PAD_EN); |
| |
| ixEthAccMacState[portId].txPADAppend = false; |
| return IX_ETH_ACC_SUCCESS; |
| } |
| |
| IxEthAccStatus |
| ixEthAccPortTxFrameAppendFCSEnablePriv (IxEthAccPortId portId) |
| { |
| UINT32 regval; |
| |
| /*Enable FCS computation by the MAC and appending to the |
| frame*/ |
| |
| IX_ETH_ACC_VALIDATE_PORT_ID(portId); |
| |
| if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId)) |
| { |
| IX_ETH_ACC_WARNING_LOG("EthAcc: Unavailable Eth %d: Cannot enable Tx Frame Append FCS.\n",(INT32)portId,0,0,0,0,0); |
| return IX_ETH_ACC_SUCCESS ; |
| } |
| |
| if (!IX_ETH_IS_PORT_INITIALIZED(portId)) |
| { |
| return (IX_ETH_ACC_PORT_UNINITIALIZED); |
| } |
| |
| REG_READ(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_TX_CNTRL1, |
| regval); |
| |
| REG_WRITE(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_TX_CNTRL1, |
| regval | IX_ETH_ACC_TX_CNTRL1_FCS_EN); |
| |
| ixEthAccMacState[portId].txFCSAppend = true; |
| return IX_ETH_ACC_SUCCESS; |
| } |
| |
| IxEthAccStatus |
| ixEthAccPortTxFrameAppendFCSDisablePriv (IxEthAccPortId portId) |
| { |
| UINT32 regval; |
| |
| /*disable FCS computation and appending*/ |
| /*Set bit 4 of Tx control register one to zero*/ |
| IX_ETH_ACC_VALIDATE_PORT_ID(portId); |
| |
| if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId)) |
| { |
| IX_ETH_ACC_WARNING_LOG("EthAcc: Unavailable Eth %d: Cannot disable Tx Frame Append FCS.\n",(INT32)portId,0,0,0,0,0); |
| return IX_ETH_ACC_SUCCESS ; |
| } |
| |
| if (!IX_ETH_IS_PORT_INITIALIZED(portId)) |
| { |
| return (IX_ETH_ACC_PORT_UNINITIALIZED); |
| } |
| |
| REG_READ(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_TX_CNTRL1, |
| regval); |
| |
| REG_WRITE(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_TX_CNTRL1, |
| regval & ~IX_ETH_ACC_TX_CNTRL1_FCS_EN); |
| |
| ixEthAccMacState[portId].txFCSAppend = false; |
| return IX_ETH_ACC_SUCCESS; |
| } |
| |
| IxEthAccStatus |
| ixEthAccPortRxFrameAppendFCSEnablePriv (IxEthAccPortId portId) |
| { |
| /*Set bit 2 of Rx control 1*/ |
| UINT32 regval; |
| |
| IX_ETH_ACC_VALIDATE_PORT_ID(portId); |
| |
| if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId)) |
| { |
| IX_ETH_ACC_WARNING_LOG("EthAcc: Unavailable Eth %d: Cannot enable Rx Frame Append FCS.\n",(INT32)portId,0,0,0,0,0); |
| return IX_ETH_ACC_SUCCESS ; |
| } |
| |
| if (!IX_ETH_IS_PORT_INITIALIZED(portId)) |
| { |
| return (IX_ETH_ACC_PORT_UNINITIALIZED); |
| } |
| |
| REG_READ(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_RX_CNTRL1, |
| regval); |
| |
| REG_WRITE(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_RX_CNTRL1, |
| regval | IX_ETH_ACC_RX_CNTRL1_CRC_EN); |
| |
| ixEthAccMacState[portId].rxFCSAppend = true; |
| return IX_ETH_ACC_SUCCESS; |
| } |
| |
| IxEthAccStatus |
| ixEthAccPortRxFrameAppendFCSDisablePriv (IxEthAccPortId portId) |
| { |
| UINT32 regval; |
| |
| /*Clear bit 2 of Rx control 1*/ |
| IX_ETH_ACC_VALIDATE_PORT_ID(portId); |
| |
| if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId)) |
| { |
| IX_ETH_ACC_WARNING_LOG("EthAcc: Unavailable Eth %d: Cannot disable Rx Frame Append FCS.\n",(INT32)portId,0,0,0,0,0); |
| return IX_ETH_ACC_SUCCESS ; |
| } |
| |
| if (!IX_ETH_IS_PORT_INITIALIZED(portId)) |
| { |
| return (IX_ETH_ACC_PORT_UNINITIALIZED); |
| } |
| |
| REG_READ(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_RX_CNTRL1, |
| regval); |
| |
| REG_WRITE(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_RX_CNTRL1, |
| regval & ~IX_ETH_ACC_RX_CNTRL1_CRC_EN); |
| |
| ixEthAccMacState[portId].rxFCSAppend = false; |
| return IX_ETH_ACC_SUCCESS; |
| } |
| |
| |
| |
| PRIVATE void |
| ixEthAccMacNpeStatsMessageCallback (IxNpeMhNpeId npeId, |
| IxNpeMhMessage msg) |
| { |
| IxEthAccPortId portId = IX_ETH_ACC_NPE_TO_PORT_ID(npeId); |
| |
| #ifndef NDEBUG |
| /* Prudent to at least check the port is within range */ |
| if (portId >= IX_ETH_ACC_NUMBER_OF_PORTS) |
| { |
| IX_ETH_ACC_FATAL_LOG( |
| "IXETHACC:ixEthAccMacNpeStatsMessageCallback: Illegal port: %u\n", |
| (UINT32)portId, 0, 0, 0, 0, 0); |
| return; |
| } |
| #endif |
| |
| /*Unblock Stats Get call*/ |
| ixOsalMutexUnlock(&ixEthAccMacState[portId].ackMIBStatsLock); |
| |
| } |
| |
| PRIVATE void |
| ixEthAccMibIIStatsEndianConvert (IxEthEthObjStats *retStats) |
| { |
| /* endianness conversion */ |
| |
| /* Rx stats */ |
| retStats->dot3StatsAlignmentErrors = |
| IX_OSAL_SWAP_BE_SHARED_LONG(retStats->dot3StatsAlignmentErrors); |
| retStats->dot3StatsFCSErrors = |
| IX_OSAL_SWAP_BE_SHARED_LONG(retStats->dot3StatsFCSErrors); |
| retStats->dot3StatsInternalMacReceiveErrors = |
| IX_OSAL_SWAP_BE_SHARED_LONG(retStats->dot3StatsInternalMacReceiveErrors); |
| retStats->RxOverrunDiscards = |
| IX_OSAL_SWAP_BE_SHARED_LONG(retStats->RxOverrunDiscards); |
| retStats->RxLearnedEntryDiscards = |
| IX_OSAL_SWAP_BE_SHARED_LONG(retStats->RxLearnedEntryDiscards); |
| retStats->RxLargeFramesDiscards = |
| IX_OSAL_SWAP_BE_SHARED_LONG(retStats->RxLargeFramesDiscards); |
| retStats->RxSTPBlockedDiscards = |
| IX_OSAL_SWAP_BE_SHARED_LONG(retStats->RxSTPBlockedDiscards); |
| retStats->RxVLANTypeFilterDiscards = |
| IX_OSAL_SWAP_BE_SHARED_LONG(retStats->RxVLANTypeFilterDiscards); |
| retStats->RxVLANIdFilterDiscards = |
| IX_OSAL_SWAP_BE_SHARED_LONG(retStats->RxVLANIdFilterDiscards); |
| retStats->RxInvalidSourceDiscards = |
| IX_OSAL_SWAP_BE_SHARED_LONG(retStats->RxInvalidSourceDiscards); |
| retStats->RxBlackListDiscards = |
| IX_OSAL_SWAP_BE_SHARED_LONG(retStats->RxBlackListDiscards); |
| retStats->RxWhiteListDiscards = |
| IX_OSAL_SWAP_BE_SHARED_LONG(retStats->RxWhiteListDiscards); |
| retStats->RxUnderflowEntryDiscards = |
| IX_OSAL_SWAP_BE_SHARED_LONG(retStats->RxUnderflowEntryDiscards); |
| |
| /* Tx stats */ |
| retStats->dot3StatsSingleCollisionFrames = |
| IX_OSAL_SWAP_BE_SHARED_LONG(retStats->dot3StatsSingleCollisionFrames); |
| retStats->dot3StatsMultipleCollisionFrames = |
| IX_OSAL_SWAP_BE_SHARED_LONG(retStats->dot3StatsMultipleCollisionFrames); |
| retStats->dot3StatsDeferredTransmissions = |
| IX_OSAL_SWAP_BE_SHARED_LONG(retStats->dot3StatsDeferredTransmissions); |
| retStats->dot3StatsLateCollisions = |
| IX_OSAL_SWAP_BE_SHARED_LONG(retStats->dot3StatsLateCollisions); |
| retStats->dot3StatsExcessiveCollsions = |
| IX_OSAL_SWAP_BE_SHARED_LONG(retStats->dot3StatsExcessiveCollsions); |
| retStats->dot3StatsInternalMacTransmitErrors = |
| IX_OSAL_SWAP_BE_SHARED_LONG(retStats->dot3StatsInternalMacTransmitErrors); |
| retStats->dot3StatsCarrierSenseErrors = |
| IX_OSAL_SWAP_BE_SHARED_LONG(retStats->dot3StatsCarrierSenseErrors); |
| retStats->TxLargeFrameDiscards = |
| IX_OSAL_SWAP_BE_SHARED_LONG(retStats->TxLargeFrameDiscards); |
| retStats->TxVLANIdFilterDiscards = |
| IX_OSAL_SWAP_BE_SHARED_LONG(retStats->TxVLANIdFilterDiscards); |
| } |
| |
| IxEthAccStatus |
| ixEthAccMibIIStatsGet (IxEthAccPortId portId, |
| IxEthEthObjStats *retStats ) |
| { |
| IxNpeMhMessage message; |
| |
| if (!IX_ETH_ACC_IS_SERVICE_INITIALIZED()) |
| { |
| printf("EthAcc: ixEthAccMibIIStatsGet (Mac) EthAcc service is not initialized\n"); |
| return (IX_ETH_ACC_FAIL); |
| } |
| |
| IX_ETH_ACC_VALIDATE_PORT_ID(portId); |
| |
| if (retStats == NULL) |
| { |
| printf("EthAcc: ixEthAccMibIIStatsGet (Mac) NULL argument\n"); |
| return (IX_ETH_ACC_FAIL); |
| } |
| |
| if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId)) |
| { |
| printf("EthAcc: ixEthAccMibIIStatsGet (Mac) NPE for port %d is not available\n", portId); |
| |
| IX_ETH_ACC_WARNING_LOG("EthAcc: Unavailable Eth %d: Cannot get MIB II Stats.\n",(INT32)portId,0,0,0,0,0); |
| |
| /* Return all zero stats */ |
| IX_ETH_ACC_MEMSET(retStats, 0, sizeof(IxEthEthObjStats)); |
| |
| return IX_ETH_ACC_SUCCESS ; |
| } |
| |
| if (!IX_ETH_IS_PORT_INITIALIZED(portId)) |
| { |
| printf("EthAcc: ixEthAccMibIIStatsGet (Mac) port %d is not initialized\n", portId); |
| return (IX_ETH_ACC_PORT_UNINITIALIZED); |
| } |
| |
| IX_OSAL_CACHE_INVALIDATE(retStats, sizeof(IxEthEthObjStats)); |
| |
| message.data[0] = IX_ETHNPE_GETSTATS << IX_ETH_ACC_MAC_MSGID_SHL; |
| message.data[1] = (UINT32) IX_OSAL_MMU_VIRT_TO_PHYS(retStats); |
| |
| /* Permit only one task to request MIB statistics Get operation |
| at a time */ |
| ixOsalMutexLock(&ixEthAccMacState[portId].MIBStatsGetAccessLock, IX_OSAL_WAIT_FOREVER); |
| |
| if(ixNpeMhMessageWithResponseSend(IX_ETH_ACC_PORT_TO_NPE_ID(portId), |
| message, |
| IX_ETHNPE_GETSTATS, |
| ixEthAccMacNpeStatsMessageCallback, |
| IX_NPEMH_SEND_RETRIES_DEFAULT) |
| != IX_SUCCESS) |
| { |
| ixOsalMutexUnlock(&ixEthAccMacState[portId].MIBStatsGetAccessLock); |
| |
| printf("EthAcc: (Mac) StatsGet failed to send NPE message\n"); |
| |
| return IX_ETH_ACC_FAIL; |
| } |
| |
| /* Wait for callback invocation indicating response to |
| this request - we need this mutex in order to ensure |
| that the return from this function is synchronous */ |
| ixOsalMutexLock(&ixEthAccMacState[portId].ackMIBStatsLock, IX_ETH_ACC_MIB_STATS_DELAY_MSECS); |
| |
| /* Permit other tasks to perform MIB statistics Get operation */ |
| ixOsalMutexUnlock(&ixEthAccMacState[portId].MIBStatsGetAccessLock); |
| |
| ixEthAccMibIIStatsEndianConvert (retStats); |
| |
| return IX_ETH_ACC_SUCCESS; |
| } |
| |
| |
| PRIVATE void |
| ixEthAccMacNpeStatsResetMessageCallback (IxNpeMhNpeId npeId, |
| IxNpeMhMessage msg) |
| { |
| IxEthAccPortId portId = IX_ETH_ACC_NPE_TO_PORT_ID(npeId); |
| |
| #ifndef NDEBUG |
| /* Prudent to at least check the port is within range */ |
| if (portId >= IX_ETH_ACC_NUMBER_OF_PORTS) |
| { |
| IX_ETH_ACC_FATAL_LOG( |
| "IXETHACC:ixEthAccMacNpeStatsResetMessageCallback: Illegal port: %u\n", |
| (UINT32)portId, 0, 0, 0, 0, 0); |
| return; |
| } |
| #endif |
| |
| /*Unblock Stats Get & reset call*/ |
| ixOsalMutexUnlock(&ixEthAccMacState[portId].ackMIBStatsResetLock); |
| |
| } |
| |
| |
| |
| IxEthAccStatus |
| ixEthAccMibIIStatsGetClear (IxEthAccPortId portId, |
| IxEthEthObjStats *retStats) |
| { |
| IxNpeMhMessage message; |
| |
| if (!IX_ETH_ACC_IS_SERVICE_INITIALIZED()) |
| { |
| printf("EthAcc: ixEthAccMibIIStatsGetClear (Mac) EthAcc service is not initialized\n"); |
| return (IX_ETH_ACC_FAIL); |
| } |
| |
| IX_ETH_ACC_VALIDATE_PORT_ID(portId); |
| |
| if (retStats == NULL) |
| { |
| printf("EthAcc: ixEthAccMibIIStatsGetClear (Mac) NULL argument\n"); |
| return (IX_ETH_ACC_FAIL); |
| } |
| |
| if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId)) |
| { |
| printf("EthAcc: ixEthAccMibIIStatsGetClear (Mac) NPE for port %d is not available\n", portId); |
| |
| IX_ETH_ACC_WARNING_LOG("EthAcc: Unavailable Eth %d: Cannot get and clear MIB II Stats.\n", (INT32)portId, 0, 0, 0, 0, 0); |
| |
| /* Return all zero stats */ |
| IX_ETH_ACC_MEMSET(retStats, 0, sizeof(IxEthEthObjStats)); |
| |
| return IX_ETH_ACC_SUCCESS ; |
| } |
| |
| if (!IX_ETH_IS_PORT_INITIALIZED(portId)) |
| { |
| printf("EthAcc: ixEthAccMibIIStatsGetClear (Mac) port %d is not initialized\n", portId); |
| return (IX_ETH_ACC_PORT_UNINITIALIZED); |
| } |
| |
| IX_OSAL_CACHE_INVALIDATE(retStats, sizeof(IxEthEthObjStats)); |
| |
| message.data[0] = IX_ETHNPE_RESETSTATS << IX_ETH_ACC_MAC_MSGID_SHL; |
| message.data[1] = (UINT32) IX_OSAL_MMU_VIRT_TO_PHYS(retStats); |
| |
| /* Permit only one task to request MIB statistics Get-Reset operation at a time */ |
| ixOsalMutexLock(&ixEthAccMacState[portId].MIBStatsGetResetAccessLock, IX_OSAL_WAIT_FOREVER); |
| |
| if(ixNpeMhMessageWithResponseSend(IX_ETH_ACC_PORT_TO_NPE_ID(portId), |
| message, |
| IX_ETHNPE_RESETSTATS, |
| ixEthAccMacNpeStatsResetMessageCallback, |
| IX_NPEMH_SEND_RETRIES_DEFAULT) |
| != IX_SUCCESS) |
| { |
| ixOsalMutexUnlock(&ixEthAccMacState[portId].MIBStatsGetResetAccessLock); |
| |
| printf("EthAcc: (Mac) ixEthAccMibIIStatsGetClear failed to send NPE message\n"); |
| |
| return IX_ETH_ACC_FAIL; |
| } |
| |
| /* Wait for callback invocation indicating response to this request */ |
| ixOsalMutexLock(&ixEthAccMacState[portId].ackMIBStatsResetLock, IX_ETH_ACC_MIB_STATS_DELAY_MSECS); |
| |
| /* permit other tasks to get and reset MIB stats*/ |
| ixOsalMutexUnlock(&ixEthAccMacState[portId].MIBStatsGetResetAccessLock); |
| |
| ixEthAccMibIIStatsEndianConvert(retStats); |
| |
| return IX_ETH_ACC_SUCCESS; |
| } |
| |
| IxEthAccStatus |
| ixEthAccMibIIStatsClear (IxEthAccPortId portId) |
| { |
| static IxEthEthObjStats retStats; |
| IxEthAccStatus status; |
| |
| if (!IX_ETH_ACC_IS_SERVICE_INITIALIZED()) |
| { |
| return (IX_ETH_ACC_FAIL); |
| } |
| |
| IX_ETH_ACC_VALIDATE_PORT_ID(portId); |
| |
| if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId)) |
| { |
| IX_ETH_ACC_WARNING_LOG("EthAcc: Unavailable Eth %d: Cannot clear MIB II Stats.\n",(INT32)portId,0,0,0,0,0); |
| return IX_ETH_ACC_SUCCESS ; |
| } |
| |
| /* there is no reset operation without a corresponding Get */ |
| status = ixEthAccMibIIStatsGetClear(portId, &retStats); |
| |
| return status; |
| } |
| |
| /* Initialize the ethernet MAC settings */ |
| IxEthAccStatus |
| ixEthAccMacInit(IxEthAccPortId portId) |
| { |
| IX_OSAL_MBUF_POOL* portDisablePool; |
| UINT8 *data; |
| |
| IX_ETH_ACC_VALIDATE_PORT_ID(portId); |
| |
| if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId)) |
| { |
| IX_ETH_ACC_WARNING_LOG("EthAcc: Unavailable Eth %d: Cannot initialize Mac.\n",(INT32)portId,0,0,0,0,0); |
| return IX_ETH_ACC_SUCCESS ; |
| } |
| |
| if(ixEthAccMacState[portId].macInitialised == false) |
| { |
| ixEthAccMacState[portId].fullDuplex = true; |
| ixEthAccMacState[portId].rxFCSAppend = true; |
| ixEthAccMacState[portId].txFCSAppend = true; |
| ixEthAccMacState[portId].txPADAppend = true; |
| ixEthAccMacState[portId].enabled = false; |
| ixEthAccMacState[portId].promiscuous = true; |
| ixEthAccMacState[portId].joinAll = false; |
| ixEthAccMacState[portId].initDone = false; |
| ixEthAccMacState[portId].macInitialised = true; |
| |
| /* initialize MIB stats mutexes */ |
| ixOsalMutexInit(&ixEthAccMacState[portId].ackMIBStatsLock); |
| ixOsalMutexLock(&ixEthAccMacState[portId].ackMIBStatsLock, IX_OSAL_WAIT_FOREVER); |
| |
| ixOsalMutexInit(&ixEthAccMacState[portId].ackMIBStatsResetLock); |
| ixOsalMutexLock(&ixEthAccMacState[portId].ackMIBStatsResetLock, IX_OSAL_WAIT_FOREVER); |
| |
| ixOsalMutexInit(&ixEthAccMacState[portId].MIBStatsGetAccessLock); |
| |
| ixOsalMutexInit(&ixEthAccMacState[portId].MIBStatsGetResetAccessLock); |
| |
| ixOsalMutexInit(&ixEthAccMacState[portId].npeLoopbackMessageLock); |
| |
| ixEthAccMacState[portId].portDisableRxMbufPtr = NULL; |
| ixEthAccMacState[portId].portDisableTxMbufPtr = NULL; |
| |
| portDisablePool = IX_OSAL_MBUF_POOL_INIT(2, |
| IX_ETHACC_RX_MBUF_MIN_SIZE, |
| "portDisable Pool"); |
| |
| IX_OSAL_ENSURE(portDisablePool != NULL, "Failed to initialize PortDisable pool"); |
| |
| ixEthAccMacState[portId].portDisableRxMbufPtr = IX_OSAL_MBUF_POOL_GET(portDisablePool); |
| ixEthAccMacState[portId].portDisableTxMbufPtr = IX_OSAL_MBUF_POOL_GET(portDisablePool); |
| |
| IX_OSAL_ENSURE(ixEthAccMacState[portId].portDisableRxMbufPtr != NULL, |
| "Pool allocation failed"); |
| IX_OSAL_ENSURE(ixEthAccMacState[portId].portDisableTxMbufPtr != NULL, |
| "Pool allocation failed"); |
| /* fill the payload of the Rx mbuf used in portDisable */ |
| IX_OSAL_MBUF_MLEN(ixEthAccMacState[portId].portDisableRxMbufPtr) = IX_ETHACC_RX_MBUF_MIN_SIZE; |
| |
| memset(IX_OSAL_MBUF_MDATA(ixEthAccMacState[portId].portDisableRxMbufPtr), |
| 0xAA, |
| IX_ETHACC_RX_MBUF_MIN_SIZE); |
| |
| /* fill the payload of the Tx mbuf used in portDisable (64 bytes) */ |
| IX_OSAL_MBUF_MLEN(ixEthAccMacState[portId].portDisableTxMbufPtr) = 64; |
| IX_OSAL_MBUF_PKT_LEN(ixEthAccMacState[portId].portDisableTxMbufPtr) = 64; |
| |
| data = (UINT8 *) IX_OSAL_MBUF_MDATA(ixEthAccMacState[portId].portDisableTxMbufPtr); |
| memset(data, 0xBB, 64); |
| data[0] = 0x00; /* unicast destination MAC address */ |
| data[6] = 0x00; /* unicast source MAC address */ |
| data[12] = 0x08; /* typelength : IP frame */ |
| data[13] = 0x00; /* typelength : IP frame */ |
| |
| IX_OSAL_CACHE_FLUSH(data, 64); |
| } |
| |
| IX_OSAL_ASSERT (ixEthAccMacBase[portId] != 0); |
| |
| REG_WRITE(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_CORE_CNTRL, |
| IX_ETH_ACC_CORE_RESET); |
| |
| ixOsalSleep(IX_ETH_ACC_MAC_RESET_DELAY); |
| |
| REG_WRITE(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_CORE_CNTRL, |
| IX_ETH_ACC_CORE_MDC_EN); |
| |
| REG_WRITE(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_INT_CLK_THRESH, |
| IX_ETH_ACC_MAC_INT_CLK_THRESH_DEFAULT); |
| |
| ixEthAccMacStateUpdate(portId); |
| |
| return IX_ETH_ACC_SUCCESS; |
| } |
| |
| /* PRIVATE Functions*/ |
| |
| PRIVATE void |
| ixEthAccMacStateUpdate(IxEthAccPortId portId) |
| { |
| UINT32 regval; |
| |
| if ( ixEthAccMacState[portId].enabled == false ) |
| { |
| /* Just disable both the transmitter and reciver in the MAC. */ |
| REG_READ(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_RX_CNTRL1, |
| regval); |
| REG_WRITE(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_RX_CNTRL1, |
| regval & ~IX_ETH_ACC_RX_CNTRL1_RX_EN); |
| |
| REG_READ(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_TX_CNTRL1, |
| regval); |
| REG_WRITE(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_TX_CNTRL1, |
| regval & ~IX_ETH_ACC_TX_CNTRL1_TX_EN); |
| } |
| |
| if(ixEthAccMacState[portId].fullDuplex) |
| { |
| ixEthAccPortDuplexModeSetPriv (portId, IX_ETH_ACC_FULL_DUPLEX); |
| } |
| else |
| { |
| ixEthAccPortDuplexModeSetPriv (portId, IX_ETH_ACC_HALF_DUPLEX); |
| } |
| |
| if(ixEthAccMacState[portId].rxFCSAppend) |
| { |
| ixEthAccPortRxFrameAppendFCSEnablePriv (portId); |
| } |
| else |
| { |
| ixEthAccPortRxFrameAppendFCSDisablePriv (portId); |
| } |
| |
| if(ixEthAccMacState[portId].txFCSAppend) |
| { |
| ixEthAccPortTxFrameAppendFCSEnablePriv (portId); |
| } |
| else |
| { |
| ixEthAccPortTxFrameAppendFCSDisablePriv (portId); |
| } |
| |
| if(ixEthAccMacState[portId].txPADAppend) |
| { |
| ixEthAccPortTxFrameAppendPaddingEnablePriv (portId); |
| } |
| else |
| { |
| ixEthAccPortTxFrameAppendPaddingDisablePriv (portId); |
| } |
| |
| if(ixEthAccMacState[portId].promiscuous) |
| { |
| ixEthAccPortPromiscuousModeSetPriv(portId); |
| } |
| else |
| { |
| ixEthAccPortPromiscuousModeClearPriv(portId); |
| } |
| |
| if ( ixEthAccMacState[portId].enabled == true ) |
| { |
| /* Enable both the transmitter and reciver in the MAC. */ |
| REG_READ(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_RX_CNTRL1, |
| regval); |
| REG_WRITE(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_RX_CNTRL1, |
| regval | IX_ETH_ACC_RX_CNTRL1_RX_EN); |
| |
| REG_READ(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_TX_CNTRL1, |
| regval); |
| REG_WRITE(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_TX_CNTRL1, |
| regval | IX_ETH_ACC_TX_CNTRL1_TX_EN); |
| } |
| } |
| |
| |
| PRIVATE BOOL |
| ixEthAccMacEqual(IxEthAccMacAddr *macAddr1, |
| IxEthAccMacAddr *macAddr2) |
| { |
| UINT32 i; |
| for(i=0;i<IX_IEEE803_MAC_ADDRESS_SIZE; i++) |
| { |
| if(macAddr1->macAddress[i] != macAddr2->macAddress[i]) |
| { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| PRIVATE void |
| ixEthAccMacPrint(IxEthAccMacAddr *m) |
| { |
| printf("%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x", |
| m->macAddress[0], m->macAddress[1], |
| m->macAddress[2], m->macAddress[3], |
| m->macAddress[4], m->macAddress[5]); |
| } |
| |
| /* Set the multicast address and address mask registers |
| * |
| * A bit in the address mask register must be set if |
| * all multicast addresses always have that bit set, or if |
| * all multicast addresses always have that bit cleared. |
| * |
| * A bit in the address register must be set if all multicast |
| * addresses have that bit set, otherwise, it should be cleared |
| */ |
| |
| PRIVATE void |
| ixEthAccMulticastAddressSet(IxEthAccPortId portId) |
| { |
| UINT32 i; |
| UINT32 j; |
| IxEthAccMacAddr addressMask; |
| IxEthAccMacAddr address; |
| IxEthAccMacAddr alwaysClearBits; |
| IxEthAccMacAddr alwaysSetBits; |
| |
| /* calculate alwaysClearBits and alwaysSetBits: |
| * alwaysClearBits is calculated by ORing all |
| * multicast addresses, those bits that are always |
| * clear are clear in the result |
| * |
| * alwaysSetBits is calculated by ANDing all |
| * multicast addresses, those bits that are always set |
| * are set in the result |
| */ |
| |
| if (ixEthAccMacState[portId].promiscuous == true) |
| { |
| /* Promiscuous Mode is set, and filtering |
| * allow all packets, and enable the mcast and |
| * bcast detection. |
| */ |
| memset(&addressMask.macAddress, |
| 0, |
| IX_IEEE803_MAC_ADDRESS_SIZE); |
| memset(&address.macAddress, |
| 0, |
| IX_IEEE803_MAC_ADDRESS_SIZE); |
| } |
| else |
| { |
| if(ixEthAccMacState[portId].joinAll == true) |
| { |
| /* Join all is set. The mask and address are |
| * the multicast settings. |
| */ |
| IxEthAccMacAddr macAddr = {{0x1,0x0,0x0,0x0,0x0,0x0}}; |
| |
| memcpy(addressMask.macAddress, |
| macAddr.macAddress, |
| IX_IEEE803_MAC_ADDRESS_SIZE); |
| memcpy(address.macAddress, |
| macAddr.macAddress, |
| IX_IEEE803_MAC_ADDRESS_SIZE); |
| } |
| else if(ixEthAccMacState[portId].mcastAddrIndex == 0) |
| { |
| /* No entry in the filtering database, |
| * Promiscuous Mode is cleared, Broadcast filtering |
| * is configured. |
| */ |
| memset(addressMask.macAddress, |
| IX_ETH_ACC_MAC_ALL_BITS_SET, |
| IX_IEEE803_MAC_ADDRESS_SIZE); |
| memset(address.macAddress, |
| IX_ETH_ACC_MAC_ALL_BITS_SET, |
| IX_IEEE803_MAC_ADDRESS_SIZE); |
| } |
| else |
| { |
| /* build a mask and an address which mix all entreis |
| * from the list of multicast addresses |
| */ |
| memset(alwaysClearBits.macAddress, |
| 0, |
| IX_IEEE803_MAC_ADDRESS_SIZE); |
| memset(alwaysSetBits.macAddress, |
| IX_ETH_ACC_MAC_ALL_BITS_SET, |
| IX_IEEE803_MAC_ADDRESS_SIZE); |
| |
| for(i=0;i<ixEthAccMacState[portId].mcastAddrIndex;i++) |
| { |
| for(j=0;j<IX_IEEE803_MAC_ADDRESS_SIZE;j++) |
| { |
| alwaysClearBits.macAddress[j] |= |
| ixEthAccMacState[portId].mcastAddrsTable[i].macAddress[j]; |
| alwaysSetBits.macAddress[j] &= |
| ixEthAccMacState[portId].mcastAddrsTable[i].macAddress[j]; |
| } |
| } |
| |
| for(i=0;i<IX_IEEE803_MAC_ADDRESS_SIZE;i++) |
| { |
| addressMask.macAddress[i] = alwaysSetBits.macAddress[i] |
| | ~alwaysClearBits.macAddress[i]; |
| address.macAddress[i] = alwaysSetBits.macAddress[i]; |
| } |
| } |
| } |
| |
| /*write the new addr filtering to h/w*/ |
| for(i=0;i<IX_IEEE803_MAC_ADDRESS_SIZE;i++) |
| { |
| REG_WRITE(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_ADDR_MASK_1+i*sizeof(UINT32), |
| addressMask.macAddress[i]); |
| REG_WRITE(ixEthAccMacBase[portId], |
| IX_ETH_ACC_MAC_ADDR_1+i*sizeof(UINT32), |
| address.macAddress[i]); |
| } |
| } |