DRM 内存管理¶
现代 Linux 系统需要大量的图形内存来存储帧缓冲区、纹理、顶点和其他图形相关数据。鉴于许多此类数据的动态特性,高效地管理图形内存对于图形堆栈至关重要,并在 DRM 基础设施中发挥着核心作用。
DRM 核心包含两个内存管理器,即转换表管理器 (TTM) 和图形执行管理器 (GEM)。TTM 是第一个被开发的 DRM 内存管理器,并试图成为一种适用于所有情况的解决方案。它提供了一个单一的用户空间 API,以满足所有硬件的需求,支持统一内存架构 (UMA) 设备和具有专用视频 RAM 的设备(即大多数独立显卡)。这导致了一段庞大而复杂的代码,对于驱动程序开发来说,使用起来很困难。
GEM 最初是英特尔赞助的项目,以应对 TTM 的复杂性。它的设计理念完全不同:GEM 没有为每个图形内存相关问题提供解决方案,而是识别了驱动程序之间的通用代码,并创建了一个支持库来共享它。GEM 比 TTM 具有更简单的初始化和执行要求,但没有视频 RAM 管理功能,因此仅限于 UMA 设备。
转换表管理器 (TTM)¶
TTM 是具有专用内存的加速器设备的内存管理器。
基本思想是将资源分组到特定大小的缓冲区对象中,TTM 处理这些对象的生命周期、移动和 CPU 映射。
待办事项:在此处添加更多设计背景和信息。
-
enum ttm_caching¶
CPU 缓存和 BUS 侦听行为。
常量
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;
struct dmem_cgroup_region *cg;
};
成员
use_type
已启用内存类型。
use_tt
是否应将 TT 对象用于后备存储。
bdev
此管理器所属的 TTM 设备
size
托管区域的大小。
func
实现范围管理器的结构指针。见上文
move_lock
移动栅栏锁
move
上次流水线移动操作的栅栏。
lru
此内存类型的 lru 列表。
usage
使用了多少资源,受 bdev->lru_lock 保护。
cg
用于内存核算的
dmem_cgroup_region
,如果不是 NULL。
描述
此结构用于标识和管理设备的内存类型。
-
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 dmem_cgroup_pool_state *css;
struct ttm_lru_item lru;
};
成员
start
分配的开始。
size
资源以字节为单位的实际大小。
mem_type
分配的资源类型。
placement
放置标志。
bus
放置在 CPU 可访问的 io 总线上
bo
对 BO 的弱引用,受 ttm_device::lru_lock 保护
css
此资源所记入的 cgroup 状态
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
批量移动范围中的第一个 res
last
批量移动范围中的最后一个 res
描述
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
struct io_mapping 表示底层线性 io_memory。
st
进入 iomap 的 sg_table,表示
struct ttm_resource
的内存。start
需要从 st 中减去的偏移量,以使 sg_dma_address(st->sgl) - start == 0 用于 iomap 开始。
cache
用于快速查找的 Scatterlist 遍历缓存。
cache.sg
指向当前缓存的 scatterlist 段的指针。
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 (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_BACKED_UP BIT(5);
#define TTM_TT_FLAG_PRIV_POPULATED BIT(6);
uint32_t page_flags;
uint32_t num_pages;
struct sg_table *sg;
dma_addr_t *dma_address;
struct file *swap_storage;
struct file *backup;
enum ttm_caching caching;
struct ttm_pool_tt_restore *restore;
};
成员
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 直接映射这些页面。
请注意,enum 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_BACKED_UP:仅限 TTM 内部使用。 如果
struct ttm_tt
已(可能部分)备份,则设置此标志。TTM_TT_FLAG_PRIV_POPULATED:仅限 TTM 内部使用。 请勿使用。 这是在
ttm_tt_populate()
成功返回后由 TTM 设置的,然后在 TTM 调用ttm_tt_unpopulate()
时取消设置。num_pages
页面数组中的页数。
sg
用于通过 dma-buf 的 SG 对象。
dma_address
页面的 DMA(总线)地址。
swap_storage
指向用于交换存储的 shmem
struct file
的指针。backup
指向备份的 tt 的备份结构的指针。 可以与 swap_storage 统一。 同时,驱动程序的
ttm_tt_create()
回调负责分配此字段。caching
页面的当前缓存状态,请参见
enum ttm_caching
。restore
从备份状态部分还原。 TTM 私有
-
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_backup_flags¶
用于控制备份行为的标志。
定义:
struct ttm_backup_flags {
u32 purge : 1;
u32 writeback : 1;
};
成员
purge
释放页面而不备份。 绕过池。
writeback
尝试将内容直接复制到交换空间,即使这意味着阻塞对外部内存的写入。
-
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
参数
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 的指针。
参数
struct ttm_tt *tt
为其分配和分配备份结构的 ttm_tt。
描述
分配一个备份结构以用于 tt 备份。 这通常应该在 bo 创建时完成,以避免在收缩时进行分配。
返回值
成功时为 0,失败时为负错误代码。
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
order
我们的页面具有的分配顺序
caching
我们的页面具有的缓存类型
shrinker_list
我们在全局收缩器列表中的位置
lock
页面列表的保护
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 对象,因此创建一个嵌入 struct struct drm_gem_object
实例的特定于驱动程序的 GEM 对象结构类型。
要创建 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()
来初始化 GEM 对象(称为私有 GEM 对象),从而创建没有 shmfs 支持的 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 对象,驱动程序必须确保它们删除它们拥有的引用(例如在对象创建时获取的初始引用),而无需对句柄进行任何特殊考虑。例如,在哑创建操作的实现中,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 offset 参数。
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 处理程序。
故障操作处理程序负责在发生页面错误时将各个页面映射到用户空间。根据内存分配方案,驱动程序可以在故障时分配页面,也可以决定在创建对象时为 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 内存映射支持
内存一致性¶
当映射到设备或在命令缓冲区中使用时,对象的后备页面会被刷新到内存中,并标记为写入组合,以便与 GPU 保持一致。同样,如果 CPU 在 GPU 完成渲染到对象后访问该对象,则必须使该对象与 CPU 的内存视图保持一致,通常涉及各种 GPU 缓存刷新。此核心 CPU<->GPU 一致性管理由特定于设备的 ioctl 提供,该 ioctl 评估对象的当前域,并执行任何必要的刷新或同步,以将对象置于所需的一致性域中(请注意,对象可能很忙,即活动的渲染目标;在这种情况下,设置域会阻止客户端并等待渲染完成,然后再执行任何必要的刷新操作)。
命令执行¶
对于 GPU 设备来说,最重要的 GEM 功能可能是为客户端提供命令执行接口。客户端程序构建包含对先前分配的内存对象的引用的命令缓冲区,然后将它们提交给 GEM。此时,GEM 会注意将所有对象绑定到 GTT 中,执行缓冲区,并在访问相同缓冲区的客户端之间提供必要的同步。这通常涉及从 GTT 中驱逐某些对象并重新绑定其他对象(这是一项相当昂贵的操作),并提供重定位支持,从而向客户端隐藏固定的 GTT 偏移量。客户端必须注意不要提交引用的对象多于 GTT 可以容纳的命令缓冲区;否则,GEM 将拒绝它们,并且不会发生渲染。同样,如果缓冲区中的多个对象需要分配 fence 寄存器才能进行正确的渲染(例如,在 965 之前的芯片上进行 2D blit),则必须注意不要需要比客户端可用的 fence 寄存器更多的寄存器。这种资源管理应该从 libdrm 中的客户端抽象出来。
GEM 函数参考¶
-
enum drm_gem_object_status¶
用于 fdinfo 报告的对象状态的位掩码
常量
DRM_GEM_OBJECT_RESIDENT
对象驻留在内存中(即未取消固定)
DRM_GEM_OBJECT_PURGEABLE
对象被用户空间标记为可清除
DRM_GEM_OBJECT_ACTIVE
对象当前正在活动提交中使用
描述
用于 fdinfo 内存统计的状态位掩码,请参见 drm_gem_object_funcs.status
和 drm_show_fdinfo()
。请注意,对象可以报告 DRM_GEM_OBJECT_PURGEABLE 并且处于活动状态或未驻留状态,在这种情况下,drm_show_fdinfo()
不会将其计为可清除的。因此,驱动程序无需检查缓冲区是否空闲和驻留即可返回此位,即使用户空间可以在缓冲区仍在 GPU 上繁忙时将其标记为可清除。在它变为空闲之前,它不会在 puregeable 统计信息中报告。状态 gem object 函数不需要考虑这一点。
-
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
返回缓冲区的 Scatter-Gather 表表示形式。
drm_gem_map_dma_buf()
帮助程序在导出缓冲区时使用。释放通过在 drm_gem_unmap_buf() 中调用 dma_unmap_sg_attrs() 和 sg_free_table() 完成,因此这些帮助程序和此处的此回调不能用于指向驱动程序私有内存范围的 sg 表。另请参见
drm_prime_pages_to_sg()
。vmap
返回缓冲区的虚拟地址。
drm_gem_dmabuf_vmap()
帮助程序使用。使用持有的 GEM 预留锁调用。此回调是可选的。
vunmap
释放先前由 vmap 返回的地址。
drm_gem_dmabuf_vunmap()
帮助程序使用。使用持有的 GEM 预留锁调用。此回调是可选的。
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。使用持有的 GEM 预留锁调用。
此回调是可选的。
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;
};
成员
lock
锁定保护 GEM 对象在 LRU 之间的移动。对象可以在其间移动的所有 LRU 都应受到同一锁的保护。
count
此 LRU 中 GEM 对象的后备页面的总数。
list
LRU 列表。
描述
一种用于跟踪给定状态下的 GEM 对象的帮助程序,以帮助驱动程序的收缩器实现。跟踪页面的计数以进行无锁 shrinker.count_objects
,并提供 drm_gem_lru_scan
用于驱动程序的 shrinker.scan_objects
实现。
-
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 dev 此对象所属。
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
A
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 对象是否共享。
-
bool drm_gem_is_imported(const struct drm_gem_object *obj)¶
测试是否已导入 GEM 对象的缓冲区
参数
const struct drm_gem_object *obj
GEM 对象
返回值
如果已导入 GEM 对象的缓冲区,则为 True,否则为 false
-
drm_gem_gpuva_set_lock¶
drm_gem_gpuva_set_lock (obj, lock)
设置保护对 gpuva 列表的访问的锁。
参数
obj
lock
用于保护 gpuva 列表的锁。锁定原语必须包含 dep_map 字段。
描述
如果您没有使用 dma-resv 锁,而是使用自定义锁来保护对 gpuva 列表的访问,请调用此函数。
-
void drm_gem_gpuva_init(struct drm_gem_object *obj)¶
初始化 GEM 对象的 gpuva 列表
参数
struct drm_gem_object *obj
描述
这将初始化 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
要删除的用户空间句柄
描述
从已使用drm_gem_handle_create()
添加的filp查找表中删除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偏移量的返回位置
描述
这实现了使用gem管理其后备存储的驱动程序的drm_driver.dumb_map_offset
kms驱动程序回调。
返回值
成功时返回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()。如果您有特殊的区域约束,请在通过mapping_set_gfp_mask()调用drm_gem_object_init()
之后设置它们。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后同步映射缓冲区内存。
此函数主要用于实现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 map 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_objects
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))¶
实现 shrinker.scan_objects 的助手
参数
struct drm_gem_lru *lru
要扫描的 LRU
unsigned int nr_to_scan
要尝试回收的页数
unsigned long *remaining
要回收的剩余页数,应由调用者初始化
bool (*shrink)(struct drm_gem_object *obj)
尝试缩小/回收对象的 回调。
描述
如果 shrink 回调成功,则期望驱动程序将对象移出此 LRU。
如果 LRU 可能包含活动缓冲区,则 shrink 回调有责任检查这一点(即 dma_resv_test_signaled()
),或者如果需要,则阻塞直到缓冲区空闲。
-
int drm_gem_evict_locked(struct drm_gem_object *obj)¶
用于驱逐 GEM 对象的后备页面的助手
参数
struct drm_gem_object *obj
有问题的 obj
GEM DMA 助手函数参考¶
DRM GEM/DMA 助手是一种提供呈现给设备的缓冲区对象的方法,这些对象是作为连续的内存块呈现的。这对于不支持 scatter-gather DMA(直接或通过使用紧密连接的 IOMMU)的设备很有用。
对于通过(外部)IOMMU 访问内存总线的设备,缓冲区对象是使用传统的基于页面的分配器分配的,并且可能分散在物理内存中。但是,它们在 IOVA 空间中是连续的,因此对于使用它们的设备来说是连续的。
对于其他设备,助手依赖 CMA 来提供物理上在内存中连续的缓冲区对象。
对于 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 缓冲区的 scatter/gather 表。该表可以有多个条目,但保证具有连续的 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
处理程序。
返回值
指向已固定页面的 scatter/gather 表的指针,如果失败,则为 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 操作。
此宏是 DRM_GEM_DMA_DRIVER_OPS 的变体,适用于覆盖 struct rm_driver
.dumb_create 的默认实现的驱动程序。如果可能,请使用 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 操作。
此宏是 DRM_GEM_DMA_DRIVER_OPS_VMAP 的变体,适用于覆盖 struct drm_driver
.dumb_create 的默认实现的驱动程序。如果可能,请使用 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 平台中用于为给定缓冲区提出地址映射。它旨在用作 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 对象提供已固定页面的 scatter/gather 表
参数
struct drm_gem_dma_object *dma_obj
DMA GEM 对象
描述
此函数通过调用标准 DMA 映射 API 导出 scatter/gather 表。
返回值
指向已固定页面的 scatter/gather 表的指针,如果失败,则为 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)¶
从另一个驱动程序的已固定页面的 scatter/gather 表生成 DMA GEM 对象
参数
struct drm_device *dev
要导入到的设备
struct dma_buf_attachment *attach
DMA-BUF 附件
struct sg_table *sgt
已固定页面的 scatter/gather 表
描述
此函数导入由另一个驱动程序通过 DMA-BUF 导出的 scatter/gather 表。导入的缓冲区必须在物理上在内存中连续(即,scatter/gather 表必须包含单个条目)。使用 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 导入另一个驱动程序的 scatter/gather 表并获取缓冲区的虚拟地址
参数
struct drm_device *dev
DRM 设备
struct dma_buf_attachment *attach
DMA-BUF 附件
struct sg_table *sgt
已固定页面的 Scatter/gather 表
描述
此函数使用 drm_gem_dma_prime_import_sg_table()
导入 scatter/gather 表,并使用 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 对象上操作的函数接收 drm_gem_shmem_object
结构体。对于 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;
refcount_t pages_use_count;
refcount_t pages_pin_count;
int madv;
struct list_head madv_list;
struct sg_table *sgt;
void *vaddr;
refcount_t 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
页表上的引用计数。当计数达到零时,页被释放。
pages_pin_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
已固定页面的 Scatter/gather 表
描述
此函数导入由另一个驱动程序通过 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 辅助库。 每个活动缓冲区对象都存储在视频 RAM 中。 活动缓冲区用于绘制当前帧,通常类似于帧的扫描输出缓冲区或光标图像。 如果 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 管理视频 RAM 区域,并向用户空间提供 GEM VRAM 对象。
您不必清理 VRAM MM 的实例。 drmm_vram_helper_init()
是一个托管接口,用于安装在 DRM 设备的释放期间运行的清理处理程序。
对于绘图或扫描输出操作,分别需要将缓冲区对象固定在视频 RAM 中。 调用带有 DRM_GEM_VRAM_PL_FLAG_VRAM
或 DRM_GEM_VRAM_PL_FLAG_SYSTEM
的 drm_gem_vram_pin()
,以将缓冲区对象固定在视频 RAM 或系统内存中。 调用 drm_gem_vram_unpin()
以在之后释放固定的对象。
固定在视频 RAM 中的缓冲区对象在该内存区域中具有固定地址。 调用 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 对象对固定和映射操作执行引用计数。 因此,使用 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,则缓冲区将固定在其当前位置(视频 RAM 或系统内存)。
小的缓冲区对象(例如光标图像)如果固定在视频 RAM 的中间,可能会导致内存碎片。在只有少量视频 RAM 的设备上,这尤其是一个问题。碎片化可能会阻止主帧缓冲区适应,即使总体上有足够的内存。修饰符 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 的参数
描述
此函数要求驱动程序使用 drm_device.vram_mm 作为其 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
的新实例并将其存储在 struct 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
要测试的模式
描述
此函数测试是否有足够的视频内存可用于指定的显示模式。Atomic 模式设置需要在逐出活动帧缓冲区之前将指定的帧缓冲区导入到视频内存中。因此,任何帧缓冲区最多可能会消耗可用 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)¶
打印 debugfs 的
ttm_buffer_object
信息
参数
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_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()
为 dumb-buffer 实现返回该偏移量。
参见 struct drm_driver.dumb_map_offset
。
返回值
成功时为 0,否则为负 errno 代码。
VMA 偏移管理器¶
vma-manager 负责将任意驱动程序相关的内存区域映射到线性用户地址空间中。它向调用者提供偏移量,然后可以在 drm 设备的 address_space 上使用这些偏移量。它负责避免区域重叠,适当调整区域大小,并且不会因不一致的虚假 vm_pgoff 字段而使 mm-core 感到困惑。驱动程序不应将此用于 VMEM 中的对象放置。此管理器应仅用于管理到线性用户空间 VM 的映射。
我们使用 drm_mm 作为后端来管理对象分配。但是它针对 alloc/free 调用进行了高度优化,而不是查找。因此,我们使用 rb-tree 来加速偏移量查找。
您不得在单个 address_space 上使用多个偏移管理器。否则,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 函数调用。在通过 drm_vma_offset_unlock_lookup()
释放锁之前,所有其他上下文都被阻止访问 VMA。
如果您需要引用 drm_vma_offset_lookup_locked()
返回的对象,然后再再次释放此锁,请使用此选项。
此锁不得用于扩展查找之外的任何其他用途。在持有此锁时,不得调用任何其他 VMA 帮助程序。
注意
在持有此锁时,您处于原子上下文中!
-
void drm_vma_offset_unlock_lookup(struct drm_vma_offset_manager *mgr)¶
解锁查找以供扩展的私有使用
参数
struct drm_vma_offset_manager *mgr
管理器对象
描述
释放 lookup-lock。有关更多信息,请参见 drm_vma_offset_lock_lookup()
。
-
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)¶
返回用户空间 mmap 的清理偏移量
参数
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()
。
-
int drm_vma_node_verify_access(struct drm_vma_offset_node *node, struct drm_file *tag)¶
TTM 的访问验证帮助程序
参数
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)¶
初始化新的 offset-manager
参数
struct drm_vma_offset_manager *mgr
管理器对象
unsigned long page_offset
可用内存区域的偏移量(基于页面)
unsigned long size
可用地址空间范围的大小(基于页面)
描述
初始化新的 offset-manager。可用于管理器的偏移量和区域大小作为 page_offset 和 size 给出。两者均解释为页码,而不是字节。
从管理器添加/删除节点在内部锁定,并防止并发访问。但是,节点分配和销毁留给调用者。在调用 vma-manager 时,必须始终保证给定节点被引用。
-
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 已在此列表中,则增加 ref-count。
允许用户列表在 drm_vma_offset_add()
和 drm_vma_offset_remove()
调用之间保留。即使节点当前未添加到任何偏移管理器,也可以调用它。
在销毁节点之前,必须将所有打开的文件删除的次数与添加它们的次数相同。否则,将导致内存泄漏。
这在内部是针对并发访问锁定的。
返回值
成功时为 0,内部故障时为负错误代码 (out-of-mem)
-
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()
不同,它不是 ref-counted,因此 drm_vma_node_revoke()
应该仅在此之后调用一次。
这在内部是针对并发访问锁定的。
返回值
成功时为 0,内部故障时为负错误代码 (out-of-mem)
参数
struct drm_vma_offset_node *node
要修改的节点
struct drm_file *tag
要删除的文件的标记
描述
在 node 上允许的打开文件列表中递减 tag 的 ref-count。如果 ref-count 降至零,则从列表中删除 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 中的跨设备缓冲区共享框架,最初是为多 GPU 平台的 OPTIMUS 系列创建的。对于用户空间 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
。它在 PRIME_HANDLE_TO_FD IOCTL 中获取此引用,当它首次调用 drm_gem_object_funcs.export
并将导出的 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 的替代品,那么它将收到一个 fd->handle 请求,用于它创建的 GEM 对象。驱动程序应检测到这种情况,并从 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 attach 和 detach 时间处理。后备存储本身由 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 {
};
成员
描述
这只包含内部的 struct dma_buf
和 PRIME 核心代码使用的每个 struct drm_file
的句柄缓存。
-
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()
,以便通用 GEM 驱动程序可以使用它,这些驱动程序使用 drm_gem_dmabuf_release()
。除了调用 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 的标志
描述
这是 GEM 驱动程序的 drm_gem_object_funcs.export
函数的实现,使用 PRIME 辅助函数。它在 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-table
描述
这是 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 抖动是一个相当陡峭的悬崖,而不是一个真正的问题。
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。
返回值
成功时为 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。
返回值
成功时为 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 的范围,则迭代器可能会遍历特殊的 _unallocated_ 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
插入到分配器中,这意味着 start、size 和 color 必须由调用者设置。所有其他字段必须清除为 0。这对于使用必须在范围分配器设置之前设置的预分配对象初始化分配器很有用,例如,当接管固件帧缓冲区时。
返回值
成功时返回 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
微调分配搜索和放置
描述
预分配的 node 必须清除为 0。
返回值
成功时为 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 清除为 0。
参数
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 signalling 关键部分插入 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
,但它也可以是“dummy”对象,可以使用 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_exec
循环,同时使用诸如 drm_gpuvm_prepare_range()
或 drm_gpuvm_prepare_objects()
等辅助函数来锁定额外的 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_for_each_op()
迭代的 drm_gpuva_op
列表。此列表包含 drm_gpuva_ops
,类似于在调用 drm_gpuvm_sm_map()
或 drm_gpuvm_sm_unmap()
时收到的回调。虽然这种方式需要更多内存(以分配 drm_gpuva_ops
),但它为驱动程序提供了一种多次迭代 drm_gpuva_op
的方法,例如,一次在可能进行内存分配的上下文中(例如,以分配 GPU 页表),另一次在 dma-fence signalling 关键路径中。
为了更新 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
,则禁用内部锁定并启用相应的 lockdep 检查。这是对能够获取相应的 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
list_head
用于将此对象附加到drm_gpuvm_bo
rb
包含数据的结构,用于在 rb 树中存储
drm_gpuvas
rb.node
rb 树节点
rb.entry
list_head
用于另外连接drm_gpuvas
,其顺序与它们在间隔树中出现的顺序相同。这有助于从通过 rb 树找到的起始节点保持迭代drm_gpuvas
,同时对 rb 树本身进行修改。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 树
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
list_head
存储用作外部对象的drm_gpuvm_bos
extobj.local_list
指向本地列表的指针,该列表临时存储来自外部对象列表的条目
extobj.lock
用于保护 extobj 列表的自旋锁
evict
保存逐出列表和逐出列表锁的结构
evict.list
list_head
存储当前正在逐出的drm_gpuvm_bos
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 将在此之前开始(但可能会重叠)
描述
此迭代器遍历 drm_gpuvm
中位于 start__ 和 end__ 之间的所有 drm_gpuvas
。它的实现类似于 list_for_each()
,但使用 drm_gpuvm
的内部间隔树来加速对起始 drm_gpuva
的搜索,因此对于元素的删除是不安全的。它假定 end__ 在 drm_gpuvm
中(或是在 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 将在此之前开始(但可能会重叠)
描述
此迭代器遍历 drm_gpuvm
中位于 start__ 和 end__ 之间的所有 drm_gpuvas
。它的实现类似于 list_for_each_safe()
,但使用 drm_gpuvm
的内部间隔树来加速对起始 drm_gpuva
的搜索,因此对于元素的删除是安全的。它假定 end__ 在 drm_gpuvm
中(或是在 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
预留的栅栏数extra
回调和相应的私有数据,供驱动程序锁定任意其他
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_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
的实例,并在 GEM 对象在此 GPU-VM 中的最后一次映射被取消映射时释放该实例。
-
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_gpuva
所关联的drm_gpuvm_bo
描述
此迭代器遍历与 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_gpuva
所关联的drm_gpuvm_bo
描述
此迭代器遍历与 drm_gpuvm_bo
关联的所有 drm_gpuva
结构。它是使用 list_for_each_entry_safe()
实现的,因此可以安全地删除元素。
调用方必须持有 GEM 的 gpuva 锁。
-
enum drm_gpuva_op_type¶
GPU VA 操作类型
常量
DRM_GPUVA_OP_MAP
map 操作类型
DRM_GPUVA_OP_REMAP
remap 操作类型
DRM_GPUVA_OP_UNMAP
unmap 操作类型
DRM_GPUVA_OP_PREFETCH
prefetch 操作类型
DRM_GPUVA_OP_DRIVER
驱动程序定义的操作类型
描述
用于更改 drm_gpuvm
跟踪的 GPU VA 映射的操作。
-
struct drm_gpuva_op_map¶
GPU VA map 操作
定义:
struct drm_gpuva_op_map {
struct {
u64 addr;
u64 range;
} va;
struct {
u64 offset;
struct drm_gem_object *obj;
} gem;
};
成员
va
包含 map 操作的地址和范围的结构
va.addr
新映射的基址
va.range
新映射的范围
gem
包含
drm_gem_object
及其偏移的结构gem.offset
drm_gem_object
中的偏移gem.obj
要映射的
drm_gem_object
描述
此结构表示 DRM GPU VA 管理器生成的单个 map 操作。
-
struct drm_gpuva_op_unmap¶
GPU VA unmap 操作
定义:
struct drm_gpuva_op_unmap {
struct drm_gpuva *va;
bool keep;
};
成员
描述
此结构表示 DRM GPU VA 管理器生成的单个 unmap 操作。
-
struct drm_gpuva_op_remap¶
GPU VA remap 操作
定义:
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
原始现有映射的 unmap 操作
描述
这表示 DRM GPU VA 管理器生成的单个 remap 操作。
当通过插入新的 GPU VA 映射或通过部分取消映射现有映射来拆分现有 GPU VA 映射时,会生成 remap 操作,因此它最多由两个 map 和一个 unmap 操作组成。
unmap 操作负责删除原始现有映射。prev 用于重新映射前一部分,next 用于重新映射后续部分。
如果新映射的起始地址与旧映射的起始地址对齐,或者新映射的结束地址与旧映射的结束地址对齐,则 prev 或 next 为 NULL。
请注意,使用专用 remap 操作而不是任意 unmap 和 map 操作的原因是让驱动程序有机会从 unmap 操作的 drm_gpuva
结构(通常嵌入在更大的驱动程序特定结构中)中提取驱动程序特定数据来创建新映射。
-
struct drm_gpuva_op_prefetch¶
GPU VA prefetch 操作
描述
此结构表示 DRM GPU VA 管理器生成的单个 prefetch 操作。
-
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
list_head
用于在drm_gpuva_ops
中分发此结构的实例。op
操作的类型
{unnamed_union}
anonymous
map
map 操作
remap
remap 操作
unmap
unmap 操作
prefetch
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
使用的回调,以向驱动程序提供 map 和 unmap 操作的拆分/合并步骤。
-
void drm_gpuva_op_remap_to_unmap_range(const struct drm_gpuva_op_remap *op, u64 *start_addr, u64 *range)¶
帮助程序获取 remap 操作的 unmap 阶段的起始地址和范围。
参数
const struct drm_gpuva_op_remap *op
Remap 操作。
u64 *start_addr
所需 unmap 的起点的输出指针。
u64 *range
所需 unmap 的长度的输出指针。
描述
给定的起始地址和范围将被设置为表示先前被重新映射的映射覆盖但现在为空的地址空间范围。
-
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
resv
drm_gem_object
,提供 GPUVM 的通用dma_resv
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_gpuvm
的 extobj 列表中,并且相应的 drm_gem_object
实际上是一个外部对象,则将其添加到该列表中。
-
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
用于初始化 prev 和 next 的
drm_gpuva_op_remap
描述
移除当前映射的 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()。
回调序列可以包含映射、取消映射和重新映射操作,但如果不需要任何操作,则回调序列也可能为空,例如,如果请求的映射已经以完全相同的方式存在。
可以有任意数量的取消映射操作,最多两个重新映射操作和一个映射操作。后者表示调用者请求的原始映射操作。
返回值
成功时为 0,或者为负错误代码
-
int drm_gpuvm_sm_unmap(struct drm_gpuvm *gpuvm, void *priv, u64 req_addr, u64 req_range)¶
创建
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()。
回调序列可以包含取消映射和重新映射操作,具体取决于是否存在要拆分的实际重叠映射。
可以有任意数量的取消映射操作和最多两个重新映射操作。
返回值
成功时为 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
进行迭代,并且必须按给定的顺序进行处理。它可以包含映射、取消映射和重新映射操作,但如果不需要任何操作,则它也可能为空,例如,如果请求的映射已经以完全相同的方式存在。
可以有任意数量的取消映射操作,最多两个重新映射操作和一个映射操作。后者表示调用者请求的原始映射操作。
请注意,在再次使用另一个映射请求调用此函数之前,必须更新 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)¶
创建
drm_gpuva_ops
以拆分取消映射
参数
struct drm_gpuvm *gpuvm
表示 GPU VA 空间的
drm_gpuvm
u64 req_addr
要取消映射的范围的起始地址
u64 req_range
要取消映射的映射的范围
描述
此函数创建要执行的操作列表,以取消映射和(如果需要)拆分与取消映射范围重叠的映射。
该列表可以使用 drm_gpuva_for_each_op
进行迭代,并且必须按给定的顺序进行处理。它可以包含取消映射和重新映射操作,具体取决于是否存在要拆分的实际重叠映射。
可以有任意数量的取消映射操作和最多两个重新映射操作。
请注意,在再次使用另一个要取消映射的范围调用此函数之前,必须更新 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
要预取的映射范围
描述
此函数创建要执行预取的 operations 列表。
可以使用 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
抽象
描述
此函数创建一个 operations 列表,用于为连接到 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
结构,包括所有与其关联的 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 管理器
描述
清理内存管理器资源和 freelist
-
struct drm_buddy_block *drm_get_buddy(struct drm_buddy_block *block)¶
获取 buddy 地址
参数
struct drm_buddy_block *block
DRM buddy 块
描述
返回 block 的相应 buddy 块,如果这是一个根块并且无法进一步合并,则返回 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
输入 list head 以释放块
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
已分配块的输入和输出列表。 MUST 包含单个块作为输入以进行修剪。 成功后,将包含构成 new_size 的新分配块。 块总是按升序排列
描述
对于连续分配,我们将大小向上舍入为最接近的 2 的幂值,驱动程序使用 actual 大小,因此剩余部分未使用,并且可以选择使用此函数释放
返回值
成功时为 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 buddy 管理器
u64 start
此块允许范围的开始
u64 end
此块允许范围的结束
u64 size
分配大小(以字节为单位)
u64 min_block_size
分配对齐方式
struct list_head *blocks
添加已分配块的输出 list head
unsigned long flags
DRM_BUDDY_*_ALLOCATION 标志
描述
在范围限制上调用的 alloc_range_bias(),它遍历树并返回所需的块。
当没有强制范围限制时调用的 alloc_from_freelist(),它从 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)¶
刷新一组页面的 dcache 行。
参数
struct page *pages[]
要刷新的页面列表。
unsigned long num_pages
数组中的页数。
描述
刷新指向数组中页面地址的每个数据缓存行条目。
-
void drm_clflush_sg(struct sg_table *st)¶
刷新指向散点/聚集的 dcache 行。
参数
struct sg_table *st
struct sg_table。
描述
刷新指向 sg 中地址的每个数据缓存行条目。
-
void drm_clflush_virt_range(void *addr, unsigned long length)¶
刷新区域的 dcache 行
参数
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 区域读取,如果不存在此类 beast,则回退到普通 memcpy。
DRM 同步对象¶
DRM 同步对象(syncobj,参见 struct drm_syncobj
)为同步原语提供了一个容器,用户空间可以使用该原语显式同步 GPU 命令,可以在用户空间进程之间共享,并且可以在不同的 DRM 驱动程序之间共享。 它们的主要用例是实现 Vulkan 栅栏和信号量。 syncobj 用户空间 API 提供了用于以下几种操作的 ioctl
创建和销毁 syncobj
将 syncobj 导入/导出到 syncobj 文件描述符/从 syncobj 文件描述符导出
将 syncobj 的底层栅栏导入/导出到同步文件/从同步文件导出
重置 syncobj(将其栅栏设置为 NULL)
发出 syncobj 信号(设置一个平凡的发出信号的栅栏)
等待 syncobj 的栅栏出现并发出信号
syncobj 用户空间 API 还提供了操作,用于根据 struct dma_fence_chain
的时间线而不是单个 struct dma_fence
操作 syncobj,通过以下操作
发出时间线上给定点的信号
等待给定点出现和/或发出信号
从/向时间线的给定点导入和导出
在其核心,syncobj 只是一个 struct dma_fence
指针的包装器,该指针可能为 NULL。 首次创建 syncobj 时,其指针为 NULL 或指向已发出信号的栅栏的指针,具体取决于 DRM_SYNCOBJ_CREATE_SIGNALED
标志是否传递给 DRM_IOCTL_SYNCOBJ_CREATE
。
如果 syncobj 被视为二进制原语(其状态为发出信号或未发出信号),则当在 DRM 驱动程序中排队 GPU 工作以发出 syncobj 信号时,syncobj 的栅栏将被完成该工作发出信号的栅栏替换。 如果 syncobj 被视为时间线原语,则当在 DRM 驱动程序中排队 GPU 工作以发出 syncobj 的给定点信号时,则会创建一个新的 struct dma_fence_chain
,该链指向 DRM 驱动程序的栅栏,也指向 syncobj 中的前一个栅栏。 新的 struct dma_fence_chain
栅栏替换 syncobj 的栅栏,并且将通过 DRM 驱动程序的工作的完成以及与先前位于 syncobj 中的栅栏相关的任何工作发出信号。
当在 DRM 驱动程序中排队 GPU 工作等待 syncobj 时,在排队工作时,它在将工作提交到硬件之前等待 syncobj 的栅栏。 该栅栏是
如果 syncobj 被视为二进制原语,则为 syncobj 的当前栅栏。
如果 syncobj 被视为时间线原语,则为与给定点关联的 struct
dma_fence
。
如果 syncobj 的栅栏为 NULL 或不在 syncobj 的时间线中,则预期排队操作将失败。
使用二进制 syncobj,对 syncobj 的栅栏的所有操作都按照在用户空间调用 ioctl 时的当前栅栏进行,而不管该操作是立即主机端操作(发出信号或重置)还是在某些驱动程序队列中排队的操作。 DRM_IOCTL_SYNCOBJ_RESET
和 DRM_IOCTL_SYNCOBJ_SIGNAL
可用于通过将其指针重置为 NULL 或将其指针设置为已发出信号的栅栏来从主机操作 syncobj。
使用时间线 syncobj,synobj 的栅栏的所有操作都按照引用时间线上点的 u64 值进行。 有关如何在时间线中找到给定点,请参见 dma_fence_chain_find_seqno()
。
请注意,在处理视为时间线的 syncobj 时,应用程序应注意始终使用时间线集 ioctl()。 将二进制集 ioctl() 与视为时间线的 syncobj 一起使用可能会导致不正确的同步。 通过使用 0 的点值,通过时间线集 ioctl() 支持使用二进制 syncobj,这将重现二进制集 ioctl() 的行为(例如,在发出信号时替换 syncobj 的栅栏)。
主机端等待 syncobj¶
DRM_IOCTL_SYNCOBJ_WAIT
采用 syncobj 句柄数组,并在主机端同时等待所有 syncobj 栅栏。 如果设置了 DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL
,则等待 ioctl 将等待所有 syncobj 栅栏发出信号,然后返回。 否则,它会在至少一个 syncobj 栅栏发出信号时返回,并且已发出信号的栅栏的索引会写回客户端。
与在 syncobj 中看到 NULL 栅栏时失败的排队 GPU 工作依赖项不同,如果设置了 DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT
,则主机端等待将首先等待 syncobj 接收非 NULL 栅栏,然后等待该栅栏。 如果未设置 DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT
并且数组中的任何一个 syncobj 具有 NULL 栅栏,则将返回 -EINVAL。 假设 syncobj 从 NULL 栅栏开始,这允许客户端在一个线程(或进程)中执行主机等待,该等待等待在另一个线程(或进程)中提交的 GPU 工作,而无需在两者之间手动同步。 此要求继承自 Vulkan 栅栏 API。
如果设置了 DRM_SYNCOBJ_WAIT_FLAGS_WAIT_DEADLINE
,则 ioctl 还将在等待之前在后备栅栏上设置栅栏截止时间提示,以便为栅栏信号发送者提供适当的紧迫感。 截止时间以纳秒为单位指定为绝对 CLOCK_MONOTONIC
值。
类似地,DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT
采用 syncobj 句柄数组以及 u64 点数组,并在主机端同时等待给定点的所有 syncobj 栅栏。
DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT
还增加了等待给定栅栏在时间线上具体化的能力,而无需使用 DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE
标志等待栅栏发出信号。 此要求继承自 Vulkan 时间线信号量 API 所需的等待之前信号行为。
或者,可以使用 DRM_IOCTL_SYNCOBJ_EVENTFD
在不阻塞的情况下等待:当 syncobj 时,将发出 eventfd 信号。 这对于将等待集成到事件循环中很有用。
syncobj 的导入/导出¶
DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE
和 DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD
提供了两种用于导入/导出 syncobj 的机制。
第一个让客户端将整个 syncobj 导入或导出到文件描述符。 这些 fd 是不透明的,除了在进程之间传递 syncobj 之外,没有其他用例。 所有导出的文件描述符和作为导入这些文件描述符的结果而创建的任何 syncobj 句柄都拥有对同一底层 struct drm_syncobj
的引用,并且可以在与之共享它的所有进程中持久地使用 syncobj。 仅当最后一个引用被删除时,才会释放 syncobj。 与 dma-buf 不同,导入 syncobj 会为每次导入创建一个新句柄(带有自己的引用),而不是去重。 此持久导入/导出的主要用例是共享 Vulkan 栅栏和信号量。
第二种导入/导出机制,由 DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE
或 DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE
指示,让客户端从/向 sync_file
导入/导出 syncobj 的当前栅栏。 当 syncobj 导出到同步文件时,该同步文件会在导出时包装 syncobj 的栅栏,并且稍后对 syncobj 的任何信号或重置操作都不会影响导出的同步文件。 当同步文件导入到 syncobj 中时,syncobj 的栅栏将设置为该同步文件包装的栅栏。 因为同步文件是不可变的,所以重置或发出 syncobj 信号不会影响已将栅栏导入到 syncobj 中的任何同步文件。
时间线 syncobj 中时间线点的导入/导出¶
DRM_IOCTL_SYNCOBJ_TRANSFER
提供了一种机制,用于将给定 u64 点的 syncobj 的 struct dma_fence_chain
传输到另一个 syncobj 中的另一个 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 列表。
lock
保护
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
同步对象。
描述
如果 drm_syncobj.fence
包含在 obj 中且不为 NULL,则此函数会获取对它的额外引用。在没有已持有引用的情况下调用此函数是非法的。无需锁。
返回值
obj 的 fence,如果没有则为 NULL。
-
struct drm_syncobj *drm_syncobj_find(struct drm_file *file_private, u32 handle)¶
查找并引用同步对象。
参数
struct drm_file *file_private
drm 文件私有指针
u32 handle
要查找的同步对象句柄。
描述
返回指向句柄指向的 syncobj 的引用,如果找不到则返回 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)¶
向同步对象添加新的时间线点
参数
struct drm_syncobj *syncobj
要添加时间线点的同步对象
struct dma_fence_chain *chain
用于添加点的链节点
struct dma_fence *fence
要封装在链节点中的 fence
uint64_t point
用于点的序列号
描述
将链节点作为新的时间线点添加到同步对象。
-
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
超时 nsec 分量,单位为 ns,0 表示轮询
描述
从 sec/nsec 中的绝对时间计算 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);
有关更多详细信息,请参见结构体 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
控制锁定行为的标志
ticket
用于获取锁的 WW ticket
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 在锁定对象的数量内,则指向与 index 对应的锁定对象。否则为 NULL。
-
drm_exec_for_each_locked_object¶
drm_exec_for_each_locked_object (exec, index, obj)
迭代所有锁定的对象
参数
exec
drm_exec 对象
index
迭代的无符号长整型索引
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 对象
index
迭代的无符号长整型索引
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)¶
在此 exec 上下文中解锁 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
要保留多少个 fence
描述
通过锁定 GEM 对象并保留 fence 插槽来准备 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 对象上保留的 fence 数量
描述
准备数组中的所有 GEM 对象,在第一个错误时中止。锁定每个 GEM 对象后,在其上保留 num_fences。
返回值
争用时为 -EDEADLOCK;如果对象已被锁定,则为 -EALREADY;内存分配失败时为 -ENOMEM;成功时为零。
GPU 调度程序¶
概述¶
GPU 调度程序提供了实体,允许用户空间将作业推送到软件队列中,然后这些队列将在硬件运行队列上进行调度。软件队列之间有一个优先级。调度程序使用 FIFO 从运行队列中选择实体。调度程序提供作业之间的依赖关系处理功能。驱动程序应为后端操作(如将作业提交到硬件运行队列、返回作业的依赖关系等)向调度程序提供回调函数。
调度程序的组织结构如下
每个硬件运行队列都有一个调度程序
每个调度程序都有多个具有不同优先级的运行队列(例如,HIGH_HW、HIGH_SW、KERNEL、NORMAL)
每个调度程序运行队列都有一个要调度的实体队列
实体本身维护一个将在硬件上调度的作业队列。
实体中的作业始终按照它们被推送的顺序进行调度。
请注意,一旦从实体队列中获取一个作业并将其推送到硬件(即挂起队列)后,不得再通过作业实体指针引用该实体。
流控制¶
DRM GPU 调度程序提供了一种流控制机制,用于调节从调度程序实体获取的作业的执行速率。
在此上下文中,drm_gpu_scheduler
跟踪驱动程序指定的信用额度限制,该限制代表此调度程序的容量和一个信用计数;每个 drm_sched_job
都携带驱动程序指定的信用额度。
一旦执行了一个作业(但尚未完成),作业的信用额度就会计入调度程序的信用计数,直到作业完成。如果通过再执行一个作业,调度程序的信用计数将超过调度程序的信用额度限制,则不会执行该作业。相反,调度程序将等待信用计数减少到足以不溢出其信用额度限制。这意味着等待先前执行的作业。
调度程序函数参考¶
-
DRM_SCHED_FENCE_DONT_PIPELINE¶
DRM_SCHED_FENCE_DONT_PIPELINE
防止依赖关系流水线化
描述
在此调度程序 fence 上设置此标志可以防止依赖于此 fence 的作业的流水线化。换句话说,在将依赖作业推送到硬件队列之前,我们总是插入一个完整的 CPU 往返。
-
DRM_SCHED_FENCE_FLAG_HAS_DEADLINE_BIT¶
DRM_SCHED_FENCE_FLAG_HAS_DEADLINE_BIT
已设置 fence 截止日期提示
描述
因为我们可能在后备硬件 fence 创建之前设置截止时间提示,所以我们需要跟踪是否已经设置了截止时间。
-
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
保护。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_schedulers 的数量。
priority
实体的优先级。可以通过调用
drm_sched_entity_set_priority()
来修改此值。受 lock 保护。job_queue
此实体的作业列表。
fence_seq
随着每个新的
drm_sched_fence
的线性递增序列号,它是实体的一部分。FIXME:
drm_sched_job_arm()
的调用者需要确保正确的锁定,这不需要是原子的。fence_context
属于此实体的所有 fence 的唯一上下文。
drm_sched_fence.scheduled
使用 fence_context,但drm_sched_fence.finished
使用 fence_context + 1。dependency
作业队列顶部的作业的依赖 fence。
cb
上述依赖 fence 的回调。
guilty
指向实体的 guilty。
last_scheduled
指向上次调度的作业的完成 fence。仅由调度程序线程写入,如果队列为空,则可以从
drm_sched_job_arm()
无锁访问。last_user
将作业推送到实体的最后一个组领导者。
stopped
将实体标记为从 rq 中删除,并注定要终止。这是通过调用
drm_sched_entity_flush()
和drm_sched_fini()
设置的。entity_idle
当实体未被使用时发出信号,用于在
drm_sched_entity_fini()
中对实体清理进行排序。oldest_job_waiting
标记 SW 队列中最早等待的作业
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 所属的调度程序。
lock
保护 entities、rb_tree_root 和 current_entity。
current_entity
要调度的实体。
entities
要调度的实体列表。
rb_tree_root
用于 FIFO 调度的基于时间的实体优先级队列的根
描述
运行队列是一组实体,用于调度一个特定环的命令提交。它实现了调度策略,该策略选择下一个从中发出命令的实体。
-
struct drm_sched_fence¶
与作业调度对应的 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
此 fence 将由调度程序在调度作业时发出信号。
finished
此 fence 将由调度程序在作业完成后发出信号。
在为作业设置 out fence 时,应使用此 fence,因为它在
drm_sched_job_init()
上立即可用,并且驱动程序从 run_job() 返回的 fence 在依赖项解决之前不会被创建。deadline
在
drm_sched_fence.finished
上设置的截止时间,可能需要传播到drm_sched_fence.parent
parent
在硬件上调度作业时,由
drm_sched_backend_ops.run_job
返回的 fence。一旦父项发出信号,我们就发出drm_sched_fence.finished
fence。sched
作业所属的调度程序实例。
lock
scheduled 和 finished fence 使用的锁。
owner
用于调试的作业所有者
-
struct drm_sched_job¶
要由实体运行的作业。
定义:
struct drm_sched_job {
u64 id;
ktime_t submit_ts;
struct drm_gpu_scheduler *sched;
struct drm_sched_fence *s_fence;
struct drm_sched_entity *entity;
enum drm_sched_priority s_priority;
u32 credits;
unsigned int last_dependency;
atomic_t karma;
struct spsc_node queue_node;
struct list_head list;
union {
struct dma_fence_cb finish_cb;
struct work_struct work;
};
struct dma_fence_cb cb;
struct xarray dependencies;
};
成员
id
分配给在调度程序上调度的每个作业的唯一 id。
submit_ts
作业推送到实体队列的时间。
sched
此作业将要或将要在其上调度的调度程序。由
drm_sched_job_arm()
设置。有效直到 drm_sched_backend_ops.free_job() 完成。s_fence
包含用于作业调度的 fence。
entity
此作业所属的实体。
s_priority
作业的优先级。
credits
此作业对调度程序贡献的信用数量
last_dependency
跟踪 dependencies,因为它们会发出信号
karma
每次由该作业引起的挂起都会增加。如果此值超过调度程序的挂起限制,则该作业将被标记为 guilty,并且不会进一步调度。
queue_node
用于将此结构附加到实体中的作业队列。
list
作业参与“pending”和“done”列表。
{unnamed_union}
anonymous
finish_cb
完成 fence 的回调。
work
帮助将作业终止重新调度到不同的上下文。
cb
s_fence 中父 fence 的回调。
dependencies
包含此作业的
struct dma_fence
作为依赖项,请参阅drm_sched_job_add_dependency()
和drm_sched_job_add_implicit_dependencies()
。
描述
作业由驱动程序使用 drm_sched_job_init()
创建,并且一旦希望调度程序调度该作业,就应调用 drm_sched_entity_push_job()
。
-
enum drm_gpu_sched_stat¶
调度程序的状态
常量
DRM_GPU_SCHED_STAT_NONE
保留。请勿使用。
DRM_GPU_SCHED_STAT_NOMINAL
操作成功。
DRM_GPU_SCHED_STAT_ENODEV
错误:设备不再可用。
-
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);
};
成员
prepare_job
当调度程序正在考虑接下来调度此作业时调用,以获取另一个
struct dma_fence
,以便此作业可以阻塞。一旦它返回 NULL,就可以调用 run_job()。如果不需要对依赖项进行额外的准备,则可以为 NULL。当作业被终止而不是运行时跳过。
run_job
一旦所有依赖项都已解决,就会调用以执行作业。
sched_job:要运行的作业
已弃用的
drm_sched_resubmit_jobs()
(由struct drm_sched_backend_ops
.timedout_job 调用)可以使用相同的参数再次调用此函数。不鼓励使用此方法,因为它违反了 dma_fence 规则,特别是dma_fence_init()
必须第二次在已初始化的 fence 上调用。此外,这是危险的,因为尝试分配内存可能会与等待重置完成的内存管理代码发生死锁。TODO:记录驱动程序应该做什么/使用什么来代替。
此方法在工作队列上下文中调用 - 可以是从驱动程序通过
drm_sched_init()
传递的 submit_wq,或者,如果驱动程序传递了 NULL,则调度程序分配的单独的有序工作队列。请注意,调度程序期望从回调中“继承”其自己的对此 fence 的引用。它不会在其上调用额外的
dma_fence_get()
。因此,此回调必须为调度程序获取一个引用,并为驱动程序的各自需求获取额外的引用。返回值:* 成功时:dma_fence 驱动程序必须在硬件完成作业后发出信号(“硬件 fence”)。* 失败时:NULL 或 ERR_PTR。
timedout_job
当作业执行时间过长时调用,以触发 GPU 恢复。
sched_job:已超时的作业
驱动程序通常发出重置以从 GPU 挂起中恢复。此过程看起来非常不同,具体取决于使用的是固件还是硬件调度程序。
对于固件调度程序,每个环都有一个调度程序,每个调度程序都有一个实体。因此,采取的步骤通常如下所示
使用
drm_sched_stop()
停止调度程序。这将暂停调度程序工作队列并取消超时工作,从而保证在删除环时不会排队任何内容。删除环。固件将确保硬件的相应部分已重置,并且其他环不受影响。
终止实体和关联的调度程序。
对于硬件调度程序,调度程序实例将来自一个或多个实体的作业调度到一个环。这意味着与受影响的调度程序关联的所有实体都无法被拆除,因为这实际上也会影响未提交错误作业的无辜用户空间进程(例如)。
因此,使用硬件调度程序进行恢复的过程应如下所示
使用
drm_sched_stop()
停止受重置影响的所有调度程序。终止错误作业源自的实体。
在所有错误的环上发出 GPU 重置(驱动程序特定)。
通过将作业重新提交到仍然处于活动状态的实体来重新提交受影响的所有调度程序上的作业。
使用
drm_sched_start()
重新启动在步骤 #1 中停止的所有调度程序。
请注意,某些 GPU 具有不同的硬件队列,但需要全局重置 GPU,这需要在不同调度程序的超时处理程序之间进行额外的同步。实现此同步的一种方法是在驱动程序级别创建一个有序工作队列(使用
alloc_ordered_workqueue()
),并将此队列作为drm_sched_init()
的 timeout_wq 参数传递。这将保证超时处理程序按顺序执行。返回值:调度程序的状态,由
enum drm_gpu_sched_stat
定义free_job
一旦作业的 finished 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
一旦作业引起的挂起超过此限制,它将被标记为 guilty,并且将不再被考虑进行调度。
score
帮助负载均衡器选择空闲调度的分数
_score
当驱动程序未提供分数时使用的分数
ready
标记底层硬件是否准备好工作
free_guilty
超时处理程序释放 guilty 作业的命中。
pause_submit
暂停 submit_wq 上 work_run_job 的排队
own_submit_wq
调度程序拥有 submit_wq 的分配
dev
描述
为每个硬件环实现一个调度程序。
-
struct drm_sched_init_args¶
用于初始化 DRM GPU 调度程序的参数
定义:
struct drm_sched_init_args {
const struct drm_sched_backend_ops *ops;
struct workqueue_struct *submit_wq;
struct workqueue_struct *timeout_wq;
u32 num_rqs;
u32 credit_limit;
unsigned int hang_limit;
long timeout;
atomic_t *score;
const char *name;
struct device *dev;
};
成员
ops
驱动程序提供的后端操作
submit_wq
用于提交的工作队列。如果为 NULL,则会分配并使用一个有序 wq。
timeout_wq
用于超时工作的工作队列。如果为 NULL,则使用 system_wq。
num_rqs
运行队列的数量。这最多可能是 DRM_SCHED_PRIORITY_COUNT,因为通常每个优先级都有一个运行队列,但可能更少。
credit_limit
此调度程序可以从所有作业中保存的信用数量
hang_limit
允许作业在被丢弃之前挂起的次数。此机制已弃用。将其设置为 0。
timeout
提交的作业的超时值(以 jiffies 为单位)。
score
与其他调度程序共享的分数原子。可能为 NULL。
name
名称(通常是驱动程序的名称)。用于调试
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
在待处理 fence 上设置的错误
描述
此函数通常用于重置恢复(有关详细信息,请参阅 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()
文档。
驱动程序必须确保 drm_sched_job_cleanup()
如果此函数成功返回,即使在调用 drm_sched_job_arm()
之前中止 job 时也是如此。
请注意,此函数不会为 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
或需要跟踪此作业完成情况的其他位置。它还初始化序列号,序列号是 fence 排序的基础。
有关锁定注意事项,请参阅 drm_sched_entity_push_job()
文档。
一旦调用此函数,您必须 使用 drm_sched_entity_push_job()
提交 job。
只有在 drm_sched_job_init()
成功调用后才能调用此函数。
-
int drm_sched_job_add_dependency(struct drm_sched_job *job, struct dma_fence *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 的 fence 添加为作业依赖项
参数
struct drm_sched_job *job
要添加依赖项的调度程序作业
struct drm_file *file
drm 文件私有指针
u32 handle
要查找的 syncobj 句柄
u32 point
时间线点
描述
这会将与给定 syncobj 匹配的 fence 添加到 job。
返回值
成功时返回 0,否则返回扩展数组失败时的错误。
-
int drm_sched_job_add_resv_dependencies(struct drm_sched_job *job, struct dma_resv *resv, enum dma_resv_usage usage)¶
将 resv 中的所有 fences 添加到作业中
参数
struct drm_sched_job *job
要添加依赖项的调度程序作业
struct dma_resv *resv
要从中获取 fences 的 dma_resv 对象
enum dma_resv_usage usage
用于过滤 fences 的 dma_resv_usage
描述
这会将来自 resv 的与给定 usage 匹配的所有 fences 添加到 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
作业是否可能写入对象(因此我们需要依赖于 reservation 对象中的共享 fences)。
描述
这应该在调用 drm_gem_lock_reservations()
之后,在作业中使用的 GEM 对象数组上,但在使用您自己的 fences 更新 reservations 之前调用。
返回值
成功时返回 0,否则返回扩展数组失败时的错误。
-
bool drm_sched_job_has_dependency(struct drm_sched_job *job, struct dma_fence *fence)¶
检查 fence 是否是作业的依赖项
参数
struct drm_sched_job *job
要检查的调度程序作业
struct dma_fence *fence
要查找的 fence
返回值
如果在作业的依赖项中找到 fence,则为 True,否则为 false。
-
void drm_sched_job_cleanup(struct drm_sched_job *job)¶
清理调度程序作业资源
参数
struct drm_sched_job *job
要清理的调度程序作业
描述
清理使用 drm_sched_job_init()
分配的资源。
如果在调用 drm_sched_job_arm()
之前中止 job,则驱动程序应从其错误展开代码中调用此函数。
drm_sched_job_arm()
是一个不可返回的点,因为它初始化了 fences 及其序列号等。一旦调用了该函数,您必须使用 drm_sched_entity_push_job()
提交它,并且不能通过调用 drm_sched_job_cleanup()
简单地中止它。
此函数应在 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 sched
参数
struct drm_gpu_scheduler **sched_list
drm_gpu_schedulers 列表
unsigned int num_sched_list
sched_list 中 drm_gpu_schedulers 的数量
描述
返回负载最小的 sched 的指针,如果没有任何 drm_gpu_schedulers 准备就绪,则返回 NULL
-
int drm_sched_init(struct drm_gpu_scheduler *sched, const struct drm_sched_init_args *args)¶
初始化 gpu 调度程序实例
参数
struct drm_gpu_scheduler *sched
调度程序实例
const struct drm_sched_init_args *args
调度程序初始化参数
描述
成功时返回 0,否则返回错误代码。
-
void drm_sched_fini(struct drm_gpu_scheduler *sched)¶
销毁 gpu 调度程序
参数
struct drm_gpu_scheduler *sched
调度程序实例
描述
分解并清理调度程序。
这会停止通过 drm_sched_backend_ops.run_job() 向硬件提交新作业。 因此,drm_sched_backend_ops.free_job() 将不会为 drm_gpu_scheduler.pending_list 中仍有的所有作业调用。 目前没有解决此问题的方法。 因此,由驱动程序确保
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”作业导致的每次挂起时递增。 如果这超过了调度程序的挂起限制,则会将相应的 sched 实体标记为 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 ring 时使用的上下文实体。
参数
struct drm_sched_entity *entity
要初始化的调度程序实体
enum drm_sched_priority priority
实体的优先级
struct drm_gpu_scheduler **sched_list
可以从该实体提交作业的 drm scheds 列表
unsigned int num_sched_list
sched_list 中 drm sched 的数量
atomic_t *guilty
当发现此队列上的作业因超时而 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)¶
修改实体的 sched
参数
struct drm_sched_entity *entity
要初始化的调度程序实体
struct drm_gpu_scheduler **sched_list
将替换现有 entity->sched_list 的新 drm scheds 列表
unsigned int num_sched_list
sched_list 中 drm sched 的数量
描述
请注意,必须在与 drm_sched_job_arm()
和 drm_sched_entity_push_job()
相同的通用锁下调用此函数,或者驱动程序需要通过其他方式保证永远不会在可以将新作业推送到 entity 时调用此函数。
-
int drm_sched_entity_error(struct drm_sched_entity *entity)¶
返回上次调度作业的错误
参数
struct drm_sched_entity *entity
要检查的调度程序实体
描述
机会性地返回上次调度作业的错误。 当新作业推送到 hw 时,结果可以随时更改。
-
long drm_sched_entity_flush(struct drm_sched_entity *entity, long timeout)¶
刷新上下文实体
参数
struct drm_sched_entity *entity
调度程序实体
long timeout
等待 Q 在 jiffies 中变为空的时间。
描述
将 drm_sched_entity_fini()
拆分为两个函数,第一个函数执行等待,从运行队列中删除实体,并在进程被杀死时返回错误。
返回输入超时剩余的 jiffies 时间
-
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
要提交的作业
注意
为了保证插入队列的顺序与作业的 fence 序列号匹配,应在 drm_sched_job_arm()
下,为 struct drm_sched_entity
(在 drm_sched_job_init()
中为 sched_job 设置)的通用锁下调用此函数。