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 進行裝置記憶體分配。

描述

初始化 struct ttm_device

返回值

!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

引數

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_item 向下轉換為 struct ttm_resource

引數

struct ttm_lru_item *item

要向下轉換的 struct ttm_lru_item

返回值

指向嵌入的 struct ttm_resource 的指標

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

sgiomap 的第一個偏移量。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)

迭代所有資源

引數

cursor

當前位置的 struct ttm_resource_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

The struct ttm_device

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

引數

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

快取的頁面保護用於對映。

bool ttm_tt_is_swapped(const struct ttm_tt *tt)

ttm_tt 是否已換出或備份

引數

const struct ttm_tt *tt

struct ttm_tt

返回值

如果已交換或備份,則為 true,否則為 false。

bool ttm_tt_is_backed_up(const struct ttm_tt *tt)

ttm_tt 是否已備份

引數

const struct ttm_tt *tt

struct ttm_tt

返回值

如果已交換或備份,則為 true,否則為 false。

void ttm_tt_clear_backed_up(struct ttm_tt *tt)

清除 ttm_tt 備份狀態

引數

struct ttm_tt *tt

struct ttm_tt

描述

驅動程式可以使用此函式來清除備份狀態,例如,在銷燬或重新驗證已清除的 tt 之前。

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_tt

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:記憶體不足。

void ttm_tt_fini(struct ttm_tt *ttm)

引數

struct ttm_tt *ttm

ttm_tt 結構。

描述

釋放 ttm_tt 結構的記憶體

void ttm_tt_destroy(struct ttm_device *bdev, struct ttm_tt *ttm)

引數

struct ttm_device *bdev

此物件所屬的 ttm_device

struct ttm_tt *ttm

struct ttm_tt

描述

取消繫結、解除安裝並銷燬常見的 struct ttm_tt

int ttm_tt_swapin(struct ttm_tt *ttm)

引數

struct ttm_tt *ttm

struct ttm_tt

描述

換入先前換出的 ttm_tt。

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 中的所有頁面

void ttm_tt_mark_for_clear(struct 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 的指標。

int ttm_tt_setup_backup(struct ttm_tt *tt)

為 ttm_tt 分配並分配備份結構

引數

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,否則為負錯誤程式碼。

void ttm_pool_free(struct ttm_pool *pool, struct ttm_tt *tt)

從 ttm_tt 物件中釋放後備頁面

引數

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

描述

初始化池及其池型別。

void ttm_pool_fini(struct ttm_pool *pool)

清理池

引數

struct ttm_pool *pool

要清理的池

描述

釋放池中的所有頁面,並從全域性收縮器中取消註冊型別。

int ttm_pool_debugfs(struct ttm_pool *pool, struct seq_file *m)

池的 Debugfs 轉儲函式

引數

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.statusdrm_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_opsmmap 回撥必須設定 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)都將被清除。

drm_device.object_name_lock 保護。

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 控制代碼時,我們會中斷生成的引用迴圈。

drm_device.object_name_lock 保護。

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 的引用。

bool drm_gem_object_is_shared_for_memory_stats(struct drm_gem_object *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

drm_gem_object

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_gem_objectdrm_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物件,當它初始化失敗時

int drm_gem_handle_delete(struct drm_file *filp, u32 handle)

刪除給定的檔案私有控制代碼

引數

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 drm_gem_object *obj

GEM 緩衝區物件

描述

這將釋放obj使用的任何結構和資源,並且是drm_gem_object_init()的逆操作。

void drm_gem_object_free(struct kref *kref)

釋放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。

int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)

GEM物件的記憶體對映例程

引數

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

預設 shmem GEM 操作

描述

此宏為設定 drm_driver 結構體中的 shmem GEM 操作提供了一個快捷方式。

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_driverDRM_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_VRAMDRM_GEM_VRAM_PL_FLAG_SYSTEMdrm_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_VRAMTTM_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_driver 的預設回撥函式

描述

使用 VRAM MM 和 GEM VRAM 的驅動程式可以使用此宏初始化 struct drm_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 ttm_device *bdev

TTM BO 裝置

返回值

struct drm_vram_mm 的包含例項

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_dumbstruct 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()

void drm_vram_mm_debugfs_init(struct drm_minor *minor)

註冊 VRAM MM debugfs 檔案。

引數

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)

實現結構 drm_driver.dumb_map_offset

引數

struct drm_file *file

DRM 檔案指標。

struct drm_device *dev

DRM 裝置。

uint32_t handle

GEM 控制代碼

uint64_t *offset

成功時返回對映的記憶體偏移量

描述

為基於 TTM 的 GEM 驅動程式提供 struct drm_driver.dumb_map_offset 的實現。TTM 在內部分配偏移量,並且 drm_gem_ttm_dumb_map_offset() 為 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_offsetsize 給出。兩者均解釋為頁碼,而不是位元組。

從管理器新增/刪除節點在內部鎖定,並防止併發訪問。但是,節點分配和銷燬留給呼叫者。在呼叫 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。

int drm_vma_node_allow(struct drm_vma_offset_node *node, struct drm_file *tag)

將開啟的檔案新增到允許使用者列表

引數

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)

void drm_vma_node_revoke(struct drm_vma_offset_node *node, struct drm_file *tag)

從允許使用者列表中刪除開啟的檔案

引數

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.exportdrm_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。

void drm_gem_dmabuf_release(struct dma_buf *dma_buf)

GEM 的 dma_buf 釋放實現

引數

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 回撥。

int drm_gem_dmabuf_vmap(struct dma_buf *dma_buf, struct iosys_map *map)

GEM 的 dma_buf vmap 實現

引數

struct dma_buf *dma_buf

要對映的緩衝區

struct iosys_map *map

緩衝區的虛擬地址

描述

設定核心虛擬對映。這可以用作 dma_buf_ops.vmap 回撥。呼叫 drm_gem_object_funcs.vmap 進行裝置特定處理。核心虛擬地址在 map 中返回。

成功時返回 0,否則返回負 errno 程式碼。

void drm_gem_dmabuf_vunmap(struct dma_buf *dma_buf, struct iosys_map *map)

GEM 的 dma_buf vunmap 實現

引數

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 來設定對映。

int drm_gem_dmabuf_mmap(struct dma_buf *dma_buf, struct vm_area_struct *vma)

GEM 的 dma_buf 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。

bool drm_mm_initialized(const struct drm_mm *mm)

檢查分配器是否已初始化

引數

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。

bool drm_mm_clean(const struct drm_mm *mm)

檢查分配器是否乾淨

引數

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__

結束偏移量,最後一個節點將在此之前開始(但可能會重疊)

描述

此迭代器遍歷範圍分配器中位於 startend 之間的所有節點。它的實現方式與 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。

void drm_mm_init(struct drm_mm *mm, u64 start, u64 size)

初始化 drm-mm 分配器

引數

struct drm_mm *mm

要初始化的 drm_mm 結構

u64 start

mm 管理的範圍的起點

u64 size

mm 管理的範圍的終點

描述

請注意,在呼叫此函式之前,必須將 mm 清除為 0。

void drm_mm_takedown(struct drm_mm *mm)

清理 drm_mm 分配器

引數

struct drm_mm *mm

要清理的 drm_mm 分配器

描述

請注意,在未清理的分配器上呼叫此函式是一個錯誤。

void drm_mm_print(const struct drm_mm *mm, struct drm_printer *p)

列印分配器狀態

引數

const struct drm_mm *mm

要列印的 drm_mm 分配器

struct drm_printer *p

要使用的 DRM 印表機

DRM GPUVM

概述

DRM GPU VA 管理器由 struct drm_gpuvm 表示,它跟蹤 GPU 的虛擬地址 (VA) 空間,並管理由 drm_gpuva 物件表示的相應虛擬對映。它還跟蹤對映的支援 drm_gem_object 緩衝區。

drm_gem_object 緩衝區維護一個 drm_gpuva 物件列表,該列表表示使用此 drm_gem_object 作為支援緩衝區的所有的 GPU VA 對映。

GPU VA 可以標記為稀疏,以便驅動程式可以使用 GPU VA 來跟蹤稀疏 PTE,以支援 Vulkan “稀疏資源”。

GPU VA 管理器在內部使用 rb 樹來管理 GPU 虛擬地址空間中的 drm_gpuva 對映。

drm_gpuvm 結構包含一個特殊的 drm_gpuva,表示核心保留的 VA 空間部分。此節點與 GPU VA 管理器例項一起初始化,並在 GPU VA 管理器銷燬時刪除。

