jtag: linuxgpiod: drop extra parenthesis
[openocd.git] / src / target / armv7a_cache.c
index d8e909e41b5941b8f9d9c210eceb452817426381..e1f0dfafb0bdd4bc25c65e2ef349ffd6fd3544c5 100644 (file)
@@ -1,16 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
 /***************************************************************************
  *   Copyright (C) 2015 by Oleksij Rempel                                  *
  *   linux@rempel-privat.de                                                *
- *                                                                         *
- *   This program is free software; you can redistribute it and/or modify  *
- *   it under the terms of the GNU General Public License as published by  *
- *   the Free Software Foundation; either version 2 of the License, or     *
- *   (at your option) any later version.                                   *
- *                                                                         *
- *   This program is distributed in the hope that it will be useful,       *
- *   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.                          *
  ***************************************************************************/
 
 #ifdef HAVE_CONFIG_H
 #include "armv7a_cache.h"
 #include <helper/time_support.h>
 #include "arm_opcodes.h"
+#include "smp.h"
 
 static int armv7a_l1_d_cache_sanity_check(struct target *target)
 {
        struct armv7a_common *armv7a = target_to_armv7a(target);
 
        if (target->state != TARGET_HALTED) {
-               LOG_ERROR("%s: target not halted", __func__);
+               LOG_TARGET_ERROR(target, "not halted");
                return ERROR_TARGET_NOT_HALTED;
        }
 
        /*  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;
        }
 
@@ -47,41 +40,31 @@ static int armv7a_l1_i_cache_sanity_check(struct target *target)
        struct armv7a_common *armv7a = target_to_armv7a(target);
 
        if (target->state != TARGET_HALTED) {
-               LOG_ERROR("%s: target not halted", __func__);
+               LOG_TARGET_ERROR(target, "not halted");
                return ERROR_TARGET_NOT_HALTED;
        }
 
        /*  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;
+               keep_alive();
+               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 +79,36 @@ static int armv7a_l1_d_cache_clean_inval_all(struct target *target)
                c_index -= 1;
        } while (c_index >= 0);
 
+ done:
+       keep_alive();
+       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:
@@ -115,33 +128,31 @@ int armv7a_cache_auto_flush_all_data(struct target *target)
 
        if (target->smp) {
                struct target_list *head;
-               struct target *curr;
-               head = target->head;
-               while (head != (struct target_list *)NULL) {
-                       curr = head->target;
+               foreach_smp_target(head, target->smp_targets) {
+                       struct target *curr = head->target;
                        if (curr->state == TARGET_HALTED)
                                retval = armv7a_l1_d_cache_clean_inval_all(curr);
-
-                       head = head->next;
                }
        } else
                retval = armv7a_l1_d_cache_clean_inval_all(target);
 
-       /* do outer cache flushing after inner caches have been flushed */
-       retval = arm7a_l2x_flush_all_data(target);
+       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;
-       int retval;
+       uint32_t linelen = armv7a_cache->dminline;
+       uint32_t va_line, va_end;
+       int retval, i = 0;
 
        retval = armv7a_l1_d_cache_sanity_check(target);
        if (retval != ERROR_OK)
@@ -151,19 +162,47 @@ 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) {
+               if ((i++ & 0x3f) == 0)
+                       keep_alive();
+               /* 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;
        }
+
+       keep_alive();
+       dpm->finish(dpm);
        return retval;
 
 done:
        LOG_ERROR("d-cache invalidate failed");
+       keep_alive();
        dpm->finish(dpm);
 
        return retval;
@@ -175,8 +214,9 @@ 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;
-       int retval;
+       uint32_t linelen = armv7a_cache->dminline;
+       uint32_t va_line, va_end;
+       int retval, i = 0;
 
        retval = armv7a_l1_d_cache_sanity_check(target);
        if (retval != ERROR_OK)
@@ -186,20 +226,71 @@ 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;
+
+       while (va_line < va_end) {
+               if ((i++ & 0x3f) == 0)
+                       keep_alive();
+               /* 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;
+       }
+
+       keep_alive();
+       dpm->finish(dpm);
+       return retval;
+
+done:
+       LOG_ERROR("d-cache invalidate failed");
+       keep_alive();
+       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, i = 0;
+
+       retval = armv7a_l1_d_cache_sanity_check(target);
+       if (retval != ERROR_OK)
+               return retval;
 
-               /* FIXME: do we need DCCVAC or DCCVAU */
-               /* FIXME: in both cases it is not enough for i-cache */
+       retval = dpm->prepare(dpm);
+       if (retval != ERROR_OK)
+               goto done;
+
+       va_line = virt & (-linelen);
+       va_end = virt + size;
+
+       while (va_line < va_end) {
+               if ((i++ & 0x3f) == 0)
+                       keep_alive();
+               /* 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;
        }
+
+       keep_alive();
+       dpm->finish(dpm);
        return retval;
 
 done:
        LOG_ERROR("d-cache invalidate failed");
+       keep_alive();
        dpm->finish(dpm);
 
        return retval;
@@ -251,7 +342,7 @@ int armv7a_l1_i_cache_inval_virt(struct target *target, uint32_t virt,
                                &armv7a->armv7a_mmu.armv7a_cache;
        uint32_t linelen = armv7a_cache->iminline;
        uint32_t va_line, va_end;
-       int retval;
+       int retval, i = 0;
 
        retval = armv7a_l1_i_cache_sanity_check(target);
        if (retval != ERROR_OK)
@@ -265,6 +356,8 @@ int armv7a_l1_i_cache_inval_virt(struct target *target, uint32_t virt,
        va_end = virt + size;
 
        while (va_line < va_end) {
+               if ((i++ & 0x3f) == 0)
+                       keep_alive();
                /* ICIMVAU - Invalidate instruction cache by VA to PoU. */
                retval = dpm->instr_write_data_r0(dpm,
                                ARMV4_5_MCR(15, 0, 0, 7, 5, 1), va_line);
@@ -277,21 +370,32 @@ int armv7a_l1_i_cache_inval_virt(struct target *target, uint32_t virt,
                        goto done;
                va_line += linelen;
        }
+       keep_alive();
+       dpm->finish(dpm);
        return retval;
 
 done:
        LOG_ERROR("i-cache invalidate failed");
+       keep_alive();
        dpm->finish(dpm);
 
        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
  * was handled by two cores, other core will loose the changes. Since it
  * is impossible to know (FIXME) which core has correct data, keep in mind
- * that some kind of data lost or korruption is possible.
+ * that some kind of data lost or corruption is possible.
  * Possible scenario:
  *  - core1 loaded and changed data on 0x12345678
  *  - we halted target and modified same data on core0
@@ -301,41 +405,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)
@@ -343,7 +417,7 @@ COMMAND_HANDLER(arm7a_l1_cache_info_cmd)
        struct target *target = get_current_target(CMD_CTX);
        struct armv7a_common *armv7a = target_to_armv7a(target);
 
-       return armv7a_handle_cache_info_command(CMD_CTX,
+       return armv7a_handle_cache_info_command(CMD,
                        &armv7a->armv7a_mmu.armv7a_cache);
 }
 
@@ -425,7 +499,7 @@ COMMAND_HANDLER(arm7a_cache_disable_auto_cmd)
        struct armv7a_common *armv7a = target_to_armv7a(target);
 
        if (CMD_ARGC == 0) {
-               command_print(CMD_CTX, "auto cache is %s",
+               command_print(CMD, "auto cache is %s",
                        armv7a->armv7a_mmu.armv7a_cache.auto_cache_enabled ? "enabled" : "disabled");
                return ERROR_OK;
        }
@@ -484,12 +558,12 @@ static const struct command_registration arm7a_l1_i_cache_commands[] = {
        COMMAND_REGISTRATION_DONE
 };
 
-const struct command_registration arm7a_l1_di_cache_group_handlers[] = {
+static const struct command_registration arm7a_l1_di_cache_group_handlers[] = {
        {
                .name = "info",
                .handler = arm7a_l1_cache_info_cmd,
                .mode = COMMAND_ANY,
-               .help = "print cache realted information",
+               .help = "print cache related information",
                .usage = "",
        },
        {
@@ -509,7 +583,7 @@ const struct command_registration arm7a_l1_di_cache_group_handlers[] = {
        COMMAND_REGISTRATION_DONE
 };
 
-const struct command_registration arm7a_cache_group_handlers[] = {
+static const struct command_registration arm7a_cache_group_handlers[] = {
        {
                .name = "auto",
                .handler = arm7a_cache_disable_auto_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)