]> begriffs open source - cmsis-freertos/blob - Demo/Common/ethernet/lwip-1.4.0/ports/MicroBlaze-Ethernet-Lite/ethernetif.c
Updated pack to FreeRTOS 10.4.6
[cmsis-freertos] / Demo / Common / ethernet / lwip-1.4.0 / ports / MicroBlaze-Ethernet-Lite / ethernetif.c
1 /*
2  * FreeRTOS V202111.00
3  * Copyright (C) 2020 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of
6  * this software and associated documentation files (the "Software"), to deal in
7  * the Software without restriction, including without limitation the rights to
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9  * the Software, and to permit persons to whom the Software is furnished to do so,
10  * subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in all
13  * copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  *
22  * https://www.FreeRTOS.org
23  * https://github.com/FreeRTOS
24  *
25  */
26
27 /* FreeRTOS includes. */
28 #include "FreeRTOS.h"
29 #include "task.h"
30 #include "queue.h"
31
32 /* BSP includes. */
33 #include "xemaclite.h"
34 #include "xintc_l.h"
35
36 /* lwIP includes. */
37 #include "lwip/opt.h"
38 #include "lwip/def.h"
39 #include "lwip/mem.h"
40 #include "lwip/pbuf.h"
41 #include "lwip/sys.h"
42 #include <lwip/stats.h>
43 #include <lwip/snmp.h>
44 #include "netif/etharp.h"
45
46 /* Define those to better describe your network interface. */
47 #define IFNAME0 'e'
48 #define IFNAME1 'l'
49
50 /* When a packet is ready to be sent, if it cannot be sent immediately then
51  * the task performing the transmit will block for netifTX_BUFFER_FREE_WAIT
52  * milliseconds.  It will do this a maximum of netifMAX_TX_ATTEMPTS before
53  * giving up.
54  */
55 #define netifTX_BUFFER_FREE_WAIT        ( ( TickType_t ) 2UL / portTICK_PERIOD_MS )
56 #define netifMAX_TX_ATTEMPTS            ( 5 )
57
58 #define netifMAX_MTU 1500
59
60 struct xEthernetIf
61 {
62         struct eth_addr *ethaddr;
63         /* Add whatever per-interface state that is needed here. */
64 };
65
66 /*
67  * Copy the received data into a pbuf.
68  */
69 static struct pbuf *prvLowLevelInput( const unsigned char * const pucInputData, unsigned short usDataLength );
70
71 /*
72  * Send data from a pbuf to the hardware.
73  */
74 static err_t prvLowLevelOutput( struct netif *pxNetIf, struct pbuf *p );
75
76 /*
77  * Perform any hardware and/or driver initialisation necessary.
78  */
79 static void prvLowLevelInit( struct netif *pxNetIf );
80
81 /*
82  * Functions that get registered as the Rx and Tx interrupt handers
83  * respectively.
84  */
85 static void prvRxHandler( void *pvNetIf );
86 static void prvTxHandler( void *pvUnused );
87
88
89 /*-----------------------------------------------------------*/
90
91 /* The instance of the xEmacLite IP being used in this driver. */
92 static XEmacLite xEMACInstance;
93
94 /*-----------------------------------------------------------*/
95
96 /**
97  * In this function, the hardware should be initialized.
98  * Called from ethernetif_init().
99  *
100  * @param pxNetIf the already initialized lwip network interface structure
101  *              for this etherpxNetIf
102  */
103 static void prvLowLevelInit( struct netif *pxNetIf )
104 {
105 portBASE_TYPE xStatus;
106 extern void vInitialisePHY( XEmacLite *xemaclitep );
107 unsigned portBASE_TYPE uxOriginalPriority;
108
109         /* Hardware initialisation can take some time, so temporarily lower the
110         task priority to ensure other functionality is not adversely effected.
111         The priority will get raised again before this function exits. */
112         uxOriginalPriority = uxTaskPriorityGet( NULL );
113         vTaskPrioritySet( NULL, tskIDLE_PRIORITY );
114
115         /* set MAC hardware address length */
116         pxNetIf->hwaddr_len = ETHARP_HWADDR_LEN;
117
118         /* set MAC hardware address */
119         pxNetIf->hwaddr[ 0 ] = configMAC_ADDR0;
120         pxNetIf->hwaddr[ 1 ] = configMAC_ADDR1;
121         pxNetIf->hwaddr[ 2 ] = configMAC_ADDR2;
122         pxNetIf->hwaddr[ 3 ] = configMAC_ADDR3;
123         pxNetIf->hwaddr[ 4 ] = configMAC_ADDR4;
124         pxNetIf->hwaddr[ 5 ] = configMAC_ADDR5;
125
126         /* device capabilities */
127         pxNetIf->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;
128
129         /* maximum transfer unit */
130         pxNetIf->mtu = netifMAX_MTU;
131
132         /* Broadcast capability */
133         pxNetIf->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;
134
135         /* Initialize the mac */
136         xStatus = XEmacLite_Initialize( &xEMACInstance, XPAR_EMACLITE_0_DEVICE_ID );
137
138         if( xStatus == XST_SUCCESS )
139         {
140                 /* Set mac address */
141                 XEmacLite_SetMacAddress( &xEMACInstance, ( Xuint8* )( pxNetIf->hwaddr ) );
142
143                 /* Flush any frames already received */
144                 XEmacLite_FlushReceive( &xEMACInstance );
145
146                 /* Set Rx, Tx interrupt handlers */
147                 XEmacLite_SetRecvHandler( &xEMACInstance, ( void * ) pxNetIf, prvRxHandler );
148                 XEmacLite_SetSendHandler( &xEMACInstance, NULL, prvTxHandler );
149
150                 /* Enable Rx, Tx interrupts */
151                 XEmacLite_EnableInterrupts( &xEMACInstance );
152
153                 /* Install the standard Xilinx library interrupt handler itself.
154                 *NOTE* The xPortInstallInterruptHandler() API function must be used
155                 for     this purpose. */
156                 xStatus = xPortInstallInterruptHandler( XPAR_INTC_0_EMACLITE_0_VEC_ID, ( XInterruptHandler ) XEmacLite_InterruptHandler, &xEMACInstance );
157
158                 vInitialisePHY( &xEMACInstance );
159
160                 /* Enable the interrupt in the interrupt controller.
161                 *NOTE* The vPortEnableInterrupt() API function must be used for this
162                 purpose. */
163                 vPortEnableInterrupt( XPAR_INTC_0_EMACLITE_0_VEC_ID );
164         }
165
166         /* Reset the task priority back to its original value. */
167         vTaskPrioritySet( NULL, uxOriginalPriority );
168
169         configASSERT( xStatus == pdPASS );
170 }
171
172 /**
173  * This function should do the actual transmission of the packet. The packet is
174  * contained in the pbuf that is passed to the function. This pbuf
175  * might be chained.
176  *
177  * @param pxNetIf the lwip network interface structure for this etherpxNetIf
178  * @param p the MAC packet to send (e.g. IP packet including MAC addresses and type)
179  * @return ERR_OK if the packet could be sent
180  *               an err_t value if the packet couldn't be sent
181  *
182  * @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to
183  *         strange results. You might consider waiting for space in the DMA queue
184  *         to become available since the stack doesn't retry to send a packet
185  *         dropped because of memory failure (except for the TCP timers).
186  */
187
188 static err_t prvLowLevelOutput( struct netif *pxNetIf, struct pbuf *p )
189 {
190
191         /* This is taken from lwIP example code and therefore does not conform
192         to the FreeRTOS coding standard. */
193
194 struct pbuf *q;
195 static unsigned char ucBuffer[ 1520 ] __attribute__((aligned(32)));
196 unsigned char *pucBuffer = ucBuffer;
197 unsigned char *pucChar;
198 struct eth_hdr *pxHeader;
199 u16_t usTotalLength = p->tot_len - ETH_PAD_SIZE;
200 err_t xReturn = ERR_OK;
201 long x;
202
203         ( void ) pxNetIf;
204
205         #if defined(LWIP_DEBUG) && LWIP_NETIF_TX_SINGLE_PBUF
206                 LWIP_ASSERT("p->next == NULL && p->len == p->tot_len", p->next == NULL && p->len == p->tot_len);
207         #endif
208
209         /* Initiate transfer. */
210         if( p->len == p->tot_len ) 
211         {
212                 /* No pbuf chain, don't have to copy -> faster. */
213                 pucBuffer = &( ( unsigned char * ) p->payload )[ ETH_PAD_SIZE ];
214         } 
215         else 
216         {
217                 /* pbuf chain, copy into contiguous ucBuffer. */
218                 if( p->tot_len >= sizeof( ucBuffer ) )
219                 {
220                         LINK_STATS_INC( link.lenerr );
221                         LINK_STATS_INC( link.drop );
222                         snmp_inc_ifoutdiscards( pxNetIf );
223                         xReturn = ERR_BUF;
224                 }
225                 else
226                 {
227                         pucChar = ucBuffer;
228
229                         for( q = p; q != NULL; q = q->next )
230                         {
231                                 /* Send the data from the pbuf to the interface, one pbuf at a
232                                 time. The size of the data in each pbuf is kept in the ->len
233                                 variable. */
234                                 /* send data from(q->payload, q->len); */
235                                 LWIP_DEBUGF( NETIF_DEBUG, ( "NETIF: send pucChar %p q->payload %p q->len %i q->next %p\n", pucChar, q->payload, ( int ) q->len, ( void* ) q->next ) );
236                                 if( q == p )
237                                 {
238                                         memcpy( pucChar, &( ( char * ) q->payload )[ ETH_PAD_SIZE ], q->len - ETH_PAD_SIZE );
239                                         pucChar += q->len - ETH_PAD_SIZE;
240                                 }
241                                 else
242                                 {
243                                         memcpy( pucChar, q->payload, q->len );
244                                         pucChar += q->len;
245                                 }
246                         }
247                 }
248         }
249
250         if( xReturn == ERR_OK )
251         {
252                 for( x = 0; x < netifMAX_TX_ATTEMPTS; x++ )
253                 {
254                         xReturn =  XEmacLite_Send( &xEMACInstance, pucBuffer, ( int ) usTotalLength );
255                         if( xReturn == XST_SUCCESS )
256                         {
257                                 break;
258                         }
259                         else
260                         {
261                                 vTaskDelay( netifTX_BUFFER_FREE_WAIT );
262                         }
263                 }
264
265                 if( xReturn != XST_SUCCESS )
266                 {
267                         LINK_STATS_INC( link.memerr );
268                         LINK_STATS_INC( link.drop );
269                         snmp_inc_ifoutdiscards( pxNetIf );
270                         xReturn = ERR_BUF;
271                 }
272                 else
273                 {
274                         LINK_STATS_INC( link.xmit );
275                         snmp_add_ifoutoctets( pxNetIf, usTotalLength );
276                         pxHeader = ( struct eth_hdr * )p->payload;
277
278                         if( ( pxHeader->dest.addr[ 0 ] & 1 ) != 0 ) 
279                         {
280                                 /* broadcast or multicast packet*/
281                                 snmp_inc_ifoutnucastpkts( pxNetIf );
282                         } 
283                         else 
284                         {
285                                 /* unicast packet */
286                                 snmp_inc_ifoutucastpkts( pxNetIf );
287                         }
288                 }
289         }
290
291         return xReturn;
292 }
293
294 /**
295  * Should allocate a pbuf and transfer the bytes of the incoming
296  * packet from the interface into the pbuf.
297  *
298  * @param pxNetIf the lwip network interface structure for this etherpxNetIf
299  * @return a pbuf filled with the received packet (including MAC header)
300  *               NULL on memory error
301  */
302 static struct pbuf *prvLowLevelInput( const unsigned char * const pucInputData, unsigned short usDataLength )
303 {
304 struct pbuf *p = NULL, *q;
305
306         if( usDataLength > 0U )
307         {
308                 #if ETH_PAD_SIZE
309                         len += ETH_PAD_SIZE; /* allow room for Ethernet padding */
310                 #endif
311
312                 /* We allocate a pbuf chain of pbufs from the pool. */
313                 p = pbuf_alloc( PBUF_RAW, usDataLength, PBUF_POOL );
314   
315                 if( p != NULL ) 
316                 {
317                         #if ETH_PAD_SIZE
318                                 pbuf_header( p, -ETH_PAD_SIZE ); /* drop the padding word */
319                         #endif
320
321                         /* We iterate over the pbuf chain until we have read the entire
322                         * packet into the pbuf. */
323                         usDataLength = 0U;
324                         for( q = p; q != NULL; q = q->next ) 
325                         {
326                                 /* Read enough bytes to fill this pbuf in the chain. The
327                                 * available data in the pbuf is given by the q->len
328                                 * variable.
329                                 * This does not necessarily have to be a memcpy, you can also preallocate
330                                 * pbufs for a DMA-enabled MAC and after receiving truncate it to the
331                                 * actually received size. In this case, ensure the usTotalLength member of the
332                                 * pbuf is the sum of the chained pbuf len members.
333                                 */
334                                 memcpy( q->payload, &( pucInputData[ usDataLength ] ), q->len );
335                                 usDataLength += q->len;
336                         }
337
338                         #if ETH_PAD_SIZE
339                                 pbuf_header( p, ETH_PAD_SIZE ); /* reclaim the padding word */
340                         #endif
341
342                         LINK_STATS_INC(link.recv);
343                 }
344         }
345
346         return p;  
347 }
348
349 /**
350  * Should be called at the beginning of the program to set up the
351  * network interface. It calls the function prvLowLevelInit() to do the
352  * actual setup of the hardware.
353  *
354  * This function should be passed as a parameter to pxNetIf_add().
355  *
356  * @param pxNetIf the lwip network interface structure for this etherpxNetIf
357  * @return ERR_OK if the loopif is initialized
358  *               ERR_MEM if private data couldn't be allocated
359  *               any other err_t on error
360  */
361 err_t ethernetif_init( struct netif *pxNetIf )
362 {
363 err_t xReturn = ERR_OK;
364
365         /* This is taken from lwIP example code and therefore does not conform
366         to the FreeRTOS coding standard. */
367         
368 struct xEthernetIf *pxEthernetIf;
369
370         LWIP_ASSERT( "pxNetIf != NULL", ( pxNetIf != NULL ) );
371         
372         pxEthernetIf = mem_malloc( sizeof( struct xEthernetIf ) );
373         if( pxEthernetIf == NULL ) 
374         {
375                 LWIP_DEBUGF(NETIF_DEBUG, ( "ethernetif_init: out of memory\n" ) );
376                 xReturn = ERR_MEM;
377         }
378         else
379         {
380                 #if LWIP_NETIF_HOSTNAME
381                 {
382                         /* Initialize interface hostname */
383                         pxNetIf->hostname = "lwip";
384                 }
385                 #endif /* LWIP_NETIF_HOSTNAME */
386
387                 pxNetIf->state = pxEthernetIf;
388                 pxNetIf->name[ 0 ] = IFNAME0;
389                 pxNetIf->name[ 1 ] = IFNAME1;
390
391                 /* We directly use etharp_output() here to save a function call.
392                 * You can instead declare your own function an call etharp_output()
393                 * from it if you have to do some checks before sending (e.g. if link
394                 * is available...) */
395                 pxNetIf->output = etharp_output;
396                 pxNetIf->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_IGMP;
397                 pxNetIf->hwaddr_len = ETHARP_HWADDR_LEN;
398                 pxNetIf->mtu = netifMAX_MTU;
399                 pxNetIf->linkoutput = prvLowLevelOutput;
400
401                 pxEthernetIf->ethaddr = ( struct eth_addr * ) &( pxNetIf->hwaddr[ 0 ] );
402
403                 /* initialize the hardware */
404                 prvLowLevelInit( pxNetIf );
405         }
406
407         return xReturn;
408 }
409 /*-----------------------------------------------------------*/
410
411 static void prvRxHandler( void *pvNetIf )
412 {
413         /* This is taken from lwIP example code and therefore does not conform
414         to the FreeRTOS coding standard. */
415
416 struct eth_hdr *pxHeader;
417 struct pbuf *p;
418 unsigned short usInputLength;
419 static unsigned char ucBuffer[ 1520 ] __attribute__((aligned(32)));
420 extern portBASE_TYPE xInsideISR;
421 struct netif *pxNetIf = ( struct netif * ) pvNetIf;
422
423         XIntc_AckIntr( XPAR_ETHERNET_LITE_BASEADDR, XPAR_ETHERNET_LITE_IP2INTC_IRPT_MASK );
424
425         /* Ensure the pbuf handling functions don't attempt to use critical
426         sections. */
427         xInsideISR++;
428
429         usInputLength = ( long ) XEmacLite_Recv( &xEMACInstance, ucBuffer );
430
431         /* move received packet into a new pbuf */
432         p = prvLowLevelInput( ucBuffer, usInputLength );
433
434         /* no packet could be read, silently ignore this */
435         if( p != NULL )
436         {
437                 /* points to packet payload, which starts with an Ethernet header */
438                 pxHeader = p->payload;
439
440                 switch( htons( pxHeader->type ) )
441                 {
442                         /* IP or ARP packet? */
443                         case ETHTYPE_IP:
444                         case ETHTYPE_ARP:
445                                                                 /* full packet send to tcpip_thread to process */
446                                                                 if( pxNetIf->input( p, pxNetIf ) != ERR_OK )
447                                                                 {
448                                                                         LWIP_DEBUGF(NETIF_DEBUG, ( "ethernetif_input: IP input error\n" ) );
449                                                                         pbuf_free(p);
450                                                                         p = NULL;
451                                                                 }
452                                                                 break;
453
454                         default:
455                                                                 pbuf_free( p );
456                                                                 p = NULL;
457                         break;
458                 }
459         }
460
461         xInsideISR--;
462 }
463 /*-----------------------------------------------------------*/
464
465 static void prvTxHandler( void *pvUnused )
466 {
467         ( void ) pvUnused;
468         XIntc_AckIntr( XPAR_ETHERNET_LITE_BASEADDR, XPAR_ETHERNET_LITE_IP2INTC_IRPT_MASK );
469 }
470
471
472
473