Linux kernel and device drivers for NXP i.MX platforms
 help / color / mirror / Atom feed
* [PATCH v5 REPOST] remoteproc: imx_rproc: Invoke the callback directly
@ 2026-07-21 14:09 Sebastian Andrzej Siewior
  2026-07-21 14:29 ` sashiko-bot
  2026-07-21 15:14 ` Mathieu Poirier
  0 siblings, 2 replies; 3+ messages in thread
From: Sebastian Andrzej Siewior @ 2026-07-21 14:09 UTC (permalink / raw)
  To: imx, linux-arm-kernel, linux-remoteproc, linux-rt-devel
  Cc: Bjorn Andersson, Clark Williams, Fabio Estevam, Frank Li,
	Jassi Brar, Mathieu Poirier, Pengutronix Kernel Team,
	Sascha Hauer, Steven Rostedt, Peng Fan, Sebastian Andrzej Siewior

The imx-mailbox driver moved the callback invocation into the threaded
IRQ handler. This means the callback is invoked in preemptible context
and there is no need to schedule the kworker for the
imx_rproc_notified_idr_cb() invocation.

This was tested with the rpmsg-tty driver on imx93.

Remove the workqueue handling and invoke the imx_rproc_notified_idr_cb()
callback directly.

Reviewed-by: Peng Fan <peng.fan@nxp.com>
Reviewed-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
This change was tested on a im93 board with rpmsg-tty driver.

v4…v5: https://lore.kernel.org/all/20260703-imx_mbox_rproc-v4-1-67b10560a861@linutronix.de/
  - Repost

v3…v4: https://lore.kernel.org/r/20260617-imx_mbox_rproc-v3-0-77948112defc@linutronix.de
  - The mailbox bits are part of v7.2-rc1. This is just a repost of the
    imx_rproc driver which is left.
   
v2…v3: https://lore.kernel.org/r/20260603-imx_mbox_rproc-v2-0-a0059dc3b69a@linutronix.de
  - Forward the error in imx_mu_generic_tx() to the caller (new patch
    #1)
  - Extend the patch description a bit for for "Start splitting the IRQ
    handler" to briefly explain why callbacks are moved to the threaded
    handler.
  - Drop imx_mu_con_priv::pending. The primary handler wakes its
    threaded handler. Once the handler is woken, the pending flag must
    be set and there is no need to set/ clear it.
  - Avoid the double clk_disable_unprepare() if
    devm_mbox_controller_register() fails.

v1…v2: https://lore.kernel.org/r/20260529-imx_mbox_rproc-v1-0-b8ffc36e11e5@linutronix.de
  - Using correct register to enable RXDB event.
  - Update commit description for the "threaded interrupt", "unmasks the
    interrupt" => "masks the interrupt event".
  - Add a shutdown field so that the interrupt does not unmask the
    interrupt if it has been already disabled because the channel is
    about to be shutdown.  A possible race mentioned by sashiko.
  - Use devm_pm_runtime_enable(). This should avoid a possible race
    sashiko mentioned.
  - Use devm_of_platform_populate().
---
 drivers/remoteproc/imx_rproc.c | 33 +--------------------------------
 1 file changed, 1 insertion(+), 32 deletions(-)

diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
index 7662ebd9d2f49..e18ae33a5cf85 100644
--- a/drivers/remoteproc/imx_rproc.c
+++ b/drivers/remoteproc/imx_rproc.c
@@ -24,7 +24,6 @@
 #include <linux/regmap.h>
 #include <linux/remoteproc.h>
 #include <linux/scmi_imx_protocol.h>
-#include <linux/workqueue.h>
 
 #include "imx_rproc.h"
 #include "remoteproc_internal.h"
@@ -115,8 +114,6 @@ struct imx_rproc {
 	struct mbox_client		cl;
 	struct mbox_chan		*tx_ch;
 	struct mbox_chan		*rx_ch;
-	struct work_struct		rproc_work;
-	struct workqueue_struct		*workqueue;
 	void __iomem			*rsc_table;
 	struct imx_sc_ipc		*ipc_handle;
 	struct notifier_block		rproc_nb;
@@ -892,21 +889,11 @@ static int imx_rproc_notified_idr_cb(int id, void *ptr, void *data)
 	return 0;
 }
 
-static void imx_rproc_vq_work(struct work_struct *work)
-{
-	struct imx_rproc *priv = container_of(work, struct imx_rproc,
-					      rproc_work);
-	struct rproc *rproc = priv->rproc;
-
-	idr_for_each(&rproc->notifyids, imx_rproc_notified_idr_cb, rproc);
-}
-
 static void imx_rproc_rx_callback(struct mbox_client *cl, void *msg)
 {
 	struct rproc *rproc = dev_get_drvdata(cl->dev);
-	struct imx_rproc *priv = rproc->priv;
 
-	queue_work(priv->workqueue, &priv->rproc_work);
+	idr_for_each(&rproc->notifyids, imx_rproc_notified_idr_cb, rproc);
 }
 
 static int imx_rproc_xtr_mbox_init(struct rproc *rproc, bool tx_block)
@@ -1271,13 +1258,6 @@ static int imx_rproc_sys_off_handler(struct sys_off_data *data)
 	return NOTIFY_DONE;
 }
 