在典型的應用程式驅動程式中,會將 struct drm_gpuvmstruct 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_gpuvmdrm_gem_object 的組合。每個這樣的組合應該是唯一的。這由 API 透過 drm_gpuvm_bo_obtain()drm_gpuvm_bo_obtain_prealloc() 確保,它們首先檢視相應的 drm_gem_objectdrm_gpuvm_bos 列表,以查詢此特定組合的現有例項。如果不存在,則建立一個新例項並將其連結到 drm_gem_object

drm_gpuvm_bo 結構,由於對於給定的 drm_gpuvm 是唯一的,因此也用作 drm_gpuvm 的外部和逐出物件列表的條目。維護這些列表是為了加速 dma-resv 鎖的鎖定和在 drm_gpuvm 中繫結的逐出物件的驗證。例如,可以透過呼叫 drm_gpuvm_exec_lock() 來鎖定給定 drm_gpuvm 的所有 drm_gem_objectdma_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_objectdma_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() 實現的生成對映之間的基本關係 - 它沒有涵蓋這些的任何任意組合。

  1. 請求的對映是相同的。替換它,但指示可以保留支援 PTE。

         0     a     1
    old: |-----------| (bo_offset=n)
    
         0     a     1
    req: |-----------| (bo_offset=n)
    
         0     a     1
    new: |-----------| (bo_offset=n)
    
  2. 請求的對映是相同的,但 BO 偏移量除外,因此替換對映。

         0     a     1
    old: |-----------| (bo_offset=n)
    
         0     a     1
    req: |-----------| (bo_offset=m)
    
         0     a     1
    new: |-----------| (bo_offset=m)
    
  3. 請求的對映是相同的,但支援 BO 除外,因此替換對映。

         0     a     1
    old: |-----------| (bo_offset=n)
    
         0     b     1
    req: |-----------| (bo_offset=n)
    
         0     b     1
    new: |-----------| (bo_offset=n)
    
  4. 現有對映是請求對映的左對齊子集,因此替換現有對映。

         0  a  1
    old: |-----|       (bo_offset=n)
    
         0     a     2
    req: |-----------| (bo_offset=n)
    
         0     a     2
    new: |-----------| (bo_offset=n)
    

    注意

    對於具有不同 BO 和/或非連續 BO 偏移量的請求,我們希望看到相同的結果。

  5. 請求的對映的範圍是現有對映的左對齊子集,但由不同的 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 偏移量的請求,我們希望看到相同的結果。

  6. 現有對映是請求對映的超集。拆分它,但指示可以保留支援 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)
    
  7. 請求的對映的範圍是現有對映的右對齊子集,但由不同的 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)
    
  8. 現有對映是請求對映的超集。拆分它,但指示可以保留支援 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)
    
  9. 現有對映在結尾處被請求的對映覆蓋,該對映由不同的 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)
    
  10. 現有對映被請求的對映覆蓋,兩者都具有具有連續偏移量的相同支援 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)
    
  11. 請求的對映的範圍是具有不同支援 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)
    
  12. 請求的對映是現有對映的連續子集。拆分它,但指示可以保留支援 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)
    
  13. 現有對映是請求對映的右對齊子集,因此替換現有對映。

               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 的請求,我們希望看到相同的結果。

  14. 現有對映是請求對映的中心子集,因此替換現有對映。

               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 的請求,我們希望看到相同的結果。

  15. 現有的對映與請求的對映在起始處重疊,而請求的對映由不同的 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_gpuvmdrm_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 以滿足給定的對映或取消對映請求,以及如何利用它們。

以下程式碼嚴格限制於說明通用使用模式。為了保持簡單性,它不使用任何通用程式碼的抽象,具有柵欄訊號的關鍵路徑的不同(非同步)階段,任何其他助手或在釋放記憶體和刪除先前獲取的鎖方面的錯誤處理。

  1. 獲取 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;
    }
    
  2. 接收每個 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 的標誌

常量

DRM_GPUVA_INVALIDATED

指示 drm_gpuva 的後備 GEM 無效的標誌。

DRM_GPUVA_SPARSE

指示 drm_gpuva 是稀疏對映的標誌。

DRM_GPUVA_USERBITS

使用者定義的位

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_objectdrm_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 相關聯。

通常,此結構嵌入在更大的驅動程式結構中。

void drm_gpuva_invalidate(struct drm_gpuva *va, bool invalidate)

設定此 drm_gpuva 的後備 GEM 是否無效

引數

struct drm_gpuva *va

要設定無效標誌的 drm_gpuva

bool invalidate

指示 drm_gpuva 是否無效

bool drm_gpuva_invalidated(struct drm_gpuva *va)

指示此 drm_gpuva 的後備 BO 是否無效

引數

struct drm_gpuva *va

要檢查的 drm_gpuva

返回值

如果 GPU VA 無效,則為 true,否則為 false

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 引用

引數

struct drm_gpuvm *gpuvm

要獲取其引用的 drm_gpuvm

描述

此函式獲取對 gpuvm 的額外引用。不持有引用就呼叫此函式是非法的。不需要鎖。

返回值

struct drm_gpuvm 指標

bool drm_gpuvm_resv_protected(struct drm_gpuvm *gpuvm)

指示是否設定了 DRM_GPUVM_RESV_PROTECTED

引數

struct drm_gpuvm *gpuvm

drm_gpuvm

返回值

如果設定了 DRM_GPUVM_RESV_PROTECTED,則為 true,否則為 false。

drm_gpuvm_resv

drm_gpuvm_resv (gpuvm__)

返回 drm_gpuvmdma_resv

引數

gpuvm__

drm_gpuvm

返回值

指向 drm_gpuvm 的共享 dma_resv 的指標

drm_gpuvm_resv_obj

drm_gpuvm_resv_obj (gpuvm__)

返回儲存 drm_gpuvmdma_resvdrm_gem_object

引數

gpuvm__

drm_gpuvm

返回值

指向儲存 drm_gpuvm 的共享 dma_resvdrm_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_resvdrm_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_gpuvmkernel_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_gpuvmkernel_alloc_node

drm_gpuvm_for_each_va

drm_gpuvm_for_each_va (va__, gpuvm__)

迭代所有 drm_gpuvas

引數

va__

要在每個迭代步驟中分配的 drm_gpuva

gpuvm__

要遍歷的 drm_gpuvm

描述

此迭代器遍歷與給定 drm_gpuvm 關聯的所有 drm_gpuva 結構。

drm_gpuvm_for_each_va_safe

drm_gpuvm_for_each_va_safe (va__, next__, gpuvm__)

安全地迭代所有 drm_gpuvas

引數

va__

要在每個迭代步驟中分配的 drm_gpuva

next__

另一個 drm_gpuva 用作臨時儲存

gpuvm__

要遍歷的 drm_gpuvm

描述

此迭代器遍歷與給定 drm_gpuvm 關聯的所有 drm_gpuva 結構。它使用 list_for_each_entry_safe() 實現,因此對於元素的刪除是安全的。

struct drm_gpuvm_exec

drm_execdrm_gpuvm 抽象

定義:

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_objectsdma_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 用法

描述

參見 drm_gpuvm_resv_add_fence()

int drm_gpuvm_exec_validate(struct drm_gpuvm_exec *vm_exec)

驗證所有標記為已驅逐的 BO

引數

struct drm_gpuvm_exec *vm_exec

drm_gpuvm_exec 包裝器

描述

參見 drm_gpuvm_validate()

返回值

成功時為 0,失敗時為負錯誤程式碼。

struct drm_gpuvm_bo

表示 drm_gpuvmdrm_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_gpuvmdrm_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 驅逐列表中刪除

引數

struct drm_gem_object *obj

drm_gem_object

bool evict

指示 obj 是否已驅逐

描述

參見 drm_gpuvm_bo_evict()

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;
};

成員

va

要取消對映的 drm_gpuva

keep

指示此 drm_gpuva 在物理上是否與原始對映請求連續。

或者,如果設定了 keep,則驅動程式可以保留此 drm_gpuva 的實際頁表對映,僅新增缺少的頁表條目,並相應地更新 drm_gpuvm

描述

此結構表示 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 用於重新對映後續部分。

如果新對映的起始地址與舊對映的起始地址對齊,或者新對映的結束地址與舊對映的結束地址對齊,則 prevnext 為 NULL。

請注意,使用專用 remap 操作而不是任意 unmap 和 map 操作的原因是讓驅動程式有機會從 unmap 操作的 drm_gpuva 結構(通常嵌入在更大的驅動程式特定結構中)中提取驅動程式特定資料來建立新對映。

struct drm_gpuva_op_prefetch

GPU VA prefetch 操作

定義:

struct drm_gpuva_op_prefetch {
    struct drm_gpuva *va;
};

成員

va

要預取的 drm_gpuva

描述

此結構表示 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

引數

op

要在每個迭代步驟中分配的 drm_gpuva_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)

從給定點向後迭代

引數

op

要在每個迭代步驟中分配的 drm_gpuva_op

ops

要遍歷的 drm_gpuva_ops

描述

此迭代器從給定操作開始,以相反的順序遍歷給定操作列表中的所有操作。

drm_gpuva_for_each_op_reverse

drm_gpuva_for_each_op_reverse (op, ops)

迭代器,用於以相反的順序遍歷 drm_gpuva_ops

引數

op

要在每個迭代步驟中分配的 drm_gpuva_op

ops

要遍歷的 drm_gpuva_ops

描述

此迭代器以相反的順序遍歷給定操作列表中的所有操作

drm_gpuva_first_op

drm_gpuva_first_op (ops)

drm_gpuva_ops 返回第一個 drm_gpuva_op

引數

ops

從中獲取第一個 drm_gpuva_opdrm_gpuva_ops

drm_gpuva_last_op

drm_gpuva_last_op (ops)

drm_gpuva_ops 返回最後一個 drm_gpuva_op

引數

ops

從中獲取最後一個 drm_gpuva_opdrm_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_mapdrm_gpuvm_sm_unmap 的指標匹配。

如果使用 drm_gpuvm_sm_map,則可以為 NULL。

sm_step_remap

drm_gpuvm_sm_mapdrm_gpuvm_sm_unmap 呼叫以拆分現有對映

當需要拆分現有對映時,會呼叫此回撥。當新請求的對映重疊或被現有對映包圍,或者請求部分取消對映現有對映時,就會發生這種情況。

priv 指標與驅動程式傳遞給 drm_gpuvm_sm_mapdrm_gpuvm_sm_unmap 的指標匹配。

如果既不使用 drm_gpuvm_sm_map 也不使用 drm_gpuvm_sm_unmap,則可以為 NULL。

sm_step_unmap

drm_gpuvm_sm_mapdrm_gpuvm_sm_unmap 呼叫以取消對映現有對映

當需要取消對映現有對映時,會呼叫此回撥。當新請求的對映包圍現有對映或請求取消對映現有對映時,就會發生這種情況。

priv 指標與驅動程式傳遞給 drm_gpuvm_sm_mapdrm_gpuvm_sm_unmap 的指標匹配。

如果既不使用 drm_gpuvm_sm_map 也不使用 drm_gpuvm_sm_unmap,則可以為 NULL。

描述

此結構定義了 drm_gpuvm_sm_mapdrm_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_sm_map / drm_gpuvm_sm_unmap 上呼叫的 drm_gpuvm_ops

描述

在使用之前,必須使用此函式初始化 drm_gpuvm

請注意,在呼叫此函式之前,必須將 gpuvm 清零為 0。給定的 name 預計由周圍的驅動程式結構管理。

void drm_gpuvm_put(struct drm_gpuvm *gpuvm)

減少 struct drm_gpuvm 的引用計數

引數

struct drm_gpuvm *gpuvm

要釋放引用的 drm_gpuvm

描述

這會釋放對 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

drm_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

drm_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

drm_gpuvm

struct drm_exec *exec

drm_exec 鎖定上下文

u64 addr

VA 空間內的起始地址

u64 range

在 VA 空間內迭代的範圍

unsigned int num_fences

要保留的 dma_fences 的數量

描述

對於在 addraddr + 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 空間內迭代的範圍

描述

獲取在 addraddr + range 之間對映的所有 drm_gem_objects 的所有 dma-resv 鎖。

返回值

成功時為 0,失敗時為負錯誤程式碼。

int drm_gpuvm_validate(struct drm_gpuvm *gpuvm, struct drm_exec *exec)

驗證所有標記為已驅逐的 BO

引數

struct drm_gpuvm *gpuvm

要驗證已驅逐的 BO 的 drm_gpuvm

struct drm_exec *exec

用於鎖定 GPUVM 的 drm_exec 例項

描述

為在給定的 drm_gpuvm 中對映的所有已驅逐的緩衝區物件呼叫 drm_gpuvm_ops::vm_bo_validate 回撥。

返回值

成功時為 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 *gpuvm

要新增 fence 的 drm_gpuvm

struct drm_exec *exec

drm_exec 鎖定上下文

struct dma_fence *fence

要新增的柵欄

enum dma_resv_usage private_usage

私有 dma-resv 用法

enum dma_resv_usage extobj_usage

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_gpuvmdrm_gem_objectdrm_gpuvm_bo

引數

struct drm_gpuvm *gpuvm

obj 在其中對映的 drm_gpuvm

struct drm_gem_object *obj

gpuvm 中對映的 drm_gem_object

描述

查詢表示給定的 drm_gpuvmdrm_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_gpuvmdrm_gem_objectdrm_gpuvm_bo 的例項

引數

struct drm_gpuvm *gpuvm

obj 在其中對映的 drm_gpuvm

struct drm_gem_object *obj

gpuvm 中對映的 drm_gem_object

描述

查詢表示給定的 drm_gpuvmdrm_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_gpuvmdrm_gem_objectdrm_gpuvm_bo 的例項

引數

struct drm_gpuvm_bo *__vm_bo

預分配的 struct drm_gpuvm_bo

描述

查詢表示給定的 drm_gpuvmdrm_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 驅逐列表或從中移除。

int drm_gpuva_insert(struct drm_gpuvm *gpuvm, struct drm_gpuva *va)

插入一個 drm_gpuva

引數

struct drm_gpuvm *gpuvm

要插入 drm_gpuvadrm_gpuvm

struct drm_gpuva *va

要插入的 drm_gpuva

描述

將具有給定地址和範圍的 drm_gpuva 插入到 drm_gpuvm 中。

使用 GPU VA 空間的迭代安全版本(例如 drm_gpuvm_for_each_va_safe()drm_gpuvm_for_each_va_range_safe())使用此函式是安全的。

返回值

成功時為 0,失敗時為負錯誤程式碼。

void drm_gpuva_remove(struct drm_gpuva *va)

移除一個 drm_gpuva

引數

struct drm_gpuva *va

要移除的 drm_gpuva

描述

這會從底層樹中移除給定的 va

使用 GPU VA 空間的迭代安全版本(例如 drm_gpuvm_for_each_va_safe()drm_gpuvm_for_each_va_range_safe())使用此函式是安全的。

連結一個 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 列表免受併發訪問。

取消連結一個 drm_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_gpuva *drm_gpuva_find(struct drm_gpuvm *gpuvm, u64 addr, u64 range)

查詢一個 drm_gpuva

引數

struct drm_gpuvm *gpuvm

要在其中搜索的 drm_gpuvm

u64 addr

drm_gpuvas 地址

u64 range

drm_gpuvas 範圍

返回值

給定 addr 且具有給定 rangedrm_gpuva

struct drm_gpuva *drm_gpuva_find_prev(struct drm_gpuvm *gpuvm, u64 start)

查詢給定地址之前的 drm_gpuva

引數

struct drm_gpuvm *gpuvm

要在其中搜索的 drm_gpuvm

u64 start

給定 GPU VA 的起始地址

描述

查詢具有給定 start 地址的 GPU VA 之前的相鄰 drm_gpuva

請注意,如果在 GPU VA 對映之間有任何可用空間,則不會返回任何對映。

返回值

指向找到的 drm_gpuva 的指標,如果未找到,則為 NULL

struct drm_gpuva *drm_gpuva_find_next(struct drm_gpuvm *gpuvm, u64 end)

查詢給定地址之後的 drm_gpuva

引數

struct drm_gpuvm *gpuvm

要在其中搜索的 drm_gpuvm

u64 end

給定 GPU VA 的結束地址

描述

查詢具有給定 end 地址的 GPU VA 之後的相鄰 drm_gpuva

請注意,如果在 GPU VA 對映之間有任何可用空間,則不會返回任何對映。

返回值

指向找到的 drm_gpuva 的指標,如果未找到,則為 NULL

bool drm_gpuvm_interval_empty(struct drm_gpuvm *gpuvm, u64 addr, u64 range)

指示 VA 空間的給定間隔是否為空

引數

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

drm_gpuvm

struct drm_gpuva *va

要插入的 drm_gpuva

struct drm_gpuva_op_map *op

用於初始化 vadrm_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

用於初始化 prevnextdrm_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_gpuvadrm_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_RESETDRM_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_HANDLEDRM_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_FILEDRM_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_listev_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() 來釋放該引用。

void drm_syncobj_free(struct kref *kref)

釋放同步物件。

引數

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 物件時,控制流助手繼續。

bool drm_exec_is_contended(struct drm_exec *exec)

檢查爭用

引數

struct drm_exec *exec

drm_exec 物件

描述

如果 drm_exec 物件在鎖定 GEM 物件時遇到一些爭用並且需要清理,則返回 true。

void drm_exec_init(struct drm_exec *exec, u32 flags, unsigned nr)

初始化 drm_exec 物件

引數

struct drm_exec *exec

要初始化的 drm_exec 物件

u32 flags

控制鎖定行為,請參見 DRM_EXEC_* 定義

unsigned nr

物件的初始數量

描述

初始化物件並確保我們可以跟蹤鎖定的物件。

如果 nr 非零,則它將用作初始物件表大小。在任何一種情況下,表都將按需增長(重新分配)。

void drm_exec_fini(struct drm_exec *exec)

完成 drm_exec 物件

引數

struct drm_exec *exec

要完成的 drm_exec 物件

描述

解鎖所有鎖定的物件,刪除對物件的引用並釋放用於跟蹤狀態的所有記憶體。

bool drm_exec_cleanup(struct drm_exec *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 從執行佇列中選擇實體。排程程式提供作業之間的依賴關係處理功能。驅動程式應為後端操作(如將作業提交到硬體執行佇列、返回作業的依賴關係等)向排程程式提供回撥函式。

排程程式的組織結構如下

  1. 每個硬體執行佇列都有一個排程程式

  2. 每個排程程式都有多個具有不同優先順序的執行佇列(例如,HIGH_HW、HIGH_SW、KERNEL、NORMAL)

  3. 每個排程程式執行佇列都有一個要排程的實體佇列

  4. 實體本身維護一個將在硬體上排程的作業佇列。

實體中的作業始終按照它們被推送的順序進行排程。

請注意,一旦從實體佇列中獲取一個作業並將其推送到硬體(即掛起佇列)後,不得再透過作業實體指標引用該實體。

流控制

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 中的實體列表中。

rqdrm_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

保護 entitiesrb_tree_rootcurrent_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 掛起中恢復。此過程看起來非常不同,具體取決於使用的是韌體還是硬體排程程式。

對於韌體排程程式,每個環都有一個排程程式,每個排程程式都有一個實體。因此,採取的步驟通常如下所示

  1. 使用 drm_sched_stop() 停止排程程式。這將暫停排程程式工作佇列並取消超時工作,從而保證在刪除環時不會排隊任何內容。

  2. 刪除環。韌體將確保硬體的相應部分已重置,並且其他環不受影響。

  3. 終止實體和關聯的排程程式。

對於硬體排程程式,排程程式例項將來自一個或多個實體的作業排程到一個環。這意味著與受影響的排程程式關聯的所有實體都無法被拆除,因為這實際上也會影響未提交錯誤作業的無辜使用者空間程序(例如)。

因此,使用硬體排程程式進行恢復的過程應如下所示

  1. 使用 drm_sched_stop() 停止受重置影響的所有排程程式。

  2. 終止錯誤作業源自的實體。

  3. 在所有錯誤的環上發出 GPU 重置(驅動程式特定)。

  4. 透過將作業重新提交到仍然處於活動狀態的實體來重新提交受影響的所有排程程式上的作業。

  5. 使用 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_jobwork_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_wqwork_run_job 的排隊

own_submit_wq

排程程式擁有 submit_wq 的分配

dev

系統 struct device

描述

為每個硬體環實現一個排程程式。

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

要準備的排程程式作業

描述

這準備排程程式作業以供執行。具體來說,它初始化 jobdrm_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 中仍有的所有作業呼叫。 目前沒有解決此問題的方法。 因此,由驅動程式確保

  1. drm_sched_fini() 僅在為所有提交的作業呼叫 drm_sched_backend_ops.free_job() 之後才被呼叫,或者

  2. 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 設定)的通用鎖下呼叫此函式。