aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2006-11-10 04:38:53 -0500
committerPaul Mackerras <paulus@samba.org>2006-12-04 04:40:16 -0500
commit974a76f51355d22f4f63d83d6bb1ccecd019ec58 (patch)
tree9a6c5745d8e1f592427d96fbf64d8546af4feb39 /arch/powerpc/kernel
parent18f2190d796198fbb5d4bc4c87511acf3ced7d47 (diff)
[POWERPC] Distinguish POWER6 partition modes and tell userspace
This adds code to look at the properties firmware puts in the device tree to determine what compatibility mode the partition is in on POWER6 machines, and set the ELF aux vector AT_HWCAP and AT_PLATFORM entries appropriately. Specifically, we look at the cpu-version property in the cpu node(s). If that contains a "logical" PVR value (of the form 0x0f00000x), we call identify_cpu again with this PVR value. A value of 0x0f000001 indicates the partition is in POWER5+ compatibility mode, and a value of 0x0f000002 indicates "POWER6 architected" mode, with various extensions disabled. We also look for various other properties: ibm,dfp, ibm,purr and ibm,spurr. Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/kernel')
-rw-r--r--arch/powerpc/kernel/cputable.c43
-rw-r--r--arch/powerpc/kernel/prom.c110
-rw-r--r--arch/powerpc/kernel/prom_init.c3
-rw-r--r--arch/powerpc/kernel/setup_32.c2
-rw-r--r--arch/powerpc/kernel/setup_64.c2
5 files changed, 117 insertions, 43 deletions
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c
index 992121b2d261..911ac442f44a 100644
--- a/arch/powerpc/kernel/cputable.c
+++ b/arch/powerpc/kernel/cputable.c
@@ -277,10 +277,45 @@ static struct cpu_spec cpu_specs[] = {
277 .oprofile_mmcra_sipr = MMCRA_SIPR, 277 .oprofile_mmcra_sipr = MMCRA_SIPR,
278 .platform = "power5+", 278 .platform = "power5+",
279 }, 279 },
280 { /* POWER6 in P5+ mode; 2.04-compliant processor */
281 .pvr_mask = 0xffffffff,
282 .pvr_value = 0x0f000001,
283 .cpu_name = "POWER5+",
284 .cpu_features = CPU_FTRS_POWER5,
285 .cpu_user_features = COMMON_USER_POWER5_PLUS,
286 .icache_bsize = 128,
287 .dcache_bsize = 128,
288 .num_pmcs = 6,
289 .oprofile_cpu_type = "ppc64/power6",
290 .oprofile_type = PPC_OPROFILE_POWER4,
291 .oprofile_mmcra_sihv = POWER6_MMCRA_SIHV,
292 .oprofile_mmcra_sipr = POWER6_MMCRA_SIPR,
293 .oprofile_mmcra_clear = POWER6_MMCRA_THRM |
294 POWER6_MMCRA_OTHER,
295 .platform = "power5+",
296 },
280 { /* Power6 */ 297 { /* Power6 */
281 .pvr_mask = 0xffff0000, 298 .pvr_mask = 0xffff0000,
282 .pvr_value = 0x003e0000, 299 .pvr_value = 0x003e0000,
283 .cpu_name = "POWER6", 300 .cpu_name = "POWER6 (raw)",
301 .cpu_features = CPU_FTRS_POWER6,
302 .cpu_user_features = COMMON_USER_POWER6 |
303 PPC_FEATURE_POWER6_EXT,
304 .icache_bsize = 128,
305 .dcache_bsize = 128,
306 .num_pmcs = 6,
307 .oprofile_cpu_type = "ppc64/power6",
308 .oprofile_type = PPC_OPROFILE_POWER4,
309 .oprofile_mmcra_sihv = POWER6_MMCRA_SIHV,
310 .oprofile_mmcra_sipr = POWER6_MMCRA_SIPR,
311 .oprofile_mmcra_clear = POWER6_MMCRA_THRM |
312 POWER6_MMCRA_OTHER,
313 .platform = "power6x",
314 },
315 { /* 2.05-compliant processor, i.e. Power6 "architected" mode */
316 .pvr_mask = 0xffffffff,
317 .pvr_value = 0x0f000002,
318 .cpu_name = "POWER6 (architected)",
284 .cpu_features = CPU_FTRS_POWER6, 319 .cpu_features = CPU_FTRS_POWER6,
285 .cpu_user_features = COMMON_USER_POWER6, 320 .cpu_user_features = COMMON_USER_POWER6,
286 .icache_bsize = 128, 321 .icache_bsize = 128,
@@ -1173,19 +1208,15 @@ static struct cpu_spec cpu_specs[] = {
1173#endif /* CONFIG_PPC32 */ 1208#endif /* CONFIG_PPC32 */
1174}; 1209};
1175 1210
1176struct cpu_spec *identify_cpu(unsigned long offset) 1211struct cpu_spec *identify_cpu(unsigned long offset, unsigned int pvr)
1177{ 1212{
1178 struct cpu_spec *s = cpu_specs; 1213 struct cpu_spec *s = cpu_specs;
1179 struct cpu_spec **cur = &cur_cpu_spec; 1214 struct cpu_spec **cur = &cur_cpu_spec;
1180 unsigned int pvr = mfspr(SPRN_PVR);
1181 int i; 1215 int i;
1182 1216
1183 s = PTRRELOC(s); 1217 s = PTRRELOC(s);
1184 cur = PTRRELOC(cur); 1218 cur = PTRRELOC(cur);
1185 1219
1186 if (*cur != NULL)
1187 return PTRRELOC(*cur);
1188
1189 for (i = 0; i < ARRAY_SIZE(cpu_specs); i++,s++) 1220 for (i = 0; i < ARRAY_SIZE(cpu_specs); i++,s++)
1190 if ((pvr & s->pvr_mask) == s->pvr_value) { 1221 if ((pvr & s->pvr_mask) == s->pvr_value) {
1191 *cur = cpu_specs + i; 1222 *cur = cpu_specs + i;
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
index 16d29d16b96f..c18dbe77fdc2 100644
--- a/arch/powerpc/kernel/prom.c
+++ b/arch/powerpc/kernel/prom.c
@@ -538,35 +538,31 @@ static struct ibm_pa_feature {
538 {CPU_FTR_REAL_LE, PPC_FEATURE_TRUE_LE, 5, 0, 0}, 538 {CPU_FTR_REAL_LE, PPC_FEATURE_TRUE_LE, 5, 0, 0},
539}; 539};
540 540
541static void __init check_cpu_pa_features(unsigned long node) 541static void __init scan_features(unsigned long node, unsigned char *ftrs,
542 unsigned long tablelen,
543 struct ibm_pa_feature *fp,
544 unsigned long ft_size)
542{ 545{
543 unsigned char *pa_ftrs; 546 unsigned long i, len, bit;
544 unsigned long len, tablelen, i, bit;
545
546 pa_ftrs = of_get_flat_dt_prop(node, "ibm,pa-features", &tablelen);
547 if (pa_ftrs == NULL)
548 return;
549 547
550 /* find descriptor with type == 0 */ 548 /* find descriptor with type == 0 */
551 for (;;) { 549 for (;;) {
552 if (tablelen < 3) 550 if (tablelen < 3)
553 return; 551 return;
554 len = 2 + pa_ftrs[0]; 552 len = 2 + ftrs[0];
555 if (tablelen < len) 553 if (tablelen < len)
556 return; /* descriptor 0 not found */ 554 return; /* descriptor 0 not found */
557 if (pa_ftrs[1] == 0) 555 if (ftrs[1] == 0)
558 break; 556 break;
559 tablelen -= len; 557 tablelen -= len;
560 pa_ftrs += len; 558 ftrs += len;
561 } 559 }
562 560
563 /* loop over bits we know about */ 561 /* loop over bits we know about */
564 for (i = 0; i < ARRAY_SIZE(ibm_pa_features); ++i) { 562 for (i = 0; i < ft_size; ++i, ++fp) {
565 struct ibm_pa_feature *fp = &ibm_pa_features[i]; 563 if (fp->pabyte >= ftrs[0])
566
567 if (fp->pabyte >= pa_ftrs[0])
568 continue; 564 continue;
569 bit = (pa_ftrs[2 + fp->pabyte] >> (7 - fp->pabit)) & 1; 565 bit = (ftrs[2 + fp->pabyte] >> (7 - fp->pabit)) & 1;
570 if (bit ^ fp->invert) { 566 if (bit ^ fp->invert) {
571 cur_cpu_spec->cpu_features |= fp->cpu_features; 567 cur_cpu_spec->cpu_features |= fp->cpu_features;
572 cur_cpu_spec->cpu_user_features |= fp->cpu_user_ftrs; 568 cur_cpu_spec->cpu_user_features |= fp->cpu_user_ftrs;
@@ -577,16 +573,59 @@ static void __init check_cpu_pa_features(unsigned long node)
577 } 573 }
578} 574}
579 575
576static void __init check_cpu_pa_features(unsigned long node)
577{
578 unsigned char *pa_ftrs;
579 unsigned long tablelen;
580
581 pa_ftrs = of_get_flat_dt_prop(node, "ibm,pa-features", &tablelen);
582 if (pa_ftrs == NULL)
583 return;
584
585 scan_features(node, pa_ftrs, tablelen,
586 ibm_pa_features, ARRAY_SIZE(ibm_pa_features));
587}
588
589static struct feature_property {
590 const char *name;
591 u32 min_value;
592 unsigned long cpu_feature;
593 unsigned long cpu_user_ftr;
594} feature_properties[] __initdata = {
595#ifdef CONFIG_ALTIVEC
596 {"altivec", 0, CPU_FTR_ALTIVEC, PPC_FEATURE_HAS_ALTIVEC},
597 {"ibm,vmx", 1, CPU_FTR_ALTIVEC, PPC_FEATURE_HAS_ALTIVEC},
598#endif /* CONFIG_ALTIVEC */
599#ifdef CONFIG_PPC64
600 {"ibm,dfp", 1, 0, PPC_FEATURE_HAS_DFP},
601 {"ibm,purr", 1, CPU_FTR_PURR, 0},
602 {"ibm,spurr", 1, CPU_FTR_SPURR, 0},
603#endif /* CONFIG_PPC64 */
604};
605
606static void __init check_cpu_feature_properties(unsigned long node)
607{
608 unsigned long i;
609 struct feature_property *fp = feature_properties;
610 const u32 *prop;
611
612 for (i = 0; i < ARRAY_SIZE(feature_properties); ++i, ++fp) {
613 prop = of_get_flat_dt_prop(node, fp->name, NULL);
614 if (prop && *prop >= fp->min_value) {
615 cur_cpu_spec->cpu_features |= fp->cpu_feature;
616 cur_cpu_spec->cpu_user_features |= fp->cpu_user_ftr;
617 }
618 }
619}
620
580static int __init early_init_dt_scan_cpus(unsigned long node, 621static int __init early_init_dt_scan_cpus(unsigned long node,
581 const char *uname, int depth, 622 const char *uname, int depth,
582 void *data) 623 void *data)
583{ 624{
584 static int logical_cpuid = 0; 625 static int logical_cpuid = 0;
585 char *type = of_get_flat_dt_prop(node, "device_type", NULL); 626 char *type = of_get_flat_dt_prop(node, "device_type", NULL);
586#ifdef CONFIG_ALTIVEC 627 const u32 *prop;
587 u32 *prop; 628 const u32 *intserv;
588#endif
589 u32 *intserv;
590 int i, nthreads; 629 int i, nthreads;
591 unsigned long len; 630 unsigned long len;
592 int found = 0; 631 int found = 0;
@@ -643,24 +682,27 @@ static int __init early_init_dt_scan_cpus(unsigned long node,
643 intserv[i]); 682 intserv[i]);
644 boot_cpuid = logical_cpuid; 683 boot_cpuid = logical_cpuid;
645 set_hard_smp_processor_id(boot_cpuid, intserv[i]); 684 set_hard_smp_processor_id(boot_cpuid, intserv[i]);
646 }
647 685
648#ifdef CONFIG_ALTIVEC 686 /*
649 /* Check if we have a VMX and eventually update CPU features */ 687 * PAPR defines "logical" PVR values for cpus that
650 prop = (u32 *)of_get_flat_dt_prop(node, "ibm,vmx", NULL); 688 * meet various levels of the architecture:
651 if (prop && (*prop) > 0) { 689 * 0x0f000001 Architecture version 2.04
652 cur_cpu_spec->cpu_features |= CPU_FTR_ALTIVEC; 690 * 0x0f000002 Architecture version 2.05
653 cur_cpu_spec->cpu_user_features |= PPC_FEATURE_HAS_ALTIVEC; 691 * If the cpu-version property in the cpu node contains
654 } 692 * such a value, we call identify_cpu again with the
655 693 * logical PVR value in order to use the cpu feature
656 /* Same goes for Apple's "altivec" property */ 694 * bits appropriate for the architecture level.
657 prop = (u32 *)of_get_flat_dt_prop(node, "altivec", NULL); 695 *
658 if (prop) { 696 * A POWER6 partition in "POWER6 architected" mode
659 cur_cpu_spec->cpu_features |= CPU_FTR_ALTIVEC; 697 * uses the 0x0f000002 PVR value; in POWER5+ mode
660 cur_cpu_spec->cpu_user_features |= PPC_FEATURE_HAS_ALTIVEC; 698 * it uses 0x0f000001.
699 */
700 prop = of_get_flat_dt_prop(node, "cpu-version", NULL);
701 if (prop && (*prop & 0xff000000) == 0x0f000000)
702 identify_cpu(0, *prop);
661 } 703 }
662#endif /* CONFIG_ALTIVEC */
663 704
705 check_cpu_feature_properties(node);
664 check_cpu_pa_features(node); 706 check_cpu_pa_features(node);
665 707
666#ifdef CONFIG_PPC_PSERIES 708#ifdef CONFIG_PPC_PSERIES
diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c
index 8671eb634a92..396109a537cd 100644
--- a/arch/powerpc/kernel/prom_init.c
+++ b/arch/powerpc/kernel/prom_init.c
@@ -627,6 +627,7 @@ static void __init early_cmdline_parse(void)
627/* Option vector 3: processor options supported */ 627/* Option vector 3: processor options supported */
628#define OV3_FP 0x80 /* floating point */ 628#define OV3_FP 0x80 /* floating point */
629#define OV3_VMX 0x40 /* VMX/Altivec */ 629#define OV3_VMX 0x40 /* VMX/Altivec */
630#define OV3_DFP 0x20 /* decimal FP */
630 631
631/* Option vector 5: PAPR/OF options supported */ 632/* Option vector 5: PAPR/OF options supported */
632#define OV5_LPAR 0x80 /* logical partitioning supported */ 633#define OV5_LPAR 0x80 /* logical partitioning supported */
@@ -668,7 +669,7 @@ static unsigned char ibm_architecture_vec[] = {
668 /* option vector 3: processor options supported */ 669 /* option vector 3: processor options supported */
669 3 - 2, /* length */ 670 3 - 2, /* length */
670 0, /* don't ignore, don't halt */ 671 0, /* don't ignore, don't halt */
671 OV3_FP | OV3_VMX, 672 OV3_FP | OV3_VMX | OV3_DFP,
672 673
673 /* option vector 4: IBM PAPR implementation */ 674 /* option vector 4: IBM PAPR implementation */
674 2 - 2, /* length */ 675 2 - 2, /* length */
diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c
index 04df53a3c86d..61c65d19ef06 100644
--- a/arch/powerpc/kernel/setup_32.c
+++ b/arch/powerpc/kernel/setup_32.c
@@ -97,7 +97,7 @@ unsigned long __init early_init(unsigned long dt_ptr)
97 * Identify the CPU type and fix up code sections 97 * Identify the CPU type and fix up code sections
98 * that depend on which cpu we have. 98 * that depend on which cpu we have.
99 */ 99 */
100 spec = identify_cpu(offset); 100 spec = identify_cpu(offset, mfspr(SPRN_PVR));
101 101
102 do_feature_fixups(spec->cpu_features, 102 do_feature_fixups(spec->cpu_features,
103 PTRRELOC(&__start___ftr_fixup), 103 PTRRELOC(&__start___ftr_fixup),
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
index f602a53b1b79..3733de30e84d 100644
--- a/arch/powerpc/kernel/setup_64.c
+++ b/arch/powerpc/kernel/setup_64.c
@@ -171,7 +171,7 @@ void __init setup_paca(int cpu)
171void __init early_setup(unsigned long dt_ptr) 171void __init early_setup(unsigned long dt_ptr)
172{ 172{
173 /* Identify CPU type */ 173 /* Identify CPU type */
174 identify_cpu(0); 174 identify_cpu(0, mfspr(SPRN_PVR));
175 175
176 /* Assume we're on cpu 0 for now. Don't write to the paca yet! */ 176 /* Assume we're on cpu 0 for now. Don't write to the paca yet! */
177 setup_paca(0); 177 setup_paca(0);