Subject: Re: [PATCH] PPC/PPC64: Introduce CPU_HAS_FEATURE() macro

From: Arnd Bergmann <[email-masked]>
Date: Sat, 5 Feb 2005 01:22:21 +0100

On Sünnavend 05 Februar 2005 00:49, Benjamin Herrenschmidt wrote:
> On Fri, 2005-02-04 at 13:36 +0100, Arnd Bergmann wrote:
> > I have a somewhat similar patch that does the same to the
> > systemcfg->platform checks. I'm not sure if we should use the same inline
> > function for both checks, but I do think that they should be used in a
> > similar way, e.g. CPU_HAS_FEATURE(x) and PLATFORM_HAS_FEATURE(x).
> 
> Note that I would prefer cpu_has_feature(), it doesn't strictly have to
> be a macro and has function semantics anyway.

> > [ ... ] 
> > which will always result in the shortest code for any combination of
> > CONFIG_PPC_ISERIES, CONFIG_PPC_PSERIES and the other platforms.
> 
> That's a good idea !

This is the patch to evaluate CPU_HAS_FEATURE() at compile time whenever
possible. Testing showed that vmlinux shrinks around 4000 bytes with
g5_defconfig. I also checked that pSeries code is completely unaltered
semantically when support for all CPU types is enabled, although a few
instructions are emitted in a different order by gcc.

I have made cpu_has_feature() an inline function that expects the full
name of a feature bit while the CPU_HAS_FEATURE() macro still behaves
the same way as in Olofs original patch for now.

I'm not sure if I got the Kconfig dependencies right, maybe you can
check them.

Signed-off-by: Arnd Bergmann <[email-masked]>

---
Index: linux-2.6-64/include/asm-ppc64/cputable.h
===================================================================
--- linux-2.6-64.orig/include/asm-ppc64/cputable.h	2005-02-05 01:24:58.975674192 +0100
+++ linux-2.6-64/include/asm-ppc64/cputable.h	2005-02-05 01:26:17.328762712 +0100
@@ -66,9 +66,6 @@
 extern struct cpu_spec		cpu_specs[];
 extern struct cpu_spec		*cur_cpu_spec;
 
-#define CPU_HAS_FEATURE(x)	(cur_cpu_spec->cpu_features & CPU_FTR_##x)
-
-
 /* firmware feature bitmask values */
 #define FIRMWARE_MAX_FEATURES 63
 
@@ -154,6 +151,80 @@
 #define CPU_FTR_PPCAS_ARCH_V2	(CPU_FTR_PPCAS_ARCH_V2_BASE | CPU_FTR_16M_PAGE)
 #endif
 
+/* We only set the altivec features if the kernel was compiled with altivec
+ * support
+ */
+#ifdef CONFIG_ALTIVEC
+#define CPU_FTR_ALTIVEC_COMP	CPU_FTR_ALTIVEC
+#define PPC_FEATURE_HAS_ALTIVEC_COMP PPC_FEATURE_HAS_ALTIVEC
+#else
+#define CPU_FTR_ALTIVEC_COMP	0
+#define PPC_FEATURE_HAS_ALTIVEC_COMP    0
+#endif
+
+enum {
+	CPU_FTR_POWER3 = CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB |
+			 CPU_FTR_HPTE_TABLE | CPU_FTR_IABR | CPU_FTR_PMC8,
+	CPU_FTR_RS64   = CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB |
+			 CPU_FTR_HPTE_TABLE | CPU_FTR_IABR | CPU_FTR_PMC8 |
+			 CPU_FTR_MMCRA,
+	CPU_FTR_POWER4 = CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB |
+			 CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 |
+			 CPU_FTR_PMC8 | CPU_FTR_MMCRA,
+	CPU_FTR_PPC970 = CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB |
+			 CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 |
+			 CPU_FTR_ALTIVEC_COMP | CPU_FTR_CAN_NAP |
+			 CPU_FTR_PMC8 | CPU_FTR_MMCRA,
+	CPU_FTR_POWER5 = CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB |
+			 CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 |
+			 CPU_FTR_MMCRA | CPU_FTR_SMT | CPU_FTR_COHERENT_ICACHE |
+			 CPU_FTR_LOCKLESS_TLBIE | CPU_FTR_MMCRA_SIHV,
+	CPU_FTR_COMPATIBLE = CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB |
+			 CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2,
+	CPU_FTR_POSSIBLE =
+#ifdef CONFIG_CPU_POWER3
+			 CPU_FTR_POWER3 |
+#endif
+#ifdef CONFIG_CPU_RS64
+			 CPU_FTR_RS64 |
+#endif
+#ifdef CONFIG_CPU_POWER4
+			 CPU_FTR_POWER4 |
+#endif
+#ifdef CONFIG_CPU_PPC970
+			 CPU_FTR_PPC970 |
+#endif
+#ifdef CONFIG_CPU_POWER5
+			 CPU_FTR_POWER5 |
+#endif
+			 0,
+	CPU_FTR_ALWAYS =
+#ifdef CONFIG_CPU_POWER3
+			 CPU_FTR_POWER3 &
+#endif
+#ifdef CONFIG_CPU_RS64
+			 CPU_FTR_RS64 &
+#endif
+#ifdef CONFIG_CPU_POWER4
+			 CPU_FTR_POWER4 &
+#endif
+#ifdef CONFIG_CPU_PPC970
+			 CPU_FTR_PPC970 &
+#endif
+#ifdef CONFIG_CPU_POWER5
+			 CPU_FTR_POWER5 &
+#endif
+			 CPU_FTR_POSSIBLE,
+};
+
+static inline int cpu_has_feature(unsigned long feature)
+{
+	return (CPU_FTR_ALWAYS & feature) ||
+	       (CPU_FTR_POSSIBLE & feature & cur_cpu_spec->cpu_features);
+}
+
+#define CPU_HAS_FEATURE(x) cpu_has_feature(CPU_FTR_##x)
+
 #define COMMON_PPC64_FW	(0)
 #endif
 
Index: linux-2.6-64/arch/ppc64/Kconfig
===================================================================
--- linux-2.6-64.orig/arch/ppc64/Kconfig	2005-02-05 01:24:31.098912104 +0100
+++ linux-2.6-64/arch/ppc64/Kconfig	2005-02-05 01:25:01.430301032 +0100
@@ -107,6 +107,31 @@
 	bool
 	default y
 
+config CPU_POWER3
+	bool
+	default y
+	depends on (PPC_ISERIES || PPC_PSERIES) && !POWER4_ONLY
+
+config CPU_RS64
+	bool
+	default y
+	depends on (PPC_ISERIES || PPC_PSERIES) && !POWER4_ONLY
+
+config CPU_POWER4
+	bool
+	default y
+	depends on PPC_ISERIES || PPC_PSERIES
+
+config CPU_PPC970
+	bool
+	default y
+	depends on PPC_PSERIES || PPC_PMAC || PPC_MAPLE
+
+config CPU_POWER5
+	bool
+	default y
+	depends on PPC_PSERIES
+
 # VMX is pSeries only for now until somebody writes the iSeries
 # exception vectors for it
 config ALTIVEC
Index: linux-2.6-64/arch/ppc64/kernel/cputable.c
===================================================================
--- linux-2.6-64.orig/arch/ppc64/kernel/cputable.c	2005-02-05 01:24:31.098912104 +0100
+++ linux-2.6-64/arch/ppc64/kernel/cputable.c	2005-02-05 01:25:01.431300880 +0100
@@ -33,137 +33,94 @@
 extern void __setup_cpu_ppc970(unsigned long offset, struct cpu_spec* spec);

-/* We only set the altivec features if the kernel was compiled with altivec
- * support
- */
-#ifdef CONFIG_ALTIVEC
-#define CPU_FTR_ALTIVEC_COMP	CPU_FTR_ALTIVEC
-#define PPC_FEATURE_HAS_ALTIVEC_COMP PPC_FEATURE_HAS_ALTIVEC
-#else
-#define CPU_FTR_ALTIVEC_COMP	0
-#define PPC_FEATURE_HAS_ALTIVEC_COMP    0
-#endif
-
 struct cpu_spec	cpu_specs[] = {
     {	/* Power3 */
 	    0xffff0000, 0x00400000, "POWER3 (630)",
-	    CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
-		    CPU_FTR_IABR | CPU_FTR_PMC8,
-	    COMMON_USER_PPC64,
+	    CPU_FTR_POWER3, COMMON_USER_PPC64,
 	    128, 128,
 	    __setup_cpu_power3,
 	    COMMON_PPC64_FW
     },
     {	/* Power3+ */
 	    0xffff0000, 0x00410000, "POWER3 (630+)",
-	    CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
-		    CPU_FTR_IABR | CPU_FTR_PMC8,
-	    COMMON_USER_PPC64,
+	    CPU_FTR_POWER3, COMMON_USER_PPC64,
 	    128, 128,
 	    __setup_cpu_power3,
 	    COMMON_PPC64_FW
     },
     {	/* Northstar */
 	    0xffff0000, 0x00330000, "RS64-II (northstar)",
-	    CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
-		    CPU_FTR_IABR | CPU_FTR_PMC8 | CPU_FTR_MMCRA,
-	    COMMON_USER_PPC64,
+	    CPU_FTR_RS64, COMMON_USER_PPC64,
 	    128, 128,
 	    __setup_cpu_power3,
 	    COMMON_PPC64_FW
     },
     {	/* Pulsar */
 	    0xffff0000, 0x00340000, "RS64-III (pulsar)",
-	    CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
-		    CPU_FTR_IABR | CPU_FTR_PMC8 | CPU_FTR_MMCRA,
-	    COMMON_USER_PPC64,
+	    CPU_FTR_RS64, COMMON_USER_PPC64,
 	    128, 128,
 	    __setup_cpu_power3,
 	    COMMON_PPC64_FW
     },
     {	/* I-star */
 	    0xffff0000, 0x00360000, "RS64-III (icestar)",
-	    CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
-		    CPU_FTR_IABR | CPU_FTR_PMC8 | CPU_FTR_MMCRA,
-	    COMMON_USER_PPC64,
+	    CPU_FTR_RS64, COMMON_USER_PPC64,
 	    128, 128,
 	    __setup_cpu_power3,
 	    COMMON_PPC64_FW
     },
     {	/* S-star */
 	    0xffff0000, 0x00370000, "RS64-IV (sstar)",
-	    CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
-		    CPU_FTR_IABR | CPU_FTR_PMC8 | CPU_FTR_MMCRA,
-	    COMMON_USER_PPC64,
+	    CPU_FTR_RS64, COMMON_USER_PPC64,
 	    128, 128,
 	    __setup_cpu_power3,
 	    COMMON_PPC64_FW
     },
     {	/* Power4 */
 	    0xffff0000, 0x00350000, "POWER4 (gp)",
-	    CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
-		    CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_PMC8 | CPU_FTR_MMCRA,
-	    COMMON_USER_PPC64,
+	    CPU_FTR_POWER4, COMMON_USER_PPC64,
 	    128, 128,
 	    __setup_cpu_power4,
 	    COMMON_PPC64_FW
     },
     {	/* Power4+ */
 	    0xffff0000, 0x00380000, "POWER4+ (gq)",
-	    CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
-		    CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_PMC8 | CPU_FTR_MMCRA,
-	    COMMON_USER_PPC64,
+	    CPU_FTR_POWER4, COMMON_USER_PPC64,
 	    128, 128,
 	    __setup_cpu_power4,
 	    COMMON_PPC64_FW
     },
     {	/* PPC970 */
 	    0xffff0000, 0x00390000, "PPC970",
-	    CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
-		    CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_ALTIVEC_COMP |
-		    CPU_FTR_CAN_NAP | CPU_FTR_PMC8 | CPU_FTR_MMCRA,
-	    COMMON_USER_PPC64 | PPC_FEATURE_HAS_ALTIVEC_COMP,
+	    CPU_FTR_PPC970, COMMON_USER_PPC64 | PPC_FEATURE_HAS_ALTIVEC_COMP,
 	    128, 128,
 	    __setup_cpu_ppc970,
 	    COMMON_PPC64_FW
     },
     {	/* PPC970FX */
 	    0xffff0000, 0x003c0000, "PPC970FX",
-	    CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
-		    CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_ALTIVEC_COMP |
-		    CPU_FTR_CAN_NAP | CPU_FTR_PMC8 | CPU_FTR_MMCRA,
-	    COMMON_USER_PPC64 | PPC_FEATURE_HAS_ALTIVEC_COMP,
+	    CPU_FTR_PPC970, COMMON_USER_PPC64 | PPC_FEATURE_HAS_ALTIVEC_COMP,
 	    128, 128,
 	    __setup_cpu_ppc970,
 	    COMMON_PPC64_FW
     },
     {	/* Power5 */
 	    0xffff0000, 0x003a0000, "POWER5 (gr)",
-	    CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
-		    CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_MMCRA | CPU_FTR_SMT |
-		    CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE |
-		    CPU_FTR_MMCRA_SIHV,
-	    COMMON_USER_PPC64,
+	    CPU_FTR_POWER5, COMMON_USER_PPC64,
 	    128, 128,
 	    __setup_cpu_power4,
 	    COMMON_PPC64_FW
     },
     {	/* Power5 */
 	    0xffff0000, 0x003b0000, "POWER5 (gs)",
-	    CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
-		    CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_MMCRA | CPU_FTR_SMT |
-		    CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE |
-		    CPU_FTR_MMCRA_SIHV,
-	    COMMON_USER_PPC64,
+	    CPU_FTR_POWER5, COMMON_USER_PPC64,
 	    128, 128,
 	    __setup_cpu_power4,
 	    COMMON_PPC64_FW
     },
     {	/* default match */
 	    0x00000000, 0x00000000, "POWER4 (compatible)",
-  	    CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
-		    CPU_FTR_PPCAS_ARCH_V2,
-	    COMMON_USER_PPC64,
+	    CPU_FTR_COMPATIBLE, COMMON_USER_PPC64,
 	    128, 128,
 	    __setup_cpu_power4,
 	    COMMON_PPC64_FW