* 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 "kernel_version_adapt.h"
#include "comm_kernel_interface.h"
#include "davinci_interface.h"
#include "pbl/pbl_davinci_api.h"
#include "devmm_adapt.h"
#include "svm_heap_mng.h"
#include "svm_log.h"
#include "svm_kernel_msg.h"
#include "devmm_mem_alloc_interface.h"
#include "devmm_dev.h"
#include "devmm_common.h"
#include "svm_dynamic_addr.h"
bool g_devmm_true = 1;
bool g_devmm_false = 0;
bool devmm_is_host_agent(u32 agent_id)
{
return (agent_id == SVM_HOST_AGENT_ID);
}
void devmm_try_usleep_by_time(u32 *pre_stamp, u32 time)
{
u32 timeinterval;
timeinterval = ka_system_jiffies_to_msecs(ka_jiffies - *pre_stamp);
if (timeinterval > time) {
ka_system_usleep_range(1, 2);
*pre_stamp = (u32)ka_jiffies;
}
}
void devmm_try_cond_resched_by_time(u32 *pre_stamp, u32 time)
{
u32 timeinterval;
timeinterval = ka_system_jiffies_to_msecs(ka_jiffies - *pre_stamp);
if ((timeinterval > time) && !ka_base_in_atomic()) {
ka_task_cond_resched();
*pre_stamp = (u32)ka_jiffies;
}
}
void devmm_try_cond_resched(u32 *pre_stamp)
{
devmm_try_cond_resched_by_time(pre_stamp, DEVMM_WAKEUP_TIMEINTERVAL);
}
bool devmm_smmu_is_opening(void)
{
return ((devmm_svm->smmu_status == DEVMM_SMMU_STATUS_OPENING) ? DEVMM_TRUE : DEVMM_FALSE);
}
static int devmm_ka_mm_pin_user_pages_fast(unsigned long start, int nr_pages, int write, ka_page_t **pages)
{
u32 i, try_times = 5;
int tmp_num;
for (i = 0; i < try_times; i++) {
tmp_num = ka_mm_pin_user_pages_fast(start, nr_pages, (write != 0) ? FOLL_WRITE : 0, pages);
if (tmp_num == nr_pages) {
return nr_pages;
}
#ifndef EMU_ST
if (tmp_num < 0) {
return 0;
}
devmm_unpin_user_pages(pages, nr_pages, tmp_num);
#endif
}
return 0;
}
int devmm_pin_user_pages_fast(u64 va, u64 total_num, int write, ka_page_t **pages)
{
u64 got_num, remained_num, tmp_va;
int tmp_num, expected_num;
u32 stamp;
stamp = (u32)ka_jiffies;
for (got_num = 0; got_num < total_num;) {
tmp_va = va + got_num * KA_MM_PAGE_SIZE;
remained_num = total_num - got_num;
expected_num = (remained_num > DEVMM_GET_2M_PAGE_NUM) ? DEVMM_GET_2M_PAGE_NUM : (int)remained_num;
tmp_num = devmm_ka_mm_pin_user_pages_fast(tmp_va, expected_num, write, &pages[got_num]);
got_num += (tmp_num > 0) ? (u32)tmp_num : 0;
if (tmp_num != expected_num) {
devmm_drv_err("Get_user_pages_fast fail. (va=0x%llx; expected_page_num=%d; real_got_page_num=%d)\n",
tmp_va, expected_num, tmp_num);
goto page_err;
}
devmm_try_cond_resched(&stamp);
}
return 0;
page_err:
devmm_unpin_user_pages(pages, total_num, got_num);
return -EFAULT;
}
void devmm_pin_user_pages(ka_page_t **pages, u64 page_num)
{
u32 stamp = (u32)ka_jiffies;
u64 i;
for (i = 0; i < page_num; i++) {
ka_mm_get_page(pages[i]);
devmm_try_cond_resched(&stamp);
}
}
void devmm_put_user_pages(ka_page_t **pages, u64 page_num, u64 unpin_num)
{
u32 stamp;
u64 i;
if (unpin_num > page_num || pages == NULL) {
return;
}
stamp = (u32)ka_jiffies;
for (i = 0; i < unpin_num; i++) {
if (pages[i] != NULL) {
ka_mm_put_page(pages[i]);
pages[i] = NULL;
}
devmm_try_cond_resched(&stamp);
}
}
void devmm_unpin_user_pages(ka_page_t **pages, u64 page_num, u64 unpin_num)
{
u32 stamp;
u64 i;
if (unpin_num > page_num || pages == NULL) {
return;
}
stamp = (u32)ka_jiffies;
for (i = 0; i < unpin_num; i++) {
if (pages[i] != NULL) {
ka_mm_unpin_user_page(pages[i]);
pages[i] = NULL;
}
devmm_try_cond_resched(&stamp);
}
}
u64 devmm_get_pagecount_by_size(u64 vptr, u64 sizes, u32 page_size)
{
u64 chunk_cnt = 0;
u64 tem_byte;
if ((page_size == 0) || ((vptr < (DEVMM_SVM_MEM_START + DEVMM_SVM_MEM_SIZE)) && (sizes > DEVMM_MAX_MAPPED_RANGE))) {
devmm_drv_err("Chunk_page_size or byte_count is error. "
"(chunk_page_size=%u; byte_count=%llu)", page_size, sizes);
return chunk_cnt;
}
tem_byte = ((vptr & (page_size - 1)) + sizes);
chunk_cnt = tem_byte / page_size;
if ((tem_byte & (page_size - 1)) != 0) {
chunk_cnt++;
}
return chunk_cnt;
}
ssize_t devmm_read_file(ka_file_t *fp, char *dst_addr, size_t fsize, loff_t *pos)
{
#ifndef EMU_ST
return ka_fs_kernel_read(fp, dst_addr, fsize, pos);
#else
return 0;
#endif
}
char *devmm_read_line(ka_file_t *fp, loff_t *offset, char *buf, u32 buf_len)
{
u32 i = 0;
long ret;
ret = devmm_read_file(fp, buf, buf_len - 1, offset);
if (ret <= 0) {
devmm_drv_warn("File filestring not right. (buf_len=%u)\n", buf_len);
return NULL;
}
while (g_devmm_true) {
if (buf[i] == '\n') {
i++;
break;
}
i++;
if (i >= ret) {
break;
}
}
if (i < ret) {
*offset += i - ret;
}
if (i < buf_len) {
buf[i] = 0;
}
return buf;
}
int devmm_check_va_add_size_by_heap(struct devmm_svm_heap *heap, u64 va, u64 size)
{
u64 heap_total_cnt, heap_used_count, heap_free_count, va_need_count;
if (size > heap->heap_size) {
devmm_drv_err("Size is bad. (va=0x%llx; size=%llu; heap_size=%llu)\n",
va, size, heap->heap_size);
return -EINVAL;
}
heap_used_count = (va - heap->start) / heap->chunk_page_size;
heap_total_cnt = heap->heap_size / heap->chunk_page_size;
heap_free_count = heap_total_cnt - heap_used_count;
va_need_count = devmm_get_pagecount_by_size(va, size, heap->chunk_page_size);
if ((va_need_count == 0) || (heap_free_count < va_need_count)) {
devmm_drv_err("Va_need_count is zero, or heap_free_count < va_need_count. (heap_free_count=%llu; "
"va_need_count=%llu; va=0x%llx; size=%llu; heap_start_va=0x%llx; page_size=%u)\n",
heap_free_count, va_need_count, va, size, heap->start, heap->chunk_page_size);
return -EINVAL;
}
return 0;
}
static int devmm_check_common_input_heap_id_and_size(struct devmm_svm_process *svm_proc, u32 heap_idx, u64 heap_size)
{
u32 heap_num = (u32)(heap_size / DEVMM_HEAP_SIZE);
if ((heap_size == 0) || ((heap_size % DEVMM_HEAP_SIZE) != 0)) {
devmm_drv_err("Input para. (heap_idx=%u; heap_size=0x%llx)\n", heap_idx, heap_size);
return -EINVAL;
}
if ((heap_idx >= DEVMM_TOTAL_MAX_HEAP_NUM) || ((heap_idx + heap_num) > DEVMM_TOTAL_MAX_HEAP_NUM)) {
devmm_drv_err("Input para. (heap_idx=%u; heap_size=0x%llx; heap_num=%u; DEVMM_TOTAL_MAX_HEAP_NUM=%llu)\n",
heap_idx, heap_size, heap_num, DEVMM_TOTAL_MAX_HEAP_NUM);
return -EINVAL;
}
if ((heap_idx < DEVMM_MAX_HEAP_NUM) && ((heap_idx + heap_num) > DEVMM_MAX_HEAP_NUM)) {
devmm_drv_err("Input para. (heap_idx=%u; heap_size=0x%llx; heap_num=%u; DEVMM_MAX_HEAP_NUM=%llu)\n",
heap_idx, heap_size, heap_num, DEVMM_MAX_HEAP_NUM);
return -EINVAL;
}
if (heap_idx < DEVMM_MAX_HEAP_NUM) {
if (heap_size > (DEVMM_MAX_ALLOC_PAGE_NUM * KA_MM_PAGE_SIZE)) {
devmm_drv_err("Input para. (heap_idx=%u; heap_size=0x%llx; max_heap_size=0x%llx)\n",
heap_idx, heap_size, DEVMM_MAX_ALLOC_PAGE_NUM * KA_MM_PAGE_SIZE);
return -EINVAL;
}
} else {
}
return 0;
}
static bool devmm_check_common_input_heap_info(struct devmm_svm_process *svm_pro,
struct devmm_update_heap_para *cmd, u32 devid)
{
if ((cmd->op == DEVMM_HEAP_ENABLE) && (devmm_svm_mem_is_enable(svm_pro) == false) &&
cmd->heap_sub_type == SUB_HOST_TYPE) {
devmm_drv_err("Host svm mem is disable.\n");
return false;
}
if ((cmd->op == DEVMM_HEAP_ENABLE)&& devmm_is_host_agent(devid) &&
((cmd->heap_sub_type != SUB_DEVICE_TYPE) || (cmd->heap_type != DEVMM_HEAP_CHUNK_PAGE))) {
devmm_drv_err("Host agent only support heap SUB_DEVICE_TYPE DEVMM_HEAP_CHUNK_PAGE."
" (heap_sub_type=%u; heap_type=%u).\n", cmd->heap_sub_type, cmd->heap_type);
return false;
}
if (devmm_check_common_input_heap_id_and_size(svm_pro, cmd->heap_idx, cmd->heap_size) != 0) {
return false;
}
if (cmd->op == DEVMM_HEAP_ENABLE) {
if ((cmd->heap_type < DEVMM_HEAP_PINNED_HOST) || (cmd->heap_type > DEVMM_HEAP_CHUNK_PAGE)) {
return false;
}
if (cmd->heap_sub_type >= SUB_MAX_TYPE) {
return false;
}
return DEVMM_TRUE;
} else if (cmd->op == DEVMM_HEAP_DISABLE) {
struct devmm_svm_heap *heap = devmm_get_heap_by_idx(svm_pro, cmd->heap_idx);
if ((devmm_check_heap_is_entity(heap) == false) || (heap->heap_idx != cmd->heap_idx) ||
(heap->heap_size != cmd->heap_size)) {
devmm_drv_err("Disable input error. (hostpid=%d; devid=%d; vfid=%d; size=0x%llx)\n",
svm_pro->process_id.hostpid, svm_pro->process_id.devid, svm_pro->process_id.vfid,
cmd->heap_size);
return false;
}
return true;
}
return false;
}
bool devmm_check_input_heap_info(struct devmm_svm_process *svm_pro,
struct devmm_update_heap_para *cmd, u32 devid)
{
struct devmm_svm_heap *heap_check = NULL;
u32 heap_num, i;
if (devmm_check_common_input_heap_info(svm_pro, cmd, devid) == false) {
devmm_drv_err("Input error. (hostpid=%d; devid=%d; vfid=%d; size=0x%llx)\n",
svm_pro->process_id.hostpid, svm_pro->process_id.devid, svm_pro->process_id.vfid, cmd->heap_size);
return false;
}
heap_num = (u32)(cmd->heap_size / DEVMM_HEAP_SIZE);
for (i = 0; i < heap_num; i++) {
heap_check = devmm_get_heap_by_idx(svm_pro, i + cmd->heap_idx);
if (cmd->op == DEVMM_HEAP_ENABLE) {
if (devmm_check_heap_is_entity(heap_check) == true) {
devmm_drv_info("The heap already exists. (hostpid=%d; devid=%d; vfid=%d; size=0x%llx)\n",
svm_pro->process_id.hostpid, svm_pro->process_id.devid, svm_pro->process_id.vfid,
cmd->heap_size);
return false;
}
} else {
if (devmm_check_heap_is_entity(heap_check) == false) {
devmm_drv_err("Disable input error. (hostpid=%d; devid=%d; vfid=%d; size=0x%llx)\n",
svm_pro->process_id.hostpid, svm_pro->process_id.devid, svm_pro->process_id.vfid,
cmd->heap_size);
return false;
}
}
}
return true;
}
static u32 devmm_get_chunk_page_size_by_heap_type(u32 heap_type, u32 heap_sub_type)
{
if (heap_sub_type == SUB_RESERVE_TYPE) {
return (heap_type == DEVMM_HEAP_CHUNK_PAGE) ? devmm_svm->host_page_size : devmm_svm->device_hpage_size;
}
if (heap_type == DEVMM_HEAP_HUGE_PAGE) {
return devmm_svm->device_hpage_size;
} else if (heap_type == DEVMM_HEAP_CHUNK_PAGE) {
return ((heap_sub_type == SUB_DEVICE_TYPE) ? devmm_svm->device_page_size : devmm_svm->svm_page_size);
} else if (heap_type == DEVMM_HEAP_PINNED_HOST) {
return devmm_svm->device_hpage_size;
}
return 0;
}
#ifndef EMU_ST
void *devmm_kvalloc(u64 size, ka_gfp_t flags)
{
void *ptr = devmm_kmalloc_ex(size, KA_GFP_KERNEL | __KA_GFP_NOWARN | __KA_GFP_ACCOUNT | flags);
if (ptr == NULL) {
ptr = __devmm_vmalloc_ex(size, KA_GFP_KERNEL | __KA_GFP_ACCOUNT | flags, KA_PAGE_KERNEL);
}
return ptr;
}
void *devmm_kvzalloc(u64 size)
{
return devmm_kvalloc(size, __KA_GFP_ZERO);
}
#endif
void devmm_kvfree(const void *ptr)
{
if (ka_mm_is_vmalloc_addr(ptr)) {
devmm_vfree_ex(ptr);
} else {
devmm_kfree_ex(ptr);
}
}
ka_vm_area_struct_t *devmm_find_vma(struct devmm_svm_process *svm_proc, u64 vaddr)
{
u64 double_pgtable_offset;
if (devmm_va_is_in_svm_range(vaddr)) {
return devmm_find_vma_proc(svm_proc->mm, svm_proc->vma, svm_proc->vma_num, vaddr);
}
double_pgtable_offset = devmm_get_double_pgtable_offset();
if ((double_pgtable_offset != 0) && (vaddr >= double_pgtable_offset)
&& devmm_va_is_in_svm_range(vaddr - double_pgtable_offset)) {
return devmm_find_vma_proc(svm_proc->mm, svm_proc->vma, svm_proc->vma_num, vaddr);
}
return svm_da_query_vma(svm_proc, vaddr);
}
struct devmm_svm_heap *devmm_get_heap_by_idx(struct devmm_svm_process *svm_proc, u32 heap_idx)
{
if (heap_idx < DEVMM_MAX_HEAP_NUM) {
return svm_proc->heaps[heap_idx];
} else if (heap_idx < DEVMM_TOTAL_MAX_HEAP_NUM) {
return svm_get_da_heap_by_idx(svm_proc, heap_idx);
} else {
return NULL;
}
}
struct devmm_svm_heap *devmm_get_heap_by_va(struct devmm_svm_process *svm_proc, u64 vaddr)
{
u64 heap_idx;
heap_idx = (vaddr - DEVMM_SVM_MEM_START) / DEVMM_HEAP_SIZE;
return devmm_get_heap_by_idx(svm_proc, heap_idx);
}
bool devmm_check_heap_is_entity(struct devmm_svm_heap *heap)
{
if ((heap == NULL) || (heap->heap_type == DEVMM_HEAP_IDLE)) {
return false;
}
return true;
}
void devmm_set_heap_used_status(struct devmm_svm_heap *heap, u64 va, u64 size)
{
u64 end_addr = ka_base_round_up(va + size, HEAP_USED_PER_MASK_SIZE);
u64 addr = ka_base_round_down(va, HEAP_USED_PER_MASK_SIZE);
u32 nr;
for (; addr < end_addr; addr += HEAP_USED_PER_MASK_SIZE) {
if ((addr < heap->start) || (addr >= (heap->start + heap->heap_size))) {
break;
}
nr = (u32)((addr - heap->start) / HEAP_USED_PER_MASK_SIZE);
ka_base_set_bit(nr, heap->used_mask);
}
}
static void devmm_set_heap_info(struct devmm_svm_heap *heap, struct devmm_update_heap_para *cmd)
{
heap->heap_type = cmd->heap_type;
heap->heap_idx = cmd->heap_idx;
heap->heap_sub_type = cmd->heap_sub_type;
heap->chunk_page_size = devmm_get_chunk_page_size_by_heap_type(cmd->heap_type, cmd->heap_sub_type);
heap->start = DEVMM_SVM_MEM_START + cmd->heap_idx * DEVMM_HEAP_SIZE;
heap->heap_size = cmd->heap_size;
ka_base_atomic64_set(&heap->occupy_cnt, 0);
heap->is_invalid = false;
}
static void devmm_set_svm_heap_struct(struct devmm_svm_process *svm_process, struct devmm_svm_heap *heap,
u32 heap_idx, u32 heap_num)
{
if (heap_idx < DEVMM_MAX_HEAP_NUM) {
u32 i;
for (i = 0; i < heap_num; i++) {
svm_process->heaps[heap_idx + i] = heap;
}
} else {
svm_set_da_heap(svm_process, heap_idx, heap);
}
}
void devmm_clear_svm_heap_struct(struct devmm_svm_process *svm_process, u32 heap_idx, u32 heap_num)
{
if (heap_idx < DEVMM_MAX_HEAP_NUM) {
u32 i;
for (i = 0; i < heap_num; i++) {
svm_process->heaps[heap_idx + i] = NULL;
}
} else {
svm_set_da_heap(svm_process, heap_idx, NULL);
}
}
#define SVM_WAIT_HEAP_IDEA_CNT 5000
bool devmm_wait_svm_heap_unoccupied(struct devmm_svm_process *svm_process, struct devmm_svm_heap *heap)
{
u32 i;
ka_task_down_write(&svm_process->heap_sem);
heap->is_invalid = true;
for (i = 0; i < SVM_WAIT_HEAP_IDEA_CNT; i++) {
if (ka_base_atomic64_read(&heap->occupy_cnt) == 0) {
ka_task_up_write(&svm_process->heap_sem);
return true;
}
ka_system_usleep_range(100, 200);
}
ka_task_up_write(&svm_process->heap_sem);
return false;
}
void devmm_free_heap_struct(struct devmm_svm_process *svm_process, u32 heap_idx, u32 heap_num)
{
struct devmm_svm_heap *heap = devmm_get_heap_by_idx(svm_process, heap_idx);
devmm_clear_svm_heap_struct(svm_process, heap_idx, heap_num);
if (heap != NULL) {
devmm_kvfree(heap);
}
}
int devmm_update_heap_info(struct devmm_svm_process *svm_process, struct devmm_update_heap_para *cmd,
struct devmm_svm_heap *free_heap)
{
struct devmm_svm_heap *heap = NULL;
u32 heap_num;
int ret;
heap_num = (u32)(cmd->heap_size / DEVMM_HEAP_SIZE);
if ((cmd->heap_idx < DEVMM_MAX_HEAP_NUM) && ((cmd->heap_idx + heap_num) > DEVMM_MAX_HEAP_NUM)) {
devmm_drv_err("Invalid heap. (heap_idx=%u; heap_size=0x%llx)\n", cmd->heap_idx, cmd->heap_size);
return -EINVAL;
}
if (cmd->op == DEVMM_HEAP_ENABLE) {
u64 used_mask_size;
heap = devmm_get_heap_by_idx(svm_process, cmd->heap_idx);
if (heap != NULL) {
return 0;
}
used_mask_size = sizeof(unsigned long) *
KA_BASE_BITS_TO_LONGS((u64)(ka_base_round_up(cmd->heap_size, HEAP_USED_PER_MASK_SIZE) / HEAP_USED_PER_MASK_SIZE));
heap = devmm_kvzalloc(sizeof(struct devmm_svm_heap) + used_mask_size);
if (heap == NULL) {
return -ENOMEM;
}
heap->used_mask = (unsigned long *)(void *)(heap + 1);
devmm_set_heap_info(heap, cmd);
ret = devmm_vmma_mng_init(&heap->vmma_mng, heap->start, heap->heap_size);
if (ret != 0) {
devmm_kvfree(heap);
return ret;
}
if ((devmm_get_end_type() == DEVMM_END_HOST) && devmm_alloc_new_heap_pagebitmap(heap) != 0) {
devmm_drv_err("Devmm_alloc_new_heap_pagebitmap error.\n");
devmm_kvfree(heap);
return -ENOMEM;
}
svm_process->alloced_heap_size += (cmd->heap_sub_type == SUB_SVM_TYPE) ? cmd->heap_size : 0;
svm_process->max_heap_use = (svm_process->max_heap_use > (cmd->heap_idx + heap_num)) ?
svm_process->max_heap_use : (cmd->heap_idx + heap_num);
devmm_set_svm_heap_struct(svm_process, heap, cmd->heap_idx, heap_num);
} else {
if (free_heap == NULL) {
return -EINVAL;
}
heap = free_heap;
devmm_kvfree(heap);
svm_process->alloced_heap_size -= (cmd->heap_sub_type == SUB_SVM_TYPE) ? cmd->heap_size : 0;
}
return 0;
}
void devmm_dev_fault_flag_set(u32 *flag, u32 shift, u32 wide, u32 value)
{
u32 msk = ((1U << wide) - 1);
u32 val = (msk & value);
(*flag) &= (u32)(~(msk << shift));
(*flag) |= (u32)(val << shift);
}
u32 devmm_dev_fault_flag_get(u32 flag, u32 shift, u32 wide)
{
u32 msk = ((1U << wide) - 1);
u32 val = flag >> shift;
return (val & msk);
}
u32 devmm_get_max_page_num_of_per_msg(u32 *bitmap)
{
u32 num;
num = DEVMM_PAGE_NUM_PER_MSG;
#ifdef CFG_SOC_PLATFORM_ESL_FPGA
if (devmm_page_bitmap_is_advise_continuty(bitmap) == true) {
num = 1024;
}
#endif
return num;
}
const char *devmm_get_chrdev_name(void)
{
return (const char *)DEVMM_CHRDEV_NAME;
}
#ifndef DEVMM_UT
bool devmm_is_pcie_connect(u32 dev_id)
{
return (devdrv_get_connect_protocol(dev_id) == CONNECT_PROTOCOL_PCIE);
}
bool devmm_is_hccs_connect(u32 dev_id)
{
return (devdrv_get_connect_protocol(dev_id) == CONNECT_PROTOCOL_HCCS);
}
#endif
bool devmm_is_dma_link_abnormal(u32 dev_id)
{
struct ascend_intf_get_status_para status_para = {0};
unsigned int status = 0;
int ret;
status_para.type = DAVINCI_STATUS_TYPE_DEVICE;
status_para.para.device_id = dev_id;
#ifndef EMU_ST
ret = ascend_intf_get_status(status_para, &status);
if ((ret != 0) || ((status & DAVINCI_INTF_DEVICE_STATUS_LINK_ABNORMAL) == DAVINCI_INTF_DEVICE_STATUS_LINK_ABNORMAL)) {
return true;
}
#endif
return false;
}
void devmm_svm_mem_enable(struct devmm_svm_process *svm_proc)
{
svm_proc->is_enable_svm_mem = true;
}
void devmm_svm_mem_disable(struct devmm_svm_process *svm_proc)
{
svm_proc->is_enable_svm_mem = false;
}
bool devmm_svm_mem_is_enable(struct devmm_svm_process *svm_proc)
{
return svm_proc->is_enable_svm_mem;
}
void devmm_phy_addr_attr_pack(struct devmm_svm_process *svm_proc, u32 pg_type, u32 mem_type, bool is_continuous,
struct devmm_phy_addr_attr *attr)
{
attr->side = DEVMM_SIDE_TYPE;
attr->devid = svm_proc->process_id.devid;
attr->vfid = svm_proc->process_id.vfid;
attr->module_id = 0;
attr->pg_type = pg_type;
attr->mem_type = mem_type;
attr->is_continuous = (pg_type == DEVMM_NORMAL_PAGE_TYPE) ? is_continuous : false;
attr->is_compound_page = ((DEVMM_SIDE_TYPE == DEVMM_SIDE_MASTER) || (DEVMM_SIDE_TYPE == DEVMM_SIDE_HOST_AGENT)) ?
true : false;
}
#define DEVMM_NSEC_PER_SEC 1000000000L
u64 devmm_get_tgid_start_time(void)
{
int vnr = ka_task_task_tgid_vnr(ka_task_get_current());
ka_task_struct_t *task = NULL;
ka_struct_pid_t *pgrp = NULL;
u64 start_time;
* vnr: hostpid in container. Could not use ka_task_get_current_tgid(), because hostpid in kernel is not
* the same as hostpid in container, will cause find pgrp fail.
*/
pgrp = ka_task_find_get_pid(vnr);
if (pgrp == NULL) {
devmm_drv_err("Pgrp is NULL. (vnr=%d)\n", vnr);
return KA_U64_MAX;
}
task = ka_task_get_pid_task(pgrp, KA_PIDTYPE_PID);
if (task == NULL) {
devmm_drv_err("Task is NULL.\n");
ka_task_put_pid(pgrp);
return KA_U64_MAX;
}
start_time = ka_task_get_starttime(task);
ka_task_put_task_struct(task);
ka_task_put_pid(pgrp);
return start_time;
}
bool devmm_palist_is_continuous(u64 *pa, u32 num, u32 page_size)
{
u64 pre_pa = 0;
int i;
for (i = 0; i < num; i++) {
if ((i != 0) && (pre_pa + page_size != pa[i])) {
return false;
}
pre_pa = pa[i];
}
return true;
}
bool devmm_palist_is_specify_continuous(u64 *pa, u32 page_size, u32 total_num, u32 min_con_num)
{
u64 pre_pa = 0;
u32 i, j;
if ((total_num == 0) || (total_num % min_con_num != 0)) {
return false;
}
for (i = 0; i < total_num;) {
for (j = 0; j < min_con_num; j++) {
if ((j != 0) && (pre_pa + page_size != pa[i + j])) {
return false;
}
pre_pa = pa[i + j];
}
i = i + min_con_num;
}
return true;
}
void devmm_update_devids(struct devmm_devid *devids, u32 logical_devid, u32 devid, u32 vfid)
{
devids->logical_devid = logical_devid;
devids->devid = devid;
devids->vfid = vfid;
}