📄 proc_pmc.c
字号:
/* * proc_pmc.c * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen IBM Corporation * * 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 *//* Change Activity: * 2001 : mikec : Created * 2001/06/05 : engebret : Software event count support. * 2001/08/03 : trautman : Added PCI Flight Recorder * End Change Activity */#include <asm/proc_fs.h>#include <asm/paca.h>#include <asm/iSeries/ItLpPaca.h>#include <asm/iSeries/ItLpQueue.h>#include <asm/iSeries/HvCallXm.h>#include <asm/iSeries/IoHriMainStore.h>#include <asm/processor.h>#include <asm/time.h>#include <asm/iSeries/LparData.h>#include <linux/config.h>#include <linux/proc_fs.h>#include <linux/spinlock.h>#include <asm/pmc.h>#include <asm/uaccess.h>#include <asm/naca.h>/* pci Flight Recorder AHT */extern void proc_pciFr_init(struct proc_dir_entry *proc_ppc64_root);static int proc_pmc_control_mode = 0;static struct proc_dir_entry *proc_ppc64_root = NULL;static struct proc_dir_entry *proc_ppc64_pmc_root = NULL;static struct proc_dir_entry *proc_ppc64_pmc_system_root = NULL;static struct proc_dir_entry *proc_ppc64_pmc_cpu_root[NR_CPUS] = {NULL, };static spinlock_t proc_ppc64_lock;static int proc_ppc64_page_read(char *page, char **start, off_t off, int count, int *eof, void *data);static void proc_ppc64_create_paca(int num, struct proc_dir_entry *paca_dir);int proc_ppc64_pmc_find_file(void *data);int proc_ppc64_pmc_read(char *page, char **start, off_t off, int count, int *eof, char *buffer);int proc_ppc64_pmc_stab_read(char *page, char **start, off_t off, int count, int *eof, void *data);int proc_ppc64_pmc_htab_read(char *page, char **start, off_t off, int count, int *eof, void *data);int proc_ppc64_pmc_hw_read(char *page, char **start, off_t off, int count, int *eof, void *data);static struct proc_dir_entry *pmc_proc_root = NULL;int proc_get_lpevents( char *page, char **start, off_t off, int count, int *eof, void *data);int proc_reset_lpevents( struct file *file, const char *buffer, unsigned long count, void *data);int proc_get_titanTod( char *page, char **start, off_t off, int count, int *eof, void *data);int proc_pmc_get_control( char *page, char **start, off_t off, int count, int *eof, void *data);int proc_pmc_set_control( struct file *file, const char *buffer, unsigned long count, void *data);int proc_pmc_set_mmcr0( struct file *file, const char *buffer, unsigned long count, void *data);int proc_pmc_set_mmcr1( struct file *file, const char *buffer, unsigned long count, void *data);int proc_pmc_set_mmcra( struct file *file, const char *buffer, unsigned long count, void *data);int proc_pmc_set_pmc1( struct file *file, const char *buffer, unsigned long count, void *data);int proc_pmc_set_pmc2( struct file *file, const char *buffer, unsigned long count, void *data);int proc_pmc_set_pmc3( struct file *file, const char *buffer, unsigned long count, void *data);int proc_pmc_set_pmc4( struct file *file, const char *buffer, unsigned long count, void *data);int proc_pmc_set_pmc5( struct file *file, const char *buffer, unsigned long count, void *data);int proc_pmc_set_pmc6( struct file *file, const char *buffer, unsigned long count, void *data);int proc_pmc_set_pmc7( struct file *file, const char *buffer, unsigned long count, void *data);int proc_pmc_set_pmc8( struct file *file, const char *buffer, unsigned long count, void *data);void proc_ppc64_init(void){ unsigned long i; struct proc_dir_entry *ent = NULL; char buf[256]; printk("proc_ppc64: Creating /proc/ppc64/pmc\n"); /* * Create the root, system, and cpu directories as follows: * /proc/ppc64/pmc/system * /proc/ppc64/pmc/cpu0 */ spin_lock(&proc_ppc64_lock); proc_ppc64_root = proc_mkdir("ppc64", 0); if (!proc_ppc64_root) return; spin_unlock(&proc_ppc64_lock); /* /proc/ppc64/naca -- raw naca contents. Only readable to root */ create_proc_read_entry("naca", S_IRUSR, proc_ppc64_root, proc_ppc64_page_read, naca); /* /proc/ppc64/paca/XX -- raw paca contents. Only readable to root */ ent = proc_mkdir("paca", proc_ppc64_root); if (ent) { for (i = 0; i < naca->processorCount; i++) proc_ppc64_create_paca(i, ent); } /* Create the /proc/ppc64/pcifr for the Pci Flight Recorder. */ proc_pciFr_init(proc_ppc64_root); proc_ppc64_pmc_root = proc_mkdir("pmc", proc_ppc64_root); proc_ppc64_pmc_system_root = proc_mkdir("system", proc_ppc64_pmc_root); for (i = 0; i < naca->processorCount; i++) { sprintf(buf, "cpu%ld", i); proc_ppc64_pmc_cpu_root[i] = proc_mkdir(buf, proc_ppc64_pmc_root); } /* Create directories for the software counters. */ for (i = 0; i < naca->processorCount; i++) { ent = create_proc_entry("stab", S_IRUGO | S_IWUSR, proc_ppc64_pmc_cpu_root[i]); if (ent) { ent->nlink = 1; ent->data = (void *)proc_ppc64_pmc_cpu_root[i]; ent->read_proc = (void *)proc_ppc64_pmc_stab_read; ent->write_proc = (void *)proc_ppc64_pmc_stab_read; } ent = create_proc_entry("htab", S_IRUGO | S_IWUSR, proc_ppc64_pmc_cpu_root[i]); if (ent) { ent->nlink = 1; ent->data = (void *)proc_ppc64_pmc_cpu_root[i]; ent->read_proc = (void *)proc_ppc64_pmc_htab_read; ent->write_proc = (void *)proc_ppc64_pmc_htab_read; } } ent = create_proc_entry("stab", S_IRUGO | S_IWUSR, proc_ppc64_pmc_system_root); if (ent) { ent->nlink = 1; ent->data = (void *)proc_ppc64_pmc_system_root; ent->read_proc = (void *)proc_ppc64_pmc_stab_read; ent->write_proc = (void *)proc_ppc64_pmc_stab_read; } ent = create_proc_entry("htab", S_IRUGO | S_IWUSR, proc_ppc64_pmc_system_root); if (ent) { ent->nlink = 1; ent->data = (void *)proc_ppc64_pmc_system_root; ent->read_proc = (void *)proc_ppc64_pmc_htab_read; ent->write_proc = (void *)proc_ppc64_pmc_htab_read; } /* Create directories for the hardware counters. */ for (i = 0; i < naca->processorCount; i++) { ent = create_proc_entry("hardware", S_IRUGO | S_IWUSR, proc_ppc64_pmc_cpu_root[i]); if (ent) { ent->nlink = 1; ent->data = (void *)proc_ppc64_pmc_cpu_root[i]; ent->read_proc = (void *)proc_ppc64_pmc_hw_read; ent->write_proc = (void *)proc_ppc64_pmc_hw_read; } } ent = create_proc_entry("hardware", S_IRUGO | S_IWUSR, proc_ppc64_pmc_system_root); if (ent) { ent->nlink = 1; ent->data = (void *)proc_ppc64_pmc_system_root; ent->read_proc = (void *)proc_ppc64_pmc_hw_read; ent->write_proc = (void *)proc_ppc64_pmc_hw_read; }}/* Read a page of raw data. "data" points to the start addr. * Intended as a proc read function. */static int proc_ppc64_page_read(char *page, char **start, off_t off, int count, int *eof, void *data){ int len = PAGE_SIZE - off; char *p = (char *)data; if (len > count) len = count; if (len <= 0) return 0; /* Rely on a "hack" in fs/proc/generic.c. * If we could return a ptr to our own data this would be * trivial (currently *start must be either an offset, or * point into the given page). */ memcpy(page, p+off, len); *start = (char *)len; return len;}/* NOTE: since paca data is always in flux the values will never be a consistant set. * In theory it could be made consistent if we made the corresponding cpu * copy the page for us (via an IPI). Probably not worth it. * */static void proc_ppc64_create_paca(int num, struct proc_dir_entry *paca_dir){ struct proc_dir_entry *ent; struct paca_struct *lpaca = paca + num; char buf[16]; sprintf(buf, "%02x", num); ent = create_proc_read_entry(buf, S_IRUSR, paca_dir, proc_ppc64_page_read, lpaca);}/* * Find the requested 'file' given a proc token. * * Inputs: void * data: proc token * Output: int : (0, ..., +N) = CPU number. * -1 = System. */int proc_ppc64_pmc_find_file(void *data){ int i; if ((unsigned long)data == (unsigned long) proc_ppc64_pmc_system_root) { return(-1); } else { for (i = 0; i < naca->processorCount; i++) { if ((unsigned long)data == (unsigned long)proc_ppc64_pmc_cpu_root[i]) { return(i); } } } /* On error, just default to a type of system. */ printk("proc_ppc64_pmc_find_file: failed to find file token.\n"); return(-1); }int proc_ppc64_pmc_read(char *page, char **start, off_t off, int count, int *eof, char *buffer){ int buffer_size, n; if (count < 0) return 0; if (buffer == NULL) { *eof = 1; return 0; } /* Check for read beyond EOF */ buffer_size = n = strlen(buffer); if (off >= buffer_size) { *eof = 1; return 0; } if (n > (buffer_size - off)) n = buffer_size - off; /* Never return more than was requested */ if (n > count) { n = count; } else { *eof = 1; } memcpy(page, buffer + off, n); *start = page; return n;}int proc_ppc64_pmc_stab_read(char *page, char **start, off_t off, int count, int *eof, void *data){ int n, file; char *buffer = NULL; if (count < 0) return 0; spin_lock(&proc_ppc64_lock); /* Figure out which file is being request. */ file = proc_ppc64_pmc_find_file(data); /* Update the counters and the text buffer representation. */ buffer = ppc64_pmc_stab(file); /* Put the data into the requestor's buffer. */ n = proc_ppc64_pmc_read(page, start, off, count, eof, buffer); spin_unlock(&proc_ppc64_lock); return n;}int proc_ppc64_pmc_htab_read(char *page, char **start, off_t off, int count, int *eof, void *data){ int n, file; char *buffer = NULL; if (count < 0) return 0; spin_lock(&proc_ppc64_lock); /* Figure out which file is being request. */ file = proc_ppc64_pmc_find_file(data); /* Update the counters and the text buffer representation. */ buffer = ppc64_pmc_htab(file); /* Put the data into the requestor's buffer. */ n = proc_ppc64_pmc_read(page, start, off, count, eof, buffer); spin_unlock(&proc_ppc64_lock); return n;}int proc_ppc64_pmc_hw_read(char *page, char **start, off_t off, int count, int *eof, void *data){ int n, file; char *buffer = NULL; if (count < 0) return 0; spin_lock(&proc_ppc64_lock); /* Figure out which file is being request. */ file = proc_ppc64_pmc_find_file(data); /* Update the counters and the text buffer representation. */ buffer = ppc64_pmc_hw(file); /* Put the data into the requestor's buffer. */ n = proc_ppc64_pmc_read(page, start, off, count, eof, buffer); spin_unlock(&proc_ppc64_lock); return n;}/* * DRENG the remainder of these functions still need work ... */void pmc_proc_init(struct proc_dir_entry *iSeries_proc){ struct proc_dir_entry *ent = NULL; ent = create_proc_entry("lpevents", S_IFREG|S_IRUGO, iSeries_proc); if (!ent) return; ent->nlink = 1; ent->data = (void *)0; ent->read_proc = proc_get_lpevents; ent->write_proc = proc_reset_lpevents; ent = create_proc_entry("titanTod", S_IFREG|S_IRUGO, iSeries_proc); if (!ent) return; ent->nlink = 1; ent->data = (void *)0; ent->read_proc = proc_get_titanTod; ent->write_proc = NULL; pmc_proc_root = proc_mkdir("pmc", iSeries_proc); if (!pmc_proc_root) return; ent = create_proc_entry("control", S_IFREG|S_IRUSR|S_IWUSR, pmc_proc_root); if (!ent) return; ent->nlink = 1; ent->data = (void *)0; ent->read_proc = proc_pmc_get_control; ent->write_proc = proc_pmc_set_control;}static int pmc_calc_metrics( char *page, char **start, off_t off, int count, int *eof, int len){ if ( len <= off+count) *eof = 1; *start = page+off; len -= off; if ( len > count ) len = count; if ( len < 0 ) len = 0; return len;}static char * lpEventTypes[9] = { "Hypervisor\t\t", "Machine Facilities\t", "Session Manager\t", "SPD I/O\t\t", "Virtual Bus\t\t", "PCI I/O\t\t", "RIO I/O\t\t", "Virtual Lan\t\t", "Virtual I/O\t\t" }; int proc_get_lpevents
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -