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 <ht@twx-software.de>
This commit is contained in:
Heinrich Toews
2026-04-02 14:57:08 +02:00
parent d8ed3da3de
commit a88b6de53f
+29 -6
View File
@@ -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);
}
/*