diff options
author | Paul Mackerras <paulus@samba.org> | 2009-06-17 07:52:09 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-06-18 05:11:45 -0400 |
commit | 079b3c569c87819e7a19d9b9f51d4746fc47bf9a (patch) | |
tree | 63dd236c582eebebb0667a3e5235b02b14c850be /arch/powerpc | |
parent | 448d64f8f4c147db466c549550767cc515a4d34c (diff) |
perf_counter: powerpc: Change how processor-specific back-ends get selected
At present, the powerpc generic (processor-independent) perf_counter
code has list of processor back-end modules, and at initialization,
it looks at the PVR (processor version register) and has a switch
statement to select a suitable processor-specific back-end.
This is going to become inconvenient as we add more processor-specific
back-ends, so this inverts the order: now each back-end checks whether
it applies to the current processor, and registers itself if so.
Furthermore, instead of looking at the PVR, back-ends now check the
cur_cpu_spec->oprofile_cpu_type string and match on that.
Lastly, each back-end now specifies a name for itself so the core can
print a nice message when a back-end registers itself.
This doesn't provide any support for unregistering back-ends, but that
wouldn't be hard to do and would allow back-ends to be modules.
Signed-off-by: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: linuxppc-dev@ozlabs.org
Cc: benh@kernel.crashing.org
LKML-Reference: <19000.55529.762227.518531@cargo.ozlabs.ibm.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/powerpc')
-rw-r--r-- | arch/powerpc/include/asm/perf_counter.h | 5 | ||||
-rw-r--r-- | arch/powerpc/kernel/perf_counter.c | 44 | ||||
-rw-r--r-- | arch/powerpc/kernel/power4-pmu.c | 15 | ||||
-rw-r--r-- | arch/powerpc/kernel/power5+-pmu.c | 16 | ||||
-rw-r--r-- | arch/powerpc/kernel/power5-pmu.c | 15 | ||||
-rw-r--r-- | arch/powerpc/kernel/power6-pmu.c | 15 | ||||
-rw-r--r-- | arch/powerpc/kernel/power7-pmu.c | 15 | ||||
-rw-r--r-- | arch/powerpc/kernel/ppc970-pmu.c | 16 |
8 files changed, 96 insertions, 45 deletions
diff --git a/arch/powerpc/include/asm/perf_counter.h b/arch/powerpc/include/asm/perf_counter.h index 2ceb0fefa93a..8ccd4e155768 100644 --- a/arch/powerpc/include/asm/perf_counter.h +++ b/arch/powerpc/include/asm/perf_counter.h | |||
@@ -21,6 +21,7 @@ | |||
21 | * describe the PMU on a particular POWER-family CPU. | 21 | * describe the PMU on a particular POWER-family CPU. |
22 | */ | 22 | */ |
23 | struct power_pmu { | 23 | struct power_pmu { |
24 | const char *name; | ||
24 | int n_counter; | 25 | int n_counter; |
25 | int max_alternatives; | 26 | int max_alternatives; |
26 | unsigned long add_fields; | 27 | unsigned long add_fields; |
@@ -41,8 +42,6 @@ struct power_pmu { | |||
41 | [PERF_COUNT_HW_CACHE_RESULT_MAX]; | 42 | [PERF_COUNT_HW_CACHE_RESULT_MAX]; |
42 | }; | 43 | }; |
43 | 44 | ||
44 | extern struct power_pmu *ppmu; | ||
45 | |||
46 | /* | 45 | /* |
47 | * Values for power_pmu.flags | 46 | * Values for power_pmu.flags |
48 | */ | 47 | */ |
@@ -56,6 +55,8 @@ extern struct power_pmu *ppmu; | |||
56 | #define PPMU_LIMITED_PMC_REQD 2 /* have to put this on a limited PMC */ | 55 | #define PPMU_LIMITED_PMC_REQD 2 /* have to put this on a limited PMC */ |
57 | #define PPMU_ONLY_COUNT_RUN 4 /* only counting in run state */ | 56 | #define PPMU_ONLY_COUNT_RUN 4 /* only counting in run state */ |
58 | 57 | ||
58 | extern int register_power_pmu(struct power_pmu *); | ||
59 | |||
59 | struct pt_regs; | 60 | struct pt_regs; |
60 | extern unsigned long perf_misc_flags(struct pt_regs *regs); | 61 | extern unsigned long perf_misc_flags(struct pt_regs *regs); |
61 | extern unsigned long perf_instruction_pointer(struct pt_regs *regs); | 62 | extern unsigned long perf_instruction_pointer(struct pt_regs *regs); |
diff --git a/arch/powerpc/kernel/perf_counter.c b/arch/powerpc/kernel/perf_counter.c index 9300638b8c26..25e656c14945 100644 --- a/arch/powerpc/kernel/perf_counter.c +++ b/arch/powerpc/kernel/perf_counter.c | |||
@@ -1214,42 +1214,14 @@ void hw_perf_counter_setup(int cpu) | |||
1214 | cpuhw->mmcr[0] = MMCR0_FC; | 1214 | cpuhw->mmcr[0] = MMCR0_FC; |
1215 | } | 1215 | } |
1216 | 1216 | ||
1217 | extern struct power_pmu power4_pmu; | 1217 | int register_power_pmu(struct power_pmu *pmu) |
1218 | extern struct power_pmu ppc970_pmu; | ||
1219 | extern struct power_pmu power5_pmu; | ||
1220 | extern struct power_pmu power5p_pmu; | ||
1221 | extern struct power_pmu power6_pmu; | ||
1222 | extern struct power_pmu power7_pmu; | ||
1223 | |||
1224 | static int init_perf_counters(void) | ||
1225 | { | 1218 | { |
1226 | unsigned long pvr; | 1219 | if (ppmu) |
1227 | 1220 | return -EBUSY; /* something's already registered */ | |
1228 | /* XXX should get this from cputable */ | 1221 | |
1229 | pvr = mfspr(SPRN_PVR); | 1222 | ppmu = pmu; |
1230 | switch (PVR_VER(pvr)) { | 1223 | pr_info("%s performance monitor hardware support registered\n", |
1231 | case PV_POWER4: | 1224 | pmu->name); |
1232 | case PV_POWER4p: | ||
1233 | ppmu = &power4_pmu; | ||
1234 | break; | ||
1235 | case PV_970: | ||
1236 | case PV_970FX: | ||
1237 | case PV_970MP: | ||
1238 | ppmu = &ppc970_pmu; | ||
1239 | break; | ||
1240 | case PV_POWER5: | ||
1241 | ppmu = &power5_pmu; | ||
1242 | break; | ||
1243 | case PV_POWER5p: | ||
1244 | ppmu = &power5p_pmu; | ||
1245 | break; | ||
1246 | case 0x3e: | ||
1247 | ppmu = &power6_pmu; | ||
1248 | break; | ||
1249 | case 0x3f: | ||
1250 | ppmu = &power7_pmu; | ||
1251 | break; | ||
1252 | } | ||
1253 | 1225 | ||
1254 | /* | 1226 | /* |
1255 | * Use FCHV to ignore kernel events if MSR.HV is set. | 1227 | * Use FCHV to ignore kernel events if MSR.HV is set. |
@@ -1259,5 +1231,3 @@ static int init_perf_counters(void) | |||
1259 | 1231 | ||
1260 | return 0; | 1232 | return 0; |
1261 | } | 1233 | } |
1262 | |||
1263 | arch_initcall(init_perf_counters); | ||
diff --git a/arch/powerpc/kernel/power4-pmu.c b/arch/powerpc/kernel/power4-pmu.c index 81a1708f83b2..db90b0c5c27b 100644 --- a/arch/powerpc/kernel/power4-pmu.c +++ b/arch/powerpc/kernel/power4-pmu.c | |||
@@ -10,7 +10,9 @@ | |||
10 | */ | 10 | */ |
11 | #include <linux/kernel.h> | 11 | #include <linux/kernel.h> |
12 | #include <linux/perf_counter.h> | 12 | #include <linux/perf_counter.h> |
13 | #include <linux/string.h> | ||
13 | #include <asm/reg.h> | 14 | #include <asm/reg.h> |
15 | #include <asm/cputable.h> | ||
14 | 16 | ||
15 | /* | 17 | /* |
16 | * Bits in event code for POWER4 | 18 | * Bits in event code for POWER4 |
@@ -587,7 +589,8 @@ static int power4_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = { | |||
587 | }, | 589 | }, |
588 | }; | 590 | }; |
589 | 591 | ||
590 | struct power_pmu power4_pmu = { | 592 | static struct power_pmu power4_pmu = { |
593 | .name = "POWER4/4+", | ||
591 | .n_counter = 8, | 594 | .n_counter = 8, |
592 | .max_alternatives = 5, | 595 | .max_alternatives = 5, |
593 | .add_fields = 0x0000001100005555ul, | 596 | .add_fields = 0x0000001100005555ul, |
@@ -600,3 +603,13 @@ struct power_pmu power4_pmu = { | |||
600 | .generic_events = p4_generic_events, | 603 | .generic_events = p4_generic_events, |
601 | .cache_events = &power4_cache_events, | 604 | .cache_events = &power4_cache_events, |
602 | }; | 605 | }; |
606 | |||
607 | static int init_power4_pmu(void) | ||
608 | { | ||
609 | if (strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power4")) | ||
610 | return -ENODEV; | ||
611 | |||
612 | return register_power_pmu(&power4_pmu); | ||
613 | } | ||
614 | |||
615 | arch_initcall(init_power4_pmu); | ||
diff --git a/arch/powerpc/kernel/power5+-pmu.c b/arch/powerpc/kernel/power5+-pmu.c index aef144d503b0..f4adca8e98a4 100644 --- a/arch/powerpc/kernel/power5+-pmu.c +++ b/arch/powerpc/kernel/power5+-pmu.c | |||
@@ -10,7 +10,9 @@ | |||
10 | */ | 10 | */ |
11 | #include <linux/kernel.h> | 11 | #include <linux/kernel.h> |
12 | #include <linux/perf_counter.h> | 12 | #include <linux/perf_counter.h> |
13 | #include <linux/string.h> | ||
13 | #include <asm/reg.h> | 14 | #include <asm/reg.h> |
15 | #include <asm/cputable.h> | ||
14 | 16 | ||
15 | /* | 17 | /* |
16 | * Bits in event code for POWER5+ (POWER5 GS) and POWER5++ (POWER5 GS DD3) | 18 | * Bits in event code for POWER5+ (POWER5 GS) and POWER5++ (POWER5 GS DD3) |
@@ -657,7 +659,8 @@ static int power5p_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = { | |||
657 | }, | 659 | }, |
658 | }; | 660 | }; |
659 | 661 | ||
660 | struct power_pmu power5p_pmu = { | 662 | static struct power_pmu power5p_pmu = { |
663 | .name = "POWER5+/++", | ||
661 | .n_counter = 6, | 664 | .n_counter = 6, |
662 | .max_alternatives = MAX_ALT, | 665 | .max_alternatives = MAX_ALT, |
663 | .add_fields = 0x7000000000055ul, | 666 | .add_fields = 0x7000000000055ul, |
@@ -672,3 +675,14 @@ struct power_pmu power5p_pmu = { | |||
672 | .generic_events = power5p_generic_events, | 675 | .generic_events = power5p_generic_events, |
673 | .cache_events = &power5p_cache_events, | 676 | .cache_events = &power5p_cache_events, |
674 | }; | 677 | }; |
678 | |||
679 | static int init_power5p_pmu(void) | ||
680 | { | ||
681 | if (strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power5+") | ||
682 | && strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power5++")) | ||
683 | return -ENODEV; | ||
684 | |||
685 | return register_power_pmu(&power5p_pmu); | ||
686 | } | ||
687 | |||
688 | arch_initcall(init_power5p_pmu); | ||
diff --git a/arch/powerpc/kernel/power5-pmu.c b/arch/powerpc/kernel/power5-pmu.c index 8694c73bfb52..29b2c6c0e83a 100644 --- a/arch/powerpc/kernel/power5-pmu.c +++ b/arch/powerpc/kernel/power5-pmu.c | |||
@@ -10,7 +10,9 @@ | |||
10 | */ | 10 | */ |
11 | #include <linux/kernel.h> | 11 | #include <linux/kernel.h> |
12 | #include <linux/perf_counter.h> | 12 | #include <linux/perf_counter.h> |
13 | #include <linux/string.h> | ||
13 | #include <asm/reg.h> | 14 | #include <asm/reg.h> |
15 | #include <asm/cputable.h> | ||
14 | 16 | ||
15 | /* | 17 | /* |
16 | * Bits in event code for POWER5 (not POWER5++) | 18 | * Bits in event code for POWER5 (not POWER5++) |
@@ -599,7 +601,8 @@ static int power5_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = { | |||
599 | }, | 601 | }, |
600 | }; | 602 | }; |
601 | 603 | ||
602 | struct power_pmu power5_pmu = { | 604 | static struct power_pmu power5_pmu = { |
605 | .name = "POWER5", | ||
603 | .n_counter = 6, | 606 | .n_counter = 6, |
604 | .max_alternatives = MAX_ALT, | 607 | .max_alternatives = MAX_ALT, |
605 | .add_fields = 0x7000090000555ul, | 608 | .add_fields = 0x7000090000555ul, |
@@ -612,3 +615,13 @@ struct power_pmu power5_pmu = { | |||
612 | .generic_events = power5_generic_events, | 615 | .generic_events = power5_generic_events, |
613 | .cache_events = &power5_cache_events, | 616 | .cache_events = &power5_cache_events, |
614 | }; | 617 | }; |
618 | |||
619 | static int init_power5_pmu(void) | ||
620 | { | ||
621 | if (strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power5")) | ||
622 | return -ENODEV; | ||
623 | |||
624 | return register_power_pmu(&power5_pmu); | ||
625 | } | ||
626 | |||
627 | arch_initcall(init_power5_pmu); | ||
diff --git a/arch/powerpc/kernel/power6-pmu.c b/arch/powerpc/kernel/power6-pmu.c index 8898622ac28c..09ae5bf5bda7 100644 --- a/arch/powerpc/kernel/power6-pmu.c +++ b/arch/powerpc/kernel/power6-pmu.c | |||
@@ -10,7 +10,9 @@ | |||
10 | */ | 10 | */ |
11 | #include <linux/kernel.h> | 11 | #include <linux/kernel.h> |
12 | #include <linux/perf_counter.h> | 12 | #include <linux/perf_counter.h> |
13 | #include <linux/string.h> | ||
13 | #include <asm/reg.h> | 14 | #include <asm/reg.h> |
15 | #include <asm/cputable.h> | ||
14 | 16 | ||
15 | /* | 17 | /* |
16 | * Bits in event code for POWER6 | 18 | * Bits in event code for POWER6 |
@@ -516,7 +518,8 @@ static int power6_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = { | |||
516 | }, | 518 | }, |
517 | }; | 519 | }; |
518 | 520 | ||
519 | struct power_pmu power6_pmu = { | 521 | static struct power_pmu power6_pmu = { |
522 | .name = "POWER6", | ||
520 | .n_counter = 6, | 523 | .n_counter = 6, |
521 | .max_alternatives = MAX_ALT, | 524 | .max_alternatives = MAX_ALT, |
522 | .add_fields = 0x1555, | 525 | .add_fields = 0x1555, |
@@ -531,3 +534,13 @@ struct power_pmu power6_pmu = { | |||
531 | .generic_events = power6_generic_events, | 534 | .generic_events = power6_generic_events, |
532 | .cache_events = &power6_cache_events, | 535 | .cache_events = &power6_cache_events, |
533 | }; | 536 | }; |
537 | |||
538 | static int init_power6_pmu(void) | ||
539 | { | ||
540 | if (strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power6")) | ||
541 | return -ENODEV; | ||
542 | |||
543 | return register_power_pmu(&power6_pmu); | ||
544 | } | ||
545 | |||
546 | arch_initcall(init_power6_pmu); | ||
diff --git a/arch/powerpc/kernel/power7-pmu.c b/arch/powerpc/kernel/power7-pmu.c index 658d1ae436a0..5d755ef7ac8f 100644 --- a/arch/powerpc/kernel/power7-pmu.c +++ b/arch/powerpc/kernel/power7-pmu.c | |||
@@ -10,7 +10,9 @@ | |||
10 | */ | 10 | */ |
11 | #include <linux/kernel.h> | 11 | #include <linux/kernel.h> |
12 | #include <linux/perf_counter.h> | 12 | #include <linux/perf_counter.h> |
13 | #include <linux/string.h> | ||
13 | #include <asm/reg.h> | 14 | #include <asm/reg.h> |
15 | #include <asm/cputable.h> | ||
14 | 16 | ||
15 | /* | 17 | /* |
16 | * Bits in event code for POWER7 | 18 | * Bits in event code for POWER7 |
@@ -346,7 +348,8 @@ static int power7_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = { | |||
346 | }, | 348 | }, |
347 | }; | 349 | }; |
348 | 350 | ||
349 | struct power_pmu power7_pmu = { | 351 | static struct power_pmu power7_pmu = { |
352 | .name = "POWER7", | ||
350 | .n_counter = 6, | 353 | .n_counter = 6, |
351 | .max_alternatives = MAX_ALT + 1, | 354 | .max_alternatives = MAX_ALT + 1, |
352 | .add_fields = 0x1555ul, | 355 | .add_fields = 0x1555ul, |
@@ -359,3 +362,13 @@ struct power_pmu power7_pmu = { | |||
359 | .generic_events = power7_generic_events, | 362 | .generic_events = power7_generic_events, |
360 | .cache_events = &power7_cache_events, | 363 | .cache_events = &power7_cache_events, |
361 | }; | 364 | }; |
365 | |||
366 | static int init_power7_pmu(void) | ||
367 | { | ||
368 | if (strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power7")) | ||
369 | return -ENODEV; | ||
370 | |||
371 | return register_power_pmu(&power7_pmu); | ||
372 | } | ||
373 | |||
374 | arch_initcall(init_power7_pmu); | ||
diff --git a/arch/powerpc/kernel/ppc970-pmu.c b/arch/powerpc/kernel/ppc970-pmu.c index 3ed88333412f..6637c87fe70e 100644 --- a/arch/powerpc/kernel/ppc970-pmu.c +++ b/arch/powerpc/kernel/ppc970-pmu.c | |||
@@ -10,7 +10,9 @@ | |||
10 | */ | 10 | */ |
11 | #include <linux/string.h> | 11 | #include <linux/string.h> |
12 | #include <linux/perf_counter.h> | 12 | #include <linux/perf_counter.h> |
13 | #include <linux/string.h> | ||
13 | #include <asm/reg.h> | 14 | #include <asm/reg.h> |
15 | #include <asm/cputable.h> | ||
14 | 16 | ||
15 | /* | 17 | /* |
16 | * Bits in event code for PPC970 | 18 | * Bits in event code for PPC970 |
@@ -470,7 +472,8 @@ static int ppc970_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = { | |||
470 | }, | 472 | }, |
471 | }; | 473 | }; |
472 | 474 | ||
473 | struct power_pmu ppc970_pmu = { | 475 | static struct power_pmu ppc970_pmu = { |
476 | .name = "PPC970/FX/MP", | ||
474 | .n_counter = 8, | 477 | .n_counter = 8, |
475 | .max_alternatives = 2, | 478 | .max_alternatives = 2, |
476 | .add_fields = 0x001100005555ull, | 479 | .add_fields = 0x001100005555ull, |
@@ -483,3 +486,14 @@ struct power_pmu ppc970_pmu = { | |||
483 | .generic_events = ppc970_generic_events, | 486 | .generic_events = ppc970_generic_events, |
484 | .cache_events = &ppc970_cache_events, | 487 | .cache_events = &ppc970_cache_events, |
485 | }; | 488 | }; |
489 | |||
490 | static int init_ppc970_pmu(void) | ||
491 | { | ||
492 | if (strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/970") | ||
493 | && strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/970MP")) | ||
494 | return -ENODEV; | ||
495 | |||
496 | return register_power_pmu(&ppc970_pmu); | ||
497 | } | ||
498 | |||
499 | arch_initcall(init_ppc970_pmu); | ||