Blame view

mm/memblock.c 28.4 KB
95f72d1ed   Yinghai Lu   lmb: rename to me...
1
2
3
4
5
6
7
8
9
10
11
12
13
  /*
   * 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>
142b45a72   Benjamin Herrenschmidt   memblock: Add arr...
14
  #include <linux/slab.h>
95f72d1ed   Yinghai Lu   lmb: rename to me...
15
16
  #include <linux/init.h>
  #include <linux/bitops.h>
449e8df39   Benjamin Herrenschmidt   memblock: Add deb...
17
  #include <linux/poison.h>
c196f76fd   Benjamin Herrenschmidt   memblock: NUMA al...
18
  #include <linux/pfn.h>
6d03b885f   Benjamin Herrenschmidt   memblock: Add deb...
19
20
  #include <linux/debugfs.h>
  #include <linux/seq_file.h>
95f72d1ed   Yinghai Lu   lmb: rename to me...
21
  #include <linux/memblock.h>
fe091c208   Tejun Heo   memblock: Kill me...
22
23
24
25
26
27
28
29
30
31
32
33
34
35
  static struct memblock_region memblock_memory_init_regions[INIT_MEMBLOCK_REGIONS] __initdata_memblock;
  static struct memblock_region memblock_reserved_init_regions[INIT_MEMBLOCK_REGIONS] __initdata_memblock;
  
  struct memblock memblock __initdata_memblock = {
  	.memory.regions		= memblock_memory_init_regions,
  	.memory.cnt		= 1,	/* empty dummy entry */
  	.memory.max		= INIT_MEMBLOCK_REGIONS,
  
  	.reserved.regions	= memblock_reserved_init_regions,
  	.reserved.cnt		= 1,	/* empty dummy entry */
  	.reserved.max		= INIT_MEMBLOCK_REGIONS,
  
  	.current_limit		= MEMBLOCK_ALLOC_ANYWHERE,
  };
95f72d1ed   Yinghai Lu   lmb: rename to me...
36

10d064398   Yinghai Lu   memblock: Option ...
37
  int memblock_debug __initdata_memblock;
1aadc0560   Tejun Heo   memblock: s/membl...
38
  static int memblock_can_resize __initdata_memblock;
181eb3942   Gavin Shan   mm/memblock: fix ...
39
40
  static int memblock_memory_in_slab __initdata_memblock = 0;
  static int memblock_reserved_in_slab __initdata_memblock = 0;
95f72d1ed   Yinghai Lu   lmb: rename to me...
41

142b45a72   Benjamin Herrenschmidt   memblock: Add arr...
42
43
44
45
46
47
48
49
50
51
  /* inline so we don't get a warning when pr_debug is compiled out */
  static inline const char *memblock_type_name(struct memblock_type *type)
  {
  	if (type == &memblock.memory)
  		return "memory";
  	else if (type == &memblock.reserved)
  		return "reserved";
  	else
  		return "unknown";
  }
eb18f1b5b   Tejun Heo   memblock: Make me...
52
53
54
55
56
  /* adjust *@size so that (@base + *@size) doesn't overflow, return new size */
  static inline phys_addr_t memblock_cap_size(phys_addr_t base, phys_addr_t *size)
  {
  	return *size = min(*size, (phys_addr_t)ULLONG_MAX - base);
  }
6ed311b28   Benjamin Herrenschmidt   memblock: Move fu...
57
58
59
  /*
   * Address comparison utilities
   */
10d064398   Yinghai Lu   memblock: Option ...
60
  static unsigned long __init_memblock memblock_addrs_overlap(phys_addr_t base1, phys_addr_t size1,
2898cc4cd   Benjamin Herrenschmidt   memblock: Change ...
61
  				       phys_addr_t base2, phys_addr_t size2)
95f72d1ed   Yinghai Lu   lmb: rename to me...
62
63
64
  {
  	return ((base1 < (base2 + size2)) && (base2 < (base1 + size1)));
  }
2d7d3eb2b   H Hartley Sweeten   mm/memblock.c: qu...
65
66
  static long __init_memblock memblock_overlaps_region(struct memblock_type *type,
  					phys_addr_t base, phys_addr_t size)
6ed311b28   Benjamin Herrenschmidt   memblock: Move fu...
67
68
69
70
71
72
73
74
75
76
77
78
  {
  	unsigned long i;
  
  	for (i = 0; i < type->cnt; i++) {
  		phys_addr_t rgnbase = type->regions[i].base;
  		phys_addr_t rgnsize = type->regions[i].size;
  		if (memblock_addrs_overlap(base, size, rgnbase, rgnsize))
  			break;
  	}
  
  	return (i < type->cnt) ? i : -1;
  }
7bd0b0f0d   Tejun Heo   memblock: Reimple...
79
80
81
82
83
84
85
86
87
88
89
90
  /**
   * memblock_find_in_range_node - find free area in given range and node
   * @start: start of candidate range
   * @end: end of candidate range, can be %MEMBLOCK_ALLOC_{ANYWHERE|ACCESSIBLE}
   * @size: size of free area to find
   * @align: alignment of free area to find
   * @nid: nid of the free area to find, %MAX_NUMNODES for any node
   *
   * Find @size free area aligned to @align in the specified range and node.
   *
   * RETURNS:
   * Found address on success, %0 on failure.
6ed311b28   Benjamin Herrenschmidt   memblock: Move fu...
91
   */
7bd0b0f0d   Tejun Heo   memblock: Reimple...
92
93
94
  phys_addr_t __init_memblock memblock_find_in_range_node(phys_addr_t start,
  					phys_addr_t end, phys_addr_t size,
  					phys_addr_t align, int nid)
6ed311b28   Benjamin Herrenschmidt   memblock: Move fu...
95
  {
7bd0b0f0d   Tejun Heo   memblock: Reimple...
96
97
  	phys_addr_t this_start, this_end, cand;
  	u64 i;
6ed311b28   Benjamin Herrenschmidt   memblock: Move fu...
98

7bd0b0f0d   Tejun Heo   memblock: Reimple...
99
100
101
  	/* pump up @end */
  	if (end == MEMBLOCK_ALLOC_ACCESSIBLE)
  		end = memblock.current_limit;
f1af98c76   Yinghai Lu   memblock: Fix wra...
102

5d53cb27d   Tejun Heo   memblock: Fix all...
103
104
  	/* avoid allocating the first page */
  	start = max_t(phys_addr_t, start, PAGE_SIZE);
7bd0b0f0d   Tejun Heo   memblock: Reimple...
105
  	end = max(start, end);
f1af98c76   Yinghai Lu   memblock: Fix wra...
106

7bd0b0f0d   Tejun Heo   memblock: Reimple...
107
108
109
  	for_each_free_mem_range_reverse(i, nid, &this_start, &this_end, NULL) {
  		this_start = clamp(this_start, start, end);
  		this_end = clamp(this_end, start, end);
6ed311b28   Benjamin Herrenschmidt   memblock: Move fu...
110

5d53cb27d   Tejun Heo   memblock: Fix all...
111
112
  		if (this_end < size)
  			continue;
7bd0b0f0d   Tejun Heo   memblock: Reimple...
113
114
115
116
  		cand = round_down(this_end - size, align);
  		if (cand >= this_start)
  			return cand;
  	}
1f5026a7e   Tejun Heo   memblock: Kill ME...
117
  	return 0;
6ed311b28   Benjamin Herrenschmidt   memblock: Move fu...
118
  }
