2 FreeRTOS V8.0.0 - Copyright (C) 2014 Real Time Engineers Ltd.
\r
5 VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
\r
7 ***************************************************************************
\r
9 * FreeRTOS provides completely free yet professionally developed, *
\r
10 * robust, strictly quality controlled, supported, and cross *
\r
11 * platform software that has become a de facto standard. *
\r
13 * Help yourself get started quickly and support the FreeRTOS *
\r
14 * project by purchasing a FreeRTOS tutorial book, reference *
\r
15 * manual, or both from: http://www.FreeRTOS.org/Documentation *
\r
19 ***************************************************************************
\r
21 This file is part of the FreeRTOS distribution.
\r
23 FreeRTOS is free software; you can redistribute it and/or modify it under
\r
24 the terms of the GNU General Public License (version 2) as published by the
\r
25 Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
\r
27 >>! NOTE: The modification to the GPL is included to allow you to distribute
\r
28 >>! a combined work that includes FreeRTOS without being obliged to provide
\r
29 >>! the source code for proprietary components outside of the FreeRTOS
\r
32 FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
\r
33 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
\r
34 FOR A PARTICULAR PURPOSE. Full license text is available from the following
\r
35 link: http://www.freertos.org/a00114.html
\r
39 ***************************************************************************
\r
41 * Having a problem? Start by reading the FAQ "My application does *
\r
42 * not run, what could be wrong?" *
\r
44 * http://www.FreeRTOS.org/FAQHelp.html *
\r
46 ***************************************************************************
\r
48 http://www.FreeRTOS.org - Documentation, books, training, latest versions,
\r
49 license and Real Time Engineers Ltd. contact details.
\r
51 http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
\r
52 including FreeRTOS+Trace - an indispensable productivity tool, a DOS
\r
53 compatible FAT file system, and our tiny thread aware UDP/IP stack.
\r
55 http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
\r
56 Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS
\r
57 licenses offer ticketed support, indemnification and middleware.
\r
59 http://www.SafeRTOS.com - High Integrity Systems also provide a safety
\r
60 engineered and independently SIL3 certified version for use in safety and
\r
61 mission critical applications that require provable dependability.
\r
66 /* Kernel includes. */
\r
67 #include "FreeRTOS.h"
\r
71 /* Hardware includes. */
\r
74 #include "eth_phy.h"
\r
79 #include "uip_arp.h"
\r
81 /* Delay between polling the PHY to see if a link has been established. */
\r
82 #define fecLINK_DELAY ( 500 / portTICK_RATE_MS )
\r
84 /* Delay to wait for an MII access. */
\r
85 #define fecMII_DELAY ( 10 / portTICK_RATE_MS )
\r
86 #define fecMAX_POLLS ( 20 )
\r
88 /* Constants used to delay while waiting for a tx descriptor to be free. */
\r
89 #define fecMAX_WAIT_FOR_TX_BUFFER ( 200 / portTICK_RATE_MS )
\r
91 /* We only use a single Tx descriptor which can lead to Txed packets being sent
\r
92 twice (due to a bug in the FEC silicon). However, in this case the bug is used
\r
93 to our advantage in that it means the uip-split mechanism is not required. */
\r
94 #define fecNUM_FEC_TX_BUFFERS ( 1 )
\r
95 #define fecTX_BUFFER_TO_USE ( 0 )
\r
96 /*-----------------------------------------------------------*/
\r
98 /* The semaphore used to wake the uIP task when data arrives. */
\r
99 xSemaphoreHandle xFECSemaphore = NULL, xTxSemaphore = NULL;
\r
101 /* The buffer used by the uIP stack. In this case the pointer is used to
\r
102 point to one of the Rx buffers to effect a zero copy policy. */
\r
103 unsigned char *uip_buf;
\r
105 /* The DMA descriptors. This is a char array to allow us to align it correctly. */
\r
106 static unsigned char xFECTxDescriptors_unaligned[ ( fecNUM_FEC_TX_BUFFERS * sizeof( FECBD ) ) + 16 ];
\r
107 static unsigned char xFECRxDescriptors_unaligned[ ( configNUM_FEC_RX_BUFFERS * sizeof( FECBD ) ) + 16 ];
\r
108 static FECBD *xFECTxDescriptors;
\r
109 static FECBD *xFECRxDescriptors;
\r
111 /* The DMA buffers. These are char arrays to allow them to be aligned correctly. */
\r
112 static unsigned char ucFECRxBuffers[ ( configNUM_FEC_RX_BUFFERS * configFEC_BUFFER_SIZE ) + 16 ];
\r
113 static unsigned portBASE_TYPE uxNextRxBuffer = 0, uxIndexToBufferOwner = 0;
\r
115 /*-----------------------------------------------------------*/
\r
118 * Enable all the required interrupts in the FEC and in the interrupt controller.
\r
120 static void prvEnableFECInterrupts( void );
\r
123 * Reset the FEC if we get into an unrecoverable state.
\r
125 static void prvResetFEC( portBASE_TYPE xCalledFromISR );
\r
127 /********************************************************************/
\r
130 * FUNCTION ADAPTED FROM FREESCALE SUPPLIED SOURCE
\r
132 * Write a value to a PHY's MII register.
\r
136 * phy_addr Address of the PHY.
\r
137 * reg_addr Address of the register in the PHY.
\r
138 * data Data to be written to the PHY register.
\r
144 * Please refer to your PHY manual for registers and their meanings.
\r
145 * mii_write() polls for the FEC's MII interrupt event and clears it.
\r
146 * If after a suitable amount of time the event isn't triggered, a
\r
147 * value of 0 is returned.
\r
149 static int fec_mii_write( int phy_addr, int reg_addr, int data )
\r
151 int timeout, iReturn;
\r
154 /* Clear the MII interrupt bit */
\r
155 MCF_FEC_EIR = MCF_FEC_EIR_MII;
\r
157 /* Mask the MII interrupt */
\r
158 eimr = MCF_FEC_EIMR;
\r
159 MCF_FEC_EIMR &= ~MCF_FEC_EIMR_MII;
\r
161 /* Write to the MII Management Frame Register to kick-off the MII write */
\r
162 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
164 /* Poll for the MII interrupt (interrupt should be masked) */
\r
165 for( timeout = 0; timeout < fecMAX_POLLS; timeout++ )
\r
167 if( MCF_FEC_EIR & MCF_FEC_EIR_MII )
\r
173 vTaskDelay( fecMII_DELAY );
\r
177 if( timeout == fecMAX_POLLS )
\r
186 /* Clear the MII interrupt bit */
\r
187 MCF_FEC_EIR = MCF_FEC_EIR_MII;
\r
189 /* Restore the EIMR */
\r
190 MCF_FEC_EIMR = eimr;
\r
195 /********************************************************************/
\r
197 * FUNCTION ADAPTED FROM FREESCALE SUPPLIED SOURCE
\r
199 * Read a value from a PHY's MII register.
\r
203 * phy_addr Address of the PHY.
\r
204 * reg_addr Address of the register in the PHY.
\r
205 * data Pointer to storage for the Data to be read
\r
206 * from the PHY register (passed by reference)
\r
212 * Please refer to your PHY manual for registers and their meanings.
\r
213 * mii_read() polls for the FEC's MII interrupt event and clears it.
\r
214 * If after a suitable amount of time the event isn't triggered, a
\r
215 * value of 0 is returned.
\r
217 static int fec_mii_read( int phy_addr, int reg_addr, unsigned short* data )
\r
219 int timeout, iReturn;
\r
222 /* Clear the MII interrupt bit */
\r
223 MCF_FEC_EIR = MCF_FEC_EIR_MII;
\r
225 /* Mask the MII interrupt */
\r
226 eimr = MCF_FEC_EIMR;
\r
227 MCF_FEC_EIMR &= ~MCF_FEC_EIMR_MII;
\r
229 /* Write to the MII Management Frame Register to kick-off the MII read */
\r
230 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
232 /* Poll for the MII interrupt (interrupt should be masked) */
\r
233 for( timeout = 0; timeout < fecMAX_POLLS; timeout++ )
\r
235 if (MCF_FEC_EIR & MCF_FEC_EIR_MII)
\r
241 vTaskDelay( fecMII_DELAY );
\r
245 if( timeout == fecMAX_POLLS )
\r
251 *data = (uint16)(MCF_FEC_MMFR & 0x0000FFFF);
\r
255 /* Clear the MII interrupt bit */
\r
256 MCF_FEC_EIR = MCF_FEC_EIR_MII;
\r
258 /* Restore the EIMR */
\r
259 MCF_FEC_EIMR = eimr;
\r
265 /********************************************************************/
\r
267 * FUNCTION ADAPTED FROM FREESCALE SUPPLIED SOURCE
\r
269 * Generate the hash table settings for the given address
\r
272 * addr 48-bit (6 byte) Address to generate the hash for
\r
275 * The 6 most significant bits of the 32-bit CRC result
\r
277 static unsigned char fec_hash_address( const unsigned char* addr )
\r
280 unsigned char byte;
\r
289 if((byte & 0x01)^(crc & 0x01))
\r
292 crc = crc ^ 0xEDB88320;
\r
303 return (unsigned char)(crc >> 26);
\r
306 /********************************************************************/
\r
308 * FUNCTION ADAPTED FROM FREESCALE SUPPLIED SOURCE
\r
310 * Set the Physical (Hardware) Address and the Individual Address
\r
311 * Hash in the selected FEC
\r
315 * pa Physical (Hardware) Address for the selected FEC
\r
317 static void fec_set_address( const unsigned char *pa )
\r
322 * Set the Physical Address
\r
324 /* Set the source address for the controller */
\r
325 MCF_FEC_PALR = ( pa[ 0 ] << 24 ) | ( pa[ 1 ] << 16 ) | ( pa[ 2 ] << 8 ) | ( pa[ 3 ] << 0 );
\r
326 MCF_FEC_PAUR = ( pa[ 4 ] << 24 ) | ( pa[ 5 ] << 16 );
\r
329 * Calculate and set the hash for given Physical Address
\r
330 * in the Individual Address Hash registers
\r
332 crc = fec_hash_address( pa );
\r
335 MCF_FEC_IAUR |= (unsigned long)(1 << (crc - 32));
\r
339 MCF_FEC_IALR |= (unsigned long)(1 << crc);
\r
342 /*-----------------------------------------------------------*/
\r
344 static void prvInitialiseFECBuffers( void )
\r
346 unsigned portBASE_TYPE ux;
\r
347 unsigned char *pcBufPointer;
\r
349 /* Correctly align the Tx descriptor pointer. */
\r
350 pcBufPointer = &( xFECTxDescriptors_unaligned[ 0 ] );
\r
351 while( ( ( unsigned long ) pcBufPointer & 0x0fUL ) != 0 )
\r
356 xFECTxDescriptors = ( FECBD * ) pcBufPointer;
\r
358 /* Likewise the Rx descriptor pointer. */
\r
359 pcBufPointer = &( xFECRxDescriptors_unaligned[ 0 ] );
\r
360 while( ( ( unsigned long ) pcBufPointer & 0x0fUL ) != 0 )
\r
365 xFECRxDescriptors = ( FECBD * ) pcBufPointer;
\r
368 /* Setup the Tx buffers and descriptors. There is no separate Tx buffer
\r
369 to point to (the Rx buffers are actually used) so the data member is
\r
370 set to NULL for now. */
\r
371 for( ux = 0; ux < fecNUM_FEC_TX_BUFFERS; ux++ )
\r
373 xFECTxDescriptors[ ux ].status = TX_BD_TC;
\r
374 xFECTxDescriptors[ ux ].data = NULL;
\r
375 xFECTxDescriptors[ ux ].length = 0;
\r
378 /* Setup the Rx buffers and descriptors, having first ensured correct
\r
380 pcBufPointer = &( ucFECRxBuffers[ 0 ] );
\r
381 while( ( ( unsigned long ) pcBufPointer & 0x0fUL ) != 0 )
\r
386 for( ux = 0; ux < configNUM_FEC_RX_BUFFERS; ux++ )
\r
388 xFECRxDescriptors[ ux ].status = RX_BD_E;
\r
389 xFECRxDescriptors[ ux ].length = configFEC_BUFFER_SIZE;
\r
390 xFECRxDescriptors[ ux ].data = pcBufPointer;
\r
391 pcBufPointer += configFEC_BUFFER_SIZE;
\r
394 /* Set the wrap bit in the last descriptors to form a ring. */
\r
395 xFECTxDescriptors[ fecNUM_FEC_TX_BUFFERS - 1 ].status |= TX_BD_W;
\r
396 xFECRxDescriptors[ configNUM_FEC_RX_BUFFERS - 1 ].status |= RX_BD_W;
\r
398 uxNextRxBuffer = 0;
\r
400 /*-----------------------------------------------------------*/
\r
402 void vFECInit( void )
\r
404 unsigned short usData;
\r
405 struct uip_eth_addr xAddr;
\r
406 unsigned portBASE_TYPE ux;
\r
408 /* The MAC address is set at the foot of FreeRTOSConfig.h. */
\r
409 const unsigned char ucMACAddress[6] =
\r
411 configMAC_0, configMAC_1,configMAC_2, configMAC_3, configMAC_4, configMAC_5
\r
414 /* Create the semaphore used by the ISR to wake the uIP task. */
\r
415 vSemaphoreCreateBinary( xFECSemaphore );
\r
417 /* Create the semaphore used to unblock any tasks that might be waiting
\r
418 for a Tx descriptor. */
\r
419 vSemaphoreCreateBinary( xTxSemaphore );
\r
421 /* Initialise all the buffers and descriptors used by the DMA. */
\r
422 prvInitialiseFECBuffers();
\r
424 for( usData = 0; usData < 6; usData++ )
\r
426 xAddr.addr[ usData ] = ucMACAddress[ usData ];
\r
428 uip_setethaddr( xAddr );
\r
430 /* Set the Reset bit and clear the Enable bit */
\r
431 MCF_FEC_ECR = MCF_FEC_ECR_RESET;
\r
433 /* Wait at least 8 clock cycles */
\r
434 for( usData = 0; usData < 10; usData++ )
\r
439 /* Set MII speed to 2.5MHz. */
\r
440 MCF_FEC_MSCR = MCF_FEC_MSCR_MII_SPEED( ( ( ( configCPU_CLOCK_HZ / 1000000 ) / 5 ) + 1 ) );
\r
442 /* Initialize PLDPAR to enable Ethernet LEDs. */
\r
443 MCF_GPIO_PLDPAR = MCF_GPIO_PLDPAR_ACTLED_ACTLED | MCF_GPIO_PLDPAR_LINKLED_LINKLED | MCF_GPIO_PLDPAR_SPDLED_SPDLED
\r
444 | MCF_GPIO_PLDPAR_DUPLED_DUPLED | MCF_GPIO_PLDPAR_COLLED_COLLED | MCF_GPIO_PLDPAR_RXLED_RXLED
\r
445 | MCF_GPIO_PLDPAR_TXLED_TXLED;
\r
447 /* Initialize Port TA to enable Axcel control. */
\r
448 MCF_GPIO_PTAPAR = 0x00;
\r
449 MCF_GPIO_DDRTA = 0x0F;
\r
450 MCF_GPIO_PORTTA = 0x04;
\r
452 /* Set phy address to zero. */
\r
453 MCF_EPHY_EPHYCTL1 = MCF_EPHY_EPHYCTL1_PHYADD( 0 );
\r
455 /* Enable EPHY module with PHY clocks disabled. Do not turn on PHY clocks
\r
456 until both FEC and EPHY are completely setup (see Below). */
\r
457 MCF_EPHY_EPHYCTL0 = (uint8)(MCF_EPHY_EPHYCTL0_DIS100 | MCF_EPHY_EPHYCTL0_DIS10);
\r
459 /* Enable auto_neg at start-up */
\r
460 MCF_EPHY_EPHYCTL0 = (uint8)(MCF_EPHY_EPHYCTL0 & (MCF_EPHY_EPHYCTL0_ANDIS));
\r
462 /* Enable EPHY module. */
\r
463 MCF_EPHY_EPHYCTL0 = (uint8)(MCF_EPHY_EPHYCTL0_EPHYEN | MCF_EPHY_EPHYCTL0);
\r
465 /* Let PHY PLLs be determined by PHY. */
\r
466 MCF_EPHY_EPHYCTL0 = (uint8)(MCF_EPHY_EPHYCTL0 & ~(MCF_EPHY_EPHYCTL0_DIS100 | MCF_EPHY_EPHYCTL0_DIS10));
\r
469 vTaskDelay( fecLINK_DELAY );
\r
471 /* Can we talk to the PHY? */
\r
474 vTaskDelay( fecLINK_DELAY );
\r
476 fec_mii_read( configPHY_ADDRESS, PHY_PHYIDR1, &usData );
\r
478 } while( usData == 0xffff );
\r
482 /* Start auto negotiate. */
\r
483 fec_mii_write( configPHY_ADDRESS, PHY_BMCR, ( PHY_BMCR_AN_RESTART | PHY_BMCR_AN_ENABLE ) );
\r
485 /* Wait for auto negotiate to complete. */
\r
491 /* Hardware bug workaround! Force 100Mbps half duplex. */
\r
492 while( !fec_mii_read( configPHY_ADDRESS, 0, &usData ) ){};
\r
493 usData &= ~0x2000; /* 10Mbps */
\r
494 usData &= ~0x0100; /* Half Duplex */
\r
495 usData &= ~0x1000; /* Manual Mode */
\r
496 while( !fec_mii_write( configPHY_ADDRESS, 0, usData ) ){};
\r
497 while( !fec_mii_write( configPHY_ADDRESS, 0, (usData|0x0200) )){}; /* Force re-negotiate */
\r
500 vTaskDelay( fecLINK_DELAY );
\r
501 fec_mii_read( configPHY_ADDRESS, PHY_BMSR, &usData );
\r
503 } while( !( usData & PHY_BMSR_AN_COMPLETE ) );
\r
505 } while( 0 ); //while( !( usData & PHY_BMSR_LINK ) );
\r
507 /* When we get here we have a link - find out what has been negotiated. */
\r
508 fec_mii_read( configPHY_ADDRESS, PHY_ANLPAR, &usData );
\r
510 if( ( usData & PHY_ANLPAR_100BTX_FDX ) || ( usData & PHY_ANLPAR_100BTX ) )
\r
512 /* Speed is 100. */
\r
519 if( ( usData & PHY_ANLPAR_100BTX_FDX ) || ( usData & PHY_ANLPAR_10BTX_FDX ) )
\r
521 MCF_FEC_RCR &= (unsigned long)~MCF_FEC_RCR_DRT;
\r
522 MCF_FEC_TCR |= MCF_FEC_TCR_FDEN;
\r
526 MCF_FEC_RCR |= MCF_FEC_RCR_DRT;
\r
527 MCF_FEC_TCR &= (unsigned long)~MCF_FEC_TCR_FDEN;
\r
530 /* Clear the Individual and Group Address Hash registers */
\r
536 /* Set the Physical Address for the selected FEC */
\r
537 fec_set_address( ucMACAddress );
\r
539 /* Set Rx Buffer Size */
\r
540 MCF_FEC_EMRBR = (unsigned short)configFEC_BUFFER_SIZE;
\r
542 /* Point to the start of the circular Rx buffer descriptor queue */
\r
543 MCF_FEC_ERDSR = ( volatile unsigned long ) &( xFECRxDescriptors[ 0 ] );
\r
545 /* Point to the start of the circular Tx buffer descriptor queue */
\r
546 MCF_FEC_ETSDR = ( volatile unsigned long ) &( xFECTxDescriptors[ 0 ] );
\r
548 /* Mask all FEC interrupts */
\r
549 MCF_FEC_EIMR = ( unsigned long ) -1;
\r
551 /* Clear all FEC interrupt events */
\r
552 MCF_FEC_EIR = ( unsigned long ) -1;
\r
554 /* Initialize the Receive Control Register */
\r
555 MCF_FEC_RCR = MCF_FEC_RCR_MAX_FL(ETH_MAX_FRM) | MCF_FEC_RCR_FCE;
\r
557 MCF_FEC_RCR |= MCF_FEC_RCR_MII_MODE;
\r
559 #if( configUSE_PROMISCUOUS_MODE == 1 )
\r
561 MCF_FEC_RCR |= MCF_FEC_RCR_PROM;
\r
565 prvEnableFECInterrupts();
\r
567 /* Finally... enable. */
\r
568 MCF_FEC_ECR = MCF_FEC_ECR_ETHER_EN;
\r
569 MCF_FEC_RDAR = MCF_FEC_RDAR_R_DES_ACTIVE;
\r
571 /*-----------------------------------------------------------*/
\r
573 static void prvEnableFECInterrupts( void )
\r
575 const unsigned portBASE_TYPE uxFirstFECVector = 23, uxLastFECVector = 35;
\r
576 unsigned portBASE_TYPE ux;
\r
578 #if configFEC_INTERRUPT_PRIORITY > configMAX_SYSCALL_INTERRUPT_PRIORITY
\r
579 #error configFEC_INTERRUPT_PRIORITY must be less than or equal to configMAX_SYSCALL_INTERRUPT_PRIORITY
\r
582 /* Set the priority of each of the FEC interrupts. */
\r
583 for( ux = uxFirstFECVector; ux <= uxLastFECVector; ux++ )
\r
585 MCF_INTC0_ICR( ux ) = MCF_INTC_ICR_IL( configFEC_INTERRUPT_PRIORITY );
\r
588 /* Enable the FEC interrupts in the mask register */
\r
589 MCF_INTC0_IMRH &= ~( MCF_INTC_IMRH_INT_MASK33 | MCF_INTC_IMRH_INT_MASK34 | MCF_INTC_IMRH_INT_MASK35 );
\r
590 MCF_INTC0_IMRL &= ~( MCF_INTC_IMRL_INT_MASK25 | MCF_INTC_IMRL_INT_MASK26 | MCF_INTC_IMRL_INT_MASK27
\r
591 | MCF_INTC_IMRL_INT_MASK28 | MCF_INTC_IMRL_INT_MASK29 | MCF_INTC_IMRL_INT_MASK30
\r
592 | MCF_INTC_IMRL_INT_MASK31 | MCF_INTC_IMRL_INT_MASK23 | MCF_INTC_IMRL_INT_MASK24
\r
593 | MCF_INTC_IMRL_MASKALL );
\r
595 /* Clear any pending FEC interrupt events */
\r
596 MCF_FEC_EIR = MCF_FEC_EIR_CLEAR_ALL;
\r
598 /* Unmask all FEC interrupts */
\r
599 MCF_FEC_EIMR = MCF_FEC_EIMR_UNMASK_ALL;
\r
601 /*-----------------------------------------------------------*/
\r
603 static void prvResetFEC( portBASE_TYPE xCalledFromISR )
\r
607 /* A critical section is used unless this function is being called from
\r
609 if( xCalledFromISR == pdFALSE )
\r
611 taskENTER_CRITICAL();
\r
615 /* Reset all buffers and descriptors. */
\r
616 prvInitialiseFECBuffers();
\r
618 /* Set the Reset bit and clear the Enable bit */
\r
619 MCF_FEC_ECR = MCF_FEC_ECR_RESET;
\r
621 /* Wait at least 8 clock cycles */
\r
622 for( x = 0; x < 10; x++ )
\r
628 MCF_FEC_ECR = MCF_FEC_ECR_ETHER_EN;
\r
629 MCF_FEC_RDAR = MCF_FEC_RDAR_R_DES_ACTIVE;
\r
632 if( xCalledFromISR == pdFALSE )
\r
634 taskEXIT_CRITICAL();
\r
637 /*-----------------------------------------------------------*/
\r
639 unsigned short usFECGetRxedData( void )
\r
641 unsigned short usLen;
\r
643 /* Obtain the size of the packet and put it into the "len" variable. */
\r
644 usLen = xFECRxDescriptors[ uxNextRxBuffer ].length;
\r
646 if( ( usLen != 0 ) && ( ( xFECRxDescriptors[ uxNextRxBuffer ].status & RX_BD_E ) == 0 ) )
\r
648 uip_buf = xFECRxDescriptors[ uxNextRxBuffer ].data;
\r
657 /*-----------------------------------------------------------*/
\r
659 void vFECRxProcessingCompleted( void )
\r
661 /* Free the descriptor as the buffer it points to is no longer in use. */
\r
662 xFECRxDescriptors[ uxNextRxBuffer ].status |= RX_BD_E;
\r
663 MCF_FEC_RDAR = MCF_FEC_RDAR_R_DES_ACTIVE;
\r
665 if( uxNextRxBuffer >= configNUM_FEC_RX_BUFFERS )
\r
667 uxNextRxBuffer = 0;
\r
670 /*-----------------------------------------------------------*/
\r
672 void vFECSendData( void )
\r
674 /* Ensure no Tx frames are outstanding. */
\r
675 if( xSemaphoreTake( xTxSemaphore, fecMAX_WAIT_FOR_TX_BUFFER ) == pdPASS )
\r
677 /* Get a DMA buffer into which we can write the data to send. */
\r
678 if( xFECTxDescriptors[ fecTX_BUFFER_TO_USE ].status & TX_BD_R )
\r
680 /*** ERROR didn't expect this. Sledge hammer error handling. ***/
\r
681 prvResetFEC( pdFALSE );
\r
683 /* Make sure we leave the semaphore in the expected state as nothing
\r
684 is being transmitted this will not happen in the Tx ISR. */
\r
685 xSemaphoreGive( xTxSemaphore );
\r
689 /* Setup the buffer descriptor for transmission. The data being
\r
690 sent is actually stored in one of the Rx descriptor buffers,
\r
691 pointed to by uip_buf. */
\r
692 xFECTxDescriptors[ fecTX_BUFFER_TO_USE ].length = uip_len;
\r
693 xFECTxDescriptors[ fecTX_BUFFER_TO_USE ].status |= ( TX_BD_R | TX_BD_L );
\r
694 xFECTxDescriptors[ fecTX_BUFFER_TO_USE ].data = uip_buf;
\r
696 /* Remember which Rx descriptor owns the buffer we are sending. */
\r
697 uxIndexToBufferOwner = uxNextRxBuffer;
\r
699 /* We have finished with this Rx descriptor now. */
\r
701 if( uxNextRxBuffer >= configNUM_FEC_RX_BUFFERS )
\r
703 uxNextRxBuffer = 0;
\r
706 /* Continue the Tx DMA (in case it was waiting for a new TxBD) */
\r
707 MCF_FEC_TDAR = MCF_FEC_TDAR_X_DES_ACTIVE;
\r
712 /* Gave up waiting. Free the buffer back to the DMA. */
\r
713 vFECRxProcessingCompleted();
\r
716 /*-----------------------------------------------------------*/
\r
718 void vFEC_ISR( void )
\r
720 unsigned long ulEvent;
\r
721 portBASE_TYPE xHighPriorityTaskWoken = pdFALSE;
\r
723 /* This handler is called in response to any of the many separate FEC
\r
726 /* Find the cause of the interrupt, then clear the interrupt. */
\r
727 ulEvent = MCF_FEC_EIR & MCF_FEC_EIMR;
\r
728 MCF_FEC_EIR = ulEvent;
\r
730 if( ( ulEvent & MCF_FEC_EIR_RXB ) || ( ulEvent & MCF_FEC_EIR_RXF ) )
\r
732 /* A packet has been received. Wake the handler task. */
\r
733 xSemaphoreGiveFromISR( xFECSemaphore, &xHighPriorityTaskWoken );
\r
736 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
738 /* Sledge hammer error handling. */
\r
739 prvResetFEC( pdTRUE );
\r
742 if( ( ulEvent & MCF_FEC_EIR_TXF ) || ( ulEvent & MCF_FEC_EIR_TXB ) )
\r
744 /* The buffer being sent is pointed to by an Rx descriptor, now the
\r
745 buffer has been sent we can mark the Rx descriptor as free again. */
\r
746 xFECRxDescriptors[ uxIndexToBufferOwner ].status |= RX_BD_E;
\r
747 MCF_FEC_RDAR = MCF_FEC_RDAR_R_DES_ACTIVE;
\r
748 xSemaphoreGiveFromISR( xTxSemaphore, &xHighPriorityTaskWoken );
\r
751 portEND_SWITCHING_ISR( xHighPriorityTaskWoken );
\r
753 /*-----------------------------------------------------------*/
\r
755 /* Install the many different interrupt vectors, all of which call the same
\r
756 handler function. */
\r
757 void __attribute__ ((interrupt)) __cs3_isr_interrupt_87( void ) { vFEC_ISR(); }
\r
758 void __attribute__ ((interrupt)) __cs3_isr_interrupt_88( void ) { vFEC_ISR(); }
\r
759 void __attribute__ ((interrupt)) __cs3_isr_interrupt_89( void ) { vFEC_ISR(); }
\r
760 void __attribute__ ((interrupt)) __cs3_isr_interrupt_90( void ) { vFEC_ISR(); }
\r
761 void __attribute__ ((interrupt)) __cs3_isr_interrupt_91( void ) { vFEC_ISR(); }
\r
762 void __attribute__ ((interrupt)) __cs3_isr_interrupt_92( void ) { vFEC_ISR(); }
\r
763 void __attribute__ ((interrupt)) __cs3_isr_interrupt_93( void ) { vFEC_ISR(); }
\r
764 void __attribute__ ((interrupt)) __cs3_isr_interrupt_94( void ) { vFEC_ISR(); }
\r
765 void __attribute__ ((interrupt)) __cs3_isr_interrupt_95( void ) { vFEC_ISR(); }
\r
766 void __attribute__ ((interrupt)) __cs3_isr_interrupt_96( void ) { vFEC_ISR(); }
\r
767 void __attribute__ ((interrupt)) __cs3_isr_interrupt_97( void ) { vFEC_ISR(); }
\r
768 void __attribute__ ((interrupt)) __cs3_isr_interrupt_98( void ) { vFEC_ISR(); }
\r
769 void __attribute__ ((interrupt)) __cs3_isr_interrupt_99( void ) { vFEC_ISR(); }
\r