/*-----------------------------------------------------------*/ void FreeRTOS_OutputARPRequest( uint32_t ulIPAddress ) { xNetworkBufferDescriptor_t *pxNetworkBuffer; /* This is called from the context of the IP event task, so a block time must not be used. */ pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( sizeof( xARPPacket_t ), 0 ); if( pxNetworkBuffer != NULL ) { pxNetworkBuffer->ulIPAddress = ulIPAddress; vARPGenerateRequestPacket( pxNetworkBuffer ); xNetworkInterfaceOutput( pxNetworkBuffer, pdTRUE ); } }
/* The deferred interrupt handler is a standard RTOS task. FreeRTOS's centralised deferred interrupt handling capabilities can also be used. */ static void prvEMACDeferredInterruptHandlerTask(void *pvParameters) { xNetworkBufferDescriptor_t *pxBufferDescriptor; size_t xBytesReceived; /* Used to indicate that xSendEventStructToIPTask() is being called because of an Ethernet receive event. */ xIPStackEvent_t xRxEvent; uint8_t *buffer; __IO ETH_DMADescTypeDef *dmarxdesc; uint32_t payloadoffset = 0; uint32_t byteslefttocopy = 0; uint32_t i = 0; xEMACRxEventSemaphore = xSemaphoreCreateCounting(10, 0); for (;;) { /* Wait for the Ethernet MAC interrupt to indicate that another packet has been received. It is assumed xEMACRxEventSemaphore is a counting semaphore (to count the Rx events) and that the semaphore has already been created (remember this is an example of a simple rather than optimised port layer). */ if (xSemaphoreTake( xEMACRxEventSemaphore, portMAX_DELAY ) == pdTRUE) { /* get received frame */ if (HAL_ETH_GetReceivedFrame_IT(&heth_global) != HAL_OK) return; /* Obtain the size of the packet */ xBytesReceived = (uint16_t) heth_global.RxFrameInfos.length; buffer = (uint8_t *) heth_global.RxFrameInfos.buffer; if (xBytesReceived > 0) { /* Allocate a network buffer descriptor that points to a buffer large enough to hold the received frame. As this is the simple rather than efficient example the received data will just be copied into this buffer. */ pxBufferDescriptor = pxGetNetworkBufferWithDescriptor(xBytesReceived, 0); if (pxBufferDescriptor != NULL) { /* pxBufferDescriptor->pucEthernetBuffer now points to an Ethernet buffer large enough to hold the received data. Copy the received data into pcNetworkBuffer->pucEthernetBuffer. Here it is assumed ReceiveData() is a peripheral driver function that copies the received data into a buffer passed in as the function's parameter. Remember! While is is a simple robust technique - it is not efficient. An example that uses a zero copy technique is provided further down this page. */ dmarxdesc = heth_global.RxFrameInfos.FSRxDesc; pxBufferDescriptor->xDataLength = xBytesReceived; byteslefttocopy = xBytesReceived; payloadoffset = 0; /* Check if the length of bytes to copy in current pbuf is bigger than Rx buffer size*/ while (byteslefttocopy > ETH_RX_BUF_SIZE) { /* Copy data to pbuf */ memcpy( (uint8_t*) ((uint8_t*) pxBufferDescriptor->pucEthernetBuffer + payloadoffset), (uint8_t*) ((uint8_t*) buffer), ETH_RX_BUF_SIZE); /* Point to next descriptor */ dmarxdesc = (ETH_DMADescTypeDef *) (dmarxdesc->Buffer2NextDescAddr); buffer = (uint8_t *) (dmarxdesc->Buffer1Addr); byteslefttocopy -= ETH_RX_BUF_SIZE; payloadoffset += ETH_RX_BUF_SIZE; } /* Copy remaining data in pbuf */ memcpy( (uint8_t*) ((uint8_t*) pxBufferDescriptor->pucEthernetBuffer + payloadoffset), (uint8_t*) ((uint8_t*) buffer), byteslefttocopy); } /* See if the data contained in the received Ethernet frame needs to be processed. NOTE! It is preferable to do this in the interrupt service routine itself, which would remove the need to unblock this task for packets that don't need processing. */ if (eConsiderFrameForProcessing(pxBufferDescriptor->pucEthernetBuffer) == eProcessBuffer) { /* The event about to be sent to the TCP/IP is an Rx event. */ xRxEvent.eEventType = eNetworkRxEvent; /* pvData is used to point to the network buffer descriptor that now references the received data. */ xRxEvent.pvData = (void *) pxBufferDescriptor; /* Send the data to the TCP/IP stack. */ if (xSendEventStructToIPTask(&xRxEvent, 0) == pdFALSE) { /* The buffer could not be sent to the IP task so the buffer must be released. */ vReleaseNetworkBufferAndDescriptor(pxBufferDescriptor); /* Make a call to the standard trace macro to log the occurrence. */ iptraceETHERNET_RX_EVENT_LOST(); } else { /* The message was successfully sent to the TCP/IP stack. Call the standard trace macro to log the occurrence. */ iptraceNETWORK_INTERFACE_RECEIVE(); gdb.monit.rx_eth_frames++; } } else { /* The Ethernet frame can be dropped, but the Ethernet buffer must be released. */ vReleaseNetworkBufferAndDescriptor(pxBufferDescriptor); } /* Release descriptors to DMA */ /* Point to first descriptor */ dmarxdesc = heth_global.RxFrameInfos.FSRxDesc; /* Set Own bit in Rx descriptors: gives the buffers back to DMA */ for (i = 0; i < heth_global.RxFrameInfos.SegCount; i++) { dmarxdesc->Status |= ETH_DMARXDESC_OWN; dmarxdesc = (ETH_DMADescTypeDef *) (dmarxdesc->Buffer2NextDescAddr); } /* Clear Segment_Count */ heth_global.RxFrameInfos.SegCount = 0; } else { /* The event was lost because a network buffer was not available. Call the standard trace macro to log the occurrence. */ iptraceETHERNET_RX_EVENT_LOST(); } } /* When Rx Buffer unavailable flag is set: clear it and resume reception */ if ((heth_global.Instance->DMASR & ETH_DMASR_RBUS) != (uint32_t) RESET) { /* Clear RBUS ETHERNET DMA flag */ heth_global.Instance->DMASR = ETH_DMASR_RBUS; /* Resume DMA reception */ heth_global.Instance->DMARPDR = 0; } } }
static uint32_t prvEMACRxPoll( void ) { unsigned char *pucUseBuffer; uint32_t ulReceiveCount, ulResult, ulReturnValue = 0; static NetworkBufferDescriptor_t *pxNextNetworkBufferDescriptor = NULL; const UBaseType_t xMinDescriptorsToLeave = 2UL; const TickType_t xBlockTime = pdMS_TO_TICKS( 100UL ); static IPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL }; for( ;; ) { /* If pxNextNetworkBufferDescriptor was not left pointing at a valid descriptor then allocate one now. */ if( ( pxNextNetworkBufferDescriptor == NULL ) && ( uxGetNumberOfFreeNetworkBuffers() > xMinDescriptorsToLeave ) ) { pxNextNetworkBufferDescriptor = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE, xBlockTime ); } if( pxNextNetworkBufferDescriptor != NULL ) { /* Point pucUseBuffer to the buffer pointed to by the descriptor. */ pucUseBuffer = ( unsigned char* ) ( pxNextNetworkBufferDescriptor->pucEthernetBuffer - ipconfigPACKET_FILLER_SIZE ); } else { /* As long as pxNextNetworkBufferDescriptor is NULL, the incoming messages will be flushed and ignored. */ pucUseBuffer = NULL; } /* Read the next packet from the hardware into pucUseBuffer. */ ulResult = gmac_dev_read( &gs_gmac_dev, pucUseBuffer, ipTOTAL_ETHERNET_FRAME_SIZE, &ulReceiveCount ); if( ( ulResult != GMAC_OK ) || ( ulReceiveCount == 0 ) ) { /* No data from the hardware. */ break; } if( pxNextNetworkBufferDescriptor == NULL ) { /* Data was read from the hardware, but no descriptor was available for it, so it will be dropped. */ iptraceETHERNET_RX_EVENT_LOST(); continue; } iptraceNETWORK_INTERFACE_RECEIVE(); pxNextNetworkBufferDescriptor->xDataLength = ( size_t ) ulReceiveCount; xRxEvent.pvData = ( void * ) pxNextNetworkBufferDescriptor; /* Send the descriptor to the IP task for processing. */ if( xSendEventStructToIPTask( &xRxEvent, xBlockTime ) != pdTRUE ) { /* The buffer could not be sent to the stack so must be released again. */ vReleaseNetworkBufferAndDescriptor( pxNextNetworkBufferDescriptor ); iptraceETHERNET_RX_EVENT_LOST(); FreeRTOS_printf( ( "prvEMACRxPoll: Can not queue return packet!\n" ) ); } /* Now the buffer has either been passed to the IP-task, or it has been released in the code above. */ pxNextNetworkBufferDescriptor = NULL; ulReturnValue++; } return ulReturnValue; }
static void prvInterruptSimulatorTask( void *pvParameters ) { struct pcap_pkthdr xHeader; static struct pcap_pkthdr *pxHeader; const uint8_t *pucPacketData; uint8_t ucRecvBuffer[ ipconfigNETWORK_MTU + ipSIZE_OF_ETH_HEADER ]; NetworkBufferDescriptor_t *pxNetworkBuffer; IPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL }; eFrameProcessingResult_t eResult; /* Remove compiler warnings about unused parameters. */ ( void ) pvParameters; for( ;; ) { /* Does the circular buffer used to pass data from the Win32 thread that handles WinPCAP Rx into the FreeRTOS simulator contain another packet? */ if( uxStreamBufferGetSize( xRecvBuffer ) > sizeof( xHeader ) ) { /* Get the next packet. */ uxStreamBufferGet( xRecvBuffer, 0, (uint8_t*)&xHeader, sizeof( xHeader ), pdFALSE ); uxStreamBufferGet( xRecvBuffer, 0, (uint8_t*)ucRecvBuffer, ( size_t ) xHeader.len, pdFALSE ); pucPacketData = ucRecvBuffer; pxHeader = &xHeader; iptraceNETWORK_INTERFACE_RECEIVE(); eResult = ipCONSIDER_FRAME_FOR_PROCESSING( pucPacketData ); if( eResult == eProcessBuffer ) { /* Will the data fit into the frame buffer? */ if( pxHeader->len <= ipTOTAL_ETHERNET_FRAME_SIZE ) { /* Obtain a buffer into which the data can be placed. This is only an interrupt simulator, not a real interrupt, so it is ok to call the task level function here, but note that some buffer implementations cannot be called from a real interrupt. */ pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( pxHeader->len, 0 ); if( pxNetworkBuffer != NULL ) { memcpy( pxNetworkBuffer->pucEthernetBuffer, pucPacketData, pxHeader->len ); pxNetworkBuffer->xDataLength = ( size_t ) pxHeader->len; #if( niDISRUPT_PACKETS == 1 ) { pxNetworkBuffer = vRxFaultInjection( pxNetworkBuffer, pucPacketData ); } #endif /* niDISRUPT_PACKETS */ if( pxNetworkBuffer != NULL ) { xRxEvent.pvData = ( void * ) pxNetworkBuffer; /* Data was received and stored. Send a message to the IP task to let it know. */ if( xSendEventStructToIPTask( &xRxEvent, ( TickType_t ) 0 ) == pdFAIL ) { /* The buffer could not be sent to the stack so must be released again. This is only an interrupt simulator, not a real interrupt, so it is ok to use the task level function here, but note no all buffer implementations will allow this function to be executed from a real interrupt. */ vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer ); iptraceETHERNET_RX_EVENT_LOST(); } } else { /* The packet was already released or stored inside vRxFaultInjection(). Don't release it here. */ } } else { iptraceETHERNET_RX_EVENT_LOST(); } } else { /* Log that a packet was dropped because it would have overflowed the buffer, but there may be more buffers to process. */ } } } else { /* There is no real way of simulating an interrupt. Make sure other tasks can run. */ vTaskDelay( configWINDOWS_MAC_INTERRUPT_SIMULATOR_DELAY ); } } }
XStatus init_dma(xemacpsif_s *xemacpsif) { NetworkBufferDescriptor_t *pxBuffer; int iIndex; UBaseType_t xRxSize; UBaseType_t xTxSize; struct xtopology_t *xtopologyp = &xXTopology; xRxSize = ipconfigNIC_N_RX_DESC * sizeof( xemacpsif->rxSegments[ 0 ] ); xTxSize = ipconfigNIC_N_TX_DESC * sizeof( xemacpsif->txSegments[ 0 ] ); /* Also round-up to 4KB */ xemacpsif->uTxUnitSize = ( ipTOTAL_ETHERNET_FRAME_SIZE + 0x1000ul ) & ~0xffful; /* * We allocate 65536 bytes for RX BDs which can accommodate a * maximum of 8192 BDs which is much more than any application * will ever need. */ xemacpsif->rxSegments = ( struct xBD_TYPE * )( pucGetUncachedMemory ( xRxSize ) ); xemacpsif->txSegments = ( struct xBD_TYPE * )( pucGetUncachedMemory ( xTxSize ) ); xemacpsif->tx_space = ( unsigned char * )( pucGetUncachedMemory ( ipconfigNIC_N_TX_DESC * xemacpsif->uTxUnitSize ) ); /* These variables will be used in XEmacPs_Start (see src/xemacps.c). */ xemacpsif->emacps.RxBdRing.BaseBdAddr = ( uint32_t ) xemacpsif->rxSegments; xemacpsif->emacps.TxBdRing.BaseBdAddr = ( uint32_t ) xemacpsif->txSegments; /* * Allocate RX descriptors, 1 RxBD at a time. */ for( iIndex = 0; iIndex < ipconfigNIC_N_RX_DESC; iIndex++ ) { pxBuffer = pxDMA_rx_buffers[ iIndex ]; if( pxBuffer == NULL ) { pxBuffer = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE, ( TickType_t ) 0 ); if( pxBuffer == NULL ) { FreeRTOS_printf( ("Unable to allocate a network buffer in recv_handler\n" ) ); return -1; } } xemacpsif->rxSegments[ iIndex ].flags = 0; xemacpsif->rxSegments[ iIndex ].address = ( ( uint32_t )pxBuffer->pucEthernetBuffer ) & XEMACPS_RXBUF_ADD_MASK; pxDMA_rx_buffers[ iIndex ] = pxBuffer; /* Make sure this memory is not in cache for now. */ if( ucIsCachedMemory( pxBuffer->pucEthernetBuffer ) != 0 ) { Xil_DCacheInvalidateRange( ( ( uint32_t )pxBuffer->pucEthernetBuffer ) - ipconfigPACKET_FILLER_SIZE, (unsigned)ipTOTAL_ETHERNET_FRAME_SIZE ); } } xemacpsif->rxSegments[ ipconfigNIC_N_RX_DESC - 1 ].address |= XEMACPS_RXBUF_WRAP_MASK; memset( xemacpsif->tx_space, '\0', ipconfigNIC_N_TX_DESC * xemacpsif->uTxUnitSize ); clean_dma_txdescs( xemacpsif ); { uint32_t value; value = XEmacPs_ReadReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_DMACR_OFFSET ); // 1xxxx: Attempt to use INCR16 AHB bursts value = ( value & ~( XEMACPS_DMACR_BLENGTH_MASK ) ) | XEMACPS_DMACR_INCR16_AHB_BURST; #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM != 0 ) value |= XEMACPS_DMACR_TCPCKSUM_MASK; #else #warning Are you sure the EMAC should not calculate outgoing checksums? value &= ~XEMACPS_DMACR_TCPCKSUM_MASK; #endif XEmacPs_WriteReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_DMACR_OFFSET, value ); } { uint32_t value; value = XEmacPs_ReadReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCFG_OFFSET ); /* Network buffers are 32-bit aligned + 2 bytes (because ipconfigPACKET_FILLER_SIZE = 2 ). Now tell the EMAC that received messages should be stored at "address + 2". */ value = ( value & ~XEMACPS_NWCFG_RXOFFS_MASK ) | 0x8000; #if( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM != 0 ) value |= XEMACPS_NWCFG_RXCHKSUMEN_MASK; #else #warning Are you sure the EMAC should not calculate incoming checksums? value &= ~XEMACPS_NWCFG_RXCHKSUMEN_MASK; #endif XEmacPs_WriteReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCFG_OFFSET, value ); } /* * Connect the device driver handler that will be called when an * interrupt for the device occurs, the handler defined above performs * the specific interrupt processing for the device. */ XScuGic_RegisterHandler(INTC_BASE_ADDR, xtopologyp->scugic_emac_intr, (Xil_ExceptionHandler)XEmacPs_IntrHandler, (void *)&xemacpsif->emacps); /* * Enable the interrupt for emacps. */ EmacEnableIntr( ); return 0; }
void emacps_set_rx_buffers( xemacpsif_s *xemacpsif, u32 ulCount ) { NetworkBufferDescriptor_t *pxBuffer; unsigned int FreeBds; int tail = xemacpsif->rxTail; int head = xemacpsif->rxHead; if( ulCount != 0 ) { FreeBds = ulCount; } else { FreeBds = is_rx_packets_available( NULL ); } while( FreeBds-- != 0 ) { pxBuffer = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE, ( TickType_t ) 0 ); if( pxBuffer == NULL ) { FreeRTOS_printf( ("unable to alloc pbuf in recv_handler\n" ) ); dsb(); return; } dsb(); if( ( xemacpsif->rxSegments[ tail ].address & XEMACPS_RXBUF_NEW_MASK ) == 0 ) { FreeRTOS_printf( ("Buffer %d too far?\n", tail ) ); } if( pxDMA_rx_buffers[ tail ] != NULL ) { FreeRTOS_printf( ("Buffer %d not used?\n", tail ) ); } pxDMA_rx_buffers[ tail ] = ( void * )pxBuffer; if( ucIsCachedMemory( pxBuffer->pucEthernetBuffer ) != 0 ) { Xil_DCacheInvalidateRange( ( ( uint32_t )pxBuffer->pucEthernetBuffer ) - ipconfigPACKET_FILLER_SIZE, (unsigned)ipTOTAL_ETHERNET_FRAME_SIZE ); } { uint32_t addr = ( ( uint32_t )pxBuffer->pucEthernetBuffer ) & XEMACPS_RXBUF_ADD_MASK; if( tail == ( ipconfigNIC_N_RX_DESC - 1 ) ) { addr |= XEMACPS_RXBUF_WRAP_MASK; } /* Clearing 'XEMACPS_RXBUF_NEW_MASK' 0x00000001 *< Used bit.. */ xemacpsif->rxSegments[ tail ].address = addr; xemacpsif->rxSegments[ tail ].flags = 0; } if( ++tail == ipconfigNIC_N_RX_DESC ) { tail = 0; } if( tail == head ) { break; } } xemacpsif->rxTail = tail; }