forked from Minki/linux
driver core: Add state_synced sysfs file for devices that support it
This can be used to check if a device supports sync_state() callbacks and therefore keeps resources left on by the bootloader enabled till all its consumers have probed. This can also be used to check if sync_state() has been called for a device or whether it is still trying to keep resources enabled because they were left enabled by the bootloader and all its consumers haven't probed yet. Signed-off-by: Saravana Kannan <saravanak@google.com> Link: https://lore.kernel.org/r/20200521191800.136035-3-saravanak@google.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
287905e68d
commit
8fd456ec0c
24
Documentation/ABI/testing/sysfs-devices-state_synced
Normal file
24
Documentation/ABI/testing/sysfs-devices-state_synced
Normal file
@ -0,0 +1,24 @@
|
||||
What: /sys/devices/.../state_synced
|
||||
Date: May 2020
|
||||
Contact: Saravana Kannan <saravanak@google.com>
|
||||
Description:
|
||||
The /sys/devices/.../state_synced attribute is only present for
|
||||
devices whose bus types or driver provides the .sync_state()
|
||||
callback. The number read from it (0 or 1) reflects the value
|
||||
of the device's 'state_synced' field. A value of 0 means the
|
||||
.sync_state() callback hasn't been called yet. A value of 1
|
||||
means the .sync_state() callback has been called.
|
||||
|
||||
Generally, if a device has sync_state() support and has some of
|
||||
the resources it provides enabled at the time the kernel starts
|
||||
(Eg: enabled by hardware reset or bootloader or anything that
|
||||
run before the kernel starts), then it'll keep those resources
|
||||
enabled and in a state that's compatible with the state they
|
||||
were in at the start of the kernel. The device will stop doing
|
||||
this only when the sync_state() callback has been called --
|
||||
which happens only when all its consumer devices are registered
|
||||
and have probed successfully. Resources that were left disabled
|
||||
at the time the kernel starts are not affected or limited in
|
||||
any way by sync_state() callbacks.
|
||||
|
||||
|
@ -462,6 +462,18 @@ static void driver_deferred_probe_add_trigger(struct device *dev,
|
||||
driver_deferred_probe_trigger();
|
||||
}
|
||||
|
||||
static ssize_t state_synced_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
bool val;
|
||||
|
||||
device_lock(dev);
|
||||
val = dev->state_synced;
|
||||
device_unlock(dev);
|
||||
return sprintf(buf, "%u\n", val);
|
||||
}
|
||||
static DEVICE_ATTR_RO(state_synced);
|
||||
|
||||
static int really_probe(struct device *dev, struct device_driver *drv)
|
||||
{
|
||||
int ret = -EPROBE_DEFER;
|
||||
@ -535,9 +547,16 @@ re_probe:
|
||||
goto dev_groups_failed;
|
||||
}
|
||||
|
||||
if (dev_has_sync_state(dev) &&
|
||||
device_create_file(dev, &dev_attr_state_synced)) {
|
||||
dev_err(dev, "state_synced sysfs add failed\n");
|
||||
goto dev_sysfs_state_synced_failed;
|
||||
}
|
||||
|
||||
if (test_remove) {
|
||||
test_remove = false;
|
||||
|
||||
device_remove_file(dev, &dev_attr_state_synced);
|
||||
device_remove_groups(dev, drv->dev_groups);
|
||||
|
||||
if (dev->bus->remove)
|
||||
@ -567,6 +586,8 @@ re_probe:
|
||||
drv->bus->name, __func__, dev_name(dev), drv->name);
|
||||
goto done;
|
||||
|
||||
dev_sysfs_state_synced_failed:
|
||||
device_remove_groups(dev, drv->dev_groups);
|
||||
dev_groups_failed:
|
||||
if (dev->bus->remove)
|
||||
dev->bus->remove(dev);
|
||||
@ -1104,6 +1125,7 @@ static void __device_release_driver(struct device *dev, struct device *parent)
|
||||
|
||||
pm_runtime_put_sync(dev);
|
||||
|
||||
device_remove_file(dev, &dev_attr_state_synced);
|
||||
device_remove_groups(dev, drv->dev_groups);
|
||||
|
||||
if (dev->bus && dev->bus->remove)
|
||||
|
Loading…
Reference in New Issue
Block a user