]> git.karo-electronics.de Git - mv-sheeva.git/commitdiff
perfcounters: add fixed-mode PMC enumeration
authorIngo Molnar <mingo@elte.hu>
Wed, 17 Dec 2008 09:51:15 +0000 (10:51 +0100)
committerIngo Molnar <mingo@elte.hu>
Tue, 23 Dec 2008 11:45:11 +0000 (12:45 +0100)
Enumerate fixed-mode PMCs based on CPUID, and feed that into the
perfcounter code.

Does not use fixed-mode PMCs yet.

Signed-off-by: Ingo Molnar <mingo@elte.hu>
arch/x86/include/asm/perf_counter.h
arch/x86/kernel/cpu/perf_counter.c

index dd5a4a559e2dcb6fffb8297dc874a75eda5d5489..945a315e6d62f644174eb0daee36a7744ced947c 100644 (file)
@@ -41,6 +41,29 @@ union cpuid10_eax {
        unsigned int full;
 };
 
+union cpuid10_edx {
+       struct {
+               unsigned int num_counters_fixed:4;
+               unsigned int reserved:28;
+       } split;
+       unsigned int full;
+};
+
+
+/*
+ * Fixed-purpose performance counters:
+ */
+
+/* Instr_Retired.Any: */
+#define MSR_ARCH_PERFMON_FIXED_CTR0                    0x309
+
+/* CPU_CLK_Unhalted.Core: */
+#define MSR_ARCH_PERFMON_FIXED_CTR1                    0x30a
+
+/* CPU_CLK_Unhalted.Ref: */
+#define MSR_ARCH_PERFMON_FIXED_CTR2                    0x30b
+
+
 #ifdef CONFIG_PERF_COUNTERS
 extern void init_hw_perf_counters(void);
 extern void perf_counters_lapic_init(int nmi);
index fc3af868823261bce57e1b424a33d1aead22621d..2fca50c45979d4c82d7bd6756662f1425bb1cd02 100644 (file)
@@ -27,6 +27,8 @@ static bool perf_counters_initialized __read_mostly;
 static int nr_hw_counters __read_mostly;
 static u32 perf_counter_mask __read_mostly;
 
+static int nr_hw_counters_fixed __read_mostly;
+
 struct cpu_hw_counters {
        struct perf_counter     *generic[X86_PMC_MAX_GENERIC];
        unsigned long           used[BITS_TO_LONGS(X86_PMC_MAX_GENERIC)];
@@ -519,8 +521,9 @@ static __read_mostly struct notifier_block perf_counter_nmi_notifier = {
 void __init init_hw_perf_counters(void)
 {
        union cpuid10_eax eax;
-       unsigned int unused;
        unsigned int ebx;
+       unsigned int unused;
+       union cpuid10_edx edx;
 
        if (!cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON))
                return;
@@ -529,14 +532,14 @@ void __init init_hw_perf_counters(void)
         * Check whether the Architectural PerfMon supports
         * Branch Misses Retired Event or not.
         */
-       cpuid(10, &(eax.full), &ebx, &unused, &unused);
+       cpuid(10, &eax.full, &ebx, &unused, &edx.full);
        if (eax.split.mask_length <= ARCH_PERFMON_BRANCH_MISSES_RETIRED)
                return;
 
        printk(KERN_INFO "Intel Performance Monitoring support detected.\n");
 
-       printk(KERN_INFO "... version:      %d\n", eax.split.version_id);
-       printk(KERN_INFO "... num_counters: %d\n", eax.split.num_counters);
+       printk(KERN_INFO "... version:         %d\n", eax.split.version_id);
+       printk(KERN_INFO "... num counters:    %d\n", eax.split.num_counters);
        nr_hw_counters = eax.split.num_counters;
        if (nr_hw_counters > X86_PMC_MAX_GENERIC) {
                nr_hw_counters = X86_PMC_MAX_GENERIC;
@@ -546,8 +549,16 @@ void __init init_hw_perf_counters(void)
        perf_counter_mask = (1 << nr_hw_counters) - 1;
        perf_max_counters = nr_hw_counters;
 
-       printk(KERN_INFO "... bit_width:    %d\n", eax.split.bit_width);
-       printk(KERN_INFO "... mask_length:  %d\n", eax.split.mask_length);
+       printk(KERN_INFO "... bit width:       %d\n", eax.split.bit_width);
+       printk(KERN_INFO "... mask length:     %d\n", eax.split.mask_length);
+
+       nr_hw_counters_fixed = edx.split.num_counters_fixed;
+       if (nr_hw_counters_fixed > X86_PMC_MAX_FIXED) {
+               nr_hw_counters_fixed = X86_PMC_MAX_FIXED;
+               WARN(1, KERN_ERR "hw perf counters fixed %d > max(%d), clipping!",
+                       nr_hw_counters_fixed, X86_PMC_MAX_FIXED);
+       }
+       printk(KERN_INFO "... fixed counters:  %d\n", nr_hw_counters_fixed);
 
        perf_counters_initialized = true;