2 FreeRTOS V6.0.0 - Copyright (C) 2009 Real Time Engineers Ltd.
\r
4 This file is part of the FreeRTOS distribution.
\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
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
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
26 ***************************************************************************
\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
32 ***************************************************************************
\r
36 Please ensure to read the configuration and relevant port sections of the
\r
37 online documentation.
\r
39 http://www.FreeRTOS.org - Documentation, latest information, license and
\r
42 http://www.SafeRTOS.com - A version that is certified for use in safety
\r
45 http://www.OpenRTOS.com - Commercial support, development, porting,
\r
46 licensing and training services.
\r
49 /* Kernel includes. */
\r
50 #include "FreeRTOS.h"
\r
54 /* Hardware includes. */
\r
57 #include "eth_phy.h"
\r
62 #include "uip_arp.h"
\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
67 /* Delay to wait for an MII access. */
\r
68 #define fecMII_DELAY ( 10 / portTICK_RATE_MS )
\r
69 #define fecMAX_POLLS ( 20 )
\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
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
81 /* The semaphore used to wake the uIP task when data arrives. */
\r
82 xSemaphoreHandle xFECSemaphore = NULL, xTxSemaphore = NULL;
\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
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
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
98 /*-----------------------------------------------------------*/
\r
101 * Enable all the required interrupts in the FEC and in the interrupt controller.
\r
103 static void prvEnableFECInterrupts( void );
\r
106 * Reset the FEC if we get into an unrecoverable state.
\r
108 static void prvResetFEC( portBASE_TYPE xCalledFromISR );
\r
110 /********************************************************************/
\r
113 * FUNCTION ADAPTED FROM FREESCALE SUPPLIED SOURCE
\r
115 * Write a value to a PHY's MII register.
\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
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
132 static int fec_mii_write( int phy_addr, int reg_addr, int data )
\r
134 int timeout, iReturn;
\r
137 /* Clear the MII interrupt bit */
\r
138 MCF_FEC_EIR = MCF_FEC_EIR_MII;
\r
140 /* Mask the MII interrupt */
\r
141 eimr = MCF_FEC_EIMR;
\r
142 MCF_FEC_EIMR &= ~MCF_FEC_EIMR_MII;
\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
147 /* Poll for the MII interrupt (interrupt should be masked) */
\r
148 for( timeout = 0; timeout < fecMAX_POLLS; timeout++ )
\r
150 if( MCF_FEC_EIR & MCF_FEC_EIR_MII )
\r
156 vTaskDelay( fecMII_DELAY );
\r
160 if( timeout == fecMAX_POLLS )
\r
169 /* Clear the MII interrupt bit */
\r
170 MCF_FEC_EIR = MCF_FEC_EIR_MII;
\r
172 /* Restore the EIMR */
\r
173 MCF_FEC_EIMR = eimr;
\r
178 /********************************************************************/
\r
180 * FUNCTION ADAPTED FROM FREESCALE SUPPLIED SOURCE
\r
182 * Read a value from a PHY's MII register.
\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
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
200 static int fec_mii_read( int phy_addr, int reg_addr, unsigned portSHORT* data )
\r
202 int timeout, iReturn;
\r
205 /* Clear the MII interrupt bit */
\r
206 MCF_FEC_EIR = MCF_FEC_EIR_MII;
\r
208 /* Mask the MII interrupt */
\r
209 eimr = MCF_FEC_EIMR;
\r
210 MCF_FEC_EIMR &= ~MCF_FEC_EIMR_MII;
\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
215 /* Poll for the MII interrupt (interrupt should be masked) */
\r
216 for( timeout = 0; timeout < fecMAX_POLLS; timeout++ )
\r
218 if (MCF_FEC_EIR & MCF_FEC_EIR_MII)
\r
224 vTaskDelay( fecMII_DELAY );
\r
228 if( timeout == fecMAX_POLLS )
\r
234 *data = (uint16)(MCF_FEC_MMFR & 0x0000FFFF);
\r
238 /* Clear the MII interrupt bit */
\r
239 MCF_FEC_EIR = MCF_FEC_EIR_MII;
\r
241 /* Restore the EIMR */
\r
242 MCF_FEC_EIMR = eimr;
\r
248 /********************************************************************/
\r
250 * FUNCTION ADAPTED FROM FREESCALE SUPPLIED SOURCE
\r
252 * Generate the hash table settings for the given address
\r
255 * addr 48-bit (6 byte) Address to generate the hash for
\r
258 * The 6 most significant bits of the 32-bit CRC result
\r
260 static unsigned portCHAR fec_hash_address( const unsigned portCHAR* addr )
\r
262 unsigned portLONG crc;
\r
263 unsigned portCHAR byte;
\r
272 if((byte & 0x01)^(crc & 0x01))
\r
275 crc = crc ^ 0xEDB88320;
\r
286 return (unsigned portCHAR)(crc >> 26);
\r
289 /********************************************************************/
\r
291 * FUNCTION ADAPTED FROM FREESCALE SUPPLIED SOURCE
\r
293 * Set the Physical (Hardware) Address and the Individual Address
\r
294 * Hash in the selected FEC
\r
298 * pa Physical (Hardware) Address for the selected FEC
\r
300 static void fec_set_address( const unsigned portCHAR *pa )
\r
302 unsigned portCHAR crc;
\r
305 * Set the Physical Address
\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
312 * Calculate and set the hash for given Physical Address
\r
313 * in the Individual Address Hash registers
\r
315 crc = fec_hash_address( pa );
\r
318 MCF_FEC_IAUR |= (unsigned portLONG)(1 << (crc - 32));
\r
322 MCF_FEC_IALR |= (unsigned portLONG)(1 << crc);
\r
325 /*-----------------------------------------------------------*/
\r
327 static void prvInitialiseFECBuffers( void )
\r
329 unsigned portBASE_TYPE ux;
\r
330 unsigned portCHAR *pcBufPointer;
\r
332 /* Correctly align the Tx descriptor pointer. */
\r
333 pcBufPointer = &( xFECTxDescriptors_unaligned[ 0 ] );
\r
334 while( ( ( unsigned portLONG ) pcBufPointer & 0x0fUL ) != 0 )
\r
339 xFECTxDescriptors = ( FECBD * ) pcBufPointer;
\r
341 /* Likewise the Rx descriptor pointer. */
\r
342 pcBufPointer = &( xFECRxDescriptors_unaligned[ 0 ] );
\r
343 while( ( ( unsigned portLONG ) pcBufPointer & 0x0fUL ) != 0 )
\r
348 xFECRxDescriptors = ( FECBD * ) pcBufPointer;
\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
356 xFECTxDescriptors[ ux ].status = TX_BD_TC;
\r
357 xFECTxDescriptors[ ux ].data = NULL;
\r
358 xFECTxDescriptors[ ux ].length = 0;
\r
361 /* Setup the Rx buffers and descriptors, having first ensured correct
\r
363 pcBufPointer = &( ucFECRxBuffers[ 0 ] );
\r
364 while( ( ( unsigned portLONG ) pcBufPointer & 0x0fUL ) != 0 )
\r
369 for( ux = 0; ux < configNUM_FEC_RX_BUFFERS; ux++ )
\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
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
381 uxNextRxBuffer = 0;
\r
383 /*-----------------------------------------------------------*/
\r
385 void vFECInit( void )
\r
387 unsigned portSHORT usData;
\r
388 struct uip_eth_addr xAddr;
\r
389 unsigned portBASE_TYPE ux;
\r
391 /* The MAC address is set at the foot of FreeRTOSConfig.h. */
\r
392 const unsigned portCHAR ucMACAddress[6] =
\r
394 configMAC_0, configMAC_1,configMAC_2, configMAC_3, configMAC_4, configMAC_5
\r
397 /* Create the semaphore used by the ISR to wake the uIP task. */
\r
398 vSemaphoreCreateBinary( xFECSemaphore );
\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
404 /* Initialise all the buffers and descriptors used by the DMA. */
\r
405 prvInitialiseFECBuffers();
\r
407 for( usData = 0; usData < 6; usData++ )
\r
409 xAddr.addr[ usData ] = ucMACAddress[ usData ];
\r
411 uip_setethaddr( xAddr );
\r
413 /* Set the Reset bit and clear the Enable bit */
\r
414 MCF_FEC_ECR = MCF_FEC_ECR_RESET;
\r
416 /* Wait at least 8 clock cycles */
\r
417 for( usData = 0; usData < 10; usData++ )
\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
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
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
435 /* Set phy address to zero. */
\r
436 MCF_EPHY_EPHYCTL1 = MCF_EPHY_EPHYCTL1_PHYADD( 0 );
\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
442 /* Enable auto_neg at start-up */
\r
443 MCF_EPHY_EPHYCTL0 = (uint8)(MCF_EPHY_EPHYCTL0 & (MCF_EPHY_EPHYCTL0_ANDIS));
\r
445 /* Enable EPHY module. */
\r
446 MCF_EPHY_EPHYCTL0 = (uint8)(MCF_EPHY_EPHYCTL0_EPHYEN | MCF_EPHY_EPHYCTL0);
\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
452 vTaskDelay( fecLINK_DELAY );
\r
454 /* Can we talk to the PHY? */
\r
457 vTaskDelay( fecLINK_DELAY );
\r
459 fec_mii_read( configPHY_ADDRESS, PHY_PHYIDR1, &usData );
\r
461 } while( usData == 0xffff );
\r
465 /* Start auto negotiate. */
\r
466 fec_mii_write( configPHY_ADDRESS, PHY_BMCR, ( PHY_BMCR_AN_RESTART | PHY_BMCR_AN_ENABLE ) );
\r
468 /* Wait for auto negotiate to complete. */
\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
483 vTaskDelay( fecLINK_DELAY );
\r
484 fec_mii_read( configPHY_ADDRESS, PHY_BMSR, &usData );
\r
486 } while( !( usData & PHY_BMSR_AN_COMPLETE ) );
\r
488 } while( 0 ); //while( !( usData & PHY_BMSR_LINK ) );
\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
493 if( ( usData & PHY_ANLPAR_100BTX_FDX ) || ( usData & PHY_ANLPAR_100BTX ) )
\r
495 /* Speed is 100. */
\r
502 if( ( usData & PHY_ANLPAR_100BTX_FDX ) || ( usData & PHY_ANLPAR_10BTX_FDX ) )
\r
504 MCF_FEC_RCR &= (unsigned portLONG)~MCF_FEC_RCR_DRT;
\r
505 MCF_FEC_TCR |= MCF_FEC_TCR_FDEN;
\r
509 MCF_FEC_RCR |= MCF_FEC_RCR_DRT;
\r
510 MCF_FEC_TCR &= (unsigned portLONG)~MCF_FEC_TCR_FDEN;
\r
513 /* Clear the Individual and Group Address Hash registers */
\r
519 /* Set the Physical Address for the selected FEC */
\r
520 fec_set_address( ucMACAddress );
\r
522 /* Set Rx Buffer Size */
\r
523 MCF_FEC_EMRBR = (unsigned portSHORT)configFEC_BUFFER_SIZE;
\r
525 /* Point to the start of the circular Rx buffer descriptor queue */
\r
526 MCF_FEC_ERDSR = ( volatile unsigned portLONG ) &( xFECRxDescriptors[ 0 ] );
\r
528 /* Point to the start of the circular Tx buffer descriptor queue */
\r
529 MCF_FEC_ETSDR = ( volatile unsigned portLONG ) &( xFECTxDescriptors[ 0 ] );
\r
531 /* Mask all FEC interrupts */
\r
532 MCF_FEC_EIMR = ( unsigned portLONG ) -1;
\r
534 /* Clear all FEC interrupt events */
\r
535 MCF_FEC_EIR = ( unsigned portLONG ) -1;
\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
540 MCF_FEC_RCR |= MCF_FEC_RCR_MII_MODE;
\r
542 #if( configUSE_PROMISCUOUS_MODE == 1 )
\r
544 MCF_FEC_RCR |= MCF_FEC_RCR_PROM;
\r
548 prvEnableFECInterrupts();
\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
554 /*-----------------------------------------------------------*/
\r
556 static void prvEnableFECInterrupts( void )
\r
558 const unsigned portBASE_TYPE uxFirstFECVector = 23, uxLastFECVector = 35;
\r
559 unsigned portBASE_TYPE ux;
\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
565 /* Set the priority of each of the FEC interrupts. */
\r
566 for( ux = uxFirstFECVector; ux <= uxLastFECVector; ux++ )
\r
568 MCF_INTC0_ICR( ux ) = MCF_INTC_ICR_IL( configFEC_INTERRUPT_PRIORITY );
\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
578 /* Clear any pending FEC interrupt events */
\r
579 MCF_FEC_EIR = MCF_FEC_EIR_CLEAR_ALL;
\r
581 /* Unmask all FEC interrupts */
\r
582 MCF_FEC_EIMR = MCF_FEC_EIMR_UNMASK_ALL;
\r
584 /*-----------------------------------------------------------*/
\r
586 static void prvResetFEC( portBASE_TYPE xCalledFromISR )
\r
590 /* A critical section is used unless this function is being called from
\r
592 if( xCalledFromISR == pdFALSE )
\r
594 taskENTER_CRITICAL();
\r
598 /* Reset all buffers and descriptors. */
\r
599 prvInitialiseFECBuffers();
\r
601 /* Set the Reset bit and clear the Enable bit */
\r
602 MCF_FEC_ECR = MCF_FEC_ECR_RESET;
\r
604 /* Wait at least 8 clock cycles */
\r
605 for( x = 0; x < 10; x++ )
\r
611 MCF_FEC_ECR = MCF_FEC_ECR_ETHER_EN;
\r
612 MCF_FEC_RDAR = MCF_FEC_RDAR_R_DES_ACTIVE;
\r
615 if( xCalledFromISR == pdFALSE )
\r
617 taskEXIT_CRITICAL();
\r
620 /*-----------------------------------------------------------*/
\r
622 unsigned short usFECGetRxedData( void )
\r
624 unsigned portSHORT usLen;
\r
626 /* Obtain the size of the packet and put it into the "len" variable. */
\r
627 usLen = xFECRxDescriptors[ uxNextRxBuffer ].length;
\r
629 if( ( usLen != 0 ) && ( ( xFECRxDescriptors[ uxNextRxBuffer ].status & RX_BD_E ) == 0 ) )
\r
631 uip_buf = xFECRxDescriptors[ uxNextRxBuffer ].data;
\r
640 /*-----------------------------------------------------------*/
\r
642 void vFECRxProcessingCompleted( void )
\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
648 if( uxNextRxBuffer >= configNUM_FEC_RX_BUFFERS )
\r
650 uxNextRxBuffer = 0;
\r
653 /*-----------------------------------------------------------*/
\r
655 void vFECSendData( void )
\r
657 /* Ensure no Tx frames are outstanding. */
\r
658 if( xSemaphoreTake( xTxSemaphore, fecMAX_WAIT_FOR_TX_BUFFER ) == pdPASS )
\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
663 /*** ERROR didn't expect this. Sledge hammer error handling. ***/
\r
664 prvResetFEC( pdFALSE );
\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
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
679 /* Remember which Rx descriptor owns the buffer we are sending. */
\r
680 uxIndexToBufferOwner = uxNextRxBuffer;
\r
682 /* We have finished with this Rx descriptor now. */
\r
684 if( uxNextRxBuffer >= configNUM_FEC_RX_BUFFERS )
\r
686 uxNextRxBuffer = 0;
\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
695 /* Gave up waiting. Free the buffer back to the DMA. */
\r
696 vFECRxProcessingCompleted();
\r
699 /*-----------------------------------------------------------*/
\r
701 void vFEC_ISR( void )
\r
703 unsigned portLONG ulEvent;
\r
704 portBASE_TYPE xHighPriorityTaskWoken = pdFALSE;
\r
706 /* This handler is called in response to any of the many separate FEC
\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
713 if( ( ulEvent & MCF_FEC_EIR_RXB ) || ( ulEvent & MCF_FEC_EIR_RXF ) )
\r
715 /* A packet has been received. Wake the handler task. */
\r
716 xSemaphoreGiveFromISR( xFECSemaphore, &xHighPriorityTaskWoken );
\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
721 /* Sledge hammer error handling. */
\r
722 prvResetFEC( pdTRUE );
\r
725 if( ( ulEvent & MCF_FEC_EIR_TXF ) || ( ulEvent & MCF_FEC_EIR_TXB ) )
\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
734 portEND_SWITCHING_ISR( xHighPriorityTaskWoken );
\r
736 /*-----------------------------------------------------------*/
\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