summaryrefslogtreecommitdiff
path: root/drivers/base/core.c
diff options
context:
space:
mode:
authorSaravana Kannan <saravanak@google.com>2023-03-03 16:53:53 -0800
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2023-03-10 09:06:21 +0100
commitffbe08a8e86d03513dc45b5389fab7f3477433b6 (patch)
tree272e4436a7bc2e9a80539751875ce83fbaade0af /drivers/base/core.c
parent22fd6153c16a40d123d8c9936967d0a59e417129 (diff)
driver core: Add fw_devlink.sync_state command line param
When all devices that could probe have finished probing (based on deferred_probe_timeout configuration or late_initcall() when !CONFIG_MODULES), this parameter controls what to do with devices that haven't yet received their sync_state() calls. fw_devlink.sync_state=strict is the default and the driver core will continue waiting on all consumers of a device to probe successfully before sync_state() is called for the device. This is the default behavior since calling sync_state() on a device when all its consumers haven't probed could make some systems unusable/unstable. When this option is selected, we also print the list of devices that haven't had sync_state() called on them by the time all devices the could probe have finished probing. fw_devlink.sync_state=timeout will cause the driver core to give up waiting on consumers and call sync_state() on any devices that haven't yet received their sync_state() calls. This option is provided for systems that won't become unusable/unstable as they might be able to save power (depends on state of hardware before kernel starts) if all devices get their sync_state(). Signed-off-by: Saravana Kannan <saravanak@google.com> Link: https://lore.kernel.org/r/20230304005355.746421-2-saravanak@google.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/base/core.c')
-rw-r--r--drivers/base/core.c58
1 files changed, 58 insertions, 0 deletions
diff --git a/drivers/base/core.c b/drivers/base/core.c
index ba11b51ce4ee..871e6513a6c8 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -1672,6 +1672,26 @@ static int __init fw_devlink_strict_setup(char *arg)
}
early_param("fw_devlink.strict", fw_devlink_strict_setup);
+#define FW_DEVLINK_SYNC_STATE_STRICT 0
+#define FW_DEVLINK_SYNC_STATE_TIMEOUT 1
+
+static int fw_devlink_sync_state;
+static int __init fw_devlink_sync_state_setup(char *arg)
+{
+ if (!arg)
+ return -EINVAL;
+
+ if (strcmp(arg, "strict") == 0) {
+ fw_devlink_sync_state = FW_DEVLINK_SYNC_STATE_STRICT;
+ return 0;
+ } else if (strcmp(arg, "timeout") == 0) {
+ fw_devlink_sync_state = FW_DEVLINK_SYNC_STATE_TIMEOUT;
+ return 0;
+ }
+ return -EINVAL;
+}
+early_param("fw_devlink.sync_state", fw_devlink_sync_state_setup);
+
static inline u32 fw_devlink_get_flags(u8 fwlink_flags)
{
if (fwlink_flags & FWLINK_FLAG_CYCLE)
@@ -1742,6 +1762,44 @@ void fw_devlink_drivers_done(void)
device_links_write_unlock();
}
+static int fw_devlink_dev_sync_state(struct device *dev, void *data)
+{
+ struct device_link *link = to_devlink(dev);
+ struct device *sup = link->supplier;
+
+ if (!(link->flags & DL_FLAG_MANAGED) ||
+ link->status == DL_STATE_ACTIVE || sup->state_synced ||
+ !dev_has_sync_state(sup))
+ return 0;
+
+ if (fw_devlink_sync_state == FW_DEVLINK_SYNC_STATE_STRICT) {
+ dev_warn(sup, "sync_state() pending due to %s\n",
+ dev_name(link->consumer));
+ return 0;
+ }
+
+ if (!list_empty(&sup->links.defer_sync))
+ return 0;
+
+ dev_warn(sup, "Timed out. Forcing sync_state()\n");
+ sup->state_synced = true;
+ get_device(sup);
+ list_add_tail(&sup->links.defer_sync, data);
+
+ return 0;
+}
+
+void fw_devlink_probing_done(void)
+{
+ LIST_HEAD(sync_list);
+
+ device_links_write_lock();
+ class_for_each_device(&devlink_class, NULL, &sync_list,
+ fw_devlink_dev_sync_state);
+ device_links_write_unlock();
+ device_links_flush_sync_list(&sync_list, NULL);
+}
+
/**
* wait_for_init_devices_probe - Try to probe any device needed for init
*