aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/lib
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/lib')
-rw-r--r--arch/powerpc/lib/rheap.c117
1 files changed, 67 insertions, 50 deletions
diff --git a/arch/powerpc/lib/rheap.c b/arch/powerpc/lib/rheap.c
index 6c5c5dd183ee..b2f6dcc59600 100644
--- a/arch/powerpc/lib/rheap.c
+++ b/arch/powerpc/lib/rheap.c
@@ -133,7 +133,7 @@ static rh_block_t *get_slot(rh_info_t * info)
133 info->empty_slots--; 133 info->empty_slots--;
134 134
135 /* Initialize */ 135 /* Initialize */
136 blk->start = NULL; 136 blk->start = 0;
137 blk->size = 0; 137 blk->size = 0;
138 blk->owner = NULL; 138 blk->owner = NULL;
139 139
@@ -158,7 +158,7 @@ static void attach_free_block(rh_info_t * info, rh_block_t * blkn)
158 158
159 /* We assume that they are aligned properly */ 159 /* We assume that they are aligned properly */
160 size = blkn->size; 160 size = blkn->size;
161 s = (unsigned long)blkn->start; 161 s = blkn->start;
162 e = s + size; 162 e = s + size;
163 163
164 /* Find the blocks immediately before and after the given one 164 /* Find the blocks immediately before and after the given one
@@ -170,7 +170,7 @@ static void attach_free_block(rh_info_t * info, rh_block_t * blkn)
170 list_for_each(l, &info->free_list) { 170 list_for_each(l, &info->free_list) {
171 blk = list_entry(l, rh_block_t, list); 171 blk = list_entry(l, rh_block_t, list);
172 172
173 bs = (unsigned long)blk->start; 173 bs = blk->start;
174 be = bs + blk->size; 174 be = bs + blk->size;
175 175
176 if (next == NULL && s >= bs) 176 if (next == NULL && s >= bs)
@@ -188,10 +188,10 @@ static void attach_free_block(rh_info_t * info, rh_block_t * blkn)
188 } 188 }
189 189
190 /* Now check if they are really adjacent */ 190 /* Now check if they are really adjacent */
191 if (before != NULL && s != (unsigned long)before->start + before->size) 191 if (before && s != (before->start + before->size))
192 before = NULL; 192 before = NULL;
193 193
194 if (after != NULL && e != (unsigned long)after->start) 194 if (after && e != after->start)
195 after = NULL; 195 after = NULL;
196 196
197 /* No coalescing; list insert and return */ 197 /* No coalescing; list insert and return */
@@ -216,7 +216,7 @@ static void attach_free_block(rh_info_t * info, rh_block_t * blkn)
216 216
217 /* Grow the after block backwards */ 217 /* Grow the after block backwards */
218 if (before == NULL && after != NULL) { 218 if (before == NULL && after != NULL) {
219 after->start = (int8_t *)after->start - size; 219 after->start -= size;
220 after->size += size; 220 after->size += size;
221 return; 221 return;
222 } 222 }
@@ -321,14 +321,14 @@ void rh_init(rh_info_t * info, unsigned int alignment, int max_blocks,
321} 321}
322 322
323/* Attach a free memory region, coalesces regions if adjuscent */ 323/* Attach a free memory region, coalesces regions if adjuscent */
324int rh_attach_region(rh_info_t * info, void *start, int size) 324int rh_attach_region(rh_info_t * info, unsigned long start, int size)
325{ 325{
326 rh_block_t *blk; 326 rh_block_t *blk;
327 unsigned long s, e, m; 327 unsigned long s, e, m;
328 int r; 328 int r;
329 329
330 /* The region must be aligned */ 330 /* The region must be aligned */
331 s = (unsigned long)start; 331 s = start;
332 e = s + size; 332 e = s + size;
333 m = info->alignment - 1; 333 m = info->alignment - 1;
334 334
@@ -338,9 +338,12 @@ int rh_attach_region(rh_info_t * info, void *start, int size)
338 /* Round end down */ 338 /* Round end down */
339 e = e & ~m; 339 e = e & ~m;
340 340
341 if (IS_ERR_VALUE(e) || (e < s))
342 return -ERANGE;
343
341 /* Take final values */ 344 /* Take final values */
342 start = (void *)s; 345 start = s;
343 size = (int)(e - s); 346 size = e - s;
344 347
345 /* Grow the blocks, if needed */ 348 /* Grow the blocks, if needed */
346 r = assure_empty(info, 1); 349 r = assure_empty(info, 1);
@@ -358,7 +361,7 @@ int rh_attach_region(rh_info_t * info, void *start, int size)
358} 361}
359 362
360/* Detatch given address range, splits free block if needed. */ 363/* Detatch given address range, splits free block if needed. */
361void *rh_detach_region(rh_info_t * info, void *start, int size) 364unsigned long rh_detach_region(rh_info_t * info, unsigned long start, int size)
362{ 365{
363 struct list_head *l; 366 struct list_head *l;
364 rh_block_t *blk, *newblk; 367 rh_block_t *blk, *newblk;
@@ -366,10 +369,10 @@ void *rh_detach_region(rh_info_t * info, void *start, int size)
366 369
367 /* Validate size */ 370 /* Validate size */
368 if (size <= 0) 371 if (size <= 0)
369 return ERR_PTR(-EINVAL); 372 return (unsigned long) -EINVAL;
370 373
371 /* The region must be aligned */ 374 /* The region must be aligned */
372 s = (unsigned long)start; 375 s = start;
373 e = s + size; 376 e = s + size;
374 m = info->alignment - 1; 377 m = info->alignment - 1;
375 378
@@ -380,34 +383,34 @@ void *rh_detach_region(rh_info_t * info, void *start, int size)
380 e = e & ~m; 383 e = e & ~m;
381 384
382 if (assure_empty(info, 1) < 0) 385 if (assure_empty(info, 1) < 0)
383 return ERR_PTR(-ENOMEM); 386 return (unsigned long) -ENOMEM;
384 387
385 blk = NULL; 388 blk = NULL;
386 list_for_each(l, &info->free_list) { 389 list_for_each(l, &info->free_list) {
387 blk = list_entry(l, rh_block_t, list); 390 blk = list_entry(l, rh_block_t, list);
388 /* The range must lie entirely inside one free block */ 391 /* The range must lie entirely inside one free block */
389 bs = (unsigned long)blk->start; 392 bs = blk->start;
390 be = (unsigned long)blk->start + blk->size; 393 be = blk->start + blk->size;
391 if (s >= bs && e <= be) 394 if (s >= bs && e <= be)
392 break; 395 break;
393 blk = NULL; 396 blk = NULL;
394 } 397 }
395 398
396 if (blk == NULL) 399 if (blk == NULL)
397 return ERR_PTR(-ENOMEM); 400 return (unsigned long) -ENOMEM;
398 401
399 /* Perfect fit */ 402 /* Perfect fit */
400 if (bs == s && be == e) { 403 if (bs == s && be == e) {
401 /* Delete from free list, release slot */ 404 /* Delete from free list, release slot */
402 list_del(&blk->list); 405 list_del(&blk->list);
403 release_slot(info, blk); 406 release_slot(info, blk);
404 return (void *)s; 407 return s;
405 } 408 }
406 409
407 /* blk still in free list, with updated start and/or size */ 410 /* blk still in free list, with updated start and/or size */
408 if (bs == s || be == e) { 411 if (bs == s || be == e) {
409 if (bs == s) 412 if (bs == s)
410 blk->start = (int8_t *)blk->start + size; 413 blk->start += size;
411 blk->size -= size; 414 blk->size -= size;
412 415
413 } else { 416 } else {
@@ -416,25 +419,29 @@ void *rh_detach_region(rh_info_t * info, void *start, int size)
416 419
417 /* the back free fragment */ 420 /* the back free fragment */
418 newblk = get_slot(info); 421 newblk = get_slot(info);
419 newblk->start = (void *)e; 422 newblk->start = e;
420 newblk->size = be - e; 423 newblk->size = be - e;
421 424
422 list_add(&newblk->list, &blk->list); 425 list_add(&newblk->list, &blk->list);
423 } 426 }
424 427
425 return (void *)s; 428 return s;
426} 429}
427 430
428void *rh_alloc_align(rh_info_t * info, int size, int alignment, const char *owner) 431/* Allocate a block of memory at the specified alignment. The value returned
432 * is an offset into the buffer initialized by rh_init(), or a negative number
433 * if there is an error.
434 */
435unsigned long rh_alloc_align(rh_info_t * info, int size, int alignment, const char *owner)
429{ 436{
430 struct list_head *l; 437 struct list_head *l;
431 rh_block_t *blk; 438 rh_block_t *blk;
432 rh_block_t *newblk; 439 rh_block_t *newblk;
433 void *start; 440 unsigned long start;
434 441
435 /* Validate size, (must be power of two) */ 442 /* Validate size, and alignment must be power of two */
436 if (size <= 0 || (alignment & (alignment - 1)) != 0) 443 if (size <= 0 || (alignment & (alignment - 1)) != 0)
437 return ERR_PTR(-EINVAL); 444 return (unsigned long) -EINVAL;
438 445
439 /* given alignment larger that default rheap alignment */ 446 /* given alignment larger that default rheap alignment */
440 if (alignment > info->alignment) 447 if (alignment > info->alignment)
@@ -444,7 +451,7 @@ void *rh_alloc_align(rh_info_t * info, int size, int alignment, const char *owne
444 size = (size + (info->alignment - 1)) & ~(info->alignment - 1); 451 size = (size + (info->alignment - 1)) & ~(info->alignment - 1);
445 452
446 if (assure_empty(info, 1) < 0) 453 if (assure_empty(info, 1) < 0)
447 return ERR_PTR(-ENOMEM); 454 return (unsigned long) -ENOMEM;
448 455
449 blk = NULL; 456 blk = NULL;
450 list_for_each(l, &info->free_list) { 457 list_for_each(l, &info->free_list) {
@@ -455,7 +462,7 @@ void *rh_alloc_align(rh_info_t * info, int size, int alignment, const char *owne
455 } 462 }
456 463
457 if (blk == NULL) 464 if (blk == NULL)
458 return ERR_PTR(-ENOMEM); 465 return (unsigned long) -ENOMEM;
459 466
460 /* Just fits */ 467 /* Just fits */
461 if (blk->size == size) { 468 if (blk->size == size) {
@@ -475,7 +482,7 @@ void *rh_alloc_align(rh_info_t * info, int size, int alignment, const char *owne
475 newblk->owner = owner; 482 newblk->owner = owner;
476 483
477 /* blk still in free list, with updated start, size */ 484 /* blk still in free list, with updated start, size */
478 blk->start = (int8_t *)blk->start + size; 485 blk->start += size;
479 blk->size -= size; 486 blk->size -= size;
480 487
481 start = newblk->start; 488 start = newblk->start;
@@ -486,19 +493,25 @@ void *rh_alloc_align(rh_info_t * info, int size, int alignment, const char *owne
486 /* this is no problem with the deallocator since */ 493 /* this is no problem with the deallocator since */
487 /* we scan for pointers that lie in the blocks */ 494 /* we scan for pointers that lie in the blocks */
488 if (alignment > info->alignment) 495 if (alignment > info->alignment)
489 start = (void *)(((unsigned long)start + alignment - 1) & 496 start = (start + alignment - 1) & ~(alignment - 1);
490 ~(alignment - 1));
491 497
492 return start; 498 return start;
493} 499}
494 500
495void *rh_alloc(rh_info_t * info, int size, const char *owner) 501/* Allocate a block of memory at the default alignment. The value returned is
502 * an offset into the buffer initialized by rh_init(), or a negative number if
503 * there is an error.
504 */
505unsigned long rh_alloc(rh_info_t * info, int size, const char *owner)
496{ 506{
497 return rh_alloc_align(info, size, info->alignment, owner); 507 return rh_alloc_align(info, size, info->alignment, owner);
498} 508}
499 509
500/* allocate at precisely the given address */ 510/* Allocate a block of memory at the given offset, rounded up to the default
501void *rh_alloc_fixed(rh_info_t * info, void *start, int size, const char *owner) 511 * alignment. The value returned is an offset into the buffer initialized by
512 * rh_init(), or a negative number if there is an error.
513 */
514unsigned long rh_alloc_fixed(rh_info_t * info, unsigned long start, int size, const char *owner)
502{ 515{
503 struct list_head *l; 516 struct list_head *l;
504 rh_block_t *blk, *newblk1, *newblk2; 517 rh_block_t *blk, *newblk1, *newblk2;
@@ -506,10 +519,10 @@ void *rh_alloc_fixed(rh_info_t * info, void *start, int size, const char *owner)
506 519
507 /* Validate size */ 520 /* Validate size */
508 if (size <= 0) 521 if (size <= 0)
509 return ERR_PTR(-EINVAL); 522 return (unsigned long) -EINVAL;
510 523
511 /* The region must be aligned */ 524 /* The region must be aligned */
512 s = (unsigned long)start; 525 s = start;
513 e = s + size; 526 e = s + size;
514 m = info->alignment - 1; 527 m = info->alignment - 1;
515 528
@@ -520,20 +533,20 @@ void *rh_alloc_fixed(rh_info_t * info, void *start, int size, const char *owner)
520 e = e & ~m; 533 e = e & ~m;
521 534
522 if (assure_empty(info, 2) < 0) 535 if (assure_empty(info, 2) < 0)
523 return ERR_PTR(-ENOMEM); 536 return (unsigned long) -ENOMEM;
524 537
525 blk = NULL; 538 blk = NULL;
526 list_for_each(l, &info->free_list) { 539 list_for_each(l, &info->free_list) {
527 blk = list_entry(l, rh_block_t, list); 540 blk = list_entry(l, rh_block_t, list);
528 /* The range must lie entirely inside one free block */ 541 /* The range must lie entirely inside one free block */
529 bs = (unsigned long)blk->start; 542 bs = blk->start;
530 be = (unsigned long)blk->start + blk->size; 543 be = blk->start + blk->size;
531 if (s >= bs && e <= be) 544 if (s >= bs && e <= be)
532 break; 545 break;
533 } 546 }
534 547
535 if (blk == NULL) 548 if (blk == NULL)
536 return ERR_PTR(-ENOMEM); 549 return (unsigned long) -ENOMEM;
537 550
538 /* Perfect fit */ 551 /* Perfect fit */
539 if (bs == s && be == e) { 552 if (bs == s && be == e) {
@@ -551,7 +564,7 @@ void *rh_alloc_fixed(rh_info_t * info, void *start, int size, const char *owner)
551 /* blk still in free list, with updated start and/or size */ 564 /* blk still in free list, with updated start and/or size */
552 if (bs == s || be == e) { 565 if (bs == s || be == e) {
553 if (bs == s) 566 if (bs == s)
554 blk->start = (int8_t *)blk->start + size; 567 blk->start += size;
555 blk->size -= size; 568 blk->size -= size;
556 569
557 } else { 570 } else {
@@ -560,14 +573,14 @@ void *rh_alloc_fixed(rh_info_t * info, void *start, int size, const char *owner)
560 573
561 /* The back free fragment */ 574 /* The back free fragment */
562 newblk2 = get_slot(info); 575 newblk2 = get_slot(info);
563 newblk2->start = (void *)e; 576 newblk2->start = e;
564 newblk2->size = be - e; 577 newblk2->size = be - e;
565 578
566 list_add(&newblk2->list, &blk->list); 579 list_add(&newblk2->list, &blk->list);
567 } 580 }
568 581
569 newblk1 = get_slot(info); 582 newblk1 = get_slot(info);
570 newblk1->start = (void *)s; 583 newblk1->start = s;
571 newblk1->size = e - s; 584 newblk1->size = e - s;
572 newblk1->owner = owner; 585 newblk1->owner = owner;
573 586
@@ -577,7 +590,11 @@ void *rh_alloc_fixed(rh_info_t * info, void *start, int size, const char *owner)
577 return start; 590 return start;
578} 591}
579 592
580int rh_free(rh_info_t * info, void *start) 593/* Deallocate the memory previously allocated by one of the rh_alloc functions.
594 * The return value is the size of the deallocated block, or a negative number
595 * if there is an error.
596 */
597int rh_free(rh_info_t * info, unsigned long start)
581{ 598{
582 rh_block_t *blk, *blk2; 599 rh_block_t *blk, *blk2;
583 struct list_head *l; 600 struct list_head *l;
@@ -642,7 +659,7 @@ int rh_get_stats(rh_info_t * info, int what, int max_stats, rh_stats_t * stats)
642 return nr; 659 return nr;
643} 660}
644 661
645int rh_set_owner(rh_info_t * info, void *start, const char *owner) 662int rh_set_owner(rh_info_t * info, unsigned long start, const char *owner)
646{ 663{
647 rh_block_t *blk, *blk2; 664 rh_block_t *blk, *blk2;
648 struct list_head *l; 665 struct list_head *l;
@@ -684,8 +701,8 @@ void rh_dump(rh_info_t * info)
684 nr = maxnr; 701 nr = maxnr;
685 for (i = 0; i < nr; i++) 702 for (i = 0; i < nr; i++)
686 printk(KERN_INFO 703 printk(KERN_INFO
687 " 0x%p-0x%p (%u)\n", 704 " 0x%lx-0x%lx (%u)\n",
688 st[i].start, (int8_t *) st[i].start + st[i].size, 705 st[i].start, st[i].start + st[i].size,
689 st[i].size); 706 st[i].size);
690 printk(KERN_INFO "\n"); 707 printk(KERN_INFO "\n");
691 708
@@ -695,8 +712,8 @@ void rh_dump(rh_info_t * info)
695 nr = maxnr; 712 nr = maxnr;
696 for (i = 0; i < nr; i++) 713 for (i = 0; i < nr; i++)
697 printk(KERN_INFO 714 printk(KERN_INFO
698 " 0x%p-0x%p (%u) %s\n", 715 " 0x%lx-0x%lx (%u) %s\n",
699 st[i].start, (int8_t *) st[i].start + st[i].size, 716 st[i].start, st[i].start + st[i].size,
700 st[i].size, st[i].owner != NULL ? st[i].owner : ""); 717 st[i].size, st[i].owner != NULL ? st[i].owner : "");
701 printk(KERN_INFO "\n"); 718 printk(KERN_INFO "\n");
702} 719}
@@ -704,6 +721,6 @@ void rh_dump(rh_info_t * info)
704void rh_dump_blk(rh_info_t * info, rh_block_t * blk) 721void rh_dump_blk(rh_info_t * info, rh_block_t * blk)
705{ 722{
706 printk(KERN_INFO 723 printk(KERN_INFO
707 "blk @0x%p: 0x%p-0x%p (%u)\n", 724 "blk @0x%p: 0x%lx-0x%lx (%u)\n",
708 blk, blk->start, (int8_t *) blk->start + blk->size, blk->size); 725 blk, blk->start, blk->start + blk->size, blk->size);
709} 726}