-static void imx_rproc_destroy_workqueue(void *data)
-{
-	struct workqueue_struct *workqueue = data;
-
-	destroy_workqueue(workqueue);
-}
-
 static int imx_rproc_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
@@ -1305,17 +1285,6 @@ static int imx_rproc_probe(struct platform_device *pdev)
 		priv->ops = dcfg->ops;
 
 	dev_set_drvdata(dev, rproc);
-	priv->workqueue = create_workqueue(dev_name(dev));
-	if (!priv->workqueue) {
-		dev_err(dev, "cannot create workqueue\n");
-		return -ENOMEM;
-	}
-
-	ret = devm_add_action_or_reset(dev, imx_rproc_destroy_workqueue, priv->workqueue);
-	if (ret)
-		return dev_err_probe(dev, ret, "Failed to add devm destroy workqueue action\n");
-
-	INIT_WORK(&priv->rproc_work, imx_rproc_vq_work);
 
 	ret = imx_rproc_xtr_mbox_init(rproc, true);
 	if (ret)

---
base-commit: b3f94b2b3f3e51ab880a51fc6510e1dafba654ed
change-id: 20260529-imx_mbox_rproc-7d512f5a6f78

Best regards,
-- 
Sebastian Andrzej Siewior <bigeasy@linutronix.de>

^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH v5 REPOST] remoteproc: imx_rproc: Invoke the callback directly
  2026-07-21 14:09 [PATCH v5 REPOST] remoteproc: imx_rproc: Invoke the callback directly Sebastian Andrzej Siewior
@ 2026-07-21 14:29 ` sashiko-bot
  2026-07-21 15:14 ` Mathieu Poirier
  1 sibling, 0 replies; 3+ messages in thread
From: sashiko-bot @ 2026-07-21 14:29 UTC (permalink / raw)
  To: Sebastian Andrzej Siewior; +Cc: linux-kernel, linux-rt-devel, imx, Frank.Li

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:

Pre-existing issues:
- [High] This problem wasn't introduced by this patch, but the IDR iteration via `idr_for_each()` in `imx_rproc_rx_callback()` is performed without holding the RCU read lock in a preemptible context, potentially leading to a use-after-free.
- [High] This problem wasn't introduced by this patch, but the mailbox channel is leaked on the `imx_rproc_start` error path, allowing concurrent mailbox callbacks during resource cleanup and causing a Use-After-Free of `rvring`.
--

--- Patch [1]: [PATCH v5 REPOST] remoteproc: imx_rproc: Invoke the callback directly ---
commit 861718f5edd7547335536b279e55e3c8605a7454
Author: Sebastian Andrzej Siewior <bigeasy@linutronix.de>

remoteproc: imx_rproc: Invoke the callback directly

This commit removes the workqueue handling in the imx_rproc driver and invokes
the imx_rproc_notified_idr_cb callback directly from the mailbox RX callback.
This change is possible because the imx-mailbox driver moved the callback
invocation into the threaded IRQ handler, which runs in a preemptible context.

Link: https://lore.kernel.org/all/20260703-imx_mbox_rproc-v4-1-67b10560a861@linutronix.de/

> diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
> --- a/drivers/remoteproc/imx_rproc.c
> +++ b/drivers/remoteproc/imx_rproc.c

[ ... ]

> @@ -860,21 +857,11 @@ static int imx_rproc_notified_idr_cb(int id, void *ptr, void *data)
>  	return 0;
>  }
>  
> -static void imx_rproc_vq_work(struct work_struct *work)
> -{
> -	struct imx_rproc *priv = container_of(work, struct imx_rproc,
> -					      rproc_work);
> -	struct rproc *rproc = priv->rproc;
> -
> -	idr_for_each(&rproc->notifyids, imx_rproc_notified_idr_cb, rproc);
> -}
> -
>  static void imx_rproc_rx_callback(struct mbox_client *cl, void *msg)
>  {
>  	struct rproc *rproc = dev_get_drvdata(cl->dev);
> -	struct imx_rproc *priv = rproc->priv;
>  
> -	queue_work(priv->workqueue, &priv->rproc_work);
> +	idr_for_each(&rproc->notifyids, imx_rproc_notified_idr_cb, rproc);

[Severity: High]
This isn't a bug introduced by this patch, but since we are now relying
on the threaded IRQ handler's preemptible context instead of the workqueue,
is it safe to call idr_for_each() here without holding the RCU read lock?

According to the IDR API rules, concurrent modifications to the IDR require
readers to hold the RCU read lock. If preemption occurs during this
traversal and a concurrent IDR removal happens (e.g., during driver
teardown), could this allow RCU grace periods to complete prematurely
and result in a use-after-free when dereferencing freed radix tree nodes?

>  }

