* Copyright (c) 2025 Huawei Technologies Co., Ltd.
* This program is free software, you can redistribute it and/or modify it under the terms and conditions of
* CANN Open Software License Agreement Version 2.0 (the "License").
* Please refer to the License for details. You may not use this file except in compliance with the License.
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
* See LICENSE in the root of the software repository for the full text of the License.
*/
#include <pthread.h>
#include <semaphore.h>
#include "ascend_hal.h"
#include "uref.h"
#include "rbtree.h"
#include "securec.h"
#include "svm_log.h"
#include "svm_atomic.h"
#include "svm_user_adapt.h"
#include "svm_pagesize.h"
#include "normal_malloc.h"
#include "cache_malloc.h"
#include "svm_dbi.h"
#include "svm_apbi.h"
#include "va_mng.h"
#include "malloc_mng.h"
#define MNG_OPS_NUM 2
enum handle_state {
HANDLE_STATE_UNINITED = 0U,
HANDLE_STATE_INITED,
HANDLE_STATE_MAX
};
struct handle_mng {
struct rbtree_root root;
pthread_rwlock_t rwlock;
struct svm_mng_ops *ops[MNG_OPS_NUM];
};
typedef struct handle {
struct rbtree_node node;
u32 ref;
u32 task_bitmap;
pthread_rwlock_t rwlock;
enum handle_state state;
struct svm_prop prop;
bool is_from_cache;
u64 align;
void *priv;
struct svm_priv_ops *priv_ops;
} handle_t;
static struct handle_mng mng = {.root = RB_ROOT, .rwlock = PTHREAD_RWLOCK_INITIALIZER};
void svm_mng_set_ops(struct svm_mng_ops *ops)
{
int i;
pthread_rwlock_wrlock(&mng.rwlock);
for (i = 0; i < MNG_OPS_NUM; i++) {
if (mng.ops[i] == NULL) {
mng.ops[i] = ops;
break;
}
}
pthread_rwlock_unlock(&mng.rwlock);
}
static int svm_mng_ops_post_malloc(void *handle, u64 start, struct svm_prop *prop)
{
int i;
for (i = 0; i < MNG_OPS_NUM; i++) {
if ((mng.ops[i] != NULL) && (mng.ops[i]->post_malloc!= NULL)) {
int ret = mng.ops[i]->post_malloc(handle, start, prop);
if (ret != 0) {
return ret;
}
}
}
return 0;
}
static void svm_mng_ops_pre_free(void *handle, u64 start, struct svm_prop *prop)
{
int i;
for (i = 0; i < MNG_OPS_NUM; i++) {
if ((mng.ops[i] != NULL) && (mng.ops[i]->pre_free!= NULL)) {
mng.ops[i]->pre_free(handle, start, prop);
}
}
}
static void rb_range_of_handle(struct rbtree_node *node, struct rb_range_handle *range)
{
handle_t *handle = rb_entry(node, handle_t, node);
range->start = handle->prop.start;
range->end = handle->prop.start + handle->prop.size - 1;
}
static void handle_set_state(handle_t *handle, enum handle_state state)
{
handle->state = state;
}
static bool handle_is_match_state(handle_t *handle, enum handle_state state)
{
return (handle->state == state);
}
static void handle_wrlock(handle_t *handle)
{
(void)pthread_rwlock_wrlock(&handle->rwlock);
}
static void handle_unlock(handle_t *handle)
{
(void)pthread_rwlock_unlock(&handle->rwlock);
}
static int handle_set_priv(handle_t *handle, void *priv, struct svm_priv_ops *priv_ops)
{
if ((handle->priv != NULL) || (handle->priv_ops != NULL)) {
return DRV_ERROR_REPEATED_INIT;
}
handle->priv = priv;
handle->priv_ops = priv_ops;
return DRV_ERROR_NONE;
}
static void *handle_get_priv(handle_t *handle)
{
return handle->priv;
}
static int handle_release_priv(handle_t *handle, bool force)
{
int ret;
if ((handle->priv_ops != NULL) && (handle->priv_ops->release != NULL)) {
ret = handle->priv_ops->release(handle->priv, force);
if (ret != DRV_ERROR_NONE) {
svm_err("Handle priv_ops.pre_release failed. (ret=%d; start=0x%llx; size=%llu)\n",
ret, handle->prop.start, handle->prop.size);
return ret;
}
handle->priv = NULL;
handle->priv_ops = NULL;
return DRV_ERROR_NONE;
}
if (handle->state == HANDLE_STATE_INITED) {
return svm_flag_is_must_with_priv(handle->prop.flag) ? DRV_ERROR_INVALID_VALUE : DRV_ERROR_NONE;
}
return DRV_ERROR_NONE;
}
static int handle_get_prop(handle_t *handle, u64 va, struct svm_prop *prop)
{
if ((handle->priv_ops != NULL) && (handle->priv_ops->get_prop != NULL)) {
return handle->priv_ops->get_prop(handle->priv, va, prop);
}
*prop = handle->prop;
return DRV_ERROR_NONE;
}
static handle_t *handle_get(u64 va)
{
handle_t *handle = NULL;
struct rbtree_node *node = NULL;
struct rb_range_handle rb_range = {.start = va, .end = va};
pthread_rwlock_rdlock(&mng.rwlock);
node = rbtree_search_by_range(&mng.root, &rb_range, rb_range_of_handle);
if (node != NULL) {
handle = rb_entry(node, handle_t, node);
if (handle_is_match_state(handle, HANDLE_STATE_INITED) == false) {
pthread_rwlock_unlock(&mng.rwlock);
return NULL;
}
svm_atomic_inc(&handle->ref);
}
pthread_rwlock_unlock(&mng.rwlock);
return handle;
}
static void handle_put(handle_t *handle)
{
svm_atomic_dec(&handle->ref);
}
static handle_t *handle_alloc(void)
{
handle_t *handle = NULL;
handle = svm_ua_calloc(1, sizeof(handle_t));
if (handle == NULL) {
svm_err("Calloc handle failed. (size=%llu)\n", sizeof(handle_t));
}
return handle;
}
static void handle_free(handle_t *handle)
{
svm_ua_free(handle);
}
static void handle_init(handle_t *handle, struct svm_prop *prop, bool is_from_cache, u64 align)
{
RB_CLEAR_NODE(&handle->node);
handle_set_state(handle, HANDLE_STATE_INITED);
(void)pthread_rwlock_init(&handle->rwlock, NULL);
handle->ref = 0;
handle->prop = *prop;
handle->is_from_cache = is_from_cache;
handle->align = align;
if ((prop->devid <= SVM_MAX_DEV_AGENT_NUM) && (!svm_flag_attr_is_va_only(prop->flag))) {
handle->task_bitmap = 1;
}
handle->priv = NULL;
handle->priv_ops = NULL;
}
static int handle_uninit(handle_t *handle, bool force)
{
int ret;
ret = handle_release_priv(handle, force);
if (ret != DRV_ERROR_NONE) {
return ((ret == DRV_ERROR_BUSY) ? DRV_ERROR_CLIENT_BUSY : ret);
}
handle_set_state(handle, HANDLE_STATE_UNINITED);
RB_CLEAR_NODE(&handle->node);
return DRV_ERROR_NONE;
}
static int _handle_insert(handle_t *handle)
{
int ret;
ret = rbtree_insert_by_range(&mng.root, &handle->node, rb_range_of_handle);
if (ret != 0) {
return DRV_ERROR_BUSY;
}
return 0;
}
static int _handle_erase(handle_t *handle)
{
if (svm_atomic_read(&handle->ref) != 0) {
svm_err("Handle is still occupied. (ref=%d)\n", handle->ref);
return DRV_ERROR_CLIENT_BUSY;
}
_rbtree_erase(&mng.root, &handle->node);
return DRV_ERROR_NONE;
}
static int handle_insert(handle_t *handle)
{
int ret;
pthread_rwlock_wrlock(&mng.rwlock);
ret = _handle_insert(handle);
pthread_rwlock_unlock(&mng.rwlock);
return ret;
}
static int handle_erase(u64 start, handle_t **handle)
{
handle_t *tmp = NULL;
struct rbtree_node *node = NULL;
struct rb_range_handle rb_range = {.start = start, .end = start};
int ret;
pthread_rwlock_wrlock(&mng.rwlock);
node = rbtree_search_by_range(&mng.root, &rb_range, rb_range_of_handle);
if (node == NULL) {
pthread_rwlock_unlock(&mng.rwlock);
return DRV_ERROR_NOT_EXIST;
}
tmp = rb_entry(node, handle_t, node);
if (tmp->prop.start != start) {
svm_err("Isn't start va. (start=0x%llx; handle.start=0x%llx)\n", start, tmp->prop.start);
pthread_rwlock_unlock(&mng.rwlock);
return DRV_ERROR_INVALID_VALUE;
}
ret = _handle_erase(tmp);
pthread_rwlock_unlock(&mng.rwlock);
if (ret == DRV_ERROR_NONE) {
*handle = tmp;
}
return ret;
}
static inline u32 svm_flag_to_cache_flag(u64 flag)
{
u32 cache_flag;
cache_flag = svm_flag_attr_is_hpage(flag) ? SVM_CACHE_MALLOC_FLAG_PA_HPAGE : 0;
cache_flag |= svm_flag_attr_is_p2p(flag) ? SVM_CACHE_MALLOC_FLAG_PA_P2P : 0;
cache_flag |= svm_flag_attr_is_master_uva(flag) ? SVM_CACHE_MALLOC_FLAG_MASTER_UVA : 0;
return cache_flag;
}
static inline u32 svm_flag_to_normal_flag(u64 flag, u32 numa_id)
{
u32 normal_flag;
normal_flag = svm_flag_attr_is_va_only(flag) ? SVM_NORMAL_MALLOC_FLAG_VA_ONLY : 0;
normal_flag |= svm_flag_attr_is_hpage(flag) ? SVM_NORMAL_MALLOC_FLAG_PA_HPAGE : 0;
normal_flag |= svm_flag_attr_is_gpage(flag) ? SVM_NORMAL_MALLOC_FLAG_PA_GPAGE : 0;
normal_flag |= svm_flag_attr_is_p2p(flag) ? SVM_NORMAL_MALLOC_FLAG_PA_P2P : 0;
normal_flag |= svm_flag_is_dev_cp_only(flag) ? SVM_NORMAL_MALLOC_FLAG_DEV_CP_ONLY : 0;
normal_flag |= svm_flag_attr_is_specified_va(flag) ? SVM_NORMAL_MALLOC_FLAG_SPACIFIED_VA : 0;
normal_flag |= svm_flag_attr_is_va_without_master(flag) ? 0 : SVM_NORMAL_MALLOC_FLAG_VA_WITH_MASTER;
normal_flag |= svm_flag_attr_is_master_uva(flag) ? SVM_NORMAL_MALLOC_FLAG_MASTER_UVA : 0;
normal_flag |= svm_flag_attr_is_pg_rdonly(flag) ? SVM_NORMAL_MALLOC_FLAG_PG_RDONLY : 0;
normal_flag |= (svm_flag_cap_is_support_sync_copy(flag) | svm_flag_cap_is_support_async_copy_submit(flag) |
svm_flag_cap_is_support_dma_desc_convert(flag) | svm_flag_cap_is_support_sync_copy_ex(flag) |
svm_flag_cap_is_support_sync_copy_2d(flag)) ? SVM_NORMAL_MALLOC_FLAG_CAP_COPY: 0;
if (numa_id != SVM_MALLOC_NUMA_NO_NODE) {
normal_flag |= SVM_NORMAL_MALLOC_FLAG_FIXED_NUMA;
normal_malloc_flag_set_numa_id(&normal_flag, numa_id);
}
return normal_flag;
}
static bool svm_flag_is_support_cache(u64 flag)
{
if (svm_flag_is_by_pass_cache(flag)) {
return false;
}
if (svm_flag_attr_is_contiguous(flag)) {
return false;
}
if (svm_flag_attr_is_gpage(flag)) {
return false;
}
if (svm_flag_attr_is_pg_rdonly(flag)) {
return false;
}
return true;
}
static bool go_malloc_cache(u32 devid, u32 numa_id, u64 flag, u64 align, u64 size)
{
u32 cache_flag = svm_flag_to_cache_flag(flag);
return ((numa_id == SVM_MALLOC_NUMA_NO_NODE) &&
svm_flag_is_support_cache(flag) && svm_cache_is_support(devid, cache_flag, align, (u32)size));
}
static int malloc_cache(u32 devid, u64 flag, u64 align, u64 size, u64 *start)
{
u32 cache_flag = svm_flag_to_cache_flag(flag);
int ret;
ret = svm_cache_malloc(devid, cache_flag, align, start, size);
if (ret != DRV_ERROR_NONE) {
svm_info("Can't cache malloc. (devid=%u; cache_flag=0x%x; size=%llu)\n", devid, cache_flag, size);
}
return ret;
}
static int free_cache(u32 devid, u64 flag, u64 align, u64 start, u64 size)
{
u32 cache_flag = svm_flag_to_cache_flag(flag);
int ret;
ret = svm_cache_free(devid, cache_flag, align, start, size);
if (ret != DRV_ERROR_NONE) {
svm_err("Cache mem free failed. (devid=%u; cache_flag=0x%x; start=0x%llx; size=%llu)\n",
devid, cache_flag, start, size);
}
return ret;
}
static void shrink_cache(u32 devid, u64 flag, u64 *shrinked_size)
{
svm_cache_shrink(devid, svm_flag_to_cache_flag(flag), shrinked_size);
}
static int malloc_normal(u32 devid, u32 numa_id, u64 flag, u64 align, u64 size, u64 *start)
{
u32 normal_flag = svm_flag_to_normal_flag(flag, numa_id);
u64 shrinked_size = 0;
int ret;
ret = svm_normal_malloc(devid, normal_flag, align, start, size);
if ((ret == DRV_ERROR_OUT_OF_MEMORY) && (svm_flag_attr_is_va_only(flag) == false)) {
shrink_cache(devid, flag, &shrinked_size);
if (shrinked_size >= size) {
ret = svm_normal_malloc(devid, normal_flag, align, start, size);
}
}
if (ret != DRV_ERROR_NONE) {
svm_info("Can't normal malloc. (devid=%u; normal_flag=%x; start=0x%llx; size=%llu)\n",
devid, normal_flag, *start, size);
}
return ret;
}
static int free_normal(u32 devid, u64 flag, u64 align, u64 start, u64 size)
{
u32 normal_flag = svm_flag_to_normal_flag(flag, SVM_MALLOC_NUMA_NO_NODE);
int ret;
ret = svm_normal_free(devid, normal_flag, align, start, size);
if ((ret != DRV_ERROR_NONE) && (ret != DRV_ERROR_BUSY)) {
svm_err("Normal mem can not free. (devid=%u; normal_flag=%u; start=0x%llx; size=%llu; ret=%u)\n",
devid, normal_flag, start, size, ret);
}
return ret;
}
static int get_aligned_size(u32 devid, u64 flag, u64 align, u64 size, u64 *aligned_size)
{
u64 pa_size;
int ret;
if (svm_flag_attr_is_contiguous(flag)) {
ret = svm_get_order_aligned_size(devid, flag, size, &pa_size);
if (ret != DRV_ERROR_NONE) {
svm_err("Get order aligned size failed. (ret=%d; devid=%u; flag=0x%llx; size=0x%llx)\n",
ret, devid, flag, size);
return ret;
}
*aligned_size = svm_align_up(pa_size, align);
} else {
*aligned_size = svm_align_up(size, align);
}
return DRV_ERROR_NONE;
}
static int _svm_malloc(u64 *start, u64 *size, u64 align, u64 flag,
struct svm_malloc_location *location, bool *is_from_cache)
{
u32 devid = location->devid;
u32 numa_id = location->numa_id;
u64 aligned_size;
bool go_cache;
int ret;
ret = get_aligned_size(devid, flag, align, *size, &aligned_size);
if (ret != DRV_ERROR_NONE) {
return ret;
}
go_cache = go_malloc_cache(devid, numa_id, flag, align, aligned_size);
if (go_cache) {
ret = malloc_cache(devid, flag, align, aligned_size, start);
} else {
ret = malloc_normal(devid, numa_id, flag, align, aligned_size, start);
}
if (ret == DRV_ERROR_NONE) {
*is_from_cache = go_cache;
*size = aligned_size;
}
return ret;
}
static int _svm_free(u32 devid, u64 flag, u64 align, u64 start, u64 size, bool is_from_cache)
{
if (is_from_cache) {
return free_cache(devid, flag, align, start, size);
} else {
return free_normal(devid, flag, align, start, size);
}
}
static int svm_prop_pack(u32 devid, u64 flag, u64 start, u64 size, bool is_from_cache, struct svm_prop *prop)
{
int ret;
prop->devid = svm_flag_attr_is_va_only(flag) ? SVM_INVALID_DEVID : devid;
prop->flag = flag;
prop->start = start;
prop->size = size;
prop->is_from_cache = is_from_cache;
if (prop->devid == SVM_INVALID_DEVID) {
return DRV_ERROR_NONE;
}
if (prop->devid == svm_get_host_devid()) {
prop->tgid = (int)drvDeviceGetBareTgid();
} else {
ret = svm_apbi_query_tgid(devid, DEVDRV_PROCESS_CP1, &prop->tgid);
if (ret != DRV_ERROR_NONE) {
svm_err("Get mem tgid failed. (ret=%d; devid=%u)\n", ret, devid);
}
return ret;
}
return DRV_ERROR_NONE;
}
static int malloc_align_matched_with_page_size_check(u32 devid, u64 flag, u64 align)
{
u64 pg_size;
int ret;
ret = svm_query_page_size_by_svm_flag(devid, flag, &pg_size);
if (ret != DRV_ERROR_NONE) {
svm_err("Query page size failed. (ret=%d; devid=%u; flag=0x%llx)\n", ret, devid, flag);
return ret;
}
if ((align % pg_size) != 0) {
svm_err("Invalid align. (align=0x%llx; pg_size=0x%llx)\n", align, pg_size);
return DRV_ERROR_INVALID_VALUE;
}
if (svm_flag_attr_is_contiguous(flag) && (svm_check_power_of_2(align / pg_size) != 0)) {
svm_err("For contiguous, align/pg_size should be power of 2. (align=0x%llx; pg_size=0x%llx)\n", align, pg_size);
return DRV_ERROR_INVALID_VALUE;
}
return DRV_ERROR_NONE;
}
static int malloc_para_check(u64 size, u64 align, u64 flag, struct svm_malloc_location *location)
{
u64 range_start, range_size;
svm_get_va_range(&range_start, &range_size);
if (size > range_size) {
return DRV_ERROR_OUT_OF_MEMORY;
}
if (location->numa_id > SVM_MALLOC_NUMA_NO_NODE) {
svm_err("Invalid numa id. (numa_id=%u)\n", location->numa_id);
return DRV_ERROR_INVALID_VALUE;
}
if (svm_flag_attr_is_va_only(flag)) {
return DRV_ERROR_NONE;
}
return malloc_align_matched_with_page_size_check(location->devid, flag, align);
}
int svm_malloc(u64 *start, u64 size, u64 align, u64 flag, struct svm_malloc_location *location)
{
u32 devid = location->devid;
u64 aligned_size;
handle_t *handle = NULL;
struct svm_prop prop;
bool is_from_cache;
int ret;
ret = malloc_para_check(size, align, flag, location);
if (ret != DRV_ERROR_NONE) {
return ret;
}
aligned_size = size;
ret = _svm_malloc(start, &aligned_size, align, flag, location, &is_from_cache);
if (ret != DRV_ERROR_NONE) {
return ret;
}
handle = handle_alloc();
if (handle == NULL) {
ret = DRV_ERROR_OUT_OF_MEMORY;
goto free_mem;
}
ret = svm_prop_pack(devid, flag, *start, size, is_from_cache, &prop);
if (ret != DRV_ERROR_NONE) {
goto free_handle;
}
prop.aligned_size = aligned_size;
handle_init(handle, &prop, is_from_cache, align);
ret = svm_mng_ops_post_malloc(handle, *start, &handle->prop);
if (ret != DRV_ERROR_NONE) {
goto uninit_handle;
}
ret = handle_insert(handle);
if (ret != DRV_ERROR_NONE) {
goto ops_pre_free;
}
return 0;
ops_pre_free:
svm_mng_ops_pre_free(handle, *start, &handle->prop);
uninit_handle:
(void)handle_uninit(handle, true);
free_handle:
handle_free(handle);
free_mem:
(void)_svm_free(devid, flag, align, *start, aligned_size, is_from_cache);
return ret;
}
int svm_free(u64 start)
{
handle_t *handle = NULL;
int ret;
ret = handle_erase(start, &handle);
if (ret != DRV_ERROR_NONE) {
return ret;
}
ret = handle_uninit(handle, false);
if (ret != DRV_ERROR_NONE) {
handle_insert(handle);
return ret;
}
svm_mng_ops_pre_free(handle, start, &handle->prop);
ret = _svm_free(handle->prop.devid, handle->prop.flag, handle->align,
handle->prop.start, handle->prop.aligned_size, handle->is_from_cache);
if (ret == DRV_ERROR_BUSY) {
ret = handle_insert(handle);
if (ret != DRV_ERROR_NONE) {
handle_free(handle);
svm_err("Unlikely insert failed.\n");
return DRV_ERROR_INNER_ERR;
}
return DRV_ERROR_BUSY;
} else {
handle_free(handle);
}
return ret;
}
static int _svm_recycle_handle(handle_t *handle)
{
int ret;
_rbtree_erase(&mng.root, &handle->node);
ret = handle_uninit(handle, true);
if (ret != DRV_ERROR_NONE) {
_handle_insert(handle);
return DRV_ERROR_INNER_ERR;
}
ret = _svm_free(handle->prop.devid, handle->prop.flag, handle->align,
handle->prop.start, handle->prop.aligned_size, handle->is_from_cache);
if (ret == DRV_ERROR_BUSY) {
ret = _handle_insert(handle);
} else {
handle_free(handle);
}
return DRV_ERROR_NONE;
}
int svm_recycle_mem_by_dev(u32 devid)
{
handle_t *handle = NULL;
struct rbtree_node *cur = NULL;
struct rbtree_node *n = NULL;
int ret = DRV_ERROR_NONE;
u32 recyle_num = 0;
pthread_rwlock_wrlock(&mng.rwlock);
rbtree_node_for_each_prev_safe(cur, n, &mng.root) {
handle = rb_entry(cur, handle_t, node);
if ((devid == handle->prop.devid) || (devid == SVM_INVALID_DEVID)) {
ret = _svm_recycle_handle(handle);
if (ret != DRV_ERROR_NONE) {
break;
}
recyle_num++;
}
}
pthread_rwlock_unlock(&mng.rwlock);
if (recyle_num > 0) {
svm_info("Recycle success. (devid=%u; recyle_num=%u)\n", devid, recyle_num);
}
return ret;
}
static u32 svm_show_mem_priv(handle_t *handle, char *buf, u32 buf_len)
{
if ((handle->priv_ops != NULL) && (handle->priv_ops->show != NULL)) {
return handle->priv_ops->show(handle->priv, buf, buf_len);
}
return 0;
}
static u32 svm_show_handle(handle_t *handle, int id, char *buf, u32 buf_len)
{
struct svm_prop *prop = &handle->prop;
if (buf == NULL) {
svm_info("id %d: ref %u task_bitmap 0x%x devid %u start 0x%llx size 0x%llx "
"aligned_size 0x%llx, flag 0x%llx tgid %d state %d is_from_cache %d\n",
id, handle->ref, handle->task_bitmap, prop->devid, prop->start, prop->size, prop->aligned_size,
prop->flag, prop->tgid, handle->state, handle->is_from_cache);
(void)svm_show_mem_priv(handle, buf, buf_len);
return 0;
} else {
int len;
u32 priv_format_len;
len = snprintf_s(buf, buf_len, buf_len - 1, "id %d: ref %u task_bitmap 0x%x devid %u start 0x%llx size 0x%llx "
"aligned_size 0x%llx, flag 0x%llx tgid %d state %d is_from_cache %d\n",
id, handle->ref, handle->task_bitmap, prop->devid, prop->start, prop->size, prop->aligned_size,
prop->flag, prop->tgid, handle->state, handle->is_from_cache);
if (len < 0) {
return 0;
}
priv_format_len = svm_show_mem_priv(handle, buf + len, buf_len - (u32)len);
return (u32)len + priv_format_len;
}
}
void svm_show_dev_mem(u32 devid, char *buf, u32 buf_len)
{
struct rbtree_node *cur = NULL;
int id = 0;
u32 len = 0;
(void)pthread_rwlock_rdlock(&mng.rwlock);
rbtree_node_for_each(cur, &mng.root) {
handle_t *handle = rb_entry(cur, handle_t, node);
if ((devid == handle->prop.devid) || (devid == SVM_INVALID_DEVID)) {
len += svm_show_handle(handle, id++, buf + len, buf_len - len);
}
}
pthread_rwlock_unlock(&mng.rwlock);
}
void svm_show_mem(void)
{
svm_show_dev_mem(SVM_INVALID_DEVID, NULL, 0);
}
static int _svm_for_each_handle(int (*func)(void *handle, u64 start, struct svm_prop *prop, void *priv),
void *priv, bool check_valid)
{
struct rbtree_node *cur = NULL;
int ret = 0;
(void)pthread_rwlock_rdlock(&mng.rwlock);
rbtree_node_for_each(cur, &mng.root) {
handle_t *handle = rb_entry(cur, handle_t, node);
if (check_valid && !handle_is_match_state((handle_t *)handle, HANDLE_STATE_INITED)) {
continue;
}
ret = func((void *)handle, handle->prop.start, &handle->prop, priv);
if (ret != 0) {
break;
}
}
pthread_rwlock_unlock(&mng.rwlock);
return ret;
}
int svm_for_each_handle(int (*func)(void *handle, u64 start, struct svm_prop *prop, void *priv), void *priv)
{
return _svm_for_each_handle(func, priv, false);
}
int svm_for_each_valid_handle(int (*func)(void *handle, u64 start, struct svm_prop *prop, void *priv), void *priv)
{
return _svm_for_each_handle(func, priv, true);
}
int svm_get_prop(u64 va, struct svm_prop *prop)
{
handle_t *handle = NULL;
int ret;
handle = handle_get(va);
if (handle == NULL) {
return DRV_ERROR_INVALID_VALUE;
}
ret = handle_get_prop(handle, va, prop);
handle_put(handle);
return ret;
}
void svm_mod_prop_flag(void *handle, u64 flag)
{
((handle_t *)handle)->prop.flag = flag;
}
void svm_mod_prop_devid(void *handle, u32 devid)
{
((handle_t *)handle)->prop.devid = devid;
}
void svm_set_task_bitmap(void *handle, u32 task_bitmap)
{
((handle_t *)handle)->task_bitmap = task_bitmap;
}
u32 svm_get_task_bitmap(void *handle)
{
return ((handle_t *)handle)->task_bitmap;
}
bool svm_handle_mem_is_cache(void *handle)
{
return ((handle_t *)handle)->is_from_cache;
}
void *svm_handle_get(u64 va)
{
return (void *)handle_get(va);
}
void svm_handle_put(void *handle)
{
handle_put((handle_t *)handle);
}
int svm_set_priv(void *handle, void *priv, struct svm_priv_ops *priv_ops)
{
handle_t *tmp = handle;
int ret;
handle_wrlock(tmp);
ret = handle_set_priv(tmp, priv, priv_ops);
handle_unlock(tmp);
return ret;
}
void *svm_get_priv(void *handle)
{
return handle_get_priv((handle_t *)handle);
}
void __attribute__((destructor)) svm_mng_uninit(void)
{
(void)svm_recycle_mem_by_dev(SVM_INVALID_DEVID);
}