This is an automated email from Gerrit.

Matthias Welwarsky ([email protected]) just uploaded a new patch set to 
Gerrit, which you can find at http://openocd.zylin.com/3024

-- gerrit

commit da6f5d7894536bd94918da5ac8b885588051e1ab
Author: Matthias Welwarsky <[email protected]>
Date:   Fri Oct 16 09:25:25 2015 +0200

    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 <[email protected]>

diff --git a/src/target/armv7a.c b/src/target/armv7a.c
index 872d8a2..0f3cca8 100644
--- a/src/target/armv7a.c
+++ b/src/target/armv7a.c
@@ -363,24 +363,42 @@ done:
 static int armv7a_handle_inner_cache_info_command(struct command_context 
*cmd_ctx,
        struct armv7a_cache_common *armv7a_cache)
 {
-       if (armv7a_cache->ctype == -1) {
+       int cl;
+
+       if (armv7a_cache->info == -1) {
                command_print(cmd_ctx, "cache not yet identified");
                return ERROR_OK;
        }
 
-       command_print(cmd_ctx,
-               "D-Cache: linelen %" PRIi32 ", associativity %" PRIi32 ", nsets 
%" PRIi32 ", cachesize %" PRId32 " KBytes",
-               armv7a_cache->d_u_size.linelen,
-               armv7a_cache->d_u_size.associativity,
-               armv7a_cache->d_u_size.nsets,
-               armv7a_cache->d_u_size.cachesize);
+       for (cl = 0; cl < armv7a_cache->loc; cl++) {
+               struct armv7a_arch_cache *arch = &(armv7a_cache->arch[cl]);
+
+               if (arch->ctype & 1) {
+                       command_print(cmd_ctx,
+                               "L%d I-Cache: linelen %" PRIi32
+                               ", associativity %" PRIi32
+                               ", nsets %" PRIi32
+                               ", cachesize %" PRId32 " KBytes",
+                               cl+1,
+                               arch->i_size.linelen,
+                               arch->i_size.associativity,
+                               arch->i_size.nsets,
+                               arch->i_size.cachesize);
+               }
 
-       command_print(cmd_ctx,
-               "I-Cache: linelen %" PRIi32 ", associativity %" PRIi32 ", nsets 
%" PRIi32 ", cachesize %" PRId32 " KBytes",
-               armv7a_cache->i_size.linelen,
-               armv7a_cache->i_size.associativity,
-               armv7a_cache->i_size.nsets,
-               armv7a_cache->i_size.cachesize);
+               if (arch->ctype >= 2) {
+                       command_print(cmd_ctx,
+                               "L%d D-Cache: linelen %" PRIi32
+                               ", associativity %" PRIi32
+                               ", nsets %" PRIi32
+                               ", cachesize %" PRId32 " KBytes",
+                               cl+1,
+                               arch->d_u_size.linelen,
+                               arch->d_u_size.associativity,
+                               arch->d_u_size.nsets,
+                               arch->d_u_size.cachesize);
+               }
+       }
 
        return ERROR_OK;
 }
@@ -441,7 +459,7 @@ int armv7a_handle_cache_info_command(struct command_context 
*cmd_ctx,
        struct armv7a_l2x_cache *l2x_cache = (struct armv7a_l2x_cache *)
                (armv7a_cache->outer_cache);
 
-       if (armv7a_cache->ctype == -1) {
+       if (armv7a_cache->info == -1) {
                command_print(cmd_ctx, "cache not yet identified");
                return ERROR_OK;
        }
@@ -501,17 +519,62 @@ done:
 
 }
 
+static int get_cache_info(struct arm_dpm *dpm, int cl, int ct, uint32_t 
*cache_reg)
+{
+       int retval = ERROR_OK;
+
+       /*  select cache level */
+       retval = dpm->instr_write_data_r0(dpm,
+                       ARMV4_5_MCR(15, 2, 0, 0, 0, 0),
+                       (cl << 1) | (ct == 1 ? 1 : 0));
+       if (retval != ERROR_OK)
+               goto done;
+
+       retval = dpm->instr_read_data_r0(dpm,
+                       ARMV4_5_MRC(15, 1, 0, 0, 0, 0),
+                       cache_reg);
+ done:
+       return retval;
+}
+
+static struct armv7a_cachesize decode_cache_reg(uint32_t cache_reg)
+{
+       struct armv7a_cachesize size;
+       int i = 0;
+
+       size.linelen = 16 << (cache_reg & 0x7);
+       size.associativity = ((cache_reg >> 3) & 0x3ff) + 1;
+       size.nsets = ((cache_reg >> 13) & 0x7fff) + 1;
+       size.cachesize = size.linelen * size.associativity * size.nsets / 1024;
+
+       /*  compute info for set way operation on cache */
+       size.index_shift = (cache_reg & 0x7) + 4;
+       size.index = (cache_reg >> 13) & 0x7fff;
+       size.way = ((cache_reg >> 3) & 0x3ff);
+       size.way_shift = size.way + 1;
+
+       while (((size.way_shift >> i) & 1) != 1)
+               i++;
+       size.way_shift = 32-i;
+
+       return size;
+}
+
 int armv7a_identify_cache(struct target *target)
 {
        /*  read cache descriptor */
        int retval = ERROR_FAIL;
        struct armv7a_common *armv7a = target_to_armv7a(target);
        struct arm_dpm *dpm = armv7a->arm.dpm;
-       uint32_t cache_selected, clidr, ctr;
-       uint32_t cache_i_reg, cache_d_reg;
-       struct armv7a_cache_common *cache = &(armv7a->armv7a_mmu.armv7a_cache);
+       uint32_t csselr, clidr, ctr;
+       uint32_t cache_reg;
+       int cl, ctype;
+       struct armv7a_cache_common *cache =
+               &(armv7a->armv7a_mmu.armv7a_cache);
+
        if (!armv7a->is_armv7r)
                armv7a_read_ttbcr(target);
+
        retval = dpm->prepare(dpm);
        if (retval != ERROR_OK)
                goto done;
@@ -536,120 +599,75 @@ int armv7a_identify_cache(struct target *target)
                        &clidr);
        if (retval != ERROR_OK)
                goto done;
-       clidr = (clidr & 0x7000000) >> 23;
-       LOG_INFO("number of cache level %" PRIx32, (uint32_t)(clidr / 2));
-       if ((clidr / 2) > 1) {
-               /* FIXME not supported present in cortex A8 and later */
-               /*  in cortex A7, A15 */
-               LOG_ERROR("cache l2 present :not supported");
-       }
-       /*  retrieve selected cache
+
+       cache->loc = (clidr & 0x7000000) >> 24;
+       LOG_INFO("Number of cache levels to PoC %" PRId32, cache->loc);
+
+       /*  retrieve selected cache for later restore
         *  MRC p15, 2,<Rd>, c0, c0, 0; Read CSSELR */
        retval = dpm->instr_read_data_r0(dpm,
                        ARMV4_5_MRC(15, 2, 0, 0, 0, 0),
-                       &cache_selected);
+                       &csselr);
        if (retval != ERROR_OK)
                goto done;
 
-       retval = armv7a->arm.mrc(target, 15,
-                       2, 0,   /* op1, op2 */
-                       0, 0,   /* CRn, CRm */
-                       &cache_selected);
-       if (retval != ERROR_OK)
-               goto done;
-       /* select instruction cache
-        *  MCR p15, 2,<Rd>, c0, c0, 0; Write CSSELR
-        *  [0]  : 1 instruction cache selection , 0 data cache selection */
-       retval = dpm->instr_write_data_r0(dpm,
-                       ARMV4_5_MRC(15, 2, 0, 0, 0, 0),
-                       1);
-       if (retval != ERROR_OK)
-               goto done;
-
-       /* read CCSIDR
-        * MRC P15,1,<RT>,C0, C0,0 ;on cortex A9 read CCSIDR
-        * [2:0] line size  001 eight word per line
-        * [27:13] NumSet 0x7f 16KB, 0xff 32Kbytes, 0x1ff 64Kbytes */
-       retval = dpm->instr_read_data_r0(dpm,
-                       ARMV4_5_MRC(15, 1, 0, 0, 0, 0),
-                       &cache_i_reg);
-       if (retval != ERROR_OK)
-               goto done;
+       /* retrieve all available inner caches */
+       for (cl = 0; cl < cache->loc; clidr >>= 3, cl++) {
+
+               /* isolate cache type at current level */
+               ctype = clidr & 7;
+
+               /* separate i-cache at this level ? */
+               if (ctype & 1) {
+                       /* retrieve i-cache info */
+                       retval = get_cache_info(dpm, cl, 1, &cache_reg);
+                       if (retval != ERROR_OK)
+                               goto done;
+                       cache->arch[cl].i_size = decode_cache_reg(cache_reg);
+
+                       LOG_DEBUG("instruction cache index %d << %d, way %d << 
%d",
+                                       cache->arch[cl].i_size.index,
+                                       cache->arch[cl].i_size.index_shift,
+                                       cache->arch[cl].i_size.way,
+                                       cache->arch[cl].i_size.way_shift);
+
+                       LOG_DEBUG("cacheline %d bytes %d KBytes asso %d ways",
+                                       cache->arch[cl].i_size.linelen,
+                                       cache->arch[cl].i_size.cachesize,
+                                       cache->arch[cl].i_size.associativity);
+               }
 
-       /*  select data cache*/
-       retval = dpm->instr_write_data_r0(dpm,
-                       ARMV4_5_MRC(15, 2, 0, 0, 0, 0),
-                       0);
-       if (retval != ERROR_OK)
-               goto done;
+               /* separate d or unified d/i cache at this level */
+               if (ctype >= 2) {
+                       /* retrieve d-cache info */
+                       retval = get_cache_info(dpm, cl, 0, &cache_reg);
+                       if (retval != ERROR_OK)
+                               goto done;
+                       cache->arch[cl].d_u_size = decode_cache_reg(cache_reg);
+
+                       LOG_DEBUG("data/unified cache index %d << %d, way %d << 
%d",
+                                       cache->arch[cl].d_u_size.index,
+                                       cache->arch[cl].d_u_size.index_shift,
+                                       cache->arch[cl].d_u_size.way,
+                                       cache->arch[cl].d_u_size.way_shift);
+
+                       LOG_DEBUG("cacheline %d bytes %d KBytes asso %d ways",
+                                       cache->arch[cl].d_u_size.linelen,
+                                       cache->arch[cl].d_u_size.cachesize,
+                                       cache->arch[cl].d_u_size.associativity);
+               }
 
-       retval = dpm->instr_read_data_r0(dpm,
-                       ARMV4_5_MRC(15, 1, 0, 0, 0, 0),
-                       &cache_d_reg);
-       if (retval != ERROR_OK)
-               goto done;
+               cache->arch[cl].ctype = ctype;
+       }
 
        /*  restore selected cache  */
        dpm->instr_write_data_r0(dpm,
                ARMV4_5_MRC(15, 2, 0, 0, 0, 0),
-               cache_selected);
+               csselr);
 
        if (retval != ERROR_OK)
                goto done;
