* 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.
*/
#ifndef EVENT_SCHED_UT
#include "pbl/pbl_uda.h"
#include "pbl/pbl_feature_loader.h"
#include "comm_kernel_interface.h"
#include "securec.h"
#include "esched.h"
#include "esched_h2d_msg.h"
#include "esched_fops.h"
#include "esched_host_msg.h"
#ifdef CFG_FEATURE_HARDWARE_SCHED
#include "esched_drv_adapt.h"
#endif
STATIC void esched_convert_dst_engine(struct sched_published_event_info *event_info)
{
if (event_info->dst_engine == VIRTUAL_CCPU_HOST) {
event_info->dst_engine = CCPU_HOST;
}
return;
}
STATIC int esched_host_msg_send(u32 dev_id, struct esched_ctrl_msg *msg, u32 msg_len)
{
int ret;
u32 out_len;
ret = devdrv_common_msg_send(dev_id, (void *)msg, msg_len, msg_len, &out_len, DEVDRV_COMMON_MSG_ESCHED);
if ((ret != 0) || (msg->head.error_code != 0)) {
if ((ret != 0) && (!esched_log_limited(SCHED_LOG_LIMIT_MSG_SEND))) {
sched_err("Send message to device failed. (dev_id=%d; deal_code=%d; ret=%d)\n",
dev_id, msg->head.error_code, ret);
}
return ret != 0 ? ret : msg->head.error_code;
}
return 0;
}
int sched_query_remote_trace_msg_send(u32 chip_id, struct sched_trace_input *para, struct sched_sync_event_trace *sched_trace)
{
struct esched_ctrl_msg msg = {0};
int ret;
sched_remote_msg_head_init(&msg.head, ESCHED_MSG_TYPE_REMOTE_QUERY_TRACE);
msg.trace_msg.para = *para;
ret = esched_host_msg_send(chip_id, (void *)&msg, sizeof(msg));
if (ret == 0) {
*sched_trace = msg.trace_msg.sched_trace;
}
return ret;
}
int sched_publish_event_to_remote(u32 chip_id, u32 event_src,
const struct sched_published_event_info *event_info, struct sched_published_event_func *event_func)
{
struct esched_publish_msg msg;
int ret, real_devid;
u32 total_len = sizeof(struct esched_publish_msg) - SCHED_MAX_EVENT_MSG_LEN_EX * sizeof(char);
if ((event_func->event_ack_func != NULL) || (event_func->event_finish_func != NULL)) {
#ifndef EMU_ST
sched_warn("The callback function is not supported for remote submission.\n");
return DRV_ERROR_NOT_SUPPORT;
#endif
}
sched_remote_msg_head_init(&msg.head, ESCHED_MSG_TYPE_REMOTE_SUBMIT);
msg.submit_msg.event_info = *event_info;
if (event_info->msg_len > 0) {
ret = memcpy_s(msg.submit_msg.msg, SCHED_MAX_EVENT_MSG_LEN_EX, event_info->msg, event_info->msg_len);
if (ret != 0) {
sched_err("Failed to copy variable msg. (pid=%d; gid=%u; event_id=%u)\n",
event_info->pid, event_info->gid, event_info->event_id);
return ret;
}
total_len += event_info->msg_len;
}
real_devid = (chip_id == uda_get_host_id()) ? event_info->dst_devid : chip_id;
return esched_host_msg_send(real_devid, (void *)&msg, total_len);
}
STATIC int sched_publish_event_proxy(u32 devid, struct sched_numa_node *node, struct esched_publish_msg *msg)
{
struct esched_remote_submit_msg *submit_msg = &msg->submit_msg;
struct sched_published_event_func event_func;
int32_t ret;
u32 chip_id = devid;
event_func.event_ack_func = NULL;
event_func.event_finish_func = NULL;
if (submit_msg->event_info.msg_len != 0) {
submit_msg->event_info.msg = submit_msg->msg;
} else {
submit_msg->event_info.msg = NULL;
}
node->curr_msg.dst_pid = submit_msg->event_info.pid;
node->curr_msg.dst_event_id = submit_msg->event_info.event_id;
node->curr_msg.dst_subevent_id = submit_msg->event_info.subevent_id;
submit_msg->event_info.publish_timestamp = sched_get_cur_timestamp();
ret = sched_publish_event_para_check(&submit_msg->event_info);
if (ret != 0) {
return ret;
}
esched_convert_dst_engine(&submit_msg->event_info);
ret = sched_submit_event_pre_proc(chip_id, SCHED_PRE_PROC_POS_REMOTE, &submit_msg->event_info, &event_func);
if (ret != 0) {
return (ret == SCHED_EVENT_PRE_PROC_SUCCESS_RETURN) ? 0 : ret;
}
return sched_publish_event(chip_id, SCHED_PUBLISH_FORM_KERNEL, &submit_msg->event_info, &event_func);
}
STATIC int sched_query_gid_proxy(u32 devid, struct esched_ctrl_msg *msg)
{
u32 host_devid = uda_get_host_id();
struct esched_remote_query_gid_msg *query_msg = &msg->query_gid_msg;
if (query_msg->dst_devid == host_devid) {
return sched_query_local_task_gid(host_devid, query_msg->pid, query_msg->grp_name, &query_msg->gid);
} else {
return sched_query_local_task_gid(devid, query_msg->pid, query_msg->grp_name, &query_msg->gid);
}
}
int sched_query_remote_task_gid_msg_send(u32 chip_id, u32 dst_chip_id, int pid, const char *grp_name, u32 *gid)
{
struct esched_ctrl_msg msg;
int ret, real_devid;
sched_remote_msg_head_init(&msg.head, ESCHED_MSG_TYPE_REMOTE_QUERY_GID);
msg.query_gid_msg.pid = pid;
msg.query_gid_msg.dst_devid = dst_chip_id;
ret = strcpy_s(msg.query_gid_msg.grp_name, EVENT_MAX_GRP_NAME_LEN, grp_name);
if (ret != 0) {
sched_err("Failed to invoke strcpy_s. (chip_id=%u; ret=%d)\n", chip_id, ret);
return DRV_ERROR_INNER_ERR;
}
real_devid = (chip_id == uda_get_host_id()) ? dst_chip_id : chip_id;
ret = esched_host_msg_send(real_devid, (void *)&msg, sizeof(msg));
if (ret == 0) {
*gid = msg.query_gid_msg.gid;
}
return ret;
}
STATIC int32_t sched_dispatch_param_check(u32 src_devid, u32 dst_devid, u32 src_pid, struct esched_remote_submit_msg *submit_msg)
{
int32_t ret;
u32 dst_pid, src_device_master_pid, dst_device_master_pid;
if (dst_devid >= SCHED_MAX_CHIP_NUM) {
sched_err("The devid is invalid. (src_devid=%u; dst_devid=%u)\n", src_devid, dst_devid);
return DRV_ERROR_INVALID_DEVICE;
}
ret = devdrv_query_master_pid_by_device_slave(src_devid, src_pid, &src_device_master_pid);
if (ret != 0) {
sched_err("Query master pid by src_pid failed. (src_devid=%u; src_pid=%u; ret=%d)\n",
src_devid, src_pid, ret);
return DRV_ERROR_NO_PROCESS;
}
dst_pid = submit_msg->event_info.pid;
ret = devdrv_query_master_pid_by_device_slave(dst_devid, dst_pid, &dst_device_master_pid);
if (ret != 0) {
sched_err("Query master pid by dst_pid failed. (dst_devid=%u; dest_pid=%u; ret=%d)\n",
dst_devid, dst_pid, ret);
return DRV_ERROR_NO_PROCESS;
}
if (src_device_master_pid != dst_device_master_pid) {
sched_err("Pid not match. (src_devid=%u; dst_devid=%u; src_pid=%u; dst_pid=%u; src_master_pid=%u; dst_master_pid=%u)\n",
src_devid, dst_devid, src_pid, dst_pid, src_device_master_pid, dst_device_master_pid);
return DRV_ERROR_INNER_ERR;
}
return DRV_ERROR_NONE;
}
STATIC int sched_dispatch_event_to_remote(u32 devid, struct esched_publish_msg *msg)
{
int ret;
u32 dst_devid;
struct esched_publish_msg msg_local;
struct esched_remote_submit_msg *submit_msg = &msg->submit_msg;
u32 total_len = sizeof(struct esched_publish_msg) - SCHED_MAX_EVENT_MSG_LEN_EX * sizeof(char);
dst_devid = submit_msg->event_info.dst_devid;
ret = sched_dispatch_param_check(devid, dst_devid, msg->head.src_pid, submit_msg);
if (ret != 0) {
return ret;
}
ret = memcpy_s(&msg_local.submit_msg, sizeof(struct esched_remote_submit_msg), submit_msg, sizeof(struct esched_remote_submit_msg));
if (ret != 0) {
sched_err("Failed to copy msg. (devid=%u; dst_devid=%u)\n", devid, dst_devid);
return ret;
}
sched_remote_msg_head_init(&msg_local.head, ESCHED_MSG_TYPE_REMOTE_SUBMIT);
total_len += submit_msg->event_info.msg_len;
return esched_host_msg_send(dst_devid, (void *)&msg_local, total_len);
}
#ifdef CFG_FEATURE_HARDWARE_SCHED
STATIC int esched_drv_remote_config_pid(u32 dev_id, u32 msg_type, u32 host_ctrl_pid, u32 pid_type, u32 pid)
{
struct esched_ctrl_msg msg;
int ret;
sched_remote_msg_head_init(&msg.head, msg_type);
msg.host_pid_msg.vfid = 0;
msg.host_pid_msg.host_ctrl_pid = host_ctrl_pid;
msg.host_pid_msg.pid_type = pid_type;
msg.host_pid_msg.pid = pid;
ret = esched_host_msg_send(dev_id, (void *)&msg, sizeof(msg));
if (ret != 0) {
sched_err("Failed to invoke the esched_host_msg_send. (dev_id=%u; pid=%u; error_code=%d; ret=%d)\n",
dev_id, pid, msg.head.error_code, ret);
return -EFAULT;
}
return 0;
}
int esched_drv_remote_add_pid(u32 dev_id, u32 host_ctrl_pid, u32 pid_type, u32 pid)
{
return esched_drv_remote_config_pid(dev_id, ESCHED_MSG_TYPE_ADD_HOST_PID, host_ctrl_pid, pid_type, pid);
}
int esched_drv_remote_del_pid(u32 dev_id, u32 host_ctrl_pid, u32 pid)
{
return esched_drv_remote_config_pid(dev_id, ESCHED_MSG_TYPE_DEL_HOST_PID, host_ctrl_pid, 0, pid);
}
int esched_drv_remote_add_pool(u32 dev_id, u32 cpu_type)
{
struct esched_ctrl_msg msg;
int ret;
sched_remote_msg_head_init(&msg.head, ESCHED_MSG_TYPE_ADD_POOL);
msg.pool_msg.cpu_type = cpu_type;
ret = esched_host_msg_send(dev_id, (void *)&msg, sizeof(msg));
if (ret != 0) {
sched_err("Failed to send msg. (dev_id=%u; error_code=%x; ret=%d)\n", dev_id, msg.head.error_code, ret);
return -EFAULT;
}
return 0;
}
int esched_drv_remote_get_cpu_mbid(u32 dev_id, u32 cpu_type, u32 *mb_id, u32 *wait_mb_id)
{
struct esched_ctrl_msg msg;
int ret;
sched_remote_msg_head_init(&msg.head, ESCHED_MSG_TYPE_GET_CPU_MBID);
msg.mbid_msg.cpu_type = cpu_type;
ret = esched_host_msg_send(dev_id, (void *)&msg, sizeof(msg));
if (ret != 0) {
sched_err("Failed to send msg. (dev_id=%u; error_code=%x; ret=%d)\n",
dev_id, msg.head.error_code, ret);
return -EFAULT;
}
*mb_id = msg.mbid_msg.mb_id;
*wait_mb_id = msg.mbid_msg.wait_mb_id;
return 0;
}
int esched_drv_remote_config_intr(u32 dev_id, u32 irq)
{
struct esched_ctrl_msg msg;
int ret;
sched_remote_msg_head_init(&msg.head, ESCHED_MSG_TYPE_CONF_INTR);
msg.intr_msg.irq = irq;
ret = esched_host_msg_send(dev_id, (void *)&msg, sizeof(msg));
if (ret != 0) {
sched_debug("Invoke the esched_host_msg_send not success. "
"(dev_id=%u; irq=%u; deal_code=%d; ret=%d)\n", dev_id, irq, msg.head.error_code, ret);
return -EFAULT;
}
return 0;
}
int esched_drv_remote_add_mb(u32 dev_id, u32 vf_id)
{
struct esched_ctrl_msg msg;
int ret;
sched_remote_msg_head_init(&msg.head, ESCHED_MSG_TYPE_ADD_MB);
msg.mb_msg.vf_id = vf_id;
ret = esched_host_msg_send(dev_id, (void *)&msg, sizeof(msg));
if (ret != 0) {
sched_err("Failed to invoke the esched_host_msg_send. "
"(dev_id=%u; vf_id=%u; error_code=%d; ret=%d)\n", dev_id, vf_id, msg.head.error_code, ret);
return -EFAULT;
}
return 0;
}
#ifndef EMU_ST
int esched_drv_remote_get_pool_id(u32 dev_id, u32 *pool_id)
{
struct esched_ctrl_msg msg;
int ret;
sched_remote_msg_head_init(&msg.head, ESCHED_MSG_TYPE_GET_POOL_ID);
ret = esched_host_msg_send(dev_id, (void *)&msg, sizeof(msg));
if (ret != 0) {
sched_err("Failed to send msg. (dev_id=%u; error_code=%x; ret=%d)\n",
dev_id, msg.head.error_code, ret);
return -EFAULT;
}
*pool_id = msg.pool_id_msg.pool_id;
return 0;
}
#endif
#endif
STATIC int esched_ctrl_msg_para_check(u32 devid, void *data, u32 in_data_len, u32 *real_out_len)
{
struct esched_publish_msg *msg = NULL;
struct esched_msg_head *msg_head = (struct esched_msg_head *)data;
u32 ctrl_len = sizeof(struct esched_publish_msg) - SCHED_MAX_EVENT_MSG_LEN_EX * sizeof(char);
if ((data == NULL) || (real_out_len == NULL)) {
sched_err("The variable devid, data or real_out_len is invalid. (devid=%u; in_data_len=%u)\n", devid, in_data_len);
return -EINVAL;
}
if ((msg_head->type == ESCHED_MSG_TYPE_REMOTE_SUBMIT) || (msg_head->type == ESCHED_MSG_TYPE_D2D_EVENT_DISPATCH)) {
if (in_data_len < ctrl_len) {
sched_err("In_data_len is invalid. (devid=%u; in_data_len=%u; ctrl_len=%u)\n", devid, in_data_len, ctrl_len);
return -EINVAL;
}
msg = (struct esched_publish_msg *)data;
if (in_data_len < (ctrl_len + msg->submit_msg.event_info.msg_len)) {
sched_err("In_data_len is invalid. (devid=%u; in_data_len=%u; msg_len=%u; ctrl_len=%u)\n",
devid, in_data_len, msg->submit_msg.event_info.msg_len, ctrl_len);
return -EINVAL;
}
} else {
if (in_data_len != sizeof(struct esched_ctrl_msg)) {
sched_err("In_data_len is invalid. (devid=%u; in_data_len=%u)\n", devid, in_data_len);
return -EINVAL;
}
}
return 0;
}
STATIC int esched_ctrl_msg_recv(u32 devid, void *data, u32 in_data_len, u32 out_data_len, u32 *real_out_len)
{
struct esched_msg_head *msg = (struct esched_msg_head *)data;
int ret;
struct sched_numa_node *node = NULL;
ret =esched_ctrl_msg_para_check(devid, data, in_data_len, real_out_len);
if (ret != 0) {
return -EINVAL;
}
node = esched_dev_get(devid);
if (node == NULL) {
sched_err("Invalid device. (chip_id=%u)\n", devid);
return DRV_ERROR_INVALID_DEVICE;
}
node->curr_msg.msg_type = msg->type;
switch (msg->type) {
case ESCHED_MSG_TYPE_REMOTE_SUBMIT:
ret = sched_publish_event_proxy(devid, node, (struct esched_publish_msg *)data);
*real_out_len = sizeof(struct esched_msg_head);
break;
case ESCHED_MSG_TYPE_REMOTE_QUERY_GID:
ret = sched_query_gid_proxy(devid, (struct esched_ctrl_msg *)data);
*real_out_len = sizeof(struct esched_ctrl_msg);
break;
case ESCHED_MSG_TYPE_D2D_EVENT_DISPATCH:
ret = sched_dispatch_event_to_remote(devid, (struct esched_publish_msg *)data);
*real_out_len = sizeof(struct esched_msg_head);
break;
default:
ret = -EINVAL;
break;
}
if ((ret != 0) && !((msg->type == ESCHED_MSG_TYPE_REMOTE_QUERY_GID) && (ret == DRV_ERROR_UNINIT))) {
sched_warn("invoke the sched_publish_event_proxy not success. (devid=%u; type=%d; ret=%d)\n",
devid, msg->type, ret);
}
node->curr_msg.msg_type = ESCHED_MSG_TYPE_MAX_NUM;
msg->error_code = ret;
esched_dev_put(node);
return 0;
}
struct devdrv_common_msg_client esched_host_msg_client = {
.type = DEVDRV_COMMON_MSG_ESCHED,
.common_msg_recv = esched_ctrl_msg_recv,
};
STATIC int esched_init_instance(u32 dev_id)
{
struct sched_dev_ops ops;
int ret;
#ifdef CFG_FEATURE_HARDWARE_SCHED
esched_setup_dev_hw_ops(&ops);
#else
esched_setup_dev_soft_ops(&ops);
#endif
ret = esched_create_dev(dev_id, &ops);
if (ret != 0) {
sched_err("Create dev failed. (dev_id=%u)\n", dev_id);
return ret;
}
ret = module_feature_auto_init_dev(dev_id);
if (ret != 0) {
#ifndef EMU_ST
esched_destroy_dev(dev_id);
sched_err("module feature init failed. (dev_id=%u)\n", dev_id);
return ret;
#endif
}
return 0;
}
STATIC int esched_uninit_instance(u32 dev_id)
{
module_feature_auto_uninit_dev(dev_id);
esched_destroy_dev(dev_id);
return 0;
}
#define ESCHED_HOST_NOTIFIER "esched_host"
static int esched_host_notifier_func(u32 udevid, enum uda_notified_action action)
{
int ret = 0;
if (udevid >= SCHED_MAX_CHIP_NUM) {
sched_err("Invalid para. (udevid=%u)\n", udevid);
return -EINVAL;
}
switch (action) {
case UDA_INIT:
ret = esched_init_instance(udevid);
break;
case UDA_UNINIT:
ret = esched_uninit_instance(udevid);
break;
#if defined(CFG_FEATURE_HARDWARE_MIA)
case UDA_TO_MIA:
(void)esched_drv_reset_phy_dev(udevid);
sched_info("Enable dev_id %u sriov\n", udevid);
break;
case UDA_TO_SIA:
esched_drv_restore_phy_dev(udevid);
sched_info("Disable dev_id %u sriov\n", udevid);
break;
#endif
default:
return 0;
}
sched_info("notifier action. (udevid=%u; action=%d; ret=%d)\n", udevid, action, ret);
return ret;
}
int esched_client_init(void)
{
struct uda_dev_type type;
int ret;
uda_davinci_near_real_entity_type_pack(&type);
ret = uda_notifier_register(ESCHED_HOST_NOTIFIER, &type, UDA_PRI3, esched_host_notifier_func);
if (ret != 0) {
sched_err("Failed to register client. (ret=%d)\n", ret);
return ret;
}
ret = devdrv_register_common_msg_client(&esched_host_msg_client);
if (ret != 0) {
(void)uda_notifier_unregister(ESCHED_HOST_NOTIFIER, &type);
sched_err("Failed to invoke the devdrv_register_common_msg_client. (type=%d)\n", esched_host_msg_client.type);
return ret;
}
return 0;
}
void esched_client_uninit(void)
{
struct uda_dev_type type;
(void)devdrv_unregister_common_msg_client(0, &esched_host_msg_client);
uda_davinci_near_real_entity_type_pack(&type);
(void)uda_notifier_unregister(ESCHED_HOST_NOTIFIER, &type);
}
#else
int tmp_esched_host_msg()
{
return 0;
}
int tmp_esched_mia_init()
{
return 0;
}
#endif