core: Move early_res from arch/x86 to kernel/
[safe/jmp/linux-2.6] / kernel / early_res.c
1 /*
2  * early_res, could be used to replace bootmem
3  */
4 #include <linux/kernel.h>
5 #include <linux/types.h>
6 #include <linux/init.h>
7 #include <linux/bootmem.h>
8 #include <linux/mm.h>
9 #include <linux/early_res.h>
10
11 /*
12  * Early reserved memory areas.
13  */
14 /*
15  * need to make sure this one is bigger enough before
16  * find_fw_memmap_area could be used
17  */
18 #define MAX_EARLY_RES_X 32
19
20 struct early_res {
21         u64 start, end;
22         char name[15];
23         char overlap_ok;
24 };
25 static struct early_res early_res_x[MAX_EARLY_RES_X] __initdata;
26
27 static int max_early_res __initdata = MAX_EARLY_RES_X;
28 static struct early_res *early_res __initdata = &early_res_x[0];
29 static int early_res_count __initdata;
30
31 static int __init find_overlapped_early(u64 start, u64 end)
32 {
33         int i;
34         struct early_res *r;
35
36         for (i = 0; i < max_early_res && early_res[i].end; i++) {
37                 r = &early_res[i];
38                 if (end > r->start && start < r->end)
39                         break;
40         }
41
42         return i;
43 }
44
45 /*
46  * Drop the i-th range from the early reservation map,
47  * by copying any higher ranges down one over it, and
48  * clearing what had been the last slot.
49  */
50 static void __init drop_range(int i)
51 {
52         int j;
53
54         for (j = i + 1; j < max_early_res && early_res[j].end; j++)
55                 ;
56
57         memmove(&early_res[i], &early_res[i + 1],
58                (j - 1 - i) * sizeof(struct early_res));
59
60         early_res[j - 1].end = 0;
61         early_res_count--;
62 }
63
64 /*
65  * Split any existing ranges that:
66  *  1) are marked 'overlap_ok', and
67  *  2) overlap with the stated range [start, end)
68  * into whatever portion (if any) of the existing range is entirely
69  * below or entirely above the stated range.  Drop the portion
70  * of the existing range that overlaps with the stated range,
71  * which will allow the caller of this routine to then add that
72  * stated range without conflicting with any existing range.
73  */
74 static void __init drop_overlaps_that_are_ok(u64 start, u64 end)
75 {
76         int i;
77         struct early_res *r;
78         u64 lower_start, lower_end;
79         u64 upper_start, upper_end;
80         char name[15];
81
82         for (i = 0; i < max_early_res && early_res[i].end; i++) {
83                 r = &early_res[i];
84
85                 /* Continue past non-overlapping ranges */
86                 if (end <= r->start || start >= r->end)
87                         continue;
88
89                 /*
90                  * Leave non-ok overlaps as is; let caller
91                  * panic "Overlapping early reservations"
92                  * when it hits this overlap.
93                  */
94                 if (!r->overlap_ok)
95                         return;
96
97                 /*
98                  * We have an ok overlap.  We will drop it from the early
99                  * reservation map, and add back in any non-overlapping
100                  * portions (lower or upper) as separate, overlap_ok,
101                  * non-overlapping ranges.
102                  */
103
104                 /* 1. Note any non-overlapping (lower or upper) ranges. */
105                 strncpy(name, r->name, sizeof(name) - 1);
106
107                 lower_start = lower_end = 0;
108                 upper_start = upper_end = 0;
109                 if (r->start < start) {
110                         lower_start = r->start;
111                         lower_end = start;
112                 }
113                 if (r->end > end) {
114                         upper_start = end;
115                         upper_end = r->end;
116                 }
117
118                 /* 2. Drop the original ok overlapping range */
119                 drop_range(i);
120
121                 i--;            /* resume for-loop on copied down entry */
122
123                 /* 3. Add back in any non-overlapping ranges. */
124                 if (lower_end)
125                         reserve_early_overlap_ok(lower_start, lower_end, name);
126                 if (upper_end)
127                         reserve_early_overlap_ok(upper_start, upper_end, name);
128         }
129 }
130
131 static void __init __reserve_early(u64 start, u64 end, char *name,
132                                                 int overlap_ok)
133 {
134         int i;
135         struct early_res *r;
136
137         i = find_overlapped_early(start, end);
138         if (i >= max_early_res)
139                 panic("Too many early reservations");
140         r = &early_res[i];
141         if (r->end)
142                 panic("Overlapping early reservations "
143                       "%llx-%llx %s to %llx-%llx %s\n",
144                       start, end - 1, name ? name : "", r->start,
145                       r->end - 1, r->name);
146         r->start = start;
147         r->end = end;
148         r->overlap_ok = overlap_ok;
149         if (name)
150                 strncpy(r->name, name, sizeof(r->name) - 1);
151         early_res_count++;
152 }
153
154 /*
155  * A few early reservtations come here.
156  *
157  * The 'overlap_ok' in the name of this routine does -not- mean it
158  * is ok for these reservations to overlap an earlier reservation.
159  * Rather it means that it is ok for subsequent reservations to
160  * overlap this one.
161  *
162  * Use this entry point to reserve early ranges when you are doing
163  * so out of "Paranoia", reserving perhaps more memory than you need,
164  * just in case, and don't mind a subsequent overlapping reservation
165  * that is known to be needed.
166  *
167  * The drop_overlaps_that_are_ok() call here isn't really needed.
168  * It would be needed if we had two colliding 'overlap_ok'
169  * reservations, so that the second such would not panic on the
170  * overlap with the first.  We don't have any such as of this
171  * writing, but might as well tolerate such if it happens in
172  * the future.
173  */
174 void __init reserve_early_overlap_ok(u64 start, u64 end, char *name)
175 {
176         drop_overlaps_that_are_ok(start, end);
177         __reserve_early(start, end, name, 1);
178 }
179
180 static void __init __check_and_double_early_res(u64 ex_start, u64 ex_end)
181 {
182         u64 start, end, size, mem;
183         struct early_res *new;
184
185         /* do we have enough slots left ? */
186         if ((max_early_res - early_res_count) > max(max_early_res/8, 2))
187                 return;
188
189         /* double it */
190         mem = -1ULL;
191         size = sizeof(struct early_res) * max_early_res * 2;
192         if (early_res == early_res_x)
193                 start = 0;
194         else
195                 start = early_res[0].end;
196         end = ex_start;
197         if (start + size < end)
198                 mem = find_fw_memmap_area(start, end, size,
199                                          sizeof(struct early_res));
200         if (mem == -1ULL) {
201                 start = ex_end;
202                 end = get_max_mapped();
203                 if (start + size < end)
204                         mem = find_fw_memmap_area(start, end, size,
205                                                  sizeof(struct early_res));
206         }
207         if (mem == -1ULL)
208                 panic("can not find more space for early_res array");
209
210         new = __va(mem);
211         /* save the first one for own */
212         new[0].start = mem;
213         new[0].end = mem + size;
214         new[0].overlap_ok = 0;
215         /* copy old to new */
216         if (early_res == early_res_x) {
217                 memcpy(&new[1], &early_res[0],
218                          sizeof(struct early_res) * max_early_res);
219                 memset(&new[max_early_res+1], 0,
220                          sizeof(struct early_res) * (max_early_res - 1));
221                 early_res_count++;
222         } else {
223                 memcpy(&new[1], &early_res[1],
224                          sizeof(struct early_res) * (max_early_res - 1));
225                 memset(&new[max_early_res], 0,
226                          sizeof(struct early_res) * max_early_res);
227         }
228         memset(&early_res[0], 0, sizeof(struct early_res) * max_early_res);
229         early_res = new;
230         max_early_res *= 2;
231         printk(KERN_DEBUG "early_res array is doubled to %d at [%llx - %llx]\n",
232                 max_early_res, mem, mem + size - 1);
233 }
234
235 /*
236  * Most early reservations come here.
237  *
238  * We first have drop_overlaps_that_are_ok() drop any pre-existing
239  * 'overlap_ok' ranges, so that we can then reserve this memory
240  * range without risk of panic'ing on an overlapping overlap_ok
241  * early reservation.
242  */
243 void __init reserve_early(u64 start, u64 end, char *name)
244 {
245         if (start >= end)
246                 return;
247
248         __check_and_double_early_res(start, end);
249
250         drop_overlaps_that_are_ok(start, end);
251         __reserve_early(start, end, name, 0);
252 }
253
254 void __init reserve_early_without_check(u64 start, u64 end, char *name)
255 {
256         struct early_res *r;
257
258         if (start >= end)
259                 return;
260
261         __check_and_double_early_res(start, end);
262
263         r = &early_res[early_res_count];
264
265         r->start = start;
266         r->end = end;
267         r->overlap_ok = 0;
268         if (name)
269                 strncpy(r->name, name, sizeof(r->name) - 1);
270         early_res_count++;
271 }
272
273 void __init free_early(u64 start, u64 end)
274 {
275         struct early_res *r;
276         int i;
277
278         i = find_overlapped_early(start, end);
279         r = &early_res[i];
280         if (i >= max_early_res || r->end != end || r->start != start)
281                 panic("free_early on not reserved area: %llx-%llx!",
282                          start, end - 1);
283
284         drop_range(i);
285 }
286
287 #ifdef CONFIG_NO_BOOTMEM
288 static void __init subtract_early_res(struct range *range, int az)
289 {
290         int i, count;
291         u64 final_start, final_end;
292         int idx = 0;
293
294         count  = 0;
295         for (i = 0; i < max_early_res && early_res[i].end; i++)
296                 count++;
297
298         /* need to skip first one ?*/
299         if (early_res != early_res_x)
300                 idx = 1;
301
302 #define DEBUG_PRINT_EARLY_RES 1
303
304 #if DEBUG_PRINT_EARLY_RES
305         printk(KERN_INFO "Subtract (%d early reservations)\n", count);
306 #endif
307         for (i = idx; i < count; i++) {
308                 struct early_res *r = &early_res[i];
309 #if DEBUG_PRINT_EARLY_RES
310                 printk(KERN_INFO "  #%d [%010llx - %010llx] %15s\n", i,
311                         r->start, r->end, r->name);
312 #endif
313                 final_start = PFN_DOWN(r->start);
314                 final_end = PFN_UP(r->end);
315                 if (final_start >= final_end)
316                         continue;
317                 subtract_range(range, az, final_start, final_end);
318         }
319
320 }
321
322 int __init get_free_all_memory_range(struct range **rangep, int nodeid)
323 {
324         int i, count;
325         u64 start = 0, end;
326         u64 size;
327         u64 mem;
328         struct range *range;
329         int nr_range;
330
331         count  = 0;
332         for (i = 0; i < max_early_res && early_res[i].end; i++)
333                 count++;
334
335         count *= 2;
336
337         size = sizeof(struct range) * count;
338         end = get_max_mapped();
339 #ifdef MAX_DMA32_PFN
340         if (end > (MAX_DMA32_PFN << PAGE_SHIFT))
341                 start = MAX_DMA32_PFN << PAGE_SHIFT;
342 #endif
343         mem = find_fw_memmap_area(start, end, size, sizeof(struct range));
344         if (mem == -1ULL)
345                 panic("can not find more space for range free");
346
347         range = __va(mem);
348         /* use early_node_map[] and early_res to get range array at first */
349         memset(range, 0, size);
350         nr_range = 0;
351
352         /* need to go over early_node_map to find out good range for node */
353         nr_range = add_from_early_node_map(range, count, nr_range, nodeid);
354 #ifdef CONFIG_X86_32
355         subtract_range(range, count, max_low_pfn, -1ULL);
356 #endif
357         subtract_early_res(range, count);
358         nr_range = clean_sort_range(range, count);
359
360         /* need to clear it ? */
361         if (nodeid == MAX_NUMNODES) {
362                 memset(&early_res[0], 0,
363                          sizeof(struct early_res) * max_early_res);
364                 early_res = NULL;
365                 max_early_res = 0;
366         }
367
368         *rangep = range;
369         return nr_range;
370 }
371 #else
372 void __init early_res_to_bootmem(u64 start, u64 end)
373 {
374         int i, count;
375         u64 final_start, final_end;
376         int idx = 0;
377
378         count  = 0;
379         for (i = 0; i < max_early_res && early_res[i].end; i++)
380                 count++;
381
382         /* need to skip first one ?*/
383         if (early_res != early_res_x)
384                 idx = 1;
385
386         printk(KERN_INFO "(%d/%d early reservations) ==> bootmem [%010llx - %010llx]\n",
387                          count - idx, max_early_res, start, end);
388         for (i = idx; i < count; i++) {
389                 struct early_res *r = &early_res[i];
390                 printk(KERN_INFO "  #%d [%010llx - %010llx] %16s", i,
391                         r->start, r->end, r->name);
392                 final_start = max(start, r->start);
393                 final_end = min(end, r->end);
394                 if (final_start >= final_end) {
395                         printk(KERN_CONT "\n");
396                         continue;
397                 }
398                 printk(KERN_CONT " ==> [%010llx - %010llx]\n",
399                         final_start, final_end);
400                 reserve_bootmem_generic(final_start, final_end - final_start,
401                                 BOOTMEM_DEFAULT);
402         }
403         /* clear them */
404         memset(&early_res[0], 0, sizeof(struct early_res) * max_early_res);
405         early_res = NULL;
406         max_early_res = 0;
407         early_res_count = 0;
408 }
409 #endif
410
411 /* Check for already reserved areas */
412 static inline int __init bad_addr(u64 *addrp, u64 size, u64 align)
413 {
414         int i;
415         u64 addr = *addrp;
416         int changed = 0;
417         struct early_res *r;
418 again:
419         i = find_overlapped_early(addr, addr + size);
420         r = &early_res[i];
421         if (i < max_early_res && r->end) {
422                 *addrp = addr = round_up(r->end, align);
423                 changed = 1;
424                 goto again;
425         }
426         return changed;
427 }
428
429 /* Check for already reserved areas */
430 static inline int __init bad_addr_size(u64 *addrp, u64 *sizep, u64 align)
431 {
432         int i;
433         u64 addr = *addrp, last;
434         u64 size = *sizep;
435         int changed = 0;
436 again:
437         last = addr + size;
438         for (i = 0; i < max_early_res && early_res[i].end; i++) {
439                 struct early_res *r = &early_res[i];
440                 if (last > r->start && addr < r->start) {
441                         size = r->start - addr;
442                         changed = 1;
443                         goto again;
444                 }
445                 if (last > r->end && addr < r->end) {
446                         addr = round_up(r->end, align);
447                         size = last - addr;
448                         changed = 1;
449                         goto again;
450                 }
451                 if (last <= r->end && addr >= r->start) {
452                         (*sizep)++;
453                         return 0;
454                 }
455         }
456         if (changed) {
457                 *addrp = addr;
458                 *sizep = size;
459         }
460         return changed;
461 }
462
463 /*
464  * Find a free area with specified alignment in a specific range.
465  * only with the area.between start to end is active range from early_node_map
466  * so they are good as RAM
467  */
468 u64 __init find_early_area(u64 ei_start, u64 ei_last, u64 start, u64 end,
469                          u64 size, u64 align)
470 {
471         u64 addr, last;
472
473         addr = round_up(ei_start, align);
474         if (addr < start)
475                 addr = round_up(start, align);
476         if (addr >= ei_last)
477                 goto out;
478         while (bad_addr(&addr, size, align) && addr+size <= ei_last)
479                 ;
480         last = addr + size;
481         if (last > ei_last)
482                 goto out;
483         if (last > end)
484                 goto out;
485
486         return addr;
487
488 out:
489         return -1ULL;
490 }
491
492 u64 __init find_early_area_size(u64 ei_start, u64 ei_last, u64 start,
493                          u64 *sizep, u64 align)
494 {
495         u64 addr, last;
496
497         addr = round_up(ei_start, align);
498         if (addr < start)
499                 addr = round_up(start, align);
500         if (addr >= ei_last)
501                 goto out;
502         *sizep = ei_last - addr;
503         while (bad_addr_size(&addr, sizep, align) && addr + *sizep <= ei_last)
504                 ;
505         last = addr + *sizep;
506         if (last > ei_last)
507                 goto out;
508
509         return addr;
510
511 out:
512         return -1ULL;
513 }