-       dpm->finish(dpm);
 
-       /* put fake type */
-       cache->d_u_size.linelen = 16 << (cache_d_reg & 0x7);
-       cache->d_u_size.cachesize = (((cache_d_reg >> 13) & 0x7fff)+1)/8;
-       cache->d_u_size.nsets = (cache_d_reg >> 13) & 0x7fff;
-       cache->d_u_size.associativity = ((cache_d_reg >> 3) & 0x3ff) + 1;
-       /*  compute info for set way operation on cache */
-       cache->d_u_size.index_shift = (cache_d_reg & 0x7) + 4;
-       cache->d_u_size.index = (cache_d_reg >> 13) & 0x7fff;
-       cache->d_u_size.way = ((cache_d_reg >> 3) & 0x3ff);
-       cache->d_u_size.way_shift = cache->d_u_size.way + 1;
-       {
-               int i = 0;
-               while (((cache->d_u_size.way_shift >> i) & 1) != 1)
-                       i++;
-               cache->d_u_size.way_shift = 32-i;
-       }
-#if 0
-       LOG_INFO("data cache index %d << %d, way %d << %d",
-                       cache->d_u_size.index, cache->d_u_size.index_shift,
-                       cache->d_u_size.way,
-                       cache->d_u_size.way_shift);
-
-       LOG_INFO("data cache %d bytes %d KBytes asso %d ways",
-                       cache->d_u_size.linelen,
-                       cache->d_u_size.cachesize,
-                       cache->d_u_size.associativity);
-#endif
-       cache->i_size.linelen = 16 << (cache_i_reg & 0x7);
-       cache->i_size.associativity = ((cache_i_reg >> 3) & 0x3ff) + 1;
-       cache->i_size.nsets = (cache_i_reg >> 13) & 0x7fff;
-       cache->i_size.cachesize = (((cache_i_reg >> 13) & 0x7fff)+1)/8;
-       /*  compute info for set way operation on cache */
-       cache->i_size.index_shift = (cache_i_reg & 0x7) + 4;
-       cache->i_size.index = (cache_i_reg >> 13) & 0x7fff;
-       cache->i_size.way = ((cache_i_reg >> 3) & 0x3ff);
-       cache->i_size.way_shift = cache->i_size.way + 1;
-       {
-               int i = 0;
-               while (((cache->i_size.way_shift >> i) & 1) != 1)
-                       i++;
-               cache->i_size.way_shift = 32-i;
-       }
-#if 0
-       LOG_INFO("instruction cache index %d << %d, way %d << %d",
-                       cache->i_size.index, cache->i_size.index_shift,
-                       cache->i_size.way, cache->i_size.way_shift);
-
-       LOG_INFO("instruction cache %d bytes %d KBytes asso %d ways",
-                       cache->i_size.linelen,
-                       cache->i_size.cachesize,
-                       cache->i_size.associativity);
-#endif
        /*  if no l2 cache initialize l1 data cache flush function function */
        if (armv7a->armv7a_mmu.armv7a_cache.flush_all_data_cache == NULL) {
                armv7a->armv7a_mmu.armv7a_cache.display_cache_info =
@@ -657,8 +675,8 @@ int armv7a_identify_cache(struct target *target)
                armv7a->armv7a_mmu.armv7a_cache.flush_all_data_cache =
                        armv7a_cache_auto_flush_all_data;
        }
