xref: /FreeRTOS-Plus-TCP-v4.0.0/source/portable/NetworkInterface/TM4C/NetworkInterface.c (revision ab3d0fa100993022e12ff3eed64cda5e40b4dc57)
1 /**
2  *       @file: NetworkInterface.c
3  *	   @author: jscott <jscott@hotstart.com>
4  *       @date: Feb 1, 2022
5  *  @copyright: Hotstart 2022 Hotstart Thermal Management. All Rights Reserved.
6  *
7  *      Permission is hereby granted, free of charge, to any person obtaining a copy of
8  *      this software and associated documentation files (the "Software"), to deal in
9  *      the Software without restriction, including without limitation the rights to
10  *      use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11  *      the Software, and to permit persons to whom the Software is furnished to do so,
12  *      subject to the following conditions:
13  *
14  *      The above copyright notice and this permission notice shall be included in all
15  *      copies or substantial portions of the Software.
16  *
17  *      THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  *      IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19  *      FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20  *      COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21  *      IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  *      CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  *
24  *      @brief:Network Interface driver for the Texas Instruments TM4C line of microcontrollers.
25  *
26  *      This driver was written and tested with the TM4C1294NCPDT, which includes a built-in MAC and
27  *      PHY. The expectation is that this driver should function correctly across all the MAC/PHY
28  *      integrated parts of the TM4C129X parts.
29  */
30 
31 #include <stdint.h>
32 #include <stdio.h>
33 #include <stdbool.h>
34 #include <stdlib.h>
35 
36 #include "inc/hw_ints.h"
37 #include "inc/hw_emac.h"
38 #include "inc/hw_memmap.h"
39 #include "inc/hw_nvic.h"
40 
41 #include "driverlib/flash.h"
42 #include "driverlib/interrupt.h"
43 #include "driverlib/gpio.h"
44 #include "driverlib/rom_map.h"
45 #include "driverlib/sysctl.h"
46 #include "driverlib/systick.h"
47 #include "driverlib/emac.h"
48 
49 #include "FreeRTOS.h"
50 #include "task.h"
51 #include "queue.h"
52 
53 #include "FreeRTOS_IP.h"
54 #include "FreeRTOS_Sockets.h"
55 #include "FreeRTOS_IP_Private.h"
56 #include "NetworkBufferManagement.h"
57 #include "NetworkInterface.h"
58 #include "phyHandling.h"
59 
60 #define BUFFER_SIZE                ( ipTOTAL_ETHERNET_FRAME_SIZE + ipBUFFER_PADDING )
61 #define BUFFER_SIZE_ROUNDED_UP     ( ( BUFFER_SIZE + 7 ) & ~0x7UL )
62 #define PHY_PHYS_ADDR              0
63 
64 #ifndef niEMAC_SYSCONFIG_HZ
65     #define niEMAC_SYSCONFIG_HZ    configCPU_CLOCK_HZ
66 #endif
67 
68 #ifndef niEMAC_TX_DMA_DESC_COUNT
69     #define niEMAC_TX_DMA_DESC_COUNT    8
70 #endif
71 
72 #ifndef niEMAC_RX_DMA_DESC_COUNT
73     #define niEMAC_RX_DMA_DESC_COUNT    8
74 #endif
75 
76 #if ipconfigUSE_LINKED_RX_MESSAGES
77     #error Linked RX Messages are not supported by this driver
78 #endif
79 
80 /* Default the size of the stack used by the EMAC deferred handler task to twice
81  * the size of the stack used by the idle task - but allow this to be overridden in
82  * FreeRTOSConfig.h as configMINIMAL_STACK_SIZE is a user definable constant. */
83 #ifndef configEMAC_TASK_STACK_SIZE
84     #define configEMAC_TASK_STACK_SIZE    ( 2 * configMINIMAL_STACK_SIZE )
85 #endif
86 
87 #ifndef niEMAC_HANDLER_TASK_PRIORITY
88     #define niEMAC_HANDLER_TASK_PRIORITY    configMAX_PRIORITIES - 1
89 #endif
90 
91 #if !defined( ipconfigETHERNET_AN_ENABLE )
92     /* Enable auto-negotiation */
93     #define ipconfigETHERNET_AN_ENABLE    1
94 #endif
95 
96 #if !defined( ipconfigETHERNET_USE_100MB )
97     #define ipconfigETHERNET_USE_100MB    1
98 #endif
99 
100 #if !defined( ipconfigETHERNET_USE_FULL_DUPLEX )
101     #define ipconfigETHERNET_USE_FULL_DUPLEX    1
102 #endif
103 
104 typedef struct
105 {
106     uint32_t number_descriptors;
107     uint32_t write;
108     uint32_t read;
109 } tDescriptorList;
110 
111 typedef enum
112 {
113     eMACInit,   /* Must initialise MAC. */
114     eMACPass,   /* Initialisation was successful. */
115     eMACFailed, /* Initialisation failed. */
116 } eMAC_INIT_STATUS_TYPE;
117 
118 typedef enum
119 {
120     eMACInterruptNone = 0,        /* No interrupts need servicing */
121     eMACInterruptRx = ( 1 << 0 ), /* Service RX interrupt */
122     eMACInterruptTx = ( 1 << 1 ), /* Service TX interrupt */
123 } eMAC_INTERRUPT_STATUS_TYPE;
124 
125 static eMAC_INIT_STATUS_TYPE xMacInitStatus = eMACInit;
126 
127 static volatile eMAC_INTERRUPT_STATUS_TYPE xMacInterruptStatus = eMACInterruptNone;
128 
129 static tEMACDMADescriptor _tx_descriptors[ niEMAC_TX_DMA_DESC_COUNT ];
130 static tEMACDMADescriptor _rx_descriptors[ niEMAC_RX_DMA_DESC_COUNT ];
131 
132 static tDescriptorList _tx_descriptor_list = { .number_descriptors = niEMAC_TX_DMA_DESC_COUNT, 0 };
133 static tDescriptorList _rx_descriptor_list = { .number_descriptors = niEMAC_RX_DMA_DESC_COUNT, 0 };
134 
135 static uint8_t _network_buffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ][ BUFFER_SIZE_ROUNDED_UP ];
136 #pragma DATA_ALIGN(_network_buffers, 4)
137 
138 static EthernetPhy_t xPhyObject;
139 
140 static TaskHandle_t _deferred_task_handle = NULL;
141 
142 const PhyProperties_t xPHYProperties =
143 {
144     #if ( ipconfigETHERNET_AN_ENABLE != 0 )
145         .ucSpeed      = PHY_SPEED_AUTO,
146         .ucDuplex     = PHY_DUPLEX_AUTO,
147     #else
148         #if ( ipconfigETHERNET_USE_100MB != 0 )
149             .ucSpeed  = PHY_SPEED_100,
150         #else
151             .ucSpeed  = PHY_SPEED_10,
152         #endif
153 
154         #if ( ipconfigETHERNET_USE_FULL_DUPLEX != 0 )
155             .ucDuplex = PHY_DUPLEX_FULL,
156         #else
157             .ucDuplex = PHY_DUPLEX_HALF,
158         #endif
159     #endif /* if ( ipconfigETHERNET_AN_ENABLE != 0 ) */
160 };
161 
162 /**
163  * Reads the Ethernet MAC from user Flash.
164  * @param mac_address_bytes[out] The byte array which will hold the MAC address
165  * @return pdPASS on success, pdFAIL if the MAC is invalid from user Flash
166  */
167 static BaseType_t _ethernet_mac_get( uint8_t * mac_address_bytes );
168 
169 /**
170  * Initialize DMA descriptors
171  */
172 static void _dma_descriptors_init( void );
173 
174 /**
175  * Frees previously sent network buffers
176  */
177 static void _process_transmit_complete( void );
178 
179 /**
180  * Processes received packets and forwards those acceptable to the network stack
181  */
182 static BaseType_t _process_received_packet( void );
183 
184 /**
185  * Processes PHY interrupts.
186  */
187 static void _process_phy_interrupts( void );
188 
189 /**
190  * Thread to forward received packets from the ISR to the network stack
191  * @param parameters Not used
192  */
193 static void _deferred_task( void * parameters );
194 
195 /**
196  * Phy read implementation for the TM4C
197  * @param xAddress
198  * @param xRegister
199  * @param pulValue
200  * @return
201  */
202 static BaseType_t xTM4C_PhyRead( BaseType_t xAddress,
203                                  BaseType_t xRegister,
204                                  uint32_t * pulValue );
205 
206 /**
207  * Phy write implementation for the TM4C
208  * @param xAddress
209  * @param xRegister
210  * @param ulValue
211  * @return
212  */
213 static BaseType_t xTM4C_PhyWrite( BaseType_t xAddress,
214                                   BaseType_t xRegister,
215                                   uint32_t ulValue );
216 
217 /**
218  * Probe the PHY
219  */
220 static void vMACBProbePhy( void );
221 
xNetworkInterfaceInitialise(void)222 BaseType_t xNetworkInterfaceInitialise( void )
223 {
224     uint8_t mac_address_bytes[ 6 ];
225     uint16_t ui16Val;
226     BaseType_t xResult = pdFAIL;
227 
228     if( eMACInit == xMacInitStatus )
229     {
230         /* Create the RX packet forwarding task */
231         if( pdFAIL == xTaskCreate( _deferred_task, "EMAC", configEMAC_TASK_STACK_SIZE, NULL, niEMAC_HANDLER_TASK_PRIORITY, &_deferred_task_handle ) )
232         {
233             xMacInitStatus = eMACFailed;
234         }
235         else
236         {
237             /* Read the MAC from user Flash */
238             if( pdPASS != _ethernet_mac_get( &mac_address_bytes[ 0 ] ) )
239             {
240                 xMacInitStatus = eMACFailed;
241             }
242             else
243             {
244                 MAP_SysCtlPeripheralReset( SYSCTL_PERIPH_EMAC0 );
245 
246                 while( !MAP_SysCtlPeripheralReady( SYSCTL_PERIPH_EMAC0 ) )
247                 {
248                 }
249 
250                 MAP_SysCtlPeripheralReset( SYSCTL_PERIPH_EPHY0 );
251 
252                 while( !MAP_SysCtlPeripheralReady( SYSCTL_PERIPH_EPHY0 ) )
253                 {
254                 }
255 
256                 MAP_EMACInit( EMAC0_BASE, niEMAC_SYSCONFIG_HZ,
257                               EMAC_BCONFIG_MIXED_BURST | EMAC_BCONFIG_PRIORITY_FIXED, 4,
258                               4, 0 );
259 
260                 MAP_EMACConfigSet(
261                     EMAC0_BASE,
262                     (
263                         EMAC_CONFIG_100MBPS |
264                         EMAC_CONFIG_FULL_DUPLEX |
265                         EMAC_CONFIG_CHECKSUM_OFFLOAD |
266                         EMAC_CONFIG_7BYTE_PREAMBLE |
267                         EMAC_CONFIG_IF_GAP_96BITS |
268                         EMAC_CONFIG_USE_MACADDR0 |
269                         EMAC_CONFIG_SA_FROM_DESCRIPTOR |
270                         EMAC_CONFIG_BO_LIMIT_1024 |
271                         EMAC_CONFIG_STRIP_CRC
272                     ),
273                     (
274                         EMAC_MODE_RX_STORE_FORWARD |
275                         EMAC_MODE_TX_STORE_FORWARD |
276                         EMAC_MODE_RX_THRESHOLD_64_BYTES |
277                         EMAC_MODE_TX_THRESHOLD_64_BYTES ),
278                     0 );
279 
280 
281                 /* Clear any stray MISR1 PHY interrupts that may be set. */
282                 ui16Val = MAP_EMACPHYRead( EMAC0_BASE, PHY_PHYS_ADDR, EPHY_MISR1 );
283                 /* Enable link status change interrupts */
284                 ui16Val |=
285                     ( EPHY_MISR1_LINKSTATEN |
286                       EPHY_MISR1_SPEEDEN |
287                       EPHY_MISR1_DUPLEXMEN |
288                       EPHY_MISR1_ANCEN
289                     );
290                 MAP_EMACPHYWrite( EMAC0_BASE, PHY_PHYS_ADDR, EPHY_MISR1, ui16Val );
291 
292                 /* Clear any stray MISR2 PHY interrupts that may be set. */
293                 ui16Val = MAP_EMACPHYRead( EMAC0_BASE, PHY_PHYS_ADDR, EPHY_MISR2 );
294 
295                 /* Configure and enable PHY interrupts */
296                 ui16Val = MAP_EMACPHYRead( EMAC0_BASE, PHY_PHYS_ADDR, EPHY_SCR );
297                 ui16Val |= ( EPHY_SCR_INTEN_EXT | EPHY_SCR_INTOE_EXT );
298                 MAP_EMACPHYWrite( EMAC0_BASE, PHY_PHYS_ADDR, EPHY_SCR, ui16Val );
299 
300                 /* Read the PHY interrupt status to clear any stray events. */
301                 ui16Val = MAP_EMACPHYRead( EMAC0_BASE, PHY_PHYS_ADDR, EPHY_MISR1 );
302 
303                 /* Set MAC filtering options.  We receive all broadcast and mui32ticast */
304                 /* packets along with those addressed specifically for us. */
305                 MAP_EMACFrameFilterSet( EMAC0_BASE, ( EMAC_FRMFILTER_HASH_AND_PERFECT |
306                                                       EMAC_FRMFILTER_PASS_MULTICAST ) );
307 
308                 /* Set the MAC address */
309                 MAP_EMACAddrSet( EMAC0_BASE, 0, &mac_address_bytes[ 0 ] );
310 
311                 /* Clears any previously asserted interrupts */
312                 MAP_EMACIntClear( EMAC0_BASE, EMACIntStatus( EMAC0_BASE, false ) );
313 
314                 /* Initialize the DMA descriptors */
315                 _dma_descriptors_init();
316 
317                 /* Enable TX/RX */
318                 MAP_EMACTxEnable( EMAC0_BASE );
319                 MAP_EMACRxEnable( EMAC0_BASE );
320 
321                 /* Set the interrupt to a lower priority than the OS scheduler interrupts */
322                 MAP_IntPrioritySet( INT_EMAC0, ( 6 << ( 8 - configPRIO_BITS ) ) );
323 
324                 /* Probe the PHY with the stack driver */
325                 vMACBProbePhy();
326 
327                 xMacInitStatus = eMACPass;
328             }
329         }
330     }
331 
332     if( eMACPass == xMacInitStatus )
333     {
334         /* Wait for the link status to come up before enabling interrupts */
335         if( xPhyObject.ulLinkStatusMask != 0U )
336         {
337             /* Enable the Ethernet RX and TX interrupt source. */
338             MAP_EMACIntEnable( EMAC0_BASE, ( EMAC_INT_RECEIVE | EMAC_INT_TRANSMIT |
339                                              EMAC_INT_TX_STOPPED | EMAC_INT_RX_NO_BUFFER |
340                                              EMAC_INT_RX_STOPPED | EMAC_INT_PHY ) );
341 
342             /* Enable EMAC interrupts */
343             MAP_IntEnable( INT_EMAC0 );
344 
345             xResult = pdPASS;
346         }
347     }
348 
349     return xResult;
350 }
351 
xNetworkInterfaceOutput(NetworkBufferDescriptor_t * const pxNetworkBuffer,BaseType_t xReleaseAfterSend)352 BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxNetworkBuffer,
353                                     BaseType_t xReleaseAfterSend )
354 {
355     BaseType_t success = pdTRUE;
356     tEMACDMADescriptor * dma_descriptor;
357 
358     /* As this driver is strictly zero-copy, assert that the stack does not call this function with */
359     /* xReleaseAfterSend as false */
360     configASSERT( 0 != xReleaseAfterSend );
361 
362     dma_descriptor = &_tx_descriptors[ _tx_descriptor_list.write ];
363 
364     /* If the DMA controller still owns the descriptor, all DMA descriptors are in use, bail out */
365     if( 0U == ( dma_descriptor->ui32CtrlStatus & DES0_RX_CTRL_OWN ) )
366     {
367         /* Assign the buffer to the DMA descriptor */
368         dma_descriptor->pvBuffer1 = pxNetworkBuffer->pucEthernetBuffer;
369 
370         /* Inform the DMA of the size of the packet */
371         dma_descriptor->ui32Count = ( pxNetworkBuffer->xDataLength & DES1_TX_CTRL_BUFF1_SIZE_M ) << DES1_TX_CTRL_BUFF1_SIZE_S;
372 
373         /* Inform the DMA that this is the first and last segment of the packet, calculate the checksums, the descriptors are */
374         /* chained, and to use interrupts */
375         dma_descriptor->ui32CtrlStatus = DES0_TX_CTRL_FIRST_SEG | DES0_TX_CTRL_IP_ALL_CKHSUMS | DES0_TX_CTRL_CHAINED
376                                          | DES0_TX_CTRL_LAST_SEG | DES0_TX_CTRL_INTERRUPT | DES0_TX_CTRL_REPLACE_CRC;
377 
378         /* Advance the index in the list */
379         _tx_descriptor_list.write++;
380 
381         /* Wrap around if required */
382         if( _tx_descriptor_list.write == niEMAC_TX_DMA_DESC_COUNT )
383         {
384             _tx_descriptor_list.write = 0;
385         }
386 
387         /* Give the DMA descriptor to the DMA controller */
388         dma_descriptor->ui32CtrlStatus |= DES0_TX_CTRL_OWN;
389 
390         /* Inform the DMA it has a new descriptor */
391         MAP_EMACTxDMAPollDemand( EMAC0_BASE );
392 
393         iptraceNETWORK_INTERFACE_TRANSMIT();
394     }
395     else
396     {
397         /* Release the stack descriptor and buffer to prevent memory leaks. */
398         vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
399 
400         success = pdFALSE;
401     }
402 
403     return success;
404 }
405 
vNetworkInterfaceAllocateRAMToBuffers(NetworkBufferDescriptor_t pxNetworkBuffers[ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS])406 void vNetworkInterfaceAllocateRAMToBuffers( NetworkBufferDescriptor_t pxNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ] )
407 {
408     BaseType_t i;
409 
410     for( i = 0; i < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; i++ )
411     {
412         /* Assign buffers to each descriptor */
413         pxNetworkBuffers[ i ].pucEthernetBuffer = &_network_buffers[ i ][ ipBUFFER_PADDING ];
414 
415         /* Set the 'hidden' reference to the descriptor for use in DMA interrupts */
416         *( ( uint32_t * ) &_network_buffers[ i ][ 0 ] ) = ( uint32_t ) &( ( pxNetworkBuffers[ i ] ) );
417     }
418 }
419 
_ethernet_mac_get(uint8_t * mac_address_bytes)420 static BaseType_t _ethernet_mac_get( uint8_t * mac_address_bytes )
421 {
422     BaseType_t success = pdPASS;
423     uint32_t mac_address_words[ 2 ] = { 0 };
424 
425     /* Attempt to read the MAC address */
426     MAP_FlashUserGet( &mac_address_words[ 0 ], &mac_address_words[ 1 ] );
427 
428     /* If the MAC is not set, fail */
429     if( ( 0xFFFFFFFF == mac_address_words[ 0 ] ) || ( 0xFFFFFFFF == mac_address_words[ 1 ] ) )
430     {
431         success = pdFAIL;
432     }
433     else
434     {
435         /* Otherwise return the MAC address in a usable format for the driver */
436         *( mac_address_bytes + 0 ) = ( mac_address_words[ 0 ] >> 0 ) & 0xFF;
437         *( mac_address_bytes + 1 ) = ( mac_address_words[ 0 ] >> 8 ) & 0xFF;
438         *( mac_address_bytes + 2 ) = ( mac_address_words[ 0 ] >> 16 ) & 0xFF;
439         *( mac_address_bytes + 3 ) = ( mac_address_words[ 1 ] >> 0 ) & 0xFF;
440         *( mac_address_bytes + 4 ) = ( mac_address_words[ 1 ] >> 8 ) & 0xFF;
441         *( mac_address_bytes + 5 ) = ( mac_address_words[ 1 ] >> 16 ) & 0xFF;
442     }
443 
444     return success;
445 }
446 
_dma_descriptors_init(void)447 static void _dma_descriptors_init( void )
448 {
449     uint32_t i;
450     size_t buffer_size_requested;
451     NetworkBufferDescriptor_t * stack_descriptor;
452 
453     /* Initialize the TX DMA descriptors */
454     for( i = 0; i < niEMAC_TX_DMA_DESC_COUNT; i++ )
455     {
456         /* Clear the length of the packet */
457         _tx_descriptors[ i ].ui32Count = 0;
458 
459         /* Clear the reference to the buffer */
460         _tx_descriptors[ i ].pvBuffer1 = NULL;
461 
462         /* Set the next link in the DMA descriptor chain, either the next in the chain or the first descriptor in the event */
463         /* that this is the last descriptor */
464         _tx_descriptors[ i ].DES3.pLink = (
465             ( i == ( niEMAC_TX_DMA_DESC_COUNT - 1 ) ) ?
466             &_tx_descriptors[ 0 ] : &_tx_descriptors[ i + 1 ] );
467         _tx_descriptors[ i ].ui32CtrlStatus = DES0_TX_CTRL_INTERRUPT | DES0_TX_CTRL_CHAINED
468                                               | DES0_TX_CTRL_IP_ALL_CKHSUMS;
469     }
470 
471     /* Set the TX descriptor index */
472     _tx_descriptor_list.write = 0;
473     _tx_descriptor_list.read = 0;
474 
475     for( i = 0; i < niEMAC_RX_DMA_DESC_COUNT; i++ )
476     {
477         stack_descriptor = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE, 0 );
478 
479         configASSERT( NULL != stack_descriptor );
480 
481         /* Get a buffer from the stack and assign it to the DMA Descriptor */
482         _rx_descriptors[ i ].pvBuffer1 = stack_descriptor->pucEthernetBuffer;
483 
484         /* Inform the DMA controller that the descriptors are chained and the size of the buffer */
485         _rx_descriptors[ i ].ui32Count = DES1_RX_CTRL_CHAINED | ( ( buffer_size_requested << DES1_TX_CTRL_BUFF1_SIZE_S ) & DES1_TX_CTRL_BUFF1_SIZE_M );
486 
487         /* Give the DMA descriptor to the DMA controller */
488         _rx_descriptors[ i ].ui32CtrlStatus = DES0_RX_CTRL_OWN;
489 
490         /* Set the next link the DMA descriptor chain */
491         _rx_descriptors[ i ].DES3.pLink = ( ( i == ( niEMAC_RX_DMA_DESC_COUNT - 1 ) ) ? &_rx_descriptors[ 0 ] : &_rx_descriptors[ i + 1 ] );
492     }
493 
494     /* Set the RX descriptor index */
495     _rx_descriptor_list.write = 0;
496 
497     /* Set the head of the DMA descriptor list in the EMAC peripheral */
498     MAP_EMACTxDMADescriptorListSet( EMAC0_BASE, &_tx_descriptors[ 0 ] );
499     MAP_EMACRxDMADescriptorListSet( EMAC0_BASE, &_rx_descriptors[ 0 ] );
500 }
501 
freertos_tcp_ethernet_int(void)502 void freertos_tcp_ethernet_int( void )
503 {
504     uint32_t status;
505     BaseType_t higher_priority_task_woken = pdFALSE;
506 
507     /* Read the interrupt status */
508     status = EMACIntStatus( EMAC0_BASE, true );
509 
510     /* Handle power management interrupts */
511     if( status & EMAC_INT_POWER_MGMNT )
512     {
513         MAP_EMACTxEnable( EMAC0_BASE );
514         MAP_EMACRxEnable( EMAC0_BASE );
515 
516         MAP_EMACPowerManagementStatusGet( EMAC0_BASE );
517 
518         status &= ~( EMAC_INT_POWER_MGMNT );
519     }
520 
521     if( status )
522     {
523         MAP_EMACIntClear( EMAC0_BASE, status );
524     }
525 
526     /* Handle PHY interrupts */
527     if( EMAC_INT_PHY & status )
528     {
529         _process_phy_interrupts();
530     }
531 
532     /* Handle Transmit Complete interrupts */
533     if( EMAC_INT_TRANSMIT & status )
534     {
535         xMacInterruptStatus |= eMACInterruptTx;
536     }
537 
538     /* Handle Receive interrupts */
539     if( ( EMAC_INT_RECEIVE | EMAC_INT_RX_NO_BUFFER | EMAC_INT_RX_STOPPED ) & status )
540     {
541         xMacInterruptStatus |= eMACInterruptRx;
542     }
543 
544     /* If interrupts of concern were found, wake the task if present */
545     if( ( 0 != xMacInterruptStatus ) && ( NULL != _deferred_task_handle ) )
546     {
547         vTaskNotifyGiveFromISR( _deferred_task_handle, &higher_priority_task_woken );
548 
549         portYIELD_FROM_ISR( higher_priority_task_woken );
550     }
551 }
552 
_process_transmit_complete(void)553 static void _process_transmit_complete( void )
554 {
555     uint32_t i;
556     tEMACDMADescriptor * dma_descriptor;
557     NetworkBufferDescriptor_t * stack_descriptor;
558 
559     for( i = 0; ( ( i < _tx_descriptor_list.number_descriptors ) && ( _tx_descriptor_list.read != _tx_descriptor_list.write ) ); i++ )
560     {
561         /* Get a reference to the current DMA descriptor */
562         dma_descriptor = &_tx_descriptors[ _tx_descriptor_list.read ];
563 
564         /* If the descriptor is still owned by the DMA controller, exit */
565         if( dma_descriptor->ui32CtrlStatus & DES0_TX_CTRL_OWN )
566         {
567             break;
568         }
569 
570         /* Get the 'hidden' reference to the stack descriptor from the buffer */
571         stack_descriptor = pxPacketBuffer_to_NetworkBuffer( dma_descriptor->pvBuffer1 );
572 
573         configASSERT( NULL != stack_descriptor );
574 
575         /* Release the stack descriptor */
576         vReleaseNetworkBufferAndDescriptor( stack_descriptor );
577 
578         _tx_descriptor_list.read++;
579 
580         if( _tx_descriptor_list.read == _tx_descriptor_list.number_descriptors )
581         {
582             _tx_descriptor_list.read = 0;
583         }
584     }
585 }
586 
_process_received_packet(void)587 static BaseType_t _process_received_packet( void )
588 {
589     NetworkBufferDescriptor_t * new_stack_descriptor;
590     NetworkBufferDescriptor_t * cur_stack_descriptor;
591     tEMACDMADescriptor * dma_descriptor;
592     uint32_t i;
593     IPStackEvent_t event;
594     BaseType_t result = pdTRUE;
595     const TickType_t max_block_time = pdMS_TO_MIN_TICKS( 50 );
596 
597     /* Go through the list of RX DMA descriptors */
598     for( i = 0; i < niEMAC_RX_DMA_DESC_COUNT; i++ )
599     {
600         /* Get a reference to the descriptor */
601         dma_descriptor = &_rx_descriptors[ _rx_descriptor_list.write ];
602 
603         /* Make sure the buffer is non-null */
604         configASSERT( NULL != dma_descriptor->pvBuffer1 );
605 
606         /* If the descriptor is still in use by DMA, stop processing here */
607         if( DES0_RX_CTRL_OWN == ( dma_descriptor->ui32CtrlStatus & DES0_RX_CTRL_OWN ) )
608         {
609             break;
610         }
611 
612         /* If there is NOT an error in the frame */
613         if( 0U == ( dma_descriptor->ui32CtrlStatus & DES0_RX_STAT_ERR ) )
614         {
615             /* Get a new empty descriptor */
616             new_stack_descriptor = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE, max_block_time );
617 
618             /* If a descriptor was provided, else this packet is dropped */
619             if( NULL != new_stack_descriptor )
620             {
621                 /* Get a reference to the current stack descriptor held by the DMA descriptor */
622                 cur_stack_descriptor = pxPacketBuffer_to_NetworkBuffer( dma_descriptor->pvBuffer1 );
623 
624                 /* Set the length of the buffer on the current descriptor */
625                 cur_stack_descriptor->xDataLength = ( dma_descriptor->ui32CtrlStatus & DES0_RX_STAT_FRAME_LENGTH_M ) >> DES0_RX_STAT_FRAME_LENGTH_S;
626 
627                 /* Assign the new stack descriptor to the DMA descriptor */
628                 dma_descriptor->pvBuffer1 = new_stack_descriptor->pucEthernetBuffer;
629 
630                 /* Ask the stack if it wants to process the frame. */
631                 if( eProcessBuffer == eConsiderFrameForProcessing( cur_stack_descriptor->pucEthernetBuffer ) )
632                 {
633                     /* Setup the event */
634                     event.eEventType = eNetworkRxEvent;
635                     event.pvData = cur_stack_descriptor;
636 
637                     /* Forward the event */
638                     if( pdFALSE == xSendEventStructToIPTask( &event, 0 ) )
639                     {
640                         /* Release the buffer if an error was encountered */
641                         vReleaseNetworkBufferAndDescriptor( cur_stack_descriptor );
642 
643                         iptraceETHERNET_RX_EVENT_LOST();
644                     }
645                     else
646                     {
647                         iptraceNETWORK_INTERFACE_RECEIVE();
648 
649                         result = pdTRUE;
650                     }
651                 }
652                 else
653                 {
654                     /* Free the descriptor */
655                     vReleaseNetworkBufferAndDescriptor( cur_stack_descriptor );
656                 }
657             } /* end if descriptor is available */
658             else
659             {
660                 /* No stack descriptor was available for the next RX DMA descriptor so this packet */
661                 /* is dropped */
662 
663                 /* Mark the RX event as lost */
664                 iptraceETHERNET_RX_EVENT_LOST();
665             }
666         } /* end if frame had error. In this case, give the buffer back to the DMA for the next RX */
667 
668         /* Set up the DMA descriptor for the next receive transaction */
669         dma_descriptor->ui32Count = DES1_RX_CTRL_CHAINED | ipTOTAL_ETHERNET_FRAME_SIZE;
670         dma_descriptor->ui32CtrlStatus = DES0_RX_CTRL_OWN;
671 
672         _rx_descriptor_list.write++;
673 
674         if( _rx_descriptor_list.write == _rx_descriptor_list.number_descriptors )
675         {
676             _rx_descriptor_list.write = 0;
677         }
678     }
679 
680     return result;
681 }
682 
683 /**
684  * This deferred interrupt handler process changes from the PHY auto-negotiation to configure the
685  * MAC as appropriate.
686  */
_process_phy_interrupts(void)687 static void _process_phy_interrupts( void )
688 {
689     uint16_t value;
690     uint16_t status;
691     uint32_t configuration;
692     uint32_t mode;
693     uint32_t max_frame_size;
694 
695     /* Read the PHY interrupts status */
696     value = MAP_EMACPHYRead( EMAC0_BASE, PHY_PHYS_ADDR, EPHY_MISR1 );
697     status = MAP_EMACPHYRead( EMAC0_BASE, PHY_PHYS_ADDR, EPHY_STS );
698 
699     if( value & ( EPHY_MISR1_SPEED | EPHY_MISR1_DUPLEXM | EPHY_MISR1_ANC ) )
700     {
701         /* If the speed or duplex has changed */
702 
703         MAP_EMACConfigGet( EMAC0_BASE, &configuration, &mode, &max_frame_size );
704 
705         if( status & EPHY_STS_SPEED )
706         {
707             configuration &= ~EMAC_CONFIG_100MBPS;
708         }
709         else
710         {
711             configuration |= EMAC_CONFIG_100MBPS;
712         }
713 
714         if( status & EPHY_STS_DUPLEX )
715         {
716             configuration |= EMAC_CONFIG_FULL_DUPLEX;
717         }
718         else
719         {
720             configuration &= ~EMAC_CONFIG_FULL_DUPLEX;
721         }
722 
723         MAP_EMACConfigSet( EMAC0_BASE, configuration, mode, max_frame_size );
724     }
725 }
726 
_deferred_task(void * parameters)727 static void _deferred_task( void * parameters )
728 {
729     BaseType_t had_reception;
730     IPStackEvent_t link_down_event;
731     const TickType_t max_block_time = pdMS_TO_TICKS( 100 );
732 
733     /* Ignore parameters */
734     ( void ) parameters;
735 
736     for( ; ; )
737     {
738         had_reception = pdFALSE;
739 
740         ulTaskNotifyTake( pdTRUE, max_block_time );
741 
742         if( eMACInterruptTx == ( xMacInterruptStatus & eMACInterruptTx ) )
743         {
744             xMacInterruptStatus &= ~( eMACInterruptTx );
745 
746             _process_transmit_complete();
747         }
748 
749         if( eMACInterruptRx == ( xMacInterruptStatus & eMACInterruptRx ) )
750         {
751             xMacInterruptStatus &= ~( eMACInterruptRx );
752 
753             had_reception = _process_received_packet();
754         }
755 
756         if( pdTRUE == xPhyCheckLinkStatus( &xPhyObject, had_reception ) )
757         {
758             /* The link has gone done */
759             if( 0 == xPhyObject.ulLinkStatusMask )
760             {
761                 link_down_event.eEventType = eNetworkDownEvent;
762                 link_down_event.pvData = NULL;
763 
764                 xSendEventStructToIPTask( &link_down_event, 0 );
765             }
766         }
767     }
768 }
769 
vMACBProbePhy(void)770 static void vMACBProbePhy( void )
771 {
772     vPhyInitialise( &xPhyObject, xTM4C_PhyRead, xTM4C_PhyWrite );
773     xPhyDiscover( &xPhyObject );
774     xPhyConfigure( &xPhyObject, &xPHYProperties );
775 }
776 
xTM4C_PhyRead(BaseType_t xAddress,BaseType_t xRegister,uint32_t * pulValue)777 static BaseType_t xTM4C_PhyRead( BaseType_t xAddress,
778                                  BaseType_t xRegister,
779                                  uint32_t * pulValue )
780 {
781     *pulValue = MAP_EMACPHYRead( EMAC0_BASE, ( uint8_t ) xAddress, ( uint8_t ) xRegister );
782 
783     return 0;
784 }
785 
xTM4C_PhyWrite(BaseType_t xAddress,BaseType_t xRegister,uint32_t ulValue)786 static BaseType_t xTM4C_PhyWrite( BaseType_t xAddress,
787                                   BaseType_t xRegister,
788                                   uint32_t ulValue )
789 {
790     MAP_EMACPHYWrite( EMAC0_BASE, ( uint8_t ) xAddress, ( uint8_t ) xRegister, ulValue );
791 
792     return 0;
793 }
794