/* * eth_rx_flow.cpp * * Created on: 7 ���. 2023 �. * Author: sychev */ #include "free_rtos/ethernet/eth_rx_flow.hpp" #include #include // Yes, it is forbidden ! #include #include #include #include /*----------------------------------------------------------------------*/ /** * ����� ������������ sysconfig. * ������������ ����� ������� � ���������� � ����� /syscfg */ #include "ti_enet_config.h" /*----------------------------------------------------------------------*/ using namespace free_rtos; /** * ���������� ������ ������ */ void free_rtos::rxIsrHandler(void *appData) { EthRxFlow * rx_flow = (EthRxFlow *)appData; if(rx_flow == nullptr) { return; } rx_flow->sem_[EthRxFlow::e_signalRxPkt].post(); } void free_rtos::rxTaskHandler(void *appData) { EthRxFlow * rx_flow = (EthRxFlow *)appData; if (rx_flow != nullptr) { rx_flow->rxProcessPktTask(); } } free_rtos::EthRxFlow::EthRxFlow(TEthFrameMacAddr& mac_addr, EthStackIface& eth_stack) : mac_addr_{mac_addr}, eth_stack_{eth_stack}, passive_mode_{false} { EnetQueue_initQ(&rx_free_pktq_); } void free_rtos::EthRxFlow::initRxFreePktQ(uint32_t qCount, void * appPriv) { EnetDma_PktQ rxReadyQ; EnetDma_Pkt *pPktInfo; uint32_t i; int32_t status; 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(&rx_free_pktq_, &pPktInfo->node); } /* Retrieve any packets which are ready */ EnetQueue_initQ(&rxReadyQ); status = EnetDma_retrieveRxPktQ(dma_handle_, &rxReadyQ); EnetAppUtils_assert(status == ENET_SOK); /* There should not be any packet with DMA during init */ EnetAppUtils_assert(EnetQueue_getQCount(&rxReadyQ) == 0U); } void free_rtos::EthRxFlow::submitFreeRxPkts(uint32_t qCount) { EnetDma_PktQ rxSubmitQ; EnetDma_Pkt* rxPktInfo = (EnetDma_Pkt *)EnetQueue_deq(&rx_free_pktq_); int32_t status; EnetQueue_initQ(&rxSubmitQ); while((rxPktInfo != nullptr) && (qCount > 0)) { EnetQueue_enq(&rxSubmitQ, &rxPktInfo->node); rxPktInfo = (EnetDma_Pkt *)EnetQueue_deq(&rx_free_pktq_); qCount--; } EnetAppUtils_validatePacketState(&rxSubmitQ, ENET_PKTSTATE_APP_WITH_FREEQ, ENET_PKTSTATE_APP_WITH_DRIVER); status = EnetDma_submitRxPktQ(dma_handle_, &rxSubmitQ); if(status != ENET_SOK) { EnetAppUtils_print("rx_flow %u: failed to reload rx dma flow\r\n", id_); EnetAppUtils_assert(status == ENET_SOK); return; } qCount = EnetQueue_getQCount(&rxSubmitQ); /* Assert here, as during init, the number of DMA descriptors should be equal to * the number of free Ethernet buffers available with app */ if(qCount != 0U) { EnetAppUtils_print("rx_flow %u: number of DMA descriptors should be equal to the number of free Ethernet buffers\r\n", id_); EnetAppUtils_assert(qCount == 0U); } } void free_rtos::EthRxFlow::rxProcessPktTask() { EnetDma_Pkt* rxPktInfo; /// ����� � ������� EnetDma_PktQ rxReadyQ; uint32_t readyQCount; int32_t status; while(1) { /// ������� ������� status = sem_[e_signalRxPkt].pend(); if(status != SystemP_SUCCESS) { continue; } do { status = EnetDma_retrieveRxPktQ(dma_handle_, &rxReadyQ); EnetAppUtils_assert(status == ENET_SOK); readyQCount = EnetQueue_getQCount(&rxReadyQ); if(readyQCount == 0) { break; } // Reload DMA with a new rx free queue as fast as possible submitFreeRxPkts(readyQCount); rxPktInfo = (EnetDma_Pkt *)EnetQueue_deq(&rxReadyQ); while(rxPktInfo != nullptr) { //if (!passive_mode_) { for (int j = 0 ; j < rxPktInfo->sgList.numScatterSegments; ++j) { eth_stack_.rx_handler(rxPktInfo->sgList.list[j].bufPtr, rxPktInfo->sgList.list[j].segmentFilledLen); } //} EnetDma_checkPktState(&rxPktInfo->pktState, ENET_PKTSTATE_MODULE_APP, ENET_PKTSTATE_APP_WITH_DRIVER, ENET_PKTSTATE_APP_WITH_FREEQ); EnetQueue_enq(&rx_free_pktq_, &rxPktInfo->node); rxPktInfo = (EnetDma_Pkt *)EnetQueue_deq(&rxReadyQ); ++rx_pkt_counter_; } } while(readyQCount > 0); } } bool free_rtos::EthRxFlow::open(uint32_t id, int32_t enetDmaRxChId, UBaseType_t task_priority, UBaseType_t task_stack_size) { EnetApp_GetDmaHandleInArgs rxInArgs; EnetApp_GetRxDmaHandleOutArgs rxChInfo; EnetAppUtils_print("rx_flow %u: opening flow...\r\n", id); rx_pkt_counter_ = 0; if (open_) { EnetAppUtils_print("rx_flow %u: rx flow is already open. Do nothing.\r\n", id_); return true; } if (!rx_task.Create("rx_task", task_priority, rxTaskHandler, this, task_stack_size)) { EnetAppUtils_print("rx_flow %u: failed to create rx task.\r\n", id_); return false; } id_ = id; /// ������������ ���������� �� ������ ������ rxInArgs.notifyCb = rxIsrHandler; /// ������� ���������� rxInArgs.cbArg = this; /// �������� ������ EnetApp_getRxDmaHandle(enetDmaRxChId, &rxInArgs, &rxChInfo); /// ��������� ������ rx_start_flow_idx_ = rxChInfo.rxFlowStartIdx; rx_flow_idx_ = rxChInfo.rxFlowIdx; dma_handle_ = rxChInfo.hRxCh; if (rxChInfo.macAddressValid) { EnetUtils_copyMacAddr(mac_addr_.bytes, rxChInfo.macAddr); mac_addr_.addr&= ETH_FRAME_MAC_ADDR_MASK; eth_stack_.set_mac_address(mac_addr_.addr); } /// �������� ������ EnetAppUtils_assert(rxChInfo.useGlobalEvt == true); EnetAppUtils_assert(rxChInfo.sizeThreshEn == 0U); EnetAppUtils_assert(rxChInfo.maxNumRxPkts >= (ENET_SYSCFG_TOTAL_NUM_RX_PKT/2U)); EnetAppUtils_assert(rxChInfo.chIdx == id_); EnetAppUtils_assert(rxChInfo.useDefaultFlow == true); if (dma_handle_ == nullptr) { EnetAppUtils_print("rx_flow %u: failed to open rx dma flow\r\n", id_); EnetAppUtils_assert(dma_handle_ != nullptr); return false; } /// ������������� ������� ������� initRxFreePktQ(ENET_SYSCFG_TOTAL_NUM_RX_PKT/2, this); submitFreeRxPkts(ENET_SYSCFG_TOTAL_NUM_RX_PKT/4); open_ = true; EnetAppUtils_print("rx_flow %u: rx flow open successfully\r\n", id); return true; }