[POWERPC] Consolidate feature fixup code
[powerpc.git] / arch / powerpc / kernel / cputable.c
index 306da4c..6fdfaa4 100644 (file)
@@ -18,6 +18,7 @@
 
 #include <asm/oprofile_impl.h>
 #include <asm/cputable.h>
+#include <asm/prom.h>          /* for PTRRELOC on ARCH=ppc */
 
 struct cpu_spec* cur_cpu_spec = NULL;
 EXPORT_SYMBOL(cur_cpu_spec);
@@ -58,6 +59,9 @@ extern void __restore_cpu_ppc970(void);
 #define COMMON_USER_POWER6     (COMMON_USER_PPC64 | PPC_FEATURE_ARCH_2_05 |\
                                 PPC_FEATURE_SMT | PPC_FEATURE_ICACHE_SNOOP | \
                                 PPC_FEATURE_TRUE_LE)
+#define COMMON_USER_PA6T       (COMMON_USER_PPC64 | PPC_FEATURE_PA6T |\
+                                PPC_FEATURE_TRUE_LE | \
+                                PPC_FEATURE_HAS_ALTIVEC_COMP)
 #define COMMON_USER_BOOKE      (PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | \
                                 PPC_FEATURE_BOOKE)
 
@@ -70,7 +74,7 @@ extern void __restore_cpu_ppc970(void);
 #define PPC_FEATURE_SPE_COMP   0
 #endif
 
