[PATCH -next v3 1/2] riscv: kdump: Implement crashkernel=X,[high,low]

Guo Ren guoren at kernel.org
Fri Apr 7 02:06:24 PDT 2023


On Thu, Apr 6, 2023 at 10:06 PM Chen Jiahao <chenjiahao16 at huawei.com> wrote:
>
> On riscv, the current crash kernel allocation logic is trying to
> allocate within 32bit addressible memory region by default, if
> failed, try to allocate without 4G restriction.
>
> In need of saving DMA zone memory while allocating a relatively large
> crash kernel region, allocating the reserved memory top down in
> high memory, without overlapping the DMA zone, is a mature solution.
> Here introduce the parameter option crashkernel=X,[high,low].
>
> One can reserve the crash kernel from high memory above DMA zone range
> by explicitly passing "crashkernel=X,high"; or reserve a memory range
> below 4G with "crashkernel=X,low".
Asked-by: Guo Ren <guoren at kernel.org>

>
> Signed-off-by: Chen Jiahao <chenjiahao16 at huawei.com>
> ---
>  arch/riscv/kernel/setup.c |  5 +++
>  arch/riscv/mm/init.c      | 74 ++++++++++++++++++++++++++++++++++++---
>  2 files changed, 74 insertions(+), 5 deletions(-)
>
> diff --git a/arch/riscv/kernel/setup.c b/arch/riscv/kernel/setup.c
> index 5d3184cbf518..ea84e5047c23 100644
> --- a/arch/riscv/kernel/setup.c
> +++ b/arch/riscv/kernel/setup.c
> @@ -176,6 +176,11 @@ static void __init init_resources(void)
>                 if (ret < 0)
>                         goto error;
>         }
> +       if (crashk_low_res.start != crashk_low_res.end) {
> +               ret = add_resource(&iomem_resource, &crashk_low_res);
> +               if (ret < 0)
> +                       goto error;
> +       }
>  #endif
>
>  #ifdef CONFIG_CRASH_DUMP
> diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
> index 478d6763a01a..b5b457193423 100644
> --- a/arch/riscv/mm/init.c
> +++ b/arch/riscv/mm/init.c
> @@ -1152,6 +1152,28 @@ static inline void setup_vm_final(void)
>  }
>  #endif /* CONFIG_MMU */
>
> +/* Reserve 128M low memory by default for swiotlb buffer */
> +#define DEFAULT_CRASH_KERNEL_LOW_SIZE  (128UL << 20)
> +
> +static int __init reserve_crashkernel_low(unsigned long long low_size)
> +{
> +       unsigned long long low_base;
> +
> +       low_base = memblock_phys_alloc_range(low_size, PMD_SIZE, 0, dma32_phys_limit);
> +       if (!low_base) {
> +               pr_err("cannot allocate crashkernel low memory (size:0x%llx).\n", low_size);
> +               return -ENOMEM;
> +       }
> +
> +       pr_info("crashkernel low memory reserved: 0x%016llx - 0x%016llx (%lld MB)\n",
> +               low_base, low_base + low_size, low_size >> 20);
> +
> +       crashk_low_res.start = low_base;
> +       crashk_low_res.end = low_base + low_size - 1;
> +
> +       return 0;
> +}
> +
>  /*
>   * reserve_crashkernel() - reserves memory for crash kernel
>   *
> @@ -1163,8 +1185,12 @@ static void __init reserve_crashkernel(void)
>  {
>         unsigned long long crash_base = 0;
>         unsigned long long crash_size = 0;
> +       unsigned long long crash_low_size = 0;
>         unsigned long search_start = memblock_start_of_DRAM();
>         unsigned long search_end = memblock_end_of_DRAM();
> +       unsigned long search_low_max = (unsigned long)dma32_phys_limit;
> +       char *cmdline = boot_command_line;
> +       bool fixed_base = false;
>
>         int ret = 0;
>
> @@ -1180,14 +1206,37 @@ static void __init reserve_crashkernel(void)
>                 return;
>         }
>
> -       ret = parse_crashkernel(boot_command_line, memblock_phys_mem_size(),
> +       ret = parse_crashkernel(cmdline, memblock_phys_mem_size(),
>                                 &crash_size, &crash_base);
> -       if (ret || !crash_size)
> +       if (ret == -ENOENT) {
> +               /*
> +                * crashkernel=X,[high,low] can be specified or not, but
> +                * invalid value is not allowed.
> +                */
> +               ret = parse_crashkernel_high(cmdline, 0, &crash_size, &crash_base);
> +               if (ret || !crash_size)
> +                       return;
> +
> +               /*
> +                * crashkernel=Y,low is valid only when crashkernel=X,high
> +                * is passed and high memory is reserved successful.
> +                */
> +               ret = parse_crashkernel_low(cmdline, 0, &crash_low_size, &crash_base);
> +               if (ret == -ENOENT)
> +                       crash_low_size = DEFAULT_CRASH_KERNEL_LOW_SIZE;
> +               else if (ret)
> +                       return;
> +
> +               search_start = search_low_max;
> +       } else if (ret || !crash_size) {
> +               /* Invalid argument value specified */
>                 return;
> +       }
>
>         crash_size = PAGE_ALIGN(crash_size);
>
>         if (crash_base) {
> +               fixed_base = true;
>                 search_start = crash_base;
>                 search_end = crash_base + crash_size;
>         }
> @@ -1201,16 +1250,31 @@ static void __init reserve_crashkernel(void)
>          */
>         crash_base = memblock_phys_alloc_range(crash_size, PMD_SIZE,
>                                                search_start,
> -                                              min(search_end, (unsigned long) SZ_4G));
> +                                              min(search_end, search_low_max));
>         if (crash_base == 0) {
> -               /* Try again without restricting region to 32bit addressible memory */
> +               if (fixed_base) {
> +                       pr_warn("crashkernel: allocating failed with given size at offset\n");
> +                       return;
> +               }
> +
> +               /* Try again above the region of 32bit addressible memory */
>                 crash_base = memblock_phys_alloc_range(crash_size, PMD_SIZE,
> -                                               search_start, search_end);
> +                                                      max(search_start, search_low_max),
> +                                                      search_end);
>                 if (crash_base == 0) {
>                         pr_warn("crashkernel: couldn't allocate %lldKB\n",
>                                 crash_size >> 10);
>                         return;
>                 }
> +
> +               if (!crash_low_size)
> +                       crash_low_size = DEFAULT_CRASH_KERNEL_LOW_SIZE;
> +       }
> +
> +       if ((crash_base > dma32_phys_limit - crash_low_size) &&
> +           crash_low_size && reserve_crashkernel_low(crash_low_size)) {
> +               memblock_phys_free(crash_base, crash_size);
> +               return;
>         }
>
>         pr_info("crashkernel: reserved 0x%016llx - 0x%016llx (%lld MB)\n",
> --
> 2.31.1
>


-- 
Best Regards
 Guo Ren



More information about the kexec mailing list