mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-15 08:14:15 +08:00
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>
This commit is contained in:
parent
22fd6153c1
commit
ffbe08a8e8
@ -1582,6 +1582,20 @@
|
||||
dependencies. This only applies for fw_devlink=on|rpm.
|
||||
Format: <bool>
|
||||
|
||||
fw_devlink.sync_state =
|
||||
[KNL] When all devices that could probe have finished
|
||||
probing, this parameter controls what to do with
|
||||
devices that haven't yet received their sync_state()
|
||||
calls.
|
||||
Format: { strict | timeout }
|
||||
strict -- Default. Continue waiting on consumers to
|
||||
probe successfully.
|
||||
timeout -- Give up waiting on consumers and call
|
||||
sync_state() on any devices that haven't yet
|
||||
received their sync_state() calls after
|
||||
deferred_probe_timeout has expired or by
|
||||
late_initcall() if !CONFIG_MODULES.
|
||||
|
||||
gamecon.map[2|3]=
|
||||
[HW,JOY] Multisystem joystick and NES/SNES/PSX pad
|
||||
support via parallel port (up to 5 devices per port)
|
||||
|
@ -209,6 +209,7 @@ extern void device_links_no_driver(struct device *dev);
|
||||
extern bool device_links_busy(struct device *dev);
|
||||
extern void device_links_unbind_consumers(struct device *dev);
|
||||
extern void fw_devlink_drivers_done(void);
|
||||
extern void fw_devlink_probing_done(void);
|
||||
|
||||
/* device pm support */
|
||||
void device_pm_move_to_tail(struct device *dev);
|
||||
|
@ -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
|
||||
*
|
||||
|
@ -315,6 +315,8 @@ static void deferred_probe_timeout_work_func(struct work_struct *work)
|
||||
list_for_each_entry(p, &deferred_probe_pending_list, deferred_probe)
|
||||
dev_info(p->device, "deferred probe pending\n");
|
||||
mutex_unlock(&deferred_probe_mutex);
|
||||
|
||||
fw_devlink_probing_done();
|
||||
}
|
||||
static DECLARE_DELAYED_WORK(deferred_probe_timeout_work, deferred_probe_timeout_work_func);
|
||||
|
||||
@ -364,6 +366,10 @@ static int deferred_probe_initcall(void)
|
||||
schedule_delayed_work(&deferred_probe_timeout_work,
|
||||
driver_deferred_probe_timeout * HZ);
|
||||
}
|
||||
|
||||
if (!IS_ENABLED(CONFIG_MODULES))
|
||||
fw_devlink_probing_done();
|
||||
|
||||
return 0;
|
||||
}
|
||||
late_initcall(deferred_probe_initcall);
|
||||
|
Loading…
Reference in New Issue
Block a user