[ ... ]

Also, while reviewing the driver's mailbox handling, I noticed another
pre-existing issue in a different part of the file:

drivers/remoteproc/imx_rproc.c:imx_rproc_start() {
    ...
    ret = priv->ops->start(rproc);
    if (ret)
        dev_err(dev, "Failed to enable remote core!\n");

    return ret;
}

[Severity: High]
This isn't a bug introduced by this patch, but does the error path in
imx_rproc_start() leak the mailbox channel?

If priv->ops->start(rproc) fails, the function returns an error without
calling imx_rproc_free_mbox(). The remoteproc core then handles the start
failure by skipping rproc->ops->stop() and directly unwinding via
rproc_resource_cleanup(). 

Since this unregisters the virtio devices, causing rvdev to be freed via
devm_kzalloc devres cleanup, could a spurious or delayed interrupt trigger
imx_rproc_rx_callback() concurrently with or after the cleanup? That would
allow the callback to access rproc->notifyids, retrieve the freed rvring,
and dereference it, leading to a use-after-free.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260721-imx_mbox_rproc-v5-1-6386a2cf8524@linutronix.de?part=1

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH v5 REPOST] remoteproc: imx_rproc: Invoke the callback directly
  2026-07-21 14:09 [PATCH v5 REPOST] remoteproc: imx_rproc: Invoke the callback directly Sebastian Andrzej Siewior
  2026-07-21 14:29 ` sashiko-bot
@ 2026-07-21 15:14 ` Mathieu Poirier
  1 sibling, 0 replies; 3+ messages in thread
From: Mathieu Poirier @ 2026-07-21 15:14 UTC (permalink / raw)
  To: Sebastian Andrzej Siewior
  Cc: imx, linux-arm-kernel, linux-remoteproc, linux-rt-devel,
	Bjorn Andersson, Clark Williams, Fabio Estevam, Frank Li,
	Jassi Brar, Pengutronix Kernel Team, Sascha Hauer, Steven Rostedt,
	Peng Fan

On Tue, Jul 21, 2026 at 04:09:06PM +0200, Sebastian Andrzej Siewior wrote:
> The imx-mailbox driver moved the callback invocation into the threaded
> IRQ handler. This means the callback is invoked in preemptible context
> and there is no need to schedule the kworker for the
> imx_rproc_notified_idr_cb() invocation.
> 
> This was tested with the rpmsg-tty driver on imx93.
> 
> Remove the workqueue handling and invoke the imx_rproc_notified_idr_cb()
> callback directly.
> 
> Reviewed-by: Peng Fan <peng.fan@nxp.com>
> Reviewed-by: Mathieu Poirier <mathieu.poirier@linaro.org>
> Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>

Jassi - can you pick this up?

