2 FreeRTOS.org V5.4.0 - Copyright (C) 2003-2009 Richard Barry.
\r
4 This file is part of the FreeRTOS.org distribution.
\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
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
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
25 ***************************************************************************
\r
27 * Get the FreeRTOS eBook! See http://www.FreeRTOS.org/Documentation *
\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
35 ***************************************************************************
\r
39 Please ensure to read the configuration and relevant port sections of the
\r
40 online documentation.
\r
42 http://www.FreeRTOS.org - Documentation, latest information, license and
\r
45 http://www.SafeRTOS.com - A version that is certified for use in safety
\r
48 http://www.OpenRTOS.com - Commercial support, development, porting,
\r
49 licensing and training services.
\r
52 /* Kernel includes. */
\r
53 #include "FreeRTOS.h"
\r
57 /* Hardware includes. */
\r
60 #include "eth_phy.h"
\r
65 #include "uip_arp.h"
\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
70 /* Delay to wait for an MII access. */
\r
71 #define fecMII_DELAY ( 10 / portTICK_RATE_MS )
\r
72 #define fecMAX_POLLS ( 20 )
\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
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
84 /* The semaphore used to wake the uIP task when data arrives. */
\r
85 xSemaphoreHandle xFECSemaphore = NULL, xTxSemaphore = NULL;
\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
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
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
101 /*-----------------------------------------------------------*/
\r
104 * Enable all the required interrupts in the FEC and in the interrupt controller.
\r
106 static void prvEnableFECInterrupts( void );
\r
109 * Reset the FEC if we get into an unrecoverable state.
\r
111 static void prvResetFEC( portBASE_TYPE xCalledFromISR );
\r
113 /********************************************************************/
\r
116 * FUNCTION ADAPTED FROM FREESCALE SUPPLIED SOURCE
\r
118 * Write a value to a PHY's MII register.
\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
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
135 static int fec_mii_write( int phy_addr, int reg_addr, int data )
\r
137 int timeout, iReturn;
\r
140 /* Clear the MII interrupt bit */
\r
141 MCF_FEC_EIR = MCF_FEC_EIR_MII;
\r
143 /* Mask the MII interrupt */
\r
144 eimr = MCF_FEC_EIMR;
\r
145 MCF_FEC_EIMR &= ~MCF_FEC_EIMR_MII;
\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
150 /* Poll for the MII interrupt (interrupt should be masked) */
\r
151 for( timeout = 0; timeout < fecMAX_POLLS; timeout++ )
\r
153 if( MCF_FEC_EIR & MCF_FEC_EIR_MII )
\r
159 vTaskDelay( fecMII_DELAY );
\r
163 if( timeout == fecMAX_POLLS )
\r
172 /* Clear the MII interrupt bit */
\r
173 MCF_FEC_EIR = MCF_FEC_EIR_MII;
\r
175 /* Restore the EIMR */
\r
176 MCF_FEC_EIMR = eimr;
\r
181 /********************************************************************/
\r
183 * FUNCTION ADAPTED FROM FREESCALE SUPPLIED SOURCE
\r
185 * Read a value from a PHY's MII register.
\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
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
203 static int fec_mii_read( int phy_addr, int reg_addr, unsigned portSHORT* data )
\r
205 int timeout, iReturn;
\r
208 /* Clear the MII interrupt bit */
\r
209 MCF_FEC_EIR = MCF_FEC_EIR_MII;
\r
211 /* Mask the MII interrupt */
\r
212 eimr = MCF_FEC_EIMR;
\r
213 MCF_FEC_EIMR &= ~MCF_FEC_EIMR_MII;
\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
218 /* Poll for the MII interrupt (interrupt should be masked) */
\r
219 for( timeout = 0; timeout < fecMAX_POLLS; timeout++ )
\r
221 if (MCF_FEC_EIR & MCF_FEC_EIR_MII)
\r
227 vTaskDelay( fecMII_DELAY );
\r
231 if( timeout == fecMAX_POLLS )
\r
237 *data = (uint16)(MCF_FEC_MMFR & 0x0000FFFF);
\r
241 /* Clear the MII interrupt bit */
\r
242 MCF_FEC_EIR = MCF_FEC_EIR_MII;
\r
244 /* Restore the EIMR */
\r
245 MCF_FEC_EIMR = eimr;
\r
251 /********************************************************************/
\r
253 * FUNCTION ADAPTED FROM FREESCALE SUPPLIED SOURCE
\r
255 * Generate the hash table settings for the given address
\r
258 * addr 48-bit (6 byte) Address to generate the hash for
\r
261 * The 6 most significant bits of the 32-bit CRC result
\r
263 static unsigned portCHAR fec_hash_address( const unsigned portCHAR* addr )
\r
265 unsigned portLONG crc;
\r
266 unsigned portCHAR byte;
\r
275 if((byte & 0x01)^(crc & 0x01))
\r
278 crc = crc ^ 0xEDB88320;
\r
289 return (unsigned portCHAR)(crc >> 26);
\r
292 /********************************************************************/
\r
294 * FUNCTION ADAPTED FROM FREESCALE SUPPLIED SOURCE
\r
296 * Set the Physical (Hardware) Address and the Individual Address
\r
297 * Hash in the selected FEC
\r
301 * pa Physical (Hardware) Address for the selected FEC
\r
303 static void fec_set_address( const unsigned portCHAR *pa )
\r
305 unsigned portCHAR crc;
\r
308 * Set the Physical Address
\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
315 * Calculate and set the hash for given Physical Address
\r
316 * in the Individual Address Hash registers
\r
318 crc = fec_hash_address( pa );
\r
321 MCF_FEC_IAUR |= (unsigned portLONG)(1 << (crc - 32));
\r
325 MCF_FEC_IALR |= (unsigned portLONG)(1 << crc);
\r
328 /*-----------------------------------------------------------*/
\r
330 static void prvInitialiseFECBuffers( void )
\r
332 unsigned portBASE_TYPE ux;
\r
333 unsigned portCHAR *pcBufPointer;
\r
335 /* Correctly align the Tx descriptor pointer. */
\r
336 pcBufPointer = &( xFECTxDescriptors_unaligned[ 0 ] );
\r
337 while( ( ( unsigned portLONG ) pcBufPointer & 0x0fUL ) != 0 )
\r
342 xFECTxDescriptors = ( FECBD * ) pcBufPointer;
\r
344 /* Likewise the Rx descriptor pointer. */
\r
345 pcBufPointer = &( xFECRxDescriptors_unaligned[ 0 ] );
\r
346 while( ( ( unsigned portLONG ) pcBufPointer & 0x0fUL ) != 0 )
\r
351 xFECRxDescriptors = ( FECBD * ) pcBufPointer;
\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
359 xFECTxDescriptors[ ux ].status = TX_BD_TC;
\r
360 xFECTxDescriptors[ ux ].data = NULL;
\r
361 xFECTxDescriptors[ ux ].length = 0;
\r
364 /* Setup the Rx buffers and descriptors, having first ensured correct
\r
366 pcBufPointer = &( ucFECRxBuffers[ 0 ] );
\r
367 while( ( ( unsigned portLONG ) pcBufPointer & 0x0fUL ) != 0 )
\r
372 for( ux = 0; ux < configNUM_FEC_RX_BUFFERS; ux++ )
\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
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
384 uxNextRxBuffer = 0;
\r
386 /*-----------------------------------------------------------*/
\r
388 void vFECInit( void )
\r
390 unsigned portSHORT usData;
\r
391 struct uip_eth_addr xAddr;
\r
392 unsigned portBASE_TYPE ux;
\r
394 /* The MAC address is set at the foot of FreeRTOSConfig.h. */
\r
395 const unsigned portCHAR ucMACAddress[6] =
\r
397 configMAC_0, configMAC_1,configMAC_2, configMAC_3, configMAC_4, configMAC_5
\r
400 /* Create the semaphore used by the ISR to wake the uIP task. */
\r
401 vSemaphoreCreateBinary( xFECSemaphore );
\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
407 /* Initialise all the buffers and descriptors used by the DMA. */
\r
408 prvInitialiseFECBuffers();
\r
410 for( usData = 0; usData < 6; usData++ )
\r
412 xAddr.addr[ usData ] = ucMACAddress[ usData ];
\r
414 uip_setethaddr( xAddr );
\r
416 /* Set the Reset bit and clear the Enable bit */
\r
417 MCF_FEC_ECR = MCF_FEC_ECR_RESET;
\r
419 /* Wait at least 8 clock cycles */
\r
420 for( usData = 0; usData < 10; usData++ )
\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
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
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
438 /* Set phy address to zero. */
\r
439 MCF_EPHY_EPHYCTL1 = MCF_EPHY_EPHYCTL1_PHYADD( 0 );
\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
445 /* Enable auto_neg at start-up */
\r
446 MCF_EPHY_EPHYCTL0 = (uint8)(MCF_EPHY_EPHYCTL0 & (MCF_EPHY_EPHYCTL0_ANDIS));
\r
448 /* Enable EPHY module. */
\r
449 MCF_EPHY_EPHYCTL0 = (uint8)(MCF_EPHY_EPHYCTL0_EPHYEN | MCF_EPHY_EPHYCTL0);
\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
455 vTaskDelay( fecLINK_DELAY );
\r
457 /* Can we talk to the PHY? */
\r
460 vTaskDelay( fecLINK_DELAY );
\r
462 fec_mii_read( configPHY_ADDRESS, PHY_PHYIDR1, &usData );
\r
464 } while( usData == 0xffff );
\r
468 /* Start auto negotiate. */
\r
469 fec_mii_write( configPHY_ADDRESS, PHY_BMCR, ( PHY_BMCR_AN_RESTART | PHY_BMCR_AN_ENABLE ) );
\r
471 /* Wait for auto negotiate to complete. */
\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
486 vTaskDelay( fecLINK_DELAY );
\r
487 fec_mii_read( configPHY_ADDRESS, PHY_BMSR, &usData );
\r
489 } while( !( usData & PHY_BMSR_AN_COMPLETE ) );
\r
491 } while( 0 ); //while( !( usData & PHY_BMSR_LINK ) );
\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
496 if( ( usData & PHY_ANLPAR_100BTX_FDX ) || ( usData & PHY_ANLPAR_100BTX ) )
\r
498 /* Speed is 100. */
\r
505 if( ( usData & PHY_ANLPAR_100BTX_FDX ) || ( usData & PHY_ANLPAR_10BTX_FDX ) )
\r
507 MCF_FEC_RCR &= (unsigned portLONG)~MCF_FEC_RCR_DRT;
\r
508 MCF_FEC_TCR |= MCF_FEC_TCR_FDEN;
\r
512 MCF_FEC_RCR |= MCF_FEC_RCR_DRT;
\r
513 MCF_FEC_TCR &= (unsigned portLONG)~MCF_FEC_TCR_FDEN;
\r
516 /* Clear the Individual and Group Address Hash registers */
\r
522 /* Set the Physical Address for the selected FEC */
\r
523 fec_set_address( ucMACAddress );
\r
525 /* Set Rx Buffer Size */
\r
526 MCF_FEC_EMRBR = (unsigned portSHORT)configFEC_BUFFER_SIZE;
\r
528 /* Point to the start of the circular Rx buffer descriptor queue */
\r
529 MCF_FEC_ERDSR = ( volatile unsigned portLONG ) &( xFECRxDescriptors[ 0 ] );
\r
531 /* Point to the start of the circular Tx buffer descriptor queue */
\r
532 MCF_FEC_ETSDR = ( volatile unsigned portLONG ) &( xFECTxDescriptors[ 0 ] );
\r
534 /* Mask all FEC interrupts */
\r
535 MCF_FEC_EIMR = ( unsigned portLONG ) -1;
\r
537 /* Clear all FEC interrupt events */
\r
538 MCF_FEC_EIR = ( unsigned portLONG ) -1;
\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
543 MCF_FEC_RCR |= MCF_FEC_RCR_MII_MODE;
\r
545 #if( configUSE_PROMISCUOUS_MODE == 1 )
\r
547 MCF_FEC_RCR |= MCF_FEC_RCR_PROM;
\r
551 prvEnableFECInterrupts();
\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
557 /*-----------------------------------------------------------*/
\r
559 static void prvEnableFECInterrupts( void )
\r
561 const unsigned portBASE_TYPE uxFirstFECVector = 23, uxLastFECVector = 35;
\r
562 unsigned portBASE_TYPE ux;
\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
568 /* Set the priority of each of the FEC interrupts. */
\r
569 for( ux = uxFirstFECVector; ux <= uxLastFECVector; ux++ )
\r
571 MCF_INTC0_ICR( ux ) = MCF_INTC_ICR_IL( configFEC_INTERRUPT_PRIORITY );
\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
581 /* Clear any pending FEC interrupt events */
\r
582 MCF_FEC_EIR = MCF_FEC_EIR_CLEAR_ALL;
\r
584 /* Unmask all FEC interrupts */
\r
585 MCF_FEC_EIMR = MCF_FEC_EIMR_UNMASK_ALL;
\r
587 /*-----------------------------------------------------------*/
\r
589 static void prvResetFEC( portBASE_TYPE xCalledFromISR )
\r
593 /* A critical section is used unless this function is being called from
\r
595 if( xCalledFromISR == pdFALSE )
\r
597 taskENTER_CRITICAL();
\r
601 /* Reset all buffers and descriptors. */
\r
602 prvInitialiseFECBuffers();
\r
604 /* Set the Reset bit and clear the Enable bit */
\r
605 MCF_FEC_ECR = MCF_FEC_ECR_RESET;
\r
607 /* Wait at least 8 clock cycles */
\r
608 for( x = 0; x < 10; x++ )
\r
614 MCF_FEC_ECR = MCF_FEC_ECR_ETHER_EN;
\r
615 MCF_FEC_RDAR = MCF_FEC_RDAR_R_DES_ACTIVE;
\r
618 if( xCalledFromISR == pdFALSE )
\r
620 taskEXIT_CRITICAL();
\r
623 /*-----------------------------------------------------------*/
\r
625 unsigned short usFECGetRxedData( void )
\r
627 unsigned portSHORT usLen;
\r
629 /* Obtain the size of the packet and put it into the "len" variable. */
\r
630 usLen = xFECRxDescriptors[ uxNextRxBuffer ].length;
\r
632 if( ( usLen != 0 ) && ( ( xFECRxDescriptors[ uxNextRxBuffer ].status & RX_BD_E ) == 0 ) )
\r
634 uip_buf = xFECRxDescriptors[ uxNextRxBuffer ].data;
\r
643 /*-----------------------------------------------------------*/
\r
645 void vFECRxProcessingCompleted( void )
\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
651 if( uxNextRxBuffer >= configNUM_FEC_RX_BUFFERS )
\r
653 uxNextRxBuffer = 0;
\r
656 /*-----------------------------------------------------------*/
\r
658 void vFECSendData( void )
\r
660 /* Ensure no Tx frames are outstanding. */
\r
661 if( xSemaphoreTake( xTxSemaphore, fecMAX_WAIT_FOR_TX_BUFFER ) == pdPASS )
\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
666 /*** ERROR didn't expect this. Sledge hammer error handling. ***/
\r
667 prvResetFEC( pdFALSE );
\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
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
682 /* Remember which Rx descriptor owns the buffer we are sending. */
\r
683 uxIndexToBufferOwner = uxNextRxBuffer;
\r
685 /* We have finished with this Rx descriptor now. */
\r
687 if( uxNextRxBuffer >= configNUM_FEC_RX_BUFFERS )
\r
689 uxNextRxBuffer = 0;
\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
698 /* Gave up waiting. Free the buffer back to the DMA. */
\r
699 vFECRxProcessingCompleted();
\r
702 /*-----------------------------------------------------------*/
\r
704 void vFEC_ISR( void )
\r
706 unsigned portLONG ulEvent;
\r
707 portBASE_TYPE xHighPriorityTaskWoken = pdFALSE;
\r
709 /* This handler is called in response to any of the many separate FEC
\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
716 if( ( ulEvent & MCF_FEC_EIR_RXB ) || ( ulEvent & MCF_FEC_EIR_RXF ) )
\r
718 /* A packet has been received. Wake the handler task. */
\r
719 xSemaphoreGiveFromISR( xFECSemaphore, &xHighPriorityTaskWoken );
\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
724 /* Sledge hammer error handling. */
\r
725 prvResetFEC( pdTRUE );
\r
728 if( ( ulEvent & MCF_FEC_EIR_TXF ) || ( ulEvent & MCF_FEC_EIR_TXB ) )
\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
737 portEND_SWITCHING_ISR( xHighPriorityTaskWoken );
\r
739 /*-----------------------------------------------------------*/
\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