PM / wakeup: Register wakeup class kobj after device is added
The device_set_wakeup_enable() function can be called on a device that hasn't been registered with device_add() yet. This allows the device to be in a state where wakeup is enabled for it but the device isn't published to userspace in sysfs yet. After commitc8377adfa7
("PM / wakeup: Show wakeup sources stats in sysfs"), calling device_set_wakeup_enable() will fail for a device that hasn't been registered with the driver core via device_add(). This is because we try to create sysfs entries for the device and associate a wakeup class kobject with it before the device has been registered. Let's follow a similar approach that device_set_wakeup_capable() takes here and register the wakeup class either from device_set_wakeup_enable() when the device is already registered, or from dpm_sysfs_add() when the device is being registered with the driver core via device_add(). Fixes:c8377adfa7
("PM / wakeup: Show wakeup sources stats in sysfs") Reported-by: Qian Cai <cai@lca.pw> Reviewed-by: Tri Vo <trong@android.com> Signed-off-by: Stephen Boyd <swboyd@chromium.org> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
This commit is contained in:
parent
ae367b7936
commit
2ca3d1ecb8
|
@ -157,4 +157,13 @@ extern int wakeup_source_sysfs_add(struct device *parent,
|
|||
struct wakeup_source *ws);
|
||||
extern void wakeup_source_sysfs_remove(struct wakeup_source *ws);
|
||||
|
||||
extern int pm_wakeup_source_sysfs_add(struct device *parent);
|
||||
|
||||
#else /* !CONFIG_PM_SLEEP */
|
||||
|
||||
static inline int pm_wakeup_source_sysfs_add(struct device *parent)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <linux/export.h>
|
||||
#include <linux/pm_qos.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/pm_wakeup.h>
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include "power.h"
|
||||
|
@ -667,8 +668,13 @@ int dpm_sysfs_add(struct device *dev)
|
|||
if (rc)
|
||||
goto err_wakeup;
|
||||
}
|
||||
rc = pm_wakeup_source_sysfs_add(dev);
|
||||
if (rc)
|
||||
goto err_latency;
|
||||
return 0;
|
||||
|
||||
err_latency:
|
||||
sysfs_unmerge_group(&dev->kobj, &pm_qos_latency_tolerance_attr_group);
|
||||
err_wakeup:
|
||||
sysfs_unmerge_group(&dev->kobj, &pm_wakeup_attr_group);
|
||||
err_runtime:
|
||||
|
|
|
@ -220,10 +220,12 @@ struct wakeup_source *wakeup_source_register(struct device *dev,
|
|||
|
||||
ws = wakeup_source_create(name);
|
||||
if (ws) {
|
||||
ret = wakeup_source_sysfs_add(dev, ws);
|
||||
if (ret) {
|
||||
wakeup_source_free(ws);
|
||||
return NULL;
|
||||
if (!dev || device_is_registered(dev)) {
|
||||
ret = wakeup_source_sysfs_add(dev, ws);
|
||||
if (ret) {
|
||||
wakeup_source_free(ws);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
wakeup_source_add(ws);
|
||||
}
|
||||
|
|
|
@ -184,6 +184,19 @@ int wakeup_source_sysfs_add(struct device *parent, struct wakeup_source *ws)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(wakeup_source_sysfs_add);
|
||||
|
||||
/**
|
||||
* pm_wakeup_source_sysfs_add - Add wakeup_source attributes to sysfs
|
||||
* for a device if they're missing.
|
||||
* @parent: Device given wakeup source is associated with
|
||||
*/
|
||||
int pm_wakeup_source_sysfs_add(struct device *parent)
|
||||
{
|
||||
if (!parent->power.wakeup || parent->power.wakeup->dev)
|
||||
return 0;
|
||||
|
||||
return wakeup_source_sysfs_add(parent, parent->power.wakeup);
|
||||
}
|
||||
|
||||
/**
|
||||
* wakeup_source_sysfs_remove - Remove wakeup_source attributes from sysfs.
|
||||
* @ws: Wakeup source to be removed from sysfs.
|
||||
|
|
Loading…
Reference in New Issue