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