DRM 內部原理

本章介紹與驅動程式作者和開發人員相關的 DRM 內部原理,他們致力於為現有驅動程式新增對最新功能的支援。

首先,我們將介紹一些典型的驅動程式初始化要求,例如設定命令緩衝區、建立初始輸出配置以及初始化核心服務。後續章節將更詳細地介紹核心內部原理,提供實現說明和示例。

DRM 層為圖形驅動程式提供多項服務,其中許多服務由它透過 libdrm 提供的應用程式介面驅動,libdrm 是包裝大多數 DRM ioctl 的庫。這些服務包括 vblank 事件處理、記憶體管理、輸出管理、幀緩衝區管理、命令提交和圍欄、掛起/恢復支援和 DMA 服務。

驅動程式初始化

每個 DRM 驅動程式的核心是一個 struct drm_driver 結構體。驅動程式通常靜態初始化一個 drm_driver 結構體,然後將其傳遞給 drm_dev_alloc() 來分配一個裝置例項。在裝置例項完全初始化後,可以使用 drm_dev_register() 註冊該裝置例項(這使其可以從使用者空間訪問)。

struct drm_driver 結構體包含描述驅動程式及其支援的特性的靜態資訊,以及指向 DRM 核心將呼叫以實現 DRM API 的方法的指標。我們將首先介紹 struct drm_driver 靜態資訊欄位,然後將在後面的章節中使用時詳細描述各個操作。

驅動程式資訊

主版本號、次版本號和補丁級別

int major; int minor; int patchlevel; DRM 核心透過主版本號、次版本號和補丁級別三元組來識別驅動程式版本。該資訊在初始化時列印到核心日誌,並透過 DRM_IOCTL_VERSION ioctl 傳遞給使用者空間。

主版本號和次版本號還用於驗證傳遞給 DRM_IOCTL_SET_VERSION 的請求的驅動程式 API 版本。當驅動程式 API 在次版本之間發生更改時,應用程式可以呼叫 DRM_IOCTL_SET_VERSION 來選擇 API 的特定版本。如果請求的主版本號不等於驅動程式主版本號,或者請求的次版本號大於驅動程式次版本號,則 DRM_IOCTL_SET_VERSION 呼叫將返回錯誤。否則,將使用請求的版本呼叫驅動程式的 set_version() 方法。

名稱和描述

char *name; char *desc; char *date; 驅動程式名稱在初始化時列印到核心日誌,用於 IRQ 註冊,並透過 DRM_IOCTL_VERSION 傳遞給使用者空間。

驅動程式描述是一個純粹的資訊性字串,透過 DRM_IOCTL_VERSION ioctl 傳遞給使用者空間,核心中未使用。

模組初始化

此庫提供在模組初始化和關閉期間註冊 DRM 驅動程式的助手函式。提供的助手函式類似於特定於匯流排的模組助手函式,例如 module_pci_driver(),但遵循控制 DRM 驅動程式註冊的附加引數。

以下是在 PCI 總線上為裝置初始化 DRM 驅動程式的示例。

struct pci_driver my_pci_drv = {
};

drm_module_pci_driver(my_pci_drv);

生成的程式碼將測試是否啟用了 DRM 驅動程式並註冊 PCI 驅動程式 my_pci_drv。對於更復雜的模組初始化,您仍然可以在驅動程式中使用 module_init()module_exit()

裝置例項和驅動程式處理

drm 驅動程式的裝置例項由 struct drm_device 表示。這使用 devm_drm_dev_alloc() 分配和初始化,通常來自驅動程式實現的特定於匯流排的 ->probe() 回撥。然後,驅動程式需要初始化 drm 裝置的所有各種子系統,例如記憶體管理、vblank 處理、模式設定支援和初始輸出配置,並顯然初始化所有相應的硬體位。最後,當一切都啟動並執行並準備好供使用者空間使用時,可以使用 drm_dev_register() 釋出裝置例項。

還存在對使用特定於匯流排的助手函式和 drm_driver.load 回撥來初始化裝置例項的已棄用支援。但是,由於向後相容性需要,必須過早地釋出裝置例項,這需要使用不漂亮的全域性鎖定才能安全,因此僅支援尚未轉換為新方案的現有驅動程式。

清理裝置例項時,所有操作都需要反向執行:首先使用 drm_dev_unregister() 取消釋出裝置例項。然後清理在裝置初始化時分配的任何其他資源,並使用 drm_dev_put() 刪除驅動程式對 drm_device 的引用。

請注意,只有在呼叫最終的 drm_dev_put() 時,而不是在驅動程式與底層物理結構 device 解綁時,才必須釋放任何使用者空間可見的分配或資源。最好使用 drm_device 管理的資源與 drmm_add_action()drmm_kmalloc() 和相關的函式。

devres 管理的資源,如 devm_kmalloc(),只能用於與底層硬體裝置直接相關的資源,並且只能在完全受 drm_dev_enter()drm_dev_exit() 保護的程式碼路徑中使用。

顯示驅動程式示例

以下示例顯示了 DRM 顯示驅動程式的典型結構。該示例重點介紹 probe() 函式以及幾乎總是存在的其他函式,並作為 devm_drm_dev_alloc() 的演示。

struct driver_device {
        struct drm_device drm;
        void *userspace_facing;
        struct clk *pclk;
};

static const struct drm_driver driver_drm_driver = {
        [...]
};

static int driver_probe(struct platform_device *pdev)
{
        struct driver_device *priv;
        struct drm_device *drm;
        int ret;

        priv = devm_drm_dev_alloc(&pdev->dev, &driver_drm_driver,
                                  struct driver_device, drm);
        if (IS_ERR(priv))
                return PTR_ERR(priv);
        drm = &priv->drm;

        ret = drmm_mode_config_init(drm);
        if (ret)
                return ret;

        priv->userspace_facing = drmm_kzalloc(..., GFP_KERNEL);
        if (!priv->userspace_facing)
                return -ENOMEM;

        priv->pclk = devm_clk_get(dev, "PCLK");
        if (IS_ERR(priv->pclk))
                return PTR_ERR(priv->pclk);

        // Further setup, display pipeline etc

        platform_set_drvdata(pdev, drm);

        drm_mode_config_reset(drm);

        ret = drm_dev_register(drm);
        if (ret)
                return ret;

        drm_fbdev_{...}_setup(drm, 32);

        return 0;
}

// This function is called before the devm_ resources are released
static int driver_remove(struct platform_device *pdev)
{
        struct drm_device *drm = platform_get_drvdata(pdev);

        drm_dev_unregister(drm);
        drm_atomic_helper_shutdown(drm)

        return 0;
}

// This function is called on kernel restart and shutdown
static void driver_shutdown(struct platform_device *pdev)
{
        drm_atomic_helper_shutdown(platform_get_drvdata(pdev));
}

static int __maybe_unused driver_pm_suspend(struct device *dev)
{
        return drm_mode_config_helper_suspend(dev_get_drvdata(dev));
}

static int __maybe_unused driver_pm_resume(struct device *dev)
{
        drm_mode_config_helper_resume(dev_get_drvdata(dev));

        return 0;
}

static const struct dev_pm_ops driver_pm_ops = {
        SET_SYSTEM_SLEEP_PM_OPS(driver_pm_suspend, driver_pm_resume)
};

static struct platform_driver driver_driver = {
        .driver = {
                [...]
                .pm = &driver_pm_ops,
        },
        .probe = driver_probe,
        .remove = driver_remove,
        .shutdown = driver_shutdown,
};
module_platform_driver(driver_driver);

希望支援裝置拔插(USB、DT 疊加解除安裝)的驅動程式應使用 drm_dev_unplug() 而不是 drm_dev_unregister()。驅動程式必須保護訪問裝置資源的區域,以防止在釋放後使用它們。這可以使用 drm_dev_enter()drm_dev_exit() 完成。但是,存在一個缺點,drm_dev_unplug() 會在呼叫 drm_atomic_helper_shutdown() 之前將 drm_device 標記為已拔插。這意味著如果停用程式碼路徑受到保護,則它們不會在常規驅動程式模組解除安裝時執行,這可能會使硬體保持啟用狀態。

enum switch_power_state

drm 裝置的電源狀態

常量

DRM_SWITCH_POWER_ON

電源狀態為 ON

DRM_SWITCH_POWER_OFF

電源狀態為 OFF

DRM_SWITCH_POWER_CHANGING

電源狀態正在改變

DRM_SWITCH_POWER_DYNAMIC_OFF

已掛起

struct drm_device

DRM 裝置結構體

定義:

struct drm_device {
    int if_version;
    struct kref ref;
    struct device *dev;
    struct device *dma_dev;
    struct {
        struct list_head resources;
        void *final_kfree;
        spinlock_t lock;
    } managed;
    const struct drm_driver *driver;
    void *dev_private;
    struct drm_minor *primary;
    struct drm_minor *render;
    struct drm_minor *accel;
    bool registered;
    struct drm_master *master;
    u32 driver_features;
    bool unplugged;
    struct inode *anon_inode;
    char *unique;
    struct mutex struct_mutex;
    struct mutex master_mutex;
    atomic_t open_count;
    struct mutex filelist_mutex;
    struct list_head filelist;
    struct list_head filelist_internal;
    struct mutex clientlist_mutex;
    struct list_head clientlist;
    bool vblank_disable_immediate;
    struct drm_vblank_crtc *vblank;
    spinlock_t vblank_time_lock;
    spinlock_t vbl_lock;
    u32 max_vblank_count;
    struct list_head vblank_event_list;
    spinlock_t event_lock;
    unsigned int num_crtcs;
    struct drm_mode_config mode_config;
    struct mutex object_name_lock;
    struct idr object_name_idr;
    struct drm_vma_offset_manager *vma_offset_manager;
    struct drm_vram_mm *vram_mm;
    enum switch_power_state switch_power_state;
    struct drm_fb_helper *fb_helper;
    struct dentry *debugfs_root;
};

成員

if_version

設定的最高介面版本

ref

物件引用計數

dev

匯流排裝置的裝置結構體

dma_dev

用於 DMA 操作的裝置。只有在裝置 dev 無法自行執行 DMA 時才需要。否則應為 NULL。呼叫 drm_dev_dma_dev() 獲取 DMA 裝置,而不是直接使用此欄位。呼叫 drm_dev_set_dma_dev() 設定此欄位。

DRM 裝置有時繫結到無法自行執行 DMA 的虛擬裝置。驅動程式應將此欄位設定為相應的 DMA 控制器。

USB 和其他外圍總線上的裝置也無法自行執行 DMA。dma_dev 欄位應指向代表此類裝置執行 DMA 的匯流排控制器。透過 dma-buf 匯入緩衝區時需要。

如果設定,DRM 核心會自動釋放對該裝置的引用。

managed

連結到此 drm_device 的生存期的託管資源,由 ref 跟蹤。

driver

管理裝置的 DRM 驅動程式

dev_private

DRM 驅動程式私有資料。此項已棄用,應保留設定為 NULL。

建議驅動程式使用 devm_drm_dev_alloc() 並將其更大的每個裝置結構體中的 drm_device 結構體嵌入到其中,而不是使用此指標。

primary

主節點。驅動程式不應直接與此互動。可以使用 drm_debugfs_add_file() 註冊 debugfs 介面,sysfs 應直接新增到硬體(而不是字元裝置節點)struct device dev

render

渲染節點。驅動程式永遠不應直接與此互動。驅動程式不應在此節點上的 debugfs 或 sysfs 中公開任何其他介面。

accel

計算加速節點

registered

drm_dev_register()drm_connector_register() 內部使用。

master

此裝置當前活動的 master。受 master_mutex 保護

driver_features

每個裝置的驅動程式特性

驅動程式可以在此處清除特定標誌,以禁止在每個裝置上使用某些特性,同時仍然在所有裝置之間共享單個 struct drm_driver 例項。

unplugged

用於指示裝置是否已拔出的標誌。請參見 drm_dev_enter()drm_dev_is_unplugged()

anon_inode

私有地址空間的 inode

unique

裝置的唯一名稱

struct_mutex

用於其他人(不是 drm_minor.masterdrm_file.is_master)的鎖

TODO:此鎖曾經是 DRM 子系統的 BKL。將鎖移動到 i915 中,i915 是唯一剩餘的使用者。

鎖移動到 i915 中,i915 是唯一剩餘的使用者。

master_mutex

用於 drm_minor.masterdrm_file.is_master 的鎖

open_count

未完成的開啟的檔案使用計數器,受 drm_global_mutex 保護

filelist_mutex

保護 filelist

filelist

使用者空間客戶端列表,透過 drm_file.lhead 連結。

filelist_internal

用於核心客戶端的已開啟 DRM 檔案列表。受 filelist_mutex 保護。

clientlist_mutex

保護 clientlist 訪問。

clientlist

核心客戶端列表。受 clientlist_mutex 保護。

vblank_disable_immediate

如果為 true,當引用計數降至零時,將立即停用 vblank 中斷,而不是透過 vblank 停用計時器。

如果硬體具有帶有高精度時間戳的正常工作的 vblank 計數器(否則存在競爭),並且驅動程式適當使用 drm_crtc_vblank_on()drm_crtc_vblank_off(),則可以將其設定為 true。另請參見 max_vblank_countdrm_crtc_funcs.get_vblank_counterdrm_vblank_crtc_config.disable_immediate

vblank

vblank 跟蹤結構體的陣列,每個 struct drm_crtc 一個。由於歷史原因(vblank 支援早於核心模式設定),它是獨立的,而不是 struct drm_crtc 本身的一部分。必須透過呼叫 drm_vblank_init() 顯式初始化它。

vblank_time_lock

保護 vblank 啟用/停用期間的 vblank 計數和時間更新

vbl_lock

頂級 vblank 引用鎖,包裝低階 vblank_time_lock

max_vblank_count

vblank 暫存器的最大值。此值 + 1 將導致 vblank 暫存器迴繞。vblank 核心使用它來處理迴繞。

如果設定為零,vblank 核心將嘗試透過高精度時間戳猜測在透過高精度時間戳停用 vblank 中斷的時間之間經過的 vblank。這種方法會受到小競爭的影響,並且在較長時間內精度較低,因此始終建議公開硬體 vblank 計數器。

這是靜態配置的裝置範圍最大值。驅動程式可以選擇使用執行時可配置的每個 crtc 值 drm_vblank_crtc.max_vblank_count,在這種情況下,max_vblank_count 必須保留為零。請參見 drm_crtc_set_max_vblank_count(),瞭解如何使用每個 crtc 值。

如果非零,則必須設定 drm_crtc_funcs.get_vblank_counter

vblank_event_list

vblank 事件列表

event_lock

保護 vblank_event_list 和總體事件傳遞。請參見 drm_send_event()drm_send_event_locked()

num_crtcs

此裝置上的 CRTC 數量

mode_config

當前模式配置

object_name_lock

GEM 資訊

object_name_idr

GEM 資訊

vma_offset_manager

GEM 資訊

vram_mm

VRAM MM 記憶體管理器

switch_power_state

客戶端的電源狀態。供支援 switcheroo 驅動程式的驅動程式使用。該狀態在 vga_switcheroo_client_ops.set_gpu_state 回撥中維護

fb_helper

指向 fbdev 模擬結構的指標。由 drm_fb_helper_init() 設定,並由 drm_fb_helper_fini() 清除。

debugfs_root

debugfs 檔案的根目錄。

描述

此結構體表示可能包含多個頭的完整卡。

struct device *drm_dev_dma_dev(struct drm_device *dev)

返回 DRM 裝置的 DMA 裝置

引數

struct drm_device *dev

DRM 裝置

描述

返回給定 DRM 裝置的 DMA 裝置。預設情況下,這是 DRM 裝置的父裝置。請參見 drm_dev_set_dma_dev()

返回值

DRM 裝置的 DMA 功能裝置。

enum drm_driver_feature

特性標誌

常量

DRIVER_GEM

驅動程式使用 GEM 記憶體管理器。應為所有現代驅動程式設定此項。

DRIVER_MODESET

驅動程式支援模式設定介面 (KMS)。

DRIVER_RENDER

驅動程式支援專用渲染節點。另請參見 關於渲染節點的章節,以瞭解詳細資訊。

DRIVER_ATOMIC

驅動程式支援完整的原子模式設定使用者空間 API。僅在內部使用原子,但不支援完整使用者空間 API 的驅動程式(例如,並非所有屬性都轉換為原子,或者不能保證多平面更新是無撕裂的)不應設定此標誌。

DRIVER_SYNCOBJ

驅動程式支援 drm_syncobj 用於顯式同步命令提交。

DRIVER_SYNCOBJ_TIMELINE

驅動程式支援時間線風格的 drm_syncobj 用於顯式同步命令提交。

DRIVER_COMPUTE_ACCEL

驅動程式支援計算加速裝置。此標誌與 DRIVER_RENDERDRIVER_MODESET 互斥。支援圖形和計算加速的裝置應由兩個使用輔助匯流排連線的驅動程式處理。

DRIVER_GEM_GPUVA

驅動程式支援 GEM 物件的使用者定義的 GPU VA 繫結。

DRIVER_CURSOR_HOTSPOT

驅動程式支援並需要游標平面中的游標熱點資訊(例如,游標平面必須實際跟蹤滑鼠游標,並且客戶端需要設定熱點才能使游標平面正常工作)。

DRIVER_USE_AGP

設定 DRM AGP 支援,請參見 drm_agp_init(),DRM 核心將管理 AGP 資源。新驅動程式不需要此項。

DRIVER_LEGACY

表示使用陰影附加的舊驅動程式。請勿使用。

DRIVER_PCI_DMA

驅動程式能夠進行 PCI DMA,將啟用 PCI DMA 緩衝區到使用者空間的對映。僅用於舊驅動程式。請勿使用。

DRIVER_SG

驅動程式可以執行分散/收集 DMA,將啟用分散/收集緩衝區的分配和對映。僅用於舊驅動程式。請勿使用。

DRIVER_HAVE_DMA

驅動程式支援 DMA,將支援使用者空間 DMA API。僅用於舊驅動程式。請勿使用。

DRIVER_HAVE_IRQ

舊的 irq 支援。僅用於舊驅動程式。請勿使用。

描述

請參見 drm_driver.driver_features、drm_device.driver_features 和 drm_core_check_feature()

struct drm_driver

DRM 驅動程式結構體

定義:

struct drm_driver {
    int (*load) (struct drm_device *, unsigned long flags);
    int (*open) (struct drm_device *, struct drm_file *);
    void (*postclose) (struct drm_device *, struct drm_file *);
    void (*unload) (struct drm_device *);
    void (*release) (struct drm_device *);
    void (*master_set)(struct drm_device *dev, struct drm_file *file_priv, bool from_open);
    void (*master_drop)(struct drm_device *dev, struct drm_file *file_priv);
    void (*debugfs_init)(struct drm_minor *minor);
    struct drm_gem_object *(*gem_create_object)(struct drm_device *dev, size_t size);
    int (*prime_handle_to_fd)(struct drm_device *dev, struct drm_file *file_priv, uint32_t handle, uint32_t flags, int *prime_fd);
    int (*prime_fd_to_handle)(struct drm_device *dev, struct drm_file *file_priv, int prime_fd, uint32_t *handle);
    struct drm_gem_object * (*gem_prime_import)(struct drm_device *dev, struct dma_buf *dma_buf);
    struct drm_gem_object *(*gem_prime_import_sg_table)(struct drm_device *dev,struct dma_buf_attachment *attach, struct sg_table *sgt);
    int (*dumb_create)(struct drm_file *file_priv,struct drm_device *dev, struct drm_mode_create_dumb *args);
    int (*dumb_map_offset)(struct drm_file *file_priv,struct drm_device *dev, uint32_t handle, uint64_t *offset);
    int (*fbdev_probe)(struct drm_fb_helper *fbdev_helper, struct drm_fb_helper_surface_size *sizes);
    void (*show_fdinfo)(struct drm_printer *p, struct drm_file *f);
    int major;
    int minor;
    int patchlevel;
    char *name;
    char *desc;
    u32 driver_features;
    const struct drm_ioctl_desc *ioctls;
    int num_ioctls;
    const struct file_operations *fops;
};

成員

load

向後相容的驅動程式回撥,用於在驅動程式註冊後完成初始化步驟。因此,可能存在競爭條件,並且不建議新驅動程式使用它。因此,僅支援尚未轉換為新方案的現有驅動程式。請參見 devm_drm_dev_alloc()drm_dev_register(),瞭解設定 struct drm_device 的正確且無競爭的方式。

此項已棄用,請勿使用!

返回值

成功時為零,失敗時為非零值。

open

開啟新的 struct drm_file 時的驅動程式回撥。對於設定驅動程式私有資料結構(如緩衝區分配器、執行上下文或類似事物)非常有用。此類驅動程式私有資源必須在 postclose 中再次釋放。

由於 DRM 的顯示/模式設定端只能由一個 struct drm_file 擁有(請參見 drm_file.is_masterdrm_device.master),因此永遠不需要在此回撥中設定任何模式設定相關資源。這樣做是驅動程式設計錯誤。

返回值

成功時為 0,失敗時為負錯誤程式碼,將作為 open() 系統呼叫的結果提升到使用者空間。

postclose

關閉新的 struct drm_file 時的驅動程式回撥之一。對於拆除在 open 中分配的驅動程式私有資料結構(如緩衝區分配器、執行上下文或類似事物)非常有用。

由於 DRM 的顯示/模式設定端只能由一個 struct drm_file 擁有(請參見 drm_file.is_masterdrm_device.master),因此永遠不需要在此回撥中拆除任何模式設定相關資源。這樣做是驅動程式設計錯誤。

unload

反轉驅動程式載入回撥的效果。理想情況下,驅動程式執行的清理應以初始化的相反順序進行。與載入掛鉤類似,此處理程式已棄用,應放棄使用它,而支援驅動程式層中的開放編碼拆卸函式。請參見 drm_dev_unregister()drm_dev_put(),以瞭解刪除 struct drm_device 的正確方法。

unload() 掛鉤在登出裝置後立即呼叫。

release

用於在釋放最終引用後銷燬裝置資料的可選回撥,即正在銷燬裝置。

此項已棄用,請使用 drmm_add_action()drmm_kmalloc() 和相關的託管資源函式清理與 drm_device 關聯的所有記憶體分配。

master_set

每當設定次要 master 時呼叫。僅由 vmwgfx 使用。

master_drop

每當刪除次要 master 時呼叫。僅由 vmwgfx 使用。

debugfs_init

允許驅動程式建立特定於驅動程式的 debugfs 檔案。

gem_create_object

gem 物件的建構函式

用於分配 GEM 物件結構體的掛鉤,供 CMA 和 SHMEM GEM 助手使用。成功時返回一個 GEM 物件,否則返回一個 ERR_PTR() 編碼的錯誤程式碼。

prime_handle_to_fd

PRIME 匯出函式。僅由 vmwgfx 使用。

prime_fd_to_handle

PRIME 匯入函式。僅由 vmwgfx 使用。

gem_prime_import

GEM 驅動程式的匯入掛鉤。

如果未設定,則預設為 drm_gem_prime_import()

gem_prime_import_sg_table

PRIME 助手函式 drm_gem_prime_import()drm_gem_prime_import_dev() 使用的可選掛鉤。

dumb_create

這會在驅動程式的後備儲存管理器(GEM、TTM 或其他完全不同的內容)中建立一個新的 dumb 緩衝區,並返回生成的緩衝區控制代碼。然後,可以將此控制代碼包裝到幀緩衝區模式設定物件中。

請注意,不允許使用者空間將此類物件用於渲染加速 - 驅動程式必須為此用例建立自己的私有 ioctl。

寬度、高度和深度在 drm_mode_create_dumb 引數中指定。回撥需要填充為建立的緩衝區的控制代碼、pitch 和大小。

由使用者透過 ioctl 呼叫。

返回值

成功時為零,失敗時為負 errno。

dumb_map_offset

在 DRM 裝置節點的地址空間中分配一個偏移量,以便能夠記憶體對映一個 dumb 緩衝區。

預設實現是 drm_gem_create_mmap_offset()。基於 GEM 的驅動程式不得覆蓋此項。

由使用者透過 ioctl 呼叫。

返回值

成功時為零,失敗時為負 errno。

fbdev_probe

為 fbdev 模擬分配並初始化 fb_info 結構。此外,還需要分配用於支援 fbdev 的 DRM 幀緩衝區。

對於 fbdev 支援,此回撥是必需的。

返回值

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

show_fdinfo

列印裝置特定的 fdinfo。請參閱 DRM 客戶端使用統計

major

驅動程式主裝置號

minor

驅動程式次裝置號

patchlevel

驅動程式補丁級別

name

驅動程式名稱

desc

驅動程式描述

driver_features

驅動程式功能,請參閱 enum drm_driver_feature。驅動程式可以使用 drm_device.driver_features 逐例項停用某些功能。

ioctls

驅動程式私有 IOCTL 描述條目的陣列。有關完整詳細資訊,請參閱有關 使用者空間介面章節中的 IOCTL 支援 的章節。

num_ioctls

ioctls 中的條目數。

fops

DRM 裝置節點的檔案操作。有關深入的討論和一些示例,請參閱 檔案操作 中的討論。

描述

此結構表示一類卡的通用程式碼。對於此類卡中的每個卡,都將有一個 struct drm_device。它包含許多 vfunc 條目,其中很多條目可能應該移動到更合適的位置,如 drm_mode_config_funcs 或 GEM 驅動程式的新操作結構中。

devm_drm_dev_alloc

devm_drm_dev_alloc (parent, driver, type, member)

資源管理的 drm_device 例項的分配

引數

parent

父裝置物件

driver

DRM 驅動程式

type

包含 struct drm_device 的結構的型別

member

typedrm_device 的名稱。

描述

這會分配並初始化一個新的 DRM 裝置。不進行設備註冊。呼叫 drm_dev_register() 以向用戶空間公佈該裝置,並將其註冊到其他核心子系統。這應該在裝置初始化序列的最後完成,以確保使用者空間無法訪問不一致的狀態。

物件的初始引用計數為 1。使用 drm_dev_get()drm_dev_put() 來獲取和刪除進一步的引用計數。

建議驅動程式將 struct drm_device 嵌入到他們自己的裝置結構中。

請注意,這使用 devres 自動管理生成的 drm_device 的生命週期。使用此函式初始化的 DRM 裝置在驅動程式分離時使用 drm_dev_put() 自動釋放。

返回值

指向新 DRM 裝置的指標,如果失敗,則為 ERR_PTR。

bool drm_dev_is_unplugged(struct drm_device *dev)

DRM 裝置是否已拔出

引數

struct drm_device *dev

DRM 裝置

描述

可以呼叫此函式來檢查熱插拔裝置是否已拔出。拔出本身透過 drm_dev_unplug() 發出訊號。如果裝置已拔出,則這兩個函式保證在呼叫 drm_dev_unplug() 之前進行的任何儲存在該函式完成後對該函式的呼叫者可見

警告:此函式從根本上與 drm_dev_unplug() 競爭。建議驅動程式改為使用底層的 drm_dev_enter()drm_dev_exit() 函式對。

bool drm_core_check_all_features(const struct drm_device *dev, u32 features)

檢查驅動程式功能標誌掩碼

引數

const struct drm_device *dev

要檢查的 DRM 裝置

u32 features

功能標誌掩碼

描述

這將檢查 dev 的驅動程式功能,請參閱 drm_driver.driver_featuresdrm_device.driver_features 以及各種 enum drm_driver_feature 標誌。

如果支援 features 掩碼中的所有功能,則返回 true,否則返回 false。

bool drm_core_check_feature(const struct drm_device *dev, enum drm_driver_feature feature)

檢查驅動程式功能標誌

引數

const struct drm_device *dev

要檢查的 DRM 裝置

enum drm_driver_feature feature

功能標誌

描述

這將檢查 dev 的驅動程式功能,請參閱 drm_driver.driver_featuresdrm_device.driver_features 以及各種 enum drm_driver_feature 標誌。

如果支援 feature,則返回 true,否則返回 false。

bool drm_drv_uses_atomic_modeset(struct drm_device *dev)

檢查驅動程式是否實現了 atomic_commit()

引數

struct drm_device *dev

DRM 裝置

描述

如果驅動程式未設定 DRIVER_ATOMIC 但在內部實現了原子模式設定,則此檢查非常有用。

void drm_put_dev(struct drm_device *dev)

登出並釋放 DRM 裝置

引數

struct drm_device *dev

DRM 裝置

描述

在模組解除安裝時或 PCI 裝置拔出時呼叫。

清理所有 DRM 裝置,呼叫 drm_lastclose()。

注意

不建議使用此函式。它最終將完全消失。請明確使用 drm_dev_unregister()drm_dev_put(),以確保在拆卸過程中使用者空間不再可訪問該裝置,從而確保使用者空間無法訪問不一致的狀態。

bool drm_dev_enter(struct drm_device *dev, int *idx)

進入裝置臨界區

引數

struct drm_device *dev

DRM 裝置

int *idx

指向將傳遞給匹配的 drm_dev_exit() 的索引的指標

描述

此函式標記並保護在裝置拔出後不應進入的區域的開頭。區域結尾用 drm_dev_exit() 標記。可以巢狀對此函式的呼叫。

返回值

如果可以進入該區域,則為 True,否則為 false。

void drm_dev_exit(int idx)

退出裝置臨界區

引數

int idx

drm_dev_enter() 返回的索引

描述

此函式標記了裝置拔出後不應進入的區域的結尾。

void drm_dev_unplug(struct drm_device *dev)

拔出 DRM 裝置

引數

struct drm_device *dev

DRM 裝置

描述

這將拔出一個熱插拔 DRM 裝置,使其無法進行使用者空間操作。入口點可以使用 drm_dev_enter()drm_dev_exit() 以無競爭的方式保護裝置資源。這本質上是登出裝置,如 drm_dev_unregister(),但可以在仍有 dev 的開放使用者時呼叫。

void drm_dev_set_dma_dev(struct drm_device *dev, struct device *dma_dev)

為 DRM 裝置設定 DMA 裝置

引數

struct drm_device *dev

DRM 裝置

struct device *dma_dev

DMA 裝置或 NULL

描述

設定給定 DRM 裝置的 DMA 裝置。僅當 DMA 裝置與 DRM 裝置的父裝置不同時才需要。呼叫此函式後,DRM 裝置將持有 dma_dev 上的引用。傳遞 NULL 以清除 DMA 裝置。

int drm_dev_wedged_event(struct drm_device *dev, unsigned long method)

生成裝置卡住的 uevent

引數

struct drm_device *dev

DRM 裝置

unsigned long method

用於恢復的方法

描述

這將為 dev 指定的 DRM 裝置生成一個裝置卡住的 uevent。所選的恢復 method 將按副作用從少到多的順序在 uevent 環境中作為 WEDGED=<method1>[,..,<methodN>] 傳送。如果呼叫者不確定恢復或 method 未知 (0),則將改為傳送 WEDGED=unknown

有關更多詳細資訊,請參閱 使用者空間介面 中的“裝置卡住”章節。

返回值

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

void *__drm_dev_alloc(struct device *parent, const struct drm_driver *driver, size_t size, size_t offset)

drm_device 例項的分配

引數

struct device *parent

父裝置物件

const struct drm_driver *driver

DRM 驅動程式

size_t size

包含 struct drm_device 的結構的大小

size_t offset

drm_device 在容器中的偏移量。

描述

任何驅動程式都應使用它,但它是用於相應的 Rust 抽象的專用介面。

這與 devm_drm_dev_alloc() 相同,但沒有透過父裝置的相應資源管理,但與 drm_dev_alloc() 不同,因為後者是已棄用的版本,不支援子類化。

返回值

指向新 DRM 裝置的指標,如果失敗,則為 ERR_PTR。

struct drm_device *drm_dev_alloc(const struct drm_driver *driver, struct device *parent)

分配新的 DRM 裝置

引數

const struct drm_driver *driver

用於為其分配裝置的 DRM 驅動程式

struct device *parent

父裝置物件

描述

這是 devm_drm_dev_alloc() 的已棄用版本,它不支援透過在驅動程式私有結構中嵌入 struct drm_device 來實現子類化,也不支援透過 devres 進行自動清理。

返回值

指向新 DRM 裝置的指標,如果失敗,則為 ERR_PTR。

void drm_dev_get(struct drm_device *dev)

獲取 DRM 裝置的引用

引數

struct drm_device *dev

要獲取引用的裝置或 NULL

描述

這將使 dev 的引用計數增加 1。呼叫此函式時,必須已經擁有一個引用。使用 drm_dev_put() 再次刪除此引用。

此函式永遠不會失敗。但是,此函式不提供任何關於裝置是否處於活動狀態或正在執行的保證。它僅提供對該物件及其關聯記憶體的引用。

void drm_dev_put(struct drm_device *dev)

刪除 DRM 裝置的引用

引數

struct drm_device *dev

要刪除引用的裝置或 NULL

描述

這將使 dev 的引用計數減少 1。如果引用計數降至零,則銷燬該裝置。

struct dmem_cgroup_region *drmm_cgroup_register_region(struct drm_device *dev, const char *region_name, u64 size)

將 DRM 裝置的區域註冊到 cgroups

引數

struct drm_device *dev

區域的裝置

const char *region_name

要註冊的區域名稱

u64 size

區域大小(以位元組為單位)

描述

這將使 dev 的引用計數減少 1。如果引用計數降至零,則銷燬該裝置。

int drm_dev_register(struct drm_device *dev, unsigned long flags)

註冊 DRM 裝置

引數

struct drm_device *dev

要註冊的裝置

unsigned long flags

傳遞給驅動程式的 .load() 函式的標誌

描述

向系統註冊 DRM 裝置 dev,向用戶空間公佈裝置並啟動正常裝置操作。必須先前透過 drm_dev_init() 初始化 dev

切勿在任何裝置上呼叫此函式兩次!

注意

為了確保與現有驅動程式方法的向後相容性,此函式在註冊裝置節點後呼叫 drm_driver.load 方法,從而導致競爭條件。因此,不建議使用 drm_driver.load 方法,驅動程式必須在呼叫 drm_dev_register() 之前執行所有初始化。

返回值

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

void drm_dev_unregister(struct drm_device *dev)

登出 DRM 裝置

引數

struct drm_device *dev

要登出的裝置

描述

從系統登出 DRM 裝置。這與 drm_dev_register() 相反,但不取消分配裝置。呼叫者必須呼叫 drm_dev_put() 以刪除其最終引用,除非它使用 devres 管理(如使用 devm_drm_dev_alloc() 分配的裝置),在這種情況下,已經註冊瞭解除操作。

熱插拔裝置的一種特殊登出形式是 drm_dev_unplug(),可以在仍有 dev 的開放使用者時呼叫。

這應該在裝置拆卸程式碼中首先呼叫,以確保使用者空間無法再訪問裝置例項。

驅動程式載入

元件助手使用

建議驅動由多個獨立硬體塊組成的邏輯裝置的 DRM 驅動程式使用 元件助手庫。為了保持一致性並更好地重用程式碼,適用以下準則

記憶體管理器初始化

每個 DRM 驅動程式都需要一個記憶體管理器,該管理器必須在載入時初始化。DRM 當前包含兩個記憶體管理器,即轉換表管理器 (TTM) 和圖形執行管理器 (GEM)。本文件僅描述 GEM 記憶體管理器的使用。有關詳細資訊,請參閱?

其他裝置配置

配置期間 PCI 裝置可能需要的另一項任務是對映影片 BIOS。在許多裝置上,VBIOS 描述了裝置配置、LCD 面板時序(如果有)幷包含指示裝置狀態的標誌。可以使用 pci_map_rom() 呼叫來完成 BIOS 的對映,這是一個方便的函式,用於處理對映實際 ROM,無論它是否已陰影到記憶體中(通常在地址 0xc0000)或存在於 ROM BAR 中的 PCI 裝置上。請注意,在對映 ROM 並提取任何必要資訊後,應取消對映 ROM;在許多裝置上,ROM 地址解碼器與其他 BAR 共享,因此保持對映狀態可能會導致不良行為,如掛起或記憶體損壞。

託管資源

受 struct device 託管資源的啟發,但與 struct drm_device 的生命週期相關聯,struct drm_device 可能比底層物理裝置存在的時間更長,通常是當用戶空間有一些開啟的檔案和其他資源控制代碼仍處於開啟狀態時。

可以使用 drmm_add_action() 添加發布操作,可以使用 drmm_kmalloc() 和相關函式直接完成記憶體分配。所有內容將在最終的 drm_dev_put() 中以添加發布操作的相反順序釋放,並且自驅動程式載入開始時使用 devm_drm_dev_alloc() 分配記憶體。

請注意,也可以在驅動程式的生命週期內新增和刪除釋出操作和託管記憶體,所有函式都是完全併發安全的。但建議僅將託管資源用於在 drm_device 例項的生命週期內很少或從未更改的資源。

void drmm_release_action(struct drm_device *dev, drmres_release_t action, void *data)

drm_device 釋放託管操作

引數

struct drm_device *dev

DRM 裝置

drmres_release_t action

當釋放 dev 時將呼叫的函式

void *data

傳遞給 action 的不透明指標

描述

此函式立即呼叫先前由 drmm_add_action() 新增的 actionaction 會從 dev 的清理操作列表中移除,這意味著它不會在最終的 drm_dev_put() 中被呼叫。

void *drmm_kmalloc(struct drm_device *dev, size_t size, gfp_t gfp)

drm_device 管理的 kmalloc()

引數

struct drm_device *dev

DRM 裝置

size_t size

記憶體分配的大小

gfp_t gfp

GFP 分配標誌

描述

這是 drm_device 管理的 kmalloc() 版本。分配的記憶體將在最終的 drm_dev_put() 上自動釋放。記憶體也可以透過呼叫 drmm_kfree() 在最終的 drm_dev_put() 之前釋放。

char *drmm_kstrdup(struct drm_device *dev, const char *s, gfp_t gfp)

drm_device 管理的 kstrdup()

引數

struct drm_device *dev

DRM 裝置

const char *s

要複製的 0 結尾的字串

gfp_t gfp

GFP 分配標誌

描述

這是 drm_device 管理的 kstrdup() 版本。分配的記憶體將在最終的 drm_dev_put() 上自動釋放,並且工作方式與透過 drmm_kmalloc() 獲得的記憶體分配完全相同。

void drmm_kfree(struct drm_device *dev, void *data)

drm_device 管理的 kfree()

引數

struct drm_device *dev

DRM 裝置

void *data

要釋放的記憶體分配

描述

這是 drm_device 管理的 kfree() 版本,可用於在 dev 的最終 drm_dev_put() 之前釋放透過 drmm_kmalloc() 或其任何相關函式分配的記憶體。

drmm_add_action

drmm_add_action (dev, action, data)

drm_device 新增託管的釋放操作

引數

dev

DRM 裝置

action

dev 被釋放時應該呼叫的函式

data

傳遞給 action 的不透明指標

描述

此函式將帶有可選引數 datarelease 操作新增到 dev 的清理操作列表中。清理操作將在 dev 的最終 drm_dev_put() 呼叫中以相反的順序執行。

drmm_add_action_or_reset

drmm_add_action_or_reset (dev, action, data)

drm_device 新增託管的釋放操作

引數

dev

DRM 裝置

action

dev 被釋放時應該呼叫的函式

data

傳遞給 action 的不透明指標

描述

類似於 drmm_add_action(),唯一的區別是,如果失敗,action 會被直接呼叫,以便對失敗進行必要的清理工作。

void *drmm_kzalloc(struct drm_device *dev, size_t size, gfp_t gfp)

drm_device 管理的 kzalloc()

引數

struct drm_device *dev

DRM 裝置

size_t size

記憶體分配的大小

gfp_t gfp

GFP 分配標誌

描述

這是 drm_device 管理的 kzalloc() 版本。分配的記憶體將在最終的 drm_dev_put() 上自動釋放。記憶體也可以透過呼叫 drmm_kfree() 在最終的 drm_dev_put() 之前釋放。

void *drmm_kmalloc_array(struct drm_device *dev, size_t n, size_t size, gfp_t flags)

drm_device 管理的 kmalloc_array()

引數

struct drm_device *dev

DRM 裝置

size_t n

要分配的陣列元素的數量

size_t size

陣列成員的大小

gfp_t flags

GFP 分配標誌

描述

這是 drm_device 管理的 kmalloc_array() 版本。分配的記憶體將在最終的 drm_dev_put() 上自動釋放,並且工作方式與透過 drmm_kmalloc() 獲得的記憶體分配完全相同。

void *drmm_kcalloc(struct drm_device *dev, size_t n, size_t size, gfp_t flags)

drm_device 管理的 kcalloc()

引數

struct drm_device *dev

DRM 裝置

size_t n

要分配的陣列元素的數量

size_t size

陣列成員的大小

gfp_t flags

GFP 分配標誌

描述

這是 drm_device 管理的 kcalloc() 版本。分配的記憶體將在最終的 drm_dev_put() 上自動釋放,並且工作方式與透過 drmm_kmalloc() 獲得的記憶體分配完全相同。

drmm_mutex_init

drmm_mutex_init (dev, lock)

引數

dev

DRM 裝置

lock

要初始化的鎖

返回值

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

描述

這是 drm_device 管理的 mutex_init() 版本。初始化的鎖在最終的 drm_dev_put() 上自動銷燬。

開啟/關閉、檔案操作和 IOCTL

檔案操作

驅動程式必須定義檔案操作結構,該結構構成 DRM 使用者空間 API 入口點,即使大多數操作都在 DRM 核心中實現。生成的 struct file_operations 必須儲存在 drm_driver.fops 欄位中。強制函式是 drm_open()drm_read()drm_ioctl()drm_compat_ioctl()(如果啟用了 CONFIG_COMPAT)。請注意,如果 CONFIG_COMPAT=n,則 drm_compat_ioctl 將為 NULL,因此無需在程式碼中散佈 #ifdef。如果驅動程式實現需要 32/64 位相容性支援的私有 ioctl,則必須提供自己的 file_operations.compat_ioctl 處理程式,該處理程式處理私有 ioctl 併為核心 ioctl 呼叫 drm_compat_ioctl()

此外,drm_read()drm_poll() 提供對 DRM 事件的支援。DRM 事件是一種通用且可擴充套件的方式,用於透過檔案描述符將非同步事件傳送到使用者空間。它們用於透過 KMS API 傳送垂直消隱事件和頁面翻轉完成。但是驅動程式也可以將其用於自己的需求,例如,指示渲染完成。

對於驅動程式側事件介面,請參閱 drm_event_reserve_init()drm_send_event() 作為主要起點。

記憶體對映的實現將根據驅動程式管理記憶體的方式而有所不同。對於基於 GEM 的驅動程式,這是 drm_gem_mmap()

DRM 使用者空間 API 不支援其他檔案操作。總的來說,以下是一個示例 file_operations 結構

static const example_drm_fops = {
        .owner = THIS_MODULE,
        .open = drm_open,
        .release = drm_release,
        .unlocked_ioctl = drm_ioctl,
        .compat_ioctl = drm_compat_ioctl, // NULL if CONFIG_COMPAT=n
        .poll = drm_poll,
        .read = drm_read,
        .mmap = drm_gem_mmap,
};

對於普通的基於 GEM 的驅動程式,有 DEFINE_DRM_GEM_FOPS() 宏,對於基於 DMA 的驅動程式,有 DEFINE_DRM_GEM_DMA_FOPS() 宏,以簡化此操作。

驅動程式的 file_operations 必須儲存在 drm_driver.fops 中。

有關驅動程式私有 IOCTL 處理的更多詳細討論,請參見 使用者區介面章節中的 IOCTL 支援

struct drm_minor

DRM 裝置次要結構

定義:

struct drm_minor {
};

成員

描述

此結構表示 /dev 中裝置節點的 DRM 次要編號。對於驅動程式完全不透明,驅動程式絕不應直接檢查它。相反,驅動程式應僅與 struct drm_file 以及當然 struct drm_device 互動,這也是驅動程式私有資料和資源可以附加到的地方。

struct drm_pending_event

為使用者空間排隊以供讀取的事件

定義:

struct drm_pending_event {
    struct completion *completion;
    void (*completion_release)(struct completion *completion);
    struct drm_event *event;
    struct dma_fence *fence;
    struct drm_file *file_priv;
    struct list_head link;
    struct list_head pending_link;
};

成員

completion

當呼叫 drm_send_event() 時發出訊號的核心內部完成的可選指標,對於內部與非阻塞操作同步很有用。

completion_release

可選回撥,目前僅由原子模式設定助手用於清理儲存 completion 的結構的引用計數。

event

應該傳送到使用者空間以使用 drm_read() 讀取的實際事件的指標。可以是可選的,因為現在事件也用於透過 completion 向核心內部執行緒發出訊號或使用 fence 進行 DMA 事務。

fence

可選的 DMA fence,用於取消阻止依賴於此事件表示的非阻塞 DRM 操作的其他硬體事務。

file_priv

應將 event 傳遞到的 struct drm_file。僅在設定 event 時設定。

link

雙向連結串列,用於跟蹤此事件。驅動程式可以在呼叫 drm_send_event() 之前使用此連結串列,之後此列表條目由核心擁有以進行自己的簿記。

pending_link

drm_file.pending_event_list 上的條目,用於跟蹤 file_priv 的所有掛起事件,以便在使用者空間關閉檔案之前正確展開它們。

描述

這表示 DRM 事件。驅動程式可以將其用作通用完成機制,該機制支援核心內部 struct completionstruct dma_fence 和 DRM 特定的 struct drm_event 傳遞機制。

struct drm_file

DRM 檔案私有資料

定義:

struct drm_file {
    bool authenticated;
    bool stereo_allowed;
    bool universal_planes;
    bool atomic;
    bool aspect_ratio_allowed;
    bool writeback_connectors;
    bool was_master;
    bool is_master;
    bool supports_virtualized_cursor_plane;
    struct drm_master *master;
    spinlock_t master_lookup_lock;
    struct pid __rcu *pid;
    u64 client_id;
    drm_magic_t magic;
    struct list_head lhead;
    struct drm_minor *minor;
    struct idr object_idr;
    spinlock_t table_lock;
    struct idr syncobj_idr;
    spinlock_t syncobj_table_lock;
    struct file *filp;
    void *driver_priv;
    struct list_head fbs;
    struct mutex fbs_lock;
    struct list_head blobs;
    wait_queue_head_t event_wait;
    struct list_head pending_event_list;
    struct list_head event_list;
    int event_space;
    struct mutex event_read_lock;
    struct drm_prime_file_private prime;
    const char *client_name;
    struct mutex client_name_lock;
};

成員

authenticated

是否允許客戶端提交渲染,對於舊節點,這意味著必須進行身份驗證。

另請參閱 關於主節點和身份驗證的部分

stereo_allowed

當客戶端要求我們公開立體 3D 模式標誌時為 True。

universal_planes

如果客戶端了解平面列表中的 CRTC 主平面和游標平面,則為 True。當設定 atomic 時自動設定。

atomic

如果客戶端了解原子屬性,則為 True。

aspect_ratio_allowed

如果客戶端可以處理圖片縱橫比,並且已請求隨模式一起傳遞此資訊,則為 True。

writeback_connectors

如果客戶端了解寫回聯結器,則為 True

was_master

此客戶端具有或曾經具有主控功能。受結構 drm_device.master_mutex 保護。

這用於確保不強制執行 CAP_SYS_ADMIN,如果客戶端過去或曾經是主節點。

is_master

此客戶端是 master 的建立者。受結構 drm_device.master_mutex 保護,並由 master_lookup_lock 序列化。

另請參閱 關於主節點和身份驗證的部分

supports_virtualized_cursor_plane

此客戶端能夠處理游標平面,並且游標平面受到虛擬化驅動程式施加的限制。

這意味著游標平面的行為必須類似於游標,即跟蹤游標移動。它還需要客戶端在游標平面上設定熱點屬性。

master

此節點當前關聯的主節點。受結構 drm_device.master_mutex 保護,並由 master_lookup_lock 序列化。

僅當 drm_is_primary_client() 返回 true 時才相關。請注意,如果主節點是當前活動的主節點,則此節點僅與 drm_device.master 匹配。

要更新 master,需要同時持有 drm_device.master_mutexmaster_lookup_lock,因此持有它們中的任何一個對於讀取側都是安全且足夠的。

當取消引用此指標時,要麼持有結構 drm_device.master_mutex 以便在指標的使用期間,要麼使用 drm_file_get_master(),如果當前未持有結構 drm_device.master_mutex 並且沒有其他需要持有它的需求。這可以防止 master 在使用期間被釋放。

另請參閱 authenticationis_master 以及 關於主節點和身份驗證的部分

master_lookup_lock

序列化 master

pid

正在使用此檔案的程序。

只能在 rcu_read_lock 或等效項下取消引用。

更新受 dev->filelist_mutex 保護,並且在 RCU 寬限期後必須刪除引用,以適應無鎖讀取器。

client_id

fdinfo 的唯一 ID

magic

身份驗證魔術,請參閱 authenticated

lhead

DRM 裝置的所有開啟檔案的列表,連結到 drm_device.filelist。受 drm_device.filelist_mutex 保護。

minor

此檔案的 struct drm_minor

object_idr

mm 物件控制代碼到物件指標的對映。由 GEM 子系統使用。受 table_lock 保護。

table_lock

保護 object_idr

syncobj_idr

同步物件控制代碼到物件指標的對映。

syncobj_table_lock

保護 syncobj_idr

filp

指向核心檔案結構的指標。

driver_priv

驅動程式私有資料的可選指標。可以在 drm_driver.open 中分配,並且應該在 drm_driver.postclose 中釋放。

fbs

與此檔案關聯的 struct drm_framebuffer 列表,使用 drm_framebuffer.filp_head 條目。

fbs_lock 保護。請注意,fbs 列表持有對幀緩衝區物件的引用,以防止它過早消失。

fbs_lock

保護 fbs

blobs

使用者建立的 blob 屬性;這保留對屬性的引用。

drm_mode_config.blob_lock 保護;

event_wait

新增到 event_list 的新事件的等待佇列。

pending_event_list

掛起的 struct drm_pending_event 的列表,用於清理掛起的事件,以防此檔案在發出事件訊號之前關閉。使用 drm_pending_event.pending_link 條目。

drm_device.event_lock 保護。

event_list

struct drm_pending_event 的列表,已準備好透過 drm_read() 傳遞到使用者空間。使用 drm_pending_event.link 條目。

drm_device.event_lock 保護。

event_space

可用事件空間,以防止使用者空間耗盡核心記憶體。目前限制為 4KB 的相當任意的值。

event_read_lock

序列化 drm_read()

prime

PRIME 緩衝區共享程式碼使用的每個檔案的緩衝區快取。

client_name

使用者空間提供的名稱;對於核算和除錯很有用。

client_name_lock

保護 client_name

描述

此結構跟蹤每個開啟檔案描述符的 DRM 狀態。

bool drm_is_primary_client(const struct drm_file *file_priv)

這是否是主節點的開啟檔案

引數

const struct drm_file *file_priv

DRM 檔案

描述

如果這是主節點的開啟檔案,即 file_privdrm_file.minor 是主節點,則返回 true。

另請參閱 關於主節點和身份驗證的部分

bool drm_is_render_client(const struct drm_file *file_priv)

這是否是渲染節點的開啟檔案

引數

const struct drm_file *file_priv

DRM 檔案

描述

如果這是渲染節點的開啟檔案,即 file_privdrm_file.minor 是渲染節點,則返回 true。

另請參閱 關於渲染節點的部分

bool drm_is_accel_client(const struct drm_file *file_priv)

這是否是計算加速節點的開啟檔案

引數

const struct drm_file *file_priv

DRM 檔案

描述

如果這是計算加速節點的開啟檔案,即 file_privdrm_file.minor 是加速節點,則返回 true。

另請參閱 計算加速器子系統簡介

struct drm_memory_stats

GEM 物件統計資訊關聯

定義:

struct drm_memory_stats {
    u64 shared;
    u64 private;
    u64 resident;
    u64 purgeable;
    u64 active;
};

成員

shared

程序間共享的 GEM 物件總大小

私有

GEM 物件總大小

常駐

GEM 物件後備頁的總大小

可清除

可以清除的 GEM 物件總大小(常駐且不活躍)

活躍

在一個或多個引擎上活躍的 GEM 物件總大小

描述

drm_print_memory_stats() 使用

int drm_open(struct inode *inode, struct file *filp)

DRM 檔案的 open 方法

引數

struct inode *inode

裝置 inode

struct file *filp

檔案指標。

描述

驅動程式必須使用此函式作為它們的 file_operations.open 方法。它會查詢正確的 DRM 裝置並例項化它的所有每個檔案的資源。它還會呼叫 drm_driver.open 驅動程式回撥。

返回值

成功時返回 0,失敗時返回負的 errno 值。

int drm_release(struct inode *inode, struct file *filp)

DRM 檔案的 release 方法

引數

struct inode *inode

裝置 inode

struct file *filp

檔案指標。

描述

驅動程式必須使用此函式作為它們的 file_operations.release 方法。它會釋放與開啟的檔案關聯的所有資源。如果這是 DRM 裝置的最後一個開啟的檔案,它還會恢復活躍的核心 DRM 客戶端。

返回值

總是成功並返回 0。

int drm_release_noglobal(struct inode *inode, struct file *filp)

DRM 檔案的 release 方法

引數

struct inode *inode

裝置 inode

struct file *filp

檔案指標。

描述

驅動程式可以使用此函式作為它們的 file_operations.release 方法。它會在獲取 drm_global_mutex 之前釋放與開啟的檔案關聯的所有資源。如果這是 DRM 裝置的最後一個開啟的檔案,那麼它會恢復活躍的核心 DRM 客戶端。

返回值

總是成功並返回 0。

ssize_t drm_read(struct file *filp, char __user *buffer, size_t count, loff_t *offset)

DRM 檔案的 read 方法

引數

struct file *filp

檔案指標

char __user *buffer

使用者空間的讀取目標指標

size_t count

要讀取的位元組數

loff_t *offset

讀取偏移量

描述

如果驅動程式使用 DRM 事件來進行非同步訊號傳送到使用者空間,則必須使用此函式作為它們的 file_operations.read 方法。由於 KMS API 使用事件來進行垂直消隱和頁面翻轉完成,這意味著所有現代顯示驅動程式都必須使用它。

offset 被忽略,DRM 事件像管道一樣被讀取。drm_poll() 提供輪詢支援。

此函式將只讀取一個完整的事件。因此,使用者空間必須提供足夠大的緩衝區來容納任何事件,以確保向前進展。由於最大事件空間當前為 4K,建議使用它來確保安全。

返回值

讀取的位元組數(總是與完整事件對齊,並且可以為 0),或者失敗時返回負的錯誤程式碼。

__poll_t drm_poll(struct file *filp, struct poll_table_struct *wait)

DRM 檔案的 poll 方法

引數

struct file *filp

檔案指標

struct poll_table_struct *wait

poll 等待表

描述

如果驅動程式使用 DRM 事件來進行非同步訊號傳送到使用者空間,則必須使用此函式作為它們的 file_operations.read 方法。由於 KMS API 使用事件來進行垂直消隱和頁面翻轉完成,這意味著所有現代顯示驅動程式都必須使用它。

另請參閱 drm_read()

返回值

指示檔案當前狀態的 POLL 標誌的掩碼。

int drm_event_reserve_init_locked(struct drm_device *dev, struct drm_file *file_priv, struct drm_pending_event *p, struct drm_event *e)

初始化 DRM 事件併為其預留空間

引數

struct drm_device *dev

DRM 裝置

struct drm_file *file_priv

DRM 檔案私有資料

struct drm_pending_event *p

掛起事件的跟蹤結構

struct drm_event *e

要傳遞給使用者空間的實際事件資料

描述

此函式準備傳入的事件以供最終傳遞。如果事件沒有被傳遞(因為 IOCTL 稍後失敗,在將任何內容排隊之前),那麼事件必須使用 drm_event_cancel_free() 取消和釋放。成功初始化的事件應該使用 drm_send_event()drm_send_event_locked() 傳送,以向用戶空間發出非同步事件完成的訊號。

如果呼叫者將 p 嵌入到更大的結構中,它必須使用 kmalloc 分配,並且 p 必須是第一個成員元素。

這是 drm_event_reserve_init() 的鎖定版本,適用於已經持有 drm_device.event_lock 的呼叫者。

返回值

成功時返回 0,失敗時返回負的錯誤程式碼。

int drm_event_reserve_init(struct drm_device *dev, struct drm_file *file_priv, struct drm_pending_event *p, struct drm_event *e)

初始化 DRM 事件併為其預留空間

引數

struct drm_device *dev

DRM 裝置

struct drm_file *file_priv

DRM 檔案私有資料

struct drm_pending_event *p

掛起事件的跟蹤結構

struct drm_event *e

要傳遞給使用者空間的實際事件資料

描述

此函式準備傳入的事件以供最終傳遞。如果事件沒有被傳遞(因為 IOCTL 稍後失敗,在將任何內容排隊之前),那麼事件必須使用 drm_event_cancel_free() 取消和釋放。成功初始化的事件應該使用 drm_send_event()drm_send_event_locked() 傳送,以向用戶空間發出非同步事件完成的訊號。

如果呼叫者將 p 嵌入到更大的結構中,它必須使用 kmalloc 分配,並且 p 必須是第一個成員元素。

已經持有 drm_device.event_lock 的呼叫者應該改用 drm_event_reserve_init_locked()

返回值

成功時返回 0,失敗時返回負的錯誤程式碼。

void drm_event_cancel_free(struct drm_device *dev, struct drm_pending_event *p)

釋放 DRM 事件並釋放其空間

引數

struct drm_device *dev

DRM 裝置

struct drm_pending_event *p

掛起事件的跟蹤結構

描述

此函式釋放使用 drm_event_reserve_init() 初始化的事件 p 並釋放任何已分配的空間。當無法提交非阻塞操作並且需要中止時,它用於取消事件。

void drm_send_event_timestamp_locked(struct drm_device *dev, struct drm_pending_event *e, ktime_t timestamp)

將 DRM 事件傳送到檔案描述符

引數

struct drm_device *dev

DRM 裝置

struct drm_pending_event *e

要傳遞的 DRM 事件

ktime_t timestamp

要在核心 CLOCK_MONOTONIC 時域中為 fence 事件設定的時間戳

描述

此函式將事件 e(使用 drm_event_reserve_init() 初始化)傳送到其關聯的使用者空間 DRM 檔案。呼叫者必須已經持有 drm_device.event_lock

請注意,當相應的 DRM 檔案關閉時,核心將負責取消連結和解除事件。驅動程式不必擔心此事件的 DRM 檔案是否仍然存在,並且可以在非同步工作完成後無條件地呼叫此函式。

void drm_send_event_locked(struct drm_device *dev, struct drm_pending_event *e)

將 DRM 事件傳送到檔案描述符

引數

struct drm_device *dev

DRM 裝置

struct drm_pending_event *e

要傳遞的 DRM 事件

描述

此函式將事件 e(使用 drm_event_reserve_init() 初始化)傳送到其關聯的使用者空間 DRM 檔案。呼叫者必須已經持有 drm_device.event_lock,有關未鎖定版本,請參見 drm_send_event()

請注意,當相應的 DRM 檔案關閉時,核心將負責取消連結和解除事件。驅動程式不必擔心此事件的 DRM 檔案是否仍然存在,並且可以在非同步工作完成後無條件地呼叫此函式。

void drm_send_event(struct drm_device *dev, struct drm_pending_event *e)

將 DRM 事件傳送到檔案描述符

引數

struct drm_device *dev

DRM 裝置

struct drm_pending_event *e

要傳遞的 DRM 事件

描述

此函式將事件 e(使用 drm_event_reserve_init() 初始化)傳送到其關聯的使用者空間 DRM 檔案。此函式獲取 drm_device.event_lock,對於已經持有此鎖的呼叫者,請參見 drm_send_event_locked()

請注意,當相應的 DRM 檔案關閉時,核心將負責取消連結和解除事件。驅動程式不必擔心此事件的 DRM 檔案是否仍然存在,並且可以在非同步工作完成後無條件地呼叫此函式。

void drm_print_memory_stats(struct drm_printer *p, const struct drm_memory_stats *stats, enum drm_gem_object_status supported_status, const char *region)

一個用於列印記憶體統計資訊的助手函式

引數

struct drm_printer *p

用於列印輸出的印表機

const struct drm_memory_stats *stats

收集的記憶體統計資訊

enum drm_gem_object_status supported_status

可用可選統計資訊的位掩碼

const char *region

記憶體區域

void drm_show_memory_stats(struct drm_printer *p, struct drm_file *file)

用於收集和顯示標準 fdinfo 記憶體統計資訊的助手函式

引數

struct drm_printer *p

用於列印輸出的印表機

struct drm_file *file

DRM 檔案

描述

用於迭代 GEM 物件(在指定檔案中分配了控制代碼)的助手函式。

void drm_show_fdinfo(struct seq_file *m, struct file *f)

DRM 檔案 fops 的助手函式

引數

struct seq_file *m

輸出流

struct file *f

裝置檔案例項

描述

用於實現 fdinfo 的助手函式,供使用者空間查詢使用 GPU 的程序的使用統計資訊等。另請參閱 drm_driver.show_fdinfo

有關文字輸出格式的說明,請參見 DRM 客戶端使用統計資訊

void drm_file_err(struct drm_file *file_priv, const char *fmt, ...)

記錄與 drm_file 關聯的程序名稱、pid 和 client_name

引數

struct drm_file *file_priv

感興趣的程序名稱和 pid 上下文

const char *fmt

printf() 樣式的格式字串

...

可變引數

描述

用於需要記錄程序詳細資訊(如名稱和 pid 等)以及使用者日誌的客戶端的助手函式。

雜項實用程式

印表機

dev_printk()、seq_printf() 等的簡單包裝器。允許相同的除錯程式碼用於 debugfs 和 printk 日誌記錄。

例如

void log_some_info(struct drm_printer *p)
{
        drm_printf(p, "foo=%d\n", foo);
        drm_printf(p, "bar=%d\n", bar);
}

#ifdef CONFIG_DEBUG_FS
void debugfs_show(struct seq_file *f)
{
        struct drm_printer p = drm_seq_file_printer(f);
        log_some_info(&p);
}
#endif

void some_other_function(...)
{
        struct drm_printer p = drm_info_printer(drm->dev);
        log_some_info(&p);
}
enum drm_debug_category

DRM 除錯類別

常量

DRM_UT_CORE

在通用 DRM 程式碼中使用:drm_ioctl.c、drm_mm.c、drm_memory.c 等。

DRM_UT_DRIVER

在驅動程式的供應商特定部分中使用:i915、radeon 等宏。

DRM_UT_KMS

在 modesetting 程式碼中使用。

DRM_UT_PRIME

在 prime 程式碼中使用。

DRM_UT_ATOMIC

在 atomic 程式碼中使用。

DRM_UT_VBL

用於 vblank 程式碼中的詳細除錯訊息。

DRM_UT_STATE

用於詳細的 atomic 狀態除錯。

DRM_UT_LEASE

在 lease 程式碼中使用。

DRM_UT_DP

在 DP 程式碼中使用。

DRM_UT_DRMRES

在 DRM 託管資原始碼中使用。

描述

每個 DRM 除錯日誌記錄宏都使用一個特定的類別,並且日誌記錄由 drm.debug 模組引數過濾。此列舉指定介面的值。

每個 DRM_DEBUG_<CATEGORY> 宏都記錄到 DRM_UT_<CATEGORY> 類別,除了 DRM_DEBUG() 記錄到 DRM_UT_CORE。

啟用詳細除錯訊息是透過 drm.debug 引數完成的,每個類別都由一位啟用

  • drm.debug=0x1 將啟用 CORE 訊息

  • drm.debug=0x2 將啟用 DRIVER 訊息

  • drm.debug=0x3 將啟用 CORE 和 DRIVER 訊息

  • ...

  • drm.debug=0x1ff 將啟用所有訊息

一個有趣的功能是,可以透過在其 sysfs 節點中回顯除錯值來在執行時啟用詳細日誌記錄

# echo 0xf > /sys/module/drm/parameters/debug
struct drm_printer

DRM 輸出“流”

定義:

struct drm_printer {
};

成員

描述

請勿直接使用結構成員。使用 drm_printer_seq_file()、drm_printer_info() 等進行初始化。並使用 drm_printf() 進行輸出。

void drm_vprintf(struct drm_printer *p, const char *fmt, va_list *va)

列印到 drm_printer

引數

struct drm_printer *p

drm_printer

const char *fmt

格式字串

va_list *va

va_list

drm_printf_indent

drm_printf_indent (printer, indent, fmt, ...)

使用縮排列印到 drm_printer

引數

printer

DRM 印表機

indent

製表符縮排級別(最大 5)

fmt

格式字串

...

可變引數

struct drm_print_iterator

與 drm_printer_coredump 一起使用的本地結構

定義:

struct drm_print_iterator {
    void *data;
    ssize_t start;
    ssize_t remain;
};

成員

data

指向 devcoredump 輸出緩衝區的指標,如果使用 drm_printer_coredump 來確定 devcoredump 的大小,則可以為 NULL

start

在緩衝區中開始寫入的偏移量

remain

此迭代要寫入的位元組數

struct drm_printer drm_coredump_printer(struct drm_print_iterator *iter)

構造一個 drm_printer,它可以將輸出輸出到來自 devcoredump 的讀取函式的緩衝區

引數

struct drm_print_iterator *iter

指向讀取例項的 struct drm_print_iterator 的指標

描述

此包裝器擴充套件了 drm_printf() 以使用 dev_coredumpm() 回撥函式。傳入的 drm_print_iterator 結構包含緩衝區指標、大小和偏移量,這些都從 devcoredump 傳入。

例如

void coredump_read(char *buffer, loff_t offset, size_t count,
        void *data, size_t datalen)
{
        struct drm_print_iterator iter;
        struct drm_printer p;

        iter.data = buffer;
        iter.start = offset;
        iter.remain = count;

        p = drm_coredump_printer(&iter);

        drm_printf(p, "foo=%d\n", foo);
}

void makecoredump(...)
{
        ...
        dev_coredumpm(dev, THIS_MODULE, data, 0, GFP_KERNEL,
                coredump_read, ...)
}

上面的示例的時間複雜度為 O(N^2),其中 N 是 devcoredump 的大小。這對於小型的 devcoredump 來說是可以接受的,但對於較大的 devcoredump 來說,擴充套件性較差。

drm_coredump_printer 的另一個用例是在 dev_coredump() 回撥之前將 devcoredump 捕獲到儲存的緩衝區中。這涉及兩次傳遞:一次確定 devcoredump 的大小,另一次將其列印到緩衝區中。然後,在 dev_coredump() 中,從儲存的緩衝區複製到 devcoredump 讀取緩衝區中。

例如

char *devcoredump_saved_buffer;

ssize_t __coredump_print(char *buffer, ssize_t count, ...)
{
        struct drm_print_iterator iter;
        struct drm_printer p;

        iter.data = buffer;
        iter.start = 0;
        iter.remain = count;

        p = drm_coredump_printer(&iter);

        drm_printf(p, "foo=%d\n", foo);
        ...
        return count - iter.remain;
}

void coredump_print(...)
{
        ssize_t count;

        count = __coredump_print(NULL, INT_MAX, ...);
        devcoredump_saved_buffer = kvmalloc(count, GFP_KERNEL);
        __coredump_print(devcoredump_saved_buffer, count, ...);
}

