Blame view

mm/bootmem.c 24.4 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
  /*
57cfc29ef   Johannes Weiner   bootmem: clean up...
2
   *  bootmem - A boot-time physical memory allocator and configurator
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3
4
   *
   *  Copyright (C) 1999 Ingo Molnar
57cfc29ef   Johannes Weiner   bootmem: clean up...
5
6
   *                1999 Kanoj Sarcar, SGI
   *                2008 Johannes Weiner
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7
   *
57cfc29ef   Johannes Weiner   bootmem: clean up...
8
9
   * Access to this subsystem has to be serialized externally (which is true
   * for the boot process anyway).
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
10
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
11
  #include <linux/init.h>
bbc7b92e3   Franck Bui-Huu   [PATCH] bootmem: ...
12
  #include <linux/pfn.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
13
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14
  #include <linux/bootmem.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15
  #include <linux/module.h>
ec3a354bd   Catalin Marinas   kmemleak: Add cal...
16
  #include <linux/kmemleak.h>
08677214e   Yinghai Lu   x86: Make 64 bit ...
17
  #include <linux/range.h>
72d7c3b33   Yinghai Lu   x86: Use memblock...
18
  #include <linux/memblock.h>
e786e86a5   Franck Bui-Huu   [PATCH] bootmem: ...
19
20
  
  #include <asm/bug.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21
  #include <asm/io.h>
dfd54cbcc   Heiko Carstens   [PATCH] bootmem: ...
22
  #include <asm/processor.h>
e786e86a5   Franck Bui-Huu   [PATCH] bootmem: ...
23

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
  #include "internal.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
25
26
27
  unsigned long max_low_pfn;
  unsigned long min_low_pfn;
  unsigned long max_pfn;
92aa63a5a   Vivek Goyal   [PATCH] kdump: Re...
28
29
30
31
32
33
34
  #ifdef CONFIG_CRASH_DUMP
  /*
   * If we have booted due to a crash, max_pfn will be a very low value. We need
   * to know the amount of memory that the previous kernel used.
   */
  unsigned long saved_max_pfn;
  #endif
08677214e   Yinghai Lu   x86: Make 64 bit ...
35
  #ifndef CONFIG_NO_BOOTMEM
b61bfa3c4   Johannes Weiner   mm: move bootmem ...
36
  bootmem_data_t bootmem_node_data[MAX_NUMNODES] __initdata;
636cc40cb   Johannes Weiner   bootmem: revisit ...
37
  static struct list_head bdata_list __initdata = LIST_HEAD_INIT(bdata_list);
2e5237daf   Johannes Weiner   bootmem: add debu...
38
39
40
41
42
43
44
45
46
47
48
49
50
  static int bootmem_debug;
  
  static int __init bootmem_debug_setup(char *buf)
  {
  	bootmem_debug = 1;
  	return 0;
  }
  early_param("bootmem_debug", bootmem_debug_setup);
  
  #define bdebug(fmt, args...) ({				\
  	if (unlikely(bootmem_debug))			\
  		printk(KERN_INFO			\
  			"bootmem::%s " fmt,		\
80a914dc0   Harvey Harrison   misc: replace __F...
51
  			__func__, ## args);		\
2e5237daf   Johannes Weiner   bootmem: add debu...
52
  })
df049a5f4   Johannes Weiner   bootmem: revisit ...
53
  static unsigned long __init bootmap_bytes(unsigned long pages)
223e8dc92   Johannes Weiner   bootmem: reorder ...
54
  {
df049a5f4   Johannes Weiner   bootmem: revisit ...
55
  	unsigned long bytes = (pages + 7) / 8;
223e8dc92   Johannes Weiner   bootmem: reorder ...
56

df049a5f4   Johannes Weiner   bootmem: revisit ...
57
  	return ALIGN(bytes, sizeof(long));
223e8dc92   Johannes Weiner   bootmem: reorder ...
58
  }
a66fd7dae   Johannes Weiner   bootmem: add docu...
59
60
61
62
  /**
   * bootmem_bootmap_pages - calculate bitmap size in pages
   * @pages: number of pages the bitmap has to represent
   */
f71bf0cac   Franck Bui-Huu   [PATCH] bootmem: ...
63
  unsigned long __init bootmem_bootmap_pages(unsigned long pages)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
64
  {
df049a5f4   Johannes Weiner   bootmem: revisit ...
65
  	unsigned long bytes = bootmap_bytes(pages);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
66

df049a5f4   Johannes Weiner   bootmem: revisit ...
67
  	return PAGE_ALIGN(bytes) >> PAGE_SHIFT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
68
  }
f71bf0cac   Franck Bui-Huu   [PATCH] bootmem: ...
69

679bc9fbb   KAMEZAWA Hiroyuki   [PATCH] for_each_...
70
71
72
  /*
   * link bdata in order
   */
69d49e681   Franck Bui-Huu   [PATCH] bootmem: ...
73
  static void __init link_bootmem(bootmem_data_t *bdata)
679bc9fbb   KAMEZAWA Hiroyuki   [PATCH] for_each_...
74
  {
636cc40cb   Johannes Weiner   bootmem: revisit ...
75
  	struct list_head *iter;
f71bf0cac   Franck Bui-Huu   [PATCH] bootmem: ...
76

636cc40cb   Johannes Weiner   bootmem: revisit ...
77
78
79
80
  	list_for_each(iter, &bdata_list) {
  		bootmem_data_t *ent;
  
  		ent = list_entry(iter, bootmem_data_t, list);
3560e249a   Johannes Weiner   bootmem: replace ...
81
  		if (bdata->node_min_pfn < ent->node_min_pfn)
636cc40cb   Johannes Weiner   bootmem: revisit ...
82
  			break;
679bc9fbb   KAMEZAWA Hiroyuki   [PATCH] for_each_...
83
  	}
636cc40cb   Johannes Weiner   bootmem: revisit ...
84
  	list_add_tail(&bdata->list, iter);
679bc9fbb   KAMEZAWA Hiroyuki   [PATCH] for_each_...
85
  }
bbc7b92e3   Franck Bui-Huu   [PATCH] bootmem: ...
86
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
87
88
   * Called once to set up the allocator itself.
   */
8ae044630   Johannes Weiner   mm: normalize int...
89
  static unsigned long __init init_bootmem_core(bootmem_data_t *bdata,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
90
91
  	unsigned long mapstart, unsigned long start, unsigned long end)
  {
bbc7b92e3   Franck Bui-Huu   [PATCH] bootmem: ...
92
  	unsigned long mapsize;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
93

2dbb51c49   Mel Gorman   mm: make defensiv...
94
  	mminit_validate_memmodel_limits(&start, &end);
bbc7b92e3   Franck Bui-Huu   [PATCH] bootmem: ...
95
  	bdata->node_bootmem_map = phys_to_virt(PFN_PHYS(mapstart));
3560e249a   Johannes Weiner   bootmem: replace ...
96
  	bdata->node_min_pfn = start;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
97
  	bdata->node_low_pfn = end;
679bc9fbb   KAMEZAWA Hiroyuki   [PATCH] for_each_...
98
  	link_bootmem(bdata);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
99
100
101
102
103
  
  	/*
  	 * Initially all pages are reserved - setup_arch() has to
  	 * register free RAM areas explicitly.
  	 */
df049a5f4   Johannes Weiner   bootmem: revisit ...
104
  	mapsize = bootmap_bytes(end - start);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
105
  	memset(bdata->node_bootmem_map, 0xff, mapsize);
2e5237daf   Johannes Weiner   bootmem: add debu...
106
107
108
  	bdebug("nid=%td start=%lx map=%lx end=%lx mapsize=%lx
  ",
  		bdata - bootmem_node_data, start, mapstart, end, mapsize);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
109
110
  	return mapsize;
  }
a66fd7dae   Johannes Weiner   bootmem: add docu...
111
112
113
114
115
116
117
118
119
  /**
   * init_bootmem_node - register a node as boot memory
   * @pgdat: node to register
   * @freepfn: pfn where the bitmap for this node is to be placed
   * @startpfn: first pfn on the node
   * @endpfn: first pfn after the node
   *
   * Returns the number of bytes needed to hold the bitmap for this node.
   */
223e8dc92   Johannes Weiner   bootmem: reorder ...
120
121
122
123
124
  unsigned long __init init_bootmem_node(pg_data_t *pgdat, unsigned long freepfn,
  				unsigned long startpfn, unsigned long endpfn)
  {
  	return init_bootmem_core(pgdat->bdata, freepfn, startpfn, endpfn);
  }
a66fd7dae   Johannes Weiner   bootmem: add docu...
125
126
127
128
129
130
131
  /**
   * init_bootmem - register boot memory
   * @start: pfn where the bitmap is to be placed
   * @pages: number of available physical pages
   *
   * Returns the number of bytes needed to hold the bitmap.
   */
223e8dc92   Johannes Weiner   bootmem: reorder ...
132
133
134
135
136
137
  unsigned long __init init_bootmem(unsigned long start, unsigned long pages)
  {
  	max_low_pfn = pages;
  	min_low_pfn = start;
  	return init_bootmem_core(NODE_DATA(0)->bdata, start, 0, pages);
  }
08677214e   Yinghai Lu   x86: Make 64 bit ...
138
  #endif
9f993ac3f   FUJITA Tomonori   bootmem: Add free...
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
  /*
   * 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;
  
  	kmemleak_free_part(__va(addr), size);
  
  	cursor = PFN_UP(addr);
  	end = PFN_DOWN(addr + size);
  
  	for (; cursor < end; cursor++) {
  		__free_pages_bootmem(pfn_to_page(cursor), 0);
  		totalram_pages++;
  	}
  }
08677214e   Yinghai Lu   x86: Make 64 bit ...
162
163
164
165
166
167
168
169
170
171
172
  #ifdef CONFIG_NO_BOOTMEM
  static void __init __free_pages_memory(unsigned long start, unsigned long end)
  {
  	int i;
  	unsigned long start_aligned, end_aligned;
  	int order = ilog2(BITS_PER_LONG);
  
  	start_aligned = (start + (BITS_PER_LONG - 1)) & ~(BITS_PER_LONG - 1);
  	end_aligned = end & ~(BITS_PER_LONG - 1);
  
  	if (end_aligned <= start_aligned) {
08677214e   Yinghai Lu   x86: Make 64 bit ...
173
174
175
176
177
  		for (i = start; i < end; i++)
  			__free_pages_bootmem(pfn_to_page(i), 0);
  
  		return;
  	}
08677214e   Yinghai Lu   x86: Make 64 bit ...
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
  	for (i = start; i < start_aligned; i++)
  		__free_pages_bootmem(pfn_to_page(i), 0);
  
  	for (i = start_aligned; i < end_aligned; i += BITS_PER_LONG)
  		__free_pages_bootmem(pfn_to_page(i), order);
  
  	for (i = end_aligned; i < end; i++)
  		__free_pages_bootmem(pfn_to_page(i), 0);
  }
  
  unsigned long __init free_all_memory_core_early(int nodeid)
  {
  	int i;
  	u64 start, end;
  	unsigned long count = 0;
  	struct range *range = NULL;
  	int nr_range;
  
  	nr_range = get_free_all_memory_range(&range, nodeid);
  
  	for (i = 0; i < nr_range; i++) {
  		start = range[i].start;
  		end = range[i].end;
  		count += end - start;
  		__free_pages_memory(start, end);
  	}
  
  	return count;
  }
  #else
223e8dc92   Johannes Weiner   bootmem: reorder ...
208
209
  static unsigned long __init free_all_bootmem_core(bootmem_data_t *bdata)
  {
41546c174   Johannes Weiner   bootmem: clean up...
210
  	int aligned;
223e8dc92   Johannes Weiner   bootmem: reorder ...
211
  	struct page *page;
41546c174   Johannes Weiner   bootmem: clean up...
212
213
214
215
  	unsigned long start, end, pages, count = 0;
  
  	if (!bdata->node_bootmem_map)
  		return 0;
3560e249a   Johannes Weiner   bootmem: replace ...
216
  	start = bdata->node_min_pfn;
41546c174   Johannes Weiner   bootmem: clean up...
217
  	end = bdata->node_low_pfn;
223e8dc92   Johannes Weiner   bootmem: reorder ...
218
  	/*
41546c174   Johannes Weiner   bootmem: clean up...
219
220
  	 * If the start is aligned to the machines wordsize, we might
  	 * be able to free pages in bulks of that order.
223e8dc92   Johannes Weiner   bootmem: reorder ...
221
  	 */
41546c174   Johannes Weiner   bootmem: clean up...
222
  	aligned = !(start & (BITS_PER_LONG - 1));
223e8dc92   Johannes Weiner   bootmem: reorder ...
223

41546c174   Johannes Weiner   bootmem: clean up...
224
225
226
  	bdebug("nid=%td start=%lx end=%lx aligned=%d
  ",
  		bdata - bootmem_node_data, start, end, aligned);
223e8dc92   Johannes Weiner   bootmem: reorder ...
227

41546c174   Johannes Weiner   bootmem: clean up...
228
229
  	while (start < end) {
  		unsigned long *map, idx, vec;
223e8dc92   Johannes Weiner   bootmem: reorder ...
230

41546c174   Johannes Weiner   bootmem: clean up...
231
  		map = bdata->node_bootmem_map;
3560e249a   Johannes Weiner   bootmem: replace ...
232
  		idx = start - bdata->node_min_pfn;
41546c174   Johannes Weiner   bootmem: clean up...
233
234
235
236
237
238
  		vec = ~map[idx / BITS_PER_LONG];
  
  		if (aligned && vec == ~0UL && start + BITS_PER_LONG < end) {
  			int order = ilog2(BITS_PER_LONG);
  
  			__free_pages_bootmem(pfn_to_page(start), order);
223e8dc92   Johannes Weiner   bootmem: reorder ...
239
  			count += BITS_PER_LONG;
41546c174   Johannes Weiner   bootmem: clean up...
240
241
242
243
244
245
  		} else {
  			unsigned long off = 0;
  
  			while (vec && off < BITS_PER_LONG) {
  				if (vec & 1) {
  					page = pfn_to_page(start + off);
223e8dc92   Johannes Weiner   bootmem: reorder ...
246
  					__free_pages_bootmem(page, 0);
41546c174   Johannes Weiner   bootmem: clean up...
247
  					count++;
223e8dc92   Johannes Weiner   bootmem: reorder ...
248
  				}
41546c174   Johannes Weiner   bootmem: clean up...
249
250
  				vec >>= 1;
  				off++;
223e8dc92   Johannes Weiner   bootmem: reorder ...
251
  			}
223e8dc92   Johannes Weiner   bootmem: reorder ...
252
  		}
41546c174   Johannes Weiner   bootmem: clean up...
253
  		start += BITS_PER_LONG;
223e8dc92   Johannes Weiner   bootmem: reorder ...
254
  	}
223e8dc92   Johannes Weiner   bootmem: reorder ...
255
  	page = virt_to_page(bdata->node_bootmem_map);
3560e249a   Johannes Weiner   bootmem: replace ...
256
  	pages = bdata->node_low_pfn - bdata->node_min_pfn;
41546c174   Johannes Weiner   bootmem: clean up...
257
258
259
260
  	pages = bootmem_bootmap_pages(pages);
  	count += pages;
  	while (pages--)
  		__free_pages_bootmem(page++, 0);
223e8dc92   Johannes Weiner   bootmem: reorder ...
261

2e5237daf   Johannes Weiner   bootmem: add debu...
262
263
  	bdebug("nid=%td released=%lx
  ", bdata - bootmem_node_data, count);
223e8dc92   Johannes Weiner   bootmem: reorder ...
264
265
  	return count;
  }
08677214e   Yinghai Lu   x86: Make 64 bit ...
266
  #endif
223e8dc92   Johannes Weiner   bootmem: reorder ...
267

a66fd7dae   Johannes Weiner   bootmem: add docu...
268
269
270
271
272
273
  /**
   * free_all_bootmem_node - release a node's free pages to the buddy allocator
   * @pgdat: node to be released
   *
   * Returns the number of pages actually released.
   */
223e8dc92   Johannes Weiner   bootmem: reorder ...
274
275
276
  unsigned long __init free_all_bootmem_node(pg_data_t *pgdat)
  {
  	register_page_bootmem_info_node(pgdat);
08677214e   Yinghai Lu   x86: Make 64 bit ...
277
278
279
280
  #ifdef CONFIG_NO_BOOTMEM
  	/* free_all_memory_core_early(MAX_NUMNODES) will be called later */
  	return 0;
  #else
223e8dc92   Johannes Weiner   bootmem: reorder ...
281
  	return free_all_bootmem_core(pgdat->bdata);
08677214e   Yinghai Lu   x86: Make 64 bit ...
282
  #endif
223e8dc92   Johannes Weiner   bootmem: reorder ...
283
  }
a66fd7dae   Johannes Weiner   bootmem: add docu...
284
285
286
287
288
  /**
   * free_all_bootmem - release free pages to the buddy allocator
   *
   * Returns the number of pages actually released.
   */
223e8dc92   Johannes Weiner   bootmem: reorder ...
289
290
  unsigned long __init free_all_bootmem(void)
  {
08677214e   Yinghai Lu   x86: Make 64 bit ...
291
  #ifdef CONFIG_NO_BOOTMEM
337998587   Yinghai Lu   nobootmem, x86: F...
292
293
294
295
296
297
298
299
  	/*
  	 * We need to use MAX_NUMNODES instead of NODE_DATA(0)->node_id
  	 *  because in some case like Node0 doesnt have RAM installed
  	 *  low ram will be on Node1
  	 * Use MAX_NUMNODES will make sure all ranges in early_node_map[]
  	 *  will be used instead of only Node0 related
  	 */
  	return free_all_memory_core_early(MAX_NUMNODES);
08677214e   Yinghai Lu   x86: Make 64 bit ...
300
  #else
aa235fc71   Yinghai Lu   bootmem, x86: Fix...
301
302
303
304
305
306
307
  	unsigned long total_pages = 0;
  	bootmem_data_t *bdata;
  
  	list_for_each_entry(bdata, &bdata_list, list)
  		total_pages += free_all_bootmem_core(bdata);
  
  	return total_pages;
08677214e   Yinghai Lu   x86: Make 64 bit ...
308
  #endif
223e8dc92   Johannes Weiner   bootmem: reorder ...
309
  }
08677214e   Yinghai Lu   x86: Make 64 bit ...
310
  #ifndef CONFIG_NO_BOOTMEM
d747fa4bc   Johannes Weiner   bootmem: free/res...
311
312
313
314
315
316
317
  static void __init __free(bootmem_data_t *bdata,
  			unsigned long sidx, unsigned long eidx)
  {
  	unsigned long idx;
  
  	bdebug("nid=%td start=%lx end=%lx
  ", bdata - bootmem_node_data,
3560e249a   Johannes Weiner   bootmem: replace ...
318
319
  		sidx + bdata->node_min_pfn,
  		eidx + bdata->node_min_pfn);
d747fa4bc   Johannes Weiner   bootmem: free/res...
320

e2bf3cae5   Johannes Weiner   bootmem: factor o...
321
322
  	if (bdata->hint_idx > sidx)
  		bdata->hint_idx = sidx;
d747fa4bc   Johannes Weiner   bootmem: free/res...
323
324
325
326
327
328
329
330
331
332
333
334
335
336
  	for (idx = sidx; idx < eidx; idx++)
  		if (!test_and_clear_bit(idx, bdata->node_bootmem_map))
  			BUG();
  }
  
  static int __init __reserve(bootmem_data_t *bdata, unsigned long sidx,
  			unsigned long eidx, int flags)
  {
  	unsigned long idx;
  	int exclusive = flags & BOOTMEM_EXCLUSIVE;
  
  	bdebug("nid=%td start=%lx end=%lx flags=%x
  ",
  		bdata - bootmem_node_data,
3560e249a   Johannes Weiner   bootmem: replace ...
337
338
  		sidx + bdata->node_min_pfn,
  		eidx + bdata->node_min_pfn,
d747fa4bc   Johannes Weiner   bootmem: free/res...
339
340
341
342
343
344
345
346
347
348
  		flags);
  
  	for (idx = sidx; idx < eidx; idx++)
  		if (test_and_set_bit(idx, bdata->node_bootmem_map)) {
  			if (exclusive) {
  				__free(bdata, sidx, idx);
  				return -EBUSY;
  			}
  			bdebug("silent double reserve of PFN %lx
  ",
3560e249a   Johannes Weiner   bootmem: replace ...
349
  				idx + bdata->node_min_pfn);
d747fa4bc   Johannes Weiner   bootmem: free/res...
350
351
352
  		}
  	return 0;
  }
e2bf3cae5   Johannes Weiner   bootmem: factor o...
353
354
355
  static int __init mark_bootmem_node(bootmem_data_t *bdata,
  				unsigned long start, unsigned long end,
  				int reserve, int flags)
223e8dc92   Johannes Weiner   bootmem: reorder ...
356
357
  {
  	unsigned long sidx, eidx;
223e8dc92   Johannes Weiner   bootmem: reorder ...
358

e2bf3cae5   Johannes Weiner   bootmem: factor o...
359
360
361
  	bdebug("nid=%td start=%lx end=%lx reserve=%d flags=%x
  ",
  		bdata - bootmem_node_data, start, end, reserve, flags);
223e8dc92   Johannes Weiner   bootmem: reorder ...
362

3560e249a   Johannes Weiner   bootmem: replace ...
363
  	BUG_ON(start < bdata->node_min_pfn);
e2bf3cae5   Johannes Weiner   bootmem: factor o...
364
  	BUG_ON(end > bdata->node_low_pfn);
223e8dc92   Johannes Weiner   bootmem: reorder ...
365

3560e249a   Johannes Weiner   bootmem: replace ...
366
367
  	sidx = start - bdata->node_min_pfn;
  	eidx = end - bdata->node_min_pfn;
223e8dc92   Johannes Weiner   bootmem: reorder ...
368

e2bf3cae5   Johannes Weiner   bootmem: factor o...
369
370
  	if (reserve)
  		return __reserve(bdata, sidx, eidx, flags);
223e8dc92   Johannes Weiner   bootmem: reorder ...
371
  	else
e2bf3cae5   Johannes Weiner   bootmem: factor o...
372
373
374
375
376
377
378
379
380
381
382
383
384
385
  		__free(bdata, sidx, eidx);
  	return 0;
  }
  
  static int __init mark_bootmem(unsigned long start, unsigned long end,
  				int reserve, int flags)
  {
  	unsigned long pos;
  	bootmem_data_t *bdata;
  
  	pos = start;
  	list_for_each_entry(bdata, &bdata_list, list) {
  		int err;
  		unsigned long max;
3560e249a   Johannes Weiner   bootmem: replace ...
386
387
  		if (pos < bdata->node_min_pfn ||
  		    pos >= bdata->node_low_pfn) {
e2bf3cae5   Johannes Weiner   bootmem: factor o...
388
389
390
391
392
  			BUG_ON(pos != start);
  			continue;
  		}
  
  		max = min(bdata->node_low_pfn, end);
223e8dc92   Johannes Weiner   bootmem: reorder ...
393

e2bf3cae5   Johannes Weiner   bootmem: factor o...
394
395
396
397
398
  		err = mark_bootmem_node(bdata, pos, max, reserve, flags);
  		if (reserve && err) {
  			mark_bootmem(start, pos, 0, 0);
  			return err;
  		}
223e8dc92   Johannes Weiner   bootmem: reorder ...
399

e2bf3cae5   Johannes Weiner   bootmem: factor o...
400
401
402
403
404
  		if (max == end)
  			return 0;
  		pos = bdata->node_low_pfn;
  	}
  	BUG();
223e8dc92   Johannes Weiner   bootmem: reorder ...
405
  }
08677214e   Yinghai Lu   x86: Make 64 bit ...
406
  #endif
223e8dc92   Johannes Weiner   bootmem: reorder ...
407

a66fd7dae   Johannes Weiner   bootmem: add docu...
408
409
410
411
412
413
414
415
  /**
   * free_bootmem_node - mark a page range as usable
   * @pgdat: node the range resides on
   * @physaddr: starting address of the range
   * @size: size of the range in bytes
   *
   * Partial pages will be considered reserved and left as they are.
   *
e2bf3cae5   Johannes Weiner   bootmem: factor o...
416
   * The range must reside completely on the specified node.
a66fd7dae   Johannes Weiner   bootmem: add docu...
417
   */
223e8dc92   Johannes Weiner   bootmem: reorder ...
418
419
420
  void __init free_bootmem_node(pg_data_t *pgdat, unsigned long physaddr,
  			      unsigned long size)
  {
08677214e   Yinghai Lu   x86: Make 64 bit ...
421
  #ifdef CONFIG_NO_BOOTMEM
72d7c3b33   Yinghai Lu   x86: Use memblock...
422
  	kmemleak_free_part(__va(physaddr), size);
a9ce6bc15   Yinghai Lu   x86, memblock: Re...
423
  	memblock_x86_free_range(physaddr, physaddr + size);
08677214e   Yinghai Lu   x86: Make 64 bit ...
424
  #else
e2bf3cae5   Johannes Weiner   bootmem: factor o...
425
  	unsigned long start, end;
ec3a354bd   Catalin Marinas   kmemleak: Add cal...
426
  	kmemleak_free_part(__va(physaddr), size);
e2bf3cae5   Johannes Weiner   bootmem: factor o...
427
428
429
430
  	start = PFN_UP(physaddr);
  	end = PFN_DOWN(physaddr + size);
  
  	mark_bootmem_node(pgdat->bdata, start, end, 0, 0);
08677214e   Yinghai Lu   x86: Make 64 bit ...
431
  #endif
223e8dc92   Johannes Weiner   bootmem: reorder ...
432
  }
a66fd7dae   Johannes Weiner   bootmem: add docu...
433
434
435
436
437
438
439
  /**
   * free_bootmem - mark a page range as usable
   * @addr: starting address of the range
   * @size: size of the range in bytes
   *
   * Partial pages will be considered reserved and left as they are.
   *
e2bf3cae5   Johannes Weiner   bootmem: factor o...
440
   * The range must be contiguous but may span node boundaries.
a66fd7dae   Johannes Weiner   bootmem: add docu...
441
   */
