Re: [PATCH 2/2] PM / Qos: Add notifier for pm qos flags

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thursday, November 01, 2012 06:47:26 PM Lan Tianyu wrote:
> If pm qos flags was changed, device driver would take different
> action according flags. E.g NO_POWER_OFF flag, if it was set when
> a device had been power off, device driver should power on the device,
> resume it and suspend it again without not power off. So device driver
> should be notified. This patch is to add notifier for pm qos flags and
> notify device when flags is changed.
> 
> Signed-off-by: Lan Tianyu <tianyu.lan@xxxxxxxxx>

I haven't added notifiers for PM QoS flags on purpose, so I'm not going
to apply this patch.

Instead, it is required that callers of dev_pm_qos_update_request() for
DEV_PM_QOS_FLAGS type of requests ensure that the device is not RPM_SUSPENDED
when calling that routine (please note that the user interface calls
pm_runtime_get_sync() on the device before changing its flags).  Well, I think
I should add that to the kerneldoc comment of dev_pm_qos_update_request().

Moreover, I'm planning to remove the notifiers from the device PM QoS code
entirely and change the locking so that dev_pm_qos_update_request() and
friends may be called from interrupt context (which is necessary for some
use cases).

Thanks,
Rafael


> ---
>  drivers/base/power/qos.c |   86 +++++++++++++++++++++++++++++++++++++---------
>  include/linux/pm_qos.h   |    7 ++--
>  2 files changed, 75 insertions(+), 18 deletions(-)
> 
> diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c
> index 31d3f48..c37f52f 100644
> --- a/drivers/base/power/qos.c
> +++ b/drivers/base/power/qos.c
> @@ -149,6 +149,10 @@ static int apply_constraint(struct dev_pm_qos_request *req,
>  	case DEV_PM_QOS_FLAGS:
>  		ret = pm_qos_update_flags(&qos->flags, &req->data.flr,
>  					  action, value);
> +		if (ret)
> +			blocking_notifier_call_chain(qos->flags.notifiers,
> +				(unsigned long)qos->flags.effective_flags,
> +				req);
>  		break;
>  	default:
>  		ret = -EINVAL;
> @@ -168,26 +172,38 @@ static int dev_pm_qos_constraints_allocate(struct device *dev)
>  {
>  	struct dev_pm_qos *qos;
>  	struct pm_qos_constraints *c;
> -	struct blocking_notifier_head *n;
> +	struct pm_qos_flags	*flags;
> +	struct blocking_notifier_head *constraints_notify;
> +	struct blocking_notifier_head *flags_notify;
> +	int ret = 0;
>  
>  	qos = kzalloc(sizeof(*qos), GFP_KERNEL);
>  	if (!qos)
>  		return -ENOMEM;
>  
> -	n = kzalloc(sizeof(*n), GFP_KERNEL);
> -	if (!n) {
> -		kfree(qos);
> -		return -ENOMEM;
> +	constraints_notify = kzalloc(sizeof(*constraints_notify), GFP_KERNEL);
> +	if (!constraints_notify) {
> +		ret = -ENOMEM;
> +		goto alloc_constraints_fail;
> +	}
> +	BLOCKING_INIT_NOTIFIER_HEAD(constraints_notify);
> +
> +	flags_notify = kzalloc(sizeof(*flags_notify), GFP_KERNEL);
> +	if (!flags_notify) {
> +		ret = -ENOMEM;
> +		goto alloc_flags_fail;
>  	}
> -	BLOCKING_INIT_NOTIFIER_HEAD(n);
> +	BLOCKING_INIT_NOTIFIER_HEAD(flags_notify);
>  
>  	c = &qos->latency;
>  	plist_head_init(&c->list);
>  	c->target_value = PM_QOS_DEV_LAT_DEFAULT_VALUE;
>  	c->default_value = PM_QOS_DEV_LAT_DEFAULT_VALUE;
>  	c->type = PM_QOS_MIN;
> -	c->notifiers = n;
> +	c->notifiers = constraints_notify;
>  
> +	flags = &qos->flags;
> +	flags->notifiers = flags_notify;
>  	INIT_LIST_HEAD(&qos->flags.list);
>  
>  	spin_lock_irq(&dev->power.lock);
> @@ -195,6 +211,12 @@ static int dev_pm_qos_constraints_allocate(struct device *dev)
>  	spin_unlock_irq(&dev->power.lock);
>  
>  	return 0;
> +
> +alloc_flags_fail:
> +	kfree(constraints_notify);
> +alloc_constraints_fail:
> +	kfree(qos);
> +	return ret;
>  }
>  
>  /**
> @@ -432,6 +454,7 @@ EXPORT_SYMBOL_GPL(dev_pm_qos_remove_request);
>   *
>   * @dev: target device for the constraint
>   * @notifier: notifier block managed by caller.
> + * @type: type of notifier
>   *
>   * Will register the notifier into a notification chain that gets called
>   * upon changes to the target value for the device.
> @@ -439,9 +462,11 @@ EXPORT_SYMBOL_GPL(dev_pm_qos_remove_request);
>   * If the device's constraints object doesn't exist when this routine is called,
>   * it will be created (or error code will be returned if that fails).
>   */
> -int dev_pm_qos_add_notifier(struct device *dev, struct notifier_block *notifier)
> +int dev_pm_qos_add_notifier(struct device *dev, struct notifier_block *notifier,
> +		enum dev_pm_qos_req_type type)
>  {
>  	int ret = 0;
> +	struct blocking_notifier_head *notifiers_head = NULL;
>  
>  	mutex_lock(&dev_pm_qos_mtx);
>  
> @@ -449,9 +474,22 @@ int dev_pm_qos_add_notifier(struct device *dev, struct notifier_block *notifier)
>  		ret = dev->power.power_state.event != PM_EVENT_INVALID ?
>  			dev_pm_qos_constraints_allocate(dev) : -ENODEV;
>  
> -	if (!ret)
> -		ret = blocking_notifier_chain_register(
> -				dev->power.qos->latency.notifiers, notifier);
> +	if (!ret) {
> +		switch (type) {
> +		case DEV_PM_QOS_LATENCY:
> +			notifiers_head = dev->power.qos->latency.notifiers;
> +			break;
> +		case DEV_PM_QOS_FLAGS:
> +			notifiers_head = dev->power.qos->flags.notifiers;
> +			break;
> +		default:
> +			break;
> +		}
> +
> +		if (notifiers_head)
> +			ret = blocking_notifier_chain_register(
> +					notifiers_head, notifier);
> +	}
>  
>  	mutex_unlock(&dev_pm_qos_mtx);
>  	return ret;
> @@ -464,22 +502,38 @@ EXPORT_SYMBOL_GPL(dev_pm_qos_add_notifier);
>   *
>   * @dev: target device for the constraint
>   * @notifier: notifier block to be removed.
> + * @type: type of notifier
>   *
>   * Will remove the notifier from the notification chain that gets called
>   * upon changes to the target value.
>   */
>  int dev_pm_qos_remove_notifier(struct device *dev,
> -			       struct notifier_block *notifier)
> +		struct notifier_block *notifier, enum dev_pm_qos_req_type type)
>  {
>  	int retval = 0;
> +	struct blocking_notifier_head *notifiers_head = NULL;
> +
>  
>  	mutex_lock(&dev_pm_qos_mtx);
>  
>  	/* Silently return if the constraints object is not present. */
> -	if (dev->power.qos)
> -		retval = blocking_notifier_chain_unregister(
> -				dev->power.qos->latency.notifiers,
> -				notifier);
> +	if (dev->power.qos) {
> +		switch (type) {
> +		case DEV_PM_QOS_LATENCY:
> +			notifiers_head = dev->power.qos->latency.notifiers;
> +			break;
> +		case DEV_PM_QOS_FLAGS:
> +			notifiers_head = dev->power.qos->flags.notifiers;
> +			break;
> +		default:
> +			break;
> +		}
> +
> +		if (notifiers_head)
> +			retval = blocking_notifier_chain_unregister(
> +					notifiers_head,
> +					notifier);
> +	}
>  
>  	mutex_unlock(&dev_pm_qos_mtx);
>  	return retval;
> diff --git a/include/linux/pm_qos.h b/include/linux/pm_qos.h
> index 5a95013..479da6c 100644
> --- a/include/linux/pm_qos.h
> +++ b/include/linux/pm_qos.h
> @@ -84,6 +84,7 @@ struct pm_qos_constraints {
>  struct pm_qos_flags {
>  	struct list_head list;
>  	s32 effective_flags;	/* Do not change to 64 bit */
> +	struct blocking_notifier_head *notifiers;
>  };
>  
>  struct dev_pm_qos {
> @@ -134,9 +135,11 @@ int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req,
>  int dev_pm_qos_update_request(struct dev_pm_qos_request *req, s32 new_value);
>  int dev_pm_qos_remove_request(struct dev_pm_qos_request *req);
>  int dev_pm_qos_add_notifier(struct device *dev,
> -			    struct notifier_block *notifier);
> +			    struct notifier_block *notifier,
> +			    enum dev_pm_qos_req_type type);
>  int dev_pm_qos_remove_notifier(struct device *dev,
> -			       struct notifier_block *notifier);
> +				struct notifier_block *notifier,
> +			    enum dev_pm_qos_req_type type);
>  int dev_pm_qos_add_global_notifier(struct notifier_block *notifier);
>  int dev_pm_qos_remove_global_notifier(struct notifier_block *notifier);
>  void dev_pm_qos_constraints_init(struct device *dev);
> 
-- 
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux IBM ACPI]     [Linux Power Management]     [Linux Kernel]     [Linux Laptop]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Video 4 Linux]     [Device Mapper]     [Linux Resources]

  Powered by Linux