跳转至

1. intel gpu分配显存和映射

intel用户态驱动创建一个buffer,这个buffer包含的信息,大小,地址,map等,通常使用一个bo来表示这些信息。bo的创建有多种方式 1. 从外部导入一个bo 2. 创建一个bo 3. 从用户指定的系统内存地址创建一个bo

外部导入

从fd导入bo

handle是每个gem context拥有的,不能跨进程传输。如果需要跨进程传输,则需要利用可以进程通信的fd,将handle和fd联系起来。android大部分buffer都是通过binder传递fd。gem在通过handle去查找一个bo。 drm提供了drmPrimeFDtoHandle接口,获得fd对应的handle。对应的handle转fd函数是drmPrimeHandleToFD。

从name导入bo

GEM name在用途上类似于句柄,但不是DRM文件的本地名称。它们可以在进程之间传递以全局引用GEM对象。名称不用直接用于引用DRM API的对象,应用程序必须分别使用DRM_IOCTL_GEM_FLINK 和 DRM_IOCTL_GEM_OPEN ioctl将句柄转换为name,并将name转换为句柄。转换由DRM核心处理,并不特定于驱动程序支持。

分配一个bo

内存类型注册

intel gpu 驱动分为system 内存和local 内存。

enum intel_memory_type {
    INTEL_MEMORY_SYSTEM = I915_MEMORY_CLASS_SYSTEM,
    INTEL_MEMORY_LOCAL = I915_MEMORY_CLASS_DEVICE,
    INTEL_MEMORY_STOLEN_SYSTEM,
    INTEL_MEMORY_STOLEN_LOCAL,
    INTEL_MEMORY_MOCK,
};

两种内存都注册成intel region. system 内存注册i915_gem_ttm_system_setup 显存注册 intel_gt_setup_lmem。 对于i915 驱动无论哪种内存方式都是用intel_memory_region_create 注册一个memory 的区域。

struct intel_memory_region {

    struct drm_i915_private *i915; //
    const struct intel_memory_region_ops *ops;
    struct io_mapping iomap;
    struct resource region;
    struct resource io;
    resource_size_t min_page_size;
    resource_size_t total;
    u16 type;
    u16 instance;
    enum intel_region_id id;
    char name[16];
    char uabi_name[16];
    bool private; /* not for userspace */
    
    struct {
        struct mutex lock; /* Protects access to objects */
        struct list_head list;
    } objects;  

    bool is_range_manager;
    void *region_private;
};

多个intel_memory_region指向同一个drm_i915_private

struct drm_i915_private {
    struct drm_device drm; //对应于上层的设备虚拟内存管理
    struct {
        struct pci_dev *pdev;
        struct resource mch_res;
        bool mchbar_need_disable;
    } gmch;

    ......

    struct i915_gem_mm mm;

    ......

    struct {
        struct i915_gem_contexts {
            spinlock_t lock; /* locks list */
            struct list_head list;
        } contexts;
        struct file *mmap_singleton;
    } gem;

    ......

    /* The TTM device structure. */
    struct ttm_device bdev; //对应于下层的设备物理内存管理
};

其中,只会在 intel_region_lmem_ops -> region_lmem_init -> i915_ttm_buddy_man_init 会初始化bdev,处理实际的显存管理。

struct ttm_device {
    struct list_head device_list;
    const struct ttm_device_funcs *funcs;
    struct ttm_resource_manager sysman;
    struct ttm_resource_manager *man_drv[TTM_NUM_MEM_TYPES]; \\ttm管理器
    struct drm_vma_offset_manager *vma_manager;
    struct ttm_pool pool; 
    spinlock_t lru_lock;
    struct list_head pinned;
    struct address_space *dev_mapping;
    struct workqueue_struct *wq;
};

struct ttm_resource_manager {
    bool use_type;
    bool use_tt;
    struct ttm_device *bdev;
    uint64_t size;
    const struct ttm_resource_manager_func *func; \\ttm_resource管理函数
    spinlock_t move_lock;
    struct dma_fence *move;
    struct list_head lru[TTM_MAX_BO_PRIORITY];
    uint64_t usage;
};
由于ttm 更新至buddy管理器,在i915_ttm_buddy_man_init中,drm_buddy_init 初始化 i915_ttm_buddy_manager -> mm, 将i915_ttm_buddy_manager ->manager绑定到 ttm_device -> ttm_resource_manager [type] ,再处理ttm_resource_manager -> func 并ttm_resource_manager_init初始化i915_ttm_buddy_manager ->manager.

struct i915_ttm_buddy_manager {
    struct ttm_resource_manager manager;
    struct drm_buddy mm;
    struct list_head reserved;
    struct mutex lock;
    unsigned long visible_size;
    unsigned long visible_avail;
    unsigned long visible_reserved;
    u64 default_page_size;

};

intel_memory_region 实际初始化了lmem, system_mem, gem_shmem, gem_stolen.

用户态分配

1.mesa 下发命令 mesa 根据配置的参数 调用DRM_IOCTL_I915_GEM_CREATE_EXT调用__i915_gem_object_create_user_ext分配内核中一个obj。

2.初始化obj 状态信息 intel_memory_region -> __i915_gem_ttm_object_init 则被使用来初始化一个ttm obj和ttm_resource. ttm_resource_alloc调用 i915_ttm_buddy_man_alloc 函数完成ttm_resource 分配和初始化。

int __i915_gem_ttm_object_init(struct intel_memory_region *mem,
                   struct drm_i915_gem_object *obj,
                   resource_size_t offset,
                   resource_size_t size,
                   resource_size_t page_size,
                   unsigned int flags)
{
    ......
    struct ttm_operation_ctx ctx = {
        .interruptible = true,
        .no_wait_gpu = false,
    };
    ......
    drm_gem_private_object_init(&i915->drm, &obj->base, size);
    i915_gem_object_init(obj, &i915_gem_ttm_obj_ops, &lock_class, flags);

    obj->bo_offset = offset;
    obj->mm.region = mem;

    INIT_LIST_HEAD(&obj->mm.region_link);
    INIT_RADIX_TREE(&obj->ttm.get_io_page.radix, GFP_KERNEL | __GFP_NOWARN);
    mutex_init(&obj->ttm.get_io_page.lock);

    bo_type = (obj->flags & I915_BO_ALLOC_USER) ? ttm_bo_type_device :
        ttm_bo_type_kernel;

     obj->base.vma_node.driver_private = i915_gem_to_ttm(obj);

    i915_gem_object_make_unshrinkable(obj);

    ret = ttm_bo_init_reserved(&i915->bdev, i915_gem_to_ttm(obj), bo_type,
                   &i915_sys_placement, page_size >> PAGE_SHIFT,
                   &ctx, NULL, NULL, i915_ttm_bo_destroy);
    ......
 
    obj->ttm.created = true;

    i915_gem_object_release_memory_region(obj);
    i915_gem_object_init_memory_region(obj, mem);
    i915_ttm_adjust_domains_after_move(obj);
    i915_ttm_adjust_gem_after_move(obj);
    i915_gem_object_unlock(obj);

    return 0;
}

drm_gem_private_object_init初始化 drm_gem_object ,其中初始化obj的引用,resv, vma_node等三个结构体。kref_init(&obj->refcount), dma_resv_init(&obj->_resv), drm_vma_node_reset(&obj->vma_node).****