armv7a: forward error value in armv7a_cache_auto_flush_all_data
[openocd.git] / src / target / armv7a_cache.c
index 984dc7c51f52527a41cd4c9490b16dfe3256d071..3e5f8d6def98a371d39b282d123d9da4befffe65 100644 (file)
@@ -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 <http://www.gnu.org/licenses/>. *
  ***************************************************************************/
 
 #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)

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)