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