~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/x86/oprofile/op_model_ppro.c

Version: ~ [ linux-5.8 ] ~ [ linux-5.7.12 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.55 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.136 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.191 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.232 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.232 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.85 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * @file op_model_ppro.h
  3  * Family 6 perfmon and architectural perfmon MSR operations
  4  *
  5  * @remark Copyright 2002 OProfile authors
  6  * @remark Copyright 2008 Intel Corporation
  7  * @remark Read the file COPYING
  8  *
  9  * @author John Levon
 10  * @author Philippe Elie
 11  * @author Graydon Hoare
 12  * @author Andi Kleen
 13  * @author Robert Richter <robert.richter@amd.com>
 14  */
 15 
 16 #include <linux/oprofile.h>
 17 #include <linux/slab.h>
 18 #include <asm/ptrace.h>
 19 #include <asm/msr.h>
 20 #include <asm/apic.h>
 21 #include <asm/nmi.h>
 22 
 23 #include "op_x86_model.h"
 24 #include "op_counter.h"
 25 
 26 static int num_counters = 2;
 27 static int counter_width = 32;
 28 
 29 #define MSR_PPRO_EVENTSEL_RESERVED      ((0xFFFFFFFFULL<<32)|(1ULL<<21))
 30 
 31 static u64 reset_value[OP_MAX_COUNTER];
 32 
 33 static void ppro_shutdown(struct op_msrs const * const msrs)
 34 {
 35         int i;
 36 
 37         for (i = 0; i < num_counters; ++i) {
 38                 if (!msrs->counters[i].addr)
 39                         continue;
 40                 release_perfctr_nmi(MSR_P6_PERFCTR0 + i);
 41                 release_evntsel_nmi(MSR_P6_EVNTSEL0 + i);
 42         }
 43 }
 44 
 45 static int ppro_fill_in_addresses(struct op_msrs * const msrs)
 46 {
 47         int i;
 48 
 49         for (i = 0; i < num_counters; i++) {
 50                 if (!reserve_perfctr_nmi(MSR_P6_PERFCTR0 + i))
 51                         goto fail;
 52                 if (!reserve_evntsel_nmi(MSR_P6_EVNTSEL0 + i)) {
 53                         release_perfctr_nmi(MSR_P6_PERFCTR0 + i);
 54                         goto fail;
 55                 }
 56                 /* both registers must be reserved */
 57                 msrs->counters[i].addr = MSR_P6_PERFCTR0 + i;
 58                 msrs->controls[i].addr = MSR_P6_EVNTSEL0 + i;
 59                 continue;
 60         fail:
 61                 if (!counter_config[i].enabled)
 62                         continue;
 63                 op_x86_warn_reserved(i);
 64                 ppro_shutdown(msrs);
 65                 return -EBUSY;
 66         }
 67 
 68         return 0;
 69 }
 70 
 71 
 72 static void ppro_setup_ctrs(struct op_x86_model_spec const *model,
 73                             struct op_msrs const * const msrs)
 74 {
 75         u64 val;
 76         int i;
 77 
 78         if (boot_cpu_has(X86_FEATURE_ARCH_PERFMON)) {
 79                 union cpuid10_eax eax;
 80                 eax.full = cpuid_eax(0xa);
 81 
 82                 /*
 83                  * For Core2 (family 6, model 15), don't reset the
 84                  * counter width:
 85                  */
 86                 if (!(eax.split.version_id == 0 &&
 87                         __this_cpu_read(cpu_info.x86) == 6 &&
 88                                 __this_cpu_read(cpu_info.x86_model) == 15)) {
 89 
 90                         if (counter_width < eax.split.bit_width)
 91                                 counter_width = eax.split.bit_width;
 92                 }
 93         }
 94 
 95         /* clear all counters */
 96         for (i = 0; i < num_counters; ++i) {
 97                 if (!msrs->controls[i].addr)
 98                         continue;
 99                 rdmsrl(msrs->controls[i].addr, val);
100                 if (val & ARCH_PERFMON_EVENTSEL_ENABLE)
101                         op_x86_warn_in_use(i);
102                 val &= model->reserved;
103                 wrmsrl(msrs->controls[i].addr, val);
104                 /*
105                  * avoid a false detection of ctr overflows in NMI *
106                  * handler
107                  */
108                 wrmsrl(msrs->counters[i].addr, -1LL);
109         }
110 
111         /* enable active counters */
112         for (i = 0; i < num_counters; ++i) {
113                 if (counter_config[i].enabled && msrs->counters[i].addr) {
114                         reset_value[i] = counter_config[i].count;
115                         wrmsrl(msrs->counters[i].addr, -reset_value[i]);
116                         rdmsrl(msrs->controls[i].addr, val);
117                         val &= model->reserved;
118                         val |= op_x86_get_ctrl(model, &counter_config[i]);
119                         wrmsrl(msrs->controls[i].addr, val);
120                 } else {
121                         reset_value[i] = 0;
122                 }
123         }
124 }
125 
126 
127 static int ppro_check_ctrs(struct pt_regs * const regs,
128                            struct op_msrs const * const msrs)
129 {
130         u64 val;
131         int i;
132 
133         for (i = 0; i < num_counters; ++i) {
134                 if (!reset_value[i])
135                         continue;
136                 rdmsrl(msrs->counters[i].addr, val);
137                 if (val & (1ULL << (counter_width - 1)))
138                         continue;
139                 oprofile_add_sample(regs, i);
140                 wrmsrl(msrs->counters[i].addr, -reset_value[i]);
141         }
142 
143         /* Only P6 based Pentium M need to re-unmask the apic vector but it
144          * doesn't hurt other P6 variant */
145         apic_write(APIC_LVTPC, apic_read(APIC_LVTPC) & ~APIC_LVT_MASKED);
146 
147         /* We can't work out if we really handled an interrupt. We
148          * might have caught a *second* counter just after overflowing
149          * the interrupt for this counter then arrives
150          * and we don't find a counter that's overflowed, so we
151          * would return 0 and get dazed + confused. Instead we always
152          * assume we found an overflow. This sucks.
153          */
154         return 1;
155 }
156 
157 
158 static void ppro_start(struct op_msrs const * const msrs)
159 {
160         u64 val;
161         int i;
162 
163         for (i = 0; i < num_counters; ++i) {
164                 if (reset_value[i]) {
165                         rdmsrl(msrs->controls[i].addr, val);
166                         val |= ARCH_PERFMON_EVENTSEL_ENABLE;
167                         wrmsrl(msrs->controls[i].addr, val);
168                 }
169         }
170 }
171 
172 
173 static void ppro_stop(struct op_msrs const * const msrs)
174 {
175         u64 val;
176         int i;
177 
178         for (i = 0; i < num_counters; ++i) {
179                 if (!reset_value[i])
180                         continue;
181                 rdmsrl(msrs->controls[i].addr, val);
182                 val &= ~ARCH_PERFMON_EVENTSEL_ENABLE;
183                 wrmsrl(msrs->controls[i].addr, val);
184         }
185 }
186 
187 struct op_x86_model_spec op_ppro_spec = {
188         .num_counters           = 2,
189         .num_controls           = 2,
190         .reserved               = MSR_PPRO_EVENTSEL_RESERVED,
191         .fill_in_addresses      = &ppro_fill_in_addresses,
192         .setup_ctrs             = &ppro_setup_ctrs,
193         .check_ctrs             = &ppro_check_ctrs,
194         .start                  = &ppro_start,
195         .stop                   = &ppro_stop,
196         .shutdown               = &ppro_shutdown
197 };
198 
199 /*
200  * Architectural performance monitoring.
201  *
202  * Newer Intel CPUs (Core1+) have support for architectural
203  * events described in CPUID 0xA. See the IA32 SDM Vol3b.18 for details.
204  * The advantage of this is that it can be done without knowing about
205  * the specific CPU.
206  */
207 
208 static void arch_perfmon_setup_counters(void)
209 {
210         union cpuid10_eax eax;
211 
212         eax.full = cpuid_eax(0xa);
213 
214         /* Workaround for BIOS bugs in 6/15. Taken from perfmon2 */
215         if (eax.split.version_id == 0 && boot_cpu_data.x86 == 6 &&
216             boot_cpu_data.x86_model == 15) {
217                 eax.split.version_id = 2;
218                 eax.split.num_counters = 2;
219                 eax.split.bit_width = 40;
220         }
221 
222         num_counters = min((int)eax.split.num_counters, OP_MAX_COUNTER);
223 
224         op_arch_perfmon_spec.num_counters = num_counters;
225         op_arch_perfmon_spec.num_controls = num_counters;
226 }
227 
228 static int arch_perfmon_init(struct oprofile_operations *ignore)
229 {
230         arch_perfmon_setup_counters();
231         return 0;
232 }
233 
234 struct op_x86_model_spec op_arch_perfmon_spec = {
235         .reserved               = MSR_PPRO_EVENTSEL_RESERVED,
236         .init                   = &arch_perfmon_init,
237         /* num_counters/num_controls filled in at runtime */
238         .fill_in_addresses      = &ppro_fill_in_addresses,
239         /* user space does the cpuid check for available events */
240         .setup_ctrs             = &ppro_setup_ctrs,
241         .check_ctrs             = &ppro_check_ctrs,
242         .start                  = &ppro_start,
243         .stop                   = &ppro_stop,
244         .shutdown               = &ppro_shutdown
245 };
246 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp