diff options
author | Sivaram Nair <sivaramn@nvidia.com> | 2012-07-04 12:53:15 +0300 |
---|---|---|
committer | Varun Colbert <vcolbert@nvidia.com> | 2012-07-31 17:13:18 -0700 |
commit | 15154c4048fee707250aa190c9e553258a9a4a9c (patch) | |
tree | 2617e36ad72ab33250027505b755c8df586a5bbe | |
parent | 95352e1e18acfe18b710c3f98b23c83491af0a5c (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.c | 61 | ||||
-rw-r--r-- | include/linux/edp.h | 8 |
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 |