Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 89877e42827f16fa5f86b1df0c2860b1 > files > 1850

kernel-2.6.18-128.1.10.el5.src.rpm

From: Janice M. Girouard <jgirouar@redhat.com>
Subject: [RHEL 5.1 FEATURE] bz# 228091 1/2 [PPC]: Handle Power6 partition  modes
Date: Wed, 18 Apr 2007 17:06:08 -0400 (Eastern Daylight Time)
Bugzilla: 228091
Message-Id: <Pine.WNT.4.64.0704181700380.5296@IBM-3MTQI3AXJFW>
Changelog: [ppc64] Handle Power6 partition modes



RHBZ#:
------
https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=228091

Description:
------------

1 of 2 patches required to support power6 partition modes.

This patch adds code to look at the properties firmware updates in the device tree to detemrine what compatibility mode the paritoin is in on power6 machines, and set's 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 -x-f00000x), we call identify_cpu again with this PVR value.  A value of 0xf000001 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 and ibm,purr.

RHEL Version Found:
-------------------
feature enhancement for cell to be supported in 5.1.

Upstream Status:
----------------
This code is accepted upstream and can be viewed in the 2.6.20.7 kernel.

Test Status:
------------
Tested by Manoj Iyer of IBM using the at_plat.c code attached to the bz.

This patch is dependent on 31034 (which must be applied first).
This patch is builds and compiles cleanly using kernel-2.6.18-15.el5.src.rpm.


Proposed Patch:
----------------
Please review and ACK for RHEL 5.1
-
diff -urN rhel-orig/arch/powerpc/kernel/cputable.c rhel-p6/arch/powerpc/kernel/cputable.c
--- rhel-orig/arch/powerpc/kernel/cputable.c	2007-01-29 16:08:50.000000000 +1100
+++ rhel-p6/arch/powerpc/kernel/cputable.c	2007-01-29 16:09:29.000000000 +1100
@@ -252,10 +252,45 @@
 		.oprofile_mmcra_sipr	= MMCRA_SIPR,
 		.platform		= "power5+",
 	},
+	{	/* POWER6 in P5+ mode; 2.04-compliant processor */
+		.pvr_mask		= 0xffffffff,
+		.pvr_value		= 0x0f000001,
+		.cpu_name		= "POWER5+",
+		.cpu_features		= CPU_FTRS_POWER5,
+		.cpu_user_features	= COMMON_USER_POWER5_PLUS,
+		.icache_bsize		= 128,
+		.dcache_bsize		= 128,
+		.num_pmcs		= 6,
+		.oprofile_cpu_type	= "ppc64/power6",
+		.oprofile_type		= PPC_OPROFILE_POWER4,
+		.oprofile_mmcra_sihv	= POWER6_MMCRA_SIHV,
+		.oprofile_mmcra_sipr	= POWER6_MMCRA_SIPR,
+		.oprofile_mmcra_clear	= POWER6_MMCRA_THRM |
+			POWER6_MMCRA_OTHER,
+		.platform		= "power5+",
+	},
 	{	/* Power6 */
 		.pvr_mask		= 0xffff0000,
 		.pvr_value		= 0x003e0000,
-		.cpu_name		= "POWER6",
+		.cpu_name		= "POWER6 (raw)",
+		.cpu_features		= CPU_FTRS_POWER6,
+		.cpu_user_features	= COMMON_USER_POWER6 |
+			PPC_FEATURE_POWER6_EXT,
+		.icache_bsize		= 128,
+		.dcache_bsize		= 128,
+		.num_pmcs		= 6,
+		.oprofile_cpu_type	= "ppc64/power6",
+		.oprofile_type		= PPC_OPROFILE_POWER4,
+		.oprofile_mmcra_sihv	= POWER6_MMCRA_SIHV,
+		.oprofile_mmcra_sipr	= POWER6_MMCRA_SIPR,
+		.oprofile_mmcra_clear	= POWER6_MMCRA_THRM |
+			POWER6_MMCRA_OTHER,
+		.platform		= "power6x",
+	},
+	{	/* 2.05-compliant processor, i.e. Power6 "architected" mode */
+		.pvr_mask		= 0xffffffff,
+		.pvr_value		= 0x0f000002,
+		.cpu_name		= "POWER6 (architected)",
 		.cpu_features		= CPU_FTRS_POWER6,
 		.cpu_user_features	= COMMON_USER_POWER6,
 		.icache_bsize		= 128,
@@ -1122,19 +1157,15 @@
 #endif /* CONFIG_PPC32 */
 };
 
