Path: blob/master/arch/powerpc/platforms/pseries/hvCall_inst.c
10818 views
/*1* Copyright (C) 2006 Mike Kravetz IBM Corporation2*3* Hypervisor Call Instrumentation4*5* This program is free software; you can redistribute it and/or modify6* it under the terms of the GNU General Public License as published by7* the Free Software Foundation; either version 2 of the License, or8* (at your option) any later version.9*10* This program is distributed in the hope that it will be useful,11* but WITHOUT ANY WARRANTY; without even the implied warranty of12* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the13* GNU General Public License for more details.14*15* You should have received a copy of the GNU General Public License16* along with this program; if not, write to the Free Software17* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA18*/1920#include <linux/kernel.h>21#include <linux/percpu.h>22#include <linux/debugfs.h>23#include <linux/seq_file.h>24#include <linux/cpumask.h>25#include <asm/hvcall.h>26#include <asm/firmware.h>27#include <asm/cputable.h>28#include <asm/trace.h>2930DEFINE_PER_CPU(struct hcall_stats[HCALL_STAT_ARRAY_SIZE], hcall_stats);3132/*33* Routines for displaying the statistics in debugfs34*/35static void *hc_start(struct seq_file *m, loff_t *pos)36{37if ((int)*pos < (HCALL_STAT_ARRAY_SIZE-1))38return (void *)(unsigned long)(*pos + 1);3940return NULL;41}4243static void *hc_next(struct seq_file *m, void *p, loff_t * pos)44{45++*pos;4647return hc_start(m, pos);48}4950static void hc_stop(struct seq_file *m, void *p)51{52}5354static int hc_show(struct seq_file *m, void *p)55{56unsigned long h_num = (unsigned long)p;57struct hcall_stats *hs = m->private;5859if (hs[h_num].num_calls) {60if (cpu_has_feature(CPU_FTR_PURR))61seq_printf(m, "%lu %lu %lu %lu\n", h_num<<2,62hs[h_num].num_calls,63hs[h_num].tb_total,64hs[h_num].purr_total);65else66seq_printf(m, "%lu %lu %lu\n", h_num<<2,67hs[h_num].num_calls,68hs[h_num].tb_total);69}7071return 0;72}7374static const struct seq_operations hcall_inst_seq_ops = {75.start = hc_start,76.next = hc_next,77.stop = hc_stop,78.show = hc_show79};8081static int hcall_inst_seq_open(struct inode *inode, struct file *file)82{83int rc;84struct seq_file *seq;8586rc = seq_open(file, &hcall_inst_seq_ops);87seq = file->private_data;88seq->private = file->f_path.dentry->d_inode->i_private;8990return rc;91}9293static const struct file_operations hcall_inst_seq_fops = {94.open = hcall_inst_seq_open,95.read = seq_read,96.llseek = seq_lseek,97.release = seq_release,98};99100#define HCALL_ROOT_DIR "hcall_inst"101#define CPU_NAME_BUF_SIZE 32102103104static void probe_hcall_entry(void *ignored, unsigned long opcode, unsigned long *args)105{106struct hcall_stats *h;107108if (opcode > MAX_HCALL_OPCODE)109return;110111h = &get_cpu_var(hcall_stats)[opcode / 4];112h->tb_start = mftb();113h->purr_start = mfspr(SPRN_PURR);114}115116static void probe_hcall_exit(void *ignored, unsigned long opcode, unsigned long retval,117unsigned long *retbuf)118{119struct hcall_stats *h;120121if (opcode > MAX_HCALL_OPCODE)122return;123124h = &__get_cpu_var(hcall_stats)[opcode / 4];125h->num_calls++;126h->tb_total += mftb() - h->tb_start;127h->purr_total += mfspr(SPRN_PURR) - h->purr_start;128129put_cpu_var(hcall_stats);130}131132static int __init hcall_inst_init(void)133{134struct dentry *hcall_root;135struct dentry *hcall_file;136char cpu_name_buf[CPU_NAME_BUF_SIZE];137int cpu;138139if (!firmware_has_feature(FW_FEATURE_LPAR))140return 0;141142if (register_trace_hcall_entry(probe_hcall_entry, NULL))143return -EINVAL;144145if (register_trace_hcall_exit(probe_hcall_exit, NULL)) {146unregister_trace_hcall_entry(probe_hcall_entry, NULL);147return -EINVAL;148}149150hcall_root = debugfs_create_dir(HCALL_ROOT_DIR, NULL);151if (!hcall_root)152return -ENOMEM;153154for_each_possible_cpu(cpu) {155snprintf(cpu_name_buf, CPU_NAME_BUF_SIZE, "cpu%d", cpu);156hcall_file = debugfs_create_file(cpu_name_buf, S_IRUGO,157hcall_root,158per_cpu(hcall_stats, cpu),159&hcall_inst_seq_fops);160if (!hcall_file)161return -ENOMEM;162}163164return 0;165}166__initcall(hcall_inst_init);167168169