* 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 "pbl_feature_loader.h"
#include "pbl_soc_res.h"
#include "casm_kernel.h"
#include "svm_pub.h"
#include "svm_ub_mem.h"
#include "svm_addr_desc.h"
#include "svm_kern_log.h"
#include "svm_sub_event_type.h"
#include "va_reserve_msg.h"
#include "linear_mem.h"
#define AIC_ATU_CFG_NAME "AIC_ATU_CFG_BASE"
#define LINEAR_MEM_MAX_SHARE_MEM_SIZE (48 * SVM_BYTES_PER_GB)
static u64 _linear_mem_get_access_va(u32 udevid, u32 mem_id, u64 offset)
{
struct soc_reg_base_info io_base;
int ret;
ret = soc_resmng_dev_get_reg_base(udevid, AIC_ATU_CFG_NAME, &io_base);
if (ret != 0) {
return 0ULL;
}
return io_base.io_base + (mem_id * LINEAR_MEM_MAX_SHARE_MEM_SIZE) + offset;
}
static int linear_mem_set_access_va(u32 udevid, u64 va, u64 size)
{
struct soc_reg_base_info io_base;
int ret;
ret = soc_resmng_dev_get_reg_base(udevid, AIC_ATU_CFG_NAME, &io_base);
if (ret == 0) {
if ((io_base.io_base == va) && (io_base.io_base_size == size)) {
return 0;
}
svm_warn("Repeat set different base. (udevid=%u)\n", udevid);
}
io_base.io_base = va;
io_base.io_base_size = size;
ret = soc_resmng_dev_set_reg_base(udevid, AIC_ATU_CFG_NAME, &io_base);
if (ret != 0) {
svm_err("Set linear_mem_base failed. (ret=%d; udevid=%u)\n", ret, udevid);
return ret;
}
return 0;
}
static int um_va_reserve_host_post_handle(u32 udevid, int master_tgid, int slave_tgid, void *msg, u32 msg_len)
{
struct svm_va_reserve_msg *reserve_msg = (struct svm_va_reserve_msg *)msg;
int ret = 0;
if (msg_len != sizeof(*reserve_msg)) {
svm_err("Invalid para. (udevid=%u; master_tgid=%d; slave_tgid=%d; msg_len=%u)\n",
udevid, master_tgid, slave_tgid, msg_len);
return -EINVAL;
}
if (reserve_msg->status != VA_RESERVE_STATUS_OK) {
return 0;
}
if (((reserve_msg->flag & SVM_MMAP_FLAG_PRIVATE) != 0) && (reserve_msg->size > SVM_BYTES_PER_TB)) {
ret = linear_mem_set_access_va(udevid, reserve_msg->va, reserve_msg->size);
}
return ret;
}
int linear_mem_get_access_va(u32 udevid, struct svm_global_va *src_va, struct casm_src_ex *src_ex, u64 *ex_info)
{
u32 mem_id;
u64 offset;
svm_ub_va_to_mem_id_and_offset(src_ex->updated_va, &mem_id, &offset);
*ex_info = _linear_mem_get_access_va(udevid, mem_id, offset);
return 0;
}
int linear_mem_register_ops(void)
{
svm_um_register_handle(SVM_VA_RESERVE_EVENT, NULL, NULL, um_va_reserve_host_post_handle);
svm_casm_register_get_src_va_ex_info_handle(linear_mem_get_access_va);
return 0;
}
DECLAER_FEATURE_AUTO_INIT(linear_mem_register_ops, FEATURE_LOADER_STAGE_2);