1 /*
2 * FreeRTOS+TCP <DEVELOPMENT BRANCH>
3 * Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
4 *
5 * SPDX-License-Identifier: MIT
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 * http://aws.amazon.com/freertos
25 * http://www.FreeRTOS.org
26 */
27
28 /* FreeRTOS includes. */
29 #include "FreeRTOS.h"
30 #include "list.h"
31 #include "queue.h"
32 #include "semphr.h"
33 #include "task.h"
34
35 /* FreeRTOS+TCP includes. */
36 #include "FreeRTOS_IP.h"
37 #include "FreeRTOS_Sockets.h"
38 #include "FreeRTOS_IP_Private.h"
39 #include "NetworkBufferManagement.h"
40 #include "NetworkInterface.h"
41
42
43 #include "m480_eth.h"
44
45 /* If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 1, then the Ethernet
46 * driver will filter incoming packets and only pass the stack those packets it
47 * considers need processing. */
48 #if ( ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES == 0 )
49 #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eProcessBuffer
50 #else
51 #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eConsiderFrameForProcessing( ( pucEthernetBuffer ) )
52 #endif
53
54 /* Default the size of the stack used by the EMAC deferred handler task to twice
55 * the size of the stack used by the idle task - but allow this to be overridden in
56 * FreeRTOSConfig.h as configMINIMAL_STACK_SIZE is a user definable constant. */
57 #ifndef configEMAC_TASK_STACK_SIZE
58 #define configEMAC_TASK_STACK_SIZE ( 2 * configMINIMAL_STACK_SIZE )
59 #endif
60
61
62 static SemaphoreHandle_t xTXMutex = NULL;
63
64 /* The handle of the task that processes Rx packets. The handle is required so
65 * the task can be notified when new packets arrive. */
66 static TaskHandle_t xRxHanderTask = NULL;
67 static TimerHandle_t xPhyHandlerTask = NULL;
68
69 /*
70 * A task that processes received frames.
71 */
72 static void prvEMACHandlerTask( void * pvParameters );
73 static void prvPhyTmrCallback( TimerHandle_t xTimer );
74
75 /* The size of each buffer when BufferAllocation_1 is used:
76 * http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Ethernet_Buffer_Management.html */
77
78 #define niBUFFER_1_PACKET_SIZE 1536
79 #ifdef __ICCARM__
80 #pragma data_alignment=4
81 static uint8_t ucNetworkPackets[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS * niBUFFER_1_PACKET_SIZE ]
82 #else
83 static uint8_t ucNetworkPackets[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS * niBUFFER_1_PACKET_SIZE ] __attribute__( ( aligned( 4 ) ) );
84 #endif
85
xNetworkInterfaceInitialise(void)86 BaseType_t xNetworkInterfaceInitialise( void )
87 {
88 uint8_t hwaddr[ 6 ];
89 BaseType_t xReturn = pdPASS;
90
91 /* Init ETH */
92 numaker_mac_address( hwaddr );
93 FreeRTOS_UpdateMACAddress( hwaddr );
94 FreeRTOS_printf( ( "mac address %02x-%02x-%02x-%02x-%02x-%02x \r\n", hwaddr[ 0 ], hwaddr[ 1 ], hwaddr[ 2 ], hwaddr[ 3 ], hwaddr[ 4 ], hwaddr[ 5 ] ) );
95
96 /* Enable clock & set EMAC configuration */
97 /* Enable MAC and DMA transmission and reception */
98 if( numaker_eth_init( hwaddr ) < 0 )
99 {
100 xReturn = pdFAIL;
101 }
102 else
103 {
104 xReturn = pdPASS;
105
106 /* Guard against the task being created more than once and the
107 * descriptors being initialized more than once. */
108 /* Timer task to monitor PHY Link status */
109 if( xPhyHandlerTask == NULL )
110 {
111 xPhyHandlerTask = xTimerCreate( "TimerPhy", pdMS_TO_TICKS( 1000 ), pdTRUE, 0, prvPhyTmrCallback );
112 configASSERT( xPhyHandlerTask );
113 xReturn = xTimerStart( xPhyHandlerTask, 0 );
114 configASSERT( xReturn );
115 }
116
117 /* Rx task */
118 if( xRxHanderTask == NULL )
119 {
120 xReturn = xTaskCreate( prvEMACHandlerTask, "EMAC", configEMAC_TASK_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, &xRxHanderTask );
121 configASSERT( xReturn );
122 }
123
124 if( xTXMutex == NULL )
125 {
126 xTXMutex = xSemaphoreCreateMutex();
127 configASSERT( xTXMutex );
128 }
129 }
130
131 NVIC_SetPriority( EMAC_RX_IRQn, configMAC_INTERRUPT_PRIORITY );
132 NVIC_SetPriority( EMAC_TX_IRQn, configMAC_INTERRUPT_PRIORITY );
133
134 numaker_eth_enable_interrupts();
135
136 FreeRTOS_printf( ( "ETH-RX priority:%d\n", NVIC_GetPriority( EMAC_RX_IRQn ) ) );
137
138 return xReturn;
139 }
140
xNetworkInterfaceOutput(NetworkBufferDescriptor_t * const pxDescriptor,BaseType_t xReleaseAfterSend)141 BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxDescriptor,
142 BaseType_t xReleaseAfterSend )
143 {
144 uint8_t * buffer = NULL;
145
146 if( pxDescriptor->xDataLength >= PACKET_BUFFER_SIZE )
147 {
148 FreeRTOS_printf( ( "TX buffer length %d over %d\n", pxDescriptor->xDataLength, PACKET_BUFFER_SIZE ) );
149 return pdFALSE;
150 }
151
152 buffer = numaker_eth_get_tx_buf();
153
154 if( buffer == NULL )
155 {
156 NU_DEBUGF( ( "Eth TX slots are busy\n" ) );
157 return pdFALSE;
158 }
159
160 /* Get exclusive access */
161 xSemaphoreTake( xTXMutex, portMAX_DELAY );
162 NU_DEBUGF( ( "%s ... buffer=0x%x\r\n", __FUNCTION__, buffer ) );
163 /*SendData: pt = pxDescriptor->pucBuffer, length = pxDescriptor->xDataLength */
164 memcpy( buffer, pxDescriptor->pucEthernetBuffer, pxDescriptor->xDataLength );
165 numaker_eth_trigger_tx( pxDescriptor->xDataLength, NULL );
166 /* Call the standard trace macro to log the send event. */
167 iptraceNETWORK_INTERFACE_TRANSMIT();
168
169 if( xReleaseAfterSend != pdFALSE )
170 {
171 /* It is assumed SendData() copies the data out of the FreeRTOS+TCP Ethernet
172 * buffer. The Ethernet buffer is therefore no longer needed, and must be
173 * freed for re-use. */
174 vReleaseNetworkBufferAndDescriptor( pxDescriptor );
175 }
176
177 xSemaphoreGive( xTXMutex );
178
179 return pdTRUE;
180 }
181
182
vNetworkInterfaceAllocateRAMToBuffers(NetworkBufferDescriptor_t pxNetworkBuffers[ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS])183 void vNetworkInterfaceAllocateRAMToBuffers( NetworkBufferDescriptor_t pxNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ] )
184 {
185 uint8_t * ucRAMBuffer = ucNetworkPackets;
186 uint32_t ul;
187
188 for( ul = 0; ul < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; ul++ )
189 {
190 pxNetworkBuffers[ ul ].pucEthernetBuffer = ucRAMBuffer + ipBUFFER_PADDING;
191 *( ( unsigned * ) ucRAMBuffer ) = ( unsigned ) ( &( pxNetworkBuffers[ ul ] ) );
192 ucRAMBuffer += niBUFFER_1_PACKET_SIZE;
193 }
194 }
195
196
xGetPhyLinkStatus(void)197 BaseType_t xGetPhyLinkStatus( void )
198 {
199 BaseType_t xReturn;
200
201 if( numaker_eth_link_ok() )
202 {
203 xReturn = pdPASS;
204 }
205 else
206 {
207 xReturn = pdFAIL;
208 }
209
210 return xReturn;
211 }
212
prvPhyTmrCallback(TimerHandle_t xTimer)213 static void prvPhyTmrCallback( TimerHandle_t xTimer )
214 {
215 IPStackEvent_t xRxEvent;
216 static BaseType_t lastLink = pdFAIL;
217 BaseType_t currLink = xGetPhyLinkStatus();
218
219 if( currLink != lastLink )
220 {
221 FreeRTOS_printf( ( "PHY Link %s\n", ( currLink ) ? "Up" : "Down" ) );
222
223 if( !currLink )
224 {
225 xRxEvent.eEventType = eNetworkDownEvent;
226 xSendEventStructToIPTask( &xRxEvent, 0 );
227 }
228
229 lastLink = currLink;
230 }
231 }
232
233
prvEMACHandlerTask(void * pvParameters)234 static void prvEMACHandlerTask( void * pvParameters )
235 {
236 TimeOut_t xPhyTime;
237 TickType_t xPhyRemTime;
238 UBaseType_t uxLastMinBufferCount = 0;
239 UBaseType_t uxCurrentCount;
240 BaseType_t xResult = 0;
241 uint32_t ulStatus;
242 uint16_t dataLength = 0;
243 uint8_t * buffer = NULL;
244 NetworkBufferDescriptor_t * pxBufferDescriptor = NULL;
245 IPStackEvent_t xRxEvent;
246 const TickType_t xBlockTime = pdMS_TO_TICKS( 5000ul );
247
248 /* Remove compiler warnings about unused parameters. */
249 ( void ) pvParameters;
250 /* A possibility to set some additional task properties. */
251
252 for( ; ; )
253 {
254 uxCurrentCount = uxGetMinimumFreeNetworkBuffers();
255
256 if( uxLastMinBufferCount != uxCurrentCount )
257 {
258 /* The logging produced below may be helpful
259 * while tuning +TCP: see how many buffers are in use. */
260 uxLastMinBufferCount = uxCurrentCount;
261 FreeRTOS_printf( ( "Network buffers: %lu lowest %lu\n",
262 uxGetNumberOfFreeNetworkBuffers(), uxCurrentCount ) );
263 }
264
265 /* No events to process now, wait for the next. */
266 ulTaskNotifyTake( pdFALSE, portMAX_DELAY );
267
268 while( 1 )
269 {
270 /* get received frame */
271 if( numaker_eth_get_rx_buf( &dataLength, &buffer ) != 0 )
272 {
273 /* The event was lost because a network buffer was not available.
274 * Call the standard trace macro to log the occurrence. */
275 iptraceETHERNET_RX_EVENT_LOST();
276 break;
277 }
278
279 /* Allocate a network buffer descriptor that points to a buffer
280 * large enough to hold the received frame. As this is the simple
281 * rather than efficient example the received data will just be copied
282 * into this buffer. */
283
284 pxBufferDescriptor = pxGetNetworkBufferWithDescriptor( PACKET_BUFFER_SIZE, 0 );
285
286 if( pxBufferDescriptor != NULL )
287 {
288 memcpy( pxBufferDescriptor->pucEthernetBuffer, buffer, dataLength );
289 pxBufferDescriptor->xDataLength = dataLength;
290 }
291 else
292 {
293 numaker_eth_rx_next();
294 iptraceETHERNET_RX_EVENT_LOST();
295 break;
296 }
297
298 /* The event about to be sent to the TCP/IP is an Rx event. */
299 xRxEvent.eEventType = eNetworkRxEvent;
300
301 /* pvData is used to point to the network buffer descriptor that
302 * now references the received data. */
303 xRxEvent.pvData = ( void * ) pxBufferDescriptor;
304
305 /* Send the data to the TCP/IP stack. */
306 if( xSendEventStructToIPTask( &xRxEvent, 0 ) == pdFALSE )
307 {
308 /* The buffer could not be sent to the IP task so the buffer
309 * must be released. */
310 vReleaseNetworkBufferAndDescriptor( pxBufferDescriptor );
311
312 /* Make a call to the standard trace macro to log the
313 * occurrence. */
314
315 iptraceETHERNET_RX_EVENT_LOST();
316 }
317 else
318 {
319 /* The message was successfully sent to the TCP/IP stack.
320 * Call the standard trace macro to log the occurrence. */
321 iptraceNETWORK_INTERFACE_RECEIVE();
322 }
323
324 numaker_eth_rx_next();
325 }
326
327 numaker_eth_trigger_rx();
328 }
329 }
330
xNetworkCallback(char event)331 void xNetworkCallback( char event )
332 {
333 BaseType_t xHigherPriorityTaskWoken = pdFALSE;
334
335 switch( event )
336 {
337 case 'R': /*For RX event */
338
339 /* Wakeup the prvEMACHandlerTask. */
340 if( xRxHanderTask != NULL )
341 {
342 vTaskNotifyGiveFromISR( xRxHanderTask, &xHigherPriorityTaskWoken );
343 portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
344 }
345
346 break;
347
348 case 'T': /*For TX event */
349 /* ack of tx done, no-op in this stage */
350 break;
351
352 default:
353 break;
354 }
355 }
356