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 <ht@twx-software.de>
This commit is contained in:
Heinrich Toews
2026-04-09 17:26:01 +02:00
parent 63dc8ec804
commit b313b9bfec
+21 -39
View File
@@ -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;
}