From b313b9bfec1e95a325aed53632f87ea800c5a9d8 Mon Sep 17 00:00:00 2001 From: Heinrich Toews Date: Thu, 9 Apr 2026 17:26:01 +0200 Subject: [PATCH] leds: wago-m4: eliminate boot delay by polling rproc with short interval The previous approach tried to peek at the rproc state in probe() to decide whether to use delay=0 (SPL path) or 5000ms (Linux-boot path). This did not work because the remoteproc subsystem registers the rproc device ~140ms after the LED driver probes, so rproc_get_by_phandle() always returned NULL at probe() time and the 5000ms delay was always used. New approach: - Schedule boot_work with delay=0 unconditionally from probe(). - Reduce WAGO_BOOT_RETRY_MS from 2000ms to 200ms so the rproc handle is found within one retry after it becomes available (~200ms total). - Increase WAGO_BOOT_MAX_RETRIES from 30 to 150 to keep the same total worst-case timeout (150 x 200ms = 30s for rproc polling). - For the Linux-boot path (-ENOENT, firmware file not found), switch directly to WAGO_BOOT_INITIAL_DELAY_MS (5000ms) per retry instead of the short rproc-poll interval to avoid hammering the filesystem. Expected boot timeline (SPL path): [0.797] probe() -> boot_work scheduled, delay=0 [0.797] boot_work #1 -> rproc not yet available, retry in 200ms [0.997] boot_work #2 -> rproc DETACHED, attach immediately [~1.0 ] RPMsg channel up -> LED strip active Signed-off-by: Heinrich Toews --- drivers/leds/rgb/wago-m4-led-wrapper.c | 60 +++++++++----------------- 1 file changed, 21 insertions(+), 39 deletions(-) diff --git a/drivers/leds/rgb/wago-m4-led-wrapper.c b/drivers/leds/rgb/wago-m4-led-wrapper.c index 29263035c619..3ba941882e74 100644 --- a/drivers/leds/rgb/wago-m4-led-wrapper.c +++ b/drivers/leds/rgb/wago-m4-led-wrapper.c @@ -108,12 +108,14 @@ /* Maximum ASCII command length for sysfs passthrough */ #define WAGO_CMD_MAX_LEN 32 -/* First boot attempt this many ms after probe() */ +/* First boot attempt this many ms after probe() — Linux-boot path only, + * gives the rootfs time to mount before loading firmware from /lib/firmware. + * Not used in the SPL path (M4 already running). */ #define WAGO_BOOT_INITIAL_DELAY_MS 5000 -/* Retry interval when filesystem is not yet available */ -#define WAGO_BOOT_RETRY_MS 2000 +/* Retry interval when rproc is not yet registered or firmware not found */ +#define WAGO_BOOT_RETRY_MS 200 /* Maximum number of boot attempts before giving up */ -#define WAGO_BOOT_MAX_RETRIES 30 +#define WAGO_BOOT_MAX_RETRIES 150 /* * vring TX ring retry policy for rpmsg_trysend(). @@ -716,12 +718,14 @@ static void wago_boot_work(struct work_struct *work) /* * -ENOENT: firmware file not found — rootfs not yet mounted. - * Retry after a short delay. + * Switch to the longer retry interval for filesystem polling. */ if (ret == -ENOENT) { dev_dbg(dev, "Firmware not found yet, retrying in %d ms\n", - WAGO_BOOT_RETRY_MS); - goto retry; + WAGO_BOOT_INITIAL_DELAY_MS); + schedule_delayed_work(&priv->boot_work, + msecs_to_jiffies(WAGO_BOOT_INITIAL_DELAY_MS)); + return; } dev_err(dev, "rproc_boot failed: %d\n", ret); @@ -768,9 +772,7 @@ static void wago_rproc_stop(struct wago_m4_led_priv *priv) static int wago_m4_led_probe(struct platform_device *pdev) { struct wago_m4_led_priv *priv; - struct device_node *rproc_np; const char *fw_name; - unsigned long boot_delay_ms; int ret; priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); @@ -822,41 +824,21 @@ static int wago_m4_led_probe(struct platform_device *pdev) #endif /* CONFIG_LEDS_WAGO_M4_WRAPPER_SYSFS_PASSTHROUGH */ /* - * Determine boot delay: + * Schedule boot_work immediately (delay=0). * - * If the rproc is already available and in RPROC_DETACHED state - * (U-Boot / SPL loaded the firmware), schedule boot_work immediately - * so the RPMsg channel comes up as fast as possible. - * - * Otherwise use WAGO_BOOT_INITIAL_DELAY_MS to give the rootfs time - * to mount before we try to load the firmware file. + * boot_work polls for the rproc handle with WAGO_BOOT_RETRY_MS + * intervals (200 ms). Once the rproc is registered by the remoteproc + * subsystem it checks the state: + * RPROC_DETACHED -> attach right away (SPL path, ~1 retry needed) + * otherwise -> load firmware from /lib/firmware (Linux-boot path, + * retries until rootfs is mounted) */ - boot_delay_ms = WAGO_BOOT_INITIAL_DELAY_MS; - rproc_np = of_parse_phandle(pdev->dev.of_node, "remoteproc", 0); - if (rproc_np) { - struct rproc *rp = rproc_get_by_phandle(rproc_np->phandle); - - of_node_put(rproc_np); - if (!IS_ERR_OR_NULL(rp)) { - if (rp->state == RPROC_DETACHED) { - boot_delay_ms = 0; - dev_info(&pdev->dev, - "M4 already running (SPL path), " - "attaching immediately\n"); - } - /* rproc_boot_work will re-acquire it lazily */ - rproc_put(rp); - } - } - INIT_DELAYED_WORK(&priv->boot_work, wago_boot_work); - schedule_delayed_work(&priv->boot_work, - msecs_to_jiffies(boot_delay_ms)); + schedule_delayed_work(&priv->boot_work, 0); dev_info(&pdev->dev, - "WAGO M4 LED wrapper probed, %d LEDs active, " - "RPMsg attach in %lu ms\n", - WAGO_LED_NUM_LEDS, boot_delay_ms); + "WAGO M4 LED wrapper probed, %d LEDs active\n", + WAGO_LED_NUM_LEDS); return 0; }