/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
 * only version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 */

#include "ka_task_pub.h"
#include "ka_system_pub.h"
#include "ka_base_pub.h"
#include "ka_list_pub.h"
#include "ka_errno_pub.h"
#include "securec.h"
#include "pbl_mem_alloc_interface.h"
#include "udis_log.h"
#include "udis_management.h"
#include "udis_msg.h"
#include "comm_kernel_interface.h"

#define UDIS_NODE_NUM_INIT 128
#define UDIS_LINK_NODES_SCALE_UP_FACTOR 2

STATIC struct devdrv_common_msg_client g_udis_common_chan;
STATIC struct udis_link_nodes g_link_nodes[UDIS_DEVICE_UDEVID_MAX] = {0};

struct devdrv_common_msg_client *udis_get_common_msg_client(void)
{
    return  &g_udis_common_chan;
}

struct udis_link_nodes *udis_get_link_nodes(unsigned int udevid)
{
    if (udevid >= UDIS_DEVICE_UDEVID_MAX) {
        udis_err("Invalid param. (udevid=%u)\n", udevid);
        return NULL;
    }
    return &g_link_nodes[udevid];
}

int udis_link_nodes_init(unsigned int udevid)
{
    struct udis_link_nodes *link_nodes = NULL;

    if (udevid >= UDIS_DEVICE_UDEVID_MAX) {
        udis_err("Invalid param. (udevid=%u)\n", udevid);
        return -EINVAL;
    }

    link_nodes = udis_get_link_nodes(udevid);
    if (link_nodes == NULL) {
        udis_err("link_nodes is NULL. (udevid=%u)\n", udevid);
        return -EFAULT;
    }

    if ((devdrv_get_connect_protocol(udevid) == CONNECT_PROTOCOL_UB)) {
        if (link_nodes->node.ub_nodes != NULL) {
            udis_info("ub_nodes is not NULL, no need to init. (udevid=%u)\n", udevid);
            return 0;
        }

        link_nodes->node.ub_nodes = (struct udis_link_ub_node *)dbl_kzalloc((sizeof(struct udis_link_ub_node) *
            UDIS_NODE_NUM_INIT), KA_GFP_KERNEL | __KA_GFP_ACCOUNT);
        if (link_nodes->node.ub_nodes == NULL) {
            udis_err("Failed to alloc ub node array. (udevid=%u)\n", udevid);
            return -ENOMEM;
        }
    } else {
        if  (link_nodes->node.dma_nodes != NULL) {
            udis_info("dma_nodes is not NULL, no need to init. (udevid=%u)\n", udevid);
            return 0;
        }

        link_nodes->node.dma_nodes = (struct devdrv_dma_node *)dbl_kzalloc((sizeof(struct devdrv_dma_node) *
            UDIS_NODE_NUM_INIT), KA_GFP_KERNEL | __KA_GFP_ACCOUNT);
        if (link_nodes->node.dma_nodes == NULL) {
            udis_err("Failed to alloc dma node array. (udevid=%u)\n", udevid);
            return -ENOMEM;
        }
    }

    link_nodes->capacity = UDIS_NODE_NUM_INIT;
    link_nodes->node_num = 0;
    return 0;
}

void udis_link_nodes_uninit(unsigned int udevid)
{
    struct udis_link_nodes *link_nodes = NULL;

    if (udevid >= UDIS_DEVICE_UDEVID_MAX) {
        udis_err("Invalid param. (udevid=%u)\n", udevid);
        return;
    }

    link_nodes = udis_get_link_nodes(udevid);
    if (link_nodes == NULL) {
        udis_err("ub_nodes_arr is NULL. (udevid=%u)\n", udevid);
        return;
    }

    if ((devdrv_get_connect_protocol(udevid) == CONNECT_PROTOCOL_UB)) {
        if (link_nodes->node.ub_nodes == NULL) {
            udis_info("ub_nodes is NULL, no need to uninit. (udevid=%u)\n", udevid);
            return;
        }
        dbl_kfree(link_nodes->node.ub_nodes);
        link_nodes->node.ub_nodes = NULL;
    } else {
        if  (link_nodes->node.dma_nodes == NULL) {
            udis_info("dma_nodes is NULL, no need to uninit. (udevid=%u)\n", udevid);
            return;
        }
        dbl_kfree(link_nodes->node.dma_nodes);
        link_nodes->node.dma_nodes = NULL;
    }

    link_nodes->capacity = 0;
    link_nodes->node_num = 0;
    return;
}

STATIC int udis_ub_nodes_scale_up(unsigned int udevid, struct udis_link_nodes *link_nodes)
{
    int ret;
    struct udis_link_ub_node *old_nodes = NULL;
    struct udis_link_ub_node *new_nodes = NULL;
    unsigned int new_capacity = 0;
    unsigned int old_capacity = 0;

    if (link_nodes->node.ub_nodes == NULL) {
        udis_err("ub_nodes is NULL. (udevid=%u)\n", udevid);
        return -EFAULT;
    }

    old_capacity = link_nodes->capacity;
    new_capacity = old_capacity * UDIS_LINK_NODES_SCALE_UP_FACTOR;
    old_nodes = link_nodes->node.ub_nodes;

    new_nodes = (struct udis_link_ub_node*)dbl_kzalloc(sizeof(struct udis_link_ub_node) * new_capacity,
        KA_GFP_KERNEL | __KA_GFP_ACCOUNT);
    if (new_nodes == NULL) {
        udis_err("Failed to alloc new ub node array. (udevid=%u)\n", udevid);
        return -ENOMEM;
    }

    ret = memcpy_s(new_nodes, sizeof(struct udis_link_ub_node) * old_capacity,
        old_nodes, sizeof(struct udis_link_ub_node) * old_capacity);
    if (ret != 0) {
        dbl_kfree(new_nodes);
        new_nodes = NULL;
        udis_err("memcpy_s failed. (udevid=%u; ret=%d)\n", udevid, ret);
        return -ENOMEM;
    }
    dbl_kfree(old_nodes);
    old_nodes = NULL;
    link_nodes->node.ub_nodes = new_nodes;
    link_nodes->capacity = new_capacity;
    return 0;
}

STATIC int udis_dma_nodes_scale_up(unsigned int udevid, struct udis_link_nodes *link_nodes)
{
    int ret;
    struct devdrv_dma_node *old_nodes = NULL;
    struct devdrv_dma_node *new_nodes = NULL;
    unsigned int new_capacity = 0;
    unsigned int old_capacity = 0;

    if (link_nodes->node.dma_nodes == NULL) {
        udis_err("dma_nodes is NULL. (udevid=%u)\n", udevid);
        return -EFAULT;
    }

    old_capacity = link_nodes->capacity;
    new_capacity = old_capacity * UDIS_LINK_NODES_SCALE_UP_FACTOR;
    old_nodes = link_nodes->node.dma_nodes;

    new_nodes = (struct devdrv_dma_node*)dbl_kzalloc(sizeof(struct devdrv_dma_node) * new_capacity,
        KA_GFP_KERNEL | __KA_GFP_ACCOUNT);
    if (new_nodes == NULL) {
        udis_err("Failed to alloc new dma node array. (udevid=%u)\n", udevid);
        return -ENOMEM;
    }

    ret = memcpy_s(new_nodes, sizeof(struct devdrv_dma_node) * old_capacity,
        old_nodes, sizeof(struct devdrv_dma_node) * old_capacity);
    if (ret != 0) {
        dbl_kfree(new_nodes);
        new_nodes = NULL;
        udis_err("memcpy_s failed. (udevid=%u; ret=%d)\n", udevid, ret);
        return -ENOMEM;
    }
    dbl_kfree(old_nodes);
    old_nodes = NULL;
    link_nodes->node.dma_nodes = new_nodes;
    link_nodes->capacity = new_capacity;
    return 0;
}

int udis_link_nodes_scale_up(unsigned int udevid)
{
    int ret;
    struct udis_link_nodes *link_nodes = NULL;
    if (udevid >= UDIS_DEVICE_UDEVID_MAX) {
        udis_err("Invalid param. (udevid=%u)\n", udevid);
        return -EINVAL;
    }

    link_nodes = udis_get_link_nodes(udevid);
    if (link_nodes == NULL) {
        udis_err("link_ub_nodes is NULL. (udevid=%u)\n", udevid);
        return -EFAULT;
    }

    if ((devdrv_get_connect_protocol(udevid) == CONNECT_PROTOCOL_UB)) {
        ret = udis_ub_nodes_scale_up(udevid, link_nodes);
        if (ret != 0) {
            udis_err("udis_ub_nodes_scale_up failed. (udevid=%u; ret=%d)\n", udevid, ret);
            return ret;
        }
    } else {
        ret = udis_dma_nodes_scale_up(udevid, link_nodes);
        if (ret != 0) {
            udis_err("udis_dma_nodes_scale_up failed. (udevid=%u; ret=%d)\n", udevid, ret);
            return ret;
        }
    }

    return 0;
}

STATIC int udis_update_ub_nodes(unsigned int udevid, const struct udis_ctrl_block *udis_cb,
    UDIS_UPDATE_TYPE update_type, struct udis_link_nodes *link_nodes)
{
    int ret;
    struct udis_node *cur;
    unsigned int node_num = 0;
    ka_list_for_each_entry(cur, &udis_cb->addr_list[update_type], list) {
        link_nodes->node.ub_nodes[node_num].host_segment = cur->host_segment;
        link_nodes->node.ub_nodes[node_num].device_segment_import = cur->device_segment_import;
        link_nodes->node.ub_nodes[node_num].host_segment_len = cur->host_segment_len;
        link_nodes->node.ub_nodes[node_num].device_segment_import_len = cur->device_segment_import_len;
        link_nodes->node.ub_nodes[node_num].host_va_addr = cur->host_va_addr;
        link_nodes->node.ub_nodes[node_num].data_len = cur->data_len;
        ++node_num;
        if (node_num < link_nodes->capacity) {
            continue;
        }
        ret = udis_link_nodes_scale_up(udevid);
        if (ret != 0) {
            udis_err("Link ub nodes scale up failed. (udevid=%u; ret=%d)\n", udevid, ret);
            goto out;
        }
    }

out:
    link_nodes->node_num = node_num;
    return ret;
}

STATIC int udis_update_dma_nodes(unsigned int udevid, const struct udis_ctrl_block *udis_cb,
    UDIS_UPDATE_TYPE update_type, struct udis_link_nodes *link_nodes)
{
    int ret;
    struct udis_node *cur;
    unsigned int node_num = 0;
    ka_list_for_each_entry(cur, &udis_cb->addr_list[update_type], list) {
        link_nodes->node.dma_nodes[node_num].src_addr = cur->dev_dma_addr;
        link_nodes->node.dma_nodes[node_num].dst_addr = cur->host_dma_addr;
        link_nodes->node.dma_nodes[node_num].size = cur->data_len;
        link_nodes->node.dma_nodes[node_num].direction = DEVDRV_DMA_DEVICE_TO_HOST;
        link_nodes->node.dma_nodes[node_num].loc_passid = DEVDRV_DMA_PASSID_DEFAULT;
        ++node_num;
        if (node_num < link_nodes->capacity) {
            continue;
        }
        ret = udis_link_nodes_scale_up(udevid);
        if (ret != 0) {
            udis_err("Link dma nodes scale up failed. (udevid=%u; ret=%d)\n", udevid, ret);
            goto out;
        }
    }

out:
    link_nodes->node_num = node_num;
    return ret;
}

STATIC int udis_update_link_nodes(unsigned int udevid, const struct udis_ctrl_block *udis_cb,
    UDIS_UPDATE_TYPE update_type)
{
    int ret = 0;
    unsigned int node_num = 0;
    struct udis_link_nodes *link_nodes = NULL;

    if (update_type < UPDATE_PERIOD_LEVEL_1) {
        udis_info("Not period update type, no need to flush link ub nodes. (udevid=%u; update_type=%u; node_num=%u)\n",
            udevid, update_type, node_num);
        return 0;
    }

    link_nodes = udis_get_link_nodes(udevid);
    if (link_nodes == NULL) {
        udis_err("nodes_arr is NULL. (udevid=%u; update_type=%u)\n", udevid, update_type);
        return -ENOMEM;
    }

    if ((devdrv_get_connect_protocol(udevid) == CONNECT_PROTOCOL_UB)) {
        ret = udis_update_ub_nodes(udevid, udis_cb, update_type, link_nodes);
        if (ret != 0) {
            udis_err("udis_update_ub_nodes failed. (udevid=%u; ret=%d)\n", udevid, ret);
            return ret;
        }
    } else {
        ret = udis_update_dma_nodes(udevid, udis_cb, update_type, link_nodes);
        if (ret != 0) {
            udis_err("udis_update_dma_nodes failed. (udevid=%u; ret=%d)\n", udevid, ret);
            return ret;
        }
    }

    return ret;
}

