Pull acpica into release branch
[pandora-kernel.git] / arch / powerpc / kernel / prom.c
index 4336390..9a07f97 100644 (file)
@@ -62,7 +62,7 @@ static int __initdata dt_root_addr_cells;
 static int __initdata dt_root_size_cells;
 
 #ifdef CONFIG_PPC64
-static int __initdata iommu_is_off;
+int __initdata iommu_is_off;
 int __initdata iommu_force_on;
 unsigned long tce_alloc_start, tce_alloc_end;
 #endif
@@ -885,6 +885,74 @@ void __init unflatten_device_tree(void)
        DBG(" <- unflatten_device_tree()\n");
 }
 
+/*
+ * ibm,pa-features is a per-cpu property that contains a string of
+ * attribute descriptors, each of which has a 2 byte header plus up
+ * to 254 bytes worth of processor attribute bits.  First header
+ * byte specifies the number of bytes following the header.
+ * Second header byte is an "attribute-specifier" type, of which
+ * zero is the only currently-defined value.
+ * Implementation:  Pass in the byte and bit offset for the feature
+ * that we are interested in.  The function will return -1 if the
+ * pa-features property is missing, or a 1/0 to indicate if the feature
+ * is supported/not supported.  Note that the bit numbers are
+ * big-endian to match the definition in PAPR.
+ */
+static struct ibm_pa_feature {
+       unsigned long   cpu_features;   /* CPU_FTR_xxx bit */
+       unsigned int    cpu_user_ftrs;  /* PPC_FEATURE_xxx bit */
+       unsigned char   pabyte;         /* byte number in ibm,pa-features */
+       unsigned char   pabit;          /* bit number (big-endian) */
+       unsigned char   invert;         /* if 1, pa bit set => clear feature */
+} ibm_pa_features[] __initdata = {
+       {0, PPC_FEATURE_HAS_MMU,        0, 0, 0},
+       {0, PPC_FEATURE_HAS_FPU,        0, 1, 0},
+       {CPU_FTR_SLB, 0,                0, 2, 0},
+       {CPU_FTR_CTRL, 0,               0, 3, 0},
+       {CPU_FTR_NOEXECUTE, 0,          0, 6, 0},
+       {CPU_FTR_NODSISRALIGN, 0,       1, 1, 1},
+       {CPU_FTR_CI_LARGE_PAGE, 0,      1, 2, 0},
+};
+
+static void __init check_cpu_pa_features(unsigned long node)
+{
+       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;
+
+       /* find descriptor with type == 0 */
+       for (;;) {
+               if (tablelen < 3)
+                       return;
+               len = 2 + pa_ftrs[0];
+               if (tablelen < len)
+                       return;         /* descriptor 0 not found */
+               if (pa_ftrs[1] == 0)
+                       break;
+               tablelen -= len;
+               pa_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])
+                       continue;
+               bit = (pa_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;
+               } else {
+                       cur_cpu_spec->cpu_features &= ~fp->cpu_features;
+                       cur_cpu_spec->cpu_user_features &= ~fp->cpu_user_ftrs;
+               }
+       }
+}
+
 static int __init early_init_dt_scan_cpus(unsigned long node,
                                          const char *uname, int depth,
                                          void *data)
@@ -969,6 +1037,8 @@ static int __init early_init_dt_scan_cpus(unsigned long node,
        }
 #endif /* CONFIG_ALTIVEC */
 
+       check_cpu_pa_features(node);
+
 #ifdef CONFIG_PPC_PSERIES
        if (nthreads > 1)
                cur_cpu_spec->cpu_features |= CPU_FTR_SMT;