pm: EDP: refactoring and bug fixes
Sivaram Nair [Fri, 7 Sep 2012 11:54:04 +0000 (14:54 +0300)]
(1) identified some generic governor functions and moved to edp.c.
(2) Changes to allow duplicate E-state entries (as long as they are in
    sorted sorted order and at least one of them is non-zero)

Change-Id: Iff5f07b3291fb0fd90449abf68d5bed77e8d7df1
Signed-off-by: Sivaram Nair <sivaramn@nvidia.com>
Reviewed-on: http://git-master/r/131066
Reviewed-by: Automatic_Commit_Validation_User
GVS: Gerrit_Virtual_Submit
Reviewed-by: Diwakar Tundlam <dtundlam@nvidia.com>

drivers/edp/edp.c
drivers/edp/edp_internal.h
drivers/edp/edp_priority.c

index 13b77a2..f913772 100644 (file)
@@ -45,7 +45,8 @@ static void promote(struct work_struct *work)
 {
        struct edp_manager *m = container_of(work, struct edp_manager, work);
        mutex_lock(&edp_lock);
-       m->gov->promote(m);
+       if (m->num_denied && m->remaining)
+               m->gov->promote(m);
        mutex_unlock(&edp_lock);
 }
 
@@ -55,6 +56,8 @@ int edp_register_manager(struct edp_manager *mgr)
 
        if (!mgr)
                return -EINVAL;
+       if (!mgr->imax)
+               return -EINVAL;
 
        mutex_lock(&edp_lock);
        if (!find_manager(mgr->name)) {
@@ -183,10 +186,10 @@ static bool states_ok(struct edp_client *client)
 
        /* state array should be sorted in descending order */
        for (i = 1; i < client->num_states; i++)
-               if (client->states[i] >= client->states[i - 1])
+               if (client->states[i] > client->states[i - 1])
                        return false;
 
-       return true;
+       return client->states[0] ? true : false;
 }
 
 /* Keep the list sorted on priority */
@@ -254,11 +257,85 @@ static void update_loans(struct edp_client *client)
        struct edp_governor *gov;
        gov = client->manager ? client->manager->gov : NULL;
        if (gov && client->cur && !list_empty(&client->borrowers)) {
-               if (gov->update_loans)
+               if (gov->update_loans && *client->cur > client->ithreshold)
                        gov->update_loans(client);
        }
 }
 
+/* generic default implementation */
+void edp_default_update_request(struct edp_client *client,
+               const unsigned int *req,
+               void (*throttle)(struct edp_client *))
+{
+       struct edp_manager *m = client->manager;
+       unsigned int old = cur_level(client);
+       unsigned int new = req ? *req : 0;
+       bool was_denied = client->cur != client->req;
+
+       client->req = req;
+
+       if (new < old) {
+               client->cur = req;
+               m->remaining += old - new;
+       } else if (new - old <= m->remaining) {
+               client->cur = req;
+               m->remaining -= new - old;
+       } else {
+               throttle(client);
+       }
+
+       if (was_denied && client->cur == client->req)
+               m->num_denied--;
+       else if (!was_denied && client->cur != client->req)
+               m->num_denied++;
+}
+
+/* generic default implementation */
+void edp_default_update_loans(struct edp_client *lender)
+{
+       unsigned int size = *lender->cur - lender->ithreshold;
+       struct loan_client *p;
+
+       list_for_each_entry(p, &lender->borrowers, link) {
+               if (size != p->size) {
+                       p->size = p->client->notify_loan_update(size, lender);
+                       WARN_ON(p->size > size);
+               }
+
+               size -= min(p->size, size);
+               if (!size)
+                       return;
+       }
+}
+
+unsigned int edp_throttling_point(struct edp_client *c, unsigned int deficit)
+{
+       unsigned int lim;
+       unsigned int i;
+
+       if (cur_level(c) - e0_level(c) <= deficit)
+               return c->e0_index;
+
+       lim = cur_level(c) - deficit;
+       i = cur_index(c);
+       while (i < c->e0_index && c->states[i] > lim)
+               i++;
+
+       return i;
+}
+
+unsigned int edp_promotion_point(struct edp_client *c, unsigned int step)
+{
+       unsigned int limit = cur_level(c) + step;
+       unsigned int ci = cur_index(c);
+       unsigned int i = req_index(c);
+
+       while (i < ci && c->states[i] > limit)
+               i++;
+
+       return i;
+}
+
 static int mod_request(struct edp_client *client, const unsigned int *req)
 {
        struct edp_manager *m = client->manager;
index e0d8902..a0b9693 100644 (file)
@@ -62,5 +62,11 @@ void edp_manager_add_kobject(struct edp_manager *mgr);
 void edp_manager_remove_kobject(struct edp_manager *mgr);
 void edp_client_add_kobject(struct edp_client *client);
 void edp_client_remove_kobject(struct edp_client *client);
+void edp_default_update_request(struct edp_client *client,
+               const unsigned int *req,
+               void (*throttle)(struct edp_client *));
+void edp_default_update_loans(struct edp_client *lender);
+unsigned int edp_throttling_point(struct edp_client *c, unsigned int deficit);
+unsigned int edp_promotion_point(struct edp_client *c, unsigned int step);
 
 #endif
index c796fb0..bb78e7e 100644 (file)
@@ -55,23 +55,6 @@ static unsigned int approvable_req(struct edp_client *client)
        return i;
 }
 
