root/arch/s390/kernel/perf_event.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. perf_pmu_name
  2. perf_num_counters
  3. is_in_guest
  4. guest_is_user_mode
  5. instruction_pointer_guest
  6. perf_instruction_pointer
  7. perf_misc_guest_flags
  8. perf_misc_flags_sf
  9. perf_misc_flags
  10. print_debug_cf
  11. print_debug_sf
  12. perf_event_print_debug
  13. sl_print_counter
  14. sl_print_sampling
  15. service_level_perf_print
  16. service_level_perf_register
  17. perf_callchain_kernel
  18. cpumf_events_sysfs_show

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

/* [<][>][^][v][top][bottom][index][help] */