2 * FreeRTOS+TCP Labs Build 200417 (C) 2016 Real Time Engineers ltd.
\r
3 * Authors include Hein Tibosch and Richard Barry
\r
5 *******************************************************************************
\r
6 ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
\r
9 *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
\r
10 *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
\r
13 *** FreeRTOS+TCP is functional and has been used in commercial products ***
\r
14 *** for some time. Be aware however that we are still refining its ***
\r
15 *** design, the source code does not yet quite conform to the strict ***
\r
16 *** coding and style standards mandated by Real Time Engineers ltd., and ***
\r
17 *** the documentation and testing is not necessarily complete. ***
\r
19 *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
\r
20 *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
\r
21 *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
\r
22 *** under a license other than that described below. ***
\r
25 ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
\r
26 *******************************************************************************
\r
28 * FreeRTOS+TCP can be used under two different free open source licenses. The
\r
29 * license that applies is dependent on the processor on which FreeRTOS+TCP is
\r
30 * executed, as follows:
\r
32 * If FreeRTOS+TCP is executed on one of the processors listed under the Special
\r
33 * License Arrangements heading of the FreeRTOS+TCP license information web
\r
34 * page, then it can be used under the terms of the FreeRTOS Open Source
\r
35 * License. If FreeRTOS+TCP is used on any other processor, then it can be used
\r
36 * under the terms of the GNU General Public License V2. Links to the relevant
\r
39 * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
\r
40 * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
\r
41 * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
\r
43 * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
\r
44 * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
\r
45 * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
\r
46 * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
\r
47 * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
\r
48 * implied, expressed, or statutory.
\r
50 * 1 tab == 4 spaces!
\r
52 * http://www.FreeRTOS.org
\r
53 * http://www.FreeRTOS.org/plus
\r
54 * http://www.FreeRTOS.org/labs
\r
58 /* Standard includes. */
\r
63 /* FreeRTOS includes. */
\r
64 #include "FreeRTOS.h"
\r
69 /* FreeRTOS+TCP includes. */
\r
70 #include "FreeRTOS_IP.h"
\r
71 #include "FreeRTOS_Sockets.h"
\r
72 #include "FreeRTOS_IP_Private.h"
\r
73 #include "NetworkBufferManagement.h"
\r
74 #include "NetworkInterface.h"
\r
76 /* Xilinx library files. */
\r
77 #include <xemacps.h>
\r
78 #include "Zynq/x_topology.h"
\r
79 #include "Zynq/x_emacpsif.h"
\r
80 #include "Zynq/x_emacpsif_hw.h"
\r
82 /* Provided memory configured as uncached. */
\r
83 #include "uncached_memory.h"
\r
85 #ifndef BMSR_LINK_STATUS
\r
86 #define BMSR_LINK_STATUS 0x0004UL
\r
89 #ifndef PHY_LS_HIGH_CHECK_TIME_MS
\r
90 /* Check if the LinkSStatus in the PHY is still high after 15 seconds of not
\r
91 receiving packets. */
\r
92 #define PHY_LS_HIGH_CHECK_TIME_MS 15000
\r
95 #ifndef PHY_LS_LOW_CHECK_TIME_MS
\r
96 /* Check if the LinkSStatus in the PHY is still low every second. */
\r
97 #define PHY_LS_LOW_CHECK_TIME_MS 1000
\r
100 /* The size of each buffer when BufferAllocation_1 is used:
\r
101 http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Ethernet_Buffer_Management.html */
\r
102 #define niBUFFER_1_PACKET_SIZE 1536
\r
104 /* Naming and numbering of PHY registers. */
\r
105 #define PHY_REG_01_BMSR 0x01 /* Basic mode status register */
\r
107 #ifndef iptraceEMAC_TASK_STARTING
\r
108 #define iptraceEMAC_TASK_STARTING() do { } while( 0 )
\r
111 /* Default the size of the stack used by the EMAC deferred handler task to twice
\r
112 the size of the stack used by the idle task - but allow this to be overridden in
\r
113 FreeRTOSConfig.h as configMINIMAL_STACK_SIZE is a user definable constant. */
\r
114 #ifndef configEMAC_TASK_STACK_SIZE
\r
115 #define configEMAC_TASK_STACK_SIZE ( 2 * configMINIMAL_STACK_SIZE )
\r
118 /*-----------------------------------------------------------*/
\r
121 * Look for the link to be up every few milliseconds until either xMaxTime time
\r
122 * has passed or a link is found.
\r
124 static BaseType_t prvGMACWaitLS( TickType_t xMaxTime );
\r
127 * A deferred interrupt handler for all MAC/DMA interrupt sources.
\r
129 static void prvEMACHandlerTask( void *pvParameters );
\r
131 /*-----------------------------------------------------------*/
\r
133 /* EMAC data/descriptions. */
\r
134 static xemacpsif_s xEMACpsif;
\r
135 struct xtopology_t xXTopology =
\r
137 .emac_baseaddr = XPAR_PS7_ETHERNET_0_BASEADDR,
\r
138 .emac_type = xemac_type_emacps,
\r
139 .intc_baseaddr = 0x0,
\r
140 .intc_emac_intr = 0x0,
\r
141 .scugic_baseaddr = XPAR_PS7_SCUGIC_0_BASEADDR,
\r
142 .scugic_emac_intr = 0x36,
\r
145 XEmacPs_Config mac_config =
\r
147 .DeviceId = XPAR_PS7_ETHERNET_0_DEVICE_ID, /**< Unique ID of device */
\r
148 .BaseAddress = XPAR_PS7_ETHERNET_0_BASEADDR /**< Physical base address of IPIF registers */
\r
151 extern int phy_detected;
\r
153 /* A copy of PHY register 1: 'PHY_REG_01_BMSR' */
\r
154 static uint32_t ulPHYLinkStatus = 0;
\r
156 #if( ipconfigUSE_LLMNR == 1 )
\r
157 static const uint8_t xLLMNR_MACAddress[] = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0xFC };
\r
160 /* ucMACAddress as it appears in main.c */
\r
161 extern const uint8_t ucMACAddress[ 6 ];
\r
163 /* Holds the handle of the task used as a deferred interrupt processor. The
\r
164 handle is used so direct notifications can be sent to the task for all EMAC/DMA
\r
165 related interrupts. */
\r
166 TaskHandle_t xEMACTaskHandle = NULL;
\r
168 /*-----------------------------------------------------------*/
\r
170 BaseType_t xNetworkInterfaceInitialise( void )
\r
172 uint32_t ulLinkSpeed, ulDMAReg;
\r
173 BaseType_t xStatus, xLinkStatus;
\r
174 XEmacPs *pxEMAC_PS;
\r
175 const TickType_t xWaitLinkDelay = pdMS_TO_TICKS( 7000UL ), xWaitRelinkDelay = pdMS_TO_TICKS( 1000UL );
\r
177 /* Guard against the init function being called more than once. */
\r
178 if( xEMACTaskHandle == NULL )
\r
180 pxEMAC_PS = &( xEMACpsif.emacps );
\r
181 memset( &xEMACpsif, '\0', sizeof( xEMACpsif ) );
\r
183 xStatus = XEmacPs_CfgInitialize( pxEMAC_PS, &mac_config, mac_config.BaseAddress);
\r
184 if( xStatus != XST_SUCCESS )
\r
186 FreeRTOS_printf( ( "xEMACInit: EmacPs Configuration Failed....\n" ) );
\r
189 /* Initialize the mac and set the MAC address. */
\r
190 XEmacPs_SetMacAddress( pxEMAC_PS, ( void * ) ucMACAddress, 1 );
\r
192 #if( ipconfigUSE_LLMNR == 1 )
\r
194 /* Also add LLMNR multicast MAC address. */
\r
195 XEmacPs_SetMacAddress( pxEMAC_PS, ( void * )xLLMNR_MACAddress, 2 );
\r
197 #endif /* ipconfigUSE_LLMNR == 1 */
\r
199 XEmacPs_SetMdioDivisor( pxEMAC_PS, MDC_DIV_224 );
\r
200 ulLinkSpeed = Phy_Setup( pxEMAC_PS );
\r
201 XEmacPs_SetOperatingSpeed( pxEMAC_PS, ulLinkSpeed);
\r
203 /* Setting the operating speed of the MAC needs a delay. */
\r
204 vTaskDelay( pdMS_TO_TICKS( 25UL ) );
\r
206 ulDMAReg = XEmacPs_ReadReg( pxEMAC_PS->Config.BaseAddress, XEMACPS_DMACR_OFFSET);
\r
208 /* DISC_WHEN_NO_AHB: when set, the GEM DMA will automatically discard receive
\r
209 packets from the receiver packet buffer memory when no AHB resource is available. */
\r
210 XEmacPs_WriteReg( pxEMAC_PS->Config.BaseAddress, XEMACPS_DMACR_OFFSET,
\r
211 ulDMAReg | XEMACPS_DMACR_DISC_WHEN_NO_AHB_MASK);
\r
213 setup_isr( &xEMACpsif );
\r
214 init_dma( &xEMACpsif );
\r
215 start_emacps( &xEMACpsif );
\r
217 prvGMACWaitLS( xWaitLinkDelay );
\r
219 /* The deferred interrupt handler task is created at the highest
\r
220 possible priority to ensure the interrupt handler can return directly
\r
221 to it. The task's handle is stored in xEMACTaskHandle so interrupts can
\r
222 notify the task when there is something to process. */
\r
223 xTaskCreate( prvEMACHandlerTask, "EMAC", configEMAC_TASK_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, &xEMACTaskHandle );
\r
227 /* Initialisation was already performed, just wait for the link. */
\r
228 prvGMACWaitLS( xWaitRelinkDelay );
\r
231 /* Only return pdTRUE when the Link Status of the PHY is high, otherwise the
\r
232 DHCP process and all other communication will fail. */
\r
233 xLinkStatus = xGetPhyLinkStatus();
\r
235 return ( xLinkStatus != pdFALSE );
\r
237 /*-----------------------------------------------------------*/
\r
239 BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxBuffer, BaseType_t bReleaseAfterSend )
\r
241 if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
\r
243 iptraceNETWORK_INTERFACE_TRANSMIT();
\r
244 emacps_send_message( &xEMACpsif, pxBuffer, bReleaseAfterSend );
\r
246 else if( bReleaseAfterSend != pdFALSE )
\r
249 vReleaseNetworkBufferAndDescriptor( pxBuffer );
\r
254 /*-----------------------------------------------------------*/
\r
256 static inline unsigned long ulReadMDIO( unsigned ulRegister )
\r
260 XEmacPs_PhyRead( &( xEMACpsif.emacps ), phy_detected, ulRegister, &usValue );
\r
263 /*-----------------------------------------------------------*/
\r
265 static BaseType_t prvGMACWaitLS( TickType_t xMaxTime )
\r
267 TickType_t xStartTime, xEndTime;
\r
268 const TickType_t xShortDelay = pdMS_TO_TICKS( 20UL );
\r
269 BaseType_t xReturn;
\r
271 xStartTime = xTaskGetTickCount();
\r
275 xEndTime = xTaskGetTickCount();
\r
277 if( xEndTime - xStartTime > xMaxTime )
\r
282 ulPHYLinkStatus = ulReadMDIO( PHY_REG_01_BMSR );
\r
284 if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
\r
290 vTaskDelay( xShortDelay );
\r
295 /*-----------------------------------------------------------*/
\r
297 void vNetworkInterfaceAllocateRAMToBuffers( NetworkBufferDescriptor_t pxNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ] )
\r
299 static uint8_t ucNetworkPackets[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS * niBUFFER_1_PACKET_SIZE ] __attribute__ ( ( aligned( 32 ) ) );
\r
300 uint8_t *ucRAMBuffer = ucNetworkPackets;
\r
303 for( ul = 0; ul < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; ul++ )
\r
305 pxNetworkBuffers[ ul ].pucEthernetBuffer = ucRAMBuffer + ipBUFFER_PADDING;
\r
306 *( ( unsigned * ) ucRAMBuffer ) = ( unsigned ) ( &( pxNetworkBuffers[ ul ] ) );
\r
307 ucRAMBuffer += niBUFFER_1_PACKET_SIZE;
\r
310 /*-----------------------------------------------------------*/
\r
312 BaseType_t xGetPhyLinkStatus( void )
\r
314 BaseType_t xReturn;
\r
316 if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) == 0 )
\r
327 /*-----------------------------------------------------------*/
\r
329 static void prvEMACHandlerTask( void *pvParameters )
\r
331 TimeOut_t xPhyTime;
\r
332 TickType_t xPhyRemTime;
\r
333 UBaseType_t uxLastMinBufferCount = 0;
\r
334 UBaseType_t uxCurrentCount;
\r
335 BaseType_t xResult = 0;
\r
337 const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( 100UL );
\r
339 /* Remove compiler warnings about unused parameters. */
\r
340 ( void ) pvParameters;
\r
342 /* A possibility to set some additional task properties like calling
\r
343 portTASK_USES_FLOATING_POINT() */
\r
344 iptraceEMAC_TASK_STARTING();
\r
346 vTaskSetTimeOutState( &xPhyTime );
\r
347 xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );
\r
351 uxCurrentCount = uxGetMinimumFreeNetworkBuffers();
\r
352 if( uxLastMinBufferCount != uxCurrentCount )
\r
354 /* The logging produced below may be helpful
\r
355 while tuning +TCP: see how many buffers are in use. */
\r
356 uxLastMinBufferCount = uxCurrentCount;
\r
357 FreeRTOS_printf( ( "Network buffers: %lu lowest %lu\n",
\r
358 uxGetNumberOfFreeNetworkBuffers(), uxCurrentCount ) );
\r
361 #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
\r
363 static UBaseType_t uxLastMinQueueSpace = 0;
\r
365 uxCurrentCount = uxGetMinimumIPQueueSpace();
\r
366 if( uxLastMinQueueSpace != uxCurrentCount )
\r
368 /* The logging produced below may be helpful
\r
369 while tuning +TCP: see how many buffers are in use. */
\r
370 uxLastMinQueueSpace = uxCurrentCount;
\r
371 FreeRTOS_printf( ( "Queue space: lowest %lu\n", uxCurrentCount ) );
\r
374 #endif /* ipconfigCHECK_IP_QUEUE_SPACE */
\r
376 if( ( xEMACpsif.isr_events & EMAC_IF_ALL_EVENT ) == 0 )
\r
378 /* No events to process now, wait for the next. */
\r
379 ulTaskNotifyTake( pdFALSE, ulMaxBlockTime );
\r
382 if( ( xEMACpsif.isr_events & EMAC_IF_RX_EVENT ) != 0 )
\r
384 xEMACpsif.isr_events &= ~EMAC_IF_RX_EVENT;
\r
385 xResult = emacps_check_rx( &xEMACpsif );
\r
388 if( ( xEMACpsif.isr_events & EMAC_IF_TX_EVENT ) != 0 )
\r
390 xEMACpsif.isr_events &= ~EMAC_IF_TX_EVENT;
\r
391 emacps_check_tx( &xEMACpsif );
\r
394 if( ( xEMACpsif.isr_events & EMAC_IF_ERR_EVENT ) != 0 )
\r
396 xEMACpsif.isr_events &= ~EMAC_IF_ERR_EVENT;
\r
397 emacps_check_errors( &xEMACpsif );
\r
402 /* A packet was received. No need to check for the PHY status now,
\r
403 but set a timer to check it later on. */
\r
404 vTaskSetTimeOutState( &xPhyTime );
\r
405 xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );
\r
408 else if( xTaskCheckForTimeOut( &xPhyTime, &xPhyRemTime ) != pdFALSE )
\r
410 xStatus = ulReadMDIO( PHY_REG_01_BMSR );
\r
412 if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != ( xStatus & BMSR_LINK_STATUS ) )
\r
414 ulPHYLinkStatus = xStatus;
\r
415 FreeRTOS_printf( ( "prvEMACHandlerTask: PHY LS now %d\n", ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 ) );
\r
418 vTaskSetTimeOutState( &xPhyTime );
\r
419 if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
\r
421 xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );
\r
425 xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );
\r
430 /*-----------------------------------------------------------*/
\r