reserve_crashkernel_cma() reserves CMA ranges for the crash kernel. If allocating the requested size fails, try to reserve in smaller pieces. Store the reserved ranges in the crashk_cma_ranges array and the number of ranges in crashk_cma_cnt. Signed-off-by: Jiri Bohac <jbohac@xxxxxxx> --- include/linux/crash_core.h | 9 +++++++ kernel/crash_core.c | 52 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/include/linux/crash_core.h b/include/linux/crash_core.h index f1edefcf7377..5afe3866d35a 100644 --- a/include/linux/crash_core.h +++ b/include/linux/crash_core.h @@ -14,6 +14,13 @@ extern struct resource crashk_res; extern struct resource crashk_low_res; +extern struct range crashk_cma_ranges[]; +#ifdef CONFIG_CMA +extern int crashk_cma_cnt; +#else +#define crashk_cma_cnt 0 +#endif + #define CRASH_CORE_NOTE_NAME "CORE" #define CRASH_CORE_NOTE_HEAD_BYTES ALIGN(sizeof(struct elf_note), 4) #define CRASH_CORE_NOTE_NAME_BYTES ALIGN(sizeof(CRASH_CORE_NOTE_NAME), 4) @@ -98,6 +105,8 @@ int __init parse_crashkernel(char *cmdline, unsigned long long system_ram, unsigned long long *low_size, unsigned long long *cma_size, bool *high); +void __init reserve_crashkernel_cma(unsigned long long cma_size); + #ifdef CONFIG_ARCH_HAS_GENERIC_CRASHKERNEL_RESERVATION #ifndef DEFAULT_CRASH_KERNEL_LOW_SIZE #define DEFAULT_CRASH_KERNEL_LOW_SIZE (128UL << 20) diff --git a/kernel/crash_core.c b/kernel/crash_core.c index 1e952d2e451b..d71ecd59f16b 100644 --- a/kernel/crash_core.c +++ b/kernel/crash_core.c @@ -15,6 +15,7 @@ #include <linux/memblock.h> #include <linux/kexec.h> #include <linux/kmemleak.h> +#include <linux/cma.h> #include <asm/page.h> #include <asm/sections.h> @@ -475,6 +476,57 @@ void __init reserve_crashkernel_generic(char *cmdline, } #endif +#ifdef CONFIG_CMA +#define CRASHKERNEL_CMA_RANGES_MAX 4 + +struct range crashk_cma_ranges[CRASHKERNEL_CMA_RANGES_MAX]; +int crashk_cma_cnt = 0; + +void __init reserve_crashkernel_cma(unsigned long long cma_size) +{ + unsigned long long request_size = roundup(cma_size, PAGE_SIZE); + unsigned long long reserved_size = 0; + + while (cma_size > reserved_size && + crashk_cma_cnt < CRASHKERNEL_CMA_RANGES_MAX) { + + struct cma *res; + + if (cma_declare_contiguous(0, request_size, 0, 0, 0, false, + "crashkernel", &res)) { + /* reservation failed, try half-sized blocks */ + if (request_size <= PAGE_SIZE) + break; + + request_size = roundup(request_size / 2, PAGE_SIZE); + continue; + } + + crashk_cma_ranges[crashk_cma_cnt].start = cma_get_base(res); + crashk_cma_ranges[crashk_cma_cnt].end = + crashk_cma_ranges[crashk_cma_cnt].start + + cma_get_size(res) - 1; + ++crashk_cma_cnt; + reserved_size += request_size; + } + + if (cma_size > reserved_size) + pr_warn("crashkernel CMA reservation failed: %lld MB requested, %lld MB reserved in %d ranges\n", + cma_size >> 20, reserved_size >> 20, crashk_cma_cnt); + else + pr_info("crashkernel CMA reserved: %lld MB in %d ranges\n", + reserved_size >> 20, crashk_cma_cnt); +} + +#else /* CONFIG_CMA */ +struct range crashk_cma_ranges[0]; +void __init reserve_crashkernel_cma(unsigned long long cma_size) +{ + if (cma_size) + pr_warn("crashkernel CMA reservation failed: CMA disabled\n"); +} +#endif + int crash_prepare_elf64_headers(struct crash_mem *mem, int need_kernel_map, void **addr, unsigned long *sz) { -- Jiri Bohac <jbohac@xxxxxxx> SUSE Labs, Prague, Czechia _______________________________________________ kexec mailing list kexec@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/kexec