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
|
@ -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();
|
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)
|
static int really_probe(struct device *dev, struct device_driver *drv)
|
||||||
{
|
{
|
||||||
int ret = -EPROBE_DEFER;
|
int ret = -EPROBE_DEFER;
|
||||||
|
@ -535,9 +547,16 @@ re_probe:
|
||||||
goto dev_groups_failed;
|
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) {
|
if (test_remove) {
|
||||||
test_remove = false;
|
test_remove = false;
|
||||||
|
|
||||||
|
device_remove_file(dev, &dev_attr_state_synced);
|
||||||
device_remove_groups(dev, drv->dev_groups);
|
device_remove_groups(dev, drv->dev_groups);
|
||||||
|
|
||||||
if (dev->bus->remove)
|
if (dev->bus->remove)
|
||||||
|
@ -567,6 +586,8 @@ re_probe:
|
||||||
drv->bus->name, __func__, dev_name(dev), drv->name);
|
drv->bus->name, __func__, dev_name(dev), drv->name);
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
|
dev_sysfs_state_synced_failed:
|
||||||
|
device_remove_groups(dev, drv->dev_groups);
|
||||||
dev_groups_failed:
|
dev_groups_failed:
|
||||||
if (dev->bus->remove)
|
if (dev->bus->remove)
|
||||||
dev->bus->remove(dev);
|
dev->bus->remove(dev);
|
||||||
|
@ -1104,6 +1125,7 @@ static void __device_release_driver(struct device *dev, struct device *parent)
|
||||||
|
|
||||||
pm_runtime_put_sync(dev);
|
pm_runtime_put_sync(dev);
|
||||||
|
|
||||||
|
device_remove_file(dev, &dev_attr_state_synced);
|
||||||
device_remove_groups(dev, drv->dev_groups);
|
device_remove_groups(dev, drv->dev_groups);
|
||||||
|
|
||||||
if (dev->bus && dev->bus->remove)
|
if (dev->bus && dev->bus->remove)
|
||||||
|
|
Loading…
Reference in New Issue