X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=blobdiff_plain;f=src%2Ftarget%2Farmv7a_cache.c;h=3e5f8d6def98a371d39b282d123d9da4befffe65;hp=984dc7c51f52527a41cd4c9490b16dfe3256d071;hb=e195b0bc812deaad4d770cb1044c5a1b905d8671;hpb=cd440bd32a120a9b4c2d703d3d16dd52f16edab2 diff --git a/src/target/armv7a_cache.c b/src/target/armv7a_cache.c index 984dc7c51f..3e5f8d6def 100644 --- a/src/target/armv7a_cache.c +++ b/src/target/armv7a_cache.c @@ -11,6 +11,9 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -35,7 +38,7 @@ static int armv7a_l1_d_cache_sanity_check(struct target *target) /* check that cache data is on at target halt */ if (!armv7a->armv7a_mmu.armv7a_cache.d_u_cache_enabled) { - LOG_DEBUG("l1 data cache is not enabled"); + LOG_DEBUG("data cache is not enabled"); return ERROR_TARGET_INVALID; } @@ -53,35 +56,24 @@ static int armv7a_l1_i_cache_sanity_check(struct target *target) /* check that cache data is on at target halt */ if (!armv7a->armv7a_mmu.armv7a_cache.i_cache_enabled) { - LOG_DEBUG("l1 data cache is not enabled"); + LOG_DEBUG("instruction cache is not enabled"); return ERROR_TARGET_INVALID; } 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 +88,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: @@ -127,19 +148,22 @@ int armv7a_cache_auto_flush_all_data(struct target *target) } else retval = armv7a_l1_d_cache_clean_inval_all(target); - /* FIXME: do l2x flushing here */ + if (retval != ERROR_OK) + return retval; - return retval; + /* do outer cache flushing after inner caches have been flushed */ + return arm7a_l2x_flush_all_data(target); } -static int armv7a_l1_d_cache_inval_virt(struct target *target, uint32_t virt, +int armv7a_l1_d_cache_inval_virt(struct target *target, uint32_t virt, uint32_t size) { struct armv7a_common *armv7a = target_to_armv7a(target); struct arm_dpm *dpm = armv7a->arm.dpm; struct armv7a_cache_common *armv7a_cache = &armv7a->armv7a_mmu.armv7a_cache; - uint32_t i, linelen = armv7a_cache->dminline; + uint32_t linelen = armv7a_cache->dminline; + uint32_t va_line, va_end; int retval; retval = armv7a_l1_d_cache_sanity_check(target); @@ -150,15 +174,39 @@ static int armv7a_l1_d_cache_inval_virt(struct target *target, uint32_t virt, if (retval != ERROR_OK) goto done; - for (i = 0; i < size; i += linelen) { - uint32_t offs = virt + i; + va_line = virt & (-linelen); + va_end = virt + size; + + /* handle unaligned start */ + if (virt != va_line) { + /* DCCIMVAC */ + retval = dpm->instr_write_data_r0(dpm, + ARMV4_5_MCR(15, 0, 0, 7, 14, 1), va_line); + if (retval != ERROR_OK) + goto done; + va_line += linelen; + } + + /* handle unaligned end */ + if ((va_end & (linelen-1)) != 0) { + va_end &= (-linelen); + /* DCCIMVAC */ + retval = dpm->instr_write_data_r0(dpm, + ARMV4_5_MCR(15, 0, 0, 7, 14, 1), va_end); + if (retval != ERROR_OK) + goto done; + } - /* DCIMVAC - Clean and invalidate data cache line by VA to PoC. */ + while (va_line < va_end) { + /* DCIMVAC - Invalidate data cache line by VA to PoC. */ retval = dpm->instr_write_data_r0(dpm, - ARMV4_5_MCR(15, 0, 0, 7, 6, 1), offs); + ARMV4_5_MCR(15, 0, 0, 7, 6, 1), va_line); if (retval != ERROR_OK) goto done; + va_line += linelen; } + + dpm->finish(dpm); return retval; done: @@ -174,7 +222,48 @@ int armv7a_l1_d_cache_clean_virt(struct target *target, uint32_t virt, struct armv7a_common *armv7a = target_to_armv7a(target); struct arm_dpm *dpm = armv7a->arm.dpm; struct armv7a_cache_common *armv7a_cache = &armv7a->armv7a_mmu.armv7a_cache; - uint32_t i, linelen = armv7a_cache->dminline; + uint32_t linelen = armv7a_cache->dminline; + uint32_t va_line, va_end; + 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; + + va_line = virt & (-linelen); + va_end = virt + size; + + while (va_line < va_end) { + /* DCCMVAC - Data Cache Clean by MVA to PoC */ + retval = dpm->instr_write_data_r0(dpm, + ARMV4_5_MCR(15, 0, 0, 7, 10, 1), va_line); + if (retval != ERROR_OK) + goto done; + va_line += linelen; + } + + dpm->finish(dpm); + return retval; + +done: + LOG_ERROR("d-cache invalidate failed"); + dpm->finish(dpm); + + return retval; +} + +int armv7a_l1_d_cache_flush_virt(struct target *target, uint32_t virt, + unsigned int size) +{ + struct armv7a_common *armv7a = target_to_armv7a(target); + struct arm_dpm *dpm = armv7a->arm.dpm; + struct armv7a_cache_common *armv7a_cache = &armv7a->armv7a_mmu.armv7a_cache; + uint32_t linelen = armv7a_cache->dminline; + uint32_t va_line, va_end; int retval; retval = armv7a_l1_d_cache_sanity_check(target); @@ -185,16 +274,19 @@ int armv7a_l1_d_cache_clean_virt(struct target *target, uint32_t virt, if (retval != ERROR_OK) goto done; - for (i = 0; i < size; i += linelen) { - uint32_t offs = virt + i; + va_line = virt & (-linelen); + va_end = virt + size; - /* FIXME: do we need DCCVAC or DCCVAU */ - /* FIXME: in both cases it is not enough for i-cache */ + while (va_line < va_end) { + /* DCCIMVAC */ retval = dpm->instr_write_data_r0(dpm, - ARMV4_5_MCR(15, 0, 0, 7, 10, 1), offs); + ARMV4_5_MCR(15, 0, 0, 7, 14, 1), va_line); if (retval != ERROR_OK) goto done; + va_line += linelen; } + + dpm->finish(dpm); return retval; done: @@ -285,6 +377,14 @@ done: return retval; } +int armv7a_cache_flush_virt(struct target *target, uint32_t virt, + uint32_t size) +{ + armv7a_l1_d_cache_flush_virt(target, virt, size); + armv7a_l2x_cache_flush_virt(target, virt, size); + + return ERROR_OK; +} /* * We assume that target core was chosen correctly. It means if same data @@ -300,41 +400,11 @@ int armv7a_cache_auto_flush_on_write(struct target *target, uint32_t virt, uint32_t size) { struct armv7a_common *armv7a = target_to_armv7a(target); - int retval = ERROR_OK; if (!armv7a->armv7a_mmu.armv7a_cache.auto_cache_enabled) return ERROR_OK; - armv7a_l1_d_cache_clean_virt(target, virt, size); - armv7a_l2x_cache_flush_virt(target, virt, size); - - if (target->smp) { - struct target_list *head; - struct target *curr; - head = target->head; - while (head != (struct target_list *)NULL) { - curr = head->target; - if (curr->state == TARGET_HALTED) { - retval = armv7a_l1_i_cache_inval_all(curr); - if (retval != ERROR_OK) - return retval; - retval = armv7a_l1_d_cache_inval_virt(target, - virt, size); - if (retval != ERROR_OK) - return retval; - } - head = head->next; - } - } else { - retval = armv7a_l1_i_cache_inval_all(target); - if (retval != ERROR_OK) - return retval; - retval = armv7a_l1_d_cache_inval_virt(target, virt, size); - if (retval != ERROR_OK) - return retval; - } - - return retval; + return armv7a_cache_flush_virt(target, virt, size); } COMMAND_HANDLER(arm7a_l1_cache_info_cmd)