diff options
author | Matthias Welwarsky <matthias@welwarsky.de> | 2015-10-16 09:25:25 +0200 |
---|---|---|
committer | Paul Fertser <fercerpav@gmail.com> | 2015-11-30 05:40:57 +0000 |
commit | 8704e53665910ba71e5bc3f99b32ead0060e1a3e (patch) | |
tree | 0be18ed0939e0905f1e23ef02c7fe7ebc3590da7 /src/target/armv7a_cache.c | |
parent | 3a292a1f34586b265b92e4662652683645e14201 (diff) |
armv7a: fix handling of inner caches
ARMv7 architecture allows up to 7 cache levels that are architecturally
visible, as opposed to "system caches", which are outside of the domain
defined by ARMv7 and require separate management. This patch enables
detection and identification of caches at all levels. It also implements
a new "flush-all" function that cleans & invalidates all cache levels to
the "Point of Coherence".
Change-Id: Ib77115d6044d39845907941c6f031e208f6e0aa5
Signed-off-by: Matthias Welwarsky <matthias@welwarsky.de>
Reviewed-on: http://openocd.zylin.com/3024
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
Tested-by: jenkins
Diffstat (limited to 'src/target/armv7a_cache.c')
-rw-r--r-- | src/target/armv7a_cache.c | 54 |
1 files changed, 36 insertions, 18 deletions
diff --git a/src/target/armv7a_cache.c b/src/target/armv7a_cache.c index d8e909e4..94fa0970 100644 --- a/src/target/armv7a_cache.c +++ b/src/target/armv7a_cache.c @@ -60,28 +60,17 @@ static int armv7a_l1_i_cache_sanity_check(struct target *target) return ERROR_OK; } -static int armv7a_l1_d_cache_clean_inval_all(struct target *target) +static int armv7a_l1_d_cache_flush_level(struct arm_dpm *dpm, struct armv7a_cachesize *size, int cl) { - struct armv7a_common *armv7a = target_to_armv7a(target); - struct arm_dpm *dpm = armv7a->arm.dpm; - struct armv7a_cachesize *d_u_size = - &(armv7a->armv7a_mmu.armv7a_cache.d_u_size); - int32_t c_way, c_index = d_u_size->index; - int retval; - - retval = armv7a_l1_d_cache_sanity_check(target); - if (retval != ERROR_OK) - return retval; - - retval = dpm->prepare(dpm); - if (retval != ERROR_OK) - goto done; + int retval = ERROR_OK; + int32_t c_way, c_index = size->index; + LOG_DEBUG("cl %" PRId32, cl); do { - c_way = d_u_size->way; + c_way = size->way; do { - uint32_t value = (c_index << d_u_size->index_shift) - | (c_way << d_u_size->way_shift); + uint32_t value = (c_index << size->index_shift) + | (c_way << size->way_shift) | (cl << 1); /* * DCCISW - Clean and invalidate data cache * line by Set/Way. @@ -96,6 +85,35 @@ static int armv7a_l1_d_cache_clean_inval_all(struct target *target) c_index -= 1; } while (c_index >= 0); + done: + return retval; +} + +static int armv7a_l1_d_cache_clean_inval_all(struct target *target) +{ + struct armv7a_common *armv7a = target_to_armv7a(target); + struct armv7a_cache_common *cache = &(armv7a->armv7a_mmu.armv7a_cache); + struct arm_dpm *dpm = armv7a->arm.dpm; + int cl; + int retval; + + retval = armv7a_l1_d_cache_sanity_check(target); + if (retval != ERROR_OK) + return retval; + + retval = dpm->prepare(dpm); + if (retval != ERROR_OK) + goto done; + + for (cl = 0; cl < cache->loc; cl++) { + /* skip i-only caches */ + if (cache->arch[cl].ctype < CACHE_LEVEL_HAS_D_CACHE) + continue; + + armv7a_l1_d_cache_flush_level(dpm, &cache->arch[cl].d_u_size, cl); + } + + retval = dpm->finish(dpm); return retval; done: |