* 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_kernel_def_pub.h"
#include "virtmnghost_msg_admin.h"
#include "virtmng_msg_admin.h"
#include "vmng_kernel_interface.h"
#include "virtmng_msg_common.h"
#include "virtmng_public_def.h"
static vmngh_admin_func g_vmngh_msg_admin_func_ops[] = {
NULL,
};
#define VMNG_ADMIN_PROC_OPCODE_MAX (sizeof(g_vmngh_msg_admin_func_ops) / sizeof(void *))
int vmngh_register_admin_rx_func(int opcode, vmngh_admin_func admin_func)
{
if (opcode >= VMNG_ADMIN_PROC_OPCODE_MAX) {
vmng_err("opcode is invalid. (opcode=%u)\n", opcode);
return -EINVAL;
}
if (g_vmngh_msg_admin_func_ops[opcode] != NULL) {
vmng_err("opcode has registered. (opcode=%u)\n", opcode);
return -EINVAL;
}
g_vmngh_msg_admin_func_ops[opcode] = admin_func;
return 0;
}
KA_EXPORT_SYMBOL(vmngh_register_admin_rx_func);
void vmngh_unregister_admin_rx_func(int opcode)
{
if (opcode >= VMNG_ADMIN_PROC_OPCODE_MAX) {
vmng_err("opcode is invalid. (opcode=%u)\n", opcode);
return;
}
g_vmngh_msg_admin_func_ops[opcode] = NULL;
}
KA_EXPORT_SYMBOL(vmngh_unregister_admin_rx_func);
STATIC int vmngh_admin_rx_msg_proc(void *msg_chan, struct vmng_msg_chan_rx_proc_info *proc_info)
{
struct vmng_msg_chan_rx *admin_msg_chan = (struct vmng_msg_chan_rx *)msg_chan;
struct vmng_msg_dev *msg_dev = (struct vmng_msg_dev *)admin_msg_chan->msg_dev;
u32 opcode;
int ret;
if (proc_info == NULL) {
vmng_err("Input parameter is error.\n");
return -EINVAL;
}
if (proc_info->data == NULL) {
vmng_err("Input parameter is error.\n");
return -EINVAL;
}
opcode = proc_info->opcode_d2;
if (opcode >= VMNG_ADMIN_PROC_OPCODE_MAX) {
vmng_err("opcode is invalid. (opcode=%u)\n", opcode);
return -ENOSYS;
}
if (g_vmngh_msg_admin_func_ops[opcode] == NULL) {
vmng_err("Got an admin opcode, but no process function. (devid=%u; fid=%u; opcode=%u)\n",
msg_dev->dev_id, msg_dev->fid, opcode);
return -EINVAL;
}
ret = g_vmngh_msg_admin_func_ops[opcode](msg_dev, proc_info);
if (ret != 0) {
vmng_err("Admin func ops error. (devid=%u; fid=%u; ret=%d)\n", msg_dev->dev_id, msg_dev->fid, ret);
return -EINVAL;
}
return ret;
}
void vmngh_init_admin_msg(struct vmng_msg_dev *msg_dev)
{
struct vmng_msg_cluster *msg_cluster = NULL;
struct vmng_msg_chan_rx *msg_chan_rx = NULL;
struct vmng_msg_chan_tx *msg_chan_tx = NULL;
msg_cluster = &(msg_dev->msg_cluster[VMNG_MSG_CHAN_TYPE_ADMIN]);
ka_task_mutex_init(&msg_cluster->mutex);
msg_dev->admin_tx = &(msg_dev->msg_chan_tx[VMNG_MSG_CHAN_TYPE_ADMIN]);
msg_chan_tx = msg_dev->admin_tx;
msg_chan_tx->tx_send_irq = msg_dev->msix_irq_base + VMNG_MSIX_MSG_ADMIN;
msg_chan_tx->tx_finish_irq = 0;
msg_chan_tx->send_irq_to_remote = msg_dev->ops.send_irq_to_remote;
ka_task_mutex_init(&msg_chan_tx->mutex);
msg_chan_tx->status = VMNG_MSG_CHAN_STATUS_IDLE;
msg_dev->admin_rx = &(msg_dev->msg_chan_rx[VMNG_MSG_CHAN_TYPE_ADMIN]);
msg_chan_rx = msg_dev->admin_rx;
msg_chan_rx->rx_recv_irq = msg_dev->db_irq_base + VMNG_DB_MSG_ADMIN;
msg_chan_rx->rx_proc = vmngh_admin_rx_msg_proc;
msg_chan_rx->rx_wq = ka_task_create_singlethread_workqueue("vpc_admin_msg_chan_proc");
if (msg_chan_rx->rx_wq == NULL) {
vmng_err("Creat workqueue failed. (dev_id=%u)\n", msg_dev->dev_id);
return;
}
KA_TASK_INIT_WORK(&msg_chan_rx->rx_work, vmng_msg_rx_msg_task);
msg_chan_rx->status = VMNG_MSG_CHAN_STATUS_IDLE;
msg_dev->admin_db_id = msg_chan_rx->rx_recv_irq;
vmng_info("Admin init OK. (dev_id=%u; fid=%u; tx_irq=%u; rx_irq=%u)\n", msg_dev->dev_id, msg_dev->fid,
msg_chan_tx->tx_send_irq, msg_chan_rx->rx_recv_irq);
}
void vmngh_uninit_admin_msg(struct vmng_msg_dev *msg_dev)
{
struct vmng_msg_cluster *msg_cluster = NULL;
struct vmng_msg_chan_rx *msg_chan_rx = NULL;
struct vmng_msg_chan_tx *msg_chan_tx = NULL;
msg_cluster = &(msg_dev->msg_cluster[VMNG_MSG_CHAN_TYPE_ADMIN]);
msg_dev->admin_tx = &(msg_dev->msg_chan_tx[VMNG_MSG_CHAN_TYPE_ADMIN]);
msg_chan_tx = msg_dev->admin_tx;
msg_chan_tx->status = VMNG_MSG_CHAN_STATUS_DISABLE;
msg_dev->admin_rx = &(msg_dev->msg_chan_rx[VMNG_MSG_CHAN_TYPE_ADMIN]);
msg_chan_rx = msg_dev->admin_rx;
msg_chan_rx->status = VMNG_MSG_CHAN_STATUS_DISABLE;
if (msg_chan_rx->rx_wq != NULL) {
ka_task_destroy_workqueue(msg_chan_rx->rx_wq);
msg_chan_rx->rx_wq = NULL;
}
vmng_info("Admin uninit OK. (dev_id=%u; fid=%u)\n", msg_dev->dev_id, msg_dev->fid);
}