summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSivaram Nair <sivaramn@nvidia.com>2012-07-04 12:53:15 +0300
committerVarun Colbert <vcolbert@nvidia.com>2012-07-31 17:13:18 -0700
commit15154c4048fee707250aa190c9e553258a9a4a9c (patch)
tree2617e36ad72ab33250027505b755c8df586a5bbe
parent95352e1e18acfe18b710c3f98b23c83491af0a5c (diff)
pm: EDP: positive E-state handing
This patch adds the basic positive E-state handling functionality. Higher state transitions will fail if there is not enough current remaining. Bug ID: 917926 Change-Id: I1555a4d5b4df35883baa1cf9260ff66254a49b95 Signed-off-by: Sivaram Nair <sivaramn@nvidia.com> Reviewed-on: http://git-master/r/115707 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Diwakar Tundlam <dtundlam@nvidia.com> Tested-by: Varun Colbert <vcolbert@nvidia.com>
-rw-r--r--drivers/edp/edp.c61
-rw-r--r--include/linux/edp.h8
2 files changed, 66 insertions, 3 deletions
diff --git a/drivers/edp/edp.c b/drivers/edp/edp.c
index fcb94288d3b7..63a7df1b3f10 100644
--- a/drivers/edp/edp.c
+++ b/drivers/edp/edp.c
@@ -51,6 +51,7 @@ int edp_register_manager(struct edp_manager *mgr)
if (!find_manager(mgr->name)) {
list_add_tail(&mgr->link, &edp_managers);
mgr->registered = true;
+ mgr->remaining = mgr->imax;
INIT_LIST_HEAD(&mgr->clients);
r = 0;
}
@@ -156,6 +157,8 @@ static int register_client(struct edp_manager *mgr, struct edp_client *client)
list_add_tail(&client->link, &mgr->clients);
client->manager = mgr;
+ client->req = NULL;
+ client->cur = NULL;
return 0;
}
@@ -172,6 +175,26 @@ int edp_register_client(struct edp_manager *mgr, struct edp_client *client)
}
EXPORT_SYMBOL(edp_register_client);
+static int mod_request(struct edp_client *client, const unsigned int *req)
+{
+ unsigned int old = client->cur ? *client->cur : 0;
+ unsigned int new = req ? *req : 0;
+ unsigned int need;
+
+ if (new < old) {
+ client->cur = req;
+ client->manager->remaining += old - new;
+ } else {
+ need = new - old;
+ if (need > client->manager->remaining)
+ return -ENODEV;
+ client->manager->remaining -= need;
+ client->cur = req;
+ }
+
+ return 0;
+}
+
static int unregister_client(struct edp_client *client)
{
if (!client)
@@ -180,9 +203,7 @@ static int unregister_client(struct edp_client *client)
if (!client->manager)
return -ENODEV;
- if (!client->manager->registered)
- return -ENODEV;
-
+ mod_request(client, NULL);
list_del(&client->link);
client->manager = NULL;
@@ -200,3 +221,37 @@ int edp_unregister_client(struct edp_client *client)
return r;
}
EXPORT_SYMBOL(edp_unregister_client);
+
+static int update_client_request(struct edp_client *client, unsigned int req,
+ int *approved)
+{
+ int r;
+
+ if (!client)
+ return -EINVAL;
+
+ if (!client->manager)
+ return -ENODEV;
+
+ if (req >= client->num_states)
+ return -EINVAL;
+
+ r = mod_request(client, client->states + req);
+ if (!r && approved)
+ *approved = client->cur - client->states;
+
+ return r;
+}
+
+int edp_update_client_request(struct edp_client *client, unsigned int req,
+ unsigned int *approved)
+{
+ int r;
+
+ mutex_lock(&edp_lock);
+ r = update_client_request(client, req, approved);
+ mutex_unlock(&edp_lock);
+
+ return r;
+}
+EXPORT_SYMBOL(edp_update_client_request);
diff --git a/include/linux/edp.h b/include/linux/edp.h
index 6d31123f4d6e..743d39a6b8e7 100644
--- a/include/linux/edp.h
+++ b/include/linux/edp.h
@@ -32,6 +32,7 @@ struct edp_manager {
struct list_head link;
struct list_head clients;
bool registered;
+ unsigned int remaining;
};
/*
@@ -50,6 +51,8 @@ struct edp_client {
/* internal */
struct list_head link;
struct edp_manager *manager;
+ const unsigned int *req;
+ const unsigned int *cur;
};
#ifdef CONFIG_EDP_FRAMEWORK
@@ -60,6 +63,8 @@ extern struct edp_manager *edp_get_manager(const char *name);
extern int edp_register_client(struct edp_manager *mgr,
struct edp_client *client);
extern int edp_unregister_client(struct edp_client *client);
+extern int edp_update_client_request(struct edp_client *client,
+ unsigned int req, unsigned int *approved);
#else
static inline int edp_register_manager(struct edp_manager *mgr)
{ return -ENODEV; }
@@ -72,6 +77,9 @@ static inline int edp_register_client(struct edp_manager *mgr,
{ return -ENODEV; }
static inline int edp_unregister_client(struct edp_client *client)
{ return -ENODEV; }
+static inline int edp_update_client_request(struct edp_client *client,
+ unsigned int req, unsigned int *approved)
+{ return -ENODEV; }
#endif
#endif