7bd0b0f0d   Tejun Heo   memblock: Reimple...
119
120
121
122
123
124
125
126
127
128
129
  /**
   * memblock_find_in_range - find free area in given range
   * @start: start of candidate range
   * @end: end of candidate range, can be %MEMBLOCK_ALLOC_{ANYWHERE|ACCESSIBLE}
   * @size: size of free area to find
   * @align: alignment of free area to find
   *
   * Find @size free area aligned to @align in the specified range.
   *
   * RETURNS:
   * Found address on success, %0 on failure.
fc769a8e7   Tejun Heo   memblock: Replace...
130
   */
7bd0b0f0d   Tejun Heo   memblock: Reimple...
131
132
133
  phys_addr_t __init_memblock memblock_find_in_range(phys_addr_t start,
  					phys_addr_t end, phys_addr_t size,
  					phys_addr_t align)
6ed311b28   Benjamin Herrenschmidt   memblock: Move fu...
134
  {
7bd0b0f0d   Tejun Heo   memblock: Reimple...
135
136
  	return memblock_find_in_range_node(start, end, size, align,
  					   MAX_NUMNODES);
6ed311b28   Benjamin Herrenschmidt   memblock: Move fu...
137
  }
10d064398   Yinghai Lu   memblock: Option ...
138
  static void __init_memblock memblock_remove_region(struct memblock_type *type, unsigned long r)
95f72d1ed   Yinghai Lu   lmb: rename to me...
139
  {
1440c4e2c   Tejun Heo   memblock: Track t...
140
  	type->total_size -= type->regions[r].size;
7c0caeb86   Tejun Heo   memblock: Add opt...
141
142
  	memmove(&type->regions[r], &type->regions[r + 1],
  		(type->cnt - (r + 1)) * sizeof(type->regions[r]));
e3239ff92   Benjamin Herrenschmidt   memblock: Rename ...
143
  	type->cnt--;
95f72d1ed   Yinghai Lu   lmb: rename to me...
144

8f7a66051   Benjamin Herrenschmidt   mm/memblock: prop...
145
146
  	/* Special case for empty arrays */
  	if (type->cnt == 0) {
1440c4e2c   Tejun Heo   memblock: Track t...
147
  		WARN_ON(type->total_size != 0);
8f7a66051   Benjamin Herrenschmidt   mm/memblock: prop...
148
149
150
  		type->cnt = 1;
  		type->regions[0].base = 0;
  		type->regions[0].size = 0;
7c0caeb86   Tejun Heo   memblock: Add opt...
151
  		memblock_set_region_node(&type->regions[0], MAX_NUMNODES);
8f7a66051   Benjamin Herrenschmidt   mm/memblock: prop...
152
  	}
95f72d1ed   Yinghai Lu   lmb: rename to me...
153
  }
29f673860   Yinghai Lu   memblock: free al...
154
155
156
157
158
159
160
161
162
163
164
  phys_addr_t __init_memblock get_allocated_memblock_reserved_regions_info(
  					phys_addr_t *addr)
  {
  	if (memblock.reserved.regions == memblock_reserved_init_regions)
  		return 0;
  
  	*addr = __pa(memblock.reserved.regions);
  
  	return PAGE_ALIGN(sizeof(struct memblock_region) *
  			  memblock.reserved.max);
  }
48c3b583b   Greg Pearson   mm/memblock: fix ...
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
  /**
   * memblock_double_array - double the size of the memblock regions array
   * @type: memblock type of the regions array being doubled
   * @new_area_start: starting address of memory range to avoid overlap with
   * @new_area_size: size of memory range to avoid overlap with
   *
   * Double the size of the @type regions array. If memblock is being used to
   * allocate memory for a new reserved regions array and there is a previously
   * allocated memory range [@new_area_start,@new_area_start+@new_area_size]
   * waiting to be reserved, ensure the memory used by the new array does
   * not overlap.
   *
   * RETURNS:
   * 0 on success, -1 on failure.
   */
  static int __init_memblock memblock_double_array(struct memblock_type *type,
  						phys_addr_t new_area_start,
  						phys_addr_t new_area_size)
142b45a72   Benjamin Herrenschmidt   memblock: Add arr...
183
184
  {
  	struct memblock_region *new_array, *old_array;
29f673860   Yinghai Lu   memblock: free al...
185
  	phys_addr_t old_alloc_size, new_alloc_size;
142b45a72   Benjamin Herrenschmidt   memblock: Add arr...
186
187
  	phys_addr_t old_size, new_size, addr;
  	int use_slab = slab_is_available();
181eb3942   Gavin Shan   mm/memblock: fix ...
188
  	int *in_slab;
142b45a72   Benjamin Herrenschmidt   memblock: Add arr...
189
190
191
192
193
194
  
  	/* We don't allow resizing until we know about the reserved regions
  	 * of memory that aren't suitable for allocation
  	 */
  	if (!memblock_can_resize)
  		return -1;
142b45a72   Benjamin Herrenschmidt   memblock: Add arr...
195
196
197
  	/* Calculate new doubled size */
  	old_size = type->max * sizeof(struct memblock_region);
  	new_size = old_size << 1;
29f673860   Yinghai Lu   memblock: free al...
198
199
200
201
202
203
  	/*
  	 * We need to allocated new one align to PAGE_SIZE,
  	 *   so we can free them completely later.
  	 */
  	old_alloc_size = PAGE_ALIGN(old_size);
  	new_alloc_size = PAGE_ALIGN(new_size);
142b45a72   Benjamin Herrenschmidt   memblock: Add arr...
204

181eb3942   Gavin Shan   mm/memblock: fix ...
205
206
207
208
209
  	/* Retrieve the slab flag */
  	if (type == &memblock.memory)
  		in_slab = &memblock_memory_in_slab;
  	else
  		in_slab = &memblock_reserved_in_slab;
142b45a72   Benjamin Herrenschmidt   memblock: Add arr...
210
211
212
  	/* Try to find some space for it.
  	 *
  	 * WARNING: We assume that either slab_is_available() and we use it or
fd07383b6   Andrew Morton   mm/memblock.c:mem...
213
214
215
  	 * we use MEMBLOCK for allocations. That means that this is unsafe to
  	 * use when bootmem is currently active (unless bootmem itself is
  	 * implemented on top of MEMBLOCK which isn't the case yet)
142b45a72   Benjamin Herrenschmidt   memblock: Add arr...
216
217
  	 *
  	 * This should however not be an issue for now, as we currently only
fd07383b6   Andrew Morton   mm/memblock.c:mem...
218
219
  	 * call into MEMBLOCK while it's still active, or much later when slab
  	 * is active for memory hotplug operations
142b45a72   Benjamin Herrenschmidt   memblock: Add arr...
220
221
222
  	 */
  	if (use_slab) {
  		new_array = kmalloc(new_size, GFP_KERNEL);
1f5026a7e   Tejun Heo   memblock: Kill ME...
223
  		addr = new_array ? __pa(new_array) : 0;
4e2f07750   Gavin Shan   mm/memblock: clea...
224
  	} else {
48c3b583b   Greg Pearson   mm/memblock: fix ...
225
226
227
228
229
230
  		/* only exclude range when trying to double reserved.regions */
  		if (type != &memblock.reserved)
  			new_area_start = new_area_size = 0;
  
  		addr = memblock_find_in_range(new_area_start + new_area_size,
  						memblock.current_limit,
29f673860   Yinghai Lu   memblock: free al...
231
  						new_alloc_size, PAGE_SIZE);
48c3b583b   Greg Pearson   mm/memblock: fix ...
232
233
  		if (!addr && new_area_size)
  			addr = memblock_find_in_range(0,
fd07383b6   Andrew Morton   mm/memblock.c:mem...
234
235
  				min(new_area_start, memblock.current_limit),
  				new_alloc_size, PAGE_SIZE);
48c3b583b   Greg Pearson   mm/memblock: fix ...
236

4e2f07750   Gavin Shan   mm/memblock: clea...
237
238
  		new_array = addr ? __va(addr) : 0;
  	}
1f5026a7e   Tejun Heo   memblock: Kill ME...
239
  	if (!addr) {
142b45a72   Benjamin Herrenschmidt   memblock: Add arr...
240
241
242
243
244
  		pr_err("memblock: Failed to double %s array from %ld to %ld entries !
  ",
  		       memblock_type_name(type), type->max, type->max * 2);
  		return -1;
  	}
142b45a72   Benjamin Herrenschmidt   memblock: Add arr...
245

fd07383b6   Andrew Morton   mm/memblock.c:mem...
246
247
248
  	memblock_dbg("memblock: %s is doubled to %ld at [%#010llx-%#010llx]",
  			memblock_type_name(type), type->max * 2, (u64)addr,
  			(u64)addr + new_size - 1);
ea9e4376b   Yinghai Lu   memblock: Improve...
249

fd07383b6   Andrew Morton   mm/memblock.c:mem...
250
251
252
253
  	/*
  	 * Found space, we now need to move the array over before we add the
  	 * reserved region since it may be our reserved array itself that is
  	 * full.
142b45a72   Benjamin Herrenschmidt   memblock: Add arr...
254
255
256
257
258
259
  	 */
  	memcpy(new_array, type->regions, old_size);
  	memset(new_array + type->max, 0, old_size);
  	old_array = type->regions;
  	type->regions = new_array;
  	type->max <<= 1;
fd07383b6   Andrew Morton   mm/memblock.c:mem...
260
  	/* Free old array. We needn't free it if the array is the static one */
181eb3942   Gavin Shan   mm/memblock: fix ...
261
262
263
264
  	if (*in_slab)
  		kfree(old_array);
  	else if (old_array != memblock_memory_init_regions &&
  		 old_array != memblock_reserved_init_regions)
29f673860   Yinghai Lu   memblock: free al...
265
  		memblock_free(__pa(old_array), old_alloc_size);
142b45a72   Benjamin Herrenschmidt   memblock: Add arr...
266

fd07383b6   Andrew Morton   mm/memblock.c:mem...
267
268
269
  	/*
  	 * Reserve the new array if that comes from the memblock.  Otherwise, we
  	 * needn't do it
181eb3942   Gavin Shan   mm/memblock: fix ...
270
271
  	 */
  	if (!use_slab)
29f673860   Yinghai Lu   memblock: free al...
272
  		BUG_ON(memblock_reserve(addr, new_alloc_size));
181eb3942   Gavin Shan   mm/memblock: fix ...
273
274
275
  
  	/* Update slab flag */
  	*in_slab = use_slab;
142b45a72   Benjamin Herrenschmidt   memblock: Add arr...
276
277
  	return 0;
  }
784656f9c   Tejun Heo   memblock: Reimple...
278
279
280
281
282
283
284
  /**
   * memblock_merge_regions - merge neighboring compatible regions
   * @type: memblock type to scan
   *
   * Scan @type and merge neighboring compatible regions.
   */
  static void __init_memblock memblock_merge_regions(struct memblock_type *type)
95f72d1ed   Yinghai Lu   lmb: rename to me...
285
  {
784656f9c   Tejun Heo   memblock: Reimple...
286
  	int i = 0;
95f72d1ed   Yinghai Lu   lmb: rename to me...
287

784656f9c   Tejun Heo   memblock: Reimple...
288
289
290
291
  	/* cnt never goes below 1 */
  	while (i < type->cnt - 1) {
  		struct memblock_region *this = &type->regions[i];
  		struct memblock_region *next = &type->regions[i + 1];
95f72d1ed   Yinghai Lu   lmb: rename to me...
292

7c0caeb86   Tejun Heo   memblock: Add opt...
293
294
295
  		if (this->base + this->size != next->base ||
  		    memblock_get_region_node(this) !=
  		    memblock_get_region_node(next)) {
784656f9c   Tejun Heo   memblock: Reimple...
296
297
298
  			BUG_ON(this->base + this->size > next->base);
  			i++;
  			continue;
8f7a66051   Benjamin Herrenschmidt   mm/memblock: prop...
299
  		}
784656f9c   Tejun Heo   memblock: Reimple...
300
301
302
  		this->size += next->size;
  		memmove(next, next + 1, (type->cnt - (i + 1)) * sizeof(*next));
  		type->cnt--;
95f72d1ed   Yinghai Lu   lmb: rename to me...
303
  	}
784656f9c   Tejun Heo   memblock: Reimple...
304
  }
95f72d1ed   Yinghai Lu   lmb: rename to me...
305

784656f9c   Tejun Heo   memblock: Reimple...
306
307
308
309
310
311
312
313
314
315
316
317
  /**
   * memblock_insert_region - insert new memblock region
   * @type: memblock type to insert into
   * @idx: index for the insertion point
   * @base: base address of the new region
   * @size: size of the new region
   *
   * Insert new memblock region [@base,@base+@size) into @type at @idx.
   * @type must already have extra room to accomodate the new region.
   */
  static void __init_memblock memblock_insert_region(struct memblock_type *type,
  						   int idx, phys_addr_t base,
7c0caeb86   Tejun Heo   memblock: Add opt...
318
  						   phys_addr_t size, int nid)
784656f9c   Tejun Heo   memblock: Reimple...
319
320
321
322
323
324
325
  {
  	struct memblock_region *rgn = &type->regions[idx];
  
  	BUG_ON(type->cnt >= type->max);
  	memmove(rgn + 1, rgn, (type->cnt - idx) * sizeof(*rgn));
  	rgn->base = base;
  	rgn->size = size;
7c0caeb86   Tejun Heo   memblock: Add opt...
326
  	memblock_set_region_node(rgn, nid);
784656f9c   Tejun Heo   memblock: Reimple...
327
  	type->cnt++;
1440c4e2c   Tejun Heo   memblock: Track t...
328
  	type->total_size += size;
784656f9c   Tejun Heo   memblock: Reimple...
329
330
331
332
333
334
335
  }
  
  /**
   * memblock_add_region - add new memblock region
   * @type: memblock type to add new region into
   * @base: base address of the new region
   * @size: size of the new region
7fb0bc3f0   Tejun Heo   memblock: Impleme...
336
   * @nid: nid of the new region
784656f9c   Tejun Heo   memblock: Reimple...
337
338
339
340
341
342
343
344
345
   *
   * Add new memblock region [@base,@base+@size) into @type.  The new region
   * is allowed to overlap with existing ones - overlaps don't affect already
   * existing regions.  @type is guaranteed to be minimal (all neighbouring
   * compatible regions are merged) after the addition.
   *
   * RETURNS:
   * 0 on success, -errno on failure.
   */
581adcbe1   Tejun Heo   memblock: Make me...
346
  static int __init_memblock memblock_add_region(struct memblock_type *type,
7fb0bc3f0   Tejun Heo   memblock: Impleme...
347
  				phys_addr_t base, phys_addr_t size, int nid)
784656f9c   Tejun Heo   memblock: Reimple...
348
349
  {
  	bool insert = false;
eb18f1b5b   Tejun Heo   memblock: Make me...
350
351
  	phys_addr_t obase = base;
  	phys_addr_t end = base + memblock_cap_size(base, &size);
784656f9c   Tejun Heo   memblock: Reimple...
352
  	int i, nr_new;
b3dc627ca   Tejun Heo   memblock: membloc...
353
354
  	if (!size)
  		return 0;
784656f9c   Tejun Heo   memblock: Reimple...
355
356
  	/* special case for empty array */
  	if (type->regions[0].size == 0) {
1440c4e2c   Tejun Heo   memblock: Track t...
357
  		WARN_ON(type->cnt != 1 || type->total_size);
8f7a66051   Benjamin Herrenschmidt   mm/memblock: prop...
358
359
  		type->regions[0].base = base;
  		type->regions[0].size = size;
7fb0bc3f0   Tejun Heo   memblock: Impleme...
360
  		memblock_set_region_node(&type->regions[0], nid);
1440c4e2c   Tejun Heo   memblock: Track t...
361
  		type->total_size = size;
8f7a66051   Benjamin Herrenschmidt   mm/memblock: prop...
362
  		return 0;
95f72d1ed   Yinghai Lu   lmb: rename to me...
363
  	}
784656f9c   Tejun Heo   memblock: Reimple...
364
365
366
367
368
  repeat:
  	/*
  	 * The following is executed twice.  Once with %false @insert and
  	 * then with %true.  The first counts the number of regions needed
  	 * to accomodate the new area.  The second actually inserts them.
142b45a72   Benjamin Herrenschmidt   memblock: Add arr...
369
  	 */
784656f9c   Tejun Heo   memblock: Reimple...
370
371
  	base = obase;
  	nr_new = 0;
95f72d1ed   Yinghai Lu   lmb: rename to me...
372

784656f9c   Tejun Heo   memblock: Reimple...
373
374
375
376
377
378
  	for (i = 0; i < type->cnt; i++) {
  		struct memblock_region *rgn = &type->regions[i];
  		phys_addr_t rbase = rgn->base;
  		phys_addr_t rend = rbase + rgn->size;
  
  		if (rbase >= end)
95f72d1ed   Yinghai Lu   lmb: rename to me...
379
  			break;
784656f9c   Tejun Heo   memblock: Reimple...
380
381
382
383
384
385
386
387
388
389
  		if (rend <= base)
  			continue;
  		/*
  		 * @rgn overlaps.  If it separates the lower part of new
  		 * area, insert that portion.
  		 */
  		if (rbase > base) {
  			nr_new++;
  			if (insert)
  				memblock_insert_region(type, i++, base,
7fb0bc3f0   Tejun Heo   memblock: Impleme...
390
  						       rbase - base, nid);
95f72d1ed   Yinghai Lu   lmb: rename to me...
391
  		}
784656f9c   Tejun Heo   memblock: Reimple...
392
393
  		/* area below @rend is dealt with, forget about it */
  		base = min(rend, end);
95f72d1ed   Yinghai Lu   lmb: rename to me...
394
  	}
784656f9c   Tejun Heo   memblock: Reimple...
395
396
397
398
399
  
  	/* insert the remaining portion */
  	if (base < end) {
  		nr_new++;
  		if (insert)
7fb0bc3f0   Tejun Heo   memblock: Impleme...
400
  			memblock_insert_region(type, i, base, end - base, nid);
95f72d1ed   Yinghai Lu   lmb: rename to me...
401
  	}
95f72d1ed   Yinghai Lu   lmb: rename to me...
402

784656f9c   Tejun Heo   memblock: Reimple...
403
404
405
  	/*
  	 * If this was the first round, resize array and repeat for actual
  	 * insertions; otherwise, merge and return.
142b45a72   Benjamin Herrenschmidt   memblock: Add arr...
406
  	 */
784656f9c   Tejun Heo   memblock: Reimple...
407
408
  	if (!insert) {
  		while (type->cnt + nr_new > type->max)
48c3b583b   Greg Pearson   mm/memblock: fix ...
409
  			if (memblock_double_array(type, obase, size) < 0)
784656f9c   Tejun Heo   memblock: Reimple...
410
411
412
413
414
415
  				return -ENOMEM;
  		insert = true;
  		goto repeat;
  	} else {
  		memblock_merge_regions(type);
  		return 0;
142b45a72   Benjamin Herrenschmidt   memblock: Add arr...
416
  	}
95f72d1ed   Yinghai Lu   lmb: rename to me...
417
  }
7fb0bc3f0   Tejun Heo   memblock: Impleme...
418
419
420
421
422
  int __init_memblock memblock_add_node(phys_addr_t base, phys_addr_t size,
  				       int nid)
  {
  	return memblock_add_region(&memblock.memory, base, size, nid);
  }
581adcbe1   Tejun Heo   memblock: Make me...
423
  int __init_memblock memblock_add(phys_addr_t base, phys_addr_t size)
95f72d1ed   Yinghai Lu   lmb: rename to me...
424
  {
7fb0bc3f0   Tejun Heo   memblock: Impleme...
425
  	return memblock_add_region(&memblock.memory, base, size, MAX_NUMNODES);
95f72d1ed   Yinghai Lu   lmb: rename to me...
426
  }
6a9ceb31c   Tejun Heo   memblock: Separat...
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
  /**
   * memblock_isolate_range - isolate given range into disjoint memblocks
   * @type: memblock type to isolate range for
   * @base: base of range to isolate
   * @size: size of range to isolate
   * @start_rgn: out parameter for the start of isolated region
   * @end_rgn: out parameter for the end of isolated region
   *
   * Walk @type and ensure that regions don't cross the boundaries defined by
   * [@base,@base+@size).  Crossing regions are split at the boundaries,
   * which may create at most two more regions.  The index of the first
   * region inside the range is returned in *@start_rgn and end in *@end_rgn.
   *
   * RETURNS:
   * 0 on success, -errno on failure.
   */
  static int __init_memblock memblock_isolate_range(struct memblock_type *type,
  					phys_addr_t base, phys_addr_t size,
  					int *start_rgn, int *end_rgn)
  {
eb18f1b5b   Tejun Heo   memblock: Make me...
447
  	phys_addr_t end = base + memblock_cap_size(base, &size);
6a9ceb31c   Tejun Heo   memblock: Separat...
448
449
450
  	int i;
  
  	*start_rgn = *end_rgn = 0;
b3dc627ca   Tejun Heo   memblock: membloc...
451
452
  	if (!size)
  		return 0;
6a9ceb31c   Tejun Heo   memblock: Separat...
453
454
  	/* we'll create at most two more regions */
  	while (type->cnt + 2 > type->max)
48c3b583b   Greg Pearson   mm/memblock: fix ...
455
  		if (memblock_double_array(type, base, size) < 0)
6a9ceb31c   Tejun Heo   memblock: Separat...
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
  			return -ENOMEM;
  
  	for (i = 0; i < type->cnt; i++) {
  		struct memblock_region *rgn = &type->regions[i];
  		phys_addr_t rbase = rgn->base;
  		phys_addr_t rend = rbase + rgn->size;
  
  		if (rbase >= end)
  			break;
  		if (rend <= base)
  			continue;
  
  		if (rbase < base) {
  			/*
  			 * @rgn intersects from below.  Split and continue
  			 * to process the next region - the new top half.
  			 */
  			rgn->base = base;
1440c4e2c   Tejun Heo   memblock: Track t...
474
475
  			rgn->size -= base - rbase;
  			type->total_size -= base - rbase;
6a9ceb31c   Tejun Heo   memblock: Separat...
476
  			memblock_insert_region(type, i, rbase, base - rbase,
719361809   Tejun Heo   memblock: Reimple...
477
  					       memblock_get_region_node(rgn));
6a9ceb31c   Tejun Heo   memblock: Separat...
478
479
480
481
482
483
  		} else if (rend > end) {
  			/*
  			 * @rgn intersects from above.  Split and redo the
  			 * current region - the new bottom half.
  			 */
  			rgn->base = end;
1440c4e2c   Tejun Heo   memblock: Track t...
484
485
  			rgn->size -= end - rbase;
  			type->total_size -= end - rbase;
6a9ceb31c   Tejun Heo   memblock: Separat...
486
  			memblock_insert_region(type, i--, rbase, end - rbase,
719361809   Tejun Heo   memblock: Reimple...
487
  					       memblock_get_region_node(rgn));
6a9ceb31c   Tejun Heo   memblock: Separat...
488
489
490
491
492
493
494
495
496
497
  		} else {
  			/* @rgn is fully contained, record it */
  			if (!*end_rgn)
  				*start_rgn = i;
  			*end_rgn = i + 1;
  		}
  	}
  
  	return 0;
  }
6a9ceb31c   Tejun Heo   memblock: Separat...
498

581adcbe1   Tejun Heo   memblock: Make me...
499
500
  static int __init_memblock __memblock_remove(struct memblock_type *type,
  					     phys_addr_t base, phys_addr_t size)
95f72d1ed   Yinghai Lu   lmb: rename to me...
501
  {
719361809   Tejun Heo   memblock: Reimple...
502
503
  	int start_rgn, end_rgn;
  	int i, ret;
95f72d1ed   Yinghai Lu   lmb: rename to me...
504

719361809   Tejun Heo   memblock: Reimple...
505
506
507
  	ret = memblock_isolate_range(type, base, size, &start_rgn, &end_rgn);
  	if (ret)
  		return ret;
95f72d1ed   Yinghai Lu   lmb: rename to me...
508

719361809   Tejun Heo   memblock: Reimple...
509
510
  	for (i = end_rgn - 1; i >= start_rgn; i--)
  		memblock_remove_region(type, i);
8f7a66051   Benjamin Herrenschmidt   mm/memblock: prop...
511
  	return 0;
95f72d1ed   Yinghai Lu   lmb: rename to me...
512
  }
581adcbe1   Tejun Heo   memblock: Make me...
513
  int __init_memblock memblock_remove(phys_addr_t base, phys_addr_t size)
95f72d1ed   Yinghai Lu   lmb: rename to me...
514
515
516
  {
  	return __memblock_remove(&memblock.memory, base, size);
  }
581adcbe1   Tejun Heo   memblock: Make me...
517
  int __init_memblock memblock_free(phys_addr_t base, phys_addr_t size)
95f72d1ed   Yinghai Lu   lmb: rename to me...
518
  {
24aa07882   Tejun Heo   memblock, x86: Re...
519
520
  	memblock_dbg("   memblock_free: [%#016llx-%#016llx] %pF
  ",
a150439c4   H. Peter Anvin   memblock: Cast ph...
521
522
523
  		     (unsigned long long)base,
  		     (unsigned long long)base + size,
  		     (void *)_RET_IP_);
24aa07882   Tejun Heo   memblock, x86: Re...
524

95f72d1ed   Yinghai Lu   lmb: rename to me...
525
526
  	return __memblock_remove(&memblock.reserved, base, size);
  }
581adcbe1   Tejun Heo   memblock: Make me...
527
  int __init_memblock memblock_reserve(phys_addr_t base, phys_addr_t size)
95f72d1ed   Yinghai Lu   lmb: rename to me...
528
  {
e3239ff92   Benjamin Herrenschmidt   memblock: Rename ...
529
  	struct memblock_type *_rgn = &memblock.reserved;
95f72d1ed   Yinghai Lu   lmb: rename to me...
530

24aa07882   Tejun Heo   memblock, x86: Re...
531
532
  	memblock_dbg("memblock_reserve: [%#016llx-%#016llx] %pF
  ",
a150439c4   H. Peter Anvin   memblock: Cast ph...
533
534
535
  		     (unsigned long long)base,
  		     (unsigned long long)base + size,
  		     (void *)_RET_IP_);
95f72d1ed   Yinghai Lu   lmb: rename to me...
536

7fb0bc3f0   Tejun Heo   memblock: Impleme...
537
  	return memblock_add_region(_rgn, base, size, MAX_NUMNODES);
95f72d1ed   Yinghai Lu   lmb: rename to me...
538
  }
35fd0808d   Tejun Heo   memblock: Impleme...
539
540
541
542
  /**
   * __next_free_mem_range - next function for for_each_free_mem_range()
   * @idx: pointer to u64 loop variable
   * @nid: nid: node selector, %MAX_NUMNODES for all nodes
dad7557eb   Wanpeng Li   mm: fix kernel-do...
543
544
545
   * @out_start: ptr to phys_addr_t for start address of the range, can be %NULL
   * @out_end: ptr to phys_addr_t for end address of the range, can be %NULL
   * @out_nid: ptr to int for nid of the range, can be %NULL
35fd0808d   Tejun Heo   memblock: Impleme...
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
   *
   * Find the first free area from *@idx which matches @nid, fill the out
   * parameters, and update *@idx for the next iteration.  The lower 32bit of
   * *@idx contains index into memory region and the upper 32bit indexes the
   * areas before each reserved region.  For example, if reserved regions
   * look like the following,
   *
   *	0:[0-16), 1:[32-48), 2:[128-130)
   *
   * The upper 32bit indexes the following regions.
   *
   *	0:[0-0), 1:[16-32), 2:[48-128), 3:[130-MAX)
   *
   * As both region arrays are sorted, the function advances the two indices
   * in lockstep and returns each intersection.
   */
  void __init_memblock __next_free_mem_range(u64 *idx, int nid,
  					   phys_addr_t *out_start,
  					   phys_addr_t *out_end, int *out_nid)
  {
  	struct memblock_type *mem = &memblock.memory;
  	struct memblock_type *rsv = &memblock.reserved;
  	int mi = *idx & 0xffffffff;
  	int ri = *idx >> 32;
  
  	for ( ; mi < mem->cnt; mi++) {
  		struct memblock_region *m = &mem->regions[mi];
  		phys_addr_t m_start = m->base;
  		phys_addr_t m_end = m->base + m->size;
  
  		/* only memory regions are associated with nodes, check it */
  		if (nid != MAX_NUMNODES && nid != memblock_get_region_node(m))
  			continue;
  
  		/* scan areas before each reservation for intersection */
  		for ( ; ri < rsv->cnt + 1; ri++) {
  			struct memblock_region *r = &rsv->regions[ri];
  			phys_addr_t r_start = ri ? r[-1].base + r[-1].size : 0;
  			phys_addr_t r_end = ri < rsv->cnt ? r->base : ULLONG_MAX;
  
  			/* if ri advanced past mi, break out to advance mi */
  			if (r_start >= m_end)
  				break;
  			/* if the two regions intersect, we're done */
  			if (m_start < r_end) {
  				if (out_start)
  					*out_start = max(m_start, r_start);
  				if (out_end)
  					*out_end = min(m_end, r_end);
  				if (out_nid)
  					*out_nid = memblock_get_region_node(m);
  				/*
  				 * The region which ends first is advanced
  				 * for the next iteration.
  				 */
  				if (m_end <= r_end)
  					mi++;
  				else
  					ri++;
  				*idx = (u32)mi | (u64)ri << 32;
  				return;
  			}
  		}
  	}
  
  	/* signal end of iteration */
  	*idx = ULLONG_MAX;
  }
7bd0b0f0d   Tejun Heo   memblock: Reimple...
614
615
616
617
  /**
   * __next_free_mem_range_rev - next function for for_each_free_mem_range_reverse()
   * @idx: pointer to u64 loop variable
   * @nid: nid: node selector, %MAX_NUMNODES for all nodes
dad7557eb   Wanpeng Li   mm: fix kernel-do...
618
619
620
   * @out_start: ptr to phys_addr_t for start address of the range, can be %NULL
   * @out_end: ptr to phys_addr_t for end address of the range, can be %NULL
   * @out_nid: ptr to int for nid of the range, can be %NULL
7bd0b0f0d   Tejun Heo   memblock: Reimple...
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
   *
   * Reverse of __next_free_mem_range().
   */
  void __init_memblock __next_free_mem_range_rev(u64 *idx, int nid,
  					   phys_addr_t *out_start,
  					   phys_addr_t *out_end, int *out_nid)
  {
  	struct memblock_type *mem = &memblock.memory;
  	struct memblock_type *rsv = &memblock.reserved;
  	int mi = *idx & 0xffffffff;
  	int ri = *idx >> 32;
  
  	if (*idx == (u64)ULLONG_MAX) {
  		mi = mem->cnt - 1;
  		ri = rsv->cnt;
  	}
  
  	for ( ; mi >= 0; mi--) {
  		struct memblock_region *m = &mem->regions[mi];
  		phys_addr_t m_start = m->base;
  		phys_addr_t m_end = m->base + m->size;
  
  		/* only memory regions are associated with nodes, check it */
  		if (nid != MAX_NUMNODES && nid != memblock_get_region_node(m))
  			continue;
  
  		/* scan areas before each reservation for intersection */
  		for ( ; ri >= 0; ri--) {
  			struct memblock_region *r = &rsv->regions[ri];
  			phys_addr_t r_start = ri ? r[-1].base + r[-1].size : 0;
  			phys_addr_t r_end = ri < rsv->cnt ? r->base : ULLONG_MAX;
  
  			/* if ri advanced past mi, break out to advance mi */
  			if (r_end <= m_start)
  				break;
  			/* if the two regions intersect, we're done */
  			if (m_end > r_start) {
  				if (out_start)
  					*out_start = max(m_start, r_start);
  				if (out_end)
  					*out_end = min(m_end, r_end);
  				if (out_nid)
  					*out_nid = memblock_get_region_node(m);
  
  				if (m_start >= r_start)
  					mi--;
  				else
  					ri--;
  				*idx = (u32)mi | (u64)ri << 32;
  				return;
  			}
  		}
  	}
  
  	*idx = ULLONG_MAX;
  }
7c0caeb86   Tejun Heo   memblock: Add opt...
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
  #ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP
  /*
   * Common iterator interface used to define for_each_mem_range().
   */
  void __init_memblock __next_mem_pfn_range(int *idx, int nid,
  				unsigned long *out_start_pfn,
  				unsigned long *out_end_pfn, int *out_nid)
  {
  	struct memblock_type *type = &memblock.memory;
  	struct memblock_region *r;
  
  	while (++*idx < type->cnt) {
  		r = &type->regions[*idx];
  
  		if (PFN_UP(r->base) >= PFN_DOWN(r->base + r->size))
  			continue;
  		if (nid == MAX_NUMNODES || nid == r->nid)
  			break;
  	}
  	if (*idx >= type->cnt) {
  		*idx = -1;
  		return;
  	}
  
  	if (out_start_pfn)
  		*out_start_pfn = PFN_UP(r->base);
  	if (out_end_pfn)
  		*out_end_pfn = PFN_DOWN(r->base + r->size);
  	if (out_nid)
  		*out_nid = r->nid;
  }
  
  /**
   * memblock_set_node - set node ID on memblock regions
   * @base: base of area to set node ID for
   * @size: size of area to set node ID for
   * @nid: node ID to set
   *
   * Set the nid of memblock memory regions in [@base,@base+@size) to @nid.
   * Regions which cross the area boundaries are split as necessary.
   *
   * RETURNS:
   * 0 on success, -errno on failure.
   */
  int __init_memblock memblock_set_node(phys_addr_t base, phys_addr_t size,
  				      int nid)
  {
  	struct memblock_type *type = &memblock.memory;
6a9ceb31c   Tejun Heo   memblock: Separat...
725
726
  	int start_rgn, end_rgn;
  	int i, ret;
7c0caeb86   Tejun Heo   memblock: Add opt...
727

6a9ceb31c   Tejun Heo   memblock: Separat...
728
729
730
  	ret = memblock_isolate_range(type, base, size, &start_rgn, &end_rgn);
  	if (ret)
  		return ret;
7c0caeb86   Tejun Heo   memblock: Add opt...
731

6a9ceb31c   Tejun Heo   memblock: Separat...
732
733
  	for (i = start_rgn; i < end_rgn; i++)
  		type->regions[i].nid = nid;
7c0caeb86   Tejun Heo   memblock: Add opt...
734
735
736
737
738
  
  	memblock_merge_regions(type);
  	return 0;
  }
  #endif /* CONFIG_HAVE_MEMBLOCK_NODE_MAP */
7bd0b0f0d   Tejun Heo   memblock: Reimple...
739
740
741
  static phys_addr_t __init memblock_alloc_base_nid(phys_addr_t size,
  					phys_addr_t align, phys_addr_t max_addr,
  					int nid)
95f72d1ed   Yinghai Lu   lmb: rename to me...
742
  {
6ed311b28   Benjamin Herrenschmidt   memblock: Move fu...
743
  	phys_addr_t found;
95f72d1ed   Yinghai Lu   lmb: rename to me...
744

847854f59   Tejun Heo   memblock: Fix siz...
745
746
  	/* align @size to avoid excessive fragmentation on reserved array */
  	size = round_up(size, align);
7bd0b0f0d   Tejun Heo   memblock: Reimple...
747
  	found = memblock_find_in_range_node(0, max_addr, size, align, nid);
9c8c27e2b   Tejun Heo   memblock: Use mem...
748
  	if (found && !memblock_reserve(found, size))
6ed311b28   Benjamin Herrenschmidt   memblock: Move fu...
749
  		return found;
95f72d1ed   Yinghai Lu   lmb: rename to me...
750

6ed311b28   Benjamin Herrenschmidt   memblock: Move fu...
751
  	return 0;
95f72d1ed   Yinghai Lu   lmb: rename to me...
752
  }
7bd0b0f0d   Tejun Heo   memblock: Reimple...
753
754
755
756
757
758
759
760
761
  phys_addr_t __init memblock_alloc_nid(phys_addr_t size, phys_addr_t align, int nid)
  {
  	return memblock_alloc_base_nid(size, align, MEMBLOCK_ALLOC_ACCESSIBLE, nid);
  }
  
  phys_addr_t __init __memblock_alloc_base(phys_addr_t size, phys_addr_t align, phys_addr_t max_addr)
  {
  	return memblock_alloc_base_nid(size, align, max_addr, MAX_NUMNODES);
  }
6ed311b28   Benjamin Herrenschmidt   memblock: Move fu...
762
  phys_addr_t __init memblock_alloc_base(phys_addr_t size, phys_addr_t align, phys_addr_t max_addr)
95f72d1ed   Yinghai Lu   lmb: rename to me...
763
  {
6ed311b28   Benjamin Herrenschmidt   memblock: Move fu...
764
765
766
767
768
769
770
771
772
773
  	phys_addr_t alloc;
  
  	alloc = __memblock_alloc_base(size, align, max_addr);
  
  	if (alloc == 0)
  		panic("ERROR: Failed to allocate 0x%llx bytes below 0x%llx.
  ",
  		      (unsigned long long) size, (unsigned long long) max_addr);
  
  	return alloc;
95f72d1ed   Yinghai Lu   lmb: rename to me...
774
  }
6ed311b28   Benjamin Herrenschmidt   memblock: Move fu...
775
  phys_addr_t __init memblock_alloc(phys_addr_t size, phys_addr_t align)
95f72d1ed   Yinghai Lu   lmb: rename to me...
776
  {
6ed311b28   Benjamin Herrenschmidt   memblock: Move fu...
777
778
  	return memblock_alloc_base(size, align, MEMBLOCK_ALLOC_ACCESSIBLE);
  }
95f72d1ed   Yinghai Lu   lmb: rename to me...
779

9d1e24928   Benjamin Herrenschmidt   memblock: Separat...
780
781
782
783
784
785
  phys_addr_t __init memblock_alloc_try_nid(phys_addr_t size, phys_addr_t align, int nid)
  {
  	phys_addr_t res = memblock_alloc_nid(size, align, nid);
  
  	if (res)
  		return res;
15fb09722   Tejun Heo   memblock: Use MEM...
786
  	return memblock_alloc_base(size, align, MEMBLOCK_ALLOC_ACCESSIBLE);
95f72d1ed   Yinghai Lu   lmb: rename to me...
787
  }
9d1e24928   Benjamin Herrenschmidt   memblock: Separat...
788
789
790
791
  
  /*
   * Remaining API functions
   */
2898cc4cd   Benjamin Herrenschmidt   memblock: Change ...
792
  phys_addr_t __init memblock_phys_mem_size(void)
95f72d1ed   Yinghai Lu   lmb: rename to me...
793
  {
1440c4e2c   Tejun Heo   memblock: Track t...
794
  	return memblock.memory.total_size;
95f72d1ed   Yinghai Lu   lmb: rename to me...
795
  }
0a93ebef6   Sam Ravnborg   memblock: add mem...
796
797
798
799
800
  /* lowest address */
  phys_addr_t __init_memblock memblock_start_of_DRAM(void)
  {
  	return memblock.memory.regions[0].base;
  }
10d064398   Yinghai Lu   memblock: Option ...
801
  phys_addr_t __init_memblock memblock_end_of_DRAM(void)
95f72d1ed   Yinghai Lu   lmb: rename to me...
802
803
  {
  	int idx = memblock.memory.cnt - 1;
e3239ff92   Benjamin Herrenschmidt   memblock: Rename ...
804
  	return (memblock.memory.regions[idx].base + memblock.memory.regions[idx].size);
95f72d1ed   Yinghai Lu   lmb: rename to me...
805
  }
c0ce8fef5   Tejun Heo   memblock: Reimple...
806
  void __init memblock_enforce_memory_limit(phys_addr_t limit)
95f72d1ed   Yinghai Lu   lmb: rename to me...
807
808
  {
  	unsigned long i;
c0ce8fef5   Tejun Heo   memblock: Reimple...
809
  	phys_addr_t max_addr = (phys_addr_t)ULLONG_MAX;
95f72d1ed   Yinghai Lu   lmb: rename to me...
810

c0ce8fef5   Tejun Heo   memblock: Reimple...
811
  	if (!limit)
95f72d1ed   Yinghai Lu   lmb: rename to me...
812
  		return;
c0ce8fef5   Tejun Heo   memblock: Reimple...
813
  	/* find out max address */
95f72d1ed   Yinghai Lu   lmb: rename to me...
814
  	for (i = 0; i < memblock.memory.cnt; i++) {
c0ce8fef5   Tejun Heo   memblock: Reimple...
815
  		struct memblock_region *r = &memblock.memory.regions[i];
95f72d1ed   Yinghai Lu   lmb: rename to me...
816

c0ce8fef5   Tejun Heo   memblock: Reimple...
817
818
819
  		if (limit <= r->size) {
  			max_addr = r->base + limit;
  			break;
95f72d1ed   Yinghai Lu   lmb: rename to me...
820
  		}
c0ce8fef5   Tejun Heo   memblock: Reimple...
821
  		limit -= r->size;
95f72d1ed   Yinghai Lu   lmb: rename to me...
822
  	}
c0ce8fef5   Tejun Heo   memblock: Reimple...
823
824
825
826
  
  	/* truncate both memory and reserved regions */
  	__memblock_remove(&memblock.memory, max_addr, (phys_addr_t)ULLONG_MAX);
  	__memblock_remove(&memblock.reserved, max_addr, (phys_addr_t)ULLONG_MAX);
95f72d1ed   Yinghai Lu   lmb: rename to me...
827
  }
cd79481d2   Yinghai Lu   memblock: Annotat...
828
  static int __init_memblock memblock_search(struct memblock_type *type, phys_addr_t addr)
72d4b0b4e   Benjamin Herrenschmidt   memblock: Impleme...
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
  {
  	unsigned int left = 0, right = type->cnt;
  
  	do {
  		unsigned int mid = (right + left) / 2;
  
  		if (addr < type->regions[mid].base)
  			right = mid;
  		else if (addr >= (type->regions[mid].base +
  				  type->regions[mid].size))
  			left = mid + 1;
  		else
  			return mid;
  	} while (left < right);
  	return -1;
  }
2898cc4cd   Benjamin Herrenschmidt   memblock: Change ...
845
  int __init memblock_is_reserved(phys_addr_t addr)
95f72d1ed   Yinghai Lu   lmb: rename to me...
846
  {
72d4b0b4e   Benjamin Herrenschmidt   memblock: Impleme...
847
848
  	return memblock_search(&memblock.reserved, addr) != -1;
  }
95f72d1ed   Yinghai Lu   lmb: rename to me...
849

3661ca66a   Yinghai Lu   memblock: Fix sec...
850
  int __init_memblock memblock_is_memory(phys_addr_t addr)
72d4b0b4e   Benjamin Herrenschmidt   memblock: Impleme...
851
852
853
  {
  	return memblock_search(&memblock.memory, addr) != -1;
  }
eab309494   Stephen Boyd   memblock: Documen...
854
855
856
857
858
859
860
861
862
863
  /**
   * memblock_is_region_memory - check if a region is a subset of memory
   * @base: base of region to check
   * @size: size of region to check
   *
   * Check if the region [@base, @base+@size) is a subset of a memory block.
   *
   * RETURNS:
   * 0 if false, non-zero if true
   */
3661ca66a   Yinghai Lu   memblock: Fix sec...
864
  int __init_memblock memblock_is_region_memory(phys_addr_t base, phys_addr_t size)
72d4b0b4e   Benjamin Herrenschmidt   memblock: Impleme...
865
  {
abb65272a   Tomi Valkeinen   memblock: fix mem...
866
  	int idx = memblock_search(&memblock.memory, base);
eb18f1b5b   Tejun Heo   memblock: Make me...
867
  	phys_addr_t end = base + memblock_cap_size(base, &size);
72d4b0b4e   Benjamin Herrenschmidt   memblock: Impleme...
868
869
870
  
  	if (idx == -1)
  		return 0;
abb65272a   Tomi Valkeinen   memblock: fix mem...
871
872
  	return memblock.memory.regions[idx].base <= base &&
  		(memblock.memory.regions[idx].base +
eb18f1b5b   Tejun Heo   memblock: Make me...
873
  		 memblock.memory.regions[idx].size) >= end;
95f72d1ed   Yinghai Lu   lmb: rename to me...
874
  }
eab309494   Stephen Boyd   memblock: Documen...
875
876
877
878
879
880
881
882
883
884
  /**
   * memblock_is_region_reserved - check if a region intersects reserved memory
   * @base: base of region to check
   * @size: size of region to check
   *
   * Check if the region [@base, @base+@size) intersects a reserved memory block.
   *
   * RETURNS:
   * 0 if false, non-zero if true
   */
10d064398   Yinghai Lu   memblock: Option ...
885
  int __init_memblock memblock_is_region_reserved(phys_addr_t base, phys_addr_t size)
95f72d1ed   Yinghai Lu   lmb: rename to me...
886
  {
eb18f1b5b   Tejun Heo   memblock: Make me...
887
  	memblock_cap_size(base, &size);
f1c2c19c4   Benjamin Herrenschmidt   memblock: Fix mem...
888
  	return memblock_overlaps_region(&memblock.reserved, base, size) >= 0;
95f72d1ed   Yinghai Lu   lmb: rename to me...
889
  }
e63075a3c   Benjamin Herrenschmidt   memblock: Introdu...
890

3661ca66a   Yinghai Lu   memblock: Fix sec...
891
  void __init_memblock memblock_set_current_limit(phys_addr_t limit)
e63075a3c   Benjamin Herrenschmidt   memblock: Introdu...
892
893
894
  {
  	memblock.current_limit = limit;
  }
7c0caeb86   Tejun Heo   memblock: Add opt...
895
  static void __init_memblock memblock_dump(struct memblock_type *type, char *name)
6ed311b28   Benjamin Herrenschmidt   memblock: Move fu...
896
897
898
  {
  	unsigned long long base, size;
  	int i;
7c0caeb86   Tejun Heo   memblock: Add opt...
899
900
  	pr_info(" %s.cnt  = 0x%lx
  ", name, type->cnt);
6ed311b28   Benjamin Herrenschmidt   memblock: Move fu...
901

7c0caeb86   Tejun Heo   memblock: Add opt...
902
903
904
905
906
907
908
909
910
911
912
913
914
915
  	for (i = 0; i < type->cnt; i++) {
  		struct memblock_region *rgn = &type->regions[i];
  		char nid_buf[32] = "";
  
  		base = rgn->base;
  		size = rgn->size;
  #ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP
  		if (memblock_get_region_node(rgn) != MAX_NUMNODES)
  			snprintf(nid_buf, sizeof(nid_buf), " on node %d",
  				 memblock_get_region_node(rgn));
  #endif
  		pr_info(" %s[%#x]\t[%#016llx-%#016llx], %#llx bytes%s
  ",
  			name, i, base, base + size - 1, size, nid_buf);
6ed311b28   Benjamin Herrenschmidt   memblock: Move fu...
916
917
  	}
  }
4ff7b82f1   Tejun Heo   memblock: Add __m...
918
  void __init_memblock __memblock_dump_all(void)
6ed311b28   Benjamin Herrenschmidt   memblock: Move fu...
919
  {
6ed311b28   Benjamin Herrenschmidt   memblock: Move fu...
920
921
  	pr_info("MEMBLOCK configuration:
  ");
1440c4e2c   Tejun Heo   memblock: Track t...
922
923
924
925
  	pr_info(" memory size = %#llx reserved size = %#llx
  ",
  		(unsigned long long)memblock.memory.total_size,
  		(unsigned long long)memblock.reserved.total_size);
6ed311b28   Benjamin Herrenschmidt   memblock: Move fu...
926
927
928
929
  
  	memblock_dump(&memblock.memory, "memory");
  	memblock_dump(&memblock.reserved, "reserved");
  }
1aadc0560   Tejun Heo   memblock: s/membl...
930
  void __init memblock_allow_resize(void)
6ed311b28   Benjamin Herrenschmidt   memblock: Move fu...
931
  {
142b45a72   Benjamin Herrenschmidt   memblock: Add arr...
932
  	memblock_can_resize = 1;
6ed311b28   Benjamin Herrenschmidt   memblock: Move fu...
933
  }
6ed311b28   Benjamin Herrenschmidt   memblock: Move fu...
934
935
936
937
938
939
940
  static int __init early_memblock(char *p)
  {
  	if (p && strstr(p, "debug"))
  		memblock_debug = 1;
  	return 0;
  }
  early_param("memblock", early_memblock);
c378ddd53   Tejun Heo   memblock, x86: Ma...
941
  #if defined(CONFIG_DEBUG_FS) && !defined(CONFIG_ARCH_DISCARD_MEMBLOCK)
6d03b885f   Benjamin Herrenschmidt   memblock: Add deb...
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
  
  static int memblock_debug_show(struct seq_file *m, void *private)
  {
  	struct memblock_type *type = m->private;
  	struct memblock_region *reg;
  	int i;
  
  	for (i = 0; i < type->cnt; i++) {
  		reg = &type->regions[i];
  		seq_printf(m, "%4d: ", i);
  		if (sizeof(phys_addr_t) == 4)
  			seq_printf(m, "0x%08lx..0x%08lx
  ",
  				   (unsigned long)reg->base,
  				   (unsigned long)(reg->base + reg->size - 1));
  		else
  			seq_printf(m, "0x%016llx..0x%016llx
  ",
  				   (unsigned long long)reg->base,
  				   (unsigned long long)(reg->base + reg->size - 1));
  
  	}
  	return 0;
  }
  
  static int memblock_debug_open(struct inode *inode, struct file *file)
  {
  	return single_open(file, memblock_debug_show, inode->i_private);
  }
  
  static const struct file_operations memblock_debug_fops = {
  	.open = memblock_debug_open,
  	.read = seq_read,
  	.llseek = seq_lseek,
  	.release = single_release,
  };
  
  static int __init memblock_init_debugfs(void)
  {
  	struct dentry *root = debugfs_create_dir("memblock", NULL);
  	if (!root)
  		return -ENXIO;
  	debugfs_create_file("memory", S_IRUGO, root, &memblock.memory, &memblock_debug_fops);
  	debugfs_create_file("reserved", S_IRUGO, root, &memblock.reserved, &memblock_debug_fops);
  
  	return 0;
  }
  __initcall(memblock_init_debugfs);
  
  #endif /* CONFIG_DEBUG_FS */