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