EDP: allow reducing manager cap on the fly
Sivaram Nair [Thu, 21 Feb 2013 16:54:22 +0000 (18:54 +0200)]
Current mechanism for reducing the maximum capacity of an EDP manager is
little cumbersome and requires multiple steps. This patch implements it
in a better way and allows the developer to achieve the effect in a
single debugfs modification.

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

drivers/edp/edp.c
drivers/edp/edp_debug.c
drivers/edp/edp_internal.h

index 311e838..0e308be 100644 (file)
@@ -216,7 +216,7 @@ static void add_client(struct edp_client *new, struct list_head *head)
        list_add_tail(&new->link, &p->link);
 }
 
-static int register_client(struct edp_manager *mgr, struct edp_client *client)
+int register_client(struct edp_manager *mgr, struct edp_client *client)
 {
        if (!mgr || !client)
                return -EINVAL;
@@ -392,7 +392,7 @@ static inline bool registered_client(struct edp_client *client)
        return client ? client->manager : false;
 }
 
-static int unregister_client(struct edp_client *client)
+int unregister_client(struct edp_client *client)
 {
        if (!registered_client(client))
                return -EINVAL;
index cdb3936..737c8a3 100644 (file)
 
 struct dentry *edp_debugfs_dir;
 
-static int __manager_cap_set(struct edp_manager *m, unsigned int new_max)
+/*
+ * Reducing the cap is tricky - we might require throttling of other
+ * clients (therefore, involving the governor). So we will fool the
+ * framework by using a dummy client that has a single E-state (E0)
+ * equalling the reduction.
+ */
+static int reduce_cap(struct edp_manager *m, unsigned int new_max)
 {
-       if (new_max < e0_current_sum(m))
-               return -EINVAL;
-
-       if (new_max < m->max - m->remaining)
-               return -EBUSY;
+       int r = 0;
+       unsigned int delta = m->max - new_max;
+       unsigned int remain;
+       struct edp_client c = {
+               .name = ".",
+               .states = &delta,
+               .num_states = 1,
+               .e0_index = 0,
+               .max_borrowers = 0,
+               .priority = EDP_MIN_PRIO
+       };
+
+       r = register_client(m, &c);
+       if (r)
+               return r;
+
+       r = edp_update_client_request_unlocked(&c, 0, NULL);
+       if (r)
+               return r;
+
+       remain = m->remaining;
+       r = unregister_client(&c);
+       if (r)
+               return r;
+
+       m->remaining = remain;
+       m->max = new_max;
+       return 0;
+}
 
-       if (new_max > m->max) {
+static int __manager_cap_set(struct edp_manager *m, unsigned int new_max)
+{
+       if (new_max >= m->max) {
                m->remaining += new_max - m->max;
                m->max = new_max;
                schedule_promotion(m);
-       } else {
-               m->remaining -= m->max - new_max;
-               m->max = new_max;
+               return 0;
        }
 
-       return 0;
+       return reduce_cap(m, new_max);
 }
 
 static int manager_status_show(struct seq_file *file, void *data)
@@ -156,6 +186,7 @@ static int __client_current_set(struct edp_client *c, unsigned int new)
                m->remaining += cl - nl;
                if (c->throttle)
                        c->throttle(new, c->private_data);
+               schedule_promotion(m);
        } else if (nl > cl) {
                m->remaining -= nl - cl;
                if (c->notify_promotion)
index f11f8c2..37d64ee 100644 (file)
@@ -54,6 +54,9 @@ static inline unsigned int req_index(struct edp_client *c)
 extern struct mutex edp_lock;
 extern struct list_head edp_governors;
 
+int register_client(struct edp_manager *m, struct edp_client *c);
+int unregister_client(struct edp_client *c);
+
 int edp_update_client_request_unlocked(struct edp_client *client,
                unsigned int req, int *approved);
 int edp_update_loan_threshold_unlocked(struct edp_client *client,