aboutsummaryrefslogtreecommitdiffstats
path: root/mm/nobootmem.c
diff options
context:
space:
mode:
authorYinghai Lu <yinghai@kernel.org>2011-02-24 08:43:05 -0500
committerTejun Heo <tj@kernel.org>2011-02-24 08:43:05 -0500
commit0932587328d9bd5b500a640fbaff3290c8d4cabf (patch)
tree7c041a41db88f7bb6d98f2a69e21a33a311b469f /mm/nobootmem.c
parent2bf50555b0920be7e29d3823f6bbd20ee5920489 (diff)
bootmem: Separate out CONFIG_NO_BOOTMEM code into nobootmem.c
mm/bootmem.c contained code paths for both bootmem and no bootmem configurations. They implement about the same set of APIs in different ways and as a result bootmem.c contains massive amount of #ifdef CONFIG_NO_BOOTMEM. Separate out CONFIG_NO_BOOTMEM code into mm/nobootmem.c. As the common part is relatively small, duplicate them in nobootmem.c instead of creating a common file or ifdef'ing in bootmem.c. The followings are duplicated. * {min|max}_low_pfn, max_pfn, saved_max_pfn * free_bootmem_late() * ___alloc_bootmem() * __alloc_bootmem_low() The followings are applicable only to nobootmem and moved verbatim. * __free_pages_memory() * free_all_memory_core_early() The followings are not applicable to nobootmem and omitted in nobootmem.c. * reserve_bootmem_node() * reserve_bootmem() The rest split function bodies according to CONFIG_NO_BOOTMEM. Makefile is updated so that only either bootmem.c or nobootmem.c is built according to CONFIG_NO_BOOTMEM. This patch doesn't introduce any behavior change. -tj: Rewrote commit description. Suggested-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Yinghai Lu <yinghai@kernel.org> Acked-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Tejun Heo <tj@kernel.org>
Diffstat (limited to 'mm/nobootmem.c')
-rw-r--r--mm/nobootmem.c405
1 files changed, 405 insertions, 0 deletions
diff --git a/mm/nobootmem.c b/mm/nobootmem.c
new file mode 100644
index 000000000000..f220b8d0a97d
--- /dev/null
+++ b/mm/nobootmem.c
@@ -0,0 +1,405 @@
1/*
2 * bootmem - A boot-time physical memory allocator and configurator
3 *
4 * Copyright (C) 1999 Ingo Molnar
5 * 1999 Kanoj Sarcar, SGI
6 * 2008 Johannes Weiner
7 *
8 * Access to this subsystem has to be serialized externally (which is true
9 * for the boot process anyway).
10 */
11#include <linux/init.h>
12#include <linux/pfn.h>
13#include <linux/slab.h>
14#include <linux/bootmem.h>
15#include <linux/module.h>
16#include <linux/kmemleak.h>
17#include <linux/range.h>
18#include <linux/memblock.h>
19
20#include <asm/bug.h>
21#include <asm/io.h>
22#include <asm/processor.h>
23
24#include "internal.h"
25
26unsigned long max_low_pfn;
27unsigned long min_low_pfn;
28unsigned long max_pfn;
29
30#ifdef CONFIG_CRASH_DUMP
31/*
32 * If we have booted due to a crash, max_pfn will be a very low value. We need
33 * to know the amount of memory that the previous kernel used.
34 */
35unsigned long saved_max_pfn;
36#endif
37
38/*
39 * free_bootmem_late - free bootmem pages directly to page allocator
40 * @addr: starting address of the range
41 * @size: size of the range in bytes
42 *
43 * This is only useful when the bootmem allocator has already been torn
44 * down, but we are still initializing the system. Pages are given directly
45 * to the page allocator, no bootmem metadata is updated because it is gone.
46 */
47void __init free_bootmem_late(unsigned long addr, unsigned long size)
48{
49 unsigned long cursor, end;
50
51 kmemleak_free_part(__va(addr), size);
52
53 cursor = PFN_UP(addr);
54 end = PFN_DOWN(addr + size);
55
56 for (; cursor < end; cursor++) {
57 __free_pages_bootmem(pfn_to_page(cursor), 0);
58 totalram_pages++;
59 }
60}
61
62static void __init __free_pages_memory(unsigned long start, unsigned long end)
63{
64 int i;
65 unsigned long start_aligned, end_aligned;
66 int order = ilog2(BITS_PER_LONG);
67
68 start_aligned = (start + (BITS_PER_LONG - 1)) & ~(BITS_PER_LONG - 1);
69 end_aligned = end & ~(BITS_PER_LONG - 1);
70
71 if (end_aligned <= start_aligned) {
72 for (i = start; i < end; i++)
73 __free_pages_bootmem(pfn_to_page(i), 0);
74
75 return;
76 }
77
78 for (i = start; i < start_aligned; i++)
79 __free_pages_bootmem(pfn_to_page(i), 0);
80
81 for (i = start_aligned; i < end_aligned; i += BITS_PER_LONG)
82 __free_pages_bootmem(pfn_to_page(i), order);
83
84 for (i = end_aligned; i < end; i++)
85 __free_pages_bootmem(pfn_to_page(i), 0);
86}
87
88unsigned long __init free_all_memory_core_early(int nodeid)
89{
90 int i;
91 u64 start, end;
92 unsigned long count = 0;
93 struct range *range = NULL;
94 int nr_range;
95
96 nr_range = get_free_all_memory_range(&range, nodeid);
97
98 for (i = 0; i < nr_range; i++) {
99 start = range[i].start;
100 end = range[i].end;
101 count += end - start;
102 __free_pages_memory(start, end);
103 }
104
105 return count;
106}
107
108/**
109 * free_all_bootmem_node - release a node's free pages to the buddy allocator
110 * @pgdat: node to be released
111 *
112 * Returns the number of pages actually released.
113 */
114unsigned long __init free_all_bootmem_node(pg_data_t *pgdat)
115{
116 register_page_bootmem_info_node(pgdat);
117
118 /* free_all_memory_core_early(MAX_NUMNODES) will be called later */
119 return 0;
120}
121
122/**
123 * free_all_bootmem - release free pages to the buddy allocator
124 *
125 * Returns the number of pages actually released.
126 */
127unsigned long __init free_all_bootmem(void)
128{
129 /*
130 * We need to use MAX_NUMNODES instead of NODE_DATA(0)->node_id
131 * because in some case like Node0 doesnt have RAM installed
132 * low ram will be on Node1
133 * Use MAX_NUMNODES will make sure all ranges in early_node_map[]
134 * will be used instead of only Node0 related
135 */
136 return free_all_memory_core_early(MAX_NUMNODES);
137}
138
139/**
140 * free_bootmem_node - mark a page range as usable
141 * @pgdat: node the range resides on
142 * @physaddr: starting address of the range
143 * @size: size of the range in bytes
144 *
145 * Partial pages will be considered reserved and left as they are.
146 *
147 * The range must reside completely on the specified node.
148 */
149void __init free_bootmem_node(pg_data_t *pgdat, unsigned long physaddr,
150 unsigned long size)
151{
152 kmemleak_free_part(__va(physaddr), size);
153 memblock_x86_free_range(physaddr, physaddr + size);
154}
155
156/**
157 * free_bootmem - mark a page range as usable
158 * @addr: starting address of the range
159 * @size: size of the range in bytes
160 *
161 * Partial pages will be considered reserved and left as they are.
162 *
163 * The range must be contiguous but may span node boundaries.
164 */
165void __init free_bootmem(unsigned long addr, unsigned long size)
166{
167 kmemleak_free_part(__va(addr), size);
168 memblock_x86_free_range(addr, addr + size);
169}
170
171static void * __init ___alloc_bootmem_nopanic(unsigned long size,
172 unsigned long align,
173 unsigned long goal,
174 unsigned long limit)
175{
176 void *ptr;
177
178 if (WARN_ON_ONCE(slab_is_available()))
179 return kzalloc(size, GFP_NOWAIT);
180
181restart:
182
183 ptr = __alloc_memory_core_early(MAX_NUMNODES, size, align, goal, limit);
184
185 if (ptr)
186 return ptr;
187
188 if (goal != 0) {
189 goal = 0;
190 goto restart;
191 }
192
193 return NULL;
194}
195
196/**
197 * __alloc_bootmem_nopanic - allocate boot memory without panicking
198 * @size: size of the request in bytes
199 * @align: alignment of the region
200 * @goal: preferred starting address of the region
201 *
202 * The goal is dropped if it can not be satisfied and the allocation will
203 * fall back to memory below @goal.
204 *
205 * Allocation may happen on any node in the system.
206 *
207 * Returns NULL on failure.
208 */
209void * __init __alloc_bootmem_nopanic(unsigned long size, unsigned long align,
210 unsigned long goal)
211{
212 unsigned long limit = -1UL;
213
214 return ___alloc_bootmem_nopanic(size, align, goal, limit);
215}
216
217static void * __init ___alloc_bootmem(unsigned long size, unsigned long align,
218 unsigned long goal, unsigned long limit)
219{
220 void *mem = ___alloc_bootmem_nopanic(size, align, goal, limit);
221
222 if (mem)
223 return mem;
224 /*
225 * Whoops, we cannot satisfy the allocation request.
226 */
227 printk(KERN_ALERT "bootmem alloc of %lu bytes failed!\n", size);
228 panic("Out of memory");
229 return NULL;
230}
231
232/**
233 * __alloc_bootmem - allocate boot memory
234 * @size: size of the request in bytes
235 * @align: alignment of the region
236 * @goal: preferred starting address of the region
237 *
238 * The goal is dropped if it can not be satisfied and the allocation will
239 * fall back to memory below @goal.
240 *
241 * Allocation may happen on any node in the system.
242 *
243 * The function panics if the request can not be satisfied.
244 */
245void * __init __alloc_bootmem(unsigned long size, unsigned long align,
246 unsigned long goal)
247{
248 unsigned long limit = -1UL;
249
250 return ___alloc_bootmem(size, align, goal, limit);
251}
252
253/**
254 * __alloc_bootmem_node - allocate boot memory from a specific node
255 * @pgdat: node to allocate from
256 * @size: size of the request in bytes
257 * @align: alignment of the region
258 * @goal: preferred starting address of the region
259 *
260 * The goal is dropped if it can not be satisfied and the allocation will
261 * fall back to memory below @goal.
262 *
263 * Allocation may fall back to any node in the system if the specified node
264 * can not hold the requested memory.
265 *
266 * The function panics if the request can not be satisfied.
267 */
268void * __init __alloc_bootmem_node(pg_data_t *pgdat, unsigned long size,
269 unsigned long align, unsigned long goal)
270{
271 void *ptr;
272
273 if (WARN_ON_ONCE(slab_is_available()))
274 return kzalloc_node(size, GFP_NOWAIT, pgdat->node_id);
275
276 ptr = __alloc_memory_core_early(pgdat->node_id, size, align,
277 goal, -1ULL);
278 if (ptr)
279 return ptr;
280
281 return __alloc_memory_core_early(MAX_NUMNODES, size, align,
282 goal, -1ULL);
283}
284
285void * __init __alloc_bootmem_node_high(pg_data_t *pgdat, unsigned long size,
286 unsigned long align, unsigned long goal)
287{
288#ifdef MAX_DMA32_PFN
289 unsigned long end_pfn;
290
291 if (WARN_ON_ONCE(slab_is_available()))
292 return kzalloc_node(size, GFP_NOWAIT, pgdat->node_id);
293
294 /* update goal according ...MAX_DMA32_PFN */
295 end_pfn = pgdat->node_start_pfn + pgdat->node_spanned_pages;
296
297 if (end_pfn > MAX_DMA32_PFN + (128 >> (20 - PAGE_SHIFT)) &&
298 (goal >> PAGE_SHIFT) < MAX_DMA32_PFN) {
299 void *ptr;
300 unsigned long new_goal;
301
302 new_goal = MAX_DMA32_PFN << PAGE_SHIFT;
303 ptr = __alloc_memory_core_early(pgdat->node_id, size, align,
304 new_goal, -1ULL);
305 if (ptr)
306 return ptr;
307 }
308#endif
309
310 return __alloc_bootmem_node(pgdat, size, align, goal);
311
312}
313
314#ifdef CONFIG_SPARSEMEM
315/**
316 * alloc_bootmem_section - allocate boot memory from a specific section
317 * @size: size of the request in bytes
318 * @section_nr: sparse map section to allocate from
319 *
320 * Return NULL on failure.
321 */
322void * __init alloc_bootmem_section(unsigned long size,
323 unsigned long section_nr)
324{
325 unsigned long pfn, goal, limit;
326
327 pfn = section_nr_to_pfn(section_nr);
328 goal = pfn << PAGE_SHIFT;
329 limit = section_nr_to_pfn(section_nr + 1) << PAGE_SHIFT;
330
331 return __alloc_memory_core_early(early_pfn_to_nid(pfn), size,
332 SMP_CACHE_BYTES, goal, limit);
333}
334#endif
335
336void * __init __alloc_bootmem_node_nopanic(pg_data_t *pgdat, unsigned long size,
337 unsigned long align, unsigned long goal)
338{
339 void *ptr;
340
341 if (WARN_ON_ONCE(slab_is_available()))
342 return kzalloc_node(size, GFP_NOWAIT, pgdat->node_id);
343
344 ptr = __alloc_memory_core_early(pgdat->node_id, size, align,
345 goal, -1ULL);
346 if (ptr)
347 return ptr;
348
349 return __alloc_bootmem_nopanic(size, align, goal);
350}
351
352#ifndef ARCH_LOW_ADDRESS_LIMIT
353#define ARCH_LOW_ADDRESS_LIMIT 0xffffffffUL
354#endif
355
356/**
357 * __alloc_bootmem_low - allocate low boot memory
358 * @size: size of the request in bytes
359 * @align: alignment of the region
360 * @goal: preferred starting address of the region
361 *
362 * The goal is dropped if it can not be satisfied and the allocation will
363 * fall back to memory below @goal.
364 *
365 * Allocation may happen on any node in the system.
366 *
367 * The function panics if the request can not be satisfied.
368 */
369void * __init __alloc_bootmem_low(unsigned long size, unsigned long align,
370 unsigned long goal)
371{
372 return ___alloc_bootmem(size, align, goal, ARCH_LOW_ADDRESS_LIMIT);
373}
374
375/**
376 * __alloc_bootmem_low_node - allocate low boot memory from a specific node
377 * @pgdat: node to allocate from
378 * @size: size of the request in bytes
379 * @align: alignment of the region
380 * @goal: preferred starting address of the region
381 *
382 * The goal is dropped if it can not be satisfied and the allocation will
383 * fall back to memory below @goal.
384 *
385 * Allocation may fall back to any node in the system if the specified node
386 * can not hold the requested memory.
387 *
388 * The function panics if the request can not be satisfied.
389 */
390void * __init __alloc_bootmem_low_node(pg_data_t *pgdat, unsigned long size,
391 unsigned long align, unsigned long goal)
392{
393 void *ptr;
394
395 if (WARN_ON_ONCE(slab_is_available()))
396 return kzalloc_node(size, GFP_NOWAIT, pgdat->node_id);
397
398 ptr = __alloc_memory_core_early(pgdat->node_id, size, align,
399 goal, ARCH_LOW_ADDRESS_LIMIT);
400 if (ptr)
401 return ptr;
402
403 return __alloc_memory_core_early(MAX_NUMNODES, size, align,
404 goal, ARCH_LOW_ADDRESS_LIMIT);
405}