diff options
Diffstat (limited to 'arch/powerpc/lib/rheap.c')
| -rw-r--r-- | arch/powerpc/lib/rheap.c | 117 |
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 */ |
| 324 | int rh_attach_region(rh_info_t * info, void *start, int size) | 324 | int 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. */ |
| 361 | void *rh_detach_region(rh_info_t * info, void *start, int size) | 364 | unsigned 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 | ||
| 428 | void *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 | */ | ||
| 435 | unsigned 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 | ||
| 495 | void *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 | */ | ||
| 505 | unsigned 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 |
| 501 | void *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 | */ | ||
| 514 | unsigned 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 | ||
| 580 | int 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 | */ | ||
| 597 | int 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 | ||
| 645 | int rh_set_owner(rh_info_t * info, void *start, const char *owner) | 662 | int 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) | |||
| 704 | void rh_dump_blk(rh_info_t * info, rh_block_t * blk) | 721 | void 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 | } |
