]> git.sur5r.net Git - freertos/blob - Demo/ColdFire_MCF52233_Eclipse/RTOSDemo/webserver/FEC.c
Update to V5.4.1
[freertos] / Demo / ColdFire_MCF52233_Eclipse / RTOSDemo / webserver / FEC.c
1 /*\r
2         FreeRTOS V5.4.1 - Copyright (C) 2009 Real Time Engineers Ltd.\r
3 \r
4         This file is part of the FreeRTOS distribution.\r
5 \r
6         FreeRTOS is free software; you can redistribute it and/or modify it     under \r
7         the terms of the GNU General Public License (version 2) as published by the \r
8         Free Software Foundation and modified by the FreeRTOS exception.\r
9         **NOTE** The exception to the GPL is included to allow you to distribute a\r
10         combined work that includes FreeRTOS without being obliged to provide the \r
11         source code for proprietary components outside of the FreeRTOS kernel.  \r
12         Alternative commercial license and support terms are also available upon \r
13         request.  See the licensing section of http://www.FreeRTOS.org for full \r
14         license details.\r
15 \r
16         FreeRTOS is distributed in the hope that it will be useful,     but WITHOUT\r
17         ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\r
18         FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\r
19         more details.\r
20 \r
21         You should have received a copy of the GNU General Public License along\r
22         with FreeRTOS; if not, write to the Free Software Foundation, Inc., 59\r
23         Temple Place, Suite 330, Boston, MA  02111-1307  USA.\r
24 \r
25 \r
26         ***************************************************************************\r
27         *                                                                         *\r
28         * Looking for a quick start?  Then check out the FreeRTOS eBook!          *\r
29         * See http://www.FreeRTOS.org/Documentation for details                   *\r
30         *                                                                         *\r
31         ***************************************************************************\r
32 \r
33         1 tab == 4 spaces!\r
34 \r
35         Please ensure to read the configuration and relevant port sections of the\r
36         online documentation.\r
37 \r
38         http://www.FreeRTOS.org - Documentation, latest information, license and\r
39         contact details.\r
40 \r
41         http://www.SafeRTOS.com - A version that is certified for use in safety\r
42         critical systems.\r
43 \r
44         http://www.OpenRTOS.com - Commercial support, development, porting,\r
45         licensing and training services.\r
46 */\r
47 \r
48 /* Kernel includes. */\r
49 #include "FreeRTOS.h"\r
50 #include "semphr.h"\r
51 #include "task.h"\r
52 \r
53 /* Hardware includes. */\r
54 #include "fecbd.h"\r
55 #include "mii.h"\r
56 #include "eth_phy.h"\r
57 #include "eth.h"\r
58 \r
59 /* uIP includes. */\r
60 #include "uip.h"\r
61 #include "uip_arp.h"\r
62 \r
63 /* Delay between polling the PHY to see if a link has been established. */\r
64 #define fecLINK_DELAY                                                   ( 500 / portTICK_RATE_MS )\r
65 \r
66 /* Delay to wait for an MII access. */\r
67 #define fecMII_DELAY                                                    ( 10 / portTICK_RATE_MS )\r
68 #define fecMAX_POLLS                                                    ( 20 )\r
69 \r
70 /* Constants used to delay while waiting for a tx descriptor to be free. */\r
71 #define fecMAX_WAIT_FOR_TX_BUFFER                                               ( 200 / portTICK_RATE_MS )\r
72 \r
73 /* We only use a single Tx descriptor which can lead to Txed packets being sent\r
74 twice (due to a bug in the FEC silicon).  However, in this case the bug is used\r
75 to our advantage in that it means the uip-split mechanism is not required. */\r
76 #define fecNUM_FEC_TX_BUFFERS                                   ( 1 )\r
77 #define fecTX_BUFFER_TO_USE                                             ( 0 )\r
78 /*-----------------------------------------------------------*/\r
79 \r
80 /* The semaphore used to wake the uIP task when data arrives. */\r
81 xSemaphoreHandle xFECSemaphore = NULL, xTxSemaphore = NULL;\r
82 \r
83 /* The buffer used by the uIP stack.  In this case the pointer is used to\r
84 point to one of the Rx buffers to effect a zero copy policy. */\r
85 unsigned portCHAR *uip_buf;\r
86 \r
87 /* The DMA descriptors.  This is a char array to allow us to align it correctly. */\r
88 static unsigned portCHAR xFECTxDescriptors_unaligned[ ( fecNUM_FEC_TX_BUFFERS * sizeof( FECBD ) ) + 16 ];\r
89 static unsigned portCHAR xFECRxDescriptors_unaligned[ ( configNUM_FEC_RX_BUFFERS * sizeof( FECBD ) ) + 16 ];\r
90 static FECBD *xFECTxDescriptors;\r
91 static FECBD *xFECRxDescriptors;\r
92 \r
93 /* The DMA buffers.  These are char arrays to allow them to be aligned correctly. */\r
94 static unsigned portCHAR ucFECRxBuffers[ ( configNUM_FEC_RX_BUFFERS * configFEC_BUFFER_SIZE ) + 16 ];\r
95 static unsigned portBASE_TYPE uxNextRxBuffer = 0, uxIndexToBufferOwner = 0;\r
96 \r
97 /*-----------------------------------------------------------*/\r
98 \r
99 /*\r
100  * Enable all the required interrupts in the FEC and in the interrupt controller.\r
101  */\r
102 static void prvEnableFECInterrupts( void );\r
103 \r
104 /*\r
105  * Reset the FEC if we get into an unrecoverable state.\r
106  */\r
107 static void prvResetFEC( portBASE_TYPE xCalledFromISR );\r
108 \r
109 /********************************************************************/\r
110 \r
111 /*\r
112  * FUNCTION ADAPTED FROM FREESCALE SUPPLIED SOURCE\r
113  *\r
114  * Write a value to a PHY's MII register.\r
115  *\r
116  * Parameters:\r
117  *  ch          FEC channel\r
118  *  phy_addr    Address of the PHY.\r
119  *  reg_addr    Address of the register in the PHY.\r
120  *  data        Data to be written to the PHY register.\r
121  *\r
122  * Return Values:\r
123  *  0 on failure\r
124  *  1 on success.\r
125  *\r
126  * Please refer to your PHY manual for registers and their meanings.\r
127  * mii_write() polls for the FEC's MII interrupt event and clears it.\r
128  * If after a suitable amount of time the event isn't triggered, a\r
129  * value of 0 is returned.\r
130  */\r
131 static int fec_mii_write( int phy_addr, int reg_addr, int data )\r
132 {\r
133 int timeout, iReturn;\r
134 uint32 eimr;\r
135 \r
136     /* Clear the MII interrupt bit */\r
137     MCF_FEC_EIR = MCF_FEC_EIR_MII;\r
138 \r
139     /* Mask the MII interrupt */\r
140     eimr = MCF_FEC_EIMR;\r
141     MCF_FEC_EIMR &= ~MCF_FEC_EIMR_MII;\r
142 \r
143     /* Write to the MII Management Frame Register to kick-off the MII write */\r
144     MCF_FEC_MMFR = MCF_FEC_MMFR_ST_01 | MCF_FEC_MMFR_OP_WRITE | MCF_FEC_MMFR_PA(phy_addr) | MCF_FEC_MMFR_RA(reg_addr) | MCF_FEC_MMFR_TA_10 | MCF_FEC_MMFR_DATA( data );\r
145 \r
146     /* Poll for the MII interrupt (interrupt should be masked) */\r
147     for( timeout = 0; timeout < fecMAX_POLLS; timeout++ )\r
148     {\r
149         if( MCF_FEC_EIR & MCF_FEC_EIR_MII )\r
150         {\r
151                         break;\r
152         }\r
153         else\r
154         {\r
155                 vTaskDelay( fecMII_DELAY );\r
156         }\r
157     }\r
158 \r
159     if( timeout == fecMAX_POLLS )\r
160     {\r
161         iReturn = 0;\r
162     }\r
163     else\r
164     {\r
165                 iReturn = 1;\r
166     }\r
167 \r
168         /* Clear the MII interrupt bit */\r
169         MCF_FEC_EIR = MCF_FEC_EIR_MII;\r
170 \r
171         /* Restore the EIMR */\r
172         MCF_FEC_EIMR = eimr;\r
173 \r
174     return iReturn;\r
175 }\r
176 \r
177 /********************************************************************/\r
178 /*\r
179  * FUNCTION ADAPTED FROM FREESCALE SUPPLIED SOURCE\r
180  *\r
181  * Read a value from a PHY's MII register.\r
182  *\r
183  * Parameters:\r
184  *  ch          FEC channel\r
185  *  phy_addr    Address of the PHY.\r
186  *  reg_addr    Address of the register in the PHY.\r
187  *  data        Pointer to storage for the Data to be read\r
188  *              from the PHY register (passed by reference)\r
189  *\r
190  * Return Values:\r
191  *  0 on failure\r
192  *  1 on success.\r
193  *\r
194  * Please refer to your PHY manual for registers and their meanings.\r
195  * mii_read() polls for the FEC's MII interrupt event and clears it.\r
196  * If after a suitable amount of time the event isn't triggered, a\r
197  * value of 0 is returned.\r
198  */\r
199 static int fec_mii_read( int phy_addr, int reg_addr, unsigned portSHORT* data )\r
200 {\r
201 int timeout, iReturn;\r
202 uint32 eimr;\r
203 \r
204     /* Clear the MII interrupt bit */\r
205     MCF_FEC_EIR = MCF_FEC_EIR_MII;\r
206 \r
207     /* Mask the MII interrupt */\r
208     eimr = MCF_FEC_EIMR;\r
209     MCF_FEC_EIMR &= ~MCF_FEC_EIMR_MII;\r
210 \r
211     /* Write to the MII Management Frame Register to kick-off the MII read */\r
212     MCF_FEC_MMFR = MCF_FEC_MMFR_ST_01 | MCF_FEC_MMFR_OP_READ | MCF_FEC_MMFR_PA(phy_addr) | MCF_FEC_MMFR_RA(reg_addr) | MCF_FEC_MMFR_TA_10;\r
213 \r
214     /* Poll for the MII interrupt (interrupt should be masked) */\r
215     for( timeout = 0; timeout < fecMAX_POLLS; timeout++ )\r
216     {\r
217         if (MCF_FEC_EIR & MCF_FEC_EIR_MII)\r
218         {\r
219             break;\r
220         }\r
221         else\r
222         {\r
223                 vTaskDelay( fecMII_DELAY );\r
224         }\r
225     }\r
226 \r
227     if( timeout == fecMAX_POLLS )\r
228     {\r
229         iReturn = 0;\r
230     }\r
231     else\r
232     {\r
233                 *data = (uint16)(MCF_FEC_MMFR & 0x0000FFFF);\r
234                 iReturn = 1;\r
235     }\r
236 \r
237         /* Clear the MII interrupt bit */\r
238         MCF_FEC_EIR = MCF_FEC_EIR_MII;\r
239 \r
240         /* Restore the EIMR */\r
241         MCF_FEC_EIMR = eimr;\r
242 \r
243     return iReturn;\r
244 }\r
245 \r
246 \r
247 /********************************************************************/\r
248 /*\r
249  * FUNCTION ADAPTED FROM FREESCALE SUPPLIED SOURCE\r
250  *\r
251  * Generate the hash table settings for the given address\r
252  *\r
253  * Parameters:\r
254  *  addr    48-bit (6 byte) Address to generate the hash for\r
255  *\r
256  * Return Value:\r
257  *  The 6 most significant bits of the 32-bit CRC result\r
258  */\r
259 static unsigned portCHAR fec_hash_address( const unsigned portCHAR* addr )\r
260 {\r
261 unsigned portLONG crc;\r
262 unsigned portCHAR byte;\r
263 int i, j;\r
264 \r
265         crc = 0xFFFFFFFF;\r
266         for(i=0; i<6; ++i)\r
267         {\r
268                 byte = addr[i];\r
269                 for(j=0; j<8; ++j)\r
270                 {\r
271                         if((byte & 0x01)^(crc & 0x01))\r
272                         {\r
273                                 crc >>= 1;\r
274                                 crc = crc ^ 0xEDB88320;\r
275                         }\r
276                         else\r
277                         {\r
278                                 crc >>= 1;\r
279                         }\r
280 \r
281                         byte >>= 1;\r
282                 }\r
283         }\r
284 \r
285         return (unsigned portCHAR)(crc >> 26);\r
286 }\r
287 \r
288 /********************************************************************/\r
289 /*\r
290  * FUNCTION ADAPTED FROM FREESCALE SUPPLIED SOURCE\r
291  *\r
292  * Set the Physical (Hardware) Address and the Individual Address\r
293  * Hash in the selected FEC\r
294  *\r
295  * Parameters:\r
296  *  ch  FEC channel\r
297  *  pa  Physical (Hardware) Address for the selected FEC\r
298  */\r
299 static void fec_set_address( const unsigned portCHAR *pa )\r
300 {\r
301         unsigned portCHAR crc;\r
302 \r
303         /*\r
304         * Set the Physical Address\r
305         */\r
306         /* Set the source address for the controller */\r
307         MCF_FEC_PALR = ( pa[ 0 ] << 24 ) | ( pa[ 1 ] << 16 ) | ( pa[ 2 ] << 8 ) | ( pa[ 3 ] << 0 );\r
308         MCF_FEC_PAUR = ( pa[ 4 ] << 24 ) | ( pa[ 5 ] << 16 );\r
309 \r
310         /*\r
311         * Calculate and set the hash for given Physical Address\r
312         * in the  Individual Address Hash registers\r
313         */\r
314         crc = fec_hash_address( pa );\r
315         if( crc >= 32 )\r
316         {\r
317                 MCF_FEC_IAUR |= (unsigned portLONG)(1 << (crc - 32));\r
318         }\r
319         else\r
320         {\r
321                 MCF_FEC_IALR |= (unsigned portLONG)(1 << crc);\r
322         }\r
323 }\r
324 /*-----------------------------------------------------------*/\r
325 \r
326 static void prvInitialiseFECBuffers( void )\r
327 {\r
328 unsigned portBASE_TYPE ux;\r
329 unsigned portCHAR *pcBufPointer;\r
330 \r
331         /* Correctly align the Tx descriptor pointer. */\r
332         pcBufPointer = &( xFECTxDescriptors_unaligned[ 0 ] );\r
333         while( ( ( unsigned portLONG ) pcBufPointer & 0x0fUL ) != 0 )\r
334         {\r
335                 pcBufPointer++;\r
336         }\r
337 \r
338         xFECTxDescriptors = ( FECBD * ) pcBufPointer;\r
339 \r
340         /* Likewise the Rx descriptor pointer. */\r
341         pcBufPointer = &( xFECRxDescriptors_unaligned[ 0 ] );\r
342         while( ( ( unsigned portLONG ) pcBufPointer & 0x0fUL ) != 0 )\r
343         {\r
344                 pcBufPointer++;\r
345         }\r
346 \r
347         xFECRxDescriptors = ( FECBD * ) pcBufPointer;\r
348 \r
349 \r
350         /* Setup the Tx buffers and descriptors.  There is no separate Tx buffer\r
351         to point to (the Rx buffers are actually used) so the data member is\r
352         set to NULL for now. */\r
353         for( ux = 0; ux < fecNUM_FEC_TX_BUFFERS; ux++ )\r
354         {\r
355                 xFECTxDescriptors[ ux ].status = TX_BD_TC;\r
356                 xFECTxDescriptors[ ux ].data = NULL;\r
357                 xFECTxDescriptors[ ux ].length = 0;\r
358         }\r
359 \r
360         /* Setup the Rx buffers and descriptors, having first ensured correct\r
361         alignment. */\r
362         pcBufPointer = &( ucFECRxBuffers[ 0 ] );\r
363         while( ( ( unsigned portLONG ) pcBufPointer & 0x0fUL ) != 0 )\r
364         {\r
365                 pcBufPointer++;\r
366         }\r
367 \r
368         for( ux = 0; ux < configNUM_FEC_RX_BUFFERS; ux++ )\r
369         {\r
370             xFECRxDescriptors[ ux ].status = RX_BD_E;\r
371             xFECRxDescriptors[ ux ].length = configFEC_BUFFER_SIZE;\r
372             xFECRxDescriptors[ ux ].data = pcBufPointer;\r
373             pcBufPointer += configFEC_BUFFER_SIZE;\r
374         }\r
375 \r
376         /* Set the wrap bit in the last descriptors to form a ring. */\r
377         xFECTxDescriptors[ fecNUM_FEC_TX_BUFFERS - 1 ].status |= TX_BD_W;\r
378         xFECRxDescriptors[ configNUM_FEC_RX_BUFFERS - 1 ].status |= RX_BD_W;\r
379 \r
380         uxNextRxBuffer = 0;\r
381 }\r
382 /*-----------------------------------------------------------*/\r
383 \r
384 void vFECInit( void )\r
385 {\r
386 unsigned portSHORT usData;\r
387 struct uip_eth_addr xAddr;\r
388 unsigned portBASE_TYPE ux;\r
389 \r
390 /* The MAC address is set at the foot of FreeRTOSConfig.h. */\r
391 const unsigned portCHAR ucMACAddress[6] =\r
392 {\r
393         configMAC_0, configMAC_1,configMAC_2, configMAC_3, configMAC_4, configMAC_5\r
394 };\r
395 \r
396         /* Create the semaphore used by the ISR to wake the uIP task. */\r
397         vSemaphoreCreateBinary( xFECSemaphore );\r
398 \r
399         /* Create the semaphore used to unblock any tasks that might be waiting\r
400         for a Tx descriptor. */\r
401         vSemaphoreCreateBinary( xTxSemaphore );\r
402 \r
403         /* Initialise all the buffers and descriptors used by the DMA. */\r
404         prvInitialiseFECBuffers();\r
405 \r
406         for( usData = 0; usData < 6; usData++ )\r
407         {\r
408                 xAddr.addr[ usData ] = ucMACAddress[ usData ];\r
409         }\r
410         uip_setethaddr( xAddr );\r
411 \r
412         /* Set the Reset bit and clear the Enable bit */\r
413         MCF_FEC_ECR = MCF_FEC_ECR_RESET;\r
414 \r
415         /* Wait at least 8 clock cycles */\r
416         for( usData = 0; usData < 10; usData++ )\r
417         {\r
418                 asm( "NOP" );\r
419         }\r
420 \r
421         /* Set MII speed to 2.5MHz. */\r
422         MCF_FEC_MSCR = MCF_FEC_MSCR_MII_SPEED( ( ( ( configCPU_CLOCK_HZ / 1000000 ) / 5 ) + 1 ) );\r
423 \r
424         /* Initialize PLDPAR to enable Ethernet LEDs. */\r
425         MCF_GPIO_PLDPAR =  MCF_GPIO_PLDPAR_ACTLED_ACTLED | MCF_GPIO_PLDPAR_LINKLED_LINKLED | MCF_GPIO_PLDPAR_SPDLED_SPDLED\r
426                                          | MCF_GPIO_PLDPAR_DUPLED_DUPLED | MCF_GPIO_PLDPAR_COLLED_COLLED | MCF_GPIO_PLDPAR_RXLED_RXLED\r
427                                          | MCF_GPIO_PLDPAR_TXLED_TXLED;\r
428 \r
429         /* Initialize Port TA to enable Axcel control. */\r
430         MCF_GPIO_PTAPAR = 0x00;\r
431         MCF_GPIO_DDRTA  = 0x0F;\r
432         MCF_GPIO_PORTTA = 0x04;\r
433 \r
434         /* Set phy address to zero. */\r
435         MCF_EPHY_EPHYCTL1 = MCF_EPHY_EPHYCTL1_PHYADD( 0 );\r
436 \r
437         /* Enable EPHY module with PHY clocks disabled.  Do not turn on PHY clocks\r
438         until both FEC and EPHY are completely setup (see Below). */\r
439         MCF_EPHY_EPHYCTL0 = (uint8)(MCF_EPHY_EPHYCTL0_DIS100 | MCF_EPHY_EPHYCTL0_DIS10);\r
440 \r
441         /* Enable auto_neg at start-up */\r
442         MCF_EPHY_EPHYCTL0 = (uint8)(MCF_EPHY_EPHYCTL0 & (MCF_EPHY_EPHYCTL0_ANDIS));\r
443 \r
444         /* Enable EPHY module. */\r
445         MCF_EPHY_EPHYCTL0 = (uint8)(MCF_EPHY_EPHYCTL0_EPHYEN | MCF_EPHY_EPHYCTL0);\r
446 \r
447         /* Let PHY PLLs be determined by PHY. */\r
448         MCF_EPHY_EPHYCTL0 = (uint8)(MCF_EPHY_EPHYCTL0  & ~(MCF_EPHY_EPHYCTL0_DIS100 | MCF_EPHY_EPHYCTL0_DIS10));\r
449 \r
450         /* Settle. */\r
451         vTaskDelay( fecLINK_DELAY );\r
452 \r
453         /* Can we talk to the PHY? */\r
454         do\r
455         {\r
456                 vTaskDelay( fecLINK_DELAY );\r
457                 usData = 0;\r
458                 fec_mii_read( configPHY_ADDRESS, PHY_PHYIDR1, &usData );\r
459 \r
460         } while( usData == 0xffff );\r
461 \r
462         do\r
463         {\r
464                 /* Start auto negotiate. */\r
465                 fec_mii_write( configPHY_ADDRESS, PHY_BMCR, ( PHY_BMCR_AN_RESTART | PHY_BMCR_AN_ENABLE ) );\r
466 \r
467                 /* Wait for auto negotiate to complete. */\r
468                 do\r
469                 {\r
470                         ux++;\r
471                         if( ux > 10 )\r
472                         {\r
473                                 /* Hardware bug workaround!  Force 100Mbps half duplex. */\r
474                                 while( !fec_mii_read( configPHY_ADDRESS, 0, &usData ) ){};\r
475                                 usData &= ~0x2000;                                                      /* 10Mbps */\r
476                                 usData &= ~0x0100;                                                      /* Half Duplex */\r
477                                 usData &= ~0x1000;                                                      /* Manual Mode */\r
478                                 while( !fec_mii_write( configPHY_ADDRESS, 0, usData ) ){};\r
479                                 while( !fec_mii_write( configPHY_ADDRESS, 0, (usData|0x0200) )){}; /* Force re-negotiate */\r
480                                 break;\r
481                         }\r
482                         vTaskDelay( fecLINK_DELAY );\r
483                         fec_mii_read( configPHY_ADDRESS, PHY_BMSR, &usData );\r
484 \r
485                 } while( !( usData & PHY_BMSR_AN_COMPLETE ) );\r
486 \r
487         } while( 0 ); //while( !( usData & PHY_BMSR_LINK ) );\r
488 \r
489         /* When we get here we have a link - find out what has been negotiated. */\r
490         fec_mii_read( configPHY_ADDRESS, PHY_ANLPAR, &usData );\r
491 \r
492         if( ( usData & PHY_ANLPAR_100BTX_FDX ) || ( usData & PHY_ANLPAR_100BTX ) )\r
493         {\r
494                 /* Speed is 100. */\r
495         }\r
496         else\r
497         {\r
498                 /* Speed is 10. */\r
499         }\r
500 \r
501         if( ( usData & PHY_ANLPAR_100BTX_FDX ) || ( usData & PHY_ANLPAR_10BTX_FDX ) )\r
502         {\r
503                 MCF_FEC_RCR &= (unsigned portLONG)~MCF_FEC_RCR_DRT;\r
504                 MCF_FEC_TCR |= MCF_FEC_TCR_FDEN;\r
505         }\r
506         else\r
507         {\r
508                 MCF_FEC_RCR |= MCF_FEC_RCR_DRT;\r
509                 MCF_FEC_TCR &= (unsigned portLONG)~MCF_FEC_TCR_FDEN;\r
510         }\r
511 \r
512         /* Clear the Individual and Group Address Hash registers */\r
513         MCF_FEC_IALR = 0;\r
514         MCF_FEC_IAUR = 0;\r
515         MCF_FEC_GALR = 0;\r
516         MCF_FEC_GAUR = 0;\r
517 \r
518         /* Set the Physical Address for the selected FEC */\r
519         fec_set_address( ucMACAddress );\r
520 \r
521         /* Set Rx Buffer Size */\r
522         MCF_FEC_EMRBR = (unsigned portSHORT)configFEC_BUFFER_SIZE;\r
523 \r
524         /* Point to the start of the circular Rx buffer descriptor queue */\r
525         MCF_FEC_ERDSR = ( volatile unsigned portLONG ) &( xFECRxDescriptors[ 0 ] );\r
526 \r
527         /* Point to the start of the circular Tx buffer descriptor queue */\r
528         MCF_FEC_ETSDR = ( volatile unsigned portLONG ) &( xFECTxDescriptors[ 0 ] );\r
529 \r
530         /* Mask all FEC interrupts */\r
531         MCF_FEC_EIMR = ( unsigned portLONG ) -1;\r
532 \r
533         /* Clear all FEC interrupt events */\r
534         MCF_FEC_EIR = ( unsigned portLONG ) -1;\r
535 \r
536         /* Initialize the Receive Control Register */\r
537         MCF_FEC_RCR = MCF_FEC_RCR_MAX_FL(ETH_MAX_FRM) | MCF_FEC_RCR_FCE;\r
538 \r
539         MCF_FEC_RCR |= MCF_FEC_RCR_MII_MODE;\r
540 \r
541         #if( configUSE_PROMISCUOUS_MODE == 1 )\r
542         {\r
543                 MCF_FEC_RCR |= MCF_FEC_RCR_PROM;\r
544         }\r
545         #endif\r
546 \r
547         prvEnableFECInterrupts();\r
548 \r
549         /* Finally... enable. */\r
550         MCF_FEC_ECR = MCF_FEC_ECR_ETHER_EN;\r
551         MCF_FEC_RDAR = MCF_FEC_RDAR_R_DES_ACTIVE;\r
552 }\r
553 /*-----------------------------------------------------------*/\r
554 \r
555 static void prvEnableFECInterrupts( void )\r
556 {\r
557 const unsigned portBASE_TYPE uxFirstFECVector = 23, uxLastFECVector = 35;\r
558 unsigned portBASE_TYPE ux;\r
559 \r
560 #if configFEC_INTERRUPT_PRIORITY > configMAX_SYSCALL_INTERRUPT_PRIORITY\r
561         #error configFEC_INTERRUPT_PRIORITY must be less than or equal to configMAX_SYSCALL_INTERRUPT_PRIORITY\r
562 #endif\r
563 \r
564         /* Set the priority of each of the FEC interrupts. */\r
565         for( ux = uxFirstFECVector; ux <= uxLastFECVector; ux++ )\r
566         {\r
567                 MCF_INTC0_ICR( ux ) = MCF_INTC_ICR_IL( configFEC_INTERRUPT_PRIORITY );\r
568         }\r
569 \r
570         /* Enable the FEC interrupts in the mask register */\r
571         MCF_INTC0_IMRH &= ~( MCF_INTC_IMRH_INT_MASK33 | MCF_INTC_IMRH_INT_MASK34 | MCF_INTC_IMRH_INT_MASK35 );\r
572         MCF_INTC0_IMRL &= ~( MCF_INTC_IMRL_INT_MASK25 | MCF_INTC_IMRL_INT_MASK26 | MCF_INTC_IMRL_INT_MASK27\r
573                                                 | MCF_INTC_IMRL_INT_MASK28 | MCF_INTC_IMRL_INT_MASK29 | MCF_INTC_IMRL_INT_MASK30\r
574                                                 | MCF_INTC_IMRL_INT_MASK31 | MCF_INTC_IMRL_INT_MASK23 | MCF_INTC_IMRL_INT_MASK24\r
575                                                 | MCF_INTC_IMRL_MASKALL );\r
576 \r
577         /* Clear any pending FEC interrupt events */\r
578         MCF_FEC_EIR = MCF_FEC_EIR_CLEAR_ALL;\r
579 \r
580         /* Unmask all FEC interrupts */\r
581         MCF_FEC_EIMR = MCF_FEC_EIMR_UNMASK_ALL;\r
582 }\r
583 /*-----------------------------------------------------------*/\r
584 \r
585 static void prvResetFEC( portBASE_TYPE xCalledFromISR )\r
586 {\r
587 portBASE_TYPE x;\r
588 \r
589         /* A critical section is used unless this function is being called from\r
590         an ISR. */\r
591         if( xCalledFromISR == pdFALSE )\r
592         {\r
593                 taskENTER_CRITICAL();\r
594         }\r
595 \r
596         {\r
597                 /* Reset all buffers and descriptors. */\r
598                 prvInitialiseFECBuffers();\r
599 \r
600                 /* Set the Reset bit and clear the Enable bit */\r
601                 MCF_FEC_ECR = MCF_FEC_ECR_RESET;\r
602 \r
603                 /* Wait at least 8 clock cycles */\r
604                 for( x = 0; x < 10; x++ )\r
605                 {\r
606                         asm( "NOP" );\r
607                 }\r
608 \r
609                 /* Re-enable. */\r
610                 MCF_FEC_ECR = MCF_FEC_ECR_ETHER_EN;\r
611                 MCF_FEC_RDAR = MCF_FEC_RDAR_R_DES_ACTIVE;\r
612         }\r
613 \r
614         if( xCalledFromISR == pdFALSE )\r
615         {\r
616                 taskEXIT_CRITICAL();\r
617         }\r
618 }\r
619 /*-----------------------------------------------------------*/\r
620 \r
621 unsigned short usFECGetRxedData( void )\r
622 {\r
623 unsigned portSHORT usLen;\r
624 \r
625         /* Obtain the size of the packet and put it into the "len" variable. */\r
626         usLen = xFECRxDescriptors[ uxNextRxBuffer ].length;\r
627 \r
628         if( ( usLen != 0 ) && ( ( xFECRxDescriptors[ uxNextRxBuffer ].status & RX_BD_E ) == 0 ) )\r
629         {\r
630                 uip_buf = xFECRxDescriptors[ uxNextRxBuffer ].data;\r
631         }\r
632         else\r
633         {\r
634                 usLen = 0;\r
635         }\r
636 \r
637         return usLen;\r
638 }\r
639 /*-----------------------------------------------------------*/\r
640 \r
641 void vFECRxProcessingCompleted( void )\r
642 {\r
643         /* Free the descriptor as the buffer it points to is no longer in use. */\r
644         xFECRxDescriptors[ uxNextRxBuffer ].status |= RX_BD_E;\r
645         MCF_FEC_RDAR = MCF_FEC_RDAR_R_DES_ACTIVE;\r
646         uxNextRxBuffer++;\r
647         if( uxNextRxBuffer >= configNUM_FEC_RX_BUFFERS )\r
648         {\r
649                 uxNextRxBuffer = 0;\r
650         }\r
651 }\r
652 /*-----------------------------------------------------------*/\r
653 \r
654 void vFECSendData( void )\r
655 {\r
656         /* Ensure no Tx frames are outstanding. */\r
657         if( xSemaphoreTake( xTxSemaphore, fecMAX_WAIT_FOR_TX_BUFFER ) == pdPASS )\r
658         {\r
659                 /* Get a DMA buffer into which we can write the data to send. */\r
660                 if( xFECTxDescriptors[ fecTX_BUFFER_TO_USE ].status & TX_BD_R )\r
661                 {\r
662                         /*** ERROR didn't expect this.  Sledge hammer error handling. ***/\r
663                         prvResetFEC( pdFALSE );\r
664 \r
665                         /* Make sure we leave the semaphore in the expected state as nothing\r
666                         is being transmitted this will not happen in the Tx ISR. */\r
667                         xSemaphoreGive( xTxSemaphore );\r
668                 }\r
669                 else\r
670                 {\r
671                         /* Setup the buffer descriptor for transmission.  The data being\r
672                         sent is actually stored in one of the Rx descriptor buffers,\r
673                         pointed to by uip_buf. */\r
674                         xFECTxDescriptors[ fecTX_BUFFER_TO_USE ].length = uip_len;\r
675                         xFECTxDescriptors[ fecTX_BUFFER_TO_USE ].status |= ( TX_BD_R | TX_BD_L );\r
676                         xFECTxDescriptors[ fecTX_BUFFER_TO_USE ].data = uip_buf;\r
677 \r
678                         /* Remember which Rx descriptor owns the buffer we are sending. */\r
679                         uxIndexToBufferOwner = uxNextRxBuffer;\r
680 \r
681                         /* We have finished with this Rx descriptor now. */\r
682                         uxNextRxBuffer++;\r
683                         if( uxNextRxBuffer >= configNUM_FEC_RX_BUFFERS )\r
684                         {\r
685                                 uxNextRxBuffer = 0;\r
686                         }\r
687 \r
688                         /* Continue the Tx DMA (in case it was waiting for a new TxBD) */\r
689                         MCF_FEC_TDAR = MCF_FEC_TDAR_X_DES_ACTIVE;\r
690                 }\r
691         }\r
692         else\r
693         {\r
694                 /* Gave up waiting.  Free the buffer back to the DMA. */\r
695                 vFECRxProcessingCompleted();\r
696         }\r
697 }\r
698 /*-----------------------------------------------------------*/\r
699 \r
700 void vFEC_ISR( void )\r
701 {\r
702 unsigned portLONG ulEvent;\r
703 portBASE_TYPE xHighPriorityTaskWoken = pdFALSE;\r
704 \r
705         /* This handler is called in response to any of the many separate FEC\r
706         interrupt. */\r
707 \r
708         /* Find the cause of the interrupt, then clear the interrupt. */\r
709         ulEvent = MCF_FEC_EIR & MCF_FEC_EIMR;\r
710         MCF_FEC_EIR = ulEvent;\r
711 \r
712         if( ( ulEvent & MCF_FEC_EIR_RXB ) || ( ulEvent & MCF_FEC_EIR_RXF ) )\r
713         {\r
714                 /* A packet has been received.  Wake the handler task. */\r
715                 xSemaphoreGiveFromISR( xFECSemaphore, &xHighPriorityTaskWoken );\r
716         }\r
717 \r
718         if( ulEvent & ( MCF_FEC_EIR_UN | MCF_FEC_EIR_RL | MCF_FEC_EIR_LC | MCF_FEC_EIR_EBERR | MCF_FEC_EIR_BABT | MCF_FEC_EIR_BABR | MCF_FEC_EIR_HBERR ) )\r
719         {\r
720                 /* Sledge hammer error handling. */\r
721                 prvResetFEC( pdTRUE );\r
722         }\r
723 \r
724         if( ( ulEvent & MCF_FEC_EIR_TXF ) || ( ulEvent & MCF_FEC_EIR_TXB ) )\r
725         {\r
726                 /* The buffer being sent is pointed to by an Rx descriptor, now the\r
727                 buffer has been sent we can mark the Rx descriptor as free again. */\r
728                 xFECRxDescriptors[ uxIndexToBufferOwner ].status |= RX_BD_E;\r
729                 MCF_FEC_RDAR = MCF_FEC_RDAR_R_DES_ACTIVE;\r
730                 xSemaphoreGiveFromISR( xTxSemaphore, &xHighPriorityTaskWoken );\r
731         }\r
732 \r
733         portEND_SWITCHING_ISR( xHighPriorityTaskWoken );\r
734 }\r
735 /*-----------------------------------------------------------*/\r
736 \r
737 /* Install the many different interrupt vectors, all of which call the same\r
738 handler function. */\r
739 void __attribute__ ((interrupt)) __cs3_isr_interrupt_87( void ) { vFEC_ISR(); }\r
740 void __attribute__ ((interrupt)) __cs3_isr_interrupt_88( void ) { vFEC_ISR(); }\r
741 void __attribute__ ((interrupt)) __cs3_isr_interrupt_89( void ) { vFEC_ISR(); }\r
742 void __attribute__ ((interrupt)) __cs3_isr_interrupt_90( void ) { vFEC_ISR(); }\r
743 void __attribute__ ((interrupt)) __cs3_isr_interrupt_91( void ) { vFEC_ISR(); }\r
744 void __attribute__ ((interrupt)) __cs3_isr_interrupt_92( void ) { vFEC_ISR(); }\r
745 void __attribute__ ((interrupt)) __cs3_isr_interrupt_93( void ) { vFEC_ISR(); }\r
746 void __attribute__ ((interrupt)) __cs3_isr_interrupt_94( void ) { vFEC_ISR(); }\r
747 void __attribute__ ((interrupt)) __cs3_isr_interrupt_95( void ) { vFEC_ISR(); }\r
748 void __attribute__ ((interrupt)) __cs3_isr_interrupt_96( void ) { vFEC_ISR(); }\r
749 void __attribute__ ((interrupt)) __cs3_isr_interrupt_97( void ) { vFEC_ISR(); }\r
750 void __attribute__ ((interrupt)) __cs3_isr_interrupt_98( void ) { vFEC_ISR(); }\r
751 void __attribute__ ((interrupt)) __cs3_isr_interrupt_99( void ) { vFEC_ISR(); }\r
752 \r
753 \r