summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/ABI/testing/sysfs-devices-state_synced24
-rw-r--r--drivers/base/dd.c22
2 files changed, 46 insertions, 0 deletions
diff --git a/Documentation/ABI/testing/sysfs-devices-state_synced b/Documentation/ABI/testing/sysfs-devices-state_synced
new file mode 100644
index 000000000000..0c922d7d02fc
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-devices-state_synced
@@ -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.
+
+
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index 2aef1e4ce60a..a0b9ff5220cf 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -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)