1
0
mirror of https://github.com/FreeRTOS/FreeRTOS-Plus-TCP synced 2025-10-24 03:32:36 +08:00
Files
FreeRTOS-Plus-TCP/source/portable/NetworkInterface/TM4C/NetworkInterface.c
Aniruddha Kanhere a4124602cc Merge changes to main.
This commit brings in the refactoring and restructuring changes
from IntegrationTesting1 branch to the main branch.
It also includes additional unit tests for 100% coverage.
The rationale behind not creating a PR is that the conflicts were too
huge to be resolved correctly. Thus, a force push to the main branch is
being done.
2022-05-26 12:42:45 -07:00

784 lines
26 KiB
C

/**
* @file: NetworkInterface.c
* @author: jscott <jscott@hotstart.com>
* @date: Feb 1, 2022
* @copyright: Hotstart 2022 Hotstart Thermal Management. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* @brief:Network Interface driver for the Texas Instruments TM4C line of microcontrollers.
*
* This driver was written and tested with the TM4C1294NCPDT, which includes a built-in MAC and
* PHY. The expectation is that this driver should function correctly across all the MAC/PHY
* integrated parts of the TM4C129X parts.
*/
#include <stdint.h>
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include "inc/hw_ints.h"
#include "inc/hw_emac.h"
#include "inc/hw_memmap.h"
#include "inc/hw_nvic.h"
#include "driverlib/flash.h"
#include "driverlib/interrupt.h"
#include "driverlib/gpio.h"
#include "driverlib/rom_map.h"
#include "driverlib/sysctl.h"
#include "driverlib/systick.h"
#include "driverlib/emac.h"
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "FreeRTOS_IP.h"
#include "FreeRTOS_Sockets.h"
#include "FreeRTOS_IP_Private.h"
#include "NetworkBufferManagement.h"
#include "NetworkInterface.h"
#include "phyHandling.h"
#define BUFFER_SIZE ( ipTOTAL_ETHERNET_FRAME_SIZE + ipBUFFER_PADDING )
#define BUFFER_SIZE_ROUNDED_UP ( ( BUFFER_SIZE + 7 ) & ~0x7UL )
#define PHY_PHYS_ADDR 0
#ifndef niEMAC_SYSCONFIG_HZ
#define niEMAC_SYSCONFIG_HZ configCPU_CLOCK_HZ
#endif
#ifndef niEMAC_TX_DMA_DESC_COUNT
#define niEMAC_TX_DMA_DESC_COUNT 8
#endif
#ifndef niEMAC_RX_DMA_DESC_COUNT
#define niEMAC_RX_DMA_DESC_COUNT 8
#endif
#if ipconfigUSE_LINKED_RX_MESSAGES
#error Linked RX Messages are not supported by this driver
#endif
/* Default the size of the stack used by the EMAC deferred handler task to twice
* the size of the stack used by the idle task - but allow this to be overridden in
* FreeRTOSConfig.h as configMINIMAL_STACK_SIZE is a user definable constant. */
#ifndef configEMAC_TASK_STACK_SIZE
#define configEMAC_TASK_STACK_SIZE ( 2 * configMINIMAL_STACK_SIZE )
#endif
#ifndef niEMAC_HANDLER_TASK_PRIORITY
#define niEMAC_HANDLER_TASK_PRIORITY configMAX_PRIORITIES - 1
#endif
#if !defined( ipconfigETHERNET_AN_ENABLE )
/* Enable auto-negotiation */
#define ipconfigETHERNET_AN_ENABLE 1
#endif
#if !defined( ipconfigETHERNET_USE_100MB )
#define ipconfigETHERNET_USE_100MB 1
#endif
#if !defined( ipconfigETHERNET_USE_FULL_DUPLEX )
#define ipconfigETHERNET_USE_FULL_DUPLEX 1
#endif
typedef struct
{
uint32_t number_descriptors;
uint32_t write;
uint32_t read;
} tDescriptorList;
typedef enum
{
eMACInit, /* Must initialise MAC. */
eMACPass, /* Initialisation was successful. */
eMACFailed, /* Initialisation failed. */
} eMAC_INIT_STATUS_TYPE;
typedef enum
{
eMACInterruptNone = 0, /* No interrupts need servicing */
eMACInterruptRx = ( 1 << 0 ), /* Service RX interrupt */
eMACInterruptTx = ( 1 << 1 ), /* Service TX interrupt */
} eMAC_INTERRUPT_STATUS_TYPE;
static eMAC_INIT_STATUS_TYPE xMacInitStatus = eMACInit;
static volatile eMAC_INTERRUPT_STATUS_TYPE xMacInterruptStatus = eMACInterruptNone;
static tEMACDMADescriptor _tx_descriptors[ niEMAC_TX_DMA_DESC_COUNT ];
static tEMACDMADescriptor _rx_descriptors[ niEMAC_RX_DMA_DESC_COUNT ];
static tDescriptorList _tx_descriptor_list = { .number_descriptors = niEMAC_TX_DMA_DESC_COUNT, 0 };
static tDescriptorList _rx_descriptor_list = { .number_descriptors = niEMAC_RX_DMA_DESC_COUNT, 0 };
static uint8_t _network_buffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ][ BUFFER_SIZE_ROUNDED_UP ];
#pragma DATA_ALIGN(_network_buffers, 4)
static EthernetPhy_t xPhyObject;
static TaskHandle_t _deferred_task_handle = NULL;
const PhyProperties_t xPHYProperties =
{
#if ( ipconfigETHERNET_AN_ENABLE != 0 )
.ucSpeed = PHY_SPEED_AUTO,
.ucDuplex = PHY_DUPLEX_AUTO,
#else
#if ( ipconfigETHERNET_USE_100MB != 0 )
.ucSpeed = PHY_SPEED_100,
#else
.ucSpeed = PHY_SPEED_10,
#endif
#if ( ipconfigETHERNET_USE_FULL_DUPLEX != 0 )
.ucDuplex = PHY_DUPLEX_FULL,
#else
.ucDuplex = PHY_DUPLEX_HALF,
#endif
#endif /* if ( ipconfigETHERNET_AN_ENABLE != 0 ) */
};
/**
* Reads the Ethernet MAC from user Flash.
* @param mac_address_bytes[out] The byte array which will hold the MAC address
* @return pdPASS on success, pdFAIL if the MAC is invalid from user Flash
*/
static BaseType_t _ethernet_mac_get( uint8_t * mac_address_bytes );
/**
* Initialize DMA descriptors
*/
static void _dma_descriptors_init( void );
/**
* Frees previously sent network buffers
*/
static void _process_transmit_complete( void );
/**
* Processes received packets and forwards those acceptable to the network stack
*/
static BaseType_t _process_received_packet( void );
/**
* Processes PHY interrupts.
*/
static void _process_phy_interrupts( void );
/**
* Thread to forward received packets from the ISR to the network stack
* @param parameters Not used
*/
static void _deferred_task( void * parameters );
/**
* Phy read implementation for the TM4C
* @param xAddress
* @param xRegister
* @param pulValue
* @return
*/
static BaseType_t xTM4C_PhyRead( BaseType_t xAddress,
BaseType_t xRegister,
uint32_t * pulValue );
/**
* Phy write implementation for the TM4C
* @param xAddress
* @param xRegister
* @param ulValue
* @return
*/
static BaseType_t xTM4C_PhyWrite( BaseType_t xAddress,
BaseType_t xRegister,
uint32_t ulValue );
/**
* Probe the PHY
*/
static void vMACBProbePhy( void );
BaseType_t xNetworkInterfaceInitialise( void )
{
uint8_t mac_address_bytes[ 6 ];
uint16_t ui16Val;
BaseType_t xResult = pdFAIL;
if( eMACInit == xMacInitStatus )
{
/* Create the RX packet forwarding task */
if( pdFAIL == xTaskCreate( _deferred_task, "EMAC", configEMAC_TASK_STACK_SIZE, NULL, niEMAC_HANDLER_TASK_PRIORITY, &_deferred_task_handle ) )
{
xMacInitStatus = eMACFailed;
}
else
{
/* Read the MAC from user Flash */
if( pdPASS != _ethernet_mac_get( &mac_address_bytes[ 0 ] ) )
{
xMacInitStatus = eMACFailed;
}
else
{
MAP_SysCtlPeripheralReset( SYSCTL_PERIPH_EMAC0 );
while( !MAP_SysCtlPeripheralReady( SYSCTL_PERIPH_EMAC0 ) )
{
}
MAP_SysCtlPeripheralReset( SYSCTL_PERIPH_EPHY0 );
while( !MAP_SysCtlPeripheralReady( SYSCTL_PERIPH_EPHY0 ) )
{
}
MAP_EMACInit( EMAC0_BASE, niEMAC_SYSCONFIG_HZ,
EMAC_BCONFIG_MIXED_BURST | EMAC_BCONFIG_PRIORITY_FIXED, 4,
4, 0 );
MAP_EMACConfigSet(
EMAC0_BASE,
(
EMAC_CONFIG_100MBPS |
EMAC_CONFIG_FULL_DUPLEX |
EMAC_CONFIG_CHECKSUM_OFFLOAD |
EMAC_CONFIG_7BYTE_PREAMBLE |
EMAC_CONFIG_IF_GAP_96BITS |
EMAC_CONFIG_USE_MACADDR0 |
EMAC_CONFIG_SA_FROM_DESCRIPTOR |
EMAC_CONFIG_BO_LIMIT_1024 |
EMAC_CONFIG_STRIP_CRC
),
(
EMAC_MODE_RX_STORE_FORWARD |
EMAC_MODE_TX_STORE_FORWARD |
EMAC_MODE_RX_THRESHOLD_64_BYTES |
EMAC_MODE_TX_THRESHOLD_64_BYTES ),
0 );
/* Clear any stray PHY interrupts that may be set. */
ui16Val = MAP_EMACPHYRead( EMAC0_BASE, PHY_PHYS_ADDR, EPHY_MISR1 );
ui16Val = MAP_EMACPHYRead( EMAC0_BASE, PHY_PHYS_ADDR, EPHY_MISR2 );
/* Configure and enable PHY interrupts */
ui16Val = MAP_EMACPHYRead( EMAC0_BASE, PHY_PHYS_ADDR, EPHY_SCR );
ui16Val |= ( EPHY_SCR_INTEN_EXT | EPHY_SCR_INTOE_EXT );
MAP_EMACPHYWrite( EMAC0_BASE, PHY_PHYS_ADDR, EPHY_SCR, ui16Val );
/* Read the PHY interrupt status to clear any stray events. */
ui16Val = MAP_EMACPHYRead( EMAC0_BASE, PHY_PHYS_ADDR, EPHY_MISR1 );
/* Set MAC filtering options. We receive all broadcast and mui32ticast */
/* packets along with those addressed specifically for us. */
MAP_EMACFrameFilterSet( EMAC0_BASE, ( EMAC_FRMFILTER_HASH_AND_PERFECT |
EMAC_FRMFILTER_PASS_MULTICAST ) );
/* Set the MAC address */
MAP_EMACAddrSet( EMAC0_BASE, 0, &mac_address_bytes[ 0 ] );
/* Clears any previously asserted interrupts */
MAP_EMACIntClear( EMAC0_BASE, EMACIntStatus( EMAC0_BASE, false ) );
/* Initialize the DMA descriptors */
_dma_descriptors_init();
/* Enable TX/RX */
MAP_EMACTxEnable( EMAC0_BASE );
MAP_EMACRxEnable( EMAC0_BASE );
/* Set the interrupt to a lower priority than the OS scheduler interrupts */
MAP_IntPrioritySet( INT_EMAC0, ( 6 << ( 8 - configPRIO_BITS ) ) );
/* Probe the PHY with the stack driver */
vMACBProbePhy();
xMacInitStatus = eMACPass;
}
}
}
if( eMACPass == xMacInitStatus )
{
/* Wait for the link status to come up before enabling interrupts */
if( xPhyObject.ulLinkStatusMask != 0U )
{
/* Enable the Ethernet RX and TX interrupt source. */
MAP_EMACIntEnable( EMAC0_BASE, ( EMAC_INT_RECEIVE | EMAC_INT_TRANSMIT |
EMAC_INT_TX_STOPPED | EMAC_INT_RX_NO_BUFFER |
EMAC_INT_RX_STOPPED | EMAC_INT_PHY ) );
/* Enable EMAC interrupts */
MAP_IntEnable( INT_EMAC0 );
xResult = pdPASS;
}
}
return xResult;
}
BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxNetworkBuffer,
BaseType_t xReleaseAfterSend )
{
BaseType_t success = pdTRUE;
tEMACDMADescriptor * dma_descriptor;
/* As this driver is strictly zero-copy, assert that the stack does not call this function with */
/* xReleaseAfterSend as false */
configASSERT( 0 != xReleaseAfterSend );
dma_descriptor = &_tx_descriptors[ _tx_descriptor_list.write ];
/* If the DMA controller still owns the descriptor, all DMA descriptors are in use, bail out */
if( 0U == ( dma_descriptor->ui32CtrlStatus & DES0_RX_CTRL_OWN ) )
{
/* Assign the buffer to the DMA descriptor */
dma_descriptor->pvBuffer1 = pxNetworkBuffer->pucEthernetBuffer;
/* Inform the DMA of the size of the packet */
dma_descriptor->ui32Count = ( pxNetworkBuffer->xDataLength & DES1_TX_CTRL_BUFF1_SIZE_M ) << DES1_TX_CTRL_BUFF1_SIZE_S;
/* Inform the DMA that this is the first and last segment of the packet, calculate the checksums, the descriptors are */
/* chained, and to use interrupts */
dma_descriptor->ui32CtrlStatus = DES0_TX_CTRL_FIRST_SEG | DES0_TX_CTRL_IP_ALL_CKHSUMS | DES0_TX_CTRL_CHAINED
| DES0_TX_CTRL_LAST_SEG | DES0_TX_CTRL_INTERRUPT | DES0_TX_CTRL_REPLACE_CRC;
/* Advance the index in the list */
_tx_descriptor_list.write++;
/* Wrap around if required */
if( _tx_descriptor_list.write == niEMAC_TX_DMA_DESC_COUNT )
{
_tx_descriptor_list.write = 0;
}
/* Give the DMA descriptor to the DMA controller */
dma_descriptor->ui32CtrlStatus |= DES0_TX_CTRL_OWN;
/* Inform the DMA it has a new descriptor */
MAP_EMACTxDMAPollDemand( EMAC0_BASE );
iptraceNETWORK_INTERFACE_TRANSMIT();
}
else
{
/* Release the stack descriptor and buffer to prevent memory leaks. */
vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
success = pdFALSE;
}
return success;
}
void vNetworkInterfaceAllocateRAMToBuffers( NetworkBufferDescriptor_t pxNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ] )
{
BaseType_t i;
for( i = 0; i < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; i++ )
{
/* Assign buffers to each descriptor */
pxNetworkBuffers[ i ].pucEthernetBuffer = &_network_buffers[ i ][ ipBUFFER_PADDING ];
/* Set the 'hidden' reference to the descriptor for use in DMA interrupts */
*( ( uint32_t * ) &_network_buffers[ i ][ 0 ] ) = ( uint32_t ) &( ( pxNetworkBuffers[ i ] ) );
}
}
static BaseType_t _ethernet_mac_get( uint8_t * mac_address_bytes )
{
BaseType_t success = pdPASS;
uint32_t mac_address_words[ 2 ] = { 0 };
/* Attempt to read the MAC address */
MAP_FlashUserGet( &mac_address_words[ 0 ], &mac_address_words[ 1 ] );
/* If the MAC is not set, fail */
if( ( 0xFFFFFFFF == mac_address_words[ 0 ] ) || ( 0xFFFFFFFF == mac_address_words[ 1 ] ) )
{
success = pdFAIL;
}
else
{
/* Otherwise return the MAC address in a usable format for the driver */
*( mac_address_bytes + 0 ) = ( mac_address_words[ 0 ] >> 0 ) & 0xFF;
*( mac_address_bytes + 1 ) = ( mac_address_words[ 0 ] >> 8 ) & 0xFF;
*( mac_address_bytes + 2 ) = ( mac_address_words[ 0 ] >> 16 ) & 0xFF;
*( mac_address_bytes + 3 ) = ( mac_address_words[ 1 ] >> 0 ) & 0xFF;
*( mac_address_bytes + 4 ) = ( mac_address_words[ 1 ] >> 8 ) & 0xFF;
*( mac_address_bytes + 5 ) = ( mac_address_words[ 1 ] >> 16 ) & 0xFF;
}
return success;
}
static void _dma_descriptors_init( void )
{
uint32_t i;
size_t buffer_size_requested;
NetworkBufferDescriptor_t * stack_descriptor;
/* Initialize the TX DMA descriptors */
for( i = 0; i < niEMAC_TX_DMA_DESC_COUNT; i++ )
{
/* Clear the length of the packet */
_tx_descriptors[ i ].ui32Count = 0;
/* Clear the reference to the buffer */
_tx_descriptors[ i ].pvBuffer1 = NULL;
/* Set the next link in the DMA descriptor chain, either the next in the chain or the first descriptor in the event */
/* that this is the last descriptor */
_tx_descriptors[ i ].DES3.pLink = (
( i == ( niEMAC_TX_DMA_DESC_COUNT - 1 ) ) ?
&_tx_descriptors[ 0 ] : &_tx_descriptors[ i + 1 ] );
_tx_descriptors[ i ].ui32CtrlStatus = DES0_TX_CTRL_INTERRUPT | DES0_TX_CTRL_CHAINED
| DES0_TX_CTRL_IP_ALL_CKHSUMS;
}
/* Set the TX descriptor index */
_tx_descriptor_list.write = 0;
_tx_descriptor_list.read = 0;
for( i = 0; i < niEMAC_RX_DMA_DESC_COUNT; i++ )
{
stack_descriptor = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE, 0 );
configASSERT( NULL != stack_descriptor );
/* Get a buffer from the stack and assign it to the DMA Descriptor */
_rx_descriptors[ i ].pvBuffer1 = stack_descriptor->pucEthernetBuffer;
/* Inform the DMA controller that the descriptors are chained and the size of the buffer */
_rx_descriptors[ i ].ui32Count = DES1_RX_CTRL_CHAINED | ( ( buffer_size_requested << DES1_TX_CTRL_BUFF1_SIZE_S ) & DES1_TX_CTRL_BUFF1_SIZE_M );
/* Give the DMA descriptor to the DMA controller */
_rx_descriptors[ i ].ui32CtrlStatus = DES0_RX_CTRL_OWN;
/* Set the next link the DMA descriptor chain */
_rx_descriptors[ i ].DES3.pLink = ( ( i == ( niEMAC_RX_DMA_DESC_COUNT - 1 ) ) ? &_rx_descriptors[ 0 ] : &_rx_descriptors[ i + 1 ] );
}
/* Set the RX descriptor index */
_rx_descriptor_list.write = 0;
/* Set the head of the DMA descriptor list in the EMAC peripheral */
MAP_EMACTxDMADescriptorListSet( EMAC0_BASE, &_tx_descriptors[ 0 ] );
MAP_EMACRxDMADescriptorListSet( EMAC0_BASE, &_rx_descriptors[ 0 ] );
}
void freertos_tcp_ethernet_int( void )
{
uint32_t status;
BaseType_t higher_priority_task_woken = pdFALSE;
/* Read the interrupt status */
status = EMACIntStatus( EMAC0_BASE, true );
/* Handle power management interrupts */
if( status & EMAC_INT_POWER_MGMNT )
{
MAP_EMACTxEnable( EMAC0_BASE );
MAP_EMACRxEnable( EMAC0_BASE );
MAP_EMACPowerManagementStatusGet( EMAC0_BASE );
status &= ~( EMAC_INT_POWER_MGMNT );
}
if( status )
{
MAP_EMACIntClear( EMAC0_BASE, status );
}
/* Handle PHY interrupts */
if( EMAC_INT_PHY & status )
{
_process_phy_interrupts();
}
/* Handle Transmit Complete interrupts */
if( EMAC_INT_TRANSMIT & status )
{
xMacInterruptStatus |= eMACInterruptTx;
}
/* Handle Receive interrupts */
if( ( EMAC_INT_RECEIVE | EMAC_INT_RX_NO_BUFFER | EMAC_INT_RX_STOPPED ) & status )
{
xMacInterruptStatus |= eMACInterruptRx;
}
/* If interrupts of concern were found, wake the task if present */
if( ( 0 != xMacInterruptStatus ) && ( NULL != _deferred_task_handle ) )
{
vTaskNotifyGiveFromISR( _deferred_task_handle, &higher_priority_task_woken );
portYIELD_FROM_ISR( higher_priority_task_woken );
}
}
static void _process_transmit_complete( void )
{
uint32_t i;
tEMACDMADescriptor * dma_descriptor;
NetworkBufferDescriptor_t * stack_descriptor;
for( i = 0; ( ( i < _tx_descriptor_list.number_descriptors ) && ( _tx_descriptor_list.read != _tx_descriptor_list.write ) ); i++ )
{
/* Get a reference to the current DMA descriptor */
dma_descriptor = &_tx_descriptors[ _tx_descriptor_list.read ];
/* If the descriptor is still owned by the DMA controller, exit */
if( dma_descriptor->ui32CtrlStatus & DES0_TX_CTRL_OWN )
{
break;
}
/* Get the 'hidden' reference to the stack descriptor from the buffer */
stack_descriptor = pxPacketBuffer_to_NetworkBuffer( dma_descriptor->pvBuffer1 );
configASSERT( NULL != stack_descriptor );
/* Release the stack descriptor */
vReleaseNetworkBufferAndDescriptor( stack_descriptor );
_tx_descriptor_list.read++;
if( _tx_descriptor_list.read == _tx_descriptor_list.number_descriptors )
{
_tx_descriptor_list.read = 0;
}
}
}
static BaseType_t _process_received_packet( void )
{
NetworkBufferDescriptor_t * new_stack_descriptor;
NetworkBufferDescriptor_t * cur_stack_descriptor;
tEMACDMADescriptor * dma_descriptor;
uint32_t i;
IPStackEvent_t event;
BaseType_t result = pdTRUE;
const TickType_t max_block_time = pdMS_TO_MIN_TICKS( 50 );
/* Go through the list of RX DMA descriptors */
for( i = 0; i < niEMAC_RX_DMA_DESC_COUNT; i++ )
{
/* Get a reference to the descriptor */
dma_descriptor = &_rx_descriptors[ _rx_descriptor_list.write ];
/* Make sure the buffer is non-null */
configASSERT( NULL != dma_descriptor->pvBuffer1 );
/* If the descriptor is still in use by DMA, stop processing here */
if( DES0_RX_CTRL_OWN == ( dma_descriptor->ui32CtrlStatus & DES0_RX_CTRL_OWN ) )
{
break;
}
/* If there is NOT an error in the frame */
if( 0U == ( dma_descriptor->ui32CtrlStatus & DES0_RX_STAT_ERR ) )
{
/* Get a new empty descriptor */
new_stack_descriptor = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE, max_block_time );
/* If a descriptor was provided, else this packet is dropped */
if( NULL != new_stack_descriptor )
{
/* Get a reference to the current stack descriptor held by the DMA descriptor */
cur_stack_descriptor = pxPacketBuffer_to_NetworkBuffer( dma_descriptor->pvBuffer1 );
/* Set the length of the buffer on the current descriptor */
cur_stack_descriptor->xDataLength = ( dma_descriptor->ui32CtrlStatus & DES0_RX_STAT_FRAME_LENGTH_M ) >> DES0_RX_STAT_FRAME_LENGTH_S;
/* Assign the new stack descriptor to the DMA descriptor */
dma_descriptor->pvBuffer1 = new_stack_descriptor->pucEthernetBuffer;
/* Ask the stack if it wants to process the frame. */
if( eProcessBuffer == eConsiderFrameForProcessing( cur_stack_descriptor->pucEthernetBuffer ) )
{
/* Setup the event */
event.eEventType = eNetworkRxEvent;
event.pvData = cur_stack_descriptor;
/* Forward the event */
if( pdFALSE == xSendEventStructToIPTask( &event, 0 ) )
{
/* Release the buffer if an error was encountered */
vReleaseNetworkBufferAndDescriptor( cur_stack_descriptor );
iptraceETHERNET_RX_EVENT_LOST();
}
else
{
iptraceNETWORK_INTERFACE_RECEIVE();
result = pdTRUE;
}
}
else
{
/* Free the descriptor */
vReleaseNetworkBufferAndDescriptor( cur_stack_descriptor );
}
} /* end if descriptor is available */
else
{
/* No stack descriptor was available for the next RX DMA descriptor so this packet */
/* is dropped */
/* Mark the RX event as lost */
iptraceETHERNET_RX_EVENT_LOST();
}
} /* end if frame had error. In this case, give the buffer back to the DMA for the next RX */
/* Set up the DMA descriptor for the next receive transaction */
dma_descriptor->ui32Count = DES1_RX_CTRL_CHAINED | ipTOTAL_ETHERNET_FRAME_SIZE;
dma_descriptor->ui32CtrlStatus = DES0_RX_CTRL_OWN;
_rx_descriptor_list.write++;
if( _rx_descriptor_list.write == _rx_descriptor_list.number_descriptors )
{
_rx_descriptor_list.write = 0;
}
}
return result;
}
/**
* This deferred interrupt handler process changes from the PHY auto-negotiation to configure the
* MAC as appropriate.
*/
static void _process_phy_interrupts( void )
{
uint16_t value;
uint16_t status;
uint32_t configuration;
uint32_t mode;
uint32_t max_frame_size;
/* Read the PHY interrupts status */
value = MAP_EMACPHYRead( EMAC0_BASE, PHY_PHYS_ADDR, EPHY_MISR1 );
status = MAP_EMACPHYRead( EMAC0_BASE, PHY_PHYS_ADDR, EPHY_STS );
if( value & ( EPHY_MISR1_SPEED | EPHY_MISR1_SPEED | EPHY_MISR1_ANC ) )
{
/* If the speed or duplex has changed */
MAP_EMACConfigGet( EMAC0_BASE, &configuration, &mode, &max_frame_size );
if( status & EPHY_STS_SPEED )
{
configuration &= ~EMAC_CONFIG_100MBPS;
}
else
{
configuration |= EMAC_CONFIG_100MBPS;
}
if( status & EPHY_STS_DUPLEX )
{
configuration |= EMAC_CONFIG_FULL_DUPLEX;
}
else
{
configuration &= ~EMAC_CONFIG_FULL_DUPLEX;
}
MAP_EMACConfigSet( EMAC0_BASE, configuration, mode, max_frame_size );
}
}
static void _deferred_task( void * parameters )
{
BaseType_t had_reception;
IPStackEvent_t link_down_event;
const TickType_t max_block_time = pdMS_TO_TICKS( 100 );
/* Ignore parameters */
( void ) parameters;
for( ; ; )
{
had_reception = pdFALSE;
ulTaskNotifyTake( pdTRUE, max_block_time );
if( eMACInterruptTx == ( xMacInterruptStatus & eMACInterruptTx ) )
{
xMacInterruptStatus &= ~( eMACInterruptTx );
_process_transmit_complete();
}
if( eMACInterruptRx == ( xMacInterruptStatus & eMACInterruptRx ) )
{
xMacInterruptStatus &= ~( eMACInterruptRx );
had_reception = _process_received_packet();
}
if( pdTRUE == xPhyCheckLinkStatus( &xPhyObject, had_reception ) )
{
/* The link has gone done */
if( 0 == xPhyObject.ulLinkStatusMask )
{
link_down_event.eEventType = eNetworkDownEvent;
link_down_event.pvData = NULL;
xSendEventStructToIPTask( &link_down_event, 0 );
}
}
}
}
static void vMACBProbePhy( void )
{
vPhyInitialise( &xPhyObject, xTM4C_PhyRead, xTM4C_PhyWrite );
xPhyDiscover( &xPhyObject );
xPhyConfigure( &xPhyObject, &xPHYProperties );
}
static BaseType_t xTM4C_PhyRead( BaseType_t xAddress,
BaseType_t xRegister,
uint32_t * pulValue )
{
*pulValue = MAP_EMACPHYRead( EMAC0_BASE, ( uint8_t ) xAddress, ( uint8_t ) xRegister );
return 0;
}
static BaseType_t xTM4C_PhyWrite( BaseType_t xAddress,
BaseType_t xRegister,
uint32_t ulValue )
{
MAP_EMACPHYWrite( EMAC0_BASE, ( uint8_t ) xAddress, ( uint8_t ) xRegister, ulValue );
return 0;
}