📄 ixethaccmac.c
字号:
} 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 voidixEthAccPortDisableRxAndReplenish (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 voidixEthAccPortDisableRxCallback (UINT32 cbTag, IX_OSAL_MBUF * mBufPtr, UINT32 learnedPortId){ IxEthAccPortId portId = (IxEthAccPortId)cbTag; /* call the portDisable receive callback */ (ixEthAccPortDisableRxTable[portId])(portId, mBufPtr, FALSE);}PRIVATE voidixEthAccPortDisableMultiBufferRxCallback (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); }}IxEthAccStatusixEthAccPortDisablePriv(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_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); /* 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); } /* 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;}IxEthAccStatusixEthAccPortEnabledQueryPriv(IxEthAccPortId portId, BOOL *enabled){ IX_ETH_ACC_VALIDATE_PORT_ID(portId); 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_IS_PORT_INITIALIZED(portId)) { return (IX_ETH_ACC_PORT_UNINITIALIZED); } /* Reset MAC core */ 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); /* Reconfigure 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,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -