]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/CORTEX_Kinetis_K60_Tower_IAR/webserver/EMAC.c
606111bc97574f50cb8ccbb3140f94977c9f77b2
[freertos] / FreeRTOS / Demo / CORTEX_Kinetis_K60_Tower_IAR / webserver / EMAC.c
1 /*\r
2  * FreeRTOS Kernel V10.0.0\r
3  * Copyright (C) 2017 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
4  *\r
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
6  * this software and associated documentation files (the "Software"), to deal in\r
7  * the Software without restriction, including without limitation the rights to\r
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
9  * the Software, and to permit persons to whom the Software is furnished to do so,\r
10  * subject to the following conditions:\r
11  *\r
12  * The above copyright notice and this permission notice shall be included in all\r
13  * copies or substantial portions of the Software. If you wish to use our Amazon\r
14  * FreeRTOS name, please do so in a fair use way that does not cause confusion.\r
15  *\r
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
18  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
19  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
20  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
22  *\r
23  * http://www.FreeRTOS.org\r
24  * http://aws.amazon.com/freertos\r
25  *\r
26  * 1 tab == 4 spaces!\r
27  */\r
28 \r
29 /* Freescale includes. */\r
30 #include "common.h"\r
31 #include "eth_phy.h"\r
32 #include "enet.h"\r
33 #include "mii.h"\r
34 \r
35 /* FreeRTOS includes. */\r
36 #include "FreeRTOS.h"\r
37 #include "task.h"\r
38 #include "queue.h"\r
39 \r
40 /* uIP includes. */\r
41 #include "net/uip.h"\r
42 \r
43 /* The time to wait between attempts to obtain a free buffer. */\r
44 #define emacBUFFER_WAIT_DELAY_ms                ( 3 / portTICK_PERIOD_MS )\r
45 \r
46 /* The number of times emacBUFFER_WAIT_DELAY_ms should be waited before giving\r
47 up on attempting to obtain a free buffer all together. */\r
48 #define emacBUFFER_WAIT_ATTEMPTS                ( 30 )\r
49 \r
50 /* The number of Rx descriptors. */\r
51 #define emacNUM_RX_DESCRIPTORS                  8\r
52 \r
53 /* The number of Tx descriptors.  When using uIP there is not point in having\r
54 more than two. */\r
55 #define emacNUM_TX_BUFFERS                              2\r
56 \r
57 /* The total number of EMAC buffers to allocate. */\r
58 #define emacNUM_BUFFERS                                 ( emacNUM_RX_DESCRIPTORS + emacNUM_TX_BUFFERS )\r
59 \r
60 /* The time to wait for the Tx descriptor to become free. */\r
61 #define emacTX_WAIT_DELAY_ms                    ( 10 / portTICK_PERIOD_MS )\r
62 \r
63 /* The total number of times to wait emacTX_WAIT_DELAY_ms for the Tx descriptor to\r
64 become free. */\r
65 #define emacTX_WAIT_ATTEMPTS                    ( 50 )\r
66 \r
67 /* Constants used for set up and initialisation. */\r
68 #define emacTX_INTERRUPT_NO                     ( 76 )\r
69 #define emacRX_INTERRUPT_NO                     ( 77 )\r
70 #define emacERROR_INTERRUPT_NO          ( 78 )\r
71 #define emacLINK_DELAY                          ( 500 / portTICK_PERIOD_MS )\r
72 #define emacPHY_STATUS                          ( 0x1F )\r
73 #define emacPHY_DUPLEX_STATUS           ( 4 << 2 )\r
74 #define emacPHY_SPEED_STATUS            ( 1 << 2 )\r
75 \r
76 /*-----------------------------------------------------------*/\r
77 \r
78 /*\r
79  * Initialise both the Rx and Tx descriptors.\r
80  */\r
81 static void prvInitialiseDescriptors( void );\r
82 \r
83 /*\r
84  * Return a pointer to a free buffer within xEthernetBuffers.\r
85  */\r
86 static unsigned char *prvGetNextBuffer( void );\r
87 \r
88 /*\r
89  * Return a buffer to the list of free buffers.\r
90  */\r
91 static void prvReturnBuffer( unsigned char *pucBuffer );\r
92 \r
93 /*\r
94  * Examine the status of the next Rx descriptor to see if it contains new data.\r
95  */\r
96 static unsigned short prvCheckRxStatus( void );\r
97 \r
98 /*\r
99  * Something has gone wrong with the descriptor usage.  Reset all the buffers\r
100  * and descriptors.\r
101  */\r
102 static void prvResetEverything( void );\r
103 \r
104 /*-----------------------------------------------------------*/\r
105 \r
106 /* The buffers and descriptors themselves.  */\r
107 #pragma data_alignment=16\r
108 volatile NBUF xRxDescriptors[ emacNUM_RX_DESCRIPTORS ];\r
109 \r
110 #pragma data_alignment=16\r
111 volatile NBUF xTxDescriptors[ emacNUM_TX_BUFFERS ];\r
112 \r
113 #pragma data_alignment=16\r
114 char xEthernetBuffers[ emacNUM_BUFFERS ][ UIP_BUFSIZE ];\r
115 \r
116 /* Used to indicate which buffers are free and which are in use.  If an index\r
117 contains 0 then the corresponding buffer in xEthernetBuffers is free, otherwise\r
118 the buffer is in use or about to be used. */\r
119 static unsigned char ucBufferInUse[ emacNUM_BUFFERS ];\r
120 \r
121 /* Points to the Rx descriptor currently in use. */\r
122 static volatile NBUF *pxCurrentRxDesc = NULL;\r
123 \r
124 /* pxCurrentRxDesc points to descriptor within the xRxDescriptors array that\r
125 has an index defined by ulRxDescriptorIndex. */\r
126 static unsigned long ulRxDescriptorIndex = 0UL;\r
127 \r
128 /* The buffer used by the uIP stack to both receive and send.  This points to\r
129 one of the Ethernet buffers when its actually in use. */\r
130 unsigned char *uip_buf = NULL;\r
131 \r
132 /*-----------------------------------------------------------*/\r
133 \r
134 void vEMACInit( void )\r
135 {\r
136 int iData;\r
137 extern int periph_clk_khz;\r
138 const unsigned char ucMACAddress[] =\r
139 {\r
140         configMAC_ADDR0, configMAC_ADDR1, configMAC_ADDR2, configMAC_ADDR3, configMAC_ADDR4, configMAC_ADDR5\r
141 };\r
142 \r
143         /* Enable the ENET clock. */\r
144         SIM_SCGC2 |= SIM_SCGC2_ENET_MASK;\r
145 \r
146         /* Allow concurrent access to MPU controller to avoid bus errors. */\r
147         MPU_CESR = 0;\r
148 \r
149         prvInitialiseDescriptors();\r
150 \r
151         /* Reset and enable. */\r
152         ENET_ECR = ENET_ECR_RESET_MASK;\r
153         \r
154         /* Wait at least 8 clock cycles */\r
155         vTaskDelay( 2 );\r
156         \r
157         /* Start the MII interface*/\r
158         mii_init( 0, periph_clk_khz / 1000L );\r
159 \r
160         /* Configure the transmit interrupt. */\r
161         set_irq_priority( emacTX_INTERRUPT_NO, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY );\r
162         enable_irq( emacTX_INTERRUPT_NO );\r
163 \r
164         /* Configure the receive interrupt. */\r
165         set_irq_priority( emacRX_INTERRUPT_NO, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY );\r
166         enable_irq( emacRX_INTERRUPT_NO );\r
167 \r
168         /* Configure the error interrupt. */\r
169         set_irq_priority( emacERROR_INTERRUPT_NO, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY );\r
170         enable_irq( emacERROR_INTERRUPT_NO );\r
171 \r
172         /* Configure the pins to the PHY - RMII mode used. */\r
173         PORTB_PCR0  = PORT_PCR_MUX( 4 ); /* RMII0_MDIO / MII0_MDIO. */\r
174         PORTB_PCR1  = PORT_PCR_MUX( 4 ); /* RMII0_MDC / MII0_MDC */\r
175         PORTA_PCR14 = PORT_PCR_MUX( 4 ); /* RMII0_CRS_DV / MII0_RXDV */\r
176         PORTA_PCR12 = PORT_PCR_MUX( 4 ); /* RMII0_RXD1 / MII0_RXD1 */\r
177         PORTA_PCR13 = PORT_PCR_MUX( 4 ); /* RMII0_RXD0/MII0_RXD0 */\r
178         PORTA_PCR15 = PORT_PCR_MUX( 4 ); /* RMII0_TXEN/MII0_TXEN */\r
179         PORTA_PCR16 = PORT_PCR_MUX( 4 ); /* RMII0_TXD0/MII0_TXD0 */\r
180         PORTA_PCR17 = PORT_PCR_MUX( 4 ); /* RMII0_TXD1/MII0_TXD1 */\r
181 \r
182         /* Is there communication with the PHY? */\r
183         do\r
184         {\r
185                 vTaskDelay( emacLINK_DELAY );\r
186                 iData = 0xFFFF;\r
187                 mii_read( 0, configPHY_ADDRESS, PHY_PHYIDR1, &iData );\r
188         \r
189         } while( iData == 0xFFFF );\r
190 \r
191         /* Start to auto negotiate. */\r
192         mii_write( 0, configPHY_ADDRESS, PHY_BMCR, ( PHY_BMCR_AN_RESTART | PHY_BMCR_AN_ENABLE ) );\r
193         \r
194         /* Wait for auto negotiate to complete. */\r
195         do\r
196         {\r
197                 vTaskDelay( emacLINK_DELAY );\r
198                 mii_read( 0, configPHY_ADDRESS, PHY_BMSR, &iData );\r
199         \r
200         } while( !( iData & PHY_BMSR_AN_COMPLETE ) );\r
201 \r
202         /* A link has been established.  What was negotiated? */\r
203         iData = 0;\r
204         mii_read( 0, configPHY_ADDRESS, emacPHY_STATUS, &iData );\r
205 \r
206         /* Clear the Individual and Group Address Hash registers */\r
207         ENET_IALR = 0;\r
208         ENET_IAUR = 0;\r
209         ENET_GALR = 0;\r
210         ENET_GAUR = 0;\r
211 \r
212         /* Set the Physical Address for the selected ENET */\r
213         enet_set_address( 0, ucMACAddress );\r
214 \r
215         ENET_RCR = ENET_RCR_MAX_FL( UIP_BUFSIZE ) | ENET_RCR_MII_MODE_MASK | ENET_RCR_CRCFWD_MASK | ENET_RCR_RMII_MODE_MASK;\r
216 \r
217         /* Clear the control registers. */\r
218         ENET_TCR = 0;\r
219 \r
220         if( iData & emacPHY_DUPLEX_STATUS )\r
221         {\r
222                 /* Full duplex */\r
223                 ENET_RCR &= ( unsigned long )~ENET_RCR_DRT_MASK;\r
224                 ENET_TCR |= ENET_TCR_FDEN_MASK;\r
225         }\r
226         else\r
227         {\r
228                 /* Half duplex */\r
229                 ENET_RCR |= ENET_RCR_DRT_MASK;\r
230                 ENET_TCR &= (unsigned long)~ENET_TCR_FDEN_MASK;\r
231         }\r
232 \r
233         if( iData & emacPHY_SPEED_STATUS )\r
234         {\r
235                 /* 10Mbps */\r
236                 ENET_RCR |= ENET_RCR_RMII_10T_MASK;\r
237         }\r
238 \r
239     ENET_ECR = ENET_ECR_EN1588_MASK;\r
240 \r
241         /* Store and forward checksum. */\r
242         ENET_TFWR = ENET_TFWR_STRFWD_MASK;\r
243 \r
244         /* Set Rx Buffer Size */\r
245         ENET_MRBR = ( unsigned short ) UIP_BUFSIZE;\r
246         \r
247         /* Point to the start of the circular Rx buffer descriptor queue */\r
248         ENET_RDSR = ( unsigned long ) &( xRxDescriptors[ 0 ] );\r
249         \r
250         /* Point to the start of the circular Tx buffer descriptor queue */\r
251         ENET_TDSR = ( unsigned long ) &( xTxDescriptors[ 0 ] );\r
252         \r
253         /* Clear all ENET interrupt events */\r
254         ENET_EIR = ( unsigned long ) -1;\r
255         \r
256         /* Enable interrupts. */\r
257         ENET_EIMR = 0\r
258                         /*rx irqs*/\r
259                         | ENET_EIMR_RXF_MASK/* only for complete frame, not partial buffer descriptor | ENET_EIMR_RXB_MASK*/\r
260                         /*xmit irqs*/\r
261                         | ENET_EIMR_TXF_MASK/* only for complete frame, not partial buffer descriptor | ENET_EIMR_TXB_MASK*/\r
262                         /*enet irqs*/\r
263                         | ENET_EIMR_UN_MASK | ENET_EIMR_RL_MASK | ENET_EIMR_LC_MASK | ENET_EIMR_BABT_MASK | ENET_EIMR_BABR_MASK | ENET_EIMR_EBERR_MASK\r
264                         ;\r
265         \r
266         /* Enable the MAC itself. */\r
267         ENET_ECR |= ENET_ECR_ETHEREN_MASK;\r
268         \r
269         /* Indicate that there have been empty receive buffers produced */\r
270         ENET_RDAR = ENET_RDAR_RDAR_MASK;\r
271 }\r
272 /*-----------------------------------------------------------*/\r
273 \r
274 static void prvInitialiseDescriptors( void )\r
275 {\r
276 volatile NBUF *pxDescriptor;\r
277 long x;\r
278 \r
279         for( x = 0; x < emacNUM_BUFFERS; x++ )\r
280         {\r
281                 /* Ensure none of the buffers are shown as in use at the start. */\r
282                 ucBufferInUse[ x ] = pdFALSE;\r
283         }\r
284 \r
285         /* Initialise the Rx descriptors. */\r
286         for( x = 0; x < emacNUM_RX_DESCRIPTORS; x++ )\r
287         {\r
288                 pxDescriptor = &( xRxDescriptors[ x ] );\r
289                 pxDescriptor->data = ( uint8_t* ) &( xEthernetBuffers[ x ][ 0 ] );\r
290                 pxDescriptor->data = ( uint8_t* ) __REV( ( unsigned long ) pxDescriptor->data );\r
291                 pxDescriptor->length = 0;\r
292                 pxDescriptor->status = RX_BD_E;\r
293                 pxDescriptor->bdu = 0;\r
294                 pxDescriptor->ebd_status = RX_BD_INT;\r
295                 \r
296                 /* Mark this buffer as in use. */\r
297                 ucBufferInUse[ x ] = pdTRUE;\r
298         }\r
299 \r
300         /* The last descriptor points back to the start. */\r
301         pxDescriptor->status |= RX_BD_W;\r
302         \r
303         /* Initialise the Tx descriptors. */\r
304         for( x = 0; x < emacNUM_TX_BUFFERS; x++ )\r
305         {\r
306                 pxDescriptor = &( xTxDescriptors[ x ] );\r
307                 \r
308                 /* A buffer is not allocated to the Tx descriptor until a send is\r
309                 actually required. */\r
310                 pxDescriptor->data = NULL;\r
311                 pxDescriptor->length = 0;\r
312                 pxDescriptor->status = TX_BD_TC;\r
313                 pxDescriptor->ebd_status = TX_BD_INT;\r
314         }\r
315 \r
316         /* The last descriptor points back to the start. */\r
317         pxDescriptor->status |= TX_BD_W;\r
318         \r
319         /* Use the first Rx descriptor to start with. */\r
320         ulRxDescriptorIndex = 0UL;\r
321         pxCurrentRxDesc = &( xRxDescriptors[ 0 ] );\r
322 }\r
323 /*-----------------------------------------------------------*/\r
324 \r
325 void vEMACWrite( void )\r
326 {\r
327 long x;\r
328 \r
329         /* Wait until the second transmission of the last packet has completed. */\r
330         for( x = 0; x < emacTX_WAIT_ATTEMPTS; x++ )\r
331         {\r
332                 if( ( xTxDescriptors[ 1 ].status & TX_BD_R ) != 0 )\r
333                 {\r
334                         /* Descriptor is still active. */\r
335                         vTaskDelay( emacTX_WAIT_DELAY_ms );\r
336                 }\r
337                 else\r
338                 {\r
339                         break;\r
340                 }\r
341         }\r
342         \r
343         /* Is the descriptor free after waiting for it? */\r
344         if( ( xTxDescriptors[ 1 ].status & TX_BD_R ) != 0 )\r
345         {\r
346                 /* Something has gone wrong. */\r
347                 prvResetEverything();\r
348         }\r
349         \r
350         /* Setup both descriptors to transmit the frame. */\r
351         xTxDescriptors[ 0 ].data = ( uint8_t * ) __REV( ( unsigned long ) uip_buf );\r
352         xTxDescriptors[ 0 ].length = __REVSH( uip_len );\r
353         xTxDescriptors[ 1 ].data = ( uint8_t * ) __REV( ( unsigned long ) uip_buf );\r
354         xTxDescriptors[ 1 ].length = __REVSH( uip_len );\r
355 \r
356         /* uip_buf is being sent by the Tx descriptor.  Allocate a new buffer\r
357         for use by the stack. */\r
358         uip_buf = prvGetNextBuffer();\r
359 \r
360         /* Clear previous settings and go. */\r
361         xTxDescriptors[ 0 ].status |= ( TX_BD_R | TX_BD_L );\r
362         xTxDescriptors[ 1 ].status |= ( TX_BD_R | TX_BD_L );\r
363 \r
364         /* Start the Tx. */\r
365         ENET_TDAR = ENET_TDAR_TDAR_MASK;\r
366 }\r
367 /*-----------------------------------------------------------*/\r
368 \r
369 static unsigned char *prvGetNextBuffer( void )\r
370 {\r
371 long x;\r
372 unsigned char *pucReturn = NULL;\r
373 unsigned long ulAttempts = 0;\r
374 \r
375         while( pucReturn == NULL )\r
376         {\r
377                 /* Look through the buffers to find one that is not in use by\r
378                 anything else. */\r
379                 for( x = 0; x < emacNUM_BUFFERS; x++ )\r
380                 {\r
381                         if( ucBufferInUse[ x ] == pdFALSE )\r
382                         {\r
383                                 ucBufferInUse[ x ] = pdTRUE;\r
384                                 pucReturn = ( unsigned char * ) &( xEthernetBuffers[ x ][ 0 ] );\r
385                                 break;\r
386                         }\r
387                 }\r
388 \r
389                 /* Was a buffer found? */\r
390                 if( pucReturn == NULL )\r
391                 {\r
392                         ulAttempts++;\r
393 \r
394                         if( ulAttempts >= emacBUFFER_WAIT_ATTEMPTS )\r
395                         {\r
396                                 break;\r
397                         }\r
398 \r
399                         /* Wait then look again. */\r
400                         vTaskDelay( emacBUFFER_WAIT_DELAY_ms );\r
401                 }\r
402         }\r
403 \r
404         return pucReturn;\r
405 }\r
406 /*-----------------------------------------------------------*/\r
407 \r
408 static void prvResetEverything( void )\r
409 {\r
410         /* Temporary code just to see if this gets called.  This function has not\r
411         been implemented. */\r
412         portDISABLE_INTERRUPTS();\r
413         for( ;; );\r
414 }\r
415 /*-----------------------------------------------------------*/\r
416 \r
417 unsigned short usEMACRead( void )\r
418 {\r
419 unsigned short usBytesReceived;\r
420 \r
421         usBytesReceived = prvCheckRxStatus();\r
422         usBytesReceived = __REVSH( usBytesReceived );\r
423 \r
424         if( usBytesReceived > 0 )\r
425         {\r
426                 /* Mark the pxDescriptor buffer as free as uip_buf is going to be set to\r
427                 the buffer that contains the received data. */\r
428                 prvReturnBuffer( uip_buf );\r
429 \r
430                 /* Point uip_buf to the data about to be processed. */\r
431                 uip_buf = ( void * ) pxCurrentRxDesc->data;\r
432                 uip_buf = ( void * ) __REV( ( unsigned long ) uip_buf );\r
433                 \r
434                 /* Allocate a new buffer to the descriptor, as uip_buf is now using it's\r
435                 old descriptor. */\r
436                 pxCurrentRxDesc->data = ( uint8_t * ) prvGetNextBuffer();\r
437                 pxCurrentRxDesc->data = ( uint8_t* ) __REV( ( unsigned long ) pxCurrentRxDesc->data );\r
438 \r
439                 /* Prepare the descriptor to go again. */\r
440                 pxCurrentRxDesc->status |= RX_BD_E;\r
441 \r
442                 /* Move onto the next buffer in the ring. */\r
443                 ulRxDescriptorIndex++;\r
444                 if( ulRxDescriptorIndex >= emacNUM_RX_DESCRIPTORS )\r
445                 {\r
446                         ulRxDescriptorIndex = 0UL;\r
447                 }\r
448                 pxCurrentRxDesc = &( xRxDescriptors[ ulRxDescriptorIndex ] );\r
449                 \r
450                 /* Restart Ethernet if it has stopped */\r
451                 ENET_RDAR = ENET_RDAR_RDAR_MASK;\r
452         }\r
453 \r
454         return usBytesReceived;\r
455 }\r
456 /*-----------------------------------------------------------*/\r
457 \r
458 static void prvReturnBuffer( unsigned char *pucBuffer )\r
459 {\r
460 unsigned long ul;\r
461 \r
462         /* Return a buffer to the pool of free buffers. */\r
463         for( ul = 0; ul < emacNUM_BUFFERS; ul++ )\r
464         {\r
465                 if( &( xEthernetBuffers[ ul ][ 0 ] ) == ( void * ) pucBuffer )\r
466                 {\r
467                         ucBufferInUse[ ul ] = pdFALSE;\r
468                         break;\r
469                 }\r
470         }\r
471 }\r
472 /*-----------------------------------------------------------*/\r
473 \r
474 static unsigned short prvCheckRxStatus( void )\r
475 {\r
476 unsigned long usReturn = 0;\r
477 \r
478         if( ( pxCurrentRxDesc->status & RX_BD_E ) != 0 )\r
479         {\r
480                 /* Current descriptor is still active. */\r
481         }\r
482         else\r
483         {\r
484                 /* The descriptor contains a frame.  Because of the size of the buffers\r
485                 the frame should always be complete. */\r
486                 usReturn = pxCurrentRxDesc->length;\r
487         }\r
488         \r
489         return usReturn;\r
490 }\r
491 /*-----------------------------------------------------------*/\r
492 \r
493 void vEMAC_TxISRHandler( void )\r
494 {\r
495         /* Clear the interrupt. */\r
496         ENET_EIR = ENET_EIR_TXF_MASK;\r
497 \r
498         /* Check the buffers have not already been freed in the first of the\r
499         two Tx interrupts - which could potentially happen if the second Tx completed\r
500         during the interrupt for the first Tx. */\r
501         if( xTxDescriptors[ 0 ].data != NULL )\r
502         {\r
503                 if( ( ( xTxDescriptors[ 0 ].status & TX_BD_R ) == 0 ) && ( ( xTxDescriptors[ 0 ].status & TX_BD_R ) == 0 ) )\r
504                 {\r
505                         configASSERT( xTxDescriptors[ 0 ].data == xTxDescriptors[ 1 ].data );\r
506                         \r
507                         xTxDescriptors[ 0 ].data = ( uint8_t* ) __REV( ( unsigned long ) xTxDescriptors[ 0 ].data );\r
508                         prvReturnBuffer( xTxDescriptors[ 0 ].data );\r
509                         \r
510                         /* Just to mark the fact that the buffer has already been released. */\r
511                         xTxDescriptors[ 0 ].data = NULL;\r
512                 }\r
513         }\r
514 }\r
515 /*-----------------------------------------------------------*/\r
516 \r
517 void vEMAC_RxISRHandler( void )\r
518 {\r
519 const unsigned long ulRxEvent = uipETHERNET_RX_EVENT;\r
520 long lHigherPriorityTaskWoken = pdFALSE;\r
521 extern QueueHandle_t xEMACEventQueue;\r
522 \r
523         /* Clear the interrupt. */\r
524         ENET_EIR = ENET_EIR_RXF_MASK;\r
525 \r
526         /* An Ethernet Rx event has occurred. */\r
527         xQueueSendFromISR( xEMACEventQueue, &ulRxEvent, &lHigherPriorityTaskWoken );\r
528         portEND_SWITCHING_ISR( lHigherPriorityTaskWoken );\r
529 }\r
530 /*-----------------------------------------------------------*/\r
531 \r
532 void vEMAC_ErrorISRHandler( void )\r
533 {\r
534         /* Clear the interrupt. */\r
535         ENET_EIR = ENET_EIR & ENET_EIMR;\r
536 \r
537         /* Attempt recovery.  Not very sophisticated. */\r
538         prvInitialiseDescriptors();\r
539         ENET_RDAR = ENET_RDAR_RDAR_MASK;\r
540 }\r
541 /*-----------------------------------------------------------*/\r
542 \r
543 \r