C Nouveau驱动程序如何在GPU端分配内存?

C Nouveau驱动程序如何在GPU端分配内存?,c,linux-kernel,gpu,driver,gpgpu,C,Linux Kernel,Gpu,Driver,Gpgpu,我一直在研究新的GPU驱动程序(Nvidia GPU的开源GPU驱动程序),因为我想了解驱动程序内部的实际情况。 具体来说,我一直在试图弄清楚CPU端运行的新代码如何能够在GPU端分配内存。 换句话说,我想学习cudamaloc()如何在GPU端分配内存。(我知道cudamaloc()是CUDA API,但我不确定CUDA的cudamaloc()在Nouveau上的等价物是什么) 以下是我目前发现的情况: Nouveau让TTM(翻译表管理器)通过int TTM_bo_init(…)初始化bo(

我一直在研究新的GPU驱动程序(Nvidia GPU的开源GPU驱动程序),因为我想了解驱动程序内部的实际情况。 具体来说,我一直在试图弄清楚CPU端运行的新代码如何能够在GPU端分配内存。
换句话说,我想学习
cudamaloc()
如何在GPU端分配内存。
(我知道
cudamaloc()
是CUDA API,但我不确定CUDA的
cudamaloc()
在Nouveau上的等价物是什么)
以下是我目前发现的情况:

  • Nouveau让TTM(翻译表管理器)通过
    int TTM_bo_init(…)
    初始化bo(缓冲区对象),其定义如下所示:
  • int ttm_bo_init(结构ttm_bo_设备*bdev,
    结构ttm_缓冲区_对象*bo,
    无符号长尺寸,
    枚举ttm_bo_类型,
    结构ttm_放置*放置,
    uint32页面对齐,
    无符号长缓冲区\u开始,
    布尔可中断,
    结构文件*永久交换存储,
    尺寸根据尺寸,
    void(*销毁)(结构ttm\u缓冲区\u对象*)
    {
    int-ret=0;
    未签名的长数页;
    结构ttm_mem_global*mem_glob=bdev->glob->mem_glob;
    ret=ttm_mem_global_alloc(mem_glob,acc_size,false,false);
    如果(ret){
    printk(内核内存不足。\n”);
    如果(销毁)
    (*销毁)(bo);
    其他的
    kfree(bo);
    return-ENOMEM;
    }
    大小+=缓冲区开始和页面掩码;
    页面数=(大小+页面大小-1)>>页面移位;
    如果(页数==0){
    printk(KERN_ERR TTM_PFX“非法缓冲区对象大小。\n”);
    如果(销毁)
    (*销毁)(bo);
    其他的
    kfree(bo);
    返回-艾因瓦尔;
    }
    bo->销毁=销毁;
    kref_init(&bo->kref);
    kref_init(&bo->list_kref);
    原子_集(&bo->cpu_写入程序,0);
    原子集(&bo->保留,1);
    init_waitqueue_head(&bo->event_queue);
    初始列表头(&bo->lru);
    初始列表头(&bo->ddestroy);
    初始列表头(&bo->交换);
    初始列表头(&bo->io\U储备\U lru);
    bo->bdev=bdev;
    bo->glob=bdev->glob;
    bo->type=类型;
    bo->num\u pages=num\u pages;
    bo->mem.size=num\u pages mem.mem\u type=TTM\u PL\u系统;
    bo->mem.num\u pages=bo->num\u pages;
    bo->mem.mm_节点=NULL;
    bo->mem.page\u alignment=页面对齐;
    bo->mem.bus.io\u reserved\u vm=false;
    bo->mem.bus.io_reserved_count=0;
    bo->buffer\U start=buffer\U start&PAGE\U MASK;
    bo->priv_标志=0;
    bo->mem.placement=(TTM_PL_FLAG_SYSTEM | TTM_PL_FLAG_CACHED);
    bo->seq_valid=false;
    bo->persistent\u swap\u storage=persistent\u swap\u storage;
    bo->acc\U size=acc\U size;
    原子计数公司(&bo->glob->bo计数);
    ret=ttm\u bo\u检查位置(bo,位置);
    如果(不太可能(ret!=0))
    出去走走;
    /*
    *对于ttm\u bo\u类型的设备缓冲区,分配
    *来自设备的地址空间。
    */
    如果(bo->type==ttm\U bo\U type\U设备){
    ret=ttm\u bo\u设置\u vm(bo);
    如果(ret)
    出去走走;
    }
    ret=ttm_bo_validate(bo、放置、可中断、假、假);
    如果(ret)
    出去走走;
    ttm_bo_unreserve(bo);
    返回0;
    错误:
    ttm_bo_unreserve(bo);
    ttm_bo_unref(&bo);
    返回ret;
    }
    
    我认为对于用户空间应用程序,缓冲区将通过
    ttm\u bo\u setup\u vm()
    在设备(GPU)端的这部分代码上分配:

    /*
    *对于ttm\u bo\u类型的设备缓冲区,分配
    *来自设备的地址空间。
    */
    如果(bo->type==ttm\U bo\U type\U设备){
    ret=ttm\u bo\u设置\u vm(bo);
    如果(ret)
    出去走走;
    }
    
    ttm\u bo\u setup\u vm()
    定义为:

    /**
    *ttm\u bo\u设置\u虚拟机:
    *
    *@bo:为其分配地址空间的缓冲区
    *
    *在drm设备中分配地址空间,以便应用程序
    *可以映射缓冲区并访问内容。仅此而已
    *适用于ttm_bo_type_设备对象,其他对象则不适用
    *放置在drm设备地址空间中。
    */
    静态int ttm\u bo\u设置\u vm(结构ttm\u缓冲区\u对象*bo)
    {
    结构ttm_bo_设备*bdev=bo->bdev;
    int ret;
    重试\u预\u获取:
    ret=drm_mm_pre_get(&bdev->addr_space_mm);
    如果(不太可能(ret!=0))
    返回ret;
    写入锁定(&bdev->vm锁定);
    bo->vm\u node=drm\u mm\u search\u free(&bdev->addr\u space\u mm),
    bo->mem.num_页面,0,0);
    if(不太可能(bo->vm_节点==NULL)){
    ret=-ENOMEM;
    跳出去解锁;
    }
    bo->vm\u节点=drm\u mm\u获取块\u原子(bo->vm\u节点,
    bo->mem.num_页面,0);
    if(不太可能(bo->vm_节点==NULL)){
    写入解锁(&bdev->vm\u锁定);
    转到重试\u pre\u get;
    }
    ttm_bo_vm_insert_rb(bo);
    写入解锁(&bdev->vm\u锁定);
    bo->addr_space_offset=((uint64_t)bo->vm_node->start)vm_lock);
    返回ret;
    }
    
    但是我很难找出锁和解锁部分中的代码是如何在GPU端分配内存的。
    此外,我还偶然发现了近10年前提出的问题,并想知道答案是否仍然有效-是否可以使用常规
    malloc()
    free()
    来分配和释放GPU端的内存

    我知道这个问题有点模糊,但我不知道我还能提供什么其他信息来让它更清楚。任何建议或想法都将不胜感激。
    提前谢谢