Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'devicetree-for-linus' of git://git.secretlab.ca/git/linux

Pull Exynos platform DT fix from Grant Likely:
"Device tree Exynos bug fix for v3.16-rc7

This bug fix has been brewing for a while. I hate sending it to you
so late, but I only got confirmation that it solves the problem this
past weekend. The diff looks big for a bug fix, but the majority of
it is only executed in the Exynos quirk case. Unfortunately it
required splitting early_init_dt_scan() in two and adding quirk
handling in the middle of it on ARM.

Exynos has buggy firmware that puts bad data into the memory node.
Commit 1c2f87c22566 ("ARM: Get rid of meminfo") exposed the bug by
dropping the artificial upper bound on the number of memory banks that
can be added. Exynos fails to boot after that commit. This branch
fixes it by splitting the early DT parse function and inserting a
fixup hook. Exynos uses the hook to correct the DT before parsing
memory regions"

* tag 'devicetree-for-linus' of git://git.secretlab.ca/git/linux:
arm: Add devicetree fixup machine function
of: Add memory limiting function for flattened devicetrees
of: Split early_init_dt_scan into two parts

+86 -2
+1
arch/arm/include/asm/mach/arch.h
··· 50 50 struct smp_operations *smp; /* SMP operations */ 51 51 bool (*smp_init)(void); 52 52 void (*fixup)(struct tag *, char **); 53 + void (*dt_fixup)(void); 53 54 void (*init_meminfo)(void); 54 55 void (*reserve)(void);/* reserve mem blocks */ 55 56 void (*map_io)(void);/* IO mapping function */
+7 -1
arch/arm/kernel/devtree.c
··· 212 212 mdesc_best = &__mach_desc_GENERIC_DT; 213 213 #endif 214 214 215 - if (!dt_phys || !early_init_dt_scan(phys_to_virt(dt_phys))) 215 + if (!dt_phys || !early_init_dt_verify(phys_to_virt(dt_phys))) 216 216 return NULL; 217 217 218 218 mdesc = of_flat_dt_match_machine(mdesc_best, arch_get_next_mach); ··· 236 236 237 237 dump_machine_table(); /* does not return */ 238 238 } 239 + 240 + /* We really don't want to do this, but sometimes firmware provides buggy data */ 241 + if (mdesc->dt_fixup) 242 + mdesc->dt_fixup(); 243 + 244 + early_init_dt_scan_nodes(); 239 245 240 246 /* Change machine number to match the mdesc we're using */ 241 247 __machine_arch_type = mdesc->nr;
+10
arch/arm/mach-exynos/exynos.c
··· 335 335 #endif 336 336 } 337 337 338 + static void __init exynos_dt_fixup(void) 339 + { 340 + /* 341 + * Some versions of uboot pass garbage entries in the memory node, 342 + * use the old CONFIG_ARM_NR_BANKS 343 + */ 344 + of_fdt_limit_memory(8); 345 + } 346 + 338 347 DT_MACHINE_START(EXYNOS_DT, "SAMSUNG EXYNOS (Flattened Device Tree)") 339 348 /* Maintainer: Thomas Abraham <thomas.abraham@linaro.org> */ 340 349 /* Maintainer: Kukjin Kim <kgene.kim@samsung.com> */ ··· 357 348 .dt_compat = exynos_dt_compat, 358 349 .restart = exynos_restart, 359 350 .reserve = exynos_reserve, 351 + .dt_fixup = exynos_dt_fixup, 360 352 MACHINE_END
+65 -1
drivers/of/fdt.c
··· 26 26 #include <asm/setup.h> /* for COMMAND_LINE_SIZE */ 27 27 #include <asm/page.h> 28 28 29 + /* 30 + * of_fdt_limit_memory - limit the number of regions in the /memory node 31 + * @limit: maximum entries 32 + * 33 + * Adjust the flattened device tree to have at most 'limit' number of 34 + * memory entries in the /memory node. This function may be called 35 + * any time after initial_boot_param is set. 36 + */ 37 + void of_fdt_limit_memory(int limit) 38 + { 39 + int memory; 40 + int len; 41 + const void *val; 42 + int nr_address_cells = OF_ROOT_NODE_ADDR_CELLS_DEFAULT; 43 + int nr_size_cells = OF_ROOT_NODE_SIZE_CELLS_DEFAULT; 44 + const uint32_t *addr_prop; 45 + const uint32_t *size_prop; 46 + int root_offset; 47 + int cell_size; 48 + 49 + root_offset = fdt_path_offset(initial_boot_params, "/"); 50 + if (root_offset < 0) 51 + return; 52 + 53 + addr_prop = fdt_getprop(initial_boot_params, root_offset, 54 + "#address-cells", NULL); 55 + if (addr_prop) 56 + nr_address_cells = fdt32_to_cpu(*addr_prop); 57 + 58 + size_prop = fdt_getprop(initial_boot_params, root_offset, 59 + "#size-cells", NULL); 60 + if (size_prop) 61 + nr_size_cells = fdt32_to_cpu(*size_prop); 62 + 63 + cell_size = sizeof(uint32_t)*(nr_address_cells + nr_size_cells); 64 + 65 + memory = fdt_path_offset(initial_boot_params, "/memory"); 66 + if (memory > 0) { 67 + val = fdt_getprop(initial_boot_params, memory, "reg", &len); 68 + if (len > limit*cell_size) { 69 + len = limit*cell_size; 70 + pr_debug("Limiting number of entries to %d\n", limit); 71 + fdt_setprop(initial_boot_params, memory, "reg", val, 72 + len); 73 + } 74 + } 75 + } 76 + 29 77 /** 30 78 * of_fdt_is_compatible - Return true if given node from the given blob has 31 79 * compat in its compatible list ··· 985 937 } 986 938 #endif 987 939 988 - bool __init early_init_dt_scan(void *params) 940 + bool __init early_init_dt_verify(void *params) 989 941 { 990 942 if (!params) 991 943 return false; ··· 999 951 return false; 1000 952 } 1001 953 954 + return true; 955 + } 956 + 957 + 958 + void __init early_init_dt_scan_nodes(void) 959 + { 1002 960 /* Retrieve various information from the /chosen node */ 1003 961 of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line); 1004 962 ··· 1013 959 1014 960 /* Setup memory, calling early_init_dt_add_memory_arch */ 1015 961 of_scan_flat_dt(early_init_dt_scan_memory, NULL); 962 + } 1016 963 964 + bool __init early_init_dt_scan(void *params) 965 + { 966 + bool status; 967 + 968 + status = early_init_dt_verify(params); 969 + if (!status) 970 + return false; 971 + 972 + early_init_dt_scan_nodes(); 1017 973 return true; 1018 974 } 1019 975
+3
include/linux/of_fdt.h
··· 73 73 int depth, void *data); 74 74 75 75 extern bool early_init_dt_scan(void *params); 76 + extern bool early_init_dt_verify(void *params); 77 + extern void early_init_dt_scan_nodes(void); 76 78 77 79 extern const char *of_flat_dt_get_machine_name(void); 78 80 extern const void *of_flat_dt_match_machine(const void *default_match, ··· 86 84 extern void early_init_devtree(void *); 87 85 extern void early_get_first_memblock_info(void *, phys_addr_t *); 88 86 extern u64 fdt_translate_address(const void *blob, int node_offset); 87 + extern void of_fdt_limit_memory(int limit); 89 88 #else /* CONFIG_OF_FLATTREE */ 90 89 static inline void early_init_fdt_scan_reserved_mem(void) {} 91 90 static inline const char *of_flat_dt_get_machine_name(void) { return NULL; }