3 Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
5 Permission is hereby granted, free of charge, to any person obtaining a copy of
6 this software and associated documentation files (the "Software"), to deal in
7 the Software without restriction, including without limitation the rights to
8 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 the Software, and to permit persons to whom the Software is furnished to do so,
10 subject to the following conditions:
12 The above copyright notice and this permission notice shall be included in all
13 copies or substantial portions of the Software.
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 http://aws.amazon.com/freertos
23 http://www.FreeRTOS.org
26 /******************************************************************************
28 * See the following web page for essential buffer allocation scheme usage and
29 * configuration details:
30 * http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Ethernet_Buffer_Management.html
32 ******************************************************************************/
34 /* Standard includes. */
37 /* FreeRTOS includes. */
43 /* FreeRTOS+TCP includes. */
44 #include "FreeRTOS_IP.h"
45 #include "FreeRTOS_IP_Private.h"
46 #include "NetworkInterface.h"
47 #include "NetworkBufferManagement.h"
49 /* For an Ethernet interrupt to be able to obtain a network buffer there must
50 be at least this number of buffers available. */
51 #define baINTERRUPT_BUFFER_GET_THRESHOLD ( 3 )
53 /* A list of free (available) NetworkBufferDescriptor_t structures. */
54 static List_t xFreeBuffersList;
56 /* Some statistics about the use of buffers. */
57 static UBaseType_t uxMinimumFreeNetworkBuffers = 0u;
59 /* Declares the pool of NetworkBufferDescriptor_t structures that are available
60 to the system. All the network buffers referenced from xFreeBuffersList exist
61 in this array. The array is not accessed directly except during initialisation,
62 when the xFreeBuffersList is filled (as all the buffers are free when the system
64 static NetworkBufferDescriptor_t xNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ];
66 /* This constant is defined as true to let FreeRTOS_TCP_IP.c know that the
67 network buffers have constant size, large enough to hold the biggest Ethernet
68 packet. No resizing will be done. */
69 const BaseType_t xBufferAllocFixedSize = pdTRUE;
71 /* The semaphore used to obtain network buffers. */
72 static SemaphoreHandle_t xNetworkBufferSemaphore = NULL;
74 #if( ipconfigTCP_IP_SANITY != 0 )
75 static char cIsLow = pdFALSE;
76 UBaseType_t bIsValidNetworkDescriptor( const NetworkBufferDescriptor_t * pxDesc );
78 static UBaseType_t bIsValidNetworkDescriptor( const NetworkBufferDescriptor_t * pxDesc );
79 #endif /* ipconfigTCP_IP_SANITY */
81 static void prvShowWarnings( void );
83 /* The user can define their own ipconfigBUFFER_ALLOC_LOCK() and
84 ipconfigBUFFER_ALLOC_UNLOCK() macros, especially for use form an ISR. If these
85 are not defined then default them to call the normal enter/exit critical
87 #if !defined( ipconfigBUFFER_ALLOC_LOCK )
89 #define ipconfigBUFFER_ALLOC_INIT( ) do {} while (0)
90 #define ipconfigBUFFER_ALLOC_LOCK_FROM_ISR() \
91 UBaseType_t uxSavedInterruptStatus = ( UBaseType_t ) portSET_INTERRUPT_MASK_FROM_ISR(); \
94 #define ipconfigBUFFER_ALLOC_UNLOCK_FROM_ISR() \
95 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); \
98 #define ipconfigBUFFER_ALLOC_LOCK() taskENTER_CRITICAL()
99 #define ipconfigBUFFER_ALLOC_UNLOCK() taskEXIT_CRITICAL()
101 #endif /* ipconfigBUFFER_ALLOC_LOCK */
103 /*-----------------------------------------------------------*/
105 #if( ipconfigTCP_IP_SANITY != 0 )
107 /* HT: SANITY code will be removed as soon as the library is stable
108 * and and ready to become public
109 * Function below gives information about the use of buffers */
110 #define WARN_LOW ( 2 )
111 #define WARN_HIGH ( ( 5 * ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ) / 10 )
113 #endif /* ipconfigTCP_IP_SANITY */
115 /*-----------------------------------------------------------*/
117 #if( ipconfigTCP_IP_SANITY != 0 )
119 BaseType_t prvIsFreeBuffer( const NetworkBufferDescriptor_t *pxDescr )
121 return ( bIsValidNetworkDescriptor( pxDescr ) != 0 ) &&
122 ( listIS_CONTAINED_WITHIN( &xFreeBuffersList, &( pxDescr->xBufferListItem ) ) != 0 );
124 /*-----------------------------------------------------------*/
126 static void prvShowWarnings( void )
128 UBaseType_t uxCount = uxGetNumberOfFreeNetworkBuffers( );
129 if( ( ( cIsLow == 0 ) && ( uxCount <= WARN_LOW ) ) || ( ( cIsLow != 0 ) && ( uxCount >= WARN_HIGH ) ) )
132 FreeRTOS_debug_printf( ( "*** Warning *** %s %lu buffers left\n", cIsLow ? "only" : "now", uxCount ) );
135 /*-----------------------------------------------------------*/
137 UBaseType_t bIsValidNetworkDescriptor( const NetworkBufferDescriptor_t * pxDesc )
139 uint32_t offset = ( uint32_t ) ( ((const char *)pxDesc) - ((const char *)xNetworkBuffers) );
140 if( ( offset >= sizeof( xNetworkBuffers ) ) ||
141 ( ( offset % sizeof( xNetworkBuffers[0] ) ) != 0 ) )
143 return (UBaseType_t) (pxDesc - xNetworkBuffers) + 1;
145 /*-----------------------------------------------------------*/
148 static UBaseType_t bIsValidNetworkDescriptor (const NetworkBufferDescriptor_t * pxDesc)
151 return ( UBaseType_t ) pdTRUE;
153 /*-----------------------------------------------------------*/
155 static void prvShowWarnings( void )
158 /*-----------------------------------------------------------*/
160 #endif /* ipconfigTCP_IP_SANITY */
162 BaseType_t xNetworkBuffersInitialise( void )
164 BaseType_t xReturn, x;
166 /* Only initialise the buffers and their associated kernel objects if they
167 have not been initialised before. */
168 if( xNetworkBufferSemaphore == NULL )
170 /* In case alternative locking is used, the mutexes can be initialised
172 ipconfigBUFFER_ALLOC_INIT();
174 xNetworkBufferSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS, ( UBaseType_t ) ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS );
175 configASSERT( xNetworkBufferSemaphore );
177 if( xNetworkBufferSemaphore != NULL )
179 vListInitialise( &xFreeBuffersList );
181 /* Initialise all the network buffers. The buffer storage comes
182 from the network interface, and different hardware has different
184 vNetworkInterfaceAllocateRAMToBuffers( xNetworkBuffers );
185 for( x = 0; x < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; x++ )
187 /* Initialise and set the owner of the buffer list items. */
188 vListInitialiseItem( &( xNetworkBuffers[ x ].xBufferListItem ) );
189 listSET_LIST_ITEM_OWNER( &( xNetworkBuffers[ x ].xBufferListItem ), &xNetworkBuffers[ x ] );
191 /* Currently, all buffers are available for use. */
192 vListInsert( &xFreeBuffersList, &( xNetworkBuffers[ x ].xBufferListItem ) );
195 uxMinimumFreeNetworkBuffers = ( UBaseType_t ) ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS;
199 if( xNetworkBufferSemaphore == NULL )
210 /*-----------------------------------------------------------*/
212 NetworkBufferDescriptor_t *pxGetNetworkBufferWithDescriptor( size_t xRequestedSizeBytes, TickType_t xBlockTimeTicks )
214 NetworkBufferDescriptor_t *pxReturn = NULL;
215 BaseType_t xInvalid = pdFALSE;
218 /* The current implementation only has a single size memory block, so
219 the requested size parameter is not used (yet). */
220 ( void ) xRequestedSizeBytes;
222 if( xNetworkBufferSemaphore != NULL )
224 /* If there is a semaphore available, there is a network buffer
226 if( xSemaphoreTake( xNetworkBufferSemaphore, xBlockTimeTicks ) == pdPASS )
228 /* Protect the structure as they are accessed from tasks and
230 ipconfigBUFFER_ALLOC_LOCK();
232 pxReturn = ( NetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &xFreeBuffersList );
234 if( ( bIsValidNetworkDescriptor( pxReturn ) != pdFALSE_UNSIGNED ) &&
235 listIS_CONTAINED_WITHIN( &xFreeBuffersList, &( pxReturn->xBufferListItem ) ) )
237 uxListRemove( &( pxReturn->xBufferListItem ) );
244 ipconfigBUFFER_ALLOC_UNLOCK();
246 if( xInvalid == pdTRUE )
248 /* _RB_ Can printf() be called from an interrupt? (comment
249 above says this can be called from an interrupt too) */
250 /* _HT_ The function shall not be called from an ISR. Comment
251 was indeed misleading. Hopefully clear now?
252 So the printf()is OK here. */
253 FreeRTOS_debug_printf( ( "pxGetNetworkBufferWithDescriptor: INVALID BUFFER: %p (valid %lu)\n",
254 pxReturn, bIsValidNetworkDescriptor( pxReturn ) ) );
259 /* Reading UBaseType_t, no critical section needed. */
260 uxCount = listCURRENT_LIST_LENGTH( &xFreeBuffersList );
262 /* For stats, latch the lowest number of network buffers since
264 if( uxMinimumFreeNetworkBuffers > uxCount )
266 uxMinimumFreeNetworkBuffers = uxCount;
269 pxReturn->xDataLength = xRequestedSizeBytes;
271 #if( ipconfigTCP_IP_SANITY != 0 )
275 #endif /* ipconfigTCP_IP_SANITY */
277 #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 )
279 /* make sure the buffer is not linked */
280 pxReturn->pxNextBuffer = NULL;
282 #endif /* ipconfigUSE_LINKED_RX_MESSAGES */
284 iptraceNETWORK_BUFFER_OBTAINED( pxReturn );
288 iptraceFAILED_TO_OBTAIN_NETWORK_BUFFER();
294 /*-----------------------------------------------------------*/
296 NetworkBufferDescriptor_t *pxNetworkBufferGetFromISR( size_t xRequestedSizeBytes )
298 NetworkBufferDescriptor_t *pxReturn = NULL;
300 /* The current implementation only has a single size memory block, so
301 the requested size parameter is not used (yet). */
302 ( void ) xRequestedSizeBytes;
304 /* If there is a semaphore available then there is a buffer available, but,
305 as this is called from an interrupt, only take a buffer if there are at
306 least baINTERRUPT_BUFFER_GET_THRESHOLD buffers remaining. This prevents,
307 to a certain degree at least, a rapidly executing interrupt exhausting
308 buffer and in so doing preventing tasks from continuing. */
309 if( uxQueueMessagesWaitingFromISR( ( QueueHandle_t ) xNetworkBufferSemaphore ) > ( UBaseType_t ) baINTERRUPT_BUFFER_GET_THRESHOLD )
311 if( xSemaphoreTakeFromISR( xNetworkBufferSemaphore, NULL ) == pdPASS )
313 /* Protect the structure as it is accessed from tasks and interrupts. */
314 ipconfigBUFFER_ALLOC_LOCK_FROM_ISR();
316 pxReturn = ( NetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &xFreeBuffersList );
317 uxListRemove( &( pxReturn->xBufferListItem ) );
319 ipconfigBUFFER_ALLOC_UNLOCK_FROM_ISR();
321 iptraceNETWORK_BUFFER_OBTAINED_FROM_ISR( pxReturn );
325 if( pxReturn == NULL )
327 iptraceFAILED_TO_OBTAIN_NETWORK_BUFFER_FROM_ISR();
332 /*-----------------------------------------------------------*/
334 BaseType_t vNetworkBufferReleaseFromISR( NetworkBufferDescriptor_t * const pxNetworkBuffer )
336 BaseType_t xHigherPriorityTaskWoken = pdFALSE;
338 /* Ensure the buffer is returned to the list of free buffers before the
339 counting semaphore is 'given' to say a buffer is available. */
340 ipconfigBUFFER_ALLOC_LOCK_FROM_ISR();
342 vListInsertEnd( &xFreeBuffersList, &( pxNetworkBuffer->xBufferListItem ) );
344 ipconfigBUFFER_ALLOC_UNLOCK_FROM_ISR();
346 xSemaphoreGiveFromISR( xNetworkBufferSemaphore, &xHigherPriorityTaskWoken );
347 iptraceNETWORK_BUFFER_RELEASED( pxNetworkBuffer );
349 return xHigherPriorityTaskWoken;
351 /*-----------------------------------------------------------*/
353 void vReleaseNetworkBufferAndDescriptor( NetworkBufferDescriptor_t * const pxNetworkBuffer )
355 BaseType_t xListItemAlreadyInFreeList;
357 if( bIsValidNetworkDescriptor( pxNetworkBuffer ) == pdFALSE_UNSIGNED )
359 FreeRTOS_debug_printf( ( "vReleaseNetworkBufferAndDescriptor: Invalid buffer %p\n", pxNetworkBuffer ) );
362 /* Ensure the buffer is returned to the list of free buffers before the
363 counting semaphore is 'given' to say a buffer is available. */
364 ipconfigBUFFER_ALLOC_LOCK();
367 xListItemAlreadyInFreeList = listIS_CONTAINED_WITHIN( &xFreeBuffersList, &( pxNetworkBuffer->xBufferListItem ) );
369 if( xListItemAlreadyInFreeList == pdFALSE )
371 vListInsertEnd( &xFreeBuffersList, &( pxNetworkBuffer->xBufferListItem ) );
375 ipconfigBUFFER_ALLOC_UNLOCK();
377 if( xListItemAlreadyInFreeList )
379 FreeRTOS_debug_printf( ( "vReleaseNetworkBufferAndDescriptor: %p ALREADY RELEASED (now %lu)\n",
380 pxNetworkBuffer, uxGetNumberOfFreeNetworkBuffers( ) ) );
382 if( xListItemAlreadyInFreeList == pdFALSE )
384 xSemaphoreGive( xNetworkBufferSemaphore );
387 iptraceNETWORK_BUFFER_RELEASED( pxNetworkBuffer );
389 /*-----------------------------------------------------------*/
391 UBaseType_t uxGetMinimumFreeNetworkBuffers( void )
393 return uxMinimumFreeNetworkBuffers;
395 /*-----------------------------------------------------------*/
397 UBaseType_t uxGetNumberOfFreeNetworkBuffers( void )
399 return listCURRENT_LIST_LENGTH( &xFreeBuffersList );
402 NetworkBufferDescriptor_t *pxResizeNetworkBufferWithDescriptor( NetworkBufferDescriptor_t * pxNetworkBuffer, size_t xNewSizeBytes )
404 /* In BufferAllocation_1.c all network buffer are allocated with a
405 maximum size of 'ipTOTAL_ETHERNET_FRAME_SIZE'.No need to resize the
407 ( void ) xNewSizeBytes;
408 return pxNetworkBuffer;
411 /*#endif */ /* ipconfigINCLUDE_TEST_CODE */