1 /*
2 * FreeRTOS+TCP <DEVELOPMENT BRANCH>
3 * Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
4 *
5 * SPDX-License-Identifier: MIT
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy of
8 * this software and associated documentation files (the "Software"), to deal in
9 * the Software without restriction, including without limitation the rights to
10 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11 * the Software, and to permit persons to whom the Software is furnished to do so,
12 * subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in all
15 * copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 *
24 * http://aws.amazon.com/freertos
25 * http://www.FreeRTOS.org
26 */
27
28 /* Standard includes. */
29 #include <stdint.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32
33 /* FreeRTOS includes. */
34 #include "FreeRTOS.h"
35 #include "task.h"
36 #include "queue.h"
37 #include "semphr.h"
38
39 /* FreeRTOS+TCP includes. */
40 #include "FreeRTOS_IP.h"
41 #include "FreeRTOS_Sockets.h"
42 #include "FreeRTOS_IP_Private.h"
43 #include "FreeRTOS_ARP.h"
44 #include "NetworkBufferManagement.h"
45 #include "NetworkInterface.h"
46 #include "FreeRTOS_DHCP.h"
47 #include "FreeRTOS_DNS.h"
48 #include "FreeRTOS_Routing.h"
49
50 /* Xilinx library files. */
51 #include <xemacps.h>
52 #include "Zynq/x_topology.h"
53 #include "Zynq/x_emacpsif.h"
54 #include "Zynq/x_emacpsif_hw.h"
55
56 /* Provided memory configured as uncached. */
57 #include "uncached_memory.h"
58
59 #ifndef niEMAC_HANDLER_TASK_PRIORITY
60 /* Define the priority of the task prvEMACHandlerTask(). */
61 #define niEMAC_HANDLER_TASK_PRIORITY configMAX_PRIORITIES - 1
62 #endif
63
64 #define niBMSR_LINK_STATUS 0x0004uL
65
66 #if defined( PHY_LS_HIGH_CHECK_TIME_MS ) || defined( PHY_LS_LOW_CHECK_TIME_MS )
67 #error please use the new defines with 'ipconfig' prefix
68 #endif
69
70 #ifndef ipconfigPHY_LS_HIGH_CHECK_TIME_MS
71
72 /* Check if the LinkStatus in the PHY is still high after 15 seconds of not
73 * receiving packets. */
74 #define ipconfigPHY_LS_HIGH_CHECK_TIME_MS 15000U
75 #endif
76
77 #ifndef ipconfigPHY_LS_LOW_CHECK_TIME_MS
78 /* Check if the LinkStatus in the PHY is still low every second. */
79 #define ipconfigPHY_LS_LOW_CHECK_TIME_MS 1000U
80 #endif
81
82
83 /* The size of each buffer when BufferAllocation_1 is used:
84 * http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Ethernet_Buffer_Management.html */
85 #define niBUFFER_1_PACKET_SIZE 1536
86
87 /* Naming and numbering of PHY registers. */
88 #define PHY_REG_01_BMSR 0x01 /* Basic mode status register */
89
90 #ifndef iptraceEMAC_TASK_STARTING
91 #define iptraceEMAC_TASK_STARTING() do {} while( ipFALSE_BOOL )
92 #endif
93
94 /* Default the size of the stack used by the EMAC deferred handler task to 8 times
95 * the size of the stack used by the idle task - but allow this to be overridden in
96 * FreeRTOSConfig.h as configMINIMAL_STACK_SIZE is a user definable constant. */
97 #ifndef configEMAC_TASK_STACK_SIZE
98 #define configEMAC_TASK_STACK_SIZE ( 8 * configMINIMAL_STACK_SIZE )
99 #endif
100
101 #if ( ipconfigNIC_LINKSPEED100 != 1 )
102
103 /* When the PHY is forces to work with a speed of 100 Mbps
104 * many outgoing packets seem to get dropped.
105 */
106 #if ( ipconfigPORT_SUPPRESS_WARNING == 0 )
107 #warning ipconfigNIC_LINKSPEED100 is btoken. Are you sure?
108 #endif
109 #endif
110
111 static NetworkInterface_t * pxMyInterfaces[ XPAR_XEMACPS_NUM_INSTANCES ];
112
113 #if ( ipconfigZERO_COPY_RX_DRIVER == 0 || ipconfigZERO_COPY_TX_DRIVER == 0 )
114 #error Please define both 'ipconfigZERO_COPY_RX_DRIVER' and 'ipconfigZERO_COPY_TX_DRIVER' as 1
115 #endif
116
117 #if ( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM == 0 || ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 )
118 #if ( ipconfigPORT_SUPPRESS_WARNING == 0 )
119 #warning Please define both 'ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM' and 'ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM' as 1
120 #endif
121 #endif
122
123 #ifndef nicUSE_UNCACHED_MEMORY
124 #define nicUSE_UNCACHED_MEMORY 1
125 #endif
126
127 /*-----------------------------------------------------------*/
128
129 /*
130 * Look for the link to be up every few milliseconds until either xMaxTime time
131 * has passed or a link is found.
132 */
133 static BaseType_t prvGMACWaitLS( BaseType_t xEMACIndex,
134 TickType_t xMaxTime );
135
136 /*
137 * A deferred interrupt handler for all MAC/DMA interrupt sources.
138 */
139 static void prvEMACHandlerTask( void * pvParameters );
140
141 /* FreeRTOS+TCP/multi :
142 * Each network device has 3 access functions:
143 * - initialise the device
144 * - output a network packet
145 * - return the PHY link-status (LS)
146 * They can be defined as static because their addresses will be
147 * stored in struct NetworkInterface_t. */
148
149 static BaseType_t xZynqNetworkInterfaceInitialise( NetworkInterface_t * pxInterface );
150
151 static BaseType_t xZynqNetworkInterfaceOutput( NetworkInterface_t * pxInterface,
152 NetworkBufferDescriptor_t * const pxBuffer,
153 BaseType_t bReleaseAfterSend );
154
155 static BaseType_t xZynqGetPhyLinkStatus( NetworkInterface_t * pxInterface );
156
157 NetworkInterface_t * pxZynq_FillInterfaceDescriptor( BaseType_t xEMACIndex,
158 NetworkInterface_t * pxInterface );
159
160 /*-----------------------------------------------------------*/
161
162 /* EMAC data/descriptions. */
163 static xemacpsif_s xEMACpsifs[ XPAR_XEMACPS_NUM_INSTANCES ];
164
165 struct xtopology_t xXTopologies[ XPAR_XEMACPS_NUM_INSTANCES ] =
166 {
167 [ 0 ] =
168 {
169 .emac_baseaddr = XPAR_PS7_ETHERNET_0_BASEADDR,
170 .emac_type = xemac_type_emacps,
171 .intc_baseaddr = 0x0,
172 .intc_emac_intr = 0x0,
173 .scugic_baseaddr = XPAR_PS7_SCUGIC_0_BASEADDR,
174 .scugic_emac_intr = 0x36,
175 },
176 #if ( XPAR_XEMACPS_NUM_INSTANCES > 1 )
177 [ 1 ] =
178 {
179 .emac_baseaddr = XPAR_PS7_ETHERNET_1_BASEADDR,
180 .emac_type = xemac_type_emacps,
181 .intc_baseaddr = 0x0,
182 .intc_emac_intr = 0x0,
183 .scugic_baseaddr = XPAR_PS7_SCUGIC_0_BASEADDR,
184 .scugic_emac_intr = 0x4D, /* See "7.2.3 Shared Peripheral Interrupts (SPI)" */
185 },
186 #endif
187 };
188
189 XEmacPs_Config mac_configs[ XPAR_XEMACPS_NUM_INSTANCES ] =
190 {
191 [ 0 ] =
192 {
193 .DeviceId = XPAR_PS7_ETHERNET_0_DEVICE_ID, /**< Unique ID of device, used for 'xEMACIndex' */
194 .BaseAddress = XPAR_PS7_ETHERNET_0_BASEADDR /**< Physical base address of IPIF registers */
195 },
196 #if ( XPAR_XEMACPS_NUM_INSTANCES > 1 )
197 [ 1 ] =
198 {
199 .DeviceId = XPAR_PS7_ETHERNET_1_DEVICE_ID, /**< Unique ID of device */
200 .BaseAddress = XPAR_PS7_ETHERNET_1_BASEADDR /**< Physical base address of IPIF registers */
201 },
202 #endif
203 };
204
205 extern int phy_detected[ XPAR_XEMACPS_NUM_INSTANCES ];
206
207 /* A copy of PHY register 1: 'PHY_REG_01_BMSR' */
208 static uint32_t ulPHYLinkStates[ XPAR_XEMACPS_NUM_INSTANCES ];
209
210
211 /* Holds the handle of the task used as a deferred interrupt processor. The
212 * handle is used so direct notifications can be sent to the task for all EMAC/DMA
213 * related interrupts. */
214 TaskHandle_t xEMACTaskHandles[ XPAR_XEMACPS_NUM_INSTANCES ];
215
216 /*-----------------------------------------------------------*/
217
218 /**
219 * @brief Initialise the interface number 'xIndex'
220 * @param xIndex: the index of the interface, between 0
221 * zero and (XPAR_XEMACPS_NUM_INSTANCES-1)
222 * @note Although the function is declared public, it should
223 * not be called directly by an application.
224 */
vInitialiseOnIndex(BaseType_t xIndex)225 void vInitialiseOnIndex( BaseType_t xIndex )
226 {
227 if( ( xIndex >= 0 ) && ( xIndex < XPAR_XEMACPS_NUM_INSTANCES ) )
228 {
229 NetworkInterface_t * pxInterface = pxMyInterfaces[ xIndex ];
230
231 if( pxInterface != NULL )
232 {
233 xZynqNetworkInterfaceInitialise( pxInterface );
234 }
235 }
236 }
237 /*-----------------------------------------------------------*/
238
xZynqNetworkInterfaceInitialise(NetworkInterface_t * pxInterface)239 static BaseType_t xZynqNetworkInterfaceInitialise( NetworkInterface_t * pxInterface )
240 {
241 uint32_t ulLinkSpeed, ulDMAReg;
242 BaseType_t xStatus, xLinkStatus;
243 XEmacPs * pxEMAC_PS;
244 const TickType_t xWaitLinkDelay = pdMS_TO_TICKS( 7000UL ), xWaitRelinkDelay = pdMS_TO_TICKS( 1000UL );
245 NetworkEndPoint_t * pxEndPoint;
246 BaseType_t xEMACIndex = ( BaseType_t ) pxInterface->pvArgument;
247
248 configASSERT( xEMACIndex >= 0 );
249 configASSERT( xEMACIndex < XPAR_XEMACPS_NUM_INSTANCES );
250
251 /* Guard against the init function being called more than once. */
252 if( xEMACTaskHandles[ xEMACIndex ] == NULL )
253 {
254 const char * pcTaskName;
255
256 pxMyInterfaces[ xEMACIndex ] = pxInterface;
257
258 pxEMAC_PS = &( xEMACpsifs[ xEMACIndex ].emacps );
259 memset( &xEMACpsifs[ xEMACIndex ], '\0', sizeof( xEMACpsifs[ xEMACIndex ] ) );
260
261 xStatus = XEmacPs_CfgInitialize( pxEMAC_PS, &( mac_configs[ xEMACIndex ] ), mac_configs[ xEMACIndex ].BaseAddress );
262
263 if( xStatus != XST_SUCCESS )
264 {
265 FreeRTOS_printf( ( "xEMACInit: EmacPs Configuration Failed....\n" ) );
266 }
267
268 pxEndPoint = FreeRTOS_FirstEndPoint( pxInterface );
269 configASSERT( pxEndPoint != NULL );
270
271 /* Initialize the mac and set the MAC address at position 1. */
272 XEmacPs_SetMacAddress( pxEMAC_PS, ( void * ) pxEndPoint->xMACAddress.ucBytes, 1 );
273
274 #if ( ipconfigUSE_LLMNR == 1 )
275 {
276 /* Also add LLMNR multicast MAC address. */
277 #if ( ipconfigUSE_IPv6 == 0 )
278 {
279 XEmacPs_SetHash( pxEMAC_PS, ( void * ) xLLMNR_MacAdress.ucBytes );
280 }
281 #else
282 {
283 NetworkEndPoint_t * pxEndPoint;
284 NetworkInterface_t * pxInterface = pxMyInterfaces[ xEMACIndex ];
285
286 for( pxEndPoint = FreeRTOS_FirstEndPoint( pxInterface );
287 pxEndPoint != NULL;
288 pxEndPoint = FreeRTOS_NextEndPoint( pxInterface, pxEndPoint ) )
289 {
290 if( pxEndPoint->bits.bIPv6 != pdFALSE_UNSIGNED )
291 {
292 unsigned char ucMACAddress[ 6 ] = { 0x33, 0x33, 0xff, 0, 0, 0 };
293 ucMACAddress[ 3 ] = pxEndPoint->ipv6_settings.xIPAddress.ucBytes[ 13 ];
294 ucMACAddress[ 4 ] = pxEndPoint->ipv6_settings.xIPAddress.ucBytes[ 14 ];
295 ucMACAddress[ 5 ] = pxEndPoint->ipv6_settings.xIPAddress.ucBytes[ 15 ];
296 XEmacPs_SetHash( pxEMAC_PS, ( void * ) ucMACAddress );
297 }
298 }
299
300 XEmacPs_SetHash( pxEMAC_PS, ( void * ) xLLMNR_MacAdressIPv6.ucBytes );
301 }
302 #endif /* if ( ipconfigUSE_IPv6 == 0 ) */
303 }
304 #endif /* ipconfigUSE_LLMNR == 1 */
305
306 #if ( ( ipconfigUSE_MDNS == 1 ) && ( ipconfigUSE_IPv6 != 0 ) )
307 XEmacPs_SetHash( pxEMAC_PS, ( void * ) xMDNS_MacAdress.ucBytes );
308 XEmacPs_SetHash( pxEMAC_PS, ( void * ) xMDNS_MACAdressIPv6.ucBytes );
309 #endif
310
311 pxEndPoint = FreeRTOS_NextEndPoint( pxInterface, pxEndPoint );
312
313 if( pxEndPoint != NULL )
314 {
315 /* If there is a second end-point, store the MAC
316 * address at position 4.*/
317 XEmacPs_SetMacAddress( pxEMAC_PS, ( void * ) pxEndPoint->xMACAddress.ucBytes, 4 );
318 }
319
320 /* MDIO goes via ETH0 only */
321 XEmacPs_SetMdioDivisor( pxEMAC_PS, MDC_DIV_224 );
322 ulLinkSpeed = Phy_Setup( pxEMAC_PS );
323 XEmacPs_SetOperatingSpeed( pxEMAC_PS, ulLinkSpeed );
324
325 /* Setting the operating speed of the MAC needs a delay. */
326 vTaskDelay( pdMS_TO_TICKS( 25UL ) );
327
328 ulDMAReg = XEmacPs_ReadReg( pxEMAC_PS->Config.BaseAddress, XEMACPS_DMACR_OFFSET );
329
330 {
331 uint32_t ulValue = XEmacPs_ReadReg( pxEMAC_PS->Config.BaseAddress, XEMACPS_NWCFG_OFFSET );
332 /* Allow the use of hashed MAC addresses. */
333 ulValue |= XEMACPS_NWCFG_MCASTHASHEN_MASK;
334 /* As 'MCASTHASHEN' doesn't seem to work, use the promiscuous mode so that IPv6 multicast packets are received. */
335 /* Allow promiscuous mode. */
336 ulValue |= XEMACPS_NWCFG_COPYALLEN_MASK;
337 XEmacPs_WriteReg( pxEMAC_PS->Config.BaseAddress, XEMACPS_NWCFG_OFFSET, ulValue );
338 }
339
340 /* DISC_WHEN_NO_AHB: when set, the GEM DMA will automatically discard receive
341 * packets from the receiver packet buffer memory when no AHB resource is available. */
342 XEmacPs_WriteReg( pxEMAC_PS->Config.BaseAddress, XEMACPS_DMACR_OFFSET,
343 ulDMAReg | XEMACPS_DMACR_DISC_WHEN_NO_AHB_MASK );
344
345 setup_isr( &( xEMACpsifs[ xEMACIndex ] ) );
346 init_dma( &( xEMACpsifs[ xEMACIndex ] ) );
347 start_emacps( &( xEMACpsifs[ xEMACIndex ] ) );
348
349 prvGMACWaitLS( xEMACIndex, xWaitLinkDelay );
350
351 /* The deferred interrupt handler task is created at the highest
352 * possible priority to ensure the interrupt handler can return directly
353 * to it. The task's handle is stored in xEMACTaskHandles[] so interrupts can
354 * notify the task when there is something to process. */
355 if( xEMACIndex == 0 )
356 {
357 pcTaskName = "GEM0";
358 }
359 else
360 {
361 pcTaskName = "GEM1";
362 }
363
364 xTaskCreate( prvEMACHandlerTask, pcTaskName, configEMAC_TASK_STACK_SIZE, ( void * ) xEMACIndex, niEMAC_HANDLER_TASK_PRIORITY, &( xEMACTaskHandles[ xEMACIndex ] ) );
365 }
366 else
367 {
368 /* Initialisation was already performed, just wait for the link. */
369 prvGMACWaitLS( xEMACIndex, xWaitRelinkDelay );
370 }
371
372 /* Only return pdTRUE when the Link Status of the PHY is high, otherwise the
373 * DHCP process and all other communication will fail. */
374 xLinkStatus = xZynqGetPhyLinkStatus( pxInterface );
375
376 /* return ( xLinkStatus != pdFALSE ); */
377 return pdTRUE; /* Workaround because network buffers are not freed when xZynqNetworkInterfaceInitialise() did not complete */
378 }
379 /*-----------------------------------------------------------*/
380
xZynqNetworkInterfaceOutput(NetworkInterface_t * pxInterface,NetworkBufferDescriptor_t * const pxBuffer,BaseType_t bReleaseAfterSend)381 static BaseType_t xZynqNetworkInterfaceOutput( NetworkInterface_t * pxInterface,
382 NetworkBufferDescriptor_t * const pxBuffer,
383 BaseType_t bReleaseAfterSend )
384 {
385 BaseType_t xEMACIndex = ( BaseType_t ) pxInterface->pvArgument;
386
387 configASSERT( xEMACIndex >= 0 );
388 configASSERT( xEMACIndex < XPAR_XEMACPS_NUM_INSTANCES );
389
390 #if ( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM != 0 )
391 {
392 ProtocolPacket_t * pxPacket;
393
394 /* If the peripheral must calculate the checksum, it wants
395 * the protocol checksum to have a value of zero. */
396 pxPacket = ( ProtocolPacket_t * ) ( pxBuffer->pucEthernetBuffer );
397
398 #if ( ipconfigUSE_IPv6 != 0 )
399 ICMPPacket_IPv6_t * pxICMPPacket = ( ICMPPacket_IPv6_t * ) pxBuffer->pucEthernetBuffer;
400
401 if( ( pxPacket->xICMPPacket.xEthernetHeader.usFrameType == ipIPv6_FRAME_TYPE ) &&
402 ( pxICMPPacket->xIPHeader.ucNextHeader == ipPROTOCOL_ICMP_IPv6 ) )
403 {
404 /* The EMAC will calculate the checksum of the IP-header.
405 * It can only calculate protocol checksums of UDP and TCP,
406 * so for ICMP and other protocols it must be done manually. */
407 usGenerateProtocolChecksum( pxBuffer->pucEthernetBuffer, pxBuffer->xDataLength, pdTRUE );
408 }
409 #endif
410
411 if( ( pxPacket->xICMPPacket.xEthernetHeader.usFrameType == ipIPv4_FRAME_TYPE ) &&
412 ( pxPacket->xICMPPacket.xIPHeader.ucProtocol == ipPROTOCOL_ICMP ) )
413 {
414 /* The EMAC will calculate the checksum of the IP-header.
415 * It can only calculate protocol checksums of UDP and TCP,
416 * so for ICMP and other protocols it must be done manually. */
417 usGenerateProtocolChecksum( pxBuffer->pucEthernetBuffer, pxBuffer->xDataLength, pdTRUE );
418 }
419 }
420 #endif /* ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM */
421
422 if( ( ulPHYLinkStates[ xEMACIndex ] & niBMSR_LINK_STATUS ) != 0UL )
423 {
424 iptraceNETWORK_INTERFACE_TRANSMIT();
425
426 /* emacps_send_message() will take ownership of pxBuffer, and
427 * make sure it will get release when bReleaseAfterSend is pdTRUE. */
428 emacps_send_message( &( xEMACpsifs[ xEMACIndex ] ), pxBuffer, bReleaseAfterSend );
429 }
430 else if( bReleaseAfterSend != pdFALSE )
431 {
432 /* No link. */
433 vReleaseNetworkBufferAndDescriptor( pxBuffer );
434 }
435
436 return pdTRUE;
437 }
438 /*-----------------------------------------------------------*/
439
ulReadMDIO(BaseType_t xEMACIndex,unsigned ulRegister)440 static inline unsigned long ulReadMDIO( BaseType_t xEMACIndex,
441 unsigned ulRegister )
442 {
443 uint16_t usValue;
444
445 /* Always ETH0 because both PHYs are connected to ETH0 MDIO */
446 XEmacPs_PhyRead( &( xEMACpsifs[ 0 ].emacps ), phy_detected[ xEMACIndex ], ulRegister, &usValue );
447 return usValue;
448 }
449 /*-----------------------------------------------------------*/
450
prvGMACWaitLS(BaseType_t xEMACIndex,TickType_t xMaxTime)451 static BaseType_t prvGMACWaitLS( BaseType_t xEMACIndex,
452 TickType_t xMaxTime )
453 {
454 TickType_t xStartTime, xEndTime;
455 const TickType_t xShortDelay = pdMS_TO_TICKS( 20UL );
456 BaseType_t xReturn;
457
458 xStartTime = xTaskGetTickCount();
459
460 for( ; ; )
461 {
462 xEndTime = xTaskGetTickCount();
463
464 if( xEndTime - xStartTime > xMaxTime )
465 {
466 xReturn = pdFALSE;
467 break;
468 }
469
470 ulPHYLinkStates[ xEMACIndex ] = ulReadMDIO( xEMACIndex, PHY_REG_01_BMSR );
471
472 if( ( ulPHYLinkStates[ xEMACIndex ] & niBMSR_LINK_STATUS ) != 0U )
473 {
474 xReturn = pdTRUE;
475 break;
476 }
477
478 vTaskDelay( xShortDelay );
479 }
480
481 return xReturn;
482 }
483 /*-----------------------------------------------------------*/
484
485 #if ( nicUSE_UNCACHED_MEMORY == 0 )
vNetworkInterfaceAllocateRAMToBuffers(NetworkBufferDescriptor_t pxNetworkBuffers[ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS])486 void vNetworkInterfaceAllocateRAMToBuffers( NetworkBufferDescriptor_t pxNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ] )
487 {
488 static uint8_t ucNetworkPackets[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS * niBUFFER_1_PACKET_SIZE ] __attribute__( ( aligned( 32 ) ) );
489 uint8_t * ucRAMBuffer = ucNetworkPackets;
490 uint32_t ul;
491
492 for( ul = 0; ul < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; ul++ )
493 {
494 pxNetworkBuffers[ ul ].pucEthernetBuffer = ucRAMBuffer + ipBUFFER_PADDING;
495 *( ( unsigned * ) ucRAMBuffer ) = ( unsigned ) ( &( pxNetworkBuffers[ ul ] ) );
496 ucRAMBuffer += niBUFFER_1_PACKET_SIZE;
497 }
498 }
499 #else /* if ( nicUSE_UNCACHED_MEMORY == 0 ) */
vNetworkInterfaceAllocateRAMToBuffers(NetworkBufferDescriptor_t pxNetworkBuffers[ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS])500 void vNetworkInterfaceAllocateRAMToBuffers( NetworkBufferDescriptor_t pxNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ] )
501 {
502 static uint8_t * pucNetworkPackets = NULL;
503
504 if( pucNetworkPackets == NULL )
505 {
506 pucNetworkPackets = pucGetUncachedMemory( ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS * niBUFFER_1_PACKET_SIZE );
507
508 if( pucNetworkPackets != NULL )
509 {
510 uint8_t * ucRAMBuffer = pucNetworkPackets;
511 uint32_t ul;
512
513 for( ul = 0; ul < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; ul++ )
514 {
515 pxNetworkBuffers[ ul ].pucEthernetBuffer = ucRAMBuffer + ipBUFFER_PADDING;
516 *( ( unsigned * ) ucRAMBuffer ) = ( unsigned ) ( &( pxNetworkBuffers[ ul ] ) );
517 ucRAMBuffer += niBUFFER_1_PACKET_SIZE;
518 }
519 }
520 }
521 }
522 #endif /* ( nicUSE_UNCACHED_MEMORY == 0 ) */
523 /*-----------------------------------------------------------*/
524
xZynqGetPhyLinkStatus(NetworkInterface_t * pxInterface)525 static BaseType_t xZynqGetPhyLinkStatus( NetworkInterface_t * pxInterface )
526 {
527 BaseType_t xReturn;
528 BaseType_t xEMACIndex = ( BaseType_t ) pxInterface->pvArgument;
529
530 if( ( ulPHYLinkStates[ xEMACIndex ] & niBMSR_LINK_STATUS ) == 0U )
531 {
532 xReturn = pdFALSE;
533 }
534 else
535 {
536 xReturn = pdTRUE;
537 }
538
539 return xReturn;
540 }
541 /*-----------------------------------------------------------*/
542
543 #if defined( ipconfigIPv4_BACKWARD_COMPATIBLE ) && ( ipconfigIPv4_BACKWARD_COMPATIBLE == 1 )
544
545 /* Do not call the following function directly. It is there for downward compatibility.
546 * The function FreeRTOS_IPInit() will call it to initialice the interface and end-point
547 * objects. See the description in FreeRTOS_Routing.h. */
pxFillInterfaceDescriptor(BaseType_t xEMACIndex,NetworkInterface_t * pxInterface)548 NetworkInterface_t * pxFillInterfaceDescriptor( BaseType_t xEMACIndex,
549 NetworkInterface_t * pxInterface )
550 {
551 pxZynq_FillInterfaceDescriptor( xEMACIndex, pxInterface );
552 }
553
554 #endif
555 /*-----------------------------------------------------------*/
556
pxZynq_FillInterfaceDescriptor(BaseType_t xEMACIndex,NetworkInterface_t * pxInterface)557 NetworkInterface_t * pxZynq_FillInterfaceDescriptor( BaseType_t xEMACIndex,
558 NetworkInterface_t * pxInterface )
559 {
560 static char pcNames[ XPAR_XEMACPS_NUM_INSTANCES ][ 8 ];
561
562 configASSERT( xEMACIndex >= 0 );
563 configASSERT( xEMACIndex < XPAR_XEMACPS_NUM_INSTANCES );
564
565 /* This function pxZynq_FillInterfaceDescriptor() adds a network-interface.
566 * Make sure that the object pointed to by 'pxInterface'
567 * is declared static or global, and that it will remain to exist. */
568
569 snprintf( pcNames[ xEMACIndex ], sizeof( pcNames[ xEMACIndex ] ), "eth%ld", xEMACIndex );
570
571 memset( pxInterface, '\0', sizeof( *pxInterface ) );
572 pxInterface->pcName = pcNames[ xEMACIndex ]; /* Just for logging, debugging. */
573 pxInterface->pvArgument = ( void * ) xEMACIndex; /* Has only meaning for the driver functions. */
574 pxInterface->pfInitialise = xZynqNetworkInterfaceInitialise;
575 pxInterface->pfOutput = xZynqNetworkInterfaceOutput;
576 pxInterface->pfGetPhyLinkStatus = xZynqGetPhyLinkStatus;
577
578 FreeRTOS_AddNetworkInterface( pxInterface );
579
580 return pxInterface;
581 }
582 /*-----------------------------------------------------------*/
583
prvEMACHandlerTask(void * pvParameters)584 static void prvEMACHandlerTask( void * pvParameters )
585 {
586 TimeOut_t xPhyTime;
587 TickType_t xPhyRemTime;
588 BaseType_t xResult = 0;
589 uint32_t xStatus;
590 const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( 100UL );
591 BaseType_t xEMACIndex = ( BaseType_t ) pvParameters;
592 xemacpsif_s * pxEMAC_PS;
593
594 configASSERT( xEMACIndex >= 0 );
595 configASSERT( xEMACIndex < XPAR_XEMACPS_NUM_INSTANCES );
596
597 pxEMAC_PS = &( xEMACpsifs[ xEMACIndex ] );
598
599 /* Remove compiler warnings about unused parameters. */
600 ( void ) pvParameters;
601
602 /* A possibility to set some additional task properties like calling
603 * portTASK_USES_FLOATING_POINT() */
604 iptraceEMAC_TASK_STARTING();
605
606 vTaskSetTimeOutState( &xPhyTime );
607 xPhyRemTime = pdMS_TO_TICKS( ipconfigPHY_LS_LOW_CHECK_TIME_MS );
608 FreeRTOS_printf( ( "prvEMACHandlerTask[ %ld ] started running\n", xEMACIndex ) );
609
610 for( ; ; )
611 {
612 #if ( ipconfigHAS_PRINTF != 0 )
613 {
614 /* Call a function that monitors resources: the amount of free network
615 * buffers and the amount of free space on the heap. See FreeRTOS_IP.c
616 * for more detailed comments. */
617 vPrintResourceStats();
618 }
619 #endif /* ( ipconfigHAS_PRINTF != 0 ) */
620
621 if( ( pxEMAC_PS->isr_events & EMAC_IF_ALL_EVENT ) == 0 )
622 {
623 /* No events to process now, wait for the next. */
624 ulTaskNotifyTake( pdFALSE, ulMaxBlockTime );
625 }
626
627 if( ( pxEMAC_PS->isr_events & EMAC_IF_RX_EVENT ) != 0 )
628 {
629 pxEMAC_PS->isr_events &= ~EMAC_IF_RX_EVENT;
630 xResult = emacps_check_rx( pxEMAC_PS, pxMyInterfaces[ xEMACIndex ] );
631 }
632
633 if( ( pxEMAC_PS->isr_events & EMAC_IF_TX_EVENT ) != 0 )
634 {
635 pxEMAC_PS->isr_events &= ~EMAC_IF_TX_EVENT;
636 emacps_check_tx( pxEMAC_PS );
637 }
638
639 if( ( pxEMAC_PS->isr_events & EMAC_IF_ERR_EVENT ) != 0 )
640 {
641 pxEMAC_PS->isr_events &= ~EMAC_IF_ERR_EVENT;
642 emacps_check_errors( pxEMAC_PS );
643 }
644
645 if( xResult > 0 )
646 {
647 /* A packet was received. No need to check for the PHY status now,
648 * but set a timer to check it later on. */
649 vTaskSetTimeOutState( &xPhyTime );
650 xPhyRemTime = pdMS_TO_TICKS( ipconfigPHY_LS_HIGH_CHECK_TIME_MS );
651 xResult = 0;
652 ulPHYLinkStates[ xEMACIndex ] |= niBMSR_LINK_STATUS;
653 }
654 else if( xTaskCheckForTimeOut( &xPhyTime, &xPhyRemTime ) != pdFALSE )
655 {
656 xStatus = ulReadMDIO( xEMACIndex, PHY_REG_01_BMSR );
657
658 if( ( ulPHYLinkStates[ xEMACIndex ] & niBMSR_LINK_STATUS ) != ( xStatus & niBMSR_LINK_STATUS ) )
659 {
660 ulPHYLinkStates[ xEMACIndex ] = xStatus;
661 FreeRTOS_printf( ( "prvEMACHandlerTask: PHY LS now %d\n", ( ulPHYLinkStates[ xEMACIndex ] & niBMSR_LINK_STATUS ) != 0 ) );
662 }
663
664 vTaskSetTimeOutState( &xPhyTime );
665
666 if( ( ulPHYLinkStates[ xEMACIndex ] & niBMSR_LINK_STATUS ) != 0 )
667 {
668 xPhyRemTime = pdMS_TO_TICKS( ipconfigPHY_LS_HIGH_CHECK_TIME_MS );
669 }
670 else
671 {
672 xPhyRemTime = pdMS_TO_TICKS( ipconfigPHY_LS_LOW_CHECK_TIME_MS );
673 }
674 }
675 }
676 }
677 /*-----------------------------------------------------------*/
678