[RFC] mips: Enable bulk write optimization for all writes
[openocd.git] / src / target / mips_m4k.c
index 623d55e0d8360e9dcabc25cf010324f8f34ae1a4..fc2a3f808a27e6175cbb2c0e1288c09f3c91c108 100644 (file)
@@ -22,7 +22,7 @@
  *   You should have received a copy of the GNU General Public License     *
  *   along with this program; if not, write to the                         *
  *   Free Software Foundation, Inc.,                                       *
- *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.           *
  ***************************************************************************/
 
 #ifdef HAVE_CONFIG_H
@@ -42,6 +42,12 @@ static int mips_m4k_set_breakpoint(struct target *target,
                struct breakpoint *breakpoint);
 static int mips_m4k_unset_breakpoint(struct target *target,
                struct breakpoint *breakpoint);
+static int mips_m4k_internal_restore(struct target *target, int current,
+               uint32_t address, int handle_breakpoints,
+               int debug_execution);
+static int mips_m4k_halt(struct target *target);
+static int mips_m4k_bulk_write_memory(struct target *target, uint32_t address,
+               uint32_t count, const uint8_t *buffer);
 
 static int mips_m4k_examine_debug_reason(struct target *target)
 {
@@ -82,10 +88,11 @@ static int mips_m4k_debug_entry(struct target *target)
 {
        struct mips32_common *mips32 = target_to_mips32(target);
        struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
-       uint32_t debug_reg;
 
-       /* read debug register */
-       mips_ejtag_read_debug(ejtag_info, &debug_reg);
+       mips32_save_context(target);
+
+       /* make sure stepping disabled, SSt bit in CP0 debug register cleared */
+       mips_ejtag_config_step(ejtag_info, 0);
 
        /* make sure break unit configured */
        mips32_configure_break_unit(target);
@@ -93,14 +100,6 @@ static int mips_m4k_debug_entry(struct target *target)
        /* attempt to find halt reason */
        mips_m4k_examine_debug_reason(target);
 
-       /* clear single step if active */
-       if (debug_reg & EJTAG_DEBUG_DSS) {
-               /* stopped due to single step - clear step bit */
-               mips_ejtag_config_step(ejtag_info, 0);
-       }
-
-       mips32_save_context(target);
-
        /* default to mips32 isa, it will be changed below if required */
        mips32->isa_mode = MIPS32_ISA_MIPS32;
 
@@ -114,12 +113,73 @@ static int mips_m4k_debug_entry(struct target *target)
        return ERROR_OK;
 }
 
+static struct target *get_mips_m4k(struct target *target, int32_t coreid)
+{
+       struct target_list *head;
+       struct target *curr;
+
+       head = target->head;
+       while (head != (struct target_list *)NULL) {
+               curr = head->target;
+               if ((curr->coreid == coreid) && (curr->state == TARGET_HALTED))
+                       return curr;
+               head = head->next;
+       }
+       return target;
+}
+
+static int mips_m4k_halt_smp(struct target *target)
+{
+       int retval = ERROR_OK;
+       struct target_list *head;
+       struct target *curr;
+       head = target->head;
+       while (head != (struct target_list *)NULL) {
+               int ret = ERROR_OK;
+               curr = head->target;
+               if ((curr != target) && (curr->state != TARGET_HALTED))
+                       ret = mips_m4k_halt(curr);
+
+               if (ret != ERROR_OK) {
+                       LOG_ERROR("halt failed target->coreid: %d", curr->coreid);
+                       retval = ret;
+               }
+               head = head->next;
+       }
+       return retval;
+}
+
+static int update_halt_gdb(struct target *target)
+{
+       int retval = ERROR_OK;
+       if (target->gdb_service->core[0] == -1) {
+               target->gdb_service->target = target;
+               target->gdb_service->core[0] = target->coreid;
+               retval = mips_m4k_halt_smp(target);
+       }
+       return retval;
+}
+
 static int mips_m4k_poll(struct target *target)
 {
-       int retval;
+       int retval = ERROR_OK;
        struct mips32_common *mips32 = target_to_mips32(target);
        struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
        uint32_t ejtag_ctrl = ejtag_info->ejtag_ctrl;
+       enum target_state prev_target_state = target->state;
+
+       /*  toggle to another core is done by gdb as follow */
+       /*  maint packet J core_id */
+       /*  continue */
+       /*  the next polling trigger an halt event sent to gdb */
+       if ((target->state == TARGET_HALTED) && (target->smp) &&
+               (target->gdb_service) &&
+               (target->gdb_service->target == NULL)) {
+               target->gdb_service->target =
+                       get_mips_m4k(target, target->gdb_service->core[1]);
+               target_call_event_callbacks(target, TARGET_EVENT_HALTED);
+               return retval;
+       }
 
        /* read ejtag control reg */
        mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL);
@@ -143,15 +203,29 @@ static int mips_m4k_poll(struct target *target)
 
        /* check for processor halted */
        if (ejtag_ctrl & EJTAG_CTRL_BRKST) {
-               if ((target->state == TARGET_RUNNING) || (target->state == TARGET_RESET)) {
+               if ((target->state != TARGET_HALTED)
+                   && (target->state != TARGET_DEBUG_RUNNING)) {
+                       if (target->state == TARGET_UNKNOWN)
+                               LOG_DEBUG("EJTAG_CTRL_BRKST already set during server startup.");
+
+                       /* OpenOCD was was probably started on the board with EJTAG_CTRL_BRKST already set
+                        * (maybe put on by HALT-ing the board in the previous session).
+                        *
+                        * Force enable debug entry for this session.
+                        */
                        mips_ejtag_set_instr(ejtag_info, EJTAG_INST_NORMALBOOT);
-
                        target->state = TARGET_HALTED;
-
                        retval = mips_m4k_debug_entry(target);
                        if (retval != ERROR_OK)
                                return retval;
 
+                       if (target->smp &&
+                               ((prev_target_state == TARGET_RUNNING)
+                            || (prev_target_state == TARGET_RESET))) {
+                               retval = update_halt_gdb(target);
+                               if (retval != ERROR_OK)
+                                       return retval;
+                       }
                        target_call_event_callbacks(target, TARGET_EVENT_HALTED);
                } else if (target->state == TARGET_DEBUG_RUNNING) {
                        target->state = TARGET_HALTED;
@@ -160,6 +234,12 @@ static int mips_m4k_poll(struct target *target)
                        if (retval != ERROR_OK)
                                return retval;
 
+                       if (target->smp) {
+                               retval = update_halt_gdb(target);
+                               if (retval != ERROR_OK)
+                                       return retval;
+                       }
+
                        target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED);
                }
        } else
@@ -211,15 +291,22 @@ static int mips_m4k_assert_reset(struct target *target)
 {
        struct mips_m4k_common *mips_m4k = target_to_m4k(target);
        struct mips_ejtag *ejtag_info = &mips_m4k->mips32.ejtag_info;
-       int assert_srst = 1;
 
        LOG_DEBUG("target->state: %s",
                target_state_name(target));
 
        enum reset_types jtag_reset_config = jtag_get_reset_config();
 
-       if (!(jtag_reset_config & RESET_HAS_SRST))
-               assert_srst = 0;
+       /* some cores support connecting while srst is asserted
+        * use that mode is it has been configured */
+
+       bool srst_asserted = false;
+
+       if (!(jtag_reset_config & RESET_SRST_PULLS_TRST) &&
+                       (jtag_reset_config & RESET_SRST_NO_GATING)) {
+               jtag_add_reset(0, 1);
+               srst_asserted = true;
+       }
 
        if (target->reset_halt) {
                /* use hardware to catch reset */
@@ -227,11 +314,11 @@ static int mips_m4k_assert_reset(struct target *target)
        } else
                mips_ejtag_set_instr(ejtag_info, EJTAG_INST_NORMALBOOT);
 
-       if (assert_srst) {
+       if (jtag_reset_config & RESET_HAS_SRST) {
                /* here we should issue a srst only, but we may have to assert trst as well */
                if (jtag_reset_config & RESET_SRST_PULLS_TRST)
                        jtag_add_reset(1, 1);
-               else
+               else if (!srst_asserted)
                        jtag_add_reset(0, 1);
        } else {
                if (mips_m4k->is_pic32mx) {
@@ -302,7 +389,33 @@ static int mips_m4k_single_step_core(struct target *target)
        return ERROR_OK;
 }
 
-static int mips_m4k_resume(struct target *target, int current,
+static int mips_m4k_restore_smp(struct target *target, uint32_t address, int handle_breakpoints)
+{
+       int retval = ERROR_OK;
+       struct target_list *head;
+       struct target *curr;
+
+       head = target->head;
+       while (head != (struct target_list *)NULL) {
+               int ret = ERROR_OK;
+               curr = head->target;
+               if ((curr != target) && (curr->state != TARGET_RUNNING)) {
+                       /*  resume current address , not in step mode */
+                       ret = mips_m4k_internal_restore(curr, 1, address,
+                                                  handle_breakpoints, 0);
+
+                       if (ret != ERROR_OK) {
+                               LOG_ERROR("target->coreid :%d failed to resume at address :0x%x",
+                                                 curr->coreid, address);
+                               retval = ret;
+                       }
+               }
+               head = head->next;
+       }
+       return retval;
+}
+
+static int mips_m4k_internal_restore(struct target *target, int current,
                uint32_t address, int handle_breakpoints, int debug_execution)
 {
        struct mips32_common *mips32 = target_to_mips32(target);
@@ -331,7 +444,10 @@ static int mips_m4k_resume(struct target *target, int current,
        if (ejtag_info->impcode & EJTAG_IMP_MIPS16)
                buf_set_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 1, mips32->isa_mode);
 
-       resume_pc = buf_get_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 32);
+       if (!current)
+               resume_pc = address;
+       else
+               resume_pc = buf_get_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 32);
 
        mips32_restore_context(target);
 
@@ -370,6 +486,33 @@ static int mips_m4k_resume(struct target *target, int current,
        return ERROR_OK;
 }
 
+static int mips_m4k_resume(struct target *target, int current,
+               uint32_t address, int handle_breakpoints, int debug_execution)
+{
+       int retval = ERROR_OK;
+
+       /* dummy resume for smp toggle in order to reduce gdb impact  */
+       if ((target->smp) && (target->gdb_service->core[1] != -1)) {
+               /*   simulate a start and halt of target */
+               target->gdb_service->target = NULL;
+               target->gdb_service->core[0] = target->gdb_service->core[1];
+               /*  fake resume at next poll we play the  target core[1], see poll*/
+               target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
+               return retval;
+       }
+
+       retval = mips_m4k_internal_restore(target, current, address,
+                               handle_breakpoints,
+                               debug_execution);
+
+       if (retval == ERROR_OK && target->smp) {
+               target->gdb_service->core[0] = -1;
+               retval = mips_m4k_restore_smp(target, address, handle_breakpoints);
+       }
+
+       return retval;
+}
+
 static int mips_m4k_step(struct target *target, int current,
                uint32_t address, int handle_breakpoints)
 {
@@ -417,12 +560,12 @@ static int mips_m4k_step(struct target *target, int current,
        /* registers are now invalid */
        register_cache_invalidate(mips32->core_cache);
 
+       LOG_DEBUG("target stepped ");
+       mips_m4k_debug_entry(target);
+
        if (breakpoint)
                mips_m4k_set_breakpoint(target, breakpoint);
 
-       LOG_DEBUG("target stepped ");
-
-       mips_m4k_debug_entry(target);
        target_call_event_callbacks(target, TARGET_EVENT_HALTED);
 
        return ERROR_OK;
@@ -837,6 +980,13 @@ static int mips_m4k_write_memory(struct target *target, uint32_t address,
                return ERROR_TARGET_NOT_HALTED;
        }
 
+       if (size == 4 && count > 32) {
+               int retval = mips_m4k_bulk_write_memory(target, address, count, buffer);
+               if (retval == ERROR_OK)
+                       return ERROR_OK;
+               LOG_WARNING("Falling back to non-bulk write");
+       }
+
        /* sanitize arguments */
        if (((size != 4) && (size != 2) && (size != 1)) || (count == 0) || !(buffer))
                return ERROR_COMMAND_SYNTAX_ERROR;
@@ -957,11 +1107,6 @@ static int mips_m4k_bulk_write_memory(struct target *target, uint32_t address,
 
        LOG_DEBUG("address: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "", address, count);
 
-       if (target->state != TARGET_HALTED) {
-               LOG_WARNING("target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
        /* check alignment */
        if (address & 0x3u)
                return ERROR_TARGET_UNALIGNED_ACCESS;
@@ -975,8 +1120,8 @@ static int mips_m4k_bulk_write_memory(struct target *target, uint32_t address,
                                MIPS32_FASTDATA_HANDLER_SIZE,
                                &mips32->fast_data_area);
                if (retval != ERROR_OK) {
-                       LOG_WARNING("No working area available, falling back to non-bulk write");
-                       return mips_m4k_write_memory(target, address, 4, count, buffer);
+                       LOG_ERROR("No working area available");
+                       return retval;
                }
 
                /* reset fastadata state so the algo get reloaded */
@@ -1000,11 +1145,8 @@ static int mips_m4k_bulk_write_memory(struct target *target, uint32_t address,
        if (t != NULL)
                free(t);
 
-       if (retval != ERROR_OK) {
-               /* FASTDATA access failed, try normal memory write */
-               LOG_DEBUG("Fastdata access Failed, falling back to non-bulk write");
-               retval = mips_m4k_write_memory(target, address, 4, count, buffer);
-       }
+       if (retval != ERROR_OK)
+               LOG_ERROR("Fastdata access Failed");
 
        return retval;
 }
@@ -1045,7 +1187,6 @@ COMMAND_HANDLER(mips_m4k_handle_cp0_command)
 
                if (CMD_ARGC == 2) {
                        uint32_t value;
-
                        retval = mips32_cp0_read(ejtag_info, &value, cp0_reg, cp0_sel);
                        if (retval != ERROR_OK) {
                                command_print(CMD_CTX,
@@ -1053,12 +1194,9 @@ COMMAND_HANDLER(mips_m4k_handle_cp0_command)
                                                cp0_reg);
                                return ERROR_OK;
                        }
-                       retval = jtag_execute_queue();
-                       if (retval != ERROR_OK)
-                               return retval;
-
                        command_print(CMD_CTX, "cp0 reg %" PRIi32 ", select %" PRIi32 ": %8.8" PRIx32,
                                        cp0_reg, cp0_sel, value);
+
                } else if (CMD_ARGC == 3) {
                        uint32_t value;
                        COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], value);
@@ -1077,6 +1215,87 @@ COMMAND_HANDLER(mips_m4k_handle_cp0_command)
        return ERROR_OK;
 }
 
+COMMAND_HANDLER(mips_m4k_handle_smp_off_command)
+{
+       struct target *target = get_current_target(CMD_CTX);
+       /* check target is an smp target */
+       struct target_list *head;
+       struct target *curr;
+       head = target->head;
+       target->smp = 0;
+       if (head != (struct target_list *)NULL) {
+               while (head != (struct target_list *)NULL) {
+                       curr = head->target;
+                       curr->smp = 0;
+                       head = head->next;
+               }
+               /*  fixes the target display to the debugger */
+               target->gdb_service->target = target;
+       }
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(mips_m4k_handle_smp_on_command)
+{
+       struct target *target = get_current_target(CMD_CTX);
+       struct target_list *head;
+       struct target *curr;
+       head = target->head;
+       if (head != (struct target_list *)NULL) {
+               target->smp = 1;
+               while (head != (struct target_list *)NULL) {
+                       curr = head->target;
+                       curr->smp = 1;
+                       head = head->next;
+               }
+       }
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(mips_m4k_handle_smp_gdb_command)
+{
+       struct target *target = get_current_target(CMD_CTX);
+       int retval = ERROR_OK;
+       struct target_list *head;
+       head = target->head;
+       if (head != (struct target_list *)NULL) {
+               if (CMD_ARGC == 1) {
+                       int coreid = 0;
+                       COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], coreid);
+                       if (ERROR_OK != retval)
+                               return retval;
+                       target->gdb_service->core[1] = coreid;
+
+               }
+               command_print(CMD_CTX, "gdb coreid  %d -> %d", target->gdb_service->core[0]
+                       , target->gdb_service->core[1]);
+       }
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(mips_m4k_handle_scan_delay_command)
+{
+       struct target *target = get_current_target(CMD_CTX);
+       struct mips_m4k_common *mips_m4k = target_to_m4k(target);
+       struct mips_ejtag *ejtag_info = &mips_m4k->mips32.ejtag_info;
+
+       if (CMD_ARGC == 1)
+               COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], ejtag_info->scan_delay);
+       else if (CMD_ARGC > 1)
+                       return ERROR_COMMAND_SYNTAX_ERROR;
+
+       command_print(CMD_CTX, "scan delay: %d nsec", ejtag_info->scan_delay);
+       if (ejtag_info->scan_delay >= 20000000) {
+               ejtag_info->mode = 0;
+               command_print(CMD_CTX, "running in legacy mode");
+       } else {
+               ejtag_info->mode = 1;
+               command_print(CMD_CTX, "running in fast queued mode");
+       }
+
+       return ERROR_OK;
+}
+
 static const struct command_registration mips_m4k_exec_command_handlers[] = {
        {
                .name = "cp0",
@@ -1085,6 +1304,34 @@ static const struct command_registration mips_m4k_exec_command_handlers[] = {
                .usage = "regnum [value]",
                .help = "display/modify cp0 register",
        },
+       {
+               .name = "smp_off",
+               .handler = mips_m4k_handle_smp_off_command,
+               .mode = COMMAND_EXEC,
+               .help = "Stop smp handling",
+               .usage = "",},
+
+       {
+               .name = "smp_on",
+               .handler = mips_m4k_handle_smp_on_command,
+               .mode = COMMAND_EXEC,
+               .help = "Restart smp handling",
+               .usage = "",
+       },
+       {
+               .name = "smp_gdb",
+               .handler = mips_m4k_handle_smp_gdb_command,
+               .mode = COMMAND_EXEC,
+               .help = "display/fix current core played to gdb",
+               .usage = "",
+       },
+       {
+               .name = "scan_delay",
+               .handler = mips_m4k_handle_scan_delay_command,
+               .mode = COMMAND_ANY,
+               .help = "display/set scan delay in nano seconds",
+               .usage = "[value]",
+       },
        COMMAND_REGISTRATION_DONE
 };
 
@@ -1122,7 +1369,6 @@ struct target_type mips_m4k_target = {
 
        .read_memory = mips_m4k_read_memory,
        .write_memory = mips_m4k_write_memory,
-       .bulk_write_memory = mips_m4k_bulk_write_memory,
        .checksum_memory = mips32_checksum_memory,
        .blank_check_memory = mips32_blank_check_memory,
 

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)