-       armv7a->armv7a_mmu.armv7a_cache.ctype = 0;
 
+       armv7a->armv7a_mmu.armv7a_cache.info = 1;
 done:
        dpm->finish(dpm);
        armv7a_read_mpidr(target);
@@ -675,7 +693,7 @@ int armv7a_init_arch_info(struct target *target, struct 
armv7a_common *armv7a)
        armv7a->arm.target = target;
        armv7a->arm.common_magic = ARM_COMMON_MAGIC;
        armv7a->common_magic = ARMV7_COMMON_MAGIC;
-       armv7a->armv7a_mmu.armv7a_cache.ctype = -1;
+       armv7a->armv7a_mmu.armv7a_cache.info = -1;
        armv7a->armv7a_mmu.armv7a_cache.outer_cache = NULL;
        armv7a->armv7a_mmu.armv7a_cache.flush_all_data_cache = NULL;
        armv7a->armv7a_mmu.armv7a_cache.display_cache_info = NULL;
diff --git a/src/target/armv7a.h b/src/target/armv7a.h
index 45c29a2..7fef798 100644
--- a/src/target/armv7a.h
+++ b/src/target/armv7a.h
@@ -63,12 +63,20 @@ struct armv7a_cachesize {
        uint32_t way_shift;
 };
 
