diff options
author | Thierry Reding <treding@nvidia.com> | 2014-08-26 17:34:23 +0200 |
---|---|---|
committer | Marcel Ziswiler <marcel.ziswiler@toradex.com> | 2014-10-11 01:21:51 +0200 |
commit | 1a8f7ecda5a3b7100950f16b7be2288fe6b5c86f (patch) | |
tree | 22485962f3727af4b20bdbd4c821925452e6ea4b /arch | |
parent | 7a14fa1f2911d618f4c7b0f91355236b7b38d982 (diff) |
ARM: Implement non-cached memory support
Implement an API that can be used by drivers to allocate memory from a
pool that is mapped uncached. This is useful if drivers would otherwise
need to do extensive cache maintenance (or explicitly maintaining the
cache isn't safe).
The API is protected using the new CONFIG_SYS_NONCACHED_MEMORY setting.
Boards can set this to the size to be used for the non-cached area. The
area will typically be right below the malloc() area, but architectures
should take care of aligning the beginning and end of the area to honor
any mapping restrictions. Architectures must also ensure that mappings
established for this area do not overlap with the malloc() area (which
should remain cached for improved performance).
While the API is currently only implemented for ARM v7, it should be
generic enough to allow other architectures to implement it as well.
Signed-off-by: Thierry Reding <treding@nvidia.com>
Conflicts:
README
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/include/asm/system.h | 5 | ||||
-rw-r--r-- | arch/arm/lib/cache.c | 42 |
2 files changed, 47 insertions, 0 deletions
diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h index 61e2914d44b..89f22946895 100644 --- a/arch/arm/include/asm/system.h +++ b/arch/arm/include/asm/system.h @@ -212,6 +212,11 @@ void mmu_set_region_dcache_behaviour(phys_addr_t start, size_t size, */ void mmu_page_table_flush(unsigned long start, unsigned long stop); +#ifdef CONFIG_SYS_NONCACHED_MEMORY +void noncached_init(void); +phys_addr_t noncached_alloc(size_t size, size_t align); +#endif /* CONFIG_SYS_NONCACHED_MEMORY */ + #endif /* __ASSEMBLY__ */ #define arch_align_stack(x) (x) diff --git a/arch/arm/lib/cache.c b/arch/arm/lib/cache.c index 4e597a4c1d1..b2aa7740d4f 100644 --- a/arch/arm/lib/cache.c +++ b/arch/arm/lib/cache.c @@ -8,6 +8,7 @@ /* for now: just dummy functions to satisfy the linker */ #include <common.h> +#include <malloc.h> __weak void flush_cache(unsigned long start, unsigned long size) { @@ -49,3 +50,44 @@ __weak void enable_caches(void) { puts("WARNING: Caches not enabled\n"); } + +#ifdef CONFIG_SYS_NONCACHED_MEMORY +/* + * Reserve one MMU section worth of address space below the malloc() area that + * will be mapped uncached. + */ +static unsigned long noncached_start; +static unsigned long noncached_end; +static unsigned long noncached_next; + +void noncached_init(void) +{ + phys_addr_t start, end; + size_t size; + + end = ALIGN(mem_malloc_start, MMU_SECTION_SIZE) - MMU_SECTION_SIZE; + size = ALIGN(CONFIG_SYS_NONCACHED_MEMORY, MMU_SECTION_SIZE); + start = end - size; + + debug("mapping memory %pa-%pa non-cached\n", &start, &end); + + noncached_start = start; + noncached_end = end; + noncached_next = start; + + mmu_set_region_dcache_behaviour(noncached_start, size, DCACHE_OFF); +} + +phys_addr_t noncached_alloc(size_t size, size_t align) +{ + phys_addr_t next = ALIGN(noncached_next, align); + + if (next >= noncached_end || (noncached_end - next) < size) + return 0; + + debug("allocated %zu bytes of uncached memory @%pa\n", size, &next); + noncached_next = next + size; + + return next; +} +#endif /* CONFIG_SYS_NONCACHED_MEMORY */ |