diff --git a/.github/.cSpellWords.txt b/.github/.cSpellWords.txt index ed12e1e9c..319b2239e 100644 --- a/.github/.cSpellWords.txt +++ b/.github/.cSpellWords.txt @@ -247,6 +247,7 @@ DIVIDEBY DIVIDEDBY DLPSTATE DMAARBITRATION +DMAB DMABD DMABMR DMAC @@ -1562,6 +1563,7 @@ x xaxiemacif XCOL xemac +XEMACMAP xemacps XEMACPS xemacpsp diff --git a/source/portable/NetworkInterface/Zynq/NetworkInterface.c b/source/portable/NetworkInterface/Zynq/NetworkInterface.c index 21ad820ce..8b5913bf1 100644 --- a/source/portable/NetworkInterface/Zynq/NetworkInterface.c +++ b/source/portable/NetworkInterface/Zynq/NetworkInterface.c @@ -254,42 +254,56 @@ static BaseType_t xZynqNetworkInterfaceInitialise( NetworkInterface_t * pxInterf /* Initialize the mac and set the MAC address at position 1. */ XEmacPs_SetMacAddress( pxEMAC_PS, ( void * ) pxEndPoint->xMACAddress.ucBytes, 1 ); - #if ( ipconfigUSE_LLMNR == 1 ) + #if ( ipconfigIS_ENABLED( ipconfigUSE_LLMNR ) ) { - /* Also add LLMNR multicast MAC address. */ - #if ( ipconfigUSE_IPv6 == 0 ) + #if ( ipconfigIS_ENABLED( ipconfigUSE_IPv4 ) ) { XEmacPs_SetHash( pxEMAC_PS, ( void * ) xLLMNR_MacAddress.ucBytes ); } - #else + #endif /* ( ipconfigIS_ENABLED( ipconfigUSE_IPv4 ) */ + + #if ( ipconfigIS_ENABLED( ipconfigUSE_IPv6 ) ) { - NetworkEndPoint_t * pxEndPoint; - NetworkInterface_t * pxInterface = pxMyInterfaces[ xEMACIndex ]; + XEmacPs_SetHash( pxEMAC_PS, ( void * ) xLLMNR_MacAddressIPv6.ucBytes ); + } + #endif /* ( ipconfigIS_ENABLED( ipconfigUSE_IPv6 ) ) */ + } + #endif /* ( ipconfigIS_ENABLED( ipconfigUSE_LLMNR ) ) */ - for( pxEndPoint = FreeRTOS_FirstEndPoint( pxInterface ); - pxEndPoint != NULL; - pxEndPoint = FreeRTOS_NextEndPoint( pxInterface, pxEndPoint ) ) - { - if( pxEndPoint->bits.bIPv6 != pdFALSE_UNSIGNED ) - { - unsigned char ucMACAddress[ 6 ] = { 0x33, 0x33, 0xff, 0, 0, 0 }; - ucMACAddress[ 3 ] = pxEndPoint->ipv6_settings.xIPAddress.ucBytes[ 13 ]; - ucMACAddress[ 4 ] = pxEndPoint->ipv6_settings.xIPAddress.ucBytes[ 14 ]; - ucMACAddress[ 5 ] = pxEndPoint->ipv6_settings.xIPAddress.ucBytes[ 15 ]; - XEmacPs_SetHash( pxEMAC_PS, ( void * ) ucMACAddress ); - } - } + #if ( ipconfigIS_ENABLED( ipconfigUSE_MDNS ) ) + { + #if ( ipconfigIS_ENABLED( ipconfigUSE_IPv4 ) ) + { + XEmacPs_SetHash( pxEMAC_PS, ( void * ) xMDNS_MacAddress.ucBytes ); + } + #endif /* ( ipconfigIS_ENABLED( ipconfigUSE_IPv4 ) */ - XEmacPs_SetHash( pxEMAC_PS, ( void * ) xLLMNR_MacAddressIPv6.ucBytes ); + #if ( ipconfigIS_ENABLED( ipconfigUSE_IPv6 ) ) + { + XEmacPs_SetHash( pxEMAC_PS, ( void * ) xMDNS_MacAddressIPv6.ucBytes ); } - #endif /* if ( ipconfigUSE_IPv6 == 0 ) */ + #endif /* ( ipconfigIS_ENABLED( ipconfigUSE_IPv6 ) ) */ } - #endif /* ipconfigUSE_LLMNR == 1 */ + #endif /* ( ipconfigIS_ENABLED( ipconfigUSE_MDNS) ) */ - #if ( ( ipconfigUSE_MDNS == 1 ) && ( ipconfigUSE_IPv6 != 0 ) ) - XEmacPs_SetHash( pxEMAC_PS, ( void * ) xMDNS_MacAddress.ucBytes ); - XEmacPs_SetHash( pxEMAC_PS, ( void * ) xMDNS_MacAddressIPv6.ucBytes ); - #endif + #if ( ipconfigIS_ENABLED( ipconfigUSE_IPv6 ) ) + { + /* set the solicited-node multicast address */ + for( NetworkEndPoint_t * pxEndPointIter = FreeRTOS_FirstEndPoint( pxInterface ); + pxEndPointIter != NULL; + pxEndPointIter = FreeRTOS_NextEndPoint( pxInterface, pxEndPointIter ) ) + { + if( pxEndPointIter->bits.bIPv6 != pdFALSE_UNSIGNED ) + { + unsigned char ucSsolicitedNodeMAC[ 6 ] = { 0x33, 0x33, 0xff, 0, 0, 0 }; + ucSsolicitedNodeMAC[ 3 ] = pxEndPointIter->ipv6_settings.xIPAddress.ucBytes[ 13 ]; + ucSsolicitedNodeMAC[ 4 ] = pxEndPointIter->ipv6_settings.xIPAddress.ucBytes[ 14 ]; + ucSsolicitedNodeMAC[ 5 ] = pxEndPointIter->ipv6_settings.xIPAddress.ucBytes[ 15 ]; + XEmacPs_SetHash( pxEMAC_PS, ( void * ) ucSsolicitedNodeMAC ); + } + } + } + #endif /* ( ipconfigIS_ENABLED( ipconfigUSE_IPv6 ) ) */ pxEndPoint = FreeRTOS_NextEndPoint( pxInterface, pxEndPoint ); @@ -378,7 +392,8 @@ static BaseType_t xZynqNetworkInterfaceOutput( NetworkInterface_t * pxInterface, * the protocol checksum to have a value of zero. */ pxPacket = ( ProtocolPacket_t * ) ( pxBuffer->pucEthernetBuffer ); - #if ( ipconfigUSE_IPv6 != 0 ) + #if ( ipconfigIS_ENABLED( ipconfigUSE_IPv6 ) ) + { ICMPPacket_IPv6_t * pxICMPPacket = ( ICMPPacket_IPv6_t * ) pxBuffer->pucEthernetBuffer; if( ( pxPacket->xICMPPacket.xEthernetHeader.usFrameType == ipIPv6_FRAME_TYPE ) && @@ -389,16 +404,21 @@ static BaseType_t xZynqNetworkInterfaceOutput( NetworkInterface_t * pxInterface, * so for ICMP and other protocols it must be done manually. */ usGenerateProtocolChecksum( pxBuffer->pucEthernetBuffer, pxBuffer->xDataLength, pdTRUE ); } - #endif + } + #endif /* ( ipconfigIS_ENABLED( ipconfigUSE_IPv6 ) ) */ - if( ( pxPacket->xICMPPacket.xEthernetHeader.usFrameType == ipIPv4_FRAME_TYPE ) && - ( pxPacket->xICMPPacket.xIPHeader.ucProtocol == ipPROTOCOL_ICMP ) ) + #if ( ipconfigIS_ENABLED( ipconfigUSE_IPv4 ) ) { - /* The EMAC will calculate the checksum of the IP-header. - * It can only calculate protocol checksums of UDP and TCP, - * so for ICMP and other protocols it must be done manually. */ - usGenerateProtocolChecksum( pxBuffer->pucEthernetBuffer, pxBuffer->xDataLength, pdTRUE ); + if( ( pxPacket->xICMPPacket.xEthernetHeader.usFrameType == ipIPv4_FRAME_TYPE ) && + ( pxPacket->xICMPPacket.xIPHeader.ucProtocol == ipPROTOCOL_ICMP ) ) + { + /* The EMAC will calculate the checksum of the IP-header. + * It can only calculate protocol checksums of UDP and TCP, + * so for ICMP and other protocols it must be done manually. */ + usGenerateProtocolChecksum( pxBuffer->pucEthernetBuffer, pxBuffer->xDataLength, pdTRUE ); + } } + #endif /* ( ipconfigIS_ENABLED( ipconfigUSE_IPv4 ) ) */ } #endif /* ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM */ diff --git a/source/portable/NetworkInterface/xilinx_ultrascale/NetworkInterface.c b/source/portable/NetworkInterface/xilinx_ultrascale/NetworkInterface.c index 6928131e6..bf97e3e27 100644 --- a/source/portable/NetworkInterface/xilinx_ultrascale/NetworkInterface.c +++ b/source/portable/NetworkInterface/xilinx_ultrascale/NetworkInterface.c @@ -43,12 +43,14 @@ #include "FreeRTOS_ARP.h" #include "NetworkBufferManagement.h" #include "NetworkInterface.h" +#include "FreeRTOS_Routing.h" /* Xilinx library files. */ #include #include "x_topology.h" #include "x_emacpsif.h" #include "x_emacpsif_hw.h" +#include "x_emac_map.h" /* Provided memory configured as uncached. */ #include "uncached_memory.h" @@ -114,7 +116,8 @@ * Look for the link to be up every few milliseconds until * xMaxTimeTicks has passed or a link is found. */ -static BaseType_t prvGMACWaitLS( TickType_t xMaxTimeTicks ); +static BaseType_t prvGMACWaitLS( BaseType_t xEMACIndex, + TickType_t xMaxTimeTicks ); /* * A deferred interrupt handler for all MAC/DMA interrupt sources. @@ -123,116 +126,279 @@ static void prvEMACHandlerTask( void * pvParameters ); /*-----------------------------------------------------------*/ +/* FreeRTOS+TCP/multi : + * Each network device has 3 access functions: + * - initialise the device + * - output a network packet + * - return the PHY link-status (LS) + * They can be defined as static because their addresses will be + * stored in struct NetworkInterface_t. */ + +static NetworkInterface_t * pxMyInterfaces[ XPAR_XEMACPS_NUM_INSTANCES ]; + +static BaseType_t xUltrascaleNetworkInterfaceInitialise( NetworkInterface_t * pxInterface ); + +static BaseType_t xUltrascaleNetworkInterfaceOutput( NetworkInterface_t * pxInterface, + NetworkBufferDescriptor_t * const pxBuffer, + BaseType_t bReleaseAfterSend ); + +static BaseType_t xUltrascaleGetPhyLinkStatus( NetworkInterface_t * pxInterface ); + +NetworkInterface_t * pxUltrascale_FillInterfaceDescriptor( BaseType_t xEMACIndex, + NetworkInterface_t * pxInterface ); + +/*-----------------------------------------------------------*/ + /* EMAC data/descriptions. */ -static xemacpsif_s xEMACpsif; -struct xtopology_t xXTopology = +static xemacpsif_s xEMACpsifs[ XPAR_XEMACPS_NUM_INSTANCES ]; + +struct xtopology_t xXTopologies[ XPAR_XEMACPS_NUM_INSTANCES ] = { - .emac_baseaddr = XPAR_XEMACPS_0_BASEADDR, - .emac_type = xemac_type_emacps, - .intc_baseaddr = 0x0, - .intc_emac_intr = 0x0, - .scugic_baseaddr = XPAR_SCUGIC_0_CPU_BASEADDR, - .scugic_emac_intr = XPAR_XEMACPS_3_INTR, + [ 0 ] = + { + .emac_baseaddr = XPAR_XEMACPS_0_BASEADDR, + .emac_type = xemac_type_emacps, + .intc_baseaddr = 0x0, + .intc_emac_intr = 0x0, + .scugic_baseaddr = XPAR_SCUGIC_0_CPU_BASEADDR, + .scugic_emac_intr = ZYNQMP_EMACPS_0_IRQ_ID, + }, + #if ( XPAR_XEMACPS_NUM_INSTANCES > 1 ) + [ 1 ] = + { + .emac_baseaddr = XPAR_XEMACPS_1_BASEADDR, + .emac_type = xemac_type_emacps, + .intc_baseaddr = 0x0, + .intc_emac_intr = 0x0, + .scugic_baseaddr = XPAR_SCUGIC_0_CPU_BASEADDR, + .scugic_emac_intr = ZYNQMP_EMACPS_1_IRQ_ID, + }, + #elif ( XPAR_XEMACPS_NUM_INSTANCES > 2 ) + [ 2 ] = + { + .emac_baseaddr = XPAR_XEMACPS_2_BASEADDR, + .emac_type = xemac_type_emacps, + .intc_baseaddr = 0x0, + .intc_emac_intr = 0x0, + .scugic_baseaddr = XPAR_SCUGIC_0_CPU_BASEADDR, + .scugic_emac_intr = ZYNQMP_EMACPS_2_IRQ_ID, + }, + #elif ( XPAR_XEMACPS_NUM_INSTANCES > 3 ) + [ 3 ] = + { + .emac_baseaddr = XPAR_XEMACPS_3_BASEADDR, + .emac_type = xemac_type_emacps, + .intc_baseaddr = 0x0, + .intc_emac_intr = 0x0, + .scugic_baseaddr = XPAR_SCUGIC_0_CPU_BASEADDR, + .scugic_emac_intr = ZYNQMP_EMACPS_3_IRQ_ID, + }, + #endif /* if ( XPAR_XEMACPS_NUM_INSTANCES > 1 ) */ }; -XEmacPs_Config mac_config = +XEmacPs_Config mac_configs[ XPAR_XEMACPS_NUM_INSTANCES ] = { - .DeviceId = XPAR_PSU_ETHERNET_3_DEVICE_ID, /**< Unique ID of device */ - .BaseAddress = XPAR_PSU_ETHERNET_3_BASEADDR, /**< Physical base address of IPIF registers */ - .IsCacheCoherent = XPAR_PSU_ETHERNET_3_IS_CACHE_COHERENT + [ 0 ] = + { + .DeviceId = XPAR_XEMACPS_0_DEVICE_ID, /**< Unique ID of device */ + .BaseAddress = XPAR_XEMACPS_0_BASEADDR, /**< Physical base address of IPIF registers */ + .IsCacheCoherent = XPAR_XEMACPS_0_IS_CACHE_COHERENT + }, + #if ( XPAR_XEMACPS_NUM_INSTANCES > 1 ) + [ 1 ] = + { + .DeviceId = XPAR_XEMACPS_1_DEVICE_ID, /**< Unique ID of device */ + .BaseAddress = XPAR_XEMACPS_1_BASEADDR, /**< Physical base address of IPIF registers */ + .IsCacheCoherent = XPAR_XEMACPS_1_IS_CACHE_COHERENT + }, + #elif ( XPAR_XEMACPS_NUM_INSTANCES > 2 ) + [ 2 ] = + { + .DeviceId = XPAR_XEMACPS_2_DEVICE_ID, /**< Unique ID of device */ + .BaseAddress = XPAR_XEMACPS_2_BASEADDR, /**< Physical base address of IPIF registers */ + .IsCacheCoherent = XPAR_XEMACPS_2_IS_CACHE_COHERENT + }, + #elif ( XPAR_XEMACPS_NUM_INSTANCES > 3 ) + [ 3 ] = + { + .DeviceId = XPAR_XEMACPS_3_DEVICE_ID, /**< Unique ID of device */ + .BaseAddress = XPAR_XEMACPS_3_BASEADDR, /**< Physical base address of IPIF registers */ + .IsCacheCoherent = XPAR_XEMACPS_3_IS_CACHE_COHERENT + }, + #endif /* if ( XPAR_XEMACPS_NUM_INSTANCES > 1 ) */ }; -/* A copy of PHY register 1: 'PHY_REG_01_BMSR' */ -static uint32_t ulPHYLinkStatus = 0uL; +extern uint32_t phy_detected[ 4 ]; -#if ( ipconfigUSE_LLMNR == 1 ) -static const uint8_t xLLMNR_MACAddress[] = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0xFC }; -#endif +/* A copy of PHY register 1: 'PHY_REG_01_BMSR' */ +static uint32_t ulPHYLinkStates[ XPAR_XEMACPS_NUM_INSTANCES ]; /* Holds the handle of the task used as a deferred interrupt processor. The * handle is used so direct notifications can be sent to the task for all EMAC/DMA * related interrupts. */ -TaskHandle_t xEMACTaskHandle = NULL; +TaskHandle_t xEMACTaskHandles[ XPAR_XEMACPS_NUM_INSTANCES ]; -/* The PHY index where a PHY was found. */ -static u32 ulPHYIndex; +/*-----------------------------------------------------------*/ + +/** + * @brief Initialise the interface number 'xIndex' + * @param xIndex: the index of the interface, between 0 + * zero and (XPAR_XEMACPS_NUM_INSTANCES-1) + * @note Although the function is declared public, it should + * not be called directly by an application. + */ +void vInitialiseOnIndex( BaseType_t xIndex ) +{ + if( ( xIndex >= 0 ) && ( xIndex < XPAR_XEMACPS_NUM_INSTANCES ) ) + { + NetworkInterface_t * pxInterface = pxMyInterfaces[ xIndex ]; + if( pxInterface != NULL ) + { + xUltrascaleNetworkInterfaceInitialise( pxInterface ); + } + } +} /*-----------------------------------------------------------*/ /* The function xNetworkInterfaceInitialise() will be called as * long as it returns the value pdFAIL. - * It will go through several stages as described in 'eEMACState'. + * It will go through several stages as described in 'eEMACStates'. */ typedef enum xEMAC_STATE { - xEMAC_Init, + xEMAC_Init = 0, xEMAC_SetupPHY, xEMAC_WaitPHY, xEMAC_Ready, xEMAC_Fatal, } EMACState_t; -static EMACState_t eEMACState = xEMAC_Init; +static EMACState_t eEMACStates[ XPAR_XEMACPS_NUM_INSTANCES ] = { xEMAC_Init }; -BaseType_t xNetworkInterfaceInitialise( void ) +static BaseType_t xUltrascaleNetworkInterfaceInitialise( NetworkInterface_t * pxInterface ) { uint32_t ulLinkSpeed, ulDMAReg; BaseType_t xStatus, xReturn = pdFAIL; - XEmacPs * pxEMAC_PS = &( xEMACpsif.emacps ); + XEmacPs * pxEMAC_PS; const TickType_t xWaitLinkDelay = pdMS_TO_TICKS( 1000U ); + NetworkEndPoint_t * pxEndPoint; + BaseType_t xEMACIndex = ( BaseType_t ) pxInterface->pvArgument; - switch( eEMACState ) + configASSERT( xEMACIndex >= 0 ); + configASSERT( xEMACIndex < XPAR_XEMACPS_NUM_INSTANCES ); + + pxEMAC_PS = &( xEMACpsifs[ xEMACIndex ].emacps ); + + switch( eEMACStates[ xEMACIndex ] ) { case xEMAC_Init: - ulPHYLinkStatus = 0U; - memset( &xEMACpsif, '\0', sizeof( xEMACpsif ) ); + pxMyInterfaces[ xEMACIndex ] = pxInterface; + + ulPHYLinkStates[ xEMACIndex ] = 0U; + memset( &xEMACpsifs[ xEMACIndex ], '\0', sizeof( xEMACpsifs[ xEMACIndex ] ) ); - xStatus = XEmacPs_CfgInitialize( pxEMAC_PS, &mac_config, mac_config.BaseAddress ); + xStatus = XEmacPs_CfgInitialize( pxEMAC_PS, &( mac_configs[ xEMACIndex ] ), mac_configs[ xEMACIndex ].BaseAddress ); if( xStatus != XST_SUCCESS ) { FreeRTOS_printf( ( "xEMACInit: EmacPs Configuration Failed....\n" ) ); - eEMACState = xEMAC_Fatal; + eEMACStates[ xEMACIndex ] = xEMAC_Fatal; break; } -/* _HT_ : the use of jumbo frames has not been tested sufficiently yet. */ + pxEndPoint = FreeRTOS_FirstEndPoint( pxInterface ); + configASSERT( pxEndPoint != NULL ); + + #if ( USE_JUMBO_FRAMES == 1 ) + /* Enable jumbo frames for zynqmp */ + XEmacPs_SetOptions( pxEMAC_PS, XEMACPS_JUMBO_ENABLE_OPTION ); + #endif + + /* Initialize the mac and set the MAC address at position 1. */ + XEmacPs_SetMacAddress( pxEMAC_PS, ( void * ) pxEndPoint->xMACAddress.ucBytes, 1 ); + + #if ( ipconfigIS_ENABLED( ipconfigUSE_LLMNR ) ) + { + #if ( ipconfigIS_ENABLED( ipconfigUSE_IPv4 ) ) + { + XEmacPs_SetHash( pxEMAC_PS, ( void * ) xLLMNR_MacAddress.ucBytes ); + } + #endif /* ( ipconfigIS_ENABLED( ipconfigUSE_IPv4 ) */ + + #if ( ipconfigIS_ENABLED( ipconfigUSE_IPv6 ) ) + { + XEmacPs_SetHash( pxEMAC_PS, ( void * ) xLLMNR_MacAddressIPv6.ucBytes ); + } + #endif /* ( ipconfigIS_ENABLED( ipconfigUSE_IPv6 ) ) */ + } + #endif /* ( ipconfigIS_ENABLED( ipconfigUSE_LLMNR ) ) */ + + #if ( ipconfigIS_ENABLED( ipconfigUSE_MDNS ) ) + { + #if ( ipconfigIS_ENABLED( ipconfigUSE_IPv4 ) ) + { + XEmacPs_SetHash( pxEMAC_PS, ( void * ) xMDNS_MacAddress.ucBytes ); + } + #endif /* ( ipconfigIS_ENABLED( ipconfigUSE_IPv4 ) */ + + #if ( ipconfigIS_ENABLED( ipconfigUSE_IPv6 ) ) + { + XEmacPs_SetHash( pxEMAC_PS, ( void * ) xMDNS_MacAddressIPv6.ucBytes ); + } + #endif /* ( ipconfigIS_ENABLED( ipconfigUSE_IPv6 ) ) */ + } + #endif /* ( ipconfigIS_ENABLED( ipconfigUSE_MDNS) ) */ - if( pxEMAC_PS->Version > 2 ) + #if ( ipconfigIS_ENABLED( ipconfigUSE_IPv6 ) ) { - #if ( USE_JUMBO_FRAMES == 1 ) - /* Enable jumbo frames for zynqmp */ - XEmacPs_SetOptions( pxEMAC_PS, XEMACPS_JUMBO_ENABLE_OPTION ); - #endif + /* set the solicited-node multicast address */ + for( NetworkEndPoint_t * pxEndPointIter = FreeRTOS_FirstEndPoint( pxInterface ); + pxEndPointIter != NULL; + pxEndPointIter = FreeRTOS_NextEndPoint( pxInterface, pxEndPointIter ) ) + { + if( pxEndPointIter->bits.bIPv6 != pdFALSE_UNSIGNED ) + { + unsigned char ucSsolicitedNodeMAC[ 6 ] = { 0x33, 0x33, 0xff, 0, 0, 0 }; + ucSsolicitedNodeMAC[ 3 ] = pxEndPointIter->ipv6_settings.xIPAddress.ucBytes[ 13 ]; + ucSsolicitedNodeMAC[ 4 ] = pxEndPointIter->ipv6_settings.xIPAddress.ucBytes[ 14 ]; + ucSsolicitedNodeMAC[ 5 ] = pxEndPointIter->ipv6_settings.xIPAddress.ucBytes[ 15 ]; + XEmacPs_SetHash( pxEMAC_PS, ( void * ) ucSsolicitedNodeMAC ); + } + } } + #endif /* ( ipconfigIS_ENABLED( ipconfigUSE_IPv6 ) ) */ - /* Initialize the mac and set the MAC address. */ - XEmacPs_SetMacAddress( pxEMAC_PS, ( void * ) ipLOCAL_MAC_ADDRESS, 1 ); + /* allow reception of multicast addresses programmed into hash (LLMNR or mDNS) */ + XEmacPs_SetOptions( pxEMAC_PS, XEMACPS_MULTICAST_OPTION ); - #if ( ipconfigUSE_LLMNR == 1 ) + /* TODO: is it needed to add the MAC of the second endpoint? */ + pxEndPoint = FreeRTOS_NextEndPoint( pxInterface, pxEndPoint ); + + if( pxEndPoint != NULL ) { - /* Also add LLMNR multicast MAC address. */ - XEmacPs_SetMacAddress( pxEMAC_PS, ( void * ) xLLMNR_MACAddress, 2 ); + /* If there is a second end-point, store the MAC + * address at position 4.*/ + XEmacPs_SetMacAddress( pxEMAC_PS, ( void * ) pxEndPoint->xMACAddress.ucBytes, 4 ); } - #endif /* ipconfigUSE_LLMNR == 1 */ XEmacPs_SetMdioDivisor( pxEMAC_PS, MDC_DIV_224 ); - ulPHYIndex = ulDetectPHY( pxEMAC_PS ); + phy_detected[ xEMACIndex ] = ulDetectPHY( pxEMAC_PS ); - if( ulPHYIndex == ~0U ) + if( phy_detected[ xEMACIndex ] == ~0U ) { FreeRTOS_printf( ( "xEMACInit: No valid PHY was found\n" ) ); - eEMACState = xEMAC_Fatal; + eEMACStates[ xEMACIndex ] = xEMAC_Fatal; break; } - eEMACState = xEMAC_SetupPHY; + eEMACStates[ xEMACIndex ] = xEMAC_SetupPHY; /* Fall through. */ case xEMAC_SetupPHY: - ulLinkSpeed = Phy_Setup_US( pxEMAC_PS, ulPHYIndex ); + ulLinkSpeed = Phy_Setup_US( pxEMAC_PS, phy_detected[ xEMACIndex ] ); if( ulLinkSpeed == XST_FAILURE ) { @@ -249,47 +415,63 @@ BaseType_t xNetworkInterfaceInitialise( void ) /* Setting the operating speed of the MAC needs a delay. */ vTaskDelay( pdMS_TO_TICKS( 25UL ) ); - ulDMAReg = XEmacPs_ReadReg( pxEMAC_PS->Config.BaseAddress, XEMACPS_DMACR_OFFSET ); /* Enable 16-bytes AHB bursts */ - ulDMAReg = ulDMAReg | XEMACPS_DMACR_INCR16_AHB_BURST; - - /* DISC_WHEN_NO_AHB: when set, the GEM DMA will automatically discard receive - * packets from the receiver packet buffer memory when no AHB resource is available. */ - XEmacPs_WriteReg( pxEMAC_PS->Config.BaseAddress, XEMACPS_DMACR_OFFSET, - ulDMAReg /*| XEMACPS_DMACR_DISC_WHEN_NO_AHB_MASK*/ ); + XEmacPs_DMABLengthUpdate( pxEMAC_PS, XEMACPS_16BYTE_BURST ); - setup_isr( &xEMACpsif ); - init_dma( &xEMACpsif ); - start_emacps( &xEMACpsif ); - eEMACState = xEMAC_WaitPHY; + setup_isr( &( xEMACpsifs[ xEMACIndex ] ) ); + init_dma( &( xEMACpsifs[ xEMACIndex ] ) ); + start_emacps( &( xEMACpsifs[ xEMACIndex ] ) ); + eEMACStates[ xEMACIndex ] = xEMAC_WaitPHY; /* Fall through. */ case xEMAC_WaitPHY: - prvGMACWaitLS( xWaitLinkDelay ); + prvGMACWaitLS( xEMACIndex, xWaitLinkDelay ); - if( xGetPhyLinkStatus() == pdFALSE ) + if( xGetPhyLinkStatus( pxInterface ) == pdFALSE ) { /* The Link Status is not yet high, Stay in 'xEMAC_WaitPHY'. */ break; } - if( xEMACTaskHandle == NULL ) + if( xEMACTaskHandles[ xEMACIndex ] == NULL ) { /* The deferred interrupt handler task is created at the highest * possible priority to ensure the interrupt handler can return directly - * to it. The task's handle is stored in xEMACTaskHandle so interrupts can + * to it. The task's handle is stored in xEMACTaskHandles[] so interrupts can * notify the task when there is something to process. */ - xTaskCreate( prvEMACHandlerTask, "EMAC", configEMAC_TASK_STACK_SIZE, NULL, niEMAC_HANDLER_TASK_PRIORITY, &xEMACTaskHandle ); + const char * pcTaskName; + + switch( xEMACIndex ) + { + case 1: + pcTaskName = "EMAC1"; + break; + + case 2: + pcTaskName = "EMAC2"; + break; + + case 3: + pcTaskName = "EMAC3"; + break; + + case 0: + default: + pcTaskName = "EMAC0"; + break; + } + + xTaskCreate( prvEMACHandlerTask, pcTaskName, configEMAC_TASK_STACK_SIZE, ( void * ) xEMACIndex, niEMAC_HANDLER_TASK_PRIORITY, &( xEMACTaskHandles[ xEMACIndex ] ) ); - if( xEMACTaskHandle == NULL ) + if( xEMACTaskHandles[ xEMACIndex ] == NULL ) { - eEMACState = xEMAC_Fatal; + eEMACStates[ xEMACIndex ] = xEMAC_Fatal; break; } } - eEMACState = xEMAC_Ready; + eEMACStates[ xEMACIndex ] = xEMAC_Ready; /* Fall through. */ @@ -307,11 +489,17 @@ BaseType_t xNetworkInterfaceInitialise( void ) return xReturn; } -/*-----------------------------------------------------------*/ -BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxBuffer, - BaseType_t bReleaseAfterSend ) +/*-----------------------------------------------------------*/ +static BaseType_t xUltrascaleNetworkInterfaceOutput( NetworkInterface_t * pxInterface, + NetworkBufferDescriptor_t * const pxBuffer, + BaseType_t bReleaseAfterSend ) { + BaseType_t xEMACIndex = ( BaseType_t ) pxInterface->pvArgument; + + configASSERT( xEMACIndex >= 0 ); + configASSERT( xEMACIndex < XPAR_XEMACPS_NUM_INSTANCES ); + #if ( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM != 0 ) { ProtocolPacket_t * pxPacket; @@ -320,22 +508,41 @@ BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxBuffer, * the protocol checksum to have a value of zero. */ pxPacket = ( ProtocolPacket_t * ) ( pxBuffer->pucEthernetBuffer ); - if( ( pxPacket->xICMPPacket.xEthernetHeader.usFrameType == ipIPv4_FRAME_TYPE ) && - ( pxPacket->xICMPPacket.xIPHeader.ucProtocol != ipPROTOCOL_UDP ) && - ( pxPacket->xICMPPacket.xIPHeader.ucProtocol != ipPROTOCOL_TCP ) ) + #if ( ipconfigIS_ENABLED( ipconfigUSE_IPv6 ) ) + ICMPPacket_IPv6_t * pxICMPPacket = ( ICMPPacket_IPv6_t * ) pxBuffer->pucEthernetBuffer; + + if( ( pxPacket->xICMPPacket.xEthernetHeader.usFrameType == ipIPv6_FRAME_TYPE ) && + ( pxICMPPacket->xIPHeader.ucNextHeader == ipPROTOCOL_ICMP_IPv6 ) ) + { + /* The EMAC will calculate the checksum of the IP-header. + * It can only calculate protocol checksums of UDP and TCP, + * so for ICMP and other protocols it must be done manually. */ + usGenerateProtocolChecksum( pxBuffer->pucEthernetBuffer, pxBuffer->xDataLength, pdTRUE ); + } + #endif /* ( ipconfigIS_ENABLED( ipconfigUSE_IPv6 ) ) */ + + #if ( ipconfigIS_ENABLED( ipconfigUSE_IPv4 ) ) { - /* The EMAC will calculate the checksum of the IP-header. - * It can only calculate protocol checksums of UDP and TCP, - * so for ICMP and other protocols it must be done manually. */ - usGenerateProtocolChecksum( ( uint8_t * ) &( pxPacket->xUDPPacket ), pxBuffer->xDataLength, pdTRUE ); + if( ( pxPacket->xICMPPacket.xEthernetHeader.usFrameType == ipIPv4_FRAME_TYPE ) && + ( pxPacket->xICMPPacket.xIPHeader.ucProtocol == ipPROTOCOL_ICMP ) ) + { + /* The EMAC will calculate the checksum of the IP-header. + * It can only calculate protocol checksums of UDP and TCP, + * so for ICMP and other protocols it must be done manually. */ + usGenerateProtocolChecksum( pxBuffer->pucEthernetBuffer, pxBuffer->xDataLength, pdTRUE ); + } } + #endif /* ( ipconfigIS_ENABLED( ipconfigUSE_IPv4 ) */ } #endif /* ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM */ - if( ( ulPHYLinkStatus & niBMSR_LINK_STATUS ) != 0UL ) + if( ( ulPHYLinkStates[ xEMACIndex ] & niBMSR_LINK_STATUS ) != 0UL ) { iptraceNETWORK_INTERFACE_TRANSMIT(); - emacps_send_message( &xEMACpsif, pxBuffer, bReleaseAfterSend ); + + /* emacps_send_message() will take ownership of pxBuffer, and + * make sure it will get release when bReleaseAfterSend is pdTRUE. */ + emacps_send_message( &( xEMACpsifs[ xEMACIndex ] ), pxBuffer, bReleaseAfterSend ); } else if( bReleaseAfterSend != pdFALSE ) { @@ -347,16 +554,18 @@ BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxBuffer, } /*-----------------------------------------------------------*/ -static inline unsigned long ulReadMDIO( unsigned ulRegister ) +static inline unsigned long ulReadMDIO( BaseType_t xEMACIndex, + unsigned ulRegister ) { uint16_t usValue; - XEmacPs_PhyRead( &( xEMACpsif.emacps ), ulPHYIndex, ulRegister, &usValue ); + XEmacPs_PhyRead( &( xEMACpsifs[ xEMACIndex ].emacps ), phy_detected[ xEMACIndex ], ulRegister, &usValue ); return usValue; } /*-----------------------------------------------------------*/ -static BaseType_t prvGMACWaitLS( TickType_t xMaxTimeTicks ) +static BaseType_t prvGMACWaitLS( BaseType_t xEMACIndex, + TickType_t xMaxTimeTicks ) { TickType_t xStartTime, xEndTime; const TickType_t xShortDelay = pdMS_TO_TICKS( 20UL ); @@ -374,9 +583,9 @@ static BaseType_t prvGMACWaitLS( TickType_t xMaxTimeTicks ) break; } - ulPHYLinkStatus = ulReadMDIO( PHY_REG_01_BMSR ); + ulPHYLinkStates[ xEMACIndex ] = ulReadMDIO( xEMACIndex, PHY_REG_01_BMSR ); - if( ( ulPHYLinkStatus & niBMSR_LINK_STATUS ) != 0uL ) + if( ( ulPHYLinkStates[ xEMACIndex ] & niBMSR_LINK_STATUS ) != 0uL ) { xReturn = pdTRUE; break; @@ -429,11 +638,12 @@ static BaseType_t prvGMACWaitLS( TickType_t xMaxTimeTicks ) #endif /* ( nicUSE_UNCACHED_MEMORY == 0 ) */ /*-----------------------------------------------------------*/ -BaseType_t xGetPhyLinkStatus( void ) +static BaseType_t xUltrascaleGetPhyLinkStatus( NetworkInterface_t * pxInterface ) { BaseType_t xReturn; + BaseType_t xEMACIndex = ( BaseType_t ) pxInterface->pvArgument; - if( ( ulPHYLinkStatus & niBMSR_LINK_STATUS ) == 0uL ) + if( ( ulPHYLinkStates[ xEMACIndex ] & niBMSR_LINK_STATUS ) == 0uL ) { xReturn = pdFALSE; } @@ -444,6 +654,56 @@ BaseType_t xGetPhyLinkStatus( void ) return xReturn; } + +/*-----------------------------------------------------------*/ +#if defined( ipconfigIPv4_BACKWARD_COMPATIBLE ) && ( ipconfigIPv4_BACKWARD_COMPATIBLE == 1 ) + +/* Do not call the following function directly. It is there for downward compatibility. + * The function FreeRTOS_IPInit() will call it to initialise the interface and end-point + * objects. See the description in FreeRTOS_Routing.h. */ + NetworkInterface_t * pxFillInterfaceDescriptor( BaseType_t xEMACIndex, + NetworkInterface_t * pxInterface ) + { + return pxUltrascale_FillInterfaceDescriptor( xEMACIndex, pxInterface ); + } +#endif + +NetworkInterface_t * pxUltrascale_FillInterfaceDescriptor( BaseType_t xEMACIndex, + NetworkInterface_t * pxInterface ) +{ + static char pcNames[ XPAR_XEMACPS_NUM_INSTANCES ][ 8 ]; + + configASSERT( xEMACIndex >= 0 ); + configASSERT( xEMACIndex < XPAR_XEMACPS_NUM_INSTANCES ); + +/* This function pxZynq_FillInterfaceDescriptor() adds a network-interface. + * Make sure that the object pointed to by 'pxInterface' + * is declared static or global, and that it will remain to exist. */ + + strcpy( pcNames[ xEMACIndex ], "ETH" ); + uint8_t temp = strlen( pcNames[ xEMACIndex ] ); + pcNames[ xEMACIndex ][ temp ] = ( char ) xEMACIndex + '0'; + pcNames[ xEMACIndex ][ temp + 1 ] = '\0'; + + memset( pxInterface, '\0', sizeof( *pxInterface ) ); + pxInterface->pcName = pcNames[ xEMACIndex ]; /* Just for logging, debugging. */ + pxInterface->pvArgument = ( void * ) xEMACIndex; /* Has meaning only for the driver functions. */ + pxInterface->pfInitialise = xUltrascaleNetworkInterfaceInitialise; + pxInterface->pfOutput = xUltrascaleNetworkInterfaceOutput; + pxInterface->pfGetPhyLinkStatus = xUltrascaleGetPhyLinkStatus; + + FreeRTOS_AddNetworkInterface( pxInterface ); + + return pxInterface; +} + +/*-----------------------------------------------------------*/ + +BaseType_t xGetPhyLinkStatus( struct xNetworkInterface * pxInterface ) +{ + return xUltrascaleGetPhyLinkStatus( pxInterface ); +} + /*-----------------------------------------------------------*/ static void prvEMACHandlerTask( void * pvParameters ) @@ -454,8 +714,13 @@ static void prvEMACHandlerTask( void * pvParameters ) uint32_t xStatus; const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( 100UL ); - /* Remove compiler warnings about unused parameters. */ - ( void ) pvParameters; + BaseType_t xEMACIndex = ( BaseType_t ) pvParameters; + xemacpsif_s * pxEMAC_PS; + + configASSERT( xEMACIndex >= 0 ); + configASSERT( xEMACIndex < XPAR_XEMACPS_NUM_INSTANCES ); + + pxEMAC_PS = &( xEMACpsifs[ xEMACIndex ] ); /* A possibility to set some additional task properties like calling * portTASK_USES_FLOATING_POINT() */ @@ -463,6 +728,7 @@ static void prvEMACHandlerTask( void * pvParameters ) vTaskSetTimeOutState( &xPhyTime ); xPhyRemTime = pdMS_TO_TICKS( ipconfigPHY_LS_LOW_CHECK_TIME_MS ); + FreeRTOS_printf( ( "prvEMACHandlerTask[ %ld ] started running\n", xEMACIndex ) ); for( ; ; ) { @@ -475,28 +741,28 @@ static void prvEMACHandlerTask( void * pvParameters ) } #endif /* ( ipconfigHAS_PRINTF != 0 ) */ - if( ( xEMACpsif.isr_events & EMAC_IF_ALL_EVENT ) == 0 ) + if( ( pxEMAC_PS->isr_events & EMAC_IF_ALL_EVENT ) == 0 ) { /* No events to process now, wait for the next. */ ulTaskNotifyTake( pdFALSE, ulMaxBlockTime ); } - if( ( xEMACpsif.isr_events & EMAC_IF_RX_EVENT ) != 0 ) + if( ( pxEMAC_PS->isr_events & EMAC_IF_RX_EVENT ) != 0 ) { - xEMACpsif.isr_events &= ~EMAC_IF_RX_EVENT; - xResult = emacps_check_rx( &xEMACpsif ); + pxEMAC_PS->isr_events &= ~EMAC_IF_RX_EVENT; + xResult = emacps_check_rx( pxEMAC_PS, pxMyInterfaces[ xEMACIndex ] ); } - if( ( xEMACpsif.isr_events & EMAC_IF_TX_EVENT ) != 0 ) + if( ( pxEMAC_PS->isr_events & EMAC_IF_TX_EVENT ) != 0 ) { - xEMACpsif.isr_events &= ~EMAC_IF_TX_EVENT; - emacps_check_tx( &xEMACpsif ); + pxEMAC_PS->isr_events &= ~EMAC_IF_TX_EVENT; + emacps_check_tx( pxEMAC_PS ); } - if( ( xEMACpsif.isr_events & EMAC_IF_ERR_EVENT ) != 0 ) + if( ( pxEMAC_PS->isr_events & EMAC_IF_ERR_EVENT ) != 0 ) { - xEMACpsif.isr_events &= ~EMAC_IF_ERR_EVENT; - emacps_check_errors( &xEMACpsif ); + pxEMAC_PS->isr_events &= ~EMAC_IF_ERR_EVENT; + emacps_check_errors( pxEMAC_PS ); } if( xResult > 0 ) @@ -507,27 +773,27 @@ static void prvEMACHandlerTask( void * pvParameters ) xPhyRemTime = pdMS_TO_TICKS( ipconfigPHY_LS_HIGH_CHECK_TIME_MS ); xResult = 0; - if( ( ulPHYLinkStatus & niBMSR_LINK_STATUS ) == 0uL ) + if( ( ulPHYLinkStates[ xEMACIndex ] & niBMSR_LINK_STATUS ) == 0uL ) { /* Indicate that the Link Status is high, so that * xNetworkInterfaceOutput() can send packets. */ - ulPHYLinkStatus |= niBMSR_LINK_STATUS; + ulPHYLinkStates[ xEMACIndex ] |= niBMSR_LINK_STATUS; FreeRTOS_printf( ( "prvEMACHandlerTask: PHY LS assume 1\n" ) ); } } else if( xTaskCheckForTimeOut( &xPhyTime, &xPhyRemTime ) != pdFALSE ) { - xStatus = ulReadMDIO( PHY_REG_01_BMSR ); + xStatus = ulReadMDIO( xEMACIndex, PHY_REG_01_BMSR ); - if( ( ulPHYLinkStatus & niBMSR_LINK_STATUS ) != ( xStatus & niBMSR_LINK_STATUS ) ) + if( ( ulPHYLinkStates[ xEMACIndex ] & niBMSR_LINK_STATUS ) != ( xStatus & niBMSR_LINK_STATUS ) ) { - ulPHYLinkStatus = xStatus; - FreeRTOS_printf( ( "prvEMACHandlerTask: PHY LS now %d\n", ( ulPHYLinkStatus & niBMSR_LINK_STATUS ) != 0uL ) ); + ulPHYLinkStates[ xEMACIndex ] = xStatus; + FreeRTOS_printf( ( "prvEMACHandlerTask: PHY LS now %d\n", ( ulPHYLinkStates[ xEMACIndex ] & niBMSR_LINK_STATUS ) != 0uL ) ); } vTaskSetTimeOutState( &xPhyTime ); - if( ( ulPHYLinkStatus & niBMSR_LINK_STATUS ) != 0uL ) + if( ( ulPHYLinkStates[ xEMACIndex ] & niBMSR_LINK_STATUS ) != 0uL ) { xPhyRemTime = pdMS_TO_TICKS( ipconfigPHY_LS_HIGH_CHECK_TIME_MS ); } diff --git a/source/portable/NetworkInterface/xilinx_ultrascale/uncached_memory.c b/source/portable/NetworkInterface/xilinx_ultrascale/uncached_memory.c index c9035c7fb..18a0d9d6a 100644 --- a/source/portable/NetworkInterface/xilinx_ultrascale/uncached_memory.c +++ b/source/portable/NetworkInterface/xilinx_ultrascale/uncached_memory.c @@ -70,33 +70,24 @@ #include "uncached_memory.h" -#if ( ipconfigULTRASCALE == 1 ) - #if defined( __aarch64__ ) || defined( ARMA53_32 ) - #ifndef uncMEMORY_SIZE - /* Reserve 2 MB of memory. */ - #define uncMEMORY_SIZE 0x200000U - #endif - #define DDR_MEMORY_END ( XPAR_PSU_DDR_0_S_AXI_HIGHADDR ) - #define uncMEMORY_ATTRIBUTE NORM_NONCACHE | INNER_SHAREABLE - #elif defined( ARMR5 ) - #ifndef uncMEMORY_SIZE - /* Reserve 1 MB of memory. */ - #define uncMEMORY_SIZE 0x100000U - #endif - #define uncMEMORY_SIZE 0x100000U - #define DDR_MEMORY_END ( XPAR_PSU_R5_DDR_0_S_AXI_HIGHADDR ) - #define uncMEMORY_ATTRIBUTE STRONG_ORDERD_SHARED | PRIV_RW_USER_RW - #else /* if defined( __aarch64__ ) || defined( ARMA53_32 ) */ - #error Please define the specific target Zynq Ultrascale+ architecture - #endif /* if defined( __aarch64__ ) || defined( ARMA53_32 ) */ -#else /* if ( ipconfigULTRASCALE == 1 ) */ +#if defined( __aarch64__ ) || defined( ARMA53_32 ) + #ifndef uncMEMORY_SIZE + /* Reserve 2 MB of memory. */ + #define uncMEMORY_SIZE 0x200000U + #endif + #define DDR_MEMORY_END ( XPAR_PSU_DDR_0_S_AXI_HIGHADDR ) + #define uncMEMORY_ATTRIBUTE NORM_NONCACHE | INNER_SHAREABLE +#elif defined( ARMR5 ) #ifndef uncMEMORY_SIZE /* Reserve 1 MB of memory. */ #define uncMEMORY_SIZE 0x100000U #endif - #define DDR_MEMORY_END ( XPAR_PS7_DDR_0_S_AXI_HIGHADDR + 1 ) - #define uncMEMORY_ATTRIBUTE 0x1C02 -#endif /* ( ipconfigULTRASCALE == 1 ) */ + #define uncMEMORY_SIZE 0x100000U + #define DDR_MEMORY_END ( XPAR_PSU_R5_DDR_0_S_AXI_HIGHADDR ) + #define uncMEMORY_ATTRIBUTE STRONG_ORDERD_SHARED | PRIV_RW_USER_RW +#else /* if defined( __aarch64__ ) || defined( ARMA53_32 ) */ + #error Please define the specific target Zynq Ultrascale+ architecture +#endif /* if defined( __aarch64__ ) || defined( ARMA53_32 ) */ /* Make sure that each pointer has an alignment of 4 KB. */ #define uncALIGNMENT_SIZE 0x1000uL diff --git a/source/portable/NetworkInterface/xilinx_ultrascale/x_emac_map.h b/source/portable/NetworkInterface/xilinx_ultrascale/x_emac_map.h new file mode 100644 index 000000000..78bf9804e --- /dev/null +++ b/source/portable/NetworkInterface/xilinx_ultrascale/x_emac_map.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2007-2013 Xilinx, Inc. All rights reserved. + * + * Xilinx, Inc. + * XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" AS A + * COURTESY TO YOU. BY PROVIDING THIS DESIGN, CODE, OR INFORMATION AS + * ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE, APPLICATION OR + * STANDARD, XILINX IS MAKING NO REPRESENTATION THAT THIS IMPLEMENTATION + * IS FREE FROM ANY CLAIMS OF INFRINGEMENT, AND YOU ARE RESPONSIBLE + * FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE FOR YOUR IMPLEMENTATION. + * XILINX EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH RESPECT TO + * THE ADEQUACY OF THE IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO + * ANY WARRANTIES OR REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE + * FROM CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE. + * + */ + +#ifndef __XEMACMAP_H_ +#define __XEMACMAP_H_ + +#include "xparameters_ps.h" +#include "xparameters.h" + + +#define ZYNQMP_EMACPS_0_BASEADDR 0xFF0B0000 +#define ZYNQMP_EMACPS_1_BASEADDR 0xFF0C0000 +#define ZYNQMP_EMACPS_2_BASEADDR 0xFF0D0000 +#define ZYNQMP_EMACPS_3_BASEADDR 0xFF0E0000 + +#if XPAR_XEMACPS_0_BASEADDR == ZYNQMP_EMACPS_0_BASEADDR + #define ZYNQMP_EMACPS_0_IRQ_ID XPAR_XEMACPS_0_INTR +#endif +#if XPAR_XEMACPS_0_BASEADDR == ZYNQMP_EMACPS_1_BASEADDR + #define ZYNQMP_EMACPS_0_IRQ_ID XPAR_XEMACPS_1_INTR +#endif +#if XPAR_XEMACPS_0_BASEADDR == ZYNQMP_EMACPS_2_BASEADDR + #define ZYNQMP_EMACPS_0_IRQ_ID XPAR_XEMACPS_2_INTR +#endif +#if XPAR_XEMACPS_0_BASEADDR == ZYNQMP_EMACPS_3_BASEADDR + #define ZYNQMP_EMACPS_0_IRQ_ID XPAR_XEMACPS_3_INTR +#endif +#if XPAR_XEMACPS_1_BASEADDR == ZYNQMP_EMACPS_0_BASEADDR + #define ZYNQMP_EMACPS_1_IRQ_ID XPAR_XEMACPS_0_INTR +#endif +#if XPAR_XEMACPS_1_BASEADDR == ZYNQMP_EMACPS_1_BASEADDR + #define ZYNQMP_EMACPS_1_IRQ_ID XPAR_XEMACPS_1_INTR +#endif +#if XPAR_XEMACPS_1_BASEADDR == ZYNQMP_EMACPS_2_BASEADDR + #define ZYNQMP_EMACPS_1_IRQ_ID XPAR_XEMACPS_2_INTR +#endif +#if XPAR_XEMACPS_1_BASEADDR == ZYNQMP_EMACPS_3_BASEADDR + #define ZYNQMP_EMACPS_1_IRQ_ID XPAR_XEMACPS_3_INTR +#endif +#if XPAR_XEMACPS_2_BASEADDR == ZYNQMP_EMACPS_0_BASEADDR + #define ZYNQMP_EMACPS_2_IRQ_ID XPAR_XEMACPS_0_INTR +#endif +#if XPAR_XEMACPS_2_BASEADDR == ZYNQMP_EMACPS_1_BASEADDR + #define ZYNQMP_EMACPS_2_IRQ_ID XPAR_XEMACPS_1_INTR +#endif +#if XPAR_XEMACPS_2_BASEADDR == ZYNQMP_EMACPS_2_BASEADDR + #define ZYNQMP_EMACPS_2_IRQ_ID XPAR_XEMACPS_2_INTR +#endif +#if XPAR_XEMACPS_2_BASEADDR == ZYNQMP_EMACPS_3_BASEADDR + #define ZYNQMP_EMACPS_2_IRQ_ID XPAR_XEMACPS_3_INTR +#endif +#if XPAR_XEMACPS_3_BASEADDR == ZYNQMP_EMACPS_0_BASEADDR + #define ZYNQMP_EMACPS_3_IRQ_ID XPAR_XEMACPS_0_INTR +#endif +#if XPAR_XEMACPS_3_BASEADDR == ZYNQMP_EMACPS_1_BASEADDR + #define ZYNQMP_EMACPS_3_IRQ_ID XPAR_XEMACPS_1_INTR +#endif +#if XPAR_XEMACPS_3_BASEADDR == ZYNQMP_EMACPS_2_BASEADDR + #define ZYNQMP_EMACPS_3_IRQ_ID XPAR_XEMACPS_2_INTR +#endif +#if XPAR_XEMACPS_3_BASEADDR == ZYNQMP_EMACPS_3_BASEADDR + #define ZYNQMP_EMACPS_3_IRQ_ID XPAR_XEMACPS_3_INTR +#endif + +#endif /* __XEMACMAP_H_ */ diff --git a/source/portable/NetworkInterface/xilinx_ultrascale/x_emacpsif.h b/source/portable/NetworkInterface/xilinx_ultrascale/x_emacpsif.h index 12522e564..a2a1c04e9 100644 --- a/source/portable/NetworkInterface/xilinx_ultrascale/x_emacpsif.h +++ b/source/portable/NetworkInterface/xilinx_ultrascale/x_emacpsif.h @@ -21,6 +21,8 @@ #include + #include "FreeRTOS_Routing.h" + #include "xstatus.h" #include "sleep.h" #include "xparameters.h" @@ -117,7 +119,8 @@ struct xNETWORK_BUFFER; - int emacps_check_rx( xemacpsif_s * xemacpsif ); + int emacps_check_rx( xemacpsif_s * xemacpsif, + NetworkInterface_t * pxInterface ); void emacps_check_tx( xemacpsif_s * xemacpsif ); int emacps_check_errors( xemacpsif_s * xemacps ); void emacps_set_rx_buffers( xemacpsif_s * xemacpsif, @@ -133,8 +136,8 @@ extern XStatus init_dma( xemacpsif_s * xemacpsif ); extern void start_emacps( xemacpsif_s * xemacpsif ); - void EmacEnableIntr( void ); - void EmacDisableIntr( void ); + void EmacEnableIntr( int xEMACIndex ); + void EmacDisableIntr( int xEMACIndex ); XStatus init_axi_dma( xemacpsif_s * xemacpsif ); void process_sent_bds( xemacpsif_s * xemacpsif ); @@ -150,6 +153,11 @@ void clean_dma_txdescs( xemacpsif_s * xemacpsif ); void resetrx_on_no_rxdata( xemacpsif_s * xemacpsif ); +/** + * @brief Initialise the interface number 'xIndex'. Do not call directly. + */ + void vInitialiseOnIndex( BaseType_t xIndex ); + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/source/portable/NetworkInterface/xilinx_ultrascale/x_emacpsif_dma.c b/source/portable/NetworkInterface/xilinx_ultrascale/x_emacpsif_dma.c index 34ec35a46..959ff0ab5 100644 --- a/source/portable/NetworkInterface/xilinx_ultrascale/x_emacpsif_dma.c +++ b/source/portable/NetworkInterface/xilinx_ultrascale/x_emacpsif_dma.c @@ -47,29 +47,12 @@ #include "uncached_memory.h" -#ifndef ipconfigULTRASCALE - #error please define ipconfigULTRASCALE -#endif - -/* Two defines used to set or clear the EMAC interrupt */ -#if ( ipconfigULTRASCALE == 1 ) - /* * XPAR_SCUGIC_0_CPU_BASEADDR 0xF9020000U * XPAR_SCUGIC_0_DIST_BASEADDR 0xF9010000U */ - #define INTC_BASE_ADDR XPAR_SCUGIC_0_CPU_BASEADDR - #define INTC_DIST_BASE_ADDR XPAR_SCUGIC_0_DIST_BASEADDR -#else - -/* - * XPAR_SCUGIC_CPU_BASEADDR (XPS_SCU_PERIPH_BASE + 0x00000100U) - * XPAR_SCUGIC_DIST_BASEADDR (XPS_SCU_PERIPH_BASE + 0x00001000U) - */ - - #define INTC_BASE_ADDR XPAR_SCUGIC_CPU_BASEADDR - #define INTC_DIST_BASE_ADDR XPAR_SCUGIC_DIST_BASEADDR -#endif +#define INTC_BASE_ADDR XPAR_SCUGIC_0_CPU_BASEADDR +#define INTC_DIST_BASE_ADDR XPAR_SCUGIC_0_DIST_BASEADDR #if ( ipconfigPACKET_FILLER_SIZE != 2 ) #error Please define ipconfigPACKET_FILLER_SIZE as the value '2' @@ -90,33 +73,31 @@ #define dmaRX_TX_BUFFER_SIZE 1536 #endif /* ( USE_JUMBO_FRAMES == 1 ) */ -#if ( ipconfigULTRASCALE == 1 ) - extern XScuGic xInterruptController; -#endif +extern XScuGic xInterruptController; /* Defined in NetworkInterface.c */ -extern TaskHandle_t xEMACTaskHandle; +extern TaskHandle_t xEMACTaskHandles[ XPAR_XEMACPS_NUM_INSTANCES ]; /* * pxDMA_tx_buffers: these are character arrays, each one is big enough to hold 1 MTU. * The actual TX buffers are located in uncached RAM. */ -static unsigned char * pxDMA_tx_buffers[ ipconfigNIC_N_TX_DESC ] = { NULL }; +static unsigned char * pxDMA_tx_buffers[ XPAR_XEMACPS_NUM_INSTANCES ][ ipconfigNIC_N_TX_DESC ]; /* * pxDMA_rx_buffers: these are pointers to 'NetworkBufferDescriptor_t'. * Once a message has been received by the EMAC, the descriptor can be passed * immediately to the IP-task. */ -static NetworkBufferDescriptor_t * pxDMA_rx_buffers[ ipconfigNIC_N_RX_DESC ] = { NULL }; +static NetworkBufferDescriptor_t * pxDMA_rx_buffers[ XPAR_XEMACPS_NUM_INSTANCES ][ ipconfigNIC_N_RX_DESC ]; /* * The FreeRTOS+TCP port is using a fixed 'topology', which is declared in * ./portable/NetworkInterface/Zynq/NetworkInterface.c */ -extern struct xtopology_t xXTopology; +extern struct xtopology_t xXTopologies[ XPAR_XEMACPS_NUM_INSTANCES ]; -static SemaphoreHandle_t xTXDescriptorSemaphore = NULL; +static SemaphoreHandle_t xTXDescriptorSemaphore[ XPAR_XEMACPS_NUM_INSTANCES ]; /* * The FreeRTOS+TCP port does not make use of "src/xemacps_bdring.c". @@ -128,13 +109,11 @@ static SemaphoreHandle_t xTXDescriptorSemaphore = NULL; int is_tx_space_available( xemacpsif_s * xemacpsif ) { size_t uxCount; + BaseType_t xEMACIndex = xemacpsif->emacps.Config.DeviceId; - /* Just to prevent compiler warnings about unused parameters. */ - ( void ) xemacpsif; - - if( xTXDescriptorSemaphore != NULL ) + if( xTXDescriptorSemaphore[ xEMACIndex ] != NULL ) { - uxCount = ( ( UBaseType_t ) ipconfigNIC_N_TX_DESC ) - uxSemaphoreGetCount( xTXDescriptorSemaphore ); + uxCount = ( ( UBaseType_t ) ipconfigNIC_N_TX_DESC ) - uxSemaphoreGetCount( xTXDescriptorSemaphore[ xEMACIndex ] ); } else { @@ -148,7 +127,8 @@ void emacps_check_tx( xemacpsif_s * xemacpsif ) { int tail = xemacpsif->txTail; int head = xemacpsif->txHead; - size_t uxCount = ( ( UBaseType_t ) ipconfigNIC_N_TX_DESC ) - uxSemaphoreGetCount( xTXDescriptorSemaphore ); + BaseType_t xEMACIndex = xemacpsif->emacps.Config.DeviceId; + size_t uxCount = ( ( UBaseType_t ) ipconfigNIC_N_TX_DESC ) - uxSemaphoreGetCount( xTXDescriptorSemaphore[ xEMACIndex ] ); /* uxCount is the number of TX descriptors that are in use by the DMA. */ /* When done, "TXBUF_USED" will be set. */ @@ -161,12 +141,12 @@ void emacps_check_tx( xemacpsif_s * xemacpsif ) } { - void * pvBuffer = pxDMA_tx_buffers[ tail ]; + void * pvBuffer = pxDMA_tx_buffers[ xEMACIndex ][ tail ]; NetworkBufferDescriptor_t * pxBuffer; if( pvBuffer != NULL ) { - pxDMA_tx_buffers[ tail ] = NULL; + pxDMA_tx_buffers[ xEMACIndex ][ tail ] = NULL; pxBuffer = pxPacketBuffer_to_NetworkBuffer( pvBuffer ); if( pxBuffer != NULL ) @@ -192,7 +172,7 @@ void emacps_check_tx( xemacpsif_s * xemacpsif ) uxCount--; /* Tell the counting semaphore that one more TX descriptor is available. */ - xSemaphoreGive( xTXDescriptorSemaphore ); + xSemaphoreGive( xTXDescriptorSemaphore[ xEMACIndex ] ); if( ++tail == ipconfigNIC_N_TX_DESC ) { @@ -207,8 +187,10 @@ void emacps_send_handler( void * arg ) { xemacpsif_s * xemacpsif; BaseType_t xHigherPriorityTaskWoken = pdFALSE; + BaseType_t xEMACIndex; xemacpsif = ( xemacpsif_s * ) arg; + xEMACIndex = xemacpsif->emacps.Config.DeviceId; /* This function is called from an ISR. The Xilinx ISR-handler has already * cleared the TXCOMPL and TXSR_USEDREAD status bits in the XEMACPS_TXSR register. @@ -221,9 +203,9 @@ void emacps_send_handler( void * arg ) xemacpsif->isr_events |= EMAC_IF_TX_EVENT; xemacpsif->txBusy = pdFALSE; - if( xEMACTaskHandle != NULL ) + if( xEMACTaskHandles[ xEMACIndex ] != NULL ) { - vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken ); + vTaskNotifyGiveFromISR( xEMACTaskHandles[ xEMACIndex ], &xHigherPriorityTaskWoken ); } portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); @@ -252,6 +234,7 @@ XStatus emacps_send_message( xemacpsif_s * xemacpsif, int head = xemacpsif->txHead; int iHasSent = 0; uint32_t ulBaseAddress = xemacpsif->emacps.Config.BaseAddress; + BaseType_t xEMACIndex = xemacpsif->emacps.Config.DeviceId; TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 5000U ); /* This driver wants to own all network buffers which are to be transmitted. */ @@ -267,19 +250,19 @@ XStatus emacps_send_message( xemacpsif_s * xemacpsif, break; } - if( xTXDescriptorSemaphore == NULL ) + if( xTXDescriptorSemaphore[ xEMACIndex ] == NULL ) { break; } - if( xSemaphoreTake( xTXDescriptorSemaphore, xBlockTimeTicks ) != pdPASS ) + if( xSemaphoreTake( xTXDescriptorSemaphore[ xEMACIndex ], xBlockTimeTicks ) != pdPASS ) { FreeRTOS_printf( ( "emacps_send_message: Time-out waiting for TX buffer\n" ) ); break; } /* Pass the pointer (and its ownership) directly to DMA. */ - pxDMA_tx_buffers[ head ] = pxBuffer->pucEthernetBuffer; + pxDMA_tx_buffers[ xEMACIndex ][ head ] = pxBuffer->pucEthernetBuffer; if( ucIsCachedMemory( pxBuffer->pucEthernetBuffer ) != 0 ) { @@ -300,7 +283,7 @@ XStatus emacps_send_message( xemacpsif_s * xemacpsif, } /* Copy the address of the buffer and set the flags. */ - xemacpsif->txSegments[ head ].address = ( uintptr_t ) pxDMA_tx_buffers[ head ]; + xemacpsif->txSegments[ head ].address = ( uintptr_t ) pxDMA_tx_buffers[ xEMACIndex ][ head ]; xemacpsif->txSegments[ head ].flags = ulFlags; iHasSent = pdTRUE; @@ -347,15 +330,16 @@ void emacps_recv_handler( void * arg ) xemacpsif = ( xemacpsif_s * ) arg; xemacpsif->isr_events |= EMAC_IF_RX_EVENT; + BaseType_t xEMACIndex = xemacpsif->emacps.Config.DeviceId; /* The driver has already cleared the FRAMERX, BUFFNA and error bits * in the XEMACPS_RXSR register, * But it forgets to do a read-back. Do so now. */ ( void ) XEmacPs_ReadReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_RXSR_OFFSET ); - if( xEMACTaskHandle != NULL ) + if( xEMACTaskHandles[ xEMACIndex ] != NULL ) { - vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken ); + vTaskNotifyGiveFromISR( xEMACTaskHandles[ xEMACIndex ], &xHigherPriorityTaskWoken ); } portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); @@ -392,12 +376,88 @@ static void prvPassEthMessages( NetworkBufferDescriptor_t * pxDescriptor ) } } -int emacps_check_rx( xemacpsif_s * xemacpsif ) +BaseType_t xMayAcceptPacket( uint8_t * pucEthernetBuffer ) +{ + const ProtocolPacket_t * pxProtPacket = ( const ProtocolPacket_t * ) pucEthernetBuffer; + + switch( pxProtPacket->xTCPPacket.xEthernetHeader.usFrameType ) + { + case ipARP_FRAME_TYPE: + /* Check it later. */ + return pdTRUE; + + case ipIPv6_FRAME_TYPE: + /* Check it later. */ + return pdTRUE; + + case ipIPv4_FRAME_TYPE: + /* Check it here. */ + break; + + default: + /* Refuse the packet. */ + return pdFALSE; + } + + #if ( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 1 ) + { + const IPHeader_t * pxIPHeader = &( pxProtPacket->xTCPPacket.xIPHeader ); + + /* Ensure that the incoming packet is not fragmented (only outgoing packets + * can be fragmented) as these are the only handled IP frames currently. */ + if( ( pxIPHeader->usFragmentOffset & FreeRTOS_ntohs( ipFRAGMENT_OFFSET_BIT_MASK ) ) != 0U ) + { + return pdFALSE; + } + + /* HT: Might want to make the following configurable because + * most IP messages have a standard length of 20 bytes */ + + /* 0x45 means: IPv4 with an IP header of 5 x 4 = 20 bytes + * 0x47 means: IPv4 with an IP header of 7 x 4 = 28 bytes */ + if( ( pxIPHeader->ucVersionHeaderLength < 0x45 ) || ( pxIPHeader->ucVersionHeaderLength > 0x4F ) ) + { + return pdFALSE; + } + + if( pxIPHeader->ucProtocol == ipPROTOCOL_UDP ) + { + uint16_t usSourcePort = FreeRTOS_ntohs( pxProtPacket->xUDPPacket.xUDPHeader.usSourcePort ); + uint16_t usDestinationPort = FreeRTOS_ntohs( pxProtPacket->xUDPPacket.xUDPHeader.usDestinationPort ); + + if( ( xPortHasUDPSocket( pxProtPacket->xUDPPacket.xUDPHeader.usDestinationPort ) == pdFALSE ) + #if ipconfigUSE_LLMNR == 1 + && ( usDestinationPort != ipLLMNR_PORT ) && + ( usSourcePort != ipLLMNR_PORT ) + #endif + #if ipconfigUSE_NBNS == 1 + && ( usDestinationPort != ipNBNS_PORT ) && + ( usSourcePort != ipNBNS_PORT ) + #endif + #if ipconfigUSE_DNS == 1 + && ( usSourcePort != ipDNS_PORT ) + #endif + ) + { + /* Drop this packet, not for this device. */ + /* FreeRTOS_printf( ( "Drop: UDP port %d -> %d\n", usSourcePort, usDestinationPort ) ); */ + return pdFALSE; + } + } + } + #endif /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */ + return pdTRUE; +} + +int emacps_check_rx( xemacpsif_s * xemacpsif, + NetworkInterface_t * pxInterface ) { NetworkBufferDescriptor_t * pxBuffer, * pxNewBuffer; int rx_bytes; volatile int msgCount = 0; int head = xemacpsif->rxHead; + BaseType_t xEMACIndex = xemacpsif->emacps.Config.DeviceId; + BaseType_t xAccepted; #if ( ipconfigUSE_LINKED_RX_MESSAGES != 0 ) NetworkBufferDescriptor_t * pxFirstDescriptor = NULL; @@ -413,26 +473,40 @@ int emacps_check_rx( xemacpsif_s * xemacpsif ) for( ; ; ) { if( ( ( xemacpsif->rxSegments[ head ].address & XEMACPS_RXBUF_NEW_MASK ) == 0 ) || - ( pxDMA_rx_buffers[ head ] == NULL ) ) + ( pxDMA_rx_buffers[ xEMACIndex ][ head ] == NULL ) ) { break; } - pxNewBuffer = pxGetNetworkBufferWithDescriptor( dmaRX_TX_BUFFER_SIZE, ( TickType_t ) 0 ); + pxBuffer = ( NetworkBufferDescriptor_t * ) pxDMA_rx_buffers[ xEMACIndex ][ head ]; + xAccepted = xMayAcceptPacket( pxBuffer->pucEthernetBuffer ); - if( pxNewBuffer == NULL ) + if( xAccepted == pdFALSE ) { - /* A packet has been received, but there is no replacement for this Network Buffer. - * The packet will be dropped, and it Network Buffer will stay in place. */ - FreeRTOS_printf( ( "emacps_check_rx: unable to allocate a Network Buffer\n" ) ); - pxNewBuffer = ( NetworkBufferDescriptor_t * ) pxDMA_rx_buffers[ head ]; + pxNewBuffer = NULL; } else { - pxBuffer = ( NetworkBufferDescriptor_t * ) pxDMA_rx_buffers[ head ]; + pxNewBuffer = pxGetNetworkBufferWithDescriptor( dmaRX_TX_BUFFER_SIZE, ( TickType_t ) 0 ); + if( pxNewBuffer == NULL ) + { + /* A packet has been received, but there is no replacement for this Network Buffer. + * The packet will be dropped, and it Network Buffer will stay in place. */ + FreeRTOS_printf( ( "emacps_check_rx: unable to allocate a Network Buffer\n" ) ); + } + } + + if( pxNewBuffer == NULL ) + { + pxNewBuffer = ( NetworkBufferDescriptor_t * ) pxDMA_rx_buffers[ xEMACIndex ][ head ]; + } + else + { + pxBuffer->pxInterface = pxInterface; + pxBuffer->pxEndPoint = FreeRTOS_MatchingEndpoint( pxInterface, pxBuffer->pucEthernetBuffer ); /* Just avoiding to use or refer to the same buffer again */ - pxDMA_rx_buffers[ head ] = pxNewBuffer; + pxDMA_rx_buffers[ xEMACIndex ][ head ] = pxNewBuffer; /* * Adjust the buffer size to the actual number of bytes received. @@ -531,12 +605,13 @@ int emacps_check_rx( xemacpsif_s * xemacpsif ) void clean_dma_txdescs( xemacpsif_s * xemacpsif ) { int index; + BaseType_t xEMACIndex = xemacpsif->emacps.Config.DeviceId; for( index = 0; index < ipconfigNIC_N_TX_DESC; index++ ) { xemacpsif->txSegments[ index ].address = ( uintptr_t ) NULL; xemacpsif->txSegments[ index ].flags = XEMACPS_TXBUF_USED_MASK; - pxDMA_tx_buffers[ index ] = ( unsigned char * ) NULL; + pxDMA_tx_buffers[ xEMACIndex ][ index ] = ( unsigned char * ) NULL; } xemacpsif->txSegments[ ipconfigNIC_N_TX_DESC - 1 ].flags = @@ -546,11 +621,12 @@ void clean_dma_txdescs( xemacpsif_s * xemacpsif ) XStatus init_dma( xemacpsif_s * xemacpsif ) { NetworkBufferDescriptor_t * pxBuffer; + BaseType_t xEMACIndex = xemacpsif->emacps.Config.DeviceId; int iIndex; UBaseType_t xRxSize; UBaseType_t xTxSize; - struct xtopology_t * xtopologyp = &xXTopology; + struct xtopology_t * xtopologyp = &xXTopologies[ xEMACIndex ]; XEmacPs_BdRing * rxRing; XEmacPs * emac = &( xemacpsif->emacps ); XEmacPs_Bd bdTemplate; @@ -596,10 +672,10 @@ XStatus init_dma( xemacpsif_s * xemacpsif ) return status; } - if( xTXDescriptorSemaphore == NULL ) + if( xTXDescriptorSemaphore[ xEMACIndex ] == NULL ) { - xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) ipconfigNIC_N_TX_DESC, ( UBaseType_t ) ipconfigNIC_N_TX_DESC ); - configASSERT( xTXDescriptorSemaphore != NULL ); + xTXDescriptorSemaphore[ xEMACIndex ] = xSemaphoreCreateCounting( ( UBaseType_t ) ipconfigNIC_N_TX_DESC, ( UBaseType_t ) ipconfigNIC_N_TX_DESC ); + configASSERT( xTXDescriptorSemaphore[ xEMACIndex ] != NULL ); } /* @@ -607,7 +683,7 @@ XStatus init_dma( xemacpsif_s * xemacpsif ) */ for( iIndex = 0; iIndex < ipconfigNIC_N_RX_DESC; iIndex++ ) { - pxBuffer = pxDMA_rx_buffers[ iIndex ]; + pxBuffer = pxDMA_rx_buffers[ xEMACIndex ][ iIndex ]; if( pxBuffer == NULL ) { @@ -642,7 +718,7 @@ XStatus init_dma( xemacpsif_s * xemacpsif ) xemacpsif->rxSegments[ iIndex ].reserved = iIndex; #endif - pxDMA_rx_buffers[ iIndex ] = pxBuffer; + pxDMA_rx_buffers[ xEMACIndex ][ iIndex ] = pxBuffer; /* Make sure this memory is not in cache for now. */ if( ucIsCachedMemory( pxBuffer->pucEthernetBuffer ) != 0 ) @@ -698,45 +774,32 @@ XStatus init_dma( xemacpsif_s * xemacpsif ) } /* Set terminating BDs for US+ GEM */ - if( xemacpsif->emacps.Version > 2 ) - { - xemacpsif->rxBdTerminator = ( struct xBD_TYPE * ) pucGetUncachedMemory( sizeof( *xemacpsif->rxBdTerminator ) ); - xemacpsif->txBdTerminator = ( struct xBD_TYPE * ) pucGetUncachedMemory( sizeof( *xemacpsif->txBdTerminator ) ); - - XEmacPs_BdClear( xemacpsif->rxBdTerminator ); - XEmacPs_BdSetAddressRx( xemacpsif->rxBdTerminator, ( XEMACPS_RXBUF_NEW_MASK | - XEMACPS_RXBUF_WRAP_MASK ) ); - XEmacPs_Out32( ( emac->Config.BaseAddress + XEMACPS_RXQ1BASE_OFFSET ), - ( UINTPTR ) xemacpsif->rxBdTerminator ); - - XEmacPs_BdClear( xemacpsif->txBdTerminator ); - XEmacPs_BdSetStatus( xemacpsif->txBdTerminator, - ( XEMACPS_TXBUF_USED_MASK | XEMACPS_TXBUF_WRAP_MASK ) ); - XEmacPs_Out32( ( emac->Config.BaseAddress + XEMACPS_TXQBASE_OFFSET ), - ( UINTPTR ) xemacpsif->txBdTerminator ); - } + xemacpsif->rxBdTerminator = ( struct xBD_TYPE * ) pucGetUncachedMemory( sizeof( *xemacpsif->rxBdTerminator ) ); + xemacpsif->txBdTerminator = ( struct xBD_TYPE * ) pucGetUncachedMemory( sizeof( *xemacpsif->txBdTerminator ) ); + + XEmacPs_BdClear( xemacpsif->rxBdTerminator ); + XEmacPs_BdSetAddressRx( xemacpsif->rxBdTerminator, ( XEMACPS_RXBUF_NEW_MASK | + XEMACPS_RXBUF_WRAP_MASK ) ); + XEmacPs_Out32( ( emac->Config.BaseAddress + XEMACPS_RXQ1BASE_OFFSET ), + ( UINTPTR ) xemacpsif->rxBdTerminator ); + + XEmacPs_BdClear( xemacpsif->txBdTerminator ); + XEmacPs_BdSetStatus( xemacpsif->txBdTerminator, + ( XEMACPS_TXBUF_USED_MASK | XEMACPS_TXBUF_WRAP_MASK ) ); + XEmacPs_Out32( ( emac->Config.BaseAddress + XEMACPS_TXQBASE_OFFSET ), + ( UINTPTR ) xemacpsif->txBdTerminator ); /* These variables will be used in XEmacPs_Start (see src/xemacps.c). */ XEmacPs_SetQueuePtr( emac, ( uintptr_t ) xemacpsif->rxSegments, 0, XEMACPS_RECV ); - if( xemacpsif->emacps.Version > 2 ) - { - XEmacPs_SetQueuePtr( emac, ( uintptr_t ) xemacpsif->txSegments, 1, XEMACPS_SEND ); - } - else - { - XEmacPs_SetQueuePtr( emac, ( uintptr_t ) xemacpsif->txSegments, 0, XEMACPS_SEND ); - } + XEmacPs_SetQueuePtr( emac, ( uintptr_t ) xemacpsif->txSegments, 1, XEMACPS_SEND ); - XScuGic_Connect( &xInterruptController, - xtopologyp->scugic_emac_intr, - XEmacPs_IntrHandler, - emac ); + XScuGic_Connect( &xInterruptController, xtopologyp->scugic_emac_intr, XEmacPs_IntrHandler, emac ); /* * Enable the interrupt for emacps. */ - EmacEnableIntr(); + EmacEnableIntr( xEMACIndex ); return 0; } @@ -777,12 +840,12 @@ void resetrx_on_no_rxdata( xemacpsif_s * xemacpsif ) xemacpsif->last_rx_frms_cntr = tempcntr; } -void EmacDisableIntr( void ) +void EmacDisableIntr( int xEMACIndex ) { - XScuGic_DisableIntr( INTC_DIST_BASE_ADDR, xXTopology.scugic_emac_intr ); + XScuGic_Disable( &xInterruptController, xXTopologies[ xEMACIndex ].scugic_emac_intr ); } -void EmacEnableIntr( void ) +void EmacEnableIntr( int xEMACIndex ) { - XScuGic_Enable( &xInterruptController, xXTopology.scugic_emac_intr ); + XScuGic_Enable( &xInterruptController, xXTopologies[ xEMACIndex ].scugic_emac_intr ); } diff --git a/source/portable/NetworkInterface/xilinx_ultrascale/x_emacpsif_hw.c b/source/portable/NetworkInterface/xilinx_ultrascale/x_emacpsif_hw.c index 03db01d3b..950ea9ceb 100644 --- a/source/portable/NetworkInterface/xilinx_ultrascale/x_emacpsif_hw.c +++ b/source/portable/NetworkInterface/xilinx_ultrascale/x_emacpsif_hw.c @@ -35,8 +35,9 @@ #include "NetworkInterface.h" #include "x_emacpsif.h" +#include "x_topology.h" -extern TaskHandle_t xEMACTaskHandle; +extern TaskHandle_t xEMACTaskHandles[ XPAR_XEMACPS_NUM_INSTANCES ]; /*** IMPORTANT: Define PEEP in xemacpsif.h and sys_arch_raw.c *** to run it on a PEEP board @@ -65,7 +66,7 @@ void start_emacps( xemacpsif_s * xemacps ) XEmacPs_Start( &xemacps->emacps ); } -extern struct xtopology_t xXTopology; +extern struct xtopology_t xXTopologies[ XPAR_XEMACPS_NUM_INSTANCES ]; volatile int error_msg_count = 0; volatile const char * last_err_msg = ""; @@ -87,8 +88,10 @@ void emacps_error_handler( void * arg, BaseType_t xHigherPriorityTaskWoken = pdFALSE; xemacpsif_s * xemacpsif; BaseType_t xNextHead = xErrorHead; + BaseType_t xEMACIndex; xemacpsif = ( xemacpsif_s * ) ( arg ); + xEMACIndex = xemacpsif->emacps.Config.DeviceId; if( ( Direction != XEMACPS_SEND ) || ( ErrorWord != XEMACPS_TXSR_USEDREAD_MASK ) ) { @@ -109,9 +112,9 @@ void emacps_error_handler( void * arg, xemacpsif->isr_events |= EMAC_IF_ERR_EVENT; } - if( xEMACTaskHandle != NULL ) + if( xEMACTaskHandles[ xEMACIndex ] != NULL ) { - vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken ); + vTaskNotifyGiveFromISR( xEMACTaskHandles[ xEMACIndex ], &xHigherPriorityTaskWoken ); } } @@ -152,9 +155,14 @@ static void emacps_handle_error( void * arg, struct xtopology_t * xtopologyp; XEmacPs * xemacps; + BaseType_t xEMACIndex; + xemacpsif = ( xemacpsif_s * ) ( arg ); - xtopologyp = &xXTopology; + xemacps = &xemacpsif->emacps; + xEMACIndex = xemacps->Config.DeviceId; + + xtopologyp = &xXTopologies[ xEMACIndex ]; xemacps = &xemacpsif->emacps; @@ -173,7 +181,7 @@ static void emacps_handle_error( void * arg, if( ( ErrorWord & XEMACPS_RXSR_HRESPNOK_MASK ) != 0 ) { last_err_msg = "Receive DMA error"; - xNetworkInterfaceInitialise(); + vInitialiseOnIndex( xEMACIndex ); } if( ( ErrorWord & XEMACPS_RXSR_RXOVR_MASK ) != 0 ) @@ -195,7 +203,7 @@ static void emacps_handle_error( void * arg, if( ( ErrorWord & XEMACPS_TXSR_HRESPNOK_MASK ) != 0 ) { last_err_msg = "Transmit DMA error"; - xNetworkInterfaceInitialise(); + vInitialiseOnIndex( xEMACIndex ); } if( ( ErrorWord & XEMACPS_TXSR_URUN_MASK ) != 0 ) diff --git a/source/portable/NetworkInterface/xilinx_ultrascale/x_emacpsif_hw.h b/source/portable/NetworkInterface/xilinx_ultrascale/x_emacpsif_hw.h index 7656579f6..8e21b0815 100644 --- a/source/portable/NetworkInterface/xilinx_ultrascale/x_emacpsif_hw.h +++ b/source/portable/NetworkInterface/xilinx_ultrascale/x_emacpsif_hw.h @@ -20,7 +20,6 @@ #define __XEMACPSIF_HW_H_ #include "x_emacpsif.h" -/*#include "lwip/netif.h" */ #ifdef __cplusplus extern "C" { @@ -28,8 +27,6 @@ XEmacPs_Config * lookup_config( unsigned mac_base ); -/*void init_emacps(xemacpsif_s *xemacpsif, struct netif *netif); */ - int emacps_check_errors( xemacpsif_s * xemacps ); /* Defined in x_emacpsif_physpeed.c. */ diff --git a/source/portable/NetworkInterface/xilinx_ultrascale/x_emacpsif_physpeed.c b/source/portable/NetworkInterface/xilinx_ultrascale/x_emacpsif_physpeed.c index 7960b8d31..b4292600c 100644 --- a/source/portable/NetworkInterface/xilinx_ultrascale/x_emacpsif_physpeed.c +++ b/source/portable/NetworkInterface/xilinx_ultrascale/x_emacpsif_physpeed.c @@ -54,7 +54,7 @@ #include #include "x_emacpsif.h" -/*#include "lwipopts.h" */ +#include "x_emac_map.h" #include "xparameters_ps.h" #include "xparameters.h" @@ -69,6 +69,7 @@ #include "FreeRTOS_IP.h" #include "FreeRTOS_Sockets.h" #include "FreeRTOS_IP_Private.h" +#include "FreeRTOS_Routing.h" #include "NetworkBufferManagement.h" #define phyMIN_PHY_ADDRESS 0 @@ -76,9 +77,8 @@ #define MINIMUM_SLEEP_TIME ( ( TickType_t ) 1 * configTICK_RATE_HZ ) -/*** IMPORTANT: Define PEEP in xemacpsif.h and sys_arch_raw.c - *** to run it on a PEEP board - ***/ + +uint32_t phy_detected[ 4 ]; /* Advertisement control register. */ #define ADVERTISE_10HALF 0x0020 /* Try for 10mbps half-duplex */ @@ -157,6 +157,7 @@ #define PHY_MARVELL_IDENTIFIER 0x0141 #define PHY_TI_IDENTIFIER 0x2000 #define PHY_REALTEK_IDENTIFIER 0x001c +#define PHY_MICREL_IDENTIFIER 0x0022 #define PHY_AR8035_IDENTIFIER 0x004D #define PHY_XILINX_PCS_PMA_ID1 0x0174 #define PHY_XILINX_PCS_PMA_ID2 0x0C00 @@ -179,30 +180,6 @@ #define PHY_TI_CRVAL 0x5048 #define PHY_TI_CFG4RESVDBIT7 0x80 -/* Frequency setting */ -#define SLCR_LOCK_ADDR ( XPS_SYS_CTRL_BASEADDR + 0x4 ) -#define SLCR_UNLOCK_ADDR ( XPS_SYS_CTRL_BASEADDR + 0x8 ) -#define SLCR_GEM0_CLK_CTRL_ADDR ( XPS_SYS_CTRL_BASEADDR + 0x140 ) -#define SLCR_GEM1_CLK_CTRL_ADDR ( XPS_SYS_CTRL_BASEADDR + 0x144 ) -#ifdef PEEP - #define SLCR_GEM_10M_CLK_CTRL_VALUE 0x00103031 - #define SLCR_GEM_100M_CLK_CTRL_VALUE 0x00103001 - #define SLCR_GEM_1G_CLK_CTRL_VALUE 0x00103011 -#endif -#define SLCR_GEM_SRCSEL_EMIO 0x40 -#define SLCR_LOCK_KEY_VALUE 0x767B -#define SLCR_UNLOCK_KEY_VALUE 0xDF0D -#define SLCR_ADDR_GEM_RST_CTRL ( XPS_SYS_CTRL_BASEADDR + 0x214 ) -#define EMACPS_SLCR_DIV_MASK 0xFC0FC0FF - -#define ZYNQ_EMACPS_0_BASEADDR 0xE000B000 -#define ZYNQ_EMACPS_1_BASEADDR 0xE000C000 - -#define ZYNQMP_EMACPS_0_BASEADDR 0xFF0B0000 -#define ZYNQMP_EMACPS_1_BASEADDR 0xFF0C0000 -#define ZYNQMP_EMACPS_2_BASEADDR 0xFF0D0000 -#define ZYNQMP_EMACPS_3_BASEADDR 0xFF0E0000 - #define CRL_APB_GEM0_REF_CTRL 0xFF5E0050 #define CRL_APB_GEM1_REF_CTRL 0xFF5E0054 #define CRL_APB_GEM2_REF_CTRL 0xFF5E0058 @@ -226,8 +203,6 @@ #define GEM_VERSION_ZYNQMP 7 #define GEM_VERSION_VERSAL 0x107 -u32 phymapemac0[ 32 ]; -u32 phymapemac1[ 32 ]; static uint16_t prvAR803x_debug_reg_write( XEmacPs * xemacpsp, uint32_t phy_addr, @@ -685,6 +660,240 @@ static uint32_t get_Realtek_phy_speed( XEmacPs * xemacpsp, return XST_FAILURE; } +#define LPA_IEEE_1000 0x0800 +#define LP5_IEEE_100 0x0100 +#define LP5_IEEE_10 0x0040 +#define MICREL_ID_KSZ9021 0x0161 +#define MICREL_ID_KSZ9031 0x0162 +#define MICREL_ID_KSZ9131 0x0164 + + +static int set_Micrel_phy_delays( XEmacPs * EmacPsInstancePtr, + uint32_t PhyAddr ) +{ + int Status; + uint16_t PhyType, PhyData; + + XEmacPs_PhyRead( EmacPsInstancePtr, PhyAddr, 0x3, ( u16 * ) &PhyData ); /* read value */ + PhyType = ( PhyData >> 4 ); + + /* enabling RGMII delays */ + if( PhyType == MICREL_ID_KSZ9131 ) /* KSZ9131 */ + { + FreeRTOS_printf( ( "Detected KSZ9131 Ethernet PHY\n\r" ) ); + /*Ctrl Delay */ + u16 RxCtrlDelay = 7; /* 0..15, default 7 */ + u16 TxCtrlDelay = 7; /* 0..15, default 7 */ + XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xD, 0x0002 ); + XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xE, 0x0004 ); /* Reg 0x4 */ + XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xD, 0x4002 ); + XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xE, ( TxCtrlDelay | ( RxCtrlDelay << 4 ) ) ); + /*Data Delay */ + u16 RxDataDelay = 7; /* 0..15, default 7 */ + u16 TxDataDelay = 7; /* 0..15, default 7 */ + XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xD, 0x0002 ); + XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xE, 0x0005 ); /* Reg 0x5 */ + XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xD, 0x4002 ); + XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xE, ( RxDataDelay | ( RxDataDelay << 4 ) | ( RxDataDelay << 8 ) | ( RxDataDelay << 12 ) ) ); + XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xD, 0x0002 ); + XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xE, 0x0006 ); /* Reg 0x6 */ + XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xD, 0x4002 ); + XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xE, ( TxDataDelay | ( TxDataDelay << 4 ) | ( TxDataDelay << 8 ) | ( TxDataDelay << 12 ) ) ); + /*Clock Delay */ + u16 RxClockDelay = 31; /* 0..31, default 15 */ + u16 TxClockDelay = 31; /* 0..31, default 15 */ + XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xD, 0x0002 ); + XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xE, 0x0008 ); /* Reg 0x8 RGMII Clock Pad Skew */ + XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xD, 0x4002 ); + XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xE, ( RxClockDelay | ( TxClockDelay << 5 ) ) ); + } + else if( PhyType == MICREL_ID_KSZ9031 ) /* KSZ9031 */ + { + FreeRTOS_printf( ( "Detected KSZ9031 Ethernet PHY\n\r" ) ); + /*Ctrl Delay */ + u16 RxCtrlDelay = 7; /* 0..15, default 7 */ + u16 TxCtrlDelay = 7; /* 0..15, default 7 */ + XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xD, 0x0002 ); + XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xE, 0x0004 ); /* Reg 0x4 */ + XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xD, 0x4002 ); + XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xE, ( TxCtrlDelay | ( RxCtrlDelay << 4 ) ) ); + /*Data Delay */ + u16 RxDataDelay = 7; /* 0..15, default 7 */ + u16 TxDataDelay = 7; /* 0..15, default 7 */ + XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xD, 0x0002 ); + XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xE, 0x0005 ); /* Reg 0x5 */ + XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xD, 0x4002 ); + XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xE, ( RxDataDelay | ( RxDataDelay << 4 ) | ( RxDataDelay << 8 ) | ( RxDataDelay << 12 ) ) ); + XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xD, 0x0002 ); + XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xE, 0x0006 ); /* Reg 0x6 */ + XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xD, 0x4002 ); + XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xE, ( TxDataDelay | ( TxDataDelay << 4 ) | ( TxDataDelay << 8 ) | ( TxDataDelay << 12 ) ) ); + /*Clock Delay */ + u16 RxClockDelay = 31; /* 0..31, default 15 */ + u16 TxClockDelay = 31; /* 0..31, default 15 */ + XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xD, 0x0002 ); + XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xE, 0x0008 ); /* Reg 0x8 RGMII Clock Pad Skew */ + XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xD, 0x4002 ); + XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xE, ( RxClockDelay | ( TxClockDelay << 5 ) ) ); + } + else if( PhyType == MICREL_ID_KSZ9021 ) /* KSZ9021 */ + { + FreeRTOS_printf( ( "Detected KSZ9021 Ethernet PHY\n\r" ) ); + XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xB, 0x8104 ); /* write Reg 0x104 */ + XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xC, 0xF0F0 ); /* set write data */ + XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xB, 0x8105 ); /* write Reg 0x105 */ + XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0xC, 0x0000 ); /* set write data */ + } + + /* Issue a reset to phy */ + Status = XEmacPs_PhyRead( EmacPsInstancePtr, PhyAddr, 0x0, &PhyData ); + PhyData |= 0x8000; + Status = XEmacPs_PhyWrite( EmacPsInstancePtr, PhyAddr, 0x0, PhyData ); + vTaskDelay( 1 ); + Status |= XEmacPs_PhyRead( EmacPsInstancePtr, PhyAddr, 0x0, &PhyData ); + + if( Status != XST_SUCCESS ) + { + return Status; + } + + return PhyType; +} + +static uint32_t get_Micrel_phy_speed( XEmacPs * xemacpsp, + uint32_t phy_addr ) +{ + const char * name_ptr; + uint16_t temp, phy_type; + uint16_t control; + uint16_t status; + uint16_t status_speed; + uint32_t timeout_counter = 0; + + /* Just to prevent compiler warnings about unused variables. */ + ( void ) name_ptr; + + + FreeRTOS_printf( ( "Start Micrel PHY program delay\r\n" ) ); + + if( ( phy_type = set_Micrel_phy_delays( xemacpsp, phy_addr ) ) != XST_FAILURE ) + { + FreeRTOS_printf( ( "Delay Set Okay!\r\n" ) ); + } + else + { + FreeRTOS_printf( ( "Delay Set Error!\r\n" ) ); + } + + switch( phy_type ) + { + case MICREL_ID_KSZ9021: + name_ptr = "KSZ9021"; + break; + + case MICREL_ID_KSZ9031: + name_ptr = "KSZ9031"; + break; + + case MICREL_ID_KSZ9131: + name_ptr = "KSZ9131"; + break; + + default: + name_ptr = "!UNKNOWN!"; + break; + } + + FreeRTOS_printf( ( "Start %s auto-negotiation\r\n", name_ptr ) ); + + XEmacPs_PhyRead( xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, &control ); + control |= IEEE_ASYMMETRIC_PAUSE_MASK; + control |= IEEE_PAUSE_MASK; + control |= ADVERTISE_100; + control |= ADVERTISE_10; + XEmacPs_PhyWrite( xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, control ); + + XEmacPs_PhyRead( xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET, &control ); + control |= ADVERTISE_1000; + XEmacPs_PhyWrite( xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET, control ); + + XEmacPs_PhyRead( xemacpsp, phy_addr, IEEE_COPPER_SPECIFIC_CONTROL_REG, &control ); + control |= ( 7 << 12 ); + control |= ( 1 << 11 ); + XEmacPs_PhyWrite( xemacpsp, phy_addr, IEEE_COPPER_SPECIFIC_CONTROL_REG, control ); + + XEmacPs_PhyRead( xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control ); + control |= IEEE_CTRL_AUTONEGOTIATE_ENABLE; + control |= IEEE_STAT_AUTONEGOTIATE_RESTART; + XEmacPs_PhyWrite( xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, control ); + + XEmacPs_PhyRead( xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control ); + control |= IEEE_CTRL_RESET_MASK; + XEmacPs_PhyWrite( xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, control ); + + while( 1 ) + { + XEmacPs_PhyRead( xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control ); + + if( control & IEEE_CTRL_RESET_MASK ) + { + continue; + } + else + { + break; + } + } + + XEmacPs_PhyRead( xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET, &status ); + + FreeRTOS_printf( ( "Waiting for %s to complete Auto-negotiation.\r\n", name_ptr ) ); + + while( !( status & IEEE_STAT_AUTONEGOTIATE_COMPLETE ) ) + { + vTaskDelay( pdMS_TO_TICKS( 1000 ) ); + XEmacPs_PhyRead( xemacpsp, phy_addr, IEEE_COPPER_SPECIFIC_STATUS_REG_2, &temp ); + timeout_counter++; + + if( timeout_counter == 30 ) + { + FreeRTOS_printf( ( "Auto negotiation error \r\n" ) ); + return XST_FAILURE; + } + + XEmacPs_PhyRead( xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET, &status ); + } + + FreeRTOS_printf( ( "%s Completed Auto-negotiation\r\n", name_ptr ) ); + + /* Check for high speed connection first */ + XEmacPs_PhyRead( xemacpsp, phy_addr, IEEE_PARTNER_ABILITIES_3_REG_OFFSET, &status_speed ); + + if( status_speed & LPA_IEEE_1000 ) + { + FreeRTOS_printf( ( "Micrel PHY %s speed 1000Mbps\r\n", name_ptr ) ); + return 1000; + } + else /* No high speed so check lows... */ + { + XEmacPs_PhyRead( xemacpsp, phy_addr, IEEE_PARTNER_ABILITIES_1_REG_OFFSET, &status_speed ); + + if( status_speed & LP5_IEEE_100 ) + { + FreeRTOS_printf( ( "Micrel PHY %s speed 100Mbps\r\n", name_ptr ) ); + return 100; + } + + if( status_speed & LP5_IEEE_10 ) + { + FreeRTOS_printf( ( "Micrel PHY %s speed 10Mbps\r\n", name_ptr ) ); + return 10; + } + } + + return XST_FAILURE; +} + /* Here is a XEmacPs_PhyRead() that returns the value of a register. */ static uint16_t XEmacPs_PhyRead2( XEmacPs * InstancePtr, u32 PhyAddress, @@ -912,7 +1121,7 @@ static uint32_t ar8035CheckStatus( XEmacPs * xemacpsp, static const char * pcGetPHIName( uint16_t usID ) { const char * pcReturn = ""; - static char pcName[ 16 ]; + static char pcName[ 32 ]; switch( usID ) { @@ -924,6 +1133,10 @@ static const char * pcGetPHIName( uint16_t usID ) pcReturn = "Realtek RTL8212"; break; + case PHY_MICREL_IDENTIFIER: + pcReturn = "MICREL PHY"; + break; + case PHY_AR8035_IDENTIFIER: pcReturn = "Atheros_ar8035"; break; @@ -971,10 +1184,12 @@ static uint32_t get_IEEE_phy_speed_US( XEmacPs * xemacpsp, RetStatus = get_Marvell_phy_speed( xemacpsp, phy_addr ); break; + case PHY_MICREL_IDENTIFIER: + RetStatus = get_Micrel_phy_speed( xemacpsp, phy_addr ); + break; + case PHY_AR8035_IDENTIFIER: RetStatus = get_AR8035_phy_speed( xemacpsp, phy_addr ); - /* RetStatus = get_Marvell_phy_speed(xemacpsp, phy_addr); */ - /* RetStatus = get_Realtek_phy_speed(xemacpsp, phy_addr); */ prvSET_AR803x_TX_Timing( xemacpsp, phy_addr ); break; @@ -990,10 +1205,6 @@ static uint32_t get_IEEE_phy_speed_US( XEmacPs * xemacpsp, static void SetUpSLCRDivisors( u32 mac_baseaddr, s32 speed ) { - volatile u32 slcrBaseAddress; - u32 SlcrDiv0 = 0; - u32 SlcrDiv1 = 0; - u32 SlcrTxClkCntrl; u32 gigeversion; volatile u32 CrlApbBaseAddr; u32 CrlApbDiv0 = 0; @@ -1002,92 +1213,7 @@ static void SetUpSLCRDivisors( u32 mac_baseaddr, gigeversion = ( ( Xil_In32( mac_baseaddr + 0xFC ) ) >> 16 ) & 0xFFF; - if( gigeversion == 2 ) - { - *( volatile u32 * ) ( SLCR_UNLOCK_ADDR ) = SLCR_UNLOCK_KEY_VALUE; - - if( mac_baseaddr == ZYNQ_EMACPS_0_BASEADDR ) - { - slcrBaseAddress = SLCR_GEM0_CLK_CTRL_ADDR; - } - else - { - slcrBaseAddress = SLCR_GEM1_CLK_CTRL_ADDR; - } - - if( ( *( volatile u32 * ) ( UINTPTR ) ( slcrBaseAddress ) ) & - SLCR_GEM_SRCSEL_EMIO ) - { - return; - } - - if( speed == 1000 ) - { - if( mac_baseaddr == XPAR_XEMACPS_0_BASEADDR ) - { - #ifdef XPAR_PS7_ETHERNET_0_ENET_SLCR_1000MBPS_DIV0 - SlcrDiv0 = XPAR_PS7_ETHERNET_0_ENET_SLCR_1000MBPS_DIV0; - SlcrDiv1 = XPAR_PS7_ETHERNET_0_ENET_SLCR_1000MBPS_DIV1; - #endif - } - else - { - #ifdef XPAR_PS7_ETHERNET_1_ENET_SLCR_1000MBPS_DIV0 - SlcrDiv0 = XPAR_PS7_ETHERNET_1_ENET_SLCR_1000MBPS_DIV0; - SlcrDiv1 = XPAR_PS7_ETHERNET_1_ENET_SLCR_1000MBPS_DIV1; - #endif - } - } - else if( speed == 100 ) - { - if( mac_baseaddr == XPAR_XEMACPS_0_BASEADDR ) - { - #ifdef XPAR_PS7_ETHERNET_0_ENET_SLCR_100MBPS_DIV0 - SlcrDiv0 = XPAR_PS7_ETHERNET_0_ENET_SLCR_100MBPS_DIV0; - SlcrDiv1 = XPAR_PS7_ETHERNET_0_ENET_SLCR_100MBPS_DIV1; - #endif - } - else - { - #ifdef XPAR_PS7_ETHERNET_1_ENET_SLCR_100MBPS_DIV0 - SlcrDiv0 = XPAR_PS7_ETHERNET_1_ENET_SLCR_100MBPS_DIV0; - SlcrDiv1 = XPAR_PS7_ETHERNET_1_ENET_SLCR_100MBPS_DIV1; - #endif - } - } - else - { - if( mac_baseaddr == XPAR_XEMACPS_0_BASEADDR ) - { - #ifdef XPAR_PS7_ETHERNET_0_ENET_SLCR_10MBPS_DIV0 - SlcrDiv0 = XPAR_PS7_ETHERNET_0_ENET_SLCR_10MBPS_DIV0; - SlcrDiv1 = XPAR_PS7_ETHERNET_0_ENET_SLCR_10MBPS_DIV1; - #endif - } - else - { - #ifdef XPAR_PS7_ETHERNET_1_ENET_SLCR_10MBPS_DIV0 - SlcrDiv0 = XPAR_PS7_ETHERNET_1_ENET_SLCR_10MBPS_DIV0; - SlcrDiv1 = XPAR_PS7_ETHERNET_1_ENET_SLCR_10MBPS_DIV1; - #endif - } - } - - if( ( SlcrDiv0 != 0 ) && ( SlcrDiv1 != 0 ) ) - { - SlcrTxClkCntrl = *( volatile u32 * ) ( UINTPTR ) ( slcrBaseAddress ); - SlcrTxClkCntrl &= EMACPS_SLCR_DIV_MASK; - SlcrTxClkCntrl |= ( SlcrDiv1 << 20 ); - SlcrTxClkCntrl |= ( SlcrDiv0 << 8 ); - *( volatile u32 * ) ( UINTPTR ) ( slcrBaseAddress ) = SlcrTxClkCntrl; - *( volatile u32 * ) ( SLCR_LOCK_ADDR ) = SLCR_LOCK_KEY_VALUE; - } - else - { - FreeRTOS_printf( ( "Clock Divisors incorrect - Please check\n" ) ); - } - } - else if( gigeversion == GEM_VERSION_ZYNQMP ) + if( gigeversion == GEM_VERSION_ZYNQMP ) { /* Setup divisors in CRL_APB for Zynq Ultrascale+ MPSoC */ if( mac_baseaddr == ZYNQMP_EMACPS_0_BASEADDR ) @@ -1314,6 +1440,11 @@ static void SetUpSLCRDivisors( u32 mac_baseaddr, FreeRTOS_printf( ( "Clock Divisors incorrect - Please check\n" ) ); } } + else + { + FreeRTOS_printf( ( "Invalid GEM version %u \n", gigeversion ) ); + return; + } } u32 Phy_Setup_US( XEmacPs * xemacpsp, diff --git a/source/portable/NetworkInterface/xilinx_ultrascale/x_topology.h b/source/portable/NetworkInterface/xilinx_ultrascale/x_topology.h index 2ed411c79..111582f64 100644 --- a/source/portable/NetworkInterface/xilinx_ultrascale/x_topology.h +++ b/source/portable/NetworkInterface/xilinx_ultrascale/x_topology.h @@ -38,11 +38,6 @@ unsigned scugic_emac_intr; /* valid only for GEM */ }; - extern int x_topology_n_emacs; - extern struct xtopology_t x_topology[]; - - int x_topology_find_index( unsigned base ); - #ifdef __cplusplus } /* extern "C" */ #endif