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); } /*