/* * eth_tx_flow.cpp * * Created on: 7 мар. 2023 г. * Author: sychev */ #include "free_rtos/ethernet/eth_tx_flow.hpp" #include #include #include #include #include #include #include #include /*----------------------------------------------------------------------*/ #include "ti_enet_config.h" /*----------------------------------------------------------------------*/ static void eth_initTxFreePktQ(void * appPriv, EnetDma_PktQ * p_packet_queue, uint32_t qCount) { EnetDma_Pkt *pPktInfo; uint32_t i; /* Initialize TX EthPkts and queue them to txFreePktInfoQ */ for (i = 0U; i < qCount; i++) { pPktInfo = EnetMem_allocEthPkt(appPriv, ENET_MEM_LARGE_POOL_PKT_SIZE, ENETDMA_CACHELINE_ALIGNMENT); EnetAppUtils_assert(pPktInfo != NULL); ENET_UTILS_SET_PKT_APP_STATE(&pPktInfo->pktState, ENET_PKTSTATE_APP_WITH_FREEQ); EnetQueue_enq(p_packet_queue, &pPktInfo->node); } EnetAppUtils_print("initQs() txFreePktInfoQ initialized with %d pkts\r\n", EnetQueue_getQCount(p_packet_queue)); } void free_rtos::txIsrHandler(void *appData) { EthTxFlow * tx_flow = (EthTxFlow *)appData; if(tx_flow == nullptr) { return; } tx_flow->retrieveFreeTxPktQ(); tx_flow->sem_[EthTxFlow::e_signalTxPkt].post(); } free_rtos::EthTxFlow::EthTxFlow() : default_port_id_{e_ethMac0}, open_{false}, tx_ch_num_{0} { EnetQueue_initQ(&tx_free_pktq_); } bool free_rtos::EthTxFlow::open(TEthMacPorts port_id, int32_t enetDmaTxChId) { if (port_id >= e_ethMacTotal) { return false; } EnetApp_GetDmaHandleInArgs txInArgs; EnetApp_GetTxDmaHandleOutArgs txChInfo; EnetAppUtils_print("tx_flow %u: opening flow...\r\n", port_id); port_data_[port_id].tx_pkt_counter = 0; if (open_) { EnetAppUtils_print("tx_flow %u: tx flow is already open. Do nothing.\r\n", port_id); return true; } /* Open the TX channel */ txInArgs.notifyCb = txIsrHandler; txInArgs.cbArg = this; EnetApp_getTxDmaHandle(enetDmaTxChId, &txInArgs, &txChInfo); default_port_id_ = port_id; tx_ch_num_ = txChInfo.txChNum; dma_handle_ = txChInfo.hTxCh; EnetAppUtils_assert(txChInfo.useGlobalEvt == true); EnetAppUtils_assert(txChInfo.maxNumTxPkts >= ENET_SYSCFG_TOTAL_NUM_TX_PKT); if (dma_handle_ == nullptr) { EnetAppUtils_print("tx_flow %u: failed to open tx dma flow\r\n", port_id); EnetAppUtils_assert(dma_handle_ != nullptr); return false; } eth_initTxFreePktQ(this, &tx_free_pktq_, ENET_SYSCFG_TOTAL_NUM_TX_PKT); open_= true; EnetAppUtils_print("tx_flow %u: tx flow open successfully\r\n", port_id); return true; } void free_rtos::EthTxFlow::enable(TEthMacPorts port_id) { if (port_id >= e_ethMacTotal) { return; } port_data_[port_id].tx_enable = true; } void free_rtos::EthTxFlow::disable(TEthMacPorts port_id) { if (port_id >= e_ethMacTotal) { return; } port_data_[port_id].tx_enable = false; } void free_rtos::EthTxFlow::retrieveFreeTxPktQ() { EnetDma_PktQ txFreeQ; EnetDma_Pkt *pktInfo; int32_t status; EnetQueue_initQ(&txFreeQ); status = EnetDma_retrieveTxPktQ(dma_handle_, &txFreeQ); if (status != ENET_SOK) { EnetAppUtils_print("retrieveFreeTxPktQ() failed to retrieve pkts: %d\r\n", status); return; } EnetAppUtils_validatePacketState( &txFreeQ, ENET_PKTSTATE_APP_WITH_DRIVER, ENET_PKTSTATE_APP_WITH_FREEQ); EnetQueue_append(&tx_free_pktq_, &txFreeQ); } EnetDma_Pkt* free_rtos::EthTxFlow::getTxPktInfo() { EnetDma_Pkt *txPktInfo = (EnetDma_Pkt *)EnetQueue_deq(&tx_free_pktq_); while(txPktInfo == NULL) { sem_[EthTxFlow::e_signalTxPkt].pend(); txPktInfo = (EnetDma_Pkt *)EnetQueue_deq(&tx_free_pktq_); } return txPktInfo; } bool free_rtos::EthTxFlow::send(TEthMacPorts port_id, uint8_t * p_data, uint32_t len) { if (port_id >= e_ethMacTotal) { EnetAppUtils_print("Wrong port id\r\n"); return false; } if (!port_data_[port_id].tx_enable) { return false; } EnetDma_PktQ txSubmitQ; EnetDma_Pkt *txPktInfo; int32_t status; EnetQueue_initQ(&txSubmitQ); txPktInfo = getTxPktInfo(); if (txPktInfo == NULL) { EnetAppUtils_print("tx_flow %u: Drop due to TX pkt not available\r\n", port_id); return false; } memcpy(txPktInfo->sgList.list[0].bufPtr, p_data, len); txPktInfo->sgList.list[0].segmentFilledLen = len; txPktInfo->sgList.numScatterSegments = 1; txPktInfo->chkSumInfo = 0U; txPktInfo->appPriv = nullptr; txPktInfo->tsInfo.txPktSeqId = 0; txPktInfo->txPktTc = 0; /// Traffic class IPv6 txPktInfo->tsInfo.enableHostTxTs = false; txPktInfo->txPortNum = (Enet_MacPort)port_id; EnetDma_checkPktState( &txPktInfo->pktState, ENET_PKTSTATE_MODULE_APP, ENET_PKTSTATE_APP_WITH_FREEQ, ENET_PKTSTATE_APP_WITH_DRIVER); EnetQueue_enq(&txSubmitQ, &txPktInfo->node); status = EnetDma_submitTxPktQ(dma_handle_, &txSubmitQ); if (status != ENET_SOK) { EnetAppUtils_print("tx_flow %u: Failed to submit TX pkt queue: %d\r\n", port_id, status); return false; } ++port_data_[port_id].tx_pkt_counter; return true; } bool free_rtos::EthTxFlow::send(TxFlowHandlerArgs& handlerArgs, uint32_t numScatterSegments) { TEthMacPorts port_id = handlerArgs.port_id; if (port_id >= e_ethMacTotal) { EnetAppUtils_print("Wrong port id\r\n"); return false; } if (port_data_[port_id].tx_enable == false) { return false; } EnetDma_PktQ txSubmitQ; EnetDma_Pkt *txPktInfo; int32_t status; EnetQueue_initQ(&txSubmitQ); txPktInfo = getTxPktInfo(); if (txPktInfo == NULL) { EnetAppUtils_print("tx_flow %u: Drop due to TX pkt not available\r\n", port_id); return false; } for(size_t scatter_segment = 0; scatter_segment < numScatterSegments; scatter_segment++) { handlerArgs.buffer = txPktInfo->sgList.list[scatter_segment].bufPtr; txPktInfo->sgList.list[scatter_segment].segmentFilledLen = handlerArgs.stack_handler->Sender(handlerArgs, scatter_segment); } txPktInfo->sgList.numScatterSegments = numScatterSegments; txPktInfo->chkSumInfo = 0U; txPktInfo->appPriv = nullptr; txPktInfo->tsInfo.txPktSeqId = 0; txPktInfo->txPktTc = 0; /// Traffic class IPv6 txPktInfo->tsInfo.enableHostTxTs = false; txPktInfo->txPortNum = (Enet_MacPort)port_id; EnetDma_checkPktState( &txPktInfo->pktState, ENET_PKTSTATE_MODULE_APP, ENET_PKTSTATE_APP_WITH_FREEQ, ENET_PKTSTATE_APP_WITH_DRIVER); EnetQueue_enq(&txSubmitQ, &txPktInfo->node); status = EnetDma_submitTxPktQ(dma_handle_, &txSubmitQ); if (status != ENET_SOK) { EnetAppUtils_print("tx_flow %u: Failed to submit TX pkt queue: %d\r\n", port_id, status); return false; } ++port_data_[handlerArgs.port_id].tx_pkt_counter; return true; }