summaryrefslogtreecommitdiffstats
path: root/arch/arm/cpu/armv7/cache_v7.c
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2016-04-09 13:53:48 +0200
committerTom Rini <trini@konsulko.com>2016-04-11 20:48:26 -0400
commitc09d29057ab0b04db0857d319c6bff74de31b9c3 (patch)
tree9f01964012e2eadce3e7d8e1b33e3d2e6d2264f9 /arch/arm/cpu/armv7/cache_v7.c
parent456ecd08ec026e67a17a77baa3778c9f1b8e474d (diff)
downloadblackbird-obmc-uboot-c09d29057ab0b04db0857d319c6bff74de31b9c3.tar.gz
blackbird-obmc-uboot-c09d29057ab0b04db0857d319c6bff74de31b9c3.zip
arm: Replace v7_maint_dcache_all(ARMV7_DCACHE_CLEAN_INVAL_ALL) with asm code
v7_maint_dcache_all() does not work reliable when build with gcc6, see: https://bugzilla.redhat.com/show_bug.cgi?id=1318788 While debugging this I learned that v7_maint_dcache_all() is unreliable when build with gcc5 too when it is marked as noinline. This commit fixes the reliability issues by replacing the C-code with the ready to use asm implementation from the kernel. Given that this code when written as C-code clearly is quite fragile (also see the existing comments about the C-code being the way it is to get optimal assembly) and that we have a proven asm alternative, I believe that this is the best solution. Note that we actually already had a copy of the kernel's v7_flush_dcache_all() before this commit in arch/arm/mach-uniphier/arm32/lowlevel_init.S. This commit moves that code arch/arm/cpu/armv7/cache_v7_asm.S, renames it to __v7_flush_dcache_all(), and adds a v7_flush_dcache_all() wrapper which saves / restores the clobbered registers for use from C-code. Signed-off-by: Hans de Goede <hdegoede@redhat.com> Acked-by: Masahiro Yamada <yamada.masahiro@socionext.com>
Diffstat (limited to 'arch/arm/cpu/armv7/cache_v7.c')
-rw-r--r--arch/arm/cpu/armv7/cache_v7.c41
1 files changed, 6 insertions, 35 deletions
diff --git a/arch/arm/cpu/armv7/cache_v7.c b/arch/arm/cpu/armv7/cache_v7.c
index 94ff48859e..dd07ba1768 100644
--- a/arch/arm/cpu/armv7/cache_v7.c
+++ b/arch/arm/cpu/armv7/cache_v7.c
@@ -16,6 +16,10 @@
#define ARMV7_DCACHE_CLEAN_INVAL_RANGE 4
#ifndef CONFIG_SYS_DCACHE_OFF
+
+/* Asm functions from cache_v7_asm.S */
+void v7_flush_dcache_all(void);
+
static int check_cache_range(unsigned long start, unsigned long stop)
{
int ok = 1;
@@ -88,34 +92,6 @@ static void v7_inval_dcache_level_setway(u32 level, u32 num_sets,
DSB;
}
-static void v7_clean_inval_dcache_level_setway(u32 level, u32 num_sets,
- u32 num_ways, u32 way_shift,
- u32 log2_line_len)
-{
- int way, set;
- u32 setway;
-
- /*
- * For optimal assembly code:
- * a. count down
- * b. have bigger loop inside
- */
- for (way = num_ways - 1; way >= 0 ; way--) {
- for (set = num_sets - 1; set >= 0; set--) {
- setway = (level << 1) | (set << log2_line_len) |
- (way << way_shift);
- /*
- * Clean & Invalidate data/unified
- * cache line by set/way
- */
- asm volatile (" mcr p15, 0, %0, c7, c14, 2"
- : : "r" (setway));
- }
- }
- /* DSB to make sure the operation is complete */
- DSB;
-}
-
static void v7_maint_dcache_level_setway(u32 level, u32 operation)
{
u32 ccsidr;
@@ -142,13 +118,8 @@ static void v7_maint_dcache_level_setway(u32 level, u32 operation)
log2_num_ways = log_2_n_round_up(num_ways);
way_shift = (32 - log2_num_ways);
- if (operation == ARMV7_DCACHE_INVAL_ALL) {
- v7_inval_dcache_level_setway(level, num_sets, num_ways,
+ v7_inval_dcache_level_setway(level, num_sets, num_ways,
way_shift, log2_line_len);
- } else if (operation == ARMV7_DCACHE_CLEAN_INVAL_ALL) {
- v7_clean_inval_dcache_level_setway(level, num_sets, num_ways,
- way_shift, log2_line_len);
- }
}
static void v7_maint_dcache_all(u32 operation)
@@ -263,7 +234,7 @@ void invalidate_dcache_all(void)
*/
void flush_dcache_all(void)
{
- v7_maint_dcache_all(ARMV7_DCACHE_CLEAN_INVAL_ALL);
+ v7_flush_dcache_all();
v7_outer_cache_flush_all();
}
OpenPOWER on IntegriCloud