1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2006 Mike Kravetz IBM Corporation
5 * Hypervisor Call Instrumentation
8 #include <linux/kernel.h>
9 #include <linux/percpu.h>
10 #include <linux/debugfs.h>
11 #include <linux/seq_file.h>
12 #include <linux/cpumask.h>
13 #include <asm/hvcall.h>
14 #include <asm/firmware.h>
15 #include <asm/cputable.h>
16 #include <asm/trace.h>
17 #include <asm/machdep.h>
19 /* For hcall instrumentation. One structure per-hcall, per-CPU */
21 unsigned long num_calls
; /* number of calls (on this CPU) */
22 unsigned long tb_total
; /* total wall time (mftb) of calls. */
23 unsigned long purr_total
; /* total cpu time (PURR) of calls. */
24 unsigned long tb_start
;
25 unsigned long purr_start
;
27 #define HCALL_STAT_ARRAY_SIZE ((MAX_HCALL_OPCODE >> 2) + 1)
29 DEFINE_PER_CPU(struct hcall_stats
[HCALL_STAT_ARRAY_SIZE
], hcall_stats
);
32 * Routines for displaying the statistics in debugfs
34 static void *hc_start(struct seq_file
*m
, loff_t
*pos
)
36 if ((int)*pos
< (HCALL_STAT_ARRAY_SIZE
-1))
37 return (void *)(unsigned long)(*pos
+ 1);
42 static void *hc_next(struct seq_file
*m
, void *p
, loff_t
* pos
)
46 return hc_start(m
, pos
);
49 static void hc_stop(struct seq_file
*m
, void *p
)
53 static int hc_show(struct seq_file
*m
, void *p
)
55 unsigned long h_num
= (unsigned long)p
;
56 struct hcall_stats
*hs
= m
->private;
58 if (hs
[h_num
].num_calls
) {
59 if (cpu_has_feature(CPU_FTR_PURR
))
60 seq_printf(m
, "%lu %lu %lu %lu\n", h_num
<<2,
63 hs
[h_num
].purr_total
);
65 seq_printf(m
, "%lu %lu %lu\n", h_num
<<2,
73 static const struct seq_operations hcall_inst_sops
= {
80 DEFINE_SEQ_ATTRIBUTE(hcall_inst
);
82 #define HCALL_ROOT_DIR "hcall_inst"
83 #define CPU_NAME_BUF_SIZE 32
86 static void probe_hcall_entry(void *ignored
, unsigned long opcode
, unsigned long *args
)
88 struct hcall_stats
*h
;
90 if (opcode
> MAX_HCALL_OPCODE
)
93 h
= this_cpu_ptr(&hcall_stats
[opcode
/ 4]);
95 h
->purr_start
= mfspr(SPRN_PURR
);
98 static void probe_hcall_exit(void *ignored
, unsigned long opcode
, long retval
,
99 unsigned long *retbuf
)
101 struct hcall_stats
*h
;
103 if (opcode
> MAX_HCALL_OPCODE
)
106 h
= this_cpu_ptr(&hcall_stats
[opcode
/ 4]);
108 h
->tb_total
+= mftb() - h
->tb_start
;
109 h
->purr_total
+= mfspr(SPRN_PURR
) - h
->purr_start
;
112 static int __init
hcall_inst_init(void)
114 struct dentry
*hcall_root
;
115 char cpu_name_buf
[CPU_NAME_BUF_SIZE
];
118 if (!firmware_has_feature(FW_FEATURE_LPAR
))
121 if (register_trace_hcall_entry(probe_hcall_entry
, NULL
))
124 if (register_trace_hcall_exit(probe_hcall_exit
, NULL
)) {
125 unregister_trace_hcall_entry(probe_hcall_entry
, NULL
);
129 hcall_root
= debugfs_create_dir(HCALL_ROOT_DIR
, NULL
);
131 for_each_possible_cpu(cpu
) {
132 snprintf(cpu_name_buf
, CPU_NAME_BUF_SIZE
, "cpu%d", cpu
);
133 debugfs_create_file(cpu_name_buf
, 0444, hcall_root
,
134 per_cpu(hcall_stats
, cpu
),
140 machine_device_initcall(pseries
, hcall_inst_init
);