Device tree Exynos bug fix for v3.16-rc7
Exynos has buggy firmware that puts bad data into the memory node. Commit1c2f87c2
(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. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJT2HI1AAoJEMWQL496c2LNvfAP/ifY6foyrO2MHGxlGdghL3Xe fHY+MxoywBqWwLuXjfSh0rIt/5KE80JvtTjnssSOHOZokOPa/O3N39SrQPaLRqW8 1XC5A/Qocokeii69iXgXn0aQChBhyrRW708q9iU43ucKwcmWNvrzgdq838XdVB3q BGHeV9ADn57PHAitsOrDCJei//jgs94NXDKPmCwrTn62aiedeiiMAWYUfsPXFtsn gloL8wT8gcD8ojaSvKWpGJtUbkFBNe1DVQgsmIfG0hNUuolpsbNZo688OoWJUCaj 0qQ2LqHD2djDMqxxj0xFxOx7GoQPZjAG9NlLkca3QG5dc1S+Bf//g11uxRAHQ2qD 3l24i825fp4kGL1NUfR+OK4PIqGwBbEnXoIgrWnVjQxw/adMlH3iWFfuZqe/fBIq 4CTe9buc+JGCdJUAp+DS3YRYtFPdlovgaJjCAAwKWEd4GpjLEKrGGL/dAkhyRP/j 77byHy8XgSB5moh7qiR0u1M3lyRmU54f5EdDimPGaMUJ2PSzSxuYZk41hRRrstVn JCzDmblvTF4wai3t4Z+laUP0dAym/gwX/87UiRsO+hyXKGiVCq9AmDkueL2xLUuV c8rqjXLcVZ5qicLP2uCtWpz96WVzTCa3CzcMufT7t6cErMLueSSARrxq2RrETsFo SpeBf3cc90Edv8LP7V9W =lmyQ -----END PGP SIGNATURE----- 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. Commit1c2f87c225
("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
This commit is contained in:
Коммит
26bcd8b725
|
@ -50,6 +50,7 @@ struct machine_desc {
|
|||
struct smp_operations *smp; /* SMP operations */
|
||||
bool (*smp_init)(void);
|
||||
void (*fixup)(struct tag *, char **);
|
||||
void (*dt_fixup)(void);
|
||||
void (*init_meminfo)(void);
|
||||
void (*reserve)(void);/* reserve mem blocks */
|
||||
void (*map_io)(void);/* IO mapping function */
|
||||
|
|
|
@ -212,7 +212,7 @@ const struct machine_desc * __init setup_machine_fdt(unsigned int dt_phys)
|
|||
mdesc_best = &__mach_desc_GENERIC_DT;
|
||||
#endif
|
||||
|
||||
if (!dt_phys || !early_init_dt_scan(phys_to_virt(dt_phys)))
|
||||
if (!dt_phys || !early_init_dt_verify(phys_to_virt(dt_phys)))
|
||||
return NULL;
|
||||
|
||||
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)
|
|||
dump_machine_table(); /* does not return */
|
||||
}
|
||||
|
||||
/* We really don't want to do this, but sometimes firmware provides buggy data */
|
||||
if (mdesc->dt_fixup)
|
||||
mdesc->dt_fixup();
|
||||
|
||||
early_init_dt_scan_nodes();
|
||||
|
||||
/* Change machine number to match the mdesc we're using */
|
||||
__machine_arch_type = mdesc->nr;
|
||||
|
||||
|
|
|
@ -335,6 +335,15 @@ static void __init exynos_reserve(void)
|
|||
#endif
|
||||
}
|
||||
|
||||
static void __init exynos_dt_fixup(void)
|
||||
{
|
||||
/*
|
||||
* Some versions of uboot pass garbage entries in the memory node,
|
||||
* use the old CONFIG_ARM_NR_BANKS
|
||||
*/
|
||||
of_fdt_limit_memory(8);
|
||||
}
|
||||
|
||||
DT_MACHINE_START(EXYNOS_DT, "SAMSUNG EXYNOS (Flattened Device Tree)")
|
||||
/* Maintainer: Thomas Abraham <thomas.abraham@linaro.org> */
|
||||
/* Maintainer: Kukjin Kim <kgene.kim@samsung.com> */
|
||||
|
@ -348,4 +357,5 @@ DT_MACHINE_START(EXYNOS_DT, "SAMSUNG EXYNOS (Flattened Device Tree)")
|
|||
.dt_compat = exynos_dt_compat,
|
||||
.restart = exynos_restart,
|
||||
.reserve = exynos_reserve,
|
||||
.dt_fixup = exynos_dt_fixup,
|
||||
MACHINE_END
|
||||
|
|
|
@ -26,6 +26,54 @@
|
|||
#include <asm/setup.h> /* for COMMAND_LINE_SIZE */
|
||||
#include <asm/page.h>
|
||||
|
||||
/*
|
||||
* of_fdt_limit_memory - limit the number of regions in the /memory node
|
||||
* @limit: maximum entries
|
||||
*
|
||||
* Adjust the flattened device tree to have at most 'limit' number of
|
||||
* memory entries in the /memory node. This function may be called
|
||||
* any time after initial_boot_param is set.
|
||||
*/
|
||||
void of_fdt_limit_memory(int limit)
|
||||
{
|
||||
int memory;
|
||||
int len;
|
||||
const void *val;
|
||||
int nr_address_cells = OF_ROOT_NODE_ADDR_CELLS_DEFAULT;
|
||||
int nr_size_cells = OF_ROOT_NODE_SIZE_CELLS_DEFAULT;
|
||||
const uint32_t *addr_prop;
|
||||
const uint32_t *size_prop;
|
||||
int root_offset;
|
||||
int cell_size;
|
||||
|
||||
root_offset = fdt_path_offset(initial_boot_params, "/");
|
||||
if (root_offset < 0)
|
||||
return;
|
||||
|
||||
addr_prop = fdt_getprop(initial_boot_params, root_offset,
|
||||
"#address-cells", NULL);
|
||||
if (addr_prop)
|
||||
nr_address_cells = fdt32_to_cpu(*addr_prop);
|
||||
|
||||
size_prop = fdt_getprop(initial_boot_params, root_offset,
|
||||
"#size-cells", NULL);
|
||||
if (size_prop)
|
||||
nr_size_cells = fdt32_to_cpu(*size_prop);
|
||||
|
||||
cell_size = sizeof(uint32_t)*(nr_address_cells + nr_size_cells);
|
||||
|
||||
memory = fdt_path_offset(initial_boot_params, "/memory");
|
||||
if (memory > 0) {
|
||||
val = fdt_getprop(initial_boot_params, memory, "reg", &len);
|
||||
if (len > limit*cell_size) {
|
||||
len = limit*cell_size;
|
||||
pr_debug("Limiting number of entries to %d\n", limit);
|
||||
fdt_setprop(initial_boot_params, memory, "reg", val,
|
||||
len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* of_fdt_is_compatible - Return true if given node from the given blob has
|
||||
* compat in its compatible list
|
||||
|
@ -937,7 +985,7 @@ int __init __weak early_init_dt_reserve_memory_arch(phys_addr_t base,
|
|||
}
|
||||
#endif
|
||||
|
||||
bool __init early_init_dt_scan(void *params)
|
||||
bool __init early_init_dt_verify(void *params)
|
||||
{
|
||||
if (!params)
|
||||
return false;
|
||||
|
@ -951,6 +999,12 @@ bool __init early_init_dt_scan(void *params)
|
|||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void __init early_init_dt_scan_nodes(void)
|
||||
{
|
||||
/* Retrieve various information from the /chosen node */
|
||||
of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line);
|
||||
|
||||
|
@ -959,7 +1013,17 @@ bool __init early_init_dt_scan(void *params)
|
|||
|
||||
/* Setup memory, calling early_init_dt_add_memory_arch */
|
||||
of_scan_flat_dt(early_init_dt_scan_memory, NULL);
|
||||
}
|
||||
|
||||
bool __init early_init_dt_scan(void *params)
|
||||
{
|
||||
bool status;
|
||||
|
||||
status = early_init_dt_verify(params);
|
||||
if (!status)
|
||||
return false;
|
||||
|
||||
early_init_dt_scan_nodes();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -73,6 +73,8 @@ extern int early_init_dt_scan_root(unsigned long node, const char *uname,
|
|||
int depth, void *data);
|
||||
|
||||
extern bool early_init_dt_scan(void *params);
|
||||
extern bool early_init_dt_verify(void *params);
|
||||
extern void early_init_dt_scan_nodes(void);
|
||||
|
||||
extern const char *of_flat_dt_get_machine_name(void);
|
||||
extern const void *of_flat_dt_match_machine(const void *default_match,
|
||||
|
@ -84,6 +86,7 @@ extern void unflatten_and_copy_device_tree(void);
|
|||
extern void early_init_devtree(void *);
|
||||
extern void early_get_first_memblock_info(void *, phys_addr_t *);
|
||||
extern u64 fdt_translate_address(const void *blob, int node_offset);
|
||||
extern void of_fdt_limit_memory(int limit);
|
||||
#else /* CONFIG_OF_FLATTREE */
|
||||
static inline void early_init_fdt_scan_reserved_mem(void) {}
|
||||
static inline const char *of_flat_dt_get_machine_name(void) { return NULL; }
|
||||
|
|
Загрузка…
Ссылка в новой задаче