static int __init reset_sub_mgr_init_hifi(void)
{
    struct task_struct    *pHifiTask = NULL;
    int     iret = BSP_RESET_OK;

    /*默认HIFI使能*/
    reset_set_cpu_status(0, RESET_CPU_HIFI_STATUS_OFF);



    /*创建需要的信号量*/
    printk(KERN_INFO "%s: enter\n", __FUNCTION__);
    hisi_io_memset(&g_reset_assistant_hifi, 0, sizeof(g_reset_assistant_hifi));
    sema_init(&(g_reset_assistant_hifi.sem_wait_hifireset), SEM_EMPTY);
    sema_init(&(g_reset_assistant_hifi.sem_wait_mcu_msg_hifireset), SEM_EMPTY);

    /*创建hifi复位处理线程*/
    pHifiTask = kthread_run(hifireset_task,  NULL, "hifireset_task");
    printk(KERN_INFO "%s: create hifireset_task, return %p\n", __FUNCTION__, pHifiTask);

    ccorereset_enable_wdt_irq();


    /*注册HIFI复位回调函数*//*hifi复位,底软不注册*/
    hifireset_regcbfunc("CODEC", drv_hifireset_cbfun, 0, BSP_DRV_CBFUN_PRIOLEVEL);

    iret = ipc_msg_req_callback(OBJ_HIFI, CMD_NOTIFY, mailbox_recfun_mcu_hifireset);
    printk(KERN_INFO"RESET LOG: LEAVE reset_sub_mgr_init0! iret = %d\n", iret);

    return BSP_RESET_OK;
}
void queue_init(struct queue *q, char *name, unsigned int len)
{
    hisi_io_memset(q->name, 0, QUEUE_NAME_LEN);
    if (name){
        strncpy(q->name, name, QUEUE_NAME_LEN);
        q->name[QUEUE_NAME_LEN - 1] = 0;
    }

    spin_lock_init(&q->lock);

    q->max  = len;
    q->head = 0;
    q->tail = 0;
    q->in = 0;
    q->out = 0;

    hisi_io_memset(q->data, 0, len);

    return;
}
void queue_destory(struct queue *q)
{
    hisi_io_memset(q->data, 0, q->max);

    q->max = 0;
    q->head = 0;
    q->tail = 0;
    q->in = 0;
    q->out = 0;

    return;
}
/*****************************************************************************
 函 数 名  : drv_hifi_read_image
 功能描述  : 读取Hifi镜像
 输入参数  : void
 输出参数  : img_head hifi镜像头信息
             img_buf  hifi镜像信息
 返 回 值  : int
             成功返回 0,失败返回 -1
 调用函数  :
 被调函数  :

 修改历史      :
  1.日    期   : 2012年8月29日
    作    者   : 刘慈红 lKF71598
    修改内容   : 新生成函数

*****************************************************************************/
int drv_hifi_read_image(void *img_head, void **img_buf)
{
    struct drv_hifi_image_head *head = NULL;
    int ret = 0;
    char **buff = NULL;

    unsigned int size = sizeof(struct drv_hifi_image_head);

    head = (struct drv_hifi_image_head *)img_head;

    buff = (char **)img_buf;

    /* read hifi image head from EMMC */
    ret = drv_read_bin((const char*)HIFI_IMAGE_NAME, 0, size, (char *)head);
    printk(KERN_INFO"RESET LOADHIFI: after drv_read_bin ret = %d.\n", ret);

    /* the size of hifi image */
    size = head->image_size;

	printk(KERN_INFO "%s: drv_read_bin size is %x \n",__FUNCTION__,size);

    *buff = vmalloc(size);
    if (NULL == *buff)
    {
        printk(KERN_INFO"drv_hifi_read_image: Fail to malloc %d bytes in load hifi bin function\n", size);
        return BSP_RESET_ERROR;
    }

    printk(KERN_INFO"RESET RESET: read hifi bin to virt addr 0x%p, size = %d\n", (void*)(*buff), size);

    hisi_io_memset((void*)*buff, 0, size);

    /* read hifi image head from EMMC */
    ret = drv_read_bin((const char*)HIFI_IMAGE_NAME, 0, size, *buff);
    if (ret < 0)
    {
        printk(KERN_INFO"RESET LOADHIFI: drv_hifi_read_image:Read image %s error.\n", HIFI_IMAGE_NAME);
    	return BSP_RESET_ERROR;
    }

    /*dma_free_coherent(NULL, sizeof(struct drv_hifi_image_head),*buff,phy_img_buf);*/

    return 0;
}
/*****************************************************************************
 函 数 名  : reset_no_ok_savelog
 功能描述  : 在调用回调函数时如果回调函数返回失败,则记录下模块名字,返回值
 输入参数  : char *pname,组件注册回调函数时注册的名字;
             int iresult,回调函数的返回值。
             ereset_module emodule, 复位的模块,ccore or hifi
 输出参数  : 无
 返 回 值  : int
        0, 成功,非0,失败
*****************************************************************************/
int reset_no_ok_savelog(char *pname, int iresult, DRV_RESET_CB_MOMENT_E eparam, ereset_module emodule)
{
#ifdef PRINK_TO_FILE    /*如果实现了printk打印信息生成文件功能,则不需要该函数功能*/
    return BSP_RESET_OK;
#else

    int     ilen = 0;
    char    *psavelog = NULL;
    char    *ptime = (MDRV_RESET_CB_BEFORE == eparam?"before":"after");

    if (NULL == pname)
    {
        printk(KERN_ERR "[%s ]name is NULL, in savelog fun\n", __FUNCTION__);
        return BSP_RESET_ERROR;
    }

    psavelog = (char*)kmalloc(BSP_RESET_LOG_INFO_ITEM_LEN, GFP_KERNEL);
    if (NULL == psavelog)
    {
        printk(KERN_ERR "%s: fail to malloc, in savelog fun\n", __FUNCTION__);
        return BSP_RESET_ERROR;
    }
    hisi_io_memset((void*)psavelog, 0, BSP_RESET_LOG_INFO_ITEM_LEN);
    switch (emodule)
    {
    case BSP_RESET_MODULE_CCORE:
        sprintf(psavelog, "%s ccore reset, %s fail, return %d\n",ptime, pname, iresult);
        break;
    case BSP_RESET_MODULE_HIFI:
        sprintf(psavelog, "%s hifi reset, %s fail, return %d\n",ptime, pname, iresult);
        break;
    default:
        sprintf(psavelog, "valid module, %s fail, return %d\n",pname, iresult);
        printk(KERN_ERR "%s: module id %d invalid!!, in savelog fun\n", __FUNCTION__, emodule);
        break;

    }
    reset_for_savelog(psavelog);
    kfree(psavelog);
    psavelog = NULL;

    return BSP_RESET_OK;
#endif /* PRINK_TO_FILE */
}
/*****************************************************************************
 函 数 名  : reset_do_regcbfunc
 功能描述  : 用于其它组件注册回调函数,处理Modem复位前后相关数据。
 输入参数  :
         sreset_mgr_LLI *plink,管理链表,注意,允许为空.
            const char *pname, 组件注册的名字
         pdrv_reset_cbfun cbfun,    组件注册的回调函数
         int userdata,组件的私有数据
         Int Priolevel, 回调函数调用优先级 0-49,其中0-9 保留。
 输出参数  : 无
 返 回 值  : int
*****************************************************************************/
sreset_mgr_LLI * reset_do_regcbfunc(sreset_mgr_LLI *plink, const char *pname, pdrv_reset_cbfun pcbfun, int userdata, int priolevel)
{
    sreset_mgr_LLI  *phead = plink;
    sreset_mgr_LLI  *pmgr_unit = NULL;

    /*判断入参是否合法,不合法返回错误*/
    if (NULL == pname
        || NULL == pcbfun
        || (priolevel < RESET_CBFUNC_PRIO_LEVEL_LOWT || priolevel > RESET_CBFUNC_PRIO_LEVEL_HIGH))
    {
        printk(KERN_ERR "%s: fail in ccore reset regcb,fail, name 0x%p, cbfun 0x%p, prio %d\n", __FUNCTION__, \
                        (void*)pname, (void*)pcbfun, priolevel);
        return NULL;
    }

    /*分配空间*/
    pmgr_unit = (sreset_mgr_LLI*)kmalloc(sizeof(sreset_mgr_LLI), GFP_KERNEL);
    if (NULL != pmgr_unit)
    {
        hisi_io_memset((void*)pmgr_unit, 0, (sizeof(sreset_mgr_LLI)));
        /*赋值*/
        strncpy(pmgr_unit->cbfuninfo.name, pname, DRV_RESET_MODULE_NAME_LEN);
        pmgr_unit->cbfuninfo.priolevel = priolevel;
        pmgr_unit->cbfuninfo.userdata = userdata;
        pmgr_unit->cbfuninfo.cbfun = pcbfun;
    }

    /*第一次调用该函数,链表为空*/
    if (NULL == phead)
    {
        phead = pmgr_unit;
    }
    else
    {
    /*根据优先级插入链表*/
        phead = reset_link_insert(phead, pmgr_unit);
    }
    return phead;
}
/*****************************************************************************
* 函 数 名  : IPF_Init
*
* 功能描述  : IPF初始化     内部使用,不作为接口函数
*
* 输入参数  : void
* 输出参数  : 无
* 返 回 值  : IPF_SUCCESS    初始化成功
*             IPF_ERROR      初始化失败
*
* 修改记录  :2011年1月21日   鲁婷  创建
*   1.修改日期 : 2012年11月29日
*     修改作者 : z00212992
*     修改记录 : 增加ADQ初始化
*****************************************************************************/
int IPF_Init(void)
{
    int s32Ret = 0;

    /* IPF内存配置越界检查 */
    if(IPF_MEM_USED_SIZE > IPF_AXI_MEM_SIZE)
    {
        IPF_PRINT_ERROR("memory overstep the boundary\n");
        return IPF_ERROR;
    }


    hisi_io_memset((BSP_VOID*)&g_stIpfCtx, 0x0, sizeof(IPF_CONTEXT_S));

    IPF_ULBD_MEM_ADDR = HISI_VA_ADDRESS(IPF_AXI_MEM_ADDR);

    if (0 == (IPF_REGBASE_ADR = (unsigned long)ioremap(REG_BASE_IPF,REG_IPF_IOSIZE))){
        BUG_ON(1);
        return IPF_ERROR;
    }

    /* 为上行BD、RD描述符分配一段连续的物理地址 */
    g_stIpfUl.pstIpfBDQ = (IPF_BD_DESC_S*)IPF_ULBD_MEM_ADDR;
    g_stIpfUl.pstIpfRDQ = (IPF_RD_DESC_S*)IPF_ULRD_MEM_ADDR;

    /* 为上行AD描述符分配一段连续内存(首地址8字节对齐)*/
    g_stIpfUl.pstIpfADQ0 = (IPF_AD_DESC_S*)IPF_ULAD0_MEM_ADDR;
    g_stIpfUl.pstIpfADQ1 = (IPF_AD_DESC_S*)IPF_ULAD1_MEM_ADDR;

    /* 为下行BD、RD描述符分配一段连续的物理地址 */
    g_stIpfDl.pstIpfBDQ = (IPF_BD_DESC_S*)IPF_DLBD_MEM_ADDR;
    g_stIpfDl.pstIpfRDQ = (IPF_RD_DESC_S*)IPF_DLRD_MEM_ADDR;

    /* 为下行AD描述符分配一段连续内存(首地址8字节对齐)*/
    g_stIpfDl.pstIpfADQ0 = (IPF_AD_DESC_S*)IPF_DLAD0_MEM_ADDR;
    g_stIpfDl.pstIpfADQ1 = (IPF_AD_DESC_S*)IPF_DLAD1_MEM_ADDR;

    /* 为下行CD描述符分配一段连续的物理地址 */
    g_stIpfDl.pstIpfCDQ = (IPF_CD_DESC_S*)IPF_DLCD_MEM_ADDR;

    /* 记录IPF上行空闲BD个数 */
    g_stIpfUl.pu32IdleBd = (unsigned int*)IPF_ULBD_IDLENUM_ADDR;

#ifdef __BSP_IPF_DEBUG__
    /* 记录IPF debug信息 */
    g_stIPFDebugInfo = (IPF_DEBUG_INFO_S*)IPF_DEBUG_INFO_ADDR;

    /* 记录IPF 下行CDdebug信息 */
    g_stIpfDl.pstIpfDebugCDQ = (IPF_CD_DESC_S*)IPF_DEBUG_DLCD_ADDR;
#endif

    /* 记录IPF 下行CD读写指针 */
    g_stIpfDl.u32IpfCdRptr = (unsigned int*)IPF_DLCD_PTR_ADDR;
    g_stIpfDl.u32IpfCdWptr = (unsigned int*)(IPF_DLCD_PTR_ADDR+4);

    /* 挂接IPF中断 */
    IPF_Int_Connect();

    /* 注册IPF设备 */
    s32Ret = platform_device_register(&ipf_pfdev);
    if(s32Ret)
    {
        IPF_PRINT_ERROR("ipf device register fail\n");
        return s32Ret;
    }

    /* 注册IPF驱动 */
    s32Ret = platform_driver_register(&ipf_pfdrv);
    if(s32Ret)
    {
        platform_device_unregister(&ipf_pfdev);
        IPF_PRINT_ERROR("ipf driver register fail\n");
        return s32Ret;
    }

    ipf_peri_ctrl_base = (unsigned long)HISI_VA_ADDRESS(SOC_PERI_SCTRL_BASE_ADDR);
	if (!ipf_peri_ctrl_base)
	{
        IPF_PRINT_ERROR("unable to ioremap ipf peri ctrl\n");
	}

    /* 打开IPF hclk时钟、axi总线时钟 */
    IPF_REG_WRITE(SOC_PERI_SCTRL_SC_PERIPH_CLKEN2_ADDR(ipf_peri_ctrl_base), \
                (0x1 << SOC_PERI_SCTRL_SC_PERIPH_CLKEN2_periph_clken2_ipf_acpu_START));

    /* 等待另外一个core ipf初始化同步完成 */
    s32Ret = BSP_SYNC_Wait(SYNC_MODULE_IPF, 5000);
    if(s32Ret != BSP_OK)
    {
        IPF_PRINT_ERROR("BSP_SYNC_Wait timeout\n");
        return IPF_ERROR;
    }

    /* IPF初始化完成 */
    g_stIpfCtx.isInit = BSP_TRUE;


    IPF_PRINT_ERROR("success\n");
    return IPF_SUCCESS;
}