[PATCH 1/2] powerpc/fadump: use static allocation for reserved memory ranges
Mahesh J Salgaonkar
mahesh at linux.ibm.com
Mon Apr 20 15:10:16 AEST 2020
On 2020-03-11 01:57:00 Wed, Hari Bathini wrote:
> At times, memory ranges have to be looked up during early boot, when
> kernel couldn't be initialized for dynamic memory allocation. In fact,
> reserved-ranges look up is needed during FADump memory reservation.
> Without accounting for reserved-ranges in reserving memory for FADump,
> MPIPL boot fails with memory corruption issues. So, extend memory
> ranges handling to support static allocation and populate reserved
> memory ranges during early boot.
>
> Fixes: dda9dbfeeb7a ("powerpc/fadump: consider reserved ranges while releasing memory")
> Cc: stable at vger.kernel.org # v5.4+
> Signed-off-by: Hari Bathini <hbathini at linux.ibm.com>
Reviewed-by: Mahesh Salgaonkar <mahesh at linux.ibm.com>
Thanks,
-Mahesh.
> ---
> arch/powerpc/include/asm/fadump-internal.h | 4 +
> arch/powerpc/kernel/fadump.c | 77 ++++++++++++++++------------
> 2 files changed, 48 insertions(+), 33 deletions(-)
>
> diff --git a/arch/powerpc/include/asm/fadump-internal.h b/arch/powerpc/include/asm/fadump-internal.h
> index c814a2b..8d61c8f 100644
> --- a/arch/powerpc/include/asm/fadump-internal.h
> +++ b/arch/powerpc/include/asm/fadump-internal.h
> @@ -64,12 +64,14 @@ struct fadump_memory_range {
> };
>
> /* fadump memory ranges info */
> +#define RNG_NAME_SZ 16
> struct fadump_mrange_info {
> - char name[16];
> + char name[RNG_NAME_SZ];
> struct fadump_memory_range *mem_ranges;
> u32 mem_ranges_sz;
> u32 mem_range_cnt;
> u32 max_mem_ranges;
> + bool is_static;
> };
>
> /* Platform specific callback functions */
> diff --git a/arch/powerpc/kernel/fadump.c b/arch/powerpc/kernel/fadump.c
> index ff0114a..7fcf4a8f 100644
> --- a/arch/powerpc/kernel/fadump.c
> +++ b/arch/powerpc/kernel/fadump.c
> @@ -38,8 +38,17 @@ static void __init fadump_reserve_crash_area(u64 base);
>
> #ifndef CONFIG_PRESERVE_FA_DUMP
> static DEFINE_MUTEX(fadump_mutex);
> -struct fadump_mrange_info crash_mrange_info = { "crash", NULL, 0, 0, 0 };
> -struct fadump_mrange_info reserved_mrange_info = { "reserved", NULL, 0, 0, 0 };
> +struct fadump_mrange_info crash_mrange_info = { "crash", NULL, 0, 0, 0, false };
> +
> +#define RESERVED_RNGS_SZ 16384 /* 16K - 128 entries */
> +#define RESERVED_RNGS_CNT (RESERVED_RNGS_SZ / \
> + sizeof(struct fadump_memory_range))
> +static struct fadump_memory_range rngs[RESERVED_RNGS_CNT];
> +struct fadump_mrange_info reserved_mrange_info = { "reserved", rngs,
> + RESERVED_RNGS_SZ, 0,
> + RESERVED_RNGS_CNT, true };
> +
> +static void __init early_init_dt_scan_reserved_ranges(unsigned long node);
>
> #ifdef CONFIG_CMA
> static struct cma *fadump_cma;
> @@ -108,6 +117,11 @@ static int __init fadump_cma_init(void) { return 1; }
> int __init early_init_dt_scan_fw_dump(unsigned long node, const char *uname,
> int depth, void *data)
> {
> + if (depth == 0) {
> + early_init_dt_scan_reserved_ranges(node);
> + return 0;
> + }
> +
> if (depth != 1)
> return 0;
>
> @@ -726,10 +740,14 @@ void fadump_free_cpu_notes_buf(void)
>
> static void fadump_free_mem_ranges(struct fadump_mrange_info *mrange_info)
> {
> + if (mrange_info->is_static) {
> + mrange_info->mem_range_cnt = 0;
> + return;
> + }
> +
> kfree(mrange_info->mem_ranges);
> - mrange_info->mem_ranges = NULL;
> - mrange_info->mem_ranges_sz = 0;
> - mrange_info->max_mem_ranges = 0;
> + memset((void *)((u64)mrange_info + RNG_NAME_SZ), 0,
> + (sizeof(struct fadump_mrange_info) - RNG_NAME_SZ));
> }
>
> /*
> @@ -786,6 +804,12 @@ static inline int fadump_add_mem_range(struct fadump_mrange_info *mrange_info,
> if (mrange_info->mem_range_cnt == mrange_info->max_mem_ranges) {
> int ret;
>
> + if (mrange_info->is_static) {
> + pr_err("Reached array size limit for %s memory ranges\n",
> + mrange_info->name);
> + return -ENOSPC;
> + }
> +
> ret = fadump_alloc_mem_ranges(mrange_info);
> if (ret)
> return ret;
> @@ -1202,20 +1226,19 @@ static void sort_and_merge_mem_ranges(struct fadump_mrange_info *mrange_info)
> * Scan reserved-ranges to consider them while reserving/releasing
> * memory for FADump.
> */
> -static inline int fadump_scan_reserved_mem_ranges(void)
> +static void __init early_init_dt_scan_reserved_ranges(unsigned long node)
> {
> - struct device_node *root;
> const __be32 *prop;
> int len, ret = -1;
> unsigned long i;
>
> - root = of_find_node_by_path("/");
> - if (!root)
> - return ret;
> + /* reserved-ranges already scanned */
> + if (reserved_mrange_info.mem_range_cnt != 0)
> + return;
>
> - prop = of_get_property(root, "reserved-ranges", &len);
> + prop = of_get_flat_dt_prop(node, "reserved-ranges", &len);
> if (!prop)
> - return ret;
> + return;
>
> /*
> * Each reserved range is an (address,size) pair, 2 cells each,
> @@ -1237,7 +1260,8 @@ static inline int fadump_scan_reserved_mem_ranges(void)
> }
> }
>
> - return ret;
> + /* Compact reserved ranges */
> + sort_and_merge_mem_ranges(&reserved_mrange_info);
> }
>
> /*
> @@ -1251,32 +1275,21 @@ static void fadump_release_memory(u64 begin, u64 end)
> u64 ra_start, ra_end, tstart;
> int i, ret;
>
> - fadump_scan_reserved_mem_ranges();
> -
> ra_start = fw_dump.reserve_dump_area_start;
> ra_end = ra_start + fw_dump.reserve_dump_area_size;
>
> /*
> - * Add reserved dump area to reserved ranges list
> - * and exclude all these ranges while releasing memory.
> + * If reserved ranges array limit is hit, overwrite the last reserved
> + * memory range with reserved dump area to ensure it is excluded from
> + * the memory being released (reused for next FADump registration).
> */
> - ret = fadump_add_mem_range(&reserved_mrange_info, ra_start, ra_end);
> - if (ret != 0) {
> - /*
> - * Not enough memory to setup reserved ranges but the system is
> - * running shortage of memory. So, release all the memory except
> - * Reserved dump area (reused for next fadump registration).
> - */
> - if (begin < ra_end && end > ra_start) {
> - if (begin < ra_start)
> - fadump_release_reserved_area(begin, ra_start);
> - if (end > ra_end)
> - fadump_release_reserved_area(ra_end, end);
> - } else
> - fadump_release_reserved_area(begin, end);
> + if (reserved_mrange_info.mem_range_cnt ==
> + reserved_mrange_info.max_mem_ranges)
> + reserved_mrange_info.mem_range_cnt--;
>
> + ret = fadump_add_mem_range(&reserved_mrange_info, ra_start, ra_end);
> + if (ret != 0)
> return;
> - }
>
> /* Get the reserved ranges list in order first. */
> sort_and_merge_mem_ranges(&reserved_mrange_info);
>
--
Mahesh J Salgaonkar
More information about the Linuxppc-dev
mailing list