DRM 内存管理¶
现代 Linux 系统需要大量的图形内存来存储帧缓冲区、纹理、顶点和其他图形相关数据。鉴于许多此类数据的动态特性,有效地管理图形内存对于图形堆栈至关重要,并在 DRM 基础设施中发挥核心作用。
DRM 核心包括两个内存管理器,即转换表管理器 (TTM) 和图形执行管理器 (GEM)。TTM 是第一个开发的 DRM 内存管理器,并试图成为一个适用于所有情况的解决方案。它提供了一个单一的用户空间 API,以满足所有硬件的需求,支持统一内存架构 (UMA) 设备和具有专用视频 RAM 的设备(即大多数独立显卡)。这导致了一个庞大而复杂的代码,事实证明对于驱动程序开发来说很难使用。
GEM 最初是英特尔赞助的项目,以应对 TTM 的复杂性。它的设计理念完全不同:GEM 没有为每个与图形内存相关的问题提供解决方案,而是识别了驱动程序之间的公共代码,并创建了一个支持库来共享它。GEM 的初始化和执行要求比 TTM 简单,但没有视频 RAM 管理功能,因此仅限于 UMA 设备。
转换表管理器 (TTM)¶
TTM 是用于具有专用内存的加速器设备的内存管理器。
基本思想是将资源分组到特定大小的缓冲区对象中,TTM 处理这些对象的生命周期、移动和 CPU 映射。
TODO:在此处添加更多设计背景和信息。
-
enum ttm_caching¶
CPU 缓存和总线窥探行为。
常量
ttm_uncached
设备映射的最具防御性的选项,甚至不允许写入合并。
ttm_write_combined
不缓存读取访问,但允许至少写入合并。
ttm_cached
像普通系统内存一样完全缓存,要求设备在访问时窥探 CPU 缓存。
TTM 设备对象引用¶
-
struct ttm_global¶
缓冲区对象驱动程序的全局数据。
定义:
struct ttm_global {
struct page *dummy_read_page;
struct list_head device_list;
atomic_t bo_count;
};
成员
dummy_read_page
指向用于映射未填充页面的虚拟页面的指针。初始化后恒定。
device_list
缓冲区对象设备的列表。受 ttm_global_mutex 保护。
bo_count
设备分配的缓冲区对象的数量。
-
struct ttm_device¶
缓冲区对象驱动程序的特定于设备的数据。
定义:
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];
struct drm_vma_offset_manager *vma_manager;
struct ttm_pool pool;
spinlock_t lru_lock;
struct list_head unevictable;
struct address_space *dev_mapping;
struct workqueue_struct *wq;
};
成员
device_list
我们在全局设备列表中的条目。在 bo 设备初始化后恒定
funcs
设备的函数表。在 bo 设备初始化后恒定
sysman
系统域的资源管理器。通过 ttm_manager_type 访问。
man_drv
resource_managers 的数组,每个资源类型一个。
vma_manager
用于查找要 mmap 的 BO 的地址空间管理器。
pool
设备的页面池。
lru_lock
保护每个管理器 LRU 和 ddestroy 列表。
unevictable
已固定或交换的缓冲区对象,因此不在 LRU 列表中。
dev_mapping
指向
struct address_space
的指针,用于在缓冲区移动时使 CPU 映射无效。受加载/卸载同步保护。wq
用于延迟删除工作队列的工作队列结构。
-
int ttm_device_init(struct ttm_device *bdev, const struct ttm_device_funcs *funcs, struct device *dev, struct address_space *mapping, struct drm_vma_offset_manager *vma_manager, bool use_dma_alloc, bool use_dma32)¶
参数
struct ttm_device *bdev
指向要初始化的
struct ttm_device
的指针。const struct ttm_device_funcs *funcs
设备的函数表。
struct device *dev
用于 DMA 映射和分配的核心内核设备指针。
struct address_space *mapping
用于此 bo 的地址空间。
struct drm_vma_offset_manager *vma_manager
指向 vma 管理器的指针。
bool use_dma_alloc
是否应使用一致的 DMA 分配 API。
bool use_dma32
是否应为设备内存分配使用 GFP_DMA32。
描述
返回
!0:失败。
TTM 资源放置引用¶
-
struct ttm_place¶
定义:
struct ttm_place {
unsigned fpfn;
unsigned lpfn;
uint32_t mem_type;
uint32_t flags;
};
成员
fpfn
放置对象的第一个有效页帧号
lpfn
放置对象的最后一个有效页帧号
mem_type
应从中分配资源的 TTM_PL_* 之一。
flags
对象的内存域和缓存标志
描述
指示放置对象的可能位置的结构。
-
struct ttm_placement¶
定义:
struct ttm_placement {
unsigned num_placement;
const struct ttm_place *placement;
};
成员
num_placement
首选放置的数量
placement
首选放置
描述
指示您为对象请求的放置的结构。
TTM 资源对象引用¶
-
enum ttm_lru_item_type¶
枚举 ttm_lru_item 子类
常量
TTM_LRU_RESOURCE
资源子类
TTM_LRU_HITCH
迭代器挂钩子类
-
struct ttm_lru_item¶
TTM lru 列表节点基类
定义:
struct ttm_lru_item {
struct list_head link;
enum ttm_lru_item_type type;
};
成员
link
列表链接
type
子类类型
-
void ttm_lru_item_init(struct ttm_lru_item *item, enum ttm_lru_item_type type)¶
参数
struct ttm_lru_item *item
要初始化的项
enum ttm_lru_item_type type
子类类型
-
struct ttm_resource_manager¶
定义:
struct ttm_resource_manager {
bool use_type;
bool use_tt;
struct ttm_device *bdev;
uint64_t size;
const struct ttm_resource_manager_func *func;
spinlock_t move_lock;
struct dma_fence *move;
struct list_head lru[TTM_MAX_BO_PRIORITY];
uint64_t usage;
};
成员
use_type
启用的内存类型。
use_tt
是否应将 TT 对象用于后备存储。
bdev
此管理器所属的 ttm 设备
size
托管区域的大小。
func
实现范围管理器的结构指针。请参见上文
move_lock
用于移动栅栏的锁
move
上次流水线移动操作的栅栏。
lru
此内存类型的 lru 列表。
usage
使用了多少资源,受 bdev->lru_lock 保护。
描述
此结构用于标识和管理设备的内存类型。
-
struct ttm_bus_placement¶
定义:
struct ttm_bus_placement {
void *addr;
phys_addr_t offset;
bool is_iomem;
enum ttm_caching caching;
};
成员
addr
映射的虚拟地址
offset
物理地址
is_iomem
这是 io 内存吗?
caching
请参见
enum ttm_caching
描述
指示对象的总线放置的结构。
-
struct ttm_resource¶
定义:
struct ttm_resource {
unsigned long start;
size_t size;
uint32_t mem_type;
uint32_t placement;
struct ttm_bus_placement bus;
struct ttm_buffer_object *bo;
struct ttm_lru_item lru;
};
成员
start
分配的起始位置。
size
资源实际大小,以字节为单位。
mem_type
分配的资源类型。
placement
放置标志。
bus
放置在 CPU 可访问的 IO 总线上
bo
对 BO 的弱引用,受 ttm_device::lru_lock 保护
lru
最近最少使用列表,请参阅
ttm_resource_manager.lru
描述
指示缓冲区对象使用的放置和空间资源的结构。
-
struct ttm_resource *ttm_lru_item_to_res(struct ttm_lru_item *item)¶
-
struct ttm_lru_bulk_move_pos¶
定义:
struct ttm_lru_bulk_move_pos {
struct ttm_resource *first;
struct ttm_resource *last;
};
成员
first
批量移动范围内的第一个资源
last
批量移动范围内的最后一个资源
描述
用于 LRU 批量移动的资源范围。
-
struct ttm_lru_bulk_move¶
定义:
struct ttm_lru_bulk_move {
struct ttm_lru_bulk_move_pos pos[TTM_NUM_MEM_TYPES][TTM_MAX_BO_PRIORITY];
struct list_head cursor_list;
};
成员
pos
每个域/优先级中资源的第一个/最后一个 LRU 条目
cursor_list
当前正在遍历 **pos** 的任何子列表的游标列表。受 ttm 设备 lru_lock 保护。
描述
当前批量移动状态的容器。应与 ttm_lru_bulk_move_init()
和 ttm_bo_set_bulk_move() 一起使用。批量移动结构中的所有 BO 都需要共享同一个预留对象,以确保即使仅逐出批量中的一个 BO,整个批量也会被锁定以进行逐出。
-
struct ttm_resource_cursor¶
定义:
struct ttm_resource_cursor {
struct ttm_resource_manager *man;
struct ttm_lru_item hitch;
struct list_head bulk_link;
struct ttm_lru_bulk_move *bulk;
unsigned int mem_type;
unsigned int priority;
};
成员
man
当前正在迭代的资源管理器
hitch
插入到要迭代的下一个资源之前的挂接列表节点。
bulk_link
用于遍历 **bulk** 的批量子列表的游标列表的列表链接。受 ttm 设备 lru_lock 保护。
bulk
指向
struct ttm_lru_bulk_move
的指针,**hitch** 插入到该指针的子范围内。如果为 NULL,则表示没有。永远不要取消对此指针的引用,因为指向的struct ttm_lru_bulk_move
对象可能已被释放。该指针仅用于比较。mem_type
正在遍历的 LRU 列表的内存类型。当 **bulk** != NULL 时,此字段有效。
priority
当前优先级
描述
用于迭代管理器中资源的游标。
-
struct ttm_kmap_iter_iomap¶
针对由 struct io_mapping + struct sg_table 支持的
struct ttm_resource
的专门化。
定义:
struct ttm_kmap_iter_iomap {
struct ttm_kmap_iter base;
struct io_mapping *iomap;
struct sg_table *st;
resource_size_t start;
struct {
struct scatterlist *sg;
pgoff_t i;
pgoff_t end;
pgoff_t offs;
} cache;
};
成员
base
嵌入的 struct ttm_kmap_iter,提供使用接口。
iomap
表示底层线性 io_memory 的 struct io_mapping。
st
进入 **iomap** 的 sg_table,表示
struct ttm_resource
的内存。start
需要从 **st** 中减去的偏移量,以使 sg_dma_address(st->sgl) - **start** == 0 用于 **iomap** 的起始位置。
cache
用于快速查找的散列表遍历缓存。
cache.sg
指向当前缓存的散列表段的指针。
cache.i
**sg** 的第一个索引。PAGE_SIZE 粒度。
cache.end
**sg** 的最后一个索引 + 1。PAGE_SIZE 粒度。
cache.offs
**sg** 的 **iomap** 的第一个偏移量。PAGE_SIZE 粒度。
-
struct ttm_kmap_iter_linear_io¶
用于线性 IO 的迭代器专门化
定义:
struct ttm_kmap_iter_linear_io {
struct ttm_kmap_iter base;
struct iosys_map dmap;
bool needs_unmap;
};
成员
base
基本迭代器
dmap
指向区域起始地址
needs_unmap
是否需要在 fini 上取消映射
-
void ttm_resource_manager_set_used(struct ttm_resource_manager *man, bool used)¶
参数
struct ttm_resource_manager *man
内存管理器对象。
bool used
要设置的使用状态。
描述
设置管理器使用标志。如果禁用,则不再将管理器用于对象放置。
-
bool ttm_resource_manager_used(struct ttm_resource_manager *man)¶
参数
struct ttm_resource_manager *man
要获取使用状态的管理器
描述
获取管理器的使用中标志。
返回
true 为使用中,false 为未使用。
-
void ttm_resource_manager_cleanup(struct ttm_resource_manager *man)¶
参数
struct ttm_resource_manager *man
内存管理器对象。
描述
从内存管理器对象中清理移动栅栏。
-
ttm_resource_manager_for_each_res¶
ttm_resource_manager_for_each_res (man, cursor, res)
迭代所有资源
-
void ttm_lru_bulk_move_init(struct ttm_lru_bulk_move *bulk)¶
初始化批量移动结构
参数
struct ttm_lru_bulk_move *bulk
要初始化的结构
描述
现在只需将结构 memset 为零。
-
void ttm_lru_bulk_move_fini(struct ttm_device *bdev, struct ttm_lru_bulk_move *bulk)¶
完成批量移动结构
参数
struct ttm_device *bdev
struct ttm_lru_bulk_move *bulk
用于最终化的结构体
描述
健全性检查,确保批量移动没有剩余任何资源,因此没有附加任何游标。
-
void ttm_lru_bulk_move_tail(struct ttm_lru_bulk_move *bulk)¶
将资源批量移动到 LRU 尾部。
参数
struct ttm_lru_bulk_move *bulk
批量移动结构体
描述
将 BO 批量移动到 LRU 尾部,仅当驱动程序确保资源顺序永远不会更改时才有效。应该在持有 ttm_device.lru_lock
的情况下调用。
-
void ttm_resource_init(struct ttm_buffer_object *bo, const struct ttm_place *place, struct ttm_resource *res)¶
资源对象构造函数
参数
struct ttm_buffer_object *bo
为此资源分配的缓冲区对象
const struct ttm_place *place
资源的位置
struct ttm_resource *res
要初始化的资源对象
描述
初始化一个新的资源对象。对应于 ttm_resource_fini()
。
-
void ttm_resource_fini(struct ttm_resource_manager *man, struct ttm_resource *res)¶
资源析构函数
参数
struct ttm_resource_manager *man
此资源所属的资源管理器
struct ttm_resource *res
要清理的资源
描述
应该由资源管理器后端使用,在释放底层结构之前清理 TTM 资源对象。确保在销毁之前从 LRU 中移除资源。对应于 ttm_resource_init()
。
-
void ttm_resource_manager_init(struct ttm_resource_manager *man, struct ttm_device *bdev, uint64_t size)¶
参数
struct ttm_resource_manager *man
要初始化的内存管理器对象
struct ttm_device *bdev
此管理器所属的 ttm 设备
uint64_t size
以任意单位表示的托管资源大小
描述
初始化管理器对象的核心部分。
-
uint64_t ttm_resource_manager_usage(struct ttm_resource_manager *man)¶
参数
struct ttm_resource_manager *man
内存管理器对象。
描述
返回当前使用了多少资源。
-
void ttm_resource_manager_debug(struct ttm_resource_manager *man, struct drm_printer *p)¶
参数
struct ttm_resource_manager *man
要转储的管理器类型。
struct drm_printer *p
用于调试的打印机。
-
struct ttm_kmap_iter *ttm_kmap_iter_iomap_init(struct ttm_kmap_iter_iomap *iter_io, struct io_mapping *iomap, struct sg_table *st, resource_size_t start)¶
参数
struct ttm_kmap_iter_iomap *iter_io
要初始化的
struct ttm_kmap_iter_iomap
。struct io_mapping *iomap
表示底层线性 io_memory 的 struct io_mapping。
struct sg_table *st
进入 **iomap** 的 sg_table,表示
struct ttm_resource
的内存。resource_size_t start
需要从 **st** 中减去的偏移量,以使 sg_dma_address(st->sgl) - **start** == 0 用于 **iomap** 的起始位置。
返回
指向嵌入式 struct ttm_kmap_iter 的指针。
-
void ttm_resource_manager_create_debugfs(struct ttm_resource_manager *man, struct dentry *parent, const char *name)¶
为指定的资源管理器创建 debugfs 条目。
参数
struct ttm_resource_manager *man
为其创建 debugfs 统计文件的 TTM 资源管理器
struct dentry * parent
文件所在的 debugfs 目录
const char *name
要创建的文件名。
描述
此函数设置一个 debugfs 文件,可用于查看指定的 ttm_resource_manager 的调试统计信息。
TTM TT 对象引用¶
-
struct ttm_tt¶
这是一个结构体,用于保存非由固定(VRAM/AGP)内存支持的缓冲区对象的页面、缓存和光圈绑定状态。
定义:
struct ttm_tt {
struct page **pages;
#define TTM_TT_FLAG_SWAPPED BIT(0);
#define TTM_TT_FLAG_ZERO_ALLOC BIT(1);
#define TTM_TT_FLAG_EXTERNAL BIT(2);
#define TTM_TT_FLAG_EXTERNAL_MAPPABLE BIT(3);
#define TTM_TT_FLAG_DECRYPTED BIT(4);
#define TTM_TT_FLAG_PRIV_POPULATED BIT(5);
uint32_t page_flags;
uint32_t num_pages;
struct sg_table *sg;
dma_addr_t *dma_address;
struct file *swap_storage;
enum ttm_caching caching;
};
成员
pages
支持数据的页面数组。
page_flags
页面标志。
支持的值
TTM_TT_FLAG_SWAPPED: 由 TTM 设置,当页面已被取消填充并由 TTM 换出时。调用
ttm_tt_populate()
将把页面换回,并取消设置该标志。驱动程序通常永远不需要接触此标志。TTM_TT_FLAG_ZERO_ALLOC:如果页面将在分配时清零,则设置此标志。
TTM_TT_FLAG_EXTERNAL:如果底层页面是外部分配的,例如使用 dma-buf 或 userptr,则设置此标志。这实际上禁用了 TTM 换出此类页面。同样重要的是防止 TTM 直接映射这些页面。
请注意,枚举 ttm_bo_type.ttm_bo_type_sg 对象将始终启用此标志。
TTM_TT_FLAG_EXTERNAL_MAPPABLE:与 TTM_TT_FLAG_EXTERNAL 相同的行为,但减少了限制,仍然可以使用 TTM 直接映射页面。当实现一个仍然在底层分配驱动程序拥有的页面(例如使用 shmem)的 ttm_tt 后端时,这很有用。
请注意,由于这也暗示了 TTM_TT_FLAG_EXTERNAL,因此此处的用法应始终为
- page_flags = TTM_TT_FLAG_EXTERNAL |
TTM_TT_FLAG_EXTERNAL_MAPPABLE;
TTM_TT_FLAG_DECRYPTED:映射的 ttm 页面应标记为未加密。框架将尝试匹配 dma 层正在执行的操作,但请注意,它有点脆弱,因为 ttm 页面错误处理有点滥用了 DMA api,并且 dma_map_attrs 不能用于确保 pgprot 始终匹配。
TTM_TT_FLAG_PRIV_POPULATED:仅限 TTM 内部使用。请勿使用。这由 TTM 在
ttm_tt_populate()
成功返回后设置,然后在 TTM 调用ttm_tt_unpopulate()
时取消设置。num_pages
页面数组中的页面数。
sg
用于通过 dma-buf 进行 SG 对象。
dma_address
页面的 DMA(总线)地址。
swap_storage
指向用于交换存储的 shmem
struct file
的指针。caching
页面的当前缓存状态,请参阅
enum ttm_caching
。
-
struct ttm_kmap_iter_tt¶
用于 tt 的映射迭代器的特殊化。
定义:
struct ttm_kmap_iter_tt {
struct ttm_kmap_iter base;
struct ttm_tt *tt;
pgprot_t prot;
};
成员
base
嵌入的 struct ttm_kmap_iter,提供使用接口
tt
缓存的
struct ttm_tt
。prot
用于映射的缓存页面保护。
-
int ttm_tt_create(struct ttm_buffer_object *bo, bool zero_alloc)¶
参数
struct ttm_buffer_object *bo
指向 struct ttm_buffer_object 的指针
bool zero_alloc
如果分配的页面需要清零,则为 true
描述
确保为给定的 BO 分配了 TTM 结构。实际上没有分配任何页面。
-
int ttm_tt_init(struct ttm_tt *ttm, struct ttm_buffer_object *bo, uint32_t page_flags, enum ttm_caching caching, unsigned long extra_pages)¶
参数
struct ttm_tt *ttm
struct ttm_buffer_object *bo
我们为其创建 ttm 的缓冲区对象。
uint32_t page_flags
由 TTM_TT_FLAG_XX 标志标识的页面标志。
enum ttm_caching caching
页面的所需缓存状态
unsigned long extra_pages
驱动程序所需的额外页面。
描述
创建一个 struct ttm_tt
,用于使用系统内存页面备份数据。实际上没有分配任何页面。
返回
NULL:内存不足。
参数
struct ttm_tt *ttm
ttm_tt 结构。
描述
释放 ttm_tt 结构的内存
-
void ttm_tt_destroy(struct ttm_device *bdev, struct ttm_tt *ttm)¶
-
int ttm_tt_populate(struct ttm_device *bdev, struct ttm_tt *ttm, struct ttm_operation_ctx *ctx)¶
为 ttm 分配页面
参数
struct ttm_device *bdev
此对象所属的 ttm_device
struct ttm_tt *ttm
指向 ttm_tt 结构的指针
struct ttm_operation_ctx *ctx
用于填充 tt 对象的操作上下文。
描述
调用驱动程序方法为 ttm 分配页面
-
void ttm_tt_unpopulate(struct ttm_device *bdev, struct ttm_tt *ttm)¶
从 ttm 释放页面
参数
struct ttm_device *bdev
此对象所属的 ttm_device
struct ttm_tt *ttm
指向 ttm_tt 结构的指针
描述
调用驱动程序方法释放 ttm 的所有页面
参数
struct ttm_tt *ttm
指向 ttm_tt 结构的指针
描述
标记页面以便清除,以便下次填充页面向量时,页面将被清除。
-
struct ttm_tt *ttm_agp_tt_create(struct ttm_buffer_object *bo, struct agp_bridge_data *bridge, uint32_t page_flags)¶
参数
struct ttm_buffer_object *bo
我们为其分配 ttm 的缓冲区对象。
struct agp_bridge_data *bridge
此设备所连接的 agp 桥。
uint32_t page_flags
由 TTM_TT_FLAG_XX 标志标识的页面标志。
描述
创建一个 TTM 后端,该后端使用指示的 AGP 桥作为 TT 内存的孔径。此函数使用 linux agpgart 接口来绑定和解绑支持 ttm_tt 的内存。
-
struct ttm_kmap_iter *ttm_kmap_iter_tt_init(struct ttm_kmap_iter_tt *iter_tt, struct ttm_tt *tt)¶
参数
struct ttm_kmap_iter_tt *iter_tt
要初始化的
struct ttm_kmap_iter_tt
。struct ttm_tt *tt
保存
struct ttm_resource
的页面指针的 Struct ttm_tt。
返回
指向嵌入式 struct ttm_kmap_iter 的指针。
TTM 页面池参考¶
-
struct ttm_pool_type¶
特定内存类型的池
定义:
struct ttm_pool_type {
struct ttm_pool *pool;
unsigned int order;
enum ttm_caching caching;
struct list_head shrinker_list;
spinlock_t lock;
struct list_head pages;
};
成员
pool
我们所属的池,全局池可能为 NULL
阶数
我们页面分配的阶数
caching
我们页面的缓存类型
shrinker_list
我们在全局收缩器列表中的位置
锁
页面列表的保护
pages
池中的页面列表
-
struct ttm_pool¶
用于所有缓存和阶数的池
定义:
struct ttm_pool {
struct device *dev;
int nid;
bool use_dma_alloc;
bool use_dma32;
struct {
struct ttm_pool_type orders[NR_PAGE_ORDERS];
} caching[TTM_NUM_CACHING_TYPES];
};
成员
dev
我们为其分配页面的设备
nid
要使用的 NUMA 节点
use_dma_alloc
是否应使用一致的 DMA 分配
use_dma32
是否应使用 GFP_DMA32
caching
每个缓存/阶数的池
-
int ttm_pool_alloc(struct ttm_pool *pool, struct ttm_tt *tt, struct ttm_operation_ctx *ctx)¶
填充一个 ttm_tt 对象
参数
struct ttm_pool *pool
要使用的 ttm_pool
struct ttm_tt *tt
要填充的 ttm_tt 对象
struct ttm_operation_ctx *ctx
操作上下文
描述
使用页面填充 ttm_tt 对象,并确保在必要时进行 DMA 映射。
返回
成功时为 0,否则为负错误代码。
参数
struct ttm_pool *pool
将页面返回到的池。
struct ttm_tt *tt
要取消填充的 ttm_tt 对象
描述
将后备页面返回到池或释放它们
-
void ttm_pool_init(struct ttm_pool *pool, struct device *dev, int nid, bool use_dma_alloc, bool use_dma32)¶
初始化一个池
参数
struct ttm_pool *pool
要初始化的池
struct device *dev
用于 DMA 分配和映射的设备
int nid
用于分配的 NUMA 节点
bool use_dma_alloc
如果应使用一致的 DMA 分配,则为 true
bool use_dma32
如果应使用 GFP_DMA32,则为 true
描述
初始化池及其池类型。
参数
struct ttm_pool *pool
要清理的池
描述
释放池中的所有页面,并从全局收缩器中注销类型。
参数
struct ttm_pool *pool
要为其转储信息的池
struct seq_file *m
要转储到的 seq_file
描述
使用每个池和全局信息进行 debugfs 转储。
图形执行管理器 (GEM)¶
GEM 设计方法导致内存管理器在其用户空间或内核 API 中未提供所有(甚至所有常见)用例的完整覆盖。 GEM 向用户空间公开一组标准的内存相关操作,并向驱动程序公开一组辅助函数,并让驱动程序使用其自己的私有 API 实现特定于硬件的操作。
GEM 用户空间 API 在 LWN 上的GEM - 图形执行管理器文章中进行了描述。虽然稍微过时,但该文档提供了 GEM API 原则的良好概述。作为通用 GEM API 的一部分描述的缓冲区分配以及读取和写入操作当前是使用特定于驱动程序的 ioctl 实现的。
GEM 与数据无关。它管理抽象的缓冲区对象,而不知道各个缓冲区包含的内容。因此,需要了解缓冲区内容或用途的 API(例如缓冲区分配或同步原语)超出了 GEM 的范围,必须使用特定于驱动程序的 ioctl 实现。
从根本上说,GEM 涉及以下几个操作
内存分配和释放
命令执行
命令执行时的光圈管理
缓冲区对象分配相对简单,并且主要由 Linux 的 shmem 层提供,该层提供内存来支持每个对象。
特定于设备的操作(例如命令执行、锁定、缓冲区读取和写入、映射以及域所有权转移)留给特定于驱动程序的 ioctl。
GEM 初始化¶
使用 GEM 的驱动程序必须在 struct struct drm_driver
driver_features 字段中设置 DRIVER_GEM 位。然后,DRM 核心将在调用加载操作之前自动初始化 GEM 核心。在后台,这将创建一个 DRM 内存管理器对象,该对象为对象分配提供地址空间池。
在 KMS 配置中,如果硬件需要,驱动程序需要在核心 GEM 初始化之后分配和初始化命令环形缓冲区。 UMA 设备通常具有所谓的“被盗”内存区域,该区域为初始帧缓冲区和设备所需的大型连续内存区域提供空间。此空间通常不由 GEM 管理,必须单独初始化到其自己的 DRM MM 对象中。
GEM 对象创建¶
GEM 将 GEM 对象的创建和支持它们的内存的分配分为两个不同的操作。
GEM 对象由 struct struct drm_gem_object
的实例表示。驱动程序通常需要使用私有信息扩展 GEM 对象,因此创建一个特定于驱动程序的 GEM 对象结构类型,该类型嵌入了 struct struct drm_gem_object
的实例。
要创建 GEM 对象,驱动程序会为其特定的 GEM 对象类型实例分配内存,并通过调用 drm_gem_object_init()
来初始化嵌入的 struct struct drm_gem_object
。该函数接收指向 DRM 设备的指针、指向 GEM 对象的指针和缓冲区对象的大小(以字节为单位)。
GEM 使用 shmem 来分配匿名的可分页内存。drm_gem_object_init()
将创建请求大小的 shmfs 文件,并将其存储到 struct struct drm_gem_object
filp 字段中。当图形硬件直接使用系统内存时,该内存用作对象的主要存储,否则用作后备存储。
驱动程序负责通过为每个页面调用 shmem_read_mapping_page_gfp() 来进行实际的物理页面分配。 请注意,他们可以决定在初始化 GEM 对象时分配页面,或者将分配延迟到需要内存时(例如,当由于用户空间内存访问或驱动程序需要启动涉及内存的 DMA 传输时发生页面错误)。
并非总是需要匿名的可分页内存,例如,当硬件需要物理上连续的系统内存时,嵌入式设备中通常是这种情况。 驱动程序可以通过调用 drm_gem_private_object_init()
而不是 drm_gem_object_init()
来创建没有 shmfs 后备(称为私有 GEM 对象)的 GEM 对象。私有 GEM 对象的存储必须由驱动程序管理。
GEM 对象生命周期¶
所有 GEM 对象都由 GEM 核心进行引用计数。可以通过分别调用 drm_gem_object_get()
和 drm_gem_object_put()
来获取和释放引用。
当对 GEM 对象的最后一个引用被释放时,GEM 核心会调用 struct drm_gem_object_funcs
的 free 操作。此操作对于启用 GEM 的驱动程序是强制性的,并且必须释放 GEM 对象和所有相关的资源。
void (*free) (struct drm_gem_object
*obj); 驱动程序负责释放所有 GEM 对象资源。这包括由 GEM 核心创建的资源,这些资源需要使用 drm_gem_object_release()
释放。
GEM 对象命名¶
用户空间和内核之间的通信使用本地句柄、全局名称或最近使用的文件描述符来引用 GEM 对象。所有这些都是 32 位整数值;通常的 Linux 内核限制适用于文件描述符。
GEM 句柄是 DRM 文件本地的。应用程序通过驱动程序特定的 ioctl 获取 GEM 对象的句柄,并且可以使用该句柄在其他标准或驱动程序特定的 ioctl 中引用该 GEM 对象。关闭 DRM 文件句柄会释放其所有 GEM 句柄并取消引用关联的 GEM 对象。
要为 GEM 对象创建句柄,驱动程序会调用 drm_gem_handle_create()
。该函数接受指向 DRM 文件和 GEM 对象的指针,并返回一个本地唯一的句柄。当不再需要该句柄时,驱动程序会通过调用 drm_gem_handle_delete()
将其删除。最后,可以通过调用 drm_gem_object_lookup()
来检索与句柄关联的 GEM 对象。
句柄不拥有 GEM 对象的所有权,它们只引用该对象,当句柄被销毁时,该引用将被删除。为了避免泄漏 GEM 对象,驱动程序必须确保在适当的时候删除它们拥有的引用(例如在对象创建时获得的初始引用),而无需特别考虑句柄。例如,在实现 dumb_create 操作中组合 GEM 对象和句柄创建的特定情况下,驱动程序必须在返回句柄之前删除对 GEM 对象的初始引用。
GEM 名称在目的上与句柄相似,但不是 DRM 文件本地的。它们可以在进程之间传递,以全局引用 GEM 对象。名称不能直接用于引用 DRM API 中的对象,应用程序必须分别使用 DRM_IOCTL_GEM_FLINK 和 DRM_IOCTL_GEM_OPEN ioctl 将句柄转换为名称,并将名称转换为句柄。转换由 DRM 核心处理,无需任何驱动程序特定的支持。
GEM 还通过 PRIME 支持使用 dma-buf 文件描述符进行缓冲区共享。基于 GEM 的驱动程序必须使用提供的帮助程序函数来正确实现导出和导入。请参阅?。由于共享文件描述符本质上比容易猜测的全局 GEM 名称更安全,因此它是首选的缓冲区共享机制。通过 GEM 名称共享缓冲区仅支持旧版用户空间。此外,PRIME 还允许跨设备缓冲区共享,因为它基于 dma-bufs。
GEM 对象映射¶
由于映射操作相当繁重,GEM 倾向于通过驱动程序特定的 ioctl 实现对缓冲区的读/写式访问,而不是将缓冲区映射到用户空间。但是,当需要对缓冲区进行随机访问(例如执行软件渲染)时,直接访问对象可能更有效。
mmap 系统调用不能直接用于映射 GEM 对象,因为它们没有自己的文件句柄。目前存在两种替代方法可以将 GEM 对象映射到用户空间。第一种方法使用驱动程序特定的 ioctl 执行映射操作,在底层调用 do_mmap()。这通常被认为是可疑的,对于新的启用 GEM 的驱动程序似乎不鼓励使用,因此这里不作描述。
第二种方法在 DRM 文件句柄上使用 mmap 系统调用。void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset); DRM 通过 mmap offset 参数传递的伪偏移量来标识要映射的 GEM 对象。在映射之前,必须将 GEM 对象与伪偏移量关联。为此,驱动程序必须在对象上调用 drm_gem_create_mmap_offset()
。
一旦分配,必须以驱动程序特定的方式将伪偏移量值传递给应用程序,然后将其用作 mmap 偏移量参数。
GEM 核心提供了一个帮助程序方法 drm_gem_mmap()
来处理对象映射。该方法可以直接设置为 mmap 文件操作处理程序。它将根据偏移量值查找 GEM 对象,并将 VMA 操作设置为 struct drm_driver
gem_vm_ops 字段。请注意,drm_gem_mmap()
不会将内存映射到用户空间,而是依赖于驱动程序提供的故障处理程序来单独映射页面。
要使用 drm_gem_mmap()
,驱动程序必须使用指向 VM 操作的指针来填充 struct struct drm_driver
gem_vm_ops 字段。
VM 操作是一个 struct vm_operations_struct
,由几个字段组成,其中比较有趣的字段是
struct vm_operations_struct {
void (*open)(struct vm_area_struct * area);
void (*close)(struct vm_area_struct * area);
vm_fault_t (*fault)(struct vm_fault *vmf);
};
open 和 close 操作必须更新 GEM 对象引用计数。驱动程序可以直接使用 drm_gem_vm_open()
和 drm_gem_vm_close()
帮助程序函数作为 open 和 close 处理程序。
当发生页面错误时,fault 操作处理程序负责将各个页面映射到用户空间。根据内存分配方案,驱动程序可以在发生错误时分配页面,或者可以决定在创建对象时为 GEM 对象分配内存。
希望预先映射 GEM 对象而不是处理页面错误的驱动程序可以实现它们自己的 mmap 文件操作处理程序。
对于没有 MMU 的平台,GEM 核心提供了一个帮助程序方法 drm_gem_dma_get_unmapped_area()
。mmap() 例程将调用此方法来获取建议的映射地址。
要使用 drm_gem_dma_get_unmapped_area()
,驱动程序必须使用指向 drm_gem_dma_get_unmapped_area()
的指针来填充 struct struct file_operations
get_unmapped_area 字段。
有关 get_unmapped_area 的更详细信息,请参见 No-MMU memory mapping support
内存一致性¶
当映射到设备或在命令缓冲区中使用时,对象的后备页面将被刷新到内存并标记为写入组合,以便与 GPU 保持一致。同样,如果 CPU 在 GPU 完成渲染对象后访问该对象,则该对象必须与 CPU 的内存视图保持一致,通常涉及各种 GPU 缓存刷新。这种核心 CPU<->GPU 一致性管理由设备特定的 ioctl 提供,该 ioctl 评估对象的当前域,并执行任何必要的刷新或同步,以将对象放入所需的一致性域(请注意,对象可能很忙,即处于活动渲染目标;在这种情况下,设置域会阻止客户端并等待渲染完成,然后再执行任何必要的刷新操作)。
命令执行¶
对于 GPU 设备,最重要的 GEM 功能可能是为客户端提供命令执行接口。客户端程序构造包含对先前分配的内存对象的引用的命令缓冲区,然后将其提交给 GEM。此时,GEM 会注意将所有对象绑定到 GTT 中,执行缓冲区,并提供客户端访问相同缓冲区之间必要的同步。这通常涉及从 GTT 中逐出一些对象并重新绑定其他对象(这是一个相当昂贵的操作),并提供从客户端隐藏固定 GTT 偏移量的重定位支持。客户端必须注意不要提交引用的对象数量超过 GTT 容量的命令缓冲区;否则,GEM 会拒绝它们,并且不会发生任何渲染。同样,如果缓冲区中的多个对象需要分配栅栏寄存器才能正确渲染(例如,在 965 之前的芯片上进行 2D blit),则必须注意不要需要的栅栏寄存器多于客户端可用的栅栏寄存器。这种资源管理应该在 libdrm 中从客户端抽象出来。
GEM 函数参考¶
-
enum drm_gem_object_status¶
用于 fdinfo 报告的对象状态的位掩码
常量
DRM_GEM_OBJECT_RESIDENT
对象驻留在内存中(即,未取消固定)
DRM_GEM_OBJECT_PURGEABLE
对象被用户空间标记为可清除
描述
用于 fdinfo 内存统计的状态位掩码,请参阅drm_gem_object_funcs.status
和drm_show_fdinfo()
。请注意,即使对象仍然处于活动状态或未驻留内存中,也可能被标记为 DRM_GEM_OBJECT_PURGEABLE,在这种情况下,drm_show_fdinfo()
将不会将其计为可清除的。因此,驱动程序无需检查缓冲区是否空闲且驻留在内存中以返回此位。(即,即使缓冲区仍在 GPU 上处于繁忙状态,用户空间也可以将其标记为可清除的... 它只有在空闲时才会 _真正_ 变为可清除的。状态 gem 对象函数无需考虑这一点。)
-
struct drm_gem_object_funcs¶
GEM 对象函数
定义:
struct drm_gem_object_funcs {
void (*free)(struct drm_gem_object *obj);
int (*open)(struct drm_gem_object *obj, struct drm_file *file);
void (*close)(struct drm_gem_object *obj, struct drm_file *file);
void (*print_info)(struct drm_printer *p, unsigned int indent, const struct drm_gem_object *obj);
struct dma_buf *(*export)(struct drm_gem_object *obj, int flags);
int (*pin)(struct drm_gem_object *obj);
void (*unpin)(struct drm_gem_object *obj);
struct sg_table *(*get_sg_table)(struct drm_gem_object *obj);
int (*vmap)(struct drm_gem_object *obj, struct iosys_map *map);
void (*vunmap)(struct drm_gem_object *obj, struct iosys_map *map);
int (*mmap)(struct drm_gem_object *obj, struct vm_area_struct *vma);
int (*evict)(struct drm_gem_object *obj);
enum drm_gem_object_status (*status)(struct drm_gem_object *obj);
size_t (*rss)(struct drm_gem_object *obj);
const struct vm_operations_struct *vm_ops;
};
成员
free
drm_gem_objects 的析构函数。
此回调是必需的。
open
在创建 GEM 句柄时调用。
此回调是可选的。
close
在释放 GEM 句柄时调用。
此回调是可选的。
print_info
如果驱动程序子类化
drm_gem_object
结构,则可以实现此可选挂钩以打印额外的驱动程序特定信息。应在回调中使用
drm_printf_indent()
,并传入 indent 参数。此回调从 drm_gem_print_info() 调用。
此回调是可选的。
export
将后备缓冲区导出为
dma_buf
。如果未设置此项,则使用drm_gem_prime_export()
。此回调是可选的。
pin
将后备缓冲区固定在内存中。由
drm_gem_map_attach()
助手使用。此回调是可选的。
unpin
取消固定后备缓冲区。由
drm_gem_map_detach()
助手使用。此回调是可选的。
get_sg_table
返回缓冲区的散列表表示。在通过
drm_gem_map_dma_buf()
助手导出缓冲区时使用。释放通过在 drm_gem_unmap_buf() 中调用 dma_unmap_sg_attrs() 和 sg_free_table() 完成,因此这些助手和此回调不能用于指向驱动程序私有内存范围的散列表。另请参阅
drm_prime_pages_to_sg()
。vmap
返回缓冲区的虚拟地址。由
drm_gem_dmabuf_vmap()
助手使用。此回调是可选的。
vunmap
释放先前由 vmap 返回的地址。由
drm_gem_dmabuf_vunmap()
助手使用。此回调是可选的。
mmap
处理 gem 对象的 mmap(),相应地设置 vma。
此回调是可选的。
此回调由
drm_gem_mmap_obj()
和drm_gem_prime_mmap()
使用。当存在 mmap 时,不使用 vm_ops,mmap 回调必须设置 vma->vm_ops。evict
从内存中驱逐 gem 对象。由 drm_gem_object_evict() 助手使用。成功时返回 0,否则返回 -errno。
此回调是可选的。
status
可选的状态回调可以返回额外的对象状态,该状态确定对象计入哪些统计信息。此回调在 table_lock 下调用。“与对象状态更改竞争”是“无害的”,并且回调可以预期不会与对象销毁竞争。
由
drm_show_memory_stats()
调用。rss
返回对象在物理内存中的驻留大小。
由
drm_show_memory_stats()
调用。vm_ops
与 mmap 一起使用的虚拟内存操作。
这是可选的,但对于 mmap 支持是必需的。
-
struct drm_gem_lru¶
一个简单的 LRU 助手
定义:
struct drm_gem_lru {
struct mutex *lock;
long count;
struct list_head list;
};
成员
锁
锁定保护 GEM 对象在 LRU 之间移动。对象可以在其间移动的所有 LRU 都应受到同一锁的保护。
count
此 LRU 中 GEM 对象的后备页总数。
list
LRU 列表。
描述
用于跟踪给定状态下的 GEM 对象的助手,以帮助驱动程序的收缩器实现。跟踪用于无锁 shrinker.count_objects
的页面计数,并为驱动程序的 shrinker.scan_objects
实现提供 drm_gem_lru_scan
。
-
struct drm_gem_object¶
GEM 缓冲区对象
定义:
struct drm_gem_object {
struct kref refcount;
unsigned handle_count;
struct drm_device *dev;
struct file *filp;
struct drm_vma_offset_node vma_node;
size_t size;
int name;
struct dma_buf *dma_buf;
struct dma_buf_attachment *import_attach;
struct dma_resv *resv;
struct dma_resv _resv;
struct {
struct list_head list;
#ifdef CONFIG_LOCKDEP;
struct lockdep_map *lock_dep_map;
#endif;
} gpuva;
const struct drm_gem_object_funcs *funcs;
struct list_head lru_node;
struct drm_gem_lru *lru;
};
成员
refcount
此对象的引用计数
请使用
drm_gem_object_get()
获取,并使用 drm_gem_object_put_locked() 或drm_gem_object_put()
释放对 GEM 缓冲区对象的引用。handle_count
这是此对象的 GEM file_priv 句柄计数。
每个句柄也保持一个引用。请注意,当 handle_count 降至 0 时,将清除任何全局名称(例如,flink 命名空间中的 id)。
dev
此对象所属的 DRM 设备。
filp
用作可交换缓冲区对象的后备存储的 SHMEM 文件节点。GEM 还支持具有驱动程序特定后备存储(连续 DMA 内存、特殊保留块)的驱动程序私有对象。在这种情况下,filp 为 NULL。
vma_node
此对象的映射信息以支持 mmap。驱动程序应使用
drm_gem_create_mmap_offset()
分配 mmap 偏移量。可以使用drm_vma_node_offset_addr()
检索偏移量本身。内存映射本身由
drm_gem_mmap()
处理,它还会检查是否允许用户空间访问该对象。size
对象的大小(以字节为单位)。在对象的生命周期内不可变。
name
此对象的全局名称,从 1 开始。0 表示未命名。访问由
drm_device.object_name_lock
覆盖。这由 GEM_FLINK 和 GEM_OPEN ioctl 使用。dma_buf
与此 GEM 对象关联的 dma-buf。
指向与此 gem 对象关联的 dma-buf 的指针(通过导入或导出)。当此对象的最后一个 gem 句柄被释放时,我们会打破生成的引用循环。
import_attach
支持此对象的 dma-buf 附件。
作为 gem 对象导入的任何外部 dma_buf 都将此设置为设备的附件点。这在 gem 对象的生命周期内是不变的。
drm_gem_object_funcs.free
回调负责清理 dma_buf 附件和导入时获取的引用。请注意,drm gem/prime 核心不再依赖于驱动程序设置此字段。因此,对于此字段没有意义的驱动程序(例如,虚拟设备或 usb 总线后面的 displaylink),它们可以简单地将其保留为 NULL。
resv
指向与此 GEM 对象关联的预留对象的指针。
通常 (resv == &**_resv**),除了导入的 GEM 对象。
_resv
此 GEM 对象的预留对象。
这对于导入的 GEM 对象未使用。
gpuva
提供附加到此 GEM 对象的 GPU VA 列表。
驱动程序应使用 GEM 的
dma_resv
锁 (drm_gem_object.resv
) 或自定义锁(如果提供了)来锁定列表访问。funcs
可选的 GEM 对象函数。如果设置了此项,它将代替相应的
drm_driver
GEM 回调。新驱动程序应使用此项。
lru_node
drm_gem_lru
中的列表节点。lru
GEM 对象所在的当前 LRU 列表。
描述
此结构定义了 GEM 缓冲区对象的通用部分,这些部分主要围绕处理 mmap 和用户空间句柄。
缓冲区对象通常缩写为 BO。
-
DRM_GEM_FOPS¶
DRM_GEM_FOPS
默认的 drm GEM 文件操作
描述
此宏提供了一种简写方式,用于在
file_operations
结构中设置 GEM 文件操作。如果您只需要默认操作,请改用 DEFINE_DRM_GEM_FOPS。
-
DEFINE_DRM_GEM_FOPS¶
DEFINE_DRM_GEM_FOPS (name)
为 GEM 驱动程序生成文件操作的宏
参数
name
生成的结构的名称
描述
此宏为基于 GEM 的驱动程序自动生成一个合适的 struct file_operations
,该结构可以分配给 drm_driver.fops
。请注意,此结构不能在驱动程序之间共享,因为它包含使用 THIS_MODULE 对当前模块的引用。
请注意,该声明已标记为静态 - 如果你需要此声明的非静态版本,你可能做错了,并且会意外破坏 THIS_MODULE 引用。
-
void drm_gem_object_get(struct drm_gem_object *obj)¶
获取 GEM 缓冲区对象引用
参数
struct drm_gem_object *obj
GEM 缓冲区对象
描述
此函数获取对 obj 的额外引用。在没有持有引用的情况下调用此函数是非法的。无需锁。
-
void drm_gem_object_put(struct drm_gem_object *obj)¶
丢弃 GEM 缓冲区对象引用
参数
struct drm_gem_object *obj
GEM 缓冲区对象
描述
此函数释放对 obj 的引用。
用于共享内存统计的辅助函数
参数
struct drm_gem_object *obj
有问题的 obj
描述
此辅助函数仅应用于 fdinfo 共享内存统计,以确定 GEM 对象是否被共享。
-
drm_gem_gpuva_set_lock¶
drm_gem_gpuva_set_lock (obj, lock)
设置保护对 gpuva 列表访问的锁。
参数
obj
the
drm_gem_object
锁
用于保护 gpuva 列表的锁。锁定原语必须包含 dep_map 字段。
描述
如果您不使用 dma-resv 锁,而是使用自定义锁来保护对 gpuva 列表的访问,请调用此函数。
-
void drm_gem_gpuva_init(struct drm_gem_object *obj)¶
初始化 GEM 对象的 gpuva 列表
参数
struct drm_gem_object *obj
the
drm_gem_object
描述
此函数初始化 drm_gem_object
的 drm_gpuvm_bo
列表。
只有打算支持 drm_driver_feature
DRIVER_GEM_GPUVA 的驱动程序才需要调用此函数。
另请参阅 drm_gem_gpuva_set_lock()
。
-
drm_gem_for_each_gpuvm_bo¶
drm_gem_for_each_gpuvm_bo (entry__, obj__)
遍历
drm_gpuvm_bo
列表的迭代器
参数
entry__
在每个迭代步骤中分配的
drm_gpuvm_bo
结构obj__
与要遍历的
drm_gpuvm_bo
相关联的drm_gem_object
描述
此迭代器遍历与 drm_gem_object
相关联的所有 drm_gpuvm_bo
结构。
-
drm_gem_for_each_gpuvm_bo_safe¶
drm_gem_for_each_gpuvm_bo_safe (entry__, next__, obj__)
安全地遍历
drm_gpuvm_bo
列表的迭代器
参数
entry__
在每个迭代步骤中分配的
drm_gpuvm_bostructure
next__
用于存储下一步的
next
drm_gpuvm_bo
obj__
与要遍历的
drm_gpuvm_bo
相关联的drm_gem_object
描述
此迭代器遍历与 drm_gem_object
相关联的所有 drm_gpuvm_bo
结构。它使用 list_for_each_entry_safe()
实现,因此可以安全地删除元素。
-
int drm_gem_object_init_with_mnt(struct drm_device *dev, struct drm_gem_object *obj, size_t size, struct vfsmount *gemfs)¶
在给定的 shmfs 挂载点初始化已分配的、由 shmem 支持的 GEM 对象
参数
struct drm_device *dev
应该为其初始化对象的 drm_device
struct drm_gem_object *obj
要初始化的 drm_gem_object
size_t size
对象大小
struct vfsmount *gemfs
将在其中创建 GEM 对象的 tmpfs 挂载点。如果为 NULL,则使用通常的 tmpfs 挂载点 (shm_mnt)。
描述
使用 shmfs 后备存储初始化指定大小的已分配 GEM 对象。
-
int drm_gem_object_init(struct drm_device *dev, struct drm_gem_object *obj, size_t size)¶
初始化已分配的、由 shmem 支持的 GEM 对象
参数
struct drm_device *dev
应该为其初始化对象的 drm_device
struct drm_gem_object *obj
要初始化的 drm_gem_object
size_t size
对象大小
描述
使用 shmfs 后备存储初始化指定大小的已分配 GEM 对象。
-
void drm_gem_private_object_init(struct drm_device *dev, struct drm_gem_object *obj, size_t size)¶
初始化已分配的私有 GEM 对象
参数
struct drm_device *dev
应该为其初始化对象的 drm_device
struct drm_gem_object *obj
要初始化的 drm_gem_object
size_t size
对象大小
描述
使用未提供的 GEM 后备存储初始化指定大小的已分配 GEM 对象。相反,调用者负责后备对象并处理它。
-
void drm_gem_private_object_fini(struct drm_gem_object *obj)¶
完成失败的 drm_gem_object
参数
struct drm_gem_object *obj
drm_gem_object
描述
当初始化失败时,取消初始化已分配的 GEM 对象
参数
struct drm_file *filp
用于句柄查找的 drm 文件私有结构
u32 handle
要删除的用户空间句柄
描述
从 filp 查找表中移除通过 drm_gem_handle_create()
添加的 GEM 句柄。如果这是最后一个句柄,还会清理链接的资源,如 GEM 名称。
-
int drm_gem_dumb_map_offset(struct drm_file *file, struct drm_device *dev, u32 handle, u64 *offset)¶
返回 gem 对象的伪 mmap 偏移量
参数
struct drm_file *file
包含 gem 对象的 drm 文件私有结构
struct drm_device *dev
对应的 drm_device
u32 handle
gem 对象句柄
u64 *offset
伪 mmap 偏移量的返回位置
描述
这实现了 drm_driver.dumb_map_offset
KMS 驱动回调,用于使用 gem 管理其后备存储的驱动程序。
返回
成功时返回 0,失败时返回负错误代码。
-
int drm_gem_handle_create(struct drm_file *file_priv, struct drm_gem_object *obj, u32 *handlep)¶
为对象创建一个 gem 句柄
参数
struct drm_file *file_priv
用于注册句柄的 drm 文件私有结构
struct drm_gem_object *obj
要注册的对象
u32 *handlep
指向将创建的句柄返回给调用者的指针
描述
为此对象创建一个句柄。 这会向对象添加一个句柄引用,其中包括一个常规的引用计数。 调用者很可能希望在之后取消对该对象的引用。
由于这会将 obj 发布到用户空间,因此到此时它必须完全设置好,驱动程序必须在其缓冲区对象创建回调中最后调用此函数。
-
void drm_gem_free_mmap_offset(struct drm_gem_object *obj)¶
释放对象的伪 mmap 偏移量
参数
struct drm_gem_object *obj
有问题的 obj
描述
此例程释放 drm_gem_create_mmap_offset()
分配的伪偏移量。
请注意,drm_gem_object_release()
已经调用了此函数,因此驱动程序在释放 GEM 对象时不必自己处理释放 mmap 偏移量的问题。
-
int drm_gem_create_mmap_offset_size(struct drm_gem_object *obj, size_t size)¶
为对象创建一个伪 mmap 偏移量
参数
struct drm_gem_object *obj
有问题的 obj
size_t size
虚拟大小
描述
GEM 内存映射的工作原理是将一个伪 mmap 偏移量返回给用户空间,以便用户空间可以在后续的 mmap(2) 调用中使用。 然后,DRM 核心代码根据偏移量查找对象并设置各种内存映射结构。
当虚拟大小与物理大小不同时(即 drm_gem_object.size
),此例程会为 obj 分配并附加一个伪偏移量。 否则,只需使用 drm_gem_create_mmap_offset()
。
此函数是幂等的,并且可以透明地处理已分配的 mmap 偏移量。 驱动程序无需检查这种情况。
-
int drm_gem_create_mmap_offset(struct drm_gem_object *obj)¶
为对象创建一个伪 mmap 偏移量
参数
struct drm_gem_object *obj
有问题的 obj
描述
GEM 内存映射的工作原理是将一个伪 mmap 偏移量返回给用户空间,以便用户空间可以在后续的 mmap(2) 调用中使用。 然后,DRM 核心代码根据偏移量查找对象并设置各种内存映射结构。
此例程为 obj 分配并附加一个伪偏移量。
驱动程序可以在释放 obj 之前调用 drm_gem_free_mmap_offset()
来再次释放伪偏移量。
-
struct page **drm_gem_get_pages(struct drm_gem_object *obj)¶
帮助程序从 shmem 为 GEM 对象分配后备页
参数
struct drm_gem_object *obj
有问题的 obj
描述
这将读取给定 gem 对象的 shmem 后备存储的页面数组。 返回一个页面数组。 如果未分配或换出页面,则会分配/换入所需的页面。 请注意,整个对象都由页面数组覆盖并固定在内存中。
使用 drm_gem_put_pages()
释放数组并取消固定所有页面。
这会使用 shmem 映射上设置的 GFP 掩码(请参阅 mapping_set_gfp_mask())。 如果您需要其他 GFP 掩码,则必须自己执行这些分配。
请注意,不允许在运行时更改 gfp 区域。 也就是说,必须使用与初始化期间设置的 gfp_zone(gfp) 相同的 gfp_zone(gfp) 来调用 shmem_read_mapping_page_gfp()。 如果您有特殊的区域约束,请在 drm_gem_object_init()
后通过 mapping_set_gfp_mask() 设置它们。 shmem-core 会注意在换入期间将页面保留在所需的区域中。
此函数仅对使用 drm_gem_object_init()
初始化的对象有效,但对于仅使用 drm_gem_private_object_init()
初始化的对象无效。
-
void drm_gem_put_pages(struct drm_gem_object *obj, struct page **pages, bool dirty, bool accessed)¶
帮助程序释放 GEM 对象的后备页
参数
struct drm_gem_object *obj
有问题的 obj
struct page **pages
要释放的页
bool dirty
如果为 true,则页面将被标记为脏
bool accessed
如果为 true,则页面将被标记为已访问
-
int drm_gem_objects_lookup(struct drm_file *filp, void __user *bo_handles, int count, struct drm_gem_object ***objs_out)¶
从句柄数组中查找 GEM 对象
参数
struct drm_file *filp
DRM 文件私有数据
void __user *bo_handles
指向用户空间句柄数组的用户指针
int count
句柄数组的大小
struct drm_gem_object ***objs_out
返回指向 drm_gem_object 指针数组的指针
描述
接受一个用户空间句柄数组,并返回一个新分配的 GEM 对象数组。
对于单个句柄查找,请使用 drm_gem_object_lookup()
。
返回
objs 使用 GEM 对象指针填充。返回的 GEM 对象需要使用 drm_gem_object_put()
释放。如果查找失败,则返回 -ENOENT。成功返回 0。
-
struct drm_gem_object *drm_gem_object_lookup(struct drm_file *filp, u32 handle)¶
从句柄查找 GEM 对象
参数
struct drm_file *filp
DRM 文件私有数据
u32 handle
用户空间句柄
描述
如果查找句柄数组,请使用 drm_gem_objects_lookup()
。
返回
如果 filp 上存在由句柄命名的对象,则返回该对象的引用;否则返回 NULL。
-
long drm_gem_dma_resv_wait(struct drm_file *filep, u32 handle, bool wait_all, unsigned long timeout)¶
等待 GEM 对象的预留对象的共享和/或独占围栏。
参数
struct drm_file *filep
DRM 文件私有数据
u32 handle
用户空间句柄
bool wait_all
如果为 true,则等待所有围栏,否则仅等待独占围栏
unsigned long timeout
以节拍为单位的超时值,或者为零以立即返回
返回
如果被中断,则返回 -ERESTARTSYS;如果等待超时,则返回 0;如果成功,则返回大于 0 的值。
-
void drm_gem_object_release(struct drm_gem_object *obj)¶
释放 GEM 缓冲区对象资源
参数
struct kref *kref
要释放的对象的 kref
描述
在丢失对该对象的最后一个引用后调用。
释放该对象
-
void drm_gem_vm_open(struct vm_area_struct *vma)¶
GEM 的 vma->ops->open 实现
参数
struct vm_area_struct *vma
VM 区域结构
描述
此函数为 GEM 驱动程序实现 #vm_operations_struct open() 回调。必须与 drm_gem_vm_close()
一起使用。
-
void drm_gem_vm_close(struct vm_area_struct *vma)¶
GEM 的 vma->ops->close 实现
参数
struct vm_area_struct *vma
VM 区域结构
描述
此函数为 GEM 驱动程序实现 #vm_operations_struct close() 回调。必须与 drm_gem_vm_open()
一起使用。
-
int drm_gem_mmap_obj(struct drm_gem_object *obj, unsigned long obj_size, struct vm_area_struct *vma)¶
内存映射 GEM 对象
参数
struct drm_gem_object *obj
要映射的 GEM 对象
unsigned long obj_size
要映射的对象大小,以字节为单位
struct vm_area_struct *vma
要映射区域的 VMA
描述
设置 VMA 以准备使用 GEM 对象的 vm_ops 映射 GEM 对象。根据他们的要求,GEM 对象可以在他们的 vm_ops 中提供一个故障处理程序(在这种情况下,对该对象的任何访问都将被捕获,以执行迁移、GTT 绑定、表面寄存器分配或性能监视),或者在调用 drm_gem_mmap_obj 后同步 mmap 缓冲区内存。
此函数主要用于实现 DMABUF mmap 操作,当 GEM 对象不是基于其伪偏移量查找时。要实现 DRM mmap 操作,驱动程序应使用 drm_gem_mmap()
函数。
drm_gem_mmap_obj()
假设用户被授予访问缓冲区的权限,而 drm_gem_mmap()
阻止非特权用户映射随机对象。因此,调用者必须在调用此辅助函数之前验证访问限制。
如果对象大小小于 VMA 大小,或者未提供 vm_ops,则返回 0 或成功,或 -EINVAL。
参数
struct file *filp
DRM 文件指针
struct vm_area_struct *vma
要映射区域的 VMA
描述
如果驱动程序支持 GEM 对象映射,则对 DRM 文件描述符的 mmap 调用将在此处结束。
根据传入的偏移量查找 GEM 对象(vma->vm_pgoff 将包含我们在对对象调用 GTT 映射 ioctl 时创建的伪偏移量),并使用对 drm_gem_mmap_obj()
的调用对其进行映射。
如果未授予调用者访问缓冲区对象的权限,则 mmap 将失败,并返回 EACCES。请参阅 VMA 管理器以获取更多信息。
-
int drm_gem_lock_reservations(struct drm_gem_object **objs, int count, struct ww_acquire_ctx *acquire_ctx)¶
设置 ww 上下文并获取 GEM 对象数组上的锁。
参数
struct drm_gem_object **objs
要锁定的 drm_gem_object
int count
objs 中的对象数量
struct ww_acquire_ctx *acquire_ctx
将作为跟踪此锁定预留集合的一部分进行初始化的 struct ww_acquire_ctx。
描述
锁定预留后,您需要为共享栅栏(如果适用)设置空间,提交作业,然后调用 drm_gem_unlock_reservations()。
-
void drm_gem_lru_init(struct drm_gem_lru *lru, struct mutex *lock)¶
初始化 LRU
参数
struct drm_gem_lru *lru
要初始化的 LRU
struct mutex *lock
保护 LRU 的锁
-
void drm_gem_lru_remove(struct drm_gem_object *obj)¶
从它所在的任何 LRU 中移除对象
参数
struct drm_gem_object *obj
要从当前 LRU 中移除的 GEM 对象
描述
如果对象当前在任何 LRU 中,则将其移除。
-
void drm_gem_lru_move_tail_locked(struct drm_gem_lru *lru, struct drm_gem_object *obj)¶
将对象移动到 LRU 的尾部
参数
struct drm_gem_lru *lru
要将对象移动到的 LRU。
struct drm_gem_object *obj
要移动到此 LRU 的 GEM 对象
描述
类似于 drm_gem_lru_move_tail
,但必须持有 lru 锁
-
void drm_gem_lru_move_tail(struct drm_gem_lru *lru, struct drm_gem_object *obj)¶
将对象移动到 LRU 的尾部
参数
struct drm_gem_lru *lru
要将对象移动到的 LRU。
struct drm_gem_object *obj
要移动到此 LRU 的 GEM 对象
描述
如果对象已在此 LRU 中,则将其移动到尾部。否则,将其从它所在的任何其他 LRU 中移除(如果有),并移动到此 LRU 中。
-
unsigned long drm_gem_lru_scan(struct drm_gem_lru *lru, unsigned int nr_to_scan, unsigned long *remaining, bool (*shrink)(struct drm_gem_object *obj))¶
用于实现收缩器 scan_objects 的助手函数
参数
struct drm_gem_lru *lru
要扫描的 LRU
unsigned int nr_to_scan
要尝试回收的页数
unsigned long *remaining
要回收的剩余页数,应由调用者初始化
bool (*shrink)(struct drm_gem_object *obj)
尝试收缩/回收对象的回调函数。
描述
如果收缩回调成功,则期望驱动程序将对象移出此 LRU。
如果 LRU 可能包含活动缓冲区,则收缩回调有责任检查这一点(例如,dma_resv_test_signaled()
)或在必要时阻塞,直到缓冲区变为空闲。
-
int drm_gem_evict(struct drm_gem_object *obj)¶
用于驱逐 GEM 对象后备页的助手函数
参数
struct drm_gem_object *obj
有问题的 obj
GEM DMA 助手函数参考¶
DRM GEM/DMA 助手是一种提供以连续内存块形式呈现给设备的缓冲区对象的方法。 这对于不支持散点/收集 DMA(直接或通过使用紧密连接的 IOMMU)的设备很有用。
对于通过(外部)IOMMU 访问内存总线的设备,则使用传统的基于页面的分配器来分配缓冲区对象,并且可以分散在物理内存中。但是,它们在 IOVA 空间中是连续的,因此对于使用它们的设备而言是连续的。
对于其他设备,助手依赖 CMA 来提供物理上连续的内存中的缓冲区对象。
对于 struct drm_gem_object
函数中的 GEM 回调助手,请参阅具有 _object_ 中缀的类似名称的函数(例如,drm_gem_dma_object_vmap() 包装 drm_gem_dma_vmap()
)。这些助手执行必要的类型转换。
-
struct drm_gem_dma_object¶
由 DMA 内存分配支持的 GEM 对象
定义:
struct drm_gem_dma_object {
struct drm_gem_object base;
dma_addr_t dma_addr;
struct sg_table *sgt;
void *vaddr;
bool map_noncoherent;
};
成员
base
基本 GEM 对象
dma_addr
后备内存的 DMA 地址
sgt
用于导入的 PRIME 缓冲区的散点/收集表。 该表可以有多个条目,但保证它们具有连续的 DMA 地址。
vaddr
后备内存的内核虚拟地址
map_noncoherent
如果为 true,则 GEM 对象由非一致性内存支持
-
void drm_gem_dma_object_free(struct drm_gem_object *obj)¶
drm_gem_dma_free()
的 GEM 对象函数
参数
struct drm_gem_object *obj
要释放的 GEM 对象
描述
此函数包装 drm_gem_dma_free_object()。 采用 DMA 助手的驱动程序应将其用作其 drm_gem_object_funcs.free
处理程序。
-
void drm_gem_dma_object_print_info(struct drm_printer *p, unsigned int indent, const struct drm_gem_object *obj)¶
为 debugfs 打印
drm_gem_dma_object
信息
参数
struct drm_printer *p
DRM 打印机
unsigned int indent
制表符缩进级别
const struct drm_gem_object *obj
GEM 对象
描述
此函数封装了 drm_gem_dma_print_info()
。使用 DMA 助手的驱动程序应使用此函数作为其 drm_gem_object_funcs.print_info
处理程序。
-
struct sg_table *drm_gem_dma_object_get_sg_table(struct drm_gem_object *obj)¶
用于
drm_gem_dma_get_sg_table()
的 GEM 对象函数
参数
struct drm_gem_object *obj
GEM 对象
描述
此函数封装了 drm_gem_dma_get_sg_table()
。使用 DMA 助手的驱动程序应使用它作为其 drm_gem_object_funcs.get_sg_table
处理程序。
返回
指向已固定页面的散布/收集表的指针,如果失败则为 NULL。
-
int drm_gem_dma_object_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma)¶
用于
drm_gem_dma_mmap()
的 GEM 对象函数
参数
struct drm_gem_object *obj
GEM 对象
struct vm_area_struct *vma
要映射区域的 VMA
描述
此函数封装了 drm_gem_dma_mmap()
。使用 DMA 助手的驱动程序应使用它作为其 drm_gem_object_funcs.mmap
处理程序。
返回
成功时返回 0,失败时返回负错误代码。
-
DRM_GEM_DMA_DRIVER_OPS_WITH_DUMB_CREATE¶
DRM_GEM_DMA_DRIVER_OPS_WITH_DUMB_CREATE (dumb_create_func)
DMA GEM 驱动程序操作
参数
dumb_create_func
用于 .dumb_create 的回调函数
描述
此宏为在 drm_driver
结构中设置默认 GEM 操作提供快捷方式。
对于覆盖 struct rm_driver
.dumb_create 默认实现的驱动程序,此宏是 DRM_GEM_DMA_DRIVER_OPS 的变体。如果可能,请使用 DRM_GEM_DMA_DRIVER_OPS。需要在导入的缓冲区上使用虚拟地址的驱动程序应使用 DRM_GEM_DMA_DRIVER_OPS_VMAP_WITH_DUMB_CREATE()
代替。
-
DRM_GEM_DMA_DRIVER_OPS¶
DRM_GEM_DMA_DRIVER_OPS
DMA GEM 驱动程序操作
描述
此宏为在
drm_driver
结构中设置默认 GEM 操作提供快捷方式。对于带有自己的
struct drm_driver
.dumb_create 实现的驱动程序,应使用DRM_GEM_DMA_DRIVER_OPS_WITH_DUMB_CREATE()
代替。如果可能,请使用 DRM_GEM_DMA_DRIVER_OPS。需要在导入的缓冲区上使用虚拟地址的驱动程序应使用 DRM_GEM_DMA_DRIVER_OPS_VMAP 代替。
-
DRM_GEM_DMA_DRIVER_OPS_VMAP_WITH_DUMB_CREATE¶
DRM_GEM_DMA_DRIVER_OPS_VMAP_WITH_DUMB_CREATE (dumb_create_func)
DMA GEM 驱动程序操作,确保缓冲区上的虚拟地址
参数
dumb_create_func
用于 .dumb_create 的回调函数
描述
此宏为在 drm_driver
结构中设置默认 GEM 操作提供快捷方式,适用于也需要在导入的缓冲区上使用虚拟地址的驱动程序。
对于覆盖 struct drm_driver
.dumb_create 默认实现的驱动程序,此宏是 DRM_GEM_DMA_DRIVER_OPS_VMAP 的变体。如果可能,请使用 DRM_GEM_DMA_DRIVER_OPS_VMAP。不需要在导入的缓冲区上使用虚拟地址的驱动程序应使用 DRM_GEM_DMA_DRIVER_OPS_WITH_DUMB_CREATE()
代替。
-
DRM_GEM_DMA_DRIVER_OPS_VMAP¶
DRM_GEM_DMA_DRIVER_OPS_VMAP
DMA GEM 驱动程序操作,确保缓冲区上的虚拟地址
描述
此宏为在
drm_driver
结构中设置默认 GEM 操作提供快捷方式,适用于也需要在导入的缓冲区上使用虚拟地址的驱动程序。对于带有自己的
struct drm_driver
.dumb_create 实现的驱动程序,应使用DRM_GEM_DMA_DRIVER_OPS_VMAP_WITH_DUMB_CREATE()
代替。如果可能,请使用 DRM_GEM_DMA_DRIVER_OPS_VMAP。不需要在导入的缓冲区上使用虚拟地址的驱动程序应使用 DRM_GEM_DMA_DRIVER_OPS 代替。
-
DEFINE_DRM_GEM_DMA_FOPS¶
DEFINE_DRM_GEM_DMA_FOPS (name)
用于为 DMA 驱动程序生成文件操作的宏
参数
name
生成的结构的名称
描述
此宏自动为基于 DMA 的驱动程序生成一个合适的 struct file_operations
,可以将其分配给 drm_driver.fops
。请注意,此结构不能在驱动程序之间共享,因为它包含对使用 THIS_MODULE 的当前模块的引用。
请注意,该声明已标记为静态 - 如果你需要此声明的非静态版本,你可能做错了,并且会意外破坏 THIS_MODULE 引用。
-
struct drm_gem_dma_object *drm_gem_dma_create(struct drm_device *drm, size_t size)¶
分配具有给定大小的对象
参数
struct drm_device *drm
DRM 设备
size_t size
要分配的对象的大小
描述
此函数创建一个 DMA GEM 对象,并分配内存作为后备存储。分配的内存将占用总线地址空间的连续块。
对于直接连接到内存总线的设备,分配的内存将在物理上是连续的。对于通过 IOMMU 访问的设备,分配的内存不期望在物理上是连续的,因为拥有连续的 IOVA 足以满足设备的 DMA 要求。
返回
成功时为 struct drm_gem_dma_object
*,失败时为 ERR_PTR()
编码的负错误代码。
-
void drm_gem_dma_free(struct drm_gem_dma_object *dma_obj)¶
释放与 DMA GEM 对象关联的资源
参数
struct drm_gem_dma_object *dma_obj
要释放的 DMA GEM 对象
描述
此函数释放 DMA GEM 对象的后备内存,清理 GEM 对象状态,并释放用于存储对象本身的内存。如果缓冲区是导入的且设置了虚拟地址,则会释放该虚拟地址。
-
int drm_gem_dma_dumb_create_internal(struct drm_file *file_priv, struct drm_device *drm, struct drm_mode_create_dumb *args)¶
创建一个哑缓冲区对象
参数
struct drm_file *file_priv
用于创建哑缓冲区的 DRM 文件私有结构
struct drm_device *drm
DRM 设备
struct drm_mode_create_dumb *args
IOCTL 数据
描述
此函数将 pitch 和 size 参数对齐到最小要求。这是一个内部辅助函数,驱动程序可以将其包装起来,以处理具有更特定对齐要求的硬件。它不应直接用作它们的 drm_driver.dumb_create
回调。
返回
成功时返回 0,失败时返回负错误代码。
-
int drm_gem_dma_dumb_create(struct drm_file *file_priv, struct drm_device *drm, struct drm_mode_create_dumb *args)¶
创建一个哑缓冲区对象
参数
struct drm_file *file_priv
用于创建哑缓冲区的 DRM 文件私有结构
struct drm_device *drm
DRM 设备
struct drm_mode_create_dumb *args
IOCTL 数据
描述
此函数计算哑缓冲区的 pitch,并将其向上舍入为每像素的整数个字节。对于对 pitch 没有其他限制的硬件,驱动程序可以直接使用此函数作为其 drm_driver.dumb_create
回调。
对于具有其他限制的硬件,驱动程序可以调整用户空间设置的字段,并将 IOCTL 数据传递给 drm_gem_dma_dumb_create_internal()
函数。
返回
成功时返回 0,失败时返回负错误代码。
-
unsigned long drm_gem_dma_get_unmapped_area(struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags)¶
在 noMMU 情况下,为映射提出地址
参数
struct file *filp
文件对象
unsigned long addr
内存地址
unsigned long len
缓冲区大小
unsigned long pgoff
页面偏移
unsigned long flags
内存标志
描述
此函数用于 noMMU 平台,以提出给定缓冲区的地址映射。它旨在用作 struct file_operations.get_unmapped_area
操作的直接处理程序。
返回
成功时的映射地址,或失败时的负错误代码。
-
void drm_gem_dma_print_info(const struct drm_gem_dma_object *dma_obj, struct drm_printer *p, unsigned int indent)¶
为 debugfs 打印
drm_gem_dma_object
信息
参数
const struct drm_gem_dma_object *dma_obj
DMA GEM 对象
struct drm_printer *p
DRM 打印机
unsigned int indent
制表符缩进级别
描述
此函数打印 dma_addr 和 vaddr,用于例如 debugfs 输出。
-
struct sg_table *drm_gem_dma_get_sg_table(struct drm_gem_dma_object *dma_obj)¶
为 DMA GEM 对象提供固定页面的分散/聚集表
参数
struct drm_gem_dma_object *dma_obj
DMA GEM 对象
描述
此函数通过调用标准 DMA 映射 API 导出分散/聚集表。
返回
指向已固定页面的散布/收集表的指针,如果失败则为 NULL。
-
struct drm_gem_object *drm_gem_dma_prime_import_sg_table(struct drm_device *dev, struct dma_buf_attachment *attach, struct sg_table *sgt)¶
从另一个驱动程序的固定页面的分散/聚集表生成 DMA GEM 对象
参数
struct drm_device *dev
要导入到的设备
struct dma_buf_attachment *attach
DMA-BUF 附件
struct sg_table *sgt
固定页面的分散/聚集表
描述
此函数导入由另一个驱动程序通过 DMA-BUF 导出的分散/聚集表。导入的缓冲区必须在内存中物理连续(即,分散/聚集表必须包含单个条目)。使用 DMA 帮助程序的驱动程序应将其设置为其 drm_driver.gem_prime_import_sg_table
回调。
返回
指向新创建的 GEM 对象的指针,或失败时指向 ERR_PTR 编码的负错误代码。
-
int drm_gem_dma_vmap(struct drm_gem_dma_object *dma_obj, struct iosys_map *map)¶
将 DMA GEM 对象映射到内核的虚拟地址空间
参数
struct drm_gem_dma_object *dma_obj
DMA GEM 对象
struct iosys_map *map
返回 DMA GEM 对象后备存储的内核虚拟地址。
描述
此函数将缓冲区映射到内核的虚拟地址空间。由于 DMA 缓冲区已映射到内核虚拟地址空间,因此它仅返回缓存的虚拟地址。
返回
成功时返回 0,否则返回负错误代码。
-
int drm_gem_dma_mmap(struct drm_gem_dma_object *dma_obj, struct vm_area_struct *vma)¶
内存映射导出的 DMA GEM 对象
参数
struct drm_gem_dma_object *dma_obj
DMA GEM 对象
struct vm_area_struct *vma
要映射区域的 VMA
描述
此函数将缓冲区映射到用户空间进程的地址空间。除了通常的 GEM VMA 设置之外,它还会立即将整个对象调入,而不是使用按需调入。
返回
成功时返回 0,失败时返回负错误代码。
-
struct drm_gem_object *drm_gem_dma_prime_import_sg_table_vmap(struct drm_device *dev, struct dma_buf_attachment *attach, struct sg_table *sgt)¶
PRIME 导入另一个驱动程序的散列表/收集表,并获取缓冲区的虚拟地址
参数
struct drm_device *dev
DRM 设备
struct dma_buf_attachment *attach
DMA-BUF 附件
struct sg_table *sgt
已固定页面的散列表/收集表
描述
此函数使用 drm_gem_dma_prime_import_sg_table()
导入散列表/收集表,并使用 dma_buf_vmap()
获取内核虚拟地址。这确保了 DMA GEM 对象始终设置了其虚拟地址。此地址在对象释放时被释放。
此函数可用作 drm_driver.gem_prime_import_sg_table
回调函数。DRM_GEM_DMA_DRIVER_OPS_VMAP
宏提供了一个快捷方式来设置必要的 DRM 驱动程序操作。
返回
指向新创建的 GEM 对象的指针,或失败时指向 ERR_PTR 编码的负错误代码。
GEM SHMEM 辅助函数参考¶
此库为由使用匿名可分页内存分配的 shmem 缓冲区支持的 GEM 对象提供辅助函数。
在 GEM 对象上运行的函数接收 struct drm_gem_shmem_object
。对于 struct drm_gem_object
函数中的 GEM 回调辅助函数,请参阅名称相似的带有 _object_ 中缀的函数(例如,drm_gem_shmem_object_vmap() 包装了 drm_gem_shmem_vmap())。这些辅助函数执行必要的类型转换。
-
struct drm_gem_shmem_object¶
由 shmem 支持的 GEM 对象
定义:
struct drm_gem_shmem_object {
struct drm_gem_object base;
struct page **pages;
unsigned int pages_use_count;
int madv;
struct list_head madv_list;
struct sg_table *sgt;
void *vaddr;
unsigned int vmap_use_count;
bool pages_mark_dirty_on_put : 1;
bool pages_mark_accessed_on_put : 1;
bool map_wc : 1;
};
成员
base
基础 GEM 对象
pages
页表
pages_use_count
页表上的引用计数。当计数达到零时,页面会被放入。
madv
madvise 的状态
0 表示激活/正在使用。负值表示对象已被清除。正值是特定于驱动程序的,辅助函数不使用。
madv_list
用于 madvise 跟踪的列表条目
通常由驱动程序用来跟踪可清除的对象
sgt
用于导入的 PRIME 缓冲区的散列表/收集表
vaddr
后备内存的内核虚拟地址
vmap_use_count
虚拟地址上的引用计数。当计数达到零时,地址将被取消映射。
pages_mark_dirty_on_put
当页面被放入时,将其标记为脏。
pages_mark_accessed_on_put
当页面被放入时,将其标记为已访问。
map_wc
映射对象写入合并(而不是使用 shmem 默认值)。
-
void drm_gem_shmem_object_free(struct drm_gem_object *obj)¶
用于
drm_gem_shmem_free()
的 GEM 对象函数
参数
struct drm_gem_object *obj
要释放的 GEM 对象
描述
此函数包装了 drm_gem_shmem_free()
。使用 shmem 辅助函数的驱动程序应将其用作 drm_gem_object_funcs.free
处理程序。
-
void drm_gem_shmem_object_print_info(struct drm_printer *p, unsigned int indent, const struct drm_gem_object *obj)¶
打印用于 debugfs 的
drm_gem_shmem_object
信息
参数
struct drm_printer *p
DRM 打印机
unsigned int indent
制表符缩进级别
const struct drm_gem_object *obj
GEM 对象
描述
此函数包装了 drm_gem_shmem_print_info()
。使用 shmem 辅助函数的驱动程序应将此函数用作 drm_gem_object_funcs.print_info
处理程序。
-
int drm_gem_shmem_object_pin(struct drm_gem_object *obj)¶
用于
drm_gem_shmem_pin()
的 GEM 对象函数
参数
struct drm_gem_object *obj
GEM 对象
描述
此函数包装了 drm_gem_shmem_pin()
。使用 shmem 辅助函数的驱动程序应将其用作 drm_gem_object_funcs.pin
处理程序。
-
void drm_gem_shmem_object_unpin(struct drm_gem_object *obj)¶
用于
drm_gem_shmem_unpin()
的 GEM 对象函数
参数
struct drm_gem_object *obj
GEM 对象
描述
此函数包装了 drm_gem_shmem_unpin()
。使用 shmem 辅助函数的驱动程序应将其用作 drm_gem_object_funcs.unpin
处理程序。
-
struct sg_table *drm_gem_shmem_object_get_sg_table(struct drm_gem_object *obj)¶
用于
drm_gem_shmem_get_sg_table()
的 GEM 对象函数
参数
struct drm_gem_object *obj
GEM 对象
描述
此函数包装了 drm_gem_shmem_get_sg_table()
。使用 shmem 辅助函数的驱动程序应将其用作 drm_gem_object_funcs.get_sg_table
处理程序。
返回
指向已固定页面的散列表/收集表的指针,如果失败,则为错误指针。
-
int drm_gem_shmem_object_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma)¶
用于
drm_gem_shmem_mmap()
的 GEM 对象函数
参数
struct drm_gem_object *obj
GEM 对象
struct vm_area_struct *vma
要映射区域的 VMA
描述
此函数包装了 drm_gem_shmem_mmap()
。使用 shmem 辅助函数的驱动程序应将其用作 drm_gem_object_funcs.mmap
处理程序。
返回
成功时返回 0,失败时返回负错误代码。
-
DRM_GEM_SHMEM_DRIVER_OPS¶
DRM_GEM_SHMEM_DRIVER_OPS
-
struct drm_gem_shmem_object *drm_gem_shmem_create(struct drm_device *dev, size_t size)¶
分配一个具有给定大小的对象
参数
struct drm_device *dev
DRM 设备
size_t size
要分配的对象的大小
描述
此函数创建一个 shmem GEM 对象。
返回
成功时返回 struct drm_gem_shmem_object
*,失败时返回 ERR_PTR()
编码的负错误代码。
-
struct drm_gem_shmem_object *drm_gem_shmem_create_with_mnt(struct drm_device *dev, size_t size, struct vfsmount *gemfs)¶
在给定的挂载点中分配一个具有给定大小的对象
参数
struct drm_device *dev
DRM 设备
size_t size
要分配的对象的大小
struct vfsmount *gemfs
将在其中创建 GEM 对象的 tmpfs 挂载点
描述
此函数在给定的 tmpfs 挂载点中创建一个 shmem GEM 对象。
返回
成功时返回 struct drm_gem_shmem_object
*,失败时返回 ERR_PTR()
编码的负错误代码。
-
void drm_gem_shmem_free(struct drm_gem_shmem_object *shmem)¶
释放与 shmem GEM 对象关联的资源
参数
struct drm_gem_shmem_object *shmem
要释放的 shmem GEM 对象
描述
此函数清理 GEM 对象状态并释放用于存储对象本身的内存。
-
int drm_gem_shmem_pin(struct drm_gem_shmem_object *shmem)¶
为 shmem GEM 对象锁定后备页
参数
struct drm_gem_shmem_object *shmem
shmem GEM 对象
描述
此函数确保在导出缓冲区时将后备页锁定在内存中。
返回
成功时返回 0,失败时返回负错误代码。
-
void drm_gem_shmem_unpin(struct drm_gem_shmem_object *shmem)¶
为 shmem GEM 对象解除锁定后备页
参数
struct drm_gem_shmem_object *shmem
shmem GEM 对象
描述
此函数取消后备页必须锁定在内存中的要求。
-
int drm_gem_shmem_dumb_create(struct drm_file *file, struct drm_device *dev, struct drm_mode_create_dumb *args)¶
创建一个哑 shmem 缓冲区对象
参数
struct drm_file *file
创建哑缓冲区的 DRM 文件结构
struct drm_device *dev
DRM 设备
struct drm_mode_create_dumb *args
IOCTL 数据
描述
此函数计算哑缓冲区的 pitch,并将其向上舍入为每像素的整数个字节。对于对 pitch 没有其他限制的硬件,驱动程序可以直接使用此函数作为其 drm_driver.dumb_create
回调。
对于具有其他限制的硬件,驱动程序可以在调用此函数之前调整用户空间设置的字段。
返回
成功时返回 0,失败时返回负错误代码。
-
int drm_gem_shmem_mmap(struct drm_gem_shmem_object *shmem, struct vm_area_struct *vma)¶
内存映射一个 shmem GEM 对象
参数
struct drm_gem_shmem_object *shmem
shmem GEM 对象
struct vm_area_struct *vma
要映射区域的 VMA
描述
此函数为 shmem 对象实现 GEM DRM 文件 mmap 操作的增强版本。
返回
成功时返回 0,失败时返回负错误代码。
-
void drm_gem_shmem_print_info(const struct drm_gem_shmem_object *shmem, struct drm_printer *p, unsigned int indent)¶
打印用于 debugfs 的
drm_gem_shmem_object
信息
参数
const struct drm_gem_shmem_object *shmem
shmem GEM 对象
struct drm_printer *p
DRM 打印机
unsigned int indent
制表符缩进级别
-
struct sg_table *drm_gem_shmem_get_sg_table(struct drm_gem_shmem_object *shmem)¶
为 shmem GEM 对象提供锁定页面的散点/收集表
参数
struct drm_gem_shmem_object *shmem
shmem GEM 对象
描述
此函数通过调用标准 DMA 映射 API 导出适用于 PRIME 使用的散点/收集表。
需要为对象获取散点/收集表的驱动程序需要调用 drm_gem_shmem_get_pages_sgt()
。
返回
指向已固定页面的散列表/收集表的指针,如果失败,则为错误指针。
-
struct sg_table *drm_gem_shmem_get_pages_sgt(struct drm_gem_shmem_object *shmem)¶
锁定页面,进行 DMA 映射,并返回 shmem GEM 对象的散点/收集表。
参数
struct drm_gem_shmem_object *shmem
shmem GEM 对象
描述
此函数返回适用于驱动程序使用的散点/收集表。如果 sg 表不存在,则锁定页面,进行 dma 映射,并创建 sg 表。
这是驱动程序获取后备存储的主要函数,它隐藏了 dma-buf 导入对象和本机分配对象之间的差异。驱动程序不应直接调用 drm_gem_shmem_get_sg_table()
。
返回
指向锁定页面的散点/收集表的指针,或者失败时返回 errno。
-
struct drm_gem_object *drm_gem_shmem_prime_import_sg_table(struct drm_device *dev, struct dma_buf_attachment *attach, struct sg_table *sgt)¶
从另一个驱动程序的锁定页面的散点/收集表生成 shmem GEM 对象
参数
struct drm_device *dev
要导入的设备
struct dma_buf_attachment *attach
DMA-BUF 附件
struct sg_table *sgt
已固定页面的散列表/收集表
描述
此函数导入由另一个驱动程序通过 DMA-BUF 导出的散点/收集表。使用 shmem 助手的驱动程序应将其设置为他们的 drm_driver.gem_prime_import_sg_table
回调。
返回
指向新创建的 GEM 对象的指针,或失败时指向 ERR_PTR 编码的负错误代码。
GEM VRAM 助手函数参考¶
此库提供 struct drm_gem_vram_object
(GEM VRAM),这是一个由视频 RAM (VRAM) 支持的 GEM 缓冲区对象。它可用于具有专用内存的帧缓冲设备。
数据结构 struct drm_vram_mm
及其辅助函数为具有专用显存的简单帧缓冲设备实现内存管理器。GEM VRAM 缓冲区对象要么放置在显存中,要么保持被换出到系统内存中。
通过 GEM 接口,用户空间应用程序可以创建、管理和销毁图形缓冲区,例如屏幕上的帧缓冲。GEM 不提供这些接口的实现。这取决于 DRM 驱动程序提供适合硬件的实现。如果硬件设备包含专用显存,则 DRM 驱动程序可以使用 VRAM 辅助库。每个活动的缓冲区对象都存储在显存中。活动缓冲区用于绘制当前帧,通常类似于帧的扫描输出缓冲区或光标图像。如果 VRAM 中没有剩余空间,则可以将不活动的 GEM 对象移动到系统内存中。
要初始化 VRAM 辅助库,请调用 drmm_vram_helper_init()
。该函数在 struct drm_device
.vram_mm 中分配并初始化一个 struct drm_vram_mm
的实例。使用 DRM_GEM_VRAM_DRIVER
初始化 struct drm_driver
,并使用 DRM_VRAM_MM_FILE_OPERATIONS
初始化 struct file_operations
,如下所示。
struct file_operations fops ={
.owner = THIS_MODULE,
DRM_VRAM_MM_FILE_OPERATION
};
struct drm_driver drv = {
.driver_feature = DRM_ ... ,
.fops = &fops,
DRM_GEM_VRAM_DRIVER
};
int init_drm_driver()
{
struct drm_device *dev;
uint64_t vram_base;
unsigned long vram_size;
int ret;
// setup device, vram base and size
// ...
ret = drmm_vram_helper_init(dev, vram_base, vram_size);
if (ret)
return ret;
return 0;
}
这将创建一个 struct drm_vram_mm
的实例,导出用于 GEM 缓冲区管理的 DRM 用户空间接口,并初始化文件操作以允许访问已创建的 GEM 缓冲区。通过这种设置,DRM 驱动程序使用 VRAM MM 管理显存区域,并向用户空间提供 GEM VRAM 对象。
您不必清理 VRAM MM 的实例。drmm_vram_helper_init()
是一个托管接口,它安装一个清理处理程序,在 DRM 设备释放期间运行。
对于绘制或扫描输出操作,相应的缓冲区对象必须固定在显存中。调用 drm_gem_vram_pin()
并使用 DRM_GEM_VRAM_PL_FLAG_VRAM
或 DRM_GEM_VRAM_PL_FLAG_SYSTEM
将缓冲区对象固定在显存或系统内存中。之后调用 drm_gem_vram_unpin()
来释放固定的对象。
固定在显存中的缓冲区对象在该内存区域中具有固定地址。调用 drm_gem_vram_offset()
来检索该值。它通常用于为帧缓冲区编程硬件的扫描输出引擎、设置鼠标光标的游标叠加图像,或将其用作硬件绘图引擎的输入。
要从 DRM 驱动程序访问缓冲区对象的内存,请调用 drm_gem_vram_vmap()
。它将缓冲区映射到内核地址空间并返回内存地址。使用 drm_gem_vram_vunmap()
来释放映射。
-
struct drm_gem_vram_object¶
由 VRAM 支持的 GEM 对象
定义:
struct drm_gem_vram_object {
struct ttm_buffer_object bo;
struct iosys_map map;
unsigned int vmap_use_count;
struct ttm_placement placement;
struct ttm_place placements[2];
};
成员
bo
TTM 缓冲区对象
map
bo 的映射信息
vmap_use_count
虚拟地址上的引用计数。当计数达到零时,地址将被取消映射。
placement
TTM 位置信息。支持的位置是
TTM_PL_VRAM
和TTM_PL_SYSTEM
placements
TTM 位置信息。
描述
类型 struct drm_gem_vram_object
表示由 VRAM 支持的 GEM 对象。它可以用于具有专用内存的简单帧缓冲设备。如果显存变得稀缺,则可以将缓冲区对象换出到系统内存。
GEM VRAM 对象对 pin 和映射操作执行引用计数。因此,使用 drm_gem_vram_pin()
固定 N 次的缓冲区对象必须使用 drm_gem_vram_unpin()
解除固定 N 次。这同样适用于 drm_gem_vram_kmap() 和 drm_gem_vram_kunmap() 对,以及 drm_gem_vram_vmap()
和 drm_gem_vram_vunmap()
对。
-
struct drm_gem_vram_object *drm_gem_vram_of_bo(struct ttm_buffer_object *bo)¶
返回字段 bo 的类型为
struct drm_gem_vram_object
的容器。
参数
struct ttm_buffer_object *bo
VRAM 缓冲区对象
返回
包含的 GEM VRAM 对象
-
struct drm_gem_vram_object *drm_gem_vram_of_gem(struct drm_gem_object *gem)¶
返回字段 gem 的类型为
struct drm_gem_vram_object
的容器。
参数
struct drm_gem_object *gem
GEM 对象
返回
包含的 GEM VRAM 对象
-
DRM_GEM_VRAM_PLANE_HELPER_FUNCS¶
DRM_GEM_VRAM_PLANE_HELPER_FUNCS
初始化用于 VRAM 处理的
struct drm_plane_helper_funcs
描述
驱动程序可以使用 GEM BO 作为帧缓冲区内存的 VRAM 助手。此宏初始化
struct drm_plane_helper_funcs
以使用相应的辅助函数。
-
DRM_GEM_VRAM_DRIVER¶
DRM_GEM_VRAM_DRIVER
-
struct drm_vram_mm¶
VRAM MM 的实例
定义:
struct drm_vram_mm {
uint64_t vram_base;
size_t vram_size;
struct ttm_device bdev;
};
成员
vram_base
托管的显存的基地址
vram_size
托管的显存的大小(以字节为单位)
bdev
TTM BO 设备。
描述
字段 struct drm_vram_mm
.vram_base 和 struct drm_vram_mm
.vrm_size 由 VRAM MM 管理,但可公开读取访问。使用字段 struct drm_vram_mm
.bdev 来访问 TTM BO 设备。
-
struct drm_vram_mm *drm_vram_mm_of_bdev(struct ttm_device *bdev)¶
返回字段 bdev 的类型为
struct ttm_device
的容器。
-
struct drm_gem_vram_object *drm_gem_vram_create(struct drm_device *dev, size_t size, unsigned long pg_align)¶
创建一个 VRAM 支持的 GEM 对象
参数
struct drm_device *dev
DRM 设备
size_t size
以字节为单位的缓冲区大小
unsigned long pg_align
缓冲区对齐的页大小的倍数
描述
GEM 对象通过调用 struct drm_driver
.gem_create_object(如果设置)进行分配。否则,将使用 kzalloc()
。驱动程序可以在 struct drm_driver
.gem_create_object 中设置自己的 GEM 对象函数。如果没有设置函数,则新的 GEM 对象将使用来自 GEM VRAM 助手程序的默认函数。
返回
成功时返回 struct drm_gem_vram_object
的新实例,否则返回 ERR_PTR()
编码的错误代码。
-
void drm_gem_vram_put(struct drm_gem_vram_object *gbo)¶
释放对 VRAM 支持的 GEM 对象的引用
参数
struct drm_gem_vram_object *gbo
GEM VRAM 对象
描述
有关更多信息,请参阅 ttm_bo_put()。
-
s64 drm_gem_vram_offset(struct drm_gem_vram_object *gbo)¶
返回 GEM VRAM 对象在显存中的偏移量
参数
struct drm_gem_vram_object *gbo
GEM VRAM 对象
描述
此函数返回缓冲区对象在设备显存中的偏移量。缓冲区对象必须固定到 TTM_PL_VRAM
。
返回
成功时返回缓冲区对象在显存中的偏移量,否则返回负的 errno 代码。
-
int drm_gem_vram_pin(struct drm_gem_vram_object *gbo, unsigned long pl_flag)¶
将 GEM VRAM 对象固定在某个区域中。
参数
struct drm_gem_vram_object *gbo
GEM VRAM 对象
unsigned long pl_flag
可能内存区域的位掩码
描述
固定缓冲区对象可确保它不会从内存区域中被逐出。固定的缓冲区对象必须先取消固定,才能固定到另一个区域。如果 pl_flag 参数为 0,则缓冲区会固定在其当前位置(显存或系统内存)。
如果小型缓冲区对象(例如光标图像)固定在显存的中间,可能会导致内存碎片。这在只有少量显存的设备上尤其是一个问题。碎片可能会阻止主帧缓冲区容纳,即使总体上有足够的内存。修饰符 DRM_GEM_VRAM_PL_FLAG_TOPDOWN 会将缓冲区对象标记为固定在内存区域的高端,以避免碎片。
返回
成功时返回 0,否则返回负错误代码。
-
int drm_gem_vram_unpin(struct drm_gem_vram_object *gbo)¶
取消固定 GEM VRAM 对象
参数
struct drm_gem_vram_object *gbo
GEM VRAM 对象
返回
成功时返回 0,否则返回负错误代码。
-
int drm_gem_vram_vmap(struct drm_gem_vram_object *gbo, struct iosys_map *map)¶
将 GEM VRAM 对象固定并映射到内核地址空间
参数
struct drm_gem_vram_object *gbo
要映射的 GEM VRAM 对象
struct iosys_map *map
返回 VRAM GEM 对象后备存储的内核虚拟地址。
描述
vmap 函数将 GEM VRAM 对象固定到其当前位置(系统内存或显存),并将其缓冲区映射到内核地址空间。由于固定对象无法重定位,因此应避免永久固定对象。使用返回的地址调用 drm_gem_vram_vunmap()
以取消映射并取消固定 GEM VRAM 对象。
返回
成功时返回 0,否则返回负错误代码。
-
void drm_gem_vram_vunmap(struct drm_gem_vram_object *gbo, struct iosys_map *map)¶
取消映射并取消固定 GEM VRAM 对象
参数
struct drm_gem_vram_object *gbo
要取消映射的 GEM VRAM 对象
struct iosys_map *map
VRAM GEM 对象映射到的内核虚拟地址
描述
调用 drm_gem_vram_vunmap()
会取消映射并取消固定 GEM VRAM 缓冲区。有关更多信息,请参阅 drm_gem_vram_vmap()
的文档。
-
int drm_gem_vram_fill_create_dumb(struct drm_file *file, struct drm_device *dev, unsigned long pg_align, unsigned long pitch_align, struct drm_mode_create_dumb *args)¶
用于实现
struct drm_driver
.dumb_create 的助手
参数
struct drm_file *file
DRM 文件
struct drm_device *dev
DRM 设备
unsigned long pg_align
缓冲区对齐的页大小的倍数
unsigned long pitch_align
扫描线对齐的 2 的幂
struct drm_mode_create_dumb *args
提供给
struct drm_driver
.dumb_create 的参数
描述
此帮助函数填充 struct drm_mode_create_dumb
,该结构由 struct drm_driver
.dumb_create 使用。此接口的实现应将其参数以及特定于驱动程序的参数转发到此助手。
返回
成功时返回 0,否则返回负错误代码。
-
int drm_gem_vram_driver_dumb_create(struct drm_file *file, struct drm_device *dev, struct drm_mode_create_dumb *args)¶
实现
struct drm_driver
.dumb_create
参数
struct drm_file *file
DRM 文件
struct drm_device *dev
DRM 设备
struct drm_mode_create_dumb *args
提供给
struct drm_driver
.dumb_create 的参数
描述
此函数要求驱动程序为其 VRAM MM 实例使用 drm_device.vram_mm。
返回
成功时返回 0,否则返回负错误代码。
-
int drm_gem_vram_plane_helper_prepare_fb(struct drm_plane *plane, struct drm_plane_state *new_state)¶
实现
struct drm_plane_helper_funcs
.prepare_fb
参数
struct drm_plane *plane
一个 DRM 平面
struct drm_plane_state *new_state
该平面的新状态
描述
在平面更新期间,此函数设置平面的栅栏并将平面新帧缓冲区的 GEM VRAM 对象固定到 VRAM。调用 drm_gem_vram_plane_helper_cleanup_fb()
来取消固定它们。
返回
成功返回 0,否则返回一个负的 errno 代码。
-
void drm_gem_vram_plane_helper_cleanup_fb(struct drm_plane *plane, struct drm_plane_state *old_state)¶
实现
struct drm_plane_helper_funcs
.cleanup_fb
参数
struct drm_plane *plane
一个 DRM 平面
struct drm_plane_state *old_state
该平面的旧状态
描述
在平面更新期间,此函数从 VRAM 中取消固定平面旧帧缓冲区的 GEM VRAM 对象。与 drm_gem_vram_plane_helper_prepare_fb()
相辅相成。
参数
struct drm_minor *minor
drm 次设备。
-
int drmm_vram_helper_init(struct drm_device *dev, uint64_t vram_base, size_t vram_size)¶
初始化
struct drm_vram_mm
的设备实例
参数
struct drm_device *dev
DRM 设备
uint64_t vram_base
视频内存的基地址
size_t vram_size
视频内存的大小(以字节为单位)
描述
创建 struct drm_vram_mm
的一个新实例,并将其存储在结构体 drm_device.vram_mm
中。该实例是自动管理的,并在设备清理时进行清理。多次调用此函数将生成错误消息。
返回
成功返回 0,否则返回一个负的 errno 代码。
-
enum drm_mode_status drm_vram_helper_mode_valid(struct drm_device *dev, const struct drm_display_mode *mode)¶
测试显示模式的帧缓冲区是否适合可用的视频内存。
参数
struct drm_device *dev
DRM 设备
const struct drm_display_mode *mode
要测试的模式
描述
此函数测试是否有足够的视频内存可用于指定的显示模式。原子模式设置要求在驱逐活动帧缓冲区之前将指定的帧缓冲区导入到视频内存中。因此,任何帧缓冲区最多可能消耗可用 VRAM 的一半。不能使用需要更大帧缓冲区的显示模式,即使 CRTC 支持它们。每个帧缓冲区都被假定为具有 32 位颜色深度。
注意
该函数只能测试是否通常支持显示模式。如果有太多帧缓冲区固定到视频内存,则在实践中可能仍然无法使用显示模式。32 位颜色深度适合所有当前用例。必要时可以添加更灵活的测试。
返回
如果支持显示模式,则返回 MODE_OK,否则返回 enum drm_mode_status
类型的错误代码。
GEM TTM 辅助函数参考¶
此库为由 ttm 支持的 gem 对象提供辅助函数。
-
void drm_gem_ttm_print_info(struct drm_printer *p, unsigned int indent, const struct drm_gem_object *gem)¶
打印
ttm_buffer_object
的 debugfs 信息
参数
struct drm_printer *p
DRM 打印机
unsigned int indent
制表符缩进级别
const struct drm_gem_object *gem
GEM 对象
描述
此函数可以用作 drm_gem_object_funcs.print_info
回调。
-
int drm_gem_ttm_vmap(struct drm_gem_object *gem, struct iosys_map *map)¶
vmap
ttm_buffer_object
参数
struct drm_gem_object *gem
GEM 对象。
struct iosys_map *map
[out] 返回 dma-buf 映射。
描述
使用 ttm_bo_vmap() 映射 GEM 对象。此函数可以用作 drm_gem_object_funcs.vmap
回调。
返回
成功返回 0,否则返回一个负的 errno 代码。
-
void drm_gem_ttm_vunmap(struct drm_gem_object *gem, struct iosys_map *map)¶
vunmap
ttm_buffer_object
参数
struct drm_gem_object *gem
GEM 对象。
struct iosys_map *map
dma-buf 映射。
描述
使用 ttm_bo_vunmap() 取消映射 GEM 对象。此函数可以用作 drm_gem_object_funcs.vmap
回调。
-
int drm_gem_ttm_mmap(struct drm_gem_object *gem, struct vm_area_struct *vma)¶
mmap
ttm_buffer_object
参数
struct drm_gem_object *gem
GEM 对象。
struct vm_area_struct *vma
vm 区域。
描述
此函数可以用作 drm_gem_object_funcs.mmap
回调。
-
int drm_gem_ttm_dumb_map_offset(struct drm_file *file, struct drm_device *dev, uint32_t handle, uint64_t *offset)¶
实现 struct
drm_driver.dumb_map_offset
参数
struct drm_file *file
DRM 文件指针。
struct drm_device *dev
DRM 设备。
uint32_t handle
GEM 句柄
uint64_t *offset
成功时返回映射的内存偏移量
描述
为基于 TTM 的 GEM 驱动程序提供 struct drm_driver.dumb_map_offset
的实现。TTM 在内部分配偏移量,并且 drm_gem_ttm_dumb_map_offset()
为哑缓冲区实现返回它。
请参阅 struct drm_driver.dumb_map_offset
。
返回
成功返回 0,否则返回一个负的 errno 代码。
VMA 偏移管理器¶
vma-manager 负责将任意驱动程序相关的内存区域映射到线性用户地址空间。它为调用者提供偏移量,然后可以在 drm-device 的地址空间中使用。它会注意不重叠区域,适当地调整它们的大小,并且不会因不一致的虚假 vm_pgoff 字段而混淆 mm-core。驱动程序不应将此用于 VMEM 中的对象放置。此管理器仅应用于管理到线性用户空间 VM 的映射。
我们使用 drm_mm 作为后端来管理对象分配。但是,它针对 alloc/free 调用进行了高度优化,而不是查找。因此,我们使用 rb-tree 来加速偏移量查找。
您不得在单个地址空间上使用多个偏移管理器。否则,mm-core 将无法拆除内存映射,因为 VM 将不再是线性的。
此偏移管理器使用基于页面的地址。也就是说,每个参数和返回代码(drm_vma_node_offset_addr()
除外)均以页数而不是字节数给出。这意味着,对象大小和偏移量必须始终按页对齐(如往常一样)。如果您想获取给定偏移量的有效的基于字节的用户空间地址,请参阅 drm_vma_node_offset_addr()
。
除了偏移量管理之外,vma 偏移管理器还处理访问管理。对于允许访问给定节点的每个打开文件上下文,您必须调用 drm_vma_node_allow()
。否则,在具有节点偏移量的此打开文件上调用 mmap() 将失败,并显示 -EACCES。要再次撤销访问,请使用 drm_vma_node_revoke()
。但是,如果需要,调用者负责销毁已经存在的映射。
-
struct drm_vma_offset_node *drm_vma_offset_exact_lookup_locked(struct drm_vma_offset_manager *mgr, unsigned long start, unsigned long pages)¶
按确切地址查找节点
参数
struct drm_vma_offset_manager *mgr
管理器对象
unsigned long start
起始地址(基于页面,而不是基于字节)
unsigned long pages
对象大小(基于页面)
描述
与 drm_vma_offset_lookup_locked()
相同,但不允许节点中的任何偏移量。它只返回具有给定起始地址的确切对象。
返回
在确切起始地址 start 处的节点。
-
void drm_vma_offset_lock_lookup(struct drm_vma_offset_manager *mgr)¶
锁定查找以供扩展的私有使用
参数
struct drm_vma_offset_manager *mgr
管理器对象
描述
锁定 VMA 管理器以进行扩展查找。在持有此锁时,只允许锁定 VMA 函数调用。所有其他上下文都被 VMA 阻止,直到通过 drm_vma_offset_unlock_lookup()
释放锁为止。
如果您需要在再次释放此锁之前获取 drm_vma_offset_lookup_locked()
返回的对象引用,请使用此方法。
此锁不得用于扩展查找之外的任何其他用途。在持有此锁时,不得调用任何其他 VMA 帮助程序。
注意
在持有此锁时,您处于原子上下文中!
-
void drm_vma_offset_unlock_lookup(struct drm_vma_offset_manager *mgr)¶
解锁查找以供扩展的私有使用
-
void drm_vma_node_reset(struct drm_vma_offset_node *node)¶
初始化或重置节点对象
参数
struct drm_vma_offset_node *node
要初始化或重置的节点
描述
将节点重置为其初始状态。必须在将其与任何 VMA 偏移管理器一起使用之前调用此方法。
不得在已分配的节点上调用此方法,否则会发生内存泄漏。
-
unsigned long drm_vma_node_start(const struct drm_vma_offset_node *node)¶
返回基于页面的寻址的起始地址
参数
const struct drm_vma_offset_node *node
要检查的节点
描述
返回给定节点的起始地址。这可以用作 VMA 偏移管理器提供的线性 VM 空间的偏移量。请注意,这只能用于基于页面的寻址。如果您需要用户空间映射的适当偏移量,则必须应用“<< PAGE_SHIFT”或使用 drm_vma_node_offset_addr()
帮助程序。
返回
用于基于页面的寻址的 node 的起始地址。如果节点未分配偏移量,则为 0。
-
unsigned long drm_vma_node_size(struct drm_vma_offset_node *node)¶
返回大小(基于页面)
参数
struct drm_vma_offset_node *node
要检查的节点
描述
以页数形式返回给定节点的大小。这与传递给 drm_vma_offset_add()
的大小相同。如果未为节点分配任何偏移量,则为 0。
返回
node 的大小(以页数为单位)。如果节点未分配偏移量,则为 0。
-
__u64 drm_vma_node_offset_addr(struct drm_vma_offset_node *node)¶
返回用户空间 mmaps 的经过清理的偏移量
参数
struct drm_vma_offset_node *node
链接的偏移量节点
描述
与 drm_vma_node_start()
相同,但返回的地址是有效的偏移量,可在 mmap() 期间用于用户空间映射。不得在未链接的节点上调用此方法。
返回
用于基于字节的寻址的 node 的偏移量。如果节点未分配对象,则为 0。
-
void drm_vma_node_unmap(struct drm_vma_offset_node *node, struct address_space *file_mapping)¶
取消映射偏移节点
参数
struct drm_vma_offset_node *node
偏移节点
struct address_space *file_mapping
要从中取消映射 node 的地址空间
描述
取消映射给定偏移节点的所有用户空间映射。 这些映射必须与 file_mapping 地址空间关联。 如果不存在偏移量,则不执行任何操作。
此调用是解锁的。 调用者必须保证不会同时在此节点上调用 drm_vma_offset_remove()
。
参数
struct drm_vma_offset_node *node
偏移节点
struct drm_file *tag
要检查的文件的标签
描述
这会检查是否已授予 tag 访问 node 的权限。 它与 drm_vma_node_is_allowed()
相同,但适合作为 TTM verify_access() 回调的直接助手。
返回
如果授予访问权限,则为 0,否则为 -EACCES。
-
void drm_vma_offset_manager_init(struct drm_vma_offset_manager *mgr, unsigned long page_offset, unsigned long size)¶
初始化新的偏移量管理器
参数
struct drm_vma_offset_manager *mgr
管理器对象
unsigned long page_offset
可用内存区域的偏移量(基于页)
unsigned long size
可用地址空间范围的大小(基于页)
描述
初始化新的偏移量管理器。管理器的可用偏移量和区域大小以 page_offset 和 size 给出。两者都被解释为页码,而不是字节。
从管理器添加/删除节点会在内部锁定,并防止并发访问。但是,节点分配和销毁留给调用者。在调用 vma 管理器时,必须始终保证对给定节点进行引用。
-
void drm_vma_offset_manager_destroy(struct drm_vma_offset_manager *mgr)¶
销毁偏移量管理器
参数
struct drm_vma_offset_manager *mgr
管理器对象
描述
销毁先前通过 drm_vma_offset_manager_init()
创建的对象管理器。 调用者必须在销毁管理器之前删除所有已分配的节点。 否则,drm_mm 将拒绝释放请求的资源。
在此函数调用后,不得访问管理器。
-
struct drm_vma_offset_node *drm_vma_offset_lookup_locked(struct drm_vma_offset_manager *mgr, unsigned long start, unsigned long pages)¶
在偏移空间中查找节点
参数
struct drm_vma_offset_manager *mgr
管理器对象
unsigned long start
对象的起始地址(基于页)
unsigned long pages
对象大小(基于页面)
描述
给定起始地址和对象大小,查找节点。 这将返回给定节点的 _最佳_ 匹配项。 也就是说,start 可能指向有效区域中的某个位置,并且只要节点跨越整个请求的区域(给定大小为 pages 的页数),就会返回给定节点。
请注意,在查找之前,必须使用 drm_vma_offset_lock_lookup()
获取 vma 偏移量管理器查找锁。 有关示例,请参见此处。 然后,可以使用它来实现使用 kref_get_unless_zero() 的弱引用查找。
drm_vma_offset_lock_lookup(mgr);
node = drm_vma_offset_lookup_locked(mgr);
if (node)
kref_get_unless_zero(container_of(node, sth, entr));
drm_vma_offset_unlock_lookup(mgr);
示例
返回
如果找不到合适的节点,则返回 NULL。 否则,将返回最佳匹配项。 调用者有责任确保节点在调用者访问之前不会被销毁。
-
int drm_vma_offset_add(struct drm_vma_offset_manager *mgr, struct drm_vma_offset_node *node, unsigned long pages)¶
向管理器添加偏移量节点
参数
struct drm_vma_offset_manager *mgr
管理器对象
struct drm_vma_offset_node *node
要添加的节点
unsigned long pages
用户空间可见的分配大小(以页数表示)
描述
向偏移量管理器添加节点。如果已添加该节点,则此操作不执行任何操作并返回 0。pages 是以页数表示的对象大小。在此调用成功后,您可以访问该节点的偏移量,直到再次将其删除。
如果此调用失败,则重试该操作或调用 drm_vma_offset_remove()
是安全的。但是,在这种情况下,不需要清理。
pages 不需要与要映射的底层内存对象的大小相同。它仅限制用户空间可以映射到其地址空间的大小。
返回
成功时为 0,失败时为负错误代码。
-
void drm_vma_offset_remove(struct drm_vma_offset_manager *mgr, struct drm_vma_offset_node *node)¶
从管理器中删除偏移量节点
参数
struct drm_vma_offset_manager *mgr
管理器对象
struct drm_vma_offset_node *node
要删除的节点
描述
从偏移量管理器中删除节点。如果之前未添加该节点,则此操作不执行任何操作。在此调用返回后,偏移量和大小将为 0,直到通过 drm_vma_offset_add()
再次分配新的偏移量。如果未分配偏移量,则 drm_vma_node_start()
和 drm_vma_node_offset_addr()
等辅助函数将返回 0。
参数
struct drm_vma_offset_node *node
要修改的节点
struct drm_file *tag
要删除的文件的标签
描述
将 tag 添加到此节点允许的打开文件列表。 如果 tag 已在此列表上,则引用计数会增加。
允许的用户列表在 drm_vma_offset_add()
和 drm_vma_offset_remove()
调用之间保留。 如果该节点当前未添加到任何偏移量管理器,您甚至可以调用它。
在销毁节点之前,您必须删除所有打开的文件,次数与添加它们的次数相同。 否则,您将泄漏内存。
这在内部锁定以防止并发访问。
返回
成功时为 0,内部失败(内存不足)时为负错误代码
-
int drm_vma_node_allow_once(struct drm_vma_offset_node *node, struct drm_file *tag)¶
将打开的文件添加到允许的用户列表
参数
struct drm_vma_offset_node *node
要修改的节点
struct drm_file *tag
要删除的文件的标签
描述
将 tag 添加到此节点允许的打开文件列表。
允许的用户列表在 drm_vma_offset_add()
和 drm_vma_offset_remove()
调用之间保留。 如果该节点当前未添加到任何偏移量管理器,您甚至可以调用它。
与 drm_vma_node_allow()
不同,它不是引用计数的,因此在调用此函数后,drm_vma_node_revoke()
应该只被调用一次。
这在内部锁定以防止并发访问。
返回
成功时为 0,内部失败(内存不足)时为负错误代码
参数
struct drm_vma_offset_node *node
要修改的节点
struct drm_file *tag
要删除的文件的标签
描述
减少 node 上允许的打开文件列表中 tag 的引用计数。如果引用计数降至零,则从列表中删除 tag。对于 tag 上的每个 drm_vma_node_allow()
,必须调用此函数一次。
这在内部锁定以防止并发访问。
如果 tag 不在列表中,则不执行任何操作。
-
bool drm_vma_node_is_allowed(struct drm_vma_offset_node *node, struct drm_file *tag)¶
检查是否授予了打开的文件访问权限。
参数
struct drm_vma_offset_node *node
要检查的节点。
struct drm_file *tag
要删除的文件的标签
描述
在 node 中搜索 tag 是否当前在允许的打开文件列表中(请参阅 drm_vma_node_allow()
)。
这在内部锁定以防止并发访问。
返回
如果 filp 在列表中,则为 true。
PRIME 缓冲区共享¶
PRIME 是 drm 中的跨设备缓冲区共享框架,最初是为 OPTIMUS 系列多 GPU 平台创建的。对于用户空间,PRIME 缓冲区是基于 dma-buf 的文件描述符。
概述和生命周期规则¶
与 GEM 全局名称类似,PRIME 文件描述符也用于在进程之间共享缓冲区对象。它们提供了额外的安全性:由于必须通过 UNIX 域套接字显式发送文件描述符才能在应用程序之间共享,因此它们不能像全局唯一的 GEM 名称那样被猜测出来。
支持 PRIME API 的驱动程序实现 drm_gem_object_funcs.export 和 drm_driver.gem_prime_import
钩子。驱动程序的 dma_buf_ops
实现都是单独导出的,供需要覆盖或重新实现其中一些的驱动程序使用。
GEM 驱动程序的引用计数¶
在导出时,dma_buf
保留对导出的缓冲区对象的引用,通常是 drm_gem_object
。它在第一次调用 drm_gem_object_funcs.export
时在 PRIME_HANDLE_TO_FD IOCTL 中获取此引用,并将导出的 GEM 对象存储在 dma_buf.priv
字段中。当删除对 dma_buf
本身的最终引用时,并且调用其 dma_buf_ops.release
函数时,需要释放此引用。对于基于 GEM 的驱动程序,应使用 drm_gem_dmabuf_export()
导出 dma_buf
,然后通过 drm_gem_dmabuf_release()
释放。
因此,引用链始终沿一个方向流动,避免循环:导入 GEM 对象 -> dma-buf -> 导出的 GEM bo。另一个复杂因素是导入和导出的查找缓存。需要这些来保证任何给定对象始终只有一个唯一的用户空间句柄。这是允许用户空间检测重复导入所必需的,因为如果给定的缓冲区对象被列出多次,某些 GEM 驱动程序确实会失败命令提交。 drm_prime_file_private
中的这些导入和导出缓存仅保留弱引用,该弱引用在释放相应的对象时会被清理。
自导入:如果用户空间使用 PRIME 作为 flink 的替代品,它将收到对其创建的 GEM 对象的 fd->handle 请求。驱动程序应检测到这种情况并从 dma-buf 私有数据返回底层对象。对于基于 GEM 的驱动程序,这已经在 drm_gem_prime_import()
中处理。
PRIME 辅助函数¶
驱动程序可以使用辅助函数 drm_gem_prime_export()
和 drm_gem_prime_import()
,通过更简单的 API 来实现 drm_gem_object_funcs.export
和 drm_driver.gem_prime_import
。这些函数根据一些较低级别的辅助函数实现 dma-buf 支持,这些辅助函数再次导出供驱动程序单独使用。
导出缓冲区¶
缓冲区的可选锁定在 drm_gem_map_attach()
和 drm_gem_map_detach()
中的 dma-buf 附加和分离时处理。后备存储本身由 drm_gem_map_dma_buf()
和 drm_gem_unmap_dma_buf()
处理,这依赖于 drm_gem_object_funcs.get_sg_table
。如果未实现 drm_gem_object_funcs.get_sg_table
,则拒绝导出到另一个设备。
对于内核内部访问,有 drm_gem_dmabuf_vmap()
和 drm_gem_dmabuf_vunmap()
。用户空间 mmap 支持由 drm_gem_dmabuf_mmap()
提供。
请注意,只有当底层后备存储完全一致且永久锁定,或者可以安全地无限期锁定时,才能使用这些导出助手。
FIXME:底层辅助函数的命名相当不一致。
导入缓冲区¶
使用 drm_gem_prime_import()
导入 dma-buf 依赖于 drm_driver.gem_prime_import_sg_table
。
请注意,与导出助手类似,这会永久锁定底层后备存储。这对于扫描输出是没问题的,但对于共享大量缓冲区进行渲染来说,不是最佳选择。
PRIME 函数参考¶
-
struct drm_prime_file_private¶
每个文件的 PRIME 跟踪。
定义:
struct drm_prime_file_private {
};
成员
描述
这仅包含 PRIME 核心代码使用的每个 struct drm_file
的内部 struct dma_buf
和句柄缓存。
-
struct dma_buf *drm_gem_dmabuf_export(struct drm_device *dev, struct dma_buf_export_info *exp_info)¶
GEM 的
dma_buf
导出实现。
参数
struct drm_device *dev
导出的 dmabuf 的父设备。
struct dma_buf_export_info *exp_info
由
dma_buf_export()
使用的导出信息
描述
此函数封装了 dma_buf_export()
,供使用 drm_gem_dmabuf_release()
的通用 GEM 驱动程序使用。除了调用 dma_buf_export()
之外,我们还会获取对 drm_device
和导出的 drm_gem_object
的引用(存储在 dma_buf_export_info.priv
中),该引用由 drm_gem_dmabuf_release()
释放。
返回新的 dmabuf。
参数
struct dma_buf *dma_buf
要释放的缓冲区
描述
作为 PRIME 缓冲区导出的 dma_bufs 的通用释放函数。GEM 驱动程序必须在其 dma_buf_ops
结构中将其用作释放回调。drm_gem_dmabuf_release()
应该与 drm_gem_dmabuf_export()
一起使用。
-
int drm_gem_prime_fd_to_handle(struct drm_device *dev, struct drm_file *file_priv, int prime_fd, uint32_t *handle)¶
GEM 驱动程序的 PRIME 导入函数
参数
struct drm_device *dev
要导入的 drm_device
struct drm_file *file_priv
drm 文件私有结构
int prime_fd
应导入的 dma-buf 的 fd ID
uint32_t *handle
用于存储导入的缓冲区对象的句柄的指针
描述
这是 PRIME 导入函数,GEM 驱动程序必须强制使用此函数以确保底层 GEM 对象的正确生命周期管理。从 dma-buf 实际导入 GEM 对象是通过 drm_driver.gem_prime_import
驱动程序回调完成的。
成功时返回 0,失败时返回负错误代码。
-
struct dma_buf *drm_gem_prime_handle_to_dmabuf(struct drm_device *dev, struct drm_file *file_priv, uint32_t handle, uint32_t flags)¶
GEM 驱动程序的 PRIME 导出函数
参数
struct drm_device *dev
从中导出缓冲区的 dev
struct drm_file *file_priv
drm 文件私有结构
uint32_t handle
要导出的缓冲区句柄
uint32_t flags
类似 DRM_CLOEXEC 的标志
描述
这是 PRIME 导出函数,GEM 驱动程序必须强制使用此函数以确保底层 GEM 对象的正确生命周期管理。从 GEM 对象实际导出到 dma-buf 是通过 drm_gem_object_funcs.export
回调完成的。
与 drm_gem_prime_handle_to_fd()
不同,它返回已创建的 struct dma_buf
,而不将其附加到任何文件描述符。这两者之间的区别类似于 anon_inode_getfile()
和 anon_inode_getfd()
之间的区别;如果需要任何清理,则插入到描述符表中是无法撤消的,因此只有在您经过最后一个失败退出并且唯一剩下的就是将新的文件描述符传递给用户空间时,才应使用返回描述符的变体。当您只需要对象本身或需要执行其他可能失败的操作时,请改用此对象。
-
int drm_gem_prime_handle_to_fd(struct drm_device *dev, struct drm_file *file_priv, uint32_t handle, uint32_t flags, int *prime_fd)¶
GEM 驱动程序的 PRIME 导出函数
参数
struct drm_device *dev
从中导出缓冲区的 dev
struct drm_file *file_priv
drm 文件私有结构
uint32_t handle
要导出的缓冲区句柄
uint32_t flags
类似 DRM_CLOEXEC 的标志
int *prime_fd
用于存储创建的 dma-buf 的 fd ID 的指针
描述
这是 PRIME 导出函数,GEM 驱动程序必须强制使用此函数以确保底层 GEM 对象的正确生命周期管理。从 GEM 对象实际导出到 dma-buf 是通过 drm_gem_object_funcs.export
回调完成的。
-
int drm_gem_map_attach(struct dma_buf *dma_buf, struct dma_buf_attachment *attach)¶
GEM 的 dma_buf 附加实现
参数
struct dma_buf *dma_buf
要附加设备的缓冲区
struct dma_buf_attachment *attach
缓冲区附加数据
描述
为设备特定处理调用 drm_gem_object_funcs.pin
。这可以用作 dma_buf_ops.attach
回调。必须与 drm_gem_map_detach()
一起使用。
成功时返回 0,失败时返回负错误代码。
-
void drm_gem_map_detach(struct dma_buf *dma_buf, struct dma_buf_attachment *attach)¶
GEM 的 dma_buf 分离实现
参数
struct dma_buf *dma_buf
要分离的缓冲区
struct dma_buf_attachment *attach
要分离的附件
描述
为设备特定处理调用 drm_gem_object_funcs.pin
。从 drm_gem_map_attach()
清理 dma_buf_attachment
。这可以用作 dma_buf_ops.detach
回调。
-
struct sg_table *drm_gem_map_dma_buf(struct dma_buf_attachment *attach, enum dma_data_direction dir)¶
GEM 的 map_dma_buf 实现
参数
struct dma_buf_attachment *attach
要返回散列表的附件
enum dma_data_direction dir
DMA 传输方向
描述
调用 drm_gem_object_funcs.get_sg_table
,然后映射散列表。这可以用作 dma_buf_ops.map_dma_buf
回调。应与 drm_gem_unmap_dma_buf()
一起使用。
返回
包含要返回的散列表的 sg_table;出错时返回 ERR_PTR。如果被信号中断,可能会返回 -EINTR。
-
void drm_gem_unmap_dma_buf(struct dma_buf_attachment *attach, struct sg_table *sgt, enum dma_data_direction dir)¶
GEM 的 unmap_dma_buf 实现
参数
struct dma_buf_attachment *attach
要从中取消映射缓冲区的附件
struct sg_table *sgt
要取消映射的缓冲区的散列表信息
enum dma_data_direction dir
DMA 传输方向
描述
这可以用作 dma_buf_ops.unmap_dma_buf
回调。
参数
struct dma_buf *dma_buf
要映射的缓冲区
struct iosys_map *map
缓冲区的虚拟地址
描述
设置内核虚拟映射。这可以用作 dma_buf_ops.vmap
回调。调用 drm_gem_object_funcs.vmap
进行设备特定的处理。内核虚拟地址在 map 中返回。
成功时返回 0,否则返回负的 errno 代码。
参数
struct dma_buf *dma_buf
要取消映射的缓冲区
struct iosys_map *map
缓冲区的虚拟地址
描述
释放内核虚拟映射。这可以用作 dma_buf_ops.vunmap
回调。调用 drm_gem_object_funcs.vunmap
进行设备特定的处理。
-
int drm_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma)¶
GEM 驱动程序的 PRIME mmap 函数
参数
struct drm_gem_object *obj
GEM 对象
struct vm_area_struct *vma
虚拟地址范围
描述
此函数使用与 DRM fd 上常规 GEM 缓冲区映射相同的代码路径,为 PRIME 导出的缓冲区设置用户空间映射。伪 GEM 偏移量添加到 vma->vm_pgoff,并调用 drm_driver->fops
->mmap 来设置映射。
参数
struct dma_buf *dma_buf
要映射的缓冲区
struct vm_area_struct *vma
虚拟地址范围
描述
为缓冲区提供内存映射。这可以用作 dma_buf_ops.mmap
回调。它只是转发到 drm_gem_prime_mmap()
。
成功时返回 0,失败时返回负错误代码。
-
struct sg_table *drm_prime_pages_to_sg(struct drm_device *dev, struct page **pages, unsigned int nr_pages)¶
将页面数组转换为 sg 列表
参数
struct drm_device *dev
DRM 设备
struct page **pages
指向要转换的页面指针数组的指针
unsigned int nr_pages
页面向量的长度
描述
此帮助程序从一组页面创建 sg 表对象,驱动程序负责将页面映射到导入者的地址空间,以便与 dma_buf 本身一起使用。
这对于实现 drm_gem_object_funcs.get_sg_table
非常有用。
-
unsigned long drm_prime_get_contiguous_size(struct sg_table *sgt)¶
返回缓冲区的连续大小
参数
struct sg_table *sgt
描述要检查的缓冲区的 sg_table
描述
此帮助程序计算由提供的 sg_table 描述的缓冲区在 DMA 地址空间中的连续大小。
这对于实现 drm_gem_object_funcs.gem_prime_import_sg_table
非常有用。
-
struct dma_buf *drm_gem_prime_export(struct drm_gem_object *obj, int flags)¶
导出回调的帮助程序库实现
参数
struct drm_gem_object *obj
要导出的 GEM 对象
int flags
DRM_CLOEXEC 和 DRM_RDWR 等标志
描述
这是使用 PRIME 帮助程序的 GEM 驱动程序的 drm_gem_object_funcs.export
函数的实现。它在 drm_gem_prime_handle_to_fd()
中用作默认值。
-
struct drm_gem_object *drm_gem_prime_import_dev(struct drm_device *dev, struct dma_buf *dma_buf, struct device *attach_dev)¶
导入回调的核心实现
参数
struct drm_device *dev
要导入的 drm_device
struct dma_buf *dma_buf
要导入的 dma-buf 对象
struct device *attach_dev
用于 dma_buf 附加的
struct device
描述
这是 drm_gem_prime_import()
的核心。它旨在被希望使用与 drm_device.dev
不同的设备结构的驱动程序调用,以便通过 dma_buf 进行连接。此函数内部调用 drm_driver.gem_prime_import_sg_table
。
驱动程序必须安排在他们的 drm_gem_object_funcs.free
钩子中使用此函数时调用 drm_prime_gem_destroy()
。
-
struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev, struct dma_buf *dma_buf)¶
导入回调的辅助库实现
参数
struct drm_device *dev
要导入的 drm_device
struct dma_buf *dma_buf
要导入的 dma-buf 对象
描述
这是使用 PRIME 辅助函数的 GEM 驱动程序的 gem_prime_import 函数的实现。驱动程序可以将此用作它们的 drm_driver.gem_prime_import
实现。它在 drm_gem_prime_fd_to_handle()
中用作默认实现。
驱动程序必须安排在他们的 drm_gem_object_funcs.free
钩子中使用此函数时调用 drm_prime_gem_destroy()
。
-
int drm_prime_sg_to_page_array(struct sg_table *sgt, struct page **pages, int max_entries)¶
将 sg 表转换为页数组
参数
struct sg_table *sgt
要转换的散列表
struct page **pages
用于存储页面的页指针数组
int max_entries
传入数组的大小
描述
将 sg 表导出为页面数组。
此函数已弃用,强烈建议不要使用。页数组仅对页面错误有用,如果导出驱动程序未处理,这些错误可能会损坏 struct page 中的字段。
-
int drm_prime_sg_to_dma_addr_array(struct sg_table *sgt, dma_addr_t *addrs, int max_entries)¶
将 sg 表转换为 dma 地址数组
参数
struct sg_table *sgt
要转换的散列表
dma_addr_t *addrs
用于存储每个页面的 dma 总线地址的数组
int max_entries
传入的两个数组的大小
描述
将 sg 表导出为地址数组。
驱动程序应在它们的 drm_driver.gem_prime_import_sg_table
实现中使用此函数。
-
void drm_prime_gem_destroy(struct drm_gem_object *obj, struct sg_table *sg)¶
用于清理 PRIME 导入的 GEM 对象的辅助函数
参数
struct drm_gem_object *obj
从 dma-buf 创建的 GEM 对象
struct sg_table *sg
在导入时锁定的 sg 表
描述
这是 GEM 驱动程序在使用 drm_gem_prime_import()
或 drm_gem_prime_import_dev()
导入 dma-bufs 时需要调用的清理函数。
DRM MM 范围分配器¶
概述¶
drm_mm 提供了一个简单的范围分配器。驱动程序可以自由地使用来自 linux 内核的资源分配器,如果它适合它们的话,drm_mm 的优点是它在 DRM 内核中。这意味着对于 GPU 的一些更疯狂的特殊用途需求,它更容易扩展。
主要的数据结构是 drm_mm
,分配在 drm_mm_node
中进行跟踪。驱动程序可以自由地将它们中的任何一个嵌入到它们自己合适的数据结构中。drm_mm 本身不会进行任何自己的内存分配,因此如果驱动程序选择不嵌入节点,它们仍然需要自己分配它们。
范围分配器还支持预分配块的预留。这对于接管固件的初始模式设置配置非常有用,在这种情况下,需要创建一个与固件的扫描输出目标完全匹配的对象。只要范围仍然空闲,它就可以在初始化分配器后的任何时间插入,这有助于避免驱动程序加载序列中的循环依赖。
drm_mm 维护一个最近释放的孔的堆栈,从所有简单的结构来看,这似乎是一种相当不错的聚类分配方法,可以避免过多的碎片。这意味着空闲空间搜索是 O(num_holes)。鉴于 drm_mm 支持的所有花哨的功能,更好的方法会相当复杂,而且由于 gfx 抖动是一个相当陡峭的悬崖,所以不是一个真正的问题。再次删除节点是 O(1)。
drm_mm 支持一些功能:可以提供对齐和范围限制。此外,每个 drm_mm_node
都有一个颜色值(只是一个不透明的无符号长整数),结合驱动程序回调,可以用来实现复杂的放置限制。i915 DRM 驱动程序使用此功能在图形 TT 中不兼容的缓存域之间实现保护页。
搜索和分配支持两种行为:自下而上和自上而下。默认值为自下而上。如果内存区域具有不同的限制,或者只是为了减少碎片,可以使用自上而下的分配。
最后,提供了用于遍历所有节点和所有孔的迭代辅助函数,以及一些用于调试的基本分配器转储器。
请注意,此范围分配器不是线程安全的,驱动程序需要使用自己的锁来保护修改。这背后的想法是,对于一个完整的内存管理器,无论如何都需要保护额外的数据,因此内部锁定将是完全多余的。
LRU 扫描/驱逐支持¶
通常,GPU 需要为给定对象进行连续分配。当驱逐对象为新对象腾出空间时,当我们简单地开始从 LRU 的尾部选择所有对象直到有一个合适的孔时,这不是最有效的:特别是对于大的对象或具有特殊分配约束的节点,很可能会不必要地驱逐许多(较小的)对象。
DRM 范围分配器通过扫描接口支持此用例。首先,需要使用 drm_mm_scan_init()
或 drm_mm_scan_init_with_range()
初始化扫描操作。驱动程序将对象添加到列表中,可能通过遍历 LRU 列表,但这可以自由实现。使用 drm_mm_scan_add_block()
添加驱逐候选项,直到找到合适的孔或没有更多可驱逐的对象。驱逐列表元数据在 struct drm_mm_scan
中进行跟踪。
驱动程序必须以完全相反的顺序再次遍历所有对象以恢复分配器状态。请注意,当分配器处于扫描模式时,不允许进行其他操作。
最后,驱动程序会驱逐扫描中选择的所有对象(drm_mm_scan_remove_block()
报告为 true),以及颜色调整后任何重叠的节点(drm_mm_scan_color_evict()
)。添加和删除对象是 O(1),并且由于释放节点也是 O(1),因此整体复杂性是 O(scanned_objects)。所以像在扫描操作开始之前需要遍历的空闲堆栈一样,这在对象数量上是线性的。似乎没有太大的损害。
DRM MM 范围分配器函数参考¶
-
enum drm_mm_insert_mode¶
控制搜索和分配行为
常量
DRM_MM_INSERT_BEST
搜索适合所需节点的最小空洞(在搜索范围内)。
从找到的空洞底部分配节点。
DRM_MM_INSERT_LOW
搜索适合所需节点的最低空洞(地址最接近 0,在搜索范围内)。
从找到的空洞底部分配节点。
DRM_MM_INSERT_HIGH
搜索适合所需节点的最高空洞(地址最接近 U64_MAX,在搜索范围内)。
从找到的空洞的顶部分配节点。为节点指定的对齐方式应用于节点的基址(
drm_mm_node.start
)。DRM_MM_INSERT_EVICT
搜索最近驱逐的适合所需节点的空洞(在搜索范围内)。这适用于在执行驱逐扫描(请参阅
drm_mm_scan_init()
)并删除所选节点以形成空洞之后立即使用。从找到的空洞底部分配节点。
DRM_MM_INSERT_ONCE
仅检查第一个空洞是否合适,否则立即报告 -ENOSPC,而不是检查每个空洞直到找到合适的空洞。只能与另一种搜索方法(例如 DRM_MM_INSERT_HIGH 或 DRM_MM_INSERT_LOW)结合使用。
DRM_MM_INSERT_HIGHEST
仅检查最高的空洞(地址最大的空洞),并将节点插入到空洞的顶部,如果空洞不合适则报告 -ENOSPC。
不搜索所有空洞。
DRM_MM_INSERT_LOWEST
仅检查最低的空洞(地址最小的空洞),并将节点插入到空洞的底部,如果空洞不合适则报告 -ENOSPC。
不搜索所有空洞。
描述
struct drm_mm
范围管理器支持使用多个搜索树来查找合适的模式。这些树按大小、地址和最近的驱逐顺序组织。这允许用户查找要重用的最小空洞、要重用的最低或最高地址,或者只是重用最适合的最近驱逐。当从空洞中分配 drm_mm_node
时,drm_mm_insert_mode
还决定是分配最低匹配地址还是最高匹配地址。
-
struct drm_mm_node¶
DRM 分配器中已分配的块
定义:
struct drm_mm_node {
unsigned long color;
u64 start;
u64 size;
};
成员
颜色
不透明的驱动程序私有标签。
start
已分配块的起始地址。
size
已分配块的大小。
描述
这表示 drm_mm
分配器中已分配的块。除了使用 drm_mm_reserve_node()
插入的预留节点外,该结构完全不透明,只能通过提供的函数访问。由于这些节点的分配完全由驱动程序处理,因此可以嵌入它们。
-
struct drm_mm¶
DRM 分配器
定义:
struct drm_mm {
void (*color_adjust)(const struct drm_mm_node *node,unsigned long color, u64 *start, u64 *end);
};
成员
color_adjust
可选的驱动程序回调,用于进一步限制空洞。 node 参数指向包含将从中分配块的空洞的节点(请参阅
drm_mm_hole_follows()
和相关函数)。其他参数是要分配的块的大小。驱动程序可以根据需要调整起始和结束位置,例如插入保护页。
描述
DRM 范围分配器,具有一些专门用于管理 GPU 内存的特殊功能。除了 color_adjust 回调之外,该结构完全不透明,只能通过提供的函数和宏访问。此结构可以嵌入到更大的驱动程序结构中。
-
struct drm_mm_scan¶
DRM 分配器驱逐名册数据
定义:
struct drm_mm_scan {
};
成员
描述
此结构跟踪使用 drm_mm_scan_init()
设置的驱逐名册所需的数据,并与 drm_mm_scan_add_block()
和 drm_mm_scan_remove_block()
一起使用。该结构完全不透明,只能通过提供的函数和宏访问。它旨在由驱动程序在堆栈上临时分配。
-
bool drm_mm_node_allocated(const struct drm_mm_node *node)¶
检查节点是否已分配
参数
const struct drm_mm_node *node
要检查的 drm_mm_node
描述
驱动程序需要在将节点与 drm_mm 范围管理器一起使用之前清除该节点。
驱动程序应使用此助手来正确封装 drm_mm 内部结构。
返回
如果 node 已分配,则为 True。
参数
const struct drm_mm *mm
要检查的 drm_mm
描述
如果驱动程序要使用此函数,则应在初始化之前清除 struct drm_mm
。
驱动程序应使用此助手来正确封装 drm_mm 内部结构。
返回
如果 mm 已初始化,则为 True。
-
bool drm_mm_hole_follows(const struct drm_mm_node *node)¶
检查此节点后是否有空洞
参数
const struct drm_mm_node *node
要检查的 drm_mm_node
描述
空洞使用 drm_mm_node 的尾部嵌入到 drm_mm 中。如果您想知道此特定节点后是否有空洞,请查询此函数。另请参阅 drm_mm_hole_node_start()
和 drm_mm_hole_node_end()
。
返回
如果 node 后有空洞,则为 True。
-
u64 drm_mm_hole_node_start(const struct drm_mm_node *hole_node)¶
计算 node 之后的空洞的起始位置
参数
const struct drm_mm_node *hole_node
隐式跟踪后续空洞的 drm_mm_node
描述
这对于特定于驱动程序的调试转储器很有用。否则,驱动程序不应自行检查空洞。驱动程序必须首先通过查看 drm_mm_hole_follows()
来检查空洞是否确实存在。
返回
后续空洞的起始位置。
-
u64 drm_mm_hole_node_end(const struct drm_mm_node *hole_node)¶
计算 node 之后的空洞的结束位置
参数
const struct drm_mm_node *hole_node
隐式跟踪后续空洞的 drm_mm_node
描述
这对于特定于驱动程序的调试转储器很有用。否则,驱动程序不应自行检查空洞。驱动程序必须首先通过查看 drm_mm_hole_follows()
来检查空洞是否确实存在。
返回
后续空洞的结束位置。
-
drm_mm_nodes¶
drm_mm_nodes (mm)
drm_mm 范围管理器下的节点列表
参数
mm
struct drm_mm
范围管理器
描述
由于 drm_mm 范围管理器将其 node_list 深藏于其结构中,因此提取它看起来很痛苦且重复。预计不会在 drm_mm_for_each_node()
宏和类似的内部函数之外使用。
返回
节点列表,可能为空。
-
drm_mm_for_each_node¶
drm_mm_for_each_node (entry, mm)
用于遍历所有已分配节点的迭代器
参数
entry
在每个迭代步骤中分配到的
struct drm_mm_node
mm
遍历
drm_mm
分配器的节点
描述
此迭代器遍历范围分配器中的所有节点。它使用 list_for_each()
实现,因此不能防止元素的删除。
-
drm_mm_for_each_node_safe¶
drm_mm_for_each_node_safe (entry, next, mm)
用于遍历所有已分配节点的迭代器
参数
entry
在每个迭代步骤中分配到的
struct drm_mm_node
next
用于存储下一步的
struct drm_mm_node
mm
遍历
drm_mm
分配器的节点
描述
此迭代器遍历范围分配器中的所有节点。它使用 list_for_each_safe()
实现,因此可以防止元素的删除。
-
drm_mm_for_each_hole¶
drm_mm_for_each_hole (pos, mm, hole_start, hole_end)
遍历所有空闲区域的迭代器
参数
pos
内部用于跟踪进度的
drm_mm_node
mm
遍历
drm_mm
分配器的节点hole_start
用于在每次迭代中分配空闲区域起点的 ulong 变量
hole_end
用于在每次迭代中分配空闲区域终点的 ulong 变量
描述
此迭代器遍历范围分配器中的所有空闲区域。它使用 list_for_each()
实现,因此不能防止元素的删除。 **entry** 在内部使用,不会反映第一个空闲区域的真实 drm_mm_node。因此,此迭代器的用户可能无法访问它。
实现注意:我们需要内联 list_for_each_entry,以便能够在每次迭代中设置 hole_start 和 hole_end,同时保持宏的健全性。
-
int drm_mm_insert_node_generic(struct drm_mm *mm, struct drm_mm_node *node, u64 size, u64 alignment, unsigned long color, enum drm_mm_insert_mode mode)¶
搜索空间并插入 node
参数
struct drm_mm *mm
从中分配的 drm_mm
struct drm_mm_node *node
要插入的预分配节点
u64 size
分配的大小
u64 alignment
分配的对齐方式
unsigned long color
用于此节点的不透明标记值
enum drm_mm_insert_mode mode
微调分配搜索和放置
描述
这是 drm_mm_insert_node_in_range()
的简化版本,没有应用范围限制。
预分配的节点必须清零。
返回
成功返回 0,如果没有合适的空闲区域则返回 -ENOSPC。
-
int drm_mm_insert_node(struct drm_mm *mm, struct drm_mm_node *node, u64 size)¶
搜索空间并插入 node
参数
struct drm_mm *mm
从中分配的 drm_mm
struct drm_mm_node *node
要插入的预分配节点
u64 size
分配的大小
描述
这是 drm_mm_insert_node_generic()
的简化版本,其中 color 设置为 0。
预分配的节点必须清零。
返回
成功返回 0,如果没有合适的空闲区域则返回 -ENOSPC。
参数
const struct drm_mm *mm
要检查的 drm_mm 分配器
返回
如果分配器完全空闲则返回 True,如果其中仍然分配了节点则返回 false。
-
drm_mm_for_each_node_in_range¶
drm_mm_for_each_node_in_range (node__, mm__, start__, end__)
遍历已分配节点范围的迭代器
参数
node__
在每个迭代步骤中分配的 drm_mm_node 结构
mm__
要遍历的 drm_mm 分配器
start__
起始偏移量,第一个节点将与此重叠
end__
结束偏移量,最后一个节点将在此之前开始(但可能重叠)
描述
此迭代器遍历范围分配器中位于 start 和 end 之间的所有节点。它的实现类似于 list_for_each()
,但使用内部区间树来加速对起始节点的搜索,因此不能防止元素的删除。它假设 end 在 drm_mm 分配器的范围内(或作为其上限)。如果 [start, end] 超出 drm_mm 的范围,则迭代器可能会遍历特殊的 _未分配的_ drm_mm.head_node
,甚至可能会无限期地继续下去。
-
void drm_mm_scan_init(struct drm_mm_scan *scan, struct drm_mm *mm, u64 size, u64 alignment, unsigned long color, enum drm_mm_insert_mode mode)¶
初始化 LRU 扫描
参数
struct drm_mm_scan *scan
扫描状态
struct drm_mm *mm
要扫描的 drm_mm
u64 size
分配的大小
u64 alignment
分配的对齐方式
unsigned long color
用于分配的不透明标记值
enum drm_mm_insert_mode mode
微调分配搜索和放置
描述
这是 drm_mm_scan_init_with_range()
的简化版本,没有应用范围限制。
这只是使用所需空闲区域的参数设置扫描例程。
警告:只要扫描列表不为空,就不允许进行除向/从扫描列表中添加/删除节点之外的任何其他操作。
-
int drm_mm_reserve_node(struct drm_mm *mm, struct drm_mm_node *node)¶
插入预初始化的节点
参数
struct drm_mm *mm
要将 node 插入到的 drm_mm 分配器
struct drm_mm_node *node
要插入的 drm_mm_node
描述
此函数将已设置的 drm_mm_node
插入到分配器中,这意味着起点、大小和颜色必须由调用者设置。所有其他字段必须清零。这对于初始化具有预分配对象的分配器很有用,这些预分配对象必须在设置范围分配器之前进行设置,例如,在接管固件帧缓冲区时。
返回
成功返回 0,如果 node 所在位置没有空闲区域则返回 -ENOSPC。
-
int drm_mm_insert_node_in_range(struct drm_mm *const mm, struct drm_mm_node *const node, u64 size, u64 alignment, unsigned long color, u64 range_start, u64 range_end, enum drm_mm_insert_mode mode)¶
在指定范围内搜索空间并插入 node
参数
struct drm_mm * const mm
从中分配的 drm_mm
struct drm_mm_node * const node
要插入的预分配节点
u64 size
分配的大小
u64 alignment
分配的对齐方式
unsigned long color
用于此节点的不透明标记值
u64 range_start
此节点的允许范围的起始位置
u64 range_end
此节点的允许范围的结束位置
enum drm_mm_insert_mode mode
微调分配搜索和放置
描述
预先分配的节点必须清零。
返回
成功返回 0,如果没有合适的空闲区域则返回 -ENOSPC。
-
void drm_mm_remove_node(struct drm_mm_node *node)¶
从分配器中移除一个内存节点。
参数
struct drm_mm_node *node
要移除的 drm_mm_node
描述
这只是从其 drm_mm 分配器中移除一个节点。该节点不需要在重新插入到此分配器或任何其他 drm_mm 分配器之前再次清除。在未分配的节点上调用此函数是错误的。
-
void drm_mm_scan_init_with_range(struct drm_mm_scan *scan, struct drm_mm *mm, u64 size, u64 alignment, unsigned long color, u64 start, u64 end, enum drm_mm_insert_mode mode)¶
初始化范围受限的 LRU 扫描
参数
struct drm_mm_scan *scan
扫描状态
struct drm_mm *mm
要扫描的 drm_mm
u64 size
分配的大小
u64 alignment
分配的对齐方式
unsigned long color
用于分配的不透明标记值
u64 start
分配的允许范围的起始位置
u64 end
分配的允许范围的结束位置
enum drm_mm_insert_mode mode
微调分配搜索和放置
描述
这只是使用所需空闲区域的参数设置扫描例程。
警告:只要扫描列表不为空,就不允许进行除向/从扫描列表中添加/删除节点之外的任何其他操作。
-
bool drm_mm_scan_add_block(struct drm_mm_scan *scan, struct drm_mm_node *node)¶
将节点添加到扫描列表
参数
struct drm_mm_scan *scan
活动的 drm_mm 扫描器
struct drm_mm_node *node
要添加的 drm_mm_node
描述
将一个节点添加到扫描列表中,该节点可能会被释放以腾出所需空洞的空间。
返回
如果已找到空洞,则为 True,否则为 false。
-
bool drm_mm_scan_remove_block(struct drm_mm_scan *scan, struct drm_mm_node *node)¶
从扫描列表中移除一个节点
参数
struct drm_mm_scan *scan
活动的 drm_mm 扫描器
struct drm_mm_node *node
要移除的 drm_mm_node
描述
节点必须按照它们添加到扫描列表中的完全相反的顺序移除(例如,使用 list_add()
添加它们,然后使用 list_for_each()
遍历该驱逐列表来移除),否则内存管理器的内部状态将损坏。
当扫描列表为空时,可以释放选定的内存节点。紧接着调用 drm_mm_insert_node_in_range_generic() 或该函数的简化版本之一,且 !DRM_MM_SEARCH_BEST 时,将返回刚刚释放的块(因为它位于 free_stack 列表的顶部)。
返回
如果应该驱逐此块,则为 True,否则为 false。当未找到空洞时,将始终返回 false。
-
struct drm_mm_node *drm_mm_scan_color_evict(struct drm_mm_scan *scan)¶
驱逐空洞两侧的重叠节点
参数
struct drm_mm_scan *scan
具有目标空洞的 drm_mm 扫描
描述
在完成驱逐扫描并删除选定的节点后,如果正在使用 mm.color_adjust,我们可能需要从目标空洞的任一侧删除更多节点。
返回
要驱逐的节点,如果没有重叠的节点,则为 NULL。
参数
struct drm_mm *mm
要初始化的 drm_mm 结构
u64 start
由 mm 管理的范围的起始位置
u64 size
由 mm 管理的范围的结束位置
描述
请注意,在调用此函数之前,必须将 mm 清零。
参数
struct drm_mm *mm
要清理的 drm_mm 分配器
描述
请注意,在未清理的分配器上调用此函数是错误的。
-
void drm_mm_print(const struct drm_mm *mm, struct drm_printer *p)¶
打印分配器状态
参数
const struct drm_mm *mm
要打印的 drm_mm 分配器
struct drm_printer *p
要使用的 DRM 打印机
DRM GPUVM¶
概述¶
DRM GPU VA 管理器,由 struct drm_gpuvm
表示,跟踪 GPU 的虚拟地址 (VA) 空间,并管理由 drm_gpuva
对象表示的相应虚拟映射。它还跟踪映射的后备 drm_gem_object
缓冲区。
drm_gem_object
缓冲区维护一个 drm_gpuva
对象列表,表示使用此 drm_gem_object
作为后备缓冲区的现有的所有 GPU VA 映射。
GPU VA 可以标记为稀疏,这样驱动程序可以使用 GPU VA 来跟踪稀疏 PTE,以支持 Vulkan“稀疏资源”。
GPU VA 管理器内部使用 rb-树来管理 GPU 虚拟地址空间中的 drm_gpuva
映射。
drm_gpuvm
结构体包含一个特殊的 drm_gpuva
,表示内核保留的 VA 空间部分。此节点与 GPU VA 管理器实例一起初始化,并在 GPU VA 管理器销毁时删除。
在典型的应用程序中,驱动程序会将 struct drm_gpuvm
和 struct drm_gpuva
嵌入到它们自己的特定于驱动程序的结构中,它本身不会有任何内存分配,也不会有 drm_gpuva
条目的内存分配。
在 drm_gpuvm
中存储 drm_gpuvas
所需的数据结构已经包含在 struct drm_gpuva
中。因此,为了从 dma-fence 信号临界区内插入 drm_gpuva
条目,预先分配 drm_gpuva
结构体就足够了。
单个 VM 私有的 drm_gem_objects
可以共享一个公共的 dma_resv
,以提高锁定效率(例如,使用 drm_exec
)。为此,驱动程序必须将一个 drm_gem_object
传递给 drm_gpuvm_init()
,在下文中称为“resv 对象”,它充当 GPUVM 共享的 dma_resv
的容器。此 resv 对象可以是驱动程序特定的 drm_gem_object
,例如包含根页表的 drm_gem_object
,但它也可以是一个“虚拟”对象,可以使用 drm_gpuvm_resv_object_alloc()
进行分配。
为了连接一个 struct drm_gpuva
及其后备 drm_gem_object
,每个 drm_gem_object
都维护一个 drm_gpuvm_bo
结构体的列表,并且每个 drm_gpuvm_bo
都包含一个 drm_gpuva
结构体的列表。
drm_gpuvm_bo
是表示 drm_gpuvm
和 drm_gem_object
组合的抽象。每个这样的组合都应该是唯一的。API 通过 drm_gpuvm_bo_obtain()
和 drm_gpuvm_bo_obtain_prealloc()
确保了这一点,它们首先查找相应的 drm_gem_object
的 drm_gpuvm_bos
列表,以查找此特定组合的现有实例。如果不存在,则会创建一个新实例并将其链接到 drm_gem_object
。
drm_gpuvm_bo
结构体,由于对于给定的 drm_gpuvm
是唯一的,也被用作 drm_gpuvm
的外部和已驱逐对象列表的条目。维护这些列表是为了加速 dma-resv 锁的锁定以及在 drm_gpuvm
中绑定的已驱逐对象的验证。例如,可以通过调用 drm_gpuvm_exec_lock()
来锁定给定 drm_gpuvm
的所有 drm_gem_object
的 dma_resv
。锁定后,驱动程序可以调用 drm_gpuvm_validate()
来验证所有已驱逐的 drm_gem_objects
。也可以通过将相应的参数提供给 drm_gpuvm_exec_lock()
以及在利用 drm_gpuvm_prepare_range()
或 drm_gpuvm_prepare_objects()
等辅助函数的同时打开代码 drm_exec
循环来锁定其他 drm_gem_objects
。
当绑定的 drm_gem_object
的 dma_resv
结构与 drm_gpuvm
的公共 dma_resv
结构不同时,每个绑定的 drm_gem_object
都被视为外部对象。
拆分和合并¶
除了管理和表示 GPU VA 空间的能力之外,GPU VA 管理器还提供了功能,让 drm_gpuvm
计算一系列操作以满足给定的映射或取消映射请求。
因此,DRM GPU VA 管理器提供了一种算法,该算法实现了现有 GPU VA 映射与请求映射或取消映射的映射的拆分和合并。Vulkan API 需要此功能来实现 Vulkan“稀疏内存绑定” - 驱动程序 UAPI 通常将其称为 VM BIND。
驱动程序可以调用 drm_gpuvm_sm_map()
来接收一系列回调,其中包含给定新请求的映射的映射、取消映射和重新映射操作。回调序列表示为了将新映射干净地集成到 GPU VA 空间的当前状态中而要执行的操作集。
根据新的 GPU VA 映射与 GPU VA 空间中现有映射的相交方式,drm_gpuvm_ops
回调包含任意数量的取消映射操作、最多两个重新映射操作和一个映射操作。如果没有操作,则调用者可能不会收到任何回调,例如,如果请求的映射已经以完全相同的方式存在。
单个映射操作表示调用者请求的原始映射操作。
drm_gpuva_op_unmap
包含一个 ‘keep’ 字段,该字段指示要取消映射的 drm_gpuva
在物理上是否与原始映射请求连续。可选地,如果设置了 ‘keep’,驱动程序可以保留此 drm_gpuva
的实际页表条目,仅添加缺少的页表条目,并相应地更新 drm_gpuvm
的视图。
驱动程序也可以对重新映射操作执行相同的优化,即增量页表更新。这是可行的,因为 drm_gpuva_op_remap
由一个取消映射操作和一个或两个映射操作组成,因此驱动程序可以相应地推导出页表更新增量。
请注意,最多只能拆分两个现有映射,一个在新映射的开头,另一个在新映射的结尾,因此最多只有两个重新映射操作。
类似于 drm_gpuvm_sm_map()
,drm_gpuvm_sm_unmap()
使用 drm_gpuvm_ops
回调到驱动程序中,以取消映射 GPU VA 空间的一部分范围。此函数背后的逻辑要简单得多:对于给定范围内的所有现有映射,将创建取消映射操作。对于仅部分位于给定范围内的映射,将创建重新映射操作,以便将这些映射拆分并部分重新映射。
作为 drm_gpuvm_sm_map()
和 drm_gpuvm_sm_unmap()
的替代方案,可以使用 drm_gpuvm_sm_map_ops_create()
和 drm_gpuvm_sm_unmap_ops_create()
直接获取 struct drm_gpuva_ops
的实例,其中包含 drm_gpuva_op
的列表,可以使用 drm_gpuva_for_each_op()
对其进行迭代。此列表包含 drm_gpuva_ops
,类似于调用 drm_gpuvm_sm_map()
或 drm_gpuvm_sm_unmap()
时会收到的回调。虽然这种方式需要更多的内存(用于分配 drm_gpuva_ops
),但它为驱动程序提供了一种多次迭代 drm_gpuva_op
的方法,例如,一次在可以进行内存分配的上下文中(例如,分配 GPU 页表),一次在 dma-fence 信号关键路径中。
要更新 drm_gpuvm
的 GPU VA 空间视图,可以使用 drm_gpuva_insert()
和 drm_gpuva_remove()
。可以从源自 drm_gpuvm_sm_map()
或 drm_gpuvm_sm_unmap()
的 drm_gpuvm_ops
回调中安全地使用这些函数。但是,使用提供的辅助函数 drm_gpuva_map()
、drm_gpuva_remap()
和 drm_gpuva_unmap()
可能更方便。
下图描绘了现有 GPU VA 映射、新请求的映射和由 drm_gpuvm_sm_map()
实现的生成的映射之间的基本关系 - 它不涵盖这些映射的任何任意组合。
请求的映射是相同的。替换它,但指示可以保留后备 PTE。
0 a 1 old: |-----------| (bo_offset=n) 0 a 1 req: |-----------| (bo_offset=n) 0 a 1 new: |-----------| (bo_offset=n)
请求的映射是相同的,除了 BO 偏移量,因此替换映射。
0 a 1 old: |-----------| (bo_offset=n) 0 a 1 req: |-----------| (bo_offset=m) 0 a 1 new: |-----------| (bo_offset=m)
请求的映射是相同的,除了后备 BO,因此替换映射。
0 a 1 old: |-----------| (bo_offset=n) 0 b 1 req: |-----------| (bo_offset=n) 0 b 1 new: |-----------| (bo_offset=n)
现有映射是请求映射的左对齐子集,因此替换现有映射。
0 a 1 old: |-----| (bo_offset=n) 0 a 2 req: |-----------| (bo_offset=n) 0 a 2 new: |-----------| (bo_offset=n)
注意
对于具有不同 BO 和/或非连续 BO 偏移量的请求,我们期望看到相同的结果。
请求映射的范围是现有映射的左对齐子集,但由不同的 BO 支持。因此,映射请求的映射并拆分现有映射,调整其 BO 偏移量。
0 a 2 old: |-----------| (bo_offset=n) 0 b 1 req: |-----| (bo_offset=n) 0 b 1 a' 2 new: |-----|-----| (b.bo_offset=n, a.bo_offset=n+1)
注意
对于具有不同 BO 和/或非连续 BO 偏移量的请求,我们期望看到相同的结果。
现有映射是请求映射的超集。将其拆分,但指示可以保留后备 PTE。
0 a 2 old: |-----------| (bo_offset=n) 0 a 1 req: |-----| (bo_offset=n) 0 a 1 a' 2 new: |-----|-----| (a.bo_offset=n, a'.bo_offset=n+1)
请求映射的范围是现有映射的右对齐子集,但由不同的 BO 支持。因此,映射请求的映射并拆分现有映射,无需调整 BO 偏移量。
0 a 2 old: |-----------| (bo_offset=n) 1 b 2 req: |-----| (bo_offset=m) 0 a 1 b 2 new: |-----|-----| (a.bo_offset=n,b.bo_offset=m)
现有映射是请求映射的超集。将其拆分,但指示可以保留后备 PTE。
0 a 2 old: |-----------| (bo_offset=n) 1 a 2 req: |-----| (bo_offset=n+1) 0 a' 1 a 2 new: |-----|-----| (a'.bo_offset=n, a.bo_offset=n+1)
现有映射的末尾与由不同 BO 支持的请求映射重叠。因此,映射请求的映射并拆分现有映射,无需调整 BO 偏移量。
0 a 2 old: |-----------| (bo_offset=n) 1 b 3 req: |-----------| (bo_offset=m) 0 a 1 b 3 new: |-----|-----------| (a.bo_offset=n,b.bo_offset=m)
现有映射与请求的映射重叠,两者都具有相同的后备 BO 和连续的偏移量。指示旧映射的后备 PTE 可以保留。
0 a 2 old: |-----------| (bo_offset=n) 1 a 3 req: |-----------| (bo_offset=n+1) 0 a' 1 a 3 new: |-----|-----------| (a'.bo_offset=n, a.bo_offset=n+1)
请求映射的范围是现有映射的中心子集,具有不同的后备 BO。因此,映射请求的映射并将现有映射拆分为两个映射,相应地调整右侧映射的 BO 偏移量。
0 a 3 old: |-----------------| (bo_offset=n) 1 b 2 req: |-----| (bo_offset=m) 0 a 1 b 2 a' 3 new: |-----|-----|-----| (a.bo_offset=n,b.bo_offset=m,a'.bo_offset=n+2)
请求的映射是现有映射的连续子集。将其拆分,但指示可以保留后备 PTE。
0 a 3 old: |-----------------| (bo_offset=n) 1 a 2 req: |-----| (bo_offset=n+1) 0 a' 1 a 2 a'' 3 old: |-----|-----|-----| (a'.bo_offset=n, a.bo_offset=n+1, a''.bo_offset=n+2)
现有映射是请求映射的右对齐子集,因此替换现有映射。
1 a 2 old: |-----| (bo_offset=n+1) 0 a 2 req: |-----------| (bo_offset=n) 0 a 2 new: |-----------| (bo_offset=n)
注意
对于具有不同 BO 和/或非连续 bo_offset 的请求,我们期望看到相同的结果。
现有映射是请求映射的中心子集,因此替换现有映射。
1 a 2 old: |-----| (bo_offset=n+1) 0 a 3 req: |----------------| (bo_offset=n) 0 a 3 new: |----------------| (bo_offset=n)
注意
对于具有不同 BO 和/或非连续 bo_offset 的请求,我们期望看到相同的结果。
现有映射的开头与由不同 BO 支持的请求映射重叠。因此,映射请求的映射并拆分现有映射,相应地调整其 BO 偏移量。
1 a 3 old: |-----------| (bo_offset=n) 0 b 2 req: |-----------| (bo_offset=m) 0 b 2 a' 3 new: |-----------|-----| (b.bo_offset=m,a.bo_offset=n+2)
锁定¶
在管理 drm_gpuva
条目方面,DRM GPUVM 本身不负责锁定,驱动程序有责任负责锁定。驱动程序可能需要保护以下操作:插入、删除和迭代 drm_gpuva
对象以及生成各种操作,例如拆分/合并或预取。
DRM GPUVM 本身也不负责锁定后备 drm_gem_object
缓冲区 GPU VA 列表和 drm_gpuvm_bo
抽象;驱动程序有责任使用 GEM 的 dma_resv 锁或驱动程序特定的外部锁来强制执行互斥。对于后者,另请参见 drm_gem_gpuva_set_lock()
。
但是,DRM GPUVM 包含 lockdep 检查,以确保其 API 的调用者在 drm_gem_objects
GPU VA 列表被 drm_gpuva_link()
或 drm_gpuva_unlink()
等函数访问时,持有相应的锁,以及 drm_gpuvm_bo_obtain()
和 drm_gpuvm_bo_put()
。
后者是必需的,因为在创建和销毁 drm_gpuvm_bo
时,drm_gpuvm_bo
会附加/从 drm_gem_objects
的 gpuva 列表中删除。为了保持实例的唯一性,后续对相同 drm_gpuvm
和 drm_gem_object
的 drm_gpuvm_bo_obtain()
调用必须能够观察到先前 drm_gpuvm_bos
的创建和销毁。
保护 drm_gpuvm
用于跟踪外部和驱逐对象的列表,使其免受并发插入/删除和内部迭代的影响。
但是,驱动程序仍然需要确保保护对迭代这些列表的函数的并发调用,即 drm_gpuvm_prepare_objects()
和 drm_gpuvm_validate()
。
或者,驱动程序可以设置 DRM_GPUVM_RESV_PROTECTED
标志,以表明相应的 dma_resv
锁被持有,以保护列表。如果设置了 DRM_GPUVM_RESV_PROTECTED
,则内部锁定将被禁用,并且相应的锁依赖检查将被启用。对于能够获取相应的 dma_resv
锁的驱动程序来说,这是一种优化,因此它们不需要内部锁定。
示例¶
本节提供了两个示例,说明如何让 DRM GPUVA 管理器生成 drm_gpuva_op
以满足给定的映射或取消映射请求,以及如何使用它们。
以下代码严格限制于说明通用使用模式。为了保持简洁,它没有使用任何常见代码的抽象、带有栅栏信号的关键路径的不同(异步)阶段、任何其他助手或在释放内存和放弃先前获取的锁方面的错误处理。
获取
drm_gpuva_op
列表以创建新映射// Allocates a new &drm_gpuva. struct drm_gpuva * driver_gpuva_alloc(void); // Typically drivers would embedd the &drm_gpuvm and &drm_gpuva // structure in individual driver structures and lock the dma-resv with // drm_exec or similar helpers. int driver_mapping_create(struct drm_gpuvm *gpuvm, u64 addr, u64 range, struct drm_gem_object *obj, u64 offset) { struct drm_gpuva_ops *ops; struct drm_gpuva_op *op struct drm_gpuvm_bo *vm_bo; driver_lock_va_space(); ops = drm_gpuvm_sm_map_ops_create(gpuvm, addr, range, obj, offset); if (IS_ERR(ops)) return PTR_ERR(ops); vm_bo = drm_gpuvm_bo_obtain(gpuvm, obj); if (IS_ERR(vm_bo)) return PTR_ERR(vm_bo); drm_gpuva_for_each_op(op, ops) { struct drm_gpuva *va; switch (op->op) { case DRM_GPUVA_OP_MAP: va = driver_gpuva_alloc(); if (!va) ; // unwind previous VA space updates, // free memory and unlock driver_vm_map(); drm_gpuva_map(gpuvm, va, &op->map); drm_gpuva_link(va, vm_bo); break; case DRM_GPUVA_OP_REMAP: { struct drm_gpuva *prev = NULL, *next = NULL; va = op->remap.unmap->va; if (op->remap.prev) { prev = driver_gpuva_alloc(); if (!prev) ; // unwind previous VA space // updates, free memory and // unlock } if (op->remap.next) { next = driver_gpuva_alloc(); if (!next) ; // unwind previous VA space // updates, free memory and // unlock } driver_vm_remap(); drm_gpuva_remap(prev, next, &op->remap); if (prev) drm_gpuva_link(prev, va->vm_bo); if (next) drm_gpuva_link(next, va->vm_bo); drm_gpuva_unlink(va); break; } case DRM_GPUVA_OP_UNMAP: va = op->unmap->va; driver_vm_unmap(); drm_gpuva_unlink(va); drm_gpuva_unmap(&op->unmap); break; default: break; } } drm_gpuvm_bo_put(vm_bo); driver_unlock_va_space(); return 0; }
接收每个
drm_gpuva_op
的回调以创建新映射struct driver_context { struct drm_gpuvm *gpuvm; struct drm_gpuvm_bo *vm_bo; struct drm_gpuva *new_va; struct drm_gpuva *prev_va; struct drm_gpuva *next_va; }; // ops to pass to drm_gpuvm_init() static const struct drm_gpuvm_ops driver_gpuvm_ops = { .sm_step_map = driver_gpuva_map, .sm_step_remap = driver_gpuva_remap, .sm_step_unmap = driver_gpuva_unmap, }; // Typically drivers would embedd the &drm_gpuvm and &drm_gpuva // structure in individual driver structures and lock the dma-resv with // drm_exec or similar helpers. int driver_mapping_create(struct drm_gpuvm *gpuvm, u64 addr, u64 range, struct drm_gem_object *obj, u64 offset) { struct driver_context ctx; struct drm_gpuvm_bo *vm_bo; struct drm_gpuva_ops *ops; struct drm_gpuva_op *op; int ret = 0; ctx.gpuvm = gpuvm; ctx.new_va = kzalloc(sizeof(*ctx.new_va), GFP_KERNEL); ctx.prev_va = kzalloc(sizeof(*ctx.prev_va), GFP_KERNEL); ctx.next_va = kzalloc(sizeof(*ctx.next_va), GFP_KERNEL); ctx.vm_bo = drm_gpuvm_bo_create(gpuvm, obj); if (!ctx.new_va || !ctx.prev_va || !ctx.next_va || !vm_bo) { ret = -ENOMEM; goto out; } // Typically protected with a driver specific GEM gpuva lock // used in the fence signaling path for drm_gpuva_link() and // drm_gpuva_unlink(), hence pre-allocate. ctx.vm_bo = drm_gpuvm_bo_obtain_prealloc(ctx.vm_bo); driver_lock_va_space(); ret = drm_gpuvm_sm_map(gpuvm, &ctx, addr, range, obj, offset); driver_unlock_va_space(); out: drm_gpuvm_bo_put(ctx.vm_bo); kfree(ctx.new_va); kfree(ctx.prev_va); kfree(ctx.next_va); return ret; } int driver_gpuva_map(struct drm_gpuva_op *op, void *__ctx) { struct driver_context *ctx = __ctx; drm_gpuva_map(ctx->vm, ctx->new_va, &op->map); drm_gpuva_link(ctx->new_va, ctx->vm_bo); // prevent the new GPUVA from being freed in // driver_mapping_create() ctx->new_va = NULL; return 0; } int driver_gpuva_remap(struct drm_gpuva_op *op, void *__ctx) { struct driver_context *ctx = __ctx; struct drm_gpuva *va = op->remap.unmap->va; drm_gpuva_remap(ctx->prev_va, ctx->next_va, &op->remap); if (op->remap.prev) { drm_gpuva_link(ctx->prev_va, va->vm_bo); ctx->prev_va = NULL; } if (op->remap.next) { drm_gpuva_link(ctx->next_va, va->vm_bo); ctx->next_va = NULL; } drm_gpuva_unlink(va); kfree(va); return 0; } int driver_gpuva_unmap(struct drm_gpuva_op *op, void *__ctx) { drm_gpuva_unlink(op->unmap.va); drm_gpuva_unmap(&op->unmap); kfree(op->unmap.va); return 0; }
DRM GPUVM 函数参考¶
-
enum drm_gpuva_flags¶
struct drm_gpuva
的标志
常量
-
struct drm_gpuva¶
跟踪 GPU VA 映射的结构
定义:
struct drm_gpuva {
struct drm_gpuvm *vm;
struct drm_gpuvm_bo *vm_bo;
enum drm_gpuva_flags flags;
struct {
u64 addr;
u64 range;
} va;
struct {
u64 offset;
struct drm_gem_object *obj;
struct list_head entry;
} gem;
struct {
struct rb_node node;
struct list_head entry;
u64 __subtree_last;
} rb;
};
成员
vm
此对象关联的
drm_gpuvm
vm_bo
映射的
drm_gem_object
的drm_gpuvm_bo
抽象flags
此映射的
drm_gpuva_flags
va
包含
drm_gpuva
的地址和范围的结构va.addr
起始地址
gem
包含
drm_gem_object
及其偏移量的结构gem.offset
drm_gem_object
中的偏移量gem.obj
映射的
drm_gem_object
gem.entry
将此对象附加到
drm_gpuvm_bo
的list_head
rb
包含在 rb-tree 中存储
drm_gpuvas
的数据的结构rb.node
rb-tree 节点
rb.entry
将
drm_gpuvas
按它们在区间树中出现的相同顺序额外连接的list_head
。这对于在对 rb-tree 本身进行修改时,保持从通过 rb-tree 找到的起始节点迭代drm_gpuvas
非常有用。rb.__subtree_last
区间树需要,持有子树中的最后一个
描述
此结构表示 GPU VA 映射,并与 drm_gpuvm
关联。
通常,此结构嵌入在更大的驱动程序结构中。
-
enum drm_gpuvm_flags¶
struct drm_gpuvm
的标志
常量
DRM_GPUVM_RESV_PROTECTED
GPUVM 由 GPUVM 的
dma_resv
锁在外部保护DRM_GPUVM_USERBITS
用户定义的位
-
struct drm_gpuvm¶
DRM GPU VA 管理器
定义:
struct drm_gpuvm {
const char *name;
enum drm_gpuvm_flags flags;
struct drm_device *drm;
u64 mm_start;
u64 mm_range;
struct {
struct rb_root_cached tree;
struct list_head list;
} rb;
struct kref kref;
struct drm_gpuva kernel_alloc_node;
const struct drm_gpuvm_ops *ops;
struct drm_gem_object *r_obj;
struct {
struct list_head list;
struct list_head *local_list;
spinlock_t lock;
} extobj;
struct {
struct list_head list;
struct list_head *local_list;
spinlock_t lock;
} evict;
};
成员
name
DRM GPU VA 空间的名称
flags
此 GPUVM 的
drm_gpuvm_flags
drm
此 VM 所在的
drm_device
mm_start
VA 空间的起始
mm_range
VA 空间的长度
rb
用于跟踪
drm_gpuva
条目的结构rb.tree
用于跟踪 GPU VA 映射的 rb-tree
rb.list
用于跟踪 GPU VA 映射的
list_head
kref
此对象的引用计数
kernel_alloc_node
表示为内核保留的地址空间切口的
drm_gpuva
ops
为驱动程序提供拆分/合并步骤的
drm_gpuvm_ops
r_obj
Resv GEM 对象;表示 GPUVM 的公共
dma_resv
。extobj
包含 extobj 列表的结构
extobj.list
存储作为外部对象的
drm_gpuvm_bos
的list_head
extobj.local_list
指向临时存储来自外部对象列表的条目的本地列表的指针
extobj.lock
用于保护 extobj 列表的自旋锁
evict
包含驱逐列表和驱逐列表锁的结构
evict.list
存储当前正在驱逐的
drm_gpuvm_bos
的list_head
evict.local_list
指向临时存储来自驱逐对象列表的条目的本地列表的指针
evict.lock
用于保护驱逐列表的自旋锁
描述
DRM GPU VA 管理器通过使用 maple_tree
结构来跟踪 GPU 的虚拟地址空间。通常,此结构嵌入在更大的驱动程序结构中。
驱动程序可以以任意单位(例如,字节或页)传递地址和范围。
每个 GPU 虚拟地址空间应该有一个管理器实例。
-
struct drm_gpuvm *drm_gpuvm_get(struct drm_gpuvm *gpuvm)¶
获取
struct drm_gpuvm
的引用
-
drm_gpuvm_resv¶
drm_gpuvm_resv (gpuvm__)
-
drm_gpuvm_resv_obj¶
drm_gpuvm_resv_obj (gpuvm__)
返回持有
drm_gpuvm
的dma_resv
的drm_gem_object
-
bool drm_gpuvm_is_extobj(struct drm_gpuvm *gpuvm, struct drm_gem_object *obj)¶
指示给定的
drm_gem_object
是否是外部对象
参数
struct drm_gpuvm *gpuvm
要检查的
drm_gpuvm
struct drm_gem_object *obj
要检查的
drm_gem_object
返回
如果 drm_gem_object
的 dma_resv
与 drm_gpuvms
的 dma_resv
不同,则为 true,否则为 false
-
drm_gpuvm_for_each_va_range¶
drm_gpuvm_for_each_va_range (va__, gpuvm__, start__, end__)
迭代
drm_gpuvas
的范围
参数
va__
在每个迭代步骤中要赋值的
drm_gpuva
结构gpuvm__
要遍历的
drm_gpuvm
start__
起始偏移量,第一个 gpuva 将与此重叠
end__
结束偏移量,最后一个 gpuva 将在此之前开始(但可能会重叠)
描述
此迭代器遍历 start__ 和 end__ 之间的 drm_gpuvm
中的所有 drm_gpuvas
。它的实现类似于 list_for_each()
,但使用 drm_gpuvm
的内部区间树来加速搜索起始 drm_gpuva
,因此对于元素的删除是不安全的。它假设 end__ 在 drm_gpuvm
内(或为上限)。此迭代器不会跳过 drm_gpuvm
的 kernel_alloc_node。
-
drm_gpuvm_for_each_va_range_safe¶
drm_gpuvm_for_each_va_range_safe (va__, next__, gpuvm__, start__, end__)
安全地迭代
drm_gpuvas
的范围
参数
va__
在每个迭代步骤中要赋值的
drm_gpuva
next__
要用作临时存储的另一个
drm_gpuva
gpuvm__
要遍历的
drm_gpuvm
start__
起始偏移量,第一个 gpuva 将与此重叠
end__
结束偏移量,最后一个 gpuva 将在此之前开始(但可能会重叠)
描述
此迭代器遍历 start__ 和 end__ 之间的 drm_gpuvm
中的所有 drm_gpuvas
。它的实现类似于 list_for_each_safe()
,但使用 drm_gpuvm
的内部区间树来加速搜索起始 drm_gpuva
,因此对于元素的删除是安全的。它假设 end__ 在 drm_gpuvm
内(或为上限)。此迭代器不会跳过 drm_gpuvm
的 kernel_alloc_node。
-
drm_gpuvm_for_each_va¶
drm_gpuvm_for_each_va (va__, gpuvm__)
迭代所有
drm_gpuvas
-
drm_gpuvm_for_each_va_safe¶
drm_gpuvm_for_each_va_safe (va__, next__, gpuvm__)
安全地迭代所有
drm_gpuvas
定义:
struct drm_gpuvm_exec {
struct drm_exec exec;
u32 flags;
struct drm_gpuvm *vm;
unsigned int num_fences;
struct {
int (*fn)(struct drm_gpuvm_exec *vm_exec);
void *priv;
} extra;
};
成员
exec
drm_exec
结构flags
struct drm_exec
的标志vm
要锁定其 DMA 预留的
drm_gpuvm
num_fences
为锁定的
drm_gem_objects
的dma_resv
保留的栅栏数量额外
驱动程序锁定任意其他
drm_gem_objects
的回调函数和相应的私有数据。extra.fn
驱动程序回调函数,用于锁定额外的
drm_gem_objects
。extra.priv
用于 fn 回调函数的驱动程序私有数据
描述
此结构应在堆栈上创建,如同 drm_exec
一样。
可以选择设置 extra 以便锁定额外的 drm_gem_objects
。
-
void drm_gpuvm_exec_unlock(struct drm_gpuvm_exec *vm_exec)¶
锁定所有关联的 BO 的所有 dma-resv
参数
struct drm_gpuvm_exec *vm_exec
drm_gpuvm_exec
包装器
描述
释放先前通过 drm_gpuvm_exec_lock()
或其变体获取的所有 drm_gem_objects
的所有 dma-resv 锁。
返回
成功时为 0,失败时为负错误代码。
-
void drm_gpuvm_exec_resv_add_fence(struct drm_gpuvm_exec *vm_exec, struct dma_fence *fence, enum dma_resv_usage private_usage, enum dma_resv_usage extobj_usage)¶
将栅栏添加到私有和所有 extobj
参数
struct drm_gpuvm_exec *vm_exec
drm_gpuvm_exec
包装器struct dma_fence *fence
要添加的栅栏
enum dma_resv_usage private_usage
私有 dma-resv 用法
enum dma_resv_usage extobj_usage
extobj dma-resv 用法
描述
-
int drm_gpuvm_exec_validate(struct drm_gpuvm_exec *vm_exec)¶
验证所有标记为已逐出的 BO
参数
struct drm_gpuvm_exec *vm_exec
drm_gpuvm_exec
包装器
描述
请参阅 drm_gpuvm_validate()
。
返回
成功时为 0,失败时为负错误代码。
-
struct drm_gpuvm_bo¶
表示
drm_gpuvm
和drm_gem_object
组合的结构
定义:
struct drm_gpuvm_bo {
struct drm_gpuvm *vm;
struct drm_gem_object *obj;
bool evicted;
struct kref kref;
struct {
struct list_head gpuva;
struct {
struct list_head gem;
struct list_head extobj;
struct list_head evict;
} entry;
} list;
};
成员
vm
obj 映射到的
drm_gpuvm
。这是一个引用计数指针。obj
正在 vm 中映射的
drm_gem_object
。这是一个引用计数指针。已逐出
指示
drm_gem_object
是否已逐出;该字段受drm_gem_object
的 dma-resv 锁保护。kref
此
drm_gpuvm_bo
的引用计数。list
包含所有
list_heads
的结构。list.gpuva
链接的
drm_gpuvas
的列表。只要持有 GEM 的 gpuva 锁,就可以安全地访问此列表中的条目。另请参阅
struct drm_gem_object
。list.entry
包含所有用作条目的
list_heads
的结构。list.entry.gem
要附加到
drm_gem_objects
gpuva 列表的列表条目。list.entry.evict
要附加到
drm_gpuvms
逐出列表的列表条目。
描述
此结构是一个抽象,表示 drm_gpuvm
和 drm_gem_object
的组合。它用作间接方式,以加速迭代由同一 drm_gem_object
支持的 drm_gpuvm
中的所有 drm_gpuvas
。
此外,它用于缓存特定 GPU-VM 的已逐出 GEM 对象,以加速验证。
通常,驱动程序希望在 GEM 对象首次映射到 GPU-VM 时创建 struct drm_gpuvm_bo
的实例,并在此 GPU-VM 中 GEM 对象的最后一次映射取消映射后释放该实例。
-
struct drm_gpuvm_bo *drm_gpuvm_bo_get(struct drm_gpuvm_bo *vm_bo)¶
获取
struct drm_gpuvm_bo
引用
参数
struct drm_gpuvm_bo *vm_bo
要获取其引用的
drm_gpuvm_bo
描述
此函数获取对 vm_bo 的额外引用。在没有持有引用的情况下调用此函数是非法的。不需要锁。
返回
struct vm_bo
指针
-
void drm_gpuvm_bo_gem_evict(struct drm_gem_object *obj, bool evict)¶
将列表中的所有
drm_gpuvm_bo
添加/删除到/从drm_gpuvms
逐出列表中
-
drm_gpuvm_bo_for_each_va¶
drm_gpuvm_bo_for_each_va (va__, vm_bo__)
迭代器,用于遍历
drm_gpuva
列表
参数
va__
在每个迭代步骤中要赋值的
drm_gpuva
结构vm_bo__
drm_gpuvm_bo
,要遍历的drm_gpuva
与之关联
描述
此迭代器遍历与 drm_gpuvm_bo
关联的所有 drm_gpuva
结构。
调用者必须持有 GEM 的 gpuva 锁。
-
drm_gpuvm_bo_for_each_va_safe¶
drm_gpuvm_bo_for_each_va_safe (va__, next__, vm_bo__)
安全遍历
drm_gpuva
列表的迭代器
参数
va__
在每个迭代步骤中要赋值的
drm_gpuva
结构next__
next
drm_gpuva
用于存储下一步vm_bo__
drm_gpuvm_bo
,要遍历的drm_gpuva
与之关联
描述
此迭代器遍历与 drm_gpuvm_bo
关联的所有 drm_gpuva
结构。它使用 list_for_each_entry_safe()
实现,因此可以安全地删除元素。
调用者必须持有 GEM 的 gpuva 锁。
-
enum drm_gpuva_op_type¶
GPU VA 操作类型
常量
DRM_GPUVA_OP_MAP
映射操作类型
DRM_GPUVA_OP_REMAP
重映射操作类型
DRM_GPUVA_OP_UNMAP
取消映射操作类型
DRM_GPUVA_OP_PREFETCH
预取操作类型
描述
用于更改由 drm_gpuvm
跟踪的 GPU VA 映射的操作。
-
struct drm_gpuva_op_map¶
GPU VA 映射操作
定义:
struct drm_gpuva_op_map {
struct {
u64 addr;
u64 range;
} va;
struct {
u64 offset;
struct drm_gem_object *obj;
} gem;
};
成员
va
包含映射操作的地址和范围的结构
va.addr
新映射的基址
va.range
新映射的范围
gem
包含
drm_gem_object
及其偏移量的结构gem.offset
drm_gem_object
中的偏移量gem.obj
要映射的
drm_gem_object
描述
此结构表示由 DRM GPU VA 管理器生成的单个映射操作。
-
struct drm_gpuva_op_unmap¶
GPU VA 取消映射操作
定义:
struct drm_gpuva_op_unmap {
struct drm_gpuva *va;
bool keep;
};
成员
描述
此结构表示由 DRM GPU VA 管理器生成的单个取消映射操作。
-
struct drm_gpuva_op_remap¶
GPU VA 重映射操作
定义:
struct drm_gpuva_op_remap {
struct drm_gpuva_op_map *prev;
struct drm_gpuva_op_map *next;
struct drm_gpuva_op_unmap *unmap;
};
成员
prev
分割映射的前一部分
next
分割映射的后一部分
unmap
原始现有映射的取消映射操作
描述
这表示由 DRM GPU VA 管理器生成的单个重映射操作。
当通过插入新的 GPU VA 映射或通过部分取消映射现有映射来分割现有 GPU VA 映射时,会生成重映射操作,因此它最多包含两个映射操作和一个取消映射操作。
unmap 操作负责删除原始现有映射。 prev 用于重映射前一部分,next 用于重映射后一部分。
如果新映射的起始地址与旧映射的起始地址对齐,或者新映射的结束地址与旧映射的结束地址对齐,则 prev 或 next 为 NULL。
请注意,使用专用重映射操作而不是任意取消映射和映射操作的原因是,使驱动程序有机会从取消映射操作的 drm_gpuva
结构(通常嵌入在更大的驱动程序特定结构中)中提取用于创建新映射的驱动程序特定数据。
-
struct drm_gpuva_op_prefetch¶
GPU VA 预取操作
描述
此结构表示由 DRM GPU VA 管理器生成的单个预取操作。
-
struct drm_gpuva_op¶
GPU VA 操作
定义:
struct drm_gpuva_op {
struct list_head entry;
enum drm_gpuva_op_type op;
union {
struct drm_gpuva_op_map map;
struct drm_gpuva_op_remap remap;
struct drm_gpuva_op_unmap unmap;
struct drm_gpuva_op_prefetch prefetch;
};
};
成员
entry
用于在
drm_gpuva_ops
中分发此结构实例的list_head
。op
操作的类型
{unnamed_union}
匿名
map
映射操作
remap
重映射操作
unmap
取消映射操作
prefetch
预取操作
描述
此结构表示单个通用操作。
操作的特定类型由 op 定义。
-
struct drm_gpuva_ops¶
包装
drm_gpuva_op
的列表
定义:
struct drm_gpuva_ops {
struct list_head list;
};
成员
list
list_head
-
drm_gpuva_for_each_op¶
drm_gpuva_for_each_op (op, ops)
用于遍历
drm_gpuva_ops
的迭代器
-
drm_gpuva_for_each_op_safe¶
drm_gpuva_for_each_op_safe (op, next, ops)
用于安全遍历
drm_gpuva_ops
的迭代器
参数
op
在每个迭代步骤中要分配的
drm_gpuva_op
next
next
drm_gpuva_op
用于存储下一步ops
要遍历的
drm_gpuva_ops
描述
此迭代器遍历给定操作列表中的所有操作。它使用 list_for_each_safe()
实现,因此可以安全地删除元素。
-
drm_gpuva_for_each_op_from_reverse¶
drm_gpuva_for_each_op_from_reverse (op, ops)
从给定点向后迭代
-
drm_gpuva_for_each_op_reverse¶
drm_gpuva_for_each_op_reverse (op, ops)
用于以相反顺序遍历
drm_gpuva_ops
的迭代器
-
drm_gpuva_first_op¶
drm_gpuva_first_op (ops)
从
drm_gpuva_ops
返回第一个drm_gpuva_op
参数
ops
要从中获取第一个
drm_gpuva_op
的drm_gpuva_ops
-
drm_gpuva_last_op¶
drm_gpuva_last_op (ops)
从
drm_gpuva_ops
返回最后一个drm_gpuva_op
参数
ops
要从中获取最后一个
drm_gpuva_op
的drm_gpuva_ops
-
drm_gpuva_prev_op¶
drm_gpuva_prev_op (op)
列表中上一个
drm_gpuva_op
参数
op
当前
drm_gpuva_op
-
drm_gpuva_next_op¶
drm_gpuva_next_op (op)
列表中下一个
drm_gpuva_op
参数
op
当前
drm_gpuva_op
-
struct drm_gpuvm_ops¶
用于拆分/合并步骤的回调
定义:
struct drm_gpuvm_ops {
void (*vm_free)(struct drm_gpuvm *gpuvm);
struct drm_gpuva_op *(*op_alloc)(void);
void (*op_free)(struct drm_gpuva_op *op);
struct drm_gpuvm_bo *(*vm_bo_alloc)(void);
void (*vm_bo_free)(struct drm_gpuvm_bo *vm_bo);
int (*vm_bo_validate)(struct drm_gpuvm_bo *vm_bo, struct drm_exec *exec);
int (*sm_step_map)(struct drm_gpuva_op *op, void *priv);
int (*sm_step_remap)(struct drm_gpuva_op *op, void *priv);
int (*sm_step_unmap)(struct drm_gpuva_op *op, void *priv);
};
成员
vm_free
当
struct drm_gpuvm
的最后一个引用被删除时调用此回调是必需的。
op_alloc
当
drm_gpuvm
分配struct drm_gpuva_op
时调用某些驱动程序可能希望将
struct drm_gpuva_op
嵌入到特定于驱动程序的结构中。通过实现此回调,驱动程序可以相应地分配内存。此回调是可选的。
op_free
当
drm_gpuvm
释放struct drm_gpuva_op
时调用某些驱动程序可能希望将
struct drm_gpuva_op
嵌入到特定于驱动程序的结构中。通过实现此回调,驱动程序可以相应地释放先前分配的内存。此回调是可选的。
vm_bo_alloc
当
drm_gpuvm
分配struct drm_gpuvm_bo
时调用某些驱动程序可能希望将
struct drm_gpuvm_bo
嵌入到特定于驱动程序的结构中。通过实现此回调,驱动程序可以相应地分配内存。此回调是可选的。
vm_bo_free
当
drm_gpuvm
释放struct drm_gpuvm_bo
时调用某些驱动程序可能希望将
struct drm_gpuvm_bo
嵌入到特定于驱动程序的结构中。通过实现此回调,驱动程序可以相应地释放先前分配的内存。此回调是可选的。
vm_bo_validate
从
drm_gpuvm_validate()
调用对于在相应的
drm_gpuvm
中映射的每个被驱逐的drm_gem_object
,驱动程序都会收到此回调。通常,驱动程序会在此回调中调用其特定于驱动程序的 ttm_bo_validate() 变体。
sm_step_map
从
drm_gpuvm_sm_map
调用,以便在完成所有先前的步骤后最终插入映射priv
指针与驱动程序传递给drm_gpuvm_sm_map
或drm_gpuvm_sm_unmap
的指针匹配。如果使用
drm_gpuvm_sm_map
,则可以为 NULL。sm_step_remap
从
drm_gpuvm_sm_map
和drm_gpuvm_sm_unmap
调用,以拆分现有的映射当需要拆分现有映射时,会调用此回调。当新请求的映射与现有映射重叠或被现有映射包围,或者请求部分取消映射现有映射时,就会发生这种情况。
priv
指针与驱动程序传递给drm_gpuvm_sm_map
或drm_gpuvm_sm_unmap
的指针匹配。如果既不使用
drm_gpuvm_sm_map
也不使用drm_gpuvm_sm_unmap
,则可以为 NULL。sm_step_unmap
从
drm_gpuvm_sm_map
和drm_gpuvm_sm_unmap
调用,以取消映射现有的映射当需要取消映射现有映射时,会调用此回调。当新请求的映射包围现有映射或请求取消映射现有映射时,就会发生这种情况。
priv
指针与驱动程序传递给drm_gpuvm_sm_map
或drm_gpuvm_sm_unmap
的指针匹配。如果既不使用
drm_gpuvm_sm_map
也不使用drm_gpuvm_sm_unmap
,则可以为 NULL。
描述
此结构定义了 drm_gpuvm_sm_map
和 drm_gpuvm_sm_unmap
使用的回调,以便为驱动程序提供映射和取消映射操作的拆分/合并步骤。
-
void drm_gpuva_op_remap_to_unmap_range(const struct drm_gpuva_op_remap *op, u64 *start_addr, u64 *range)¶
辅助函数,用于获取重映射操作的取消映射阶段的起始地址和范围。
参数
const struct drm_gpuva_op_remap *op
重映射操作。
u64 *start_addr
所需取消映射起始地址的输出指针。
u64 *range
所需取消映射长度的输出指针。
描述
将设置给定的起始地址和范围,使其表示先前被重新映射的映射覆盖的地址空间范围,但现在为空。
-
bool drm_gpuvm_range_valid(struct drm_gpuvm *gpuvm, u64 addr, u64 range)¶
检查给定的范围对于给定的
drm_gpuvm
是否有效
参数
struct drm_gpuvm *gpuvm
用于检查范围的 GPUVM
u64 addr
基地址
u64 range
从基地址开始的范围
描述
检查该范围是否在 GPUVM 的管理边界内。
返回
有效范围返回 true,否则返回 false
-
struct drm_gem_object *drm_gpuvm_resv_object_alloc(struct drm_device *drm)¶
分配一个虚拟
drm_gem_object
参数
struct drm_device *drm
驱动程序的
drm_device
描述
分配一个虚拟 drm_gem_object
,它可以传递给 drm_gpuvm_init()
,以便用作根 GEM 对象,从而提供跨单个 GPUVM 本地的 drm_gem_objects
共享的 drm_resv
。
返回
成功时返回 drm_gem_object
,失败时返回 NULL
-
void drm_gpuvm_init(struct drm_gpuvm *gpuvm, const char *name, enum drm_gpuvm_flags flags, struct drm_device *drm, struct drm_gem_object *r_obj, u64 start_offset, u64 range, u64 reserve_offset, u64 reserve_range, const struct drm_gpuvm_ops *ops)¶
初始化一个
drm_gpuvm
参数
struct drm_gpuvm *gpuvm
指向要初始化的
drm_gpuvm
的指针const char *name
GPU VA 空间的名称
enum drm_gpuvm_flags flags
此 GPUVM 的
drm_gpuvm_flags
struct drm_device *drm
此 VM 所在的
drm_device
struct drm_gem_object *r_obj
提供 GPUVM 通用
dma_resv
的 resvdrm_gem_object
u64 start_offset
GPU VA 空间的起始偏移量
u64 range
GPU VA 空间的大小
u64 reserve_offset
内核保留的 GPU VA 区域的起始位置
u64 reserve_range
内核保留的 GPU VA 区域的大小
const struct drm_gpuvm_ops *ops
描述
必须在使用前使用此函数初始化 drm_gpuvm
。
请注意,在调用此函数之前,必须将 gpuvm 清零为 0。给定的 name
预计由周围的驱动程序结构管理。
-
void drm_gpuvm_put(struct drm_gpuvm *gpuvm)¶
删除
struct drm_gpuvm
引用
-
int drm_gpuvm_prepare_vm(struct drm_gpuvm *gpuvm, struct drm_exec *exec, unsigned int num_fences)¶
准备 GPUVM 的通用 dma-resv
参数
struct drm_gpuvm *gpuvm
struct drm_exec *exec
drm_exec
上下文unsigned int num_fences
要保留的
dma_fences
的数量
描述
为 GPUVM 的虚拟 drm_gem_object
调用 drm_exec_prepare_obj()
;如果 num_fences 为零,则改为调用 drm_exec_lock_obj()
。
直接使用此函数时,驱动程序有责任相应地调用 drm_exec_init()
和 drm_exec_fini()
。
返回
成功时为 0,失败时为负错误代码。
-
int drm_gpuvm_prepare_objects(struct drm_gpuvm *gpuvm, struct drm_exec *exec, unsigned int num_fences)¶
准备所有关联的 BO
参数
struct drm_gpuvm *gpuvm
struct drm_exec *exec
drm_exec
锁定上下文unsigned int num_fences
要保留的
dma_fences
的数量
描述
为给定的 drm_gpuvm
包含的映射中的所有 drm_gem_objects
调用 drm_exec_prepare_obj()
;如果 num_fences 为零,则改为调用 drm_exec_lock_obj()
。
直接使用此函数时,驱动程序有责任相应地调用 drm_exec_init()
和 drm_exec_fini()
。
驱动程序需要确保通过外部 VM 锁或在 drm_exec_until_all_locked()
循环中调用此函数之前调用 drm_gpuvm_prepare_vm()
来保护这种情况,以便 GPUVM 的 dma-resv 锁确保互斥。
注意
此函数可以防止并发插入和删除外部对象,但本身不能防止并发使用。
返回
成功时为 0,失败时为负错误代码。
-
int drm_gpuvm_prepare_range(struct drm_gpuvm *gpuvm, struct drm_exec *exec, u64 addr, u64 range, unsigned int num_fences)¶
准备给定范围内的所有映射 BO
参数
struct drm_gpuvm *gpuvm
struct drm_exec *exec
drm_exec
锁定上下文u64 addr
VA 空间内的起始地址
u64 range
要在 VA 空间中迭代的范围
unsigned int num_fences
要保留的
dma_fences
的数量
描述
为映射在 addr 和 addr + range 之间的所有 drm_gem_objects
调用 drm_exec_prepare_obj()
;如果 num_fences 为零,则改为调用 drm_exec_lock_obj()
。
返回
成功时为 0,失败时为负错误代码。
-
int drm_gpuvm_exec_lock(struct drm_gpuvm_exec *vm_exec)¶
锁定所有关联的 BO 的所有 dma-resv
参数
struct drm_gpuvm_exec *vm_exec
drm_gpuvm_exec
包装器
描述
获取给定 drm_gpuvm
包含的映射中所有 drm_gem_objects
的所有 dma-resv 锁。
此外,当使用设置了 struct drm_gpuvm_exec
::extra 的参数调用此函数时,驱动程序会接收到给定的 fn 回调,以便在 drm_gpuvm_exec
实例的上下文中锁定额外的 dma-resv。通常,驱动程序会在此回调中调用 drm_exec_prepare_obj()
。
返回
成功时为 0,失败时为负错误代码。
-
int drm_gpuvm_exec_lock_array(struct drm_gpuvm_exec *vm_exec, struct drm_gem_object **objs, unsigned int num_objs)¶
锁定所有关联的 BO 的所有 dma-resv
参数
struct drm_gpuvm_exec *vm_exec
drm_gpuvm_exec
包装器struct drm_gem_object **objs
要锁定的其他
drm_gem_objects
unsigned int num_objs
要锁定的其他
drm_gem_objects
的数量
描述
获取给定 drm_gpuvm
包含映射的所有 drm_gem_objects
的所有 dma-resv 锁,以及通过 objs 给出的锁。
返回
成功时为 0,失败时为负错误代码。
-
int drm_gpuvm_exec_lock_range(struct drm_gpuvm_exec *vm_exec, u64 addr, u64 range)¶
准备给定范围内的所有映射 BO
参数
struct drm_gpuvm_exec *vm_exec
drm_gpuvm_exec
包装器u64 addr
VA 空间内的起始地址
u64 range
要在 VA 空间中迭代的范围
描述
获取映射在 addr 和 addr + range 之间的所有 drm_gem_objects
的所有 dma-resv 锁。
返回
成功时为 0,失败时为负错误代码。
-
void drm_gpuvm_resv_add_fence(struct drm_gpuvm *gpuvm, struct drm_exec *exec, struct dma_fence *fence, enum dma_resv_usage private_usage, enum dma_resv_usage extobj_usage)¶
将 fence 添加到私有和所有 extobj dma-resv
参数
-
struct drm_gpuvm_bo *drm_gpuvm_bo_create(struct drm_gpuvm *gpuvm, struct drm_gem_object *obj)¶
创建
struct drm_gpuvm_bo
的新实例
参数
struct drm_gpuvm *gpuvm
obj 在其中映射的
drm_gpuvm
。struct drm_gem_object *obj
在 gpuvm 中映射的
drm_gem_object
。
描述
如果驱动程序提供了此函数,则此函数使用 drm_gpuvm_ops
vm_bo_alloc() 回调进行分配。
返回
成功时指向 drm_gpuvm_bo
的指针,失败时为 NULL
-
bool drm_gpuvm_bo_put(struct drm_gpuvm_bo *vm_bo)¶
删除
struct drm_gpuvm_bo
引用
参数
struct drm_gpuvm_bo *vm_bo
要释放其引用的
drm_gpuvm_bo
描述
这将释放对 vm_bo 的引用。
如果引用计数降至零,则销毁 gpuvm_bo
,其中包括将其从 GEM 的 gpuva 列表中删除。因此,如果对此函数的调用可能会使引用计数降至零,则调用方必须持有 dma-resv 或特定于驱动程序的 GEM gpuva 锁。
此函数只能从非原子上下文中调用。
返回
如果 vm_bo 被销毁,则为 true,否则为 false。
-
struct drm_gpuvm_bo *drm_gpuvm_bo_find(struct drm_gpuvm *gpuvm, struct drm_gem_object *obj)¶
查找给定
drm_gpuvm
和drm_gem_object
的drm_gpuvm_bo
参数
struct drm_gpuvm *gpuvm
obj 在其中映射的
drm_gpuvm
。struct drm_gem_object *obj
在 gpuvm 中映射的
drm_gem_object
。
描述
查找表示给定 drm_gpuvm
和 drm_gem_object
组合的 drm_gpuvm_bo
。如果找到,则相应地增加 drm_gpuvm_bo
的引用计数。
返回
成功时指向 drm_gpuvm_bo
的指针,失败时为 NULL
-
struct drm_gpuvm_bo *drm_gpuvm_bo_obtain(struct drm_gpuvm *gpuvm, struct drm_gem_object *obj)¶
获取给定
drm_gpuvm
和drm_gem_object
的drm_gpuvm_bo
实例。
参数
struct drm_gpuvm *gpuvm
obj 在其中映射的
drm_gpuvm
。struct drm_gem_object *obj
在 gpuvm 中映射的
drm_gem_object
。
描述
查找表示给定 drm_gpuvm
和 drm_gem_object
组合的 drm_gpuvm_bo
。如果找到,则相应地增加 drm_gpuvm_bo
的引用计数。如果未找到,则分配一个新的 drm_gpuvm_bo
。
一个新的 drm_gpuvm_bo
被添加到 GEM 的 gpuva 列表中。
返回
成功时返回指向 drm_gpuvm_bo
的指针,失败时返回 ERR_PTR。
-
struct drm_gpuvm_bo *drm_gpuvm_bo_obtain_prealloc(struct drm_gpuvm_bo *__vm_bo)¶
获取给定
drm_gpuvm
和drm_gem_object
的drm_gpuvm_bo
实例。
参数
struct drm_gpuvm_bo *__vm_bo
一个预先分配的
struct drm_gpuvm_bo
。
描述
查找表示给定 drm_gpuvm
和 drm_gem_object
组合的 drm_gpuvm_bo
。如果找到,则相应地增加找到的 drm_gpuvm_bo
的引用计数,同时减少 __vm_bo 的引用计数。如果未找到,则返回 __vm_bo,而无需进一步增加引用计数。
一个新的 drm_gpuvm_bo
被添加到 GEM 的 gpuva 列表中。
返回
如果未找到现有的 drm_gpuvm_bo
,则返回指向找到的 drm_gpuvm_bo
或 __vm_bo 的指针。
-
void drm_gpuvm_bo_extobj_add(struct drm_gpuvm_bo *vm_bo)¶
将
drm_gpuvm_bo
添加到其drm_gpuvm
的 extobj 列表中。
参数
struct drm_gpuvm_bo *vm_bo
要添加到其
drm_gpuvm
的 extobj 列表中的drm_gpuvm_bo
。
描述
如果给定的 vm_bo 尚未在列表中,并且对应的 drm_gem_object
实际上是一个外部对象,则将其添加到其 drm_gpuvm
的 extobj 列表中。
-
void drm_gpuvm_bo_evict(struct drm_gpuvm_bo *vm_bo, bool evict)¶
将
drm_gpuvm_bo
添加到drm_gpuvms
的驱逐列表中或从中删除。
参数
struct drm_gpuvm_bo *vm_bo
要添加或删除的
drm_gpuvm_bo
。bool evict
指示对象是否被驱逐。
描述
将 drm_gpuvm_bo
添加到 drm_gpuvms
的驱逐列表中或从中删除。
参数
描述
将具有给定地址和范围的 drm_gpuva
插入到 drm_gpuvm
中。
使用 GPU VA 空间的迭代安全版本(例如 drm_gpuvm_for_each_va_safe()
和 drm_gpuvm_for_each_va_range_safe()
)使用此函数是安全的。
返回
成功时为 0,失败时为负错误代码。
参数
struct drm_gpuva *va
要删除的
drm_gpuva
。
描述
这会从底层树中删除给定的 va
。
使用 GPU VA 空间的迭代安全版本(例如 drm_gpuvm_for_each_va_safe()
和 drm_gpuvm_for_each_va_range_safe()
)使用此函数是安全的。
-
void drm_gpuva_link(struct drm_gpuva *va, struct drm_gpuvm_bo *vm_bo)¶
链接一个
drm_gpuva
。
参数
struct drm_gpuva *va
要链接的
drm_gpuva
。struct drm_gpuvm_bo *vm_bo
要将
drm_gpuva
添加到的drm_gpuvm_bo
。
描述
这会将给定的 va
添加到 drm_gpuvm_bo
的 GPU VA 列表中,并将 drm_gpuvm_bo
添加到其关联的 drm_gem_object
中。
对于添加到 drm_gpuvm_bo
的每个 drm_gpuva
条目,后者的引用计数会额外增加。
此函数期望调用者使用 GEM 的 dma_resv 锁或通过 drm_gem_gpuva_set_lock()
设置的驱动程序特定锁来保护 GEM 的 GPUVA 列表免受并发访问。
参数
struct drm_gpuva *va
要取消链接的
drm_gpuva
。
描述
这将从与之关联的 drm_gem_object
的 GPU VA 列表中删除给定的 va
。
这将从 drm_gpuvm_bo
的 GPU VA 列表中删除给定的 va
,并且在本次调用取消链接 drm_gpuvm_bo
中最后一个 drm_gpuva
的情况下,也会从与之关联的 drm_gem_object
中删除 drm_gpuvm_bo
。
对于从 drm_gpuvm_bo
中删除的每个 drm_gpuva
条目,都会删除后者的一个引用。
此函数期望调用者使用 GEM 的 dma_resv 锁或通过 drm_gem_gpuva_set_lock()
设置的驱动程序特定锁来保护 GEM 的 GPUVA 列表免受并发访问。
-
struct drm_gpuva *drm_gpuva_find_first(struct drm_gpuvm *gpuvm, u64 addr, u64 range)¶
查找给定范围内的第一个
drm_gpuva
参数
struct drm_gpuvm *gpuvm
要搜索的
drm_gpuvm
u64 addr
drm_gpuvas
的地址u64 range
drm_gpuvas
的范围
返回
给定范围内的第一个 drm_gpuva
参数
struct drm_gpuvm *gpuvm
要搜索的
drm_gpuvm
u64 addr
drm_gpuvas
的地址u64 range
drm_gpuvas
的范围
返回
在给定 addr
且具有给定 range
的 drm_gpuva
参数
struct drm_gpuvm *gpuvm
要搜索的
drm_gpuvm
u64 start
给定 GPU VA 的起始地址
描述
查找具有给定 start
地址的 GPU VA 之前的相邻 drm_gpuva
。
请注意,如果 GPU VA 映射之间有任何可用空间,则不会返回任何映射。
返回
指向找到的 drm_gpuva
的指针,如果没有找到则为 NULL
参数
struct drm_gpuvm *gpuvm
要搜索的
drm_gpuvm
u64 end
给定 GPU VA 的结束地址
描述
查找具有给定 end
地址的 GPU VA 之后的相邻 drm_gpuva
。
请注意,如果 GPU VA 映射之间有任何可用空间,则不会返回任何映射。
返回
指向找到的 drm_gpuva
的指针,如果没有找到则为 NULL
参数
struct drm_gpuvm *gpuvm
要检查范围的
drm_gpuvm
u64 addr
范围的起始地址
u64 range
间隔的范围
返回
如果间隔为空则为 true,否则为 false
-
void drm_gpuva_map(struct drm_gpuvm *gpuvm, struct drm_gpuva *va, struct drm_gpuva_op_map *op)¶
根据
drm_gpuva_op_map
插入drm_gpuva
的助手
参数
struct drm_gpuvm *gpuvm
struct drm_gpuva *va
要插入的
drm_gpuva
。struct drm_gpuva_op_map *op
用于初始化 va 的
drm_gpuva_op_map
描述
从 op 初始化 va 并将其插入到给定的 gpuvm 中。
-
void drm_gpuva_remap(struct drm_gpuva *prev, struct drm_gpuva *next, struct drm_gpuva_op_remap *op)¶
根据
drm_gpuva_op_remap
重新映射drm_gpuva
的助手
参数
struct drm_gpuva *prev
在保持映射的起始位置时要重新映射的
drm_gpuva
struct drm_gpuva *next
在保持映射的结束位置时要重新映射的
drm_gpuva
struct drm_gpuva_op_remap *op
使用
drm_gpuva_op_remap
初始化 prev 和 next
描述
移除当前已映射的 drm_gpuva
,并使用 prev 和/或 next 重新映射它。
-
void drm_gpuva_unmap(struct drm_gpuva_op_unmap *op)¶
根据
drm_gpuva_op_unmap
移除drm_gpuva
的辅助函数
参数
struct drm_gpuva_op_unmap *op
指定要移除的
drm_gpuva
的drm_gpuva_op_unmap
描述
移除与 drm_gpuva_op_unmap
关联的 drm_gpuva
。
-
int drm_gpuvm_sm_map(struct drm_gpuvm *gpuvm, void *priv, u64 req_addr, u64 req_range, struct drm_gem_object *req_obj, u64 req_offset)¶
创建
drm_gpuva_op
分割/合并步骤
参数
struct drm_gpuvm *gpuvm
表示 GPU VA 空间的
drm_gpuvm
void *priv
指向驱动程序私有数据结构的指针
u64 req_addr
新映射的起始地址
u64 req_range
新映射的范围
struct drm_gem_object *req_obj
要映射的
drm_gem_object
u64 req_offset
drm_gem_object
中的偏移量
描述
此函数遍历 GPU VA 空间的给定范围。它利用 drm_gpuvm_ops
回调到驱动程序,提供分割和合并步骤。
驱动程序可以使用这些回调立即在回调中更新 GPU VA 空间。如果驱动程序决定复制并存储操作以供稍后处理,则在 drm_gpuvm
对 GPU VA 空间的视图使用上一组操作进行更新之前,不允许调用此函数或 drm_gpuvm_sm_unmap
。要更新 drm_gpuvm
的 GPU VA 空间视图,应使用 drm_gpuva_insert()
、drm_gpuva_destroy_locked() 和/或 drm_gpuva_destroy_unlocked()。
回调序列可以包含 map、unmap 和 remap 操作,但如果不需要操作,例如,如果请求的映射已经以完全相同的方式存在,则回调序列也可能为空。
可以有任意数量的 unmap 操作,最多两个 remap 操作和一个 map 操作。后者表示调用者请求的原始 map 操作。
返回
成功时返回 0 或负错误代码
-
int drm_gpuvm_sm_unmap(struct drm_gpuvm *gpuvm, void *priv, u64 req_addr, u64 req_range)¶
创建用于在 unmap 时分割的
drm_gpuva_ops
参数
struct drm_gpuvm *gpuvm
表示 GPU VA 空间的
drm_gpuvm
void *priv
指向驱动程序私有数据结构的指针
u64 req_addr
要取消映射的范围的起始地址
u64 req_range
要取消映射的映射范围
描述
此函数遍历 GPU VA 空间的给定范围。它利用 drm_gpuvm_ops
回调到驱动程序,提供用于取消映射的操作,并在需要时分割现有的映射。
驱动程序可以使用这些回调立即在回调中更新 GPU VA 空间。如果驱动程序决定复制并存储操作以供稍后处理,则在 drm_gpuvm
对 GPU VA 空间的视图使用上一组操作进行更新之前,不允许调用此函数或 drm_gpuvm_sm_map
。要更新 drm_gpuvm
的 GPU VA 空间视图,应使用 drm_gpuva_insert()
、drm_gpuva_destroy_locked() 和/或 drm_gpuva_destroy_unlocked()。
回调序列可以包含 unmap 和 remap 操作,具体取决于是否存在需要分割的实际重叠映射。
可以有任意数量的 unmap 操作,以及最多两个 remap 操作。
返回
成功时返回 0 或负错误代码
-
struct drm_gpuva_ops *drm_gpuvm_sm_map_ops_create(struct drm_gpuvm *gpuvm, u64 req_addr, u64 req_range, struct drm_gem_object *req_obj, u64 req_offset)¶
创建用于分割和合并的
drm_gpuva_ops
参数
struct drm_gpuvm *gpuvm
表示 GPU VA 空间的
drm_gpuvm
u64 req_addr
新映射的起始地址
u64 req_range
新映射的范围
struct drm_gem_object *req_obj
要映射的
drm_gem_object
u64 req_offset
drm_gem_object
中的偏移量
描述
此函数创建要执行的操作列表,以将现有映射与新请求的映射进行分割和合并。
可以使用 drm_gpuva_for_each_op
遍历列表,并且必须按给定的顺序处理列表。它可以包含 map、unmap 和 remap 操作,但如果不需要操作,例如,如果请求的映射已经以完全相同的方式存在,则它也可能为空。
可以有任意数量的 unmap 操作,最多两个 remap 操作和一个 map 操作。后者表示调用者请求的原始 map 操作。
请注意,在再次使用另一个映射请求调用此函数之前,必须更新 drm_gpuvm
对 GPU VA 空间的视图。先前获得的操作必须被处理或放弃。要更新 drm_gpuvm
的 GPU VA 空间视图,应使用 drm_gpuva_insert()
、drm_gpuva_destroy_locked() 和/或 drm_gpuva_destroy_unlocked()。
在调用者完成处理返回的 drm_gpuva_ops
后,必须使用 drm_gpuva_ops_free
释放它们。
返回
成功时返回指向 drm_gpuva_ops
的指针,失败时返回 ERR_PTR
-
struct drm_gpuva_ops *drm_gpuvm_sm_unmap_ops_create(struct drm_gpuvm *gpuvm, u64 req_addr, u64 req_range)¶
创建用于在 unmap 时分割的
drm_gpuva_ops
参数
struct drm_gpuvm *gpuvm
表示 GPU VA 空间的
drm_gpuvm
u64 req_addr
要取消映射的范围的起始地址
u64 req_range
要取消映射的映射范围
描述
此函数创建一个操作列表,用于执行取消映射,并且如果需要,还可以拆分与取消映射范围重叠的映射。
该列表可以使用 drm_gpuva_for_each_op
进行迭代,并且必须按给定的顺序进行处理。根据是否存在要拆分的实际重叠映射,它可以包含取消映射和重新映射操作。
可以有任意数量的 unmap 操作,以及最多两个 remap 操作。
请注意,在再次调用此函数并使用另一个取消映射的范围之前,必须更新 drm_gpuvm
的 GPU VA 空间视图。之前获得的操作必须被处理或放弃。要更新 drm_gpuvm
的 GPU VA 空间视图,应使用 drm_gpuva_insert()
、drm_gpuva_destroy_locked() 和/或 drm_gpuva_destroy_unlocked()。
在调用者完成处理返回的 drm_gpuva_ops
后,必须使用 drm_gpuva_ops_free
释放它们。
返回
成功时返回指向 drm_gpuva_ops
的指针,失败时返回 ERR_PTR
-
struct drm_gpuva_ops *drm_gpuvm_prefetch_ops_create(struct drm_gpuvm *gpuvm, u64 addr, u64 range)¶
创建要预取的
drm_gpuva_ops
参数
struct drm_gpuvm *gpuvm
表示 GPU VA 空间的
drm_gpuvm
u64 addr
要预取的范围的起始地址
u64 range
要预取的映射的范围
描述
此函数创建一个操作列表,用于执行预取。
该列表可以使用 drm_gpuva_for_each_op
进行迭代,并且必须按给定的顺序进行处理。它可以包含预取操作。
可以有任意数量的预取操作。
在调用者完成处理返回的 drm_gpuva_ops
后,必须使用 drm_gpuva_ops_free
释放它们。
返回
成功时返回指向 drm_gpuva_ops
的指针,失败时返回 ERR_PTR
-
struct drm_gpuva_ops *drm_gpuvm_bo_unmap_ops_create(struct drm_gpuvm_bo *vm_bo)¶
创建用于取消映射 GEM 的
drm_gpuva_ops
参数
struct drm_gpuvm_bo *vm_bo
drm_gpuvm_bo
抽象
描述
此函数创建一个操作列表,用于执行与 GEM 关联的每个 GPUVA 的取消映射。
该列表可以使用 drm_gpuva_for_each_op
进行迭代,并且包含任意数量的取消映射操作。
在调用者完成处理返回的 drm_gpuva_ops
后,必须使用 drm_gpuva_ops_free
释放它们。
调用者有责任使用 GEM 的 dma_resv 锁来保护 GEM 的 GPUVA 列表免受并发访问。
返回
成功时返回指向 drm_gpuva_ops
的指针,失败时返回 ERR_PTR
-
void drm_gpuva_ops_free(struct drm_gpuvm *gpuvm, struct drm_gpuva_ops *ops)¶
释放给定的
drm_gpuva_ops
参数
struct drm_gpuvm *gpuvm
创建 ops 的
drm_gpuvm
struct drm_gpuva_ops *ops
要释放的
drm_gpuva_ops
描述
释放给定的 drm_gpuva_ops
结构,包括与之关联的所有操作。
DRM Buddy 分配器¶
DRM Buddy 函数参考¶
-
int drm_buddy_init(struct drm_buddy *mm, u64 size, u64 chunk_size)¶
初始化内存管理器
参数
struct drm_buddy *mm
要初始化的 DRM buddy 管理器
u64 size
要管理的字节大小
u64 chunk_size
我们分配的最小页面大小(以字节为单位)
描述
初始化内存管理器及其资源。
返回
成功返回 0,失败返回错误代码。
-
void drm_buddy_fini(struct drm_buddy *mm)¶
关闭内存管理器
参数
struct drm_buddy *mm
要释放的 DRM buddy 管理器
描述
清理内存管理器资源和空闲列表
-
struct drm_buddy_block *drm_get_buddy(struct drm_buddy_block *block)¶
获取伙伴地址
参数
struct drm_buddy_block *block
DRM buddy 块
描述
返回 block 的相应伙伴块,如果这是一个根块并且不能进一步合并,则返回 NULL。需要某种类型的锁定来防止任何并发的分配和释放操作。
-
void drm_buddy_free_block(struct drm_buddy *mm, struct drm_buddy_block *block)¶
释放一个块
参数
struct drm_buddy *mm
DRM buddy 管理器
struct drm_buddy_block *block
要释放的块
-
void drm_buddy_free_list(struct drm_buddy *mm, struct list_head *objects, unsigned int flags)¶
释放块
参数
struct drm_buddy *mm
DRM buddy 管理器
struct list_head *objects
要释放块的输入列表头
unsigned int flags
可选标志,如 DRM_BUDDY_CLEARED
-
int drm_buddy_block_trim(struct drm_buddy *mm, u64 *start, u64 new_size, struct list_head *blocks)¶
释放未使用的页面
参数
struct drm_buddy *mm
DRM buddy 管理器
u64 *start
开始修剪的起始地址。
u64 new_size
原始请求的大小
struct list_head *blocks
已分配块的输入和输出列表。必须包含单个块作为要修剪的输入。成功后,将包含构成 new_size 的新分配的块。块始终按升序排列
描述
对于连续分配,我们会将大小向上取整到最接近的 2 的幂的值,驱动程序会消耗实际大小,因此剩余部分未使用,可以使用此函数选择性地释放。
返回
成功返回 0,失败返回错误代码。
-
int drm_buddy_alloc_blocks(struct drm_buddy *mm, u64 start, u64 end, u64 size, u64 min_block_size, struct list_head *blocks, unsigned long flags)¶
分配 2 的幂的块
参数
struct drm_buddy *mm
用于分配的 DRM 伙伴管理器
u64 start
此块的允许范围的起始位置
u64 end
此块的允许范围的结束位置
u64 size
以字节为单位的分配大小
u64 min_block_size
分配的对齐方式
struct list_head *blocks
添加分配块的输出列表头
unsigned long flags
DRM_BUDDY_*_ALLOCATION 标志
描述
在范围限制上调用 alloc_range_bias(),它会遍历树并返回所需的块。
当没有强制执行范围限制时调用 alloc_from_freelist(),它会从空闲列表中选择块。
返回
成功返回 0,失败返回错误代码。
-
void drm_buddy_block_print(struct drm_buddy *mm, struct drm_buddy_block *block, struct drm_printer *p)¶
打印块信息
参数
struct drm_buddy *mm
DRM buddy 管理器
struct drm_buddy_block *block
DRM buddy 块
struct drm_printer *p
要使用的 DRM 打印机
-
void drm_buddy_print(struct drm_buddy *mm, struct drm_printer *p)¶
打印分配器状态
参数
struct drm_buddy *mm
DRM buddy 管理器
struct drm_printer *p
要使用的 DRM 打印机
DRM 缓存处理和快速 WC memcpy() ¶
-
void drm_clflush_pages(struct page *pages[], unsigned long num_pages)¶
刷新一组页面的数据缓存行。
参数
struct page *pages[]
要刷新的页面列表。
unsigned long num_pages
数组中的页数。
描述
刷新指向数组中页面的地址的每个数据缓存行条目。
-
void drm_clflush_sg(struct sg_table *st)¶
刷新指向散布聚集的数据缓存行。
参数
struct sg_table *st
struct sg_table。
描述
刷新指向 sg 中地址的每个数据缓存行条目。
-
void drm_clflush_virt_range(void *addr, unsigned long length)¶
刷新区域的数据缓存行
参数
void *addr
初始内核内存地址。
unsigned long length
区域大小。
描述
刷新指向所请求区域中的地址的每个数据缓存行条目。
-
void drm_memcpy_from_wc(struct iosys_map *dst, const struct iosys_map *src, unsigned long len)¶
从可能是 WC 的源执行最快的可用 memcpy。
参数
struct iosys_map *dst
目标指针
const struct iosys_map *src
源指针
unsigned long len
要传输的区域的大小(以字节为单位)
描述
尝试使用 arch 优化的 memcpy,用于从 WC 区域进行预取读取,如果没有此类可用,则回退到正常的 memcpy。
DRM 同步对象 ¶
DRM 同步对象(syncobj,请参阅结构体 drm_syncobj
)为同步原语提供一个容器,用户空间可以使用它来显式同步 GPU 命令,可以在用户空间进程之间共享,并且可以在不同的 DRM 驱动程序之间共享。它们的主要用例是实现 Vulkan 栅栏和信号量。syncobj 用户空间 API 提供了几个操作的 ioctl:
创建和销毁同步对象
将同步对象导入/导出到/从同步对象文件描述符
将同步对象的底层栅栏导入/导出到/从同步文件
重置同步对象(将其栅栏设置为 NULL)
发送信号给同步对象(设置一个轻易发送信号的栅栏)
等待同步对象的栅栏出现并发送信号
syncobj 用户空间 API 还提供了用于操作同步对象的操作,其操作是根据 dma_fence_chain
结构体的时间线而不是单个 dma_fence
结构体,通过以下操作:
发送时间线上给定点的信号
等待给定点出现和/或发送信号
从/到时间线的给定点导入和导出
其核心是一个同步对象,它只是一个指向 dma_fence
结构体的指针的包装器,该指针可能为 NULL。当首次创建同步对象时,其指针要么为 NULL,要么是指向已发送信号的栅栏的指针,具体取决于是否将 DRM_SYNCOBJ_CREATE_SIGNALED
标志传递给 DRM_IOCTL_SYNCOBJ_CREATE
。
如果同步对象被视为二进制原语(其状态为已发送信号或未发送信号),则当 DRM 驱动程序中入队 GPU 工作以发送同步对象信号时,同步对象的栅栏将替换为将通过该工作完成发送信号的栅栏。如果将同步对象视为时间线原语,则当 DRM 驱动程序中入队 GPU 工作以发送同步对象的给定点的信号时,将创建一个新的 dma_fence_chain
结构体,该结构体指向 DRM 驱动程序的栅栏,并且还指向同步对象中之前的栅栏。新的 dma_fence_chain
栅栏将替换同步对象的栅栏,并且将通过 DRM 驱动程序的工作完成和与之前在同步对象中的栅栏关联的任何工作来发送信号。
当在 DRM 驱动程序中入队等待同步对象的 GPU 工作时,在入队工作时,它会在将工作提交到硬件之前等待同步对象的栅栏。该栅栏为:
如果将同步对象视为二进制原语,则为同步对象的当前栅栏。
如果将同步对象视为时间线原语,则为与给定点关联的
dma_fence
结构体。
如果同步对象的栅栏为 NULL 或不存在于同步对象的时间线中,则入队操作应失败。
使用二进制同步对象,所有对同步对象的栅栏的操作都是根据用户空间调用 ioctl 时的当前栅栏进行的,无论该操作是立即主机端操作(发送信号或重置)还是在某些驱动程序队列中入队的操作。DRM_IOCTL_SYNCOBJ_RESET
和 DRM_IOCTL_SYNCOBJ_SIGNAL
可用于通过将指针重置为 NULL 或将其指针设置为已发送信号的栅栏来从主机操作同步对象。
对于时间线同步对象,对同步对象的 fence 的所有操作都以引用时间线上点的 u64 值进行。请参阅 dma_fence_chain_find_seqno()
,了解如何在时间线中找到给定的点。
请注意,当处理被视为时间线的同步对象时,应用程序应始终小心使用时间线 ioctl() 集。对被视为时间线的同步对象使用二进制 ioctl() 集可能会导致不正确的同步。通过使用点值为 0 的时间线 ioctl() 集支持使用二进制同步对象,这将重现二进制 ioctl() 集的行为(例如,在发出信号时替换同步对象的 fence)。
主机端等待同步对象¶
DRM_IOCTL_SYNCOBJ_WAIT
接受一个同步对象句柄数组,并在所有同步对象 fence 上同时执行主机端等待。如果设置了 DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL
,则等待 ioctl 将等待所有同步对象 fence 都发出信号后才返回。否则,它将在至少一个同步对象 fence 发出信号后返回,并将发出信号的 fence 的索引写回客户端。
与在同步对象中看到 NULL fence 时会失败的排队 GPU 工作依赖项不同,如果设置了 DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT
,则主机端等待将首先等待同步对象接收非 NULL fence,然后等待该 fence。如果未设置 DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT
,并且数组中的任何一个同步对象具有 NULL fence,则将返回 -EINVAL。假设同步对象以 NULL fence 开始,这允许客户端在一个线程(或进程)中执行主机等待,该线程(或进程)等待在另一个线程(或进程)中提交的 GPU 工作,而无需在两者之间手动同步。此要求继承自 Vulkan fence API。
如果设置了 DRM_SYNCOBJ_WAIT_FLAGS_WAIT_DEADLINE
,则 ioctl 还将在等待之前在后备 fence 上设置一个 fence 截止日期提示,以便为 fence 发送者提供适当的紧迫感。截止日期在纳秒单位中指定为绝对 CLOCK_MONOTONIC
值。
类似地,DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT
接受一个同步对象句柄数组以及一个 u64 点数组,并在所有同步对象 fence 的给定点上同时执行主机端等待。
DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT
还增加了等待给定 fence 在时间线上实体化而不等待 fence 发出信号的能力,方法是使用 DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE
标志。此要求继承自 Vulkan 时间线信号量 API 所需的等待后发送信号行为。
或者,可以使用 DRM_IOCTL_SYNCOBJ_EVENTFD
在不阻塞的情况下等待:当同步对象发出信号时,将发出一个 eventfd 信号。这有助于将等待集成到事件循环中。
同步对象的导入/导出¶
DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE
和 DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD
提供了两种导入/导出同步对象的机制。
第一种机制允许客户端将整个同步对象导入或导出到文件描述符。这些 fd 是不透明的,除了在进程之间传递同步对象外,没有其他用例。所有导出的文件描述符以及通过导入这些文件描述符而创建的任何同步对象句柄都拥有对同一个底层结构 drm_syncobj
的引用,并且同步对象可以在与其共享的所有进程中持久使用。只有在最后一个引用被删除后,同步对象才会被释放。与 dma-buf 不同,导入同步对象会为每次导入创建一个新的句柄(及其自身的引用),而不是重复数据删除。这种持久导入/导出的主要用例是共享 Vulkan fence 和信号量。
第二种导入/导出机制,由 DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE
或 DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE
指示,允许客户端从/向 sync_file
导入/导出同步对象的当前 fence。当同步对象导出到 sync 文件时,该 sync 文件会包装导出时同步对象的 fence,并且对同步对象的任何后续信号或重置操作都不会影响导出的 sync 文件。当 sync 文件导入到同步对象时,同步对象的 fence 将设置为该 sync 文件包装的 fence。由于 sync 文件是不可变的,因此重置或发出同步对象信号不会影响任何已将 fence 导入到同步对象的 sync 文件。
时间线同步对象中时间线点的导入/导出¶
DRM_IOCTL_SYNCOBJ_TRANSFER
提供了一种机制,用于将给定 u64 点的同步对象的结构 dma_fence_chain
传输到另一个同步对象中的另一个 u64 点。
请注意,如果要将结构 dma_fence_chain
从时间线同步对象上的给定点传输到/从二进制同步对象传输,则可以使用点 0 表示获取/替换同步对象中的 fence。
-
struct drm_syncobj¶
同步对象。
定义:
struct drm_syncobj {
struct kref refcount;
struct dma_fence __rcu *fence;
struct list_head cb_list;
struct list_head ev_fd_list;
spinlock_t lock;
struct file *file;
};
成员
refcount
此对象的引用计数。
fence
NULL 或指向绑定到此对象的 fence 的指针。
此字段不应直接使用。请改用
drm_syncobj_fence_get()
和drm_syncobj_replace_fence()
。cb_list
当
fence
被替换时要调用的回调列表。ev_fd_list
注册的 eventfd 列表。
锁
保护
cb_list
和ev_fd_list
,并写锁定fence
。file
此同步对象的后备文件。
描述
此结构定义了一个通用同步对象,它包装了一个 dma_fence
。
-
void drm_syncobj_get(struct drm_syncobj *obj)¶
获取同步对象引用
参数
struct drm_syncobj *obj
同步对象
描述
这会获取对 obj 的额外引用。在没有已经持有引用的情况下调用此函数是非法的。无需锁定。
-
void drm_syncobj_put(struct drm_syncobj *obj)¶
释放对同步对象的引用。
参数
struct drm_syncobj *obj
同步对象。
-
struct dma_fence *drm_syncobj_fence_get(struct drm_syncobj *syncobj)¶
获取对同步对象中 fence 的引用
参数
struct drm_syncobj *syncobj
同步对象。
描述
如果不是 NULL,则会获取对 obj 中包含的 drm_syncobj.fence
的额外引用。在没有已经持有引用的情况下调用此函数是非法的。无需锁定。
返回
obj 的 fence,如果没有,则为 NULL。
-
struct drm_syncobj *drm_syncobj_find(struct drm_file *file_private, u32 handle)¶
查找并引用同步对象。
参数
struct drm_file *file_private
drm 文件私有指针
u32 handle
要查找的同步对象句柄。
描述
返回指向句柄所指向的同步对象的引用,或 NULL。必须通过调用 drm_syncobj_put()
来释放引用。
-
void drm_syncobj_add_point(struct drm_syncobj *syncobj, struct dma_fence_chain *chain, struct dma_fence *fence, uint64_t point)¶
向 syncobj 添加新的时间线点
参数
struct drm_syncobj *syncobj
要添加时间线点的同步对象
struct dma_fence_chain *chain
用于添加点的链节点
struct dma_fence *fence
要封装在链节点中的 fence
uint64_t point
该点使用的序列号
描述
将链节点作为新的时间线点添加到 syncobj。
-
void drm_syncobj_replace_fence(struct drm_syncobj *syncobj, struct dma_fence *fence)¶
替换同步对象中的 fence。
参数
struct drm_syncobj *syncobj
要替换 fence 的同步对象
struct dma_fence *fence
要安装在同步文件中的 fence。
描述
这将替换同步对象上的 fence。
-
int drm_syncobj_find_fence(struct drm_file *file_private, u32 handle, u64 point, u64 flags, struct dma_fence **fence)¶
查找并引用同步对象中的 fence
参数
struct drm_file *file_private
drm 文件私有指针
u32 handle
要查找的同步对象句柄。
u64 point
时间线点
u64 flags
DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT 或不等待
struct dma_fence **fence
fence 的输出参数
描述
这只是一个方便的函数,它结合了 drm_syncobj_find()
和 drm_syncobj_fence_get()
。
成功时返回 0,失败时返回负错误值。成功时,fence 包含对 fence 的引用,必须通过调用 dma_fence_put()
来释放。
参数
struct kref *kref
要释放的 kref。
描述
只能从 drm_syncobj_put 中的 kref_put 调用。
-
int drm_syncobj_create(struct drm_syncobj **out_syncobj, uint32_t flags, struct dma_fence *fence)¶
创建一个新的 syncobj
参数
struct drm_syncobj **out_syncobj
返回的 syncobj
uint32_t flags
DRM_SYNCOBJ_* 标志
struct dma_fence *fence
如果非 NULL,则 syncobj 将表示此 fence
描述
这是创建同步对象的第一个函数。创建后,驱动程序可能希望通过 drm_syncobj_get_handle()
或 drm_syncobj_get_fd()
使其对用户空间可用。
成功时返回 0,失败时返回负错误值。
-
int drm_syncobj_get_handle(struct drm_file *file_private, struct drm_syncobj *syncobj, u32 *handle)¶
从 syncobj 获取句柄
参数
struct drm_file *file_private
drm 文件私有指针
struct drm_syncobj *syncobj
要导出的同步对象
u32 *handle
带有新句柄的输出参数
描述
将使用 drm_syncobj_create()
创建的同步对象作为 file_private 上的句柄导出到用户空间。
成功时返回 0,失败时返回负错误值。
-
int drm_syncobj_get_fd(struct drm_syncobj *syncobj, int *p_fd)¶
从 syncobj 获取文件描述符
参数
struct drm_syncobj *syncobj
要导出的同步对象
int *p_fd
带有新文件描述符的输出参数
描述
将使用 drm_syncobj_create()
创建的同步对象作为文件描述符导出。
成功时返回 0,失败时返回负错误值。
-
signed long drm_timeout_abs_to_jiffies(int64_t timeout_nsec)¶
从绝对值计算 jiffies 超时
参数
int64_t timeout_nsec
以纳秒为单位的超时纳秒分量,轮询时为 0
描述
从秒/纳秒的绝对时间计算 jiffies 的超时时间。
DRM 执行上下文¶
此组件主要抽象了在准备硬件操作(例如,命令提交、页表更新等)时锁定多个 GEM 对象所必需的重试循环。
如果在锁定 GEM 对象时检测到争用,则清理过程会解锁所有先前锁定的 GEM 对象,并首先锁定争用的对象,然后再锁定任何其他对象。
在锁定对象后,可以选择在 GEM 对象内的 dma_resv 对象上保留 fence 插槽。
典型的用法模式应如下所示
struct drm_gem_object *obj;
struct drm_exec exec;
unsigned long index;
int ret;
drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT);
drm_exec_until_all_locked(&exec) {
ret = drm_exec_prepare_obj(&exec, boA, 1);
drm_exec_retry_on_contention(&exec);
if (ret)
goto error;
ret = drm_exec_prepare_obj(&exec, boB, 1);
drm_exec_retry_on_contention(&exec);
if (ret)
goto error;
}
drm_exec_for_each_locked_object(&exec, index, obj) {
dma_resv_add_fence(obj->resv, fence, DMA_RESV_USAGE_READ);
...
}
drm_exec_fini(&exec);
有关更多详细信息,请参见 struct dma_exec。
-
struct drm_exec¶
执行上下文
定义:
struct drm_exec {
u32 flags;
struct ww_acquire_ctx ticket;
unsigned int num_objects;
unsigned int max_objects;
struct drm_gem_object **objects;
struct drm_gem_object *contended;
struct drm_gem_object *prelocked;
};
成员
flags
控制锁定行为的标志
票证
用于获取锁定的 WW 票证
num_objects
锁定的对象数
max_objects
数组中的最大对象数
objects
锁定的对象数组
contended
我们为之退出的争用的 GEM 对象
prelocked
由于争用而预先锁定的 GEM 对象
-
struct drm_gem_object *drm_exec_obj(struct drm_exec *exec, unsigned long index)¶
返回给定 drm_exec 索引的对象
参数
struct drm_exec *exec
指向 drm_exec 上下文的指针
unsigned long index
索引。
返回
如果索引在已锁定对象的数量范围内,则指向与 index 对应的已锁定对象的指针。否则为 NULL。
-
drm_exec_for_each_locked_object¶
drm_exec_for_each_locked_object (exec, index, obj)
遍历所有已锁定的对象
参数
exec
drm_exec 对象
索引
用于迭代的 unsigned long 索引
obj
当前的 GEM 对象
描述
遍历 drm_exec 对象内的所有已锁定 GEM 对象。
-
drm_exec_for_each_locked_object_reverse¶
drm_exec_for_each_locked_object_reverse (exec, index, obj)
按反向锁定顺序遍历所有已锁定的对象
参数
exec
drm_exec 对象
索引
用于迭代的 unsigned long 索引
obj
当前的 GEM 对象
描述
按反向锁定顺序遍历 drm_exec 对象内的所有已锁定 GEM 对象。请注意,index 可能会低于零并回绕,但这将被 drm_exec_obj()
捕获,从而返回一个 NULL 对象。
-
drm_exec_until_all_locked¶
drm_exec_until_all_locked (exec)
循环直到所有 GEM 对象都被锁定
参数
exec
drm_exec 对象
描述
drm_exec 对象的的核心功能。循环直到所有 GEM 对象都被锁定并且不存在更多争用。在循环开始时,保证没有 GEM 对象被锁定。
由于标签不能在循环体本地定义,我们使用跳转指针来确保重试仅在循环体内使用。
-
drm_exec_retry_on_contention¶
drm_exec_retry_on_contention (exec)
重新启动循环以获取所有锁
参数
exec
drm_exec 对象
描述
当检测到争用,并且我们需要清理并重新启动循环以准备所有 GEM 对象时,控制流助手用于继续。
参数
struct drm_exec *exec
drm_exec 对象
描述
如果 drm_exec 对象在锁定 GEM 对象时遇到一些争用并且需要清理,则返回 true。
参数
struct drm_exec *exec
要初始化的 drm_exec 对象
u32 flags
控制锁定行为,请参阅 DRM_EXEC_* 定义
unsigned nr
初始对象数量
描述
初始化对象并确保我们可以跟踪已锁定的对象。
如果 nr 非零,则将其用作初始对象表大小。无论哪种情况,表都将按需增长(重新分配)。
参数
struct drm_exec *exec
要完成的 drm_exec 对象
描述
解锁所有已锁定的对象,删除对对象的引用,并释放用于跟踪状态的所有内存。
参数
struct drm_exec *exec
要清理的 drm_exec 对象
描述
清理当前状态,如果应该停留在重试循环中则返回 true,如果未检测到任何争用并且可以保持对象锁定,则返回 false。
-
int drm_exec_lock_obj(struct drm_exec *exec, struct drm_gem_object *obj)¶
锁定 GEM 对象以供使用
参数
struct drm_exec *exec
具有状态的 drm_exec 对象
struct drm_gem_object *obj
要锁定的 GEM 对象
描述
锁定 GEM 对象以供使用并获取对其的引用。
返回
如果检测到争用则返回 -EDEADLK,如果对象已被锁定则返回 -EALREADY(可以通过设置 DRM_EXEC_IGNORE_DUPLICATES 标志来禁止),如果内存分配失败则返回 -ENOMEM,成功则返回零。
-
void drm_exec_unlock_obj(struct drm_exec *exec, struct drm_gem_object *obj)¶
在此执行上下文中解锁 GEM 对象
参数
struct drm_exec *exec
具有状态的 drm_exec 对象
struct drm_gem_object *obj
要解锁的 GEM 对象
描述
解锁 GEM 对象并将其从已锁定对象的集合中删除。应仅用于解锁最近锁定的对象。解锁很久以前锁定的对象效率不高。
-
int drm_exec_prepare_obj(struct drm_exec *exec, struct drm_gem_object *obj, unsigned int num_fences)¶
准备 GEM 对象以供使用
参数
struct drm_exec *exec
具有状态的 drm_exec 对象
struct drm_gem_object *obj
要准备的 GEM 对象
unsigned int num_fences
要保留的栅栏数量
描述
通过锁定并保留栅栏槽来准备 GEM 对象以供使用。
返回
如果检测到争用则返回 -EDEADLK,如果对象已被锁定则返回 -EALREADY,如果内存分配失败则返回 -ENOMEM,成功则返回零。
-
int drm_exec_prepare_array(struct drm_exec *exec, struct drm_gem_object **objects, unsigned int num_objects, unsigned int num_fences)¶
用于准备对象数组的助手
参数
struct drm_exec *exec
具有状态的 drm_exec 对象
struct drm_gem_object **objects
要准备的 GEM 对象数组
unsigned int num_objects
数组中 GEM 对象的数量
unsigned int num_fences
要在每个 GEM 对象上保留的栅栏数量
描述
准备数组中的所有 GEM 对象,在第一个错误时中止。锁定每个 GEM 对象后,在其上保留 num_fences 个栅栏。
返回
争用时返回 -EDEADLOCK,如果对象已被锁定则返回 -EALREADY,如果内存分配失败则返回 -ENOMEM,成功则返回零。
GPU 调度器¶
概述¶
GPU 调度器提供实体,允许用户空间将作业推送到软件队列中,然后这些作业在硬件运行队列上进行调度。软件队列之间具有优先级。调度器使用 FIFO 从运行队列中选择实体。调度器提供作业之间的依赖关系处理功能。驱动程序应该为调度器的后端操作提供回调函数,例如将作业提交到硬件运行队列、返回作业的依赖关系等。
调度器的组织如下
每个硬件运行队列都有一个调度器
每个调度器都有多个具有不同优先级的运行队列(例如,HIGH_HW、HIGH_SW、KERNEL、NORMAL)
每个调度器运行队列都有一个要调度的实体队列
实体本身维护一个将在硬件上调度的作业队列。
实体中的作业始终按照它们被推送的顺序进行调度。
请注意,一旦作业从实体队列中取出并推送到硬件(即,挂起队列),则不得再通过作业实体指针引用该实体。
流控制¶
DRM GPU 调度器提供了一种流控制机制,用于调节从调度器实体获取的作业的执行速率。
在此上下文中,drm_gpu_scheduler
跟踪驱动程序指定的信用额度,该信用额度表示此调度器的容量,以及一个信用计数;每个 drm_sched_job
携带驱动程序指定的信用数量。
一旦作业被执行(但尚未完成),作业的信用额度将计入调度器的信用计数,直到作业完成。如果通过执行另一个作业,调度器的信用计数将超过调度器的信用额度,则该作业将不会被执行。相反,调度器将等待信用计数减少到足以不超出其信用额度的程度。这意味着需要等待先前执行的作业。
可选地,驱动程序可以注册一个回调函数(update_job_credits),该函数由 struct drm_sched_backend_ops
提供,以动态更新作业的信用额度。调度器每次考虑执行作业时都会执行此回调函数,并随后检查作业是否符合调度器的信用额度限制。
调度器函数引用¶
-
DRM_SCHED_FENCE_DONT_PIPELINE¶
DRM_SCHED_FENCE_DONT_PIPELINE
防止依赖流水线
描述
在调度器栅栏上设置此标志可防止依赖此栅栏的作业进行流水线处理。换句话说,在将依赖作业推送到硬件队列之前,我们始终会插入一个完整的 CPU 往返。
-
DRM_SCHED_FENCE_FLAG_HAS_DEADLINE_BIT¶
DRM_SCHED_FENCE_FLAG_HAS_DEADLINE_BIT
已设置栅栏截止时间提示
描述
因为我们可以在创建后备硬件栅栏之前设置截止时间提示,所以我们需要跟踪是否已设置截止时间。
-
struct drm_sched_entity¶
作业队列的包装器(通常附加到 DRM file_priv)。
定义:
struct drm_sched_entity {
struct list_head list;
spinlock_t lock;
struct drm_sched_rq *rq;
struct drm_gpu_scheduler **sched_list;
unsigned int num_sched_list;
enum drm_sched_priority priority;
struct spsc_queue job_queue;
atomic_t fence_seq;
uint64_t fence_context;
struct dma_fence *dependency;
struct dma_fence_cb cb;
atomic_t *guilty;
struct dma_fence __rcu *last_scheduled;
struct task_struct *last_user;
bool stopped;
struct completion entity_idle;
ktime_t oldest_job_waiting;
struct rb_node rb_tree_node;
};
成员
list
用于将此结构附加到
drm_sched_rq.entities
下的运行队列 rq 中的实体列表。受 rq 的
drm_sched_rq.lock
保护。锁
保护此实体所属的运行队列 (rq)、priority 和调度器列表(sched_list,num_sched_list)的锁。
rq
此实体当前被调度的运行队列。
FIXME:此锁的锁定非常不明确。写入器受 lock 保护,但读取器通常是无锁的,并且似乎只是在没有 READ_ONCE 的情况下竞争。
sched_list
调度器列表(
struct drm_gpu_scheduler
)。此实体中的作业可以调度到此列表中的任何调度器上。可以通过调用
drm_sched_entity_modify_sched()
来修改此项。锁定完全由驱动程序决定,有关详细信息,请参阅上面的函数。如果
num_sched_list
等于 1 且已设置 rq,则此项将设置为 NULL。FIXME:这意味着在这种情况下,通过
drm_sched_entity_set_priority()
更改的优先级将丢失。num_sched_list
sched_list 中的 drm_gpu_scheduler 的数量。
priority
实体的优先级。可以通过调用
drm_sched_entity_set_priority()
来修改此项。受 lock 保护。job_queue
此实体的作业列表。
fence_seq
一个线性递增的序列号,每个属于实体的新的
drm_sched_fence
都会递增。FIXME:
drm_sched_job_arm()
的调用者需要确保正确的锁定,这不需要是原子操作。fence_context
属于此实体的所有栅栏的唯一上下文。
drm_sched_fence.scheduled
使用 fence_context,但drm_sched_fence.finished
使用 fence_context + 1。dependency
作业队列顶部的作业的依赖栅栏。
cb
上述依赖栅栏的回调。
guilty
指向实体的 guilty。
last_scheduled
指向上次调度的作业的已完成栅栏。仅由调度器线程写入,如果队列为空,则可以从
drm_sched_job_arm()
无锁访问。last_user
最后一个将作业推送到实体的组领导者。
stopped
将实体标记为从 rq 中删除并注定要终止。这是通过调用
drm_sched_entity_flush()
和drm_sched_fini()
设置的。entity_idle
当实体未使用时发出信号,用于在
drm_sched_entity_fini()
中按顺序进行实体清理。oldest_job_waiting
标记在软件队列中等待的最早作业
rb_tree_node
用于将此实体插入基于时间的优先级队列的节点
描述
实体将按照其对应的硬件环的顺序发出作业,并且调度器将根据调度策略在实体之间交替。
-
struct drm_sched_rq¶
要调度的实体队列。
定义:
struct drm_sched_rq {
struct drm_gpu_scheduler *sched;
spinlock_t lock;
struct drm_sched_entity *current_entity;
struct list_head entities;
struct rb_root_cached rb_tree_root;
};
成员
sched
此 rq 所属的调度器。
锁
保护 entities、rb_tree_root 和 current_entity。
current_entity
要调度的实体。
entities
要调度的实体列表。
rb_tree_root
基于时间的 FIFO 调度实体优先级队列的根
描述
运行队列是一组实体,用于调度一个特定环的命令提交。它实现了调度策略,该策略选择要从中发出命令的下一个实体。
-
struct drm_sched_fence¶
与作业调度对应的栅栏。
定义:
struct drm_sched_fence {
struct dma_fence scheduled;
struct dma_fence finished;
ktime_t deadline;
struct dma_fence *parent;
struct drm_gpu_scheduler *sched;
spinlock_t lock;
void *owner;
};
成员
scheduled
此栅栏将在作业被调度时由调度器发出信号。
finished
此栅栏将在作业完成时由调度器发出信号。
在为作业设置输出栅栏时,应使用此栅栏,因为它在
drm_sched_job_init()
中立即可用,并且驱动程序从 run_job() 返回的栅栏将在依赖关系解决之前不会创建。deadline
在
drm_sched_fence.finished
上设置的截止时间,可能需要传播到drm_sched_fence.parent
parent
在硬件上调度作业时,由
drm_sched_backend_ops.run_job
返回的栅栏。一旦父级发出信号,我们将发出drm_sched_fence.finished
栅栏信号。sched
作业所属的调度器实例,该实例具有此结构。
锁
计划栅栏和已完成栅栏使用的锁。
owner
用于调试的作业所有者
-
struct drm_sched_job¶
要由实体运行的作业。
定义:
struct drm_sched_job {
struct spsc_node queue_node;
struct list_head list;
struct drm_gpu_scheduler *sched;
struct drm_sched_fence *s_fence;
u32 credits;
union {
struct dma_fence_cb finish_cb;
struct work_struct work;
};
uint64_t id;
atomic_t karma;
enum drm_sched_priority s_priority;
struct drm_sched_entity *entity;
struct dma_fence_cb cb;
struct xarray dependencies;
unsigned long last_dependency;
ktime_t submit_ts;
};
成员
queue_node
用于将此结构附加到实体中的作业队列。
list
作业参与“pending”和“done”列表。
sched
此作业正在或将要调度的调度器。由
drm_sched_job_arm()
设置。在 drm_sched_backend_ops.free_job() 完成之前有效。s_fence
包含作业调度的栅栏。
credits
此作业贡献给调度器的信用额度数量
{unnamed_union}
匿名
finish_cb
已完成栅栏的回调。
work
帮助将作业终止重新调度到不同的上下文。
id
分配给调度器上调度的每个作业的唯一 ID。
karma
每次由该作业引起的挂起都会增加。如果此值超过调度器的挂起限制,则该作业将被标记为 guilty,并且不会进一步调度。
s_priority
作业的优先级。
entity
此作业所属的实体。
cb
s_fence 中父栅栏的回调。
dependencies
包含此作业的依赖项,形式为
struct dma_fence
,请参阅drm_sched_job_add_dependency()
和drm_sched_job_add_implicit_dependencies()
。last_dependency
跟踪 dependencies 的信号
submit_ts
作业被推送到实体队列的时间。
描述
作业由驱动程序使用 drm_sched_job_init()
创建,并且一旦希望调度程序调度该作业,应调用 drm_sched_entity_push_job()
。
-
struct drm_sched_backend_ops¶
定义调度程序调用的后端操作
定义:
struct drm_sched_backend_ops {
struct dma_fence *(*prepare_job)(struct drm_sched_job *sched_job, struct drm_sched_entity *s_entity);
struct dma_fence *(*run_job)(struct drm_sched_job *sched_job);
enum drm_gpu_sched_stat (*timedout_job)(struct drm_sched_job *sched_job);
void (*free_job)(struct drm_sched_job *sched_job);
u32 (*update_job_credits)(struct drm_sched_job *sched_job);
};
成员
prepare_job
当调度程序考虑接下来调度此作业时调用,以获取此作业要阻塞的另一个
struct dma_fence
。一旦它返回 NULL,可能会调用 run_job()。如果不需要对依赖项进行额外的准备,则可以为 NULL。当作业被杀死而不是运行时跳过。
run_job
一旦所有依赖项都已解决,则调用以执行作业。如果发生 timedout_job() 并且 drm_sched_job_recovery() 决定再次尝试,则可能会多次调用此函数。
timedout_job
当作业执行时间过长时调用,以触发 GPU 恢复。
此方法在工作队列上下文中调用。
驱动程序通常会发出重置以从 GPU 挂起中恢复,此过程通常遵循以下工作流程
使用
drm_sched_stop()
停止调度程序。这将暂停调度程序线程并取消超时工作,保证在我们重置硬件队列时不会排队任何内容尝试优雅地停止非故障作业(可选)
发出 GPU 重置(驱动程序特定)
使用
drm_sched_resubmit_jobs()
重新提交作业使用
drm_sched_start()
重新启动调度程序。此时,可以对新作业进行排队,并且调度程序线程将被解除阻塞
请注意,某些 GPU 具有不同的硬件队列,但需要全局重置 GPU,这需要在不同
drm_gpu_scheduler
的超时处理程序之间进行额外的同步。实现此同步的一种方法是在驱动程序级别创建一个有序工作队列(使用alloc_ordered_workqueue()
),并将此队列传递给drm_sched_init()
,以保证超时处理程序按顺序执行。在这种情况下,需要稍微调整上述工作流程使用
drm_sched_stop()
停止受重置影响的所有调度程序尝试优雅地停止所有受重置影响的队列上的非故障作业(可选)
在所有故障队列上发出 GPU 重置(驱动程序特定)
使用
drm_sched_resubmit_jobs()
重新提交所有受重置影响的调度程序上的作业使用
drm_sched_start()
重新启动在步骤 #1 中停止的所有调度程序
当一切正常,并且底层驱动程序已启动或完成恢复时,返回 DRM_GPU_SCHED_STAT_NOMINAL。
如果设备不再可用,即已拔出,则返回 DRM_GPU_SCHED_STAT_ENODEV。
free_job
一旦作业的完成 fence 已发出信号并且需要清理时调用。
update_job_credits
当调度程序正在考虑执行此作业时调用。
此回调返回如果推送到硬件,作业将占用的信用额度。驱动程序可以使用此函数来动态更新作业的信用额度。例如,扣除已发出信号的本机 fence 的信用额度。
此回调是可选的。
描述
这些函数应在驱动程序端实现。
-
struct drm_gpu_scheduler¶
调度程序实例特定数据
定义:
struct drm_gpu_scheduler {
const struct drm_sched_backend_ops *ops;
u32 credit_limit;
atomic_t credit_count;
long timeout;
const char *name;
u32 num_rqs;
struct drm_sched_rq **sched_rq;
wait_queue_head_t job_scheduled;
atomic64_t job_id_count;
struct workqueue_struct *submit_wq;
struct workqueue_struct *timeout_wq;
struct work_struct work_run_job;
struct work_struct work_free_job;
struct delayed_work work_tdr;
struct list_head pending_list;
spinlock_t job_list_lock;
int hang_limit;
atomic_t *score;
atomic_t _score;
bool ready;
bool free_guilty;
bool pause_submit;
bool own_submit_wq;
struct device *dev;
};
成员
ops
驱动程序提供的后端操作。
credit_limit
此调度程序的信用额度
credit_count
此调度程序的当前信用计数
timeout
作业从调度程序中删除的时间。
name
正在使用此调度程序的环的名称。
num_rqs
运行队列的数量。这最多为 DRM_SCHED_PRIORITY_COUNT,因为每个优先级通常有一个运行队列,但可能会更少。
sched_rq
大小为 num_rqs 的运行队列的已分配数组;
job_scheduled
一旦调用 drm_sched_entity_do_release,调度程序将在此等待队列上等待,直到所有调度的作业完成。
job_id_count
用于为每个作业分配唯一 ID。
submit_wq
用于将 work_run_job 和 work_free_job 排队的工作队列
timeout_wq
用于将 work_tdr 排队的工作队列
work_run_job
调用每个调度程序的 run_job 操作的工作。
work_free_job
调用每个调度程序的 free_job 操作的工作。
work_tdr
在超时时间过后,计划延迟调用 drm_sched_job_timedout。
pending_list
当前位于作业队列中的作业列表。
job_list_lock
用于保护 pending_list 的锁。
hang_limit
一旦作业的挂起次数超过此限制,则将其标记为有罪,并且不再考虑进行调度。
score
帮助负载均衡器选择空闲调度程序的评分
_score
当驱动程序不提供评分时使用的评分
ready
标记底层硬件是否已准备好工作
free_guilty
超时处理程序的一个命中,用于释放有罪的作业。
pause_submit
暂停在 submit_wq 上排队 work_run_job
own_submit_wq
调度程序拥有 submit_wq 的分配
dev
描述
为每个硬件环实现一个调度程序。
-
void drm_sched_tdr_queue_imm(struct drm_gpu_scheduler *sched)¶
立即启动作业超时处理程序
参数
struct drm_gpu_scheduler *sched
应启动超时处理的调度程序。
描述
立即为指定的调度程序启动超时处理。
-
void drm_sched_fault(struct drm_gpu_scheduler *sched)¶
立即启动超时处理程序
参数
struct drm_gpu_scheduler *sched
应启动超时处理的调度程序。
描述
当驱动程序检测到硬件故障时,立即启动超时处理。
-
unsigned long drm_sched_suspend_timeout(struct drm_gpu_scheduler *sched)¶
暂停调度程序作业超时
参数
struct drm_gpu_scheduler *sched
要暂停超时的调度程序实例
描述
暂停调度程序的延迟工作超时。这是通过将延迟工作超时修改为任意大值来实现的,在本例中为 MAX_SCHEDULE_TIMEOUT。
返回剩余的超时时间
-
void drm_sched_resume_timeout(struct drm_gpu_scheduler *sched, unsigned long remaining)¶
恢复调度程序作业超时
参数
struct drm_gpu_scheduler *sched
要恢复超时的调度程序实例
unsigned long remaining
剩余超时时间
描述
恢复调度程序的延迟工作超时。
-
void drm_sched_stop(struct drm_gpu_scheduler *sched, struct drm_sched_job *bad)¶
停止调度程序
参数
struct drm_gpu_scheduler *sched
调度程序实例
struct drm_sched_job *bad
导致超时的作业
描述
停止调度程序并删除并释放所有已完成的作业。此函数通常用于重置恢复(有关详细信息,请参阅 drm_sched_backend_ops.timedout_job() 的文档)。不要在调用 drm_sched_fini()
之前为调度程序拆解调用它。
注意
如果坏的任务可能在之后被使用,则不会被释放,因此,如果它不再是待处理列表的一部分,调用者有责任手动释放它。
-
void drm_sched_start(struct drm_gpu_scheduler *sched, int errno)¶
在重置后恢复任务
参数
struct drm_gpu_scheduler *sched
调度程序实例
int errno
要在待处理的栅栏上设置的错误
描述
此函数通常用于重置恢复(有关详细信息,请参阅 drm_sched_backend_ops.timedout_job() 的文档)。请勿在调度程序启动时调用它。调度程序本身在 drm_sched_init()
成功后即可完全运行。
-
void drm_sched_resubmit_jobs(struct drm_gpu_scheduler *sched)¶
已弃用,请勿在新代码中使用!
参数
struct drm_gpu_scheduler *sched
调度程序实例
描述
重新提交任务是 AMD 提出的一种廉价的实现任务超时后恢复的方法。
事实证明这效果不是很好。首先,dma_fence 的实现和要求存在很多问题。要么实现存在与核心内存管理死锁的风险,要么违反了 dma_fence 对象的文档化实现细节。
驱动程序仍然可以保存和恢复其状态以进行恢复操作,但我们不应将其作为围绕 dma_fence 接口的通用调度程序功能。
-
int drm_sched_job_init(struct drm_sched_job *job, struct drm_sched_entity *entity, u32 credits, void *owner)¶
初始化一个调度程序任务
参数
struct drm_sched_job *job
要初始化的调度程序任务
struct drm_sched_entity *entity
要使用的调度程序实体
u32 credits
此任务对调度程序信用额度的贡献的信用数量
void *owner
用于调试的作业所有者
描述
有关锁定注意事项,请参阅 drm_sched_entity_push_job()
文档。
如果此函数成功返回,即使 **job** 在调用 drm_sched_job_arm()
之前中止,驱动程序也必须确保调用 drm_sched_job_cleanup()
。
请注意,此函数不会为 struct drm_sched_job
的每个结构成员分配有效值。请查看该结构的文档,了解谁在什么生命周期内设置哪个结构成员。
警告:amdgpu 滥用 drm_sched.ready
来指示硬件何时死机,这可能意味着 **entity** 没有有效的运行队列。在这种情况下,此函数返回 -ENOENT(可能应该返回 -EIO 作为更有意义的返回值)。
成功返回 0,否则返回负错误代码。
-
void drm_sched_job_arm(struct drm_sched_job *job)¶
准备一个调度程序任务以供执行
参数
struct drm_sched_job *job
要准备的调度程序任务
描述
这将准备一个调度程序任务以供执行。具体来说,它初始化 **job** 的 drm_sched_job.s_fence
,以便可以将其附加到 struct dma_resv
或其他需要跟踪此任务完成情况的地方。
有关锁定注意事项,请参阅 drm_sched_entity_push_job()
文档。
只有在 drm_sched_job_init()
成功后才能调用此函数。
-
int drm_sched_job_add_dependency(struct drm_sched_job *job, struct dma_fence *fence)¶
将栅栏添加为任务依赖项
参数
struct drm_sched_job *job
要添加依赖项的调度程序任务
struct dma_fence *fence
要添加到依赖项列表中的 dma_fence。
描述
请注意,在成功和错误情况下都会消耗 **fence**。
返回
成功时为 0,或在扩展数组失败时返回错误。
-
int drm_sched_job_add_syncobj_dependency(struct drm_sched_job *job, struct drm_file *file, u32 handle, u32 point)¶
将 syncobj 的栅栏添加为任务依赖项
参数
struct drm_sched_job *job
要添加依赖项的调度程序任务
struct drm_file *file
drm 文件私有指针
u32 handle
要查找的 syncobj 句柄
u32 point
时间线点
描述
这将与给定 syncobj 匹配的栅栏添加到 **job**。
返回
成功时为 0,或在扩展数组失败时返回错误。
-
int drm_sched_job_add_resv_dependencies(struct drm_sched_job *job, struct dma_resv *resv, enum dma_resv_usage usage)¶
将 resv 中的所有栅栏添加到任务
参数
struct drm_sched_job *job
要添加依赖项的调度程序任务
struct dma_resv *resv
从中获取栅栏的 dma_resv 对象
enum dma_resv_usage usage
用于筛选栅栏的 dma_resv_usage
描述
这会将与给定用法匹配的所有栅栏从 **resv** 添加到 **job**。必须在持有 **resv** 锁的情况下调用。
返回
成功时为 0,或在扩展数组失败时返回错误。
-
int drm_sched_job_add_implicit_dependencies(struct drm_sched_job *job, struct drm_gem_object *obj, bool write)¶
将隐式依赖项添加为任务依赖项
参数
struct drm_sched_job *job
要添加依赖项的调度程序任务
struct drm_gem_object *obj
从中添加新依赖项的 gem 对象。
bool write
任务是否可能写入对象(因此我们需要依赖于预留对象中的共享栅栏)。
描述
这应该在 drm_gem_lock_reservations()
在你的任务中使用的 GEM 对象数组之后,但在使用自己的栅栏更新预留之前调用。
返回
成功时为 0,或在扩展数组失败时返回错误。
-
void drm_sched_job_cleanup(struct drm_sched_job *job)¶
清理调度程序任务资源
参数
struct drm_sched_job *job
要清理的调度程序任务
描述
清理使用 drm_sched_job_init()
分配的资源。
如果 **job** 在调用 drm_sched_job_arm()
之前中止,驱动程序应从其错误回退代码中调用此函数。
过了那个无法返回的点后,**job** 将被提交给调度程序执行,并且应从 drm_sched_backend_ops.free_job
回调中调用此函数。
-
struct drm_gpu_scheduler *drm_sched_pick_best(struct drm_gpu_scheduler **sched_list, unsigned int num_sched_list)¶
从 sched_list 中获取负载最小的 drm 调度器
参数
struct drm_gpu_scheduler **sched_list
drm_gpu_scheduler 的列表
unsigned int num_sched_list
sched_list 中 drm_gpu_scheduler 的数量
描述
返回负载最小的调度器的指针,如果所有 drm_gpu_scheduler 都未准备好,则返回 NULL
-
int drm_sched_init(struct drm_gpu_scheduler *sched, const struct drm_sched_backend_ops *ops, struct workqueue_struct *submit_wq, u32 num_rqs, u32 credit_limit, unsigned int hang_limit, long timeout, struct workqueue_struct *timeout_wq, atomic_t *score, const char *name, struct device *dev)¶
初始化一个 GPU 调度器实例
参数
struct drm_gpu_scheduler *sched
调度程序实例
const struct drm_sched_backend_ops *ops
此调度器的后端操作
struct workqueue_struct *submit_wq
用于提交的工作队列。如果为 NULL,则会分配并使用一个有序的 wq
u32 num_rqs
运行队列的数量,每个优先级一个,最多为 DRM_SCHED_PRIORITY_COUNT
u32 credit_limit
此调度器可以从所有作业中持有的信用额度
unsigned int hang_limit
在放弃作业之前允许作业挂起的次数
long timeout
调度器的超时值(以 jiffies 为单位)
struct workqueue_struct *timeout_wq
用于超时工作的工作队列。如果为 NULL,则使用 system_wq
atomic_t *score
与其它调度器共享的可选分数原子变量
const char *name
用于调试的名称
struct device *dev
描述
成功返回 0,否则返回错误代码。
-
void drm_sched_fini(struct drm_gpu_scheduler *sched)¶
销毁一个 GPU 调度器
参数
struct drm_gpu_scheduler *sched
调度程序实例
描述
拆卸并清理调度器。
这将停止通过 drm_sched_backend_ops.run_job() 向硬件提交新作业。 因此,不会为仍在 drm_gpu_scheduler.pending_list 中的所有作业调用 drm_sched_backend_ops.free_job()。 目前没有解决此问题的方案。 因此,驱动程序需要确保
drm_sched_fini()
仅在所有提交的作业都调用了 drm_sched_backend_ops.free_job() 后调用,或者在运行
drm_sched_fini()
后,未调用 drm_sched_backend_ops.free_job() 的作业被手动释放。
FIXME:解决上述问题,并防止此函数在任何情况下泄漏 drm_gpu_scheduler.pending_list 中的作业。
-
void drm_sched_increase_karma(struct drm_sched_job *bad)¶
更新 sched_entity 的 guilty 标志
参数
struct drm_sched_job *bad
导致超时的作业
描述
在 ‘bad’ 作业导致的每次挂起时递增。 如果此值超过调度器的挂起限制,则相应的调度实体会被标记为 guilty,并且不会再调度来自该实体的作业
-
bool drm_sched_wqueue_ready(struct drm_gpu_scheduler *sched)¶
调度器是否准备好提交
参数
struct drm_gpu_scheduler *sched
调度程序实例
描述
如果准备好提交,则返回 true
-
void drm_sched_wqueue_stop(struct drm_gpu_scheduler *sched)¶
停止调度器提交
参数
struct drm_gpu_scheduler *sched
调度程序实例
描述
阻止调度器从实体中提取新作业。它还会停止通过 drm_sched_backend_ops.free_job() 自动释放作业。
-
void drm_sched_wqueue_start(struct drm_gpu_scheduler *sched)¶
启动调度器提交
参数
struct drm_gpu_scheduler *sched
调度程序实例
描述
在 drm_sched_wqueue_stop()
停止调度器后重新启动调度器。
此函数对于“传统”启动不是必需的。 在 drm_sched_init()
成功后,调度器即可完全运行。
-
int drm_sched_entity_init(struct drm_sched_entity *entity, enum drm_sched_priority priority, struct drm_gpu_scheduler **sched_list, unsigned int num_sched_list, atomic_t *guilty)¶
初始化一个上下文实体,该实体在提交到 HW 环时由调度器使用。
参数
struct drm_sched_entity *entity
要初始化的调度器实体
enum drm_sched_priority priority
实体的优先级
struct drm_gpu_scheduler **sched_list
可以提交此实体作业的 drm 调度器列表
unsigned int num_sched_list
sched_list 中 drm 调度器的数量
atomic_t *guilty
当发现此队列上的作业导致超时时,atomic_t 设置为 1
描述
请注意,sched_list
必须至少有一个元素才能调度实体。
有关稍后在运行时更改 **priority**,请参阅 drm_sched_entity_set_priority()
。 有关在运行时更改调度器集 **sched_list**,请参阅 drm_sched_entity_modify_sched()
。
通过调用 drm_sched_entity_fini()
来清理实体。 另请参阅 drm_sched_entity_destroy()
。
成功时返回 0,失败时返回负错误代码。
-
void drm_sched_entity_modify_sched(struct drm_sched_entity *entity, struct drm_gpu_scheduler **sched_list, unsigned int num_sched_list)¶
修改实体的调度器。
参数
struct drm_sched_entity *entity
要初始化的调度器实体
struct drm_gpu_scheduler **sched_list
新的 DRM 调度器列表,将替换现有的 entity->sched_list。
unsigned int num_sched_list
sched_list 中 drm 调度器的数量
描述
请注意,此函数必须在与 drm_sched_job_arm()
和 drm_sched_entity_push_job()
相同的通用锁下调用 **entity**,或者驱动程序需要通过其他方式保证在向 **entity** 推送新作业时永远不会调用此函数。
-
int drm_sched_entity_error(struct drm_sched_entity *entity)¶
返回上次调度作业的错误。
参数
struct drm_sched_entity *entity
要检查的调度器实体。
描述
选择性地返回上次调度作业的错误。当新作业被推送到硬件时,结果可能随时更改。
-
long drm_sched_entity_flush(struct drm_sched_entity *entity, long timeout)¶
刷新上下文实体。
参数
struct drm_sched_entity *entity
调度器实体。
long timeout
以节拍为单位等待队列变空的时间。
描述
将 drm_sched_entity_fini()
分割成两个函数,第一个函数执行等待,从运行队列中删除实体,并在进程被杀死时返回错误。
返回输入超时剩余的节拍时间。
-
void drm_sched_entity_fini(struct drm_sched_entity *entity)¶
销毁上下文实体。
参数
struct drm_sched_entity *entity
调度器实体。
描述
清理由 drm_sched_entity_init()
初始化的 **entity**。
如果可能仍有正在运行或新加入队列的作业,则必须首先调用 drm_sched_entity_flush()
。然后此函数会遍历实体,并在进程被杀死时使用错误代码向所有作业发出信号。
-
void drm_sched_entity_destroy(struct drm_sched_entity *entity)¶
销毁上下文实体。
参数
struct drm_sched_entity *entity
调度器实体。
描述
为了方便起见,调用 drm_sched_entity_flush()
和 drm_sched_entity_fini()
作为便捷的包装器。
-
void drm_sched_entity_set_priority(struct drm_sched_entity *entity, enum drm_sched_priority priority)¶
设置实体的优先级。
参数
struct drm_sched_entity *entity
调度器实体。
enum drm_sched_priority priority
调度器优先级。
描述
更新用于实体的运行队列的优先级。
-
void drm_sched_entity_push_job(struct drm_sched_job *sched_job)¶
将作业提交到实体的作业队列。
参数
struct drm_sched_job *sched_job
要提交的作业。
注意
为了保证插入队列的顺序与作业的栅栏序列号相匹配,此函数应在为 struct drm_sched_entity
设置的公共锁下,与 drm_sched_job_arm()
一起调用,该实体在 drm_sched_job_init()
中为 **sched_job** 设置。