Hi Thierry, On 26 August 2014 09:34, Thierry Reding <thierry.red...@gmail.com> wrote: > From: Thierry Reding <tred...@nvidia.com> > > 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 <tred...@nvidia.com> > --- > Changes in v2: > - avoid overflow when checking for available space > > README | 19 +++++++++++++++++++ > arch/arm/include/asm/system.h | 5 +++++ > arch/arm/lib/cache.c | 42 ++++++++++++++++++++++++++++++++++++++++++ > common/board_r.c | 11 +++++++++++ > 4 files changed, 77 insertions(+) > > diff --git a/README b/README > index 1d713596ec6f..526e06edb52c 100644 > --- a/README > +++ b/README > @@ -3759,6 +3759,25 @@ Configuration Settings: > Pre-relocation malloc() is only supported on ARM at present > but is fairly easy to enable for other archs. > > +- CONFIG_SYS_NONCACHED_MEMORY: > + Size of non-cached memory area. This area of memory will be > + typically located right below the malloc() area and mapped > + uncached in the MMU. This is useful for drivers that would > + otherwise require a lot of explicit cache maintenance. For > + some drivers it's also impossible to properly maintain the > + cache. For example if the regions that need to be flushed > + are not a multiple of the cache-line size, *and* padding > + cannot be allocated between the regions to align them (i.e. > + if the HW requires a contiguous array of regions, and the > + size of each region is not cache-aligned), then a flush of > + one region may result in overwriting data that hardware has > + written to another region in the same cache-line. This can > + happen for example in network drivers where descriptors for > + buffers are typically smaller than the CPU cache-line (e.g. > + 16 bytes vs. 32 or 64 bytes). > + > + Non-cached memory is only supported on 32-bit ARM at present.
Is this better than allocating 1MB with memalign() and then changing the MMU settings with something like set_section_dcache()? > + > - CONFIG_SYS_BOOTM_LEN: > Normally compressed uImages are limited to an > uncompressed size of 8 MBytes. If this is not enough, > diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h > index fb31a8faf2b1..fb1bc0699a56 100644 > --- a/arch/arm/include/asm/system.h > +++ b/arch/arm/include/asm/system.h > @@ -211,6 +211,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 4e597a4c1d16..b2aa7740d4f8 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. It looks like it can be >1 section. > + */ > +static unsigned long noncached_start; > +static unsigned long noncached_end; > +static unsigned long noncached_next; You can use ulong if you like. > + > +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; Should this be aligned? I suspect it doesn't matter, and you do it anyway on the next call. > + > + return next; > +} > +#endif /* CONFIG_SYS_NONCACHED_MEMORY */ > diff --git a/common/board_r.c b/common/board_r.c > index ba9a68dc6691..6b8e62bf032b 100644 > --- a/common/board_r.c > +++ b/common/board_r.c > @@ -270,6 +270,14 @@ static int initr_malloc(void) > return 0; > } > > +#ifdef CONFIG_SYS_NONCACHED_MEMORY > +static int initr_noncached(void) > +{ > + noncached_init(); Could you make this function return 0 to avoid needing this helper? > + return 0; > +} > +#endif > + > #ifdef CONFIG_DM > static int initr_dm(void) > { > @@ -765,6 +773,9 @@ init_fnc_t init_sequence_r[] = { > #endif > initr_barrier, > initr_malloc, > +#ifdef CONFIG_SYS_NONCACHED_MEMORY > + initr_noncached, > +#endif > bootstage_relocate, > #ifdef CONFIG_DM > initr_dm, > -- > 2.0.4 > Regards, Simon _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot