Skip to content

Commit 26bcd8b

Browse files
committed
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 1c2f87c ("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
2 parents acba648 + 5a12a59 commit 26bcd8b

File tree

5 files changed

+86
-2
lines changed

5 files changed

+86
-2
lines changed

arch/arm/include/asm/mach/arch.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ struct machine_desc {
5050
struct smp_operations *smp; /* SMP operations */
5151
bool (*smp_init)(void);
5252
void (*fixup)(struct tag *, char **);
53+
void (*dt_fixup)(void);
5354
void (*init_meminfo)(void);
5455
void (*reserve)(void);/* reserve mem blocks */
5556
void (*map_io)(void);/* IO mapping function */

arch/arm/kernel/devtree.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ const struct machine_desc * __init setup_machine_fdt(unsigned int dt_phys)
212212
mdesc_best = &__mach_desc_GENERIC_DT;
213213
#endif
214214

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)))
216216
return NULL;
217217

218218
mdesc = of_flat_dt_match_machine(mdesc_best, arch_get_next_mach);
@@ -237,6 +237,12 @@ const struct machine_desc * __init setup_machine_fdt(unsigned int dt_phys)
237237
dump_machine_table(); /* does not return */
238238
}
239239

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();
245+
240246
/* Change machine number to match the mdesc we're using */
241247
__machine_arch_type = mdesc->nr;
242248

arch/arm/mach-exynos/exynos.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,15 @@ static void __init exynos_reserve(void)
335335
#endif
336336
}
337337

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+
338347
DT_MACHINE_START(EXYNOS_DT, "SAMSUNG EXYNOS (Flattened Device Tree)")
339348
/* Maintainer: Thomas Abraham <[email protected]> */
340349
/* Maintainer: Kukjin Kim <[email protected]> */
@@ -348,4 +357,5 @@ DT_MACHINE_START(EXYNOS_DT, "SAMSUNG EXYNOS (Flattened Device Tree)")
348357
.dt_compat = exynos_dt_compat,
349358
.restart = exynos_restart,
350359
.reserve = exynos_reserve,
360+
.dt_fixup = exynos_dt_fixup,
351361
MACHINE_END

drivers/of/fdt.c

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,54 @@
2626
#include <asm/setup.h> /* for COMMAND_LINE_SIZE */
2727
#include <asm/page.h>
2828

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+
2977
/**
3078
* of_fdt_is_compatible - Return true if given node from the given blob has
3179
* compat in its compatible list
@@ -937,7 +985,7 @@ int __init __weak early_init_dt_reserve_memory_arch(phys_addr_t base,
937985
}
938986
#endif
939987

940-
bool __init early_init_dt_scan(void *params)
988+
bool __init early_init_dt_verify(void *params)
941989
{
942990
if (!params)
943991
return false;
@@ -951,6 +999,12 @@ bool __init early_init_dt_scan(void *params)
951999
return false;
9521000
}
9531001

1002+
return true;
1003+
}
1004+
1005+
1006+
void __init early_init_dt_scan_nodes(void)
1007+
{
9541008
/* Retrieve various information from the /chosen node */
9551009
of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line);
9561010

@@ -959,7 +1013,17 @@ bool __init early_init_dt_scan(void *params)
9591013

9601014
/* Setup memory, calling early_init_dt_add_memory_arch */
9611015
of_scan_flat_dt(early_init_dt_scan_memory, NULL);
1016+
}
1017+
1018+
bool __init early_init_dt_scan(void *params)
1019+
{
1020+
bool status;
1021+
1022+
status = early_init_dt_verify(params);
1023+
if (!status)
1024+
return false;
9621025

1026+
early_init_dt_scan_nodes();
9631027
return true;
9641028
}
9651029

include/linux/of_fdt.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ extern int early_init_dt_scan_root(unsigned long node, const char *uname,
7373
int depth, void *data);
7474

7575
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);
7678

7779
extern const char *of_flat_dt_get_machine_name(void);
7880
extern const void *of_flat_dt_match_machine(const void *default_match,
@@ -84,6 +86,7 @@ extern void unflatten_and_copy_device_tree(void);
8486
extern void early_init_devtree(void *);
8587
extern void early_get_first_memblock_info(void *, phys_addr_t *);
8688
extern u64 fdt_translate_address(const void *blob, int node_offset);
89+
extern void of_fdt_limit_memory(int limit);
8790
#else /* CONFIG_OF_FLATTREE */
8891
static inline void early_init_fdt_scan_reserved_mem(void) {}
8992
static inline const char *of_flat_dt_get_machine_name(void) { return NULL; }

0 commit comments

Comments
 (0)