[PATCH] PM / Sleep: Fall back to subsystem level PM callbacks for PM domains

Rafael J. Wysocki rjw at rjwysocki.net
Tue Apr 29 15:47:28 PDT 2014


On Friday, April 25, 2014 12:44:55 PM Ulf Hansson wrote:
> Previously once the PM core found a PM domain pointer for a device,
> but which didn't have a valid PM callback, it falled back to try the
> driver's PM callback.
> 
> In this scenario, change the behavior of the PM core to try out the
> other subsystem level PM callbacks, before it moves on to the driver.
> 
> This gives provision for PM domains to easier re-use subsystem level
> code to handle the needed operations.
> 
> Signed-off-by: Ulf Hansson <ulf.hansson at linaro.org>

Are you sure this is not going to break the existing PM domains?

> ---
>  Documentation/power/devices.txt |    6 +++--
>  drivers/base/power/main.c       |   55 +++++++++++++++++++++++++++++++--------
>  2 files changed, 48 insertions(+), 13 deletions(-)
> 
> diff --git a/Documentation/power/devices.txt b/Documentation/power/devices.txt
> index 47d46df..c875056 100644
> --- a/Documentation/power/devices.txt
> +++ b/Documentation/power/devices.txt
> @@ -303,8 +303,10 @@ The PM domain, type, class and bus callbacks may in turn invoke device- or
>  driver-specific methods stored in dev->driver->pm, but they don't have to do
>  that.
>  
> -If the subsystem callback chosen for execution is not present, the PM core will
> -execute the corresponding method from dev->driver->pm instead if there is one.
> +If a PM domain exist, but the callback chosen for execution isn't present, the
> +PM core will fall back to try the other subsystem level callbacks.  Finally, if
> +no subsystem level callback is found, it executes the corresponding method from
> +dev->driver->pm instead if there is one.
>  
>  
>  Entering System Suspend
> diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
> index 86d5e4f..e604db9 100644
> --- a/drivers/base/power/main.c
> +++ b/drivers/base/power/main.c
> @@ -490,7 +490,11 @@ static int device_resume_noirq(struct device *dev, pm_message_t state, bool asyn
>  	if (dev->pm_domain) {
>  		info = "noirq power domain ";
>  		callback = pm_noirq_op(&dev->pm_domain->ops, state);
> -	} else if (dev->type && dev->type->pm) {
> +		if (callback)
> +			goto End;
> +	}
> +
> +	if (dev->type && dev->type->pm) {
>  		info = "noirq type ";
>  		callback = pm_noirq_op(dev->type->pm, state);
>  	} else if (dev->class && dev->class->pm) {
> @@ -506,6 +510,7 @@ static int device_resume_noirq(struct device *dev, pm_message_t state, bool asyn
>  		callback = pm_noirq_op(dev->driver->pm, state);
>  	}
>  
> + End:
>  	error = dpm_run_callback(callback, dev, state, info);
>  	dev->power.is_noirq_suspended = false;
>  
> @@ -616,7 +621,11 @@ static int device_resume_early(struct device *dev, pm_message_t state, bool asyn
>  	if (dev->pm_domain) {
>  		info = "early power domain ";
>  		callback = pm_late_early_op(&dev->pm_domain->ops, state);
> -	} else if (dev->type && dev->type->pm) {
> +		if (callback)
> +			goto End;
> +	}
> +
> +	if (dev->type && dev->type->pm) {
>  		info = "early type ";
>  		callback = pm_late_early_op(dev->type->pm, state);
>  	} else if (dev->class && dev->class->pm) {
> @@ -632,6 +641,7 @@ static int device_resume_early(struct device *dev, pm_message_t state, bool asyn
>  		callback = pm_late_early_op(dev->driver->pm, state);
>  	}
>  
> + End:
>  	error = dpm_run_callback(callback, dev, state, info);
>  	dev->power.is_late_suspended = false;
>  
> @@ -751,7 +761,8 @@ static int device_resume(struct device *dev, pm_message_t state, bool async)
>  	if (dev->pm_domain) {
>  		info = "power domain ";
>  		callback = pm_op(&dev->pm_domain->ops, state);
> -		goto Driver;
> +		if (callback)
> +			goto End;
>  	}
>  
>  	if (dev->type && dev->type->pm) {
> @@ -889,7 +900,11 @@ static void device_complete(struct device *dev, pm_message_t state)
>  	if (dev->pm_domain) {
>  		info = "completing power domain ";
>  		callback = dev->pm_domain->ops.complete;
> -	} else if (dev->type && dev->type->pm) {
> +		if (callback)
> +			goto End;
> +	}
> +
> +	if (dev->type && dev->type->pm) {
>  		info = "completing type ";
>  		callback = dev->type->pm->complete;
>  	} else if (dev->class && dev->class->pm) {
> @@ -905,6 +920,7 @@ static void device_complete(struct device *dev, pm_message_t state)
>  		callback = dev->driver->pm->complete;
>  	}
>  
> + End:
>  	if (callback) {
>  		pm_dev_dbg(dev, state, info);
>  		callback(dev);
> @@ -1015,7 +1031,11 @@ static int __device_suspend_noirq(struct device *dev, pm_message_t state, bool a
>  	if (dev->pm_domain) {
>  		info = "noirq power domain ";
>  		callback = pm_noirq_op(&dev->pm_domain->ops, state);
> -	} else if (dev->type && dev->type->pm) {
> +		if (callback)
> +			goto End;
> +	}
> +
> +	if (dev->type && dev->type->pm) {
>  		info = "noirq type ";
>  		callback = pm_noirq_op(dev->type->pm, state);
>  	} else if (dev->class && dev->class->pm) {
> @@ -1031,6 +1051,7 @@ static int __device_suspend_noirq(struct device *dev, pm_message_t state, bool a
>  		callback = pm_noirq_op(dev->driver->pm, state);
>  	}
>  
> + End:
>  	error = dpm_run_callback(callback, dev, state, info);
>  	if (!error)
>  		dev->power.is_noirq_suspended = true;
> @@ -1154,7 +1175,11 @@ static int __device_suspend_late(struct device *dev, pm_message_t state, bool as
>  	if (dev->pm_domain) {
>  		info = "late power domain ";
>  		callback = pm_late_early_op(&dev->pm_domain->ops, state);
> -	} else if (dev->type && dev->type->pm) {
> +		if (callback)
> +			goto End;
> +	}
> +
> +	if (dev->type && dev->type->pm) {
>  		info = "late type ";
>  		callback = pm_late_early_op(dev->type->pm, state);
>  	} else if (dev->class && dev->class->pm) {
> @@ -1170,6 +1195,7 @@ static int __device_suspend_late(struct device *dev, pm_message_t state, bool as
>  		callback = pm_late_early_op(dev->driver->pm, state);
>  	}
>  
> + End:
>  	error = dpm_run_callback(callback, dev, state, info);
>  	if (!error)
>  		dev->power.is_late_suspended = true;
> @@ -1338,20 +1364,21 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
>  	if (dev->pm_domain) {
>  		info = "power domain ";
>  		callback = pm_op(&dev->pm_domain->ops, state);
> -		goto Run;
> +		if (callback)
> +			goto Run;
>  	}
>  
>  	if (dev->type && dev->type->pm) {
>  		info = "type ";
>  		callback = pm_op(dev->type->pm, state);
> -		goto Run;
> +		goto Driver;
>  	}
>  
>  	if (dev->class) {
>  		if (dev->class->pm) {
>  			info = "class ";
>  			callback = pm_op(dev->class->pm, state);
> -			goto Run;
> +			goto Driver;
>  		} else if (dev->class->suspend) {
>  			pm_dev_dbg(dev, state, "legacy class ");
>  			error = legacy_suspend(dev, state, dev->class->suspend,
> @@ -1372,12 +1399,13 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
>  		}
>  	}
>  
> - Run:
> + Driver:
>  	if (!callback && dev->driver && dev->driver->pm) {
>  		info = "driver ";
>  		callback = pm_op(dev->driver->pm, state);
>  	}
>  
> + Run:
>  	error = dpm_run_callback(callback, dev, state, info);
>  
>   End:
> @@ -1507,7 +1535,11 @@ static int device_prepare(struct device *dev, pm_message_t state)
>  	if (dev->pm_domain) {
>  		info = "preparing power domain ";
>  		callback = dev->pm_domain->ops.prepare;
> -	} else if (dev->type && dev->type->pm) {
> +		if (callback)
> +			goto End;
> +	}
> +
> +	if (dev->type && dev->type->pm) {
>  		info = "preparing type ";
>  		callback = dev->type->pm->prepare;
>  	} else if (dev->class && dev->class->pm) {
> @@ -1523,6 +1555,7 @@ static int device_prepare(struct device *dev, pm_message_t state)
>  		callback = dev->driver->pm->prepare;
>  	}
>  
> + End:
>  	if (callback) {
>  		error = callback(dev);
>  		suspend_report_result(callback, error);
> 

-- 
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.



More information about the linux-arm-kernel mailing list