📄 ixethaccdataplane.c
字号:
/* Convert the mbuf header after NPE transmission * Since there is nothing changed by the NPE, there is no need * to process anything but the update of internal stats * when they are enabled*/PRIVATE voidixEthAccMbufFromTxQ(IX_OSAL_MBUF *mbuf){#ifndef NDEBUG /* test for unchained mbufs */ if (IX_ETHACC_NE_NEXT(mbuf) == 0) { /* unchained mbufs : update the stats */ IX_ETH_ACC_STATS_INC(ixEthAccDataStats.unchainedTxDoneMBufs); } else { /* chained mbufs : walk the chain and update the stats */ IX_OSAL_MBUF *ptr = mbuf; do { IX_ETH_ACC_STATS_INC(ixEthAccDataStats.chainedTxDoneMBufs); ptr = IX_OSAL_MBUF_NEXT_BUFFER_IN_PKT_PTR(ptr); } while (ptr != NULL); }#endif}/* Convert the mbuf header after NPE reception */PRIVATE voidixEthAccMbufFromRxQ(IX_OSAL_MBUF *mbuf){ UINT32 len; /* endianess swap for tci and flags note: this is done only once, even for chained buffers */ IX_ETHACC_NE_FLAGS(mbuf) = IX_OSAL_SWAP_BE_SHARED_SHORT(IX_ETHACC_NE_FLAGS(mbuf)); IX_ETHACC_NE_VLANTCI(mbuf) = IX_OSAL_SWAP_BE_SHARED_SHORT(IX_ETHACC_NE_VLANTCI(mbuf)); /* test for unchained mbufs */ if (IX_ETHACC_NE_NEXT(mbuf) == 0) { /* unchained mbufs */ IX_ETH_ACC_STATS_INC(ixEthAccDataStats.unchainedRxMBufs); /* get the frame length. it is the same than the buffer length */ len = IX_OSAL_SWAP_BE_SHARED_LONG(IX_ETHACC_NE_LEN(mbuf)); len &= IX_ETHNPE_ACC_PKTLENGTH_MASK; IX_OSAL_MBUF_PKT_LEN(mbuf) = IX_OSAL_MBUF_MLEN(mbuf) = len; /* clears the next packet field */ IX_OSAL_MBUF_NEXT_BUFFER_IN_PKT_PTR(mbuf) = NULL; } else { IX_OSAL_MBUF *ptr = mbuf; IX_OSAL_MBUF *nextPtr; UINT32 frmLen; /* convert the frame length */ frmLen = IX_OSAL_SWAP_BE_SHARED_LONG(IX_ETHACC_NE_LEN(mbuf)); IX_OSAL_MBUF_PKT_LEN(mbuf) = (frmLen & IX_ETHNPE_ACC_PKTLENGTH_MASK); /* chained mbufs */ do { IX_ETH_ACC_STATS_INC(ixEthAccDataStats.chainedRxMBufs); /* convert the length */ len = IX_OSAL_SWAP_BE_SHARED_LONG(IX_ETHACC_NE_LEN(ptr)); IX_OSAL_MBUF_MLEN(ptr) = (len >> IX_ETHNPE_ACC_LENGTH_OFFSET); /* get the next pointer */ PTR_NPE2VIRT(IX_OSAL_MBUF *,IX_ETHACC_NE_NEXT(ptr), nextPtr); if (nextPtr != NULL) { nextPtr = (IX_OSAL_MBUF *)((UINT8 *)nextPtr - offsetof(IX_OSAL_MBUF,ix_ne)); } /* set the next pointer */ IX_OSAL_MBUF_NEXT_BUFFER_IN_PKT_PTR(ptr) = nextPtr; /* move to the next buffer */ ptr = nextPtr; } while (ptr != NULL); }}/* write to qmgr if possible and report an overflow if not possible * Use a fast lock to protect the queue write. * This way, the tx feature is reentrant. */PRIVATE IX_STATUSixEthAccQmgrLockTxWrite(IxEthAccPortId portId, UINT32 qBuffer){ IX_STATUS qStatus; if (ixOsalFastMutexTryLock(&txWriteMutex[portId]) == IX_SUCCESS) { qStatus = ixQMgrQWrite( IX_ETH_ACC_PORT_TO_TX_Q_ID(portId), &qBuffer);#ifndef NDEBUG if (qStatus != IX_SUCCESS) { TX_STATS_INC(portId, txOverflow); }#endif ixOsalFastMutexUnlock(&txWriteMutex[portId]); } else { TX_STATS_INC(portId, txLock); qStatus = IX_QMGR_Q_OVERFLOW; } return qStatus;}/* write to qmgr if possible and report an overflow if not possible * Use a fast lock to protect the queue write. * This way, the Rx feature is reentrant. */PRIVATE IX_STATUSixEthAccQmgrLockRxWrite(IxEthAccPortId portId, UINT32 qBuffer){ IX_STATUS qStatus; if (ixOsalFastMutexTryLock(&rxWriteMutex[portId]) == IX_SUCCESS) { qStatus = ixQMgrQWrite( IX_ETH_ACC_PORT_TO_RX_FREE_Q_ID(portId), &qBuffer);#ifndef NDEBUG if (qStatus != IX_SUCCESS) { RX_STATS_INC(portId, rxFreeOverflow); }#endif ixOsalFastMutexUnlock(&rxWriteMutex[portId]); } else { RX_STATS_INC(portId, rxFreeLock); qStatus = IX_QMGR_Q_OVERFLOW; } return qStatus;}/* * Set the priority and write to a qmgr queue. */PRIVATE IX_STATUSixEthAccQmgrTxWrite(IxEthAccPortId portId, UINT32 qBuffer, UINT32 priority){ /* fill the priority field */ qBuffer |= (priority << IX_ETHNPE_QM_Q_FIELD_PRIOR_R); return ixEthAccQmgrLockTxWrite(portId, qBuffer);}/** * * @brief This function will discover the highest priority S/W Tx Q that * has entries in it * * @param portId - (in) the id of the port whose S/W Tx queues are to be searched * priorityPtr - (out) the priority of the highest priority occupied q will be written * here * * @return IX_ETH_ACC_SUCCESS if an occupied Q is found * IX_ETH_ACC_FAIL if no Q has entries * * @internal */PRIVATE IxEthAccStatusixEthAccTxSwQHighestPriorityGet(IxEthAccPortId portId, IxEthAccTxPriority *priorityPtr){ if (ixEthAccPortData[portId].ixEthAccTxData.schDiscipline == FIFO_NO_PRIORITY) { if(IX_ETH_ACC_DATAPLANE_IS_Q_EMPTY(ixEthAccPortData[portId]. ixEthAccTxData.txQ[IX_ETH_ACC_TX_DEFAULT_PRIORITY])) { return IX_ETH_ACC_FAIL; } else { *priorityPtr = IX_ETH_ACC_TX_DEFAULT_PRIORITY; TX_STATS_INC(portId,txPriority[*priorityPtr]); return IX_ETH_ACC_SUCCESS; } } else { IxEthAccTxPriority highestPriority = IX_ETH_ACC_TX_PRIORITY_7; while(1) { if(!IX_ETH_ACC_DATAPLANE_IS_Q_EMPTY(ixEthAccPortData[portId]. ixEthAccTxData.txQ[highestPriority])) { *priorityPtr = highestPriority; TX_STATS_INC(portId,txPriority[highestPriority]); return IX_ETH_ACC_SUCCESS; } if (highestPriority == IX_ETH_ACC_TX_PRIORITY_0) { return IX_ETH_ACC_FAIL; } highestPriority--; } }}/** * * @brief This function will take a buffer from a TX S/W Q and attempt * to add it to the relevant TX H/W Q * * @param portId - the port whose TX queue is to be written to * priority - identifies the queue from which the entry is to be read * * @internal */PRIVATE IxEthAccStatusixEthAccTxFromSwQ(IxEthAccPortId portId, IxEthAccTxPriority priority){ IX_OSAL_MBUF *mbuf; IX_STATUS qStatus; IX_OSAL_ENSURE((UINT32)priority <= (UINT32)7, "Invalid priority"); IX_ETH_ACC_DATAPLANE_REMOVE_MBUF_FROM_Q_HEAD( ixEthAccPortData[portId].ixEthAccTxData.txQ[priority], mbuf); if (mbuf != NULL) { /* * Add the Tx buffer to the H/W Tx Q * We do not need to flush here as it is already done * in TxFrameSubmit(). */ qStatus = ixEthAccQmgrTxWrite( portId, IX_OSAL_MMU_VIRT_TO_PHYS((UINT32)IX_ETHACC_NE_SHARED(mbuf)), priority); if (qStatus == IX_SUCCESS) { TX_STATS_INC(portId,txFromSwQOK); return IX_SUCCESS; } else if (qStatus == IX_QMGR_Q_OVERFLOW) { /* * H/W Q overflow, need to save the buffer * back on the s/w Q. * we must put it back on the head of the q to avoid * reordering packet tx */ TX_STATS_INC(portId,txFromSwQDelayed); IX_ETH_ACC_DATAPLANE_ADD_MBUF_TO_Q_HEAD( ixEthAccPortData[portId].ixEthAccTxData.txQ[priority], mbuf); /*enable Q notification*/ qStatus = ixQMgrNotificationEnable( IX_ETH_ACC_PORT_TO_TX_Q_ID(portId), IX_ETH_ACC_PORT_TO_TX_Q_SOURCE(portId)); if (qStatus != IX_SUCCESS && qStatus != IX_QMGR_WARNING) { TX_INC(portId,txUnexpectedError); IX_ETH_ACC_FATAL_LOG( "ixEthAccTxFromSwQ:Unexpected Error: %u\n", qStatus, 0, 0, 0, 0, 0); } } else { TX_INC(portId,txUnexpectedError); /* recovery attempt */ IX_ETH_ACC_DATAPLANE_ADD_MBUF_TO_Q_HEAD( ixEthAccPortData[portId].ixEthAccTxData.txQ[priority], mbuf); IX_ETH_ACC_FATAL_LOG( "ixEthAccTxFromSwQ:Error: unexpected QM status 0x%08X\n", qStatus, 0, 0, 0, 0, 0); } } else { /* sw queue is empty */ } return IX_ETH_ACC_FAIL;}/** * * @brief This function will take a buffer from a RXfree S/W Q and attempt * to add it to the relevant RxFree H/W Q * * @param portId - the port whose RXFree queue is to be written to * * @internal */PRIVATE IxEthAccStatusixEthAccRxFreeFromSwQ(IxEthAccPortId portId){ IX_OSAL_MBUF *mbuf; IX_STATUS qStatus = IX_SUCCESS; IX_ETH_ACC_DATAPLANE_REMOVE_MBUF_FROM_Q_HEAD( ixEthAccPortData[portId].ixEthAccRxData.freeBufferList, mbuf); if (mbuf != NULL) { /* * Add The Rx Buffer to the H/W Free buffer Q if possible */ qStatus = ixEthAccQmgrLockRxWrite(portId, IX_OSAL_MMU_VIRT_TO_PHYS( (UINT32)IX_ETHACC_NE_SHARED(mbuf))); if (qStatus == IX_SUCCESS) { RX_STATS_INC(portId,rxFreeRepFromSwQOK); /* * Buffer added to h/w Q. */ return IX_SUCCESS; } else if (qStatus == IX_QMGR_Q_OVERFLOW) { /* * H/W Q overflow, need to save the buffer back on the s/w Q. */ RX_STATS_INC(portId,rxFreeRepFromSwQDelayed); IX_ETH_ACC_DATAPLANE_ADD_MBUF_TO_Q_HEAD( ixEthAccPortData[portId].ixEthAccRxData.freeBufferList, mbuf); } else { /* unexpected qmgr error */ RX_INC(portId,rxUnexpectedError); IX_ETH_ACC_DATAPLANE_ADD_MBUF_TO_Q_HEAD( ixEthAccPortData[portId].ixEthAccRxData.freeBufferList, mbuf); IX_ETH_ACC_FATAL_LOG("IxEthAccRxFreeFromSwQ:Error: unexpected QM status 0x%08X\n", qStatus, 0, 0, 0, 0, 0); } } else { /* sw queue is empty */ } return IX_ETH_ACC_FAIL;}IX_ETH_ACC_PUBLICIxEthAccStatus ixEthAccInitDataPlane(){ UINT32 portId; /* * Initialize the service and register callback to other services. */ IX_ETH_ACC_MEMSET(&ixEthAccDataStats, 0, sizeof(ixEthAccDataStats)); for(portId=0; portId < IX_ETH_ACC_NUMBER_OF_PORTS; portId++) { ixOsalFastMutexInit(&txWriteMutex[portId]); ixOsalFastMutexInit(&rxWriteMutex[portId]); IX_ETH_ACC_MEMSET(&ixEthAccPortData[portId], 0, sizeof(ixEthAccPortData[portId])); ixEthAccPortData[portId].ixEthAccTxData.schDiscipline = FIFO_NO_PRIORITY; } return (IX_ETH_ACC_SUCCESS);}IX_ETH_ACC_PUBLICIxEthAccStatus ixEthAccPortTxDoneCallbackRegister(IxEthAccPortId portId, IxEthAccPortTxDoneCallback txCallbackFn, UINT32 callbackTag){ if (!IX_ETH_ACC_IS_SERVICE_INITIALIZED()) { return (IX_ETH_ACC_FAIL); } if (!IX_ETH_ACC_IS_PORT_VALID(portId)) { return (IX_ETH_ACC_INVALID_PORT); }/* HACK: removing this code to enable NPE-A preliminary testing * if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId)) * { * IX_ETH_ACC_WARNING_LOG("ixEthAccPortTxDoneCallbackRegister: Unavailable Eth %d: Cannot register TxDone Callback.\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 (txCallbackFn == 0) /* Check for null function pointer here. */ { return (IX_ETH_ACC_INVALID_ARG); } ixEthAccPortData[portId].ixEthAccTxData.txBufferDoneCallbackFn = txCallbackFn; ixEthAccPortData[portId].ixEthAccTxData.txCallbackTag = callbackTag; return (IX_ETH_ACC_SUCCESS);}IX_ETH_ACC_PUBLICIxEthAccStatus ixEthAccPortRxCallbackRegister(IxEthAccPortId portId, IxEthAccPortRxCallback rxCallbackFn, UINT32 callbackTag){ IxEthAccPortId port; if (!IX_ETH_ACC_IS_SERVICE_INITIALIZED()) { return (IX_ETH_ACC_FAIL); } if (!IX_ETH_ACC_IS_PORT_VALID(portId)) { return (IX_ETH_ACC_INVALID_PORT); } if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId)) { IX_ETH_ACC_WARNING_LOG("ixEthAccPortRxCallbackRegister: Unavailable Eth %d: Cannot register Rx Callback.\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 for null function pointer here. */ if (rxCallbackFn == NULL) { return (IX_ETH_ACC_INVALID_ARG); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -