2 FreeRTOS.org V5.1.0 - Copyright (C) 2003-2008 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
\r
7 it under the terms of the GNU General Public License as published by
\r
8 the Free Software Foundation; either version 2 of the License, or
\r
9 (at your option) any later version.
\r
11 FreeRTOS.org is distributed in the hope that it will be useful,
\r
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
14 GNU General Public License for more details.
\r
16 You should have received a copy of the GNU General Public License
\r
17 along with FreeRTOS.org; if not, write to the Free Software
\r
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
\r
20 A special exception to the GPL can be applied should you wish to distribute
\r
21 a combined work that includes FreeRTOS.org, without being obliged to provide
\r
22 the source code for any proprietary components. See the licensing section
\r
23 of http://www.FreeRTOS.org for full details of how and when the exception
\r
26 ***************************************************************************
\r
27 See http://www.FreeRTOS.org for documentation, latest information, license
\r
28 and contact details. Please ensure to read the configuration and relevant
\r
29 port sections of the online documentation.
\r
30 ***************************************************************************
\r
33 /* Kernel includes. */
\r
34 #include "FreeRTOS.h"
\r
38 /* Hardware includes. */
\r
41 #include "eth_phy.h"
\r
46 #include "uip_arp.h"
\r
48 /* Delay between polling the PHY to see if a link has been established. */
\r
49 #define fecLINK_DELAY ( 500 / portTICK_RATE_MS )
\r
51 /* Delay to wait for an MII access. */
\r
52 #define fecMII_DELAY ( 10 / portTICK_RATE_MS )
\r
53 #define fecMAX_POLLS ( 20 )
\r
55 /* Constants used to delay while waiting for a tx descriptor to be free. */
\r
56 #define fecMAX_WAIT_FOR_TX_BUFFER ( 200 / portTICK_RATE_MS )
\r
58 /* We only use a single Tx descriptor which can lead to Txed packets being sent
\r
59 twice (due to a bug in the FEC silicon). However, in this case the bug is used
\r
60 to our advantage in that it means the uip-split mechanism is not required. */
\r
61 #define fecNUM_FEC_TX_BUFFERS ( 1 )
\r
62 #define fecTX_BUFFER_TO_USE ( 0 )
\r
63 /*-----------------------------------------------------------*/
\r
65 /* The semaphore used to wake the uIP task when data arrives. */
\r
66 xSemaphoreHandle xFECSemaphore = NULL, xTxSemaphore = NULL;
\r
68 /* The buffer used by the uIP stack. In this case the pointer is used to
\r
69 point to one of the Rx buffers to effect a zero copy policy. */
\r
70 unsigned portCHAR *uip_buf;
\r
72 /* The DMA descriptors. This is a char array to allow us to align it correctly. */
\r
73 static unsigned portCHAR xFECTxDescriptors_unaligned[ ( fecNUM_FEC_TX_BUFFERS * sizeof( FECBD ) ) + 16 ];
\r
74 static unsigned portCHAR xFECRxDescriptors_unaligned[ ( configNUM_FEC_RX_BUFFERS * sizeof( FECBD ) ) + 16 ];
\r
75 static FECBD *xFECTxDescriptors;
\r
76 static FECBD *xFECRxDescriptors;
\r
78 /* The DMA buffers. These are char arrays to allow them to be aligned correctly. */
\r
79 static unsigned portCHAR ucFECRxBuffers[ ( configNUM_FEC_RX_BUFFERS * configFEC_BUFFER_SIZE ) + 16 ];
\r
80 static unsigned portBASE_TYPE uxNextRxBuffer = 0, uxIndexToBufferOwner = 0;
\r
82 /*-----------------------------------------------------------*/
\r
85 * Enable all the required interrupts in the FEC and in the interrupt controller.
\r
87 static void prvEnableFECInterrupts( void );
\r
90 * Reset the FEC if we get into an unrecoverable state.
\r
92 static void prvResetFEC( portBASE_TYPE xCalledFromISR );
\r
94 /********************************************************************/
\r
97 * FUNCTION ADAPTED FROM FREESCALE SUPPLIED SOURCE
\r
99 * Write a value to a PHY's MII register.
\r
103 * phy_addr Address of the PHY.
\r
104 * reg_addr Address of the register in the PHY.
\r
105 * data Data to be written to the PHY register.
\r
111 * Please refer to your PHY manual for registers and their meanings.
\r
112 * mii_write() polls for the FEC's MII interrupt event and clears it.
\r
113 * If after a suitable amount of time the event isn't triggered, a
\r
114 * value of 0 is returned.
\r
116 static int fec_mii_write( int phy_addr, int reg_addr, int data )
\r
118 int timeout, iReturn;
\r
121 /* Clear the MII interrupt bit */
\r
122 MCF_FEC_EIR = MCF_FEC_EIR_MII;
\r
124 /* Mask the MII interrupt */
\r
125 eimr = MCF_FEC_EIMR;
\r
126 MCF_FEC_EIMR &= ~MCF_FEC_EIMR_MII;
\r
128 /* Write to the MII Management Frame Register to kick-off the MII write */
\r
129 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
131 /* Poll for the MII interrupt (interrupt should be masked) */
\r
132 for( timeout = 0; timeout < fecMAX_POLLS; timeout++ )
\r
134 if( MCF_FEC_EIR & MCF_FEC_EIR_MII )
\r
140 vTaskDelay( fecMII_DELAY );
\r
144 if( timeout == fecMAX_POLLS )
\r
153 /* Clear the MII interrupt bit */
\r
154 MCF_FEC_EIR = MCF_FEC_EIR_MII;
\r
156 /* Restore the EIMR */
\r
157 MCF_FEC_EIMR = eimr;
\r
162 /********************************************************************/
\r
164 * FUNCTION ADAPTED FROM FREESCALE SUPPLIED SOURCE
\r
166 * Read a value from a PHY's MII register.
\r
170 * phy_addr Address of the PHY.
\r
171 * reg_addr Address of the register in the PHY.
\r
172 * data Pointer to storage for the Data to be read
\r
173 * from the PHY register (passed by reference)
\r
179 * Please refer to your PHY manual for registers and their meanings.
\r
180 * mii_read() polls for the FEC's MII interrupt event and clears it.
\r
181 * If after a suitable amount of time the event isn't triggered, a
\r
182 * value of 0 is returned.
\r
184 static int fec_mii_read( int phy_addr, int reg_addr, unsigned portSHORT* data )
\r
186 int timeout, iReturn;
\r
189 /* Clear the MII interrupt bit */
\r
190 MCF_FEC_EIR = MCF_FEC_EIR_MII;
\r
192 /* Mask the MII interrupt */
\r
193 eimr = MCF_FEC_EIMR;
\r
194 MCF_FEC_EIMR &= ~MCF_FEC_EIMR_MII;
\r
196 /* Write to the MII Management Frame Register to kick-off the MII read */
\r
197 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
199 /* Poll for the MII interrupt (interrupt should be masked) */
\r
200 for( timeout = 0; timeout < fecMAX_POLLS; timeout++ )
\r
202 if (MCF_FEC_EIR & MCF_FEC_EIR_MII)
\r
208 vTaskDelay( fecMII_DELAY );
\r
212 if( timeout == fecMAX_POLLS )
\r
218 *data = (uint16)(MCF_FEC_MMFR & 0x0000FFFF);
\r
222 /* Clear the MII interrupt bit */
\r
223 MCF_FEC_EIR = MCF_FEC_EIR_MII;
\r
225 /* Restore the EIMR */
\r
226 MCF_FEC_EIMR = eimr;
\r
232 /********************************************************************/
\r
234 * FUNCTION ADAPTED FROM FREESCALE SUPPLIED SOURCE
\r
236 * Generate the hash table settings for the given address
\r
239 * addr 48-bit (6 byte) Address to generate the hash for
\r
242 * The 6 most significant bits of the 32-bit CRC result
\r
244 static unsigned portCHAR fec_hash_address( const unsigned portCHAR* addr )
\r
246 unsigned portLONG crc;
\r
247 unsigned portCHAR byte;
\r
256 if((byte & 0x01)^(crc & 0x01))
\r
259 crc = crc ^ 0xEDB88320;
\r
270 return (unsigned portCHAR)(crc >> 26);
\r
273 /********************************************************************/
\r
275 * FUNCTION ADAPTED FROM FREESCALE SUPPLIED SOURCE
\r
277 * Set the Physical (Hardware) Address and the Individual Address
\r
278 * Hash in the selected FEC
\r
282 * pa Physical (Hardware) Address for the selected FEC
\r
284 static void fec_set_address( const unsigned portCHAR *pa )
\r
286 unsigned portCHAR crc;
\r
289 * Set the Physical Address
\r
291 /* Set the source address for the controller */
\r
292 MCF_FEC_PALR = ( pa[ 0 ] << 24 ) | ( pa[ 1 ] << 16 ) | ( pa[ 2 ] << 8 ) | ( pa[ 3 ] << 0 );
\r
293 MCF_FEC_PAUR = ( pa[ 4 ] << 24 ) | ( pa[ 5 ] << 16 );
\r
296 * Calculate and set the hash for given Physical Address
\r
297 * in the Individual Address Hash registers
\r
299 crc = fec_hash_address( pa );
\r
302 MCF_FEC_IAUR |= (unsigned portLONG)(1 << (crc - 32));
\r
306 MCF_FEC_IALR |= (unsigned portLONG)(1 << crc);
\r
309 /*-----------------------------------------------------------*/
\r
311 static void prvInitialiseFECBuffers( void )
\r
313 unsigned portBASE_TYPE ux;
\r
314 unsigned portCHAR *pcBufPointer;
\r
316 /* Correctly align the Tx descriptor pointer. */
\r
317 pcBufPointer = &( xFECTxDescriptors_unaligned[ 0 ] );
\r
318 while( ( ( unsigned portLONG ) pcBufPointer & 0x0fUL ) != 0 )
\r
323 xFECTxDescriptors = ( FECBD * ) pcBufPointer;
\r
325 /* Likewise the Rx descriptor pointer. */
\r
326 pcBufPointer = &( xFECRxDescriptors_unaligned[ 0 ] );
\r
327 while( ( ( unsigned portLONG ) pcBufPointer & 0x0fUL ) != 0 )
\r
332 xFECRxDescriptors = ( FECBD * ) pcBufPointer;
\r
335 /* Setup the Tx buffers and descriptors. There is no separate Tx buffer
\r
336 to point to (the Rx buffers are actually used) so the data member is
\r
337 set to NULL for now. */
338 for( ux = 0; ux < fecNUM_FEC_TX_BUFFERS; ux++ )
\r
340 xFECTxDescriptors[ ux ].status = TX_BD_TC;
\r
341 xFECTxDescriptors[ ux ].data = NULL;
\r
342 xFECTxDescriptors[ ux ].length = 0;
\r
345 /* Setup the Rx buffers and descriptors, having first ensured correct
\r
347 pcBufPointer = &( ucFECRxBuffers[ 0 ] );
\r
348 while( ( ( unsigned portLONG ) pcBufPointer & 0x0fUL ) != 0 )
\r
353 for( ux = 0; ux < configNUM_FEC_RX_BUFFERS; ux++ )
\r
355 xFECRxDescriptors[ ux ].status = RX_BD_E;
\r
356 xFECRxDescriptors[ ux ].length = configFEC_BUFFER_SIZE;
\r
357 xFECRxDescriptors[ ux ].data = pcBufPointer;
\r
358 pcBufPointer += configFEC_BUFFER_SIZE;
\r
361 /* Set the wrap bit in the last descriptors to form a ring. */
\r
362 xFECTxDescriptors[ fecNUM_FEC_TX_BUFFERS - 1 ].status |= TX_BD_W;
\r
363 xFECRxDescriptors[ configNUM_FEC_RX_BUFFERS - 1 ].status |= RX_BD_W;
\r
365 uxNextRxBuffer = 0;
\r
367 /*-----------------------------------------------------------*/
\r
369 void vFECInit( void )
\r
371 unsigned portSHORT usData;
\r
372 struct uip_eth_addr xAddr;
\r
374 /* The MAC address is set at the foot of FreeRTOSConfig.h. */
\r
375 const unsigned portCHAR ucMACAddress[6] =
\r
377 configMAC_0, configMAC_1,configMAC_2, configMAC_3, configMAC_4, configMAC_5
\r
380 /* Create the semaphore used by the ISR to wake the uIP task. */
\r
381 vSemaphoreCreateBinary( xFECSemaphore );
\r
383 /* Create the semaphore used to unblock any tasks that might be waiting
\r
384 for a Tx descriptor. */
\r
385 vSemaphoreCreateBinary( xTxSemaphore );
\r
387 /* Initialise all the buffers and descriptors used by the DMA. */
\r
388 prvInitialiseFECBuffers();
\r
390 for( usData = 0; usData < 6; usData++ )
\r
392 xAddr.addr[ usData ] = ucMACAddress[ usData ];
\r
394 uip_setethaddr( xAddr );
\r
396 /* Set the Reset bit and clear the Enable bit */
\r
397 MCF_FEC_ECR = MCF_FEC_ECR_RESET;
\r
399 /* Wait at least 8 clock cycles */
\r
400 for( usData = 0; usData < 10; usData++ )
\r
405 /* Set MII speed to 2.5MHz. */
\r
406 MCF_FEC_MSCR = MCF_FEC_MSCR_MII_SPEED( ( ( ( configCPU_CLOCK_HZ / 1000000 ) / 5 ) + 1 ) );
\r
408 /* Initialize PLDPAR to enable Ethernet LEDs. */
\r
409 MCF_GPIO_PLDPAR = MCF_GPIO_PLDPAR_ACTLED_ACTLED | MCF_GPIO_PLDPAR_LINKLED_LINKLED | MCF_GPIO_PLDPAR_SPDLED_SPDLED
\r
410 | MCF_GPIO_PLDPAR_DUPLED_DUPLED | MCF_GPIO_PLDPAR_COLLED_COLLED | MCF_GPIO_PLDPAR_RXLED_RXLED
\r
411 | MCF_GPIO_PLDPAR_TXLED_TXLED;
\r
413 /* Initialize Port TA to enable Axcel control. */
\r
414 MCF_GPIO_PTAPAR = 0x00;
\r
415 MCF_GPIO_DDRTA = 0x0F;
\r
416 MCF_GPIO_PORTTA = 0x04;
\r
418 /* Set phy address to zero. */
\r
419 MCF_EPHY_EPHYCTL1 = MCF_EPHY_EPHYCTL1_PHYADD( 0 );
\r
421 /* Enable EPHY module with PHY clocks disabled. Do not turn on PHY clocks
\r
422 until both FEC and EPHY are completely setup (see Below). */
\r
423 MCF_EPHY_EPHYCTL0 = (uint8)(MCF_EPHY_EPHYCTL0_DIS100 | MCF_EPHY_EPHYCTL0_DIS10);
\r
425 /* Enable auto_neg at start-up */
\r
426 MCF_EPHY_EPHYCTL0 = (uint8)(MCF_EPHY_EPHYCTL0 & (MCF_EPHY_EPHYCTL0_ANDIS));
\r
428 /* Enable EPHY module. */
\r
429 MCF_EPHY_EPHYCTL0 = (uint8)(MCF_EPHY_EPHYCTL0_EPHYEN | MCF_EPHY_EPHYCTL0);
\r
431 /* Let PHY PLLs be determined by PHY. */
\r
432 MCF_EPHY_EPHYCTL0 = (uint8)(MCF_EPHY_EPHYCTL0 & ~(MCF_EPHY_EPHYCTL0_DIS100 | MCF_EPHY_EPHYCTL0_DIS10));
\r
435 vTaskDelay( fecLINK_DELAY );
\r
437 /* Can we talk to the PHY? */
\r
440 vTaskDelay( fecLINK_DELAY );
\r
442 fec_mii_read( configPHY_ADDRESS, PHY_PHYIDR1, &usData );
\r
444 } while( usData == 0xffff );
\r
448 /* Start auto negotiate. */
\r
449 fec_mii_write( configPHY_ADDRESS, PHY_BMCR, ( PHY_BMCR_AN_RESTART | PHY_BMCR_AN_ENABLE ) );
\r
451 /* Wait for auto negotiate to complete. */
\r
454 vTaskDelay( fecLINK_DELAY );
\r
455 fec_mii_read( configPHY_ADDRESS, PHY_BMSR, &usData );
\r
457 } while( !( usData & PHY_BMSR_AN_COMPLETE ) );
\r
459 } while( 0 ); //while( !( usData & PHY_BMSR_LINK ) );
\r
461 /* When we get here we have a link - find out what has been negotiated. */
\r
462 fec_mii_read( configPHY_ADDRESS, PHY_ANLPAR, &usData );
\r
464 if( ( usData & PHY_ANLPAR_100BTX_FDX ) || ( usData & PHY_ANLPAR_100BTX ) )
\r
466 /* Speed is 100. */
\r
473 if( ( usData & PHY_ANLPAR_100BTX_FDX ) || ( usData & PHY_ANLPAR_10BTX_FDX ) )
\r
475 MCF_FEC_RCR &= (unsigned portLONG)~MCF_FEC_RCR_DRT;
\r
476 MCF_FEC_TCR |= MCF_FEC_TCR_FDEN;
\r
480 MCF_FEC_RCR |= MCF_FEC_RCR_DRT;
\r
481 MCF_FEC_TCR &= (unsigned portLONG)~MCF_FEC_TCR_FDEN;
\r
484 /* Clear the Individual and Group Address Hash registers */
\r
490 /* Set the Physical Address for the selected FEC */
\r
491 fec_set_address( ucMACAddress );
\r
493 /* Set Rx Buffer Size */
\r
494 MCF_FEC_EMRBR = (unsigned portSHORT)configFEC_BUFFER_SIZE;
\r
496 /* Point to the start of the circular Rx buffer descriptor queue */
\r
497 MCF_FEC_ERDSR = ( volatile unsigned portLONG ) &( xFECRxDescriptors[ 0 ] );
\r
499 /* Point to the start of the circular Tx buffer descriptor queue */
\r
500 MCF_FEC_ETSDR = ( volatile unsigned portLONG ) &( xFECTxDescriptors[ 0 ] );
\r
502 /* Mask all FEC interrupts */
\r
503 MCF_FEC_EIMR = ( unsigned portLONG ) -1;
\r
505 /* Clear all FEC interrupt events */
\r
506 MCF_FEC_EIR = ( unsigned portLONG ) -1;
\r
508 /* Initialize the Receive Control Register */
\r
509 MCF_FEC_RCR = MCF_FEC_RCR_MAX_FL(ETH_MAX_FRM) | MCF_FEC_RCR_FCE;
\r
511 MCF_FEC_RCR |= MCF_FEC_RCR_MII_MODE;
\r
513 #if( configUSE_PROMISCUOUS_MODE == 1 )
\r
515 MCF_FEC_RCR |= MCF_FEC_RCR_PROM;
\r
519 prvEnableFECInterrupts();
\r
521 /* Finally... enable. */
\r
522 MCF_FEC_ECR = MCF_FEC_ECR_ETHER_EN;
\r
523 MCF_FEC_RDAR = MCF_FEC_RDAR_R_DES_ACTIVE;
\r
525 /*-----------------------------------------------------------*/
\r
527 static void prvEnableFECInterrupts( void )
\r
529 const unsigned portBASE_TYPE uxFirstFECVector = 23, uxLastFECVector = 35;
\r
530 unsigned portBASE_TYPE ux;
\r
532 #if configFEC_INTERRUPT_PRIORITY > configMAX_SYSCALL_INTERRUPT_PRIORITY
\r
533 #error configFEC_INTERRUPT_PRIORITY must be less than or equal to configMAX_SYSCALL_INTERRUPT_PRIORITY
\r
536 /* Set the priority of each of the FEC interrupts. */
\r
537 for( ux = uxFirstFECVector; ux <= uxLastFECVector; ux++ )
\r
539 MCF_INTC0_ICR( ux ) = MCF_INTC_ICR_IL( configFEC_INTERRUPT_PRIORITY );
\r
542 /* Enable the FEC interrupts in the mask register */
\r
543 MCF_INTC0_IMRH &= ~( MCF_INTC_IMRH_INT_MASK33 | MCF_INTC_IMRH_INT_MASK34 | MCF_INTC_IMRH_INT_MASK35 );
\r
544 MCF_INTC0_IMRL &= ~( MCF_INTC_IMRL_INT_MASK25 | MCF_INTC_IMRL_INT_MASK26 | MCF_INTC_IMRL_INT_MASK27
\r
545 | MCF_INTC_IMRL_INT_MASK28 | MCF_INTC_IMRL_INT_MASK29 | MCF_INTC_IMRL_INT_MASK30
\r
546 | MCF_INTC_IMRL_INT_MASK31 | MCF_INTC_IMRL_INT_MASK23 | MCF_INTC_IMRL_INT_MASK24
\r
547 | MCF_INTC_IMRL_MASKALL );
\r
549 /* Clear any pending FEC interrupt events */
\r
550 MCF_FEC_EIR = MCF_FEC_EIR_CLEAR_ALL;
\r
552 /* Unmask all FEC interrupts */
\r
553 MCF_FEC_EIMR = MCF_FEC_EIMR_UNMASK_ALL;
\r
555 /*-----------------------------------------------------------*/
\r
557 static void prvResetFEC( portBASE_TYPE xCalledFromISR )
\r
561 /* A critical section is used unless this function is being called from
\r
563 if( xCalledFromISR == pdFALSE )
\r
565 taskENTER_CRITICAL();
\r
569 /* Reset all buffers and descriptors. */
\r
570 prvInitialiseFECBuffers();
\r
572 /* Set the Reset bit and clear the Enable bit */
\r
573 MCF_FEC_ECR = MCF_FEC_ECR_RESET;
\r
575 /* Wait at least 8 clock cycles */
\r
576 for( x = 0; x < 10; x++ )
\r
582 MCF_FEC_ECR = MCF_FEC_ECR_ETHER_EN;
\r
583 MCF_FEC_RDAR = MCF_FEC_RDAR_R_DES_ACTIVE;
\r
586 if( xCalledFromISR == pdFALSE )
\r
588 taskEXIT_CRITICAL();
\r
591 /*-----------------------------------------------------------*/
\r
593 unsigned short usFECGetRxedData( void )
\r
595 unsigned portSHORT usLen;
\r
597 /* Obtain the size of the packet and put it into the "len" variable. */
\r
598 usLen = xFECRxDescriptors[ uxNextRxBuffer ].length;
\r
600 if( ( usLen != 0 ) && ( ( xFECRxDescriptors[ uxNextRxBuffer ].status & RX_BD_E ) == 0 ) )
\r
602 uip_buf = xFECRxDescriptors[ uxNextRxBuffer ].data;
\r
611 /*-----------------------------------------------------------*/
\r
613 void vFECRxProcessingCompleted( void )
\r
615 /* Free the descriptor as the buffer it points to is no longer in use. */
\r
616 xFECRxDescriptors[ uxNextRxBuffer ].status |= RX_BD_E;
\r
617 MCF_FEC_RDAR = MCF_FEC_RDAR_R_DES_ACTIVE;
\r
619 if( uxNextRxBuffer >= configNUM_FEC_RX_BUFFERS )
\r
621 uxNextRxBuffer = 0;
\r
624 /*-----------------------------------------------------------*/
\r
626 void vFECSendData( void )
\r
628 /* Ensure no Tx frames are outstanding. */
\r
629 if( xSemaphoreTake( xTxSemaphore, fecMAX_WAIT_FOR_TX_BUFFER ) == pdPASS )
\r
631 /* Get a DMA buffer into which we can write the data to send. */
\r
632 if( xFECTxDescriptors[ fecTX_BUFFER_TO_USE ].status & TX_BD_R )
\r
634 /*** ERROR didn't expect this. Sledge hammer error handling. ***/
\r
635 prvResetFEC( pdFALSE );
\r
637 /* Make sure we leave the semaphore in the expected state as nothing
\r
638 is being transmitted this will not happen in the Tx ISR. */
\r
639 xSemaphoreGive( xTxSemaphore );
\r
643 /* Setup the buffer descriptor for transmission. The data being
\r
644 sent is actually stored in one of the Rx descriptor buffers,
\r
645 pointed to by uip_buf. */
\r
646 xFECTxDescriptors[ fecTX_BUFFER_TO_USE ].length = uip_len;
\r
647 xFECTxDescriptors[ fecTX_BUFFER_TO_USE ].status |= ( TX_BD_R | TX_BD_L );
\r
648 xFECTxDescriptors[ fecTX_BUFFER_TO_USE ].data = uip_buf;
\r
650 /* Remember which Rx descriptor owns the buffer we are sending. */
\r
651 uxIndexToBufferOwner = uxNextRxBuffer;
\r
653 /* We have finished with this Rx descriptor now. */
\r
655 if( uxNextRxBuffer >= configNUM_FEC_RX_BUFFERS )
\r
657 uxNextRxBuffer = 0;
\r
660 /* Continue the Tx DMA (in case it was waiting for a new TxBD) */
\r
661 MCF_FEC_TDAR = MCF_FEC_TDAR_X_DES_ACTIVE;
\r
666 /* Gave up waiting. Free the buffer back to the DMA. */
\r
667 vFECRxProcessingCompleted();
\r
670 /*-----------------------------------------------------------*/
\r
672 void vFEC_ISR( void )
\r
674 unsigned portLONG ulEvent;
\r
675 portBASE_TYPE xHighPriorityTaskWoken = pdFALSE;
\r
677 /* This handler is called in response to any of the many separate FEC
\r
680 /* Find the cause of the interrupt, then clear the interrupt. */
\r
681 ulEvent = MCF_FEC_EIR & MCF_FEC_EIMR;
\r
682 MCF_FEC_EIR = ulEvent;
\r
684 if( ( ulEvent & MCF_FEC_EIR_RXB ) || ( ulEvent & MCF_FEC_EIR_RXF ) )
\r
686 /* A packet has been received. Wake the handler task. */
\r
687 xSemaphoreGiveFromISR( xFECSemaphore, &xHighPriorityTaskWoken );
\r
690 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
692 /* Sledge hammer error handling. */
\r
693 prvResetFEC( pdTRUE );
\r
696 if( ( ulEvent & MCF_FEC_EIR_TXF ) || ( ulEvent & MCF_FEC_EIR_TXB ) )
\r
698 /* The buffer being sent is pointed to by an Rx descriptor, now the
\r
699 buffer has been sent we can mark the Rx descriptor as free again. */
\r
700 xFECRxDescriptors[ uxIndexToBufferOwner ].status |= RX_BD_E;
\r
701 MCF_FEC_RDAR = MCF_FEC_RDAR_R_DES_ACTIVE;
\r
702 xSemaphoreGiveFromISR( xTxSemaphore, &xHighPriorityTaskWoken );
\r
705 portEND_SWITCHING_ISR( xHighPriorityTaskWoken );
\r
707 /*-----------------------------------------------------------*/
\r
709 /* Install the many different interrupt vectors, all of which call the same
\r
710 handler function. */
\r
711 void __attribute__ ((interrupt)) __cs3_isr_interrupt_87( void ) { vFEC_ISR(); }
\r
712 void __attribute__ ((interrupt)) __cs3_isr_interrupt_88( void ) { vFEC_ISR(); }
\r
713 void __attribute__ ((interrupt)) __cs3_isr_interrupt_89( void ) { vFEC_ISR(); }
\r
714 void __attribute__ ((interrupt)) __cs3_isr_interrupt_90( void ) { vFEC_ISR(); }
\r
715 void __attribute__ ((interrupt)) __cs3_isr_interrupt_91( void ) { vFEC_ISR(); }
\r
716 void __attribute__ ((interrupt)) __cs3_isr_interrupt_92( void ) { vFEC_ISR(); }
\r
717 void __attribute__ ((interrupt)) __cs3_isr_interrupt_93( void ) { vFEC_ISR(); }
\r
718 void __attribute__ ((interrupt)) __cs3_isr_interrupt_94( void ) { vFEC_ISR(); }
\r
719 void __attribute__ ((interrupt)) __cs3_isr_interrupt_95( void ) { vFEC_ISR(); }
\r
720 void __attribute__ ((interrupt)) __cs3_isr_interrupt_96( void ) { vFEC_ISR(); }
\r
721 void __attribute__ ((interrupt)) __cs3_isr_interrupt_97( void ) { vFEC_ISR(); }
\r
722 void __attribute__ ((interrupt)) __cs3_isr_interrupt_98( void ) { vFEC_ISR(); }
\r
723 void __attribute__ ((interrupt)) __cs3_isr_interrupt_99( void ) { vFEC_ISR(); }
\r