Commit c4772d19 authored by MyungJoo Ham's avatar MyungJoo Ham Committed by Rafael J. Wysocki

PM / QoS: add pm_qos_update_request_timeout() API

The new API, pm_qos_update_request_timeout() is to provide a timeout
with pm_qos_update_request.

For example, pm_qos_update_request_timeout(req, 100, 1000), means that
QoS request on req with value 100 will be active for 1000 microseconds.
After 1000 microseconds, the QoS request thru req is reset. If there
were another pm_qos_update_request(req, x) during the 1000 us, this
new request with value x will override as this is another request on the
same req handle. A new request on the same req handle will always
override the previous request whether it is the conventional request or
it is the new timeout request.
Signed-off-by: default avatarMyungJoo Ham <myungjoo.ham@samsung.com>
Signed-off-by: default avatarKyungmin Park <kyungmin.park@samsung.com>
Acked-by: default avatarMark Gross <markgross@thegnar.org>
Signed-off-by: default avatarRafael J. Wysocki <rjw@sisk.pl>
parent a36cf844
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <linux/notifier.h> #include <linux/notifier.h>
#include <linux/miscdevice.h> #include <linux/miscdevice.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/workqueue.h>
enum { enum {
PM_QOS_RESERVED = 0, PM_QOS_RESERVED = 0,
...@@ -29,6 +30,7 @@ enum { ...@@ -29,6 +30,7 @@ enum {
struct pm_qos_request { struct pm_qos_request {
struct plist_node node; struct plist_node node;
int pm_qos_class; int pm_qos_class;
struct delayed_work work; /* for pm_qos_update_request_timeout */
}; };
struct dev_pm_qos_request { struct dev_pm_qos_request {
...@@ -73,6 +75,8 @@ void pm_qos_add_request(struct pm_qos_request *req, int pm_qos_class, ...@@ -73,6 +75,8 @@ void pm_qos_add_request(struct pm_qos_request *req, int pm_qos_class,
s32 value); s32 value);
void pm_qos_update_request(struct pm_qos_request *req, void pm_qos_update_request(struct pm_qos_request *req,
s32 new_value); 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); void pm_qos_remove_request(struct pm_qos_request *req);
int pm_qos_request(int pm_qos_class); int pm_qos_request(int pm_qos_class);
......
...@@ -229,6 +229,21 @@ int pm_qos_request_active(struct pm_qos_request *req) ...@@ -229,6 +229,21 @@ int pm_qos_request_active(struct pm_qos_request *req)
} }
EXPORT_SYMBOL_GPL(pm_qos_request_active); 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 * pm_qos_add_request - inserts new qos request into the list
* @req: pointer to a preallocated handle * @req: pointer to a preallocated handle
...@@ -253,6 +268,7 @@ void pm_qos_add_request(struct pm_qos_request *req, ...@@ -253,6 +268,7 @@ void pm_qos_add_request(struct pm_qos_request *req,
return; return;
} }
req->pm_qos_class = pm_qos_class; 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, pm_qos_update_target(pm_qos_array[pm_qos_class]->constraints,
&req->node, PM_QOS_ADD_REQ, value); &req->node, PM_QOS_ADD_REQ, value);
} }
...@@ -279,6 +295,9 @@ void pm_qos_update_request(struct pm_qos_request *req, ...@@ -279,6 +295,9 @@ void pm_qos_update_request(struct pm_qos_request *req,
return; return;
} }
if (delayed_work_pending(&req->work))
cancel_delayed_work_sync(&req->work);
if (new_value != req->node.prio) if (new_value != req->node.prio)
pm_qos_update_target( pm_qos_update_target(
pm_qos_array[req->pm_qos_class]->constraints, pm_qos_array[req->pm_qos_class]->constraints,
...@@ -286,6 +305,34 @@ void pm_qos_update_request(struct pm_qos_request *req, ...@@ -286,6 +305,34 @@ void pm_qos_update_request(struct pm_qos_request *req,
} }
EXPORT_SYMBOL_GPL(pm_qos_update_request); 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 * pm_qos_remove_request - modifies an existing qos request
* @req: handle to request list element * @req: handle to request list element
...@@ -305,6 +352,9 @@ void pm_qos_remove_request(struct pm_qos_request *req) ...@@ -305,6 +352,9 @@ void pm_qos_remove_request(struct pm_qos_request *req)
return; 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, pm_qos_update_target(pm_qos_array[req->pm_qos_class]->constraints,
&req->node, PM_QOS_REMOVE_REQ, &req->node, PM_QOS_REMOVE_REQ,
PM_QOS_DEFAULT_VALUE); PM_QOS_DEFAULT_VALUE);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment