diff options
| author | Steve French <sfrench@us.ibm.com> | 2008-05-06 13:55:32 -0400 |
|---|---|---|
| committer | Steve French <sfrench@us.ibm.com> | 2008-05-06 13:55:32 -0400 |
| commit | a815752ac0ffdb910e92958d41d28f4fb28e5296 (patch) | |
| tree | a3aa16a282354da0debe8e3a3a7ed8aac6e54001 /lib/lmb.c | |
| parent | 5ade9deaaa3e1f7291467d97b238648e43eae15e (diff) | |
| parent | a15306365a16380f3bafee9e181ba01231d4acd7 (diff) | |
Merge branch 'master' of /pub/scm/linux/kernel/git/torvalds/linux-2.6
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 | } | ||
