* describe the PMU on a particular POWER-family CPU.
*/
struct power_pmu {
+ const char *name;
int n_counter;
int max_alternatives;
unsigned long add_fields;
[PERF_COUNT_HW_CACHE_RESULT_MAX];
};
-extern struct power_pmu *ppmu;
-
/*
* Values for power_pmu.flags
*/
#define PPMU_LIMITED_PMC_REQD 2 /* have to put this on a limited PMC */
#define PPMU_ONLY_COUNT_RUN 4 /* only counting in run state */
+extern int register_power_pmu(struct power_pmu *);
+
struct pt_regs;
extern unsigned long perf_misc_flags(struct pt_regs *regs);
extern unsigned long perf_instruction_pointer(struct pt_regs *regs);
cpuhw->mmcr[0] = MMCR0_FC;
}
-extern struct power_pmu power4_pmu;
-extern struct power_pmu ppc970_pmu;
-extern struct power_pmu power5_pmu;
-extern struct power_pmu power5p_pmu;
-extern struct power_pmu power6_pmu;
-extern struct power_pmu power7_pmu;
-
-static int init_perf_counters(void)
+int register_power_pmu(struct power_pmu *pmu)
{
- unsigned long pvr;
-
- /* XXX should get this from cputable */
- pvr = mfspr(SPRN_PVR);
- switch (PVR_VER(pvr)) {
- case PV_POWER4:
- case PV_POWER4p:
- ppmu = &power4_pmu;
- break;
- case PV_970:
- case PV_970FX:
- case PV_970MP:
- ppmu = &ppc970_pmu;
- break;
- case PV_POWER5:
- ppmu = &power5_pmu;
- break;
- case PV_POWER5p:
- ppmu = &power5p_pmu;
- break;
- case 0x3e:
- ppmu = &power6_pmu;
- break;
- case 0x3f:
- ppmu = &power7_pmu;
- break;
- }
+ if (ppmu)
+ return -EBUSY; /* something's already registered */
+
+ ppmu = pmu;
+ pr_info("%s performance monitor hardware support registered\n",
+ pmu->name);
/*
* Use FCHV to ignore kernel events if MSR.HV is set.
return 0;
}
-
-arch_initcall(init_perf_counters);
*/
#include <linux/kernel.h>
#include <linux/perf_counter.h>
+#include <linux/string.h>
#include <asm/reg.h>
+#include <asm/cputable.h>
/*
* Bits in event code for POWER4
},
};
-struct power_pmu power4_pmu = {
+static struct power_pmu power4_pmu = {
+ .name = "POWER4/4+",
.n_counter = 8,
.max_alternatives = 5,
.add_fields = 0x0000001100005555ul,
.generic_events = p4_generic_events,
.cache_events = &power4_cache_events,
};
+
+static int init_power4_pmu(void)
+{
+ if (strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power4"))
+ return -ENODEV;
+
+ return register_power_pmu(&power4_pmu);
+}
+
+arch_initcall(init_power4_pmu);
*/
#include <linux/kernel.h>
#include <linux/perf_counter.h>
+#include <linux/string.h>
#include <asm/reg.h>
+#include <asm/cputable.h>
/*
* Bits in event code for POWER5+ (POWER5 GS) and POWER5++ (POWER5 GS DD3)
},
};
-struct power_pmu power5p_pmu = {
+static struct power_pmu power5p_pmu = {
+ .name = "POWER5+/++",
.n_counter = 6,
.max_alternatives = MAX_ALT,
.add_fields = 0x7000000000055ul,
.generic_events = power5p_generic_events,
.cache_events = &power5p_cache_events,
};
+
+static int init_power5p_pmu(void)
+{
+ if (strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power5+")
+ && strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power5++"))
+ return -ENODEV;
+
+ return register_power_pmu(&power5p_pmu);
+}
+
+arch_initcall(init_power5p_pmu);
*/
#include <linux/kernel.h>
#include <linux/perf_counter.h>
+#include <linux/string.h>
#include <asm/reg.h>
+#include <asm/cputable.h>
/*
* Bits in event code for POWER5 (not POWER5++)
},
};
-struct power_pmu power5_pmu = {
+static struct power_pmu power5_pmu = {
+ .name = "POWER5",
.n_counter = 6,
.max_alternatives = MAX_ALT,
.add_fields = 0x7000090000555ul,
.generic_events = power5_generic_events,
.cache_events = &power5_cache_events,
};
+
+static int init_power5_pmu(void)
+{
+ if (strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power5"))
+ return -ENODEV;
+
+ return register_power_pmu(&power5_pmu);
+}
+
+arch_initcall(init_power5_pmu);
*/
#include <linux/kernel.h>
#include <linux/perf_counter.h>
+#include <linux/string.h>
#include <asm/reg.h>
+#include <asm/cputable.h>
/*
* Bits in event code for POWER6
},
};
-struct power_pmu power6_pmu = {
+static struct power_pmu power6_pmu = {
+ .name = "POWER6",
.n_counter = 6,
.max_alternatives = MAX_ALT,
.add_fields = 0x1555,
.generic_events = power6_generic_events,
.cache_events = &power6_cache_events,
};
+
+static int init_power6_pmu(void)
+{
+ if (strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power6"))
+ return -ENODEV;
+
+ return register_power_pmu(&power6_pmu);
+}
+
+arch_initcall(init_power6_pmu);
*/
#include <linux/kernel.h>
#include <linux/perf_counter.h>
+#include <linux/string.h>
#include <asm/reg.h>
+#include <asm/cputable.h>
/*
* Bits in event code for POWER7
},
};
-struct power_pmu power7_pmu = {
+static struct power_pmu power7_pmu = {
+ .name = "POWER7",
.n_counter = 6,
.max_alternatives = MAX_ALT + 1,
.add_fields = 0x1555ul,
.generic_events = power7_generic_events,
.cache_events = &power7_cache_events,
};
+
+static int init_power7_pmu(void)
+{
+ if (strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power7"))
+ return -ENODEV;
+
+ return register_power_pmu(&power7_pmu);
+}
+
+arch_initcall(init_power7_pmu);
*/
#include <linux/string.h>
#include <linux/perf_counter.h>
+#include <linux/string.h>
#include <asm/reg.h>
+#include <asm/cputable.h>
/*
* Bits in event code for PPC970
},
};
-struct power_pmu ppc970_pmu = {
+static struct power_pmu ppc970_pmu = {
+ .name = "PPC970/FX/MP",
.n_counter = 8,
.max_alternatives = 2,
.add_fields = 0x001100005555ull,
.generic_events = ppc970_generic_events,
.cache_events = &ppc970_cache_events,
};
+
+static int init_ppc970_pmu(void)
+{
+ if (strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/970")
+ && strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/970MP"))
+ return -ENODEV;
+
+ return register_power_pmu(&ppc970_pmu);
+}
+
+arch_initcall(init_ppc970_pmu);