-struct armv7a_cache_common {
-       int ctype;
+/* information about one architecture cache at any level */
+struct armv7a_arch_cache {
+       int ctype;                              /* cache type, CLIDR encoding */
        struct armv7a_cachesize d_u_size;       /* data cache */
        struct armv7a_cachesize i_size;         /* instruction cache */
+};
+
+/* common cache information */
+struct armv7a_cache_common {
+       int info;                               /* -1 invalid, else valid */
+       int loc;                                /* level of coherency */
        uint32_t dminline;                      /* minimum d-cache linelen */
        uint32_t iminline;                      /* minimum i-cache linelen */
+       struct armv7a_arch_cache arch[6];       /* cache info, L1 - L7 */
        int i_cache_enabled;
        int d_u_cache_enabled;
        int auto_cache_enabled;                 /* openocd automatic
diff --git a/src/target/armv7a_cache.c b/src/target/armv7a_cache.c
index e78ee46..2cd5deb 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 < 2)
+                       continue;
+
+               armv7a_l1_d_cache_flush_level(dpm, &cache->arch[cl].d_u_size, 
cl);
+       }
+
+       retval = dpm->finish(dpm);
        return retval;
 
 done:
diff --git a/src/target/armv7a_cache_l2x.c b/src/target/armv7a_cache_l2x.c
index 5af589e..8b35fd8 100644
--- a/src/target/armv7a_cache_l2x.c
+++ b/src/target/armv7a_cache_l2x.c
@@ -179,7 +179,7 @@ static int arm7a_handle_l2x_cache_info_command(struct 
command_context *cmd_ctx,
        struct armv7a_l2x_cache *l2x_cache = (struct armv7a_l2x_cache *)
                (armv7a_cache->outer_cache);
 
-       if (armv7a_cache->ctype == -1) {
+       if (armv7a_cache->info == -1) {
                command_print(cmd_ctx, "cache not yet identified");
                return ERROR_OK;
        }
diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c
index dbda51a..3cafff0 100644
--- a/src/target/cortex_a.c
+++ b/src/target/cortex_a.c
@@ -1305,7 +1305,7 @@ static int cortex_a_post_debug_entry(struct target 
*target)
        LOG_DEBUG("cp15_control_reg: %8.8" PRIx32, cortex_a->cp15_control_reg);
        cortex_a->cp15_control_reg_curr = cortex_a->cp15_control_reg;
 
-       if (armv7a->armv7a_mmu.armv7a_cache.ctype == -1)
+       if (armv7a->armv7a_mmu.armv7a_cache.info == -1)
                armv7a_identify_cache(target);
 
        if (armv7a->is_armv7r) {

-- 

------------------------------------------------------------------------------
_______________________________________________
OpenOCD-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/openocd-devel

Reply via email to