/* * Copyright (c) 2013-2014, 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 "sysedp_internal.h" struct dentry *edp_debugfs_dir; struct dentry *sysedp_debugfs_dir; static int sysedp_status_show(struct seq_file *file, void *data) { struct sysedp_consumer *c; int limit; /* Amount of power available when OC=1*/ int oc_relax; /* Additional power available when OC=0 */ int pmax_sum = 0; /* sum of peak values (OC=1) */ int pthres_sum = 0; /* sum of peak values (OC=0) */ mutex_lock(&sysedp_lock); list_for_each_entry(c, ®istered_consumers, link) { pmax_sum += _cur_oclevel(c); pthres_sum += _cur_level(c); } limit = (int)avail_budget - pmax_sum - margin; limit = limit >= min_budget ? limit : min_budget; oc_relax = pmax_sum - pthres_sum; oc_relax = oc_relax >= 0 ? oc_relax : 0; seq_printf(file, " avail_budget : %u\n", avail_budget); seq_printf(file, "- pmax_sum : %u\n", pmax_sum); seq_printf(file, "- margin : %d\n", margin); seq_printf(file, "( minimum budget : %d)\n", min_budget); seq_printf(file, "= remaining (OC=1) : %d\n", limit); seq_printf(file, "+ oc_relax : %d\n", oc_relax); seq_printf(file, "= remaining (OC=0) : %d\n", limit + oc_relax); seq_puts(file, "------------------------------------------\n"); seq_printf(file, "%-16s %7s %7s\n", "consumer", "pmax", "pthresh" ); seq_puts(file, "------------------------------------------\n"); list_for_each_entry(c, ®istered_consumers, link) seq_printf(file, "%-16s %7u %7u\n", c->name, _cur_oclevel(c), _cur_level(c)); mutex_unlock(&sysedp_lock); return 0; } static int sysedp_status_open(struct inode *inode, struct file *file) { return single_open(file, sysedp_status_show, inode->i_private); } static const struct file_operations sysedp_status_fops = { .open = sysedp_status_open, .read = seq_read, }; static int sysedp_min_budget_set(void *data, u64 val) { int old; old = min_budget; min_budget = (((int)val) < 0) ? 0 : (int)val; if (old != min_budget) { mutex_lock(&sysedp_lock); /* Changes to min_budget require sysedp refresh */ _sysedp_refresh(); mutex_unlock(&sysedp_lock); } return 0; } static int sysedp_min_budget_get(void *data, u64 *val) { *val = min_budget; return 0; } DEFINE_SIMPLE_ATTRIBUTE(sysedp_min_budget_fops, sysedp_min_budget_get, sysedp_min_budget_set, "%lld\n"); void sysedp_init_debugfs(void) { struct dentry *d; d = debugfs_create_dir("edp", NULL); if (IS_ERR_OR_NULL(d)) { WARN_ON(1); return; } edp_debugfs_dir = d; d = debugfs_create_dir("sysedp", edp_debugfs_dir); if (IS_ERR_OR_NULL(d)) { WARN_ON(1); return; } sysedp_debugfs_dir = d; d = debugfs_create_file("status", S_IRUGO, sysedp_debugfs_dir, NULL, &sysedp_status_fops); WARN_ON(IS_ERR_OR_NULL(d)); d = debugfs_create_file("min_budget", S_IRUGO | S_IWUSR, sysedp_debugfs_dir, NULL, &sysedp_min_budget_fops); WARN_ON(IS_ERR_OR_NULL(d)); }