📄 ixethaccdataplane.c
字号:
IX_ETHACC_NE_LEN(ptr) = IX_OSAL_SWAP_BE_SHARED_LONG(len); /* flush shared header after all address conversions */ IX_ETHACC_NE_CACHE_FLUSH(ptr); /* remove shared header cache line */ IX_ETHACC_NE_CACHE_INVALIDATE(ptr); /* next mbuf in the chain */ ptr = nextPtr; } while(ptr != NULL); } /* virt2phys mbuf itself */ qbuf = (UINT32)IX_OSAL_MMU_VIRT_TO_PHYS( IX_ETHACC_NE_SHARED(mbuf)); /* Ensure the bits which are reserved to exchange information with * the NPE are cleared * * If the mbuf address is not correctly aligned, or from an * incompatible memory range, there is no point to continue */ IX_OSAL_ENSURE(((qbuf & ~IX_ETHNPE_QM_Q_RXENET_ADDR_MASK) == 0), "Invalid address range"); return qbuf;}/* 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 void ixEthAccMbufFromTxQ(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 void ixEthAccMbufFromRxQ(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; /* Try a lock on this port's TX queue */ 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(){ IxEthNpePhysicalId physicalId; /* * Initialize the service and register callback to other services. */ IX_ETH_ACC_MEMSET(&ixEthAccDataStats, 0, sizeof(ixEthAccDataStats)); /* init port data */ for(physicalId=0; physicalId < IX_ETH_ACC_NUMBER_OF_PORTS; physicalId++) { ixOsalFastMutexInit(&txWriteMutex[physicalId]); ixOsalFastMutexInit(&rxWriteMutex[physicalId]); IX_ETH_ACC_MEMSET(&ixEthAccPortData[physicalId], 0, sizeof(ixEthAccPortData[physicalId])); ixEthAccPortData[physicalId].ixEthAccTxData.schDiscipline = FIFO_NO_PRIORITY; } ixEthAccDataInfo.schDiscipline = FIFO_NO_PRIORITY; ixEthAccDataInfo.rxQMCbTypeSet = UNREGISTERED; ixEthAccDataInfo.npeCount = 0; 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); } 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);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -