commented early_printk patch because of rejects.
[linux-flexiantxendom0-3.2.10.git] / mm / bootmem.c
1 /*
2  *  linux/mm/bootmem.c
3  *
4  *  Copyright (C) 1999 Ingo Molnar
5  *  Discontiguous memory support, Kanoj Sarcar, SGI, Nov 1999
6  *
7  *  simple boot-time physical memory area allocator and
8  *  free memory collector. It's used to deal with reserved
9  *  system memory and memory holes as well.
10  */
11
12 #include <linux/mm.h>
13 #include <linux/kernel_stat.h>
14 #include <linux/swap.h>
15 #include <linux/interrupt.h>
16 #include <linux/init.h>
17 #include <linux/bootmem.h>
18 #include <linux/mmzone.h>
19 #include <asm/dma.h>
20 #include <asm/io.h>
21
22 /*
23  * Access to this subsystem has to be serialized externally. (this is
24  * true for the boot process anyway)
25  */
26 unsigned long max_low_pfn;
27 unsigned long min_low_pfn;
28 unsigned long max_pfn;
29
30 /* return the number of _pages_ that will be allocated for the boot bitmap */
31 unsigned long __init bootmem_bootmap_pages (unsigned long pages)
32 {
33         unsigned long mapsize;
34
35         mapsize = (pages+7)/8;
36         mapsize = (mapsize + ~PAGE_MASK) & PAGE_MASK;
37         mapsize >>= PAGE_SHIFT;
38
39         return mapsize;
40 }
41
42 /*
43  * Called once to set up the allocator itself.
44  */
45 static unsigned long __init init_bootmem_core (pg_data_t *pgdat,
46         unsigned long mapstart, unsigned long start, unsigned long end)
47 {
48         bootmem_data_t *bdata = pgdat->bdata;
49         unsigned long mapsize = ((end - start)+7)/8;
50
51
52         /*
53          * sort pgdat_list so that the lowest one comes first,
54          * which makes alloc_bootmem_low_pages work as desired.
55          */
56         if (!pgdat_list || pgdat_list->node_start_pfn > pgdat->node_start_pfn) {
57                 pgdat->pgdat_next = pgdat_list;
58                 pgdat_list = pgdat;
59         } else {
60                 pg_data_t *tmp = pgdat_list;
61                 while (tmp->pgdat_next) {
62                         if (tmp->pgdat_next->node_start_pfn > pgdat->node_start_pfn)
63                                 break;
64                         tmp = tmp->pgdat_next;
65                 }
66                 pgdat->pgdat_next = tmp->pgdat_next;
67                 tmp->pgdat_next = pgdat;
68         }
69
70         mapsize = (mapsize + (sizeof(long) - 1UL)) & ~(sizeof(long) - 1UL);
71         bdata->node_bootmem_map = phys_to_virt(mapstart << PAGE_SHIFT);
72         bdata->node_boot_start = (start << PAGE_SHIFT);
73         bdata->node_low_pfn = end;
74
75         /*
76          * Initially all pages are reserved - setup_arch() has to
77          * register free RAM areas explicitly.
78          */
79         memset(bdata->node_bootmem_map, 0xff, mapsize);
80
81         return mapsize;
82 }
83
84 /*
85  * Marks a particular physical memory range as unallocatable. Usable RAM
86  * might be used for boot-time allocations - or it might get added
87  * to the free page pool later on.
88  */
89 static void __init reserve_bootmem_core(bootmem_data_t *bdata, unsigned long addr, unsigned long size)
90 {
91         unsigned long i;
92         /*
93          * round up, partially reserved pages are considered
94          * fully reserved.
95          */
96         unsigned long sidx = (addr - bdata->node_boot_start)/PAGE_SIZE;
97         unsigned long eidx = (addr + size - bdata->node_boot_start + 
98                                                         PAGE_SIZE-1)/PAGE_SIZE;
99         unsigned long end = (addr + size + PAGE_SIZE-1)/PAGE_SIZE;
100
101         if (!size) BUG();
102
103         if (sidx >= eidx)
104                 BUG();
105         if ((addr >> PAGE_SHIFT) >= bdata->node_low_pfn)
106                 BUG();
107         if (end > bdata->node_low_pfn)
108                 BUG();
109         for (i = sidx; i < eidx; i++)
110                 if (test_and_set_bit(i, bdata->node_bootmem_map))
111                         printk("hm, page %08lx reserved twice.\n", i*PAGE_SIZE);
112 }
113
114 static void __init free_bootmem_core(bootmem_data_t *bdata, unsigned long addr, unsigned long size)
115 {
116         unsigned long i;
117         unsigned long start;
118         /*
119          * round down end of usable mem, partially free pages are
120          * considered reserved.
121          */
122         unsigned long sidx;
123         unsigned long eidx = (addr + size - bdata->node_boot_start)/PAGE_SIZE;
124         unsigned long end = (addr + size)/PAGE_SIZE;
125
126         if (!size) BUG();
127         if (end > bdata->node_low_pfn)
128                 BUG();
129
130         if (addr < bdata->last_success)
131                 bdata->last_success = addr;
132
133         /*
134          * Round up the beginning of the address.
135          */
136         start = (addr + PAGE_SIZE-1) / PAGE_SIZE;
137         sidx = start - (bdata->node_boot_start/PAGE_SIZE);
138
139         for (i = sidx; i < eidx; i++) {
140                 if (!test_and_clear_bit(i, bdata->node_bootmem_map))
141                         BUG();
142         }
143 }
144
145 /*
146  * We 'merge' subsequent allocations to save space. We might 'lose'
147  * some fraction of a page if allocations cannot be satisfied due to
148  * size constraints on boxes where there is physical RAM space
149  * fragmentation - in these cases * (mostly large memory boxes) this
150  * is not a problem.
151  *
152  * On low memory boxes we get it right in 100% of the cases.
153  *
154  * alignment has to be a power of 2 value.
155  *
156  * NOTE:  This function is _not_ reenetrant.
157  */
158 static void * __init
159 __alloc_bootmem_core(struct bootmem_data *bdata, unsigned long size,
160                 unsigned long align, unsigned long goal)
161 {
162         unsigned long offset, remaining_size, areasize, preferred;
163         unsigned long i, start = 0, incr, eidx;
164         void *ret;
165
166         if(!size) {
167                 printk("__alloc_bootmem_core(): zero-sized request\n");
168                 dump_stack();
169                 BUG();
170         }
171         BUG_ON(align & (align-1));
172
173         eidx = bdata->node_low_pfn - (bdata->node_boot_start >> PAGE_SHIFT);
174         offset = 0;
175         if (align &&
176             (bdata->node_boot_start & (align - 1UL)) != 0)
177                 offset = (align - (bdata->node_boot_start & (align - 1UL)));
178         offset >>= PAGE_SHIFT;
179
180         /*
181          * We try to allocate bootmem pages above 'goal'
182          * first, then we try to allocate lower pages.
183          */
184         if (goal && (goal >= bdata->node_boot_start) && 
185             ((goal >> PAGE_SHIFT) < bdata->node_low_pfn)) {
186                 preferred = goal - bdata->node_boot_start;
187
188                 if (bdata->last_success >= preferred)
189                         preferred = bdata->last_success;
190         } else
191                 preferred = 0;
192
193         preferred = ((preferred + align - 1) & ~(align - 1)) >> PAGE_SHIFT;
194         preferred += offset;
195         areasize = (size+PAGE_SIZE-1)/PAGE_SIZE;
196         incr = align >> PAGE_SHIFT ? : 1;
197
198 restart_scan:
199         for (i = preferred; i < eidx; i += incr) {
200                 unsigned long j;
201                 i = find_next_zero_bit(bdata->node_bootmem_map, eidx, i);
202                 i = ALIGN(i, incr);
203                 if (test_bit(i, bdata->node_bootmem_map))
204                         continue;
205                 for (j = i + 1; j < i + areasize; ++j) {
206                         if (j >= eidx)
207                                 goto fail_block;
208                         if (test_bit (j, bdata->node_bootmem_map))
209                                 goto fail_block;
210                 }
211                 start = i;
212                 goto found;
213         fail_block:
214                 i = ALIGN(j, incr);
215         }
216
217         if (preferred > offset) {
218                 preferred = offset;
219                 goto restart_scan;
220         }
221         return NULL;
222
223 found:
224         bdata->last_success = start << PAGE_SHIFT;
225         BUG_ON(start >= eidx);
226
227         /*
228          * Is the next page of the previous allocation-end the start
229          * of this allocation's buffer? If yes then we can 'merge'
230          * the previous partial page with this allocation.
231          */
232         if (align < PAGE_SIZE &&
233             bdata->last_offset && bdata->last_pos+1 == start) {
234                 offset = (bdata->last_offset+align-1) & ~(align-1);
235                 BUG_ON(offset > PAGE_SIZE);
236                 remaining_size = PAGE_SIZE-offset;
237                 if (size < remaining_size) {
238                         areasize = 0;
239                         /* last_pos unchanged */
240                         bdata->last_offset = offset+size;
241                         ret = phys_to_virt(bdata->last_pos*PAGE_SIZE + offset +
242                                                 bdata->node_boot_start);
243                 } else {
244                         remaining_size = size - remaining_size;
245                         areasize = (remaining_size+PAGE_SIZE-1)/PAGE_SIZE;
246                         ret = phys_to_virt(bdata->last_pos*PAGE_SIZE + offset +
247                                                 bdata->node_boot_start);
248                         bdata->last_pos = start+areasize-1;
249                         bdata->last_offset = remaining_size;
250                 }
251                 bdata->last_offset &= ~PAGE_MASK;
252         } else {
253                 bdata->last_pos = start + areasize - 1;
254                 bdata->last_offset = size & ~PAGE_MASK;
255                 ret = phys_to_virt(start * PAGE_SIZE + bdata->node_boot_start);
256         }
257
258         /*
259          * Reserve the area now:
260          */
261         for (i = start; i < start+areasize; i++)
262                 if (unlikely(test_and_set_bit(i, bdata->node_bootmem_map)))
263                         BUG();
264         memset(ret, 0, size);
265         return ret;
266 }
267
268 static unsigned long __init free_all_bootmem_core(pg_data_t *pgdat)
269 {
270         struct page *page;
271         bootmem_data_t *bdata = pgdat->bdata;
272         unsigned long i, count, total = 0;
273         unsigned long idx;
274         unsigned long *map; 
275
276         if (!bdata->node_bootmem_map) BUG();
277
278         count = 0;
279         /* first extant page of the node */
280         page = virt_to_page(phys_to_virt(bdata->node_boot_start));
281         idx = bdata->node_low_pfn - (bdata->node_boot_start >> PAGE_SHIFT);
282         map = bdata->node_bootmem_map;
283         for (i = 0; i < idx; ) {
284                 unsigned long v = ~map[i / BITS_PER_LONG];
285                 if (v) {
286                         unsigned long m;
287                         for (m = 1; m && i < idx; m<<=1, page++, i++) {
288                                 if (v & m) {
289                                         count++;
290                                         ClearPageReserved(page);
291                                         set_page_count(page, 1);
292                                         __free_page(page);
293                                 }
294                         }
295                 } else {
296                         i+=BITS_PER_LONG;
297                         page += BITS_PER_LONG;
298                 }
299         }
300         total += count;
301
302         /*
303          * Now free the allocator bitmap itself, it's not
304          * needed anymore:
305          */
306         page = virt_to_page(bdata->node_bootmem_map);
307         count = 0;
308         for (i = 0; i < ((bdata->node_low_pfn-(bdata->node_boot_start >> PAGE_SHIFT))/8 + PAGE_SIZE-1)/PAGE_SIZE; i++,page++) {
309                 count++;
310                 ClearPageReserved(page);
311                 set_page_count(page, 1);
312                 __free_page(page);
313         }
314         total += count;
315         bdata->node_bootmem_map = NULL;
316
317         return total;
318 }
319
320 unsigned long __init init_bootmem_node (pg_data_t *pgdat, unsigned long freepfn, unsigned long startpfn, unsigned long endpfn)
321 {
322         return(init_bootmem_core(pgdat, freepfn, startpfn, endpfn));
323 }
324
325 void __init reserve_bootmem_node (pg_data_t *pgdat, unsigned long physaddr, unsigned long size)
326 {
327         reserve_bootmem_core(pgdat->bdata, physaddr, size);
328 }
329
330 void __init free_bootmem_node (pg_data_t *pgdat, unsigned long physaddr, unsigned long size)
331 {
332         free_bootmem_core(pgdat->bdata, physaddr, size);
333 }
334
335 unsigned long __init free_all_bootmem_node (pg_data_t *pgdat)
336 {
337         return(free_all_bootmem_core(pgdat));
338 }
339
340 #ifndef CONFIG_DISCONTIGMEM
341 unsigned long __init init_bootmem (unsigned long start, unsigned long pages)
342 {
343         max_low_pfn = pages;
344         min_low_pfn = start;
345         return(init_bootmem_core(&contig_page_data, start, 0, pages));
346 }
347
348 #ifndef CONFIG_HAVE_ARCH_BOOTMEM_NODE
349 void __init reserve_bootmem (unsigned long addr, unsigned long size)
350 {
351         reserve_bootmem_core(contig_page_data.bdata, addr, size);
352 }
353 #endif /* !CONFIG_HAVE_ARCH_BOOTMEM_NODE */
354
355 void __init free_bootmem (unsigned long addr, unsigned long size)
356 {
357         free_bootmem_core(contig_page_data.bdata, addr, size);
358 }
359
360 unsigned long __init free_all_bootmem (void)
361 {
362         return(free_all_bootmem_core(&contig_page_data));
363 }
364 #endif /* !CONFIG_DISCONTIGMEM */
365
366 void * __init __alloc_bootmem (unsigned long size, unsigned long align, unsigned long goal)
367 {
368         pg_data_t *pgdat = pgdat_list;
369         void *ptr;
370
371         for_each_pgdat(pgdat)
372                 if ((ptr = __alloc_bootmem_core(pgdat->bdata, size,
373                                                 align, goal)))
374                         return(ptr);
375
376         /*
377          * Whoops, we cannot satisfy the allocation request.
378          */
379         printk(KERN_ALERT "bootmem alloc of %lu bytes failed!\n", size);
380         panic("Out of memory");
381         return NULL;
382 }
383
384 void * __init __alloc_bootmem_node (pg_data_t *pgdat, unsigned long size, unsigned long align, unsigned long goal)
385 {
386         void *ptr;
387
388         ptr = __alloc_bootmem_core(pgdat->bdata, size, align, goal);
389         if (ptr)
390                 return (ptr);
391
392         /*
393          * Whoops, we cannot satisfy the allocation request.
394          */
395         printk(KERN_ALERT "bootmem alloc of %lu bytes failed!\n", size);
396         panic("Out of memory");
397         return NULL;
398 }
399