root/arch/s390/kernel/perf_cpum_cf_common.c

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

DEFINITIONS

This source file includes following definitions.
  1. cpumf_measurement_alert
  2. cpum_cf_setup_cpu
  3. kernel_cpumcf_avail
  4. __kernel_cpumcf_begin
  5. kernel_cpumcf_alert
  6. __kernel_cpumcf_end
  7. cpum_cf_setup
  8. cpum_cf_online_cpu
  9. cpum_cf_offline_cpu
  10. cpum_cf_init

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * CPU-Measurement Counter Facility Support - Common Layer
   4  *
   5  *  Copyright IBM Corp. 2019
   6  *  Author(s): Hendrik Brueckner <brueckner@linux.ibm.com>
   7  */
   8 #define KMSG_COMPONENT  "cpum_cf_common"
   9 #define pr_fmt(fmt)     KMSG_COMPONENT ": " fmt
  10 
  11 #include <linux/kernel.h>
  12 #include <linux/kernel_stat.h>
  13 #include <linux/percpu.h>
  14 #include <linux/notifier.h>
  15 #include <linux/init.h>
  16 #include <linux/export.h>
  17 #include <asm/ctl_reg.h>
  18 #include <asm/irq.h>
  19 #include <asm/cpu_mcf.h>
  20 
  21 /* Per-CPU event structure for the counter facility */
  22 DEFINE_PER_CPU(struct cpu_cf_events, cpu_cf_events) = {
  23         .ctr_set = {
  24                 [CPUMF_CTR_SET_BASIC]   = ATOMIC_INIT(0),
  25                 [CPUMF_CTR_SET_USER]    = ATOMIC_INIT(0),
  26                 [CPUMF_CTR_SET_CRYPTO]  = ATOMIC_INIT(0),
  27                 [CPUMF_CTR_SET_EXT]     = ATOMIC_INIT(0),
  28                 [CPUMF_CTR_SET_MT_DIAG] = ATOMIC_INIT(0),
  29         },
  30         .alert = ATOMIC64_INIT(0),
  31         .state = 0,
  32         .flags = 0,
  33         .txn_flags = 0,
  34 };
  35 /* Indicator whether the CPU-Measurement Counter Facility Support is ready */
  36 static bool cpum_cf_initalized;
  37 
  38 /* CPU-measurement alerts for the counter facility */
  39 static void cpumf_measurement_alert(struct ext_code ext_code,
  40                                     unsigned int alert, unsigned long unused)
  41 {
  42         struct cpu_cf_events *cpuhw;
  43 
  44         if (!(alert & CPU_MF_INT_CF_MASK))
  45                 return;
  46 
  47         inc_irq_stat(IRQEXT_CMC);
  48         cpuhw = this_cpu_ptr(&cpu_cf_events);
  49 
  50         /* Measurement alerts are shared and might happen when the PMU
  51          * is not reserved.  Ignore these alerts in this case. */
  52         if (!(cpuhw->flags & PMU_F_RESERVED))
  53                 return;
  54 
  55         /* counter authorization change alert */
  56         if (alert & CPU_MF_INT_CF_CACA)
  57                 qctri(&cpuhw->info);
  58 
  59         /* loss of counter data alert */
  60         if (alert & CPU_MF_INT_CF_LCDA)
  61                 pr_err("CPU[%i] Counter data was lost\n", smp_processor_id());
  62 
  63         /* loss of MT counter data alert */
  64         if (alert & CPU_MF_INT_CF_MTDA)
  65                 pr_warn("CPU[%i] MT counter data was lost\n",
  66                         smp_processor_id());
  67 
  68         /* store alert for special handling by in-kernel users */
  69         atomic64_or(alert, &cpuhw->alert);
  70 }
  71 
  72 #define PMC_INIT      0
  73 #define PMC_RELEASE   1
  74 static void cpum_cf_setup_cpu(void *flags)
  75 {
  76         struct cpu_cf_events *cpuhw = this_cpu_ptr(&cpu_cf_events);
  77 
  78         switch (*((int *) flags)) {
  79         case PMC_INIT:
  80                 memset(&cpuhw->info, 0, sizeof(cpuhw->info));
  81                 qctri(&cpuhw->info);
  82                 cpuhw->flags |= PMU_F_RESERVED;
  83                 break;
  84 
  85         case PMC_RELEASE:
  86                 cpuhw->flags &= ~PMU_F_RESERVED;
  87                 break;
  88         }
  89 
  90         /* Disable CPU counter sets */
  91         lcctl(0);
  92 }
  93 
  94 bool kernel_cpumcf_avail(void)
  95 {
  96         return cpum_cf_initalized;
  97 }
  98 EXPORT_SYMBOL(kernel_cpumcf_avail);
  99 
 100 
 101 /* Reserve/release functions for sharing perf hardware */
 102 static DEFINE_SPINLOCK(cpumcf_owner_lock);
 103 static void *cpumcf_owner;
 104 
 105 /* Initialize the CPU-measurement counter facility */
 106 int __kernel_cpumcf_begin(void)
 107 {
 108         int flags = PMC_INIT;
 109         int err = 0;
 110 
 111         spin_lock(&cpumcf_owner_lock);
 112         if (cpumcf_owner)
 113                 err = -EBUSY;
 114         else
 115                 cpumcf_owner = __builtin_return_address(0);
 116         spin_unlock(&cpumcf_owner_lock);
 117         if (err)
 118                 return err;
 119 
 120         on_each_cpu(cpum_cf_setup_cpu, &flags, 1);
 121         irq_subclass_register(IRQ_SUBCLASS_MEASUREMENT_ALERT);
 122 
 123         return 0;
 124 }
 125 EXPORT_SYMBOL(__kernel_cpumcf_begin);
 126 
 127 /* Obtain the CPU-measurement alerts for the counter facility */
 128 unsigned long kernel_cpumcf_alert(int clear)
 129 {
 130         struct cpu_cf_events *cpuhw = this_cpu_ptr(&cpu_cf_events);
 131         unsigned long alert;
 132 
 133         alert = atomic64_read(&cpuhw->alert);
 134         if (clear)
 135                 atomic64_set(&cpuhw->alert, 0);
 136 
 137         return alert;
 138 }
 139 EXPORT_SYMBOL(kernel_cpumcf_alert);
 140 
 141 /* Release the CPU-measurement counter facility */
 142 void __kernel_cpumcf_end(void)
 143 {
 144         int flags = PMC_RELEASE;
 145 
 146         on_each_cpu(cpum_cf_setup_cpu, &flags, 1);
 147         irq_subclass_unregister(IRQ_SUBCLASS_MEASUREMENT_ALERT);
 148 
 149         spin_lock(&cpumcf_owner_lock);
 150         cpumcf_owner = NULL;
 151         spin_unlock(&cpumcf_owner_lock);
 152 }
 153 EXPORT_SYMBOL(__kernel_cpumcf_end);
 154 
 155 static int cpum_cf_setup(unsigned int cpu, int flags)
 156 {
 157         local_irq_disable();
 158         cpum_cf_setup_cpu(&flags);
 159         local_irq_enable();
 160         return 0;
 161 }
 162 
 163 static int cpum_cf_online_cpu(unsigned int cpu)
 164 {
 165         return cpum_cf_setup(cpu, PMC_INIT);
 166 }
 167 
 168 static int cpum_cf_offline_cpu(unsigned int cpu)
 169 {
 170         return cpum_cf_setup(cpu, PMC_RELEASE);
 171 }
 172 
 173 static int __init cpum_cf_init(void)
 174 {
 175         int rc;
 176 
 177         if (!cpum_cf_avail())
 178                 return -ENODEV;
 179 
 180         /* clear bit 15 of cr0 to unauthorize problem-state to
 181          * extract measurement counters */
 182         ctl_clear_bit(0, 48);
 183 
 184         /* register handler for measurement-alert interruptions */
 185         rc = register_external_irq(EXT_IRQ_MEASURE_ALERT,
 186                                    cpumf_measurement_alert);
 187         if (rc) {
 188                 pr_err("Registering for CPU-measurement alerts "
 189                        "failed with rc=%i\n", rc);
 190                 return rc;
 191         }
 192 
 193         rc = cpuhp_setup_state(CPUHP_AP_PERF_S390_CF_ONLINE,
 194                                 "perf/s390/cf:online",
 195                                 cpum_cf_online_cpu, cpum_cf_offline_cpu);
 196         if (!rc)
 197                 cpum_cf_initalized = true;
 198 
 199         return rc;
 200 }
 201 early_initcall(cpum_cf_init);

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