Blame view

mm/memblock.c 29.6 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
  /* inline so we don't get a warning when pr_debug is compiled out */
c22331166   Raghavendra D Prabhu   mm: avoid section...
43
44
  static __init_memblock const char *
  memblock_type_name(struct memblock_type *type)
142b45a72   Benjamin Herrenschmidt   memblock: Add arr...
45
46
47
48
49
50
51
52
  {
  	if (type == &memblock.memory)
  		return "memory";
  	else if (type == &memblock.reserved)
  		return "reserved";
  	else
  		return "unknown";
  }
eb18f1b5b   Tejun Heo   memblock: Make me...
53
54
55
56
57
  /* 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...
58
59
60
  /*
   * Address comparison utilities
   */
10d064398   Yinghai Lu   memblock: Option ...
61
  static unsigned long __init_memblock memblock_addrs_overlap(phys_addr_t base1, phys_addr_t size1,
2898cc4cd   Benjamin Herrenschmidt   memblock: Change ...
62
  				       phys_addr_t base2, phys_addr_t size2)
95f72d1ed   Yinghai Lu   lmb: rename to me...
63
64
65
  {
  	return ((base1 < (base2 + size2)) && (base2 < (base1 + size1)));
  }
2d7d3eb2b   H Hartley Sweeten   mm/memblock.c: qu...
66
67
  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...
68
69
70
71
72
73
74
75
76
77
78
79
  {
  	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...
80
81
82
83
84
85
86
87
88
89
90
91
  /**
   * 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...
92
   */
f7210e6c4   Tang Chen   mm/memblock.c: us...
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
  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)
  {
  	phys_addr_t this_start, this_end, cand;
  	u64 i;
  
  	/* pump up @end */
  	if (end == MEMBLOCK_ALLOC_ACCESSIBLE)
  		end = memblock.current_limit;
  
  	/* avoid allocating the first page */
  	start = max_t(phys_addr_t, start, PAGE_SIZE);
  	end = max(start, end);
  
  	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);
  
  		if (this_end < size)
  			continue;
  
  		cand = round_down(this_end - size, align);
  		if (cand >= this_start)
  			return cand;
  	}
  	return 0;
  }
6ed311b28   Benjamin Herrenschmidt   memblock: Move fu...
121

7bd0b0f0d   Tejun Heo   memblock: Reimple...
122
123
124
125
126
127
128
129
130
131
132
  /**
   * 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...
133
   */
7bd0b0f0d   Tejun Heo   memblock: Reimple...
134
135
136
  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...
137
  {
7bd0b0f0d   Tejun Heo   memblock: Reimple...
138
139
  	return memblock_find_in_range_node(start, end, size, align,
  					   MAX_NUMNODES);
6ed311b28   Benjamin Herrenschmidt   memblock: Move fu...
140
  }
10d064398   Yinghai Lu   memblock: Option ...
141
  static void __init_memblock memblock_remove_region(struct memblock_type *type, unsigned long r)
95f72d1ed   Yinghai Lu   lmb: rename to me...
142
  {
1440c4e2c   Tejun Heo   memblock: Track t...
143
  	type->total_size -= type->regions[r].size;
7c0caeb86   Tejun Heo   memblock: Add opt...
144
145
  	memmove(&type->regions[r], &type->regions[r + 1],
  		(type->cnt - (r + 1)) * sizeof(type->regions[r]));
e3239ff92   Benjamin Herrenschmidt   memblock: Rename ...
146
  	type->cnt--;
95f72d1ed   Yinghai Lu   lmb: rename to me...
147

8f7a66051   Benjamin Herrenschmidt   mm/memblock: prop...
148
149
  	/* Special case for empty arrays */
  	if (type->cnt == 0) {
1440c4e2c   Tejun Heo   memblock: Track t...
150
  		WARN_ON(type->total_size != 0);
8f7a66051   Benjamin Herrenschmidt   mm/memblock: prop...
151
152
153
  		type->cnt = 1;
  		type->regions[0].base = 0;
  		type->regions[0].size = 0;
7c0caeb86   Tejun Heo   memblock: Add opt...
154
  		memblock_set_region_node(&type->regions[0], MAX_NUMNODES);
8f7a66051   Benjamin Herrenschmidt   mm/memblock: prop...
155
  	}
95f72d1ed   Yinghai Lu   lmb: rename to me...
156
  }
29f673860   Yinghai Lu   memblock: free al...
157
158
159
160
161
162
163
164
165
166
167
  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 ...
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
  /**
   * 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...
186
187
  {
  	struct memblock_region *new_array, *old_array;
29f673860   Yinghai Lu   memblock: free al...
188
  	phys_addr_t old_alloc_size, new_alloc_size;
142b45a72   Benjamin Herrenschmidt   memblock: Add arr...
189
190
  	phys_addr_t old_size, new_size, addr;
  	int use_slab = slab_is_available();
181eb3942   Gavin Shan   mm/memblock: fix ...
191
  	int *in_slab;
142b45a72   Benjamin Herrenschmidt   memblock: Add arr...
192
193
194
195
196
197
  
  	/* 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...
198
199
200
  	/* Calculate new doubled size */
  	old_size = type->max * sizeof(struct memblock_region);
  	new_size = old_size << 1;
29f673860   Yinghai Lu   memblock: free al...
201
202
203
204
205
206
  	/*
  	 * 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...
207

181eb3942   Gavin Shan   mm/memblock: fix ...
208
209
210
211
212
  	/* 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...
213
214
215
  	/* 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...
216
217
218
  	 * 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...
219
220
  	 *
  	 * This should however not be an issue for now, as we currently only
fd07383b6   Andrew Morton   mm/memblock.c:mem...
221
222
  	 * 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...
223
224
225
  	 */
  	if (use_slab) {
  		new_array = kmalloc(new_size, GFP_KERNEL);
1f5026a7e   Tejun Heo   memblock: Kill ME...
226
  		addr = new_array ? __pa(new_array) : 0;
4e2f07750   Gavin Shan   mm/memblock: clea...
227
  	} else {
48c3b583b   Greg Pearson   mm/memblock: fix ...
228
229
230
231
232
233
  		/* 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...
234
  						new_alloc_size, PAGE_SIZE);
48c3b583b   Greg Pearson   mm/memblock: fix ...
235
236
  		if (!addr && new_area_size)
  			addr = memblock_find_in_range(0,
fd07383b6   Andrew Morton   mm/memblock.c:mem...
237
238
  				min(new_area_start, memblock.current_limit),
  				new_alloc_size, PAGE_SIZE);
48c3b583b   Greg Pearson   mm/memblock: fix ...
239

15674868d   Sachin Kamat   mm/memblock: Use ...
240
  		new_array = addr ? __va(addr) : NULL;
4e2f07750   Gavin Shan   mm/memblock: clea...
241
  	}
1f5026a7e   Tejun Heo   memblock: Kill ME...
242
  	if (!addr) {
142b45a72   Benjamin Herrenschmidt   memblock: Add arr...
243
244
245
246
247
  		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...
248

fd07383b6   Andrew Morton   mm/memblock.c:mem...
249
250
251
  	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...
252

fd07383b6   Andrew Morton   mm/memblock.c:mem...
253
254
255
256
  	/*
  	 * 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...
257
258
259
260
261
262
  	 */
  	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...
263
  	/* Free old array. We needn't free it if the array is the static one */
181eb3942   Gavin Shan   mm/memblock: fix ...
264
265
266
267
  	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...
268
  		memblock_free(__pa(old_array), old_alloc_size);
142b45a72   Benjamin Herrenschmidt   memblock: Add arr...
269

fd07383b6   Andrew Morton   mm/memblock.c:mem...
270
271
272
  	/*
  	 * Reserve the new array if that comes from the memblock.  Otherwise, we
  	 * needn't do it
181eb3942   Gavin Shan   mm/memblock: fix ...
273
274
  	 */
  	if (!use_slab)
29f673860   Yinghai Lu   memblock: free al...
275
  		BUG_ON(memblock_reserve(addr, new_alloc_size));
181eb3942   Gavin Shan   mm/memblock: fix ...
276
277
278
  
  	/* Update slab flag */
  	*in_slab = use_slab;
142b45a72   Benjamin Herrenschmidt   memblock: Add arr...
279
280
  	return 0;
  }
784656f9c   Tejun Heo   memblock: Reimple...
281
282
283
284
285
286
287
  /**
   * 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...
288
  {
784656f9c   Tejun Heo   memblock: Reimple...
289
  	int i = 0;
95f72d1ed   Yinghai Lu   lmb: rename to me...
290

784656f9c   Tejun Heo   memblock: Reimple...
291
292
293
294
  	/* 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...
295

7c0caeb86   Tejun Heo   memblock: Add opt...
296
297
298
  		if (this->base + this->size != next->base ||
  		    memblock_get_region_node(this) !=
  		    memblock_get_region_node(next)) {
784656f9c   Tejun Heo   memblock: Reimple...
299
300
301
  			BUG_ON(this->base + this->size > next->base);
  			i++;
  			continue;
8f7a66051   Benjamin Herrenschmidt   mm/memblock: prop...
302
  		}
784656f9c   Tejun Heo   memblock: Reimple...
303
  		this->size += next->size;
c0232ae86   Lin Feng   mm: memblock: fix...
304
305
  		/* move forward from next + 1, index of which is i + 2 */
  		memmove(next, next + 1, (type->cnt - (i + 2)) * sizeof(*next));
784656f9c   Tejun Heo   memblock: Reimple...
306
  		type->cnt--;
95f72d1ed   Yinghai Lu   lmb: rename to me...
307
  	}
784656f9c   Tejun Heo   memblock: Reimple...
308
  }
95f72d1ed   Yinghai Lu   lmb: rename to me...
309

784656f9c   Tejun Heo   memblock: Reimple...
310
311
  /**
   * memblock_insert_region - insert new memblock region
209ff86d6   Tang Chen   memblock: fix mis...
312
313
314
315
316
   * @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
   * @nid:	node id of the new region
784656f9c   Tejun Heo   memblock: Reimple...
317
318
319
320
321
322
   *
   * 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...
323
  						   phys_addr_t size, int nid)
784656f9c   Tejun Heo   memblock: Reimple...
324
325
326
327
328
329
330
  {
  	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...
331
  	memblock_set_region_node(rgn, nid);
784656f9c   Tejun Heo   memblock: Reimple...
332
  	type->cnt++;
1440c4e2c   Tejun Heo   memblock: Track t...
333
  	type->total_size += size;
784656f9c   Tejun Heo   memblock: Reimple...
334
335
336
337
338
339
340
  }
  
  /**
   * 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...
341
   * @nid: nid of the new region
784656f9c   Tejun Heo   memblock: Reimple...
342
343
344
345
346
347
348
349
350
   *
   * 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...
351
  static int __init_memblock memblock_add_region(struct memblock_type *type,
7fb0bc3f0   Tejun Heo   memblock: Impleme...
352
  				phys_addr_t base, phys_addr_t size, int nid)
784656f9c   Tejun Heo   memblock: Reimple...
353
354
  {
  	bool insert = false;
eb18f1b5b   Tejun Heo   memblock: Make me...
355
356
  	phys_addr_t obase = base;
  	phys_addr_t end = base + memblock_cap_size(base, &size);
784656f9c   Tejun Heo   memblock: Reimple...
357
  	int i, nr_new;
b3dc627ca   Tejun Heo   memblock: membloc...
358
359
  	if (!size)
  		return 0;
784656f9c   Tejun Heo   memblock: Reimple...
360
361
  	/* special case for empty array */
  	if (type->regions[0].size == 0) {
1440c4e2c   Tejun Heo   memblock: Track t...
362
  		WARN_ON(type->cnt != 1 || type->total_size);
8f7a66051   Benjamin Herrenschmidt   mm/memblock: prop...
363
364
  		type->regions[0].base = base;
  		type->regions[0].size = size;
7fb0bc3f0   Tejun Heo   memblock: Impleme...
365
  		memblock_set_region_node(&type->regions[0], nid);
1440c4e2c   Tejun Heo   memblock: Track t...
366
  		type->total_size = size;
8f7a66051   Benjamin Herrenschmidt   mm/memblock: prop...
367
  		return 0;
95f72d1ed   Yinghai Lu   lmb: rename to me...
368
  	}
784656f9c   Tejun Heo   memblock: Reimple...
369
370
371
372
373
  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...
374
  	 */
784656f9c   Tejun Heo   memblock: Reimple...
375
376
  	base = obase;
  	nr_new = 0;
95f72d1ed   Yinghai Lu   lmb: rename to me...
377

784656f9c   Tejun Heo   memblock: Reimple...
378
379
380
381
382
383
  	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...
384
  			break;
784656f9c   Tejun Heo   memblock: Reimple...
385
386
387
388
389
390
391
392
393
394
  		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...
395
  						       rbase - base, nid);
95f72d1ed   Yinghai Lu   lmb: rename to me...
396
  		}
784656f9c   Tejun Heo   memblock: Reimple...
397
398
  		/* area below @rend is dealt with, forget about it */
  		base = min(rend, end);
95f72d1ed   Yinghai Lu   lmb: rename to me...
399
  	}
784656f9c   Tejun Heo   memblock: Reimple...
400
401
402
403
404
  
  	/* insert the remaining portion */
  	if (base < end) {
  		nr_new++;
  		if (insert)
7fb0bc3f0   Tejun Heo   memblock: Impleme...
405
  			memblock_insert_region(type, i, base, end - base, nid);
95f72d1ed   Yinghai Lu   lmb: rename to me...
406
  	}
95f72d1ed   Yinghai Lu   lmb: rename to me...
407

784656f9c   Tejun Heo   memblock: Reimple...
408
409
410
  	/*
  	 * If this was the first round, resize array and repeat for actual
  	 * insertions; otherwise, merge and return.
142b45a72   Benjamin Herrenschmidt   memblock: Add arr...
411
  	 */
784656f9c   Tejun Heo   memblock: Reimple...
412
413
  	if (!insert) {
  		while (type->cnt + nr_new > type->max)
48c3b583b   Greg Pearson   mm/memblock: fix ...
414
  			if (memblock_double_array(type, obase, size) < 0)
784656f9c   Tejun Heo   memblock: Reimple...
415
416
417
418
419
420
  				return -ENOMEM;
  		insert = true;
  		goto repeat;
  	} else {
  		memblock_merge_regions(type);
  		return 0;
142b45a72   Benjamin Herrenschmidt   memblock: Add arr...
421
  	}
95f72d1ed   Yinghai Lu   lmb: rename to me...
422
  }
7fb0bc3f0   Tejun Heo   memblock: Impleme...
423
424
425
426
427
  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...
428
  int __init_memblock memblock_add(phys_addr_t base, phys_addr_t size)
95f72d1ed   Yinghai Lu   lmb: rename to me...
429
  {
7fb0bc3f0   Tejun Heo   memblock: Impleme...
430
  	return memblock_add_region(&memblock.memory, base, size, MAX_NUMNODES);
95f72d1ed   Yinghai Lu   lmb: rename to me...
431
  }
6a9ceb31c   Tejun Heo   memblock: Separat...
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
  /**
   * 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...
452
  	phys_addr_t end = base + memblock_cap_size(base, &size);
6a9ceb31c   Tejun Heo   memblock: Separat...
453
454
455
  	int i;
  
  	*start_rgn = *end_rgn = 0;
b3dc627ca   Tejun Heo   memblock: membloc...
456
457
  	if (!size)
  		return 0;
6a9ceb31c   Tejun Heo   memblock: Separat...
458
459
  	/* we'll create at most two more regions */
  	while (type->cnt + 2 > type->max)
48c3b583b   Greg Pearson   mm/memblock: fix ...
460
  		if (memblock_double_array(type, base, size) < 0)
6a9ceb31c   Tejun Heo   memblock: Separat...
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
  			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...
479
480
  			rgn->size -= base - rbase;
  			type->total_size -= base - rbase;
6a9ceb31c   Tejun Heo   memblock: Separat...
481
  			memblock_insert_region(type, i, rbase, base - rbase,
719361809   Tejun Heo   memblock: Reimple...
482
  					       memblock_get_region_node(rgn));
6a9ceb31c   Tejun Heo   memblock: Separat...
483
484
485
486
487
488
  		} 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...
489
490
  			rgn->size -= end - rbase;
  			type->total_size -= end - rbase;
6a9ceb31c   Tejun Heo   memblock: Separat...
491
  			memblock_insert_region(type, i--, rbase, end - rbase,
719361809   Tejun Heo   memblock: Reimple...
492
  					       memblock_get_region_node(rgn));
6a9ceb31c   Tejun Heo   memblock: Separat...
493
494
495
496
497
498
499
500
501
502
  		} else {
  			/* @rgn is fully contained, record it */
  			if (!*end_rgn)
  				*start_rgn = i;
  			*end_rgn = i + 1;
  		}
  	}
  
  	return 0;
  }
6a9ceb31c   Tejun Heo   memblock: Separat...
503

581adcbe1   Tejun Heo   memblock: Make me...
504
505
  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...
506
  {
719361809   Tejun Heo   memblock: Reimple...
507
508
  	int start_rgn, end_rgn;
  	int i, ret;
95f72d1ed   Yinghai Lu   lmb: rename to me...
509

719361809   Tejun Heo   memblock: Reimple...
510
511
512
  	ret = memblock_isolate_range(type, base, size, &start_rgn, &end_rgn);
  	if (ret)
  		return ret;
95f72d1ed   Yinghai Lu   lmb: rename to me...
513

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

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

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

7fb0bc3f0   Tejun Heo   memblock: Impleme...
542
  	return memblock_add_region(_rgn, base, size, MAX_NUMNODES);
95f72d1ed   Yinghai Lu   lmb: rename to me...
543
  }
35fd0808d   Tejun Heo   memblock: Impleme...
544
545
546
547
  /**
   * __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...
548
549
550
   * @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...
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
614
615
616
617
618
   *
   * 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...
619
620
621
622
  /**
   * __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...
623
624
625
   * @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...
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
677
678
679
680
681
   *
   * 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...
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
725
726
727
728
729
  #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...
730
731
  	int start_rgn, end_rgn;
  	int i, ret;
7c0caeb86   Tejun Heo   memblock: Add opt...
732

6a9ceb31c   Tejun Heo   memblock: Separat...
733
734
735
  	ret = memblock_isolate_range(type, base, size, &start_rgn, &end_rgn);
  	if (ret)
  		return ret;
7c0caeb86   Tejun Heo   memblock: Add opt...
736

6a9ceb31c   Tejun Heo   memblock: Separat...
737
  	for (i = start_rgn; i < end_rgn; i++)
e9d24ad30   Wanpeng Li   mm/memblock: use ...
738
  		memblock_set_region_node(&type->regions[i], nid);
7c0caeb86   Tejun Heo   memblock: Add opt...
739
740
741
742
743
  
  	memblock_merge_regions(type);
  	return 0;
  }
  #endif /* CONFIG_HAVE_MEMBLOCK_NODE_MAP */
7bd0b0f0d   Tejun Heo   memblock: Reimple...
744
745
746
  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...
747
  {
6ed311b28   Benjamin Herrenschmidt   memblock: Move fu...
748
  	phys_addr_t found;
95f72d1ed   Yinghai Lu   lmb: rename to me...
749

94f3d3afb   Vineet Gupta   memblock: add ass...
750
751
  	if (WARN_ON(!align))
  		align = __alignof__(long long);
847854f59   Tejun Heo   memblock: Fix siz...
752
753
  	/* align @size to avoid excessive fragmentation on reserved array */
  	size = round_up(size, align);
7bd0b0f0d   Tejun Heo   memblock: Reimple...
754
  	found = memblock_find_in_range_node(0, max_addr, size, align, nid);
9c8c27e2b   Tejun Heo   memblock: Use mem...
755
  	if (found && !memblock_reserve(found, size))
6ed311b28   Benjamin Herrenschmidt   memblock: Move fu...
756
  		return found;
95f72d1ed   Yinghai Lu   lmb: rename to me...
757

6ed311b28   Benjamin Herrenschmidt   memblock: Move fu...
758
  	return 0;
95f72d1ed   Yinghai Lu   lmb: rename to me...
759
  }
7bd0b0f0d   Tejun Heo   memblock: Reimple...
760
761
762
763
764
765
766
767
768
  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...
769
  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...
770
  {
6ed311b28   Benjamin Herrenschmidt   memblock: Move fu...
771
772
773
774
775
776
777
778
779
780
  	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...
781
  }
6ed311b28   Benjamin Herrenschmidt   memblock: Move fu...
782
  phys_addr_t __init memblock_alloc(phys_addr_t size, phys_addr_t align)
95f72d1ed   Yinghai Lu   lmb: rename to me...
783
  {
6ed311b28   Benjamin Herrenschmidt   memblock: Move fu...
784
785
  	return memblock_alloc_base(size, align, MEMBLOCK_ALLOC_ACCESSIBLE);
  }
95f72d1ed   Yinghai Lu   lmb: rename to me...
786

9d1e24928   Benjamin Herrenschmidt   memblock: Separat...
787
788
789
790
791
792
  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...
793
  	return memblock_alloc_base(size, align, MEMBLOCK_ALLOC_ACCESSIBLE);
95f72d1ed   Yinghai Lu   lmb: rename to me...
794
  }
9d1e24928   Benjamin Herrenschmidt   memblock: Separat...
795
796
797
798
  
  /*
   * Remaining API functions
   */
2898cc4cd   Benjamin Herrenschmidt   memblock: Change ...
799
  phys_addr_t __init memblock_phys_mem_size(void)
95f72d1ed   Yinghai Lu   lmb: rename to me...
800
  {
1440c4e2c   Tejun Heo   memblock: Track t...
801
  	return memblock.memory.total_size;
95f72d1ed   Yinghai Lu   lmb: rename to me...
802
  }
595ad9af8   Yinghai Lu   memblock: Add mem...
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
  phys_addr_t __init memblock_mem_size(unsigned long limit_pfn)
  {
  	unsigned long pages = 0;
  	struct memblock_region *r;
  	unsigned long start_pfn, end_pfn;
  
  	for_each_memblock(memory, r) {
  		start_pfn = memblock_region_memory_base_pfn(r);
  		end_pfn = memblock_region_memory_end_pfn(r);
  		start_pfn = min_t(unsigned long, start_pfn, limit_pfn);
  		end_pfn = min_t(unsigned long, end_pfn, limit_pfn);
  		pages += end_pfn - start_pfn;
  	}
  
  	return (phys_addr_t)pages << PAGE_SHIFT;
  }
0a93ebef6   Sam Ravnborg   memblock: add mem...
819
820
821
822
823
  /* lowest address */
  phys_addr_t __init_memblock memblock_start_of_DRAM(void)
  {
  	return memblock.memory.regions[0].base;
  }
10d064398   Yinghai Lu   memblock: Option ...
824
  phys_addr_t __init_memblock memblock_end_of_DRAM(void)
95f72d1ed   Yinghai Lu   lmb: rename to me...
825
826
  {
  	int idx = memblock.memory.cnt - 1;
e3239ff92   Benjamin Herrenschmidt   memblock: Rename ...
827
  	return (memblock.memory.regions[idx].base + memblock.memory.regions[idx].size);
95f72d1ed   Yinghai Lu   lmb: rename to me...
828
  }
c0ce8fef5   Tejun Heo   memblock: Reimple...
829
  void __init memblock_enforce_memory_limit(phys_addr_t limit)
95f72d1ed   Yinghai Lu   lmb: rename to me...
830
831
  {
  	unsigned long i;
c0ce8fef5   Tejun Heo   memblock: Reimple...
832
  	phys_addr_t max_addr = (phys_addr_t)ULLONG_MAX;
95f72d1ed   Yinghai Lu   lmb: rename to me...
833

c0ce8fef5   Tejun Heo   memblock: Reimple...
834
  	if (!limit)
95f72d1ed   Yinghai Lu   lmb: rename to me...
835
  		return;
c0ce8fef5   Tejun Heo   memblock: Reimple...
836
  	/* find out max address */
95f72d1ed   Yinghai Lu   lmb: rename to me...
837
  	for (i = 0; i < memblock.memory.cnt; i++) {
c0ce8fef5   Tejun Heo   memblock: Reimple...
838
  		struct memblock_region *r = &memblock.memory.regions[i];
95f72d1ed   Yinghai Lu   lmb: rename to me...
839

c0ce8fef5   Tejun Heo   memblock: Reimple...
840
841
842
  		if (limit <= r->size) {
  			max_addr = r->base + limit;
  			break;
95f72d1ed   Yinghai Lu   lmb: rename to me...
843
  		}
c0ce8fef5   Tejun Heo   memblock: Reimple...
844
  		limit -= r->size;
95f72d1ed   Yinghai Lu   lmb: rename to me...
845
  	}
c0ce8fef5   Tejun Heo   memblock: Reimple...
846
847
848
849
  
  	/* 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...
850
  }
cd79481d2   Yinghai Lu   memblock: Annotat...
851
  static int __init_memblock memblock_search(struct memblock_type *type, phys_addr_t addr)
72d4b0b4e   Benjamin Herrenschmidt   memblock: Impleme...
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
  {
  	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 ...
868
  int __init memblock_is_reserved(phys_addr_t addr)
95f72d1ed   Yinghai Lu   lmb: rename to me...
869
  {
72d4b0b4e   Benjamin Herrenschmidt   memblock: Impleme...
870
871
  	return memblock_search(&memblock.reserved, addr) != -1;
  }
95f72d1ed   Yinghai Lu   lmb: rename to me...
872

3661ca66a   Yinghai Lu   memblock: Fix sec...
873
  int __init_memblock memblock_is_memory(phys_addr_t addr)
72d4b0b4e   Benjamin Herrenschmidt   memblock: Impleme...
874
875
876
  {
  	return memblock_search(&memblock.memory, addr) != -1;
  }
eab309494   Stephen Boyd   memblock: Documen...
877
878
879
880
881
882
883
884
885
886
  /**
   * 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...
887
  int __init_memblock memblock_is_region_memory(phys_addr_t base, phys_addr_t size)
72d4b0b4e   Benjamin Herrenschmidt   memblock: Impleme...
888
  {
abb65272a   Tomi Valkeinen   memblock: fix mem...
889
  	int idx = memblock_search(&memblock.memory, base);
eb18f1b5b   Tejun Heo   memblock: Make me...
890
  	phys_addr_t end = base + memblock_cap_size(base, &size);
72d4b0b4e   Benjamin Herrenschmidt   memblock: Impleme...
891
892
893
  
  	if (idx == -1)
  		return 0;
abb65272a   Tomi Valkeinen   memblock: fix mem...
894
895
  	return memblock.memory.regions[idx].base <= base &&
  		(memblock.memory.regions[idx].base +
eb18f1b5b   Tejun Heo   memblock: Make me...
896
  		 memblock.memory.regions[idx].size) >= end;
95f72d1ed   Yinghai Lu   lmb: rename to me...
897
  }
eab309494   Stephen Boyd   memblock: Documen...
898
899
900
901
902
903
904
905
906
907
  /**
   * 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 ...
908
  int __init_memblock memblock_is_region_reserved(phys_addr_t base, phys_addr_t size)
95f72d1ed   Yinghai Lu   lmb: rename to me...
909
  {
eb18f1b5b   Tejun Heo   memblock: Make me...
910
  	memblock_cap_size(base, &size);
f1c2c19c4   Benjamin Herrenschmidt   memblock: Fix mem...
911
  	return memblock_overlaps_region(&memblock.reserved, base, size) >= 0;
95f72d1ed   Yinghai Lu   lmb: rename to me...
912
  }
6ede1fd3c   Yinghai Lu   x86, mm: Trim mem...
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
  void __init_memblock memblock_trim_memory(phys_addr_t align)
  {
  	int i;
  	phys_addr_t start, end, orig_start, orig_end;
  	struct memblock_type *mem = &memblock.memory;
  
  	for (i = 0; i < mem->cnt; i++) {
  		orig_start = mem->regions[i].base;
  		orig_end = mem->regions[i].base + mem->regions[i].size;
  		start = round_up(orig_start, align);
  		end = round_down(orig_end, align);
  
  		if (start == orig_start && end == orig_end)
  			continue;
  
  		if (start < end) {
  			mem->regions[i].base = start;
  			mem->regions[i].size = end - start;
  		} else {
  			memblock_remove_region(mem, i);
  			i--;
  		}
  	}
  }
e63075a3c   Benjamin Herrenschmidt   memblock: Introdu...
937

3661ca66a   Yinghai Lu   memblock: Fix sec...
938
  void __init_memblock memblock_set_current_limit(phys_addr_t limit)
e63075a3c   Benjamin Herrenschmidt   memblock: Introdu...
939
940
941
  {
  	memblock.current_limit = limit;
  }
7c0caeb86   Tejun Heo   memblock: Add opt...
942
  static void __init_memblock memblock_dump(struct memblock_type *type, char *name)
6ed311b28   Benjamin Herrenschmidt   memblock: Move fu...
943
944
945
  {
  	unsigned long long base, size;
  	int i;
7c0caeb86   Tejun Heo   memblock: Add opt...
946
947
  	pr_info(" %s.cnt  = 0x%lx
  ", name, type->cnt);
6ed311b28   Benjamin Herrenschmidt   memblock: Move fu...
948

7c0caeb86   Tejun Heo   memblock: Add opt...
949
950
951
952
953
954
955
956
957
958
959
960
961
962
  	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...
963
964
  	}
  }
4ff7b82f1   Tejun Heo   memblock: Add __m...
965
  void __init_memblock __memblock_dump_all(void)
6ed311b28   Benjamin Herrenschmidt   memblock: Move fu...
966
  {
6ed311b28   Benjamin Herrenschmidt   memblock: Move fu...
967
968
  	pr_info("MEMBLOCK configuration:
  ");
1440c4e2c   Tejun Heo   memblock: Track t...
969
970
971
972
  	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...
973
974
975
976
  
  	memblock_dump(&memblock.memory, "memory");
  	memblock_dump(&memblock.reserved, "reserved");
  }
1aadc0560   Tejun Heo   memblock: s/membl...
977
  void __init memblock_allow_resize(void)
6ed311b28   Benjamin Herrenschmidt   memblock: Move fu...
978
  {
142b45a72   Benjamin Herrenschmidt   memblock: Add arr...
979
  	memblock_can_resize = 1;
6ed311b28   Benjamin Herrenschmidt   memblock: Move fu...
980
  }
6ed311b28   Benjamin Herrenschmidt   memblock: Move fu...
981
982
983
984
985
986
987
  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...
988
  #if defined(CONFIG_DEBUG_FS) && !defined(CONFIG_ARCH_DISCARD_MEMBLOCK)
6d03b885f   Benjamin Herrenschmidt   memblock: Add deb...
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
  
  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 */