1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Performance event support for s390x 4 * 5 * Copyright IBM Corp. 2012, 2013 6 * Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com> 7 */ 8 #define KMSG_COMPONENT "perf" 9 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt 10 11 #include <linux/kernel.h> 12 #include <linux/perf_event.h> 13 #include <linux/kvm_host.h> 14 #include <linux/percpu.h> 15 #include <linux/seq_file.h> 16 #include <linux/spinlock.h> 17 #include <linux/uaccess.h> 18 #include <linux/compat.h> 19 #include <linux/sysfs.h> 20 #include <asm/stacktrace.h> 21 #include <asm/irq.h> 22 #include <asm/cpu_mf.h> 23 #include <asm/lowcore.h> 24 #include <asm/processor.h> 25 #include <asm/sysinfo.h> 26 #include <asm/unwind.h> 27 28 static struct kvm_s390_sie_block *sie_block(struct pt_regs *regs) 29 { 30 struct stack_frame *stack = (struct stack_frame *) regs->gprs[15]; 31 32 if (!stack) 33 return NULL; 34 35 return (struct kvm_s390_sie_block *)stack->sie_control_block; 36 } 37 38 static bool is_in_guest(struct pt_regs *regs) 39 { 40 if (user_mode(regs)) 41 return false; 42 #if IS_ENABLED(CONFIG_KVM) 43 return instruction_pointer(regs) == (unsigned long) &sie_exit; 44 #else 45 return false; 46 #endif 47 } 48 49 static unsigned long guest_is_user_mode(struct pt_regs *regs) 50 { 51 return sie_block(regs)->gpsw.mask & PSW_MASK_PSTATE; 52 } 53 54 static unsigned long instruction_pointer_guest(struct pt_regs *regs) 55 { 56 return sie_block(regs)->gpsw.addr; 57 } 58 59 unsigned long perf_arch_instruction_pointer(struct pt_regs *regs) 60 { 61 return is_in_guest(regs) ? instruction_pointer_guest(regs) 62 : instruction_pointer(regs); 63 } 64 65 static unsigned long perf_misc_guest_flags(struct pt_regs *regs) 66 { 67 return guest_is_user_mode(regs) ? PERF_RECORD_MISC_GUEST_USER 68 : PERF_RECORD_MISC_GUEST_KERNEL; 69 } 70 71 static unsigned long perf_misc_flags_sf(struct pt_regs *regs) 72 { 73 struct perf_sf_sde_regs *sde_regs; 74 unsigned long flags; 75 76 sde_regs = (struct perf_sf_sde_regs *) ®s->int_parm_long; 77 if (sde_regs->in_guest) 78 flags = user_mode(regs) ? PERF_RECORD_MISC_GUEST_USER 79 : PERF_RECORD_MISC_GUEST_KERNEL; 80 else 81 flags = user_mode(regs) ? PERF_RECORD_MISC_USER 82 : PERF_RECORD_MISC_KERNEL; 83 return flags; 84 } 85 86 unsigned long perf_arch_misc_flags(struct pt_regs *regs) 87 { 88 /* Check if the cpum_sf PMU has created the pt_regs structure. 89 * In this case, perf misc flags can be easily extracted. Otherwise, 90 * do regular checks on the pt_regs content. 91 */ 92 if (regs->int_code == 0x1407 && regs->int_parm == CPU_MF_INT_SF_PRA) 93 if (!regs->gprs[15]) 94 return perf_misc_flags_sf(regs); 95 96 if (is_in_guest(regs)) 97 return perf_misc_guest_flags(regs); 98 99 return user_mode(regs) ? PERF_RECORD_MISC_USER 100 : PERF_RECORD_MISC_KERNEL; 101 } 102 103 static void print_debug_cf(void) 104 { 105 struct cpumf_ctr_info cf_info; 106 int cpu = smp_processor_id(); 107 108 memset(&cf_info, 0, sizeof(cf_info)); 109 if (!qctri(&cf_info)) 110 pr_info("CPU[%i] CPUM_CF: ver=%u.%u A=%04x E=%04x C=%04x\n", 111 cpu, cf_info.cfvn, cf_info.csvn, 112 cf_info.auth_ctl, cf_info.enable_ctl, cf_info.act_ctl); 113 } 114 115 static void print_debug_sf(void) 116 { 117 struct hws_qsi_info_block si; 118 int cpu = smp_processor_id(); 119 120 memset(&si, 0, sizeof(si)); 121 if (qsi(&si)) 122 return; 123 124 pr_info("CPU[%i] CPUM_SF: basic=%i diag=%i min=%lu max=%lu cpu_speed=%u\n", 125 cpu, si.as, si.ad, si.min_sampl_rate, si.max_sampl_rate, 126 si.cpu_speed); 127 128 if (si.as) 129 pr_info("CPU[%i] CPUM_SF: Basic-sampling: a=%i e=%i c=%i" 130 " bsdes=%i tear=%016lx dear=%016lx\n", cpu, 131 si.as, si.es, si.cs, si.bsdes, si.tear, si.dear); 132 if (si.ad) 133 pr_info("CPU[%i] CPUM_SF: Diagnostic-sampling: a=%i e=%i c=%i" 134 " dsdes=%i tear=%016lx dear=%016lx\n", cpu, 135 si.ad, si.ed, si.cd, si.dsdes, si.tear, si.dear); 136 } 137 138 void perf_event_print_debug(void) 139 { 140 unsigned long flags; 141 142 local_irq_save(flags); 143 if (cpum_cf_avail()) 144 print_debug_cf(); 145 if (cpum_sf_avail()) 146 print_debug_sf(); 147 local_irq_restore(flags); 148 } 149 150 /* Service level infrastructure */ 151 static void sl_print_counter(struct seq_file *m) 152 { 153 struct cpumf_ctr_info ci; 154 155 memset(&ci, 0, sizeof(ci)); 156 if (qctri(&ci)) 157 return; 158 159 seq_printf(m, "CPU-MF: Counter facility: version=%u.%u " 160 "authorization=%04x\n", ci.cfvn, ci.csvn, ci.auth_ctl); 161 } 162 163 static void sl_print_sampling(struct seq_file *m) 164 { 165 struct hws_qsi_info_block si; 166 167 memset(&si, 0, sizeof(si)); 168 if (qsi(&si)) 169 return; 170 171 if (!si.as && !si.ad) 172 return; 173 174 seq_printf(m, "CPU-MF: Sampling facility: min_rate=%lu max_rate=%lu" 175 " cpu_speed=%u\n", si.min_sampl_rate, si.max_sampl_rate, 176 si.cpu_speed); 177 if (si.as) 178 seq_printf(m, "CPU-MF: Sampling facility: mode=basic" 179 " sample_size=%u\n", si.bsdes); 180 if (si.ad) 181 seq_printf(m, "CPU-MF: Sampling facility: mode=diagnostic" 182 " sample_size=%u\n", si.dsdes); 183 } 184 185 static void service_level_perf_print(struct seq_file *m, 186 struct service_level *sl) 187 { 188 if (cpum_cf_avail()) 189 sl_print_counter(m); 190 if (cpum_sf_avail()) 191 sl_print_sampling(m); 192 } 193 194 static struct service_level service_level_perf = { 195 .seq_print = service_level_perf_print, 196 }; 197 198 static int __init service_level_perf_register(void) 199 { 200 return register_service_level(&service_level_perf); 201 } 202 arch_initcall(service_level_perf_register); 203 204 void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry, 205 struct pt_regs *regs) 206 { 207 struct unwind_state state; 208 unsigned long addr; 209 210 unwind_for_each_frame(&state, current, regs, 0) { 211 addr = unwind_get_return_address(&state); 212 if (!addr || perf_callchain_store(entry, addr)) 213 return; 214 } 215 } 216 217 void perf_callchain_user(struct perf_callchain_entry_ctx *entry, 218 struct pt_regs *regs) 219 { 220 arch_stack_walk_user_common(NULL, NULL, entry, regs, true); 221 } 222 223 /* Perf definitions for PMU event attributes in sysfs */ 224 ssize_t cpumf_events_sysfs_show(struct device *dev, 225 struct device_attribute *attr, char *page) 226 { 227 struct perf_pmu_events_attr *pmu_attr; 228 229 pmu_attr = container_of(attr, struct perf_pmu_events_attr, attr); 230 return sysfs_emit(page, "event=0x%04llx\n", pmu_attr->id); 231 } 232