-struct cpu_spec *identify_cpu(unsigned long offset)
+struct cpu_spec *identify_cpu(unsigned long offset, unsigned int pvr)
 {
 	struct cpu_spec *s = cpu_specs;
 	struct cpu_spec **cur = &cur_cpu_spec;
-	unsigned int pvr = mfspr(SPRN_PVR);
 	int i;
 
 	s = PTRRELOC(s);
 	cur = PTRRELOC(cur);
 
-	if (*cur != NULL)
-		return PTRRELOC(*cur);
-
 	for (i = 0; i < ARRAY_SIZE(cpu_specs); i++,s++)
 		if ((pvr & s->pvr_mask) == s->pvr_value) {
 			*cur = cpu_specs + i;
diff -urN rhel-orig/arch/powerpc/kernel/prom.c rhel-p6/arch/powerpc/kernel/prom.c
--- rhel-orig/arch/powerpc/kernel/prom.c	2006-09-20 13:42:06.000000000 +1000
+++ rhel-p6/arch/powerpc/kernel/prom.c	2007-01-29 16:09:29.000000000 +1100
@@ -538,35 +538,31 @@
 	{CPU_FTR_REAL_LE, PPC_FEATURE_TRUE_LE, 5, 0, 0},
 };
 
-static void __init check_cpu_pa_features(unsigned long node)
+static void __init scan_features(unsigned long node, unsigned char *ftrs,
+				 unsigned long tablelen,
+				 struct ibm_pa_feature *fp,
+				 unsigned long ft_size)
 {
-	unsigned char *pa_ftrs;
-	unsigned long len, tablelen, i, bit;
-
-	pa_ftrs = of_get_flat_dt_prop(node, "ibm,pa-features", &tablelen);
-	if (pa_ftrs == NULL)
-		return;
+	unsigned long i, len, bit;
 
 	/* find descriptor with type == 0 */
 	for (;;) {
 		if (tablelen < 3)
 			return;
-		len = 2 + pa_ftrs[0];
+		len = 2 + ftrs[0];
 		if (tablelen < len)
 			return;		/* descriptor 0 not found */
-		if (pa_ftrs[1] == 0)
+		if (ftrs[1] == 0)
 			break;
 		tablelen -= len;
-		pa_ftrs += len;
+		ftrs += len;
 	}
 
 	/* loop over bits we know about */
-	for (i = 0; i < ARRAY_SIZE(ibm_pa_features); ++i) {
-		struct ibm_pa_feature *fp = &ibm_pa_features[i];
-
-		if (fp->pabyte >= pa_ftrs[0])
+	for (i = 0; i < ft_size; ++i, ++fp) {
+		if (fp->pabyte >= ftrs[0])
 			continue;
-		bit = (pa_ftrs[2 + fp->pabyte] >> (7 - fp->pabit)) & 1;
+		bit = (ftrs[2 + fp->pabyte] >> (7 - fp->pabit)) & 1;
 		if (bit ^ fp->invert) {
 			cur_cpu_spec->cpu_features |= fp->cpu_features;
 			cur_cpu_spec->cpu_user_features |= fp->cpu_user_ftrs;
@@ -577,16 +573,58 @@
 	}
 }
 
+static void __init check_cpu_pa_features(unsigned long node)
+{
+	unsigned char *pa_ftrs;
+	unsigned long tablelen;
+
+	pa_ftrs = of_get_flat_dt_prop(node, "ibm,pa-features", &tablelen);
+	if (pa_ftrs == NULL)
+		return;
+
+	scan_features(node, pa_ftrs, tablelen,
+		      ibm_pa_features, ARRAY_SIZE(ibm_pa_features));
+}
+
+static struct feature_property {
+	const char *name;
+	u32 min_value;
+	unsigned long cpu_feature;
+	unsigned long cpu_user_ftr;
+} feature_properties[] __initdata = {
+#ifdef CONFIG_ALTIVEC
+	{"altivec", 0, CPU_FTR_ALTIVEC, PPC_FEATURE_HAS_ALTIVEC},
+	{"ibm,vmx", 1, CPU_FTR_ALTIVEC, PPC_FEATURE_HAS_ALTIVEC},
+#endif /* CONFIG_ALTIVEC */
+#ifdef CONFIG_PPC64
+	{"ibm,dfp", 1, 0, PPC_FEATURE_HAS_DFP},
+	{"ibm,purr", 1, CPU_FTR_PURR, 0},
+#endif /* CONFIG_PPC64 */
+};
+
+static void __init check_cpu_feature_properties(unsigned long node)
+{
+	unsigned long i;
+	struct feature_property *fp = feature_properties;
+	const u32 *prop;
+
+	for (i = 0; i < ARRAY_SIZE(feature_properties); ++i, ++fp) {
+		prop = of_get_flat_dt_prop(node, fp->name, NULL);
+		if (prop && *prop >= fp->min_value) {
+			cur_cpu_spec->cpu_features |= fp->cpu_feature;
+			cur_cpu_spec->cpu_user_features |= fp->cpu_user_ftr;
+		}
+	}
+}
+
 static int __init early_init_dt_scan_cpus(unsigned long node,
 					  const char *uname, int depth,
 					  void *data)
 {
 	static int logical_cpuid = 0;
 	char *type = of_get_flat_dt_prop(node, "device_type", NULL);
-#ifdef CONFIG_ALTIVEC
-	u32 *prop;
-#endif
-	u32 *intserv;
+	const u32 *prop;
+	const u32 *intserv;
 	int i, nthreads;
 	unsigned long len;
 	int found = 0;
@@ -643,24 +681,27 @@
 			intserv[i]);
 		boot_cpuid = logical_cpuid;
 		set_hard_smp_processor_id(boot_cpuid, intserv[i]);
-	}
 
-#ifdef CONFIG_ALTIVEC
-	/* Check if we have a VMX and eventually update CPU features */
-	prop = (u32 *)of_get_flat_dt_prop(node, "ibm,vmx", NULL);
-	if (prop && (*prop) > 0) {
-		cur_cpu_spec->cpu_features |= CPU_FTR_ALTIVEC;
-		cur_cpu_spec->cpu_user_features |= PPC_FEATURE_HAS_ALTIVEC;
-	}
-
-	/* Same goes for Apple's "altivec" property */
-	prop = (u32 *)of_get_flat_dt_prop(node, "altivec", NULL);
-	if (prop) {
-		cur_cpu_spec->cpu_features |= CPU_FTR_ALTIVEC;
-		cur_cpu_spec->cpu_user_features |= PPC_FEATURE_HAS_ALTIVEC;
+		/*
+		 * PAPR defines "logical" PVR values for cpus that
+		 * meet various levels of the architecture:
+		 * 0x0f000001	Architecture version 2.04
+		 * 0x0f000002	Architecture version 2.05
+		 * If the cpu-version property in the cpu node contains
+		 * such a value, we call identify_cpu again with the
+		 * logical PVR value in order to use the cpu feature
+		 * bits appropriate for the architecture level.
+		 *
+		 * A POWER6 partition in "POWER6 architected" mode
+		 * uses the 0x0f000002 PVR value; in POWER5+ mode
+		 * it uses 0x0f000001.
+		 */
+		prop = of_get_flat_dt_prop(node, "cpu-version", NULL);
+		if (prop && (*prop & 0xff000000) == 0x0f000000)
+			identify_cpu(0, *prop);
 	}
-#endif /* CONFIG_ALTIVEC */
 
+	check_cpu_feature_properties(node);
 	check_cpu_pa_features(node);
 
 #ifdef CONFIG_PPC_PSERIES
diff -urN rhel-orig/arch/powerpc/kernel/setup_32.c rhel-p6/arch/powerpc/kernel/setup_32.c
--- rhel-orig/arch/powerpc/kernel/setup_32.c	2007-01-29 16:08:50.000000000 +1100
+++ rhel-p6/arch/powerpc/kernel/setup_32.c	2007-01-29 16:09:29.000000000 +1100
@@ -105,7 +105,7 @@
 	 * Identify the CPU type and fix up code sections
 	 * that depend on which cpu we have.
 	 */
-	spec = identify_cpu(offset);
+	spec = identify_cpu(offset, mfspr(SPRN_PVR));
 
 	do_feature_fixups(spec->cpu_features,
 			  PTRRELOC(&__start___ftr_fixup),
diff -urN rhel-orig/arch/powerpc/kernel/setup_64.c rhel-p6/arch/powerpc/kernel/setup_64.c
--- rhel-orig/arch/powerpc/kernel/setup_64.c	2007-01-29 16:08:50.000000000 +1100
+++ rhel-p6/arch/powerpc/kernel/setup_64.c	2007-01-29 16:09:29.000000000 +1100
@@ -177,7 +177,7 @@
 void __init early_setup(unsigned long dt_ptr)
 {
 	/* Identify CPU type */
-	identify_cpu(0);
+	identify_cpu(0, mfspr(SPRN_PVR));
 
 	/* Assume we're on cpu 0 for now. Don't write to the paca yet! */
 	setup_paca(0);
diff -urN rhel-orig/arch/powerpc/platforms/iseries/setup.c rhel-p6/arch/powerpc/platforms/iseries/setup.c
--- rhel-orig/arch/powerpc/platforms/iseries/setup.c	2007-01-29 16:08:21.000000000 +1100
+++ rhel-p6/arch/powerpc/platforms/iseries/setup.c	2007-01-29 16:09:29.000000000 +1100
@@ -657,7 +657,7 @@
 	/* Identify CPU type. This is done again by the common code later
 	 * on but calling this function multiple times is fine.
 	 */
-	identify_cpu(0);
+	identify_cpu(0, mfspr(SPRN_PVR));
 
 	powerpc_firmware_features |= FW_FEATURE_ISERIES;
 	powerpc_firmware_features |= FW_FEATURE_LPAR;
diff -urN rhel-orig/arch/ppc/kernel/setup.c rhel-p6/arch/ppc/kernel/setup.c
--- rhel-orig/arch/ppc/kernel/setup.c	2007-01-29 16:08:50.000000000 +1100
+++ rhel-p6/arch/ppc/kernel/setup.c	2007-01-29 16:09:29.000000000 +1100
@@ -310,7 +310,7 @@
 	 * Identify the CPU type and fix up code sections
 	 * that depend on which cpu we have.
 	 */
-	spec = identify_cpu(offset);
+	spec = identify_cpu(offset, mfspr(SPRN_PVR));
 	do_feature_fixups(spec->cpu_features,
 			  PTRRELOC(&__start___ftr_fixup),
 			  PTRRELOC(&__stop___ftr_fixup));
diff -urN rhel-orig/include/asm-powerpc/cputable.h rhel-p6/include/asm-powerpc/cputable.h
--- rhel-orig/include/asm-powerpc/cputable.h	2007-01-29 16:08:50.000000000 +1100
+++ rhel-p6/include/asm-powerpc/cputable.h	2007-01-29 16:11:16.000000000 +1100
@@ -23,6 +23,8 @@
 #define PPC_FEATURE_SMT			0x00004000
 #define PPC_FEATURE_ICACHE_SNOOP	0x00002000
 #define PPC_FEATURE_ARCH_2_05		0x00001000
+#define PPC_FEATURE_HAS_DFP		0x00000400
+#define PPC_FEATURE_POWER6_EXT		0x00000200
 
 #define PPC_FEATURE_TRUE_LE		0x00000002
 #define PPC_FEATURE_PPC_LE		0x00000001
@@ -87,7 +89,7 @@
 
 extern unsigned int __start___ftr_fixup, __stop___ftr_fixup;
 
-extern struct cpu_spec *identify_cpu(unsigned long offset);
+extern struct cpu_spec *identify_cpu(unsigned long offset, unsigned int pvr);
 extern void do_feature_fixups(unsigned long value, void *fixup_start,
 			      void *fixup_end);