* 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_base_pub.h"
#include "ka_task_pub.h"
#include "ka_fs_pub.h"
#include "devmm_common.h"
#include "svm_proc_mng.h"
#include "svm_page_cnt_stats.h"
#include "svm_mem_stats.h"
#include "devmm_dev.h"
#include "svm_proc_fs.h"
#ifdef CONFIG_PROC_FS
ka_proc_dir_entry_t *devmm_task_entry = NULL;
static void devmm_proc_fs_format_task_dir_name(ka_pid_t pid, char *name, int len)
{
if (sprintf_s(name, (unsigned long)len, "%d", pid) <= 0) {
devmm_drv_warn("Sprintf_s failed.\n");
}
}
static ka_proc_dir_entry_t *devmm_proc_fs_mk_task_dir(ka_pid_t pid, ka_proc_dir_entry_t *parent)
{
char name[DEVMM_PROC_FS_NAME_LEN] = {0};
devmm_proc_fs_format_task_dir_name(pid, name, DEVMM_PROC_FS_NAME_LEN);
return ka_fs_proc_mkdir((const char *)name, parent);
}
static void devmm_proc_fs_rm_task_dir(ka_pid_t pid, ka_proc_dir_entry_t *parent)
{
char name[DEVMM_PROC_FS_NAME_LEN] = {0};
devmm_proc_fs_format_task_dir_name(pid, name, DEVMM_PROC_FS_NAME_LEN);
ka_fs_remove_proc_subtree((const char *)name, parent);
}
static void devmm_task_pg_cnt_stats_show(ka_seq_file_t *seq)
{
struct devmm_svm_process *svm_proc = (struct devmm_svm_process *)ka_fs_get_seq_file_private(seq);
u64 cgroup_used_page_cnt, cgroup_used_hpage_cnt, cgroup_used_gpage_cnt;
u64 cdm_used_page_cnt, cdm_used_hpage_cnt, cdm_used_gpage_cnt;
u64 peak_page_cnt, peak_hpage_cnt, peak_gpage_cnt;
cdm_used_page_cnt = devmm_get_cdm_used_page_cnt(&svm_proc->pg_cnt_stats, DEVMM_NORMAL_PAGE_TYPE);
cdm_used_hpage_cnt = devmm_get_cdm_used_page_cnt(&svm_proc->pg_cnt_stats, DEVMM_HUGE_PAGE_TYPE);
cdm_used_gpage_cnt = devmm_get_cdm_used_page_cnt(&svm_proc->pg_cnt_stats, DEVMM_GIANT_PAGE_TYPE);
cgroup_used_page_cnt = devmm_get_cgroup_used_page_cnt(&svm_proc->pg_cnt_stats, DEVMM_NORMAL_PAGE_TYPE);
cgroup_used_hpage_cnt = devmm_get_cgroup_used_page_cnt(&svm_proc->pg_cnt_stats, DEVMM_HUGE_PAGE_TYPE);
cgroup_used_gpage_cnt = devmm_get_cgroup_used_page_cnt(&svm_proc->pg_cnt_stats, DEVMM_GIANT_PAGE_TYPE);
peak_page_cnt = devmm_get_peak_page_cnt(&svm_proc->pg_cnt_stats, DEVMM_NORMAL_PAGE_TYPE);
peak_hpage_cnt = devmm_get_peak_page_cnt(&svm_proc->pg_cnt_stats, DEVMM_HUGE_PAGE_TYPE);
peak_gpage_cnt = devmm_get_peak_page_cnt(&svm_proc->pg_cnt_stats, DEVMM_GIANT_PAGE_TYPE);
ka_fs_seq_printf(seq, "Svm page cnt stats:\nhostpid=%u; devpid=%u; devid=%u; vfid=%u; "
"cgroup_used_page_cnt=%llu; cgroup_used_hpage_cnt=%llu; cgroup_used_gpage_cnt=%llu; "
"cdm_used_page_cnt=%llu; cdm_used_hpage_cnt=%llu; cdm_used_gpage_cnt=%llu; "
"peak_page_cnt=%llu; peak_hpage_cnt=%llu; peak_gpage_cnt=%llu\n",
svm_proc->process_id.hostpid, svm_proc->devpid, svm_proc->process_id.devid, svm_proc->process_id.vfid,
cgroup_used_page_cnt, cgroup_used_hpage_cnt, cgroup_used_gpage_cnt,
cdm_used_page_cnt, cdm_used_hpage_cnt, cdm_used_gpage_cnt,
peak_page_cnt, peak_hpage_cnt, peak_gpage_cnt);
}
static void devmm_task_status_stats_show(ka_seq_file_t *seq)
{
struct devmm_svm_process *svm_proc = (struct devmm_svm_process *)ka_fs_get_seq_file_private(seq);
u32 i;
ka_fs_seq_printf(seq, "\ntask status stats:\n");
ka_task_mutex_lock(&svm_proc->proc_lock);
ka_fs_seq_printf(seq, "notifier_reg_flag=0x%x; status=%u; index=%u; msg_processing=%u; other_proc_occupying=%u\n",
svm_proc->notifier_reg_flag, svm_proc->proc_status, svm_proc->proc_idx,
svm_proc->msg_processing, svm_proc->other_proc_occupying);
ka_task_mutex_unlock(&svm_proc->proc_lock);
for (i = 0; i < DEVMM_CUSTOM_PROCESS_NUM; i++) {
ka_task_mutex_lock(&svm_proc->custom[i].proc_lock);
if (svm_proc->custom[i].status != DEVMM_CUSTOM_IDLE) {
ka_fs_seq_printf(seq, "custom_pid=%u; index=%u; status=%u\n",
svm_proc->custom[i].custom_pid, svm_proc->custom[i].idx, svm_proc->custom[i].status);
}
ka_task_mutex_unlock(&svm_proc->custom[i].proc_lock);
}
}
static int devmm_task_info_show(ka_seq_file_t *seq, void *offset)
{
#ifndef EMU_ST
struct devmm_svm_process *svm_proc = (struct devmm_svm_process *)ka_fs_get_seq_file_private(seq);
if (devmm_thread_is_run_in_docker() == true) {
if (ka_task_get_current_mnt_ns() != ka_task_get_mnt_ns(svm_proc->tsk)) {
return 0;
}
}
#endif
devmm_task_pg_cnt_stats_show(seq);
devmm_task_status_stats_show(seq);
devmm_task_mem_stats_show(seq);
return 0;
}
STATIC int devmm_task_sum_open(ka_inode_t *inode, ka_file_t *file)
{
return ka_fs_single_open(file, devmm_task_info_show, ka_base_pde_data(inode));
}
static const ka_procfs_ops_t devmm_task_sum_ops = {
ka_fs_init_pf_owner(KA_THIS_MODULE) \
ka_fs_init_pf_open(devmm_task_sum_open) \
ka_fs_init_pf_read(ka_fs_seq_read) \
ka_fs_init_pf_lseek(ka_fs_seq_lseek) \
ka_fs_init_pf_release(ka_fs_single_release) \
};
void devmm_proc_fs_add_task(struct devmm_svm_process *svm_proc)
{
ka_pid_t pid;
#ifndef EMU_ST
if ((devmm_task_entry == NULL) || (svm_proc->task_entry != NULL)) {
return;
}
#endif
if (devmm_get_end_type() == DEVMM_END_DEVICE) {
pid = svm_proc->devpid;
} else {
pid = svm_proc->process_id.hostpid;
}
svm_proc->task_entry = devmm_proc_fs_mk_task_dir(pid, devmm_task_entry);
if (svm_proc->task_entry != NULL) {
ka_fs_proc_create_data("summary", DEVMM_PROC_FS_MODE, svm_proc->task_entry, &devmm_task_sum_ops, svm_proc);
return;
}
}
void devmm_proc_fs_del_task(struct devmm_svm_process *svm_proc)
{
ka_pid_t pid;
if ((devmm_task_entry == NULL) || (svm_proc->task_entry == NULL)) {
return;
}
if (devmm_get_end_type() == DEVMM_END_DEVICE) {
pid = svm_proc->devpid;
} else {
pid = svm_proc->process_id.hostpid;
}
devmm_proc_fs_rm_task_dir(pid, devmm_task_entry);
svm_proc->task_entry = NULL;
}
STATIC int devmm_sum_open(ka_inode_t *inode, ka_file_t *file)
{
return ka_fs_single_open(file, devmm_info_show, ka_base_pde_data(inode));
}
static const ka_procfs_ops_t devmm_sum_ops = {
ka_fs_init_pf_owner(KA_THIS_MODULE) \
ka_fs_init_pf_open(devmm_sum_open) \
ka_fs_init_pf_read(ka_fs_seq_read) \
ka_fs_init_pf_lseek(ka_fs_seq_lseek) \
ka_fs_init_pf_release(ka_fs_single_release) \
};
static ka_proc_dir_entry_t *devmm_top_entry = NULL;
void devmm_proc_fs_init(struct devmm_svm_dev *svm_dev)
{
devmm_top_entry = ka_fs_proc_mkdir("svm", NULL);
if (devmm_top_entry != NULL) {
devmm_task_entry = ka_fs_proc_mkdir("task", devmm_top_entry);
ka_fs_proc_create_data("summary", DEVMM_PROC_FS_MODE, devmm_top_entry, &devmm_sum_ops, svm_dev);
devmm_dev_proc_fs_init();
}
}
void devmm_proc_fs_uninit(void)
{
if (devmm_top_entry != NULL) {
devmm_dev_proc_fs_uninit();
ka_fs_remove_proc_subtree("svm", NULL);
}
}
ka_proc_dir_entry_t *devmm_get_top_entry(void)
{
return devmm_top_entry;
}
#else
void devmm_proc_fs_add_task(struct devmm_svm_process *svm_proc)
{
}
void devmm_proc_fs_del_task(struct devmm_svm_process *svm_proc)
{
}
void devmm_proc_fs_init(struct devmm_svm_dev *svm_dev)
{
return;
}
void devmm_proc_fs_uninit(void)
{
}
#endif