blob: 1cedc3468ce5b85f1a91db1938631f882c4de64c [file] [log] [blame]
Ingo Molnar241771e2008-12-03 10:39:53 +01001/*
2 * Performance counter x86 architecture code
3 *
4 * Copyright(C) 2008 Thomas Gleixner <tglx@linutronix.de>
5 * Copyright(C) 2008 Red Hat, Inc., Ingo Molnar
Jaswinder Singh Rajputb56a3802009-02-27 18:09:09 +05306 * Copyright(C) 2009 Jaswinder Singh Rajput
Ingo Molnar241771e2008-12-03 10:39:53 +01007 *
8 * For licencing details see kernel-base/COPYING
9 */
10
11#include <linux/perf_counter.h>
12#include <linux/capability.h>
13#include <linux/notifier.h>
14#include <linux/hardirq.h>
15#include <linux/kprobes.h>
Thomas Gleixner4ac13292008-12-09 21:43:39 +010016#include <linux/module.h>
Ingo Molnar241771e2008-12-03 10:39:53 +010017#include <linux/kdebug.h>
18#include <linux/sched.h>
19
Ingo Molnar241771e2008-12-03 10:39:53 +010020#include <asm/apic.h>
21
22static bool perf_counters_initialized __read_mostly;
23
24/*
25 * Number of (generic) HW counters:
26 */
Ingo Molnar862a1a52008-12-17 13:09:20 +010027static int nr_counters_generic __read_mostly;
28static u64 perf_counter_mask __read_mostly;
Ingo Molnar2f18d1e2008-12-22 11:10:42 +010029static u64 counter_value_mask __read_mostly;
Peter Zijlstrab0f3f282009-03-05 18:08:27 +010030static int counter_value_bits __read_mostly;
Ingo Molnar241771e2008-12-03 10:39:53 +010031
Ingo Molnar862a1a52008-12-17 13:09:20 +010032static int nr_counters_fixed __read_mostly;
Ingo Molnar703e9372008-12-17 10:51:15 +010033
Ingo Molnar241771e2008-12-03 10:39:53 +010034struct cpu_hw_counters {
Ingo Molnar862a1a52008-12-17 13:09:20 +010035 struct perf_counter *counters[X86_PMC_IDX_MAX];
36 unsigned long used[BITS_TO_LONGS(X86_PMC_IDX_MAX)];
Mike Galbraith4b39fd92009-01-23 14:36:16 +010037 unsigned long interrupts;
Peter Zijlstrab0f3f282009-03-05 18:08:27 +010038 u64 throttle_ctrl;
Peter Zijlstra184fe4ab2009-03-08 11:34:19 +010039 unsigned long active_mask[BITS_TO_LONGS(X86_PMC_IDX_MAX)];
Peter Zijlstrab0f3f282009-03-05 18:08:27 +010040 int enabled;
Ingo Molnar241771e2008-12-03 10:39:53 +010041};
42
43/*
Jaswinder Singh Rajputb56a3802009-02-27 18:09:09 +053044 * struct pmc_x86_ops - performance counter x86 ops
Ingo Molnar241771e2008-12-03 10:39:53 +010045 */
Jaswinder Singh Rajputb56a3802009-02-27 18:09:09 +053046struct pmc_x86_ops {
Jaswinder Singh Rajput169e41e2009-02-28 18:37:49 +053047 u64 (*save_disable_all)(void);
Peter Zijlstrab0f3f282009-03-05 18:08:27 +010048 void (*restore_all)(u64);
49 u64 (*get_status)(u64);
50 void (*ack_status)(u64);
51 void (*enable)(int, u64);
52 void (*disable)(int, u64);
Jaswinder Singh Rajput169e41e2009-02-28 18:37:49 +053053 unsigned eventsel;
54 unsigned perfctr;
Peter Zijlstrab0f3f282009-03-05 18:08:27 +010055 u64 (*event_map)(int);
56 u64 (*raw_event)(u64);
Jaswinder Singh Rajput169e41e2009-02-28 18:37:49 +053057 int max_events;
Jaswinder Singh Rajputb56a3802009-02-27 18:09:09 +053058};
59
60static struct pmc_x86_ops *pmc_ops;
61
Peter Zijlstrab0f3f282009-03-05 18:08:27 +010062static DEFINE_PER_CPU(struct cpu_hw_counters, cpu_hw_counters) = {
63 .enabled = 1,
64};
Ingo Molnar241771e2008-12-03 10:39:53 +010065
Jaswinder Singh Rajputb56a3802009-02-27 18:09:09 +053066/*
67 * Intel PerfMon v3. Used on Core2 and later.
68 */
Peter Zijlstrab0f3f282009-03-05 18:08:27 +010069static const u64 intel_perfmon_event_map[] =
Ingo Molnar241771e2008-12-03 10:39:53 +010070{
Ingo Molnarf650a672008-12-23 12:17:29 +010071 [PERF_COUNT_CPU_CYCLES] = 0x003c,
Ingo Molnar241771e2008-12-03 10:39:53 +010072 [PERF_COUNT_INSTRUCTIONS] = 0x00c0,
73 [PERF_COUNT_CACHE_REFERENCES] = 0x4f2e,
74 [PERF_COUNT_CACHE_MISSES] = 0x412e,
75 [PERF_COUNT_BRANCH_INSTRUCTIONS] = 0x00c4,
76 [PERF_COUNT_BRANCH_MISSES] = 0x00c5,
Ingo Molnarf650a672008-12-23 12:17:29 +010077 [PERF_COUNT_BUS_CYCLES] = 0x013c,
Ingo Molnar241771e2008-12-03 10:39:53 +010078};
79
Peter Zijlstrab0f3f282009-03-05 18:08:27 +010080static u64 pmc_intel_event_map(int event)
Jaswinder Singh Rajputb56a3802009-02-27 18:09:09 +053081{
82 return intel_perfmon_event_map[event];
83}
Ingo Molnar241771e2008-12-03 10:39:53 +010084
Peter Zijlstrab0f3f282009-03-05 18:08:27 +010085static u64 pmc_intel_raw_event(u64 event)
86{
87#define CORE_EVNTSEL_EVENT_MASK 0x000000FF
88#define CORE_EVNTSEL_UNIT_MASK 0x0000FF00
89#define CORE_EVNTSEL_COUNTER_MASK 0xFF000000
90
91#define CORE_EVNTSEL_MASK \
92 (CORE_EVNTSEL_EVENT_MASK | \
93 CORE_EVNTSEL_UNIT_MASK | \
94 CORE_EVNTSEL_COUNTER_MASK)
95
96 return event & CORE_EVNTSEL_MASK;
97}
98
Ingo Molnar241771e2008-12-03 10:39:53 +010099/*
Jaswinder Singh Rajputf87ad352009-02-27 20:15:14 +0530100 * AMD Performance Monitor K7 and later.
101 */
Peter Zijlstrab0f3f282009-03-05 18:08:27 +0100102static const u64 amd_perfmon_event_map[] =
Jaswinder Singh Rajputf87ad352009-02-27 20:15:14 +0530103{
104 [PERF_COUNT_CPU_CYCLES] = 0x0076,
105 [PERF_COUNT_INSTRUCTIONS] = 0x00c0,
106 [PERF_COUNT_CACHE_REFERENCES] = 0x0080,
107 [PERF_COUNT_CACHE_MISSES] = 0x0081,
108 [PERF_COUNT_BRANCH_INSTRUCTIONS] = 0x00c4,
109 [PERF_COUNT_BRANCH_MISSES] = 0x00c5,
110};
111
Peter Zijlstrab0f3f282009-03-05 18:08:27 +0100112static u64 pmc_amd_event_map(int event)
Jaswinder Singh Rajputf87ad352009-02-27 20:15:14 +0530113{
114 return amd_perfmon_event_map[event];
115}
116
Peter Zijlstrab0f3f282009-03-05 18:08:27 +0100117static u64 pmc_amd_raw_event(u64 event)
118{
119#define K7_EVNTSEL_EVENT_MASK 0x7000000FF
120#define K7_EVNTSEL_UNIT_MASK 0x00000FF00
121#define K7_EVNTSEL_COUNTER_MASK 0x0FF000000
122
123#define K7_EVNTSEL_MASK \
124 (K7_EVNTSEL_EVENT_MASK | \
125 K7_EVNTSEL_UNIT_MASK | \
126 K7_EVNTSEL_COUNTER_MASK)
127
128 return event & K7_EVNTSEL_MASK;
129}
130
Jaswinder Singh Rajputf87ad352009-02-27 20:15:14 +0530131/*
Ingo Molnaree060942008-12-13 09:00:03 +0100132 * Propagate counter elapsed time into the generic counter.
133 * Can only be executed on the CPU where the counter is active.
134 * Returns the delta events processed.
135 */
136static void
137x86_perf_counter_update(struct perf_counter *counter,
138 struct hw_perf_counter *hwc, int idx)
139{
140 u64 prev_raw_count, new_raw_count, delta;
141
Ingo Molnaree060942008-12-13 09:00:03 +0100142 /*
143 * Careful: an NMI might modify the previous counter value.
144 *
145 * Our tactic to handle this is to first atomically read and
146 * exchange a new raw count - then add that new-prev delta
147 * count to the generic counter atomically:
148 */
149again:
150 prev_raw_count = atomic64_read(&hwc->prev_count);
151 rdmsrl(hwc->counter_base + idx, new_raw_count);
152
153 if (atomic64_cmpxchg(&hwc->prev_count, prev_raw_count,
154 new_raw_count) != prev_raw_count)
155 goto again;
156
157 /*
158 * Now we have the new raw value and have updated the prev
159 * timestamp already. We can now calculate the elapsed delta
160 * (counter-)time and add that to the generic counter.
161 *
162 * Careful, not all hw sign-extends above the physical width
163 * of the count, so we do that by clipping the delta to 32 bits:
164 */
165 delta = (u64)(u32)((s32)new_raw_count - (s32)prev_raw_count);
Ingo Molnaree060942008-12-13 09:00:03 +0100166
167 atomic64_add(delta, &counter->count);
168 atomic64_sub(delta, &hwc->period_left);
169}
170
171/*
Ingo Molnar241771e2008-12-03 10:39:53 +0100172 * Setup the hardware configuration for a given hw_event_type
173 */
Ingo Molnar621a01e2008-12-11 12:46:46 +0100174static int __hw_perf_counter_init(struct perf_counter *counter)
Ingo Molnar241771e2008-12-03 10:39:53 +0100175{
Ingo Molnar9f66a382008-12-10 12:33:23 +0100176 struct perf_counter_hw_event *hw_event = &counter->hw_event;
Ingo Molnar241771e2008-12-03 10:39:53 +0100177 struct hw_perf_counter *hwc = &counter->hw;
178
179 if (unlikely(!perf_counters_initialized))
180 return -EINVAL;
181
182 /*
Paul Mackerras0475f9e2009-02-11 14:35:35 +1100183 * Generate PMC IRQs:
Ingo Molnar241771e2008-12-03 10:39:53 +0100184 * (keep 'enabled' bit clear for now)
185 */
Paul Mackerras0475f9e2009-02-11 14:35:35 +1100186 hwc->config = ARCH_PERFMON_EVENTSEL_INT;
Ingo Molnar241771e2008-12-03 10:39:53 +0100187
188 /*
Paul Mackerras0475f9e2009-02-11 14:35:35 +1100189 * Count user and OS events unless requested not to.
190 */
191 if (!hw_event->exclude_user)
192 hwc->config |= ARCH_PERFMON_EVENTSEL_USR;
193 if (!hw_event->exclude_kernel)
194 hwc->config |= ARCH_PERFMON_EVENTSEL_OS;
195
196 /*
197 * If privileged enough, allow NMI events:
Ingo Molnar241771e2008-12-03 10:39:53 +0100198 */
199 hwc->nmi = 0;
Paul Mackerras0475f9e2009-02-11 14:35:35 +1100200 if (capable(CAP_SYS_ADMIN) && hw_event->nmi)
201 hwc->nmi = 1;
Ingo Molnar241771e2008-12-03 10:39:53 +0100202
Ingo Molnar9f66a382008-12-10 12:33:23 +0100203 hwc->irq_period = hw_event->irq_period;
Ingo Molnar241771e2008-12-03 10:39:53 +0100204 /*
205 * Intel PMCs cannot be accessed sanely above 32 bit width,
206 * so we install an artificial 1<<31 period regardless of
207 * the generic counter period:
208 */
Jaswinder Singh Rajputf87ad352009-02-27 20:15:14 +0530209 if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL)
210 if ((s64)hwc->irq_period <= 0 || hwc->irq_period > 0x7FFFFFFF)
211 hwc->irq_period = 0x7FFFFFFF;
Ingo Molnar241771e2008-12-03 10:39:53 +0100212
Ingo Molnaree060942008-12-13 09:00:03 +0100213 atomic64_set(&hwc->period_left, hwc->irq_period);
Ingo Molnar241771e2008-12-03 10:39:53 +0100214
215 /*
Thomas Gleixnerdfa7c892008-12-08 19:35:37 +0100216 * Raw event type provide the config in the event structure
Ingo Molnar241771e2008-12-03 10:39:53 +0100217 */
Ingo Molnar9f66a382008-12-10 12:33:23 +0100218 if (hw_event->raw) {
Peter Zijlstrab0f3f282009-03-05 18:08:27 +0100219 hwc->config |= pmc_ops->raw_event(hw_event->type);
Ingo Molnar241771e2008-12-03 10:39:53 +0100220 } else {
Jaswinder Singh Rajputb56a3802009-02-27 18:09:09 +0530221 if (hw_event->type >= pmc_ops->max_events)
Ingo Molnar241771e2008-12-03 10:39:53 +0100222 return -EINVAL;
223 /*
224 * The generic map:
225 */
Jaswinder Singh Rajputb56a3802009-02-27 18:09:09 +0530226 hwc->config |= pmc_ops->event_map(hw_event->type);
Ingo Molnar241771e2008-12-03 10:39:53 +0100227 }
Ingo Molnar241771e2008-12-03 10:39:53 +0100228 counter->wakeup_pending = 0;
229
230 return 0;
231}
232
Jaswinder Singh Rajputb56a3802009-02-27 18:09:09 +0530233static u64 pmc_intel_save_disable_all(void)
Thomas Gleixner4ac13292008-12-09 21:43:39 +0100234{
235 u64 ctrl;
236
237 rdmsrl(MSR_CORE_PERF_GLOBAL_CTRL, ctrl);
Ingo Molnar862a1a52008-12-17 13:09:20 +0100238 wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, 0);
Ingo Molnar2b9ff0d2008-12-14 18:36:30 +0100239
Thomas Gleixner4ac13292008-12-09 21:43:39 +0100240 return ctrl;
241}
Jaswinder Singh Rajputb56a3802009-02-27 18:09:09 +0530242
Jaswinder Singh Rajputf87ad352009-02-27 20:15:14 +0530243static u64 pmc_amd_save_disable_all(void)
244{
Peter Zijlstrab0f3f282009-03-05 18:08:27 +0100245 struct cpu_hw_counters *cpuc = &__get_cpu_var(cpu_hw_counters);
246 int enabled, idx;
247
248 enabled = cpuc->enabled;
249 cpuc->enabled = 0;
250 barrier();
Jaswinder Singh Rajputf87ad352009-02-27 20:15:14 +0530251
252 for (idx = 0; idx < nr_counters_generic; idx++) {
Peter Zijlstrab0f3f282009-03-05 18:08:27 +0100253 u64 val;
254
Jaswinder Singh Rajputf87ad352009-02-27 20:15:14 +0530255 rdmsrl(MSR_K7_EVNTSEL0 + idx, val);
Peter Zijlstrab0f3f282009-03-05 18:08:27 +0100256 if (val & ARCH_PERFMON_EVENTSEL0_ENABLE) {
257 val &= ~ARCH_PERFMON_EVENTSEL0_ENABLE;
258 wrmsrl(MSR_K7_EVNTSEL0 + idx, val);
259 }
Jaswinder Singh Rajputf87ad352009-02-27 20:15:14 +0530260 }
261
Peter Zijlstrab0f3f282009-03-05 18:08:27 +0100262 return enabled;
Jaswinder Singh Rajputf87ad352009-02-27 20:15:14 +0530263}
264
Jaswinder Singh Rajputb56a3802009-02-27 18:09:09 +0530265u64 hw_perf_save_disable(void)
266{
267 if (unlikely(!perf_counters_initialized))
268 return 0;
269
270 return pmc_ops->save_disable_all();
271}
Peter Zijlstrab0f3f282009-03-05 18:08:27 +0100272/*
273 * Exported because of ACPI idle
274 */
Ingo Molnar01b28382008-12-11 13:45:51 +0100275EXPORT_SYMBOL_GPL(hw_perf_save_disable);
Ingo Molnar241771e2008-12-03 10:39:53 +0100276
Jaswinder Singh Rajputb56a3802009-02-27 18:09:09 +0530277static void pmc_intel_restore_all(u64 ctrl)
278{
279 wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, ctrl);
280}
281
Jaswinder Singh Rajputf87ad352009-02-27 20:15:14 +0530282static void pmc_amd_restore_all(u64 ctrl)
283{
Peter Zijlstrab0f3f282009-03-05 18:08:27 +0100284 struct cpu_hw_counters *cpuc = &__get_cpu_var(cpu_hw_counters);
Jaswinder Singh Rajputf87ad352009-02-27 20:15:14 +0530285 int idx;
286
Peter Zijlstrab0f3f282009-03-05 18:08:27 +0100287 cpuc->enabled = ctrl;
288 barrier();
289 if (!ctrl)
290 return;
291
Jaswinder Singh Rajputf87ad352009-02-27 20:15:14 +0530292 for (idx = 0; idx < nr_counters_generic; idx++) {
Peter Zijlstra184fe4ab2009-03-08 11:34:19 +0100293 if (test_bit(idx, cpuc->active_mask)) {
Peter Zijlstrab0f3f282009-03-05 18:08:27 +0100294 u64 val;
295
Jaswinder Singh Rajputf87ad352009-02-27 20:15:14 +0530296 rdmsrl(MSR_K7_EVNTSEL0 + idx, val);
297 val |= ARCH_PERFMON_EVENTSEL0_ENABLE;
298 wrmsrl(MSR_K7_EVNTSEL0 + idx, val);
299 }
300 }
301}
302
Ingo Molnaree060942008-12-13 09:00:03 +0100303void hw_perf_restore(u64 ctrl)
304{
Ingo Molnar2b9ff0d2008-12-14 18:36:30 +0100305 if (unlikely(!perf_counters_initialized))
306 return;
307
Jaswinder Singh Rajputb56a3802009-02-27 18:09:09 +0530308 pmc_ops->restore_all(ctrl);
Ingo Molnaree060942008-12-13 09:00:03 +0100309}
Peter Zijlstrab0f3f282009-03-05 18:08:27 +0100310/*
311 * Exported because of ACPI idle
312 */
Ingo Molnaree060942008-12-13 09:00:03 +0100313EXPORT_SYMBOL_GPL(hw_perf_restore);
314
Peter Zijlstrab0f3f282009-03-05 18:08:27 +0100315static u64 pmc_intel_get_status(u64 mask)
316{
317 u64 status;
318
319 rdmsrl(MSR_CORE_PERF_GLOBAL_STATUS, status);
320
321 return status;
322}
323
324static u64 pmc_amd_get_status(u64 mask)
325{
326 u64 status = 0;
327 int idx;
328
329 for (idx = 0; idx < nr_counters_generic; idx++) {
330 s64 val;
331
332 if (!(mask & (1 << idx)))
333 continue;
334
335 rdmsrl(MSR_K7_PERFCTR0 + idx, val);
336 val <<= (64 - counter_value_bits);
337 if (val >= 0)
338 status |= (1 << idx);
339 }
340
341 return status;
342}
343
344static u64 hw_perf_get_status(u64 mask)
345{
346 if (unlikely(!perf_counters_initialized))
347 return 0;
348
349 return pmc_ops->get_status(mask);
350}
351
352static void pmc_intel_ack_status(u64 ack)
353{
354 wrmsrl(MSR_CORE_PERF_GLOBAL_OVF_CTRL, ack);
355}
356
357static void pmc_amd_ack_status(u64 ack)
358{
359}
360
361static void hw_perf_ack_status(u64 ack)
362{
363 if (unlikely(!perf_counters_initialized))
364 return;
365
366 pmc_ops->ack_status(ack);
367}
368
369static void pmc_intel_enable(int idx, u64 config)
370{
371 wrmsrl(MSR_ARCH_PERFMON_EVENTSEL0 + idx,
372 config | ARCH_PERFMON_EVENTSEL0_ENABLE);
373}
374
375static void pmc_amd_enable(int idx, u64 config)
376{
377 struct cpu_hw_counters *cpuc = &__get_cpu_var(cpu_hw_counters);
378
Peter Zijlstra184fe4ab2009-03-08 11:34:19 +0100379 set_bit(idx, cpuc->active_mask);
Peter Zijlstrab0f3f282009-03-05 18:08:27 +0100380 if (cpuc->enabled)
381 config |= ARCH_PERFMON_EVENTSEL0_ENABLE;
382
383 wrmsrl(MSR_K7_EVNTSEL0 + idx, config);
384}
385
386static void hw_perf_enable(int idx, u64 config)
387{
388 if (unlikely(!perf_counters_initialized))
389 return;
390
391 pmc_ops->enable(idx, config);
392}
393
394static void pmc_intel_disable(int idx, u64 config)
395{
396 wrmsrl(MSR_ARCH_PERFMON_EVENTSEL0 + idx, config);
397}
398
399static void pmc_amd_disable(int idx, u64 config)
400{
401 struct cpu_hw_counters *cpuc = &__get_cpu_var(cpu_hw_counters);
402
Peter Zijlstra184fe4ab2009-03-08 11:34:19 +0100403 clear_bit(idx, cpuc->active_mask);
Peter Zijlstrab0f3f282009-03-05 18:08:27 +0100404 wrmsrl(MSR_K7_EVNTSEL0 + idx, config);
405
406}
407
408static void hw_perf_disable(int idx, u64 config)
409{
410 if (unlikely(!perf_counters_initialized))
411 return;
412
413 pmc_ops->disable(idx, config);
414}
415
Ingo Molnar7e2ae342008-12-09 11:40:46 +0100416static inline void
Ingo Molnar2f18d1e2008-12-22 11:10:42 +0100417__pmc_fixed_disable(struct perf_counter *counter,
418 struct hw_perf_counter *hwc, unsigned int __idx)
419{
420 int idx = __idx - X86_PMC_IDX_FIXED;
421 u64 ctrl_val, mask;
422 int err;
423
424 mask = 0xfULL << (idx * 4);
425
426 rdmsrl(hwc->config_base, ctrl_val);
427 ctrl_val &= ~mask;
428 err = checking_wrmsrl(hwc->config_base, ctrl_val);
429}
430
431static inline void
Ingo Molnareb2b8612008-12-17 09:09:13 +0100432__pmc_generic_disable(struct perf_counter *counter,
Ingo Molnaree060942008-12-13 09:00:03 +0100433 struct hw_perf_counter *hwc, unsigned int idx)
Ingo Molnar7e2ae342008-12-09 11:40:46 +0100434{
Ingo Molnar2f18d1e2008-12-22 11:10:42 +0100435 if (unlikely(hwc->config_base == MSR_ARCH_PERFMON_FIXED_CTR_CTRL))
Jaswinder Singh Rajput2b583d82008-12-27 19:15:43 +0530436 __pmc_fixed_disable(counter, hwc, idx);
437 else
Peter Zijlstrab0f3f282009-03-05 18:08:27 +0100438 hw_perf_disable(idx, hwc->config);
Ingo Molnar7e2ae342008-12-09 11:40:46 +0100439}
440
Ingo Molnar2f18d1e2008-12-22 11:10:42 +0100441static DEFINE_PER_CPU(u64, prev_left[X86_PMC_IDX_MAX]);
Ingo Molnar241771e2008-12-03 10:39:53 +0100442
Ingo Molnaree060942008-12-13 09:00:03 +0100443/*
444 * Set the next IRQ period, based on the hwc->period_left value.
445 * To be called with the counter disabled in hw:
446 */
447static void
448__hw_perf_counter_set_period(struct perf_counter *counter,
449 struct hw_perf_counter *hwc, int idx)
Ingo Molnar241771e2008-12-03 10:39:53 +0100450{
Ingo Molnar2f18d1e2008-12-22 11:10:42 +0100451 s64 left = atomic64_read(&hwc->period_left);
Peter Zijlstra595258a2009-03-13 12:21:28 +0100452 s64 period = hwc->irq_period;
Ingo Molnar2f18d1e2008-12-22 11:10:42 +0100453 int err;
Ingo Molnar241771e2008-12-03 10:39:53 +0100454
Ingo Molnaree060942008-12-13 09:00:03 +0100455 /*
456 * If we are way outside a reasoable range then just skip forward:
457 */
458 if (unlikely(left <= -period)) {
459 left = period;
460 atomic64_set(&hwc->period_left, left);
461 }
462
463 if (unlikely(left <= 0)) {
464 left += period;
465 atomic64_set(&hwc->period_left, left);
466 }
467
Ingo Molnaree060942008-12-13 09:00:03 +0100468 per_cpu(prev_left[idx], smp_processor_id()) = left;
469
470 /*
471 * The hw counter starts counting from this counter offset,
472 * mark it to be able to extra future deltas:
473 */
Ingo Molnar2f18d1e2008-12-22 11:10:42 +0100474 atomic64_set(&hwc->prev_count, (u64)-left);
Ingo Molnaree060942008-12-13 09:00:03 +0100475
Ingo Molnar2f18d1e2008-12-22 11:10:42 +0100476 err = checking_wrmsrl(hwc->counter_base + idx,
477 (u64)(-left) & counter_value_mask);
478}
479
480static inline void
481__pmc_fixed_enable(struct perf_counter *counter,
482 struct hw_perf_counter *hwc, unsigned int __idx)
483{
484 int idx = __idx - X86_PMC_IDX_FIXED;
485 u64 ctrl_val, bits, mask;
486 int err;
487
488 /*
Paul Mackerras0475f9e2009-02-11 14:35:35 +1100489 * Enable IRQ generation (0x8),
490 * and enable ring-3 counting (0x2) and ring-0 counting (0x1)
491 * if requested:
Ingo Molnar2f18d1e2008-12-22 11:10:42 +0100492 */
Paul Mackerras0475f9e2009-02-11 14:35:35 +1100493 bits = 0x8ULL;
494 if (hwc->config & ARCH_PERFMON_EVENTSEL_USR)
495 bits |= 0x2;
Ingo Molnar2f18d1e2008-12-22 11:10:42 +0100496 if (hwc->config & ARCH_PERFMON_EVENTSEL_OS)
497 bits |= 0x1;
498 bits <<= (idx * 4);
499 mask = 0xfULL << (idx * 4);
500
501 rdmsrl(hwc->config_base, ctrl_val);
502 ctrl_val &= ~mask;
503 ctrl_val |= bits;
504 err = checking_wrmsrl(hwc->config_base, ctrl_val);
Ingo Molnar7e2ae342008-12-09 11:40:46 +0100505}
506
Ingo Molnaree060942008-12-13 09:00:03 +0100507static void
Ingo Molnareb2b8612008-12-17 09:09:13 +0100508__pmc_generic_enable(struct perf_counter *counter,
Ingo Molnaree060942008-12-13 09:00:03 +0100509 struct hw_perf_counter *hwc, int idx)
Ingo Molnar7e2ae342008-12-09 11:40:46 +0100510{
Ingo Molnar2f18d1e2008-12-22 11:10:42 +0100511 if (unlikely(hwc->config_base == MSR_ARCH_PERFMON_FIXED_CTR_CTRL))
Jaswinder Singh Rajput2b583d82008-12-27 19:15:43 +0530512 __pmc_fixed_enable(counter, hwc, idx);
513 else
Peter Zijlstrab0f3f282009-03-05 18:08:27 +0100514 hw_perf_enable(idx, hwc->config);
Ingo Molnar241771e2008-12-03 10:39:53 +0100515}
516
Ingo Molnar2f18d1e2008-12-22 11:10:42 +0100517static int
518fixed_mode_idx(struct perf_counter *counter, struct hw_perf_counter *hwc)
Ingo Molnar862a1a52008-12-17 13:09:20 +0100519{
Ingo Molnar2f18d1e2008-12-22 11:10:42 +0100520 unsigned int event;
521
Jaswinder Singh Rajputf87ad352009-02-27 20:15:14 +0530522 if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
523 return -1;
524
Ingo Molnar2f18d1e2008-12-22 11:10:42 +0100525 if (unlikely(hwc->nmi))
526 return -1;
527
528 event = hwc->config & ARCH_PERFMON_EVENT_MASK;
529
Jaswinder Singh Rajputb56a3802009-02-27 18:09:09 +0530530 if (unlikely(event == pmc_ops->event_map(PERF_COUNT_INSTRUCTIONS)))
Ingo Molnar2f18d1e2008-12-22 11:10:42 +0100531 return X86_PMC_IDX_FIXED_INSTRUCTIONS;
Jaswinder Singh Rajputb56a3802009-02-27 18:09:09 +0530532 if (unlikely(event == pmc_ops->event_map(PERF_COUNT_CPU_CYCLES)))
Ingo Molnar2f18d1e2008-12-22 11:10:42 +0100533 return X86_PMC_IDX_FIXED_CPU_CYCLES;
Jaswinder Singh Rajputb56a3802009-02-27 18:09:09 +0530534 if (unlikely(event == pmc_ops->event_map(PERF_COUNT_BUS_CYCLES)))
Ingo Molnar2f18d1e2008-12-22 11:10:42 +0100535 return X86_PMC_IDX_FIXED_BUS_CYCLES;
536
Ingo Molnar862a1a52008-12-17 13:09:20 +0100537 return -1;
538}
539
Ingo Molnaree060942008-12-13 09:00:03 +0100540/*
541 * Find a PMC slot for the freshly enabled / scheduled in counter:
542 */
Ingo Molnar95cdd2e2008-12-21 13:50:42 +0100543static int pmc_generic_enable(struct perf_counter *counter)
Ingo Molnar241771e2008-12-03 10:39:53 +0100544{
545 struct cpu_hw_counters *cpuc = &__get_cpu_var(cpu_hw_counters);
546 struct hw_perf_counter *hwc = &counter->hw;
Ingo Molnar2f18d1e2008-12-22 11:10:42 +0100547 int idx;
Ingo Molnar241771e2008-12-03 10:39:53 +0100548
Ingo Molnar2f18d1e2008-12-22 11:10:42 +0100549 idx = fixed_mode_idx(counter, hwc);
550 if (idx >= 0) {
551 /*
552 * Try to get the fixed counter, if that is already taken
553 * then try to get a generic counter:
554 */
555 if (test_and_set_bit(idx, cpuc->used))
556 goto try_generic;
Ingo Molnar0dff86a2008-12-23 12:28:12 +0100557
Ingo Molnar2f18d1e2008-12-22 11:10:42 +0100558 hwc->config_base = MSR_ARCH_PERFMON_FIXED_CTR_CTRL;
559 /*
560 * We set it so that counter_base + idx in wrmsr/rdmsr maps to
561 * MSR_ARCH_PERFMON_FIXED_CTR0 ... CTR2:
562 */
563 hwc->counter_base =
564 MSR_ARCH_PERFMON_FIXED_CTR0 - X86_PMC_IDX_FIXED;
Ingo Molnar241771e2008-12-03 10:39:53 +0100565 hwc->idx = idx;
Ingo Molnar2f18d1e2008-12-22 11:10:42 +0100566 } else {
567 idx = hwc->idx;
568 /* Try to get the previous generic counter again */
569 if (test_and_set_bit(idx, cpuc->used)) {
570try_generic:
571 idx = find_first_zero_bit(cpuc->used, nr_counters_generic);
572 if (idx == nr_counters_generic)
573 return -EAGAIN;
574
575 set_bit(idx, cpuc->used);
576 hwc->idx = idx;
577 }
Jaswinder Singh Rajputb56a3802009-02-27 18:09:09 +0530578 hwc->config_base = pmc_ops->eventsel;
579 hwc->counter_base = pmc_ops->perfctr;
Ingo Molnar241771e2008-12-03 10:39:53 +0100580 }
581
582 perf_counters_lapic_init(hwc->nmi);
583
Ingo Molnareb2b8612008-12-17 09:09:13 +0100584 __pmc_generic_disable(counter, hwc, idx);
Ingo Molnar241771e2008-12-03 10:39:53 +0100585
Ingo Molnar862a1a52008-12-17 13:09:20 +0100586 cpuc->counters[idx] = counter;
Ingo Molnar2f18d1e2008-12-22 11:10:42 +0100587 /*
588 * Make it visible before enabling the hw:
589 */
590 smp_wmb();
Ingo Molnar7e2ae342008-12-09 11:40:46 +0100591
Ingo Molnaree060942008-12-13 09:00:03 +0100592 __hw_perf_counter_set_period(counter, hwc, idx);
Ingo Molnareb2b8612008-12-17 09:09:13 +0100593 __pmc_generic_enable(counter, hwc, idx);
Ingo Molnar95cdd2e2008-12-21 13:50:42 +0100594
595 return 0;
Ingo Molnar241771e2008-12-03 10:39:53 +0100596}
597
598void perf_counter_print_debug(void)
599{
Ingo Molnar2f18d1e2008-12-22 11:10:42 +0100600 u64 ctrl, status, overflow, pmc_ctrl, pmc_count, prev_left, fixed;
Ingo Molnar0dff86a2008-12-23 12:28:12 +0100601 struct cpu_hw_counters *cpuc;
Ingo Molnar1e125672008-12-09 12:18:18 +0100602 int cpu, idx;
603
Ingo Molnar862a1a52008-12-17 13:09:20 +0100604 if (!nr_counters_generic)
Ingo Molnar1e125672008-12-09 12:18:18 +0100605 return;
Ingo Molnar241771e2008-12-03 10:39:53 +0100606
607 local_irq_disable();
608
609 cpu = smp_processor_id();
Ingo Molnar0dff86a2008-12-23 12:28:12 +0100610 cpuc = &per_cpu(cpu_hw_counters, cpu);
Ingo Molnar241771e2008-12-03 10:39:53 +0100611
Jaswinder Singh Rajputf87ad352009-02-27 20:15:14 +0530612 if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) {
Jaswinder Singh Rajputa1ef58f2009-02-28 18:45:39 +0530613 rdmsrl(MSR_CORE_PERF_GLOBAL_CTRL, ctrl);
614 rdmsrl(MSR_CORE_PERF_GLOBAL_STATUS, status);
615 rdmsrl(MSR_CORE_PERF_GLOBAL_OVF_CTRL, overflow);
616 rdmsrl(MSR_ARCH_PERFMON_FIXED_CTR_CTRL, fixed);
Ingo Molnar241771e2008-12-03 10:39:53 +0100617
Jaswinder Singh Rajputa1ef58f2009-02-28 18:45:39 +0530618 pr_info("\n");
619 pr_info("CPU#%d: ctrl: %016llx\n", cpu, ctrl);
620 pr_info("CPU#%d: status: %016llx\n", cpu, status);
621 pr_info("CPU#%d: overflow: %016llx\n", cpu, overflow);
622 pr_info("CPU#%d: fixed: %016llx\n", cpu, fixed);
Jaswinder Singh Rajputf87ad352009-02-27 20:15:14 +0530623 }
Jaswinder Singh Rajputa1ef58f2009-02-28 18:45:39 +0530624 pr_info("CPU#%d: used: %016llx\n", cpu, *(u64 *)cpuc->used);
Ingo Molnar241771e2008-12-03 10:39:53 +0100625
Ingo Molnar862a1a52008-12-17 13:09:20 +0100626 for (idx = 0; idx < nr_counters_generic; idx++) {
Jaswinder Singh Rajputb56a3802009-02-27 18:09:09 +0530627 rdmsrl(pmc_ops->eventsel + idx, pmc_ctrl);
628 rdmsrl(pmc_ops->perfctr + idx, pmc_count);
Ingo Molnar241771e2008-12-03 10:39:53 +0100629
Ingo Molnaree060942008-12-13 09:00:03 +0100630 prev_left = per_cpu(prev_left[idx], cpu);
Ingo Molnar241771e2008-12-03 10:39:53 +0100631
Jaswinder Singh Rajputa1ef58f2009-02-28 18:45:39 +0530632 pr_info("CPU#%d: gen-PMC%d ctrl: %016llx\n",
Ingo Molnar241771e2008-12-03 10:39:53 +0100633 cpu, idx, pmc_ctrl);
Jaswinder Singh Rajputa1ef58f2009-02-28 18:45:39 +0530634 pr_info("CPU#%d: gen-PMC%d count: %016llx\n",
Ingo Molnar241771e2008-12-03 10:39:53 +0100635 cpu, idx, pmc_count);
Jaswinder Singh Rajputa1ef58f2009-02-28 18:45:39 +0530636 pr_info("CPU#%d: gen-PMC%d left: %016llx\n",
Ingo Molnaree060942008-12-13 09:00:03 +0100637 cpu, idx, prev_left);
Ingo Molnar241771e2008-12-03 10:39:53 +0100638 }
Ingo Molnar2f18d1e2008-12-22 11:10:42 +0100639 for (idx = 0; idx < nr_counters_fixed; idx++) {
640 rdmsrl(MSR_ARCH_PERFMON_FIXED_CTR0 + idx, pmc_count);
641
Jaswinder Singh Rajputa1ef58f2009-02-28 18:45:39 +0530642 pr_info("CPU#%d: fixed-PMC%d count: %016llx\n",
Ingo Molnar2f18d1e2008-12-22 11:10:42 +0100643 cpu, idx, pmc_count);
644 }
Ingo Molnar241771e2008-12-03 10:39:53 +0100645 local_irq_enable();
646}
647
Ingo Molnareb2b8612008-12-17 09:09:13 +0100648static void pmc_generic_disable(struct perf_counter *counter)
Ingo Molnar241771e2008-12-03 10:39:53 +0100649{
650 struct cpu_hw_counters *cpuc = &__get_cpu_var(cpu_hw_counters);
651 struct hw_perf_counter *hwc = &counter->hw;
652 unsigned int idx = hwc->idx;
653
Ingo Molnareb2b8612008-12-17 09:09:13 +0100654 __pmc_generic_disable(counter, hwc, idx);
Ingo Molnar241771e2008-12-03 10:39:53 +0100655
656 clear_bit(idx, cpuc->used);
Ingo Molnar862a1a52008-12-17 13:09:20 +0100657 cpuc->counters[idx] = NULL;
Ingo Molnar2f18d1e2008-12-22 11:10:42 +0100658 /*
659 * Make sure the cleared pointer becomes visible before we
660 * (potentially) free the counter:
661 */
662 smp_wmb();
Ingo Molnar241771e2008-12-03 10:39:53 +0100663
Ingo Molnaree060942008-12-13 09:00:03 +0100664 /*
665 * Drain the remaining delta count out of a counter
666 * that we are disabling:
667 */
668 x86_perf_counter_update(counter, hwc, idx);
Ingo Molnar241771e2008-12-03 10:39:53 +0100669}
670
671static void perf_store_irq_data(struct perf_counter *counter, u64 data)
672{
673 struct perf_data *irqdata = counter->irqdata;
674
675 if (irqdata->len > PERF_DATA_BUFLEN - sizeof(u64)) {
676 irqdata->overrun++;
677 } else {
678 u64 *p = (u64 *) &irqdata->data[irqdata->len];
679
680 *p = data;
681 irqdata->len += sizeof(u64);
682 }
683}
684
Ingo Molnar7e2ae342008-12-09 11:40:46 +0100685/*
Ingo Molnaree060942008-12-13 09:00:03 +0100686 * Save and restart an expired counter. Called by NMI contexts,
687 * so it has to be careful about preempting normal counter ops:
Ingo Molnar7e2ae342008-12-09 11:40:46 +0100688 */
Ingo Molnar241771e2008-12-03 10:39:53 +0100689static void perf_save_and_restart(struct perf_counter *counter)
690{
691 struct hw_perf_counter *hwc = &counter->hw;
692 int idx = hwc->idx;
Ingo Molnar241771e2008-12-03 10:39:53 +0100693
Ingo Molnaree060942008-12-13 09:00:03 +0100694 x86_perf_counter_update(counter, hwc, idx);
695 __hw_perf_counter_set_period(counter, hwc, idx);
Ingo Molnar7e2ae342008-12-09 11:40:46 +0100696
Ingo Molnar2f18d1e2008-12-22 11:10:42 +0100697 if (counter->state == PERF_COUNTER_STATE_ACTIVE)
Ingo Molnareb2b8612008-12-17 09:09:13 +0100698 __pmc_generic_enable(counter, hwc, idx);
Ingo Molnar241771e2008-12-03 10:39:53 +0100699}
700
701static void
Ingo Molnar04289bb2008-12-11 08:38:42 +0100702perf_handle_group(struct perf_counter *sibling, u64 *status, u64 *overflown)
Ingo Molnar241771e2008-12-03 10:39:53 +0100703{
Ingo Molnar04289bb2008-12-11 08:38:42 +0100704 struct perf_counter *counter, *group_leader = sibling->group_leader;
Ingo Molnar241771e2008-12-03 10:39:53 +0100705
Ingo Molnar04289bb2008-12-11 08:38:42 +0100706 /*
Ingo Molnaree060942008-12-13 09:00:03 +0100707 * Store sibling timestamps (if any):
Ingo Molnar04289bb2008-12-11 08:38:42 +0100708 */
709 list_for_each_entry(counter, &group_leader->sibling_list, list_entry) {
Ingo Molnar2f18d1e2008-12-22 11:10:42 +0100710
Ingo Molnaree060942008-12-13 09:00:03 +0100711 x86_perf_counter_update(counter, &counter->hw, counter->hw.idx);
Ingo Molnar04289bb2008-12-11 08:38:42 +0100712 perf_store_irq_data(sibling, counter->hw_event.type);
Ingo Molnaree060942008-12-13 09:00:03 +0100713 perf_store_irq_data(sibling, atomic64_read(&counter->count));
Ingo Molnar241771e2008-12-03 10:39:53 +0100714 }
715}
716
717/*
Mike Galbraith4b39fd92009-01-23 14:36:16 +0100718 * Maximum interrupt frequency of 100KHz per CPU
719 */
Jaswinder Singh Rajput169e41e2009-02-28 18:37:49 +0530720#define PERFMON_MAX_INTERRUPTS (100000/HZ)
Mike Galbraith4b39fd92009-01-23 14:36:16 +0100721
722/*
Ingo Molnar241771e2008-12-03 10:39:53 +0100723 * This handler is triggered by the local APIC, so the APIC IRQ handling
724 * rules apply:
725 */
Peter Zijlstrab0f3f282009-03-05 18:08:27 +0100726static int __smp_perf_counter_interrupt(struct pt_regs *regs, int nmi)
Ingo Molnar241771e2008-12-03 10:39:53 +0100727{
728 int bit, cpu = smp_processor_id();
Mike Galbraith4b39fd92009-01-23 14:36:16 +0100729 u64 ack, status;
Mike Galbraith1b023a92009-01-23 10:13:01 +0100730 struct cpu_hw_counters *cpuc = &per_cpu(cpu_hw_counters, cpu);
Peter Zijlstrab0f3f282009-03-05 18:08:27 +0100731 int ret = 0;
Ingo Molnar43874d22008-12-09 12:23:59 +0100732
Peter Zijlstrab0f3f282009-03-05 18:08:27 +0100733 cpuc->throttle_ctrl = hw_perf_save_disable();
Ingo Molnar241771e2008-12-03 10:39:53 +0100734
Peter Zijlstrab0f3f282009-03-05 18:08:27 +0100735 status = hw_perf_get_status(cpuc->throttle_ctrl);
Ingo Molnar87b9cf42008-12-08 14:20:16 +0100736 if (!status)
737 goto out;
738
Peter Zijlstrab0f3f282009-03-05 18:08:27 +0100739 ret = 1;
Ingo Molnar241771e2008-12-03 10:39:53 +0100740again:
Mike Galbraithd278c482009-02-09 07:38:50 +0100741 inc_irq_stat(apic_perf_irqs);
Ingo Molnar241771e2008-12-03 10:39:53 +0100742 ack = status;
Ingo Molnar2f18d1e2008-12-22 11:10:42 +0100743 for_each_bit(bit, (unsigned long *)&status, X86_PMC_IDX_MAX) {
Ingo Molnar862a1a52008-12-17 13:09:20 +0100744 struct perf_counter *counter = cpuc->counters[bit];
Ingo Molnar241771e2008-12-03 10:39:53 +0100745
746 clear_bit(bit, (unsigned long *) &status);
747 if (!counter)
748 continue;
749
750 perf_save_and_restart(counter);
751
Ingo Molnar9f66a382008-12-10 12:33:23 +0100752 switch (counter->hw_event.record_type) {
Ingo Molnar241771e2008-12-03 10:39:53 +0100753 case PERF_RECORD_SIMPLE:
754 continue;
755 case PERF_RECORD_IRQ:
756 perf_store_irq_data(counter, instruction_pointer(regs));
757 break;
758 case PERF_RECORD_GROUP:
Ingo Molnar241771e2008-12-03 10:39:53 +0100759 perf_handle_group(counter, &status, &ack);
760 break;
761 }
762 /*
763 * From NMI context we cannot call into the scheduler to
Ingo Molnareb2b8612008-12-17 09:09:13 +0100764 * do a task wakeup - but we mark these generic as
Ingo Molnar241771e2008-12-03 10:39:53 +0100765 * wakeup_pending and initate a wakeup callback:
766 */
767 if (nmi) {
768 counter->wakeup_pending = 1;
769 set_tsk_thread_flag(current, TIF_PERF_COUNTERS);
770 } else {
771 wake_up(&counter->waitq);
772 }
773 }
774
Peter Zijlstrab0f3f282009-03-05 18:08:27 +0100775 hw_perf_ack_status(ack);
Ingo Molnar241771e2008-12-03 10:39:53 +0100776
777 /*
778 * Repeat if there is more work to be done:
779 */
Peter Zijlstrab0f3f282009-03-05 18:08:27 +0100780 status = hw_perf_get_status(cpuc->throttle_ctrl);
Ingo Molnar241771e2008-12-03 10:39:53 +0100781 if (status)
782 goto again;
Ingo Molnar87b9cf42008-12-08 14:20:16 +0100783out:
Ingo Molnar241771e2008-12-03 10:39:53 +0100784 /*
Mike Galbraith1b023a92009-01-23 10:13:01 +0100785 * Restore - do not reenable when global enable is off or throttled:
Ingo Molnar241771e2008-12-03 10:39:53 +0100786 */
Mike Galbraith4b39fd92009-01-23 14:36:16 +0100787 if (++cpuc->interrupts < PERFMON_MAX_INTERRUPTS)
Peter Zijlstrab0f3f282009-03-05 18:08:27 +0100788 hw_perf_restore(cpuc->throttle_ctrl);
789
790 return ret;
Mike Galbraith1b023a92009-01-23 10:13:01 +0100791}
792
793void perf_counter_unthrottle(void)
794{
795 struct cpu_hw_counters *cpuc;
796
797 if (!cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON))
798 return;
799
800 if (unlikely(!perf_counters_initialized))
801 return;
802
Peter Zijlstrab0f3f282009-03-05 18:08:27 +0100803 cpuc = &__get_cpu_var(cpu_hw_counters);
Mike Galbraith4b39fd92009-01-23 14:36:16 +0100804 if (cpuc->interrupts >= PERFMON_MAX_INTERRUPTS) {
Mike Galbraith1b023a92009-01-23 10:13:01 +0100805 if (printk_ratelimit())
Mike Galbraith4b39fd92009-01-23 14:36:16 +0100806 printk(KERN_WARNING "PERFMON: max interrupts exceeded!\n");
Peter Zijlstrab0f3f282009-03-05 18:08:27 +0100807 hw_perf_restore(cpuc->throttle_ctrl);
Mike Galbraith1b023a92009-01-23 10:13:01 +0100808 }
Mike Galbraith4b39fd92009-01-23 14:36:16 +0100809 cpuc->interrupts = 0;
Ingo Molnar241771e2008-12-03 10:39:53 +0100810}
811
812void smp_perf_counter_interrupt(struct pt_regs *regs)
813{
814 irq_enter();
Ingo Molnar241771e2008-12-03 10:39:53 +0100815 apic_write(APIC_LVTPC, LOCAL_PERF_VECTOR);
Peter Zijlstrab0f3f282009-03-05 18:08:27 +0100816 ack_APIC_irq();
Ingo Molnar241771e2008-12-03 10:39:53 +0100817 __smp_perf_counter_interrupt(regs, 0);
Ingo Molnar241771e2008-12-03 10:39:53 +0100818 irq_exit();
819}
820
821/*
822 * This handler is triggered by NMI contexts:
823 */
824void perf_counter_notify(struct pt_regs *regs)
825{
826 struct cpu_hw_counters *cpuc;
827 unsigned long flags;
828 int bit, cpu;
829
830 local_irq_save(flags);
831 cpu = smp_processor_id();
832 cpuc = &per_cpu(cpu_hw_counters, cpu);
833
Ingo Molnar862a1a52008-12-17 13:09:20 +0100834 for_each_bit(bit, cpuc->used, X86_PMC_IDX_MAX) {
835 struct perf_counter *counter = cpuc->counters[bit];
Ingo Molnar241771e2008-12-03 10:39:53 +0100836
837 if (!counter)
838 continue;
839
840 if (counter->wakeup_pending) {
841 counter->wakeup_pending = 0;
842 wake_up(&counter->waitq);
843 }
844 }
845
846 local_irq_restore(flags);
847}
848
Mike Galbraith3415dd92009-01-23 14:16:53 +0100849void perf_counters_lapic_init(int nmi)
Ingo Molnar241771e2008-12-03 10:39:53 +0100850{
851 u32 apic_val;
852
853 if (!perf_counters_initialized)
854 return;
855 /*
856 * Enable the performance counter vector in the APIC LVT:
857 */
858 apic_val = apic_read(APIC_LVTERR);
859
860 apic_write(APIC_LVTERR, apic_val | APIC_LVT_MASKED);
861 if (nmi)
862 apic_write(APIC_LVTPC, APIC_DM_NMI);
863 else
864 apic_write(APIC_LVTPC, LOCAL_PERF_VECTOR);
865 apic_write(APIC_LVTERR, apic_val);
866}
867
868static int __kprobes
869perf_counter_nmi_handler(struct notifier_block *self,
870 unsigned long cmd, void *__args)
871{
872 struct die_args *args = __args;
873 struct pt_regs *regs;
Peter Zijlstrab0f3f282009-03-05 18:08:27 +0100874 int ret;
Ingo Molnar241771e2008-12-03 10:39:53 +0100875
Peter Zijlstrab0f3f282009-03-05 18:08:27 +0100876 switch (cmd) {
877 case DIE_NMI:
878 case DIE_NMI_IPI:
879 break;
880
881 default:
Ingo Molnar241771e2008-12-03 10:39:53 +0100882 return NOTIFY_DONE;
Peter Zijlstrab0f3f282009-03-05 18:08:27 +0100883 }
Ingo Molnar241771e2008-12-03 10:39:53 +0100884
885 regs = args->regs;
886
887 apic_write(APIC_LVTPC, APIC_DM_NMI);
Peter Zijlstrab0f3f282009-03-05 18:08:27 +0100888 ret = __smp_perf_counter_interrupt(regs, 1);
Ingo Molnar241771e2008-12-03 10:39:53 +0100889
Peter Zijlstrab0f3f282009-03-05 18:08:27 +0100890 return ret ? NOTIFY_STOP : NOTIFY_OK;
Ingo Molnar241771e2008-12-03 10:39:53 +0100891}
892
893static __read_mostly struct notifier_block perf_counter_nmi_notifier = {
Mike Galbraith5b75af02009-02-04 17:11:34 +0100894 .notifier_call = perf_counter_nmi_handler,
895 .next = NULL,
896 .priority = 1
Ingo Molnar241771e2008-12-03 10:39:53 +0100897};
898
Jaswinder Singh Rajputb56a3802009-02-27 18:09:09 +0530899static struct pmc_x86_ops pmc_intel_ops = {
900 .save_disable_all = pmc_intel_save_disable_all,
901 .restore_all = pmc_intel_restore_all,
Peter Zijlstrab0f3f282009-03-05 18:08:27 +0100902 .get_status = pmc_intel_get_status,
903 .ack_status = pmc_intel_ack_status,
904 .enable = pmc_intel_enable,
905 .disable = pmc_intel_disable,
Jaswinder Singh Rajputb56a3802009-02-27 18:09:09 +0530906 .eventsel = MSR_ARCH_PERFMON_EVENTSEL0,
907 .perfctr = MSR_ARCH_PERFMON_PERFCTR0,
908 .event_map = pmc_intel_event_map,
Peter Zijlstrab0f3f282009-03-05 18:08:27 +0100909 .raw_event = pmc_intel_raw_event,
Jaswinder Singh Rajputb56a3802009-02-27 18:09:09 +0530910 .max_events = ARRAY_SIZE(intel_perfmon_event_map),
911};
912
Jaswinder Singh Rajputf87ad352009-02-27 20:15:14 +0530913static struct pmc_x86_ops pmc_amd_ops = {
914 .save_disable_all = pmc_amd_save_disable_all,
915 .restore_all = pmc_amd_restore_all,
Peter Zijlstrab0f3f282009-03-05 18:08:27 +0100916 .get_status = pmc_amd_get_status,
917 .ack_status = pmc_amd_ack_status,
918 .enable = pmc_amd_enable,
919 .disable = pmc_amd_disable,
Jaswinder Singh Rajputf87ad352009-02-27 20:15:14 +0530920 .eventsel = MSR_K7_EVNTSEL0,
921 .perfctr = MSR_K7_PERFCTR0,
922 .event_map = pmc_amd_event_map,
Peter Zijlstrab0f3f282009-03-05 18:08:27 +0100923 .raw_event = pmc_amd_raw_event,
Jaswinder Singh Rajputf87ad352009-02-27 20:15:14 +0530924 .max_events = ARRAY_SIZE(amd_perfmon_event_map),
925};
926
Jaswinder Singh Rajputb56a3802009-02-27 18:09:09 +0530927static struct pmc_x86_ops *pmc_intel_init(void)
Ingo Molnar241771e2008-12-03 10:39:53 +0100928{
929 union cpuid10_eax eax;
Ingo Molnar241771e2008-12-03 10:39:53 +0100930 unsigned int ebx;
Ingo Molnar703e9372008-12-17 10:51:15 +0100931 unsigned int unused;
932 union cpuid10_edx edx;
Ingo Molnar241771e2008-12-03 10:39:53 +0100933
Ingo Molnar241771e2008-12-03 10:39:53 +0100934 /*
935 * Check whether the Architectural PerfMon supports
936 * Branch Misses Retired Event or not.
937 */
Ingo Molnar703e9372008-12-17 10:51:15 +0100938 cpuid(10, &eax.full, &ebx, &unused, &edx.full);
Ingo Molnar241771e2008-12-03 10:39:53 +0100939 if (eax.split.mask_length <= ARCH_PERFMON_BRANCH_MISSES_RETIRED)
Jaswinder Singh Rajputb56a3802009-02-27 18:09:09 +0530940 return NULL;
Ingo Molnar241771e2008-12-03 10:39:53 +0100941
Jaswinder Singh Rajputa1ef58f2009-02-28 18:45:39 +0530942 pr_info("Intel Performance Monitoring support detected.\n");
943 pr_info("... version: %d\n", eax.split.version_id);
944 pr_info("... bit width: %d\n", eax.split.bit_width);
945 pr_info("... mask length: %d\n", eax.split.mask_length);
Jaswinder Singh Rajputb56a3802009-02-27 18:09:09 +0530946
Ingo Molnar862a1a52008-12-17 13:09:20 +0100947 nr_counters_generic = eax.split.num_counters;
Jaswinder Singh Rajputb56a3802009-02-27 18:09:09 +0530948 nr_counters_fixed = edx.split.num_counters_fixed;
949 counter_value_mask = (1ULL << eax.split.bit_width) - 1;
950
951 return &pmc_intel_ops;
952}
953
Jaswinder Singh Rajputf87ad352009-02-27 20:15:14 +0530954static struct pmc_x86_ops *pmc_amd_init(void)
955{
956 nr_counters_generic = 4;
957 nr_counters_fixed = 0;
Peter Zijlstrab5e8acf2009-03-05 20:34:21 +0100958 counter_value_mask = 0x0000FFFFFFFFFFFFULL;
959 counter_value_bits = 48;
Jaswinder Singh Rajputf87ad352009-02-27 20:15:14 +0530960
Jaswinder Singh Rajputa1ef58f2009-02-28 18:45:39 +0530961 pr_info("AMD Performance Monitoring support detected.\n");
Jaswinder Singh Rajputf87ad352009-02-27 20:15:14 +0530962
963 return &pmc_amd_ops;
964}
965
Jaswinder Singh Rajputb56a3802009-02-27 18:09:09 +0530966void __init init_hw_perf_counters(void)
967{
968 if (!cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON))
969 return;
970
971 switch (boot_cpu_data.x86_vendor) {
972 case X86_VENDOR_INTEL:
973 pmc_ops = pmc_intel_init();
974 break;
Jaswinder Singh Rajputf87ad352009-02-27 20:15:14 +0530975 case X86_VENDOR_AMD:
976 pmc_ops = pmc_amd_init();
977 break;
Jaswinder Singh Rajputb56a3802009-02-27 18:09:09 +0530978 }
979 if (!pmc_ops)
980 return;
981
Jaswinder Singh Rajputa1ef58f2009-02-28 18:45:39 +0530982 pr_info("... num counters: %d\n", nr_counters_generic);
Ingo Molnar862a1a52008-12-17 13:09:20 +0100983 if (nr_counters_generic > X86_PMC_MAX_GENERIC) {
984 nr_counters_generic = X86_PMC_MAX_GENERIC;
Ingo Molnar241771e2008-12-03 10:39:53 +0100985 WARN(1, KERN_ERR "hw perf counters %d > max(%d), clipping!",
Ingo Molnar862a1a52008-12-17 13:09:20 +0100986 nr_counters_generic, X86_PMC_MAX_GENERIC);
Ingo Molnar241771e2008-12-03 10:39:53 +0100987 }
Ingo Molnar862a1a52008-12-17 13:09:20 +0100988 perf_counter_mask = (1 << nr_counters_generic) - 1;
989 perf_max_counters = nr_counters_generic;
Ingo Molnar241771e2008-12-03 10:39:53 +0100990
Jaswinder Singh Rajputa1ef58f2009-02-28 18:45:39 +0530991 pr_info("... value mask: %016Lx\n", counter_value_mask);
Ingo Molnar2f18d1e2008-12-22 11:10:42 +0100992
Ingo Molnar862a1a52008-12-17 13:09:20 +0100993 if (nr_counters_fixed > X86_PMC_MAX_FIXED) {
994 nr_counters_fixed = X86_PMC_MAX_FIXED;
Ingo Molnar703e9372008-12-17 10:51:15 +0100995 WARN(1, KERN_ERR "hw perf counters fixed %d > max(%d), clipping!",
Ingo Molnar862a1a52008-12-17 13:09:20 +0100996 nr_counters_fixed, X86_PMC_MAX_FIXED);
Ingo Molnar703e9372008-12-17 10:51:15 +0100997 }
Jaswinder Singh Rajputa1ef58f2009-02-28 18:45:39 +0530998 pr_info("... fixed counters: %d\n", nr_counters_fixed);
Ingo Molnar241771e2008-12-03 10:39:53 +0100999
Ingo Molnar862a1a52008-12-17 13:09:20 +01001000 perf_counter_mask |= ((1LL << nr_counters_fixed)-1) << X86_PMC_IDX_FIXED;
1001
Jaswinder Singh Rajputa1ef58f2009-02-28 18:45:39 +05301002 pr_info("... counter mask: %016Lx\n", perf_counter_mask);
Ingo Molnar75f224c2008-12-14 21:58:46 +01001003 perf_counters_initialized = true;
1004
Ingo Molnar241771e2008-12-03 10:39:53 +01001005 perf_counters_lapic_init(0);
1006 register_die_notifier(&perf_counter_nmi_notifier);
Ingo Molnar241771e2008-12-03 10:39:53 +01001007}
Ingo Molnar621a01e2008-12-11 12:46:46 +01001008
Ingo Molnareb2b8612008-12-17 09:09:13 +01001009static void pmc_generic_read(struct perf_counter *counter)
Ingo Molnaree060942008-12-13 09:00:03 +01001010{
1011 x86_perf_counter_update(counter, &counter->hw, counter->hw.idx);
1012}
1013
Ingo Molnar5c92d122008-12-11 13:21:10 +01001014static const struct hw_perf_counter_ops x86_perf_counter_ops = {
Ingo Molnar76715812008-12-17 14:20:28 +01001015 .enable = pmc_generic_enable,
1016 .disable = pmc_generic_disable,
1017 .read = pmc_generic_read,
Ingo Molnar621a01e2008-12-11 12:46:46 +01001018};
1019
Ingo Molnar5c92d122008-12-11 13:21:10 +01001020const struct hw_perf_counter_ops *
1021hw_perf_counter_init(struct perf_counter *counter)
Ingo Molnar621a01e2008-12-11 12:46:46 +01001022{
1023 int err;
1024
1025 err = __hw_perf_counter_init(counter);
1026 if (err)
1027 return NULL;
1028
1029 return &x86_perf_counter_ops;
1030}