aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2007-10-04 00:18:01 -0400
committerPaul Mackerras <paulus@samba.org>2007-10-11 07:37:50 -0400
commit87a72f9e171e558a0288aa83ef1dc6ae4af32224 (patch)
tree7b5102ebef8b8405d83a141163f08d1a0a2c9e46
parent64f2758514e3bad19cab03d22851ab37654399a4 (diff)
[POWERPC] Fix performance monitor on machines with logical PVR
Some IBM machines supply a "logical" PVR (processor version register) value in the device tree in the cpu nodes rather than the real PVR. This is used for instance to indicate that the processors in a POWER6 partition have been configured by the hypervisor to run in POWER5+ mode rather than POWER6 mode. To cope with this, we call identify_cpu a second time with the logical PVR value (the first call is with the real PVR value in the very early setup code). However, POWER5+ machines can also supply a logical PVR value, and use the same value (the value that indicates a v2.04 architecture compliant processor). This causes problems for code that uses the performance monitor (such as oprofile), because the PMU registers are different in POWER6 (even in POWER5+ mode) from the real POWER5+. This change works around this problem by taking out the PMU information from the cputable entries for the logical PVR values, and changing identify_cpu so that the second call to it won't overwrite the PMU information that was established by the first call (the one with the real PVR), but does update the other fields. Specifically, if the cputable entry for the logical PVR value has num_pmcs == 0, none of the PMU-related fields get used. So that we can create a mixed cputable entry, we now make cur_cpu_spec point to a single static struct cpu_spec, and copy stuff from cpu_specs[i] into it. This has the side-effect that we can now make cpu_specs[] be initdata. Ultimately it would be good to move the PMU-related fields out to a separate structure, pointed to by the cputable entries, and change identify_cpu so that it saves the PMU info pointer, copies the whole structure, and restores the PMU info pointer, rather than identify_cpu having to list all the fields that are *not* PMU-related. Signed-off-by: Paul Mackerras <paulus@samba.org> Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
-rw-r--r--arch/powerpc/kernel/cputable.c45
-rw-r--r--include/asm-powerpc/cputable.h1
2 files changed, 25 insertions, 21 deletions
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c
index b03a442b7888..8662cf053fa0 100644
--- a/arch/powerpc/kernel/cputable.c
+++ b/arch/powerpc/kernel/cputable.c
@@ -71,7 +71,7 @@ extern void __restore_cpu_ppc970(void);
71#define COMMON_USER_BOOKE (PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | \ 71#define COMMON_USER_BOOKE (PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | \
72 PPC_FEATURE_BOOKE) 72 PPC_FEATURE_BOOKE)
73 73
74static struct cpu_spec cpu_specs[] = { 74static struct cpu_spec __initdata cpu_specs[] = {
75#ifdef CONFIG_PPC64 75#ifdef CONFIG_PPC64
76 { /* Power3 */ 76 { /* Power3 */
77 .pvr_mask = 0xffff0000, 77 .pvr_mask = 0xffff0000,
@@ -327,14 +327,6 @@ static struct cpu_spec cpu_specs[] = {
327 .cpu_user_features = COMMON_USER_POWER5_PLUS, 327 .cpu_user_features = COMMON_USER_POWER5_PLUS,
328 .icache_bsize = 128, 328 .icache_bsize = 128,
329 .dcache_bsize = 128, 329 .dcache_bsize = 128,
330 .num_pmcs = 6,
331 .pmc_type = PPC_PMC_IBM,
332 .oprofile_cpu_type = "ppc64/power6",
333 .oprofile_type = PPC_OPROFILE_POWER4,
334 .oprofile_mmcra_sihv = POWER6_MMCRA_SIHV,
335 .oprofile_mmcra_sipr = POWER6_MMCRA_SIPR,
336 .oprofile_mmcra_clear = POWER6_MMCRA_THRM |
337 POWER6_MMCRA_OTHER,
338 .platform = "power5+", 330 .platform = "power5+",
339 }, 331 },
340 { /* Power6 */ 332 { /* Power6 */
@@ -364,14 +356,6 @@ static struct cpu_spec cpu_specs[] = {
364 .cpu_user_features = COMMON_USER_POWER6, 356 .cpu_user_features = COMMON_USER_POWER6,
365 .icache_bsize = 128, 357 .icache_bsize = 128,
366 .dcache_bsize = 128, 358 .dcache_bsize = 128,
367 .num_pmcs = 6,
368 .pmc_type = PPC_PMC_IBM,
369 .oprofile_cpu_type = "ppc64/power6",
370 .oprofile_type = PPC_OPROFILE_POWER4,
371 .oprofile_mmcra_sihv = POWER6_MMCRA_SIHV,
372 .oprofile_mmcra_sipr = POWER6_MMCRA_SIPR,
373 .oprofile_mmcra_clear = POWER6_MMCRA_THRM |
374 POWER6_MMCRA_OTHER,
375 .platform = "power6", 359 .platform = "power6",
376 }, 360 },
377 { /* Cell Broadband Engine */ 361 { /* Cell Broadband Engine */
@@ -1316,18 +1300,37 @@ static struct cpu_spec cpu_specs[] = {
1316#endif /* CONFIG_PPC32 */ 1300#endif /* CONFIG_PPC32 */
1317}; 1301};
1318 1302
1319struct cpu_spec *identify_cpu(unsigned long offset, unsigned int pvr) 1303static struct cpu_spec the_cpu_spec;
1304
1305struct cpu_spec * __init identify_cpu(unsigned long offset, unsigned int pvr)
1320{ 1306{
1321 struct cpu_spec *s = cpu_specs; 1307 struct cpu_spec *s = cpu_specs;
1322 struct cpu_spec **cur = &cur_cpu_spec; 1308 struct cpu_spec *t = &the_cpu_spec;
1323 int i; 1309 int i;
1324 1310
1325 s = PTRRELOC(s); 1311 s = PTRRELOC(s);
1326 cur = PTRRELOC(cur); 1312 t = PTRRELOC(t);
1327 1313
1328 for (i = 0; i < ARRAY_SIZE(cpu_specs); i++,s++) 1314 for (i = 0; i < ARRAY_SIZE(cpu_specs); i++,s++)
1329 if ((pvr & s->pvr_mask) == s->pvr_value) { 1315 if ((pvr & s->pvr_mask) == s->pvr_value) {
1330 *cur = cpu_specs + i; 1316 /*
1317 * If we are overriding a previous value derived
1318 * from the real PVR with a new value obtained
1319 * using a logical PVR value, don't modify the
1320 * performance monitor fields.
1321 */
1322 if (t->num_pmcs && !s->num_pmcs) {
1323 t->cpu_name = s->cpu_name;
1324 t->cpu_features = s->cpu_features;
1325 t->cpu_user_features = s->cpu_user_features;
1326 t->icache_bsize = s->icache_bsize;
1327 t->dcache_bsize = s->dcache_bsize;
1328 t->cpu_setup = s->cpu_setup;
1329 t->cpu_restore = s->cpu_restore;
1330 t->platform = s->platform;
1331 } else
1332 *t = *s;
1333 *PTRRELOC(&cur_cpu_spec) = &the_cpu_spec;
1331#if defined(CONFIG_PPC64) || defined(CONFIG_BOOKE) 1334#if defined(CONFIG_PPC64) || defined(CONFIG_BOOKE)
1332 /* ppc64 and booke expect identify_cpu to also call 1335 /* ppc64 and booke expect identify_cpu to also call
1333 * setup_cpu for that processor. I will consolidate 1336 * setup_cpu for that processor. I will consolidate
diff --git a/include/asm-powerpc/cputable.h b/include/asm-powerpc/cputable.h
index c9b8f64bbb45..d913f460e710 100644
--- a/include/asm-powerpc/cputable.h
+++ b/include/asm-powerpc/cputable.h
@@ -57,6 +57,7 @@ enum powerpc_pmc_type {
57 PPC_PMC_PA6T = 2, 57 PPC_PMC_PA6T = 2,
58}; 58};
59 59
60/* NOTE WELL: Update identify_cpu() if fields are added or removed! */
60struct cpu_spec { 61struct cpu_spec {
61 /* CPU is matched via (PVR & pvr_mask) == pvr_value */ 62 /* CPU is matched via (PVR & pvr_mask) == pvr_value */
62 unsigned int pvr_mask; 63 unsigned int pvr_mask;