X-Git-Url: http://git.monstr.eu/?a=blobdiff_plain;f=drivers%2Fof%2Ffdt.c;h=4546572af24bbf1433460b6a837477041e5286fa;hb=265113f70f3d63ae8b6eb1ce4303d14dbbd71b2d;hp=e0f96e3ef1da0d531947e7974ffb080f27734fa0;hpb=64b4fc45bea6f4faa843d2f97ff51665280efee1;p=linux-2.6-microblaze.git diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index e0f96e3ef1da..4546572af24b 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -8,6 +8,7 @@ #define pr_fmt(fmt) "OF: fdt: " fmt +#include #include #include #include @@ -193,16 +194,12 @@ static void populate_properties(const void *blob, pp->length = len; pp->value = pp + 1; *pprev = pp; - pprev = &pp->next; memcpy(pp->value, ps, len - 1); ((char *)pp->value)[len - 1] = 0; pr_debug("fixed up name for %s -> %s\n", nodename, (char *)pp->value); } } - - if (!dryrun) - *pprev = NULL; } static int populate_node(const void *blob, @@ -479,6 +476,22 @@ void *initial_boot_params __ro_after_init; static u32 of_fdt_crc32; +static int __init early_init_dt_reserve_memory_arch(phys_addr_t base, + phys_addr_t size, bool nomap) +{ + if (nomap) { + /* + * If the memory is already reserved (by another region), we + * should not allow it to be marked nomap. + */ + if (memblock_is_region_reserved(base, size)) + return -EBUSY; + + return memblock_mark_nomap(base, size); + } + return memblock_reserve(base, size); +} + /* * __reserved_mem_reserve_reg() - reserve all memory described in 'reg' property */ @@ -585,6 +598,30 @@ static int __init __fdt_scan_reserved_mem(unsigned long node, const char *uname, return 0; } +/* + * fdt_reserve_elfcorehdr() - reserves memory for elf core header + * + * This function reserves the memory occupied by an elf core header + * described in the device tree. This region contains all the + * information about primary kernel's core image and is used by a dump + * capture kernel to access the system memory on primary kernel. + */ +static void __init fdt_reserve_elfcorehdr(void) +{ + if (!IS_ENABLED(CONFIG_CRASH_DUMP) || !elfcorehdr_size) + return; + + if (memblock_is_region_reserved(elfcorehdr_addr, elfcorehdr_size)) { + pr_warn("elfcorehdr is overlapped\n"); + return; + } + + memblock_reserve(elfcorehdr_addr, elfcorehdr_size); + + pr_info("Reserving %llu KiB of memory at 0x%llx for elfcorehdr\n", + elfcorehdr_size >> 10, elfcorehdr_addr); +} + /** * early_init_fdt_scan_reserved_mem() - create reserved memory regions * @@ -610,6 +647,7 @@ void __init early_init_fdt_scan_reserved_mem(void) of_scan_flat_dt(__fdt_scan_reserved_mem, NULL); fdt_init_reserved_mem(); + fdt_reserve_elfcorehdr(); } /** @@ -858,7 +896,6 @@ const void * __init of_flat_dt_match_machine(const void *default_match, return best_data; } -#ifdef CONFIG_BLK_DEV_INITRD static void __early_init_dt_declare_initrd(unsigned long start, unsigned long end) { @@ -884,6 +921,9 @@ static void __init early_init_dt_check_for_initrd(unsigned long node) int len; const __be32 *prop; + if (!IS_ENABLED(CONFIG_BLK_DEV_INITRD)) + return; + pr_debug("Looking for initrd properties... "); prop = of_get_flat_dt_prop(node, "linux,initrd-start", &len); @@ -902,11 +942,58 @@ static void __init early_init_dt_check_for_initrd(unsigned long node) pr_debug("initrd_start=0x%llx initrd_end=0x%llx\n", start, end); } -#else -static inline void early_init_dt_check_for_initrd(unsigned long node) + +/** + * early_init_dt_check_for_elfcorehdr - Decode elfcorehdr location from flat + * tree + * @node: reference to node containing elfcorehdr location ('chosen') + */ +static void __init early_init_dt_check_for_elfcorehdr(unsigned long node) +{ + const __be32 *prop; + int len; + + if (!IS_ENABLED(CONFIG_CRASH_DUMP)) + return; + + pr_debug("Looking for elfcorehdr property... "); + + prop = of_get_flat_dt_prop(node, "linux,elfcorehdr", &len); + if (!prop || (len < (dt_root_addr_cells + dt_root_size_cells))) + return; + + elfcorehdr_addr = dt_mem_next_cell(dt_root_addr_cells, &prop); + elfcorehdr_size = dt_mem_next_cell(dt_root_size_cells, &prop); + + pr_debug("elfcorehdr_start=0x%llx elfcorehdr_size=0x%llx\n", + elfcorehdr_addr, elfcorehdr_size); +} + +static phys_addr_t cap_mem_addr; +static phys_addr_t cap_mem_size; + +/** + * early_init_dt_check_for_usable_mem_range - Decode usable memory range + * location from flat tree + * @node: reference to node containing usable memory range location ('chosen') + */ +static void __init early_init_dt_check_for_usable_mem_range(unsigned long node) { + const __be32 *prop; + int len; + + pr_debug("Looking for usable-memory-range property... "); + + prop = of_get_flat_dt_prop(node, "linux,usable-memory-range", &len); + if (!prop || (len < (dt_root_addr_cells + dt_root_size_cells))) + return; + + cap_mem_addr = dt_mem_next_cell(dt_root_addr_cells, &prop); + cap_mem_size = dt_mem_next_cell(dt_root_size_cells, &prop); + + pr_debug("cap_mem_start=%pa cap_mem_size=%pa\n", &cap_mem_addr, + &cap_mem_size); } -#endif /* CONFIG_BLK_DEV_INITRD */ #ifdef CONFIG_SERIAL_EARLYCON @@ -1033,7 +1120,7 @@ int __init early_init_dt_scan_memory(unsigned long node, const char *uname, if (!hotpluggable) continue; - if (early_init_dt_mark_hotplug_memory_arch(base, size)) + if (memblock_mark_hotplug(base, size)) pr_warn("failed to mark hotplug range 0x%llx - 0x%llx\n", base, base + size); } @@ -1055,6 +1142,8 @@ int __init early_init_dt_scan_chosen(unsigned long node, const char *uname, return 0; early_init_dt_check_for_initrd(node); + early_init_dt_check_for_elfcorehdr(node); + early_init_dt_check_for_usable_mem_range(node); /* Retrieve command line */ p = of_get_flat_dt_prop(node, "bootargs", &l); @@ -1146,27 +1235,6 @@ void __init __weak early_init_dt_add_memory_arch(u64 base, u64 size) memblock_add(base, size); } -int __init __weak early_init_dt_mark_hotplug_memory_arch(u64 base, u64 size) -{ - return memblock_mark_hotplug(base, size); -} - -int __init __weak early_init_dt_reserve_memory_arch(phys_addr_t base, - phys_addr_t size, bool nomap) -{ - if (nomap) { - /* - * If the memory is already reserved (by another region), we - * should not allow it to be marked nomap. - */ - if (memblock_is_region_reserved(base, size)) - return -EBUSY; - - return memblock_mark_nomap(base, size); - } - return memblock_reserve(base, size); -} - static void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align) { void *ptr = memblock_alloc(size, align); @@ -1199,16 +1267,19 @@ void __init early_init_dt_scan_nodes(void) { int rc = 0; + /* Initialize {size,address}-cells info */ + of_scan_flat_dt(early_init_dt_scan_root, NULL); + /* Retrieve various information from the /chosen node */ rc = of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line); if (!rc) pr_warn("No chosen node found, continuing without\n"); - /* 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); + + /* Handle linux,usable-memory-range property */ + memblock_cap_memory_range(cap_mem_addr, cap_mem_size); } bool __init early_init_dt_scan(void *params)