-struct cpu_spec        cpu_specs[] = {
+static struct cpu_spec cpu_specs[] = {
 #ifdef CONFIG_PPC64
        {       /* Power3 */
                .pvr_mask               = 0xffff0000,
@@ -224,6 +228,21 @@ struct cpu_spec    cpu_specs[] = {
                .oprofile_type          = PPC_OPROFILE_POWER4,
                .platform               = "ppc970",
        },
+       {       /* PPC970GX */
+               .pvr_mask               = 0xffff0000,
+               .pvr_value              = 0x00450000,
+               .cpu_name               = "PPC970GX",
+               .cpu_features           = CPU_FTRS_PPC970,
+               .cpu_user_features      = COMMON_USER_POWER4 |
+                       PPC_FEATURE_HAS_ALTIVEC_COMP,
+               .icache_bsize           = 128,
+               .dcache_bsize           = 128,
+               .num_pmcs               = 8,
+               .cpu_setup              = __setup_cpu_ppc970,
+               .oprofile_cpu_type      = "ppc64/970",
+               .oprofile_type          = PPC_OPROFILE_POWER4,
+               .platform               = "ppc970",
+       },
        {       /* Power5 GR */
                .pvr_mask               = 0xffff0000,
                .pvr_value              = 0x003a0000,
@@ -265,7 +284,7 @@ struct cpu_spec     cpu_specs[] = {
                .cpu_user_features      = COMMON_USER_POWER6,
                .icache_bsize           = 128,
                .dcache_bsize           = 128,
-               .num_pmcs               = 8,
+               .num_pmcs               = 6,
                .oprofile_cpu_type      = "ppc64/power6",
                .oprofile_type          = PPC_OPROFILE_POWER4,
                .oprofile_mmcra_sihv    = POWER6_MMCRA_SIHV,
@@ -286,6 +305,17 @@ struct cpu_spec    cpu_specs[] = {
                .dcache_bsize           = 128,
                .platform               = "ppc-cell-be",
        },
+       {       /* PA Semi PA6T */
+               .pvr_mask               = 0x7fff0000,
+               .pvr_value              = 0x00900000,
+               .cpu_name               = "PA6T",
+               .cpu_features           = CPU_FTRS_PA6T,
+               .cpu_user_features      = COMMON_USER_PA6T,
+               .icache_bsize           = 64,
+               .dcache_bsize           = 64,
+               .num_pmcs               = 6,
+               .platform               = "pa6t",
+       },
        {       /* default match */
                .pvr_mask               = 0x00000000,
                .pvr_value              = 0x00000000,
@@ -749,10 +779,10 @@ struct cpu_spec   cpu_specs[] = {
                .cpu_setup              = __setup_cpu_603,
                .platform               = "ppc603",
        },
-       {       /* e300 (a 603e core, plus some) on 83xx */
+       {       /* e300c1 (a 603e core, plus some) on 83xx */
                .pvr_mask               = 0x7fff0000,
                .pvr_value              = 0x00830000,
-               .cpu_name               = "e300",
+               .cpu_name               = "e300c1",
                .cpu_features           = CPU_FTRS_E300,
                .cpu_user_features      = COMMON_USER,
                .icache_bsize           = 32,
@@ -760,6 +790,17 @@ struct cpu_spec    cpu_specs[] = {
                .cpu_setup              = __setup_cpu_603,
                .platform               = "ppc603",
        },
+       {       /* e300c2 (an e300c1 core, plus some, minus FPU) on 83xx */
+               .pvr_mask               = 0x7fff0000,
+               .pvr_value              = 0x00840000,
+               .cpu_name               = "e300c2",
+               .cpu_features           = CPU_FTRS_E300,
+               .cpu_user_features      = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU,
+               .icache_bsize           = 32,
+               .dcache_bsize           = 32,
+               .cpu_setup              = __setup_cpu_603,
+               .platform               = "ppc603",
+       },
        {       /* default match, we assume split I/D cache & TB (non-601)... */
                .pvr_mask               = 0x00000000,
                .pvr_value              = 0x00000000,
@@ -935,6 +976,7 @@ struct cpu_spec     cpu_specs[] = {
                        PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
+               .platform               = "ppc405",
        },
        {       /* 405EP */
                .pvr_mask               = 0xffff0000,
@@ -1126,3 +1168,72 @@ struct cpu_spec  cpu_specs[] = {
 #endif /* !CLASSIC_PPC */
 #endif /* CONFIG_PPC32 */
 };
+
+struct cpu_spec *identify_cpu(unsigned long offset)
+{
+       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;
+#ifdef CONFIG_PPC64
+                       /* ppc64 expects identify_cpu to also call setup_cpu
+                        * for that processor. I will consolidate that at a
+                        * later time, for now, just use our friend #ifdef.
+                        * we also don't need to PTRRELOC the function pointer
+                        * on ppc64 as we are running at 0 in real mode.
+                        */
+                       if (s->cpu_setup) {
+                               s->cpu_setup(offset, s);
+                       }
+#endif /* CONFIG_PPC64 */
+                       return s;
+               }
+       BUG();
+       return NULL;
+}
+
+void do_feature_fixups(unsigned long offset, unsigned long value,
+                      void *fixup_start, void *fixup_end)
+{
+       struct fixup_entry {
+               unsigned long   mask;
+               unsigned long   value;
+               unsigned int    *start;
+               unsigned int    *end;
+       } *fcur, *fend;
+
+       fcur = fixup_start;
+       fend = fixup_end;
+
+       for (; fcur < fend; fcur++) {
+               unsigned int *pstart, *pend, *p;
+
+               if ((value & fcur->mask) == fcur->value)
+                       continue;
+
+               /* These PTRRELOCs will disappear once the new scheme for
+                * modules and vdso is implemented
+                */
+               pstart = PTRRELOC(fcur->start);
+               pend = PTRRELOC(fcur->end);
+
+               for (p = pstart; p < pend; p++) {
+                       *p = 0x60000000u;
+                       asm volatile ("dcbst 0, %0" : : "r" (p));
+               }
+               asm volatile ("sync" : : : "memory");
+               for (p = pstart; p < pend; p++)
+                       asm volatile ("icbi 0,%0" : : "r" (p));
+               asm volatile ("sync; isync" : : : "memory");
+       }
+}