aboutsummaryrefslogtreecommitdiff
path: root/arch/powerpc/kernel/prom.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/kernel/prom.c')
-rw-r--r--arch/powerpc/kernel/prom.c174
1 files changed, 137 insertions, 37 deletions
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
index 865b9648d0d..1fc732a552d 100644
--- a/arch/powerpc/kernel/prom.c
+++ b/arch/powerpc/kernel/prom.c
@@ -538,35 +538,31 @@ static struct ibm_pa_feature {
{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,59 @@ static void __init check_cpu_pa_features(unsigned long node)
}
}
+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},
+ {"ibm,spurr", 1, CPU_FTR_SPURR, 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 +682,27 @@ static int __init early_init_dt_scan_cpus(unsigned long node,
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
@@ -762,6 +804,56 @@ static unsigned long __init dt_mem_next_cell(int s, cell_t **cellp)
return of_read_ulong(p, s);
}
+#ifdef CONFIG_PPC_PSERIES
+/*
+ * Interpret the ibm,dynamic-memory property in the
+ * /ibm,dynamic-reconfiguration-memory node.
+ * This contains a list of memory blocks along with NUMA affinity
+ * information.
+ */
+static int __init early_init_dt_scan_drconf_memory(unsigned long node)
+{
+ cell_t *dm, *ls;
+ unsigned long l, n;
+ unsigned long base, size, lmb_size, flags;
+
+ ls = (cell_t *)of_get_flat_dt_prop(node, "ibm,lmb-size", &l);
+ if (ls == NULL || l < dt_root_size_cells * sizeof(cell_t))
+ return 0;
+ lmb_size = dt_mem_next_cell(dt_root_size_cells, &ls);
+
+ dm = (cell_t *)of_get_flat_dt_prop(node, "ibm,dynamic-memory", &l);
+ if (dm == NULL || l < sizeof(cell_t))
+ return 0;
+
+ n = *dm++; /* number of entries */
+ if (l < (n * (dt_root_addr_cells + 4) + 1) * sizeof(cell_t))
+ return 0;
+
+ for (; n != 0; --n) {
+ base = dt_mem_next_cell(dt_root_addr_cells, &dm);
+ flags = dm[3];
+ /* skip DRC index, pad, assoc. list index, flags */
+ dm += 4;
+ /* skip this block if the reserved bit is set in flags (0x80)
+ or if the block is not assigned to this partition (0x8) */
+ if ((flags & 0x80) || !(flags & 0x8))
+ continue;
+ size = lmb_size;
+ if (iommu_is_off) {
+ if (base >= 0x80000000ul)
+ continue;
+ if ((base + size) > 0x80000000ul)
+ size = 0x80000000ul - base;
+ }
+ lmb_add(base, size);
+ }
+ lmb_dump_all();
+ return 0;
+}
+#else
+#define early_init_dt_scan_drconf_memory(node) 0
+#endif /* CONFIG_PPC_PSERIES */
static int __init early_init_dt_scan_memory(unsigned long node,
const char *uname, int depth, void *data)
@@ -770,6 +862,11 @@ static int __init early_init_dt_scan_memory(unsigned long node,
cell_t *reg, *endp;
unsigned long l;
+ /* Look for the ibm,dynamic-reconfiguration-memory node */
+ if (depth == 1 &&
+ strcmp(uname, "ibm,dynamic-reconfiguration-memory") == 0)
+ return early_init_dt_scan_drconf_memory(node);
+
/* We are scanning "memory" nodes only */
if (type == NULL) {
/*
@@ -1014,7 +1111,7 @@ EXPORT_SYMBOL(find_all_nodes);
/** Checks if the given "compat" string matches one of the strings in
* the device's "compatible" property
*/
-int device_is_compatible(struct device_node *device, const char *compat)
+int device_is_compatible(const struct device_node *device, const char *compat)
{
const char* cp;
int cplen, l;
@@ -1491,7 +1588,8 @@ static int __init prom_reconfig_setup(void)
__initcall(prom_reconfig_setup);
#endif
-struct property *of_find_property(struct device_node *np, const char *name,
+struct property *of_find_property(const struct device_node *np,
+ const char *name,
int *lenp)
{
struct property *pp;
@@ -1512,7 +1610,8 @@ struct property *of_find_property(struct device_node *np, const char *name,
* Find a property with a given name for a given node
* and return the value.
*/
-const void *get_property(struct device_node *np, const char *name, int *lenp)
+const void *get_property(const struct device_node *np, const char *name,
+ int *lenp)
{
struct property *pp = of_find_property(np,name,lenp);
return pp ? pp->value : NULL;
@@ -1672,6 +1771,7 @@ struct device_node *of_get_cpu_node(int cpu, unsigned int *thread)
}
return NULL;
}
+EXPORT_SYMBOL(of_get_cpu_node);
#ifdef DEBUG
static struct debugfs_blob_wrapper flat_dt_blob;