/** * \brief Test GMAC read/write interfaces. * * \param test Current test case. */ static void run_gmac_read_write_test(const struct test_case *test) { uint32_t ul_frm_size; uint8_t uc_rc = 0; uint32_t ul_retry_time = 0; /* Write the arp frame first */ gmac_dev_write(&gs_gmac_dev, gs_arp_frame, sizeof(gs_arp_frame), NULL); while ( ul_retry_time < GMAC_UINT_TEST_MAX_RETRY_TIME ) { /* Read the frame in the gmac buffer */ if (GMAC_OK != gmac_dev_read(&gs_gmac_dev, (uint8_t *) gs_uc_eth_buffer, sizeof(gs_uc_eth_buffer), &ul_frm_size)) { continue; } /* Is arp frame sent? */ if (strncmp((const char *)gs_uc_eth_buffer, (const char *)gs_uc_mac_address, sizeof(gs_uc_mac_address))) { uc_rc = 1; break; } ul_retry_time++; } test_assert_true(test, uc_rc == 1, "Test GMAC: gmac write error!"); }
/** * \brief Should allocate a pbuf and transfer the bytes of the incoming * packet from the interface into the pbuf. * * \param netif the lwip network interface structure for this ethernetif. * * \return a pbuf filled with the received packet (including MAC header) * NULL on memory error. */ static struct pbuf *low_level_input(struct netif *netif) { struct pbuf *p = NULL, *q = NULL; u16_t s_len; uint8_t pc_buf[NET_RW_BUFF_SIZE]; int8_t *bufptr = (int8_t *)&pc_buf[0]; uint32_t ul_frmlen; uint8_t uc_rc; /* Obtain the size of the packet and put it into the "len" * variable. */ uc_rc = gmac_dev_read(&gs_gmac_dev, pc_buf, sizeof(pc_buf), &ul_frmlen); if (uc_rc != GMAC_OK) { return NULL; } s_len = ul_frmlen; #if ETH_PAD_SIZE s_len += ETH_PAD_SIZE; /* allow room for Ethernet padding */ #endif /* We allocate a pbuf chain of pbufs from the pool. */ p = pbuf_alloc(PBUF_RAW, s_len, PBUF_POOL); if (p != NULL) { #if ETH_PAD_SIZE pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */ #endif /* Iterate over the pbuf chain until we have read the entire * packet into the pbuf. */ for (q = p; q != NULL; q = q->next) { /* Read enough bytes to fill this pbuf in the chain. The * available data in the pbuf is given by the q->len * variable. */ /* read data into(q->payload, q->len); */ memcpy(q->payload, bufptr, q->len); bufptr += q->len; } /* Acknowledge that packet has been read(); */ #if ETH_PAD_SIZE pbuf_header(p, ETH_PAD_SIZE); /* Reclaim the padding word */ #endif LINK_STATS_INC(link.recv); } else { /* Drop packet(); */ LINK_STATS_INC(link.memerr); LINK_STATS_INC(link.drop); } return p; }
static void prvGMACDeferredInterruptHandlerTask( void *pvParameters ) { xNetworkBufferDescriptor_t *pxNetworkBuffer = NULL; xIPStackEvent_t xRxEvent = { eEthernetRxEvent, NULL }; static const TickType_t xBufferWaitDelay = 1500UL / portTICK_RATE_MS; uint32_t ulReturned; /* This is a very simply but also inefficient implementation. */ ( void ) pvParameters; for( ;; ) { /* Wait for the GMAC interrupt to indicate that another packet has been received. A while loop is used to process all received frames each time this task is notified, so it is ok to clear the notification count on the take (hence the first parameter is pdTRUE ). */ ulTaskNotifyTake( pdTRUE, xBufferWaitDelay ); ulReturned = GMAC_OK; while( ulReturned == GMAC_OK ) { /* Allocate a buffer to hold the data if one is not already held. */ if( pxNetworkBuffer == NULL ) { pxNetworkBuffer = pxNetworkBufferGet( ipTOTAL_ETHERNET_FRAME_SIZE, xBufferWaitDelay ); } if( pxNetworkBuffer != NULL ) { /* Attempt to read data. */ ulReturned = gmac_dev_read( &xGMACStruct, pxNetworkBuffer->pucEthernetBuffer, ipTOTAL_ETHERNET_FRAME_SIZE, ( uint32_t * ) &( pxNetworkBuffer->xDataLength ) ); if( ulReturned == GMAC_OK ) { #if ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES == 1 { if( pxNetworkBuffer->xDataLength > 0 ) { /* If the frame would not be processed by the IP stack then don't even bother sending it to the IP stack. */ if( eConsiderFrameForProcessing( pxNetworkBuffer->pucEthernetBuffer ) != eProcessBuffer ) { pxNetworkBuffer->xDataLength = 0; } } } #endif if( pxNetworkBuffer->xDataLength > 0 ) { /* Store a pointer to the network buffer structure in the padding space that was left in front of the Ethernet frame. The pointer is needed to ensure the network buffer structure can be located when it is time for it to be freed if the Ethernet frame gets used as a zero copy buffer. */ *( ( xNetworkBufferDescriptor_t ** ) ( ( pxNetworkBuffer->pucEthernetBuffer - ipBUFFER_PADDING ) ) ) = pxNetworkBuffer; /* Data was received and stored. Send it to the IP task for processing. */ xRxEvent.pvData = ( void * ) pxNetworkBuffer; if( xQueueSendToBack( xNetworkEventQueue, &xRxEvent, ( TickType_t ) 0 ) == pdFALSE ) { /* The buffer could not be sent to the IP task. The frame will be dropped and the buffer reused. */ iptraceETHERNET_RX_EVENT_LOST(); } else { iptraceNETWORK_INTERFACE_RECEIVE(); /* The buffer is not owned by the IP task - a new buffer is needed the next time around. */ pxNetworkBuffer = NULL; } } else { /* The buffer does not contain any data so there is no point sending it to the IP task. Re-use the buffer on the next loop. */ iptraceETHERNET_RX_EVENT_LOST(); } } else { /* No data was received, keep the buffer for re-use. The loop will exit as ulReturn is not GMAC_OK. */ } } else { /* Left a frame in the driver as a buffer was not available. Break out of loop. */ ulReturned = GMAC_INVALID; } } } }
static void prvGMACDeferredInterruptHandlerTask( void *pvParameters ) { xNetworkBufferDescriptor_t *pxNetworkBuffer; xIPStackEvent_t xRxEvent = { eEthernetRxEvent, NULL }; static const TickType_t xBufferWaitDelay = 1500UL / portTICK_RATE_MS; uint32_t ulReturned; ( void ) pvParameters; configASSERT( xGMACRxEventSemaphore ); for( ;; ) { /* Wait for the GMAC interrupt to indicate that another packet has been received. The while() loop is only needed if INCLUDE_vTaskSuspend is set to 0 in FreeRTOSConfig.h. If INCLUDE_vTaskSuspend is set to 1 then portMAX_DELAY would be an indefinite block time and xSemaphoreTake() would only return when the semaphore was actually obtained. */ while( xSemaphoreTake( xGMACRxEventSemaphore, portMAX_DELAY ) == pdFALSE ); /* Allocate a buffer to hold the data. */ pxNetworkBuffer = pxNetworkBufferGet( ipTOTAL_ETHERNET_FRAME_SIZE, xBufferWaitDelay ); if( pxNetworkBuffer != NULL ) { /* At least one packet has been received. */ ulReturned = gmac_dev_read( &xGMACStruct, pxNetworkBuffer->pucEthernetBuffer, ipTOTAL_ETHERNET_FRAME_SIZE, ( uint32_t * ) &( pxNetworkBuffer->xDataLength ) ); if( ulReturned == GMAC_OK ) { #if ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES == 1 { if( pxNetworkBuffer->xDataLength > 0 ) { /* If the frame would not be processed by the IP stack then don't even bother sending it to the IP stack. */ if( eConsiderFrameForProcessing( pxNetworkBuffer->pucEthernetBuffer ) != eProcessBuffer ) { pxNetworkBuffer->xDataLength = 0; } } } #endif if( pxNetworkBuffer->xDataLength > 0 ) { /* Store a pointer to the network buffer structure in the padding space that was left in front of the Ethernet frame. The pointer is needed to ensure the network buffer structure can be located when it is time for it to be freed if the Ethernet frame gets used as a zero copy buffer. */ *( ( xNetworkBufferDescriptor_t ** ) ( ( pxNetworkBuffer->pucEthernetBuffer - ipBUFFER_PADDING ) ) ) = pxNetworkBuffer; /* Data was received and stored. Send it to the IP task for processing. */ xRxEvent.pvData = ( void * ) pxNetworkBuffer; if( xQueueSendToBack( xNetworkEventQueue, &xRxEvent, ( TickType_t ) 0 ) == pdFALSE ) { /* The buffer could not be sent to the IP task so the buffer must be released. */ vNetworkBufferRelease( pxNetworkBuffer ); iptraceETHERNET_RX_EVENT_LOST(); } else { iptraceNETWORK_INTERFACE_RECEIVE(); } } else { /* The buffer does not contain any data so there is no point sending it to the IP task. Just release it. */ vNetworkBufferRelease( pxNetworkBuffer ); iptraceETHERNET_RX_EVENT_LOST(); } } else { vNetworkBufferRelease( pxNetworkBuffer ); iptraceETHERNET_RX_EVENT_LOST(); } } else { /* Left a frame in the driver as a buffer was not available. */ gmac_dev_reset( &xGMACStruct ); } } }
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; }