[PATCH 1/2] rtems: Add rtems_cache_coherent_allocate()
Daniel Hellstrom
daniel at gaisler.com
Mon Dec 1 14:33:43 UTC 2014
Hello Sebastian,
The coherent code looks nice and clean. I'm wondering, is it possbile to add a memory region to the coherent area and at the same time make malloc() return memory from that area when the default heap
connected to malloc() is empty? As I recall that is the behaviour of linux, when the standard zone is empty it allocates from the DMA able memory zone since it can do both. I would be interested in
such an approach for the LEON, where all memory can be used for the CPU but only 256MB of memory can be accessed from the PCI.
Thanks,
DanielH
On 11/25/2014 05:28 PM, Sebastian Huber wrote:
> Add rtems_cache_coherent_free() and rtems_cache_coherent_add_area().
> ---
> cpukit/libcsupport/Makefile.am | 1 +
> cpukit/libcsupport/src/cachecoherentalloc.c | 122 ++++++++++++++++++++++++++++
> cpukit/rtems/include/rtems/rtems/cache.h | 61 ++++++++++++++
> testsuites/sptests/spcache01/init.c | 47 +++++++++++
> testsuites/sptests/spcache01/spcache01.doc | 3 +
> testsuites/sptests/spcache01/spcache01.scn | 1 +
> 6 files changed, 235 insertions(+)
> create mode 100644 cpukit/libcsupport/src/cachecoherentalloc.c
>
> diff --git a/cpukit/libcsupport/Makefile.am b/cpukit/libcsupport/Makefile.am
> index 95c85c4..dfa8736 100644
> --- a/cpukit/libcsupport/Makefile.am
> +++ b/cpukit/libcsupport/Makefile.am
> @@ -109,6 +109,7 @@ MALLOC_C_FILES = src/malloc_initialize.c src/calloc.c src/malloc.c \
> src/rtems_heap_extend.c \
> src/rtems_heap_greedy.c
> MALLOC_C_FILES += src/cachealignedalloc.c
> +MALLOC_C_FILES += src/cachecoherentalloc.c
>
> PASSWORD_GROUP_C_FILES = src/pwdgrp.c
> PASSWORD_GROUP_C_FILES += src/getgrent.c
> diff --git a/cpukit/libcsupport/src/cachecoherentalloc.c b/cpukit/libcsupport/src/cachecoherentalloc.c
> new file mode 100644
> index 0000000..bf8167d
> --- /dev/null
> +++ b/cpukit/libcsupport/src/cachecoherentalloc.c
> @@ -0,0 +1,122 @@
> +/**
> + * @file
> + *
> + * @ingroup ClassicCache
> + */
> +
> +/*
> + * Copyright (c) 2014 embedded brains GmbH. All rights reserved.
> + *
> + * embedded brains GmbH
> + * Dornierstr. 4
> + * 82178 Puchheim
> + * Germany
> + * <rtems at embedded-brains.de>
> + *
> + * The license and distribution terms for this file may be
> + * found in the file LICENSE in this distribution or at
> + * http://www.rtems.org/license/LICENSE.
> + */
> +
> +#if HAVE_CONFIG_H
> + #include "config.h"
> +#endif
> +
> +#include <rtems.h>
> +#include <rtems/malloc.h>
> +#include <rtems/score/apimutex.h>
> +#include <rtems/score/heapimpl.h>
> +#include <rtems/score/sysstate.h>
> +
> +static Heap_Control cache_coherent_heap_instance;
> +
> +static Heap_Control *cache_coherent_heap;
> +
> +void *rtems_cache_coherent_allocate(
> + size_t size,
> + uintptr_t alignment,
> + uintptr_t boundary
> +)
> +{
> + void *ptr;
> + Heap_Control *heap;
> +
> + _RTEMS_Lock_allocator();
> +
> + heap = cache_coherent_heap;
> + if ( heap == NULL ) {
> + heap = RTEMS_Malloc_Heap;
> + }
> +
> + ptr = _Heap_Allocate_aligned_with_boundary(
> + heap,
> + size,
> + alignment,
> + boundary
> + );
> +
> + _RTEMS_Unlock_allocator();
> +
> + return ptr;
> +}
> +
> +void rtems_cache_coherent_free( void *ptr )
> +{
> + Heap_Control *heap;
> +
> + _RTEMS_Lock_allocator();
> +
> + heap = cache_coherent_heap;
> + if ( heap != NULL ) {
> + if ( _Heap_Free( heap, ptr ) ) {
> + heap = NULL;
> + } else {
> + heap = RTEMS_Malloc_Heap;
> + }
> + } else {
> + heap = RTEMS_Malloc_Heap;
> + }
> +
> + if ( heap != NULL ) {
> + _Heap_Free( heap, ptr );
> + }
> +
> + _RTEMS_Unlock_allocator();
> +}
> +
> +static void add_area(
> + void *area_begin,
> + uintptr_t area_size
> +)
> +{
> + Heap_Control *heap = cache_coherent_heap;
> +
> + if ( heap == NULL ) {
> + bool ok;
> +
> + heap = &cache_coherent_heap_instance;
> +
> + ok = _Heap_Initialize( heap, area_begin, area_size, 0 );
> + if ( ok ) {
> + cache_coherent_heap = heap;
> + }
> + } else {
> + _Heap_Extend( heap, area_begin, area_size, 0 );
> + }
> +}
> +
> +void rtems_cache_coherent_add_area(
> + void *area_begin,
> + uintptr_t area_size
> +)
> +{
> + if ( _System_state_Is_up( _System_state_Get()) ) {
> + _RTEMS_Lock_allocator();
> +
> + add_area( area_begin, area_size );
> +
> + _RTEMS_Unlock_allocator();
> + } else {
> + add_area( area_begin, area_size );
> + }
> +}
> diff --git a/cpukit/rtems/include/rtems/rtems/cache.h b/cpukit/rtems/include/rtems/rtems/cache.h
> index ce399c6..a7dcaa6 100644
> --- a/cpukit/rtems/include/rtems/rtems/cache.h
> +++ b/cpukit/rtems/include/rtems/rtems/cache.h
> @@ -191,6 +191,67 @@ void rtems_cache_disable_instruction( void );
> */
> void *rtems_cache_aligned_malloc ( size_t nbytes );
>
> +/**
> + * @brief Allocates a memory area of size @a size bytes from cache coherent
> + * memory.
> + *
> + * A size value of zero will return a unique address which may be freed with
> + * rtems_cache_coherent_free().
> + *
> + * The memory allocated by this function can be released with a call to
> + * rtems_cache_coherent_free().
> + *
> + * By default the C program heap allocator is used. In case special memory
> + * areas must be used, then the BSP or the application must add cache coherent
> + * memory areas for the allocator via rtems_cache_coherent_add_area().
> + *
> + * This function must be called from driver initialization or task context
> + * only.
> + *
> + * @param[in] alignment If the alignment parameter is not equal to zero, the
> + * allocated memory area will begin at an address aligned by this value.
> + * @param[in] boundary If the boundary parameter is not equal to zero, the
> + * allocated memory area will comply with a boundary constraint. The
> + * boundary value specifies the set of addresses which are aligned by the
> + * boundary value. The interior of the allocated memory area will not
> + * contain an element of this set. The begin or end address of the area may
> + * be a member of the set.
> + *
> + * @retval NULL If no memory is available or the parameters are inconsistent.
> + * @retval other A pointer to the begin of the allocated memory area.
> + */
> +void *rtems_cache_coherent_allocate(
> + size_t size,
> + uintptr_t alignment,
> + uintptr_t boundary
> +);
> +
> +/**
> + * @brief Frees memory allocated by rtems_cache_coherent_allocate().
> + *
> + * This function must be called from driver initialization or task context
> + * only.
> + *
> + * @param[in] ptr A pointer returned by rtems_cache_coherent_allocate().
> + */
> +void rtems_cache_coherent_free( void *ptr );
> +
> +/**
> + * @brief Adds a cache coherent memory area to the cache coherent allocator.
> + *
> + * This function must be called from BSP initialization, driver initialization
> + * or task context only.
> + *
> + * @param[in] area_begin The area begin address.
> + * @param[in] area_size The area size in bytes.
> + *
> + * @see rtems_cache_coherent_allocate().
> + */
> +void rtems_cache_coherent_add_area(
> + void *area_begin,
> + uintptr_t area_size
> +);
> +
> #if defined( RTEMS_SMP )
>
> /**
> diff --git a/testsuites/sptests/spcache01/init.c b/testsuites/sptests/spcache01/init.c
> index 95777e1..8ed3dbe 100644
> --- a/testsuites/sptests/spcache01/init.c
> +++ b/testsuites/sptests/spcache01/init.c
> @@ -22,6 +22,7 @@
>
> #include <rtems.h>
> #include <rtems/counter.h>
> +#include <rtems/score/sysstate.h>
>
> #define TESTS_USE_PRINTF
> #include "tmacros.h"
> @@ -409,6 +410,51 @@ static void test_cache_aligned_alloc(void)
> free(p1);
> }
>
> +#define AREA_SIZE 256
> +
> +static char cache_coherent_area_0[AREA_SIZE];
> +
> +static char cache_coherent_area_1[AREA_SIZE];
> +
> +static char cache_coherent_area_2[AREA_SIZE];
> +
> +static void add_area(void *begin)
> +{
> + rtems_cache_coherent_add_area(NULL, 0);
> + rtems_cache_coherent_add_area(begin, AREA_SIZE);
> +}
> +
> +static void test_cache_coherent_alloc(void)
> +{
> + void *p0;
> + void *p1;
> + System_state_Codes previous_state;
> +
> + printf("test cache coherent allocation\n");
> +
> + p0 = rtems_cache_coherent_allocate(1, 0, 0);
> + rtems_test_assert(p0 != NULL);
> +
> + rtems_cache_coherent_free(p0);
> +
> + p0 = rtems_cache_coherent_allocate(1, 0, 0);
> + rtems_test_assert(p0 != NULL);
> +
> + add_area(&cache_coherent_area_0[0]);
> + add_area(&cache_coherent_area_1[0]);
> +
> + previous_state = _System_state_Get();
> + _System_state_Set(previous_state + 1);
> + add_area(&cache_coherent_area_2[0]);
> + _System_state_Set(previous_state);
> +
> + p1 = rtems_cache_coherent_allocate(1, 0, 0);
> + rtems_test_assert(p1 != NULL);
> +
> + rtems_cache_coherent_free(p0);
> + rtems_cache_coherent_free(p1);
> +}
> +
> static void Init(rtems_task_argument arg)
> {
> TEST_BEGIN();
> @@ -416,6 +462,7 @@ static void Init(rtems_task_argument arg)
> test_data_flush_and_invalidate();
> test_timing();
> test_cache_aligned_alloc();
> + test_cache_coherent_alloc();
>
> TEST_END();
>
> diff --git a/testsuites/sptests/spcache01/spcache01.doc b/testsuites/sptests/spcache01/spcache01.doc
> index 04e32a1..9c33d94 100644
> --- a/testsuites/sptests/spcache01/spcache01.doc
> +++ b/testsuites/sptests/spcache01/spcache01.doc
> @@ -14,6 +14,9 @@ directives:
> - rtems_cache_invalidate_multiple_data_lines()
> - rtems_cache_invalidate_multiple_instruction_lines()
> - rtems_cache_aligned_malloc()
> + - rtems_cache_coherent_allocate()
> + - rtems_cache_coherent_free()
> + - rtems_cache_coherent_add_area()
>
> concepts:
>
> diff --git a/testsuites/sptests/spcache01/spcache01.scn b/testsuites/sptests/spcache01/spcache01.scn
> index 4e7d53a..6f1d2a6 100644
> --- a/testsuites/sptests/spcache01/spcache01.scn
> +++ b/testsuites/sptests/spcache01/spcache01.scn
> @@ -43,4 +43,5 @@ invalidate multiple instruction
> duration with warm cache 640 ns
> duration with invalidated cache 2600 ns
> test rtems_cache_aligned_malloc()
> +test cache coherent allocation
> *** END OF TEST SPCACHE 1 ***
More information about the devel
mailing list