2 * early_res, could be used to replace bootmem
4 #include <linux/kernel.h>
5 #include <linux/types.h>
6 #include <linux/init.h>
7 #include <linux/bootmem.h>
9 #include <linux/early_res.h>
12 * Early reserved memory areas.
15 * need to make sure this one is bigger enough before
16 * find_fw_memmap_area could be used
18 #define MAX_EARLY_RES_X 32
25 static struct early_res early_res_x
[MAX_EARLY_RES_X
] __initdata
;
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
;
31 static int __init
find_overlapped_early(u64 start
, u64 end
)
36 for (i
= 0; i
< max_early_res
&& early_res
[i
].end
; i
++) {
38 if (end
> r
->start
&& start
< r
->end
)
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.
50 static void __init
drop_range(int i
)
54 for (j
= i
+ 1; j
< max_early_res
&& early_res
[j
].end
; j
++)
57 memmove(&early_res
[i
], &early_res
[i
+ 1],
58 (j
- 1 - i
) * sizeof(struct early_res
));
60 early_res
[j
- 1].end
= 0;
64 static void __init
drop_range_partial(int i
, u64 start
, u64 end
)
66 u64 common_start
, common_end
;
67 u64 old_start
, old_end
;
69 old_start
= early_res
[i
].start
;
70 old_end
= early_res
[i
].end
;
71 common_start
= max(old_start
, start
);
72 common_end
= min(old_end
, end
);
75 if (common_start
>= common_end
)
78 if (old_start
< common_start
) {
79 /* make head segment */
80 early_res
[i
].end
= common_start
;
81 if (old_end
> common_end
) {
85 * Save a local copy of the name, since the
86 * early_res array could get resized inside
87 * reserve_early_without_check() ->
88 * __check_and_double_early_res(), which would
89 * make the current name pointer invalid.
91 strncpy(name
, early_res
[i
].name
,
92 sizeof(early_res
[i
].name
) - 1);
93 /* add another for left over on tail */
94 reserve_early_without_check(common_end
, old_end
, name
);
98 if (old_end
> common_end
) {
99 /* reuse the entry for tail left */
100 early_res
[i
].start
= common_end
;
109 * Split any existing ranges that:
110 * 1) are marked 'overlap_ok', and
111 * 2) overlap with the stated range [start, end)
112 * into whatever portion (if any) of the existing range is entirely
113 * below or entirely above the stated range. Drop the portion
114 * of the existing range that overlaps with the stated range,
115 * which will allow the caller of this routine to then add that
116 * stated range without conflicting with any existing range.
118 static void __init
drop_overlaps_that_are_ok(u64 start
, u64 end
)
122 u64 lower_start
, lower_end
;
123 u64 upper_start
, upper_end
;
126 for (i
= 0; i
< max_early_res
&& early_res
[i
].end
; i
++) {
129 /* Continue past non-overlapping ranges */
130 if (end
<= r
->start
|| start
>= r
->end
)
134 * Leave non-ok overlaps as is; let caller
135 * panic "Overlapping early reservations"
136 * when it hits this overlap.
142 * We have an ok overlap. We will drop it from the early
143 * reservation map, and add back in any non-overlapping
144 * portions (lower or upper) as separate, overlap_ok,
145 * non-overlapping ranges.
148 /* 1. Note any non-overlapping (lower or upper) ranges. */
149 strncpy(name
, r
->name
, sizeof(name
) - 1);
151 lower_start
= lower_end
= 0;
152 upper_start
= upper_end
= 0;
153 if (r
->start
< start
) {
154 lower_start
= r
->start
;
162 /* 2. Drop the original ok overlapping range */
165 i
--; /* resume for-loop on copied down entry */
167 /* 3. Add back in any non-overlapping ranges. */
169 reserve_early_overlap_ok(lower_start
, lower_end
, name
);
171 reserve_early_overlap_ok(upper_start
, upper_end
, name
);
175 static void __init
__reserve_early(u64 start
, u64 end
, char *name
,
181 i
= find_overlapped_early(start
, end
);
182 if (i
>= max_early_res
)
183 panic("Too many early reservations");
186 panic("Overlapping early reservations "
187 "%llx-%llx %s to %llx-%llx %s\n",
188 start
, end
- 1, name
? name
: "", r
->start
,
189 r
->end
- 1, r
->name
);
192 r
->overlap_ok
= overlap_ok
;
194 strncpy(r
->name
, name
, sizeof(r
->name
) - 1);
199 * A few early reservtations come here.
201 * The 'overlap_ok' in the name of this routine does -not- mean it
202 * is ok for these reservations to overlap an earlier reservation.
203 * Rather it means that it is ok for subsequent reservations to
206 * Use this entry point to reserve early ranges when you are doing
207 * so out of "Paranoia", reserving perhaps more memory than you need,
208 * just in case, and don't mind a subsequent overlapping reservation
209 * that is known to be needed.
211 * The drop_overlaps_that_are_ok() call here isn't really needed.
212 * It would be needed if we had two colliding 'overlap_ok'
213 * reservations, so that the second such would not panic on the
214 * overlap with the first. We don't have any such as of this
215 * writing, but might as well tolerate such if it happens in
218 void __init
reserve_early_overlap_ok(u64 start
, u64 end
, char *name
)
220 drop_overlaps_that_are_ok(start
, end
);
221 __reserve_early(start
, end
, name
, 1);
224 static void __init
__check_and_double_early_res(u64 ex_start
, u64 ex_end
)
226 u64 start
, end
, size
, mem
;
227 struct early_res
*new;
229 /* do we have enough slots left ? */
230 if ((max_early_res
- early_res_count
) > max(max_early_res
/8, 2))
235 size
= sizeof(struct early_res
) * max_early_res
* 2;
236 if (early_res
== early_res_x
)
239 start
= early_res
[0].end
;
241 if (start
+ size
< end
)
242 mem
= find_fw_memmap_area(start
, end
, size
,
243 sizeof(struct early_res
));
246 end
= get_max_mapped();
247 if (start
+ size
< end
)
248 mem
= find_fw_memmap_area(start
, end
, size
,
249 sizeof(struct early_res
));
252 panic("can not find more space for early_res array");
255 /* save the first one for own */
257 new[0].end
= mem
+ size
;
258 new[0].overlap_ok
= 0;
259 /* copy old to new */
260 if (early_res
== early_res_x
) {
261 memcpy(&new[1], &early_res
[0],
262 sizeof(struct early_res
) * max_early_res
);
263 memset(&new[max_early_res
+1], 0,
264 sizeof(struct early_res
) * (max_early_res
- 1));
267 memcpy(&new[1], &early_res
[1],
268 sizeof(struct early_res
) * (max_early_res
- 1));
269 memset(&new[max_early_res
], 0,
270 sizeof(struct early_res
) * max_early_res
);
272 memset(&early_res
[0], 0, sizeof(struct early_res
) * max_early_res
);
275 printk(KERN_DEBUG
"early_res array is doubled to %d at [%llx - %llx]\n",
276 max_early_res
, mem
, mem
+ size
- 1);
280 * Most early reservations come here.
282 * We first have drop_overlaps_that_are_ok() drop any pre-existing
283 * 'overlap_ok' ranges, so that we can then reserve this memory
284 * range without risk of panic'ing on an overlapping overlap_ok
287 void __init
reserve_early(u64 start
, u64 end
, char *name
)
292 __check_and_double_early_res(start
, end
);
294 drop_overlaps_that_are_ok(start
, end
);
295 __reserve_early(start
, end
, name
, 0);
298 void __init
reserve_early_without_check(u64 start
, u64 end
, char *name
)
305 __check_and_double_early_res(start
, end
);
307 r
= &early_res
[early_res_count
];
313 strncpy(r
->name
, name
, sizeof(r
->name
) - 1);
317 void __init
free_early(u64 start
, u64 end
)
322 i
= find_overlapped_early(start
, end
);
324 if (i
>= max_early_res
|| r
->end
!= end
|| r
->start
!= start
)
325 panic("free_early on not reserved area: %llx-%llx!",
331 void __init
free_early_partial(u64 start
, u64 end
)
339 if (WARN_ONCE(start
> end
, " wrong range [%#llx, %#llx]\n", start
, end
))
343 i
= find_overlapped_early(start
, end
);
344 if (i
>= max_early_res
)
349 if (r
->end
>= end
&& r
->start
<= start
) {
350 drop_range_partial(i
, start
, end
);
354 drop_range_partial(i
, start
, end
);
358 #ifdef CONFIG_NO_BOOTMEM
359 static void __init
subtract_early_res(struct range
*range
, int az
)
362 u64 final_start
, final_end
;
366 for (i
= 0; i
< max_early_res
&& early_res
[i
].end
; i
++)
369 /* need to skip first one ?*/
370 if (early_res
!= early_res_x
)
373 #define DEBUG_PRINT_EARLY_RES 1
375 #if DEBUG_PRINT_EARLY_RES
376 printk(KERN_INFO
"Subtract (%d early reservations)\n", count
);
378 for (i
= idx
; i
< count
; i
++) {
379 struct early_res
*r
= &early_res
[i
];
380 #if DEBUG_PRINT_EARLY_RES
381 printk(KERN_INFO
" #%d [%010llx - %010llx] %15s\n", i
,
382 r
->start
, r
->end
, r
->name
);
384 final_start
= PFN_DOWN(r
->start
);
385 final_end
= PFN_UP(r
->end
);
386 if (final_start
>= final_end
)
388 subtract_range(range
, az
, final_start
, final_end
);
393 int __init
get_free_all_memory_range(struct range
**rangep
, int nodeid
)
403 for (i
= 0; i
< max_early_res
&& early_res
[i
].end
; i
++)
408 size
= sizeof(struct range
) * count
;
409 end
= get_max_mapped();
411 if (end
> (MAX_DMA32_PFN
<< PAGE_SHIFT
))
412 start
= MAX_DMA32_PFN
<< PAGE_SHIFT
;
414 mem
= find_fw_memmap_area(start
, end
, size
, sizeof(struct range
));
416 panic("can not find more space for range free");
419 /* use early_node_map[] and early_res to get range array at first */
420 memset(range
, 0, size
);
423 /* need to go over early_node_map to find out good range for node */
424 nr_range
= add_from_early_node_map(range
, count
, nr_range
, nodeid
);
426 subtract_range(range
, count
, max_low_pfn
, -1ULL);
428 subtract_early_res(range
, count
);
429 nr_range
= clean_sort_range(range
, count
);
431 /* need to clear it ? */
432 if (nodeid
== MAX_NUMNODES
) {
433 memset(&early_res
[0], 0,
434 sizeof(struct early_res
) * max_early_res
);
443 void __init
early_res_to_bootmem(u64 start
, u64 end
)
446 u64 final_start
, final_end
;
450 for (i
= 0; i
< max_early_res
&& early_res
[i
].end
; i
++)
453 /* need to skip first one ?*/
454 if (early_res
!= early_res_x
)
457 printk(KERN_INFO
"(%d/%d early reservations) ==> bootmem [%010llx - %010llx]\n",
458 count
- idx
, max_early_res
, start
, end
);
459 for (i
= idx
; i
< count
; i
++) {
460 struct early_res
*r
= &early_res
[i
];
461 printk(KERN_INFO
" #%d [%010llx - %010llx] %16s", i
,
462 r
->start
, r
->end
, r
->name
);
463 final_start
= max(start
, r
->start
);
464 final_end
= min(end
, r
->end
);
465 if (final_start
>= final_end
) {
466 printk(KERN_CONT
"\n");
469 printk(KERN_CONT
" ==> [%010llx - %010llx]\n",
470 final_start
, final_end
);
471 reserve_bootmem_generic(final_start
, final_end
- final_start
,
475 memset(&early_res
[0], 0, sizeof(struct early_res
) * max_early_res
);
482 /* Check for already reserved areas */
483 static inline int __init
bad_addr(u64
*addrp
, u64 size
, u64 align
)
490 i
= find_overlapped_early(addr
, addr
+ size
);
492 if (i
< max_early_res
&& r
->end
) {
493 *addrp
= addr
= round_up(r
->end
, align
);
500 /* Check for already reserved areas */
501 static inline int __init
bad_addr_size(u64
*addrp
, u64
*sizep
, u64 align
)
504 u64 addr
= *addrp
, last
;
509 for (i
= 0; i
< max_early_res
&& early_res
[i
].end
; i
++) {
510 struct early_res
*r
= &early_res
[i
];
511 if (last
> r
->start
&& addr
< r
->start
) {
512 size
= r
->start
- addr
;
516 if (last
> r
->end
&& addr
< r
->end
) {
517 addr
= round_up(r
->end
, align
);
522 if (last
<= r
->end
&& addr
>= r
->start
) {
535 * Find a free area with specified alignment in a specific range.
536 * only with the area.between start to end is active range from early_node_map
537 * so they are good as RAM
539 u64 __init
find_early_area(u64 ei_start
, u64 ei_last
, u64 start
, u64 end
,
544 addr
= round_up(ei_start
, align
);
546 addr
= round_up(start
, align
);
549 while (bad_addr(&addr
, size
, align
) && addr
+size
<= ei_last
)
563 u64 __init
find_early_area_size(u64 ei_start
, u64 ei_last
, u64 start
,
564 u64
*sizep
, u64 align
)
568 addr
= round_up(ei_start
, align
);
570 addr
= round_up(start
, align
);
573 *sizep
= ei_last
- addr
;
574 while (bad_addr_size(&addr
, sizep
, align
) && addr
+ *sizep
<= ei_last
)
576 last
= addr
+ *sizep
;