diff options
Diffstat (limited to 'mm/memblock.c')
| -rw-r--r-- | mm/memblock.c | 76 | 
1 files changed, 68 insertions, 8 deletions
diff --git a/mm/memblock.c b/mm/memblock.c index a48f520c2d01..7d4f61ae666a 100644 --- a/mm/memblock.c +++ b/mm/memblock.c @@ -1,13 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later  /*   * Procedures for maintaining information about logical memory blocks.   *   * Peter Bergner, IBM Corp.	June 2001.   * Copyright (C) 2001 Peter Bergner. - * - *      This program is free software; you can redistribute it and/or - *      modify it under the terms of the GNU General Public License - *      as published by the Free Software Foundation; either version - *      2 of the License, or (at your option) any later version.   */  #include <linux/kernel.h> @@ -94,7 +90,7 @@   * :c:func:`mem_init` function frees all the memory to the buddy page   * allocator.   * - * If an architecure enables %CONFIG_ARCH_DISCARD_MEMBLOCK, the + * Unless an architecure enables %CONFIG_ARCH_KEEP_MEMBLOCK, the   * memblock data structures will be discarded after the system   * initialization compltes.   */ @@ -375,7 +371,7 @@ static void __init_memblock memblock_remove_region(struct memblock_type *type, u  	}  } -#ifdef CONFIG_ARCH_DISCARD_MEMBLOCK +#ifndef CONFIG_ARCH_KEEP_MEMBLOCK  /**   * memblock_discard - discard memory and reserved arrays if they were allocated   */ @@ -1255,6 +1251,70 @@ int __init_memblock memblock_set_node(phys_addr_t base, phys_addr_t size,  	return 0;  }  #endif /* CONFIG_HAVE_MEMBLOCK_NODE_MAP */ +#ifdef CONFIG_DEFERRED_STRUCT_PAGE_INIT +/** + * __next_mem_pfn_range_in_zone - iterator for for_each_*_range_in_zone() + * + * @idx: pointer to u64 loop variable + * @zone: zone in which all of the memory blocks reside + * @out_spfn: ptr to ulong for start pfn of the range, can be %NULL + * @out_epfn: ptr to ulong for end pfn of the range, can be %NULL + * + * This function is meant to be a zone/pfn specific wrapper for the + * for_each_mem_range type iterators. Specifically they are used in the + * deferred memory init routines and as such we were duplicating much of + * this logic throughout the code. So instead of having it in multiple + * locations it seemed like it would make more sense to centralize this to + * one new iterator that does everything they need. + */ +void __init_memblock +__next_mem_pfn_range_in_zone(u64 *idx, struct zone *zone, +			     unsigned long *out_spfn, unsigned long *out_epfn) +{ +	int zone_nid = zone_to_nid(zone); +	phys_addr_t spa, epa; +	int nid; + +	__next_mem_range(idx, zone_nid, MEMBLOCK_NONE, +			 &memblock.memory, &memblock.reserved, +			 &spa, &epa, &nid); + +	while (*idx != U64_MAX) { +		unsigned long epfn = PFN_DOWN(epa); +		unsigned long spfn = PFN_UP(spa); + +		/* +		 * Verify the end is at least past the start of the zone and +		 * that we have at least one PFN to initialize. +		 */ +		if (zone->zone_start_pfn < epfn && spfn < epfn) { +			/* if we went too far just stop searching */ +			if (zone_end_pfn(zone) <= spfn) { +				*idx = U64_MAX; +				break; +			} + +			if (out_spfn) +				*out_spfn = max(zone->zone_start_pfn, spfn); +			if (out_epfn) +				*out_epfn = min(zone_end_pfn(zone), epfn); + +			return; +		} + +		__next_mem_range(idx, zone_nid, MEMBLOCK_NONE, +				 &memblock.memory, &memblock.reserved, +				 &spa, &epa, &nid); +	} + +	/* signal end of iteration */ +	if (out_spfn) +		*out_spfn = ULONG_MAX; +	if (out_epfn) +		*out_epfn = 0; +} + +#endif /* CONFIG_DEFERRED_STRUCT_PAGE_INIT */  /**   * memblock_alloc_range_nid - allocate boot memory block @@ -1923,7 +1983,7 @@ unsigned long __init memblock_free_all(void)  	return pages;  } -#if defined(CONFIG_DEBUG_FS) && !defined(CONFIG_ARCH_DISCARD_MEMBLOCK) +#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_ARCH_KEEP_MEMBLOCK)  static int memblock_debug_show(struct seq_file *m, void *private)  {  |