From a88b6de53fdb0a889189e41fb6930168cc70e91c Mon Sep 17 00:00:00 2001 From: Heinrich Toews Date: Thu, 2 Apr 2026 14:57:08 +0200 Subject: [PATCH] leds: rgb: wago-m4-led-wrapper: fix priv lookup in rpmsg probe The rpmsg probe callback attempted to retrieve the driver private data by walking three levels up the device parent chain, but never actually stored the pointer on rproc->dev before rproc_boot() triggered the virtio/RPMsg stack. This caused a NULL dereference and -ENODEV on every probe attempt. Fix this by explicitly calling dev_set_drvdata(&priv->rproc->dev, priv) in wago_boot_work() after the rproc handle is obtained and before rproc_boot() is called, ensuring the pointer is visible to wago_rpmsg_probe(). Additionally, make the parent chain walk more robust by falling back one extra level (rproc->dev.parent) when the three-level lookup returns NULL. This handles kernel versions where the ti_k3_m4 platform device inserts an extra level in the hierarchy: rpdev->dev rpmsg device .parent virtio_device .parent rproc_vdev pdev .parent rproc->dev <- primary lookup .parent <- fallback lookup The comment block in wago_rpmsg_probe() is also updated to accurately describe the device topology and the point at which dev_set_drvdata is called. Signed-off-by: Heinrich Toews --- drivers/leds/rgb/wago-m4-led-wrapper.c | 35 +++++++++++++++++++++----- 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/drivers/leds/rgb/wago-m4-led-wrapper.c b/drivers/leds/rgb/wago-m4-led-wrapper.c index 02ae852d05da..7334e6204d76 100644 --- a/drivers/leds/rgb/wago-m4-led-wrapper.c +++ b/drivers/leds/rgb/wago-m4-led-wrapper.c @@ -312,18 +312,33 @@ static int wago_led_register_leds(struct wago_m4_led_priv *priv) static int wago_rpmsg_probe(struct rpmsg_device *rpdev) { /* - * Retrieve our private data. The platform driver stored it in the - * rproc device; walk up the parent chain to find it. + * Walk up the device parent chain to find our priv pointer. * - * rpmsg device -> virtio device -> rproc vdev -> rproc device - * ^ platform_set_drvdata + * The chain built by the remoteproc / virtio stack is: + * + * rpdev->dev rpmsg device (this device) + * .parent virtio_device (vrp->vdev) + * .parent rproc_vdev platform_device (rvdev->pdev) + * .parent rproc->dev <- dev_set_drvdata set here + * + * We set dev_set_drvdata on rproc->dev in wago_boot_work() as soon + * as we obtained the rproc handle, so three levels up is correct. */ struct device *rproc_dev = rpdev->dev.parent->parent->parent; - struct wago_m4_led_priv *priv = dev_get_drvdata(rproc_dev); + struct wago_m4_led_priv *priv; int ret; + /* Try three levels up first, then four (rproc->dev.parent layout + * may differ across kernel versions). */ + priv = dev_get_drvdata(rproc_dev); if (!priv) { - dev_err(&rpdev->dev, "No driver private data found\n"); + /* One more level up: rproc->dev.parent = ti_k3_m4 pdev */ + priv = dev_get_drvdata(rproc_dev->parent); + } + + if (!priv) { + dev_err(&rpdev->dev, + "No driver private data found in parent chain\n"); return -ENODEV; } @@ -406,6 +421,14 @@ static void wago_boot_work(struct work_struct *work) dev_warn(dev, "rproc not yet available, retrying...\n"); goto retry; } + + /* + * Store priv on the rproc device so wago_rpmsg_probe() can + * retrieve it by walking up the parent chain from the rpmsg + * device. This must be done before rproc_boot() triggers the + * virtio / RPMsg stack. + */ + dev_set_drvdata(&priv->rproc->dev, priv); } /*