#include <stdlib.h>
#include <stdio.h>
#include "osp_type_def.h"
#include "osp_mem.h"
#include "err_num.h"
#include "ucp_printf.h"
#include "ucp_tick.h"
#include "smartos.h"
#include "osp_io.h"
#include "spu_shell.h"

#define ALIGN(x,align)  (((unsigned int)(x) + (align - 1)) & ~(align - 1))

#define OSP_MEM_IM_FLAG     (0x121212ef)

typedef struct osp_double_link_node_struct
{
    int len;
    int IsBusy;
    uint32_t u32flag;
    struct osp_double_link_node_struct *prev;
    struct osp_double_link_node_struct *next;
}osp_mem_node;

#define OSP_NODE_SIZE               sizeof(osp_mem_node)
#define OSP_MEM_BUF_TO_HEAD(pbuf)   (osp_mem_node *)((UINTPTR)pbuf - OSP_NODE_SIZE)

typedef struct osp_mem_cb
{
    osp_mem_node *root;
    osp_mem_node *cur_avaliable;
}osp_mem_cb;

#define OSP_MEM_CB_SIZE sizeof(osp_mem_cb)

//static osp_mem_node *g_osp_mem_im_head = NULLPTR;
osp_mem_cb g_st_osp_mem_im_head;

extern int osp_show_im_mem_by_coreid(uint8_t core_id);

/* 
函数功能：查找内存节点
从内存节点查看剩余空间是否还够分配
*/
osp_mem_node* osp_search_node(osp_mem_node* head, uint32_t size)
{
    osp_mem_node* node;
    node = head;

    while(node)
    {
        if((node->len > (size + OSP_NODE_SIZE))&&(!node->IsBusy))
        {
            return node;
        }
        node = node->next;
    }
    return NULL;
}

/* 划分内存节点 */
/* 若当前内存空间只够本次分配，则直接返回该内存节点 */
/* 若当前内存空间充足（大于本次空间和节点头空间），则划分内存节点 */
osp_mem_node* osp_split_node(osp_mem_node* node, uint32_t size)
{
    osp_mem_node* new_node;
    osp_mem_node* next;
    uint32_t len;

    if(node->len-size < OSP_NODE_SIZE)
    {
        return node;
    }

    len = node->len;

    node->len = size;
    new_node = (osp_mem_node*)((UINTPTR)node + OSP_NODE_SIZE + node->len);

    new_node->len = len - size - OSP_NODE_SIZE;
    new_node->IsBusy = 0;
    //UCP_PRINT_LOG("new is 0x%08x, new->len is 0x%08x,len is 0x%08x, size is 0x%08x, OSP_NODE_SIZE is 0x%08 \r\n",new, new->len,len, size, OSP_NODE_SIZE);
    new_node->next = node->next;
    next = new_node->next;
    if(next)
    {
        next->prev = new_node;
    }
    new_node->prev = node;
    node->next = new_node;
    //UCP_PRINT_LOG("new is 0x%x, new->len is 0x%08x\r\n", new, new->len);
    return new_node;
}

/* 设置内存节点状态为忙 */
int osp_set_node_busy(osp_mem_node* node)
{
    node->IsBusy = 1;
    return 0;
}

int osp_clear_node_busy(osp_mem_node* node)
{
    node->IsBusy = 0;
    return 0;
}

osp_mem_node* osp_get_next_node(osp_mem_node* node)
{
    return node->next;
}

osp_mem_node* osp_get_pre_node(osp_mem_node* node)
{
    return node->prev;
}

int osp_node_need_merge(osp_mem_node *node, osp_mem_node *nextnode)
{
    if((0 == node->IsBusy)&&(0 == nextnode->IsBusy))
    {
        return 1;
    }
    return 0;
}

int osp_node_merge(osp_mem_node *node, osp_mem_node *nextnode)
{
    osp_mem_node * nextnext;

    nextnext = nextnode->next;

    node->next = nextnext;
    if(nextnext)
    {
        nextnext->prev = node;
    }

    node->len +=nextnode->len + OSP_NODE_SIZE;

    if (nextnode == g_st_osp_mem_im_head.cur_avaliable)
    {
        g_st_osp_mem_im_head.cur_avaliable = node;
    }
    return 0;
}

/* 内存模块初始化函数 */
int osp_mem_init(void)
{
    /* 现在的要求是平台的内存管理都是管理IM的内存 */
    memset(&g_st_osp_mem_im_head, 0, sizeof(g_st_osp_mem_im_head));

    //g_osp_mem_im_head = (osp_mem_node *)((void*)OSP_MEM_POOL_START);
    g_st_osp_mem_im_head.root = (osp_mem_node*)malloc(OSP_MEM_POOL_SIZE);
    if (NULL == g_st_osp_mem_im_head.root)
    {
        UCP_PRINT_LOG("osp_mem_init malloc error.\r\n");
#ifdef OSP_DEBUG_TEST
        debug_write(OSP_DEBUG_POT(g_ape_id, 8), 0xFFFFEEEE);
#endif
        return -OSP_ERROR;
    }
    g_st_osp_mem_im_head.root->len     = (OSP_MEM_POOL_SIZE - OSP_MEM_CB_SIZE - OSP_NODE_SIZE);
    g_st_osp_mem_im_head.root->IsBusy  = 0;
    g_st_osp_mem_im_head.root->u32flag = OSP_MEM_IM_FLAG;
    g_st_osp_mem_im_head.root->next = NULL;
    g_st_osp_mem_im_head.root->prev = NULL;
    g_st_osp_mem_im_head.cur_avaliable = g_st_osp_mem_im_head.root;

#ifdef OSP_DEBUG_TEST
    debug_write(OSP_DEBUG_POT(g_ape_id, 9), g_st_osp_mem_im_head.root->len);
    debug_write(OSP_DEBUG_POT(g_ape_id, 10), g_st_osp_mem_im_head.root);
#endif

    spu_insert_cmd_ext("im_ape", (OSP_FUNCPTR)osp_show_im_mem_by_coreid, "osp im info by id", 1);

    UCP_PRINT_LOG("g_osp_mem_im_head OK\r\n");
    return 0;
}

/* 内部接口：申请IM内存空间 */
char *osp_malloc_im_mem(uint32_t size)
{
    osp_mem_node *node;
    uint32_t len = ALIGN(size, 4);

    node = osp_search_node(g_st_osp_mem_im_head.cur_avaliable, len);
    if(!node)
    {
        node = osp_search_node(g_st_osp_mem_im_head.root, len);
        if (!node)
        {
            return NULL;
        }
    }
    //osp_set_node_busy(node);
    node->IsBusy  = 1;
    node->u32flag = OSP_MEM_IM_FLAG;

    //new = osp_split_node(node, len);
    g_st_osp_mem_im_head.cur_avaliable = osp_split_node(node, len);

    //memset((void*)((UINTPTR)node + OSP_NODE_SIZE), 0, len);
    //UCP_PRINT_LOG("(UINTPTR)node + OSP_NODE_SIZE is 0x%08x, len is 0x%08x\r\n",(UINTPTR)node + OSP_NODE_SIZE , len );

    return (char*)((UINTPTR)node + OSP_NODE_SIZE);
}

int osp_free_im_mem(char* pbuf)
{
    osp_mem_node *node = OSP_MEM_BUF_TO_HEAD(pbuf);
    osp_mem_node *nextnode;
    osp_mem_node *prenode;

    if (1 != node->IsBusy)
    {
        UCP_PRINT_ERROR("free im addr[0x%x] error!(IsBusy:%d)", pbuf, node->IsBusy);
        return 0;
    }
    if (OSP_MEM_IM_FLAG != node->u32flag)
    {
        UCP_PRINT_ERROR("free im addr[0x%x] error!(u32flag:0x%x)", pbuf, node->u32flag);
        return 0;
    }

    //osp_clear_node_busy(node);
    node->IsBusy = 0;
    //nextnode = osp_get_next_node(node);
    nextnode = node->next;
    //prenode = osp_get_pre_node(node);
    prenode = node->prev;

    if(nextnode){
        if(osp_node_need_merge(node, nextnode)){
            osp_node_merge(node, nextnode);
        }
    }

    if(prenode){
        if(osp_node_need_merge(prenode, node)){
            osp_node_merge(prenode, node);
        }
    }

    return 0;
}

int osp_show_im_mem(void)
{
    int busynum = 0;
    int freenum = 0;
    int busymem = 0;
    int freemem = 0;
    //char *buf=osp_malloc(1024);

    osp_mem_node * node= g_st_osp_mem_im_head.root;

    //UCP_PRINT_LOG("im mem is 0x%08x\r\n", g_osp_mem_im_head);
    while(node){
        //UCP_PRINT_LOG("node: 0x%08x, node->len is 0x%08x, node->IsBusy is 0x%08x \r\n", node, node->len, node->IsBusy);
        if(node->IsBusy){
            busynum++;
            busymem+=node->len;
        }else{
            freenum++;
            freemem+=node->len;
        }
        node=node->next;
    }
    UCP_PRINT_LOG("busynum\tbusymem\tfreenum\tfreemem\t\r\n");
    UCP_PRINT_LOG("0x%08x\t0x%08x\t0x%08x\t0x%08x\t\r\n", busynum, busymem, freenum, freemem);

    return 0;
}

int osp_show_im_mem_by_coreid(uint8_t core_id)
{
    int busynum = 0;
    int freenum = 0;
    int busymem = 0;
    int freemem = 0;

    osp_mem_node * node= g_st_osp_mem_im_head.root;

    if (core_id != g_ape_id)
    {
        return 0;
    }

    while(node){
        UCP_PRINT_ERROR("node:0x%x,len=%d,IsBusy=%d,Flag=0x%x, next=0x%x", node, node->len, node->IsBusy, node->u32flag, node->next);
        if(node->IsBusy){
            busynum++;
            busymem+=node->len;
        }else{
            freenum++;
            freemem+=node->len;
        }
        node=node->next;
    }
    UCP_PRINT_ERROR("busynum\tbusymem\tfreenum\tfreemem\t\r\n");
    UCP_PRINT_ERROR("0x%08x\t0x%08x\t0x%08x\t0x%08x\t\r\n", busynum, busymem, freenum, freemem);

    return 0;
}


/* 对外接口：申请内存空间 */
char *osp_malloc(int size)
{
    char *p;
    OS_ENTER_CRITICAL();
    p = osp_malloc_im_mem(size);
    OS_EXIT_CRITICAL();

    return p;
}

void osp_free(char *p)
{
    OS_ENTER_CRITICAL();
    osp_free_im_mem(p);
    p = NULL;
    OS_EXIT_CRITICAL();

    return ;
}

/* 若提供 getFreeSpace()接口可有该函数 */
void osp_show_memory(void)
{
    osp_show_im_mem();

    return ;
}

#if 0
/********************************************************/
/*                      DDR                             */
uint32_t osp_get_ddr_mem(void)
{
    return OSP_PHY_DDR_ADDR;
}
#endif

