/*
 * 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 "vmng_mem_alloc_interface.h"
#include "virtmng_public_def.h"
#include "virtmnghost_unit.h"

int vmngh_dev_id_check(u32 dev_id, u32 fid)
{
    if (dev_id >= ASCEND_PDEV_MAX_NUM) {
        vmng_err("Input parameter is error. (dev_id=%u; fid=%u)\n", dev_id, fid);
        return -EINVAL;
    }
    if (fid >= VMNG_VDEV_MAX_PER_PDEV) {
        vmng_err("Input parameter is error. (dev_id=%u; fid=%u)\n", dev_id, fid);
        return -EINVAL;
    }
    return 0;
}

int vmngh_vm_id_check(u32 vm_id, u32 vm_devid)
{
    if (vm_id >= VMNG_VM_MAX) {
        vmng_err("Input parameter is error. (vm_id=%u; vm_devid=%u)\n", vm_id, vm_devid);
        return -EINVAL;
    }
    if (vm_devid >= ASCEND_PDEV_MAX_NUM) {
        vmng_err("Input parameter is error. (vm_id=%u; vm_devid=%u)\n", vm_id, vm_devid);
        return -EINVAL;
    }

    return 0;
}

struct vmngh_unit g_vmngh_unit;

struct vmng_msg_dev *vmngh_get_msg_dev_by_id(u32 dev_id, u32 fid)
{
    struct vmngh_vd_dev *vd_dev = NULL;

    if (vmngh_dev_id_check(dev_id, fid) != 0) {
        vmng_err("Parameter check failed. (dev_id=%u; fid=%u)\n", dev_id, fid);
        return NULL;
    }
    vd_dev = g_vmngh_unit.vmngh_pcidev[dev_id].vd_dev[fid];

    return vd_dev->msg_dev;
}

struct vmngh_vd_dev *vmngh_get_vddev_by_id(u32 dev_id, u32 fid)
{
    if (vmngh_dev_id_check(dev_id, fid) != 0) {
        vmng_err("Parameter check failed. (dev_id=%u; fid=%u)\n", dev_id, fid);
        return NULL;
    }

    return g_vmngh_unit.vmngh_pcidev[dev_id].vd_dev[fid];
}

void *vmngh_get_vdavinci_by_id(u32 dev_id, u32 fid)
{
    struct vmngh_vd_dev *vd_dev = NULL;

    if (vmngh_dev_id_check(dev_id, fid) != 0) {
        vmng_err("Parameter check failed. (dev_id=%u; fid=%u)\n", dev_id, fid);
        return NULL;
    }

    vd_dev = vmngh_get_vddev_by_id(dev_id, fid);
    if (vd_dev == NULL) {
        return NULL;
    }
    return vd_dev->vdavinci;
}
KA_EXPORT_SYMBOL(vmngh_get_vdavinci_by_id);

ka_mutex_t *vmngh_get_vdev_lock_from_unit(u32 dev_id, u32 fid)
{
    return &g_vmngh_unit.vmngh_pcidev[dev_id].vddev_mutex[fid];
}

struct vmngh_vd_dev *vmngh_get_vdev_from_unit(u32 dev_id, u32 fid)
{
    if (vmngh_dev_id_check(dev_id, fid) != 0) {
        vmng_err("Parameter check failed. (dev_id=%u; fid=%u)\n", dev_id, fid);
        return NULL;
    }

    return g_vmngh_unit.vmngh_pcidev[dev_id].vd_dev[fid];
}

struct vmngh_pci_dev *vmngh_get_pdev_from_unit(u32 dev_id)
{
    return &(g_vmngh_unit.vmngh_pcidev[dev_id]);
}

void vmngh_set_device_status(u32 dev_id, u32 valid)
{
    struct vmngh_pci_dev *dev = &g_vmngh_unit.vmngh_pcidev[dev_id];
    dev->valid = valid;
    vmng_info("Set status finished. (devid=%d; status=%d)\n", dev_id, valid);
}

u32 vmngh_get_device_status(u32 dev_id)
{
    return g_vmngh_unit.vmngh_pcidev[dev_id].valid;
}

void vmngh_set_peer_dev_id(u32 dev_id, int peer_dev_id)
{
    g_vmngh_unit.vmngh_pcidev[dev_id].peer_dev_id = (u32)peer_dev_id;
}

void vmngh_free_vdev(struct vmngh_vd_dev *vd_dev)
{
    u32 dev_id;
    u32 fid;

    if (vd_dev == NULL) {
        vmng_err("Input parameter is error.\n");
        return;
    }
    dev_id = vd_dev->dev_id;
    fid = vd_dev->fid;
    if (vmngh_dev_id_check(dev_id, fid) == 0) {
        g_vmngh_unit.vmngh_pcidev[dev_id].vd_dev[fid] = NULL;
    }

    if (vd_dev->vpc_unit != NULL) {
        vmng_kfree(vd_dev->vpc_unit);
        vd_dev->vpc_unit = NULL;
    }
    vmng_kfree(vd_dev);
    vd_dev = NULL;
}

int vmngh_init_unit(void)
{
    u32 dev_id;

    if (memset_s(&g_vmngh_unit, sizeof(g_vmngh_unit), 0, sizeof(g_vmngh_unit)) != EOK) {
        vmng_err("Call memset_s failed.\n");
        return -EINVAL;
    }

    for (dev_id = 0; dev_id < ASCEND_PDEV_MAX_NUM; dev_id++) {
        g_vmngh_unit.vmngh_pcidev[dev_id].dev_id = (u32)VMNG_CTRL_DEVICE_ID_INIT;
    }

    return 0;
}

u32 vmngh_vd_dev_alive(void)
{
    u32 dev_id;
    u32 fid;

    for (dev_id = 0; dev_id < ASCEND_PDEV_MAX_NUM; dev_id++) {
        for (fid = 0; fid < VMNG_VDEV_MAX_PER_PDEV; fid++) {
            if (g_vmngh_unit.vmngh_pcidev[dev_id].vd_dev[fid] != NULL) {
                return VMNGA_VD_DEV_ALIVE_OK;
            }
        }
    }

    return VMNGA_VD_DEV_ALIVE_NOK;
}