?? proc.c
字號:
/* * drivers/dpm/proc.c Dynamic Power Management /proc * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Copyright (C) 2002, International Business Machines Corporation * All Rights Reserved * * Bishop Brock * IBM Research, Austin Center for Low-Power Computing * bcbrock@us.ibm.com * September, 2002 * */#include <linux/dpm.h>#include <linux/init.h>#include <linux/interrupt.h>#include <linux/mm.h>#include <linux/module.h>#include <linux/proc_fs.h>#include <linux/sched.h>#include <linux/slab.h>#include <linux/spinlock.h>#include <asm/semaphore.h>#include <asm/system.h>#include <asm/uaccess.h>#define DEBUG#ifdef DEBUG#define DPRINT(args...) printk(KERN_CRIT args)#else#define DPRINT(args...) do {} while (0)#endif/**************************************************************************** * /proc/driver/dpm interfaces * * NB: Some of these are borrowed from the 405LP, and may need to be made * machine independent. ****************************************************************************//*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ * /proc/driver/dpm/cmd (Write-Only) * * Writing a string to this file is equivalent to issuing a DPM command. * Currently only one command per "write" is allowed, and there is a maximum on * the number of tokens that will be accepted (PAGE_SIZE / sizeof(char *)). * DPM can be initialized by a linewise copy of a configuration file to this * /proc file. * * DPM Control * ----------- * * init : dpm_init() * enable : dpm_enable() * disable : dpm_disable() * terminate : dpm_terminate() * * Policy Control * -------------- * * set_policy <policy> : Set the policy by name * set_task_state <pid> <state> : Set the task state for a given pid, 0 = self * * Policy Creation * --------------- * * create_opt <name> <pp0> ... <ppn> * Create a named operating point from DPM_PP_NBR paramaters. All * parameters must be given. Parameter order and meaning are machine * dependent. * * create_class <name> <opt0> [ ... <optn> ] * Create a named class from 1 or more named operating points. All * operating points must be defined before the call. * * create_policy <name> <class0> ... <classn> * Create a named policy from DPM_STATES class names. All classes must be * defined before the call. The order is machine dependent. * *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/static voidpwarn(char *command, int ntoks, char *requirement, int require){ printk(KERN_WARNING "/proc/driver/dpm/cmd: " "Command %s requires %s%d arguments - %d were given\n", command, requirement, require - 1, ntoks - 1);}static int write_proc_dpm_cmd (struct file *file, const char *buffer, unsigned long count, void *data){ char *buf, *tok, **tokptrs; char *whitespace = " \t\r\n"; int ret = 0, ntoks; if (current->uid != 0) return -EACCES; if (count == 0) return 0; if (!(buf = kmalloc(count + 1, GFP_KERNEL))) return -ENOMEM; if (copy_from_user(buf, buffer, count)) { ret = -EFAULT; goto out0; } buf[count] = '\0'; if (!(tokptrs = (char **)__get_free_page(GFP_KERNEL))) { ret = -ENOMEM; goto out1; } ret = -EINVAL; ntoks = 0; do { buf = buf + strspn(buf, whitespace); tok = strsep(&buf, whitespace); if (*tok == '\0') { if (ntoks == 0) { ret = 0; goto out1; } else break; } if (ntoks == (PAGE_SIZE / sizeof(char **))) goto out1; tokptrs[ntoks++] = tok; } while(buf); if (ntoks == 1) { if (strcmp(tokptrs[0], "init") == 0) { ret = dpm_init(); } else if (strcmp(tokptrs[0], "enable") == 0) { ret = dpm_enable(); } else if (strcmp(tokptrs[0], "disable") == 0) { ret = dpm_disable(); } else if (strcmp(tokptrs[0], "terminate") == 0) { ret = dpm_terminate(); } } else if (ntoks == 2) { if (strcmp(tokptrs[0], "set_policy") == 0) ret = dpm_set_policy(tokptrs[1]); else if (strcmp(tokptrs[0], "set_state") == 0) ret = dpm_set_op_state(tokptrs[1]); } else { if (strcmp(tokptrs[0], "set_task_state") == 0) { if (ntoks != 3) pwarn("set_task_state", ntoks, "", 3); else ret = dpm_set_task_state(simple_strtol(tokptrs[1], NULL, 0), simple_strtol(tokptrs[2], NULL, 0)); } else if (strcmp(tokptrs[0], "create_opt") == 0) { if (ntoks != DPM_PP_NBR + 2) pwarn("create_opt", ntoks, "", DPM_PP_NBR + 2); else { dpm_md_pp_t pp[DPM_PP_NBR]; int i; for (i = 0; i < DPM_PP_NBR; i++) pp[i] = simple_strtol(tokptrs[i + 2], NULL, 0); ret = dpm_create_opt(tokptrs[1], pp); } } else if (strcmp(tokptrs[0], "create_class") == 0) { if (ntoks < 3) pwarn("create_class", ntoks, ">= ", 3); else ret = dpm_create_class(tokptrs[1], &tokptrs[2], ntoks - 2); } else if (strcmp(tokptrs[0], "create_policy") == 0) { if (ntoks != (DPM_STATES + 2)) pwarn("create_policy", ntoks, "", DPM_STATES + 2); else ret = dpm_create_policy(tokptrs[1], &tokptrs[2]); } }out1: free_page((unsigned long)tokptrs);out0: kfree(buf); if (ret == 0) return count; else return ret;}#ifdef CONFIG_DPM_STATS/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ * /proc/driver/dpm/stats (Read-Only) * * Reading this file produces the following line for each defined operating * state: * * state_name total_time count opt_name * * Where: * * state_name = The operating state name. * total_time = The 64-bit number of dpm_md_time_t ticks spent in this * operating state. * count = The 64-bit number of times this operating state was entered. * opt_name = The name of the operating point currently assigned to this * operating state. * *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/static intsprintf_u64(char *buf, int fill, char *s, u64 ul){ int len = 0; u32 u, l; u = (u32)((ul >> 32) & 0xffffffffU); l = (u32)(ul & 0xffffffffU); len += sprintf(buf + len, s); if (fill) len += sprintf(buf + len, "0x%08x%08x", u, l); else { if (u) len += sprintf(buf + len, "0x%x%x", u, l); else len += sprintf(buf + len, "0x%x", l); } return len;}static intread_proc_dpm_stats(char *page, char **start, off_t offset, int count, int *eof, void *data){ int i, len = 0; struct dpm_stats stats[DPM_STATES]; if (!dpm_enabled) { len += sprintf(page + len, "DPM IS DISABLED\n"); *eof = 1; return len; } dpm_get_os_stats(stats); for (i = 0; i < DPM_STATES; i++) { len += sprintf(page + len, "%20s", dpm_state_names[i]); len += sprintf_u64(page + len, 1, " ", (u64)stats[i].total_time); len += sprintf_u64(page + len, 1, " ", (u64)stats[i].count); len += sprintf(page + len, " %s\n", dpm_active_policy->classes[i]->opt->name); } *eof = 1; return len;}#ifdef CONFIG_DPM_OPT_STATS/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ * /proc/driver/dpm/opt_stats (Read-Only) * * Reading this file produces the following line for each defined operating * point: * * name total_time count * * Where: * * name = The operating point name. * total_time = The 64-bit number of dpm_md_time_t ticks spent in this * operating state. * count = The 64-bit number of times this operating point was entered. * *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/static intread_proc_dpm_opt_stats(char *page, char **start, off_t offset, int count, int *eof, void *data){ int len = 0; struct dpm_opt *opt; struct list_head *p; dpm_md_time_t total_time; if (dpm_lock_interruptible()) return -ERESTARTSYS; if (!dpm_enabled) { dpm_unlock(); len += sprintf(page + len, "DPM IS DISABLED\n"); *eof = 1; return len; } for (p = dpm_opts.next; p != &dpm_opts; p = p->next) { opt = list_entry(p, struct dpm_opt, list); len += sprintf(page + len, "%s", opt->name); total_time = opt->stats.total_time; if (opt == dpm_active_opt) total_time += dpm_md_time() - opt->stats.start_time; len += sprintf_u64(page + len, 0, " ", opt->stats.total_time); len += sprintf_u64(page + len, 0, " ", opt->stats.count); len += sprintf(page + len, "\n"); } dpm_unlock(); *eof = 1; return len;}#endif /* CONFIG_DPM_OPT_STATS */#ifdef CONFIG_DPM_IDLE_STATS/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ * * /proc/driver/dpm/idle_stats (Read/Write) * * Read to get a dump of statistics. Write anything to clear all statistics. * *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/static intsprintf_usec(char *s, u32 tb){ unsigned nsec = (tb * 1000000) / (tb_ticks_per_second / 1000); return sprintf(s, " (%d.%03d uS)\n", nsec / 1000, nsec % 1000);}static intread_proc_dpm_idle_stats(char *page, char **start, off_t offset, int count, int *eof, void *data){ int len = 0; len += sprintf(page + len, "Total Idles : %u\n", idle_lats.idles); len += sprintf(page + len, "Idle Preemptions : %u\n", idle_lats.idle_preemptions); len += sprintf(page + len,
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -