diff options
Diffstat (limited to 'arch/arm/kernel/devtree.c')
| -rw-r--r-- | arch/arm/kernel/devtree.c | 128 | 
1 files changed, 62 insertions, 66 deletions
diff --git a/arch/arm/kernel/devtree.c b/arch/arm/kernel/devtree.c index f35906b3d8c..11c54de9f8c 100644 --- a/arch/arm/kernel/devtree.c +++ b/arch/arm/kernel/devtree.c @@ -18,6 +18,7 @@  #include <linux/of_fdt.h>  #include <linux/of_irq.h>  #include <linux/of_platform.h> +#include <linux/smp.h>  #include <asm/cputype.h>  #include <asm/setup.h> @@ -26,42 +27,37 @@  #include <asm/mach/arch.h>  #include <asm/mach-types.h> -void __init early_init_dt_add_memory_arch(u64 base, u64 size) -{ -	arm_add_memory(base, size); -} -void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align) -{ -	return alloc_bootmem_align(size, align); -} +#ifdef CONFIG_SMP +extern struct of_cpu_method __cpu_method_of_table[]; -void __init arm_dt_memblock_reserve(void) +static const struct of_cpu_method __cpu_method_of_table_sentinel +	__used __section(__cpu_method_of_table_end); + + +static int __init set_smp_ops_by_method(struct device_node *node)  { -	u64 *reserve_map, base, size; +	const char *method; +	struct of_cpu_method *m = __cpu_method_of_table; -	if (!initial_boot_params) -		return; +	if (of_property_read_string(node, "enable-method", &method)) +		return 0; -	/* Reserve the dtb region */ -	memblock_reserve(virt_to_phys(initial_boot_params), -			 be32_to_cpu(initial_boot_params->totalsize)); +	for (; m->method; m++) +		if (!strcmp(m->method, method)) { +			smp_set_ops(m->ops); +			return 1; +		} -	/* -	 * Process the reserve map.  This will probably overlap the initrd -	 * and dtb locations which are already reserved, but overlaping -	 * doesn't hurt anything -	 */ -	reserve_map = ((void*)initial_boot_params) + -			be32_to_cpu(initial_boot_params->off_mem_rsvmap); -	while (1) { -		base = be64_to_cpup(reserve_map++); -		size = be64_to_cpup(reserve_map++); -		if (!size) -			break; -		memblock_reserve(base, size); -	} +	return 0;  } +#else +static inline int set_smp_ops_by_method(struct device_node *node) +{ +	return 1; +} +#endif +  /*   * arm_dt_init_cpu_maps - Function retrieves cpu nodes from the device tree @@ -79,6 +75,7 @@ void __init arm_dt_init_cpu_maps(void)  	 * read as 0.  	 */  	struct device_node *cpu, *cpus; +	int found_method = 0;  	u32 i, j, cpuidx = 1;  	u32 mpidr = is_smp() ? read_cpuid_mpidr() & MPIDR_HWID_BITMASK : 0; @@ -150,8 +147,18 @@ void __init arm_dt_init_cpu_maps(void)  		}  		tmp_map[i] = hwid; + +		if (!found_method) +			found_method = set_smp_ops_by_method(cpu);  	} +	/* +	 * Fallback to an enable-method in the cpus node if nothing found in +	 * a cpu node. +	 */ +	if (!found_method) +		set_smp_ops_by_method(cpus); +  	if (!bootcpu_valid) {  		pr_warn("DT missing boot CPU MPIDR[23:0], fall back to default cpu_logical_map\n");  		return; @@ -171,7 +178,20 @@ void __init arm_dt_init_cpu_maps(void)  bool arch_match_cpu_phys_id(int cpu, u64 phys_id)  { -	return (phys_id & MPIDR_HWID_BITMASK) == cpu_logical_map(cpu); +	return phys_id == cpu_logical_map(cpu); +} + +static const void * __init arch_get_next_mach(const char *const **match) +{ +	static const struct machine_desc *mdesc = __arch_info_begin; +	const struct machine_desc *m = mdesc; + +	if (m >= __arch_info_end) +		return NULL; + +	mdesc++; +	*match = m->dt_compat; +	return m;  }  /** @@ -183,11 +203,7 @@ bool arch_match_cpu_phys_id(int cpu, u64 phys_id)   */  const struct machine_desc * __init setup_machine_fdt(unsigned int dt_phys)  { -	struct boot_param_header *devtree;  	const struct machine_desc *mdesc, *mdesc_best = NULL; -	unsigned int score, mdesc_score = ~1; -	unsigned long dt_root; -	const char *model;  #ifdef CONFIG_ARCH_MULTIPLATFORM  	DT_MACHINE_START(GENERIC_DT, "Generic DT based system") @@ -196,32 +212,20 @@ const struct machine_desc * __init setup_machine_fdt(unsigned int dt_phys)  	mdesc_best = &__mach_desc_GENERIC_DT;  #endif -	if (!dt_phys) +	if (!dt_phys || !early_init_dt_verify(phys_to_virt(dt_phys)))  		return NULL; -	devtree = phys_to_virt(dt_phys); +	mdesc = of_flat_dt_match_machine(mdesc_best, arch_get_next_mach); -	/* check device tree validity */ -	if (be32_to_cpu(devtree->magic) != OF_DT_HEADER) -		return NULL; - -	/* Search the mdescs for the 'best' compatible value match */ -	initial_boot_params = devtree; -	dt_root = of_get_flat_dt_root(); -	for_each_machine_desc(mdesc) { -		score = of_flat_dt_match(dt_root, mdesc->dt_compat); -		if (score > 0 && score < mdesc_score) { -			mdesc_best = mdesc; -			mdesc_score = score; -		} -	} -	if (!mdesc_best) { +	if (!mdesc) {  		const char *prop; -		long size; +		int size; +		unsigned long dt_root;  		early_print("\nError: unrecognized/unsupported "  			    "device tree compatible list:\n[ "); +		dt_root = of_get_flat_dt_root();  		prop = of_get_flat_dt_prop(dt_root, "compatible", &size);  		while (size > 0) {  			early_print("'%s' ", prop); @@ -233,22 +237,14 @@ const struct machine_desc * __init setup_machine_fdt(unsigned int dt_phys)  		dump_machine_table(); /* does not return */  	} -	model = of_get_flat_dt_prop(dt_root, "model", NULL); -	if (!model) -		model = of_get_flat_dt_prop(dt_root, "compatible", NULL); -	if (!model) -		model = "<unknown>"; -	pr_info("Machine: %s, model: %s\n", mdesc_best->name, model); +	/* We really don't want to do this, but sometimes firmware provides buggy data */ +	if (mdesc->dt_fixup) +		mdesc->dt_fixup(); -	/* Retrieve various information from the /chosen node */ -	of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line); -	/* Initialize {size,address}-cells info */ -	of_scan_flat_dt(early_init_dt_scan_root, NULL); -	/* Setup memory, calling early_init_dt_add_memory_arch */ -	of_scan_flat_dt(early_init_dt_scan_memory, NULL); +	early_init_dt_scan_nodes();  	/* Change machine number to match the mdesc we're using */ -	__machine_arch_type = mdesc_best->nr; +	__machine_arch_type = mdesc->nr; -	return mdesc_best; +	return mdesc;  }  | 