void coredump_read(char *buffer, loff_t offset, size_t count,
                   void *data, size_t datalen)
{
        ...
        memcpy(buffer, devcoredump_saved_buffer + offset, count);
        ...
}

上面的示例的時間複雜度為 O(N*2),其中 N 是 devcoredump 的大小。對於較大的 devcoredump,這比之前的示例具有更好的擴充套件性。

返回值

drm_printer 物件

bool drm_coredump_printer_is_full(struct drm_printer *p)

DRM coredump 印表機輸出已滿

引數

struct drm_printer *p

DRM coredump 印表機

描述

DRM 印表機輸出已滿,可用於在印表機已滿後短路 coredump 列印。

返回值

如果 DRM coredump 印表機輸出緩衝區已滿,則返回 True,否則返回 False

struct drm_printer drm_seq_file_printer(struct seq_file *f)

構造一個 drm_printer,它輸出到 seq_file

引數

struct seq_file *f

要輸出到的 struct seq_file

返回值

drm_printer 物件

struct drm_printer drm_info_printer(struct device *dev)

構造一個 drm_printer,它輸出到 dev_printk()

引數

struct device *dev

struct device 指標

返回值

drm_printer 物件

struct drm_printer drm_dbg_printer(struct drm_device *drm, enum drm_debug_category category, const char *prefix)

構造一個用於 DRM 裝置特定輸出的 drm_printer

引數

struct drm_device *drm

struct drm_device 指標,或 NULL

enum drm_debug_category category

要使用的除錯類別

const char *prefix

除錯輸出字首,或 NULL 表示無字首

返回值

drm_printer 物件

struct drm_printer drm_err_printer(struct drm_device *drm, const char *prefix)

構造一個輸出到 drm_err() 的 drm_printer

引數

struct drm_device *drm

struct drm_device 指標

const char *prefix

除錯輸出字首,或 NULL 表示無字首

返回值

drm_printer 物件

struct drm_printer drm_line_printer(struct drm_printer *p, const char *prefix, unsigned int series)

構造一個 drm_printer,它使用行號作為輸出的字首

引數

struct drm_printer *p

實際生成輸出的 struct drm_printer

const char *prefix

可選的輸出字首,如果沒有字首則為 NULL

unsigned int series

可選的唯一序列識別符號,如果要在輸出中省略識別符號則為 0

描述

此印表機可用於提高捕獲輸出的魯棒性,以確保我們不會丟失輸出的任何中間行。在捕獲一些崩潰資料時很有用。

示例 1

void crash_dump(struct drm_device *drm)
{
        static unsigned int id;
        struct drm_printer p = drm_err_printer(drm, "crash");
        struct drm_printer lp = drm_line_printer(&p, "dump", ++id);

        drm_printf(&lp, "foo");
        drm_printf(&lp, "bar");
}

上面的程式碼將列印到 dmesg 中,如下所示

[ ] 0000:00:00.0: [drm] *ERROR* crash dump 1.1: foo
[ ] 0000:00:00.0: [drm] *ERROR* crash dump 1.2: bar

示例 2

void line_dump(struct device *dev)
{
        struct drm_printer p = drm_info_printer(dev);
        struct drm_printer lp = drm_line_printer(&p, NULL, 0);

        drm_printf(&lp, "foo");
        drm_printf(&lp, "bar");
}

上面的程式碼將列印

[ ] 0000:00:00.0: [drm] 1: foo
[ ] 0000:00:00.0: [drm] 2: bar

返回值

drm_printer 物件

DRM_DEV_ERROR

DRM_DEV_ERROR (dev, fmt, ...)

錯誤輸出。

引數

dev

裝置指標

fmt

類似於 printf() 的格式字串。

...

可變引數

注意

此方法已被棄用,請使用 drm_err() 或 dev_err()。

DRM_DEV_ERROR_RATELIMITED

DRM_DEV_ERROR_RATELIMITED (dev, fmt, ...)

速率限制錯誤輸出。

引數

dev

裝置指標

fmt

類似於 printf() 的格式字串。

...

可變引數

注意

此方法已被棄用,請使用 drm_err_ratelimited() 或 dev_err_ratelimited()。

描述

類似於 DRM_ERROR(),但不會使日誌氾濫。

DRM_DEV_DEBUG

DRM_DEV_DEBUG (dev, fmt, ...)

用於通用 DRM 程式碼的除錯輸出

引數

dev

裝置指標

fmt

類似於 printf() 的格式字串。

...

可變引數

注意

此方法已被棄用,請使用 drm_dbg_core()。

DRM_DEV_DEBUG_DRIVER

DRM_DEV_DEBUG_DRIVER (dev, fmt, ...)

用於驅動程式供應商特定部分的除錯輸出

引數

dev

裝置指標

fmt

類似於 printf() 的格式字串。

...

可變引數

注意

此方法已被棄用,請使用 drm_dbg() 或 dev_dbg()。

DRM_DEV_DEBUG_KMS

DRM_DEV_DEBUG_KMS (dev, fmt, ...)

用於模式設定程式碼的除錯輸出

引數

dev

裝置指標

fmt

類似於 printf() 的格式字串。

...

可變引數

注意

此方法已被棄用,請使用 drm_dbg_kms()。

void drm_puts(struct drm_printer *p, const char *str)

將常量字串列印到 drm_printer

引數

struct drm_printer *p

drm 印表機

const char *str

常量字串

描述

允許具有常量字串選項的 drm_printer 型別使用它。

void drm_printf(struct drm_printer *p, const char *f, ...)

列印到 drm_printer

引數

struct drm_printer *p

drm_printer

const char *f

格式字串

...

可變引數

void drm_print_bits(struct drm_printer *p, unsigned long value, const char *const bits[], unsigned int nbits)

將位列印到 drm_printer

引數

struct drm_printer *p

drm_printer

unsigned long value

欄位值。

const char * const bits[]

帶有位名稱的陣列。

unsigned int nbits

位名稱陣列的大小。

描述

以人類可讀的形式列印位(例如,在標誌欄位中)。

void drm_print_regset32(struct drm_printer *p, struct debugfs_regset32 *regset)

將暫存器的內容列印到 drm_printer 流。

引數

struct drm_printer *p

drm 印表機

struct debugfs_regset32 *regset

要列印的暫存器列表。

描述

通常在驅動程式除錯中,能夠使用 debugfs 或在操作期間的特定點捕獲暫存器的內容很有用。 這使驅動程式可以為兩者提供單個暫存器列表。

void drm_print_hex_dump(struct drm_printer *p, const char *prefix, const u8 *buf, size_t len)

將十六進位制轉儲列印到 drm_printer

引數

struct drm_printer *p

drm_printer

const char *prefix

每行的字首,如果沒有字首則可能為 NULL

const u8 *buf

要轉儲的緩衝區

size_t len

緩衝區長度

描述

將十六進位制轉儲列印到 drm_printer,每行有 16 個空格分隔的十六進位制位元組,可以選擇在每行上帶有字首。 字首後不會新增分隔符。

實用程式

不自然地屬於其他位置的宏和行內函數

bool drm_can_sleep(void)

如果當前可以休眠,則返回 true

引數

void

沒有引數

描述

此函式不應在新程式碼中使用。 對在原子上下文中執行的檢查可能不起作用 - 請參見 linux/preempt.h。

FIXME:應刪除 drm_can_sleep 的所有使用者(請參見 TODO 列表

返回值

如果 kgdb 處於活動狀態、我們在原子上下文中或 irq 被停用,則為 False。

單元測試

KUnit

KUnit(核心單元測試框架)為 Linux 核心中的單元測試提供了一個通用框架。

本節介紹 DRM 子系統的具體資訊。 有關 KUnit 的一般資訊,請參閱 入門

如何執行測試?

為了方便執行測試套件,配置檔案位於 drivers/gpu/drm/tests/.kunitconfig 中。 可以透過 kunit.py 按如下方式使用它

$ ./tools/testing/kunit/kunit.py run --kunitconfig=drivers/gpu/drm/tests \
        --kconfig_add CONFIG_VIRTIO_UML=y \
        --kconfig_add CONFIG_UML_PCI_OVER_VIRTIO=y

注意

包含在 .kunitconfig 中的配置應儘可能通用。 CONFIG_VIRTIO_UMLCONFIG_UML_PCI_OVER_VIRTIO 未包含在其中,因為它們僅對於使用者模式 Linux 是必需的。

KUnit 覆蓋率規則

KUnit 支援正逐步新增到 DRM 框架和輔助函式中。 目前對於框架和輔助函式沒有強制要求必須具有 KUnit 測試。 但是,如果更改需要,影響 KUnit 測試已覆蓋的函式或輔助函式的補丁必須提供測試。

舊版支援程式碼

本節簡要介紹了一些舊的舊版支援程式碼,這些程式碼僅由舊的 DRM 驅動程式使用,這些驅動程式已對底層裝置進行了所謂的影子附加,而不是註冊為真正的驅動程式。 這還包括一些舊的通用緩衝區管理和命令提交程式碼。 不要在新的和現代的驅動程式中使用任何這些程式碼。

舊版掛起/恢復

DRM 核心提供了一些掛起/恢復程式碼,但希望獲得完全掛起/恢復支援的驅動程式應提供 save() 和 restore() 函式。 這些函式在掛起、休眠或恢復時被呼叫,並且應在掛起或休眠狀態之間執行您的裝置所需的任何狀態儲存或恢復。

int (*suspend) (struct drm_device *, pm_message_t state); int (*resume) (struct drm_device *); 這些是舊版的掛起和恢復方法,適用於舊版的影子附加驅動程式註冊函式。 新驅動程式應使用其匯流排型別提供的電源管理介面(通常透過 struct device_driver dev_pm_ops)並將這些方法設定為 NULL。

舊版 DMA 服務

這應涵蓋核心如何支援 DMA 對映等。 這些函式已被棄用,不應使用。