Re: [PATCH 0/2] remoteproc: k3: Recover a crashed remote core

From: Chrispine Tinega

Date: Mon Nov 09 2026 - 11:22:25 EST


Hi Francesco,

On Mon, 9 Nov 2026, Francesco Valla wrote:
> If you share details on the Zephyr side of things, I can test this
> against rproc-next on a AM67A (BeagleY-AI).

Thank you, that would help. The AM67A has no M4F, so patch 2 does not
apply there. Patch 1 does: the R5F driver uses the same mailbox
callback, and it keeps recovery disabled. So on the main R5F I would
expect this:

- Without the series, the crash is only logged, and the core stays in
"running" until the next boot.
- With the series, the core moves to "crashed", the crash is counted,
and it can be stopped and started again through sysfs.

The Zephyr side is upstream's openamp_rsc_table sample with one file
added. The handler sends RP_MBOX_CRASH over the mailbox before it
halts, and a thread forces a fault 20 s after boot. This builds on
Zephyr v4.5.0 for beagley_ai/j722s/main_r5f0_0, but I have not run it
on that board.

Copy samples/subsys/ipc/openamp_rsc_table, add src/crash.c below, and
list it in CMakeLists.txt:

target_sources(app PRIVATE src/main_remote.c src/crash.c)

Build it:

west build -b beagley_ai/j722s/main_r5f0_0 path/to/the/copy

Load build/zephyr/zephyr_openamp_rsc_table.elf as the main R5F's
firmware. After 20 s, check the state:

cat /sys/class/remoteproc/remoteprocN/state
dmesg | grep -i crash

To bring the core back:

echo stop > /sys/class/remoteproc/remoteprocN/state
echo start > /sys/class/remoteproc/remoteprocN/state

It will crash again 20 s after each start. That is a quick way to check
that a second crash is handled as well.

--- src/crash.c ---
/*
* Report a fatal error to Linux as RP_MBOX_CRASH, then force one.
*/
#include <zephyr/kernel.h>
#include <zephyr/drivers/ipm.h>
#include <zephyr/fatal.h>
#include <zephyr/logging/log_ctrl.h>

#define RP_MBOX_CRASH 0xFFFFFF02U
#define CRASH_AFTER_S 20

static const struct device *const crash_ipm =
DEVICE_DT_GET(DT_CHOSEN(zephyr_ipc));

void k_sys_fatal_error_handler(unsigned int reason,
const struct arch_esf *esf)
{
uint32_t crash = RP_MBOX_CRASH;

ARG_UNUSED(reason);
ARG_UNUSED(esf);

LOG_PANIC();
/* The FIFO can be briefly full of vring kicks. */
for (int i = 0; i < 100; i++) {
if (ipm_send(crash_ipm, 0, 0, &crash, sizeof(crash)) != -EBUSY)
break;
k_busy_wait(100);
}
(void)arch_irq_lock();
for (;;)
arch_cpu_idle();
}

static void crash_thread(void *a, void *b, void *c)
{
k_sleep(K_SECONDS(CRASH_AFTER_S));
k_oops();
}

K_THREAD_DEFINE(crash_tid, 1024, crash_thread, NULL, NULL, NULL,
K_PRIO_PREEMPT(10), 0, 0);
--- end ---

Regards,
Chrispine