mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	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
					
				
					 4 changed files with 34 additions and 4 deletions
				
			
		| 
						 | 
				
			
			@ -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,11 +220,13 @@ struct wakeup_source *wakeup_source_register(struct device *dev,
 | 
			
		|||
 | 
			
		||||
	ws = wakeup_source_create(name);
 | 
			
		||||
	if (ws) {
 | 
			
		||||
		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);
 | 
			
		||||
	}
 | 
			
		||||
	return 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 a new issue