2 * FreeRTOS Kernel V10.0.1
\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.
\r
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
\r
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
\r
17 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
\r
18 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
\r
19 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
\r
20 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\r
22 * http://www.FreeRTOS.org
\r
23 * http://aws.amazon.com/freertos
\r
25 * 1 tab == 4 spaces!
\r
28 /* Kernel includes. */
\r
29 #include "FreeRTOS.h"
\r
33 /* Hardware includes. */
\r
36 #include "eth_phy.h"
\r
41 #include "uip_arp.h"
\r
43 /* Delay between polling the PHY to see if a link has been established. */
\r
44 #define fecLINK_DELAY ( 500 / portTICK_RATE_MS )
\r
46 /* Delay to wait for an MII access. */
\r
47 #define fecMII_DELAY ( 10 / portTICK_RATE_MS )
\r
48 #define fecMAX_POLLS ( 20 )
\r
50 /* Constants used to delay while waiting for a tx descriptor to be free. */
\r
51 #define fecMAX_WAIT_FOR_TX_BUFFER ( 200 / portTICK_RATE_MS )
\r
53 /* We only use a single Tx descriptor which can lead to Txed packets being sent
\r
54 twice (due to a bug in the FEC silicon). However, in this case the bug is used
\r
55 to our advantage in that it means the uip-split mechanism is not required. */
\r
56 #define fecNUM_FEC_TX_BUFFERS ( 1 )
\r
57 #define fecTX_BUFFER_TO_USE ( 0 )
\r
58 /*-----------------------------------------------------------*/
\r
60 /* The semaphore used to wake the uIP task when data arrives. */
\r
61 xSemaphoreHandle xFECSemaphore = NULL, xTxSemaphore = NULL;
\r
63 /* The buffer used by the uIP stack. In this case the pointer is used to
\r
64 point to one of the Rx buffers to effect a zero copy policy. */
\r
65 unsigned char *uip_buf;
\r
67 /* The DMA descriptors. This is a char array to allow us to align it correctly. */
\r
68 static unsigned char xFECTxDescriptors_unaligned[ ( fecNUM_FEC_TX_BUFFERS * sizeof( FECBD ) ) + 16 ];
\r
69 static unsigned char xFECRxDescriptors_unaligned[ ( configNUM_FEC_RX_BUFFERS * sizeof( FECBD ) ) + 16 ];
\r
70 static FECBD *xFECTxDescriptors;
\r
71 static FECBD *xFECRxDescriptors;
\r
73 /* The DMA buffers. These are char arrays to allow them to be aligned correctly. */
\r
74 static unsigned char ucFECRxBuffers[ ( configNUM_FEC_RX_BUFFERS * configFEC_BUFFER_SIZE ) + 16 ];
\r
75 static unsigned portBASE_TYPE uxNextRxBuffer = 0, uxIndexToBufferOwner = 0;
\r
77 /*-----------------------------------------------------------*/
\r
80 * Enable all the required interrupts in the FEC and in the interrupt controller.
\r
82 static void prvEnableFECInterrupts( void );
\r
85 * Reset the FEC if we get into an unrecoverable state.
\r
87 static void prvResetFEC( portBASE_TYPE xCalledFromISR );
\r
89 /********************************************************************/
\r
92 * FUNCTION ADAPTED FROM FREESCALE SUPPLIED SOURCE
\r
94 * Write a value to a PHY's MII register.
\r
98 * phy_addr Address of the PHY.
\r
99 * reg_addr Address of the register in the PHY.
\r
100 * data Data to be written to the PHY register.
\r
106 * Please refer to your PHY manual for registers and their meanings.
\r
107 * mii_write() polls for the FEC's MII interrupt event and clears it.
\r
108 * If after a suitable amount of time the event isn't triggered, a
\r
109 * value of 0 is returned.
\r
111 static int fec_mii_write( int phy_addr, int reg_addr, int data )
\r
113 int timeout, iReturn;
\r
116 /* Clear the MII interrupt bit */
\r
117 MCF_FEC_EIR = MCF_FEC_EIR_MII;
\r
119 /* Mask the MII interrupt */
\r
120 eimr = MCF_FEC_EIMR;
\r
121 MCF_FEC_EIMR &= ~MCF_FEC_EIMR_MII;
\r
123 /* Write to the MII Management Frame Register to kick-off the MII write */
\r
124 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
126 /* Poll for the MII interrupt (interrupt should be masked) */
\r
127 for( timeout = 0; timeout < fecMAX_POLLS; timeout++ )
\r
129 if( MCF_FEC_EIR & MCF_FEC_EIR_MII )
\r
135 vTaskDelay( fecMII_DELAY );
\r
139 if( timeout == fecMAX_POLLS )
\r
148 /* Clear the MII interrupt bit */
\r
149 MCF_FEC_EIR = MCF_FEC_EIR_MII;
\r
151 /* Restore the EIMR */
\r
152 MCF_FEC_EIMR = eimr;
\r
157 /********************************************************************/
\r
159 * FUNCTION ADAPTED FROM FREESCALE SUPPLIED SOURCE
\r
161 * Read a value from a PHY's MII register.
\r
165 * phy_addr Address of the PHY.
\r
166 * reg_addr Address of the register in the PHY.
\r
167 * data Pointer to storage for the Data to be read
\r
168 * from the PHY register (passed by reference)
\r
174 * Please refer to your PHY manual for registers and their meanings.
\r
175 * mii_read() polls for the FEC's MII interrupt event and clears it.
\r
176 * If after a suitable amount of time the event isn't triggered, a
\r
177 * value of 0 is returned.
\r
179 static int fec_mii_read( int phy_addr, int reg_addr, unsigned short* data )
\r
181 int timeout, iReturn;
\r
184 /* Clear the MII interrupt bit */
\r
185 MCF_FEC_EIR = MCF_FEC_EIR_MII;
\r
187 /* Mask the MII interrupt */
\r
188 eimr = MCF_FEC_EIMR;
\r
189 MCF_FEC_EIMR &= ~MCF_FEC_EIMR_MII;
\r
191 /* Write to the MII Management Frame Register to kick-off the MII read */
\r
192 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
194 /* Poll for the MII interrupt (interrupt should be masked) */
\r
195 for( timeout = 0; timeout < fecMAX_POLLS; timeout++ )
\r
197 if (MCF_FEC_EIR & MCF_FEC_EIR_MII)
\r
203 vTaskDelay( fecMII_DELAY );
\r
207 if( timeout == fecMAX_POLLS )
\r
213 *data = (uint16)(MCF_FEC_MMFR & 0x0000FFFF);
\r
217 /* Clear the MII interrupt bit */
\r
218 MCF_FEC_EIR = MCF_FEC_EIR_MII;
\r
220 /* Restore the EIMR */
\r
221 MCF_FEC_EIMR = eimr;
\r
227 /********************************************************************/
\r
229 * FUNCTION ADAPTED FROM FREESCALE SUPPLIED SOURCE
\r
231 * Generate the hash table settings for the given address
\r
234 * addr 48-bit (6 byte) Address to generate the hash for
\r
237 * The 6 most significant bits of the 32-bit CRC result
\r
239 static unsigned char fec_hash_address( const unsigned char* addr )
\r
242 unsigned char byte;
\r
251 if((byte & 0x01)^(crc & 0x01))
\r
254 crc = crc ^ 0xEDB88320;
\r
265 return (unsigned char)(crc >> 26);
\r
268 /********************************************************************/
\r
270 * FUNCTION ADAPTED FROM FREESCALE SUPPLIED SOURCE
\r
272 * Set the Physical (Hardware) Address and the Individual Address
\r
273 * Hash in the selected FEC
\r
277 * pa Physical (Hardware) Address for the selected FEC
\r
279 static void fec_set_address( const unsigned char *pa )
\r
284 * Set the Physical Address
\r
286 /* Set the source address for the controller */
\r
287 MCF_FEC_PALR = ( pa[ 0 ] << 24 ) | ( pa[ 1 ] << 16 ) | ( pa[ 2 ] << 8 ) | ( pa[ 3 ] << 0 );
\r
288 MCF_FEC_PAUR = ( pa[ 4 ] << 24 ) | ( pa[ 5 ] << 16 );
\r
291 * Calculate and set the hash for given Physical Address
\r
292 * in the Individual Address Hash registers
\r
294 crc = fec_hash_address( pa );
\r
297 MCF_FEC_IAUR |= (unsigned long)(1 << (crc - 32));
\r
301 MCF_FEC_IALR |= (unsigned long)(1 << crc);
\r
304 /*-----------------------------------------------------------*/
\r
306 static void prvInitialiseFECBuffers( void )
\r
308 unsigned portBASE_TYPE ux;
\r
309 unsigned char *pcBufPointer;
\r
311 /* Correctly align the Tx descriptor pointer. */
\r
312 pcBufPointer = &( xFECTxDescriptors_unaligned[ 0 ] );
\r
313 while( ( ( unsigned long ) pcBufPointer & 0x0fUL ) != 0 )
\r
318 xFECTxDescriptors = ( FECBD * ) pcBufPointer;
\r
320 /* Likewise the Rx descriptor pointer. */
\r
321 pcBufPointer = &( xFECRxDescriptors_unaligned[ 0 ] );
\r
322 while( ( ( unsigned long ) pcBufPointer & 0x0fUL ) != 0 )
\r
327 xFECRxDescriptors = ( FECBD * ) pcBufPointer;
\r
330 /* Setup the Tx buffers and descriptors. There is no separate Tx buffer
\r
331 to point to (the Rx buffers are actually used) so the data member is
\r
332 set to NULL for now. */
\r
333 for( ux = 0; ux < fecNUM_FEC_TX_BUFFERS; ux++ )
\r
335 xFECTxDescriptors[ ux ].status = TX_BD_TC;
\r
336 xFECTxDescriptors[ ux ].data = NULL;
\r
337 xFECTxDescriptors[ ux ].length = 0;
\r
340 /* Setup the Rx buffers and descriptors, having first ensured correct
\r
342 pcBufPointer = &( ucFECRxBuffers[ 0 ] );
\r
343 while( ( ( unsigned long ) pcBufPointer & 0x0fUL ) != 0 )
\r
348 for( ux = 0; ux < configNUM_FEC_RX_BUFFERS; ux++ )
\r
350 xFECRxDescriptors[ ux ].status = RX_BD_E;
\r
351 xFECRxDescriptors[ ux ].length = configFEC_BUFFER_SIZE;
\r
352 xFECRxDescriptors[ ux ].data = pcBufPointer;
\r
353 pcBufPointer += configFEC_BUFFER_SIZE;
\r
356 /* Set the wrap bit in the last descriptors to form a ring. */
\r
357 xFECTxDescriptors[ fecNUM_FEC_TX_BUFFERS - 1 ].status |= TX_BD_W;
\r
358 xFECRxDescriptors[ configNUM_FEC_RX_BUFFERS - 1 ].status |= RX_BD_W;
\r
360 uxNextRxBuffer = 0;
\r
362 /*-----------------------------------------------------------*/
\r
364 void vFECInit( void )
\r
366 unsigned short usData;
\r
367 struct uip_eth_addr xAddr;
\r
368 unsigned portBASE_TYPE ux;
\r
370 /* The MAC address is set at the foot of FreeRTOSConfig.h. */
\r
371 const unsigned char ucMACAddress[6] =
\r
373 configMAC_0, configMAC_1,configMAC_2, configMAC_3, configMAC_4, configMAC_5
\r
376 /* Create the semaphore used by the ISR to wake the uIP task. */
\r
377 vSemaphoreCreateBinary( xFECSemaphore );
\r
379 /* Create the semaphore used to unblock any tasks that might be waiting
\r
380 for a Tx descriptor. */
\r
381 vSemaphoreCreateBinary( xTxSemaphore );
\r
383 /* Initialise all the buffers and descriptors used by the DMA. */
\r
384 prvInitialiseFECBuffers();
\r
386 for( usData = 0; usData < 6; usData++ )
\r
388 xAddr.addr[ usData ] = ucMACAddress[ usData ];
\r
390 uip_setethaddr( xAddr );
\r
392 /* Set the Reset bit and clear the Enable bit */
\r
393 MCF_FEC_ECR = MCF_FEC_ECR_RESET;
\r
395 /* Wait at least 8 clock cycles */
\r
396 for( usData = 0; usData < 10; usData++ )
\r
401 /* Set MII speed to 2.5MHz. */
\r
402 MCF_FEC_MSCR = MCF_FEC_MSCR_MII_SPEED( ( ( ( configCPU_CLOCK_HZ / 1000000 ) / 5 ) + 1 ) );
\r
404 /* Initialize PLDPAR to enable Ethernet LEDs. */
\r
405 MCF_GPIO_PLDPAR = MCF_GPIO_PLDPAR_ACTLED_ACTLED | MCF_GPIO_PLDPAR_LINKLED_LINKLED | MCF_GPIO_PLDPAR_SPDLED_SPDLED
\r
406 | MCF_GPIO_PLDPAR_DUPLED_DUPLED | MCF_GPIO_PLDPAR_COLLED_COLLED | MCF_GPIO_PLDPAR_RXLED_RXLED
\r
407 | MCF_GPIO_PLDPAR_TXLED_TXLED;
\r
409 /* Initialize Port TA to enable Axcel control. */
\r
410 MCF_GPIO_PTAPAR = 0x00;
\r
411 MCF_GPIO_DDRTA = 0x0F;
\r
412 MCF_GPIO_PORTTA = 0x04;
\r
414 /* Set phy address to zero. */
\r
415 MCF_EPHY_EPHYCTL1 = MCF_EPHY_EPHYCTL1_PHYADD( 0 );
\r
417 /* Enable EPHY module with PHY clocks disabled. Do not turn on PHY clocks
\r
418 until both FEC and EPHY are completely setup (see Below). */
\r
419 MCF_EPHY_EPHYCTL0 = (uint8)(MCF_EPHY_EPHYCTL0_DIS100 | MCF_EPHY_EPHYCTL0_DIS10);
\r
421 /* Enable auto_neg at start-up */
\r
422 MCF_EPHY_EPHYCTL0 = (uint8)(MCF_EPHY_EPHYCTL0 & (MCF_EPHY_EPHYCTL0_ANDIS));
\r
424 /* Enable EPHY module. */
\r
425 MCF_EPHY_EPHYCTL0 = (uint8)(MCF_EPHY_EPHYCTL0_EPHYEN | MCF_EPHY_EPHYCTL0);
\r
427 /* Let PHY PLLs be determined by PHY. */
\r
428 MCF_EPHY_EPHYCTL0 = (uint8)(MCF_EPHY_EPHYCTL0 & ~(MCF_EPHY_EPHYCTL0_DIS100 | MCF_EPHY_EPHYCTL0_DIS10));
\r
431 vTaskDelay( fecLINK_DELAY );
\r
433 /* Can we talk to the PHY? */
\r
436 vTaskDelay( fecLINK_DELAY );
\r
438 fec_mii_read( configPHY_ADDRESS, PHY_PHYIDR1, &usData );
\r
440 } while( usData == 0xffff );
\r
444 /* Start auto negotiate. */
\r
445 fec_mii_write( configPHY_ADDRESS, PHY_BMCR, ( PHY_BMCR_AN_RESTART | PHY_BMCR_AN_ENABLE ) );
\r
447 /* Wait for auto negotiate to complete. */
\r
453 /* Hardware bug workaround! Force 100Mbps half duplex. */
\r
454 while( !fec_mii_read( configPHY_ADDRESS, 0, &usData ) ){};
\r
455 usData &= ~0x2000; /* 10Mbps */
\r
456 usData &= ~0x0100; /* Half Duplex */
\r
457 usData &= ~0x1000; /* Manual Mode */
\r
458 while( !fec_mii_write( configPHY_ADDRESS, 0, usData ) ){};
\r
459 while( !fec_mii_write( configPHY_ADDRESS, 0, (usData|0x0200) )){}; /* Force re-negotiate */
\r
462 vTaskDelay( fecLINK_DELAY );
\r
463 fec_mii_read( configPHY_ADDRESS, PHY_BMSR, &usData );
\r
465 } while( !( usData & PHY_BMSR_AN_COMPLETE ) );
\r
467 } while( 0 ); //while( !( usData & PHY_BMSR_LINK ) );
\r
469 /* When we get here we have a link - find out what has been negotiated. */
\r
470 fec_mii_read( configPHY_ADDRESS, PHY_ANLPAR, &usData );
\r
472 if( ( usData & PHY_ANLPAR_100BTX_FDX ) || ( usData & PHY_ANLPAR_100BTX ) )
\r
474 /* Speed is 100. */
\r
481 if( ( usData & PHY_ANLPAR_100BTX_FDX ) || ( usData & PHY_ANLPAR_10BTX_FDX ) )
\r
483 MCF_FEC_RCR &= (unsigned long)~MCF_FEC_RCR_DRT;
\r
484 MCF_FEC_TCR |= MCF_FEC_TCR_FDEN;
\r
488 MCF_FEC_RCR |= MCF_FEC_RCR_DRT;
\r
489 MCF_FEC_TCR &= (unsigned long)~MCF_FEC_TCR_FDEN;
\r
492 /* Clear the Individual and Group Address Hash registers */
\r
498 /* Set the Physical Address for the selected FEC */
\r
499 fec_set_address( ucMACAddress );
\r
501 /* Set Rx Buffer Size */
\r
502 MCF_FEC_EMRBR = (unsigned short)configFEC_BUFFER_SIZE;
\r
504 /* Point to the start of the circular Rx buffer descriptor queue */
\r
505 MCF_FEC_ERDSR = ( volatile unsigned long ) &( xFECRxDescriptors[ 0 ] );
\r
507 /* Point to the start of the circular Tx buffer descriptor queue */
\r
508 MCF_FEC_ETSDR = ( volatile unsigned long ) &( xFECTxDescriptors[ 0 ] );
\r
510 /* Mask all FEC interrupts */
\r
511 MCF_FEC_EIMR = ( unsigned long ) -1;
\r
513 /* Clear all FEC interrupt events */
\r
514 MCF_FEC_EIR = ( unsigned long ) -1;
\r
516 /* Initialize the Receive Control Register */
\r
517 MCF_FEC_RCR = MCF_FEC_RCR_MAX_FL(ETH_MAX_FRM) | MCF_FEC_RCR_FCE;
\r
519 MCF_FEC_RCR |= MCF_FEC_RCR_MII_MODE;
\r
521 #if( configUSE_PROMISCUOUS_MODE == 1 )
\r
523 MCF_FEC_RCR |= MCF_FEC_RCR_PROM;
\r
527 prvEnableFECInterrupts();
\r
529 /* Finally... enable. */
\r
530 MCF_FEC_ECR = MCF_FEC_ECR_ETHER_EN;
\r
531 MCF_FEC_RDAR = MCF_FEC_RDAR_R_DES_ACTIVE;
\r
533 /*-----------------------------------------------------------*/
\r
535 static void prvEnableFECInterrupts( void )
\r
537 const unsigned portBASE_TYPE uxFirstFECVector = 23, uxLastFECVector = 35;
\r
538 unsigned portBASE_TYPE ux;
\r
540 #if configFEC_INTERRUPT_PRIORITY > configMAX_SYSCALL_INTERRUPT_PRIORITY
\r
541 #error configFEC_INTERRUPT_PRIORITY must be less than or equal to configMAX_SYSCALL_INTERRUPT_PRIORITY
\r
544 /* Set the priority of each of the FEC interrupts. */
\r
545 for( ux = uxFirstFECVector; ux <= uxLastFECVector; ux++ )
\r
547 MCF_INTC0_ICR( ux ) = MCF_INTC_ICR_IL( configFEC_INTERRUPT_PRIORITY );
\r
550 /* Enable the FEC interrupts in the mask register */
\r
551 MCF_INTC0_IMRH &= ~( MCF_INTC_IMRH_INT_MASK33 | MCF_INTC_IMRH_INT_MASK34 | MCF_INTC_IMRH_INT_MASK35 );
\r
552 MCF_INTC0_IMRL &= ~( MCF_INTC_IMRL_INT_MASK25 | MCF_INTC_IMRL_INT_MASK26 | MCF_INTC_IMRL_INT_MASK27
\r
553 | MCF_INTC_IMRL_INT_MASK28 | MCF_INTC_IMRL_INT_MASK29 | MCF_INTC_IMRL_INT_MASK30
\r
554 | MCF_INTC_IMRL_INT_MASK31 | MCF_INTC_IMRL_INT_MASK23 | MCF_INTC_IMRL_INT_MASK24
\r
555 | MCF_INTC_IMRL_MASKALL );
\r
557 /* Clear any pending FEC interrupt events */
\r
558 MCF_FEC_EIR = MCF_FEC_EIR_CLEAR_ALL;
\r
560 /* Unmask all FEC interrupts */
\r
561 MCF_FEC_EIMR = MCF_FEC_EIMR_UNMASK_ALL;
\r
563 /*-----------------------------------------------------------*/
\r
565 static void prvResetFEC( portBASE_TYPE xCalledFromISR )
\r
569 /* A critical section is used unless this function is being called from
\r
571 if( xCalledFromISR == pdFALSE )
\r
573 taskENTER_CRITICAL();
\r
577 /* Reset all buffers and descriptors. */
\r
578 prvInitialiseFECBuffers();
\r
580 /* Set the Reset bit and clear the Enable bit */
\r
581 MCF_FEC_ECR = MCF_FEC_ECR_RESET;
\r
583 /* Wait at least 8 clock cycles */
\r
584 for( x = 0; x < 10; x++ )
\r
590 MCF_FEC_ECR = MCF_FEC_ECR_ETHER_EN;
\r
591 MCF_FEC_RDAR = MCF_FEC_RDAR_R_DES_ACTIVE;
\r
594 if( xCalledFromISR == pdFALSE )
\r
596 taskEXIT_CRITICAL();
\r
599 /*-----------------------------------------------------------*/
\r
601 unsigned short usFECGetRxedData( void )
\r
603 unsigned short usLen;
\r
605 /* Obtain the size of the packet and put it into the "len" variable. */
\r
606 usLen = xFECRxDescriptors[ uxNextRxBuffer ].length;
\r
608 if( ( usLen != 0 ) && ( ( xFECRxDescriptors[ uxNextRxBuffer ].status & RX_BD_E ) == 0 ) )
\r
610 uip_buf = xFECRxDescriptors[ uxNextRxBuffer ].data;
\r
619 /*-----------------------------------------------------------*/
\r
621 void vFECRxProcessingCompleted( void )
\r
623 /* Free the descriptor as the buffer it points to is no longer in use. */
\r
624 xFECRxDescriptors[ uxNextRxBuffer ].status |= RX_BD_E;
\r
625 MCF_FEC_RDAR = MCF_FEC_RDAR_R_DES_ACTIVE;
\r
627 if( uxNextRxBuffer >= configNUM_FEC_RX_BUFFERS )
\r
629 uxNextRxBuffer = 0;
\r
632 /*-----------------------------------------------------------*/
\r
634 void vFECSendData( void )
\r
636 /* Ensure no Tx frames are outstanding. */
\r
637 if( xSemaphoreTake( xTxSemaphore, fecMAX_WAIT_FOR_TX_BUFFER ) == pdPASS )
\r
639 /* Get a DMA buffer into which we can write the data to send. */
\r
640 if( xFECTxDescriptors[ fecTX_BUFFER_TO_USE ].status & TX_BD_R )
\r
642 /*** ERROR didn't expect this. Sledge hammer error handling. ***/
\r
643 prvResetFEC( pdFALSE );
\r
645 /* Make sure we leave the semaphore in the expected state as nothing
\r
646 is being transmitted this will not happen in the Tx ISR. */
\r
647 xSemaphoreGive( xTxSemaphore );
\r
651 /* Setup the buffer descriptor for transmission. The data being
\r
652 sent is actually stored in one of the Rx descriptor buffers,
\r
653 pointed to by uip_buf. */
\r
654 xFECTxDescriptors[ fecTX_BUFFER_TO_USE ].length = uip_len;
\r
655 xFECTxDescriptors[ fecTX_BUFFER_TO_USE ].status |= ( TX_BD_R | TX_BD_L );
\r
656 xFECTxDescriptors[ fecTX_BUFFER_TO_USE ].data = uip_buf;
\r
658 /* Remember which Rx descriptor owns the buffer we are sending. */
\r
659 uxIndexToBufferOwner = uxNextRxBuffer;
\r
661 /* We have finished with this Rx descriptor now. */
\r
663 if( uxNextRxBuffer >= configNUM_FEC_RX_BUFFERS )
\r
665 uxNextRxBuffer = 0;
\r
668 /* Continue the Tx DMA (in case it was waiting for a new TxBD) */
\r
669 MCF_FEC_TDAR = MCF_FEC_TDAR_X_DES_ACTIVE;
\r
674 /* Gave up waiting. Free the buffer back to the DMA. */
\r
675 vFECRxProcessingCompleted();
\r
678 /*-----------------------------------------------------------*/
\r
680 void vFEC_ISR( void )
\r
682 unsigned long ulEvent;
\r
683 portBASE_TYPE xHighPriorityTaskWoken = pdFALSE;
\r
685 /* This handler is called in response to any of the many separate FEC
\r
688 /* Find the cause of the interrupt, then clear the interrupt. */
\r
689 ulEvent = MCF_FEC_EIR & MCF_FEC_EIMR;
\r
690 MCF_FEC_EIR = ulEvent;
\r
692 if( ( ulEvent & MCF_FEC_EIR_RXB ) || ( ulEvent & MCF_FEC_EIR_RXF ) )
\r
694 /* A packet has been received. Wake the handler task. */
\r
695 xSemaphoreGiveFromISR( xFECSemaphore, &xHighPriorityTaskWoken );
\r
698 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
700 /* Sledge hammer error handling. */
\r
701 prvResetFEC( pdTRUE );
\r
704 if( ( ulEvent & MCF_FEC_EIR_TXF ) || ( ulEvent & MCF_FEC_EIR_TXB ) )
\r
706 /* The buffer being sent is pointed to by an Rx descriptor, now the
\r
707 buffer has been sent we can mark the Rx descriptor as free again. */
\r
708 xFECRxDescriptors[ uxIndexToBufferOwner ].status |= RX_BD_E;
\r
709 MCF_FEC_RDAR = MCF_FEC_RDAR_R_DES_ACTIVE;
\r
710 xSemaphoreGiveFromISR( xTxSemaphore, &xHighPriorityTaskWoken );
\r
713 portEND_SWITCHING_ISR( xHighPriorityTaskWoken );
\r
715 /*-----------------------------------------------------------*/
\r
717 /* Install the many different interrupt vectors, all of which call the same
\r
718 handler function. */
\r
719 void __attribute__ ((interrupt)) __cs3_isr_interrupt_87( void ) { vFEC_ISR(); }
\r
720 void __attribute__ ((interrupt)) __cs3_isr_interrupt_88( void ) { vFEC_ISR(); }
\r
721 void __attribute__ ((interrupt)) __cs3_isr_interrupt_89( void ) { vFEC_ISR(); }
\r
722 void __attribute__ ((interrupt)) __cs3_isr_interrupt_90( void ) { vFEC_ISR(); }
\r
723 void __attribute__ ((interrupt)) __cs3_isr_interrupt_91( void ) { vFEC_ISR(); }
\r
724 void __attribute__ ((interrupt)) __cs3_isr_interrupt_92( void ) { vFEC_ISR(); }
\r
725 void __attribute__ ((interrupt)) __cs3_isr_interrupt_93( void ) { vFEC_ISR(); }
\r
726 void __attribute__ ((interrupt)) __cs3_isr_interrupt_94( void ) { vFEC_ISR(); }
\r
727 void __attribute__ ((interrupt)) __cs3_isr_interrupt_95( void ) { vFEC_ISR(); }
\r
728 void __attribute__ ((interrupt)) __cs3_isr_interrupt_96( void ) { vFEC_ISR(); }
\r
729 void __attribute__ ((interrupt)) __cs3_isr_interrupt_97( void ) { vFEC_ISR(); }
\r
730 void __attribute__ ((interrupt)) __cs3_isr_interrupt_98( void ) { vFEC_ISR(); }
\r
731 void __attribute__ ((interrupt)) __cs3_isr_interrupt_99( void ) { vFEC_ISR(); }
\r