* 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 "virtmnghost_external.h"
#include "virtmnghost_unit.h"
#include "virtmnghost_ctrl.h"
#include "hw_vdavinci.h"
#include "virtmng_resource.h"
#include "virtmng_public_def.h"
#include "comm_kernel_interface.h"
#include "vmng_kernel_interface.h"
#include "vmng_mem_alloc_interface.h"
int vmngh_alloc_external_db_entries(struct vmngh_vd_dev *vd_dev)
{
struct vmngh_db_mng *db_mng = NULL;
struct vmngh_db_entry *db_info = NULL;
u32 i;
db_mng = &(vd_dev->db_mng);
db_mng->db_num = VMNG_DB_NUM_EXTERNAL;
db_mng->db_entries = (struct vmngh_db_entry *)vmng_kzalloc(sizeof(struct vmngh_db_entry) * db_mng->db_num, KA_GFP_KERNEL);
if (db_mng->db_entries == NULL) {
vmng_err("Alloc db entries failed. (dev_id=%u; fid=%u)\n", vd_dev->dev_id, vd_dev->fid);
return -ENOMEM;
}
for (i = 0; i < db_mng->db_num; i++) {
db_info = &(db_mng->db_entries[i]);
db_info->index = VMNG_DB_BASE_EXTERNAL + i;
db_info->handler = NULL;
db_info->data = NULL;
db_info->db_count = 0;
}
return 0;
}
void vmngh_free_external_db_entries(struct vmngh_vd_dev *vd_dev)
{
if ((vd_dev != NULL) && (vd_dev->db_mng.db_entries != NULL)) {
vmng_kfree(vd_dev->db_mng.db_entries);
vd_dev->db_mng.db_entries = NULL;
}
}
int vmngh_get_local_db(u32 dev_id, u32 fid, enum vmng_get_irq_type type, u32 *db_base, u32 *db_num)
{
if (vmngh_dev_id_check(dev_id, fid) != 0) {
vmng_err("Parameter check failed. (dev_id=%u; fid=%u)\n", dev_id, fid);
return -EINVAL;
}
if (db_base == NULL) {
vmng_err("Input parameter is error. (dev_id=%u; fid=%u)\n", dev_id, fid);
return -EINVAL;
}
if (db_num == NULL) {
vmng_err("Input parameter is error. (dev_id=%u; fid=%u)\n", dev_id, fid);
return -EINVAL;
}
switch (type) {
case VMNG_GET_IRQ_TYPE_TSDRV:
*db_base = VMNG_DB_BASE_EXTERNAL_TSDRV;
*db_num = VMNG_DB_NUM_EXTERNAL_TSDRV;
break;
default:
vmng_err("type is overflow. (dev_id=%u; fid=%u; type=%u)\n", dev_id, fid, type);
return -EINVAL;
}
return 0;
}
KA_EXPORT_SYMBOL(vmngh_get_local_db);
int vmngh_register_local_db(u32 dev_id, u32 fid, u32 db_index, db_handler_t handler, void *data)
{
struct vmngh_vd_dev *vd_dev = NULL;
struct vmngh_db_mng *db_mng = NULL;
if (handler == NULL) {
vmng_err("Input parameter is error. (dev_id=%u; fid=%u)\n", dev_id, fid);
return -EINVAL;
}
if ((db_index >= VMNG_DB_BASE_EXTERNAL_MAX) || (db_index < VMNG_DB_BASE_EXTERNAL_MIN)) {
vmng_err("Input parameter is error. (dev_id=%u; fid=%u; db_index=%u)\n", dev_id, fid, db_index);
return -EINVAL;
}
db_index = db_index - VMNG_DB_BASE_EXTERNAL_MIN;
vd_dev = vmngh_get_bottom_half_vdev_by_id(dev_id, fid);
if (vd_dev == NULL) {
vmng_err("mdev is not ready. (dev_id=%u; fid=%u)\n", dev_id, fid);
return -EINVAL;
}
db_mng = &(vd_dev->db_mng);
if (db_index >= db_mng->db_num) {
vmng_err("db_index is error. (dev_id=%u; fid=%u; db_index=%u)\n",
dev_id, fid, db_index + VMNG_DB_BASE_EXTERNAL_MIN);
return -EINVAL;
}
db_mng->db_entries[db_index].handler = handler;
db_mng->db_entries[db_index].data = data;
return 0;
}
KA_EXPORT_SYMBOL(vmngh_register_local_db);
* otherwise vpc will invoke unknown func pointer, as vm still send db to pm.
*/
int vmngh_unregister_local_db(u32 dev_id, u32 fid, u32 db_index, const void *data)
{
struct vmngh_vd_dev *vd_dev = NULL;
struct vmngh_db_mng *db_mng = NULL;
if ((db_index >= VMNG_DB_BASE_EXTERNAL_MAX) || (db_index < VMNG_DB_BASE_EXTERNAL_MIN)) {
vmng_err("db_index is error. (dev_id=%u; fid=%u; db_index=%u)\n", dev_id, fid, db_index);
return -EINVAL;
}
db_index = db_index - VMNG_DB_BASE_EXTERNAL_MIN;
vd_dev = vmngh_get_bottom_half_vdev_by_id(dev_id, fid);
if (vd_dev == NULL) {
vmng_err("mdev is not ready. (dev_id=%u; fid=%u)\n", dev_id, fid);
return -EINVAL;
}
db_mng = &(vd_dev->db_mng);
if (db_index >= db_mng->db_num) {
vmng_err("db_index is error. (dev_id=%u; fid=%u; db_index=%u)\n", dev_id, fid, db_index);
return -EINVAL;
}
if (db_mng->db_entries[db_index].data != data) {
vmng_err("Irq data is error. (dev_id=%u; fid=%u)\n", dev_id, fid);
return -EINVAL;
}
db_mng->db_entries[db_index].handler = NULL;
db_mng->db_entries[db_index].data = NULL;
return 0;
}
KA_EXPORT_SYMBOL(vmngh_unregister_local_db);
int vmngh_external_db_handler(struct vmngh_vd_dev *vd_dev, int db_index)
{
struct vmngh_db_mng *db_mng = NULL;
struct vmngh_db_entry *db_info = NULL;
db_mng = &(vd_dev->db_mng);
db_info = &(db_mng->db_entries[db_index - VMNG_DB_BASE_EXTERNAL_MIN]);
db_info->db_count++;
if (db_info->handler == NULL) {
vmng_err("handler is NULL. (dev_id=%u; fid=%u; db_index=%u)\n", vd_dev->dev_id, vd_dev->fid, db_index);
return -EINVAL;
}
return db_info->handler(db_index, db_info->data);
}
int vmngh_get_remote_msix(u32 dev_id, u32 fid, enum vmng_get_irq_type type, u32 *msix_base, u32 *msix_num)
{
if (vmngh_dev_id_check(dev_id, fid) != 0) {
vmng_err("Parameter check failed. (dev_id=%u; fid=%u)\n", dev_id, fid);
return -EINVAL;
}
if (msix_base == NULL) {
vmng_err("Input parameter is error. (dev_id=%u; fid=%u; type=%u)\n", dev_id, fid, type);
return -EINVAL;
}
if (msix_num == NULL) {
vmng_err("Input parameter is error. (dev_id=%u; fid=%u; type=%u)\n", dev_id, fid, type);
return -EINVAL;
}
switch (type) {
case VMNG_GET_IRQ_TYPE_TSDRV:
*msix_base = VMNG_MSIX_BASE_EXTERNAL_TSDRV;
*msix_num = VMNG_MSIX_NUM_EXTERNAL_TSDRV;
break;
default:
vmng_err("Parameter type is overflow. (dev_id=%u; fid=%u; type=%u)\n", dev_id, fid, type);
return -EINVAL;
}
return 0;
}
KA_EXPORT_SYMBOL(vmngh_get_remote_msix);
int vmngh_trigger_remote_msix(u32 dev_id, u32 fid, u32 msix_index)
{
struct vmngh_vd_dev *vd_dev = NULL;
u32 msix_offset;
int ret;
if ((msix_index >= VMNG_MSIX_BASE_EXTERNAL_MAX) || (msix_index < VMNG_DB_BASE_EXTERNAL_MIN)) {
vmng_err("Input parameter is error. (dev_id=%u; fid=%u; msix_index=%u)\n", dev_id, fid, msix_index);
return -EINVAL;
}
vd_dev = vmngh_get_bottom_half_vdev_by_id(dev_id, fid);
if (vd_dev == NULL) {
vmng_err("mdev is not ready. (dev_id=%u; fid=%u)\n", dev_id, fid);
return -EINVAL;
}
msix_offset = vd_dev->shr_para->msix_offset;
ret = hw_dvt_hypervisor_inject_msix(vd_dev->vdavinci, msix_index + msix_offset);
if (ret != 0) {
vmng_err("Send msix to remote failed. (dev_id=%u; mdev_id=%u; msix=%u)\n", dev_id, fid, msix_index);
return -ENODEV;
}
return 0;
}
KA_EXPORT_SYMBOL(vmngh_trigger_remote_msix);