pm: EDP: enable updates via sysfs
This patch allows the user space to issue E-state and threshold change
requests. E-state updates are allowed only if the change is guaranteed
to be approved.
Change-Id: Id31f06ebb95f0b1fdfce205cb17038cb7a9eb30e
Signed-off-by: Sivaram Nair <sivaramn@nvidia.com>
Reviewed-on: http://git-master/r/145256
Reviewed-by: Automatic_Commit_Validation_User
GVS: Gerrit_Virtual_Submit
Reviewed-by: Diwakar Tundlam <dtundlam@nvidia.com>
Reviewed-by: Juha Tukkinen <jtukkinen@nvidia.com>
Rebase-Id: R91a3a085ffb54115e0e45297b1a6716d7529260c
diff --git a/drivers/edp/edp.c b/drivers/edp/edp.c
index b82375b..a2bd3ad 100644
--- a/drivers/edp/edp.c
+++ b/drivers/edp/edp.c
@@ -410,8 +410,8 @@
}
EXPORT_SYMBOL(edp_unregister_client);
-static int update_client_request(struct edp_client *client, unsigned int req,
- int *approved)
+int edp_update_client_request_unlocked(struct edp_client *client,
+ unsigned int req, int *approved)
{
int r;
@@ -434,7 +434,7 @@
int r;
mutex_lock(&edp_lock);
- r = update_client_request(client, req, approved);
+ r = edp_update_client_request_unlocked(client, req, approved);
mutex_unlock(&edp_lock);
return r;
@@ -568,18 +568,23 @@
}
EXPORT_SYMBOL(edp_unregister_loan);
+int edp_update_loan_threshold_unlocked(struct edp_client *client,
+ unsigned int threshold)
+{
+ if (!registered_client(client))
+ return -EINVAL;
+
+ client->ithreshold = threshold;
+ update_loans(client);
+ return 0;
+}
+
int edp_update_loan_threshold(struct edp_client *client, unsigned int threshold)
{
- int r = -EINVAL;
+ int r;
mutex_lock(&edp_lock);
-
- if (registered_client(client)) {
- client->ithreshold = threshold;
- update_loans(client);
- r = 0;
- }
-
+ r = edp_update_loan_threshold_unlocked(client, threshold);
mutex_unlock(&edp_lock);
return r;
diff --git a/drivers/edp/edp_internal.h b/drivers/edp/edp_internal.h
index a0b9693..51b11ea 100644
--- a/drivers/edp/edp_internal.h
+++ b/drivers/edp/edp_internal.h
@@ -54,6 +54,10 @@
extern struct mutex edp_lock;
extern struct list_head edp_governors;
+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,
+ unsigned int threshold);
struct edp_governor *edp_find_governor_unlocked(const char *s);
int edp_set_governor_unlocked(struct edp_manager *mgr,
struct edp_governor *gov);
diff --git a/drivers/edp/sysfs.c b/drivers/edp/sysfs.c
index d23996b..c8baf88 100644
--- a/drivers/edp/sysfs.c
+++ b/drivers/edp/sysfs.c
@@ -174,6 +174,7 @@
struct client_attr {
struct attribute attr;
ssize_t (*show)(struct edp_client *, char *);
+ ssize_t (*store)(struct edp_client *, const char *);
};
static ssize_t states_show(struct edp_client *c, char *s)
@@ -214,6 +215,23 @@
return scnprintf(s, PAGE_SIZE, "%u\n", req_level(c));
}
+/* Allow only updates that are guaranteed to succeed */
+static ssize_t request_store(struct edp_client *c, const char *s)
+{
+ unsigned int id;
+
+ if (sscanf(s, "%u", &id) != 1)
+ return -EINVAL;
+
+ if (id >= c->num_states)
+ return -EINVAL;
+
+ if (id < c->e0_index && id < req_index(c))
+ return -EPERM;
+
+ return edp_update_client_request_unlocked(c, id, NULL);
+}
+
static ssize_t current_show(struct edp_client *c, char *s)
{
return scnprintf(s, PAGE_SIZE, "%u\n", cur_level(c));
@@ -221,8 +239,17 @@
static ssize_t threshold_show(struct edp_client *c, char *s)
{
- return scnprintf(s, PAGE_SIZE, "%u\n",
- c->num_loans ? c->ithreshold : 0);
+ return scnprintf(s, PAGE_SIZE, "%u\n", c->ithreshold);
+}
+
+static ssize_t threshold_store(struct edp_client *c, const char *s)
+{
+ unsigned int tv;
+
+ if (sscanf(s, "%u", &tv) != 1)
+ return -EINVAL;
+
+ return edp_update_loan_threshold_unlocked(c, tv);
}
static ssize_t borrowers_show(struct edp_client *c, char *s)
@@ -240,8 +267,10 @@
struct client_attr attr_e0 = __ATTR_RO(e0);
struct client_attr attr_max_borrowers = __ATTR_RO(max_borrowers);
struct client_attr attr_priority = __ATTR_RO(priority);
-struct client_attr attr_request = __ATTR_RO(request);
-struct client_attr attr_threshold = __ATTR_RO(threshold);
+struct client_attr attr_request = __ATTR(request, 0644, request_show,
+ request_store);
+struct client_attr attr_threshold = __ATTR(threshold, 0644, threshold_show,
+ threshold_store);
struct client_attr attr_borrowers = __ATTR_RO(borrowers);
struct client_attr attr_loans = __ATTR_RO(loans);
struct client_attr attr_current = {
@@ -286,8 +315,30 @@
return r;
}
+static ssize_t client_state_store(struct kobject *kobj,
+ struct attribute *attr, const char *buf, size_t count)
+{
+ ssize_t r = -EINVAL;
+ struct edp_client *c;
+ struct client_attr *cattr;
+
+ mutex_lock(&edp_lock);
+
+ c = to_client(kobj);
+ cattr = container_of(attr, struct client_attr, attr);
+ if (c && cattr) {
+ if (cattr->store)
+ r = cattr->store(c, buf);
+ }
+
+ mutex_unlock(&edp_lock);
+
+ return r ?: count;
+}
+
static const struct sysfs_ops client_sysfs_ops = {
- .show = client_state_show
+ .show = client_state_show,
+ .store = client_state_store
};
static struct kobj_type ktype_client = {