diff options
author | Kevin Winchester <kjwinchester@gmail.com> | 2011-08-30 19:41:05 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2011-09-26 06:58:00 -0400 |
commit | de0428a7ad4856c7b5b8a2792488ac893e6f3faa (patch) | |
tree | 63cf492f6e6a1b11aa8d4271df50b7c71649a49d /arch/x86/kernel/cpu/perf_event.h | |
parent | ed3982cf3748b657ffb79d9d1c2e4a562661db2d (diff) |
x86, perf: Clean up perf_event cpu code
The CPU support for perf events on x86 was implemented via included C files
with #ifdefs. Clean this up by creating a new header file and compiling
the vendor-specific files as needed.
Signed-off-by: Kevin Winchester <kjwinchester@gmail.com>
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/r/1314747665-2090-1-git-send-email-kjwinchester@gmail.com
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/kernel/cpu/perf_event.h')
-rw-r--r-- | arch/x86/kernel/cpu/perf_event.h | 493 |
1 files changed, 493 insertions, 0 deletions
diff --git a/arch/x86/kernel/cpu/perf_event.h b/arch/x86/kernel/cpu/perf_event.h new file mode 100644 index 000000000000..fb330b0a816e --- /dev/null +++ b/arch/x86/kernel/cpu/perf_event.h | |||
@@ -0,0 +1,493 @@ | |||
1 | /* | ||
2 | * Performance events x86 architecture header | ||
3 | * | ||
4 | * Copyright (C) 2008 Thomas Gleixner <tglx@linutronix.de> | ||
5 | * Copyright (C) 2008-2009 Red Hat, Inc., Ingo Molnar | ||
6 | * Copyright (C) 2009 Jaswinder Singh Rajput | ||
7 | * Copyright (C) 2009 Advanced Micro Devices, Inc., Robert Richter | ||
8 | * Copyright (C) 2008-2009 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com> | ||
9 | * Copyright (C) 2009 Intel Corporation, <markus.t.metzger@intel.com> | ||
10 | * Copyright (C) 2009 Google, Inc., Stephane Eranian | ||
11 | * | ||
12 | * For licencing details see kernel-base/COPYING | ||
13 | */ | ||
14 | |||
15 | #include <linux/perf_event.h> | ||
16 | |||
17 | /* | ||
18 | * | NHM/WSM | SNB | | ||
19 | * register ------------------------------- | ||
20 | * | HT | no HT | HT | no HT | | ||
21 | *----------------------------------------- | ||
22 | * offcore | core | core | cpu | core | | ||
23 | * lbr_sel | core | core | cpu | core | | ||
24 | * ld_lat | cpu | core | cpu | core | | ||
25 | *----------------------------------------- | ||
26 | * | ||
27 | * Given that there is a small number of shared regs, | ||
28 | * we can pre-allocate their slot in the per-cpu | ||
29 | * per-core reg tables. | ||
30 | */ | ||
31 | enum extra_reg_type { | ||
32 | EXTRA_REG_NONE = -1, /* not used */ | ||
33 | |||
34 | EXTRA_REG_RSP_0 = 0, /* offcore_response_0 */ | ||
35 | EXTRA_REG_RSP_1 = 1, /* offcore_response_1 */ | ||
36 | |||
37 | EXTRA_REG_MAX /* number of entries needed */ | ||
38 | }; | ||
39 | |||
40 | struct event_constraint { | ||
41 | union { | ||
42 | unsigned long idxmsk[BITS_TO_LONGS(X86_PMC_IDX_MAX)]; | ||
43 | u64 idxmsk64; | ||
44 | }; | ||
45 | u64 code; | ||
46 | u64 cmask; | ||
47 | int weight; | ||
48 | }; | ||
49 | |||
50 | struct amd_nb { | ||
51 | int nb_id; /* NorthBridge id */ | ||
52 | int refcnt; /* reference count */ | ||
53 | struct perf_event *owners[X86_PMC_IDX_MAX]; | ||
54 | struct event_constraint event_constraints[X86_PMC_IDX_MAX]; | ||
55 | }; | ||
56 | |||
57 | /* The maximal number of PEBS events: */ | ||
58 | #define MAX_PEBS_EVENTS 4 | ||
59 | |||
60 | /* | ||
61 | * A debug store configuration. | ||
62 | * | ||
63 | * We only support architectures that use 64bit fields. | ||
64 | */ | ||
65 | struct debug_store { | ||
66 | u64 bts_buffer_base; | ||
67 | u64 bts_index; | ||
68 | u64 bts_absolute_maximum; | ||
69 | u64 bts_interrupt_threshold; | ||
70 | u64 pebs_buffer_base; | ||
71 | u64 pebs_index; | ||
72 | u64 pebs_absolute_maximum; | ||
73 | u64 pebs_interrupt_threshold; | ||
74 | u64 pebs_event_reset[MAX_PEBS_EVENTS]; | ||
75 | }; | ||
76 | |||
77 | /* | ||
78 | * Per register state. | ||
79 | */ | ||
80 | struct er_account { | ||
81 | raw_spinlock_t lock; /* per-core: protect structure */ | ||
82 | u64 config; /* extra MSR config */ | ||
83 | u64 reg; /* extra MSR number */ | ||
84 | atomic_t ref; /* reference count */ | ||
85 | }; | ||
86 | |||
87 | /* | ||
88 | * Per core/cpu state | ||
89 | * | ||
90 | * Used to coordinate shared registers between HT threads or | ||
91 | * among events on a single PMU. | ||
92 | */ | ||
93 | struct intel_shared_regs { | ||
94 | struct er_account regs[EXTRA_REG_MAX]; | ||
95 | int refcnt; /* per-core: #HT threads */ | ||
96 | unsigned core_id; /* per-core: core id */ | ||
97 | }; | ||
98 | |||
99 | #define MAX_LBR_ENTRIES 16 | ||
100 | |||
101 | struct cpu_hw_events { | ||
102 | /* | ||
103 | * Generic x86 PMC bits | ||
104 | */ | ||
105 | struct perf_event *events[X86_PMC_IDX_MAX]; /* in counter order */ | ||
106 | unsigned long active_mask[BITS_TO_LONGS(X86_PMC_IDX_MAX)]; | ||
107 | unsigned long running[BITS_TO_LONGS(X86_PMC_IDX_MAX)]; | ||
108 | int enabled; | ||
109 | |||
110 | int n_events; | ||
111 | int n_added; | ||
112 | int n_txn; | ||
113 | int assign[X86_PMC_IDX_MAX]; /* event to counter assignment */ | ||
114 | u64 tags[X86_PMC_IDX_MAX]; | ||
115 | struct perf_event *event_list[X86_PMC_IDX_MAX]; /* in enabled order */ | ||
116 | |||
117 | unsigned int group_flag; | ||
118 | |||
119 | /* | ||
120 | * Intel DebugStore bits | ||
121 | */ | ||
122 | struct debug_store *ds; | ||
123 | u64 pebs_enabled; | ||
124 | |||
125 | /* | ||
126 | * Intel LBR bits | ||
127 | */ | ||
128 | int lbr_users; | ||
129 | void *lbr_context; | ||
130 | struct perf_branch_stack lbr_stack; | ||
131 | struct perf_branch_entry lbr_entries[MAX_LBR_ENTRIES]; | ||
132 | |||
133 | /* | ||
134 | * manage shared (per-core, per-cpu) registers | ||
135 | * used on Intel NHM/WSM/SNB | ||
136 | */ | ||
137 | struct intel_shared_regs *shared_regs; | ||
138 | |||
139 | /* | ||
140 | * AMD specific bits | ||
141 | */ | ||
142 | struct amd_nb *amd_nb; | ||
143 | |||
144 | void *kfree_on_online; | ||
145 | }; | ||
146 | |||
147 | #define __EVENT_CONSTRAINT(c, n, m, w) {\ | ||
148 | { .idxmsk64 = (n) }, \ | ||
149 | .code = (c), \ | ||
150 | .cmask = (m), \ | ||
151 | .weight = (w), \ | ||
152 | } | ||
153 | |||
154 | #define EVENT_CONSTRAINT(c, n, m) \ | ||
155 | __EVENT_CONSTRAINT(c, n, m, HWEIGHT(n)) | ||
156 | |||
157 | /* | ||
158 | * Constraint on the Event code. | ||
159 | */ | ||
160 | #define INTEL_EVENT_CONSTRAINT(c, n) \ | ||
161 | EVENT_CONSTRAINT(c, n, ARCH_PERFMON_EVENTSEL_EVENT) | ||
162 | |||
163 | /* | ||
164 | * Constraint on the Event code + UMask + fixed-mask | ||
165 | * | ||
166 | * filter mask to validate fixed counter events. | ||
167 | * the following filters disqualify for fixed counters: | ||
168 | * - inv | ||
169 | * - edge | ||
170 | * - cnt-mask | ||
171 | * The other filters are supported by fixed counters. | ||
172 | * The any-thread option is supported starting with v3. | ||
173 | */ | ||
174 | #define FIXED_EVENT_CONSTRAINT(c, n) \ | ||
175 | EVENT_CONSTRAINT(c, (1ULL << (32+n)), X86_RAW_EVENT_MASK) | ||
176 | |||
177 | /* | ||
178 | * Constraint on the Event code + UMask | ||
179 | */ | ||
180 | #define INTEL_UEVENT_CONSTRAINT(c, n) \ | ||
181 | EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK) | ||
182 | |||
183 | #define EVENT_CONSTRAINT_END \ | ||
184 | EVENT_CONSTRAINT(0, 0, 0) | ||
185 | |||
186 | #define for_each_event_constraint(e, c) \ | ||
187 | for ((e) = (c); (e)->weight; (e)++) | ||
188 | |||
189 | /* | ||
190 | * Extra registers for specific events. | ||
191 | * | ||
192 | * Some events need large masks and require external MSRs. | ||
193 | * Those extra MSRs end up being shared for all events on | ||
194 | * a PMU and sometimes between PMU of sibling HT threads. | ||
195 | * In either case, the kernel needs to handle conflicting | ||
196 | * accesses to those extra, shared, regs. The data structure | ||
197 | * to manage those registers is stored in cpu_hw_event. | ||
198 | */ | ||
199 | struct extra_reg { | ||
200 | unsigned int event; | ||
201 | unsigned int msr; | ||
202 | u64 config_mask; | ||
203 | u64 valid_mask; | ||
204 | int idx; /* per_xxx->regs[] reg index */ | ||
205 | }; | ||
206 | |||
207 | #define EVENT_EXTRA_REG(e, ms, m, vm, i) { \ | ||
208 | .event = (e), \ | ||
209 | .msr = (ms), \ | ||
210 | .config_mask = (m), \ | ||
211 | .valid_mask = (vm), \ | ||
212 | .idx = EXTRA_REG_##i \ | ||
213 | } | ||
214 | |||
215 | #define INTEL_EVENT_EXTRA_REG(event, msr, vm, idx) \ | ||
216 | EVENT_EXTRA_REG(event, msr, ARCH_PERFMON_EVENTSEL_EVENT, vm, idx) | ||
217 | |||
218 | #define EVENT_EXTRA_END EVENT_EXTRA_REG(0, 0, 0, 0, RSP_0) | ||
219 | |||
220 | union perf_capabilities { | ||
221 | struct { | ||
222 | u64 lbr_format:6; | ||
223 | u64 pebs_trap:1; | ||
224 | u64 pebs_arch_reg:1; | ||
225 | u64 pebs_format:4; | ||
226 | u64 smm_freeze:1; | ||
227 | }; | ||
228 | u64 capabilities; | ||
229 | }; | ||
230 | |||
231 | /* | ||
232 | * struct x86_pmu - generic x86 pmu | ||
233 | */ | ||
234 | struct x86_pmu { | ||
235 | /* | ||
236 | * Generic x86 PMC bits | ||
237 | */ | ||
238 | const char *name; | ||
239 | int version; | ||
240 | int (*handle_irq)(struct pt_regs *); | ||
241 | void (*disable_all)(void); | ||
242 | void (*enable_all)(int added); | ||
243 | void (*enable)(struct perf_event *); | ||
244 | void (*disable)(struct perf_event *); | ||
245 | int (*hw_config)(struct perf_event *event); | ||
246 | int (*schedule_events)(struct cpu_hw_events *cpuc, int n, int *assign); | ||
247 | unsigned eventsel; | ||
248 | unsigned perfctr; | ||
249 | u64 (*event_map)(int); | ||
250 | int max_events; | ||
251 | int num_counters; | ||
252 | int num_counters_fixed; | ||
253 | int cntval_bits; | ||
254 | u64 cntval_mask; | ||
255 | int apic; | ||
256 | u64 max_period; | ||
257 | struct event_constraint * | ||
258 | (*get_event_constraints)(struct cpu_hw_events *cpuc, | ||
259 | struct perf_event *event); | ||
260 | |||
261 | void (*put_event_constraints)(struct cpu_hw_events *cpuc, | ||
262 | struct perf_event *event); | ||
263 | struct event_constraint *event_constraints; | ||
264 | void (*quirks)(void); | ||
265 | int perfctr_second_write; | ||
266 | |||
267 | int (*cpu_prepare)(int cpu); | ||
268 | void (*cpu_starting)(int cpu); | ||
269 | void (*cpu_dying)(int cpu); | ||
270 | void (*cpu_dead)(int cpu); | ||
271 | |||
272 | /* | ||
273 | * Intel Arch Perfmon v2+ | ||
274 | */ | ||
275 | u64 intel_ctrl; | ||
276 | union perf_capabilities intel_cap; | ||
277 | |||
278 | /* | ||
279 | * Intel DebugStore bits | ||
280 | */ | ||
281 | int bts, pebs; | ||
282 | int bts_active, pebs_active; | ||
283 | int pebs_record_size; | ||
284 | void (*drain_pebs)(struct pt_regs *regs); | ||
285 | struct event_constraint *pebs_constraints; | ||
286 | |||
287 | /* | ||
288 | * Intel LBR | ||
289 | */ | ||
290 | unsigned long lbr_tos, lbr_from, lbr_to; /* MSR base regs */ | ||
291 | int lbr_nr; /* hardware stack size */ | ||
292 | |||
293 | /* | ||
294 | * Extra registers for events | ||
295 | */ | ||
296 | struct extra_reg *extra_regs; | ||
297 | unsigned int er_flags; | ||
298 | }; | ||
299 | |||
300 | #define ERF_NO_HT_SHARING 1 | ||
301 | #define ERF_HAS_RSP_1 2 | ||
302 | |||
303 | extern struct x86_pmu x86_pmu __read_mostly; | ||
304 | |||
305 | DECLARE_PER_CPU(struct cpu_hw_events, cpu_hw_events); | ||
306 | |||
307 | int x86_perf_event_set_period(struct perf_event *event); | ||
308 | |||
309 | /* | ||
310 | * Generalized hw caching related hw_event table, filled | ||
311 | * in on a per model basis. A value of 0 means | ||
312 | * 'not supported', -1 means 'hw_event makes no sense on | ||
313 | * this CPU', any other value means the raw hw_event | ||
314 | * ID. | ||
315 | */ | ||
316 | |||
317 | #define C(x) PERF_COUNT_HW_CACHE_##x | ||
318 | |||
319 | extern u64 __read_mostly hw_cache_event_ids | ||
320 | [PERF_COUNT_HW_CACHE_MAX] | ||
321 | [PERF_COUNT_HW_CACHE_OP_MAX] | ||
322 | [PERF_COUNT_HW_CACHE_RESULT_MAX]; | ||
323 | extern u64 __read_mostly hw_cache_extra_regs | ||
324 | [PERF_COUNT_HW_CACHE_MAX] | ||
325 | [PERF_COUNT_HW_CACHE_OP_MAX] | ||
326 | [PERF_COUNT_HW_CACHE_RESULT_MAX]; | ||
327 | |||
328 | u64 x86_perf_event_update(struct perf_event *event); | ||
329 | |||
330 | static inline int x86_pmu_addr_offset(int index) | ||
331 | { | ||
332 | int offset; | ||
333 | |||
334 | /* offset = X86_FEATURE_PERFCTR_CORE ? index << 1 : index */ | ||
335 | alternative_io(ASM_NOP2, | ||
336 | "shll $1, %%eax", | ||
337 | X86_FEATURE_PERFCTR_CORE, | ||
338 | "=a" (offset), | ||
339 | "a" (index)); | ||
340 | |||
341 | return offset; | ||
342 | } | ||
343 | |||
344 | static inline unsigned int x86_pmu_config_addr(int index) | ||
345 | { | ||
346 | return x86_pmu.eventsel + x86_pmu_addr_offset(index); | ||
347 | } | ||
348 | |||
349 | static inline unsigned int x86_pmu_event_addr(int index) | ||
350 | { | ||
351 | return x86_pmu.perfctr + x86_pmu_addr_offset(index); | ||
352 | } | ||
353 | |||
354 | int x86_setup_perfctr(struct perf_event *event); | ||
355 | |||
356 | int x86_pmu_hw_config(struct perf_event *event); | ||
357 | |||
358 | void x86_pmu_disable_all(void); | ||
359 | |||
360 | static inline void __x86_pmu_enable_event(struct hw_perf_event *hwc, | ||
361 | u64 enable_mask) | ||
362 | { | ||
363 | if (hwc->extra_reg.reg) | ||
364 | wrmsrl(hwc->extra_reg.reg, hwc->extra_reg.config); | ||
365 | wrmsrl(hwc->config_base, hwc->config | enable_mask); | ||
366 | } | ||
367 | |||
368 | void x86_pmu_enable_all(int added); | ||
369 | |||
370 | int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign); | ||
371 | |||
372 | void x86_pmu_stop(struct perf_event *event, int flags); | ||
373 | |||
374 | static inline void x86_pmu_disable_event(struct perf_event *event) | ||
375 | { | ||
376 | struct hw_perf_event *hwc = &event->hw; | ||
377 | |||
378 | wrmsrl(hwc->config_base, hwc->config); | ||
379 | } | ||
380 | |||
381 | void x86_pmu_enable_event(struct perf_event *event); | ||
382 | |||
383 | int x86_pmu_handle_irq(struct pt_regs *regs); | ||
384 | |||
385 | extern struct event_constraint emptyconstraint; | ||
386 | |||
387 | extern struct event_constraint unconstrained; | ||
388 | |||
389 | #ifdef CONFIG_CPU_SUP_AMD | ||
390 | |||
391 | int amd_pmu_init(void); | ||
392 | |||
393 | #else /* CONFIG_CPU_SUP_AMD */ | ||
394 | |||
395 | static inline int amd_pmu_init(void) | ||
396 | { | ||
397 | return 0; | ||
398 | } | ||
399 | |||
400 | #endif /* CONFIG_CPU_SUP_AMD */ | ||
401 | |||
402 | #ifdef CONFIG_CPU_SUP_INTEL | ||
403 | |||
404 | int intel_pmu_save_and_restart(struct perf_event *event); | ||
405 | |||
406 | struct event_constraint * | ||
407 | x86_get_event_constraints(struct cpu_hw_events *cpuc, struct perf_event *event); | ||
408 | |||
409 | struct intel_shared_regs *allocate_shared_regs(int cpu); | ||
410 | |||
411 | int intel_pmu_init(void); | ||
412 | |||
413 | void init_debug_store_on_cpu(int cpu); | ||
414 | |||
415 | void fini_debug_store_on_cpu(int cpu); | ||
416 | |||
417 | void release_ds_buffers(void); | ||
418 | |||
419 | void reserve_ds_buffers(void); | ||
420 | |||
421 | extern struct event_constraint bts_constraint; | ||
422 | |||
423 | void intel_pmu_enable_bts(u64 config); | ||
424 | |||
425 | void intel_pmu_disable_bts(void); | ||
426 | |||
427 | int intel_pmu_drain_bts_buffer(void); | ||
428 | |||
429 | extern struct event_constraint intel_core2_pebs_event_constraints[]; | ||
430 | |||
431 | extern struct event_constraint intel_atom_pebs_event_constraints[]; | ||
432 | |||
433 | extern struct event_constraint intel_nehalem_pebs_event_constraints[]; | ||
434 | |||
435 | extern struct event_constraint intel_westmere_pebs_event_constraints[]; | ||
436 | |||
437 | extern struct event_constraint intel_snb_pebs_event_constraints[]; | ||
438 | |||
439 | struct event_constraint *intel_pebs_constraints(struct perf_event *event); | ||
440 | |||
441 | void intel_pmu_pebs_enable(struct perf_event *event); | ||
442 | |||
443 | void intel_pmu_pebs_disable(struct perf_event *event); | ||
444 | |||
445 | void intel_pmu_pebs_enable_all(void); | ||
446 | |||
447 | void intel_pmu_pebs_disable_all(void); | ||
448 | |||
449 | void intel_ds_init(void); | ||
450 | |||
451 | void intel_pmu_lbr_reset(void); | ||
452 | |||
453 | void intel_pmu_lbr_enable(struct perf_event *event); | ||
454 | |||
455 | void intel_pmu_lbr_disable(struct perf_event *event); | ||
456 | |||
457 | void intel_pmu_lbr_enable_all(void); | ||
458 | |||
459 | void intel_pmu_lbr_disable_all(void); | ||
460 | |||
461 | void intel_pmu_lbr_read(void); | ||
462 | |||
463 | void intel_pmu_lbr_init_core(void); | ||
464 | |||
465 | void intel_pmu_lbr_init_nhm(void); | ||
466 | |||
467 | void intel_pmu_lbr_init_atom(void); | ||
468 | |||
469 | int p4_pmu_init(void); | ||
470 | |||
471 | int p6_pmu_init(void); | ||
472 | |||
473 | #else /* CONFIG_CPU_SUP_INTEL */ | ||
474 | |||
475 | static inline void reserve_ds_buffers(void) | ||
476 | { | ||
477 | } | ||
478 | |||
479 | static inline void release_ds_buffers(void) | ||
480 | { | ||
481 | } | ||
482 | |||
483 | static inline int intel_pmu_init(void) | ||
484 | { | ||
485 | return 0; | ||
486 | } | ||
487 | |||
488 | static inline struct intel_shared_regs *allocate_shared_regs(int cpu) | ||
489 | { | ||
490 | return NULL; | ||
491 | } | ||
492 | |||
493 | #endif /* CONFIG_CPU_SUP_INTEL */ | ||