STATIC int udis_check_addr_node(const struct udis_node *addr_node)
{
    int is_discrete_info;
    unsigned int name_len = 0;

    if (addr_node == NULL) {
        udis_err("Addr node is NULL\n");
        return -EINVAL;
    }

    if (addr_node->module_type >= UDIS_MODULE_MAX) {
        udis_err("Invalid module_type. (module_type=%u; max_module_type=%u)\n",
            addr_node->module_type, UDIS_MODULE_MAX - 1);
        return -EINVAL;
    }

    name_len = ka_base_strnlen(addr_node->name, UDIS_MAX_NAME_LEN);
    if ((name_len == 0) || (name_len >= UDIS_MAX_NAME_LEN)) {
        udis_err("Invalid name_len. (module_type=%u; name_len=%u; max_name_len=%u)\n",
            addr_node->module_type, name_len, UDIS_MAX_NAME_LEN - 1);
        return -EINVAL;
    }

    if (addr_node->update_type >= UPDATE_TYPE_MAX) {
        udis_err("Invalid update type. (mode_type=%u; name=%s; update_type=%u; max_update_type=%u)\n",
            addr_node->module_type, addr_node->name, addr_node->update_type, UPDATE_TYPE_MAX - 1);
        return -EINVAL;
    }

    is_discrete_info = ka_base_strcmp(addr_node->name, UDIS_UNIFIED_MODULE_INFO);
    if (((addr_node->dev_dma_addr == UDIS_BAD_DMA_ADDR) && (addr_node->dev_va_addr == UDIS_BAD_VA_ADDR)) || (addr_node->data_len == 0) ||
        ((is_discrete_info != 0) && (addr_node->data_len > UDIS_MAX_DATA_LEN)) ||
        ((is_discrete_info == 0) && (addr_node->data_len != UDIS_UNIFIED_MODULE_OFFSET))) {
        udis_err("Invalid param. (module_type=%u; name=%s; dma_addr_is_bad=%d; data_len=%u)\n",
            addr_node->module_type, addr_node->name,
            addr_node->dev_dma_addr == UDIS_BAD_DMA_ADDR, addr_node->data_len);
        return -EINVAL;
    }
    
    return 0;
}

STATIC struct devdrv_seg_info *udis_alloc_seg_info(unsigned int udevid, va_addr_t addr, unsigned int data_len, u32 token_value)
{
    struct devdrv_seg_info *seg_info = NULL;
    seg_info = (struct devdrv_seg_info *)dbl_kzalloc(sizeof(struct devdrv_seg_info), KA_GFP_KERNEL | __KA_GFP_ACCOUNT);
    if (seg_info == NULL) {
        udis_err("kzalloc reg_seg failed. (dev_id=%u)\n", udevid);
        return NULL;
    }
    seg_info->va = addr;
    seg_info->token_value = token_value;
    seg_info->access = DEVDRV_ACCESS_READ | DEVDRV_ACCESS_WRITE;
    seg_info->mem_len = data_len;
    return seg_info;
}

STATIC void udis_free_seg_info(struct devdrv_seg_info *seg_info)
{
    if (seg_info != NULL) {
        dbl_kfree(seg_info);
        seg_info = NULL;
    }
    return;
}

STATIC int udis_get_segment(unsigned int udevid, struct udis_ctrl_block *udis_cb, struct udis_node *addr_node)
{
    int ret;
    void *host_segment = NULL;
    void *device_segment_import = NULL;
    size_t device_segment_import_len = 0;
    size_t host_segment_len = 0;
    u32 token_value = 0;
    struct devdrv_seg_info *seg_info = NULL;

    device_segment_import = devdrv_import_seg(udevid, addr_node->token_value, (void *)addr_node->device_segment, addr_node->device_segment_len, &device_segment_import_len);
    if (KA_IS_ERR_OR_NULL(device_segment_import)) {
        udis_err("devdrv_import_seg failed. (udevid=%u)\n", udevid);
        return -EINVAL;
    }

    ret = devdrv_get_token_val(udevid, &token_value);
    if (ret != 0) {
        udis_err("devdrv_get_token_val failed. (udevid=%u)\n", udevid);
        return ret;
    }
    seg_info = udis_alloc_seg_info(udevid, (va_addr_t)(uintptr_t)(udis_cb->udis_info_buf), UDIS_MODULE_OFFSET * UDIS_MODULE_MAX, token_value);
    if (seg_info == NULL) {
        udis_err("udis_alloc_seg_info failed. (udevid=%u)\n", udevid);
        return ret;
    }

    ret = devdrv_register_seg(udevid, seg_info, &host_segment, &host_segment_len);
    udis_free_seg_info(seg_info);
    if (ret != 0) {
        udis_err("devdrv_register_seg failed. (udevid=%u)\n", udevid);
        return ret;
    }

    addr_node->host_segment = host_segment;
    addr_node->device_segment_import = device_segment_import;
    addr_node->host_segment_len = host_segment_len;
    addr_node->device_segment_import_len = device_segment_import_len;
    return 0;
}

STATIC int udis_addr_node_register(unsigned int udevid, struct udis_ctrl_block *udis_cb,
    struct udis_node *addr_node)
{
    int ret;
    ka_dma_addr_t host_addr = 0;

    ret = udis_alloc_info_block(udevid, addr_node, &host_addr);
    if (ret != 0) {
        udis_err("Init info block failed. (udevid=%u; module_type=%u; name=%s; ret=%d)\n", udevid,
            addr_node->module_type, addr_node->name, ret);
        return ret;
    }
    if ((devdrv_get_connect_protocol(udevid) == CONNECT_PROTOCOL_UB)) { 
        addr_node->host_va_addr = host_addr;
    } else {
        addr_node->host_dma_addr = host_addr;
    }

    if ((devdrv_get_connect_protocol(udevid)) == CONNECT_PROTOCOL_UB) {
        ret = udis_get_segment(udevid, udis_cb, addr_node);
        if (ret != 0) {
            udis_err("udis_get_segment failed. (udevid=%u; module_type=%u; name=%s; ret=%d)\n", udevid,
                addr_node->module_type, addr_node->name, ret);
            goto free_info_block;
        }
    }

    ret = udis_addr_list_add_node(udevid, udis_cb, addr_node);
    if (ret != 0) {
        udis_err("Add node to addr list failed. (udevid=%u; module_type=%u; name=%s; ret=%d)\n", udevid,
            addr_node->module_type, addr_node->name, ret);
        goto free_info_block;
    }
    ret = udis_update_link_nodes(udevid, udis_cb, addr_node->update_type);
    if (ret != 0) {
        udis_err("Update link nodes failed. (udevid=%u; module_type=%u; name=%s; ret=%d)\n", udevid,
            addr_node->module_type, addr_node->name, ret);
        goto remove_node;
    }
    return 0;

remove_node:
    udis_addr_list_remove_node(udevid, udis_cb, addr_node);
free_info_block:
    udis_free_info_block(udevid, addr_node);
    return ret;
}

STATIC int udis_register_addr(void *msg, u32 *ack_len)
{
    int ret;
    unsigned int udevid;
    struct udis_msg_info *msg_info = NULL;
    struct udis_node *addr_node = NULL;
    struct udis_ctrl_block *udis_cb = NULL;
    struct udis_node *repeat_node = NULL;

    msg_info = (struct udis_msg_info *)msg;
    addr_node = (struct udis_node *)msg_info->payload;
    udevid = msg_info->head.dev_id;

    if ((udevid >= UDIS_DEVICE_UDEVID_MAX) || (udis_check_addr_node(addr_node) != 0)) {
        udis_err("Invalid udevid or udis addr node. (udevid=%u)\n", udevid);
        return -EINVAL;
    }

    udis_cb_read_lock(udevid);
    udis_cb = udis_get_ctrl_block(udevid);
    if (udis_cb == NULL) {
        udis_err("Get udis ctrl block failed. (udevid=%u)\n", udevid);
        ret = -ENODEV;
        goto unlock_cb_read_lock;
    }

    ka_task_down_write(&udis_cb->addr_list_lock);
    repeat_node = udis_addr_list_find_node(udis_cb, addr_node->module_type, addr_node->name);
    if (repeat_node != NULL) {
        udis_info("Already have the same addr node. (udevid=%u; module_type=%u; name=%s)\n",
            udevid, addr_node->module_type, addr_node->name);
        *ack_len = 0;
        ret = 0;
        goto unlock_addr_list_lock;
    }

    ret = udis_addr_node_register(udevid, udis_cb, addr_node);
    if (ret != 0) {
        udis_err("Add new addr node failed. (udevid=%u; module_type=%u; name=%s; ret=%d)\n",
            udevid, addr_node->module_type, addr_node->name, ret);
        goto unlock_addr_list_lock;
    }

    (void)udis_sync_copy(udevid, udis_cb, addr_node);

    *ack_len = 0;
    udis_info("Register addr node success.\
 (udevid=%u; module_type=%u; name=%s; update_type=%u; acc_ctrl=%u; data_len=%u)\n", udevid, addr_node->module_type,
        addr_node->name, addr_node->update_type, addr_node->acc_ctrl, addr_node->data_len);

unlock_addr_list_lock:
    ka_task_up_write(&udis_cb->addr_list_lock);
unlock_cb_read_lock:
    udis_cb_read_unlock(udevid);
    return ret;
}

STATIC int udis_unregister_addr(void *msg, u32 *ack_len)
{
    int ret;
    unsigned int udevid;
    struct udis_msg_info *msg_info = NULL;
    struct udis_node *addr_node = NULL;
    struct udis_node *target_node = NULL;
    struct udis_ctrl_block *udis_cb = NULL;

    msg_info = (struct udis_msg_info *)msg;
    udevid = msg_info->head.dev_id;
    addr_node = (struct udis_node *)msg_info->payload;

    if ((udevid >= UDIS_DEVICE_UDEVID_MAX) || (udis_check_addr_node(addr_node) != 0)) {
        udis_err("Invalid udevid or udis addr node. (udevid=%u)\n", udevid);
        return -EINVAL;
    }

    udis_cb_read_lock(udevid);
    udis_cb = udis_get_ctrl_block(udevid);
    if (udis_cb == NULL) {
        udis_cb_read_unlock(udevid);
        udis_err("Get udis ctrl block failed. (udevid=%u)\n", udevid);
        return -ENODEV;
    }

    ka_task_down_write(&udis_cb->addr_list_lock);

    target_node = udis_addr_list_find_node(udis_cb, addr_node->module_type, addr_node->name);
    if (target_node == NULL) {
        udis_info("No matched node found. (udevid=%u; module_type=%u; name=%s)\n", udevid, addr_node->module_type,
            addr_node->name);
        *ack_len = 0;
        ret = 0;
        goto out;
    }

    ka_list_del(&target_node->list);

    ret = udis_update_link_nodes(udevid, udis_cb, addr_node->update_type);
    if (ret != 0) {
        ka_list_add(&target_node->list, &udis_cb->addr_list[target_node->update_type]);
        udis_err("Update link nodes failed. (udevid=%u; module_type=%u; name=%s; ret=%d)\n", udevid,
            addr_node->module_type, addr_node->name, ret);
        goto out;
    }
    udis_free_info_block(udevid, target_node);
    dbl_kfree(target_node);
    target_node = NULL;

    *ack_len = 0;
    udis_info("Unregister addr node success.\
 (udevid=%u; module_type=%u; name=%s; update_type=%u; acc_ctrl=%u; data_len=%u)\n", udevid, addr_node->module_type,
        addr_node->name, addr_node->update_type, addr_node->acc_ctrl, addr_node->data_len);
out:
    ka_task_up_write(&udis_cb->addr_list_lock);
    udis_cb_read_unlock(udevid);
    return ret;
}

STATIC int (*udis_chan_msg_processes[UDIS_CHAN_D2H_MAX_ID])(void *msg, u32 *ack_len) = {
    [UDIS_CHAN_D2H_REGIST] = udis_register_addr,
    [UDIS_CHAN_D2H_UNREGIST] = udis_unregister_addr,
};

STATIC int udis_rx_common_msg_process(unsigned int dev_id, void *data, unsigned int in_data_len, unsigned int out_data_len,
    unsigned int *real_out_len)
{
    unsigned int msg_id;
    struct udis_msg_info *msg_info = NULL;

    if ((dev_id >= UDIS_DEVICE_UDEVID_MAX) || (data == NULL) || (real_out_len == NULL) ||
        (in_data_len < sizeof(struct udis_msg_info))) {
        udis_err("date(%pK) or real_out_len(%pK) is NULL. (devid=%u; in_data_len=%u)\n",
            data, real_out_len, dev_id, in_data_len);
        return -EINVAL;
    }
    msg_info = (struct udis_msg_info *)data;
    msg_id = msg_info->head.msg_id;
    if (msg_id >= UDIS_CHAN_D2H_MAX_ID) {
        udis_err("Invalid msg_id. (dev_id=%u; msg_id=%u)\n", dev_id, msg_id);
        return -EINVAL;
    }

    if (udis_chan_msg_processes[msg_id] == NULL) {
        udis_err("udis_chan_msg_processes[%u] is NULL. (dev_id=%u)\n", msg_id, dev_id);
        return -EINVAL;
    }
    msg_info->head.dev_id = dev_id;
    return udis_chan_msg_processes[msg_id](data, real_out_len);
}

int udis_send_host_vf_uninit_notify(unsigned int udevid)
{
    int ret;
    unsigned int out_len = 0;
    struct udis_msg_info udis_msg_info = {{0}, {0}};

    if ((udevid >= UDIS_DEVICE_UDEVID_MAX)) {
        udis_err("Invalid para. (udevid=%u)\n", udevid);
        return -EINVAL;
    }

    udis_msg_info.head.dev_id = udevid;
    udis_msg_info.head.msg_id = UDIS_CHAN_H2D_UNINIT;
    udis_msg_info.head.valid = (u16)UDIS_MSG_VALID;
    udis_msg_info.head.result = (u16)UDIS_MSG_INVALID_RESULT;
    udis_msg_info.payload[0] = 1;

    ret = devdrv_common_msg_send(udevid, &udis_msg_info, sizeof(udis_msg_info),
        sizeof(udis_msg_info), &out_len, DEVDRV_COMMON_MSG_UDIS);
    if (ret != 0) {
        udis_err("H2D Send host uninit msg to device failed. (devid=%u; ret=%d)\n", udevid, ret);
        return ret;
    }

    return 0;
}

int udis_send_host_ready_msg_to_device(unsigned int udevid)
{
    int ret;
    unsigned int out_len = 0;
    struct udis_msg_info udis_msg_info = {{0}, {0}};

    if ((udevid >= UDIS_DEVICE_UDEVID_MAX)) {
        udis_err("Invalid para. (udevid=%u)\n", udevid);
        return -EINVAL;
    }

    udis_msg_info.head.dev_id = udevid;
    udis_msg_info.head.msg_id = UDIS_CHAN_H2D_READY;
    udis_msg_info.head.valid = (u16)UDIS_MSG_VALID;
    udis_msg_info.head.result = (u16)UDIS_MSG_INVALID_RESULT;
    udis_msg_info.payload[0] = 1;

    ret = devdrv_common_msg_send(udevid, &udis_msg_info, sizeof(udis_msg_info),
        sizeof(udis_msg_info), &out_len, DEVDRV_COMMON_MSG_UDIS);
    if (ret != 0) {
        udis_err("H2D Send host ready msg to device failed. (devid=%u; ret=%d)\n", udevid, ret);
        return ret;
    }

    return 0;
}

int udis_common_chan_init(void)
{
    g_udis_common_chan.type = DEVDRV_COMMON_MSG_UDIS;
    g_udis_common_chan.common_msg_recv = udis_rx_common_msg_process;
    g_udis_common_chan.init_notify = NULL;
    return 0;
}

void udis_common_chan_uninit(void)
{
    g_udis_common_chan.type = DEVDRV_COMMON_MSG_TYPE_MAX;
    g_udis_common_chan.common_msg_recv = NULL;
    g_udis_common_chan.init_notify = NULL;
}