aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/cpu/perf_counter.c
diff options
context:
space:
mode:
authorJaswinder Singh Rajput <jaswinderrajput@gmail.com>2009-02-27 07:39:09 -0500
committerIngo Molnar <mingo@elte.hu>2009-02-28 04:38:27 -0500
commitb56a3802dc6df29aa27d2c12edf420258091ad66 (patch)
tree0cc92cd879cb24e931565dbe05c0a22207ced750 /arch/x86/kernel/cpu/perf_counter.c
parent0c489c47d45ecac21059567c163f92138b2fbaa2 (diff)
x86: prepare perf_counter to add more cpus
Introduced struct pmc_x86_ops to add more cpus. Signed-off-by: Jaswinder Singh Rajput <jaswinderrajput@gmail.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/kernel/cpu/perf_counter.c')
-rw-r--r--arch/x86/kernel/cpu/perf_counter.c106
1 files changed, 78 insertions, 28 deletions
diff --git a/arch/x86/kernel/cpu/perf_counter.c b/arch/x86/kernel/cpu/perf_counter.c
index 383d4c6423a1..a3c88529bb72 100644
--- a/arch/x86/kernel/cpu/perf_counter.c
+++ b/arch/x86/kernel/cpu/perf_counter.c
@@ -3,6 +3,7 @@
3 * 3 *
4 * Copyright(C) 2008 Thomas Gleixner <tglx@linutronix.de> 4 * Copyright(C) 2008 Thomas Gleixner <tglx@linutronix.de>
5 * Copyright(C) 2008 Red Hat, Inc., Ingo Molnar 5 * Copyright(C) 2008 Red Hat, Inc., Ingo Molnar
6 * Copyright(C) 2009 Jaswinder Singh Rajput
6 * 7 *
7 * For licencing details see kernel-base/COPYING 8 * For licencing details see kernel-base/COPYING
8 */ 9 */
@@ -38,10 +39,24 @@ struct cpu_hw_counters {
38}; 39};
39 40
40/* 41/*
41 * Intel PerfMon v3. Used on Core2 and later. 42 * struct pmc_x86_ops - performance counter x86 ops
42 */ 43 */
44struct pmc_x86_ops {
45 u64 (*save_disable_all) (void);
46 void (*restore_all) (u64 ctrl);
47 unsigned eventsel;
48 unsigned perfctr;
49 int (*event_map) (int event);
50 int max_events;
51};
52
53static struct pmc_x86_ops *pmc_ops;
54
43static DEFINE_PER_CPU(struct cpu_hw_counters, cpu_hw_counters); 55static DEFINE_PER_CPU(struct cpu_hw_counters, cpu_hw_counters);
44 56
57/*
58 * Intel PerfMon v3. Used on Core2 and later.
59 */
45static const int intel_perfmon_event_map[] = 60static const int intel_perfmon_event_map[] =
46{ 61{
47 [PERF_COUNT_CPU_CYCLES] = 0x003c, 62 [PERF_COUNT_CPU_CYCLES] = 0x003c,
@@ -53,7 +68,10 @@ static const int intel_perfmon_event_map[] =
53 [PERF_COUNT_BUS_CYCLES] = 0x013c, 68 [PERF_COUNT_BUS_CYCLES] = 0x013c,
54}; 69};
55 70
56static const int max_intel_perfmon_events = ARRAY_SIZE(intel_perfmon_event_map); 71static int pmc_intel_event_map(int event)
72{
73 return intel_perfmon_event_map[event];
74}
57 75
58/* 76/*
59 * Propagate counter elapsed time into the generic counter. 77 * Propagate counter elapsed time into the generic counter.
@@ -144,38 +162,48 @@ static int __hw_perf_counter_init(struct perf_counter *counter)
144 if (hw_event->raw) { 162 if (hw_event->raw) {
145 hwc->config |= hw_event->type; 163 hwc->config |= hw_event->type;
146 } else { 164 } else {
147 if (hw_event->type >= max_intel_perfmon_events) 165 if (hw_event->type >= pmc_ops->max_events)
148 return -EINVAL; 166 return -EINVAL;
149 /* 167 /*
150 * The generic map: 168 * The generic map:
151 */ 169 */
152 hwc->config |= intel_perfmon_event_map[hw_event->type]; 170 hwc->config |= pmc_ops->event_map(hw_event->type);
153 } 171 }
154 counter->wakeup_pending = 0; 172 counter->wakeup_pending = 0;
155 173
156 return 0; 174 return 0;
157} 175}
158 176
159u64 hw_perf_save_disable(void) 177static u64 pmc_intel_save_disable_all(void)
160{ 178{
161 u64 ctrl; 179 u64 ctrl;
162 180
163 if (unlikely(!perf_counters_initialized))
164 return 0;
165
166 rdmsrl(MSR_CORE_PERF_GLOBAL_CTRL, ctrl); 181 rdmsrl(MSR_CORE_PERF_GLOBAL_CTRL, ctrl);
167 wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, 0); 182 wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, 0);
168 183
169 return ctrl; 184 return ctrl;
170} 185}
186
187u64 hw_perf_save_disable(void)
188{
189 if (unlikely(!perf_counters_initialized))
190 return 0;
191
192 return pmc_ops->save_disable_all();
193}
171EXPORT_SYMBOL_GPL(hw_perf_save_disable); 194EXPORT_SYMBOL_GPL(hw_perf_save_disable);
172 195
196static void pmc_intel_restore_all(u64 ctrl)
197{
198 wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, ctrl);
199}
200
173void hw_perf_restore(u64 ctrl) 201void hw_perf_restore(u64 ctrl)
174{ 202{
175 if (unlikely(!perf_counters_initialized)) 203 if (unlikely(!perf_counters_initialized))
176 return; 204 return;
177 205
178 wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, ctrl); 206 pmc_ops->restore_all(ctrl);
179} 207}
180EXPORT_SYMBOL_GPL(hw_perf_restore); 208EXPORT_SYMBOL_GPL(hw_perf_restore);
181 209
@@ -291,11 +319,11 @@ fixed_mode_idx(struct perf_counter *counter, struct hw_perf_counter *hwc)
291 319
292 event = hwc->config & ARCH_PERFMON_EVENT_MASK; 320 event = hwc->config & ARCH_PERFMON_EVENT_MASK;
293 321
294 if (unlikely(event == intel_perfmon_event_map[PERF_COUNT_INSTRUCTIONS])) 322 if (unlikely(event == pmc_ops->event_map(PERF_COUNT_INSTRUCTIONS)))
295 return X86_PMC_IDX_FIXED_INSTRUCTIONS; 323 return X86_PMC_IDX_FIXED_INSTRUCTIONS;
296 if (unlikely(event == intel_perfmon_event_map[PERF_COUNT_CPU_CYCLES])) 324 if (unlikely(event == pmc_ops->event_map(PERF_COUNT_CPU_CYCLES)))
297 return X86_PMC_IDX_FIXED_CPU_CYCLES; 325 return X86_PMC_IDX_FIXED_CPU_CYCLES;
298 if (unlikely(event == intel_perfmon_event_map[PERF_COUNT_BUS_CYCLES])) 326 if (unlikely(event == pmc_ops->event_map(PERF_COUNT_BUS_CYCLES)))
299 return X86_PMC_IDX_FIXED_BUS_CYCLES; 327 return X86_PMC_IDX_FIXED_BUS_CYCLES;
300 328
301 return -1; 329 return -1;
@@ -339,8 +367,8 @@ try_generic:
339 set_bit(idx, cpuc->used); 367 set_bit(idx, cpuc->used);
340 hwc->idx = idx; 368 hwc->idx = idx;
341 } 369 }
342 hwc->config_base = MSR_ARCH_PERFMON_EVENTSEL0; 370 hwc->config_base = pmc_ops->eventsel;
343 hwc->counter_base = MSR_ARCH_PERFMON_PERFCTR0; 371 hwc->counter_base = pmc_ops->perfctr;
344 } 372 }
345 373
346 perf_counters_lapic_init(hwc->nmi); 374 perf_counters_lapic_init(hwc->nmi);
@@ -386,8 +414,8 @@ void perf_counter_print_debug(void)
386 printk(KERN_INFO "CPU#%d: used: %016llx\n", cpu, *(u64 *)cpuc->used); 414 printk(KERN_INFO "CPU#%d: used: %016llx\n", cpu, *(u64 *)cpuc->used);
387 415
388 for (idx = 0; idx < nr_counters_generic; idx++) { 416 for (idx = 0; idx < nr_counters_generic; idx++) {
389 rdmsrl(MSR_ARCH_PERFMON_EVENTSEL0 + idx, pmc_ctrl); 417 rdmsrl(pmc_ops->eventsel + idx, pmc_ctrl);
390 rdmsrl(MSR_ARCH_PERFMON_PERFCTR0 + idx, pmc_count); 418 rdmsrl(pmc_ops->perfctr + idx, pmc_count);
391 419
392 prev_left = per_cpu(prev_left[idx], cpu); 420 prev_left = per_cpu(prev_left[idx], cpu);
393 421
@@ -655,29 +683,56 @@ static __read_mostly struct notifier_block perf_counter_nmi_notifier = {
655 .priority = 1 683 .priority = 1
656}; 684};
657 685
658void __init init_hw_perf_counters(void) 686static struct pmc_x86_ops pmc_intel_ops = {
687 .save_disable_all = pmc_intel_save_disable_all,
688 .restore_all = pmc_intel_restore_all,
689 .eventsel = MSR_ARCH_PERFMON_EVENTSEL0,
690 .perfctr = MSR_ARCH_PERFMON_PERFCTR0,
691 .event_map = pmc_intel_event_map,
692 .max_events = ARRAY_SIZE(intel_perfmon_event_map),
693};
694
695static struct pmc_x86_ops *pmc_intel_init(void)
659{ 696{
660 union cpuid10_eax eax; 697 union cpuid10_eax eax;
661 unsigned int ebx; 698 unsigned int ebx;
662 unsigned int unused; 699 unsigned int unused;
663 union cpuid10_edx edx; 700 union cpuid10_edx edx;
664 701
665 if (!cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON))
666 return;
667
668 /* 702 /*
669 * Check whether the Architectural PerfMon supports 703 * Check whether the Architectural PerfMon supports
670 * Branch Misses Retired Event or not. 704 * Branch Misses Retired Event or not.
671 */ 705 */
672 cpuid(10, &eax.full, &ebx, &unused, &edx.full); 706 cpuid(10, &eax.full, &ebx, &unused, &edx.full);
673 if (eax.split.mask_length <= ARCH_PERFMON_BRANCH_MISSES_RETIRED) 707 if (eax.split.mask_length <= ARCH_PERFMON_BRANCH_MISSES_RETIRED)
674 return; 708 return NULL;
675 709
676 printk(KERN_INFO "Intel Performance Monitoring support detected.\n"); 710 printk(KERN_INFO "Intel Performance Monitoring support detected.\n");
677
678 printk(KERN_INFO "... version: %d\n", eax.split.version_id); 711 printk(KERN_INFO "... version: %d\n", eax.split.version_id);
679 printk(KERN_INFO "... num counters: %d\n", eax.split.num_counters); 712 printk(KERN_INFO "... bit width: %d\n", eax.split.bit_width);
713 printk(KERN_INFO "... mask length: %d\n", eax.split.mask_length);
714
680 nr_counters_generic = eax.split.num_counters; 715 nr_counters_generic = eax.split.num_counters;
716 nr_counters_fixed = edx.split.num_counters_fixed;
717 counter_value_mask = (1ULL << eax.split.bit_width) - 1;
718
719 return &pmc_intel_ops;
720}
721
722void __init init_hw_perf_counters(void)
723{
724 if (!cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON))
725 return;
726
727 switch (boot_cpu_data.x86_vendor) {
728 case X86_VENDOR_INTEL:
729 pmc_ops = pmc_intel_init();
730 break;
731 }
732 if (!pmc_ops)
733 return;
734
735 printk(KERN_INFO "... num counters: %d\n", nr_counters_generic);
681 if (nr_counters_generic > X86_PMC_MAX_GENERIC) { 736 if (nr_counters_generic > X86_PMC_MAX_GENERIC) {
682 nr_counters_generic = X86_PMC_MAX_GENERIC; 737 nr_counters_generic = X86_PMC_MAX_GENERIC;
683 WARN(1, KERN_ERR "hw perf counters %d > max(%d), clipping!", 738 WARN(1, KERN_ERR "hw perf counters %d > max(%d), clipping!",
@@ -686,13 +741,8 @@ void __init init_hw_perf_counters(void)
686 perf_counter_mask = (1 << nr_counters_generic) - 1; 741 perf_counter_mask = (1 << nr_counters_generic) - 1;
687 perf_max_counters = nr_counters_generic; 742 perf_max_counters = nr_counters_generic;
688 743
689 printk(KERN_INFO "... bit width: %d\n", eax.split.bit_width);
690 counter_value_mask = (1ULL << eax.split.bit_width) - 1;
691 printk(KERN_INFO "... value mask: %016Lx\n", counter_value_mask); 744 printk(KERN_INFO "... value mask: %016Lx\n", counter_value_mask);
692 745
693 printk(KERN_INFO "... mask length: %d\n", eax.split.mask_length);
694
695 nr_counters_fixed = edx.split.num_counters_fixed;
696 if (nr_counters_fixed > X86_PMC_MAX_FIXED) { 746 if (nr_counters_fixed > X86_PMC_MAX_FIXED) {
697 nr_counters_fixed = X86_PMC_MAX_FIXED; 747 nr_counters_fixed = X86_PMC_MAX_FIXED;
698 WARN(1, KERN_ERR "hw perf counters fixed %d > max(%d), clipping!", 748 WARN(1, KERN_ERR "hw perf counters fixed %d > max(%d), clipping!",