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;
};
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)
.****