summaryrefslogtreecommitdiff
path: root/drivers/edp
diff options
context:
space:
mode:
authorSivaram Nair <sivaramn@nvidia.com>2012-07-03 17:20:58 +0300
committerVarun Colbert <vcolbert@nvidia.com>2012-07-23 18:49:29 -0700
commit07c9244642b4be07816e99f3c183ff58d5a6c98b (patch)
tree25920b8ad15250a526365e862c05772d26c684ce /drivers/edp
parent2969c3d9ef7d7e777c7bf046028c82300c29a4fd (diff)
pm: EDP: adding client registration
This patch adds client registration functionality to the existing EDP framework. Bug ID: 917926 Change-Id: I8c9fbe3e1d934a6d95745f3c3933df4c1cbea4e7 Signed-off-by: Sivaram Nair <sivaramn@nvidia.com> Reviewed-on: http://git-master/r/115706 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Matthew Longnecker <mlongnecker@nvidia.com> Reviewed-by: Aleksandr Frid <afrid@nvidia.com> Reviewed-by: Bo Yan <byan@nvidia.com> Reviewed-by: Diwakar Tundlam <dtundlam@nvidia.com>
Diffstat (limited to 'drivers/edp')
-rw-r--r--drivers/edp/edp.c117
1 files changed, 114 insertions, 3 deletions
diff --git a/drivers/edp/edp.c b/drivers/edp/edp.c
index 97ae21d21b6e..fcb94288d3b7 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;
+ INIT_LIST_HEAD(&mgr->clients);
r = 0;
}
mutex_unlock(&edp_lock);
@@ -61,16 +62,19 @@ EXPORT_SYMBOL(edp_register_manager);
int edp_unregister_manager(struct edp_manager *mgr)
{
- int r = -ENODEV;
+ int r = 0;
if (!mgr)
return -EINVAL;
mutex_lock(&edp_lock);
- if (mgr->registered) {
+ if (!mgr->registered) {
+ r = -ENODEV;
+ } else if (!list_empty(&mgr->clients)) {
+ r = -EBUSY;
+ } else {
list_del(&mgr->link);
mgr->registered = false;
- r = 0;
}
mutex_unlock(&edp_lock);
@@ -89,3 +93,110 @@ struct edp_manager *edp_get_manager(const char *name)
return mgr;
}
EXPORT_SYMBOL(edp_get_manager);
+
+static struct edp_client *find_client(struct edp_manager *mgr,
+ const char *name)
+{
+ struct edp_client *p;
+
+ if (!name)
+ return NULL;
+
+ list_for_each_entry(p, &mgr->clients, link)
+ if (!strcmp(p->name, name))
+ return p;
+
+ return NULL;
+}
+
+static unsigned int e0_current_sum(struct edp_manager *mgr)
+{
+ struct edp_client *p;
+ unsigned int sum = 0;
+
+ list_for_each_entry(p, &mgr->clients, link)
+ sum += p->states[p->e0_index];
+
+ return sum;
+}
+
+static bool states_ok(struct edp_client *client)
+{
+ int i;
+
+ if (!client->states || !client->num_states ||
+ client->e0_index >= client->num_states)
+ return false;
+
+ /* state array should be sorted in descending order */
+ for (i = 1; i < client->num_states; i++)
+ if (client->states[i] >= client->states[i - 1])
+ return false;
+
+ return true;
+}
+
+static int register_client(struct edp_manager *mgr, struct edp_client *client)
+{
+ if (!mgr || !client)
+ return -EINVAL;
+
+ if (client->manager || find_client(mgr, client->name))
+ return -EEXIST;
+
+ if (!mgr->registered)
+ return -ENODEV;
+
+ if (!states_ok(client))
+ return -EINVAL;
+
+ /* make sure that we can satisfy E0 for all registered clients */
+ if (e0_current_sum(mgr) + client->states[client->e0_index] > mgr->imax)
+ return -E2BIG;
+
+ list_add_tail(&client->link, &mgr->clients);
+ client->manager = mgr;
+
+ return 0;
+}
+
+int edp_register_client(struct edp_manager *mgr, struct edp_client *client)
+{
+ int r;
+
+ mutex_lock(&edp_lock);
+ r = register_client(mgr, client);
+ mutex_unlock(&edp_lock);
+
+ return r;
+}
+EXPORT_SYMBOL(edp_register_client);
+
+static int unregister_client(struct edp_client *client)
+{
+ if (!client)
+ return -EINVAL;
+
+ if (!client->manager)
+ return -ENODEV;
+
+ if (!client->manager->registered)
+ return -ENODEV;
+
+ list_del(&client->link);
+ client->manager = NULL;
+
+ return 0;
+}
+
+int edp_unregister_client(struct edp_client *client)
+{
+ int r;
+
+ mutex_lock(&edp_lock);
+ r = unregister_client(client);
+ mutex_unlock(&edp_lock);
+
+ return r;
+}
+EXPORT_SYMBOL(edp_unregister_client);