]> begriffs open source - freertos/blob - FreeRTOS/Demo/CORTEX_Kinetis_K60_Tower_IAR/webserver/EMAC.c
Add additional critical section to the default tickless implementations.
[freertos] / FreeRTOS / Demo / CORTEX_Kinetis_K60_Tower_IAR / webserver / EMAC.c
1 /*\r
2     FreeRTOS V7.5.2 - Copyright (C) 2013 Real Time Engineers Ltd.\r
3 \r
4     VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.\r
5 \r
6     ***************************************************************************\r
7      *                                                                       *\r
8      *    FreeRTOS provides completely free yet professionally developed,    *\r
9      *    robust, strictly quality controlled, supported, and cross          *\r
10      *    platform software that has become a de facto standard.             *\r
11      *                                                                       *\r
12      *    Help yourself get started quickly and support the FreeRTOS         *\r
13      *    project by purchasing a FreeRTOS tutorial book, reference          *\r
14      *    manual, or both from: http://www.FreeRTOS.org/Documentation        *\r
15      *                                                                       *\r
16      *    Thank you!                                                         *\r
17      *                                                                       *\r
18     ***************************************************************************\r
19 \r
20     This file is part of the FreeRTOS distribution.\r
21 \r
22     FreeRTOS is free software; you can redistribute it and/or modify it under\r
23     the terms of the GNU General Public License (version 2) as published by the\r
24     Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.\r
25 \r
26     >>! NOTE: The modification to the GPL is included to allow you to distribute\r
27     >>! a combined work that includes FreeRTOS without being obliged to provide\r
28     >>! the source code for proprietary components outside of the FreeRTOS\r
29     >>! kernel.\r
30 \r
31     FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY\r
32     WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS\r
33     FOR A PARTICULAR PURPOSE.  Full license text is available from the following\r
34     link: http://www.freertos.org/a00114.html\r
35 \r
36     1 tab == 4 spaces!\r
37 \r
38     ***************************************************************************\r
39      *                                                                       *\r
40      *    Having a problem?  Start by reading the FAQ "My application does   *\r
41      *    not run, what could be wrong?"                                     *\r
42      *                                                                       *\r
43      *    http://www.FreeRTOS.org/FAQHelp.html                               *\r
44      *                                                                       *\r
45     ***************************************************************************\r
46 \r
47     http://www.FreeRTOS.org - Documentation, books, training, latest versions,\r
48     license and Real Time Engineers Ltd. contact details.\r
49 \r
50     http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,\r
51     including FreeRTOS+Trace - an indispensable productivity tool, a DOS\r
52     compatible FAT file system, and our tiny thread aware UDP/IP stack.\r
53 \r
54     http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High\r
55     Integrity Systems to sell under the OpenRTOS brand.  Low cost OpenRTOS\r
56     licenses offer ticketed support, indemnification and middleware.\r
57 \r
58     http://www.SafeRTOS.com - High Integrity Systems also provide a safety\r
59     engineered and independently SIL3 certified version for use in safety and\r
60     mission critical applications that require provable dependability.\r
61 \r
62     1 tab == 4 spaces!\r
63 */\r
64 \r
65 /* Freescale includes. */\r
66 #include "common.h"\r
67 #include "eth_phy.h"\r
68 #include "enet.h"\r
69 #include "mii.h"\r
70 \r
71 /* FreeRTOS includes. */\r
72 #include "FreeRTOS.h"\r
73 #include "task.h"\r
74 #include "queue.h"\r
75 \r
76 /* uIP includes. */\r
77 #include "net/uip.h"\r
78 \r
79 /* The time to wait between attempts to obtain a free buffer. */\r
80 #define emacBUFFER_WAIT_DELAY_ms                ( 3 / portTICK_RATE_MS )\r
81 \r
82 /* The number of times emacBUFFER_WAIT_DELAY_ms should be waited before giving\r
83 up on attempting to obtain a free buffer all together. */\r
84 #define emacBUFFER_WAIT_ATTEMPTS                ( 30 )\r
85 \r
86 /* The number of Rx descriptors. */\r
87 #define emacNUM_RX_DESCRIPTORS                  8\r
88 \r
89 /* The number of Tx descriptors.  When using uIP there is not point in having\r
90 more than two. */\r
91 #define emacNUM_TX_BUFFERS                              2\r
92 \r
93 /* The total number of EMAC buffers to allocate. */\r
94 #define emacNUM_BUFFERS                                 ( emacNUM_RX_DESCRIPTORS + emacNUM_TX_BUFFERS )\r
95 \r
96 /* The time to wait for the Tx descriptor to become free. */\r
97 #define emacTX_WAIT_DELAY_ms                    ( 10 / portTICK_RATE_MS )\r
98 \r
99 /* The total number of times to wait emacTX_WAIT_DELAY_ms for the Tx descriptor to\r
100 become free. */\r
101 #define emacTX_WAIT_ATTEMPTS                    ( 50 )\r
102 \r
103 /* Constants used for set up and initialisation. */\r
104 #define emacTX_INTERRUPT_NO                     ( 76 )\r
105 #define emacRX_INTERRUPT_NO                     ( 77 )\r
106 #define emacERROR_INTERRUPT_NO          ( 78 )\r
107 #define emacLINK_DELAY                          ( 500 / portTICK_RATE_MS )\r
108 #define emacPHY_STATUS                          ( 0x1F )\r
109 #define emacPHY_DUPLEX_STATUS           ( 4 << 2 )\r
110 #define emacPHY_SPEED_STATUS            ( 1 << 2 )\r
111 \r
112 /*-----------------------------------------------------------*/\r
113 \r
114 /*\r
115  * Initialise both the Rx and Tx descriptors.\r
116  */\r
117 static void prvInitialiseDescriptors( void );\r
118 \r
119 /*\r
120  * Return a pointer to a free buffer within xEthernetBuffers.\r
121  */\r
122 static unsigned char *prvGetNextBuffer( void );\r
123 \r
124 /*\r
125  * Return a buffer to the list of free buffers.\r
126  */\r
127 static void prvReturnBuffer( unsigned char *pucBuffer );\r
128 \r
129 /*\r
130  * Examine the status of the next Rx descriptor to see if it contains new data.\r
131  */\r
132 static unsigned short prvCheckRxStatus( void );\r
133 \r
134 /*\r
135  * Something has gone wrong with the descriptor usage.  Reset all the buffers\r
136  * and descriptors.\r
137  */\r
138 static void prvResetEverything( void );\r
139 \r
140 /*-----------------------------------------------------------*/\r
141 \r
142 /* The buffers and descriptors themselves.  */\r
143 #pragma data_alignment=16\r
144 volatile NBUF xRxDescriptors[ emacNUM_RX_DESCRIPTORS ];\r
145 \r
146 #pragma data_alignment=16\r
147 volatile NBUF xTxDescriptors[ emacNUM_TX_BUFFERS ];\r
148 \r
149 #pragma data_alignment=16\r
150 char xEthernetBuffers[ emacNUM_BUFFERS ][ UIP_BUFSIZE ];\r
151 \r
152 /* Used to indicate which buffers are free and which are in use.  If an index\r
153 contains 0 then the corresponding buffer in xEthernetBuffers is free, otherwise\r
154 the buffer is in use or about to be used. */\r
155 static unsigned char ucBufferInUse[ emacNUM_BUFFERS ];\r
156 \r
157 /* Points to the Rx descriptor currently in use. */\r
158 static volatile NBUF *pxCurrentRxDesc = NULL;\r
159 \r
160 /* pxCurrentRxDesc points to descriptor within the xRxDescriptors array that\r
161 has an index defined by ulRxDescriptorIndex. */\r
162 static unsigned long ulRxDescriptorIndex = 0UL;\r
163 \r
164 /* The buffer used by the uIP stack to both receive and send.  This points to\r
165 one of the Ethernet buffers when its actually in use. */\r
166 unsigned char *uip_buf = NULL;\r
167 \r
168 /*-----------------------------------------------------------*/\r
169 \r
170 void vEMACInit( void )\r
171 {\r
172 int iData;\r
173 extern int periph_clk_khz;\r
174 const unsigned portCHAR ucMACAddress[] =\r
175 {\r
176         configMAC_ADDR0, configMAC_ADDR1, configMAC_ADDR2, configMAC_ADDR3, configMAC_ADDR4, configMAC_ADDR5\r
177 };\r
178 \r
179         /* Enable the ENET clock. */\r
180         SIM_SCGC2 |= SIM_SCGC2_ENET_MASK;\r
181 \r
182         /* Allow concurrent access to MPU controller to avoid bus errors. */\r
183         MPU_CESR = 0;\r
184 \r
185         prvInitialiseDescriptors();\r
186 \r
187         /* Reset and enable. */\r
188         ENET_ECR = ENET_ECR_RESET_MASK;\r
189         \r
190         /* Wait at least 8 clock cycles */\r
191         vTaskDelay( 2 );\r
192         \r
193         /* Start the MII interface*/\r
194         mii_init( 0, periph_clk_khz / 1000L );\r
195 \r
196         /* Configure the transmit interrupt. */\r
197         set_irq_priority( emacTX_INTERRUPT_NO, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY );\r
198         enable_irq( emacTX_INTERRUPT_NO );\r
199 \r
200         /* Configure the receive interrupt. */\r
201         set_irq_priority( emacRX_INTERRUPT_NO, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY );\r
202         enable_irq( emacRX_INTERRUPT_NO );\r
203 \r
204         /* Configure the error interrupt. */\r
205         set_irq_priority( emacERROR_INTERRUPT_NO, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY );\r
206         enable_irq( emacERROR_INTERRUPT_NO );\r
207 \r
208         /* Configure the pins to the PHY - RMII mode used. */\r
209         PORTB_PCR0  = PORT_PCR_MUX( 4 ); /* RMII0_MDIO / MII0_MDIO. */\r
210         PORTB_PCR1  = PORT_PCR_MUX( 4 ); /* RMII0_MDC / MII0_MDC */\r
211         PORTA_PCR14 = PORT_PCR_MUX( 4 ); /* RMII0_CRS_DV / MII0_RXDV */\r
212         PORTA_PCR12 = PORT_PCR_MUX( 4 ); /* RMII0_RXD1 / MII0_RXD1 */\r
213         PORTA_PCR13 = PORT_PCR_MUX( 4 ); /* RMII0_RXD0/MII0_RXD0 */\r
214         PORTA_PCR15 = PORT_PCR_MUX( 4 ); /* RMII0_TXEN/MII0_TXEN */\r
215         PORTA_PCR16 = PORT_PCR_MUX( 4 ); /* RMII0_TXD0/MII0_TXD0 */\r
216         PORTA_PCR17 = PORT_PCR_MUX( 4 ); /* RMII0_TXD1/MII0_TXD1 */\r
217 \r
218         /* Is there communication with the PHY? */\r
219         do\r
220         {\r
221                 vTaskDelay( emacLINK_DELAY );\r
222                 iData = 0xFFFF;\r
223                 mii_read( 0, configPHY_ADDRESS, PHY_PHYIDR1, &iData );\r
224         \r
225         } while( iData == 0xFFFF );\r
226 \r
227         /* Start to auto negotiate. */\r
228         mii_write( 0, configPHY_ADDRESS, PHY_BMCR, ( PHY_BMCR_AN_RESTART | PHY_BMCR_AN_ENABLE ) );\r
229         \r
230         /* Wait for auto negotiate to complete. */\r
231         do\r
232         {\r
233                 vTaskDelay( emacLINK_DELAY );\r
234                 mii_read( 0, configPHY_ADDRESS, PHY_BMSR, &iData );\r
235         \r
236         } while( !( iData & PHY_BMSR_AN_COMPLETE ) );\r
237 \r
238         /* A link has been established.  What was negotiated? */\r
239         iData = 0;\r
240         mii_read( 0, configPHY_ADDRESS, emacPHY_STATUS, &iData );\r
241 \r
242         /* Clear the Individual and Group Address Hash registers */\r
243         ENET_IALR = 0;\r
244         ENET_IAUR = 0;\r
245         ENET_GALR = 0;\r
246         ENET_GAUR = 0;\r
247 \r
248         /* Set the Physical Address for the selected ENET */\r
249         enet_set_address( 0, ucMACAddress );\r
250 \r
251         ENET_RCR = ENET_RCR_MAX_FL( UIP_BUFSIZE ) | ENET_RCR_MII_MODE_MASK | ENET_RCR_CRCFWD_MASK | ENET_RCR_RMII_MODE_MASK;\r
252 \r
253         /* Clear the control registers. */\r
254         ENET_TCR = 0;\r
255 \r
256         if( iData & emacPHY_DUPLEX_STATUS )\r
257         {\r
258                 /* Full duplex */\r
259                 ENET_RCR &= ( unsigned long )~ENET_RCR_DRT_MASK;\r
260                 ENET_TCR |= ENET_TCR_FDEN_MASK;\r
261         }\r
262         else\r
263         {\r
264                 /* Half duplex */\r
265                 ENET_RCR |= ENET_RCR_DRT_MASK;\r
266                 ENET_TCR &= (unsigned portLONG)~ENET_TCR_FDEN_MASK;\r
267         }\r
268 \r
269         if( iData & emacPHY_SPEED_STATUS )\r
270         {\r
271                 /* 10Mbps */\r
272                 ENET_RCR |= ENET_RCR_RMII_10T_MASK;\r
273         }\r
274 \r
275     ENET_ECR = ENET_ECR_EN1588_MASK;\r
276 \r
277         /* Store and forward checksum. */\r
278         ENET_TFWR = ENET_TFWR_STRFWD_MASK;\r
279 \r
280         /* Set Rx Buffer Size */\r
281         ENET_MRBR = ( unsigned short ) UIP_BUFSIZE;\r
282         \r
283         /* Point to the start of the circular Rx buffer descriptor queue */\r
284         ENET_RDSR = ( unsigned long ) &( xRxDescriptors[ 0 ] );\r
285         \r
286         /* Point to the start of the circular Tx buffer descriptor queue */\r
287         ENET_TDSR = ( unsigned long ) &( xTxDescriptors[ 0 ] );\r
288         \r
289         /* Clear all ENET interrupt events */\r
290         ENET_EIR = ( unsigned long ) -1;\r
291         \r
292         /* Enable interrupts. */\r
293         ENET_EIMR = 0\r
294                         /*rx irqs*/\r
295                         | ENET_EIMR_RXF_MASK/* only for complete frame, not partial buffer descriptor | ENET_EIMR_RXB_MASK*/\r
296                         /*xmit irqs*/\r
297                         | ENET_EIMR_TXF_MASK/* only for complete frame, not partial buffer descriptor | ENET_EIMR_TXB_MASK*/\r
298                         /*enet irqs*/\r
299                         | 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
300                         ;\r
301         \r
302         /* Enable the MAC itself. */\r
303         ENET_ECR |= ENET_ECR_ETHEREN_MASK;\r
304         \r
305         /* Indicate that there have been empty receive buffers produced */\r
306         ENET_RDAR = ENET_RDAR_RDAR_MASK;\r
307 }\r
308 /*-----------------------------------------------------------*/\r
309 \r
310 static void prvInitialiseDescriptors( void )\r
311 {\r
312 volatile NBUF *pxDescriptor;\r
313 long x;\r
314 \r
315         for( x = 0; x < emacNUM_BUFFERS; x++ )\r
316         {\r
317                 /* Ensure none of the buffers are shown as in use at the start. */\r
318                 ucBufferInUse[ x ] = pdFALSE;\r
319         }\r
320 \r
321         /* Initialise the Rx descriptors. */\r
322         for( x = 0; x < emacNUM_RX_DESCRIPTORS; x++ )\r
323         {\r
324                 pxDescriptor = &( xRxDescriptors[ x ] );\r
325                 pxDescriptor->data = ( uint8_t* ) &( xEthernetBuffers[ x ][ 0 ] );\r
326                 pxDescriptor->data = ( uint8_t* ) __REV( ( unsigned long ) pxDescriptor->data );\r
327                 pxDescriptor->length = 0;\r
328                 pxDescriptor->status = RX_BD_E;\r
329                 pxDescriptor->bdu = 0;\r
330                 pxDescriptor->ebd_status = RX_BD_INT;\r
331                 \r
332                 /* Mark this buffer as in use. */\r
333                 ucBufferInUse[ x ] = pdTRUE;\r
334         }\r
335 \r
336         /* The last descriptor points back to the start. */\r
337         pxDescriptor->status |= RX_BD_W;\r
338         \r
339         /* Initialise the Tx descriptors. */\r
340         for( x = 0; x < emacNUM_TX_BUFFERS; x++ )\r
341         {\r
342                 pxDescriptor = &( xTxDescriptors[ x ] );\r
343                 \r
344                 /* A buffer is not allocated to the Tx descriptor until a send is\r
345                 actually required. */\r
346                 pxDescriptor->data = NULL;\r
347                 pxDescriptor->length = 0;\r
348                 pxDescriptor->status = TX_BD_TC;\r
349                 pxDescriptor->ebd_status = TX_BD_INT;\r
350         }\r
351 \r
352         /* The last descriptor points back to the start. */\r
353         pxDescriptor->status |= TX_BD_W;\r
354         \r
355         /* Use the first Rx descriptor to start with. */\r
356         ulRxDescriptorIndex = 0UL;\r
357         pxCurrentRxDesc = &( xRxDescriptors[ 0 ] );\r
358 }\r
359 /*-----------------------------------------------------------*/\r
360 \r
361 void vEMACWrite( void )\r
362 {\r
363 long x;\r
364 \r
365         /* Wait until the second transmission of the last packet has completed. */\r
366         for( x = 0; x < emacTX_WAIT_ATTEMPTS; x++ )\r
367         {\r
368                 if( ( xTxDescriptors[ 1 ].status & TX_BD_R ) != 0 )\r
369                 {\r
370                         /* Descriptor is still active. */\r
371                         vTaskDelay( emacTX_WAIT_DELAY_ms );\r
372                 }\r
373                 else\r
374                 {\r
375                         break;\r
376                 }\r
377         }\r
378         \r
379         /* Is the descriptor free after waiting for it? */\r
380         if( ( xTxDescriptors[ 1 ].status & TX_BD_R ) != 0 )\r
381         {\r
382                 /* Something has gone wrong. */\r
383                 prvResetEverything();\r
384         }\r
385         \r
386         /* Setup both descriptors to transmit the frame. */\r
387         xTxDescriptors[ 0 ].data = ( uint8_t * ) __REV( ( unsigned long ) uip_buf );\r
388         xTxDescriptors[ 0 ].length = __REVSH( uip_len );\r
389         xTxDescriptors[ 1 ].data = ( uint8_t * ) __REV( ( unsigned long ) uip_buf );\r
390         xTxDescriptors[ 1 ].length = __REVSH( uip_len );\r
391 \r
392         /* uip_buf is being sent by the Tx descriptor.  Allocate a new buffer\r
393         for use by the stack. */\r
394         uip_buf = prvGetNextBuffer();\r
395 \r
396         /* Clear previous settings and go. */\r
397         xTxDescriptors[ 0 ].status |= ( TX_BD_R | TX_BD_L );\r
398         xTxDescriptors[ 1 ].status |= ( TX_BD_R | TX_BD_L );\r
399 \r
400         /* Start the Tx. */\r
401         ENET_TDAR = ENET_TDAR_TDAR_MASK;\r
402 }\r
403 /*-----------------------------------------------------------*/\r
404 \r
405 static unsigned char *prvGetNextBuffer( void )\r
406 {\r
407 long x;\r
408 unsigned char *pucReturn = NULL;\r
409 unsigned long ulAttempts = 0;\r
410 \r
411         while( pucReturn == NULL )\r
412         {\r
413                 /* Look through the buffers to find one that is not in use by\r
414                 anything else. */\r
415                 for( x = 0; x < emacNUM_BUFFERS; x++ )\r
416                 {\r
417                         if( ucBufferInUse[ x ] == pdFALSE )\r
418                         {\r
419                                 ucBufferInUse[ x ] = pdTRUE;\r
420                                 pucReturn = ( unsigned char * ) &( xEthernetBuffers[ x ][ 0 ] );\r
421                                 break;\r
422                         }\r
423                 }\r
424 \r
425                 /* Was a buffer found? */\r
426                 if( pucReturn == NULL )\r
427                 {\r
428                         ulAttempts++;\r
429 \r
430                         if( ulAttempts >= emacBUFFER_WAIT_ATTEMPTS )\r
431                         {\r
432                                 break;\r
433                         }\r
434 \r
435                         /* Wait then look again. */\r
436                         vTaskDelay( emacBUFFER_WAIT_DELAY_ms );\r
437                 }\r
438         }\r
439 \r
440         return pucReturn;\r
441 }\r
442 /*-----------------------------------------------------------*/\r
443 \r
444 static void prvResetEverything( void )\r
445 {\r
446         /* Temporary code just to see if this gets called.  This function has not\r
447         been implemented. */\r
448         portDISABLE_INTERRUPTS();\r
449         for( ;; );\r
450 }\r
451 /*-----------------------------------------------------------*/\r
452 \r
453 unsigned short usEMACRead( void )\r
454 {\r
455 unsigned short usBytesReceived;\r
456 \r
457         usBytesReceived = prvCheckRxStatus();\r
458         usBytesReceived = __REVSH( usBytesReceived );\r
459 \r
460         if( usBytesReceived > 0 )\r
461         {\r
462                 /* Mark the pxDescriptor buffer as free as uip_buf is going to be set to\r
463                 the buffer that contains the received data. */\r
464                 prvReturnBuffer( uip_buf );\r
465 \r
466                 /* Point uip_buf to the data about to be processed. */\r
467                 uip_buf = ( void * ) pxCurrentRxDesc->data;\r
468                 uip_buf = ( void * ) __REV( ( unsigned long ) uip_buf );\r
469                 \r
470                 /* Allocate a new buffer to the descriptor, as uip_buf is now using it's\r
471                 old descriptor. */\r
472                 pxCurrentRxDesc->data = ( uint8_t * ) prvGetNextBuffer();\r
473                 pxCurrentRxDesc->data = ( uint8_t* ) __REV( ( unsigned long ) pxCurrentRxDesc->data );\r
474 \r
475                 /* Prepare the descriptor to go again. */\r
476                 pxCurrentRxDesc->status |= RX_BD_E;\r
477 \r
478                 /* Move onto the next buffer in the ring. */\r
479                 ulRxDescriptorIndex++;\r
480                 if( ulRxDescriptorIndex >= emacNUM_RX_DESCRIPTORS )\r
481                 {\r
482                         ulRxDescriptorIndex = 0UL;\r
483                 }\r
484                 pxCurrentRxDesc = &( xRxDescriptors[ ulRxDescriptorIndex ] );\r
485                 \r
486                 /* Restart Ethernet if it has stopped */\r
487                 ENET_RDAR = ENET_RDAR_RDAR_MASK;\r
488         }\r
489 \r
490         return usBytesReceived;\r
491 }\r
492 /*-----------------------------------------------------------*/\r
493 \r
494 static void prvReturnBuffer( unsigned char *pucBuffer )\r
495 {\r
496 unsigned long ul;\r
497 \r
498         /* Return a buffer to the pool of free buffers. */\r
499         for( ul = 0; ul < emacNUM_BUFFERS; ul++ )\r
500         {\r
501                 if( &( xEthernetBuffers[ ul ][ 0 ] ) == ( void * ) pucBuffer )\r
502                 {\r
503                         ucBufferInUse[ ul ] = pdFALSE;\r
504                         break;\r
505                 }\r
506         }\r
507 }\r
508 /*-----------------------------------------------------------*/\r
509 \r
510 static unsigned short prvCheckRxStatus( void )\r
511 {\r
512 unsigned long usReturn = 0;\r
513 \r
514         if( ( pxCurrentRxDesc->status & RX_BD_E ) != 0 )\r
515         {\r
516                 /* Current descriptor is still active. */\r
517         }\r
518         else\r
519         {\r
520                 /* The descriptor contains a frame.  Because of the size of the buffers\r
521                 the frame should always be complete. */\r
522                 usReturn = pxCurrentRxDesc->length;\r
523         }\r
524         \r
525         return usReturn;\r
526 }\r
527 /*-----------------------------------------------------------*/\r
528 \r
529 void vEMAC_TxISRHandler( void )\r
530 {\r
531         /* Clear the interrupt. */\r
532         ENET_EIR = ENET_EIR_TXF_MASK;\r
533 \r
534         /* Check the buffers have not already been freed in the first of the\r
535         two Tx interrupts - which could potentially happen if the second Tx completed\r
536         during the interrupt for the first Tx. */\r
537         if( xTxDescriptors[ 0 ].data != NULL )\r
538         {\r
539                 if( ( ( xTxDescriptors[ 0 ].status & TX_BD_R ) == 0 ) && ( ( xTxDescriptors[ 0 ].status & TX_BD_R ) == 0 ) )\r
540                 {\r
541                         configASSERT( xTxDescriptors[ 0 ].data == xTxDescriptors[ 1 ].data );\r
542                         \r
543                         xTxDescriptors[ 0 ].data = ( uint8_t* ) __REV( ( unsigned long ) xTxDescriptors[ 0 ].data );\r
544                         prvReturnBuffer( xTxDescriptors[ 0 ].data );\r
545                         \r
546                         /* Just to mark the fact that the buffer has already been released. */\r
547                         xTxDescriptors[ 0 ].data = NULL;\r
548                 }\r
549         }\r
550 }\r
551 /*-----------------------------------------------------------*/\r
552 \r
553 void vEMAC_RxISRHandler( void )\r
554 {\r
555 const unsigned long ulRxEvent = uipETHERNET_RX_EVENT;\r
556 long lHigherPriorityTaskWoken = pdFALSE;\r
557 extern xQueueHandle xEMACEventQueue;\r
558 \r
559         /* Clear the interrupt. */\r
560         ENET_EIR = ENET_EIR_RXF_MASK;\r
561 \r
562         /* An Ethernet Rx event has occurred. */\r
563         xQueueSendFromISR( xEMACEventQueue, &ulRxEvent, &lHigherPriorityTaskWoken );\r
564         portEND_SWITCHING_ISR( lHigherPriorityTaskWoken );\r
565 }\r
566 /*-----------------------------------------------------------*/\r
567 \r
568 void vEMAC_ErrorISRHandler( void )\r
569 {\r
570         /* Clear the interrupt. */\r
571         ENET_EIR = ENET_EIR & ENET_EIMR;\r
572 \r
573         /* Attempt recovery.  Not very sophisticated. */\r
574         prvInitialiseDescriptors();\r
575         ENET_RDAR = ENET_RDAR_RDAR_MASK;\r
576 }\r
577 /*-----------------------------------------------------------*/\r
578 \r
579 \r