nobootmem.c 4.21 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0
2 3 4 5 6 7 8 9 10 11 12 13 14
/*
 *  bootmem - A boot-time physical memory allocator and configurator
 *
 *  Copyright (C) 1999 Ingo Molnar
 *                1999 Kanoj Sarcar, SGI
 *                2008 Johannes Weiner
 *
 * Access to this subsystem has to be serialized externally (which is true
 * for the boot process anyway).
 */
#include <linux/init.h>
#include <linux/pfn.h>
#include <linux/slab.h>
15
#include <linux/export.h>
16 17 18
#include <linux/kmemleak.h>
#include <linux/range.h>
#include <linux/memblock.h>
19
#include <linux/bootmem.h>
20 21 22 23 24 25

#include <asm/bug.h>
#include <asm/io.h>

#include "internal.h"

26 27 28 29 30
#ifndef CONFIG_NEED_MULTIPLE_NODES
struct pglist_data __refdata contig_page_data;
EXPORT_SYMBOL(contig_page_data);
#endif

31 32 33
unsigned long max_low_pfn;
unsigned long min_low_pfn;
unsigned long max_pfn;
34
unsigned long long max_possible_pfn;
35

36
/**
37 38 39 40 41 42 43 44 45 46 47 48
 * free_bootmem_late - free bootmem pages directly to page allocator
 * @addr: starting address of the range
 * @size: size of the range in bytes
 *
 * This is only useful when the bootmem allocator has already been torn
 * down, but we are still initializing the system.  Pages are given directly
 * to the page allocator, no bootmem metadata is updated because it is gone.
 */
void __init free_bootmem_late(unsigned long addr, unsigned long size)
{
	unsigned long cursor, end;

49
	kmemleak_free_part_phys(addr, size);
50 51 52 53 54

	cursor = PFN_UP(addr);
	end = PFN_DOWN(addr + size);

	for (; cursor < end; cursor++) {
55
		__free_pages_bootmem(pfn_to_page(cursor), cursor, 0);
56 57 58 59 60 61
		totalram_pages++;
	}
}

static void __init __free_pages_memory(unsigned long start, unsigned long end)
{
62
	int order;
63

64 65
	while (start < end) {
		order = min(MAX_ORDER - 1UL, __ffs(start));
66

67 68
		while (start + (1UL << order) > end)
			order--;
69

70
		__free_pages_bootmem(pfn_to_page(start), start, order);
71

72 73
		start += (1UL << order);
	}
74 75
}

76 77 78 79 80 81 82
static unsigned long __init __free_memory_core(phys_addr_t start,
				 phys_addr_t end)
{
	unsigned long start_pfn = PFN_UP(start);
	unsigned long end_pfn = min_t(unsigned long,
				      PFN_DOWN(end), max_low_pfn);

83
	if (start_pfn >= end_pfn)
84 85 86 87 88 89 90
		return 0;

	__free_pages_memory(start_pfn, end_pfn);

	return end_pfn - start_pfn;
}

91
static unsigned long __init free_low_memory_core_early(void)
92 93
{
	unsigned long count = 0;
94
	phys_addr_t start, end;
95 96
	u64 i;

97 98
	memblock_clear_hotplug(0, -1);

99 100 101
	for_each_reserved_mem_region(i, &start, &end)
		reserve_bootmem_region(start, end);

102 103 104 105 106
	/*
	 * We need to use NUMA_NO_NODE instead of NODE_DATA(0)->node_id
	 *  because in some case like Node0 doesn't have RAM installed
	 *  low ram will be on Node1
	 */
107 108
	for_each_free_mem_range(i, NUMA_NO_NODE, MEMBLOCK_NONE, &start, &end,
				NULL)
109 110
		count += __free_memory_core(start, end);

111 112 113
	return count;
}

114 115
static int reset_managed_pages_done __initdata;

116
void reset_node_managed_pages(pg_data_t *pgdat)
117 118 119 120
{
	struct zone *z;

	for (z = pgdat->node_zones; z < pgdat->node_zones + MAX_NR_ZONES; z++)
121 122 123 124 125 126 127
		z->managed_pages = 0;
}

void __init reset_all_zones_managed_pages(void)
{
	struct pglist_data *pgdat;

128 129 130
	if (reset_managed_pages_done)
		return;

131 132
	for_each_online_pgdat(pgdat)
		reset_node_managed_pages(pgdat);
133

134
	reset_managed_pages_done = 1;
135 136
}

137 138 139
/**
 * free_all_bootmem - release free pages to the buddy allocator
 *
140
 * Return: the number of pages actually released.
141 142 143
 */
unsigned long __init free_all_bootmem(void)
{
144 145
	unsigned long pages;

146
	reset_all_zones_managed_pages();
147

148 149 150 151
	pages = free_low_memory_core_early();
	totalram_pages += pages;

	return pages;
152 153 154 155 156
}

/**
 * free_bootmem_node - mark a page range as usable
 * @pgdat: node the range resides on
157
 * @physaddr: starting physical address of the range
158 159 160 161 162 163 164 165 166
 * @size: size of the range in bytes
 *
 * Partial pages will be considered reserved and left as they are.
 *
 * The range must reside completely on the specified node.
 */
void __init free_bootmem_node(pg_data_t *pgdat, unsigned long physaddr,
			      unsigned long size)
{
167
	memblock_free(physaddr, size);
168 169 170 171
}

/**
 * free_bootmem - mark a page range as usable
172
 * @addr: starting physical address of the range
173 174 175 176 177 178 179 180
 * @size: size of the range in bytes
 *
 * Partial pages will be considered reserved and left as they are.
 *
 * The range must be contiguous but may span node boundaries.
 */
void __init free_bootmem(unsigned long addr, unsigned long size)
{
181
	memblock_free(addr, size);
182
}