* 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_system_pub.h"
#include "ka_memory_pub.h"
#include "ka_pci_pub.h"
#include "ka_pci_pub.h"
#include "ka_task_pub.h"
#include "ka_base_pub.h"
#include "ka_system_pub.h"
#include "ka_memory_pub.h"
#include "ka_barrier_pub.h"
#include "ka_common_pub.h"
#include "ka_kernel_def_pub.h"
#include "pbl/pbl_feature_loader.h"
#include "pbl/pbl_uda.h"
#include "pbl/pbl_soc_res.h"
#include "virtmnghost_vpc_unit.h"
#include "virtmnghost_unit.h"
#include "virtmnghost_ctrl.h"
#include "virtmnghost_msg.h"
#include "virtmnghost_msg_admin.h"
#include "virtmnghost_external.h"
#include "virtmnghost_vpc.h"
#include "virtmnghost_sysfs.h"
#include "virtmnghost_msg_common.h"
#include "virtmng_msg_pub.h"
#include "virtmng_msg_admin.h"
#include "virtmng_public_def.h"
#include "vmng_kernel_interface.h"
#include "virtmng_resource.h"
#include "comm_kernel_interface.h"
#include "hw_vdavinci.h"
#include "virtmnghost_proc_fs.h"
#include "vmng_mem_alloc_interface.h"
#include "virtmnghost_pci.h"
static const ka_pci_device_id_t g_vmngh_tbl[] = {{ KA_PCI_VDEVICE(HUAWEI, HISI_EP_DEVICE_ID_MINIV2), 0 },
{ KA_PCI_VDEVICE(HUAWEI, HISI_EP_DEVICE_ID_CLOUD), 0 },
{ KA_PCI_VDEVICE(HUAWEI, HISI_EP_DEVICE_ID_CLOUD_V2), 0 },
{ DEVDRV_DIVERSITY_PCIE_VENDOR_ID, 0xd500,
KA_PCI_ANY_ID, KA_PCI_ANY_ID, 0, 0, 0 },
{ KA_PCI_VDEVICE(HUAWEI, HISI_EP_DEVICE_ID_CLOUD_V5), 0 },
{ 0x20C6, 0xd500, KA_PCI_ANY_ID, KA_PCI_ANY_ID, 0, 0, 0 },
{ 0x203F, 0xd500, KA_PCI_ANY_ID, KA_PCI_ANY_ID, 0, 0, 0 },
{ 0x20C6, 0xd802, KA_PCI_ANY_ID, KA_PCI_ANY_ID, 0, 0, 0 },
{ 0x203F, 0xd802, KA_PCI_ANY_ID, KA_PCI_ANY_ID, 0, 0, 0 },
{ 0x20E9, 0xd802, KA_PCI_ANY_ID, KA_PCI_ANY_ID, 0, 0, 0 },
{ 0x20E9, 0xd500, KA_PCI_ANY_ID, KA_PCI_ANY_ID, 0, 0, 0 },
{}};
KA_MODULE_DEVICE_TABLE(pci, g_vmngh_tbl);
ka_mutex_t g_vmngh_pci_mutex;
u32 procfs_valid;
u32 g_max_msix_num;
u32 g_max_pass_to_vm_msix_num;
#define VMNGH_VF_SRIOV_MDEV_MODE 0
#define VMNGH_PF_MDEV_MODE 1
#define VMNGH_VF_MDEV_MODE 2
STATIC inline u32 vmngh_get_fid_for_host(struct vdavinci_dev *vdev)
{
return vdev->fid + 1;
}
static inline u32 vmngh_get_dtype_by_aicore(unsigned int aicore_num)
{
return (u32)(__builtin_clz((u32)KA_BASE_BIT(0)) - __builtin_clz(aicore_num));
}
STATIC int vmngh_ctrl_msg_send(u32 devid, void *data, u32 in_data_len, u32 out_data_len, u32 *real_out_len)
{
return devdrv_common_msg_send(devid, data, in_data_len, out_data_len, real_out_len, DEVDRV_COMMON_MSG_VMNG);
}
int vmngh_vdev_msg_send(struct vmng_ctrl_msg_info *info, int msg_type)
{
struct vmng_ctrl_msg msg = { 0 };
int ret;
u32 len = 0;
if (info == NULL) {
vmng_err("Param NULL\n");
return VMNG_ERR;
}
ret = memcpy_s(&msg.info_msg, sizeof(struct vmng_ctrl_msg_info), info, sizeof(struct vmng_ctrl_msg_info));
if (ret != EOK) {
vmng_err("Call memcpy_s err.(dev_id=%u; vfid=%u; msg_type=%d)\n", info->dev_id, info->vfid, msg_type);
return ret;
}
msg.type = msg_type;
ret = vmngh_ctrl_msg_send(info->dev_id, (void *)&msg, sizeof(msg), sizeof(msg), &len);
if ((ret != VMNG_OK) || (len != sizeof(msg)) || (msg.error_code != VMNG_OK)) {
vmng_err("Send message failed. (dev_id=%d; vfid=%d; ret=%d; len=%u; error_code=%d)\n", info->dev_id, info->vfid,
ret, len, msg.error_code);
return ret != 0 ? ret : msg.error_code;
}
ret = memcpy_s(info, sizeof(struct vmng_ctrl_msg_info), &msg.info_msg, sizeof(struct vmng_ctrl_msg_info));
if (ret != EOK) {
vmng_err("Call memcpy_s err.(dev_id=%d; vfid=%d)\n", info->dev_id, info->vfid);
return ret;
}
return VMNG_OK;
}
int vmngh_add_mia_dev(u32 dev_id, u32 vfid, u32 agent_flag)
{
struct uda_dev_type type;
struct uda_dev_para para;
struct uda_mia_dev_para mia_para;
enum uda_dev_prop prop = devdrv_is_sriov_support(dev_id) ? UDA_REAL : UDA_VIRTUAL;
enum uda_dev_object object = (agent_flag == 0) ? UDA_ENTITY : UDA_AGENT;
u32 udevid = dev_id;
ka_device_t *dev = NULL;
int ret;
if (devdrv_is_sriov_support(dev_id)) {
(void)devdrv_get_devid_by_pfvf_id(dev_id, vfid, &udevid);
dev = devdrv_base_comm_get_device(dev_id, vfid, udevid);
if (dev == NULL) {
vmng_err("Get uda device failed. (devid=%u;vfid=%u;udevid=%u)\n", dev_id, vfid, udevid);
return -EINVAL;
}
}
uda_dev_type_pack(&type, UDA_DAVINCI, object, UDA_NEAR, prop);
uda_mia_dev_para_pack(&mia_para, dev_id, vfid - 1);
if (agent_flag == 0) {
uda_dev_para_pack(¶, UDA_INVALID_UDEVID, UDA_INVALID_UDEVID, uda_get_chip_type(dev_id), dev);
ret = uda_add_mia_dev(&type, ¶, &mia_para, &udevid);
} else {
(void)uda_mia_devid_to_udevid(&mia_para, &udevid);
uda_dev_para_pack(¶, udevid, UDA_INVALID_UDEVID, uda_get_chip_type(dev_id), dev);
ret = uda_add_dev(&type, ¶, &udevid);
}
if (ret != 0) {
vmng_err("Add uda mia device failed.(dev_id=%u; vfid=%u; ret=%d; agent_flag=%u)\n",
dev_id, vfid, ret, agent_flag);
return ret;
}
return 0;
}
int vmngh_remove_mia_dev(u32 dev_id, u32 vfid, u32 agent_flag)
{
struct uda_dev_type type;
struct uda_mia_dev_para mia_para;
enum uda_dev_prop prop = devdrv_is_sriov_support(dev_id) ? UDA_REAL : UDA_VIRTUAL;
enum uda_dev_object object = (agent_flag == 0) ? UDA_ENTITY : UDA_AGENT;
u32 udevid;
int ret;
uda_mia_dev_para_pack(&mia_para, dev_id, vfid - 1);
ret = uda_mia_devid_to_udevid(&mia_para, &udevid);
if (ret != 0) {
vmng_err("Get udevid failed.(dev_id=%u; vfid=%u; ret=%d)\n", dev_id, vfid, ret);
return ret;
}
uda_dev_type_pack(&type, UDA_DAVINCI, object, UDA_NEAR, prop);
ret = uda_remove_dev(&type, udevid);
if (ret != 0) {
vmng_err("Remove uda mia device failed.(dev_id=%u; vfid=%u; ret=%d)\n", dev_id, vfid, ret);
return ret;
}
return 0;
}
STATIC int vmngh_device_online(const struct vmngh_vd_dev *vd_dev)
{
int ret;
u32 dev_id = vd_dev->dev_id;
u32 vfid = vd_dev->fid;
if (vfid == 0) {
return 0;
}
if (dev_id >= ASCEND_PDEV_MAX_NUM) {
vmng_err("Input parameter is error. (dev_id=%d)\n", dev_id);
return VMNG_ERR;
}
if (vmngh_get_device_status(dev_id) != VMNG_VALID) {
vmng_err("Device is not ready. (dev_id=%d)\n", dev_id);
return VMNG_ERR;
}
ret = vmngh_init_instance_client_device(dev_id, vfid);
if (ret != VMNG_OK) {
vmng_err("Init_instance_client_device failed. (dev_id=%u; vfid=%u)\n", dev_id, vfid);
return VMNG_ERR;
}
vmng_info("Device online. (dev_id=%u; fid=%u)\n", vd_dev->dev_id, vd_dev->fid);
return VMNG_OK;
}
STATIC void vmngh_device_offline(const struct vmngh_vd_dev *vd_dev)
{
int ret;
u32 dev_id = vd_dev->dev_id;
u32 vfid = vd_dev->fid;
if (dev_id >= ASCEND_PDEV_MAX_NUM) {
vmng_err("Input parameter is error. (dev_id=%d)\n", dev_id);
return;
}
if (vmngh_get_device_status(dev_id) != VMNG_VALID) {
vmng_err("Device is not ready. (dev_id=%d)\n", dev_id);
return;
}
ret = vmngh_uninit_instance_client_device(dev_id, vfid);
if (ret != VMNG_OK) {
vmng_err("Unnit_instance_client_device failed. (dev_id=%u; vfid=%u)\n", dev_id, vfid);
return;
}
vmng_info("Device offline. (dev_id=%u; fid=%u)\n", vd_dev->dev_id, vd_dev->fid);
}
STATIC void vmngh_admin_notify_rm_vdev(struct vmng_msg_dev *msg_dev, u32 flag)
{
struct vmng_host_rm_vdev_cmd_reply cmd;
struct vmng_tx_msg_proc_info tx_info;
u32 dev_id = msg_dev->dev_id;
u32 fid = msg_dev->fid;
u32 ret;
cmd.opcode = VMNGH_ADMIN_OPCODE_RM_VDEV;
cmd.rm_mode = flag;
cmd.finish = 0x0;
tx_info.data = &cmd;
tx_info.in_data_len = sizeof(struct vmng_host_rm_vdev_cmd_reply);
tx_info.out_data_len = sizeof(struct vmng_host_rm_vdev_cmd_reply);
tx_info.real_out_len = 0;
ret = (u32)vmng_admin_msg_send(msg_dev->admin_tx, &tx_info, (u32)VMNG_MSG_CHAN_TYPE_ADMIN,
(u32)VMNGH_ADMIN_OPCODE_RM_VDEV);
if ((ret != 0) || (tx_info.real_out_len != tx_info.out_data_len)) {
vmng_err("Message send failed. (dev_id=%u; fid=%u; out_len=%u; ret=%d)\n",
dev_id, fid, ret, tx_info.real_out_len);
return;
}
if (cmd.finish != VMNG_VM_SUSPEND_SUCCESS) {
vmng_err("Proc host stop failed. (dev_id=%u; fid=%u; ret=%d)\n", dev_id, fid, cmd.finish);
}
}
STATIC int vmngh_admin_para_check(const struct vmng_msg_dev *msg_dev,
const struct vmng_msg_chan_rx_proc_info *proc_info)
{
if (msg_dev == NULL) {
vmng_err("Input parameter is error.\n");
return -EINVAL;
}
if (proc_info == NULL) {
vmng_err("Input parameter is error. (dev_id=%u; fid=%u)\n", msg_dev->dev_id, msg_dev->fid);
return -EINVAL;
}
if (proc_info->data == NULL) {
vmng_err("Input parameter is error. (dev_id=%u; fid=%u)\n", msg_dev->dev_id, msg_dev->fid);
return -EINVAL;
}
return 0;
}
STATIC int vmngh_admin_rx_agent_rm_pdev(struct vmng_msg_dev *msg_dev, struct vmng_msg_chan_rx_proc_info *proc_info)
{
struct vmng_agent_rm_pdev_cmd_reply *cmd = NULL;
u32 dev_id;
u32 fid;
if (vmngh_admin_para_check(msg_dev, proc_info) != 0) {
vmng_err("Parameter check failed.\n");
return -EINVAL;
}
dev_id = msg_dev->dev_id;
fid = msg_dev->fid;
cmd = (struct vmng_agent_rm_pdev_cmd_reply *)proc_info->data;
if ((cmd->rm_mode == VMNG_VM_SHUTDOWN_WAIT) || (cmd->rm_mode == VMNG_VM_REMOVE_WAIT)) {
vmng_info("Agent vdevice remove or shutdown. (dev_id=%u; fid=%u; rm_mode=0x%x)\n", dev_id, fid, cmd->rm_mode);
vmngh_host_stop(dev_id, fid);
*(proc_info->real_out_len) = sizeof(struct vmng_agent_rm_pdev_cmd_reply);
cmd->finish = VMNG_VM_SUSPEND_SUCCESS;
return 0;
} else {
cmd->finish = 0;
return -1;
}
}
STATIC int vmngh_vdev_start_check(const struct vmngh_vd_dev *vd_dev)
{
u32 dev_id = vd_dev->dev_id;
u32 fid = vd_dev->fid;
if (vmngh_get_ctrl_startup_flag(dev_id, fid) != VMNG_STARTUP_TOP_HALF_OK) {
vmng_err("Top half not finish. (dev_id=%u; fid=%u)\n", dev_id, fid);
return -EINVAL;
}
if (vd_dev->shr_para->start_flag != VMNG_VM_START_WAIT) {
vmng_err("start_flag is error. (dev_id=%u; fid=%u; start_flag=0x%x)\n",
dev_id, fid, vd_dev->shr_para->start_flag);
return -EINVAL;
}
return 0;
}
STATIC int vmngh_vdev_prepare(struct vmngh_vd_dev *vd_dev)
{
u32 dev_id = vd_dev->dev_id;
u32 fid = vd_dev->fid;
int ret;
ret = vmngh_vdev_start_check(vd_dev);
if (ret != 0) {
vmng_err("Start check failed. (dev_id=%u; fid=%u; ret=%d)\n", dev_id, fid, ret);
goto directly_out;
}
vmng_info("Start check ok. (dev_id=%u; fid=%u)\n", dev_id, fid);
ret = vmngh_prepare_msg_chan(vd_dev->msg_dev);
if (ret != 0) {
vmng_err("Prepare msg chans error. (dev_id=%u; fid=%u; pid=%u)\n", dev_id, fid, vd_dev->vm_pid);
goto directly_out;
}
vd_dev->agent_device = vd_dev->shr_para->agent_device;
vd_dev->agent_bdf = vd_dev->shr_para->agent_bdf;
vd_dev->agent_dev_id = vd_dev->shr_para->agent_dev_id;
if (vd_dev->agent_dev_id >= ASCEND_PDEV_MAX_NUM) {
vmng_err("Trans virt devid error. (dev_id=%u; fid=%u; pid=%u)\n", dev_id, fid, vd_dev->vm_pid);
vmngh_unprepare_msg_chan(vd_dev->msg_dev);
return -EINVAL;
}
ret = vmngh_alloc_vm_id(dev_id, fid, vd_dev->vm_pid, vd_dev->agent_dev_id);
if (ret != 0) {
vmng_err("Alloc vm id failed. (dev_id=%u; fid=%u; pid=%u)\n", dev_id, fid, vd_dev->vm_pid);
goto unprepare_msg_chan;
}
vmngh_ctrl_register_half(vd_dev);
vd_dev->vm_id = (u32)vmngh_ctrl_get_vm_id(dev_id, fid);
return 0;
unprepare_msg_chan:
vmngh_unprepare_msg_chan(vd_dev->msg_dev);
directly_out:
return ret;
}
STATIC void vmngh_vdev_unprepare(struct vmngh_vd_dev *vd_dev)
{
vmngh_ctrl_unregister_half(vd_dev);
vmngh_ctrl_rm_vm_id(vd_dev->dev_id, vd_dev->fid, vd_dev->agent_dev_id);
vmngh_unprepare_msg_chan(vd_dev->msg_dev);
}
STATIC int vmngh_notify_vdev_probe_bottom_half(struct vmngh_vd_dev *vd_dev)
{
struct vmngh_start_dev *start_dev = &(vd_dev->start_dev);
u32 msix_offset;
int ret;
vd_dev->shr_para->dtype = (u32)vd_dev->dtype.type;
vd_dev->shr_para->start_flag = VMNG_VM_START_SUCCESS;
ka_wmb();
msix_offset = vd_dev->shr_para->msix_offset;
ret = hw_dvt_hypervisor_inject_msix(vd_dev->vdavinci, start_dev->msix_irq + msix_offset);
if (ret != 0) {
vmng_err("Notify vm start half probe failed. (devid=%u; fid=%u; ret=%d)\n", vd_dev->dev_id, vd_dev->fid, ret);
return -EIO;
}
return 0;
}
STATIC int vmngh_vm_add_dev(u32 dev_id, u32 vfid)
{
int ret;
ret = vmngh_add_mia_dev(dev_id, vfid, 0);
if (ret != 0) {
vmng_err("Add entity failed. (devid=%u; vfid=%u; ret=%d)\n", dev_id, vfid, ret);
return ret;
}
ret = vmngh_add_mia_dev(dev_id, vfid, 1);
if (ret != 0) {
(void)vmngh_remove_mia_dev(dev_id, vfid, 0);
vmng_err("Add agent failed. (devid=%u; vfid=%u; ret=%d)\n", dev_id, vfid, ret);
return ret;
}
return 0;
}
STATIC void vmngh_vm_remove_dev(u32 dev_id, u32 vfid)
{
(void)vmngh_remove_mia_dev(dev_id, vfid, 1);
(void)vmngh_remove_mia_dev(dev_id, vfid, 0);
}
STATIC int vmngh_add_sec_eh_dev(u32 dev_id, u32 vfid)
{
struct uda_dev_type type;
struct uda_dev_para para;
struct uda_mia_dev_para mia_para;
u32 udevid = dev_id;
if (devdrv_is_sriov_support(dev_id)) {
(void)devdrv_get_devid_by_pfvf_id(dev_id, vfid, &udevid);
}
uda_dev_type_pack(&type, UDA_DAVINCI, UDA_ENTITY, UDA_NEAR, UDA_REAL_SEC_EH);
uda_dev_para_pack(¶, UDA_INVALID_UDEVID,
UDA_INVALID_UDEVID, uda_get_chip_type(dev_id),
devdrv_base_comm_get_device(dev_id, vfid, udevid));
uda_mia_dev_para_pack(&mia_para, dev_id, vfid - 1);
return uda_add_mia_dev(&type, ¶, &mia_para, &udevid);
}
STATIC void vmngh_remove_sec_eh_dev(u32 dev_id, u32 vfid)
{
struct uda_dev_type type;
struct uda_mia_dev_para mia_para;
u32 udevid;
int ret;
uda_mia_dev_para_pack(&mia_para, dev_id, vfid - 1);
ret = uda_mia_devid_to_udevid(&mia_para, &udevid);
if (ret != 0) {
vmng_err("Get udevid failed.(dev_id=%u; vfid=%u; ret=%d)\n", dev_id, vfid, ret);
return;
}
uda_dev_type_pack(&type, UDA_DAVINCI, UDA_ENTITY, UDA_NEAR, UDA_REAL_SEC_EH);
(void)uda_remove_dev(&type, udevid);
}
STATIC int vmngh_service_online(struct vmngh_vd_dev *vd_dev)
{
u32 dev_id = vd_dev->dev_id;
u32 fid = vd_dev->fid;
int ret;
if ((dev_id >= ASCEND_PDEV_MAX_NUM) || (fid >= VMNG_VDEV_MAX_PER_PDEV) || (fid == 0)) {
vmng_err("dev_id is invalid. (dev_id=%d;fid=%u)\n", dev_id, fid);
return -EINVAL;
}
if (devdrv_is_sriov_support(dev_id)) {
ret = vmngh_device_online(vd_dev);
if (ret != 0) {
vmng_err("Agent online failed. (devid=%u; fid=%u; ret=%d)\n", dev_id, fid, ret);
return ret;
}
ret = vmngh_ctrl_sriov_init_instance(dev_id, fid);
if (ret != 0) {
vmng_err("Init pcie initstance failed. (ret=%d;dev_id=%u)\n", ret, dev_id);
vmngh_device_offline(vd_dev);
return ret;
}
ret = vmngh_add_sec_eh_dev(dev_id, fid);
if (ret != 0) {
(void)vmngh_ctrl_sriov_uninit_instance(dev_id, fid);
vmngh_device_offline(vd_dev);
return ret;
}
ret = vmngh_init_instance_after_probe(dev_id, fid);
if (ret != 0) {
vmng_err("Init instance all client failed. (devid=%u; fid=%u; ret=%d)\n", dev_id, fid, ret);
vmngh_remove_sec_eh_dev(dev_id, fid);
vmngh_ctrl_sriov_uninit_instance(dev_id, fid);
vmngh_device_offline(vd_dev);
return ret;
}
} else {
ret = vmngh_vm_add_dev(dev_id, fid);
if (ret != 0) {
return ret;
}
ret = vmngh_init_instance_after_probe(dev_id, fid);
if (ret != 0) {
vmng_err("Init instance all client failed. (devid=%u; fid=%u; ret=%d)\n", dev_id, fid, ret);
vmngh_vm_remove_dev(dev_id, fid);
return ret;
}
ret = vmngh_device_online(vd_dev);
if (ret != 0) {
vmng_err("Agent online failed. (devid=%u; fid=%u; ret=%d)\n", dev_id, fid, ret);
(void)vmngh_uninit_instance_remove_vdev(dev_id, fid);
vmngh_vm_remove_dev(dev_id, fid);
return ret;
}
}
return 0;
}
STATIC void vmngh_service_offline(struct vmngh_vd_dev *vd_dev)
{
u32 dev_id = vd_dev->dev_id;
u32 fid = vd_dev->fid;
int ret;
if ((dev_id >= ASCEND_PDEV_MAX_NUM) || (fid >= VMNG_VDEV_MAX_PER_PDEV) || (fid == 0)) {
vmng_err("dev_id is invalid. (dev_id=%d;fid=%u)\n", dev_id, fid);
return;
}
if (devdrv_is_sriov_support(dev_id)) {
ret = vmngh_uninit_instance_remove_vdev(vd_dev->dev_id, vd_dev->fid);
if (ret != 0) {
vmng_err("Uninit instance remove vdev failed. (ret=%d)\n", ret);
}
vmngh_remove_sec_eh_dev(dev_id, fid);
ret = vmngh_ctrl_sriov_uninit_instance(dev_id, fid);
if (ret != 0) {
vmng_err("Uninit pcie initstance failed. (ret=%d;dev_id=%u)\n", ret, dev_id);
}
vmngh_device_offline(vd_dev);
} else {
vmngh_device_offline(vd_dev);
ret = vmngh_uninit_instance_remove_vdev(vd_dev->dev_id, vd_dev->fid);
if (ret != 0) {
vmng_err("Uninit instance remove vdev failed. (ret=%d)\n", ret);
}
vmngh_vm_remove_dev(dev_id, fid);
}
return;
}
STATIC int vmngh_vdev_feature(struct vmngh_vd_dev *vd_dev)
{
u32 dev_id = vd_dev->dev_id;
u32 fid = vd_dev->fid;
int ret;
ret = vmngh_service_online(vd_dev);
if (ret != 0) {
vmng_err("Init instance failed. (dev_id=%u;fid=%u;ret=%d)\n", dev_id, fid, ret);
return ret;
}
vmng_info("Init instance ok. (devid=%u; fid=%u)\n", dev_id, fid);
ret = vmngh_notify_vdev_probe_bottom_half(vd_dev);
if (ret != 0) {
vmng_err("Notify vdev start probe bottom half failed. (dev_id=%u; fid=%u; ret=%d)\n", dev_id, fid, ret);
goto uninit_instance;
}
return 0;
uninit_instance:
vmngh_service_offline(vd_dev);
return ret;
}
STATIC int vmngh_vdev_unfeature(struct vmngh_vd_dev *vd_dev)
{
vmngh_service_offline(vd_dev);
return 0;
}
static void vmngh_start_timer_task(ka_timer_list_t *t)
{
struct vmngh_start_dev *start_dev = ka_system_from_timer(start_dev, t, wd_timer);
struct vmngh_vd_dev *vd_dev = ka_container_of(start_dev, struct vmngh_vd_dev, start_dev);
u32 dev_id = vd_dev->dev_id;
u32 fid = vd_dev->fid;
if (ka_base_atomic_read(&start_dev->start_flag) == VMNG_TASK_SUCCESS) {
vmng_info("Startup success, timer close. (devid=%u; fid=%u)\n", dev_id, fid);
return;
}
if (start_dev->timer_remain > 0) {
start_dev->timer_remain--;
start_dev->wd_timer.expires = ka_jiffies + start_dev->timer_cycle;
ka_system_add_timer(&(start_dev->wd_timer));
vmng_debug("Startup timer rebuild. (devid=%u; fid=%u)\n", dev_id, fid);
} else {
vmng_warn("Startup timeout. (devid=%u; fid=%u)\n", dev_id, fid);
ka_base_atomic_set(&start_dev->start_flag, VMNG_TASK_TIMEOUT);
}
}
STATIC void vmngh_set_start_timer(struct vmngh_vd_dev *vd_dev)
{
struct vmngh_start_dev *start_dev = &(vd_dev->start_dev);
start_dev->timer_remain = VMNG_START_TIMER_OUT;
start_dev->timer_cycle = VMNG_START_TIMER_CYCLE;
ka_system_timer_setup(&start_dev->wd_timer, vmngh_start_timer_task, 0);
start_dev->wd_timer.expires = ka_jiffies + start_dev->timer_cycle;
ka_system_add_timer(&(start_dev->wd_timer));
}
STATIC void vmngh_del_start_timer(struct vmngh_vd_dev *vd_dev)
{
if (vd_dev->start_dev.timer_cycle != 0) {
ka_system_del_timer_sync(&vd_dev->start_dev.wd_timer);
vd_dev->start_dev.timer_cycle = 0;
vmng_info("Delete start timer. (devid=%u; fid=%u)\n", vd_dev->dev_id, vd_dev->fid);
}
}
#define MAX_PCIE_MSIX_NUM 64
#define MAX_PASS_TO_VM_MSIX_NUM 44
STATIC ka_irqreturn_t msi_inject_interrupt(int irq, void *data)
{
struct vm_msix_struct *vm_msix = (struct vm_msix_struct *)data;
int ret;
if ((vm_msix == NULL) || (vm_msix->vdavinci == NULL)) {
vmng_err("Vdavinci is null. (irq=%d)\n", irq);
return KA_IRQ_NONE;
}
if (((u32)vm_msix->irq_vector >= g_max_pass_to_vm_msix_num) || (vm_msix->irq_vector < 0)) {
vmng_err("Invalid irq vector. (vector=%d, irq=%d)\n", vm_msix->irq_vector, irq);
return KA_IRQ_NONE;
}
ret = hw_dvt_hypervisor_inject_msix(vm_msix->vdavinci, (u32)vm_msix->irq_vector);
if (ret != 0) {
vmng_err("Inject msix irq fail.(irq=%d;vector=%d;ret=%d)\n", irq, vm_msix->irq_vector, ret);
return KA_IRQ_NONE;
}
return KA_IRQ_HANDLED;
}
int vmngh_hypervisor_inject_msix(unsigned int dev_id, unsigned int irq_vector)
{
struct uda_mia_dev_para mia_para;
void *vdavinci;
int ret;
ret = uda_udevid_to_mia_devid(dev_id, &mia_para);
if (ret != 0) {
return ret;
}
vdavinci = vmngh_get_vdavinci_by_id(mia_para.phy_devid, mia_para.sub_devid + 1);
if (vdavinci == NULL) {
return -EINVAL;
}
return hw_dvt_hypervisor_inject_msix(vdavinci, irq_vector);
}
KA_EXPORT_SYMBOL(vmngh_hypervisor_inject_msix);
STATIC int vmngh_passthrough_msix_irq_to_vm(unsigned int dev_id, struct vmngh_vd_dev *vd_dev)
{
struct vm_msix_struct *vm_msix;
ka_pci_dev_t *pdev;
int ret;
int irq;
int i;
pdev = hal_kernel_devdrv_get_pci_pdev_by_devid(dev_id);
if (pdev == NULL) {
vmng_err("pdev is NULL.\n");
return -EINVAL;
}
vm_msix = vmng_kzalloc(sizeof(struct vm_msix_struct) * g_max_msix_num, KA_GFP_KERNEL);
if (vm_msix == NULL) {
vmng_err("Alloc vm msix failed. (dev_id=%u;vfid=%u)\n", vd_dev->dev_id, vd_dev->fid);
return -ENOMEM;
}
vd_dev->vm_msix = vm_msix;
for (i = 0; (u32)i < g_max_pass_to_vm_msix_num; i++) {
vm_msix[i].vdavinci = vd_dev->vdavinci;
vm_msix[i].irq_vector = i;
ka_pci_irq_vector(pdev, (u32)i, dev_id, (u32 *)&irq, devdrv_get_irq_vector);
ret = ka_system_request_irq((u32)irq, msi_inject_interrupt, 0, "msix_inject", vm_msix + i);
if (ret < 0) {
vmng_err("request irq failed, ret : %d\n", ret);
goto failed;
}
}
return 0;
failed:
for (--i; i >= 0; --i) {
ka_pci_irq_vector(pdev, (u32)i, dev_id, (u32 *)&irq, devdrv_get_irq_vector);
ka_system_free_irq(irq, vm_msix + i);
}
vmng_kfree(vm_msix);
vd_dev->vm_msix = NULL;
return ret;
}
STATIC void vmngh_release_passthrough_to_vm_msix_irq(unsigned int dev_id, struct vmngh_vd_dev *vd_dev)
{
ka_pci_dev_t *pdev;
int irq;
u32 i;
pdev = hal_kernel_devdrv_get_pci_pdev_by_devid(dev_id);
if (pdev == NULL) {
vmng_err("pdev is NULL.\n");
return;
}
for (i = 0; i < g_max_pass_to_vm_msix_num; i++) {
ka_pci_irq_vector(pdev, (u32)i, dev_id, (u32 *)&irq, devdrv_get_irq_vector);
(void)ka_system_free_irq((u32)irq, vd_dev->vm_msix + i);
}
vmng_kfree(vd_dev->vm_msix);
vd_dev->vm_msix = NULL;
}
STATIC void vmngh_disable_pcie_feature(struct vmngh_vd_dev *vd_dev)
{
struct vmng_ctrl_msg msg = {0};
u32 dev_id;
u32 len;
int ret;
if (devdrv_is_sriov_support(vd_dev->dev_id) == false) {
return;
}
ret = devdrv_get_devid_by_pfvf_id(vd_dev->dev_id, vd_dev->fid, &dev_id);
if (ret != 0) {
vmng_err("Get devid by pfvf id failed. (ret=%d;dev_id=%u;fid=%u)\n", ret, vd_dev->dev_id, vd_dev->fid);
return;
}
msg.type = VMNG_CTRL_MSG_TYPE_IOVA_INFO;
msg.info_msg.vfid = vd_dev->fid;
msg.info_msg.iova_info.vfid = vd_dev->fid;
msg.info_msg.iova_info.action = VMNG_INSTANCE_FLAG_UNINIT;
(void)vmngh_ctrl_msg_send(vd_dev->dev_id, (void *)&msg, sizeof(msg), sizeof(msg), &len);
(void)devdrv_mdev_set_pm_iova_addr_range(dev_id, (ka_dma_addr_t)0, (size_t)0);
vmngh_release_passthrough_to_vm_msix_irq(dev_id, vd_dev);
devdrv_mdev_pm_uninit_msi_interrupt(dev_id);
devdrv_mdev_free_vf_dma_sqcq_on_pm(dev_id);
return;
}
STATIC int vmngh_enable_pcie_feature(struct vmngh_vd_dev *vd_dev)
{
struct vmng_ctrl_msg msg = {0};
u32 dev_id;
u32 len;
int ret;
if (devdrv_is_sriov_support(vd_dev->dev_id) == false) {
return 0;
}
ret = devdrv_get_devid_by_pfvf_id(vd_dev->dev_id, vd_dev->fid, &dev_id);
if (ret != 0) {
vmng_err("Get devid by pfvf id failed. (ret=%d;dev_id=%u;fid=%u)\n", ret, vd_dev->dev_id, vd_dev->fid);
return ret;
}
ret = devdrv_mdev_pm_init_msi_interrupt(dev_id);
if (ret != 0) {
vmng_err("PCI-e alloc msix irq failed. (ret=%d;dev_id=%u)\n", ret, dev_id);
return ret;
}
ret = vmngh_passthrough_msix_irq_to_vm(dev_id, vd_dev);
if (ret != 0) {
vmng_err("Passthrough msix irq to vm failed. (ret=%d;dev_id=%u)\n", ret, dev_id);
devdrv_mdev_pm_uninit_msi_interrupt(dev_id);
return ret;
}
ret = hw_dvt_hypervisor_get_reserve_iova(vd_dev->resource_dev, &vd_dev->iova_addr, &vd_dev->size);
if (ret != 0) {
vmngh_release_passthrough_to_vm_msix_irq(dev_id, vd_dev);
devdrv_mdev_pm_uninit_msi_interrupt(dev_id);
vmng_err("Get iova reserver failed. (dev_id=%u;ret=%d)\n", dev_id, ret);
return ret;
}
ret = devdrv_mdev_set_pm_iova_addr_range(dev_id, vd_dev->iova_addr, vd_dev->size);
if (ret != 0) {
vmngh_release_passthrough_to_vm_msix_irq(dev_id, vd_dev);
devdrv_mdev_pm_uninit_msi_interrupt(dev_id);
vmng_err("Set iova info to pcie failed.(vdev_id=%u;ret=%d)\n", dev_id, ret);
return ret;
}
msg.type = VMNG_CTRL_MSG_TYPE_IOVA_INFO;
#ifndef DRV_UT
msg.info_msg.vfid = vd_dev->fid;
#endif
msg.info_msg.iova_info.vfid = vd_dev->fid;
msg.info_msg.iova_info.iova_base = vd_dev->iova_addr;
msg.info_msg.iova_info.size = vd_dev->size;
msg.info_msg.iova_info.action = VMNG_INSTANCE_FLAG_INIT;
ret = vmngh_ctrl_msg_send(vd_dev->dev_id, (void *)&msg, sizeof(msg), sizeof(msg), &len);
if ((ret != VMNG_OK) || (len != sizeof(msg)) || (msg.error_code != VMNG_OK)) {
vmng_err("Send iova msg to device failed.(ret=%d;error_code=%d)\n", ret, msg.error_code);
devdrv_mdev_set_pm_iova_addr_range(dev_id, (ka_dma_addr_t)0, 0);
vmngh_release_passthrough_to_vm_msix_irq(dev_id, vd_dev);
devdrv_mdev_pm_uninit_msi_interrupt(dev_id);
return VMNG_ERR;
}
return 0;
}
STATIC void vmngh_vdev_create_bottom(ka_work_struct_t *p_work)
{
struct vmngh_vd_dev *vd_dev = ka_container_of(p_work, struct vmngh_vd_dev, start_work);
int ret;
u32 dev_id = vd_dev->dev_id;
u32 fid = vd_dev->fid;
vd_dev->dfx.create_bottom_cnt++;
vmng_info("Get create_bottom_cnt. (dev_id=%u; fid=%u; dtype=%u; agent_dev_id=%u; create_bottom_cnt=%u)\n",
dev_id, fid, vd_dev->dtype.type, vd_dev->shr_para->agent_dev_id, vd_dev->dfx.create_bottom_cnt);
if ((dev_id >= ASCEND_PDEV_MAX_NUM) || (fid >= VMNG_VDEV_MAX_PER_PDEV)) {
vmng_err("dev_id is invalid. (dev_id=%d;fid=%u)\n", dev_id, fid);
return;
}
if (ka_base_atomic_read(&vd_dev->reset_ref_flag) != VMNGH_MDEV_FLR_STATE) {
ret = hw_dvt_hypervisor_dma_pool_init(vd_dev->vdavinci);
if (ret != 0) {
vmng_err("Dma pool init failed. (dev_id=%u; fid=%u; ret=%d)\n", dev_id, fid, ret);
goto directly_out;
}
} else {
vmng_info("Skip dma pool init in flr process. (dev_id=%u; fid=%u)\n", dev_id, fid);
}
ret = vmngh_enable_pcie_feature(vd_dev);
if (ret != 0) {
vmng_err("enable pcie msix inject failed. (dev_id=%u; fid=%u; ret=%d)\n", dev_id, fid, ret);
goto dma_pool_uninit;
}
ret = vmngh_vdev_prepare(vd_dev);
if (ret != 0) {
vmng_err("Prepara vdev failed. (dev_id=%u; fid=%u; ret=%d)\n", dev_id, fid, ret);
goto msix_disable;
}
ret = vmngh_vdev_feature(vd_dev);
if (ret != 0) {
vmng_err("Initialize feature failed. (dev_id=%u; fid=%u; ret=%d)\n", dev_id, fid, ret);
goto vdev_unprepare;
}
if (devdrv_is_sriov_support(dev_id) == false) {
ret = vmngh_bw_set_token_limit(dev_id, fid);
if (ret != 0) {
vmng_err("Set bandwidth limit failed. (dev_id=%u; fid=%u; ret=%d)\n", dev_id, fid, ret);
goto vdev_unprepare;
}
vmngh_bw_data_clear_timer_init(dev_id, fid);
}
vd_dev->init_status = VMNG_STARTUP_BOTTOM_HALF_OK;
ka_base_atomic_set(&vd_dev->reset_ref_flag, VMNGH_MDEV_RUNNING_STATE);
vmng_info("Bottom create success. (dev_id=%u; fid=%u)\n", dev_id, fid);
return;
vdev_unprepare:
vmngh_vdev_unprepare(vd_dev);
msix_disable:
vmngh_disable_pcie_feature(vd_dev);
dma_pool_uninit:
if (ka_base_atomic_read(&vd_dev->reset_ref_flag) != VMNGH_MDEV_FLR_STATE) {
hw_dvt_hypervisor_dma_pool_uninit(vd_dev->vdavinci);
}
ka_base_atomic_set(&vd_dev->reset_ref_flag, VMNGH_MDEV_RUNNING_STATE);
directly_out:
vmng_err("Create half bottom failed. (dev_id=%u; fid=%u)\n", dev_id, fid);
return;
}
STATIC int vmngh_vdev_free_bottom(struct vmngh_vd_dev *vd_dev)
{
u32 dev_id = vd_dev->dev_id;
u32 fid = vd_dev->fid;
vmng_info("Free bottom begin. (dev_id=%u; fid=%u)\n", dev_id, fid);
vmngh_bw_data_clear_timer_uninit();
vd_dev->init_status = VMNG_STARTUP_TOP_HALF_OK;
(void)vmngh_vdev_unfeature(vd_dev);
vmngh_vdev_unprepare(vd_dev);
vmngh_disable_pcie_feature(vd_dev);
if (ka_base_atomic_read(&vd_dev->reset_ref_flag) != VMNGH_MDEV_FLR_STATE) {
hw_dvt_hypervisor_dma_pool_uninit(vd_dev->vdavinci);
vmng_info("Dma pool uninit end. (dev_id=%u; fid=%u)\n", dev_id, fid);
} else {
vmng_info("Skip dma pool uninit in flr process. (dev_id=%u; fid=%u)\n", dev_id, fid);
}
vmngh_del_start_timer(vd_dev);
vmngh_ctrl_set_startup_flag(vd_dev->dev_id, vd_dev->fid, VMNG_STARTUP_TOP_HALF_OK);
ka_base_atomic_set(&(vd_dev->start_dev.start_flag), VMNG_TASK_WAIT);
vmng_info("Free bottom finish. (dev_id=%u; fid=%u)\n", dev_id, fid);
return 0;
}
static void vmngh_wait_vm_start(struct vmngh_vd_dev *vd_dev)
{
KA_TASK_INIT_WORK(&vd_dev->start_work, vmngh_vdev_create_bottom);
ka_base_atomic_set(&(vd_dev->start_dev.start_flag), VMNG_TASK_WAIT);
}
static void vmngh_start_exit(struct vmngh_vd_dev *vd_dev)
{
if (vd_dev->start_work.func != NULL) {
ka_task_cancel_work_sync(&vd_dev->start_work);
}
}
static struct vmngh_vd_dev *vmngh_alloc_vdev(u32 fid, void *vdavinci, struct vmngh_pci_dev *vm_pdev,
struct vdavinci_type *vd_type, ka_uuid_le_t uuid)
{
struct vmngh_vd_dev *vd_dev = NULL;
int ret;
if (vm_pdev->vd_dev[fid] != NULL) {
vmng_err("Input parameter is error. (dev_id=%u; fid=%u)\n", vm_pdev->dev_id, fid);
return NULL;
}
vd_dev = vmng_kzalloc(sizeof(struct vmngh_vd_dev), KA_GFP_KERNEL);
if (vd_dev == NULL) {
vmng_err("Alloc device failed. (dev_id=%u; fid=%u)\n", vm_pdev->dev_id, fid);
return NULL;
}
vd_dev->vm_pdev = vm_pdev;
vd_dev->fid = fid;
vd_dev->vdavinci = vdavinci;
vd_dev->dev_id = vm_pdev->dev_id;
vd_dev->vascend_uuid = uuid;
ret = memcpy_s((void *)(&vd_dev->dtype), sizeof(struct vdavinci_type),
(void *)vd_type, sizeof(struct vdavinci_type));
if (ret != 0) {
vmng_err("Call memcpy failed. (dev_id=%u; fid=%u)\n", vm_pdev->dev_id, fid);
goto free_vd_dev;
}
vd_dev->dtype.template_name[HW_DVT_MAX_TYPE_NAME - 1] = '\0';
vd_dev->dtype.type = (int)vmngh_get_dtype_by_aicore(vd_type->aicore_num);
ret = hw_dvt_hypervisor_mmio_get(&vd_dev->mm_res.io_base, &vd_dev->mm_res.io_size, vdavinci, IO_REGION_INDEX);
if ((ret != 0) || (vd_dev->mm_res.io_base == NULL)) {
vmng_err("Hypervisor get bar2 failed. (dev_id=%u; fid=%u)\n", vm_pdev->dev_id, fid);
goto free_vd_dev;
}
ret = hw_dvt_hypervisor_mmio_get(&vd_dev->mm_res.mem_base, &vd_dev->mm_res.mem_size, vdavinci, MEM_REGION_INDEX);
if ((ret != 0) || (vd_dev->mm_res.mem_base == NULL)) {
vmng_err("Hypervisor get bar4 failed. (dev_id=%u; fid=%u)", vm_pdev->dev_id, fid);
goto free_vd_dev;
}
vd_dev->shr_para = (struct vmng_shr_para *)vd_dev->mm_res.io_base + VMNG_SHR_PARA_ADDR_BASE;
vd_dev->shr_para->dtype = (u32)vd_type->type;
if (vm_pdev->vm_full_spec_enable) {
vd_dev->shr_para->aicore_num = vm_pdev->dev_info.aicore_num;
} else {
vd_dev->shr_para->aicore_num = vd_type->aicore_num;
}
vd_dev->shr_para->hbmmem_size = vd_type->hbmmem_size;
vd_dev->shr_para->ddrmem_size = vd_type->ddrmem_size;
ka_base_atomic_set(&vd_dev->reset_ref_flag, VMNGH_MDEV_RUNNING_STATE);
vm_pdev->vd_dev[fid] = vd_dev;
return vd_dev;
free_vd_dev:
vmng_kfree(vd_dev);
vd_dev = NULL;
return NULL;
}
STATIC int vmngh_alloc_vpc_unit(struct vmngh_vd_dev *vd_dev)
{
struct vmngh_pci_dev *vm_pdev = vd_dev->vm_pdev;
struct vmngh_vpc_unit *vpc_unit;
vpc_unit = vmng_kzalloc(sizeof(struct vmngh_vpc_unit), KA_GFP_KERNEL);
if (vpc_unit == NULL) {
vmng_err("Kzalloc vpc unit failed.\n");
return -ENOMEM;
}
vpc_unit->vdavinci = vd_dev->vdavinci;
vpc_unit->pdev = vm_pdev->pdev;
vpc_unit->db_base = 0x0;
vpc_unit->msg_base = vd_dev->mm_res.io_base + VMNG_MSG_QUEUE_BASE;
vpc_unit->shr_para = vd_dev->shr_para;
if (devdrv_is_sriov_support(vd_dev->dev_id)) {
(void)devdrv_get_devid_by_pfvf_id(vd_dev->dev_id, vd_dev->fid, &vpc_unit->dev_id);
vpc_unit->fid = 0;
} else {
vpc_unit->dev_id = vd_dev->dev_id;
vpc_unit->fid = vd_dev->fid;
}
vd_dev->vpc_unit = vpc_unit;
return 0;
}
STATIC int vmngh_info_vpc_init(struct vmngh_vd_dev *vd_dev)
{
unsigned int dev_id;
int ret;
if (devdrv_is_sriov_support(vd_dev->dev_id) == false) {
return 0;
}
if (vd_dev->fid == 0) {
dev_id = vd_dev->dev_id;
} else {
ret = devdrv_get_devid_by_pfvf_id(vd_dev->dev_id, vd_dev->fid, &dev_id);
if (ret != 0) {
vmng_err("get dev_id by pfvf id failed. (dev_id=%u;fid=%u;ret=%d)\n",
vd_dev->dev_id, vd_dev->fid, ret);
return ret;
}
}
ret = devdrv_vpc_client_init(dev_id);
if (ret != 0) {
vmng_err("Init pcie vpc failed. (dev_id=%u;ret=%d)\n", dev_id, ret);
}
return ret;
}
STATIC int vmngh_create_base_feature(struct vmngh_vd_dev *vd_dev)
{
u32 dev_id = vd_dev->dev_id;
u32 fid = vd_dev->fid;
int ret;
ret = vmngh_alloc_vpc_unit(vd_dev);
if (ret != 0) {
vmng_err("Alloc vpc unit failed. (ret=%d)\n", ret);
goto out;
}
ret = vmngh_init_vpc_msg((void *)vd_dev->vpc_unit);
if (ret != 0) {
vmng_err("Message device init failed. (dev_id=%u; fid=%u; ret=%d)\n", dev_id, fid, ret);
goto free_vpc_unit;
}
vd_dev->msg_dev = vd_dev->vpc_unit->msg_dev;
vmngh_register_extended_common_msg_client(vd_dev->msg_dev);
ret = vmngh_alloc_external_db_entries(vd_dev);
if (ret != 0) {
vmng_err("Alloc external db failed. (dev_id=%u; fid=%u)\n", dev_id, fid);
goto unregister_extended_common_msg_client;
}
ret = vmngh_info_vpc_init(vd_dev);
if (ret != 0) {
vmng_err("Info vpc init failed. (dev_id=%u;fid=%u;ret=%d)\n", dev_id, fid, ret);
goto free_external_db_entries;
}
return 0;
free_external_db_entries:
vmngh_free_external_db_entries(vd_dev);
unregister_extended_common_msg_client:
vmngh_unregister_extended_common_msg_client(vd_dev->msg_dev);
vmngh_uninit_vpc_msg((void *)vd_dev->vpc_unit);
free_vpc_unit:
if (vd_dev->vpc_unit != NULL) {
vmng_kfree(vd_dev->vpc_unit);
vd_dev->vpc_unit = NULL;
}
out:
return ret;
}
STATIC void vmngh_destroy_base_feature(struct vmngh_vd_dev *vd_dev)
{
vmngh_free_external_db_entries(vd_dev);
vmngh_unregister_extended_common_msg_client(vd_dev->msg_dev);
vmngh_uninit_vpc_msg((void *)vd_dev->vpc_unit);
}
STATIC int vmngh_vdev_free_top(struct vmngh_vd_dev *vd_dev)
{
struct vmngh_ctrl_ops *ops = vmngh_get_ctrl_ops(vd_dev->dev_id);
u32 dev_id = vd_dev->dev_id;
u32 fid = vd_dev->fid;
vmngh_del_start_timer(vd_dev);
vmngh_start_exit(vd_dev);
if ((ops->free_vf != NULL) && (ops->free_vf(dev_id, fid) != VMNG_OK)) {
vmng_err("Send msg failed. (dev_id=%d; vfid=%d)\n", dev_id, fid);
}
vmngh_destroy_base_feature(vd_dev);
vmngh_unregister_ctrls(dev_id, fid);
vmngh_free_vdev(vd_dev);
vmng_info("Free top finish. (dev_id=%u; fid=%u)\n", dev_id, fid);
return 0;
}
STATIC int vmngh_vdev_create_para_check(const struct vdavinci_dev *vdev, const void *vdavinci,
struct vdavinci_type *type)
{
if (vdev == NULL) {
vmng_err("vdev is error.\n");
return -EINVAL;
}
if (vdev->dev == NULL) {
vmng_err("vdev->dev is error.\n");
return -EINVAL;
}
if (vdavinci == NULL) {
vmng_err("Input parameter is error. (fid=%u)\n", vdev->fid);
return -EINVAL;
}
if (type == NULL) {
vmng_err("type is NULL.\n");
return -EINVAL;
}
if (vdev->fid + 1 >= VMNG_VDEV_MAX_PER_PDEV) {
vmng_err("Input parameter is error. (fid=%u)\n", vdev->fid);
return -EINVAL;
}
return 0;
}
void vmngh_free_vdev_host_stop(u32 dev_id, u32 fid)
{
struct vmngh_vd_dev *vd_dev = NULL;
vd_dev = vmngh_get_vdev_from_unit(dev_id, fid);
if (vd_dev != NULL) {
vmngh_vdev_free_bottom(vd_dev);
}
}
#define SHARE_WITH_FOUR_DEVICES(share_num) ((share_num) == 4)
#define SHARE_WITH_TWO_DEVICES(share_num) ((share_num) == 2)
#define VMNG_SHARE_CORE_NUM 0xFFFF
STATIC int vmngh_adapt_vfresource_for_vm(struct vmng_vf_res_info *vf_resource, struct vdavinci_type *type)
{
int ret;
vf_resource->vfg.vfg_id = KA_U32_MAX;
vf_resource->stars_refresh.device_aicpu = type->aicpu_num;
if (SHARE_WITH_FOUR_DEVICES(type->share)) {
vf_resource->stars_refresh.device_aicpu = VMNG_SHARE_CORE_NUM;
} else if (SHARE_WITH_TWO_DEVICES(type->share)) {
vf_resource->stars_refresh.device_aicpu = VMNG_SHARE_CORE_NUM;
}
vf_resource->memory.size = 0;
vf_resource->stars_refresh.jpegd = type->jpegd_num;
vf_resource->stars_refresh.jpege = type->jpege_num;
vf_resource->stars_refresh.vpc = type->vpc_num;
vf_resource->stars_refresh.vdec = type->vdec_num;
vf_resource->stars_refresh.pngd = KA_U32_MAX;
vf_resource->stars_refresh.venc = type->venc_num;
ret = strcpy_s(vf_resource->name, VMNG_VF_TEMP_NAME_LEN, type->template_name);
if (ret != 0) {
vmng_err("strcpy_s failed. (ret=%d)\n", ret);
return ret;
}
return VMNG_OK;
}
STATIC void vmngh_adapt_vfresource_for_vf_vnic_support(u32 dev_id, struct vmng_vf_res_info *vf_resource)
{
struct vmngh_pci_dev *vm_pdev = NULL;
vm_pdev = vmngh_get_pdev_from_unit(dev_id);
if (vm_pdev->vm_full_spec_enable == 0) {
return;
}
vf_resource->vm_full_spec_enable = vm_pdev->vm_full_spec_enable;
vf_resource->stars_refresh.device_aicpu = vm_pdev->dev_info.aicpu_num;
vf_resource->memory.size = 0;
vf_resource->stars_refresh.jpegd = vm_pdev->dev_info.jpegd_num;
vf_resource->stars_refresh.jpege = vm_pdev->dev_info.jpege_num;
vf_resource->stars_refresh.vpc = vm_pdev->dev_info.vpc_num;
vf_resource->stars_refresh.vdec = vm_pdev->dev_info.vdec_num;
vf_resource->stars_refresh.pngd = KA_U32_MAX;
vf_resource->stars_refresh.venc = vm_pdev->dev_info.venc_num;
vf_resource->stars_static.aic = vm_pdev->dev_info.aicore_num;
memset_s(vf_resource->name, VMNG_VF_TEMP_NAME_LEN, 0, VMNG_VF_TEMP_NAME_LEN);
return;
}
STATIC int vmngh_alloc_vf(u32 dev_id, u32 fid, struct vdavinci_dev *vdev, struct vdavinci_type *type)
{
struct vmng_vf_res_info vf_resource;
struct vmngh_ctrl_ops *ops = NULL;
u32 dtype;
int ret;
if (fid == 0) {
return 0;
}
(void)memset_s(&vf_resource, sizeof(struct vmng_vf_res_info), 0, sizeof(struct vmng_vf_res_info));
vf_resource.dev_id = dev_id;
vf_resource.vfid = fid;
vf_resource.stars_static.aic = type->aicore_num;
dtype = vmngh_get_dtype_by_aicore(type->aicore_num);
ret = vmngh_adapt_vfresource_for_vm(&vf_resource, type);
if (ret != VMNG_OK) {
return ret;
}
vmngh_adapt_vfresource_for_vf_vnic_support(dev_id, &vf_resource);
ops = vmngh_get_ctrl_ops(dev_id);
if (ops->alloc_vf != NULL) {
ret = ops->alloc_vf(dev_id, &fid, dtype, &vf_resource);
if (ret != VMNG_OK) {
vmng_err("Send alloc vf msg to device failed, (ret=%d).\n", ret);
return ret;
}
}
return 0;
}
STATIC void vmngh_free_vf(u32 dev_id, u32 fid)
{
struct vmngh_ctrl_ops *ops = NULL;
ops = vmngh_get_ctrl_ops(dev_id);
if (ops->free_vf != NULL) {
(void)ops->free_vf(dev_id, fid);
}
}
STATIC int _vmngh_vdev_create(struct vdavinci_dev *vdev, void *vdavinci,
struct vdavinci_type *type, ka_uuid_le_t uuid, u32 fid)
{
struct vmngh_pci_dev *vm_pdev = NULL;
struct vmngh_vd_dev *vd_dev = NULL;
ka_pci_dev_t *pdev = NULL;
u32 dev_id;
int ret;
pdev = ka_pci_to_pci_dev(vdev->dev);
vmng_info("Create mdev through pf.\n");
dev_id = (u32)devdrv_get_dev_id_by_pdev_with_dev_index(pdev, (int)vdev->dev_index);
if (dev_id >= ASCEND_PDEV_MAX_NUM) {
vmng_err("device_id is invalid. (dev_id=%u)\n", dev_id);
return -EINVAL;
}
vm_pdev = vmngh_get_pdev_from_unit(dev_id);
vd_dev = vmngh_alloc_vdev(fid, vdavinci, vm_pdev, type, uuid);
if (vd_dev == NULL) {
vmng_err("Alloc dev failed. (dev_id=%d; fid=%u)\n", dev_id, fid);
return -ENOMEM;
}
vd_dev->init_status = VMNG_STARTUP_PROBED;
vd_dev->resource_dev = vdev->resource_dev;
ret = vmngh_alloc_vf(dev_id, fid, vdev, type);
if (ret != 0) {
vmng_err("Vm alloc vf resource failed. (ret=%d)\n", ret);
goto free_vdev;
}
ret = vmngh_register_ctrls(vd_dev);
if (ret != 0) {
vmng_err("Register ctrls failed. (dev_id=%d; fid=%u; ret=%d)\n", dev_id, fid, ret);
goto free_vf;
}
ret = vmngh_create_base_feature(vd_dev);
if (ret != 0) {
vmng_err("Create base feature error. (dev_id=%d; fid=%u; ret=%d)\n", dev_id, fid, ret);
goto unregister_ctrl;
}
vmngh_wait_vm_start(vd_dev);
vmngh_ctrl_set_startup_flag(vd_dev->dev_id, fid, VMNG_STARTUP_TOP_HALF_OK);
vd_dev->init_status = VMNG_STARTUP_TOP_HALF_OK;
vmng_info("Create top half finish. (dev_id=%d; fid=%u)\n", dev_id, fid);
return 0;
unregister_ctrl:
vmngh_unregister_ctrls(dev_id, fid);
free_vf:
vmngh_free_vf(dev_id, fid);
free_vdev:
vmngh_free_vdev(vd_dev);
return ret;
}
STATIC int vmngh_check_device_is_amp(bool *is_amp)
{
#ifdef CFG_FEATURE_NOT_SUPPROT_SMP
struct vmngh_pci_dev *vm_pdev = NULL;
u32 master_id;
u32 dev_id;
int ret;
for (dev_id = 0; dev_id < ASCEND_PDEV_MAX_NUM; ++dev_id) {
vm_pdev = vmngh_get_pdev_from_unit(dev_id);
if (vm_pdev->dev_id == (u32)VMNG_CTRL_DEVICE_ID_INIT) {
continue;
}
ret = devdrv_get_master_devid_in_the_same_os(dev_id, &master_id);
if (ret != 0) {
vmng_err("Get master id failed. (dev_id=%u;ret=%d)\n", dev_id, ret);
return ret;
}
if (dev_id != master_id) {
*is_amp = false;
return 0;
}
}
#endif
*is_amp = true;
return 0;
}
STATIC bool vmngh_check_is_support_vdev(void)
{
bool is_amp = true;
int ret;
ret = vmngh_check_device_is_amp(&is_amp);
if (ret != 0) {
vmng_err("Get device amp or smp mode failed. (ret=%d)\n", ret);
return false;
}
if (is_amp == false) {
return false;
}
return true;
}
STATIC int vmngh_vdev_create(struct vdavinci_dev *vdev, void *vdavinci,
struct vdavinci_type *type, ka_uuid_le_t uuid)
{
struct vmngh_pci_dev *vm_pdev = NULL;
u32 fid;
u32 dev_id;
int ret;
if (vmngh_vdev_create_para_check(vdev, vdavinci, type) != 0) {
vmng_err("Parameter check failed.\n");
return -EINVAL;
}
if (!vmngh_check_is_support_vdev()) {
vmng_err("Not support to create vdevice in smp mode.\n");
return -EOPNOTSUPP;
}
dev_id = (u32)devdrv_get_dev_id_by_pdev_with_dev_index(ka_pci_to_pci_dev(vdev->dev), (int)vdev->dev_index);
if (dev_id >= ASCEND_PDEV_MAX_NUM) {
vmng_err("dev_id is invalid. (dev_id=%d)\n", dev_id);
return -EINVAL;
}
fid = vmngh_get_fid_for_host(vdev);
vm_pdev = vmngh_get_pdev_from_unit(dev_id);
ka_task_mutex_lock(&vm_pdev->vpdev_mutex);
if (vm_pdev->vdev_ref == 0) {
ret = uda_dev_ctrl(dev_id, UDA_CTRL_TO_MIA);
if (ret != 0) {
ka_task_mutex_unlock(&vm_pdev->vpdev_mutex);
vmng_err("To mia mode failed. (dev_id=%u)\n", dev_id);
return ret;
}
vmng_set_device_split_mode(dev_id, VMNG_VIRTUAL_SPLIT_MODE);
}
vm_pdev->vdev_ref++;
ret = _vmngh_vdev_create(vdev, vdavinci, type, uuid, fid);
if (ret != 0) {
vm_pdev->vdev_ref--;
if (vm_pdev->vdev_ref == 0) {
vmng_set_device_split_mode(dev_id, VMNG_NORMAL_NONE_SPLIT_MODE);
(void)uda_dev_ctrl(dev_id, UDA_CTRL_TO_SIA);
}
}
ka_task_mutex_unlock(&vm_pdev->vpdev_mutex);
return ret;
}
STATIC int vmngh_vdev_check_vdev(const struct vdavinci_dev *vdev)
{
if (vdev == NULL || vdev->dev == NULL) {
vmng_err("dev is invalid.\n");
return -EINVAL;
}
if (vdev->fid + 1 >= VMNG_VDEV_MAX_PER_PDEV) {
vmng_err("fid is invalid. (fid=%u)\n", vdev->fid);
return -EINVAL;
}
return 0;
}
STATIC void vmngh_vdev_destroy(struct vdavinci_dev *vdev)
{
u32 dev_id;
struct vmngh_vd_dev *vd_dev = NULL;
ka_pci_dev_t *pdev = NULL;
u32 fid;
int ret;
ret = vmngh_vdev_check_vdev(vdev);
if (ret != 0) {
vmng_err("vdev is invalid.\n");
return;
}
fid = vmngh_get_fid_for_host(vdev);
pdev = ka_pci_to_pci_dev(vdev->dev);
dev_id = (u32)devdrv_get_dev_id_by_pdev_with_dev_index(pdev, (int)vdev->dev_index);
if (dev_id >= ASCEND_PDEV_MAX_NUM) {
vmng_err("device_id is invalid. (dev_id=%u)\n", dev_id);
return;
}
vmng_debug("Destroy begin. (dev_id=%d; fid=%u)\n", dev_id, fid);
ka_task_mutex_lock(vmngh_get_vdev_lock_from_unit(dev_id, fid));
vd_dev = vmngh_get_vdev_from_unit(dev_id, fid);
if (vd_dev != NULL) {
struct vmngh_pci_dev *vm_pdev = vmngh_get_pdev_from_unit(dev_id);
if (vd_dev->init_status == VMNG_STARTUP_BOTTOM_HALF_OK) {
vmngh_suspend_instance_remove_vdev(dev_id, fid);
vmngh_vdev_free_bottom(vd_dev);
}
vmngh_vdev_free_top(vd_dev);
ka_task_mutex_lock(&vm_pdev->vpdev_mutex);
vm_pdev->vdev_ref--;
if (vm_pdev->vdev_ref == 0) {
vmng_set_device_split_mode(dev_id, VMNG_NORMAL_NONE_SPLIT_MODE);
(void)uda_dev_ctrl(dev_id, UDA_CTRL_TO_SIA);
}
ka_task_mutex_unlock(&vm_pdev->vpdev_mutex);
}
ka_task_mutex_unlock(vmngh_get_vdev_lock_from_unit(dev_id, fid));
vmng_info("Release finish. (dev_id=%d; fid=%u)\n", dev_id, fid);
}
STATIC void vmngh_vdev_release(struct vdavinci_dev *vdev)
{
u32 dev_id, vdev_id;
struct vmngh_vd_dev *vd_dev = NULL;
ka_pci_dev_t *pdev = NULL;
u32 fid;
int ret;
ret = vmngh_vdev_check_vdev(vdev);
if (ret != 0) {
vmng_err("vdev is invalid.\n");
return;
}
fid = vmngh_get_fid_for_host(vdev);
pdev = ka_pci_to_pci_dev(vdev->dev);
dev_id = (u32)devdrv_get_dev_id_by_pdev_with_dev_index(pdev, (int)vdev->dev_index);
if (dev_id >= ASCEND_PDEV_MAX_NUM) {
vmng_err("dev_id is invalid. (dev_id=%u)\n", dev_id);
return;
}
ka_task_mutex_lock(vmngh_get_vdev_lock_from_unit(dev_id, fid));
vd_dev = vmngh_get_vdev_from_unit(dev_id, fid);
if (vd_dev != NULL) {
if (vd_dev->init_status == VMNG_STARTUP_BOTTOM_HALF_OK) {
vmngh_suspend_instance_remove_vdev(dev_id, fid);
vmngh_vdev_free_bottom(vd_dev);
} else {
vmng_info("init_status is not half ok. (init_status=%u)\n", vd_dev->init_status);
}
if (devdrv_is_sriov_support(dev_id)) {
devdrv_get_devid_by_pfvf_id(dev_id, fid, &vdev_id);
(void)devdrv_hot_reset_device(vdev_id);
}
}
ka_task_mutex_unlock(vmngh_get_vdev_lock_from_unit(dev_id, fid));
vmng_info("Release finish. (dev_id=%d; fid=%u)\n", dev_id, fid);
}
STATIC int vmngh_vdev_reset(struct vdavinci_dev *vdev)
{
u32 dev_id, vdev_id;
struct vmngh_vd_dev *vd_dev = NULL;
ka_pci_dev_t *pdev = NULL;
u32 fid;
int ret;
ret = vmngh_vdev_check_vdev(vdev);
if (ret != 0) {
vmng_err("vdev is invalid.\n");
return -EINVAL;
}
fid = vmngh_get_fid_for_host(vdev);
pdev = ka_pci_to_pci_dev(vdev->dev);
dev_id = (u32)devdrv_get_dev_id_by_pdev_with_dev_index(pdev, (int)vdev->dev_index);
if (dev_id >= ASCEND_PDEV_MAX_NUM) {
vmng_err("device_id is invalid. (dev_id=%u)\n", dev_id);
return -EINVAL;
}
vmng_debug("Reset begin. (dev_id=%d; fid=%u)\n", dev_id, fid);
ka_task_mutex_lock(vmngh_get_vdev_lock_from_unit(dev_id, fid));
vd_dev = vmngh_get_vdev_from_unit(dev_id, fid);
if (vd_dev != NULL) {
ka_base_atomic_set(&vd_dev->reset_ref_flag, VMNGH_MDEV_VM_RESET_STATE);
vd_dev->vm_pid = (u32)ka_task_get_current_tgid();
if (vd_dev->init_status == VMNG_STARTUP_BOTTOM_HALF_OK) {
vmngh_suspend_instance_remove_vdev(dev_id, fid);
vmngh_vdev_free_bottom(vd_dev);
}
if (devdrv_is_sriov_support(dev_id)) {
(void)devdrv_get_devid_by_pfvf_id(dev_id, fid, &vdev_id);
(void)devdrv_hot_reset_device(vdev_id);
}
vmngh_del_start_timer(vd_dev);
vmngh_set_start_timer(vd_dev);
vd_dev->dfx.reset_cnt++;
vmng_info("Reset finish. (dev_id=%d; fid=%u; reset_cnt=%u; vm_pid=%u)\n",
dev_id, fid, vd_dev->dfx.reset_cnt, vd_dev->vm_pid);
} else {
vmng_err("vd_dev is NULL. (dev_id=%d; fid=%u)\n", dev_id, fid);
}
ka_task_mutex_unlock(vmngh_get_vdev_lock_from_unit(dev_id, fid));
return 0;
}
STATIC int vmngh_vdev_flr(struct vdavinci_dev *vdev)
{
u32 dev_id;
struct vmngh_vd_dev *vd_dev = NULL;
ka_pci_dev_t *pdev = NULL;
u32 fid;
int ret;
ret = vmngh_vdev_check_vdev(vdev);
if (ret != 0) {
vmng_err("vdev is invalid.\n");
return -EINVAL;
}
fid = vmngh_get_fid_for_host(vdev);
pdev = ka_pci_to_pci_dev(vdev->dev);
dev_id = (u32)devdrv_get_dev_id_by_pdev_with_dev_index(pdev, (int)vdev->dev_index);
if (dev_id >= ASCEND_PDEV_MAX_NUM) {
vmng_err("device_id is invalid. (dev_id=%u)\n", dev_id);
return -EINVAL;
}
vmng_debug("Reset begin. (dev_id=%d; fid=%u)\n", dev_id, fid);
ka_task_mutex_lock(vmngh_get_vdev_lock_from_unit(dev_id, fid));
vd_dev = vmngh_get_vdev_from_unit(dev_id, fid);
if (vd_dev != NULL) {
vd_dev->vm_pid = (u32)ka_task_get_current_tgid();
if (vd_dev->init_status == VMNG_STARTUP_BOTTOM_HALF_OK) {
ka_base_atomic_set(&vd_dev->reset_ref_flag, VMNGH_MDEV_FLR_STATE);
vmngh_suspend_instance_remove_vdev(dev_id, fid);
vmngh_vdev_free_bottom(vd_dev);
}
vmngh_del_start_timer(vd_dev);
vmngh_set_start_timer(vd_dev);
vd_dev->dfx.reset_cnt++;
vmng_info("Reset finish. (dev_id=%d; fid=%u; reset_cnt=%u; vm_pid=%u)\n",
dev_id, fid, vd_dev->dfx.reset_cnt, vd_dev->vm_pid);
} else {
vmng_err("vd_dev is NULL. (dev_id=%d; fid=%u)\n", dev_id, fid);
}
ka_task_mutex_unlock(vmngh_get_vdev_lock_from_unit(dev_id, fid));
return 0;
}
static int vmngh_vm_startup_irq(void *data)
{
struct vmngh_vd_dev *vd_dev = NULL;
vd_dev = (struct vmngh_vd_dev *)data;
if (vd_dev->shr_para->start_flag == VMNG_VM_START_WAIT) {
vmng_info("Start wait. (dev_id=%u; fid=%u)\n", vd_dev->dev_id, vd_dev->fid);
ka_base_atomic_set(&(vd_dev->start_dev.start_flag), VMNG_TASK_SUCCESS);
ka_task_schedule_work_on(ka_system_raw_smp_processor_id(), &vd_dev->start_work);
}
return 0;
}
STATIC void vmngh_vdev_notify(struct vdavinci_dev *vdev, int db_index)
{
struct vmngh_vd_dev *vd_dev = NULL;
ka_pci_dev_t *pdev = NULL;
u32 dev_id;
int ret;
u32 fid;
ret = vmngh_vdev_check_vdev(vdev);
if (ret != 0) {
vmng_err("vdev is invalid.\n");
return;
}
fid = vmngh_get_fid_for_host(vdev);
pdev = ka_pci_to_pci_dev(vdev->dev);
dev_id = (u32)devdrv_get_dev_id_by_pdev_with_dev_index(pdev, (int)vdev->dev_index);
if (dev_id >= ASCEND_PDEV_MAX_NUM) {
vmng_err("dev_id is invalid. (dev_id=%d)\n", dev_id);
return;
}
vd_dev = vmngh_get_vdev_from_unit(dev_id, fid);
if (vd_dev == NULL) {
vmng_err("vd_dev is NULL. (dev_id=%d; fid=%u; db_index=%u)\n", dev_id, fid, db_index);
return;
}
if (db_index == VMNG_DB_BASE_LOAD) {
ret = vmngh_vm_startup_irq(vd_dev);
} else if ((db_index >= VMNG_DB_BASE_MSG) && (db_index < VMNG_DB_BASE_MSG_BLOCK_TX_FINISH)) {
ret = vmngh_msg_db_hanlder(vd_dev->msg_dev, (u32)db_index);
} else if ((db_index >= VMNG_DB_BASE_MSG_BLOCK_TX_FINISH) && (db_index < VMNG_DB_BASE_EXTERNAL)) {
ret = vmngh_tx_finish_db_hander(vd_dev->msg_dev, (u32)db_index);
} else if ((db_index >= VMNG_DB_BASE_EXTERNAL) && (db_index < VMNG_DB_BASE_MAX)) {
ret = vmngh_external_db_handler(vd_dev, db_index);
} else {
vmng_err("Doorbell index is out of range. (dev_id=%d; fid=%u; db_index=%u)\n", dev_id, fid, db_index);
return;
}
if (ret != 0) {
vmng_err("Handler is error. (dev_id=%d; fid=%u; db_index=%u; ret=%d)\n", dev_id, fid, db_index, ret);
} else {
vmng_debug("Doorbell finish. (dev_id=%d; fid=%u; db_index=%u)\n", dev_id, fid, db_index);
}
}
STATIC int vmngh_vdev_get_map_info(struct vdavinci_dev *vdev, struct vdavinci_type *type,
u32 bar_id, struct vdavinci_mapinfo *map_info)
{
struct vmngh_map_info client_map_info = {0};
struct vmngh_client_instance instance = {0};
struct vmng_vdev_ctrl dev_ctrl = {0};
ka_pci_dev_t *pdev = NULL;
u32 vfid;
u32 dev_id;
u64 i;
if ((vdev == NULL) || (vdev->dev == NULL) || (type == NULL) || (map_info == NULL)) {
vmng_err("Input parameter is error. (vdev=%s; type=%s; map_info=%s)\n",
vdev == NULL ? "NULL" : "OK", type == NULL ? "NULL" : "OK",
map_info == NULL ? "NULL" : "OK");
return -EINVAL;
}
vfid = vmngh_get_fid_for_host(vdev);
pdev = ka_pci_to_pci_dev(vdev->dev);
dev_id = (u32)devdrv_get_dev_id_by_pdev_with_dev_index(pdev, (int)vdev->dev_index);
if (dev_id >= ASCEND_PDEV_MAX_NUM) {
vmng_err("dev_id is invalid. (dev_id=%d)\n", dev_id);
return -EINVAL;
}
dev_ctrl.dev_id = dev_id;
dev_ctrl.vfid = vfid;
dev_ctrl.dtype = vmngh_get_dtype_by_aicore(type->aicore_num);
dev_ctrl.bar0_size = type->bar0_size;
dev_ctrl.bar2_size = type->bar2_size;
dev_ctrl.bar4_size = type->bar4_size;
instance.dev_ctrl = &dev_ctrl;
instance.type = VMNG_CLIENT_TYPE_TSDRV;
if (vmngh_get_map_info_client(&instance, VMNG_CLIENT_TYPE_TSDRV, &client_map_info) != 0) {
vmng_err("Get map info client failed. (dev_id=%d; fid=%u)\n", dev_id, vfid);
return -EINVAL;
}
if (client_map_info.num > HW_BAR_SPARSE_MAP_MAX) {
vmng_err("Too many map info. (dev_id=%d; fid=%u; num=%llu)\n", dev_id, vfid, client_map_info.num);
return -EINVAL;
}
for (i = 0; i < client_map_info.num; i++) {
map_info->map_info[i].offset = client_map_info.map_info[i].offset;
map_info->map_info[i].paddr = client_map_info.map_info[i].paddr;
map_info->map_info[i].size = client_map_info.map_info[i].size;
vmng_info("Get map info (dev_id=%d; fid=%u; i=%llu; offset=0x%lx; size=0x%lx)\n",
dev_id, vfid, i, map_info->map_info[i].offset, map_info->map_info[i].size);
}
map_info->num = client_map_info.num;
vmng_info("Get map info success. (dev_id=%d; fid=%u; num=%llu)\n", dev_id, vfid, map_info->num);
return 0;
}
STATIC int vmngh_vdev_put_map_info(struct vdavinci_dev *vdev)
{
struct vmngh_client_instance instance = {0};
struct vmng_vdev_ctrl dev_ctrl = {0};
ka_pci_dev_t *pdev = NULL;
u32 vfid;
u32 dev_id;
int ret;
ret = vmngh_vdev_check_vdev(vdev);
if (ret != 0) {
vmng_err("vdev is invalid.\n");
return -EINVAL;
}
vfid = vmngh_get_fid_for_host(vdev);
pdev = ka_pci_to_pci_dev(vdev->dev);
dev_id = (u32)devdrv_get_dev_id_by_pdev_with_dev_index(pdev, (int)vdev->dev_index);
if (dev_id >= ASCEND_PDEV_MAX_NUM) {
vmng_err("dev_id is invalid. (dev_id=%d)\n", dev_id);
return -EINVAL;
}
dev_ctrl.dev_id = dev_id;
dev_ctrl.vfid = vfid;
instance.dev_ctrl = &dev_ctrl;
instance.type = VMNG_CLIENT_TYPE_TSDRV;
if (vmngh_put_map_info_client(&instance, VMNG_CLIENT_TYPE_TSDRV) != 0) {
vmng_err("Put map info client. (dev_id=%d; fid=%u)\n", dev_id, vfid);
return -EINVAL;
}
vmng_info("Put map info success. (dev_id=%d; fid=%u)\n", dev_id, vfid);
return 0;
}
STATIC int vmngh_vdev_get_devnum_by_pdev(ka_device_t *dev)
{
ka_pci_dev_t *pdev = NULL;
int dev_num;
if (dev == NULL) {
vmng_err("Input parameter is error.\n");
return -EINVAL;
}
pdev = ka_pci_to_pci_dev(dev);
dev_num = devdrv_get_davinci_dev_num_by_pdev(pdev);
return dev_num;
}
STATIC int vmngh_vdev_wait_aicore_ready(u32 dev_id)
{
int timeout = VMNG_WAIT_INIT_TIME;
u32 aicore_num;
while (timeout > 0) {
aicore_num = vmngh_get_total_core_num(dev_id);
if (aicore_num != 0) {
break;
}
ka_rmb();
ka_system_usleep_range(100000, 200000);
timeout--;
}
if (timeout <= 0) {
vmng_err("Wait for set total aicore num timeout. (dev_id=%d)\n", dev_id);
return VMNG_ERR;
}
return 0;
}
#define MAX_CPU_NUM 32
#define GET_MEMORY_MODULE_SIZE(mem) KA_BASE_DIV_ROUND_UP((mem) / 1024, 8) * 8
STATIC int vmngh_vdev_wait_dev_resource_ready(u32 dev_id, struct dvt_devinfo *dev_info)
{
struct vmng_soc_resource_enquire info;
unsigned long aicpu_bitmap;
int ret;
#define MILAN_BIN3_AIC_NUM 25
#define MILAN_BIN0_AIC_NUM 24
if (dev_info->aicore_num == MILAN_BIN3_AIC_NUM) {
dev_info->aicore_num = MILAN_BIN0_AIC_NUM;
}
(void)memset_s(&info, sizeof(struct vmng_soc_resource_enquire), 0, sizeof(struct vmng_soc_resource_enquire));
ret = vmngh_enquire_soc_resource(dev_id, 0, &info);
if (ret != 0) {
vmng_err("Get device resource failed. (ret=%d;dev_id=%u)\n", ret, dev_id);
return ret;
}
aicpu_bitmap = (unsigned long)info.total.stars_refresh.device_aicpu;
dev_info->aicpu_num = (u32)ka_base_bitmap_weight(&aicpu_bitmap, MAX_CPU_NUM);
dev_info->mem_size = GET_MEMORY_MODULE_SIZE(info.total.base.memory_spec);
dev_info->jpegd_num = info.total.stars_refresh.jpegd;
dev_info->jpege_num = info.total.stars_refresh.jpege;
dev_info->vpc_num = info.total.stars_refresh.vpc;
dev_info->vdec_num = info.total.stars_refresh.vdec;
dev_info->venc_num = info.total.stars_refresh.venc;
return 0;
}
STATIC int vmngh_vdev_get_devinfo(ka_device_t *dev, u32 dev_index, struct dvt_devinfo *dev_info)
{
struct vmngh_pci_dev *vm_pdev = NULL;
ka_pci_dev_t *pdev = NULL;
u32 dev_id;
int ret;
if ((dev == NULL) || (dev_info == NULL)) {
vmng_err("Input parameter is error.\n");
return -EINVAL;
}
pdev = ka_pci_to_pci_dev(dev);
dev_id = (u32)devdrv_get_dev_id_by_pdev_with_dev_index(pdev, (int)dev_index);
if (dev_id >= ASCEND_PDEV_MAX_NUM) {
vmng_err("device_id is invalid. (dev_id=%d)\n", dev_id);
return -EINVAL;
}
vm_pdev = vmngh_get_pdev_from_unit(dev_id);
if (vm_pdev == NULL) {
vmng_err("vm_pdev is NULL. (dev_id=%d)\n", dev_id);
return -EINVAL;
}
ret = vmngh_vdev_wait_aicore_ready(dev_id);
if (ret != 0) {
return -EINVAL;
}
ret = vmngh_vdev_wait_dev_resource_ready(dev_id, &vm_pdev->dev_info);
if (ret != 0) {
vmng_err("Get dvt info failed. (ret=%d)\n", ret);
return ret;
}
ret = memcpy_s(dev_info, sizeof(struct dvt_devinfo), &vm_pdev->dev_info, sizeof(struct dvt_devinfo));
if (ret != 0) {
vmng_err("Memcpy dev_info failed. (ret=%d)\n", ret);
return ret;
}
return 0;
}
void *vmngh_dma_alloc_coherent(ka_device_t *dev, size_t size, ka_dma_addr_t *dma_handle, ka_gfp_t gfp)
{
return hw_dvt_hypervisor_dma_alloc_coherent(dev, size, dma_handle, gfp);
}
KA_EXPORT_SYMBOL(vmngh_dma_alloc_coherent);
void vmngh_dma_free_coherent(ka_device_t *dev, size_t size, void *cpu_addr, ka_dma_addr_t dma_handle)
{
hw_dvt_hypervisor_dma_free_coherent(dev, size, cpu_addr, dma_handle);
}
KA_EXPORT_SYMBOL(vmngh_dma_free_coherent);
#define VMNG_SUPPORT_SRIOV_VF_NUM 8
STATIC int vmngh_vm_enable_sriov(ka_pci_dev_t *pdev, int numvfs)
{
struct vmngh_pci_dev *vm_pdev = NULL;
u32 dev_id;
int ret = 0;
if (pdev == NULL) {
vmng_err("Input pdev is NULL.\n");
return -EINVAL;
}
dev_id = (u32)devdrv_get_dev_id_by_pdev(pdev);
if (dev_id >= VMNG_PDEV_MAX) {
vmng_err("Input parameter is error. (dev_id=%u; MAX=%u)\n", dev_id, VMNG_PDEV_MAX);
return VMNG_ERR;
}
vm_pdev = vmngh_get_pdev_from_unit(dev_id);
ka_task_mutex_lock(&vm_pdev->vpdev_mutex);
if (numvfs == VMNG_SUPPORT_SRIOV_VF_NUM) {
vmng_info("vmng enable sriov. (dev_id=%u)\n", dev_id);
ret = vmngh_common_enable_sriov(dev_id, DEVDRV_BOOT_MDEV_AND_SRIOV);
} else if (numvfs == 0) {
vmng_info("vmng disable sriov. (dev_id=%u)\n", dev_id);
ret = vmngh_common_disable_sriov(dev_id, DEVDRV_BOOT_DEFAULT_MODE);
} else {
vmng_err("Invalid vfs nums. (numvfs=%d)\n", numvfs);
ret = -EINVAL;
}
ka_task_mutex_unlock(&vm_pdev->vpdev_mutex);
return ret;
}
struct vdavinci_priv_ops g_vmngh_ops = {
.vdavinci_create = vmngh_vdev_create,
.vdavinci_destroy = vmngh_vdev_destroy,
.vdavinci_release = vmngh_vdev_release,
.vdavinci_reset = vmngh_vdev_reset,
.vdavinci_flr = vmngh_vdev_flr,
.vdavinci_notify = vmngh_vdev_notify,
.vdavinci_getmapinfo = vmngh_vdev_get_map_info,
.vdavinci_putmapinfo = vmngh_vdev_put_map_info,
.davinci_getdevnum = vmngh_vdev_get_devnum_by_pdev,
.davinci_getdevinfo = vmngh_vdev_get_devinfo,
.vascend_enable_sriov = vmngh_vm_enable_sriov,
};
static void vmngh_init_pci_pdev(struct vmngh_pci_dev *vmngh_pcidev, u32 dev_id, ka_device_t *dev)
{
int i;
vmngh_pcidev->dev_id = dev_id;
vmngh_pcidev->dev = dev;
vmngh_pcidev->vdev_num = VMNG_FID_BEGIN;
if (devdrv_get_connect_protocol(dev_id) != CONNECT_PROTOCOL_UB) {
vmngh_pcidev->pdev = ka_pci_to_pci_dev(dev);
vmngh_pcidev->ep_devic_id = ka_pci_get_device_id(vmngh_pcidev->pdev);
}
ka_task_mutex_init(&vmngh_pcidev->vpdev_mutex);
for (i = 0; i < VMNG_VDEV_MAX_PER_PDEV; i++) {
ka_task_mutex_init(&vmngh_pcidev->vddev_mutex[i]);
}
vmngh_pcidev->vdev_ref = 0;
}
static void vmngh_uninit_pci_pdev(struct vmngh_pci_dev *vmngh_pcidev)
{
vmngh_pcidev->dev_id = (u32)VMNG_CTRL_DEVICE_ID_INIT;
vmngh_pcidev->pdev = NULL;
vmngh_pcidev->dev = NULL;
vmngh_pcidev->vdev_num = 0;
vmngh_pcidev->ep_devic_id = 0;
vmngh_pcidev->vdev_ref = 0;
}
STATIC bool vmngh_all_devices_are_valid(struct vmngh_pci_dev *vmngh_dev)
{
struct vmngh_ctrl_ops *ctrl_ops;
int dev_num;
int start_dev_id;
int i;
dev_num = devdrv_get_davinci_dev_num_by_pdev(vmngh_dev->pdev);
start_dev_id = ka_base_rounddown((int)vmngh_dev->dev_id, dev_num);
vmng_info("Get ka_base_rounddown dev_id = %u;dev_num=%d\n", start_dev_id, dev_num);
for (i = 0; i < dev_num; ++i) {
ctrl_ops = vmngh_get_ctrl_ops((u32)(start_dev_id + i));
if (ctrl_ops->valid == VMNG_INVALID) {
return false;
}
}
return true;
}
STATIC int vmngh_dvt_init(struct vmngh_pci_dev *vmngh_dev)
{
struct vdavinci_priv *vdavinci_set = NULL;
int ret;
if (devdrv_get_connect_protocol(vmngh_dev->dev_id) == CONNECT_PROTOCOL_UB) {
return 0;
}
vdavinci_set = (struct vdavinci_priv *)devdrv_get_devdrv_priv(vmngh_dev->pdev);
if (vdavinci_set == NULL) {
vmng_err("vdavinci_set is null. (dev_id=%u)", vmngh_dev->dev_id);
return VMNG_ERR;
}
ka_task_mutex_lock(&g_vmngh_pci_mutex);
if (!vmngh_all_devices_are_valid(vmngh_dev)) {
ka_task_mutex_unlock(&g_vmngh_pci_mutex);
return 0;
}
if (vdavinci_set->ops != NULL) {
ka_task_mutex_unlock(&g_vmngh_pci_mutex);
return 0;
}
vdavinci_set->dev = vmngh_dev->dev;
vdavinci_set->ops = &g_vmngh_ops;
ret = hw_dvt_init((void *)vdavinci_set);
if (ret != 0) {
vmng_err("Register vdavinci failed. (dev_id=%u; ret=%d)\n", vmngh_dev->dev_id, ret);
vdavinci_set->ops = NULL;
ka_task_mutex_unlock(&g_vmngh_pci_mutex);
return VMNG_ERR;
}
ka_task_mutex_unlock(&g_vmngh_pci_mutex);
return VMNG_OK;
}
STATIC int vmngh_sync_udevid_to_remote(u32 udevid)
{
struct uda_mia_dev_para mia_para = {0};
struct vmng_ctrl_msg msg = {0};
u32 phy_devid, vfid, remote_id;
u32 len = 0;
int ret;
if (uda_is_phy_dev(udevid)) {
phy_devid = udevid;
vfid = 0;
} else {
ret = uda_udevid_to_mia_devid(udevid, &mia_para);
if (ret != 0) {
vmng_err("Trans udevid to phy devid failed. (udevid=%u;ret=%d)\n", udevid, ret);
return ret;
}
phy_devid = mia_para.phy_devid;
vfid = mia_para.sub_devid + 1;
}
msg.type = VMNG_CTRL_MSG_TYPE_SYNC_ID;
msg.info_msg.vfid = vfid;
msg.info_msg.id_info.udevid = udevid;
msg.error_code = VMNG_OK;
ret = vmngh_ctrl_msg_send(phy_devid, (void *)&msg, sizeof(msg), sizeof(msg), &len);
if ((ret != VMNG_OK) || (msg.error_code != VMNG_OK)) {
vmng_err("Sync udevid to remote failed. (dev_id=%u;ret=%d;error_code=%d)\n", udevid, ret, msg.error_code);
return ret != 0 ? ret : msg.error_code;
}
remote_id = msg.info_msg.id_info.remote_udevid;
(void)uda_dev_set_remote_udevid(udevid, remote_id);
vmng_info("Set remote id success.(udevid=%u;remote_udevid=%u)\n", udevid, remote_id);
return 0;
}
STATIC int vmngh_init_vpc_msg_chan(struct vmngh_pci_dev *vmngh_dev)
{
struct vmng_ctrl_msg msg;
u32 len = 0;
int ret;
msg.type = VMNG_CTRL_MSG_TYPE_SYNC;
msg.sync_msg.dev_id = (int)vmngh_dev->dev_id;
msg.error_code = VMNG_OK;
vmng_info("Device work begin. (dev_id=%d)\n", vmngh_dev->dev_id);
ret = vmngh_ctrl_msg_send(vmngh_dev->dev_id, (void *)&msg, sizeof(msg), sizeof(msg), &len);
if ((ret != VMNG_OK) || (len != sizeof(msg)) || (msg.error_code != VMNG_OK)) {
vmng_err("Sync failed. (dev_id=%d)\n", vmngh_dev->dev_id);
return -EFAULT;
}
Send msg to device to get aic num instead of waiting for devmng to set.*/
vmngh_set_total_core_num(vmngh_dev->dev_id, msg.sync_msg.aicore_num);
ret = vmngh_sync_udevid_to_remote(vmngh_dev->dev_id);
if (ret != VMNG_OK) {
return ret;
}
vmng_info("Device work begin. (dev_id=%u)\n", vmngh_dev->dev_id);
ret = vmngh_dvt_init(vmngh_dev);
if (ret != VMNG_OK) {
return ret;
}
vmngh_set_peer_dev_id(vmngh_dev->dev_id, msg.sync_msg.dev_id);
vmngh_set_device_status(vmngh_dev->dev_id, VMNG_VALID);
ka_task_mutex_lock(&g_vmngh_pci_mutex);
vmngh_dev->status = VMNG_STARTUP_PROBED;
ka_task_mutex_unlock(&g_vmngh_pci_mutex);
vmng_info("Device work end. (dev_id=%d; peer_dev_id=%d)\n", vmngh_dev->dev_id, vmngh_dev->peer_dev_id);
return 0;
}
#define MAX_HCCS_MSIX_NUM 33
#define MAX_HCCS_VM_MSIX_NUM 29
STATIC void vmngh_init_msix_num(u32 dev_id)
{
if (devdrv_get_connect_protocol(dev_id) == CONNECT_PROTOCOL_HCCS) {
g_max_msix_num = MAX_HCCS_MSIX_NUM;
g_max_pass_to_vm_msix_num = MAX_HCCS_VM_MSIX_NUM;
} else {
g_max_msix_num = MAX_PCIE_MSIX_NUM;
g_max_pass_to_vm_msix_num = MAX_PASS_TO_VM_MSIX_NUM;
}
vmng_info("Get connect protocol. (max_msix_num=%u; max_vm_msix_num=%u)\n",
g_max_msix_num, g_max_pass_to_vm_msix_num);
}
STATIC int vmngh_pci_init_instance(u32 dev_id, ka_device_t *dev)
{
struct vmngh_pci_dev *vmngh_pdev = NULL;
int ret, sysfs_ret;
if (devdrv_get_pfvf_type_by_devid(dev_id) != DEVDRV_SRIOV_TYPE_PF) {
vmng_debug("Skip vf pci init instance. (dev_id=%u)\n", dev_id);
return 0;
}
vmng_info("Call vmngh_pci_init_instance start. (dev_id=%u)\n", dev_id);
if (vmngh_init_ctrl_ops(dev_id) != VMNG_OK) {
vmng_err("Init ctrl ops error. (dev_id=%u)\n", dev_id);
return -EINVAL;
}
vmngh_init_msix_num(dev_id);
vmngh_pdev = vmngh_get_pdev_from_unit(dev_id);
if (vmngh_pdev == NULL) {
vmng_err("vmngh_pdev is NULL. (dev_id=%u)\n", dev_id);
return -EINVAL;
}
vmngh_init_pci_pdev(vmngh_pdev, dev_id, dev);
sysfs_ret = vmngh_sysfs_init(dev_id, vmngh_pdev->pdev);
if (sysfs_ret != 0) {
vmng_warn("Init sysfs incomplete. (dev_id=%u;ret=%d)\n", dev_id, sysfs_ret);
}
ret = vmngh_init_vpc_msg_chan(vmngh_pdev);
if (ret != 0) {
if (sysfs_ret == 0) {
vmngh_sysfs_exit(dev_id, vmngh_pdev->pdev);
}
return ret;
}
if (devdrv_is_sriov_support(dev_id) == false) {
vmngh_bw_ctrl_info_init(dev_id);
}
vmng_info("Instance init finish. (dev_id=%u)\n", dev_id);
return 0;
}
STATIC int vmngh_free_all_vdev(u32 dev_id)
{
u32 fid;
struct vmngh_vd_dev *vd_dev = NULL;
int vd_dev_alive_cnt = 0;
vmng_debug("Free all vdev begin. (dev_id=%u)\n", dev_id);
for (fid = 0; fid < VMNG_VDEV_MAX_PER_PDEV; fid++) {
vd_dev = vmngh_get_vdev_from_unit(dev_id, fid);
if (vd_dev != NULL) {
vd_dev_alive_cnt++;
if (vd_dev->init_status == VMNG_STARTUP_BOTTOM_HALF_OK) {
vmngh_suspend_instance_remove_vdev(dev_id, fid);
vmngh_admin_notify_rm_vdev(vd_dev->msg_dev, VMNG_VM_RM_HOST_PDEV_WAIT);
vmngh_vdev_free_bottom(vd_dev);
}
vmngh_vdev_free_top(vd_dev);
}
}
vmng_info("Free all vdev finish. (dev_id=%u; free_cnt=%d)\n", dev_id, vd_dev_alive_cnt);
return vd_dev_alive_cnt;
}
STATIC int vmngh_pci_uninit_instance(u32 dev_id)
{
struct vdavinci_priv *vdavinci_set = NULL;
struct vmngh_pci_dev *vmngh_pdev = NULL;
int vd_dev_alive_cnt;
u32 dev_num;
u32 fid;
int ret;
if (devdrv_get_pfvf_type_by_devid(dev_id) != DEVDRV_SRIOV_TYPE_PF) {
vmng_debug("Skip vf pci uninit instance. (dev_id=%u)\n", dev_id);
return 0;
}
vmngh_pdev = vmngh_get_pdev_from_unit(dev_id);
if (devdrv_is_sriov_support(dev_id) == false) {
for (fid = 1; fid < VMNG_VDEV_MAX_PER_PDEV; ++fid) {
vmngh_bw_data_clear_timer_uninit();
}
vmngh_bw_ctrl_info_uninit(dev_id);
}
vmngh_suspend_instance_remove_pdev(dev_id);
vd_dev_alive_cnt = vmngh_free_all_vdev(dev_id);
if (vd_dev_alive_cnt != 0) {
vmng_warn("mdevs are maybe alive when phy pci uninit.(dev_id=%u; free_cnt=%d)\n", dev_id, vd_dev_alive_cnt);
}
if (devdrv_get_connect_protocol(dev_id) == CONNECT_PROTOCOL_UB) {
goto exit;
}
vdavinci_set = (struct vdavinci_priv *)devdrv_get_devdrv_priv(vmngh_pdev->pdev);
if (vdavinci_set == NULL) {
vmng_err("Get devdrv priv NULL. (dev_id=%u)\n", dev_id);
return -EINVAL;
}
dev_num = (u32)devdrv_get_davinci_dev_num_by_pdev(vmngh_pdev->pdev);
if (dev_num == 0) {
vmng_err("Davinci device num is zero. (dev_id=%u)\n", dev_id);
return -EINVAL;
}
ka_task_mutex_lock(&g_vmngh_pci_mutex);
if (vmngh_pdev->status == VMNG_STARTUP_PROBED) {
vmngh_pdev->status = VMNG_STARTUP_UNPROBED;
ka_task_mutex_unlock(&g_vmngh_pci_mutex);
if (dev_id % dev_num == 0) {
ret = hw_dvt_uninit((void *)vdavinci_set);
if (ret != 0) {
vmng_err("Call hw_dvt_uninit failed. (dev_id=%u; ret=%d)\n", dev_id, ret);
} else {
vmng_info("Call hw_dvt_uninit success. (dev_id=%u)\n", dev_id);
}
}
} else {
ka_task_mutex_unlock(&g_vmngh_pci_mutex);
}
exit:
vmngh_sysfs_exit(dev_id, vmngh_pdev->pdev);
vmngh_uninit_pci_pdev(vmngh_pdev);
(void)vmngh_uninit_ctrl_ops(dev_id);
vmng_info("Call instance uninit finish. (dev_id=%u)\n", dev_id);
return 0;
}
#define VMNG_ONLINE_NOTIFIER "vmng_online"
#define VMNG_INFO_NOTIFIER "vmng_set_info"
STATIC int vmngh_sriov_dev_notifier_func(u32 udevid, enum uda_notified_action action)
{
int ret = 0;
if (action == UDA_INIT) {
(void)module_feature_auto_init_dev(udevid);
} else if (action == UDA_UNINIT) {
module_feature_auto_uninit_dev(udevid);
} else if (action == UDA_REMOVE) {
struct uda_dev_type type;
uda_davinci_near_real_entity_type_pack(&type);
(void)uda_remove_dev(&type, udevid);
}
vmng_info("notifier action. (udevid=%u; action=%d; ret=%d)\n", udevid, action, ret);
return 0;
}
STATIC int vmngh_sync_udevid_notifier_func(u32 udevid, enum uda_notified_action action)
{
int ret;
if (udevid >= ASCEND_PDEV_MAX_NUM && action == UDA_INIT) {
ret = vmngh_sync_udevid_to_remote(udevid);
if (ret != VMNG_OK) {
return ret;
}
vmng_info("Sync udevid notifier func action. (udevid=%u; action=%d)\n", udevid, action);
}
return 0;
}
static int vmngh_notifier_func(u32 udevid, enum uda_notified_action action)
{
int ret = 0;
if (udevid >= ASCEND_PDEV_MAX_NUM) {
return vmngh_sriov_dev_notifier_func(udevid, action);
}
if (action == UDA_INIT) {
ret = vmngh_pci_init_instance(udevid, uda_get_device(udevid));
} else if (action == UDA_UNINIT) {
ret = vmngh_pci_uninit_instance(udevid);
}
vmng_info("notifier action. (udevid=%u; action=%d; ret=%d)\n", udevid, action, ret);
return ret;
}
#ifndef CFG_SOC_PLATFORM_CLOUD_V4
static int vmngh_set_mia_dev_res(u32 udevid, u32 version)
{
struct vmngh_vdev_ctrl *ctrl = NULL;
struct vmng_vdev_ctrl *vdev_ctrl = NULL;
struct uda_mia_dev_para mia_para;
u32 fid;
u32 ret;
ret = (u32)uda_udevid_to_mia_devid(udevid, &mia_para);
if (ret != 0) {
vmng_err("Invalid para. (udevid=%u)\n", udevid);
return (int)ret;
}
fid = mia_para.sub_devid + 1;
ctrl = vmngh_get_ctrl(mia_para.phy_devid, fid);
vdev_ctrl = &ctrl->vdev_ctrl;
if (version == 0) {
u64 aic_bitmap = 0;
u32 i;
for (i = 0; i < vdev_ctrl->core_num; i++) {
aic_bitmap |= (0x1 << i);
}
ret = (u32)soc_resmng_dev_set_mia_res(udevid, MIA_AC_AIC, aic_bitmap, 1);
} else {
vf_ac_info_t *ac = &vdev_ctrl->vf_cfg.accelerator;
struct res_inst_info inst;
soc_resmng_inst_pack(&inst, udevid, TS_SUBSYS, 0);
ret = (u32)soc_resmng_dev_set_mia_res(udevid, MIA_AC_AIC, (u64)ac->aic_bitmap, 1);
ret |= (u32)soc_resmng_set_mia_res(&inst, MIA_STARS_RTSQ, (u64)ac->rtsq_slice_bitmap, 128);
ret |= (u32)soc_resmng_set_mia_res(&inst, MIA_STARS_EVENT, (u64)ac->event_slice_bitmap, 4096);
ret |= (u32)soc_resmng_set_mia_res(&inst, MIA_STARS_NOTIFY, (u64)ac->notify_slice_bitmap, 512);
}
return (int)ret;
}
#endif
static int vmngh_mia_dev_notifier_func(u32 udevid, enum uda_notified_action action)
{
int ret = 0;
#ifndef CFG_SOC_PLATFORM_CLOUD_V4
if (action == UDA_INIT) {
ret = vmngh_set_mia_dev_res(udevid, 0);
}
#endif
vmng_info("notifier action. (udevid=%u; action=%d; ret=%d)\n", udevid, action, ret);
return ret;
}
STATIC int vmngh_sec_eh_notifier_func(u32 udevid, enum uda_notified_action action)
{
int ret = 0;
if (action == UDA_INIT) {
ret = vmngh_sync_udevid_to_remote(udevid);
if (ret != VMNG_OK) {
return ret;
}
#ifndef CFG_SOC_PLATFORM_CLOUD_V4
ret = vmngh_set_mia_dev_res(udevid, 1);
#endif
}
vmng_info("notifier action. (udevid=%u; action=%d; ret=%d)\n", udevid, action, ret);
return ret;
}
int vmngh_init_module(void)
{
struct uda_dev_type type;
int ret;
vmng_info("Call vmngh_init_module start.\n");
vmng_info("ASCEND_PDEV_MAX_NUM = %d, ASCEND_DEV_MAX_NUM=%d\n", ASCEND_PDEV_MAX_NUM, ASCEND_DEV_MAX_NUM);
ret = vmngh_init_unit();
if (ret != 0) {
vmng_err("Call vmngh_init_unit failed. (ret=%d)\n", ret);
return ret;
}
ret = vmngh_init_ctrl();
if (ret != 0) {
vmng_err("Call vmngh_init_ctrl failed. (ret=%d)\n", ret);
return ret;
}
ret = vmngh_register_admin_rx_func(VMNGA_ADMIN_OPCODE_RM_PDEV, vmngh_admin_rx_agent_rm_pdev);
if (ret != 0) {
vmng_err("Register admin rx func failed. (ret=%d)\n", ret);
vmngh_uninit_ctrl();
return ret;
}
ka_task_mutex_init(&g_vmngh_pci_mutex);
* description: register client, wait for pcie host module callback init_intance
* next function: vmngh_init_instance
*/
uda_davinci_near_real_entity_type_pack(&type);
ret = uda_notifier_register(VMNG_INFO_NOTIFIER, &type, UDA_PRI0, vmngh_sync_udevid_notifier_func);
if (ret != 0) {
vmng_err("Call uda_notifier_register failed. (ret=%d)\n", ret);
#ifndef DRV_UT
goto sync_udevid_register_failed;
#endif
}
uda_davinci_near_real_entity_type_pack(&type);
ret = uda_notifier_register(VMNG_ONLINE_NOTIFIER, &type, UDA_PRI3, vmngh_notifier_func);
if (ret != 0) {
vmng_err("Call uda_notifier_register failed. (ret=%d)\n", ret);
goto uda_register_failed;
}
uda_davinci_near_virtual_entity_type_pack(&type);
ret = uda_notifier_register(VMNG_ONLINE_NOTIFIER, &type, UDA_PRI0, vmngh_mia_dev_notifier_func);
if (ret != 0) {
vmng_err("Call uda_notifier_register failed. (ret=%d)\n", ret);
goto mia_register_failed;
}
uda_dev_type_pack(&type, UDA_DAVINCI, UDA_ENTITY, UDA_NEAR, UDA_REAL_SEC_EH);
ret = uda_notifier_register(VMNG_ONLINE_NOTIFIER, &type, UDA_PRI0, vmngh_sec_eh_notifier_func);
if (ret != 0) {
vmng_err("Call uda_notifier_register failed. (ret=%d)\n", ret);
goto sec_eh_register_failed;
}
ret = vmngh_proc_fs_init();
if (ret == 0) {
procfs_valid = VMNG_PROCFS_VALID;
vmng_info("Proc fs init finish.\n");
}
module_feature_auto_init();
vmng_info("Init module finish.\n");
return 0;
sec_eh_register_failed:
uda_davinci_near_virtual_entity_type_pack(&type);
(void)uda_notifier_unregister(VMNG_ONLINE_NOTIFIER, &type);
mia_register_failed:
uda_davinci_near_real_entity_type_pack(&type);
(void)uda_notifier_unregister(VMNG_ONLINE_NOTIFIER, &type);
uda_register_failed:
#ifndef DRV_UT
uda_davinci_near_real_entity_type_pack(&type);
(void)uda_notifier_unregister(VMNG_INFO_NOTIFIER, &type);
#endif
sync_udevid_register_failed:
vmngh_unregister_admin_rx_func(VMNGA_ADMIN_OPCODE_RM_PDEV);
vmngh_uninit_ctrl();
return ret;
}
void vmngh_exit_module(void)
{
struct uda_dev_type type;
u32 alive_status;
module_feature_auto_uninit();
if (procfs_valid == VMNG_PROCFS_VALID) {
vmngh_proc_fs_uninit();
procfs_valid = VMNG_PROCFS_INVALID;
vmng_info("Proc fs uninit finish.\n");
}
alive_status = vmngh_vd_dev_alive();
if (alive_status == VMNGA_VD_DEV_ALIVE_OK) {
vmng_warn("There are mdevs alive, rmmod ko would cause mistake.\n");
}
uda_dev_type_pack(&type, UDA_DAVINCI, UDA_ENTITY, UDA_NEAR, UDA_REAL_SEC_EH);
(void)uda_notifier_unregister(VMNG_ONLINE_NOTIFIER, &type);
uda_davinci_near_virtual_entity_type_pack(&type);
(void)uda_notifier_unregister(VMNG_ONLINE_NOTIFIER, &type);
uda_davinci_near_real_entity_type_pack(&type);
(void)uda_notifier_unregister(VMNG_ONLINE_NOTIFIER, &type);
uda_davinci_near_real_entity_type_pack(&type);
(void)uda_notifier_unregister(VMNG_INFO_NOTIFIER, &type);
vmngh_unregister_admin_rx_func(VMNGA_ADMIN_OPCODE_RM_PDEV);
vmngh_uninit_ctrl();
vmng_info("Exit module finish.\n");
}