2 * FreeRTOS Kernel V10.0.0
\r
3 * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
\r
5 * Permission is hereby granted, free of charge, to any person obtaining a copy of
\r
6 * this software and associated documentation files (the "Software"), to deal in
\r
7 * the Software without restriction, including without limitation the rights to
\r
8 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
\r
9 * the Software, and to permit persons to whom the Software is furnished to do so,
\r
10 * subject to the following conditions:
\r
12 * The above copyright notice and this permission notice shall be included in all
\r
13 * copies or substantial portions of the Software. If you wish to use our Amazon
\r
14 * FreeRTOS name, please do so in a fair use way that does not cause confusion.
\r
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
\r
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
\r
18 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
\r
19 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
\r
20 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
\r
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\r
23 * http://www.FreeRTOS.org
\r
24 * http://aws.amazon.com/freertos
\r
26 * 1 tab == 4 spaces!
\r
29 /* Kernel includes. */
\r
30 #include "FreeRTOS.h"
\r
34 /* Hardware includes. */
\r
37 #include "eth_phy.h"
\r
42 #include "uip_arp.h"
\r
44 /* Delay between polling the PHY to see if a link has been established. */
\r
45 #define fecLINK_DELAY ( 500 / portTICK_RATE_MS )
\r
47 /* Delay to wait for an MII access. */
\r
48 #define fecMII_DELAY ( 10 / portTICK_RATE_MS )
\r
49 #define fecMAX_POLLS ( 20 )
\r
51 /* Constants used to delay while waiting for a tx descriptor to be free. */
\r
52 #define fecMAX_WAIT_FOR_TX_BUFFER ( 200 / portTICK_RATE_MS )
\r
54 /* We only use a single Tx descriptor which can lead to Txed packets being sent
\r
55 twice (due to a bug in the FEC silicon). However, in this case the bug is used
\r
56 to our advantage in that it means the uip-split mechanism is not required. */
\r
57 #define fecNUM_FEC_TX_BUFFERS ( 1 )
\r
58 #define fecTX_BUFFER_TO_USE ( 0 )
\r
59 /*-----------------------------------------------------------*/
\r
61 /* The semaphore used to wake the uIP task when data arrives. */
\r
62 xSemaphoreHandle xFECSemaphore = NULL, xTxSemaphore = NULL;
\r
64 /* The buffer used by the uIP stack. In this case the pointer is used to
\r
65 point to one of the Rx buffers to effect a zero copy policy. */
\r
66 unsigned char *uip_buf;
\r
68 /* The DMA descriptors. This is a char array to allow us to align it correctly. */
\r
69 static unsigned char xFECTxDescriptors_unaligned[ ( fecNUM_FEC_TX_BUFFERS * sizeof( FECBD ) ) + 16 ];
\r
70 static unsigned char xFECRxDescriptors_unaligned[ ( configNUM_FEC_RX_BUFFERS * sizeof( FECBD ) ) + 16 ];
\r
71 static FECBD *xFECTxDescriptors;
\r
72 static FECBD *xFECRxDescriptors;
\r
74 /* The DMA buffers. These are char arrays to allow them to be aligned correctly. */
\r
75 static unsigned char ucFECRxBuffers[ ( configNUM_FEC_RX_BUFFERS * configFEC_BUFFER_SIZE ) + 16 ];
\r
76 static unsigned portBASE_TYPE uxNextRxBuffer = 0, uxIndexToBufferOwner = 0;
\r
78 /*-----------------------------------------------------------*/
\r
81 * Enable all the required interrupts in the FEC and in the interrupt controller.
\r
83 static void prvEnableFECInterrupts( void );
\r
86 * Reset the FEC if we get into an unrecoverable state.
\r
88 static void prvResetFEC( portBASE_TYPE xCalledFromISR );
\r
90 /********************************************************************/
\r
93 * FUNCTION ADAPTED FROM FREESCALE SUPPLIED SOURCE
\r
95 * Write a value to a PHY's MII register.
\r
99 * phy_addr Address of the PHY.
\r
100 * reg_addr Address of the register in the PHY.
\r
101 * data Data to be written to the PHY register.
\r
107 * Please refer to your PHY manual for registers and their meanings.
\r
108 * mii_write() polls for the FEC's MII interrupt event and clears it.
\r
109 * If after a suitable amount of time the event isn't triggered, a
\r
110 * value of 0 is returned.
\r
112 static int fec_mii_write( int phy_addr, int reg_addr, int data )
\r
114 int timeout, iReturn;
\r
117 /* Clear the MII interrupt bit */
\r
118 MCF_FEC_EIR = MCF_FEC_EIR_MII;
\r
120 /* Mask the MII interrupt */
\r
121 eimr = MCF_FEC_EIMR;
\r
122 MCF_FEC_EIMR &= ~MCF_FEC_EIMR_MII;
\r
124 /* Write to the MII Management Frame Register to kick-off the MII write */
\r
125 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
127 /* Poll for the MII interrupt (interrupt should be masked) */
\r
128 for( timeout = 0; timeout < fecMAX_POLLS; timeout++ )
\r
130 if( MCF_FEC_EIR & MCF_FEC_EIR_MII )
\r
136 vTaskDelay( fecMII_DELAY );
\r
140 if( timeout == fecMAX_POLLS )
\r
149 /* Clear the MII interrupt bit */
\r
150 MCF_FEC_EIR = MCF_FEC_EIR_MII;
\r
152 /* Restore the EIMR */
\r
153 MCF_FEC_EIMR = eimr;
\r
158 /********************************************************************/
\r
160 * FUNCTION ADAPTED FROM FREESCALE SUPPLIED SOURCE
\r
162 * Read a value from a PHY's MII register.
\r
166 * phy_addr Address of the PHY.
\r
167 * reg_addr Address of the register in the PHY.
\r
168 * data Pointer to storage for the Data to be read
\r
169 * from the PHY register (passed by reference)
\r
175 * Please refer to your PHY manual for registers and their meanings.
\r
176 * mii_read() polls for the FEC's MII interrupt event and clears it.
\r
177 * If after a suitable amount of time the event isn't triggered, a
\r
178 * value of 0 is returned.
\r
180 static int fec_mii_read( int phy_addr, int reg_addr, unsigned short* data )
\r
182 int timeout, iReturn;
\r
185 /* Clear the MII interrupt bit */
\r
186 MCF_FEC_EIR = MCF_FEC_EIR_MII;
\r
188 /* Mask the MII interrupt */
\r
189 eimr = MCF_FEC_EIMR;
\r
190 MCF_FEC_EIMR &= ~MCF_FEC_EIMR_MII;
\r
192 /* Write to the MII Management Frame Register to kick-off the MII read */
\r
193 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
195 /* Poll for the MII interrupt (interrupt should be masked) */
\r
196 for( timeout = 0; timeout < fecMAX_POLLS; timeout++ )
\r
198 if (MCF_FEC_EIR & MCF_FEC_EIR_MII)
\r
204 vTaskDelay( fecMII_DELAY );
\r
208 if( timeout == fecMAX_POLLS )
\r
214 *data = (uint16)(MCF_FEC_MMFR & 0x0000FFFF);
\r
218 /* Clear the MII interrupt bit */
\r
219 MCF_FEC_EIR = MCF_FEC_EIR_MII;
\r
221 /* Restore the EIMR */
\r
222 MCF_FEC_EIMR = eimr;
\r
228 /********************************************************************/
\r
230 * FUNCTION ADAPTED FROM FREESCALE SUPPLIED SOURCE
\r
232 * Generate the hash table settings for the given address
\r
235 * addr 48-bit (6 byte) Address to generate the hash for
\r
238 * The 6 most significant bits of the 32-bit CRC result
\r
240 static unsigned char fec_hash_address( const unsigned char* addr )
\r
243 unsigned char byte;
\r
252 if((byte & 0x01)^(crc & 0x01))
\r
255 crc = crc ^ 0xEDB88320;
\r
266 return (unsigned char)(crc >> 26);
\r
269 /********************************************************************/
\r
271 * FUNCTION ADAPTED FROM FREESCALE SUPPLIED SOURCE
\r
273 * Set the Physical (Hardware) Address and the Individual Address
\r
274 * Hash in the selected FEC
\r
278 * pa Physical (Hardware) Address for the selected FEC
\r
280 static void fec_set_address( const unsigned char *pa )
\r
285 * Set the Physical Address
\r
287 /* Set the source address for the controller */
\r
288 MCF_FEC_PALR = ( pa[ 0 ] << 24 ) | ( pa[ 1 ] << 16 ) | ( pa[ 2 ] << 8 ) | ( pa[ 3 ] << 0 );
\r
289 MCF_FEC_PAUR = ( pa[ 4 ] << 24 ) | ( pa[ 5 ] << 16 );
\r
292 * Calculate and set the hash for given Physical Address
\r
293 * in the Individual Address Hash registers
\r
295 crc = fec_hash_address( pa );
\r
298 MCF_FEC_IAUR |= (unsigned long)(1 << (crc - 32));
\r
302 MCF_FEC_IALR |= (unsigned long)(1 << crc);
\r
305 /*-----------------------------------------------------------*/
\r
307 static void prvInitialiseFECBuffers( void )
\r
309 unsigned portBASE_TYPE ux;
\r
310 unsigned char *pcBufPointer;
\r
312 /* Correctly align the Tx descriptor pointer. */
\r
313 pcBufPointer = &( xFECTxDescriptors_unaligned[ 0 ] );
\r
314 while( ( ( unsigned long ) pcBufPointer & 0x0fUL ) != 0 )
\r
319 xFECTxDescriptors = ( FECBD * ) pcBufPointer;
\r
321 /* Likewise the Rx descriptor pointer. */
\r
322 pcBufPointer = &( xFECRxDescriptors_unaligned[ 0 ] );
\r
323 while( ( ( unsigned long ) pcBufPointer & 0x0fUL ) != 0 )
\r
328 xFECRxDescriptors = ( FECBD * ) pcBufPointer;
\r
331 /* Setup the Tx buffers and descriptors. There is no separate Tx buffer
\r
332 to point to (the Rx buffers are actually used) so the data member is
\r
333 set to NULL for now. */
\r
334 for( ux = 0; ux < fecNUM_FEC_TX_BUFFERS; ux++ )
\r
336 xFECTxDescriptors[ ux ].status = TX_BD_TC;
\r
337 xFECTxDescriptors[ ux ].data = NULL;
\r
338 xFECTxDescriptors[ ux ].length = 0;
\r
341 /* Setup the Rx buffers and descriptors, having first ensured correct
\r
343 pcBufPointer = &( ucFECRxBuffers[ 0 ] );
\r
344 while( ( ( unsigned long ) pcBufPointer & 0x0fUL ) != 0 )
\r
349 for( ux = 0; ux < configNUM_FEC_RX_BUFFERS; ux++ )
\r
351 xFECRxDescriptors[ ux ].status = RX_BD_E;
\r
352 xFECRxDescriptors[ ux ].length = configFEC_BUFFER_SIZE;
\r
353 xFECRxDescriptors[ ux ].data = pcBufPointer;
\r
354 pcBufPointer += configFEC_BUFFER_SIZE;
\r
357 /* Set the wrap bit in the last descriptors to form a ring. */
\r
358 xFECTxDescriptors[ fecNUM_FEC_TX_BUFFERS - 1 ].status |= TX_BD_W;
\r
359 xFECRxDescriptors[ configNUM_FEC_RX_BUFFERS - 1 ].status |= RX_BD_W;
\r
361 uxNextRxBuffer = 0;
\r
363 /*-----------------------------------------------------------*/
\r
365 void vFECInit( void )
\r
367 unsigned short usData;
\r
368 struct uip_eth_addr xAddr;
\r
369 unsigned portBASE_TYPE ux;
\r
371 /* The MAC address is set at the foot of FreeRTOSConfig.h. */
\r
372 const unsigned char ucMACAddress[6] =
\r
374 configMAC_0, configMAC_1,configMAC_2, configMAC_3, configMAC_4, configMAC_5
\r
377 /* Create the semaphore used by the ISR to wake the uIP task. */
\r
378 vSemaphoreCreateBinary( xFECSemaphore );
\r
380 /* Create the semaphore used to unblock any tasks that might be waiting
\r
381 for a Tx descriptor. */
\r
382 vSemaphoreCreateBinary( xTxSemaphore );
\r
384 /* Initialise all the buffers and descriptors used by the DMA. */
\r
385 prvInitialiseFECBuffers();
\r
387 for( usData = 0; usData < 6; usData++ )
\r
389 xAddr.addr[ usData ] = ucMACAddress[ usData ];
\r
391 uip_setethaddr( xAddr );
\r
393 /* Set the Reset bit and clear the Enable bit */
\r
394 MCF_FEC_ECR = MCF_FEC_ECR_RESET;
\r
396 /* Wait at least 8 clock cycles */
\r
397 for( usData = 0; usData < 10; usData++ )
\r
402 /* Set MII speed to 2.5MHz. */
\r
403 MCF_FEC_MSCR = MCF_FEC_MSCR_MII_SPEED( ( ( ( configCPU_CLOCK_HZ / 1000000 ) / 5 ) + 1 ) );
\r
405 /* Initialize PLDPAR to enable Ethernet LEDs. */
\r
406 MCF_GPIO_PLDPAR = MCF_GPIO_PLDPAR_ACTLED_ACTLED | MCF_GPIO_PLDPAR_LINKLED_LINKLED | MCF_GPIO_PLDPAR_SPDLED_SPDLED
\r
407 | MCF_GPIO_PLDPAR_DUPLED_DUPLED | MCF_GPIO_PLDPAR_COLLED_COLLED | MCF_GPIO_PLDPAR_RXLED_RXLED
\r
408 | MCF_GPIO_PLDPAR_TXLED_TXLED;
\r
410 /* Initialize Port TA to enable Axcel control. */
\r
411 MCF_GPIO_PTAPAR = 0x00;
\r
412 MCF_GPIO_DDRTA = 0x0F;
\r
413 MCF_GPIO_PORTTA = 0x04;
\r
415 /* Set phy address to zero. */
\r
416 MCF_EPHY_EPHYCTL1 = MCF_EPHY_EPHYCTL1_PHYADD( 0 );
\r
418 /* Enable EPHY module with PHY clocks disabled. Do not turn on PHY clocks
\r
419 until both FEC and EPHY are completely setup (see Below). */
\r
420 MCF_EPHY_EPHYCTL0 = (uint8)(MCF_EPHY_EPHYCTL0_DIS100 | MCF_EPHY_EPHYCTL0_DIS10);
\r
422 /* Enable auto_neg at start-up */
\r
423 MCF_EPHY_EPHYCTL0 = (uint8)(MCF_EPHY_EPHYCTL0 & (MCF_EPHY_EPHYCTL0_ANDIS));
\r
425 /* Enable EPHY module. */
\r
426 MCF_EPHY_EPHYCTL0 = (uint8)(MCF_EPHY_EPHYCTL0_EPHYEN | MCF_EPHY_EPHYCTL0);
\r
428 /* Let PHY PLLs be determined by PHY. */
\r
429 MCF_EPHY_EPHYCTL0 = (uint8)(MCF_EPHY_EPHYCTL0 & ~(MCF_EPHY_EPHYCTL0_DIS100 | MCF_EPHY_EPHYCTL0_DIS10));
\r
432 vTaskDelay( fecLINK_DELAY );
\r
434 /* Can we talk to the PHY? */
\r
437 vTaskDelay( fecLINK_DELAY );
\r
439 fec_mii_read( configPHY_ADDRESS, PHY_PHYIDR1, &usData );
\r
441 } while( usData == 0xffff );
\r
445 /* Start auto negotiate. */
\r
446 fec_mii_write( configPHY_ADDRESS, PHY_BMCR, ( PHY_BMCR_AN_RESTART | PHY_BMCR_AN_ENABLE ) );
\r
448 /* Wait for auto negotiate to complete. */
\r
454 /* Hardware bug workaround! Force 100Mbps half duplex. */
\r
455 while( !fec_mii_read( configPHY_ADDRESS, 0, &usData ) ){};
\r
456 usData &= ~0x2000; /* 10Mbps */
\r
457 usData &= ~0x0100; /* Half Duplex */
\r
458 usData &= ~0x1000; /* Manual Mode */
\r
459 while( !fec_mii_write( configPHY_ADDRESS, 0, usData ) ){};
\r
460 while( !fec_mii_write( configPHY_ADDRESS, 0, (usData|0x0200) )){}; /* Force re-negotiate */
\r
463 vTaskDelay( fecLINK_DELAY );
\r
464 fec_mii_read( configPHY_ADDRESS, PHY_BMSR, &usData );
\r
466 } while( !( usData & PHY_BMSR_AN_COMPLETE ) );
\r
468 } while( 0 ); //while( !( usData & PHY_BMSR_LINK ) );
\r
470 /* When we get here we have a link - find out what has been negotiated. */
\r
471 fec_mii_read( configPHY_ADDRESS, PHY_ANLPAR, &usData );
\r
473 if( ( usData & PHY_ANLPAR_100BTX_FDX ) || ( usData & PHY_ANLPAR_100BTX ) )
\r
475 /* Speed is 100. */
\r
482 if( ( usData & PHY_ANLPAR_100BTX_FDX ) || ( usData & PHY_ANLPAR_10BTX_FDX ) )
\r
484 MCF_FEC_RCR &= (unsigned long)~MCF_FEC_RCR_DRT;
\r
485 MCF_FEC_TCR |= MCF_FEC_TCR_FDEN;
\r
489 MCF_FEC_RCR |= MCF_FEC_RCR_DRT;
\r
490 MCF_FEC_TCR &= (unsigned long)~MCF_FEC_TCR_FDEN;
\r
493 /* Clear the Individual and Group Address Hash registers */
\r
499 /* Set the Physical Address for the selected FEC */
\r
500 fec_set_address( ucMACAddress );
\r
502 /* Set Rx Buffer Size */
\r
503 MCF_FEC_EMRBR = (unsigned short)configFEC_BUFFER_SIZE;
\r
505 /* Point to the start of the circular Rx buffer descriptor queue */
\r
506 MCF_FEC_ERDSR = ( volatile unsigned long ) &( xFECRxDescriptors[ 0 ] );
\r
508 /* Point to the start of the circular Tx buffer descriptor queue */
\r
509 MCF_FEC_ETSDR = ( volatile unsigned long ) &( xFECTxDescriptors[ 0 ] );
\r
511 /* Mask all FEC interrupts */
\r
512 MCF_FEC_EIMR = ( unsigned long ) -1;
\r
514 /* Clear all FEC interrupt events */
\r
515 MCF_FEC_EIR = ( unsigned long ) -1;
\r
517 /* Initialize the Receive Control Register */
\r
518 MCF_FEC_RCR = MCF_FEC_RCR_MAX_FL(ETH_MAX_FRM) | MCF_FEC_RCR_FCE;
\r
520 MCF_FEC_RCR |= MCF_FEC_RCR_MII_MODE;
\r
522 #if( configUSE_PROMISCUOUS_MODE == 1 )
\r
524 MCF_FEC_RCR |= MCF_FEC_RCR_PROM;
\r
528 prvEnableFECInterrupts();
\r
530 /* Finally... enable. */
\r
531 MCF_FEC_ECR = MCF_FEC_ECR_ETHER_EN;
\r
532 MCF_FEC_RDAR = MCF_FEC_RDAR_R_DES_ACTIVE;
\r
534 /*-----------------------------------------------------------*/
\r
536 static void prvEnableFECInterrupts( void )
\r
538 const unsigned portBASE_TYPE uxFirstFECVector = 23, uxLastFECVector = 35;
\r
539 unsigned portBASE_TYPE ux;
\r
541 #if configFEC_INTERRUPT_PRIORITY > configMAX_SYSCALL_INTERRUPT_PRIORITY
\r
542 #error configFEC_INTERRUPT_PRIORITY must be less than or equal to configMAX_SYSCALL_INTERRUPT_PRIORITY
\r
545 /* Set the priority of each of the FEC interrupts. */
\r
546 for( ux = uxFirstFECVector; ux <= uxLastFECVector; ux++ )
\r
548 MCF_INTC0_ICR( ux ) = MCF_INTC_ICR_IL( configFEC_INTERRUPT_PRIORITY );
\r
551 /* Enable the FEC interrupts in the mask register */
\r
552 MCF_INTC0_IMRH &= ~( MCF_INTC_IMRH_INT_MASK33 | MCF_INTC_IMRH_INT_MASK34 | MCF_INTC_IMRH_INT_MASK35 );
\r
553 MCF_INTC0_IMRL &= ~( MCF_INTC_IMRL_INT_MASK25 | MCF_INTC_IMRL_INT_MASK26 | MCF_INTC_IMRL_INT_MASK27
\r
554 | MCF_INTC_IMRL_INT_MASK28 | MCF_INTC_IMRL_INT_MASK29 | MCF_INTC_IMRL_INT_MASK30
\r
555 | MCF_INTC_IMRL_INT_MASK31 | MCF_INTC_IMRL_INT_MASK23 | MCF_INTC_IMRL_INT_MASK24
\r
556 | MCF_INTC_IMRL_MASKALL );
\r
558 /* Clear any pending FEC interrupt events */
\r
559 MCF_FEC_EIR = MCF_FEC_EIR_CLEAR_ALL;
\r
561 /* Unmask all FEC interrupts */
\r
562 MCF_FEC_EIMR = MCF_FEC_EIMR_UNMASK_ALL;
\r
564 /*-----------------------------------------------------------*/
\r
566 static void prvResetFEC( portBASE_TYPE xCalledFromISR )
\r
570 /* A critical section is used unless this function is being called from
\r
572 if( xCalledFromISR == pdFALSE )
\r
574 taskENTER_CRITICAL();
\r
578 /* Reset all buffers and descriptors. */
\r
579 prvInitialiseFECBuffers();
\r
581 /* Set the Reset bit and clear the Enable bit */
\r
582 MCF_FEC_ECR = MCF_FEC_ECR_RESET;
\r
584 /* Wait at least 8 clock cycles */
\r
585 for( x = 0; x < 10; x++ )
\r
591 MCF_FEC_ECR = MCF_FEC_ECR_ETHER_EN;
\r
592 MCF_FEC_RDAR = MCF_FEC_RDAR_R_DES_ACTIVE;
\r
595 if( xCalledFromISR == pdFALSE )
\r
597 taskEXIT_CRITICAL();
\r
600 /*-----------------------------------------------------------*/
\r
602 unsigned short usFECGetRxedData( void )
\r
604 unsigned short usLen;
\r
606 /* Obtain the size of the packet and put it into the "len" variable. */
\r
607 usLen = xFECRxDescriptors[ uxNextRxBuffer ].length;
\r
609 if( ( usLen != 0 ) && ( ( xFECRxDescriptors[ uxNextRxBuffer ].status & RX_BD_E ) == 0 ) )
\r
611 uip_buf = xFECRxDescriptors[ uxNextRxBuffer ].data;
\r
620 /*-----------------------------------------------------------*/
\r
622 void vFECRxProcessingCompleted( void )
\r
624 /* Free the descriptor as the buffer it points to is no longer in use. */
\r
625 xFECRxDescriptors[ uxNextRxBuffer ].status |= RX_BD_E;
\r
626 MCF_FEC_RDAR = MCF_FEC_RDAR_R_DES_ACTIVE;
\r
628 if( uxNextRxBuffer >= configNUM_FEC_RX_BUFFERS )
\r
630 uxNextRxBuffer = 0;
\r
633 /*-----------------------------------------------------------*/
\r
635 void vFECSendData( void )
\r
637 /* Ensure no Tx frames are outstanding. */
\r
638 if( xSemaphoreTake( xTxSemaphore, fecMAX_WAIT_FOR_TX_BUFFER ) == pdPASS )
\r
640 /* Get a DMA buffer into which we can write the data to send. */
\r
641 if( xFECTxDescriptors[ fecTX_BUFFER_TO_USE ].status & TX_BD_R )
\r
643 /*** ERROR didn't expect this. Sledge hammer error handling. ***/
\r
644 prvResetFEC( pdFALSE );
\r
646 /* Make sure we leave the semaphore in the expected state as nothing
\r
647 is being transmitted this will not happen in the Tx ISR. */
\r
648 xSemaphoreGive( xTxSemaphore );
\r
652 /* Setup the buffer descriptor for transmission. The data being
\r
653 sent is actually stored in one of the Rx descriptor buffers,
\r
654 pointed to by uip_buf. */
\r
655 xFECTxDescriptors[ fecTX_BUFFER_TO_USE ].length = uip_len;
\r
656 xFECTxDescriptors[ fecTX_BUFFER_TO_USE ].status |= ( TX_BD_R | TX_BD_L );
\r
657 xFECTxDescriptors[ fecTX_BUFFER_TO_USE ].data = uip_buf;
\r
659 /* Remember which Rx descriptor owns the buffer we are sending. */
\r
660 uxIndexToBufferOwner = uxNextRxBuffer;
\r
662 /* We have finished with this Rx descriptor now. */
\r
664 if( uxNextRxBuffer >= configNUM_FEC_RX_BUFFERS )
\r
666 uxNextRxBuffer = 0;
\r
669 /* Continue the Tx DMA (in case it was waiting for a new TxBD) */
\r
670 MCF_FEC_TDAR = MCF_FEC_TDAR_X_DES_ACTIVE;
\r
675 /* Gave up waiting. Free the buffer back to the DMA. */
\r
676 vFECRxProcessingCompleted();
\r
679 /*-----------------------------------------------------------*/
\r
681 void vFEC_ISR( void )
\r
683 unsigned long ulEvent;
\r
684 portBASE_TYPE xHighPriorityTaskWoken = pdFALSE;
\r
686 /* This handler is called in response to any of the many separate FEC
\r
689 /* Find the cause of the interrupt, then clear the interrupt. */
\r
690 ulEvent = MCF_FEC_EIR & MCF_FEC_EIMR;
\r
691 MCF_FEC_EIR = ulEvent;
\r
693 if( ( ulEvent & MCF_FEC_EIR_RXB ) || ( ulEvent & MCF_FEC_EIR_RXF ) )
\r
695 /* A packet has been received. Wake the handler task. */
\r
696 xSemaphoreGiveFromISR( xFECSemaphore, &xHighPriorityTaskWoken );
\r
699 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
701 /* Sledge hammer error handling. */
\r
702 prvResetFEC( pdTRUE );
\r
705 if( ( ulEvent & MCF_FEC_EIR_TXF ) || ( ulEvent & MCF_FEC_EIR_TXB ) )
\r
707 /* The buffer being sent is pointed to by an Rx descriptor, now the
\r
708 buffer has been sent we can mark the Rx descriptor as free again. */
\r
709 xFECRxDescriptors[ uxIndexToBufferOwner ].status |= RX_BD_E;
\r
710 MCF_FEC_RDAR = MCF_FEC_RDAR_R_DES_ACTIVE;
\r
711 xSemaphoreGiveFromISR( xTxSemaphore, &xHighPriorityTaskWoken );
\r
714 portEND_SWITCHING_ISR( xHighPriorityTaskWoken );
\r
716 /*-----------------------------------------------------------*/
\r
718 /* Install the many different interrupt vectors, all of which call the same
\r
719 handler function. */
\r
720 void __attribute__ ((interrupt)) __cs3_isr_interrupt_87( void ) { vFEC_ISR(); }
\r
721 void __attribute__ ((interrupt)) __cs3_isr_interrupt_88( void ) { vFEC_ISR(); }
\r
722 void __attribute__ ((interrupt)) __cs3_isr_interrupt_89( void ) { vFEC_ISR(); }
\r
723 void __attribute__ ((interrupt)) __cs3_isr_interrupt_90( void ) { vFEC_ISR(); }
\r
724 void __attribute__ ((interrupt)) __cs3_isr_interrupt_91( void ) { vFEC_ISR(); }
\r
725 void __attribute__ ((interrupt)) __cs3_isr_interrupt_92( void ) { vFEC_ISR(); }
\r
726 void __attribute__ ((interrupt)) __cs3_isr_interrupt_93( void ) { vFEC_ISR(); }
\r
727 void __attribute__ ((interrupt)) __cs3_isr_interrupt_94( void ) { vFEC_ISR(); }
\r
728 void __attribute__ ((interrupt)) __cs3_isr_interrupt_95( void ) { vFEC_ISR(); }
\r
729 void __attribute__ ((interrupt)) __cs3_isr_interrupt_96( void ) { vFEC_ISR(); }
\r
730 void __attribute__ ((interrupt)) __cs3_isr_interrupt_97( void ) { vFEC_ISR(); }
\r
731 void __attribute__ ((interrupt)) __cs3_isr_interrupt_98( void ) { vFEC_ISR(); }
\r
732 void __attribute__ ((interrupt)) __cs3_isr_interrupt_99( void ) { vFEC_ISR(); }
\r