|
16 | 16 | #include <linux/kvm_host.h> |
17 | 17 | #include <linux/percpu.h> |
18 | 18 | #include <linux/export.h> |
| 19 | +#include <linux/seq_file.h> |
19 | 20 | #include <linux/spinlock.h> |
20 | 21 | #include <linux/sysfs.h> |
21 | 22 | #include <asm/irq.h> |
22 | 23 | #include <asm/cpu_mf.h> |
23 | 24 | #include <asm/lowcore.h> |
24 | 25 | #include <asm/processor.h> |
| 26 | +#include <asm/sysinfo.h> |
25 | 27 |
|
26 | 28 | const char *perf_pmu_name(void) |
27 | 29 | { |
28 | 30 | if (cpum_cf_avail() || cpum_sf_avail()) |
29 | | - return "CPU-measurement facilities (CPUMF)"; |
| 31 | + return "CPU-Measurement Facilities (CPU-MF)"; |
30 | 32 | return "pmu"; |
31 | 33 | } |
32 | 34 | EXPORT_SYMBOL(perf_pmu_name); |
@@ -138,6 +140,60 @@ void perf_event_print_debug(void) |
138 | 140 | local_irq_restore(flags); |
139 | 141 | } |
140 | 142 |
|
| 143 | +/* Service level infrastructure */ |
| 144 | +static void sl_print_counter(struct seq_file *m) |
| 145 | +{ |
| 146 | + struct cpumf_ctr_info ci; |
| 147 | + |
| 148 | + memset(&ci, 0, sizeof(ci)); |
| 149 | + if (qctri(&ci)) |
| 150 | + return; |
| 151 | + |
| 152 | + seq_printf(m, "CPU-MF: Counter facility: version=%u.%u " |
| 153 | + "authorization=%04x\n", ci.cfvn, ci.csvn, ci.auth_ctl); |
| 154 | +} |
| 155 | + |
| 156 | +static void sl_print_sampling(struct seq_file *m) |
| 157 | +{ |
| 158 | + struct hws_qsi_info_block si; |
| 159 | + |
| 160 | + memset(&si, 0, sizeof(si)); |
| 161 | + if (qsi(&si)) |
| 162 | + return; |
| 163 | + |
| 164 | + if (!si.as && !si.ad) |
| 165 | + return; |
| 166 | + |
| 167 | + seq_printf(m, "CPU-MF: Sampling facility: min_rate=%lu max_rate=%lu" |
| 168 | + " cpu_speed=%u\n", si.min_sampl_rate, si.max_sampl_rate, |
| 169 | + si.cpu_speed); |
| 170 | + if (si.as) |
| 171 | + seq_printf(m, "CPU-MF: Sampling facility: mode=basic" |
| 172 | + " sample_size=%u\n", si.bsdes); |
| 173 | + if (si.ad) |
| 174 | + seq_printf(m, "CPU-MF: Sampling facility: mode=diagnostic" |
| 175 | + " sample_size=%u\n", si.dsdes); |
| 176 | +} |
| 177 | + |
| 178 | +static void service_level_perf_print(struct seq_file *m, |
| 179 | + struct service_level *sl) |
| 180 | +{ |
| 181 | + if (cpum_cf_avail()) |
| 182 | + sl_print_counter(m); |
| 183 | + if (cpum_sf_avail()) |
| 184 | + sl_print_sampling(m); |
| 185 | +} |
| 186 | + |
| 187 | +static struct service_level service_level_perf = { |
| 188 | + .seq_print = service_level_perf_print, |
| 189 | +}; |
| 190 | + |
| 191 | +static int __init service_level_perf_register(void) |
| 192 | +{ |
| 193 | + return register_service_level(&service_level_perf); |
| 194 | +} |
| 195 | +arch_initcall(service_level_perf_register); |
| 196 | + |
141 | 197 | /* See also arch/s390/kernel/traps.c */ |
142 | 198 | static unsigned long __store_trace(struct perf_callchain_entry *entry, |
143 | 199 | unsigned long sp, |
|
0 commit comments