]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/ColdFire_MCF51CN128_CodeWarrior/Sources/FEC.c
Add FreeRTOS-Plus directory.
[freertos] / FreeRTOS / Demo / ColdFire_MCF51CN128_CodeWarrior / Sources / FEC.c
1 /*\r
2     This file is part of the FreeRTOS.org distribution.\r
3 \r
4     FreeRTOS.org is free software; you can redistribute it and/or modify it \r
5     under the terms of the GNU General Public License (version 2) as published\r
6     by the Free Software Foundation and modified by the FreeRTOS exception.\r
7 \r
8     FreeRTOS.org is distributed in the hope that it will be useful,    but WITHOUT\r
9     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or \r
10     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for \r
11     more details.\r
12 \r
13     You should have received a copy of the GNU General Public License along \r
14     with FreeRTOS.org; if not, write to the Free Software Foundation, Inc., 59 \r
15     Temple Place, Suite 330, Boston, MA  02111-1307  USA.\r
16 \r
17     A special exception to the GPL is included to allow you to distribute a \r
18     combined work that includes FreeRTOS.org without being obliged to provide\r
19     the source code for any proprietary components.  See the licensing section\r
20     of http://www.FreeRTOS.org for full details.\r
21 \r
22 \r
23     ***************************************************************************\r
24     *                                                                         *\r
25     * Get the FreeRTOS eBook!  See http://www.FreeRTOS.org/Documentation      *\r
26     *                                                                         *\r
27     * This is a concise, step by step, 'hands on' guide that describes both   *\r
28     * general multitasking concepts and FreeRTOS specifics. It presents and   *\r
29     * explains numerous examples that are written using the FreeRTOS API.     *\r
30     * Full source code for all the examples is provided in an accompanying    *\r
31     * .zip file.                                                              *\r
32     *                                                                         *\r
33     ***************************************************************************\r
34 \r
35     1 tab == 4 spaces!\r
36 \r
37     Please ensure to read the configuration and relevant port sections of the\r
38     online documentation.\r
39     \r
40     ***************************************************************************\r
41      *                                                                       *\r
42      *    Having a problem?  Start by reading the FAQ "My application does   *\r
43      *    not run, what could be wrong?                                      *\r
44      *                                                                       *\r
45      *    http://www.FreeRTOS.org/FAQHelp.html                               *\r
46      *                                                                       *\r
47     ***************************************************************************\r
48 \r
49     \r
50     http://www.FreeRTOS.org - Documentation, training, latest information, \r
51     license and contact details.\r
52     \r
53     http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,\r
54     including FreeRTOS+Trace - an indispensable productivity tool.\r
55 \r
56     Real Time Engineers ltd license FreeRTOS to High Integrity Systems, who sell \r
57     the code with commercial support, indemnification, and middleware, under \r
58     the OpenRTOS brand: http://www.OpenRTOS.com.  High Integrity Systems also\r
59     provide a safety engineered and independently SIL3 certified version under \r
60     the SafeRTOS brand: http://www.SafeRTOS.com.\r
61 */\r
62 \r
63 \r
64 /* Kernel includes. */\r
65 #include "FreeRTOS.h"\r
66 #include "semphr.h"\r
67 #include "task.h"\r
68 \r
69 /* Demo includes. */\r
70 #include "FEC.h"\r
71 #include "fecbd.h"\r
72 #include "mii.h"\r
73 #include "eth_phy.h"\r
74 #include "eth.h"\r
75 \r
76 /* uIP includes. */\r
77 #include "uip.h"\r
78 #include "uip_arp.h"\r
79 \r
80 /*-----------------------------------------------------------*/\r
81 \r
82 /* FEC hardware specifics. */\r
83 #define MCF_FEC_MSCR_MII_SPEED(x)                       (((x)&0x3F)<<0x1)\r
84 #define MCF_FEC_RDAR_R_DES_ACTIVE           ( 0x1000000 )\r
85 #define MCF_FEC_TDAR_X_DES_ACTIVE           ( 0x1000000 )\r
86 \r
87 /* PHY hardware specifics. */\r
88 #define PHY_STATUS                                                      ( 16 )\r
89 #define PHY_DUPLEX_STATUS                                       ( 4 )\r
90 \r
91 /* Delay between polling the PHY to see if a link has been established. */\r
92 #define fecLINK_DELAY                                           ( 500 / portTICK_RATE_MS )\r
93 \r
94 /* Very short delay to use when waiting for the Tx to finish with a buffer if\r
95 we run out of Rx buffers. */\r
96 #define fecMINIMAL_DELAY                                        ( 3 / portTICK_RATE_MS )\r
97 \r
98 /* Don't block to wait for a buffer more than this many times. */\r
99 #define uipBUFFER_WAIT_ATTEMPTS ( 30 )\r
100 \r
101 /* The Tx re-uses the Rx buffers and only has one descriptor. */\r
102 #define fecNUM_TX_DESCRIPTORS                           ( 1 )\r
103 \r
104 /* The total number of buffers available, which should be greater than the\r
105 number of Rx descriptors. */\r
106 #define fecNUM_BUFFERS                                          ( configNUM_FEC_RX_DESCRIPTORS + 2 )\r
107 \r
108 /*-----------------------------------------------------------*/\r
109 \r
110 /* \r
111  * Return an unused buffer to the pool of free buffers. \r
112  */\r
113 static void prvReturnBuffer( unsigned char *pucBuffer );\r
114 \r
115 /*\r
116  * Find and return the next buffer that is not in use by anything else.\r
117  */\r
118 static unsigned char *prvGetFreeBuffer( void ); \r
119 /*-----------------------------------------------------------*/\r
120 \r
121 /* The semaphore used to wake the uIP task when data arrives. */\r
122 xSemaphoreHandle xFECSemaphore = NULL;\r
123 \r
124 /* The buffer used by the uIP stack.  In this case the pointer is used to\r
125 point to one of the Rx buffers to avoid having to copy the Rx buffer into\r
126 the uIP buffer. */\r
127 unsigned char *uip_buf;\r
128 \r
129 /* The DMA descriptors.  These are char arrays to allow us to align them \r
130 correctly. */\r
131 static unsigned char xFECTxDescriptors_unaligned[ ( fecNUM_TX_DESCRIPTORS * sizeof( FECBD ) ) + 16 ];\r
132 static unsigned char xFECRxDescriptors_unaligned[ ( configNUM_FEC_RX_DESCRIPTORS * sizeof( FECBD ) ) + 16 ];\r
133 static FECBD *pxFECTxDescriptor;\r
134 static FECBD *xFECRxDescriptors;\r
135 \r
136 /* The DMA buffer.  This is a char arrays to allow it to be aligned correctly. */\r
137 static unsigned char ucFECRxBuffers[ ( fecNUM_BUFFERS * configFEC_BUFFER_SIZE ) + 16 ];\r
138 \r
139 /* Index to the next descriptor to be inspected for received data. */\r
140 static unsigned long ulNextRxDescriptor = 0;\r
141 \r
142 /* Contains the start address of each Rx buffer, after it has been correctly \r
143 aligned. */\r
144 static unsigned char *pucAlignedBufferStartAddresses[ fecNUM_BUFFERS ] = { 0 };\r
145 \r
146 /* Each ucBufferInUse index corresponds to a position in the same index in the\r
147 pucAlignedBufferStartAddresses array.  If the index contains a 1 then the \r
148 buffer within pucAlignedBufferStartAddresses is in use, if it contains a 0 then\r
149 the buffer is free. */\r
150 static unsigned char ucBufferInUse[ fecNUM_BUFFERS ] = { 0 };\r
151 \r
152 /*-----------------------------------------------------------*/\r
153 \r
154 /********************************************************************/\r
155 /*\r
156  * Write a value to a PHY's MII register.\r
157  *\r
158  * Parameters:\r
159  *  ch          FEC channel\r
160  *  phy_addr    Address of the PHY.\r
161  *  reg_addr    Address of the register in the PHY.\r
162  *  data        Data to be written to the PHY register.\r
163  *\r
164  * Return Values:\r
165  *  0 on failure\r
166  *  1 on success.\r
167  *\r
168  * Please refer to your PHY manual for registers and their meanings.\r
169  * mii_write() polls for the FEC's MII interrupt event and clears it. \r
170  * If after a suitable amount of time the event isn't triggered, a \r
171  * value of 0 is returned.\r
172  */\r
173 static int fec_mii_write( int phy_addr, int reg_addr, int data )\r
174 {\r
175 int timeout;\r
176 unsigned long eimr;\r
177 \r
178         /* Clear the MII interrupt bit */\r
179         EIR = EIR_MII;\r
180 \r
181         /* Mask the MII interrupt */\r
182         eimr = EIMR;\r
183         EIMR &= ~EIMR_MII;\r
184 \r
185         /* Write to the MII Management Frame Register to kick-off the MII write */\r
186         MMFR = ( unsigned long ) ( FEC_MMFR_ST_01 | FEC_MMFR_OP_WRITE | FEC_MMFR_PA(phy_addr) | FEC_MMFR_RA(reg_addr) | FEC_MMFR_TA_10 | FEC_MMFR_DATA( data ) );\r
187 \r
188         /* Poll for the MII interrupt (interrupt should be masked) */\r
189         for (timeout = 0; timeout < FEC_MII_TIMEOUT; timeout++)\r
190         {\r
191                 if( EIR & EIR_MII)\r
192                 {\r
193                         break;\r
194                 }\r
195         }\r
196 \r
197         if( timeout == FEC_MII_TIMEOUT )\r
198         {\r
199                 return 0;\r
200         }\r
201 \r
202         /* Clear the MII interrupt bit */\r
203         EIR = EIR_MII;\r
204 \r
205         /* Restore the EIMR */\r
206         EIMR = eimr;\r
207 \r
208         return 1;\r
209 }\r
210 \r
211 /********************************************************************/\r
212 /*\r
213  * Read a value from a PHY's MII register.\r
214  *\r
215  * Parameters:\r
216  *  ch          FEC channel\r
217  *  phy_addr    Address of the PHY.\r
218  *  reg_addr    Address of the register in the PHY.\r
219  *  data        Pointer to storage for the Data to be read\r
220  *              from the PHY register (passed by reference)\r
221  *\r
222  * Return Values:\r
223  *  0 on failure\r
224  *  1 on success.\r
225  *\r
226  * Please refer to your PHY manual for registers and their meanings.\r
227  * mii_read() polls for the FEC's MII interrupt event and clears it. \r
228  * If after a suitable amount of time the event isn't triggered, a \r
229  * value of 0 is returned.\r
230  */\r
231 static int fec_mii_read( int phy_addr, int reg_addr, unsigned short* data )\r
232 {\r
233 int timeout;\r
234 unsigned long eimr;\r
235 \r
236         /* Clear the MII interrupt bit */\r
237         EIR = 0xffffffff;\r
238 \r
239         /* Mask the MII interrupt */\r
240         eimr = EIMR;\r
241         EIMR &= ~EIMR_MII;\r
242 \r
243         /* Write to the MII Management Frame Register to kick-off the MII read */\r
244         MMFR = ( unsigned long ) ( FEC_MMFR_ST_01 | FEC_MMFR_OP_READ | FEC_MMFR_PA(phy_addr) | FEC_MMFR_RA(reg_addr) | FEC_MMFR_TA_10 );\r
245 \r
246         /* Poll for the MII interrupt (interrupt should be masked) */\r
247         for (timeout = 0; timeout < FEC_MII_TIMEOUT; timeout++)\r
248         {\r
249                 if (EIR)\r
250                 {\r
251                         break;\r
252                 }\r
253         }\r
254 \r
255         if(timeout == FEC_MII_TIMEOUT)\r
256         {\r
257                 return 0;\r
258         }\r
259 \r
260         /* Clear the MII interrupt bit */\r
261         EIR = EIR_MII;\r
262 \r
263         /* Restore the EIMR */\r
264         EIMR = eimr;\r
265 \r
266         *data = (unsigned short)(MMFR & 0x0000FFFF);\r
267 \r
268         return 1;\r
269 }\r
270 \r
271 \r
272 /********************************************************************/\r
273 /*\r
274  * Generate the hash table settings for the given address\r
275  *\r
276  * Parameters:\r
277  *  addr    48-bit (6 byte) Address to generate the hash for\r
278  *\r
279  * Return Value:\r
280  *  The 6 most significant bits of the 32-bit CRC result\r
281  */\r
282 static unsigned char fec_hash_address( const unsigned char* addr )\r
283 {\r
284 unsigned long crc;\r
285 unsigned char byte;\r
286 int i, j;\r
287 \r
288         crc = 0xFFFFFFFF;\r
289         for(i=0; i<6; ++i)\r
290         {\r
291                 byte = addr[i];\r
292                 for(j=0; j<8; ++j)\r
293                 {\r
294                         if((byte & 0x01)^(crc & 0x01))\r
295                         {\r
296                                 crc >>= 1;\r
297                                 crc = crc ^ 0xEDB88320;\r
298                         }\r
299                         else\r
300                         {\r
301                                 crc >>= 1;\r
302                         }\r
303 \r
304                         byte >>= 1;\r
305                 }\r
306         }\r
307 \r
308         return (unsigned char)(crc >> 26);\r
309 }\r
310 \r
311 /********************************************************************/\r
312 /*\r
313  * Set the Physical (Hardware) Address and the Individual Address\r
314  * Hash in the selected FEC\r
315  *\r
316  * Parameters:\r
317  *  ch  FEC channel\r
318  *  pa  Physical (Hardware) Address for the selected FEC\r
319  */\r
320 static void fec_set_address( const unsigned char *pa )\r
321 {\r
322         unsigned char crc;\r
323 \r
324         /*\r
325         * Set the Physical Address\r
326         */\r
327         PALR = (unsigned long)((pa[0]<<24) | (pa[1]<<16) | (pa[2]<<8) | pa[3]);\r
328         PAUR = (unsigned long)((pa[4]<<24) | (pa[5]<<16));\r
329 \r
330         /*\r
331         * Calculate and set the hash for given Physical Address\r
332         * in the  Individual Address Hash registers\r
333         */\r
334         crc = fec_hash_address(pa);\r
335         if(crc >= 32)\r
336         {\r
337                 IAUR |= (unsigned long)(1 << (crc - 32));\r
338         }\r
339         else\r
340         {\r
341                 IALR |= (unsigned long)(1 << crc);\r
342         }\r
343 }\r
344 /*-----------------------------------------------------------*/\r
345 \r
346 static void prvInitialiseFECBuffers( void )\r
347 {\r
348 unsigned portBASE_TYPE ux;\r
349 unsigned char *pcBufPointer;\r
350 \r
351         /* Set the pointer to a correctly aligned address. */\r
352         pcBufPointer = &( xFECTxDescriptors_unaligned[ 0 ] );\r
353         while( ( ( unsigned long ) pcBufPointer & 0x0fUL ) != 0 )\r
354         {\r
355                 pcBufPointer++;\r
356         }\r
357         \r
358         pxFECTxDescriptor = ( FECBD * ) pcBufPointer;   \r
359 \r
360         /* Likewise the pointer to the Rx descriptor. */        \r
361         pcBufPointer = &( xFECRxDescriptors_unaligned[ 0 ] );\r
362         while( ( ( unsigned long ) pcBufPointer & 0x0fUL ) != 0 )\r
363         {\r
364                 pcBufPointer++;\r
365         }\r
366         \r
367         xFECRxDescriptors = ( FECBD * ) pcBufPointer;\r
368 \r
369         /* There is no Tx buffer as the Rx buffer is reused. */\r
370         pxFECTxDescriptor->length = 0;\r
371         pxFECTxDescriptor->status = 0;\r
372 \r
373         /* Align the Rx buffers. */\r
374         pcBufPointer = &( ucFECRxBuffers[ 0 ] );\r
375         while( ( ( unsigned long ) pcBufPointer & 0x0fUL ) != 0 )\r
376         {\r
377                 pcBufPointer++;\r
378         }\r
379         \r
380         /* Then fill in the Rx descriptors. */\r
381         for( ux = 0; ux < configNUM_FEC_RX_DESCRIPTORS; ux++ )\r
382         {\r
383             xFECRxDescriptors[ ux ].status = RX_BD_E;\r
384             xFECRxDescriptors[ ux ].length = configFEC_BUFFER_SIZE;\r
385             xFECRxDescriptors[ ux ].data = pcBufPointer;\r
386                 \r
387                 /* Note the start address of the buffer now that it is correctly\r
388                 aligned. */\r
389                 pucAlignedBufferStartAddresses[ ux ] = pcBufPointer;\r
390                 \r
391                 /* The buffer is in use by the descriptor. */\r
392                 ucBufferInUse[ ux ] = pdTRUE;\r
393                 \r
394             pcBufPointer += configFEC_BUFFER_SIZE;\r
395         }\r
396         \r
397         /* Note the start address of the last buffer as one more buffer is\r
398         allocated than there are Rx descriptors. */\r
399         pucAlignedBufferStartAddresses[ ux ] = pcBufPointer;\r
400         \r
401         /* Set uip_buf to point to the last buffer. */\r
402         uip_buf = pcBufPointer;\r
403         ucBufferInUse[ ux ] = pdTRUE;\r
404 \r
405         /* Set the wrap bit in the last descriptors to form a ring. */\r
406         xFECRxDescriptors[ configNUM_FEC_RX_DESCRIPTORS - 1 ].status |= RX_BD_W;\r
407 \r
408         /* We start with descriptor 0. */\r
409         ulNextRxDescriptor = 0;\r
410 }\r
411 /*-----------------------------------------------------------*/\r
412 \r
413 void vInitFEC( void )\r
414 {\r
415 unsigned short usData;\r
416 struct uip_eth_addr xAddr;\r
417 const unsigned char ucMACAddress[6] = \r
418 {\r
419         configMAC_0, configMAC_1,configMAC_2,configMAC_3,configMAC_4,configMAC_5\r
420 };\r
421 \r
422         prvInitialiseFECBuffers();\r
423 \r
424         /* Create the semaphore used to wake the uIP task when data arrives. */\r
425         vSemaphoreCreateBinary( xFECSemaphore );\r
426         \r
427         /* Set the MAC address within the stack. */\r
428         for( usData = 0; usData < 6; usData++ )\r
429         {\r
430                 xAddr.addr[ usData ] = ucMACAddress[ usData ];\r
431         }\r
432         uip_setethaddr( xAddr );        \r
433 \r
434         /* Set the Reset bit and clear the Enable bit */\r
435         ECR_RESET = 1;\r
436         \r
437         /* Enable the clock. */\r
438         SCGC4 |= SCGC4_FEC_MASK;\r
439 \r
440         /* Wait at least 8 clock cycles */\r
441         for( usData = 0; usData < 10; usData++ )\r
442         {\r
443                 asm( "NOP" );\r
444         }\r
445 \r
446         /* Set MII speed to 2.5MHz. */\r
447         MSCR = MCF_FEC_MSCR_MII_SPEED( ( ( configCPU_CLOCK_HZ / 1000000 ) / 5 ) + 1 );\r
448 \r
449         /*\r
450          * Make sure the external interface signals are enabled\r
451          */\r
452     PTCPF2_C0 = 1;\r
453     PTCPF2_C1 = 1;\r
454     PTCPF2_C2 = 1;\r
455     PTAPF1 = 0x55;\r
456     PTAPF2 = 0x55;\r
457     PTBPF1 = 0x55;\r
458     PTBPF2 = 0x55;\r
459     \r
460     /* Set all pins to full drive with no filter. */\r
461     PTADS = 0x06;\r
462     PTAIFE = 0x06;\r
463     PTBDS = 0xf4;\r
464     PTBIFE = 0xf4;\r
465     PTCDS = 0;\r
466     PTCIFE = 0;                         \r
467 \r
468     \r
469         /* Can we talk to the PHY? */\r
470         do\r
471         {\r
472                 vTaskDelay( fecLINK_DELAY );\r
473                 usData = 0xffff;\r
474                 fec_mii_read( configPHY_ADDRESS, PHY_PHYIDR1, &usData );\r
475 \r
476         } while( usData == 0xffff );\r
477 \r
478         /* Start auto negotiate. */\r
479         fec_mii_write( configPHY_ADDRESS, PHY_BMCR, ( PHY_BMCR_AN_RESTART | PHY_BMCR_AN_ENABLE ) );\r
480 \r
481         /* Wait for auto negotiate to complete. */\r
482         do\r
483         {\r
484                 vTaskDelay( fecLINK_DELAY );\r
485                 fec_mii_read( configPHY_ADDRESS, PHY_BMSR, &usData );\r
486 \r
487         } while( !( usData & PHY_BMSR_AN_COMPLETE ) );\r
488 \r
489         /* When we get here we have a link - find out what has been negotiated. */\r
490         usData = 0;\r
491         fec_mii_read( configPHY_ADDRESS, PHY_STATUS, &usData ); \r
492 \r
493         /* Setup half or full duplex. */\r
494         if( usData & PHY_DUPLEX_STATUS )\r
495         {\r
496                 RCR &= (unsigned long)~RCR_DRT;\r
497                 TCR |= TCR_FDEN;\r
498         }\r
499         else\r
500         {\r
501                 RCR |= RCR_DRT;\r
502                 TCR &= (unsigned long)~TCR_FDEN;\r
503         }\r
504         \r
505         /* Clear the Individual and Group Address Hash registers */\r
506         IALR = 0;\r
507         IAUR = 0;\r
508         GALR = 0;\r
509         GAUR = 0;\r
510 \r
511         /* Set the Physical Address for the selected FEC */\r
512         fec_set_address( ucMACAddress );\r
513 \r
514         /* Set Rx Buffer Size */\r
515         EMRBR = (unsigned short) configFEC_BUFFER_SIZE;\r
516 \r
517         /* Point to the start of the circular Rx buffer descriptor queue */\r
518         ERDSR = ( volatile unsigned long ) &( xFECRxDescriptors[ 0 ] );\r
519 \r
520         /* Point to the start of the circular Tx buffer descriptor queue */\r
521         ETSDR = ( volatile unsigned long ) pxFECTxDescriptor;\r
522 \r
523         /* Clear all FEC interrupt events */\r
524         EIR = ( unsigned long ) -1;\r
525 \r
526         /* Various mode/status setup. */\r
527         RCR = 0;\r
528         RCR_MAX_FL = configFEC_BUFFER_SIZE;\r
529         RCR_MII_MODE = 1;\r
530 \r
531         #if( configUSE_PROMISCUOUS_MODE == 1 )\r
532         {\r
533                 RCR |= RCR_PROM;\r
534         }\r
535         #endif\r
536 \r
537         /* Enable interrupts. */\r
538         EIMR = EIR_TXF_MASK | EIMR_RXF_MASK | EIMR_RXB_MASK | EIMR_UN_MASK | EIMR_RL_MASK | EIMR_LC_MASK | EIMR_BABT_MASK | EIMR_BABR_MASK | EIMR_HBERR_MASK;\r
539 \r
540         /* Enable the MAC itself. */\r
541     ECR = ECR_ETHER_EN_MASK;\r
542 \r
543     /* Indicate that there have been empty receive buffers produced */\r
544     RDAR = MCF_FEC_RDAR_R_DES_ACTIVE;\r
545 }\r
546 /*-----------------------------------------------------------*/\r
547 \r
548 unsigned long ulFECRx( void )\r
549 {\r
550 unsigned long ulLen = 0UL;\r
551 \r
552         /* Is a buffer ready? */\r
553         if( ( xFECRxDescriptors[ ulNextRxDescriptor ].status & RX_BD_E ) == 0 )\r
554         {\r
555                 /* uip_buf is about to be set to a new buffer, so return the buffer it\r
556                 is already pointing to. */\r
557                 prvReturnBuffer( uip_buf );\r
558         \r
559                 /* Obtain the size of the packet and put it into the "len" variable. */\r
560                 ulLen = xFECRxDescriptors[ ulNextRxDescriptor ].length;\r
561                 uip_buf = xFECRxDescriptors[ ulNextRxDescriptor ].data;\r
562 \r
563                 /* The buffer that this descriptor was using is now in use by the\r
564                 TCP/IP stack, so allocate it a new buffer. */\r
565                 xFECRxDescriptors[ ulNextRxDescriptor ].data = prvGetFreeBuffer();\r
566 \r
567                 /* Doing this here could cause corruption! */           \r
568                 xFECRxDescriptors[ ulNextRxDescriptor ].status |= RX_BD_E;              \r
569                 \r
570                 portENTER_CRITICAL();\r
571                 {\r
572                         ulNextRxDescriptor++;\r
573                         if( ulNextRxDescriptor >= configNUM_FEC_RX_DESCRIPTORS )\r
574                         {\r
575                                 ulNextRxDescriptor = 0;\r
576                         }\r
577                 }\r
578                 portEXIT_CRITICAL();    \r
579 \r
580                 /* Tell the DMA a new buffer is available. */\r
581                 RDAR = MCF_FEC_RDAR_R_DES_ACTIVE;               \r
582         }\r
583 \r
584     return ulLen;\r
585 }\r
586 /*-----------------------------------------------------------*/\r
587 \r
588 void vFECTx( void )\r
589 {\r
590         /* When we get here the Tx descriptor should show as having completed. */\r
591         while( pxFECTxDescriptor->status & TX_BD_R )\r
592         {\r
593                 vTaskDelay( fecMINIMAL_DELAY );\r
594         }\r
595 \r
596         portENTER_CRITICAL();\r
597         {\r
598                 /* To maintain the zero copy implementation, point the Tx descriptor\r
599                 to the data from the Rx buffer. */\r
600                 pxFECTxDescriptor->data = uip_buf;\r
601                 \r
602                 /* Setup the buffer descriptor for transmission */\r
603                 pxFECTxDescriptor->length = uip_len;\r
604                 \r
605                 /* NB this assumes only one Tx descriptor! */\r
606                 pxFECTxDescriptor->status = ( TX_BD_R | TX_BD_L | TX_BD_TC | TX_BD_W );\r
607         }\r
608         portEXIT_CRITICAL();\r
609         \r
610         /* Continue the Tx DMA task (in case it was waiting for a new TxBD) */\r
611         TDAR = MCF_FEC_TDAR_X_DES_ACTIVE;\r
612         \r
613         /* uip_buf is being used by the Tx descriptor.  Allocate a new buffer to\r
614         uip_buf. */\r
615         uip_buf = prvGetFreeBuffer();\r
616 }\r
617 /*-----------------------------------------------------------*/\r
618 \r
619 static void prvReturnBuffer( unsigned char *pucBuffer )\r
620 {\r
621 unsigned long ul;\r
622 \r
623         /* Mark a buffer as free for use. */\r
624         for( ul = 0; ul < fecNUM_BUFFERS; ul++ )\r
625         {\r
626                 if( pucAlignedBufferStartAddresses[ ul ] == pucBuffer )\r
627                 {\r
628                         ucBufferInUse[ ul ] = pdFALSE;\r
629                         break;\r
630                 }\r
631         }\r
632 }\r
633 /*-----------------------------------------------------------*/\r
634 \r
635 static unsigned char *prvGetFreeBuffer( void )\r
636 {\r
637 portBASE_TYPE x;\r
638 unsigned char *pucReturn = NULL;\r
639 unsigned long ulAttempts = 0;\r
640 \r
641         while( pucReturn == NULL )\r
642         {\r
643                 /* Look through the buffers to find one that is not in use by\r
644                 anything else. */\r
645                 for( x = 0; x < fecNUM_BUFFERS; x++ )\r
646                 {\r
647                         if( ucBufferInUse[ x ] == pdFALSE )\r
648                         {\r
649                                 ucBufferInUse[ x ] = pdTRUE;\r
650                                 pucReturn = pucAlignedBufferStartAddresses[ x ];\r
651                                 break;\r
652                         }\r
653                 }\r
654 \r
655                 /* Was a buffer found? */\r
656                 if( pucReturn == NULL )\r
657                 {\r
658                         ulAttempts++;\r
659 \r
660                         if( ulAttempts >= uipBUFFER_WAIT_ATTEMPTS )\r
661                         {\r
662                                 break;\r
663                         }\r
664 \r
665                         /* Wait then look again. */\r
666                         vTaskDelay( fecMINIMAL_DELAY );\r
667                 }\r
668         }\r
669 \r
670         return pucReturn;\r
671 }\r
672 /*-----------------------------------------------------------*/\r
673 \r
674 void interrupt 86 vFECISRHandler( void )\r
675 {\r
676 unsigned long ulEvent;\r
677 portBASE_TYPE xHighPriorityTaskWoken = pdFALSE;\r
678    \r
679         /* Determine the cause of the interrupt. */\r
680         ulEvent = EIR & EIMR;\r
681         EIR = ulEvent;\r
682 \r
683         if( ulEvent & EIR_RXF_MASK )\r
684         {\r
685                 /* A packet has been received.  Wake the handler task in case it is \r
686                 blocked. */\r
687                 xSemaphoreGiveFromISR( xFECSemaphore, &xHighPriorityTaskWoken );\r
688         }\r
689         \r
690         if( ulEvent & EIR_TXF_MASK )\r
691         {\r
692                 /* The Tx has completed.  Mark the buffer it was using as free again. */\r
693                 prvReturnBuffer( pxFECTxDescriptor->data );\r
694                 pxFECTxDescriptor->data = NULL;\r
695         }\r
696 \r
697         if (ulEvent & ( EIR_UN_MASK | EIR_RL_MASK | EIR_LC_MASK | EIR_EBERR_MASK | EIR_BABT_MASK | EIR_BABR_MASK | EIR_HBERR_MASK ) )\r
698         {\r
699                 /* Sledge hammer error handling. */\r
700                 prvInitialiseFECBuffers();\r
701                 RDAR = MCF_FEC_RDAR_R_DES_ACTIVE;\r
702         }\r
703 \r
704         portEND_SWITCHING_ISR( xHighPriorityTaskWoken );\r
705 }\r