-static unsigned int throttling_point(struct edp_client *c,
-               unsigned int deficit)
-{
-       unsigned int lim;
-       unsigned int i;
-
-       if (cur_level(c) - e0_level(c) <= deficit)
-               return c->e0_index;
-
-       lim = cur_level(c) - deficit;
-       i = cur_index(c);
-       while (i < c->e0_index && c->states[i] > lim)
-               i++;
-
-       return i;
-}
-
 static void throttle(struct edp_client *client)
 {
        unsigned int ar;
@@ -97,7 +80,7 @@ static void throttle(struct edp_client *client)
                if (p == client || cur_level(p) <= e0_level(p))
                        continue;
 
-               p->gwt = throttling_point(p, deficit - pledged);
+               p->gwt = edp_throttling_point(p, deficit - pledged);
                pledged += cur_level(p) - p->states[p->gwt];
                if (pledged >= deficit)
                        break;
@@ -138,63 +121,33 @@ ret:
 static void prio_update_request(struct edp_client *client,
                const unsigned int *req)
 {
-       struct edp_manager *m = client->manager;
-       unsigned int old = cur_level(client);
-       unsigned int new = req ? *req : 0;
-       bool was_denied = client->cur != client->req;
-
-       client->req = req;
-
-       if (new < old) {
-               client->cur = req;
-               m->remaining += old - new;
-       } else if (new - old <= m->remaining) {
-               client->cur = req;
-               m->remaining -= new - old;
-       } else {
-               throttle(client);
-       }
-
-       if (was_denied && client->cur == client->req)
-               m->num_denied--;
-       else if (!was_denied && client->cur != client->req)
-               m->num_denied++;
-}
-
-static void prio_update_loans(struct edp_client *lender)
-{
-       unsigned int size = *lender->cur <= lender->ithreshold ? 0 :
-               *lender->cur - lender->ithreshold;
-       struct loan_client *p;
-
-       list_for_each_entry(p, &lender->borrowers, link) {
-               if (!size)
-                       return;
-
-               if (size != p->size) {
-                       p->size = p->client->notify_loan_update(size, lender);
-                       WARN_ON(p->size > size);
-                       size -= min(p->size, size);
-               }
-       }
+       edp_default_update_request(client, req, throttle);
 }
 
 static void prio_promote(struct edp_manager *mgr)
 {
        struct edp_client *p;
        unsigned int delta;
+       unsigned int pp;
 
        list_for_each_entry(p, &mgr->clients, link) {
-               if (!mgr->num_denied || !mgr->remaining)
-                       return;
+               if (req_level(p) <= cur_level(p) || !p->notify_promotion)
+                       continue;
 
                delta = req_level(p) - cur_level(p);
-               if (delta && delta <= mgr->remaining && p->notify_promotion) {
-                       p->cur = p->req;
+               if (delta > mgr->remaining)
+                       delta = mgr->remaining;
+
+               pp = edp_promotion_point(p, delta);
+               mgr->remaining -= p->states[pp] - cur_level(p);
+               p->cur = p->states + pp;
+
+               if (p->cur == p->req)
                        mgr->num_denied--;
-                       mgr->remaining -= delta;
-                       p->notify_promotion(cur_index(p));
-               }
+
+               p->notify_promotion(pp);
+               if (!mgr->remaining || !mgr->num_denied)
+                       return;
        }
 }
 
@@ -202,7 +155,7 @@ static struct edp_governor prio_governor = {
        .name = "priority",
        .owner = THIS_MODULE,
        .update_request = prio_update_request,
-       .update_loans = prio_update_loans,
+       .update_loans = edp_default_update_loans,
        .promote = prio_promote
 };