From 02865374406279f3c77fd075e833b1fe4e1daae3 Mon Sep 17 00:00:00 2001 From: Timo Alho Date: Sun, 29 Dec 2013 13:58:09 +0200 Subject: EDP: remove old system EDP framework (framework code) Revised system edp software framework has been put in place. This patch removes old framework code under drivers/edp. Bug 1431977 Change-Id: Icde6ad7066e15172863a39388904309ce2c75c39 Signed-off-by: Timo Alho Reviewed-on: http://git-master/r/350414 Reviewed-by: Juha Tukkinen --- drivers/edp/Makefile | 10 - drivers/edp/edp.c | 702 -------------------------------------------- drivers/edp/edp_bestfit.c | 348 ---------------------- drivers/edp/edp_debug.c | 275 ----------------- drivers/edp/edp_fair.c | 232 --------------- drivers/edp/edp_internal.h | 86 ------ drivers/edp/edp_overage.c | 249 ---------------- drivers/edp/edp_priority.c | 169 ----------- drivers/edp/edp_sysfs.c | 511 -------------------------------- drivers/edp/edp_temporal.c | 234 --------------- drivers/edp/psy_depletion.c | 414 -------------------------- drivers/edp/tegra_core.c | 697 ------------------------------------------- 12 files changed, 3927 deletions(-) delete mode 100644 drivers/edp/edp.c delete mode 100644 drivers/edp/edp_bestfit.c delete mode 100644 drivers/edp/edp_debug.c delete mode 100644 drivers/edp/edp_fair.c delete mode 100644 drivers/edp/edp_internal.h delete mode 100644 drivers/edp/edp_overage.c delete mode 100644 drivers/edp/edp_priority.c delete mode 100644 drivers/edp/edp_sysfs.c delete mode 100644 drivers/edp/edp_temporal.c delete mode 100644 drivers/edp/psy_depletion.c delete mode 100644 drivers/edp/tegra_core.c (limited to 'drivers/edp') diff --git a/drivers/edp/Makefile b/drivers/edp/Makefile index c4aa90c234c1..7a6f2c26b99f 100644 --- a/drivers/edp/Makefile +++ b/drivers/edp/Makefile @@ -1,19 +1,9 @@ GCOV_PROFILE := y -obj-$(CONFIG_EDP_FRAMEWORK) += edp.o -obj-$(CONFIG_EDP_FRAMEWORK) += edp_bestfit.o -obj-$(CONFIG_EDP_FRAMEWORK) += edp_fair.o -obj-$(CONFIG_EDP_FRAMEWORK) += edp_overage.o -obj-$(CONFIG_EDP_FRAMEWORK) += edp_priority.o -obj-$(CONFIG_EDP_FRAMEWORK) += edp_temporal.o -obj-$(CONFIG_EDP_FRAMEWORK) += edp_sysfs.o -obj-$(CONFIG_EDP_FRAMEWORK) += psy_depletion.o -obj-$(CONFIG_EDP_FRAMEWORK) += tegra_core.o obj-$(CONFIG_SYSEDP_FRAMEWORK) += sysedp.o obj-$(CONFIG_SYSEDP_FRAMEWORK) += sysedp_sysfs.o obj-$(CONFIG_SYSEDP_FRAMEWORK) += sysedp_dynamic_capping.o obj-$(CONFIG_SYSEDP_FRAMEWORK) += sysedp_batmon_calc.o ifdef CONFIG_DEBUG_FS -obj-$(CONFIG_EDP_FRAMEWORK) += edp_debug.o obj-$(CONFIG_SYSEDP_FRAMEWORK) += sysedp_debug.o endif \ No newline at end of file diff --git a/drivers/edp/edp.c b/drivers/edp/edp.c deleted file mode 100644 index fdee002d4b79..000000000000 --- a/drivers/edp/edp.c +++ /dev/null @@ -1,702 +0,0 @@ -/* - * Copyright (c) 2012-2013, NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include -#include "edp_internal.h" - -DEFINE_MUTEX(edp_lock); -static LIST_HEAD(edp_managers); -LIST_HEAD(edp_governors); - -static struct edp_manager *find_manager(const char *name) -{ - struct edp_manager *mgr; - - if (!name) - return NULL; - - list_for_each_entry(mgr, &edp_managers, link) - if (!strcmp(mgr->name, name)) - return mgr; - - return NULL; -} - -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) - gov->update_loans(client); - } -} - -static void promote(struct work_struct *work) -{ - unsigned int prev_denied; - struct edp_client *c; - struct edp_manager *m = container_of(work, struct edp_manager, work); - - mutex_lock(&edp_lock); - - if (m->num_denied && m->remaining && m->gov) { - prev_denied = m->num_denied; - m->gov->promote(m); - if (prev_denied != m->num_denied) - sysfs_notify(m->kobj, NULL, "denied"); - list_for_each_entry(c, &m->clients, link) - update_loans(c); - } - - mutex_unlock(&edp_lock); -} - -void schedule_promotion(struct edp_manager *mgr) -{ - if (mgr->remaining && mgr->num_denied && mgr->gov->promote) - schedule_work(&mgr->work); -} - -int edp_register_manager(struct edp_manager *mgr) -{ - int r = -EEXIST; - - if (!mgr) - return -EINVAL; - if (!mgr->max) - return -EINVAL; - - mutex_lock(&edp_lock); - if (!find_manager(mgr->name)) { - list_add_tail(&mgr->link, &edp_managers); - mgr->registered = true; - mgr->remaining = mgr->max; - mgr->gov = NULL; - mgr->gov_data = NULL; - INIT_LIST_HEAD(&mgr->clients); - INIT_WORK(&mgr->work, promote); - mgr->kobj = NULL; - edp_manager_add_kobject(mgr); - manager_add_dentry(mgr); - r = 0; - } - mutex_unlock(&edp_lock); - - return r; -} -EXPORT_SYMBOL(edp_register_manager); - -int edp_set_governor_unlocked(struct edp_manager *mgr, - struct edp_governor *gov) -{ - int r = 0; - - if (mgr ? !mgr->registered : 1) - return -EINVAL; - - if (mgr->gov) { - if (mgr->gov->stop) - mgr->gov->stop(mgr); - mgr->gov->refcnt--; - module_put(mgr->gov->owner); - mgr->gov = NULL; - } - - if (gov) { - if (!gov->refcnt) - return -EINVAL; - if (!try_module_get(gov->owner)) - return -EINVAL; - if (gov->start) - r = gov->start(mgr); - if (r) { - module_put(gov->owner); - WARN_ON(1); - return r; - } - - gov->refcnt++; - mgr->gov = gov; - } - - return 0; -} - -int edp_unregister_manager(struct edp_manager *mgr) -{ - if (!mgr) - return -EINVAL; - - mutex_lock(&edp_lock); - - if (!mgr->registered) { - mutex_unlock(&edp_lock); - return -ENODEV; - } - - if (!list_empty(&mgr->clients)) { - mutex_unlock(&edp_lock); - return -EBUSY; - } - - manager_remove_dentry(mgr); - edp_manager_remove_kobject(mgr); - edp_set_governor_unlocked(mgr, NULL); - list_del(&mgr->link); - mgr->registered = false; - - mutex_unlock(&edp_lock); - cancel_work_sync(&mgr->work); - - return 0; -} -EXPORT_SYMBOL(edp_unregister_manager); - -struct edp_manager *edp_get_manager(const char *name) -{ - struct edp_manager *mgr; - - mutex_lock(&edp_lock); - mgr = find_manager(name); - mutex_unlock(&edp_lock); - - 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; -} - -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 client->states[0] ? true : false; -} - -/* Keep the list sorted on priority */ -static void add_client(struct edp_client *new, struct list_head *head) -{ - struct edp_client *p; - - list_for_each_entry(p, head, link) { - if (p->priority > new->priority) { - list_add_tail(&new->link, &p->link); - return; - } - } - - list_add_tail(&new->link, &p->link); -} - -int register_client(struct edp_manager *mgr, struct edp_client *client) -{ - if (!mgr || !client) - return -EINVAL; - - if (!mgr->registered) - return -ENODEV; - - if (client->manager || find_client(mgr, client->name)) - return -EEXIST; - - if (!states_ok(client) || client->priority > EDP_MIN_PRIO || - client->priority < EDP_MAX_PRIO || - (client->e0_index && !client->throttle)) - return -EINVAL; - - /* make sure that we can satisfy E0 for all registered clients */ - if (e0_current_sum(mgr) + client->states[client->e0_index] > mgr->max) - return -E2BIG; - - add_client(client, &mgr->clients); - client->manager = mgr; - client->req = NULL; - client->cur = NULL; - INIT_LIST_HEAD(&client->borrowers); - client->num_borrowers = 0; - client->num_loans = 0; - client->ithreshold = client->states[0]; - client->kobj = NULL; - edp_client_add_kobject(client); - client_add_dentry(client); - - 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); - -/* 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; - unsigned int cur; - struct loan_client *p; - - cur = cur_level(lender); - size = cur > lender->ithreshold ? cur - lender->ithreshold : 0; - - list_for_each_entry(p, &lender->borrowers, link) { - if (size != p->size) { - p->size = p->client->notify_loan_update( - size, lender, p->client->private_data); - WARN_ON(p->size > size); - } - - size -= min(p->size, size); - } -} - -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++; - - WARN_ON(i >= c->num_states); - return i; -} - -static int mod_request(struct edp_client *client, const unsigned int *req) -{ - struct edp_manager *m = client->manager; - unsigned int prev_remain = m->remaining; - unsigned int prev_denied = m->num_denied; - - if (!m->gov) - return -ENODEV; - - m->gov->update_request(client, req); - update_loans(client); - - /* Do not block calling clients for promotions */ - if (m->remaining > prev_remain) - schedule_promotion(m); - - if (m->num_denied != prev_denied) - sysfs_notify(m->kobj, NULL, "denied"); - - return 0; -} - -static void del_borrower(struct edp_client *lender, struct loan_client *pcl) -{ - pcl->client->notify_loan_close(lender, pcl->client->private_data); - lender->num_borrowers--; - pcl->client->num_loans--; - list_del(&pcl->link); - kfree(pcl); -} - -static void close_all_loans(struct edp_client *client) -{ - struct loan_client *p; - - while (!list_empty(&client->borrowers)) { - p = list_first_entry(&client->borrowers, struct loan_client, - link); - del_borrower(client, p); - } -} - -static inline bool registered_client(struct edp_client *client) -{ - return client ? client->manager : false; -} - -int unregister_client(struct edp_client *client) -{ - if (!registered_client(client)) - return -EINVAL; - - if (client->num_loans) - return -EBUSY; - - client_remove_dentry(client); - edp_client_remove_kobject(client); - close_all_loans(client); - mod_request(client, NULL); - 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); - -int edp_update_client_request_unlocked(struct edp_client *client, - unsigned int req, int *approved) -{ - int r; - - if (!registered_client(client)) - return -EINVAL; - - 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 = edp_update_client_request_unlocked(client, req, approved); - mutex_unlock(&edp_lock); - - return r; -} -EXPORT_SYMBOL(edp_update_client_request); - -static struct edp_client *get_client(const char *name) -{ - struct edp_client *client; - struct edp_manager *mgr; - - if (!name) - return NULL; - - list_for_each_entry(mgr, &edp_managers, link) { - client = find_client(mgr, name); - if (client) - return client; - } - - return NULL; -} - -struct edp_client *edp_get_client(const char *name) -{ - struct edp_client *client; - - mutex_lock(&edp_lock); - client = get_client(name); - mutex_unlock(&edp_lock); - - return client; -} -EXPORT_SYMBOL(edp_get_client); - -static struct loan_client *find_borrower(struct edp_client *lender, - struct edp_client *borrower) -{ - struct loan_client *p; - - list_for_each_entry(p, &lender->borrowers, link) - if (p->client == borrower) - return p; - return NULL; -} - -/* Keep the list sorted on priority */ -static void add_borrower(struct loan_client *new, struct list_head *head) -{ - struct loan_client *p; - - list_for_each_entry(p, head, link) { - if (p->client->priority > new->client->priority) { - list_add_tail(&new->link, &p->link); - return; - } - } - - list_add_tail(&new->link, &p->link); -} - -static int register_loan(struct edp_client *lender, struct edp_client *borrower) -{ - struct loan_client *p; - - if (!registered_client(lender) || !registered_client(borrower)) - return -EINVAL; - - if (lender->manager != borrower->manager || - !borrower->notify_loan_update || - !borrower->notify_loan_close) - return -EINVAL; - - if (find_borrower(lender, borrower)) - return -EEXIST; - - if (lender->num_borrowers >= lender->max_borrowers) - return -EBUSY; - - p = kzalloc(sizeof(*p), GFP_KERNEL); - if (!p) - return -ENOMEM; - - p->client = borrower; - lender->num_borrowers++; - borrower->num_loans++; - add_borrower(p, &lender->borrowers); - - update_loans(lender); - return 0; -} - -int edp_register_loan(struct edp_client *lender, struct edp_client *borrower) -{ - int r; - - mutex_lock(&edp_lock); - r = register_loan(lender, borrower); - mutex_unlock(&edp_lock); - - return r; -} -EXPORT_SYMBOL(edp_register_loan); - -static int unregister_loan(struct edp_client *lender, - struct edp_client *borrower) -{ - struct loan_client *p; - - if (!registered_client(lender) || !registered_client(borrower)) - return -EINVAL; - - p = find_borrower(lender, borrower); - if (!p) - return -EINVAL; - - del_borrower(lender, p); - update_loans(lender); - return 0; -} - -int edp_unregister_loan(struct edp_client *lender, struct edp_client *borrower) -{ - int r; - - mutex_lock(&edp_lock); - r = unregister_loan(lender, borrower); - mutex_unlock(&edp_lock); - - return r; -} -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; - - mutex_lock(&edp_lock); - r = edp_update_loan_threshold_unlocked(client, threshold); - mutex_unlock(&edp_lock); - - return r; -} -EXPORT_SYMBOL(edp_update_loan_threshold); - -struct edp_governor *edp_find_governor_unlocked(const char *s) -{ - struct edp_governor *g; - - list_for_each_entry(g, &edp_governors, link) - if (!strnicmp(s, g->name, EDP_NAME_LEN)) - return g; - - return NULL; -} - -int edp_register_governor(struct edp_governor *gov) -{ - int r = 0; - - if (!gov) - return -EINVAL; - - if (!gov->update_request) - return -EINVAL; - - mutex_lock(&edp_lock); - if (edp_find_governor_unlocked(gov->name)) { - r = -EEXIST; - } else { - gov->refcnt = 1; - list_add(&gov->link, &edp_governors); - } - mutex_unlock(&edp_lock); - - return r; -} -EXPORT_SYMBOL(edp_register_governor); - -int edp_unregister_governor(struct edp_governor *gov) -{ - int r = 0; - - mutex_lock(&edp_lock); - if (!gov) { - r = -EINVAL; - } else if (gov->refcnt != 1) { - r = gov->refcnt > 1 ? -EBUSY : -ENODEV; - } else { - list_del(&gov->link); - gov->refcnt = 0; - } - mutex_unlock(&edp_lock); - - return r; -} -EXPORT_SYMBOL(edp_unregister_governor); - -struct edp_governor *edp_get_governor(const char *name) -{ - struct edp_governor *g; - - mutex_lock(&edp_lock); - g = edp_find_governor_unlocked(name); - mutex_unlock(&edp_lock); - - return g; -} -EXPORT_SYMBOL(edp_get_governor); - -int edp_set_governor(struct edp_manager *mgr, struct edp_governor *gov) -{ - int r; - - mutex_lock(&edp_lock); - r = edp_set_governor_unlocked(mgr, gov); - mutex_unlock(&edp_lock); - - return r; -} -EXPORT_SYMBOL(edp_set_governor); diff --git a/drivers/edp/edp_bestfit.c b/drivers/edp/edp_bestfit.c deleted file mode 100644 index f9425cc96df0..000000000000 --- a/drivers/edp/edp_bestfit.c +++ /dev/null @@ -1,348 +0,0 @@ -/* - * Copyright (c) 2012-2013, NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include "edp_internal.h" - -static struct list_head hilist; -static struct list_head lolist_hash[10]; - -static void init_hash(void) -{ - int i; - INIT_LIST_HEAD(&hilist); - for (i = 0; i < ARRAY_SIZE(lolist_hash); i++) - INIT_LIST_HEAD(lolist_hash + i); -} - -/* Return the minimum state that we must approve */ -static unsigned int min_ai(struct edp_client *c) -{ - unsigned int ri = req_index(c); - if (ri >= c->e0_index) - return ri; - return min(cur_index(c), c->e0_index); -} - -static struct edp_client *lolist_hi_entry(int hash) -{ - int i; - - for (i = hash; i < ARRAY_SIZE(lolist_hash); i++) { - if (!list_empty(lolist_hash + i)) - return list_first_entry(lolist_hash + i, - struct edp_client, glnk); - } - - return NULL; -} - -static struct edp_client *lolist_li_entry(int hash) -{ - int i; - - for (i = hash; i >= 0; i--) { - if (!list_empty(lolist_hash + i)) - return list_first_entry(lolist_hash + i, - struct edp_client, glnk); - } - - return NULL; -} - -static struct edp_client *lolist_entry(int hash, bool hifirst) -{ - struct edp_client *c; - - if (hifirst) - c = lolist_hi_entry(hash) ?: lolist_li_entry(hash - 1); - else - c = lolist_li_entry(hash) ?: lolist_hi_entry(hash + 1); - - return c; -} - -/* - * Use hashing to fasten up the lookup for bestfit (we might have to do - * multiple passes). If a single client can supply the minimum - * requirement, put them into hilist. Otherwise, compute a simple hash - * from the ratio of (cur - E0) to the minimum requirement and add to - * the corresponding lolist queue. Entries are added to the list head - * so that lower priority clients are throttled first. - */ -static void prep_throttle_hash(struct edp_client *client, unsigned int mn) -{ - struct edp_manager *m = client->manager; - struct edp_client *c; - unsigned int i; - unsigned int more; - - init_hash(); - - list_for_each_entry(c, &m->clients, link) { - if (c == client || cur_level(c) <= e0_level(c)) - continue; - - more = cur_level(c) - e0_level(c); - - if (more + m->remaining < mn) { - i = more * ARRAY_SIZE(lolist_hash) / mn; - list_add(&c->glnk, lolist_hash + i); - } else { - list_add(&c->glnk, &hilist); - } - } -} - -/* - * Find the bestfit point between the requesting client and a potential - * throttle-victim. Choose the one with lowest remaining current. - */ -static unsigned int bestfit_point(struct edp_client *rc, struct edp_client *c, - unsigned int mn, unsigned int *opt_bal) -{ - unsigned int ai = cur_index(rc); - unsigned int ri = req_index(rc); - unsigned int cl = cur_level(rc); - unsigned int step; - unsigned int bal; - unsigned int i; - unsigned int j; - - *opt_bal = rc->manager->max; - - for (i = cur_index(c) + 1; i <= c->e0_index && ai > ri; i++) { - step = rc->manager->remaining + *c->cur - c->states[i]; - if (step < mn) - continue; - - j = edp_promotion_point(rc, step); - bal = step - (rc->states[j] - cl); - if (bal < *opt_bal) { - *opt_bal = bal; - c->gwt = i; - ai = j; - } - } - - return ai; -} - -static struct edp_client *throttle_bestfit_hi(struct edp_client *rc, - unsigned int mn, unsigned int *bfi, unsigned int *opt_bal) -{ - struct edp_client *c; - struct edp_client *opt_c; - unsigned int bal; - unsigned int i; - - if (list_empty(&hilist)) - return NULL; - - opt_c = NULL; - *opt_bal = rc->manager->max; - - list_for_each_entry(c, &hilist, glnk) { - i = bestfit_point(rc, c, mn, &bal); - if (bal < *opt_bal) { - *bfi = i; - *opt_bal = bal; - opt_c = c; - } - } - - WARN_ON(!opt_c); - return opt_c; -} - -static unsigned int throttle_recover(struct edp_manager *m, unsigned int mn) -{ - struct edp_client *c; - unsigned int i; - unsigned int tp; - unsigned int step; - unsigned int rsum = m->remaining; - - while (rsum < mn) { - i = ((mn - rsum) * ARRAY_SIZE(lolist_hash) + mn - 1) / mn; - c = lolist_entry(i, true); - if (!c) - break; - - list_del(&c->glnk); - step = min(cur_level(c) - e0_level(c), mn - rsum); - tp = edp_throttling_point(c, step); - if (tp == cur_index(c)) - continue; - - rsum += cur_level(c) - c->states[tp]; - c->throttle(tp, c->private_data); - if (c->cur == c->req) - m->num_denied++; - c->cur = c->states + tp; - } - - WARN_ON(rsum < mn); - return rsum; -} - -static void throttle(struct edp_client *client) -{ - struct edp_manager *m = client->manager; - unsigned int ai; - unsigned int mn; - struct edp_client *c; - unsigned int balance; - - ai = min_ai(client); - mn = client->states[ai] - cur_level(client); - - if (mn <= m->remaining) { - ai = edp_promotion_point(client, m->remaining); - m->remaining -= client->states[ai] - cur_level(client); - client->cur = client->states + ai; - return; - } - - prep_throttle_hash(client, mn); - c = throttle_bestfit_hi(client, mn, &ai, &balance); - - if (c) { - c->throttle(c->gwt, c->private_data); - if (c->cur == c->req) - m->num_denied++; - m->remaining = balance; - c->cur = c->states + c->gwt; - client->cur = client->states + ai; - return; - } - - balance = throttle_recover(m, mn); - WARN_ON(balance < mn); - ai = edp_promotion_point(client, balance); - m->remaining = balance - (client->states[ai] - cur_level(client)); - client->cur = client->states + ai; -} - -static void bestfit_update_request(struct edp_client *client, - const unsigned int *req) -{ - edp_default_update_request(client, req, throttle); -} - -static void prep_promotion_hash(struct edp_manager *m) -{ - unsigned int balance = m->remaining; - struct edp_client *c; - unsigned int step; - unsigned int i; - - init_hash(); - - list_for_each_entry(c, &m->clients, link) { - if (req_level(c) <= cur_level(c) || !c->notify_promotion) - continue; - - step = req_level(c) - cur_level(c); - - /* - * Add to the list tail so that higher priority clients - * are promoted first - */ - if (step < balance) { - i = step * ARRAY_SIZE(lolist_hash) / balance; - list_add_tail(&c->glnk, lolist_hash + i); - } else { - list_add_tail(&c->glnk, &hilist); - } - } -} - -static struct edp_client *promotion_bestfit_hi(unsigned int balance) -{ - struct edp_client *c; - unsigned int i; - unsigned int step; - struct edp_client *opt_c = NULL; - unsigned int opt_bal = balance; - - list_for_each_entry(c, &hilist, glnk) { - i = edp_promotion_point(c, balance); - step = c->states[i] - cur_level(c); - if (balance - step < opt_bal) { - c->gwt = i; - opt_c = c; - } - } - - return opt_c; -} - -static void bestfit_promote(struct edp_manager *mgr) -{ - unsigned int balance = mgr->remaining; - struct edp_client *c; - unsigned int i; - - prep_promotion_hash(mgr); - c = promotion_bestfit_hi(balance); - - if (c) { - balance -= c->states[c->gwt] - cur_level(c); - c->cur = c->states + c->gwt; - if (c->cur == c->req) - mgr->num_denied--; - c->notify_promotion(c->gwt, c->private_data); - } - - while (balance && mgr->num_denied) { - i = balance * ARRAY_SIZE(lolist_hash) / mgr->remaining; - if (i) - i--; - c = lolist_entry(i, false); - if (!c) - break; - - list_del(&c->glnk); - c->gwt = edp_promotion_point(c, balance); - if (c->gwt == cur_index(c)) - continue; - - balance -= c->states[c->gwt] - cur_level(c); - c->cur = c->states + c->gwt; - if (c->cur == c->req) - mgr->num_denied--; - c->notify_promotion(c->gwt, c->private_data); - } - - mgr->remaining = balance; -} - -static struct edp_governor bestfit_governor = { - .name = "bestfit", - .owner = THIS_MODULE, - .update_request = bestfit_update_request, - .update_loans = edp_default_update_loans, - .promote = bestfit_promote -}; - -static int __init bestfit_init(void) -{ - return edp_register_governor(&bestfit_governor); -} -postcore_initcall(bestfit_init); diff --git a/drivers/edp/edp_debug.c b/drivers/edp/edp_debug.c deleted file mode 100644 index 2464bcce74d7..000000000000 --- a/drivers/edp/edp_debug.c +++ /dev/null @@ -1,275 +0,0 @@ -/* - * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include "edp_internal.h" - -struct dentry *edp_debugfs_dir; - -/* - * 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) -{ - int r = 0; - unsigned int delta = m->max - new_max; - unsigned int remain; - struct edp_client c = { - .name = ".debug", - .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; -} - -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); - return 0; - } - - return reduce_cap(m, new_max); -} - -static int manager_status_show(struct seq_file *file, void *data) -{ - struct edp_manager *m; - struct edp_client *c; - - if (!file->private) - return -ENODEV; - - m = file->private; - - mutex_lock(&edp_lock); - - seq_printf(file, "cap : %u\n", m->max); - seq_printf(file, "sum(E0) : %u\n", e0_current_sum(m)); - seq_printf(file, "remaining: %u\n", m->remaining); - - seq_printf(file, "------------------------------------------\n"); - seq_printf(file, "%-16s %3s %5s %7s %7s\n", - "client", "pri", "E0", "request", "current"); - seq_printf(file, "------------------------------------------\n"); - - list_for_each_entry(c, &m->clients, link) - seq_printf(file, "%-16s %3d %5u %7u %7u\n", c->name, - c->priority, e0_level(c), req_level(c), - cur_level(c)); - - mutex_unlock(&edp_lock); - return 0; -} - -static int manager_status_open(struct inode *inode, struct file *file) -{ - return single_open(file, manager_status_show, inode->i_private); -} - -static const struct file_operations manager_status_fops = { - .open = manager_status_open, - .read = seq_read, -}; - -static int manager_cap_set(void *data, u64 val) -{ - struct edp_manager *m = data; - int r; - - mutex_lock(&edp_lock); - r = __manager_cap_set(m, val); - mutex_unlock(&edp_lock); - return r; -} - -static int manager_cap_get(void *data, u64 *val) -{ - struct edp_manager *m = data; - - mutex_lock(&edp_lock); - *val = m->max; - mutex_unlock(&edp_lock); - return 0; -} - -DEFINE_SIMPLE_ATTRIBUTE(manager_cap_fops, manager_cap_get, - manager_cap_set, "%lld\n"); - -void manager_add_dentry(struct edp_manager *m) -{ - struct dentry *d; - - if (!edp_debugfs_dir) - return; - - d = debugfs_create_dir(m->name, edp_debugfs_dir); - if (IS_ERR_OR_NULL(d)) - return; - - m->dentry = d; - - d = debugfs_create_file("status", S_IRUGO, m->dentry, m, - &manager_status_fops); - WARN_ON(IS_ERR_OR_NULL(d)); - - d = debugfs_create_file("cap", S_IRUGO | S_IWUSR, m->dentry, m, - &manager_cap_fops); - WARN_ON(IS_ERR_OR_NULL(d)); -} - -void manager_remove_dentry(struct edp_manager *m) -{ - debugfs_remove_recursive(m->dentry); - m->dentry = NULL; -} - -static int __client_current_set(struct edp_client *c, unsigned int new) -{ - struct edp_manager *m; - unsigned int nl; - unsigned int cl; - - if (new >= c->num_states) - return -EINVAL; - - nl = c->states[new]; - cl = cur_level(c); - m = c->manager; - - if (nl > cl && nl - cl > m->remaining) - return -EBUSY; - - c->cur = c->states + new; - c->req = c->states + new; - - if (nl < cl) { - 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) - c->notify_promotion(new, c->private_data); - } - - return 0; -} - -static int client_current_set(void *data, u64 val) -{ - struct edp_client *c = data; - int r; - - mutex_lock(&edp_lock); - r = __client_current_set(c, val); - mutex_unlock(&edp_lock); - return r; -} - -static int client_current_get(void *data, u64 *val) -{ - struct edp_client *c = data; - - mutex_lock(&edp_lock); - *val = cur_level(c); - mutex_unlock(&edp_lock); - return 0; -} - -DEFINE_SIMPLE_ATTRIBUTE(client_current_fops, client_current_get, - client_current_set, "%lld\n"); - -void client_add_dentry(struct edp_client *c) -{ - struct dentry *d; - - if (!c->manager->dentry) - return; - - d = debugfs_create_dir(c->name, c->manager->dentry); - if (IS_ERR_OR_NULL(d)) { - WARN_ON(1); - return; - } - - c->dentry = d; - - d = debugfs_create_file("current", S_IRUGO | S_IWUSR, c->dentry, - c, &client_current_fops); - WARN_ON(IS_ERR_OR_NULL(d)); -} - -void client_remove_dentry(struct edp_client *c) -{ - debugfs_remove_recursive(c->dentry); - c->dentry = NULL; -} - -static void dbg_update_request(struct edp_client *c, const unsigned int *r) {} -static void dbg_update_loans(struct edp_client *c) {} -static void dbg_promote(struct edp_manager *mgr) {} - -static struct edp_governor dbg_governor = { - .name = "debug", - .owner = THIS_MODULE, - .update_request = dbg_update_request, - .update_loans = dbg_update_loans, - .promote = dbg_promote -}; - -static int __init debug_init(void) -{ - struct dentry *d; - - d = debugfs_create_dir("edp", NULL); - if (IS_ERR_OR_NULL(d)) { - WARN_ON(1); - return -EFAULT; - } - - edp_debugfs_dir = d; - return edp_register_governor(&dbg_governor); -} -postcore_initcall(debug_init); diff --git a/drivers/edp/edp_fair.c b/drivers/edp/edp_fair.c deleted file mode 100644 index d21e87f25583..000000000000 --- a/drivers/edp/edp_fair.c +++ /dev/null @@ -1,232 +0,0 @@ -/* - * Copyright (c) 2012-2013, NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include "edp_internal.h" - -static unsigned int approvable_req(struct edp_client *c, unsigned int net) -{ - unsigned int fair_level; - unsigned int step; - unsigned int cl; - - if (req_index(c) >= c->e0_index) - return req_index(c); - - cl = cur_level(c); - fair_level = c->manager->max * e0_level(c) / net; - step = max(fair_level, cl + c->manager->remaining) - cl; - return edp_promotion_point(c, step); -} - -static struct edp_client *throttle_pledge(struct edp_client *client, - unsigned int required, unsigned int net, - unsigned int *pledged) -{ - struct edp_manager *m = client->manager; - struct edp_client *c; - unsigned int step; - unsigned int fair; - - *pledged = m->remaining; - - list_for_each_entry_reverse(c, &m->clients, link) { - fair = c->manager->max * e0_level(c) / net; - if (c == client || cur_level(c) <= fair) - continue; - - step = min(cur_level(c) - fair, required - *pledged); - c->gwt = edp_throttling_point(c, step); - *pledged += cur_level(c) - c->states[c->gwt]; - if (*pledged >= required) - break; - } - - WARN_ON(*pledged < required); - return c; -} - -static void throttle_recover(struct edp_client *client, struct edp_client *tp, - unsigned int required) -{ - struct edp_manager *m = client->manager; - unsigned int recovered = m->remaining; - - list_for_each_entry_from(tp, &m->clients, link) { - if (tp == client || cur_level(tp) <= e0_level(tp) || - tp->gwt == cur_index(tp)) - continue; - - tp->throttle(tp->gwt, tp->private_data); - recovered += cur_level(tp) - tp->states[tp->gwt]; - if (tp->cur == tp->req) - m->num_denied++; - - tp->cur = tp->states + tp->gwt; - if (recovered >= required) - return; - } -} - -static void throttle(struct edp_client *client) -{ - struct edp_manager *m = client->manager; - struct edp_client *tp; - unsigned int ar; - unsigned int pledged; - unsigned int required; - unsigned int net; - - net = e0_current_sum(m); - if (!net) { - WARN_ON(1); - return; - } - - ar = approvable_req(client, net); - required = client->states[ar] - cur_level(client); - - if (required <= m->remaining) { - client->cur = client->states + ar; - m->remaining -= required; - return; - } - - tp = throttle_pledge(client, required, net, &pledged); - - /* E-states are discrete - we may get more than we asked for */ - if (pledged > required && ar != req_index(client)) { - ar = edp_promotion_point(client, pledged); - required = client->states[ar] - cur_level(client); - } - - throttle_recover(client, tp, required); - client->cur = client->states + ar; - m->remaining = pledged - required; -} - -static void fair_update_request(struct edp_client *client, - const unsigned int *req) -{ - edp_default_update_request(client, req, throttle); -} - -static unsigned int fair_promotion_point(struct edp_client *c, - unsigned int step, unsigned int max) -{ - unsigned int lim = cur_level(c) + step; - unsigned int ci = cur_index(c); - unsigned int i = req_index(c); - - while (i < ci && c->states[i] > lim) - i++; - - /* - * While being throttled, we probably contributed more than our - * fare share - so take the ceiling E-state here - */ - if (c->states[i] < lim && i > req_index(c)) { - if (c->states[i - 1] <= cur_level(c) + max) - i--; - } - - return i; -} - -static unsigned int promotion_pledge(struct edp_manager *m, unsigned int net) -{ - unsigned int budget = m->remaining; - unsigned int unpledged = m->remaining; - unsigned int denied = m->num_denied; - struct edp_client *c; - unsigned int step; - - list_for_each_entry(c, &m->clients, link) { - if (req_level(c) <= cur_level(c) || !c->notify_promotion) - continue; - - step = (e0_level(c) * budget + net - 1) / net; - step = min(step, unpledged); - - c->gwt = fair_promotion_point(c, step, unpledged); - unpledged -= c->states[c->gwt] - cur_level(c); - if (req_index(c) == c->gwt) - denied--; - if (!unpledged || !denied) - break; - } - - return unpledged; -} - -static void fair_promote(struct edp_manager *mgr) -{ - unsigned int net = 0; - struct edp_client *c; - unsigned int step; - unsigned int pp; - unsigned int unpledged; - - list_for_each_entry(c, &mgr->clients, link) { - if (req_level(c) > cur_level(c) && c->notify_promotion) { - net += e0_level(c); - c->gwt = cur_index(c); - } - } - - /* if the net is 0, fall back on priority */ - unpledged = net ? promotion_pledge(mgr, net) : mgr->remaining; - - list_for_each_entry(c, &mgr->clients, link) { - if (req_level(c) <= cur_level(c) || !c->notify_promotion || - c->gwt == cur_index(c)) - continue; - - pp = c->gwt; - - /* make sure that the unpledged current is not wasted */ - if (unpledged && req_index(c) != pp) { - step = c->states[pp] - cur_level(c) + unpledged; - pp = edp_promotion_point(c, step); - unpledged -= c->states[pp] - c->states[c->gwt]; - } - - mgr->remaining -= c->states[pp] - cur_level(c); - c->cur = c->states + pp; - if (c->cur == c->req) - mgr->num_denied--; - - c->notify_promotion(pp, c->private_data); - if (!mgr->remaining || !mgr->num_denied) - return; - } -} - -static struct edp_governor fair_governor = { - .name = "fair", - .owner = THIS_MODULE, - .update_request = fair_update_request, - .update_loans = edp_default_update_loans, - .promote = fair_promote -}; - -static int __init fair_init(void) -{ - return edp_register_governor(&fair_governor); -} -postcore_initcall(fair_init); diff --git a/drivers/edp/edp_internal.h b/drivers/edp/edp_internal.h deleted file mode 100644 index 37d64ee65c3b..000000000000 --- a/drivers/edp/edp_internal.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) 2012-2013, NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef _EDP_INTERNAL_H -#define _EDP_INTERNAL_H - -#include -#include - -struct loan_client { - struct list_head link; - struct edp_client *client; - unsigned int size; -}; - -static inline unsigned int cur_level(struct edp_client *c) -{ - return c->cur ? *c->cur : 0; -} - -static inline unsigned int req_level(struct edp_client *c) -{ - return c->req ? *c->req : 0; -} - -static inline unsigned int e0_level(struct edp_client *c) -{ - return c->states[c->e0_index]; -} - -static inline unsigned int cur_index(struct edp_client *c) -{ - return c->cur ? c->cur - c->states : c->num_states; -} - -static inline unsigned int req_index(struct edp_client *c) -{ - return c->req ? c->req - c->states : c->num_states; -} - -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, - 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); - -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); - -void manager_add_dentry(struct edp_manager *m); -void manager_remove_dentry(struct edp_manager *m); -void client_add_dentry(struct edp_client *c); -void client_remove_dentry(struct edp_client *c); -void schedule_promotion(struct edp_manager *m); -unsigned int e0_current_sum(struct edp_manager *mgr); - -#endif diff --git a/drivers/edp/edp_overage.c b/drivers/edp/edp_overage.c deleted file mode 100644 index 2dc1c2edc6aa..000000000000 --- a/drivers/edp/edp_overage.c +++ /dev/null @@ -1,249 +0,0 @@ -/* - * Copyright (c) 2012-2013, NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include "edp_internal.h" - -static inline unsigned int cur_overage(struct edp_client *c) -{ - unsigned int cl = cur_level(c); - unsigned int el = e0_level(c); - return cl > el ? cl - el : 0; -} - -static inline unsigned int req_overage(struct edp_client *c) -{ - unsigned int rl = req_level(c); - unsigned int el = e0_level(c); - return rl > el ? rl - el : 0; -} - -/* - * Find the maximum that we can allocate for this client. Since we are - * using a propotional allocation, ensure that the allowed budget is - * fare to other clients. Note that the maximum E-state level is used as - * reference for normalizing client requests (E0 can not be used since - * it could be zer0 for some clients) - */ -static unsigned int approvable_req(struct edp_client *c, - unsigned int net_overage, unsigned int net_max) -{ - unsigned int tot_overage; - unsigned int tot_max; - unsigned int fair_level; - unsigned int step; - - if (req_index(c) >= c->e0_index) - return req_index(c); - - tot_overage = net_overage + c->manager->remaining; - if (cur_overage(c)) - tot_overage += cur_overage(c); - else - tot_overage -= e0_level(c) - cur_level(c); - tot_max = net_max + c->states[0]; - fair_level = tot_overage * c->states[0] / tot_max + e0_level(c); - step = max(fair_level, cur_level(c) + c->manager->remaining) - - cur_level(c); - - return edp_promotion_point(c, step); -} - -static void find_net(struct edp_client *client, unsigned int *net_overage, - unsigned int *net_max) -{ - struct edp_client *c; - struct edp_manager *m = client->manager; - - *net_overage = 0; - *net_max = 0; - - list_for_each_entry(c, &m->clients, link) { - if (c != client && cur_level(c) > e0_level(c)) { - *net_overage += cur_overage(c); - *net_max += c->states[0]; - } - } -} - -static struct edp_client *throttle_pledge(struct edp_client *client, - unsigned int required, unsigned int net_overage, - unsigned int *pledged) -{ - struct edp_manager *m = client->manager; - unsigned int deficit = required - m->remaining; - struct edp_client *c; - unsigned int step; - - *pledged = m->remaining; - - list_for_each_entry_reverse(c, &m->clients, link) { - if (c == client || cur_level(c) <= e0_level(c)) - continue; - - step = (deficit * cur_overage(c) + - net_overage - 1) / net_overage; - c->gwt = edp_throttling_point(c, step); - *pledged += cur_level(c) - c->states[c->gwt]; - if (*pledged >= required) - return c; - } - - WARN_ON(*pledged < required); - return c; -} - -static void throttle_recover(struct edp_client *client, struct edp_client *tp, - unsigned int required) -{ - struct edp_manager *m = client->manager; - unsigned int recovered = m->remaining; - - list_for_each_entry_from(tp, &m->clients, link) { - if (tp == client || cur_level(tp) <= e0_level(tp) || - tp->gwt == cur_index(tp)) - continue; - - tp->throttle(tp->gwt, tp->private_data); - recovered += cur_level(tp) - tp->states[tp->gwt]; - if (tp->cur == tp->req) - m->num_denied++; - - tp->cur = tp->states + tp->gwt; - if (recovered >= required) - return; - } -} - -static void throttle(struct edp_client *client) -{ - struct edp_manager *m = client->manager; - struct edp_client *tp; - unsigned int ar; - unsigned int pledged; - unsigned int required; - unsigned int net_overage; - unsigned int net_max; - - find_net(client, &net_overage, &net_max); - ar = approvable_req(client, net_overage, net_max); - required = client->states[ar] - cur_level(client); - - if (required <= m->remaining) { - client->cur = client->states + ar; - m->remaining -= required; - return; - } - - tp = throttle_pledge(client, required, net_overage, &pledged); - - /* E-states are discrete - we may get more than we asked for */ - if (pledged > required && ar != req_index(client)) { - ar = edp_promotion_point(client, pledged); - required = client->states[ar] - cur_level(client); - } - - throttle_recover(client, tp, required); - client->cur = client->states + ar; - m->remaining = pledged - required; -} - -static void overage_update_request(struct edp_client *client, - const unsigned int *req) -{ - edp_default_update_request(client, req, throttle); -} - -static unsigned int overage_promotion_point(struct edp_client *c, - unsigned int step, unsigned int max) -{ - unsigned int lim = cur_level(c) + step; - unsigned int ci = cur_index(c); - unsigned int i = req_index(c); - - while (i < ci && c->states[i] > lim) - i++; - - /* - * While being throttled, we probably contributed more than our - * fare share - so take the ceiling E-state here - */ - if (c->states[i] < lim && i > req_index(c)) { - if (c->states[i - 1] <= cur_level(c) + max) - i--; - } - - return i; -} - -static void overage_promote(struct edp_manager *mgr) -{ - unsigned int budget = mgr->remaining; - unsigned int net_overage = 0; - struct edp_client *c; - unsigned int step; - unsigned int pp; - - list_for_each_entry(c, &mgr->clients, link) { - if (req_level(c) > cur_level(c) && c->notify_promotion) - net_overage += req_overage(c); - } - - /* Guarding against division-by-zero */ - if (!net_overage) { - WARN_ON(1); - return; - } - - list_for_each_entry(c, &mgr->clients, link) { - if (req_level(c) <= cur_level(c) || !c->notify_promotion) - continue; - - step = (req_overage(c) * budget + - net_overage - 1) / net_overage; - if (step > mgr->remaining) - step = mgr->remaining; - - pp = overage_promotion_point(c, step, mgr->remaining); - if (pp == cur_index(c)) - continue; - - mgr->remaining -= c->states[pp] - cur_level(c); - c->cur = c->states + pp; - - if (c->cur == c->req) - mgr->num_denied--; - c->notify_promotion(pp, c->private_data); - if (!mgr->remaining || !mgr->num_denied) - return; - } -} - -static struct edp_governor overage_governor = { - .name = "overage", - .owner = THIS_MODULE, - .update_request = overage_update_request, - .update_loans = edp_default_update_loans, - .promote = overage_promote -}; - -static int __init overage_init(void) -{ - return edp_register_governor(&overage_governor); -} -postcore_initcall(overage_init); diff --git a/drivers/edp/edp_priority.c b/drivers/edp/edp_priority.c deleted file mode 100644 index 937c20bdf16e..000000000000 --- a/drivers/edp/edp_priority.c +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include "edp_internal.h" - -/* - * Calculate the approvable E-state for the requesting client. - * Non-negative E-state requests are always approved. A (higher) - * negative E-state request is approved only if lower priority clients - * can be throttled (at most to E0) in order to recover the necessary - * power deficit. If this can not be met, a lower E-state is approved - * (at least E0). - */ -static unsigned int approvable_req(struct edp_client *client) -{ - struct edp_manager *m = client->manager; - unsigned int old = cur_level(client); - unsigned int deficit = *client->req - old; - unsigned int recoverable = m->remaining; - unsigned int i = req_index(client); - struct edp_client *p = client; - - if (i >= client->e0_index) - return i; - - list_for_each_entry_continue(p, &m->clients, link) { - if (cur_level(p) > e0_level(p)) { - recoverable += cur_level(p) - e0_level(p); - if (recoverable >= deficit) - return i; - } - } - - while (i < client->e0_index && recoverable < deficit) { - i++; - deficit = client->states[i] - old; - } - - return i; -} - -static void throttle(struct edp_client *client) -{ - unsigned int ar; - unsigned int deficit; - struct edp_client *p; - struct edp_manager *m = client->manager; - unsigned int pledged = m->remaining; - unsigned int recovered = m->remaining; - - /* Check if we can satisfy the request as it is */ - ar = approvable_req(client); - deficit = client->states[ar] - cur_level(client); - if (m->remaining >= deficit) - goto ret; - - /* - * We do the throttling in two steps: first we will identify and - * mark the clients starting from the lower priority ones. We - * stop when we find the highest priority client that should be - * throttled. - */ - list_for_each_entry_reverse(p, &m->clients, link) { - if (p == client || cur_level(p) <= e0_level(p)) - continue; - - p->gwt = edp_throttling_point(p, deficit - pledged); - pledged += cur_level(p) - p->states[p->gwt]; - if (pledged >= deficit) - break; - } - - /* - * By now, we are guaranteed to have at least the adjusted - * deficit - may be even more. - */ - WARN_ON(pledged < deficit); - - /* - * We now do the actual throttling starting from where we stoped - * in step 1 and going in the opposite direction. This way we - * can avoid situations where clients are throttled needlessly - * and promoted back immediately. - */ - list_for_each_entry_from(p, &m->clients, link) { - if (p == client || cur_level(p) <= e0_level(p) || - p->gwt == cur_index(p)) - continue; - - p->throttle(p->gwt, p->private_data); - recovered += cur_level(p) - p->states[p->gwt]; - if (p->cur == p->req) - m->num_denied++; - - p->cur = p->states + p->gwt; - if (recovered >= deficit) - break; - } - -ret: - client->cur = client->states + ar; - m->remaining = recovered - deficit; -} - -static void prio_update_request(struct edp_client *client, - const unsigned int *req) -{ - 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 (req_level(p) <= cur_level(p) || !p->notify_promotion) - continue; - - delta = req_level(p) - cur_level(p); - if (delta > mgr->remaining) - delta = mgr->remaining; - - pp = edp_promotion_point(p, delta); - if (pp == cur_index(p)) - continue; - - mgr->remaining -= p->states[pp] - cur_level(p); - p->cur = p->states + pp; - - if (p->cur == p->req) - mgr->num_denied--; - - p->notify_promotion(pp, p->private_data); - if (!mgr->remaining || !mgr->num_denied) - return; - } -} - -static struct edp_governor prio_governor = { - .name = "priority", - .owner = THIS_MODULE, - .update_request = prio_update_request, - .update_loans = edp_default_update_loans, - .promote = prio_promote -}; - -static int __init prio_init(void) -{ - return edp_register_governor(&prio_governor); -} -postcore_initcall(prio_init); diff --git a/drivers/edp/edp_sysfs.c b/drivers/edp/edp_sysfs.c deleted file mode 100644 index 721a3902a5ee..000000000000 --- a/drivers/edp/edp_sysfs.c +++ /dev/null @@ -1,511 +0,0 @@ -/* - * Copyright (c) 2012-2013, NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include "edp_internal.h" - -static struct kobject edp_kobj; - -struct manager_entry { - struct edp_manager *manager; - struct kobject kobj; -}; - -struct manager_attr { - struct attribute attr; - ssize_t (*show)(struct edp_manager *, char *); - ssize_t (*store)(struct edp_manager *, const char *, size_t); -}; - -static ssize_t cap_show(struct edp_manager *m, char *s) -{ - return scnprintf(s, PAGE_SIZE, "%u\n", m->max); -} - -static ssize_t remaining_show(struct edp_manager *m, char *s) -{ - return scnprintf(s, PAGE_SIZE, "%u\n", m->remaining); -} - -static ssize_t denied_show(struct edp_manager *m, char *s) -{ - return scnprintf(s, PAGE_SIZE, "%u\n", m->num_denied); -} - -static ssize_t manager_governor_show(struct edp_manager *m, char *s) -{ - return scnprintf(s, PAGE_SIZE, "%s\n", m->gov ? m->gov->name : ""); -} - -static ssize_t manager_governor_store(struct edp_manager *m, const char *s, - size_t count) -{ - char name[EDP_NAME_LEN]; - struct edp_governor *gov; - - if (!count || count >= sizeof(name)) - return -EINVAL; - - memcpy(name, s, count); - name[count] = 0; - strim(name); - gov = edp_find_governor_unlocked(name); - if (!gov) - return -EINVAL; - - return edp_set_governor_unlocked(m, gov) ?: count; -} - -struct manager_attr attr_cap = __ATTR_RO(cap); -struct manager_attr attr_remaining = __ATTR_RO(remaining); -struct manager_attr attr_denied = __ATTR_RO(denied); -struct manager_attr attr_mgr_gov = __ATTR(governor, 0644, - manager_governor_show, manager_governor_store); - -static struct attribute *manager_attrs[] = { - &attr_cap.attr, - &attr_remaining.attr, - &attr_denied.attr, - &attr_mgr_gov.attr, - NULL -}; - -static struct edp_manager *to_manager(struct kobject *kobj) -{ - struct manager_entry *me = container_of(kobj, struct manager_entry, - kobj); - return me ? me->manager : NULL; -} - -static ssize_t manager_state_show(struct kobject *kobj, - struct attribute *attr, char *buf) -{ - ssize_t r; - struct edp_manager *m; - struct manager_attr *mattr; - - mutex_lock(&edp_lock); - m = to_manager(kobj); - mattr = container_of(attr, struct manager_attr, attr); - r = m && mattr ? mattr->show(m, buf) : -EINVAL; - mutex_unlock(&edp_lock); - - return r; -} - -static ssize_t manager_state_store(struct kobject *kobj, - struct attribute *attr, const char *buf, size_t count) -{ - ssize_t r; - struct edp_manager *m; - struct manager_attr *mattr; - - mutex_lock(&edp_lock); - m = to_manager(kobj); - mattr = container_of(attr, struct manager_attr, attr); - r = m && mattr ? mattr->store(m, buf, count) : -EINVAL; - mutex_unlock(&edp_lock); - - return r; -} - -static const struct sysfs_ops manager_sysfs_ops = { - .show = manager_state_show, - .store = manager_state_store -}; - -static struct kobj_type ktype_manager = { - .sysfs_ops = &manager_sysfs_ops, - .default_attrs = manager_attrs -}; - -void edp_manager_add_kobject(struct edp_manager *mgr) -{ - struct manager_entry *me; - - me = kzalloc(sizeof(*me), GFP_KERNEL); - if (!me) { - pr_err("%s: failed to alloc sysfs manager entry\n", - mgr->name); - return; - } - - if (kobject_init_and_add(&me->kobj, &ktype_manager, &edp_kobj, - mgr->name)) { - pr_err("%s: failed to init & add sysfs manager entry\n", - mgr->name); - kfree(me); - return; - } - - me->manager = mgr; - mgr->kobj = &me->kobj; - kobject_uevent(&me->kobj, KOBJ_ADD); - return; -} - -void edp_manager_remove_kobject(struct edp_manager *mgr) -{ - struct manager_entry *me; - - if (!mgr->kobj) - return; - - me = container_of(mgr->kobj, struct manager_entry, kobj); - mgr->kobj = NULL; - kobject_put(&me->kobj); - kfree(me); -} - -struct client_entry { - struct edp_client *client; - struct kobject kobj; -}; - -static ssize_t states_show(struct edp_client *c, - struct edp_client_attribute *attr, char *s) -{ - unsigned int i; - int cnt = 0; - const int sz = sizeof(*c->states) * 3 + 2; - - for (i = 0; i < c->num_states && (cnt + sz) < PAGE_SIZE; i++) - cnt += sprintf(s + cnt, "%s%u", i ? " " : "", c->states[i]); - - cnt += sprintf(s + cnt, "\n"); - return cnt; -} - -static ssize_t num_states_show(struct edp_client *c, - struct edp_client_attribute *attr, char *s) -{ - return scnprintf(s, PAGE_SIZE, "%u\n", c->num_states); -} - -static ssize_t e0_show(struct edp_client *c, - struct edp_client_attribute *attr, char *s) -{ - return scnprintf(s, PAGE_SIZE, "%u\n", c->states[c->e0_index]); -} - -static ssize_t max_borrowers_show(struct edp_client *c, - struct edp_client_attribute *attr, char *s) -{ - return scnprintf(s, PAGE_SIZE, "%u\n", c->max_borrowers); -} - -static ssize_t priority_show(struct edp_client *c, - struct edp_client_attribute *attr, char *s) -{ - return scnprintf(s, PAGE_SIZE, "%d\n", c->priority); -} - -static ssize_t request_show(struct edp_client *c, - struct edp_client_attribute *attr, char *s) -{ - 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, - struct edp_client_attribute *attr, const char *s, size_t count) -{ - unsigned int id; - int r; - - if (sscanf(s, "%u", &id) != 1) - return -EINVAL; - - mutex_lock(&edp_lock); - - if (id >= c->num_states) { - r = -EINVAL; - goto out; - } - - if (id < c->e0_index && id < req_index(c)) { - r = -EPERM; - goto out; - } - - r = edp_update_client_request_unlocked(c, id, NULL); - -out: - mutex_unlock(&edp_lock); - return r ?: count; -} - -static ssize_t current_show(struct edp_client *c, - struct edp_client_attribute *attr, char *s) -{ - return scnprintf(s, PAGE_SIZE, "%u\n", cur_level(c)); -} - -static ssize_t threshold_show(struct edp_client *c, - struct edp_client_attribute *attr, char *s) -{ - return scnprintf(s, PAGE_SIZE, "%u\n", c->ithreshold); -} - -static ssize_t threshold_store(struct edp_client *c, - struct edp_client_attribute *attr, const char *s, size_t count) -{ - unsigned int tv; - int r; - - if (sscanf(s, "%u", &tv) != 1) - return -EINVAL; - - r = edp_update_loan_threshold(c, tv); - return r ?: count; -} - -static ssize_t borrowers_show(struct edp_client *c, - struct edp_client_attribute *attr, char *s) -{ - return scnprintf(s, PAGE_SIZE, "%u\n", c->num_borrowers); -} - -static ssize_t loans_show(struct edp_client *c, - struct edp_client_attribute *attr, char *s) -{ - return scnprintf(s, PAGE_SIZE, "%u\n", c->num_loans); -} - -static ssize_t notify_show(struct edp_client *c, - struct edp_client_attribute *attr, char *s) -{ - return scnprintf(s, PAGE_SIZE, "%u\n", c->notify_ui); -} - -static ssize_t notify_store(struct edp_client *c, - struct edp_client_attribute *attr, const char *s, size_t count) -{ - unsigned int f; - - if (sscanf(s, "%u", &f) != 1) - return -EINVAL; - c->notify_ui = f; - return count; -} - -struct edp_client_attribute attr_states = __ATTR_RO(states); -struct edp_client_attribute attr_num_states = __ATTR_RO(num_states); -struct edp_client_attribute attr_e0 = __ATTR_RO(e0); -struct edp_client_attribute attr_max_borrowers = __ATTR_RO(max_borrowers); -struct edp_client_attribute attr_priority = __ATTR_RO(priority); -struct edp_client_attribute attr_request = __ATTR(request, 0644, request_show, - request_store); -struct edp_client_attribute attr_threshold = __ATTR(threshold, 0644, - threshold_show, threshold_store); -struct edp_client_attribute attr_borrowers = __ATTR_RO(borrowers); -struct edp_client_attribute attr_loans = __ATTR_RO(loans); -struct edp_client_attribute attr_current = { - .attr = { .name = "current", .mode = 0444 }, - .show = current_show -}; -struct edp_client_attribute attr_notify = __ATTR(notify, 0644, notify_show, - notify_store); - -static struct attribute *client_attrs[] = { - &attr_states.attr, - &attr_num_states.attr, - &attr_e0.attr, - &attr_max_borrowers.attr, - &attr_priority.attr, - &attr_request.attr, - &attr_current.attr, - &attr_threshold.attr, - &attr_borrowers.attr, - &attr_loans.attr, - &attr_notify.attr, - NULL -}; - -static struct edp_client *to_client(struct kobject *kobj) -{ - struct client_entry *ce = container_of(kobj, struct client_entry, - kobj); - return ce ? ce->client : NULL; -} - -static ssize_t client_state_show(struct kobject *kobj, - struct attribute *attr, char *buf) -{ - ssize_t r = -EINVAL; - struct edp_client *c; - struct edp_client_attribute *cattr; - - c = to_client(kobj); - cattr = container_of(attr, struct edp_client_attribute, attr); - if (c && cattr) { - if (cattr->show) - r = cattr->show(c, cattr, buf); - } - - 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 edp_client_attribute *cattr; - - c = to_client(kobj); - cattr = container_of(attr, struct edp_client_attribute, attr); - if (c && cattr) { - if (cattr->store) - r = cattr->store(c, cattr, buf, count); - } - - return r; -} - -static const struct sysfs_ops client_sysfs_ops = { - .show = client_state_show, - .store = client_state_store -}; - -static struct kobj_type ktype_client = { - .sysfs_ops = &client_sysfs_ops, - .default_attrs = client_attrs -}; - -static void create_driver_attrs(struct edp_client *c) -{ - struct edp_client_attribute *p; - int r; - - if (!c->attrs) - return; - - for (p = c->attrs; attr_name(*p); p++) { - r = sysfs_create_file(c->kobj, &p->attr); - WARN_ON(r); - } -} - -static void remove_driver_attrs(struct edp_client *c) -{ - struct edp_client_attribute *p; - - if (!c->attrs) - return; - - for (p = c->attrs; attr_name(*p); p++) - sysfs_remove_file(c->kobj, &p->attr); -} - -void edp_client_add_kobject(struct edp_client *client) -{ - struct client_entry *ce; - struct kobject *parent = client->manager->kobj; - - if (!parent) - return; - - ce = kzalloc(sizeof(*ce), GFP_KERNEL); - if (!ce) { - pr_err("%s: failed to alloc sysfs client entry\n", - client->name); - return; - } - - if (kobject_init_and_add(&ce->kobj, &ktype_client, parent, - client->name)) { - pr_err("%s: failed to init & add sysfs client entry\n", - client->name); - kfree(ce); - return; - } - - ce->client = client; - client->kobj = &ce->kobj; - create_driver_attrs(client); - kobject_uevent(&ce->kobj, KOBJ_ADD); -} - -void edp_client_remove_kobject(struct edp_client *client) -{ - struct client_entry *ce; - - if (!client->kobj) - return; - - ce = container_of(client->kobj, struct client_entry, kobj); - - remove_driver_attrs(client); - client->kobj = NULL; - kobject_put(&ce->kobj); - kfree(ce); -} - -static ssize_t governors_show(struct kobject *kobj, struct attribute *attr, - char *s) -{ - struct edp_governor *g; - int cnt = 0; - - mutex_lock(&edp_lock); - - list_for_each_entry(g, &edp_governors, link) { - if (cnt + EDP_NAME_LEN + 2 >= PAGE_SIZE) - break; - cnt += sprintf(s + cnt, "%s%s", cnt ? " " : "", g->name); - } - - cnt += sprintf(s + cnt, "\n"); - - mutex_unlock(&edp_lock); - - return cnt; -} - -static const struct sysfs_ops edp_sysfs_ops = { - .show = governors_show -}; - -static struct attribute attr_governors = { - .name = "governors", - .mode = 0444 -}; - -static struct attribute *edp_attrs[] = { - &attr_governors, - NULL -}; - -static struct kobj_type ktype_edp = { - .sysfs_ops = &edp_sysfs_ops, - .default_attrs = edp_attrs -}; - -static int __init edp_sysfs_init(void) -{ - struct kobject *parent = NULL; - -#ifdef CONFIG_PM - parent = power_kobj; -#endif - - return kobject_init_and_add(&edp_kobj, &ktype_edp, parent, "edp"); -} -postcore_initcall(edp_sysfs_init); diff --git a/drivers/edp/edp_temporal.c b/drivers/edp/edp_temporal.c deleted file mode 100644 index 5db123e6e29a..000000000000 --- a/drivers/edp/edp_temporal.c +++ /dev/null @@ -1,234 +0,0 @@ -/* - * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include "edp_internal.h" - -/* - * This file implements the (1) LRR: least recently requested (2) MRR: - * most recently requested and (3) RR: round robin governors. - * - * Since they are all based on some timestamps, we use a simple list - * (the 'temporal list') for ordering the clients according to the main - * selection criteria. This list is maintained in such a way that - * throttle-victims appear at the tail and promotions are done from the - * head. - */ - -static void throttle(struct edp_client *client); - -/* Temporal list is manager specific */ -static int temporal_start(struct edp_manager *m) -{ - struct list_head *head; - struct edp_client *c; - - head = kzalloc(sizeof(*head), GFP_KERNEL); - if (!head) - return -ENOMEM; - - INIT_LIST_HEAD(head); - m->gov_data = head; - - list_for_each_entry(c, &m->clients, link) { - if (req_index(c) < c->e0_index) - list_add(&c->glnk, head); - } - - return 0; -} - -static void temporal_stop(struct edp_manager *m) -{ - kfree(m->gov_data); - m->gov_data = NULL; -} - -/* - * We need to remember only those clients that can either be throttled - * or promoted - this way, we have a smaller list. - */ -static void lrr_update_request(struct edp_client *client, - const unsigned int *req) -{ - struct list_head *head; - - if (req_index(client) < client->e0_index) - list_del(&client->glnk); - - edp_default_update_request(client, req, throttle); - - if (req_index(client) < client->e0_index) { - head = client->manager->gov_data; - list_add(&client->glnk, head); - } -} - -/* - * We need to remember only those clients that can either be throttled - * or promoted - this way, we have a smaller list. - */ -static void mrr_update_request(struct edp_client *client, - const unsigned int *req) -{ - struct list_head *head; - - if (req_index(client) < client->e0_index) - list_del(&client->glnk); - - edp_default_update_request(client, req, throttle); - - if (req_index(client) < client->e0_index) { - head = client->manager->gov_data; - list_add_tail(&client->glnk, head); - } -} - -static void rr_update_request(struct edp_client *client, - const unsigned int *req) -{ - struct list_head *head; - - /* new entry */ - if (!client->req) { - head = client->manager->gov_data; - list_add(&client->glnk, head); - } - - edp_default_update_request(client, req, throttle); -} - -static void temporal_promote(struct edp_manager *m) -{ - struct list_head *head = m->gov_data; - struct edp_client *c; - unsigned int i; - - list_for_each_entry(c, head, glnk) { - if (req_level(c) <= cur_level(c) || !c->notify_promotion) - continue; - - i = edp_promotion_point(c, m->remaining); - if (i == cur_index(c)) - continue; - - m->remaining -= c->states[i] - cur_level(c); - c->cur = c->states + i; - if (c->cur == c->req) - m->num_denied--; - - c->notify_promotion(i, c->private_data); - if (!m->remaining || !m->num_denied) - return; - } -} - -#define DEFINE_TEMPORAL_GOV(_gov, _name, _func) \ - struct edp_governor _gov = { \ - .name = _name, \ - .owner = THIS_MODULE, \ - .start = temporal_start, \ - .stop = temporal_stop, \ - .update_request = _func, \ - .update_loans = edp_default_update_loans, \ - .promote = temporal_promote \ - }; - -static DEFINE_TEMPORAL_GOV(lrr_governor, "least_recent", lrr_update_request); -static DEFINE_TEMPORAL_GOV(mrr_governor, "most_recent", mrr_update_request); -static DEFINE_TEMPORAL_GOV(rr_governor, "round_robin", rr_update_request); - -static void throttle(struct edp_client *client) -{ - struct edp_manager *m = client->manager; - unsigned int required = req_level(client) - cur_level(client); - struct list_head *head = m->gov_data; - struct edp_client *n; - struct edp_client *c; - unsigned int bal; - - bal = m->remaining; - n = NULL; - - list_for_each_entry_reverse(c, head, glnk) { - if (cur_level(c) > e0_level(c) && c != client) { - c->gwt = edp_throttling_point(c, required - bal); - bal += cur_level(c) - c->states[c->gwt]; - n = c; - if (bal >= required) - break; - } - } - - c = n; - bal = m->remaining; - if (!c) - goto finish; - - /* use the safe version as we might be re-arraging the list */ - list_for_each_entry_safe_from(c, n, head, glnk) { - if (cur_level(c) <= e0_level(c) || c == client || - c->gwt == cur_index(c)) - continue; - - c->throttle(c->gwt, c->private_data); - bal += cur_level(c) - c->states[c->gwt]; - if (c->cur == c->req) - m->num_denied++; - c->cur = c->states + c->gwt; - - /* for RR, move this client to the head */ - if (m->gov == &rr_governor) - list_move(&c->glnk, head); - if (bal >= required) - break; - } - -finish: - m->remaining = bal + cur_level(client); - client->cur = client->states + edp_promotion_point(client, bal); - m->remaining -= cur_level(client); -} - -static int __init temporal_init(void) -{ - int ret = 0; - int r; - - r = edp_register_governor(&lrr_governor); - if (r) { - pr_err("least_recent governor registration failed: %d\n", r); - ret = r; - } - - r = edp_register_governor(&mrr_governor); - if (r) { - pr_err("most_recent governor registration failed: %d\n", r); - ret = r; - } - - r = edp_register_governor(&rr_governor); - if (r) { - pr_err("round_robin governor registration failed: %d\n", r); - ret = r; - } - - return ret; -} -postcore_initcall(temporal_init); diff --git a/drivers/edp/psy_depletion.c b/drivers/edp/psy_depletion.c deleted file mode 100644 index e31b07609768..000000000000 --- a/drivers/edp/psy_depletion.c +++ /dev/null @@ -1,414 +0,0 @@ -/* - * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DEPL_INTERVAL 60000 - -struct depl_driver { - struct edp_client client; - struct psy_depletion_platform_data *pdata; - struct delayed_work work; - struct edp_manager *manager; - struct power_supply *psy; - bool emulator_mode; - int capacity; - int (*get_ocv)(struct depl_driver *drv, unsigned int capacity); -}; - -static int depl_psy_get_property(struct depl_driver *drv, - enum power_supply_property psp, int *val) -{ - union power_supply_propval pv; - - if (!drv->psy) - return -ENODEV; - if (drv->psy->get_property(drv->psy, psp, &pv)) - return -EFAULT; - if (val) - *val = pv.intval; - return 0; -} - -static int depl_psy_ocv_from_chip(struct depl_driver *drv, - unsigned int capacity) -{ - int val; - if (depl_psy_get_property(drv, POWER_SUPPLY_PROP_VOLTAGE_OCV, &val)) - return drv->pdata->vsys_min; - return val; -} - -static int depl_psy_capacity(struct depl_driver *drv) -{ - int val; - if (drv->emulator_mode) - return drv->capacity; - if (depl_psy_get_property(drv, POWER_SUPPLY_PROP_CAPACITY, &val)) - return 0; - return val; -} - -static unsigned int depl_psy_temp(struct depl_driver *drv) -{ - int val; - if (depl_psy_get_property(drv, POWER_SUPPLY_PROP_TEMP, &val)) - return 25; - return max(0, val); -} - -static inline unsigned int depl_maximum(struct depl_driver *drv) -{ - return drv->client.states[0]; -} - -/* Given two points (x1, y1) and (x2, y2), find the y coord of x */ -static int depl_interpolate(int x, int x1, int y1, int x2, int y2) -{ - if (x1 == x2) - return y1; - return (y2 * (x - x1) - y1 * (x - x2)) / (x2 - x1); -} - -static int depl_psy_ocv_from_lut(struct depl_driver *drv, - unsigned int capacity) -{ - struct psy_depletion_ocv_lut *p; - struct psy_depletion_ocv_lut *q; - - p = drv->pdata->ocv_lut; - - while (p->capacity > capacity) - p++; - - if (p == drv->pdata->ocv_lut) - return p->ocv; - - q = p - 1; - - return depl_interpolate(capacity, p->capacity, p->ocv, q->capacity, - q->ocv); -} - -/* Calc RBAT for current capacity (SOC) */ -static int depl_rbat(struct depl_driver *drv, unsigned int capacity) -{ - struct psy_depletion_rbat_lut *p; - struct psy_depletion_rbat_lut *q; - int rbat; - - rbat = drv->pdata->r_const; - p = drv->pdata->rbat_lut; - if (!p) - return rbat; - - while (p->capacity > capacity) - p++; - - if (p == drv->pdata->rbat_lut) - return rbat + p->rbat; - - q = p - 1; - - rbat += depl_interpolate(capacity, p->capacity, p->rbat, - q->capacity, q->rbat); - return rbat; -} - -static s64 depl_ibat_possible(struct depl_driver *drv, s64 ocv, s64 rbat) -{ - return div64_s64(1000 * (ocv - drv->pdata->vsys_min), rbat); -} - -/* Calc IBAT for a given temperature */ -static int depl_ibat(struct depl_driver *drv, unsigned int temp) -{ - struct psy_depletion_ibat_lut *p; - struct psy_depletion_ibat_lut *q; - int ibat; - - p = drv->pdata->ibat_lut; - while (p->ibat && p->temp > temp) - p++; - - if (p == drv->pdata->ibat_lut || !p->ibat) - return p->ibat; - - q = p - 1; - ibat = depl_interpolate(temp, p->temp, p->ibat, q->temp, q->ibat); - - return ibat; -} - -static s64 depl_pbat(s64 ocv, s64 ibat, s64 rbat) -{ - s64 pbat; - pbat = ocv - div64_s64(ibat * rbat, 1000); - pbat = div64_s64(pbat * ibat, 1000000); - return pbat; -} - -static unsigned int depl_calc(struct depl_driver *drv) -{ - unsigned int capacity; - s64 ocv; - s64 rbat; - s64 ibat_pos; - s64 ibat_tbat; - s64 ibat_lcm; - s64 pbat_lcm; - s64 pbat_nom; - s64 pbat_gain; - s64 depl; - - capacity = depl_psy_capacity(drv); - if (capacity >= 100) - return 0; - - ocv = drv->get_ocv(drv, capacity); - rbat = depl_rbat(drv, capacity); - - ibat_pos = depl_ibat_possible(drv, ocv, rbat); - ibat_tbat = depl_ibat(drv, depl_psy_temp(drv)); - ibat_lcm = min(ibat_pos, ibat_tbat); - - pbat_lcm = depl_pbat(ocv, ibat_lcm, rbat); - pbat_nom = depl_pbat(drv->pdata->vcharge, drv->pdata->ibat_nom, rbat); - pbat_gain = div64_s64(drv->manager->max * 1000, pbat_nom); - - depl = drv->manager->max - div64_s64(pbat_gain * pbat_lcm, 1000); - - pr_debug("capacity : %u\n", capacity); - pr_debug("ocv : %lld\n", ocv); - pr_debug("rbat : %lld\n", rbat); - pr_debug("ibat_pos : %lld\n", ibat_pos); - pr_debug("ibat_tbat: %lld\n", ibat_tbat); - pr_debug("ibat_lcm : %lld\n", ibat_lcm); - pr_debug("pbat_lcm : %lld\n", pbat_lcm); - pr_debug("pbat_nom : %lld\n", pbat_nom); - pr_debug("pbat_gain: %lld\n", pbat_gain); - pr_debug("depletion: %lld\n", depl); - - depl = clamp_t(s64, depl, 0, depl_maximum(drv)); - return depl; -} - -static void depl_update(struct work_struct *work) -{ - struct depl_driver *drv; - struct edp_client *c; - unsigned int depl; - unsigned int i; - - drv = container_of(work, struct depl_driver, work.work); - c = &drv->client; - depl = depl_calc(drv); - - i = c->num_states - 1; - while (i && c->states[i] < depl) - i--; - - edp_update_client_request(c, i, NULL); - - schedule_delayed_work(to_delayed_work(work), - msecs_to_jiffies(DEPL_INTERVAL)); -} - -/* Nothing to do */ -static void depl_edp_callback(unsigned int new_state, void *priv_data) -{ -} - -static void depl_shutdown(struct platform_device *pdev) -{ - struct depl_driver *drv = platform_get_drvdata(pdev); - cancel_delayed_work_sync(&drv->work); -} - -static int depl_suspend(struct platform_device *pdev, pm_message_t state) -{ - depl_shutdown(pdev); - return 0; -} - -static int depl_resume(struct platform_device *pdev) -{ - struct depl_driver *drv = platform_get_drvdata(pdev); - schedule_delayed_work(&drv->work, 0); - return 0; -} - -static int depl_init_ocv_reader(struct depl_driver *drv) -{ - if (!depl_psy_get_property(drv, POWER_SUPPLY_PROP_VOLTAGE_OCV, NULL)) - drv->get_ocv = depl_psy_ocv_from_chip; - else if (drv->pdata->ocv_lut) - drv->get_ocv = depl_psy_ocv_from_lut; - else - return -ENODEV; - - return 0; -} - -#ifdef CONFIG_DEBUG_FS -static int capacity_set(void *data, u64 val) -{ - struct depl_driver *drv = data; - - drv->capacity = clamp_t(int, val, 0, 100); - flush_delayed_work(&drv->work); - - return 0; -} - -static int capacity_get(void *data, u64 *val) -{ - struct depl_driver *drv = data; - *val = drv->capacity; - return 0; -} - -static int vsysmin_set(void *data, u64 val) -{ - struct depl_driver *drv = data; - - drv->pdata->vsys_min = val; - flush_delayed_work(&drv->work); - - return 0; -} - -static int vsysmin_get(void *data, u64 *val) -{ - struct depl_driver *drv = data; - *val = drv->pdata->vsys_min; - return 0; -} - -DEFINE_SIMPLE_ATTRIBUTE(capacity_fops, capacity_get, capacity_set, "%lld\n"); -DEFINE_SIMPLE_ATTRIBUTE(vsysmin_fops, vsysmin_get, vsysmin_set, "%lld\n"); - -static void init_debug(struct depl_driver *drv) -{ - struct dentry *d; - - if (!drv->client.dentry) { - WARN_ON(1); - return; - } - - d = debugfs_create_file("vsys_min", S_IRUGO | S_IWUSR, - drv->client.dentry, drv, &vsysmin_fops); - WARN_ON(IS_ERR_OR_NULL(d)); - - if (!drv->emulator_mode) - return; - - d = debugfs_create_file("capacity", S_IRUGO | S_IWUSR, - drv->client.dentry, drv, &capacity_fops); - WARN_ON(IS_ERR_OR_NULL(d)); -} -#else -static inline void init_debug(struct depl_driver *drv) {} -#endif - -static int depl_probe(struct platform_device *pdev) -{ - struct depl_driver *drv; - struct edp_manager *m; - struct edp_client *c; - int r = -EFAULT; - - if (!pdev->dev.platform_data) - return -EINVAL; - - m = edp_get_manager("battery"); - if (!m) { - dev_err(&pdev->dev, "could not get EDP manager\n"); - return -ENODEV; - } - - drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL); - if (!drv) - return -ENOMEM; - - drv->pdata = pdev->dev.platform_data; - drv->manager = m; - drv->psy = power_supply_get_by_name(drv->pdata->power_supply); - if (!drv->psy) { - if (!drv->pdata->ocv_lut) - goto fail; - drv->capacity = 100; - drv->emulator_mode = true; - } - - r = depl_init_ocv_reader(drv); - if (r) - goto fail; - - c = &drv->client; - strncpy(c->name, "depletion", EDP_NAME_LEN - 1); - c->name[EDP_NAME_LEN - 1] = 0; - c->priority = EDP_MAX_PRIO; - c->throttle = depl_edp_callback; - c->notify_promotion = depl_edp_callback; - c->states = drv->pdata->states; - c->num_states = drv->pdata->num_states; - c->e0_index = drv->pdata->e0_index; - - r = edp_register_client(m, c); - if (r) { - dev_err(&pdev->dev, "failed to register: %d\n", r); - goto fail; - } - - platform_set_drvdata(pdev, drv); - INIT_DEFERRABLE_WORK(&drv->work, depl_update); - schedule_delayed_work(&drv->work, 0); - - init_debug(drv); - - return 0; - -fail: - devm_kfree(&pdev->dev, drv); - return r; -} - -static struct platform_driver depl_driver = { - .probe = depl_probe, - .shutdown = depl_shutdown, - .suspend = depl_suspend, - .resume = depl_resume, - .driver = { - .name = "psy_depletion", - .owner = THIS_MODULE - } -}; - -static __init int depl_init(void) -{ - return platform_driver_register(&depl_driver); -} -late_initcall(depl_init); diff --git a/drivers/edp/tegra_core.c b/drivers/edp/tegra_core.c deleted file mode 100644 index cbde63f58837..000000000000 --- a/drivers/edp/tegra_core.c +++ /dev/null @@ -1,697 +0,0 @@ -/* - * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct freqcap { - unsigned int cpu; - unsigned int gpu; - unsigned int emc; -}; - -static unsigned int gpu_high_threshold = 500; -static unsigned int gpu_window = 80; -static unsigned int gpu_high_hist; -static unsigned int gpu_high_count = 2; -static unsigned int online_cpu_count; -static bool gpu_busy; -static unsigned int core_state; -static unsigned int core_loan; -static struct tegra_sysedp_corecap *cur_corecap; -static struct clk *emc_cap_clk; -static struct clk *gpu_cap_clk; -static struct pm_qos_request cpufreq_qos; -static unsigned int cpu_power_offset = 499; -static unsigned int cpu_power_balance; -static unsigned int force_gpu_pri; -static struct delayed_work core_work; -static unsigned int *core_edp_states; -static struct tegra_sysedp_platform_data *core_platdata; -static struct freqcap core_policy; -static struct freqcap forced_caps; -static struct freqcap cur_caps; -static DEFINE_MUTEX(core_lock); - -/* To save some cycles from a linear search */ -static unsigned int cpu_lut_match(unsigned int power, - struct tegra_system_edp_entry *lut, unsigned int lutlen) -{ - unsigned int fv; - unsigned int lv; - unsigned int step; - unsigned int i; - - if (lutlen == 1) - return 0; - - fv = lut[0].power_limit_100mW * 100; - lv = lut[lutlen - 1].power_limit_100mW * 100; - step = (lv - fv) / (lutlen - 1); - - i = (power - fv + step - 1) / step; - i = min_t(unsigned int, i, lutlen - 1); - if (lut[i].power_limit_100mW * 100 >= power) - return i; - - /* Didn't work, search back from the end */ - return lutlen - 1; -} - -static unsigned int get_cpufreq_lim(unsigned int power) -{ - struct tegra_system_edp_entry *p; - int i; - - i = cpu_lut_match(power, core_platdata->cpufreq_lim, - core_platdata->cpufreq_lim_size); - p = core_platdata->cpufreq_lim + i; - - for (; i > 0; i--, p--) { - if (p->power_limit_100mW * 100 <= power) - break; - } - - WARN_ON(p->power_limit_100mW > power); - return p->freq_limits[online_cpu_count - 1]; -} - -static void pr_caps(struct freqcap *old, struct freqcap *new, - unsigned int cpu_power) -{ - if (!IS_ENABLED(CONFIG_DEBUG_KERNEL)) - return; - - if (new->cpu == old->cpu && - new->gpu == old->gpu && - new->emc == old->emc) - return; - - pr_debug("sysedp: ncpus %u, gpupri %d, core %5u mW, " - "cpu %5u mW %u kHz, gpu %u kHz, emc %u kHz\n", - online_cpu_count, gpu_busy, cur_corecap->power, - cpu_power, new->cpu, new->gpu, new->emc); -} - -static void apply_caps(struct tegra_sysedp_devcap *devcap) -{ - struct freqcap new; - int r; - - core_policy.cpu = get_cpufreq_lim(devcap->cpu_power + - cpu_power_balance + - cpu_power_offset); - core_policy.gpu = devcap->gpufreq; - core_policy.emc = devcap->emcfreq; - - new.cpu = forced_caps.cpu ?: core_policy.cpu; - new.gpu = forced_caps.gpu ?: core_policy.gpu; - new.emc = forced_caps.emc ?: core_policy.emc; - - if (new.cpu != cur_caps.cpu) - pm_qos_update_request(&cpufreq_qos, new.cpu); - - if (new.emc != cur_caps.emc) { - r = clk_set_rate(emc_cap_clk, new.emc * 1000); - WARN_ON(r); - } - - if (new.gpu != cur_caps.gpu) { - r = clk_set_rate(gpu_cap_clk, new.gpu * 1000); - WARN_ON(r); - } - - pr_caps(&cur_caps, &new, devcap->cpu_power); - cur_caps = new; -} - -static inline bool gpu_priority(void) -{ - return gpu_busy || force_gpu_pri; -} - -static inline struct tegra_sysedp_devcap *get_devcap(void) -{ - return gpu_priority() ? &cur_corecap->gpupri : &cur_corecap->cpupri; -} - -static void __do_cap_control(void) -{ - struct tegra_sysedp_devcap *cap; - - if (!cur_corecap) - return; - - cap = get_devcap(); - apply_caps(cap); -} - -static void do_cap_control(void) -{ - mutex_lock(&core_lock); - __do_cap_control(); - mutex_unlock(&core_lock); -} - -static void update_cur_corecap(void) -{ - struct tegra_sysedp_corecap *cap; - unsigned int power; - int i; - - if (!core_platdata) - return; - - power = core_edp_states[core_state] * core_platdata->core_gain / 100; - power += core_loan; - i = core_platdata->corecap_size - 1; - cap = core_platdata->corecap + i; - - for (; i >= 0; i--, cap--) { - if (cap->power <= power) { - cur_corecap = cap; - cpu_power_balance = power - cap->power; - return; - } - } - - WARN_ON(1); - cur_corecap = core_platdata->corecap; -} - -static void state_change_cb(unsigned int new_state, void *priv_data) -{ - mutex_lock(&core_lock); - core_state = new_state; - update_cur_corecap(); - __do_cap_control(); - mutex_unlock(&core_lock); -} - -static unsigned int loan_update_cb(unsigned int new_size, - struct edp_client *lender, void *priv_data) -{ - mutex_lock(&core_lock); - core_loan = new_size; - update_cur_corecap(); - __do_cap_control(); - mutex_unlock(&core_lock); - return new_size; -} - -static void loan_close_cb(struct edp_client *lender, void *priv_data) -{ - loan_update_cb(0, lender, priv_data); -} - -static void core_worker(struct work_struct *work) -{ - if (!gpu_busy) - do_cap_control(); -} - -/* - * Return true if load was above threshold for at least - * gpu_high_count number of notifications - */ -static bool calc_gpu_busy(unsigned int load) -{ - unsigned int mask; - - mask = (1 << gpu_high_count) - 1; - - gpu_high_hist <<= 1; - if (load >= gpu_high_threshold) - gpu_high_hist |= 1; - - return (gpu_high_hist & mask) == mask; -} - -void tegra_edp_notify_gpu_load(unsigned int load) -{ - bool old; - - old = gpu_busy; - gpu_busy = calc_gpu_busy(load); - - if (gpu_busy == old || force_gpu_pri || !core_platdata) - return; - - cancel_delayed_work(&core_work); - - if (gpu_busy) - do_cap_control(); - else - schedule_delayed_work(&core_work, - msecs_to_jiffies(gpu_window)); -} - -static int tegra_edp_cpu_notify(struct notifier_block *nb, - unsigned long action, void *data) -{ - switch (action) { - case CPU_UP_PREPARE: - online_cpu_count = num_online_cpus() + 1; - break; - case CPU_DEAD: - online_cpu_count = num_online_cpus(); - break; - default: - return NOTIFY_OK; - } - - do_cap_control(); - return NOTIFY_OK; -} - -static struct notifier_block tegra_edp_cpu_nb = { - .notifier_call = tegra_edp_cpu_notify -}; - -static ssize_t core_request_store(struct edp_client *c, - struct edp_client_attribute *attr, const char *s, size_t count) -{ - unsigned int id; - unsigned int approved; - int r; - - if (sscanf(s, "%u", &id) != 1) - return -EINVAL; - - mutex_lock(&core_lock); - - r = edp_update_client_request(c, id, &approved); - if (r) - goto out; - - core_state = approved; - update_cur_corecap(); - __do_cap_control(); - -out: - mutex_unlock(&core_lock); - return r ?: count; -} - -struct edp_client_attribute core_attrs[] = { - __ATTR(set_request, 0200, NULL, core_request_store), - __ATTR_NULL -}; - -static struct edp_client core_client = { - .name = "core", - .priority = EDP_MIN_PRIO, - .throttle = state_change_cb, - .attrs = core_attrs, - .notify_promotion = state_change_cb, - .notify_loan_update = loan_update_cb, - .notify_loan_close = loan_close_cb -}; - -#ifdef CONFIG_DEBUG_FS -static int core_set(void *data, u64 val) -{ - unsigned int *pdata = data; - unsigned int old; - - old = *pdata; - *pdata = val; - - if (old != *pdata) { - /* Changes to core_gain require corecap update */ - if (pdata == &core_platdata->core_gain) - update_cur_corecap(); - do_cap_control(); - } - - return 0; -} - -static int core_get(void *data, u64 *val) -{ - unsigned int *pdata = data; - *val = *pdata; - return 0; -} - -DEFINE_SIMPLE_ATTRIBUTE(core_fops, core_get, core_set, "%lld\n"); - -static void create_attr(const char *name, unsigned int *data) -{ - struct dentry *d; - - d = debugfs_create_file(name, S_IRUGO | S_IWUSR, core_client.dentry, - data, &core_fops); - WARN_ON(IS_ERR_OR_NULL(d)); -} - -static inline void edp_show_2core_cpucaps(struct seq_file *file) -{ - int i; - struct tegra_system_edp_entry *p = core_platdata->cpufreq_lim; - - seq_printf(file, "%5s %10s %10s\n", - "Power", "1-core", "2-cores"); - - for (i = 0; i < core_platdata->cpufreq_lim_size; i++, p++) { - seq_printf(file, "%5d %10u %10u\n", - p->power_limit_100mW * 100, - p->freq_limits[0], - p->freq_limits[1]); - } -} - -static inline void edp_show_4core_cpucaps(struct seq_file *file) -{ - int i; - struct tegra_system_edp_entry *p = core_platdata->cpufreq_lim; - - seq_printf(file, "%5s %10s %10s %10s %10s\n", - "Power", "1-core", "2-cores", "3-cores", "4-cores"); - - for (i = 0; i < core_platdata->cpufreq_lim_size; i++, p++) { - seq_printf(file, "%5d %10u %10u %10u %10u\n", - p->power_limit_100mW * 100, - p->freq_limits[0], - p->freq_limits[1], - p->freq_limits[2], - p->freq_limits[3]); - } -} - -static int cpucaps_show(struct seq_file *file, void *data) -{ - unsigned int max_nr_cpus = num_possible_cpus(); - - if (core_platdata ? !core_platdata->cpufreq_lim : true) - return -ENODEV; - - if (max_nr_cpus == 2) - edp_show_2core_cpucaps(file); - else if (max_nr_cpus == 4) - edp_show_4core_cpucaps(file); - - return 0; -} - -static int corecaps_show(struct seq_file *file, void *data) -{ - int i; - struct tegra_sysedp_corecap *p; - struct tegra_sysedp_devcap *c; - struct tegra_sysedp_devcap *g; - - if (core_platdata ? !core_platdata->corecap : true) - return -ENODEV; - - p = core_platdata->corecap; - - seq_printf(file, "%s %s { %s %9s %9s } %s { %s %9s %9s }\n", - "E-state", - "CPU-pri", "CPU-mW", "GPU-kHz", "EMC-kHz", - "GPU-pri", "CPU-mW", "GPU-kHz", "EMC-kHz"); - - for (i = 0; i < core_platdata->corecap_size; i++, p++) { - c = &p->cpupri; - g = &p->gpupri; - seq_printf(file, "%7u %16u %9u %9u %18u %9u %9u\n", - p->power, - c->cpu_power, c->gpufreq, c->emcfreq, - g->cpu_power, g->gpufreq, g->emcfreq); - } - - return 0; -} - -static int status_show(struct seq_file *file, void *data) -{ - mutex_lock(&core_lock); - - seq_printf(file, "cpus online : %u\n", online_cpu_count); - seq_printf(file, "gpu priority: %u\n", gpu_priority()); - seq_printf(file, "E-state : %u\n", core_edp_states[core_state]); - seq_printf(file, "gain : %u\n", core_platdata->core_gain); - seq_printf(file, "loan : %u\n", core_loan); - seq_printf(file, "core cap : %u\n", cur_corecap->power); - seq_printf(file, "cpu balance : %u\n", cpu_power_balance); - seq_printf(file, "cpu offset : %u\n", cpu_power_offset); - seq_printf(file, "cpu power : %u\n", get_devcap()->cpu_power + - cpu_power_balance + cpu_power_offset); - seq_printf(file, "cpu cap : %u kHz\n", cur_caps.cpu); - seq_printf(file, "gpu cap : %u kHz\n", cur_caps.gpu); - seq_printf(file, "emc cap : %u kHz\n", cur_caps.emc); - - mutex_unlock(&core_lock); - return 0; -} - -static int longattr_open(struct inode *inode, struct file *file) -{ - return single_open(file, inode->i_private, NULL); -} - -static const struct file_operations longattr_fops = { - .open = longattr_open, - .read = seq_read, -}; - -static void create_longattr(const char *name, - int (*show)(struct seq_file *, void *)) -{ - struct dentry *d; - - d = debugfs_create_file(name, S_IRUGO, core_client.dentry, show, - &longattr_fops); - WARN_ON(IS_ERR_OR_NULL(d)); -} - -static void init_debug(void) -{ - if (!core_client.dentry) { - WARN_ON(1); - return; - } - - create_attr("cpu_offset", &cpu_power_offset); - create_attr("favor_gpu", &force_gpu_pri); - create_attr("gpu_threshold", &gpu_high_threshold); - create_attr("force_cpu", &forced_caps.cpu); - create_attr("force_gpu", &forced_caps.gpu); - create_attr("force_emc", &forced_caps.emc); - create_attr("gpu_window", &gpu_window); - create_attr("gain", &core_platdata->core_gain); - create_attr("gpu_high_count", &gpu_high_count); - - create_longattr("corecaps", corecaps_show); - create_longattr("cpucaps", cpucaps_show); - create_longattr("status", status_show); -} -#else -static inline void init_debug(void) {} -#endif - -static void register_loan(struct tegra_sysedp_platform_data *pdata) -{ - struct edp_client *c; - int r; - - if (!pdata->bbc) - return; - - c = edp_get_client(pdata->bbc); - if (!c) { - pr_info("Could not access modem EDP client\n"); - return; - } - - r = edp_register_loan(c, &core_client); - WARN_ON(r && r != -EEXIST); -} - -/* Power without gain */ -static unsigned int to_base_power(unsigned int power, - struct tegra_sysedp_platform_data *pdata) -{ - return (power * 100 + pdata->core_gain - 1) / pdata->core_gain; -} - -static unsigned int get_num_states( - struct tegra_sysedp_platform_data *pdata) -{ - unsigned int power = 0; - unsigned int num = 0; - unsigned int i; - - for (i = 0; i < pdata->corecap_size; i++) { - if (pdata->corecap[i].power != power) { - power = pdata->corecap[i].power; - num++; - } - } - - return num; -} - -static void get_states(struct tegra_sysedp_platform_data *pdata, - unsigned int num, unsigned int *states) -{ - unsigned int power = 0; - unsigned int e0i = 0; - unsigned int i; - - for (i = 0; i < pdata->corecap_size; i++) { - if (pdata->corecap[i].power == power) - continue; - - power = to_base_power(pdata->corecap[i].power, pdata); - states[num - e0i - 1] = power; - e0i++; - } -} - -static unsigned int initial_req(struct edp_client *client, - struct tegra_sysedp_platform_data *pdata) -{ - int i; - unsigned int watts; - - watts = to_base_power(pdata->init_req_watts, pdata); - - for (i = 0; i < client->num_states; i++) { - if (client->states[i] == watts) - return i; - } - - WARN_ON(1); - return 0; -} - -static int init_client(struct tegra_sysedp_platform_data *pdata) -{ - struct edp_manager *m; - unsigned int cnt; - unsigned int ei; - int r; - - m = edp_get_manager("battery"); - if (!m) - return -ENODEV; - - cnt = get_num_states(pdata); - if (!cnt) - return -EINVAL; - - core_edp_states = kzalloc(sizeof(*core_edp_states) * cnt, GFP_KERNEL); - if (!core_edp_states) - return -ENOMEM; - - get_states(pdata, cnt, core_edp_states); - - core_client.states = core_edp_states; - core_client.num_states = cnt; - core_client.e0_index = cnt - 1; - core_client.private_data = &core_client; - - r = edp_register_client(m, &core_client); - if (r) - goto fail; - - ei = initial_req(&core_client, pdata); - r = edp_update_client_request(&core_client, ei, &core_state); - if (r) - return r; - - register_loan(pdata); - return 0; - -fail: - kfree(core_edp_states); - core_edp_states = NULL; - return r; -} - -static int init_clks(void) -{ - emc_cap_clk = clk_get_sys("battery_edp", "emc"); - if (IS_ERR(emc_cap_clk)) - return -ENODEV; - - gpu_cap_clk = clk_get_sys("battery_edp", "gpu"); - if (IS_ERR(gpu_cap_clk)) { - clk_put(emc_cap_clk); - return -ENODEV; - } - - return 0; -} - -static int tegra_sysedp_probe(struct platform_device *pdev) -{ - int r; - - if (!pdev->dev.platform_data) - return -EINVAL; - - online_cpu_count = num_online_cpus(); - INIT_DELAYED_WORK(&core_work, core_worker); - pm_qos_add_request(&cpufreq_qos, PM_QOS_CPU_FREQ_MAX, - PM_QOS_CPU_FREQ_MAX_DEFAULT_VALUE); - - r = register_cpu_notifier(&tegra_edp_cpu_nb); - if (r) - return r; - - r = init_clks(); - if (r) - return r; - - r = init_client(pdev->dev.platform_data); - if (r) - return r; - - mutex_lock(&core_lock); - core_platdata = pdev->dev.platform_data; - update_cur_corecap(); - __do_cap_control(); - mutex_unlock(&core_lock); - - init_debug(); - - return 0; -} - -static struct platform_driver tegra_sysedp_driver = { - .probe = tegra_sysedp_probe, - .driver = { - .owner = THIS_MODULE, - .name = "tegra_sysedp" - } -}; - -static __init int tegra_sysedp_init(void) -{ - return platform_driver_register(&tegra_sysedp_driver); -} -late_initcall(tegra_sysedp_init); -- cgit v1.2.3