223e8dc92   Johannes Weiner   bootmem: reorder ...
442
443
  void __init free_bootmem(unsigned long addr, unsigned long size)
  {
08677214e   Yinghai Lu   x86: Make 64 bit ...
444
  #ifdef CONFIG_NO_BOOTMEM
72d7c3b33   Yinghai Lu   x86: Use memblock...
445
  	kmemleak_free_part(__va(addr), size);
a9ce6bc15   Yinghai Lu   x86, memblock: Re...
446
  	memblock_x86_free_range(addr, addr + size);
08677214e   Yinghai Lu   x86: Make 64 bit ...
447
  #else
e2bf3cae5   Johannes Weiner   bootmem: factor o...
448
  	unsigned long start, end;
a5645a61b   Yinghai Lu   mm: allow reserve...
449

ec3a354bd   Catalin Marinas   kmemleak: Add cal...
450
  	kmemleak_free_part(__va(addr), size);
e2bf3cae5   Johannes Weiner   bootmem: factor o...
451
452
  	start = PFN_UP(addr);
  	end = PFN_DOWN(addr + size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
453

e2bf3cae5   Johannes Weiner   bootmem: factor o...
454
  	mark_bootmem(start, end, 0, 0);
08677214e   Yinghai Lu   x86: Make 64 bit ...
455
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
456
  }
a66fd7dae   Johannes Weiner   bootmem: add docu...
457
458
459
460
461
462
463
464
465
  /**
   * reserve_bootmem_node - mark a page range as reserved
   * @pgdat: node the range resides on
   * @physaddr: starting address of the range
   * @size: size of the range in bytes
   * @flags: reservation flags (see linux/bootmem.h)
   *
   * Partial pages will be reserved.
   *
e2bf3cae5   Johannes Weiner   bootmem: factor o...
466
   * The range must reside completely on the specified node.
a66fd7dae   Johannes Weiner   bootmem: add docu...
467
   */
223e8dc92   Johannes Weiner   bootmem: reorder ...
468
469
  int __init reserve_bootmem_node(pg_data_t *pgdat, unsigned long physaddr,
  				 unsigned long size, int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
470
  {
08677214e   Yinghai Lu   x86: Make 64 bit ...
471
472
473
474
  #ifdef CONFIG_NO_BOOTMEM
  	panic("no bootmem");
  	return 0;
  #else
e2bf3cae5   Johannes Weiner   bootmem: factor o...
475
  	unsigned long start, end;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
476

e2bf3cae5   Johannes Weiner   bootmem: factor o...
477
478
479
480
  	start = PFN_DOWN(physaddr);
  	end = PFN_UP(physaddr + size);
  
  	return mark_bootmem_node(pgdat->bdata, start, end, 1, flags);
08677214e   Yinghai Lu   x86: Make 64 bit ...
481
  #endif
223e8dc92   Johannes Weiner   bootmem: reorder ...
482
  }
5a982cbc7   Yinghai Lu   mm: fix boundary ...
483

a66fd7dae   Johannes Weiner   bootmem: add docu...
484
485
486
487
488
489
490
491
  /**
   * reserve_bootmem - mark a page range as usable
   * @addr: starting address of the range
   * @size: size of the range in bytes
   * @flags: reservation flags (see linux/bootmem.h)
   *
   * Partial pages will be reserved.
   *
e2bf3cae5   Johannes Weiner   bootmem: factor o...
492
   * The range must be contiguous but may span node boundaries.
a66fd7dae   Johannes Weiner   bootmem: add docu...
493
   */
223e8dc92   Johannes Weiner   bootmem: reorder ...
494
495
496
  int __init reserve_bootmem(unsigned long addr, unsigned long size,
  			    int flags)
  {
08677214e   Yinghai Lu   x86: Make 64 bit ...
497
498
499
500
  #ifdef CONFIG_NO_BOOTMEM
  	panic("no bootmem");
  	return 0;
  #else
e2bf3cae5   Johannes Weiner   bootmem: factor o...
501
  	unsigned long start, end;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
502

e2bf3cae5   Johannes Weiner   bootmem: factor o...
503
504
  	start = PFN_DOWN(addr);
  	end = PFN_UP(addr + size);
223e8dc92   Johannes Weiner   bootmem: reorder ...
505

e2bf3cae5   Johannes Weiner   bootmem: factor o...
506
  	return mark_bootmem(start, end, 1, flags);
08677214e   Yinghai Lu   x86: Make 64 bit ...
507
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
508
  }
08677214e   Yinghai Lu   x86: Make 64 bit ...
509
  #ifndef CONFIG_NO_BOOTMEM
f88eff74a   Yinghai Lu   bootmem, x86: Add...
510
511
512
513
514
  int __weak __init reserve_bootmem_generic(unsigned long phys, unsigned long len,
  				   int flags)
  {
  	return reserve_bootmem(phys, len, flags);
  }
8aa043d74   Jan Beulich   mm/bootmem.c: pro...
515
516
  static unsigned long __init align_idx(struct bootmem_data *bdata,
  				      unsigned long idx, unsigned long step)
481ebd0d7   Johannes Weiner   bootmem: fix alig...
517
518
519
520
521
522
523
524
525
526
  {
  	unsigned long base = bdata->node_min_pfn;
  
  	/*
  	 * Align the index with respect to the node start so that the
  	 * combination of both satisfies the requested alignment.
  	 */
  
  	return ALIGN(base + idx, step) - base;
  }
8aa043d74   Jan Beulich   mm/bootmem.c: pro...
527
528
  static unsigned long __init align_off(struct bootmem_data *bdata,
  				      unsigned long off, unsigned long align)
481ebd0d7   Johannes Weiner   bootmem: fix alig...
529
530
531
532
533
534
535
  {
  	unsigned long base = PFN_PHYS(bdata->node_min_pfn);
  
  	/* Same as align_idx for byte offsets */
  
  	return ALIGN(base + off, align) - base;
  }
d0c4f5702   Tejun Heo   bootmem, x86: fur...
536
537
538
  static void * __init alloc_bootmem_core(struct bootmem_data *bdata,
  					unsigned long size, unsigned long align,
  					unsigned long goal, unsigned long limit)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
539
  {
0f3caba21   Johannes Weiner   bootmem: respect ...
540
  	unsigned long fallback = 0;
5f2809e69   Johannes Weiner   bootmem: clean up...
541
  	unsigned long min, max, start, sidx, midx, step;
594fe1a04   Johannes Weiner   bootmem: print re...
542
543
544
545
  	bdebug("nid=%td size=%lx [%lu pages] align=%lx goal=%lx limit=%lx
  ",
  		bdata - bootmem_node_data, size, PAGE_ALIGN(size) >> PAGE_SHIFT,
  		align, goal, limit);
5f2809e69   Johannes Weiner   bootmem: clean up...
546
547
548
  	BUG_ON(!size);
  	BUG_ON(align & (align - 1));
  	BUG_ON(limit && goal + size > limit);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
549

7c309a64d   Christian Krafft   [PATCH] enable bo...
550
551
  	if (!bdata->node_bootmem_map)
  		return NULL;
3560e249a   Johannes Weiner   bootmem: replace ...
552
  	min = bdata->node_min_pfn;
5f2809e69   Johannes Weiner   bootmem: clean up...
553
  	max = bdata->node_low_pfn;
9a2dc04cf   Yinghai Lu   mm: offset align ...
554

5f2809e69   Johannes Weiner   bootmem: clean up...
555
556
557
558
559
560
  	goal >>= PAGE_SHIFT;
  	limit >>= PAGE_SHIFT;
  
  	if (limit && max > limit)
  		max = limit;
  	if (max <= min)
9a2dc04cf   Yinghai Lu   mm: offset align ...
561
  		return NULL;
5f2809e69   Johannes Weiner   bootmem: clean up...
562
  	step = max(align >> PAGE_SHIFT, 1UL);
281dd25cd   Yasunori Goto   [PATCH] swiotlb: ...
563

5f2809e69   Johannes Weiner   bootmem: clean up...
564
565
566
567
  	if (goal && min < goal && goal < max)
  		start = ALIGN(goal, step);
  	else
  		start = ALIGN(min, step);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
568

481ebd0d7   Johannes Weiner   bootmem: fix alig...
569
  	sidx = start - bdata->node_min_pfn;
3560e249a   Johannes Weiner   bootmem: replace ...
570
  	midx = max - bdata->node_min_pfn;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
571

5f2809e69   Johannes Weiner   bootmem: clean up...
572
  	if (bdata->hint_idx > sidx) {
0f3caba21   Johannes Weiner   bootmem: respect ...
573
574
575
576
577
  		/*
  		 * Handle the valid case of sidx being zero and still
  		 * catch the fallback below.
  		 */
  		fallback = sidx + 1;
481ebd0d7   Johannes Weiner   bootmem: fix alig...
578
  		sidx = align_idx(bdata, bdata->hint_idx, step);
5f2809e69   Johannes Weiner   bootmem: clean up...
579
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
580

5f2809e69   Johannes Weiner   bootmem: clean up...
581
582
583
584
585
586
  	while (1) {
  		int merge;
  		void *region;
  		unsigned long eidx, i, start_off, end_off;
  find_block:
  		sidx = find_next_zero_bit(bdata->node_bootmem_map, midx, sidx);
481ebd0d7   Johannes Weiner   bootmem: fix alig...
587
  		sidx = align_idx(bdata, sidx, step);
5f2809e69   Johannes Weiner   bootmem: clean up...
588
  		eidx = sidx + PFN_UP(size);
ad09315ca   Yinghai Lu   mm: fix alloc_boo...
589

5f2809e69   Johannes Weiner   bootmem: clean up...
590
  		if (sidx >= midx || eidx > midx)
66d43e98e   Haren Myneni   [PATCH] fix in __...
591
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
592

5f2809e69   Johannes Weiner   bootmem: clean up...
593
594
  		for (i = sidx; i < eidx; i++)
  			if (test_bit(i, bdata->node_bootmem_map)) {
481ebd0d7   Johannes Weiner   bootmem: fix alig...
595
  				sidx = align_idx(bdata, i, step);
5f2809e69   Johannes Weiner   bootmem: clean up...
596
597
598
599
  				if (sidx == i)
  					sidx += step;
  				goto find_block;
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
600

627240aaa   Mikulas Patocka   bootmem allocator...
601
  		if (bdata->last_end_off & (PAGE_SIZE - 1) &&
5f2809e69   Johannes Weiner   bootmem: clean up...
602
  				PFN_DOWN(bdata->last_end_off) + 1 == sidx)
481ebd0d7   Johannes Weiner   bootmem: fix alig...
603
  			start_off = align_off(bdata, bdata->last_end_off, align);
5f2809e69   Johannes Weiner   bootmem: clean up...
604
605
606
607
608
609
610
611
612
613
614
615
  		else
  			start_off = PFN_PHYS(sidx);
  
  		merge = PFN_DOWN(start_off) < sidx;
  		end_off = start_off + size;
  
  		bdata->last_end_off = end_off;
  		bdata->hint_idx = PFN_UP(end_off);
  
  		/*
  		 * Reserve the area now:
  		 */
d747fa4bc   Johannes Weiner   bootmem: free/res...
616
617
618
  		if (__reserve(bdata, PFN_DOWN(start_off) + merge,
  				PFN_UP(end_off), BOOTMEM_EXCLUSIVE))
  			BUG();
5f2809e69   Johannes Weiner   bootmem: clean up...
619

3560e249a   Johannes Weiner   bootmem: replace ...
620
621
  		region = phys_to_virt(PFN_PHYS(bdata->node_min_pfn) +
  				start_off);
5f2809e69   Johannes Weiner   bootmem: clean up...
622
  		memset(region, 0, size);
008139d91   Catalin Marinas   kmemleak: Do not ...
623
624
625
626
627
  		/*
  		 * The min_count is set to 0 so that bootmem allocated blocks
  		 * are never reported as leaks.
  		 */
  		kmemleak_alloc(region, size, 0, 0);
5f2809e69   Johannes Weiner   bootmem: clean up...
628
  		return region;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
629
  	}
0f3caba21   Johannes Weiner   bootmem: respect ...
630
  	if (fallback) {
481ebd0d7   Johannes Weiner   bootmem: fix alig...
631
  		sidx = align_idx(bdata, fallback - 1, step);
0f3caba21   Johannes Weiner   bootmem: respect ...
632
633
634
635
636
637
  		fallback = 0;
  		goto find_block;
  	}
  
  	return NULL;
  }
d0c4f5702   Tejun Heo   bootmem, x86: fur...
638
639
640
641
  static void * __init alloc_arch_preferred_bootmem(bootmem_data_t *bdata,
  					unsigned long size, unsigned long align,
  					unsigned long goal, unsigned long limit)
  {
441c7e0a2   Pekka Enberg   bootmem: use slab...
642
643
  	if (WARN_ON_ONCE(slab_is_available()))
  		return kzalloc(size, GFP_NOWAIT);
d0c4f5702   Tejun Heo   bootmem, x86: fur...
644
  #ifdef CONFIG_HAVE_ARCH_BOOTMEM
433f13a72   Joe Perches   bootmem.c: avoid ...
645
646
647
648
649
650
651
652
653
  	{
  		bootmem_data_t *p_bdata;
  
  		p_bdata = bootmem_arch_preferred_node(bdata, size, align,
  							goal, limit);
  		if (p_bdata)
  			return alloc_bootmem_core(p_bdata, size, align,
  							goal, limit);
  	}
d0c4f5702   Tejun Heo   bootmem, x86: fur...
654
655
656
  #endif
  	return NULL;
  }
08677214e   Yinghai Lu   x86: Make 64 bit ...
657
  #endif
d0c4f5702   Tejun Heo   bootmem, x86: fur...
658

0f3caba21   Johannes Weiner   bootmem: respect ...
659
660
661
662
663
  static void * __init ___alloc_bootmem_nopanic(unsigned long size,
  					unsigned long align,
  					unsigned long goal,
  					unsigned long limit)
  {
08677214e   Yinghai Lu   x86: Make 64 bit ...
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
  #ifdef CONFIG_NO_BOOTMEM
  	void *ptr;
  
  	if (WARN_ON_ONCE(slab_is_available()))
  		return kzalloc(size, GFP_NOWAIT);
  
  restart:
  
  	ptr = __alloc_memory_core_early(MAX_NUMNODES, size, align, goal, limit);
  
  	if (ptr)
  		return ptr;
  
  	if (goal != 0) {
  		goal = 0;
  		goto restart;
  	}
  
  	return NULL;
  #else
0f3caba21   Johannes Weiner   bootmem: respect ...
684
  	bootmem_data_t *bdata;
d0c4f5702   Tejun Heo   bootmem, x86: fur...
685
  	void *region;
0f3caba21   Johannes Weiner   bootmem: respect ...
686
687
  
  restart:
d0c4f5702   Tejun Heo   bootmem, x86: fur...
688
689
690
  	region = alloc_arch_preferred_bootmem(NULL, size, align, goal, limit);
  	if (region)
  		return region;
0f3caba21   Johannes Weiner   bootmem: respect ...
691

d0c4f5702   Tejun Heo   bootmem, x86: fur...
692
  	list_for_each_entry(bdata, &bdata_list, list) {
0f3caba21   Johannes Weiner   bootmem: respect ...
693
694
  		if (goal && bdata->node_low_pfn <= PFN_DOWN(goal))
  			continue;
3560e249a   Johannes Weiner   bootmem: replace ...
695
  		if (limit && bdata->node_min_pfn >= PFN_DOWN(limit))
0f3caba21   Johannes Weiner   bootmem: respect ...
696
697
698
699
700
701
  			break;
  
  		region = alloc_bootmem_core(bdata, size, align, goal, limit);
  		if (region)
  			return region;
  	}
5f2809e69   Johannes Weiner   bootmem: clean up...
702
703
  	if (goal) {
  		goal = 0;
0f3caba21   Johannes Weiner   bootmem: respect ...
704
  		goto restart;
5f2809e69   Johannes Weiner   bootmem: clean up...
705
  	}
2e5237daf   Johannes Weiner   bootmem: add debu...
706

5f2809e69   Johannes Weiner   bootmem: clean up...
707
  	return NULL;
08677214e   Yinghai Lu   x86: Make 64 bit ...
708
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
709
  }
a66fd7dae   Johannes Weiner   bootmem: add docu...
710
711
712
713
714
715
716
717
718
719
720
721
722
  /**
   * __alloc_bootmem_nopanic - allocate boot memory without panicking
   * @size: size of the request in bytes
   * @align: alignment of the region
   * @goal: preferred starting address of the region
   *
   * The goal is dropped if it can not be satisfied and the allocation will
   * fall back to memory below @goal.
   *
   * Allocation may happen on any node in the system.
   *
   * Returns NULL on failure.
   */
bb0923a66   Franck Bui-Huu   [PATCH] bootmem: ...
723
  void * __init __alloc_bootmem_nopanic(unsigned long size, unsigned long align,
0f3caba21   Johannes Weiner   bootmem: respect ...
724
  					unsigned long goal)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
725
  {
08677214e   Yinghai Lu   x86: Make 64 bit ...
726
727
728
729
730
731
732
  	unsigned long limit = 0;
  
  #ifdef CONFIG_NO_BOOTMEM
  	limit = -1UL;
  #endif
  
  	return ___alloc_bootmem_nopanic(size, align, goal, limit);
0f3caba21   Johannes Weiner   bootmem: respect ...
733
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
734

0f3caba21   Johannes Weiner   bootmem: respect ...
735
736
737
738
739
740
741
742
743
744
745
746
747
  static void * __init ___alloc_bootmem(unsigned long size, unsigned long align,
  					unsigned long goal, unsigned long limit)
  {
  	void *mem = ___alloc_bootmem_nopanic(size, align, goal, limit);
  
  	if (mem)
  		return mem;
  	/*
  	 * Whoops, we cannot satisfy the allocation request.
  	 */
  	printk(KERN_ALERT "bootmem alloc of %lu bytes failed!
  ", size);
  	panic("Out of memory");
a8062231d   Andi Kleen   [PATCH] x86_64: H...
748
749
  	return NULL;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
750

a66fd7dae   Johannes Weiner   bootmem: add docu...
751
752
753
754
755
756
757
758
759
760
761
762
763
  /**
   * __alloc_bootmem - allocate boot memory
   * @size: size of the request in bytes
   * @align: alignment of the region
   * @goal: preferred starting address of the region
   *
   * The goal is dropped if it can not be satisfied and the allocation will
   * fall back to memory below @goal.
   *
   * Allocation may happen on any node in the system.
   *
   * The function panics if the request can not be satisfied.
   */
bb0923a66   Franck Bui-Huu   [PATCH] bootmem: ...
764
765
  void * __init __alloc_bootmem(unsigned long size, unsigned long align,
  			      unsigned long goal)
a8062231d   Andi Kleen   [PATCH] x86_64: H...
766
  {
08677214e   Yinghai Lu   x86: Make 64 bit ...
767
768
769
770
771
772
773
  	unsigned long limit = 0;
  
  #ifdef CONFIG_NO_BOOTMEM
  	limit = -1UL;
  #endif
  
  	return ___alloc_bootmem(size, align, goal, limit);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
774
  }
08677214e   Yinghai Lu   x86: Make 64 bit ...
775
  #ifndef CONFIG_NO_BOOTMEM
4cc278b72   Johannes Weiner   bootmem: Make __a...
776
777
778
779
780
  static void * __init ___alloc_bootmem_node(bootmem_data_t *bdata,
  				unsigned long size, unsigned long align,
  				unsigned long goal, unsigned long limit)
  {
  	void *ptr;
d0c4f5702   Tejun Heo   bootmem, x86: fur...
781
782
783
  	ptr = alloc_arch_preferred_bootmem(bdata, size, align, goal, limit);
  	if (ptr)
  		return ptr;
4cc278b72   Johannes Weiner   bootmem: Make __a...
784
785
786
787
788
789
  	ptr = alloc_bootmem_core(bdata, size, align, goal, limit);
  	if (ptr)
  		return ptr;
  
  	return ___alloc_bootmem(size, align, goal, limit);
  }
08677214e   Yinghai Lu   x86: Make 64 bit ...
790
  #endif
4cc278b72   Johannes Weiner   bootmem: Make __a...
791

a66fd7dae   Johannes Weiner   bootmem: add docu...
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
  /**
   * __alloc_bootmem_node - allocate boot memory from a specific node
   * @pgdat: node to allocate from
   * @size: size of the request in bytes
   * @align: alignment of the region
   * @goal: preferred starting address of the region
   *
   * The goal is dropped if it can not be satisfied and the allocation will
   * fall back to memory below @goal.
   *
   * Allocation may fall back to any node in the system if the specified node
   * can not hold the requested memory.
   *
   * The function panics if the request can not be satisfied.
   */
bb0923a66   Franck Bui-Huu   [PATCH] bootmem: ...
807
808
  void * __init __alloc_bootmem_node(pg_data_t *pgdat, unsigned long size,
  				   unsigned long align, unsigned long goal)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
809
  {
b8ab9f820   Yinghai Lu   x86,nobootmem: ma...
810
  	void *ptr;
c91c4773b   Pekka Enberg   bootmem: fix slab...
811
812
  	if (WARN_ON_ONCE(slab_is_available()))
  		return kzalloc_node(size, GFP_NOWAIT, pgdat->node_id);
08677214e   Yinghai Lu   x86: Make 64 bit ...
813
  #ifdef CONFIG_NO_BOOTMEM
b8ab9f820   Yinghai Lu   x86,nobootmem: ma...
814
815
816
817
818
819
  	ptr = __alloc_memory_core_early(pgdat->node_id, size, align,
  					 goal, -1ULL);
  	if (ptr)
  		return ptr;
  
  	ptr = __alloc_memory_core_early(MAX_NUMNODES, size, align,
08677214e   Yinghai Lu   x86: Make 64 bit ...
820
821
  					 goal, -1ULL);
  #else
b8ab9f820   Yinghai Lu   x86,nobootmem: ma...
822
  	ptr = ___alloc_bootmem_node(pgdat->bdata, size, align, goal, 0);
08677214e   Yinghai Lu   x86: Make 64 bit ...
823
  #endif
b8ab9f820   Yinghai Lu   x86,nobootmem: ma...
824
825
  
  	return ptr;
08677214e   Yinghai Lu   x86: Make 64 bit ...
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
  }
  
  void * __init __alloc_bootmem_node_high(pg_data_t *pgdat, unsigned long size,
  				   unsigned long align, unsigned long goal)
  {
  #ifdef MAX_DMA32_PFN
  	unsigned long end_pfn;
  
  	if (WARN_ON_ONCE(slab_is_available()))
  		return kzalloc_node(size, GFP_NOWAIT, pgdat->node_id);
  
  	/* update goal according ...MAX_DMA32_PFN */
  	end_pfn = pgdat->node_start_pfn + pgdat->node_spanned_pages;
  
  	if (end_pfn > MAX_DMA32_PFN + (128 >> (20 - PAGE_SHIFT)) &&
  	    (goal >> PAGE_SHIFT) < MAX_DMA32_PFN) {
  		void *ptr;
  		unsigned long new_goal;
  
  		new_goal = MAX_DMA32_PFN << PAGE_SHIFT;
  #ifdef CONFIG_NO_BOOTMEM
  		ptr =  __alloc_memory_core_early(pgdat->node_id, size, align,
  						 new_goal, -1ULL);
  #else
  		ptr = alloc_bootmem_core(pgdat->bdata, size, align,
  						 new_goal, 0);
  #endif
  		if (ptr)
  			return ptr;
  	}
  #endif
  
  	return __alloc_bootmem_node(pgdat, size, align, goal);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
859
  }
e70260aab   Yasunori Goto   memory hotplug: m...
860
  #ifdef CONFIG_SPARSEMEM
a66fd7dae   Johannes Weiner   bootmem: add docu...
861
862
863
864
865
866
867
  /**
   * alloc_bootmem_section - allocate boot memory from a specific section
   * @size: size of the request in bytes
   * @section_nr: sparse map section to allocate from
   *
   * Return NULL on failure.
   */
e70260aab   Yasunori Goto   memory hotplug: m...
868
869
870
  void * __init alloc_bootmem_section(unsigned long size,
  				    unsigned long section_nr)
  {
08677214e   Yinghai Lu   x86: Make 64 bit ...
871
872
873
874
875
876
877
878
879
880
  #ifdef CONFIG_NO_BOOTMEM
  	unsigned long pfn, goal, limit;
  
  	pfn = section_nr_to_pfn(section_nr);
  	goal = pfn << PAGE_SHIFT;
  	limit = section_nr_to_pfn(section_nr + 1) << PAGE_SHIFT;
  
  	return __alloc_memory_core_early(early_pfn_to_nid(pfn), size,
  					 SMP_CACHE_BYTES, goal, limit);
  #else
75a56cfe9   Johannes Weiner   bootmem: revisit ...
881
882
  	bootmem_data_t *bdata;
  	unsigned long pfn, goal, limit;
e70260aab   Yasunori Goto   memory hotplug: m...
883
884
  
  	pfn = section_nr_to_pfn(section_nr);
75a56cfe9   Johannes Weiner   bootmem: revisit ...
885
886
887
  	goal = pfn << PAGE_SHIFT;
  	limit = section_nr_to_pfn(section_nr + 1) << PAGE_SHIFT;
  	bdata = &bootmem_node_data[early_pfn_to_nid(pfn)];
e70260aab   Yasunori Goto   memory hotplug: m...
888

75a56cfe9   Johannes Weiner   bootmem: revisit ...
889
  	return alloc_bootmem_core(bdata, size, SMP_CACHE_BYTES, goal, limit);
08677214e   Yinghai Lu   x86: Make 64 bit ...
890
  #endif
e70260aab   Yasunori Goto   memory hotplug: m...
891
892
  }
  #endif
b54bbf7b8   Andi Kleen   mm: introduce non...
893
894
895
896
  void * __init __alloc_bootmem_node_nopanic(pg_data_t *pgdat, unsigned long size,
  				   unsigned long align, unsigned long goal)
  {
  	void *ptr;
c91c4773b   Pekka Enberg   bootmem: fix slab...
897
898
  	if (WARN_ON_ONCE(slab_is_available()))
  		return kzalloc_node(size, GFP_NOWAIT, pgdat->node_id);
08677214e   Yinghai Lu   x86: Make 64 bit ...
899
900
901
902
  #ifdef CONFIG_NO_BOOTMEM
  	ptr =  __alloc_memory_core_early(pgdat->node_id, size, align,
  						 goal, -1ULL);
  #else
d0c4f5702   Tejun Heo   bootmem, x86: fur...
903
904
905
  	ptr = alloc_arch_preferred_bootmem(pgdat->bdata, size, align, goal, 0);
  	if (ptr)
  		return ptr;
b54bbf7b8   Andi Kleen   mm: introduce non...
906
  	ptr = alloc_bootmem_core(pgdat->bdata, size, align, goal, 0);
08677214e   Yinghai Lu   x86: Make 64 bit ...
907
  #endif
b54bbf7b8   Andi Kleen   mm: introduce non...
908
909
910
911
912
  	if (ptr)
  		return ptr;
  
  	return __alloc_bootmem_nopanic(size, align, goal);
  }
dfd54cbcc   Heiko Carstens   [PATCH] bootmem: ...
913
914
915
  #ifndef ARCH_LOW_ADDRESS_LIMIT
  #define ARCH_LOW_ADDRESS_LIMIT	0xffffffffUL
  #endif
008857c1a   Ravikiran G Thirumalai   [PATCH] Cleanup b...
916

a66fd7dae   Johannes Weiner   bootmem: add docu...
917
918
919
920
921
922
923
924
925
926
927
928
929
  /**
   * __alloc_bootmem_low - allocate low boot memory
   * @size: size of the request in bytes
   * @align: alignment of the region
   * @goal: preferred starting address of the region
   *
   * The goal is dropped if it can not be satisfied and the allocation will
   * fall back to memory below @goal.
   *
   * Allocation may happen on any node in the system.
   *
   * The function panics if the request can not be satisfied.
   */
bb0923a66   Franck Bui-Huu   [PATCH] bootmem: ...
930
931
  void * __init __alloc_bootmem_low(unsigned long size, unsigned long align,
  				  unsigned long goal)
008857c1a   Ravikiran G Thirumalai   [PATCH] Cleanup b...
932
  {
0f3caba21   Johannes Weiner   bootmem: respect ...
933
  	return ___alloc_bootmem(size, align, goal, ARCH_LOW_ADDRESS_LIMIT);
008857c1a   Ravikiran G Thirumalai   [PATCH] Cleanup b...
934
  }
a66fd7dae   Johannes Weiner   bootmem: add docu...
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
  /**
   * __alloc_bootmem_low_node - allocate low boot memory from a specific node
   * @pgdat: node to allocate from
   * @size: size of the request in bytes
   * @align: alignment of the region
   * @goal: preferred starting address of the region
   *
   * The goal is dropped if it can not be satisfied and the allocation will
   * fall back to memory below @goal.
   *
   * Allocation may fall back to any node in the system if the specified node
   * can not hold the requested memory.
   *
   * The function panics if the request can not be satisfied.
   */
008857c1a   Ravikiran G Thirumalai   [PATCH] Cleanup b...
950
951
952
  void * __init __alloc_bootmem_low_node(pg_data_t *pgdat, unsigned long size,
  				       unsigned long align, unsigned long goal)
  {
b8ab9f820   Yinghai Lu   x86,nobootmem: ma...
953
  	void *ptr;
c91c4773b   Pekka Enberg   bootmem: fix slab...
954
955
  	if (WARN_ON_ONCE(slab_is_available()))
  		return kzalloc_node(size, GFP_NOWAIT, pgdat->node_id);
08677214e   Yinghai Lu   x86: Make 64 bit ...
956
  #ifdef CONFIG_NO_BOOTMEM
b8ab9f820   Yinghai Lu   x86,nobootmem: ma...
957
958
959
960
961
  	ptr = __alloc_memory_core_early(pgdat->node_id, size, align,
  				goal, ARCH_LOW_ADDRESS_LIMIT);
  	if (ptr)
  		return ptr;
  	ptr = __alloc_memory_core_early(MAX_NUMNODES, size, align,
08677214e   Yinghai Lu   x86: Make 64 bit ...
962
963
  				goal, ARCH_LOW_ADDRESS_LIMIT);
  #else
b8ab9f820   Yinghai Lu   x86,nobootmem: ma...
964
  	ptr = ___alloc_bootmem_node(pgdat->bdata, size, align,
4cc278b72   Johannes Weiner   bootmem: Make __a...
965
  				goal, ARCH_LOW_ADDRESS_LIMIT);
08677214e   Yinghai Lu   x86: Make 64 bit ...
966
  #endif
b8ab9f820   Yinghai Lu   x86,nobootmem: ma...
967
  	return ptr;
008857c1a   Ravikiran G Thirumalai   [PATCH] Cleanup b...
968
  }