> ---
> This change was tested on a im93 board with rpmsg-tty driver.
> 
> v4…v5: https://lore.kernel.org/all/20260703-imx_mbox_rproc-v4-1-67b10560a861@linutronix.de/
>   - Repost
>
> v3…v4: https://lore.kernel.org/r/20260617-imx_mbox_rproc-v3-0-77948112defc@linutronix.de
>   - The mailbox bits are part of v7.2-rc1. This is just a repost of the
>     imx_rproc driver which is left.
>    
> v2…v3: https://lore.kernel.org/r/20260603-imx_mbox_rproc-v2-0-a0059dc3b69a@linutronix.de
>   - Forward the error in imx_mu_generic_tx() to the caller (new patch
>     #1)
>   - Extend the patch description a bit for for "Start splitting the IRQ
>     handler" to briefly explain why callbacks are moved to the threaded
>     handler.
>   - Drop imx_mu_con_priv::pending. The primary handler wakes its
>     threaded handler. Once the handler is woken, the pending flag must
>     be set and there is no need to set/ clear it.
>   - Avoid the double clk_disable_unprepare() if
>     devm_mbox_controller_register() fails.
> 
> v1…v2: https://lore.kernel.org/r/20260529-imx_mbox_rproc-v1-0-b8ffc36e11e5@linutronix.de
>   - Using correct register to enable RXDB event.
>   - Update commit description for the "threaded interrupt", "unmasks the
>     interrupt" => "masks the interrupt event".
>   - Add a shutdown field so that the interrupt does not unmask the
>     interrupt if it has been already disabled because the channel is
>     about to be shutdown.  A possible race mentioned by sashiko.
>   - Use devm_pm_runtime_enable(). This should avoid a possible race
>     sashiko mentioned.
>   - Use devm_of_platform_populate().
> ---
>  drivers/remoteproc/imx_rproc.c | 33 +--------------------------------
>  1 file changed, 1 insertion(+), 32 deletions(-)
> 
> diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
> index 7662ebd9d2f49..e18ae33a5cf85 100644
> --- a/drivers/remoteproc/imx_rproc.c
> +++ b/drivers/remoteproc/imx_rproc.c
> @@ -24,7 +24,6 @@
>  #include <linux/regmap.h>
>  #include <linux/remoteproc.h>
>  #include <linux/scmi_imx_protocol.h>
> -#include <linux/workqueue.h>
>  
>  #include "imx_rproc.h"
>  #include "remoteproc_internal.h"
> @@ -115,8 +114,6 @@ struct imx_rproc {
>  	struct mbox_client		cl;
>  	struct mbox_chan		*tx_ch;
>  	struct mbox_chan		*rx_ch;
> -	struct work_struct		rproc_work;
> -	struct workqueue_struct		*workqueue;
>  	void __iomem			*rsc_table;
>  	struct imx_sc_ipc		*ipc_handle;
>  	struct notifier_block		rproc_nb;
> @@ -892,21 +889,11 @@ static int imx_rproc_notified_idr_cb(int id, void *ptr, void *data)
>  	return 0;
>  }
>  
> -static void imx_rproc_vq_work(struct work_struct *work)
> -{
> -	struct imx_rproc *priv = container_of(work, struct imx_rproc,
> -					      rproc_work);
> -	struct rproc *rproc = priv->rproc;
> -
> -	idr_for_each(&rproc->notifyids, imx_rproc_notified_idr_cb, rproc);
> -}
> -
>  static void imx_rproc_rx_callback(struct mbox_client *cl, void *msg)
>  {
>  	struct rproc *rproc = dev_get_drvdata(cl->dev);
> -	struct imx_rproc *priv = rproc->priv;
>  
> -	queue_work(priv->workqueue, &priv->rproc_work);
> +	idr_for_each(&rproc->notifyids, imx_rproc_notified_idr_cb, rproc);
>  }
>  
>  static int imx_rproc_xtr_mbox_init(struct rproc *rproc, bool tx_block)
> @@ -1271,13 +1258,6 @@ static int imx_rproc_sys_off_handler(struct sys_off_data *data)
>  	return NOTIFY_DONE;
>  }
>  
> -static void imx_rproc_destroy_workqueue(void *data)
> -{
> -	struct workqueue_struct *workqueue = data;
> -
> -	destroy_workqueue(workqueue);
> -}
> -
>  static int imx_rproc_probe(struct platform_device *pdev)
>  {
>  	struct device *dev = &pdev->dev;
> @@ -1305,17 +1285,6 @@ static int imx_rproc_probe(struct platform_device *pdev)
>  		priv->ops = dcfg->ops;
>  
>  	dev_set_drvdata(dev, rproc);
> -	priv->workqueue = create_workqueue(dev_name(dev));
> -	if (!priv->workqueue) {
> -		dev_err(dev, "cannot create workqueue\n");
> -		return -ENOMEM;
> -	}
> -
> -	ret = devm_add_action_or_reset(dev, imx_rproc_destroy_workqueue, priv->workqueue);
> -	if (ret)
> -		return dev_err_probe(dev, ret, "Failed to add devm destroy workqueue action\n");
> -
> -	INIT_WORK(&priv->rproc_work, imx_rproc_vq_work);
>  
>  	ret = imx_rproc_xtr_mbox_init(rproc, true);
>  	if (ret)
> 
> ---
> base-commit: b3f94b2b3f3e51ab880a51fc6510e1dafba654ed
> change-id: 20260529-imx_mbox_rproc-7d512f5a6f78
> 
> Best regards,
> -- 
> Sebastian Andrzej Siewior <bigeasy@linutronix.de>

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-07-21 15:14 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-21 14:09 [PATCH v5 REPOST] remoteproc: imx_rproc: Invoke the callback directly Sebastian Andrzej Siewior
2026-07-21 14:29 ` sashiko-bot
2026-07-21 15:14 ` Mathieu Poirier

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox