This macro is used to allocate cache line size aligned stack buffers for use with DMA hardware.
Signed-off-by: Anton Staaf <robot...@chromium.org> Acked-by: Mike Frysinger <vap...@gentoo.org> Cc: Lukasz Majewski <l.majew...@samsung.com> Cc: Kyungmin Park <kyungmin.p...@samsung.com> Cc: Mike Frysinger <vap...@gentoo.org> Cc: Aneesh V <ane...@ti.com> Cc: Albert ARIBAUD <albert.u.b...@aribaud.net> --- doc/README.arm-caches | 2 + include/common.h | 59 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 0 deletions(-) diff --git a/doc/README.arm-caches b/doc/README.arm-caches index cd2b458..f6a52e3 100644 --- a/doc/README.arm-caches +++ b/doc/README.arm-caches @@ -40,6 +40,8 @@ Buffer Requirements: - If the buffer is not cache-line aligned invalidation will be restricted to the aligned part. That is, one cache-line at the respective boundary may be left out while doing invalidation. +- A suitable buffer can be alloced on the stack using the + ALLOC_CACHE_ALIGN_BUFFER macro. Cleanup Before Linux: - cleanup_before_linux() should flush the D-cache, invalidate I-cache, and diff --git a/include/common.h b/include/common.h index aeb2d84..cdd76c5 100644 --- a/include/common.h +++ b/include/common.h @@ -789,6 +789,65 @@ int cpu_release(int nr, int argc, char * const argv[]); #define ALIGN(x,a) __ALIGN_MASK((x),(typeof(x))(a)-1) #define __ALIGN_MASK(x,mask) (((x)+(mask))&~(mask)) +/* + * The ALLOC_CACHE_ALIGN_BUFFER macro is used to allocate a cache line size + * aligned buffer on the stack. Such a buffer is useful for DMA operations + * where flushing and invalidating the cache before and after a read and/or + * write operation is required for correct operations. + * + * When called the macro creates an array on the stack that is sized such + * that: + * + * 1) The beginning of the array can be advanced enough to be aligned. + * + * 2) The size of the aligned portion of the array is a multiple of the cache + * line size. + * + * 3) The aligned portion contains enough space for the original number of + * elements requested. + * + * The macro then creates a pointer to the aligned portion of this array and + * assigns to the pointer the address of the first element in the aligned + * portion of the array. + * + * Calling the macro as: + * + * ALLOC_CACHE_ALIGN_BUFFER(uint32_t, buffer, 1024); + * + * Will result in something similar to saying: + * + * uint32_t buffer[1024]; + * + * The following differences exist: + * + * 1) The resulting buffer is guaranteed to be aligned to the value of + * CONFIG_SYS_CACHELINE_SIZE + * + * 2) the buffer variable created by the macro is a pointer to the specified + * type, and NOT an array of the specified type. This can be very important + * if you want the address of the buffer, which you probably do, to pass it + * to the DMA hardware. The value of &buffer is different in the two cases. + * In the macro case it will be the address of the pointer, not the address + * of the space reserved for the buffer. However, in the second case it + * would be the address of the buffer. So if you are replacing hard coded + * stack buffers with this macro you need to make sure you remove the & from + * the locations where you are taking the address of the buffer. + * + * Note that the size parameter is the number of array elements to allocate, + * not the number of bytes. + * + * This macro can not be used outside of function scope, or for the creation + * of a function scoped static buffer. It can not be used to create a cache + * line aligned global buffer. + */ +#define ALLOC_CACHE_ALIGN_BUFFER(type, name, size) \ + char __##name[ROUND(size * sizeof(type), \ + CONFIG_SYS_CACHELINE_SIZE) + \ + CONFIG_SYS_CACHELINE_SIZE - 1]; \ + \ + type *name = (type *) ALIGN((uintptr_t)__##name, \ + CONFIG_SYS_CACHELINE_SIZE) + /* Pull in stuff for the build system */ #ifdef DO_DEPS_ONLY # include <environment.h> -- 1.7.3.1 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot