diff options
Diffstat (limited to 'lib/lmb.c')
-rw-r--r-- | lib/lmb.c | 99 |
1 files changed, 90 insertions, 9 deletions
@@ -46,14 +46,13 @@ void lmb_dump_all(void) | |||
46 | #endif /* DEBUG */ | 46 | #endif /* DEBUG */ |
47 | } | 47 | } |
48 | 48 | ||
49 | static unsigned long __init lmb_addrs_overlap(u64 base1, u64 size1, | 49 | static unsigned long lmb_addrs_overlap(u64 base1, u64 size1, u64 base2, |
50 | u64 base2, u64 size2) | 50 | u64 size2) |
51 | { | 51 | { |
52 | return ((base1 < (base2 + size2)) && (base2 < (base1 + size1))); | 52 | return ((base1 < (base2 + size2)) && (base2 < (base1 + size1))); |
53 | } | 53 | } |
54 | 54 | ||
55 | static long __init lmb_addrs_adjacent(u64 base1, u64 size1, | 55 | static long lmb_addrs_adjacent(u64 base1, u64 size1, u64 base2, u64 size2) |
56 | u64 base2, u64 size2) | ||
57 | { | 56 | { |
58 | if (base2 == base1 + size1) | 57 | if (base2 == base1 + size1) |
59 | return 1; | 58 | return 1; |
@@ -63,7 +62,7 @@ static long __init lmb_addrs_adjacent(u64 base1, u64 size1, | |||
63 | return 0; | 62 | return 0; |
64 | } | 63 | } |
65 | 64 | ||
66 | static long __init lmb_regions_adjacent(struct lmb_region *rgn, | 65 | static long lmb_regions_adjacent(struct lmb_region *rgn, |
67 | unsigned long r1, unsigned long r2) | 66 | unsigned long r1, unsigned long r2) |
68 | { | 67 | { |
69 | u64 base1 = rgn->region[r1].base; | 68 | u64 base1 = rgn->region[r1].base; |
@@ -74,7 +73,7 @@ static long __init lmb_regions_adjacent(struct lmb_region *rgn, | |||
74 | return lmb_addrs_adjacent(base1, size1, base2, size2); | 73 | return lmb_addrs_adjacent(base1, size1, base2, size2); |
75 | } | 74 | } |
76 | 75 | ||
77 | static void __init lmb_remove_region(struct lmb_region *rgn, unsigned long r) | 76 | static void lmb_remove_region(struct lmb_region *rgn, unsigned long r) |
78 | { | 77 | { |
79 | unsigned long i; | 78 | unsigned long i; |
80 | 79 | ||
@@ -86,7 +85,7 @@ static void __init lmb_remove_region(struct lmb_region *rgn, unsigned long r) | |||
86 | } | 85 | } |
87 | 86 | ||
88 | /* Assumption: base addr of region 1 < base addr of region 2 */ | 87 | /* Assumption: base addr of region 1 < base addr of region 2 */ |
89 | static void __init lmb_coalesce_regions(struct lmb_region *rgn, | 88 | static void lmb_coalesce_regions(struct lmb_region *rgn, |
90 | unsigned long r1, unsigned long r2) | 89 | unsigned long r1, unsigned long r2) |
91 | { | 90 | { |
92 | rgn->region[r1].size += rgn->region[r2].size; | 91 | rgn->region[r1].size += rgn->region[r2].size; |
@@ -118,7 +117,7 @@ void __init lmb_analyze(void) | |||
118 | lmb.memory.size += lmb.memory.region[i].size; | 117 | lmb.memory.size += lmb.memory.region[i].size; |
119 | } | 118 | } |
120 | 119 | ||
121 | static long __init lmb_add_region(struct lmb_region *rgn, u64 base, u64 size) | 120 | static long lmb_add_region(struct lmb_region *rgn, u64 base, u64 size) |
122 | { | 121 | { |
123 | unsigned long coalesced = 0; | 122 | unsigned long coalesced = 0; |
124 | long adjacent, i; | 123 | long adjacent, i; |
@@ -182,7 +181,7 @@ static long __init lmb_add_region(struct lmb_region *rgn, u64 base, u64 size) | |||
182 | return 0; | 181 | return 0; |
183 | } | 182 | } |
184 | 183 | ||
185 | long __init lmb_add(u64 base, u64 size) | 184 | long lmb_add(u64 base, u64 size) |
186 | { | 185 | { |
187 | struct lmb_region *_rgn = &lmb.memory; | 186 | struct lmb_region *_rgn = &lmb.memory; |
188 | 187 | ||
@@ -194,6 +193,55 @@ long __init lmb_add(u64 base, u64 size) | |||
194 | 193 | ||
195 | } | 194 | } |
196 | 195 | ||
196 | long lmb_remove(u64 base, u64 size) | ||
197 | { | ||
198 | struct lmb_region *rgn = &(lmb.memory); | ||
199 | u64 rgnbegin, rgnend; | ||
200 | u64 end = base + size; | ||
201 | int i; | ||
202 | |||
203 | rgnbegin = rgnend = 0; /* supress gcc warnings */ | ||
204 | |||
205 | /* Find the region where (base, size) belongs to */ | ||
206 | for (i=0; i < rgn->cnt; i++) { | ||
207 | rgnbegin = rgn->region[i].base; | ||
208 | rgnend = rgnbegin + rgn->region[i].size; | ||
209 | |||
210 | if ((rgnbegin <= base) && (end <= rgnend)) | ||
211 | break; | ||
212 | } | ||
213 | |||
214 | /* Didn't find the region */ | ||
215 | if (i == rgn->cnt) | ||
216 | return -1; | ||
217 | |||
218 | /* Check to see if we are removing entire region */ | ||
219 | if ((rgnbegin == base) && (rgnend == end)) { | ||
220 | lmb_remove_region(rgn, i); | ||
221 | return 0; | ||
222 | } | ||
223 | |||
224 | /* Check to see if region is matching at the front */ | ||
225 | if (rgnbegin == base) { | ||
226 | rgn->region[i].base = end; | ||
227 | rgn->region[i].size -= size; | ||
228 | return 0; | ||
229 | } | ||
230 | |||
231 | /* Check to see if the region is matching at the end */ | ||
232 | if (rgnend == end) { | ||
233 | rgn->region[i].size -= size; | ||
234 | return 0; | ||
235 | } | ||
236 | |||
237 | /* | ||
238 | * We need to split the entry - adjust the current one to the | ||
239 | * beginging of the hole and add the region after hole. | ||
240 | */ | ||
241 | rgn->region[i].size = base - rgn->region[i].base; | ||
242 | return lmb_add_region(rgn, end, rgnend - end); | ||
243 | } | ||
244 | |||
197 | long __init lmb_reserve(u64 base, u64 size) | 245 | long __init lmb_reserve(u64 base, u64 size) |
198 | { | 246 | { |
199 | struct lmb_region *_rgn = &lmb.reserved; | 247 | struct lmb_region *_rgn = &lmb.reserved; |
@@ -426,3 +474,36 @@ int __init lmb_is_reserved(u64 addr) | |||
426 | } | 474 | } |
427 | return 0; | 475 | return 0; |
428 | } | 476 | } |
477 | |||
478 | /* | ||
479 | * Given a <base, len>, find which memory regions belong to this range. | ||
480 | * Adjust the request and return a contiguous chunk. | ||
481 | */ | ||
482 | int lmb_find(struct lmb_property *res) | ||
483 | { | ||
484 | int i; | ||
485 | u64 rstart, rend; | ||
486 | |||
487 | rstart = res->base; | ||
488 | rend = rstart + res->size - 1; | ||
489 | |||
490 | for (i = 0; i < lmb.memory.cnt; i++) { | ||
491 | u64 start = lmb.memory.region[i].base; | ||
492 | u64 end = start + lmb.memory.region[i].size - 1; | ||
493 | |||
494 | if (start > rend) | ||
495 | return -1; | ||
496 | |||
497 | if ((end >= rstart) && (start < rend)) { | ||
498 | /* adjust the request */ | ||
499 | if (rstart < start) | ||
500 | rstart = start; | ||
501 | if (rend > end) | ||
502 | rend = end; | ||
503 | res->base = rstart; | ||
504 | res->size = rend - rstart + 1; | ||
505 | return 0; | ||
506 | } | ||
507 | } | ||
508 | return -1; | ||
509 | } | ||