openocd: src/target: replace the GPL-2.0-or-later license tag
[fw/openocd] / src / target / espressif / esp_xtensa_smp.c
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2
3 /***************************************************************************
4  *   ESP Xtensa SMP target API for OpenOCD                                 *
5  *   Copyright (C) 2020 Espressif Systems Ltd. Co                          *
6  *   Author: Alexey Gerenkov <alexey@espressif.com>                        *
7  ***************************************************************************/
8
9 #ifdef HAVE_CONFIG_H
10 #include "config.h"
11 #endif
12
13 #include "assert.h"
14 #include <target/target.h>
15 #include <target/target_type.h>
16 #include <target/smp.h>
17 #include "esp_xtensa_smp.h"
18
19 /*
20 Multiprocessor stuff common:
21
22 The ESP Xtensa chip can have several cores in it, which can run in SMP-mode if an
23 SMP-capable OS is running. The hardware has a few features which makes
24 SMP debugging much easier.
25
26 First of all, there's something called a 'break network', consisting of a
27 BreakIn input  and a BreakOut output on each CPU. The idea is that as soon
28 as a CPU goes into debug mode for whatever reason, it'll signal that using
29 its DebugOut pin. This signal is connected to the other CPU's DebugIn
30 input, causing this CPU also to go into debugging mode. To resume execution
31 when using only this break network, we will need to manually resume both
32 CPUs.
33
34 An alternative to this is the XOCDMode output and the RunStall (or DebugStall)
35 input. When these are cross-connected, a CPU that goes into debug mode will
36 halt execution entirely on the other CPU. Execution on the other CPU can be
37 resumed by either the first CPU going out of debug mode, or the second CPU
38 going into debug mode: the stall is temporarily lifted as long as the stalled
39 CPU is in debug mode.
40
41 A third, separate, signal is CrossTrigger. This is connected in the same way
42 as the breakIn/breakOut network, but is for the TRAX (trace memory) feature;
43 it does not affect OCD in any way.
44 */
45
46 /*
47 Multiprocessor stuff:
48
49 The ESP Xtensa chip has several Xtensa cores inside, but represent themself to the OCD
50 as one chip that works in multithreading mode under FreeRTOS OS.
51 The core that initiate the stop condition will be defined as an active cpu.
52 When one core stops, then other core will be stopped automatically by smpbreak.
53 The core that initiates stop condition will be defined as an active core, and
54 registers of this core will be transferred.
55 */
56
57 #define ESP_XTENSA_SMP_EXAMINE_OTHER_CORES      5
58
59 static int esp_xtensa_smp_update_halt_gdb(struct target *target, bool *need_resume);
60
61 static inline struct esp_xtensa_smp_common *target_to_esp_xtensa_smp(struct target *target)
62 {
63         return container_of(target->arch_info, struct esp_xtensa_smp_common, esp_xtensa);
64 }
65
66 int esp_xtensa_smp_assert_reset(struct target *target)
67 {
68         return ERROR_OK;
69 }
70
71 int esp_xtensa_smp_deassert_reset(struct target *target)
72 {
73         LOG_TARGET_DEBUG(target, "begin");
74
75         int ret = xtensa_deassert_reset(target);
76         if (ret != ERROR_OK)
77                 return ret;
78         /* in SMP mode when chip was running single-core app the other core can be left un-examined,
79            because examination is done before SOC reset. But after SOC reset it is functional and should be handled.
80            So try to examine un-examined core just after SOC reset */
81         if (target->smp && !target_was_examined(target))
82                 ret = xtensa_examine(target);
83         return ret;
84 }
85
86 int esp_xtensa_smp_soft_reset_halt(struct target *target)
87 {
88         int res;
89         struct target_list *head;
90         struct esp_xtensa_smp_common *esp_xtensa_smp = target_to_esp_xtensa_smp(target);
91
92         LOG_TARGET_DEBUG(target, "begin");
93         /* in SMP mode we need to ensure that at first we reset SOC on PRO-CPU
94            and then call xtensa_assert_reset() for all cores */
95         if (target->smp && target->coreid != 0)
96                 return ERROR_OK;
97         /* Reset the SoC first */
98         if (esp_xtensa_smp->chip_ops->reset) {
99                 res = esp_xtensa_smp->chip_ops->reset(target);
100                 if (res != ERROR_OK)
101                         return res;
102         }
103         if (!target->smp)
104                 return xtensa_assert_reset(target);
105
106         foreach_smp_target(head, target->smp_targets) {
107                 res = xtensa_assert_reset(head->target);
108                 if (res != ERROR_OK)
109                         return res;
110         }
111         return ERROR_OK;
112 }
113
114 static struct target *get_halted_esp_xtensa_smp(struct target *target, int32_t coreid)
115 {
116         struct target_list *head;
117         struct target *curr;
118
119         foreach_smp_target(head, target->smp_targets) {
120                 curr = head->target;
121                 if ((curr->coreid == coreid) && (curr->state == TARGET_HALTED))
122                         return curr;
123         }
124
125         return target;
126 }
127
128 int esp_xtensa_smp_poll(struct target *target)
129 {
130         enum target_state old_state = target->state;
131         struct esp_xtensa_smp_common *esp_xtensa_smp = target_to_esp_xtensa_smp(target);
132         struct target_list *head;
133         struct target *curr;
134         bool other_core_resume_req = false;
135
136         if (target->state == TARGET_HALTED && target->smp && target->gdb_service && !target->gdb_service->target) {
137                 target->gdb_service->target = get_halted_esp_xtensa_smp(target, target->gdb_service->core[1]);
138                 LOG_INFO("Switch GDB target to '%s'", target_name(target->gdb_service->target));
139                 if (esp_xtensa_smp->chip_ops->on_halt)
140                         esp_xtensa_smp->chip_ops->on_halt(target);
141                 target_call_event_callbacks(target, TARGET_EVENT_HALTED);
142                 return ERROR_OK;
143         }
144
145         int ret = esp_xtensa_poll(target);
146         if (ret != ERROR_OK)
147                 return ret;
148
149         if (target->smp) {
150                 if (target->state == TARGET_RESET) {
151                         esp_xtensa_smp->examine_other_cores = ESP_XTENSA_SMP_EXAMINE_OTHER_CORES;
152                 } else if (esp_xtensa_smp->examine_other_cores > 0 &&
153                         (target->state == TARGET_RUNNING || target->state == TARGET_HALTED)) {
154                         LOG_TARGET_DEBUG(target, "Check for unexamined cores after reset");
155                         bool all_examined = true;
156                         foreach_smp_target(head, target->smp_targets) {
157                                 curr = head->target;
158                                 if (curr == target)
159                                         continue;
160                                 if (!target_was_examined(curr)) {
161                                         if (target_examine_one(curr) != ERROR_OK) {
162                                                 LOG_DEBUG("Failed to examine!");
163                                                 all_examined = false;
164                                         }
165                                 }
166                         }
167                         if (all_examined)
168                                 esp_xtensa_smp->examine_other_cores = 0;
169                         else
170                                 esp_xtensa_smp->examine_other_cores--;
171                 }
172         }
173
174         if (old_state != TARGET_HALTED && target->state == TARGET_HALTED) {
175                 if (target->smp) {
176                         ret = esp_xtensa_smp_update_halt_gdb(target, &other_core_resume_req);
177                         if (ret != ERROR_OK)
178                                 return ret;
179                 }
180                 /* Call any event callbacks that are applicable */
181                 if (old_state == TARGET_DEBUG_RUNNING) {
182                         target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED);
183                 } else {
184                         /* check whether any core polled by esp_xtensa_smp_update_halt_gdb() requested resume */
185                         if (target->smp && other_core_resume_req) {
186                                 /* Resume xtensa_resume will handle BREAK instruction. */
187                                 ret = target_resume(target, 1, 0, 1, 0);
188                                 if (ret != ERROR_OK) {
189                                         LOG_ERROR("Failed to resume target");
190                                         return ret;
191                                 }
192                                 return ERROR_OK;
193                         }
194                         if (esp_xtensa_smp->chip_ops->on_halt)
195                                 esp_xtensa_smp->chip_ops->on_halt(target);
196                         target_call_event_callbacks(target, TARGET_EVENT_HALTED);
197                 }
198         }
199
200         return ERROR_OK;
201 }
202
203 static int esp_xtensa_smp_update_halt_gdb(struct target *target, bool *need_resume)
204 {
205         struct esp_xtensa_smp_common *esp_xtensa_smp;
206         struct target *gdb_target = NULL;
207         struct target_list *head;
208         struct target *curr;
209         int ret = ERROR_OK;
210
211         *need_resume = false;
212
213         if (target->gdb_service && target->gdb_service->target)
214                 LOG_DEBUG("GDB target '%s'", target_name(target->gdb_service->target));
215
216         if (target->gdb_service && target->gdb_service->core[0] == -1) {
217                 target->gdb_service->target = target;
218                 target->gdb_service->core[0] = target->coreid;
219                 LOG_INFO("Set GDB target to '%s'", target_name(target));
220         }
221
222         if (target->gdb_service)
223                 gdb_target = target->gdb_service->target;
224
225         /* due to smpbreak config other cores can also go to HALTED state */
226         foreach_smp_target(head, target->smp_targets) {
227                 curr = head->target;
228                 LOG_DEBUG("Check target '%s'", target_name(curr));
229                 /* skip calling context */
230                 if (curr == target)
231                         continue;
232                 if (!target_was_examined(curr)) {
233                         curr->state = TARGET_HALTED;
234                         continue;
235                 }
236                 /* skip targets that were already halted */
237                 if (curr->state == TARGET_HALTED)
238                         continue;
239                 /* Skip gdb_target; it alerts GDB so has to be polled as last one */
240                 if (curr == gdb_target)
241                         continue;
242                 LOG_DEBUG("Poll target '%s'", target_name(curr));
243
244                 esp_xtensa_smp = target_to_esp_xtensa_smp(curr);
245                 /* avoid auto-resume after syscall, it will be done later */
246                 esp_xtensa_smp->other_core_does_resume = true;
247                 /* avoid recursion in esp_xtensa_smp_poll() */
248                 curr->smp = 0;
249                 if (esp_xtensa_smp->chip_ops->poll)
250                         ret = esp_xtensa_smp->chip_ops->poll(curr);
251                 else
252                         ret = esp_xtensa_smp_poll(curr);
253                 curr->smp = 1;
254                 if (ret != ERROR_OK)
255                         return ret;
256                 esp_xtensa_smp->other_core_does_resume = false;
257         }
258
259         /* after all targets were updated, poll the gdb serving target */
260         if (gdb_target && gdb_target != target) {
261                 esp_xtensa_smp = target_to_esp_xtensa_smp(gdb_target);
262                 if (esp_xtensa_smp->chip_ops->poll)
263                         ret = esp_xtensa_smp->chip_ops->poll(gdb_target);
264                 else
265                         ret = esp_xtensa_smp_poll(gdb_target);
266         }
267
268         LOG_DEBUG("exit");
269
270         return ret;
271 }
272
273 static inline int esp_xtensa_smp_smpbreak_disable(struct target *target, uint32_t *smp_break)
274 {
275         int res = xtensa_smpbreak_get(target, smp_break);
276         if (res != ERROR_OK)
277                 return res;
278         return xtensa_smpbreak_set(target, 0);
279 }
280
281 static inline int esp_xtensa_smp_smpbreak_restore(struct target *target, uint32_t smp_break)
282 {
283         return xtensa_smpbreak_set(target, smp_break);
284 }
285
286 static int esp_xtensa_smp_resume_cores(struct target *target,
287         int handle_breakpoints,
288         int debug_execution)
289 {
290         struct target_list *head;
291         struct target *curr;
292
293         LOG_TARGET_DEBUG(target, "begin");
294
295         foreach_smp_target(head, target->smp_targets) {
296                 curr = head->target;
297                 /* in single-core mode disabled core cannot be examined, but need to be resumed too*/
298                 if ((curr != target) && (curr->state != TARGET_RUNNING) && target_was_examined(curr)) {
299                         /*  resume current address, not in SMP mode */
300                         curr->smp = 0;
301                         int res = esp_xtensa_smp_resume(curr, 1, 0, handle_breakpoints, debug_execution);
302                         curr->smp = 1;
303                         if (res != ERROR_OK)
304                                 return res;
305                 }
306         }
307         return ERROR_OK;
308 }
309
310 int esp_xtensa_smp_resume(struct target *target,
311         int current,
312         target_addr_t address,
313         int handle_breakpoints,
314         int debug_execution)
315 {
316         int res;
317         uint32_t smp_break;
318
319         xtensa_smpbreak_get(target, &smp_break);
320         LOG_TARGET_DEBUG(target, "smp_break=0x%" PRIx32, smp_break);
321
322         /* dummy resume for smp toggle in order to reduce gdb impact  */
323         if ((target->smp) && (target->gdb_service) && (target->gdb_service->core[1] != -1)) {
324                 /* simulate a start and halt of target */
325                 target->gdb_service->target = NULL;
326                 target->gdb_service->core[0] = target->gdb_service->core[1];
327                 /* fake resume at next poll we play the  target core[1], see poll*/
328                 LOG_TARGET_DEBUG(target, "Fake resume");
329                 target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
330                 return ERROR_OK;
331         }
332
333         /* xtensa_prepare_resume() can step over breakpoint/watchpoint and generate signals on BreakInOut circuit for
334          * other cores. So disconnect this core from BreakInOut circuit and do xtensa_prepare_resume(). */
335         res = esp_xtensa_smp_smpbreak_disable(target, &smp_break);
336         if (res != ERROR_OK)
337                 return res;
338         res = xtensa_prepare_resume(target, current, address, handle_breakpoints, debug_execution);
339         /* restore configured BreakInOut signals config */
340         int ret = esp_xtensa_smp_smpbreak_restore(target, smp_break);
341         if (ret != ERROR_OK)
342                 return ret;
343         if (res != ERROR_OK) {
344                 LOG_TARGET_ERROR(target, "Failed to prepare for resume!");
345                 return res;
346         }
347
348         if (target->smp) {
349                 if (target->gdb_service)
350                         target->gdb_service->core[0] = -1;
351                 res = esp_xtensa_smp_resume_cores(target, handle_breakpoints, debug_execution);
352                 if (res != ERROR_OK)
353                         return res;
354         }
355
356         res = xtensa_do_resume(target);
357         if (res != ERROR_OK) {
358                 LOG_TARGET_ERROR(target, "Failed to resume!");
359                 return res;
360         }
361
362         target->debug_reason = DBG_REASON_NOTHALTED;
363         if (!debug_execution)
364                 target->state = TARGET_RUNNING;
365         else
366                 target->state = TARGET_DEBUG_RUNNING;
367
368         target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
369         return ERROR_OK;
370 }
371
372 int esp_xtensa_smp_step(struct target *target,
373         int current,
374         target_addr_t address,
375         int handle_breakpoints)
376 {
377         int res;
378         uint32_t smp_break = 0;
379         struct esp_xtensa_smp_common *esp_xtensa_smp = target_to_esp_xtensa_smp(target);
380
381         if (target->smp) {
382                 res = esp_xtensa_smp_smpbreak_disable(target, &smp_break);
383                 if (res != ERROR_OK)
384                         return res;
385         }
386         res = xtensa_step(target, current, address, handle_breakpoints);
387
388         if (res == ERROR_OK) {
389                 if (esp_xtensa_smp->chip_ops->on_halt)
390                         esp_xtensa_smp->chip_ops->on_halt(target);
391                 target_call_event_callbacks(target, TARGET_EVENT_HALTED);
392         }
393
394         if (target->smp) {
395                 int ret = esp_xtensa_smp_smpbreak_restore(target, smp_break);
396                 if (ret != ERROR_OK)
397                         return ret;
398         }
399
400         return res;
401 }
402
403 int esp_xtensa_smp_watchpoint_add(struct target *target, struct watchpoint *watchpoint)
404 {
405         int res = xtensa_watchpoint_add(target, watchpoint);
406         if (res != ERROR_OK)
407                 return res;
408
409         if (!target->smp)
410                 return ERROR_OK;
411
412         struct target_list *head;
413         foreach_smp_target(head, target->smp_targets) {
414                 struct target *curr = head->target;
415                 if (curr == target || !target_was_examined(curr))
416                         continue;
417                 /* Need to use high level API here because every target for core contains list of watchpoints.
418                  * GDB works with active core only, so we need to duplicate every watchpoint on other cores,
419                  * otherwise watchpoint_free() on active core can fail if WP has been initially added on another core. */
420                 curr->smp = 0;
421                 res = watchpoint_add(curr, watchpoint->address, watchpoint->length,
422                         watchpoint->rw, watchpoint->value, watchpoint->mask);
423                 curr->smp = 1;
424                 if (res != ERROR_OK)
425                         return res;
426         }
427         return ERROR_OK;
428 }
429
430 int esp_xtensa_smp_watchpoint_remove(struct target *target, struct watchpoint *watchpoint)
431 {
432         int res = xtensa_watchpoint_remove(target, watchpoint);
433         if (res != ERROR_OK)
434                 return res;
435
436         if (!target->smp)
437                 return ERROR_OK;
438
439         struct target_list *head;
440         foreach_smp_target(head, target->smp_targets) {
441                 struct target *curr = head->target;
442                 if (curr == target)
443                         continue;
444                 /* see big comment in esp_xtensa_smp_watchpoint_add() */
445                 curr->smp = 0;
446                 watchpoint_remove(curr, watchpoint->address);
447                 curr->smp = 1;
448         }
449         return ERROR_OK;
450 }
451
452 int esp_xtensa_smp_init_arch_info(struct target *target,
453         struct esp_xtensa_smp_common *esp_xtensa_smp,
454         const struct xtensa_config *xtensa_cfg,
455         struct xtensa_debug_module_config *dm_cfg,
456         const struct esp_xtensa_smp_chip_ops *chip_ops)
457 {
458         int ret = esp_xtensa_init_arch_info(target, &esp_xtensa_smp->esp_xtensa, xtensa_cfg, dm_cfg);
459         if (ret != ERROR_OK)
460                 return ret;
461         esp_xtensa_smp->chip_ops = chip_ops;
462         esp_xtensa_smp->examine_other_cores = ESP_XTENSA_SMP_EXAMINE_OTHER_CORES;
463         return ERROR_OK;
464 }
465
466 int esp_xtensa_smp_target_init(struct command_context *cmd_ctx, struct target *target)
467 {
468         return esp_xtensa_target_init(cmd_ctx, target);
469 }
470
471 COMMAND_HANDLER(esp_xtensa_smp_cmd_permissive_mode)
472 {
473         struct target *target = get_current_target(CMD_CTX);
474         if (target->smp && CMD_ARGC > 0) {
475                 struct target_list *head;
476                 struct target *curr;
477                 foreach_smp_target(head, target->smp_targets) {
478                         curr = head->target;
479                         int ret = CALL_COMMAND_HANDLER(xtensa_cmd_permissive_mode_do,
480                                 target_to_xtensa(curr));
481                         if (ret != ERROR_OK)
482                                 return ret;
483                 }
484                 return ERROR_OK;
485         }
486         return CALL_COMMAND_HANDLER(xtensa_cmd_permissive_mode_do,
487                 target_to_xtensa(target));
488 }
489
490 COMMAND_HANDLER(esp_xtensa_smp_cmd_smpbreak)
491 {
492         struct target *target = get_current_target(CMD_CTX);
493         if (target->smp && CMD_ARGC > 0) {
494                 struct target_list *head;
495                 struct target *curr;
496                 foreach_smp_target(head, target->smp_targets) {
497                         curr = head->target;
498                         int ret = CALL_COMMAND_HANDLER(xtensa_cmd_smpbreak_do, curr);
499                         if (ret != ERROR_OK)
500                                 return ret;
501                 }
502                 return ERROR_OK;
503         }
504         return CALL_COMMAND_HANDLER(xtensa_cmd_smpbreak_do, target);
505 }
506
507 COMMAND_HANDLER(esp_xtensa_smp_cmd_mask_interrupts)
508 {
509         struct target *target = get_current_target(CMD_CTX);
510         if (target->smp && CMD_ARGC > 0) {
511                 struct target_list *head;
512                 struct target *curr;
513                 foreach_smp_target(head, target->smp_targets) {
514                         curr = head->target;
515                         int ret = CALL_COMMAND_HANDLER(xtensa_cmd_mask_interrupts_do,
516                                 target_to_xtensa(curr));
517                         if (ret != ERROR_OK)
518                                 return ret;
519                 }
520                 return ERROR_OK;
521         }
522         return CALL_COMMAND_HANDLER(xtensa_cmd_mask_interrupts_do,
523                 target_to_xtensa(target));
524 }
525
526 COMMAND_HANDLER(esp_xtensa_smp_cmd_perfmon_enable)
527 {
528         struct target *target = get_current_target(CMD_CTX);
529         if (target->smp && CMD_ARGC > 0) {
530                 struct target_list *head;
531                 struct target *curr;
532                 foreach_smp_target(head, target->smp_targets) {
533                         curr = head->target;
534                         int ret = CALL_COMMAND_HANDLER(xtensa_cmd_perfmon_enable_do,
535                                 target_to_xtensa(curr));
536                         if (ret != ERROR_OK)
537                                 return ret;
538                 }
539                 return ERROR_OK;
540         }
541         return CALL_COMMAND_HANDLER(xtensa_cmd_perfmon_enable_do,
542                 target_to_xtensa(target));
543 }
544
545 COMMAND_HANDLER(esp_xtensa_smp_cmd_perfmon_dump)
546 {
547         struct target *target = get_current_target(CMD_CTX);
548         if (target->smp) {
549                 struct target_list *head;
550                 struct target *curr;
551                 foreach_smp_target(head, target->smp_targets) {
552                         curr = head->target;
553                         LOG_INFO("CPU%d:", curr->coreid);
554                         int ret = CALL_COMMAND_HANDLER(xtensa_cmd_perfmon_dump_do,
555                                 target_to_xtensa(curr));
556                         if (ret != ERROR_OK)
557                                 return ret;
558                 }
559                 return ERROR_OK;
560         }
561         return CALL_COMMAND_HANDLER(xtensa_cmd_perfmon_dump_do,
562                 target_to_xtensa(target));
563 }
564
565 COMMAND_HANDLER(esp_xtensa_smp_cmd_tracestart)
566 {
567         struct target *target = get_current_target(CMD_CTX);
568         if (target->smp) {
569                 struct target_list *head;
570                 struct target *curr;
571                 foreach_smp_target(head, target->smp_targets) {
572                         curr = head->target;
573                         int ret = CALL_COMMAND_HANDLER(xtensa_cmd_tracestart_do,
574                                 target_to_xtensa(curr));
575                         if (ret != ERROR_OK)
576                                 return ret;
577                 }
578                 return ERROR_OK;
579         }
580         return CALL_COMMAND_HANDLER(xtensa_cmd_tracestart_do,
581                 target_to_xtensa(target));
582 }
583
584 COMMAND_HANDLER(esp_xtensa_smp_cmd_tracestop)
585 {
586         struct target *target = get_current_target(CMD_CTX);
587         if (target->smp) {
588                 struct target_list *head;
589                 struct target *curr;
590                 foreach_smp_target(head, target->smp_targets) {
591                         curr = head->target;
592                         int ret = CALL_COMMAND_HANDLER(xtensa_cmd_tracestop_do,
593                                 target_to_xtensa(curr));
594                         if (ret != ERROR_OK)
595                                 return ret;
596                 }
597                 return ERROR_OK;
598         }
599         return CALL_COMMAND_HANDLER(xtensa_cmd_tracestop_do,
600                 target_to_xtensa(target));
601 }
602
603 COMMAND_HANDLER(esp_xtensa_smp_cmd_tracedump)
604 {
605         struct target *target = get_current_target(CMD_CTX);
606         if (target->smp) {
607                 struct target_list *head;
608                 struct target *curr;
609                 int32_t cores_max_id = 0;
610                 /* assume that core IDs are assigned to SMP targets sequentially: 0,1,2... */
611                 foreach_smp_target(head, target->smp_targets) {
612                         curr = head->target;
613                         if (cores_max_id < curr->coreid)
614                                 cores_max_id = curr->coreid;
615                 }
616                 if (CMD_ARGC < ((uint32_t)cores_max_id + 1)) {
617                         command_print(CMD,
618                                 "Need %d filenames to dump to as output!",
619                                 cores_max_id + 1);
620                         return ERROR_FAIL;
621                 }
622                 foreach_smp_target(head, target->smp_targets) {
623                         curr = head->target;
624                         int ret = CALL_COMMAND_HANDLER(xtensa_cmd_tracedump_do,
625                                 target_to_xtensa(curr), CMD_ARGV[curr->coreid]);
626                         if (ret != ERROR_OK)
627                                 return ret;
628                 }
629                 return ERROR_OK;
630         }
631         return CALL_COMMAND_HANDLER(xtensa_cmd_tracedump_do,
632                 target_to_xtensa(target), CMD_ARGV[0]);
633 }
634
635 const struct command_registration esp_xtensa_smp_xtensa_command_handlers[] = {
636         {
637                 .name = "set_permissive",
638                 .handler = esp_xtensa_smp_cmd_permissive_mode,
639                 .mode = COMMAND_ANY,
640                 .help = "When set to 1, enable Xtensa permissive mode (less client-side checks)",
641                 .usage = "[0|1]",
642         },
643         {
644                 .name = "maskisr",
645                 .handler = esp_xtensa_smp_cmd_mask_interrupts,
646                 .mode = COMMAND_ANY,
647                 .help = "mask Xtensa interrupts at step",
648                 .usage = "['on'|'off']",
649         },
650         {
651                 .name = "smpbreak",
652                 .handler = esp_xtensa_smp_cmd_smpbreak,
653                 .mode = COMMAND_ANY,
654                 .help = "Set the way the CPU chains OCD breaks",
655                 .usage =
656                         "[none|breakinout|runstall] | [BreakIn] [BreakOut] [RunStallIn] [DebugModeOut]",
657         },
658         {
659                 .name = "perfmon_enable",
660                 .handler = esp_xtensa_smp_cmd_perfmon_enable,
661                 .mode = COMMAND_EXEC,
662                 .help = "Enable and start performance counter",
663                 .usage = "<counter_id> <select> [mask] [kernelcnt] [tracelevel]",
664         },
665         {
666                 .name = "perfmon_dump",
667                 .handler = esp_xtensa_smp_cmd_perfmon_dump,
668                 .mode = COMMAND_EXEC,
669                 .help =
670                         "Dump performance counter value. If no argument specified, dumps all counters.",
671                 .usage = "[counter_id]",
672         },
673         {
674                 .name = "tracestart",
675                 .handler = esp_xtensa_smp_cmd_tracestart,
676                 .mode = COMMAND_EXEC,
677                 .help =
678                         "Tracing: Set up and start a trace. Optionally set stop trigger address and amount of data captured after.",
679                 .usage = "[pc <pcval>/[maskbitcount]] [after <n> [ins|words]]",
680         },
681         {
682                 .name = "tracestop",
683                 .handler = esp_xtensa_smp_cmd_tracestop,
684                 .mode = COMMAND_EXEC,
685                 .help = "Tracing: Stop current trace as started by the tracestart command",
686                 .usage = "",
687         },
688         {
689                 .name = "tracedump",
690                 .handler = esp_xtensa_smp_cmd_tracedump,
691                 .mode = COMMAND_EXEC,
692                 .help = "Tracing: Dump trace memory to a files. One file per core.",
693                 .usage = "<outfile1> <outfile2>",
694         },
695         COMMAND_REGISTRATION_DONE
696 };
697
698 const struct command_registration esp_xtensa_smp_command_handlers[] = {
699         {
700                 .name = "xtensa",
701                 .usage = "",
702                 .chain = esp_xtensa_smp_xtensa_command_handlers,
703         },
704         COMMAND_REGISTRATION_DONE
705 };