diff options
| -rw-r--r-- | include/linux/pm_qos.h | 4 | ||||
| -rw-r--r-- | kernel/power/qos.c | 50 | 
2 files changed, 54 insertions, 0 deletions
diff --git a/include/linux/pm_qos.h b/include/linux/pm_qos.h index 2e9191a712f..233149cb19f 100644 --- a/include/linux/pm_qos.h +++ b/include/linux/pm_qos.h @@ -8,6 +8,7 @@  #include <linux/notifier.h>  #include <linux/miscdevice.h>  #include <linux/device.h> +#include <linux/workqueue.h>  enum {  	PM_QOS_RESERVED = 0, @@ -29,6 +30,7 @@ enum {  struct pm_qos_request {  	struct plist_node node;  	int pm_qos_class; +	struct delayed_work work; /* for pm_qos_update_request_timeout */  };  struct dev_pm_qos_request { @@ -73,6 +75,8 @@ void pm_qos_add_request(struct pm_qos_request *req, int pm_qos_class,  			s32 value);  void pm_qos_update_request(struct pm_qos_request *req,  			   s32 new_value); +void pm_qos_update_request_timeout(struct pm_qos_request *req, +				   s32 new_value, unsigned long timeout_us);  void pm_qos_remove_request(struct pm_qos_request *req);  int pm_qos_request(int pm_qos_class); diff --git a/kernel/power/qos.c b/kernel/power/qos.c index d6d6dbd1ecc..6a031e68402 100644 --- a/kernel/power/qos.c +++ b/kernel/power/qos.c @@ -230,6 +230,21 @@ int pm_qos_request_active(struct pm_qos_request *req)  EXPORT_SYMBOL_GPL(pm_qos_request_active);  /** + * pm_qos_work_fn - the timeout handler of pm_qos_update_request_timeout + * @work: work struct for the delayed work (timeout) + * + * This cancels the timeout request by falling back to the default at timeout. + */ +static void pm_qos_work_fn(struct work_struct *work) +{ +	struct pm_qos_request *req = container_of(to_delayed_work(work), +						  struct pm_qos_request, +						  work); + +	pm_qos_update_request(req, PM_QOS_DEFAULT_VALUE); +} + +/**   * pm_qos_add_request - inserts new qos request into the list   * @req: pointer to a preallocated handle   * @pm_qos_class: identifies which list of qos request to use @@ -253,6 +268,7 @@ void pm_qos_add_request(struct pm_qos_request *req,  		return;  	}  	req->pm_qos_class = pm_qos_class; +	INIT_DELAYED_WORK(&req->work, pm_qos_work_fn);  	pm_qos_update_target(pm_qos_array[pm_qos_class]->constraints,  			     &req->node, PM_QOS_ADD_REQ, value);  } @@ -279,6 +295,9 @@ void pm_qos_update_request(struct pm_qos_request *req,  		return;  	} +	if (delayed_work_pending(&req->work)) +		cancel_delayed_work_sync(&req->work); +  	if (new_value != req->node.prio)  		pm_qos_update_target(  			pm_qos_array[req->pm_qos_class]->constraints, @@ -287,6 +306,34 @@ void pm_qos_update_request(struct pm_qos_request *req,  EXPORT_SYMBOL_GPL(pm_qos_update_request);  /** + * pm_qos_update_request_timeout - modifies an existing qos request temporarily. + * @req : handle to list element holding a pm_qos request to use + * @new_value: defines the temporal qos request + * @timeout_us: the effective duration of this qos request in usecs. + * + * After timeout_us, this qos request is cancelled automatically. + */ +void pm_qos_update_request_timeout(struct pm_qos_request *req, s32 new_value, +				   unsigned long timeout_us) +{ +	if (!req) +		return; +	if (WARN(!pm_qos_request_active(req), +		 "%s called for unknown object.", __func__)) +		return; + +	if (delayed_work_pending(&req->work)) +		cancel_delayed_work_sync(&req->work); + +	if (new_value != req->node.prio) +		pm_qos_update_target( +			pm_qos_array[req->pm_qos_class]->constraints, +			&req->node, PM_QOS_UPDATE_REQ, new_value); + +	schedule_delayed_work(&req->work, usecs_to_jiffies(timeout_us)); +} + +/**   * pm_qos_remove_request - modifies an existing qos request   * @req: handle to request list element   * @@ -305,6 +352,9 @@ void pm_qos_remove_request(struct pm_qos_request *req)  		return;  	} +	if (delayed_work_pending(&req->work)) +		cancel_delayed_work_sync(&req->work); +  	pm_qos_update_target(pm_qos_array[req->pm_qos_class]->constraints,  			     &req->node, PM_QOS_REMOVE_REQ,  			     PM_QOS_DEFAULT_VALUE);  |