diff options
Diffstat (limited to 'drivers/base/power/main.c')
| -rw-r--r-- | drivers/base/power/main.c | 83 | 
1 files changed, 44 insertions, 39 deletions
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index fbc5b6e7c59..aa632020774 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -63,6 +63,7 @@ void device_pm_init(struct device *dev)  	dev->power.wakeup = NULL;  	spin_lock_init(&dev->power.lock);  	pm_runtime_init(dev); +	INIT_LIST_HEAD(&dev->power.entry);  }  /** @@ -425,10 +426,8 @@ static int device_resume_noirq(struct device *dev, pm_message_t state)  	if (dev->pwr_domain) {  		pm_dev_dbg(dev, state, "EARLY power domain "); -		pm_noirq_op(dev, &dev->pwr_domain->ops, state); -	} - -	if (dev->type && dev->type->pm) { +		error = pm_noirq_op(dev, &dev->pwr_domain->ops, state); +	} else if (dev->type && dev->type->pm) {  		pm_dev_dbg(dev, state, "EARLY type ");  		error = pm_noirq_op(dev, dev->type->pm, state);  	} else if (dev->class && dev->class->pm) { @@ -516,7 +515,8 @@ static int device_resume(struct device *dev, pm_message_t state, bool async)  	if (dev->pwr_domain) {  		pm_dev_dbg(dev, state, "power domain "); -		pm_op(dev, &dev->pwr_domain->ops, state); +		error = pm_op(dev, &dev->pwr_domain->ops, state); +		goto End;  	}  	if (dev->type && dev->type->pm) { @@ -579,11 +579,13 @@ static bool is_async(struct device *dev)   * Execute the appropriate "resume" callback for all devices whose status   * indicates that they are suspended.   */ -static void dpm_resume(pm_message_t state) +void dpm_resume(pm_message_t state)  {  	struct device *dev;  	ktime_t starttime = ktime_get(); +	might_sleep(); +  	mutex_lock(&dpm_list_mtx);  	pm_transition = state;  	async_error = 0; @@ -628,12 +630,11 @@ static void device_complete(struct device *dev, pm_message_t state)  {  	device_lock(dev); -	if (dev->pwr_domain && dev->pwr_domain->ops.complete) { +	if (dev->pwr_domain) {  		pm_dev_dbg(dev, state, "completing power domain "); -		dev->pwr_domain->ops.complete(dev); -	} - -	if (dev->type && dev->type->pm) { +		if (dev->pwr_domain->ops.complete) +			dev->pwr_domain->ops.complete(dev); +	} else if (dev->type && dev->type->pm) {  		pm_dev_dbg(dev, state, "completing type ");  		if (dev->type->pm->complete)  			dev->type->pm->complete(dev); @@ -657,10 +658,12 @@ static void device_complete(struct device *dev, pm_message_t state)   * Execute the ->complete() callbacks for all devices whose PM status is not   * DPM_ON (this allows new devices to be registered).   */ -static void dpm_complete(pm_message_t state) +void dpm_complete(pm_message_t state)  {  	struct list_head list; +	might_sleep(); +  	INIT_LIST_HEAD(&list);  	mutex_lock(&dpm_list_mtx);  	while (!list_empty(&dpm_prepared_list)) { @@ -689,7 +692,6 @@ static void dpm_complete(pm_message_t state)   */  void dpm_resume_end(pm_message_t state)  { -	might_sleep();  	dpm_resume(state);  	dpm_complete(state);  } @@ -731,7 +733,12 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state)  {  	int error; -	if (dev->type && dev->type->pm) { +	if (dev->pwr_domain) { +		pm_dev_dbg(dev, state, "LATE power domain "); +		error = pm_noirq_op(dev, &dev->pwr_domain->ops, state); +		if (error) +			return error; +	} else if (dev->type && dev->type->pm) {  		pm_dev_dbg(dev, state, "LATE type ");  		error = pm_noirq_op(dev, dev->type->pm, state);  		if (error) @@ -748,11 +755,6 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state)  			return error;  	} -	if (dev->pwr_domain) { -		pm_dev_dbg(dev, state, "LATE power domain "); -		pm_noirq_op(dev, &dev->pwr_domain->ops, state); -	} -  	return 0;  } @@ -840,21 +842,27 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)  		goto End;  	} +	if (dev->pwr_domain) { +		pm_dev_dbg(dev, state, "power domain "); +		error = pm_op(dev, &dev->pwr_domain->ops, state); +		goto End; +	} +  	if (dev->type && dev->type->pm) {  		pm_dev_dbg(dev, state, "type ");  		error = pm_op(dev, dev->type->pm, state); -		goto Domain; +		goto End;  	}  	if (dev->class) {  		if (dev->class->pm) {  			pm_dev_dbg(dev, state, "class ");  			error = pm_op(dev, dev->class->pm, state); -			goto Domain; +			goto End;  		} else if (dev->class->suspend) {  			pm_dev_dbg(dev, state, "legacy class ");  			error = legacy_suspend(dev, state, dev->class->suspend); -			goto Domain; +			goto End;  		}  	} @@ -868,12 +876,6 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)  		}  	} - Domain: -	if (!error && dev->pwr_domain) { -		pm_dev_dbg(dev, state, "power domain "); -		pm_op(dev, &dev->pwr_domain->ops, state); -	} -   End:  	device_unlock(dev);  	complete_all(&dev->power.completion); @@ -913,11 +915,13 @@ static int device_suspend(struct device *dev)   * dpm_suspend - Execute "suspend" callbacks for all non-sysdev devices.   * @state: PM transition of the system being carried out.   */ -static int dpm_suspend(pm_message_t state) +int dpm_suspend(pm_message_t state)  {  	ktime_t starttime = ktime_get();  	int error = 0; +	might_sleep(); +  	mutex_lock(&dpm_list_mtx);  	pm_transition = state;  	async_error = 0; @@ -964,7 +968,14 @@ static int device_prepare(struct device *dev, pm_message_t state)  	device_lock(dev); -	if (dev->type && dev->type->pm) { +	if (dev->pwr_domain) { +		pm_dev_dbg(dev, state, "preparing power domain "); +		if (dev->pwr_domain->ops.prepare) +			error = dev->pwr_domain->ops.prepare(dev); +		suspend_report_result(dev->pwr_domain->ops.prepare, error); +		if (error) +			goto End; +	} else if (dev->type && dev->type->pm) {  		pm_dev_dbg(dev, state, "preparing type ");  		if (dev->type->pm->prepare)  			error = dev->type->pm->prepare(dev); @@ -983,13 +994,6 @@ static int device_prepare(struct device *dev, pm_message_t state)  		if (dev->bus->pm->prepare)  			error = dev->bus->pm->prepare(dev);  		suspend_report_result(dev->bus->pm->prepare, error); -		if (error) -			goto End; -	} - -	if (dev->pwr_domain && dev->pwr_domain->ops.prepare) { -		pm_dev_dbg(dev, state, "preparing power domain "); -		dev->pwr_domain->ops.prepare(dev);  	}   End: @@ -1004,10 +1008,12 @@ static int device_prepare(struct device *dev, pm_message_t state)   *   * Execute the ->prepare() callback(s) for all devices.   */ -static int dpm_prepare(pm_message_t state) +int dpm_prepare(pm_message_t state)  {  	int error = 0; +	might_sleep(); +  	mutex_lock(&dpm_list_mtx);  	while (!list_empty(&dpm_list)) {  		struct device *dev = to_device(dpm_list.next); @@ -1056,7 +1062,6 @@ int dpm_suspend_start(pm_message_t state)  {  	int error; -	might_sleep();  	error = dpm_prepare(state);  	if (!error)  		error = dpm_suspend(state);  |