aboutsummaryrefslogtreecommitdiffstats
path: root/mm/memblock.c
diff options
context:
space:
mode:
Diffstat (limited to 'mm/memblock.c')
-rw-r--r--mm/memblock.c104
1 files changed, 102 insertions, 2 deletions
diff --git a/mm/memblock.c b/mm/memblock.c
index e5f3f9bdc311..0787790b1ce0 100644
--- a/mm/memblock.c
+++ b/mm/memblock.c
@@ -11,6 +11,7 @@
11 */ 11 */
12 12
13#include <linux/kernel.h> 13#include <linux/kernel.h>
14#include <linux/slab.h>
14#include <linux/init.h> 15#include <linux/init.h>
15#include <linux/bitops.h> 16#include <linux/bitops.h>
16#include <linux/poison.h> 17#include <linux/poison.h>
@@ -18,12 +19,23 @@
18 19
19struct memblock memblock; 20struct memblock memblock;
20 21
21static int memblock_debug; 22static int memblock_debug, memblock_can_resize;
22static struct memblock_region memblock_memory_init_regions[INIT_MEMBLOCK_REGIONS + 1]; 23static struct memblock_region memblock_memory_init_regions[INIT_MEMBLOCK_REGIONS + 1];
23static struct memblock_region memblock_reserved_init_regions[INIT_MEMBLOCK_REGIONS + 1]; 24static struct memblock_region memblock_reserved_init_regions[INIT_MEMBLOCK_REGIONS + 1];
24 25
25#define MEMBLOCK_ERROR (~(phys_addr_t)0) 26#define MEMBLOCK_ERROR (~(phys_addr_t)0)
26 27
28/* inline so we don't get a warning when pr_debug is compiled out */
29static inline const char *memblock_type_name(struct memblock_type *type)
30{
31 if (type == &memblock.memory)
32 return "memory";
33 else if (type == &memblock.reserved)
34 return "reserved";
35 else
36 return "unknown";
37}
38
27/* 39/*
28 * Address comparison utilities 40 * Address comparison utilities
29 */ 41 */
@@ -156,6 +168,79 @@ static void memblock_coalesce_regions(struct memblock_type *type,
156 memblock_remove_region(type, r2); 168 memblock_remove_region(type, r2);
157} 169}
158 170
171/* Defined below but needed now */
172static long memblock_add_region(struct memblock_type *type, phys_addr_t base, phys_addr_t size);
173
174static int memblock_double_array(struct memblock_type *type)
175{
176 struct memblock_region *new_array, *old_array;
177 phys_addr_t old_size, new_size, addr;
178 int use_slab = slab_is_available();
179
180 /* We don't allow resizing until we know about the reserved regions
181 * of memory that aren't suitable for allocation
182 */
183 if (!memblock_can_resize)
184 return -1;
185
186 pr_debug("memblock: %s array full, doubling...", memblock_type_name(type));
187
188 /* Calculate new doubled size */
189 old_size = type->max * sizeof(struct memblock_region);
190 new_size = old_size << 1;
191
192 /* Try to find some space for it.
193 *
194 * WARNING: We assume that either slab_is_available() and we use it or
195 * we use MEMBLOCK for allocations. That means that this is unsafe to use
196 * when bootmem is currently active (unless bootmem itself is implemented
197 * on top of MEMBLOCK which isn't the case yet)
198 *
199 * This should however not be an issue for now, as we currently only
200 * call into MEMBLOCK while it's still active, or much later when slab is
201 * active for memory hotplug operations
202 */
203 if (use_slab) {
204 new_array = kmalloc(new_size, GFP_KERNEL);
205 addr = new_array == NULL ? MEMBLOCK_ERROR : __pa(new_array);
206 } else
207 addr = memblock_find_base(new_size, sizeof(phys_addr_t), MEMBLOCK_ALLOC_ACCESSIBLE);
208 if (addr == MEMBLOCK_ERROR) {
209 pr_err("memblock: Failed to double %s array from %ld to %ld entries !\n",
210 memblock_type_name(type), type->max, type->max * 2);
211 return -1;
212 }
213 new_array = __va(addr);
214
215 /* Found space, we now need to move the array over before
216 * we add the reserved region since it may be our reserved
217 * array itself that is full.
218 */
219 memcpy(new_array, type->regions, old_size);
220 memset(new_array + type->max, 0, old_size);
221 old_array = type->regions;
222 type->regions = new_array;
223 type->max <<= 1;
224
225 /* If we use SLAB that's it, we are done */
226 if (use_slab)
227 return 0;
228
229 /* Add the new reserved region now. Should not fail ! */
230 BUG_ON(memblock_add_region(&memblock.reserved, addr, new_size) < 0);
231
232 /* If the array wasn't our static init one, then free it. We only do
233 * that before SLAB is available as later on, we don't know whether
234 * to use kfree or free_bootmem_pages(). Shouldn't be a big deal
235 * anyways
236 */
237 if (old_array != memblock_memory_init_regions &&
238 old_array != memblock_reserved_init_regions)
239 memblock_free(__pa(old_array), old_size);
240
241 return 0;
242}
243
159static long memblock_add_region(struct memblock_type *type, phys_addr_t base, phys_addr_t size) 244static long memblock_add_region(struct memblock_type *type, phys_addr_t base, phys_addr_t size)
160{ 245{
161 unsigned long coalesced = 0; 246 unsigned long coalesced = 0;
@@ -196,7 +281,11 @@ static long memblock_add_region(struct memblock_type *type, phys_addr_t base, ph
196 281
197 if (coalesced) 282 if (coalesced)
198 return coalesced; 283 return coalesced;
199 if (type->cnt >= type->max) 284
285 /* If we are out of space, we fail. It's too late to resize the array
286 * but then this shouldn't have happened in the first place.
287 */
288 if (WARN_ON(type->cnt >= type->max))
200 return -1; 289 return -1;
201 290
202 /* Couldn't coalesce the MEMBLOCK, so add it to the sorted table. */ 291 /* Couldn't coalesce the MEMBLOCK, so add it to the sorted table. */
@@ -217,6 +306,14 @@ static long memblock_add_region(struct memblock_type *type, phys_addr_t base, ph
217 } 306 }
218 type->cnt++; 307 type->cnt++;
219 308
309 /* The array is full ? Try to resize it. If that fails, we undo
310 * our allocation and return an error
311 */
312 if (type->cnt == type->max && memblock_double_array(type)) {
313 type->cnt--;
314 return -1;
315 }
316
220 return 0; 317 return 0;
221} 318}
222 319
@@ -541,6 +638,9 @@ void __init memblock_analyze(void)
541 638
542 for (i = 0; i < memblock.memory.cnt; i++) 639 for (i = 0; i < memblock.memory.cnt; i++)
543 memblock.memory_size += memblock.memory.regions[i].size; 640 memblock.memory_size += memblock.memory.regions[i].size;
641
642 /* We allow resizing from there */
643 memblock_can_resize = 1;
544} 644}
545 645
546void __init memblock_init(void) 646void __init memblock_init(void)