From 2cb30ac13dab6e604c3dca0bb02e6db581951e56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ula=C5=9F=20Sertan=20Keme=C3=A7?= Date: Sat, 19 Sep 2026 09:38:43 +0300 Subject: [PATCH] arch/arm/am67: Answer the remoteproc shutdown request in rptun. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The mailbox handler drained the FIFO without checking the message body. That caused shutdown messages to be lost, hence being unable to start/stop the R5 cores from the Linux side. The additions allow checking messages for control and virtqueue types. Shutdown messages fall to the control branch, which ACKs the shutdown request and parks the core in WFI. Virtqueues still work as intended; the only difference is that control messages are now handled correctly. Assisted-by: Claude Code:claude-opus-5 Signed-off-by: Ulaş Sertan Kemeç --- arch/arm/src/am67/am67_rptun.c | 60 +++++++++++++++++++++++++--------- 1 file changed, 45 insertions(+), 15 deletions(-) diff --git a/arch/arm/src/am67/am67_rptun.c b/arch/arm/src/am67/am67_rptun.c index ce79df863e4..39ef0173191 100644 --- a/arch/arm/src/am67/am67_rptun.c +++ b/arch/arm/src/am67/am67_rptun.c @@ -93,6 +93,17 @@ #define AM67_MBOX_USER (3U) +/* Control messages the Linux side exchanges in the mailbox payload. Any + * value outside [READY, END_MSG) is a virtqueue index instead. Values are + * from the TI kernel's drivers/remoteproc/omap_remoteproc.h; SHUTDOWN and + * SHUTDOWN_ACK are TI additions used by ti_k3_r5_remoteproc.c. + */ + +#define RP_MBOX_READY (0xffffff00ul) +#define RP_MBOX_SHUTDOWN (0xffffff14ul) +#define RP_MBOX_SHUTDOWN_ACK (0xffffff15ul) +#define RP_MBOX_END_MSG (0xffffff16ul) + /* VIM IRQ number on MAIN_R5FSS0_0 for mailbox0_cluster3/user3 */ #ifndef CONFIG_AM67_RPTUN_IRQ @@ -141,7 +152,6 @@ static const struct rptun_addrenv_s * am67_rptun_get_addrenv(struct rptun_dev_s *dev); static struct resource_table * am67_rptun_get_resource(struct rptun_dev_s *dev); -static size_t am67_rptun_get_rsc_size(struct rptun_dev_s *dev); static bool am67_rptun_is_autostart(struct rptun_dev_s *dev); static bool am67_rptun_is_master(struct rptun_dev_s *dev); static int am67_rptun_start(struct rptun_dev_s *dev); @@ -161,7 +171,6 @@ static const struct rptun_ops_s g_am67_rptun_ops = .get_firmware = am67_rptun_get_firmware, .get_addrenv = am67_rptun_get_addrenv, .get_resource = am67_rptun_get_resource, - .get_rsc_size = am67_rptun_get_rsc_size, .is_autostart = am67_rptun_is_autostart, .is_master = am67_rptun_is_master, .start = am67_rptun_start, @@ -204,16 +213,6 @@ am67_rptun_get_resource(struct rptun_dev_s *dev) return (struct resource_table *)&g_am67_rsc_table; } -static size_t am67_rptun_get_rsc_size(struct rptun_dev_s *dev) -{ - /* Return the real size of the extended resource table so that OpenAMP's - * remoteproc_set_rsc_table() can find both vdev entries (rptun.c would - * otherwise cap the visible region to sizeof(struct rptun_rsc_s)). - */ - - return sizeof(struct am67_rsc_s); -} - static bool am67_rptun_is_autostart(struct rptun_dev_s *dev) { return true; /* start rptun thread automatically */ @@ -309,14 +308,27 @@ static void am67_rptun_notify_work(void *arg) static int am67_rptun_interrupt(int irq, void *context, void *arg) { struct am67_rptun_dev_s *priv = (struct am67_rptun_dev_s *)arg; + bool shutdown = false; + bool kick = false; /* Drain all messages Linux wrote into FIFO 1. Each read pops one - * entry; stop when MSG_STATUS reports 0 pending messages. + * entry; stop when MSG_STATUS reports 0 pending messages. A single + * interrupt can carry both control messages and virtqueue kicks, so + * classify every entry rather than the batch. */ while (getreg32(AM67_MBOX_MSG_STATUS(AM67_MBOX_RX_FIFO)) != 0) { - (void)getreg32(AM67_MBOX_MESSAGE(AM67_MBOX_RX_FIFO)); + uint32_t msg = getreg32(AM67_MBOX_MESSAGE(AM67_MBOX_RX_FIFO)); + + if (msg == RP_MBOX_SHUTDOWN) + { + shutdown = true; + } + else if (msg < RP_MBOX_READY || msg >= RP_MBOX_END_MSG) + { + kick = true; + } } /* Clear the new-message interrupt status for user-3 / FIFO-1. @@ -333,8 +345,26 @@ static int am67_rptun_interrupt(int irq, void *context, void *arg) putreg32(0, AM67_MBOX_EOI); UP_DSB(); + /* Honour a shutdown request: acknowledge it, then park the core. Linux + * polls the TI-SCI WFI status for 2 ms after the ACK and only halts the + * R5F once it sees us in WFI, so this must never return. + */ + + if (shutdown) + { + putreg32(RP_MBOX_SHUTDOWN_ACK, AM67_MBOX_MESSAGE(AM67_MBOX_TX_FIFO)); + UP_DSB(); + + up_irq_save(); + + for (; ; ) + { + __asm__ __volatile__ ("wfi"); + } + } + if (priv != NULL && priv->callback != NULL && - work_available(&priv->work)) + work_available(&priv->work) && kick) { work_queue(HPWORK, &priv->work, am67_rptun_notify_work, priv, 0); }