* Copyright (c) Huawei Technologies Co., Ltd. 2025-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_ioctl_pub.h"
#include "ka_base_pub.h"
#include "ka_compiler_pub.h"
#include "pbl_feature_loader.h"
#include "pbl_task_ctx.h"
#include "pbl_uda.h"
#include "svm_pub.h"
#include "svm_kern_log.h"
#include "copy_pub.h"
#include "svm_ioctl_ex.h"
#include "framework_cmd.h"
#include "async_copy_task.h"
#include "async_copy_ctx.h"
#include "async_copy_core.h"
static int async_copy_extract_va_info_from_ioctl_para(struct svm_async_copy_submit_para *para,
struct copy_va_info *info)
{
int ret;
ret = uda_devid_to_udevid_ex(para->src_devid, &info->src_udevid);
if (ret != 0) {
svm_err("uda_devid_to_udevid_ex failed. (ret=%d; src_devid=%u)\n", ret, para->src_devid);
return ret;
}
ret = uda_devid_to_udevid_ex(para->dst_devid, &info->dst_udevid);
if (ret != 0) {
svm_err("uda_devid_to_udevid_ex failed. (ret=%d; dst_devid=%u)\n", ret, para->dst_devid);
return ret;
}
info->src_va = para->src_va;
info->dst_va = para->dst_va;
info->size = para->size;
info->src_host_tgid = para->src_host_tgid;
info->dst_host_tgid = para->dst_host_tgid;
return 0;
}
static int _async_copy_ioctl_submit(struct async_copy_ctx *ctx, unsigned long __ka_user arg)
{
struct svm_async_copy_submit_para para;
struct copy_va_info info;
int ret;
ret = (int)ka_base_copy_from_user(¶, (void __ka_user *)(uintptr_t)arg, sizeof(struct svm_async_copy_submit_para));
if (ret != 0) {
svm_err("Copy_from_user fail.\n");
return -EINVAL;
}
ret = async_copy_extract_va_info_from_ioctl_para(¶, &info);
if (ret != 0) {
return ret;
}
ret = copy_va_info_check(copy_va_info_get_exec_udevid(&info), &info);
if (ret != 0) {
return ret;
}
ret = async_copy_task_submit(ctx, &info, ¶.id);
if (ret != 0) {
return ret;
}
ret = ka_base_copy_to_user((void *)(uintptr_t)arg, (void *)¶, sizeof(struct svm_async_copy_submit_para));
if (ret != 0) {
svm_err("Copy to user failed. (ret=%d)\n", ret);
async_copy_task_wait(ctx, para.id);
return -EINVAL;
}
return 0;
}
static int _async_copy_ioctl_wait(struct async_copy_ctx *ctx, unsigned long __ka_user arg)
{
struct svm_async_copy_wait_para para;
int ret;
ret = ka_base_copy_from_user(¶, (void __ka_user *)(uintptr_t)arg, sizeof(struct svm_async_copy_wait_para));
if (ret != 0) {
svm_err("Copy_from_user fail.\n");
return -EINVAL;
}
return async_copy_task_wait(ctx, para.id);
}
static int async_copy_ioctl_submit(u32 udevid, u32 cmd, unsigned long arg)
{
struct async_copy_ctx *ctx = NULL;
int ret;
ctx = async_copy_ctx_get(udevid, ka_task_get_current_tgid());
if (ctx == NULL) {
svm_err("async_copy_ctx_get fail. (devid=%u; tgid=%d)\n", udevid, ka_task_get_current_tgid());
return -EINVAL;
}
ret = _async_copy_ioctl_submit(ctx, arg);
async_copy_ctx_put(ctx);
return ret;
}
static int async_copy_ioctl_wait(u32 udevid, u32 cmd, unsigned long arg)
{
struct async_copy_ctx *ctx = NULL;
int ret;
ctx = async_copy_ctx_get(udevid, ka_task_get_current_tgid());
if (ctx == NULL) {
return -EINVAL;
}
ret = _async_copy_ioctl_wait(ctx, arg);
async_copy_ctx_put(ctx);
return ret;
}
int async_copy_ioctl_init(void)
{
svm_register_ioctl_cmd_handle(_IOC_NR(SVM_ASYNC_COPY_SUBMIT), async_copy_ioctl_submit);
svm_register_ioctl_cmd_handle(_IOC_NR(SVM_ASYNC_COPY_WAIT), async_copy_ioctl_wait);
return 0;
}
DECLAER_FEATURE_AUTO_INIT(async_copy_ioctl_init, FEATURE_LOADER_STAGE_6);