aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/kernel/cpu/amd.c4
-rw-r--r--arch/x86/kernel/cpu/perf_counter.c83
2 files changed, 85 insertions, 2 deletions
diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c
index 25423a5b80ed..edcde52bd170 100644
--- a/arch/x86/kernel/cpu/amd.c
+++ b/arch/x86/kernel/cpu/amd.c
@@ -368,6 +368,10 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)
368 if (c->x86 >= 6) 368 if (c->x86 >= 6)
369 set_cpu_cap(c, X86_FEATURE_FXSAVE_LEAK); 369 set_cpu_cap(c, X86_FEATURE_FXSAVE_LEAK);
370 370
371 /* Enable Performance counter for K7 and later */
372 if (c->x86 > 6 && c->x86 <= 0x11)
373 set_cpu_cap(c, X86_FEATURE_ARCH_PERFMON);
374
371 if (!c->x86_model_id[0]) { 375 if (!c->x86_model_id[0]) {
372 switch (c->x86) { 376 switch (c->x86) {
373 case 0xf: 377 case 0xf:
diff --git a/arch/x86/kernel/cpu/perf_counter.c b/arch/x86/kernel/cpu/perf_counter.c
index a3c88529bb72..266618aa1a03 100644
--- a/arch/x86/kernel/cpu/perf_counter.c
+++ b/arch/x86/kernel/cpu/perf_counter.c
@@ -74,6 +74,24 @@ static int pmc_intel_event_map(int event)
74} 74}
75 75
76/* 76/*
77 * AMD Performance Monitor K7 and later.
78 */
79static const int amd_perfmon_event_map[] =
80{
81 [PERF_COUNT_CPU_CYCLES] = 0x0076,
82 [PERF_COUNT_INSTRUCTIONS] = 0x00c0,
83 [PERF_COUNT_CACHE_REFERENCES] = 0x0080,
84 [PERF_COUNT_CACHE_MISSES] = 0x0081,
85 [PERF_COUNT_BRANCH_INSTRUCTIONS] = 0x00c4,
86 [PERF_COUNT_BRANCH_MISSES] = 0x00c5,
87};
88
89static int pmc_amd_event_map(int event)
90{
91 return amd_perfmon_event_map[event];
92}
93
94/*
77 * Propagate counter elapsed time into the generic counter. 95 * Propagate counter elapsed time into the generic counter.
78 * Can only be executed on the CPU where the counter is active. 96 * Can only be executed on the CPU where the counter is active.
79 * Returns the delta events processed. 97 * Returns the delta events processed.
@@ -151,8 +169,9 @@ static int __hw_perf_counter_init(struct perf_counter *counter)
151 * so we install an artificial 1<<31 period regardless of 169 * so we install an artificial 1<<31 period regardless of
152 * the generic counter period: 170 * the generic counter period:
153 */ 171 */
154 if ((s64)hwc->irq_period <= 0 || hwc->irq_period > 0x7FFFFFFF) 172 if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL)
155 hwc->irq_period = 0x7FFFFFFF; 173 if ((s64)hwc->irq_period <= 0 || hwc->irq_period > 0x7FFFFFFF)
174 hwc->irq_period = 0x7FFFFFFF;
156 175
157 atomic64_set(&hwc->period_left, hwc->irq_period); 176 atomic64_set(&hwc->period_left, hwc->irq_period);
158 177
@@ -184,6 +203,22 @@ static u64 pmc_intel_save_disable_all(void)
184 return ctrl; 203 return ctrl;
185} 204}
186 205
206static u64 pmc_amd_save_disable_all(void)
207{
208 int idx;
209 u64 val, ctrl = 0;
210
211 for (idx = 0; idx < nr_counters_generic; idx++) {
212 rdmsrl(MSR_K7_EVNTSEL0 + idx, val);
213 if (val & ARCH_PERFMON_EVENTSEL0_ENABLE)
214 ctrl |= (1 << idx);
215 val &= ~ARCH_PERFMON_EVENTSEL0_ENABLE;
216 wrmsrl(MSR_K7_EVNTSEL0 + idx, val);
217 }
218
219 return ctrl;
220}
221
187u64 hw_perf_save_disable(void) 222u64 hw_perf_save_disable(void)
188{ 223{
189 if (unlikely(!perf_counters_initialized)) 224 if (unlikely(!perf_counters_initialized))
@@ -198,6 +233,20 @@ static void pmc_intel_restore_all(u64 ctrl)
198 wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, ctrl); 233 wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, ctrl);
199} 234}
200 235
236static void pmc_amd_restore_all(u64 ctrl)
237{
238 u64 val;
239 int idx;
240
241 for (idx = 0; idx < nr_counters_generic; idx++) {
242 if (ctrl & (1 << idx)) {
243 rdmsrl(MSR_K7_EVNTSEL0 + idx, val);
244 val |= ARCH_PERFMON_EVENTSEL0_ENABLE;
245 wrmsrl(MSR_K7_EVNTSEL0 + idx, val);
246 }
247 }
248}
249
201void hw_perf_restore(u64 ctrl) 250void hw_perf_restore(u64 ctrl)
202{ 251{
203 if (unlikely(!perf_counters_initialized)) 252 if (unlikely(!perf_counters_initialized))
@@ -314,6 +363,9 @@ fixed_mode_idx(struct perf_counter *counter, struct hw_perf_counter *hwc)
314{ 363{
315 unsigned int event; 364 unsigned int event;
316 365
366 if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
367 return -1;
368
317 if (unlikely(hwc->nmi)) 369 if (unlikely(hwc->nmi))
318 return -1; 370 return -1;
319 371
@@ -401,6 +453,7 @@ void perf_counter_print_debug(void)
401 cpu = smp_processor_id(); 453 cpu = smp_processor_id();
402 cpuc = &per_cpu(cpu_hw_counters, cpu); 454 cpuc = &per_cpu(cpu_hw_counters, cpu);
403 455
456 if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) {
404 rdmsrl(MSR_CORE_PERF_GLOBAL_CTRL, ctrl); 457 rdmsrl(MSR_CORE_PERF_GLOBAL_CTRL, ctrl);
405 rdmsrl(MSR_CORE_PERF_GLOBAL_STATUS, status); 458 rdmsrl(MSR_CORE_PERF_GLOBAL_STATUS, status);
406 rdmsrl(MSR_CORE_PERF_GLOBAL_OVF_CTRL, overflow); 459 rdmsrl(MSR_CORE_PERF_GLOBAL_OVF_CTRL, overflow);
@@ -411,6 +464,7 @@ void perf_counter_print_debug(void)
411 printk(KERN_INFO "CPU#%d: status: %016llx\n", cpu, status); 464 printk(KERN_INFO "CPU#%d: status: %016llx\n", cpu, status);
412 printk(KERN_INFO "CPU#%d: overflow: %016llx\n", cpu, overflow); 465 printk(KERN_INFO "CPU#%d: overflow: %016llx\n", cpu, overflow);
413 printk(KERN_INFO "CPU#%d: fixed: %016llx\n", cpu, fixed); 466 printk(KERN_INFO "CPU#%d: fixed: %016llx\n", cpu, fixed);
467 }
414 printk(KERN_INFO "CPU#%d: used: %016llx\n", cpu, *(u64 *)cpuc->used); 468 printk(KERN_INFO "CPU#%d: used: %016llx\n", cpu, *(u64 *)cpuc->used);
415 469
416 for (idx = 0; idx < nr_counters_generic; idx++) { 470 for (idx = 0; idx < nr_counters_generic; idx++) {
@@ -588,6 +642,9 @@ void perf_counter_unthrottle(void)
588 if (!cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON)) 642 if (!cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON))
589 return; 643 return;
590 644
645 if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
646 return;
647
591 if (unlikely(!perf_counters_initialized)) 648 if (unlikely(!perf_counters_initialized))
592 return; 649 return;
593 650
@@ -692,6 +749,15 @@ static struct pmc_x86_ops pmc_intel_ops = {
692 .max_events = ARRAY_SIZE(intel_perfmon_event_map), 749 .max_events = ARRAY_SIZE(intel_perfmon_event_map),
693}; 750};
694 751
752static struct pmc_x86_ops pmc_amd_ops = {
753 .save_disable_all = pmc_amd_save_disable_all,
754 .restore_all = pmc_amd_restore_all,
755 .eventsel = MSR_K7_EVNTSEL0,
756 .perfctr = MSR_K7_PERFCTR0,
757 .event_map = pmc_amd_event_map,
758 .max_events = ARRAY_SIZE(amd_perfmon_event_map),
759};
760
695static struct pmc_x86_ops *pmc_intel_init(void) 761static struct pmc_x86_ops *pmc_intel_init(void)
696{ 762{
697 union cpuid10_eax eax; 763 union cpuid10_eax eax;
@@ -719,6 +785,16 @@ static struct pmc_x86_ops *pmc_intel_init(void)
719 return &pmc_intel_ops; 785 return &pmc_intel_ops;
720} 786}
721 787
788static struct pmc_x86_ops *pmc_amd_init(void)
789{
790 nr_counters_generic = 4;
791 nr_counters_fixed = 0;
792
793 printk(KERN_INFO "AMD Performance Monitoring support detected.\n");
794
795 return &pmc_amd_ops;
796}
797
722void __init init_hw_perf_counters(void) 798void __init init_hw_perf_counters(void)
723{ 799{
724 if (!cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON)) 800 if (!cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON))
@@ -728,6 +804,9 @@ void __init init_hw_perf_counters(void)
728 case X86_VENDOR_INTEL: 804 case X86_VENDOR_INTEL:
729 pmc_ops = pmc_intel_init(); 805 pmc_ops = pmc_intel_init();
730 break; 806 break;
807 case X86_VENDOR_AMD:
808 pmc_ops = pmc_amd_init();
809 break;
731 } 810 }
732 if (!pmc_ops) 811 if (!pmc_ops)
733 return; 812 return;