/*
 * Two Levels Segregate Fit memory allocator (TLSF)
 * Version 1.3
 *
 * Written by Miguel Masmano Tello <mmasmano@disca.upv.es>
 * Copyright (C) Dec, 2002 OCERA Consortium
 * Release under the terms of the GNU General Public License Version 2
 *
 */

#include "TLSF_nondep.h"
#include "TLSF_struct_functions.h"

/* 
 * This  functions  allow  to  insert   a  new  memory  block  into  a
 * preexistent TLSF structure
 */

int add_new_block (char *new_block, int size, char *block_ptr) {
  block_header_t *new_block_ptr;
  __s32 fl, sl, new_size;
  __u32 *ptr_following;
  TLSF_t *ptr_TLSF;
  
  ptr_TLSF = (TLSF_t *) block_ptr;

  if (size < TLSF_WORDS2BYTES(beg_header_overhead)) {
    PRINT_MSG ("add_new_block() error: New block is too much small\n");
    PRINT_MSG ("Hint: New added blocks size must be > %d\n", 
	       TLSF_WORDS2BYTES(beg_header_overhead));
    return -1;
  }
  
  new_block_ptr = (block_header_t *) ((__u32 *) new_block + sizeof (__u32 *));

  new_block_ptr -> prev_phys_block = NULL;

  ptr_following =  ptr_TLSF -> following_non_cont_bh;
  
  while (*ptr_following)
    ptr_following = (__u32 *) *ptr_following;
  
  // Now the new block is linked
  *ptr_following = (__u32) new_block;
  ptr_following = (__u32 *)*ptr_following;
  *ptr_following = 0;
  
  new_block_ptr -> size = 
    BYTES2TLSF_WORDS(size - sizeof (__u32 *)) - beg_header_overhead;

  SET_LAST_BLOCK (new_block_ptr);

  if (TLSF_WORDS2BYTES(GET_BLOCK_SIZE(new_block_ptr)) 
      <= MIN_SIZE) {
    return -1;
  } else {
    if (GET_BLOCK_SIZE(new_block_ptr) < ptr_TLSF ->  TLSF_max_struct_size)
      mapping_function (GET_BLOCK_SIZE(new_block_ptr), &fl, &sl, &new_size,
			ptr_TLSF);
    else {
      fl =  ptr_TLSF -> max_fl_index - 1;
      sl = ptr_TLSF -> max_sl_index - 1;
    }
    fl -= MIN_LOG2_SIZE;
  }

  init_and_insert_block (ptr_TLSF, new_block_ptr, fl, sl); 

  return TLSF_WORDS2BYTES(GET_BLOCK_SIZE(new_block_ptr));
}
