drm/i915 Intel GFX 驅動程式¶
drm/i915 驅動程式支援所有(除了某些非常早期的型號)整合 GFX 晶片組,包括 Intel 顯示和渲染模組。這不包括一組帶有 SGX 渲染單元的 SoC 平臺,這些平臺透過 gma500 drm 驅動程式提供基本支援。
核心驅動程式基礎設施¶
本節介紹驅動程式的顯示和 GEM 部分使用的核心驅動程式基礎設施。
執行時電源管理¶
i915 驅動程式支援在執行時動態啟用和停用整個硬體模組。這在顯示方面尤其重要,因為軟體應該在最新的硬體上手動控制許多電源門,因為在 GT 方面,大部分電源管理由硬體完成。但即使在那裡,也需要在裝置級別進行一些手動控制。
由於 i915 支援具有統一程式碼庫的各種平臺,並且硬體工程師喜歡在電源域之間隨意切換功能,因此需要大量的間接性。此檔案為驅動程式提供通用函式,用於獲取和釋放抽象電源域的引用。然後,它將這些引用對映到給定平臺存在的實際電源井。
-
intel_wakeref_t intel_runtime_pm_get_raw(struct intel_runtime_pm *rpm)¶
獲取原始執行時 pm 引用
引數
struct intel_runtime_pm *rpmintel_runtime_pm 結構
描述
這是 intel_display_power_is_enabled() 的未鎖定版本,應僅從可能發生死鎖的錯誤捕獲和恢復程式碼中使用。此函式獲取裝置級別的執行時 pm 引用(主要用於顯示程式碼中的非同步 PM 管理),並確保已啟動電源。在喚醒鎖斷言檢查期間不考慮原始引用。
透過此函式獲得的任何執行時 pm 引用都必須對稱呼叫 intel_runtime_pm_put_raw() 再次釋放引用。
返回
傳遞給 intel_runtime_pm_put_raw() 的 wakeref cookie,如果已獲取 wakeref,則評估為 True,否則為 False。
-
intel_wakeref_t intel_runtime_pm_get(struct intel_runtime_pm *rpm)¶
獲取執行時 pm 引用
引數
struct intel_runtime_pm *rpmintel_runtime_pm 結構
描述
此函式獲取裝置級別的執行時 pm 引用(主要用於 GEM 程式碼以確保 GTT 或 GT 已開啟),並確保已啟動電源。
透過此函式獲得的任何執行時 pm 引用都必須對稱呼叫 intel_runtime_pm_put() 再次釋放引用。
返回
傳遞給 intel_runtime_pm_put() 的 wakeref cookie
-
intel_wakeref_t __intel_runtime_pm_get_if_active(struct intel_runtime_pm *rpm, bool ignore_usecount)¶
如果裝置處於活動狀態,則獲取執行時 pm 引用
引數
struct intel_runtime_pm *rpmintel_runtime_pm 結構
bool ignore_usecount即使 dev->power.usage_count 為 0,也獲取引用
描述
如果裝置已處於活動狀態,此函式將獲取裝置級別的執行時 pm 引用,並確保已啟動電源。如果 intel_runtime_pm_get_if_active() 報告失敗,則嘗試訪問硬體是非法的。
如果 ignore_usecount 為 true,即使沒有使用者需要裝置上電(dev->power.usage_count == 0),也會獲取引用。如果該函式在這種情況下返回 false,則保證裝置的執行時掛起鉤子已被呼叫,或者將被呼叫(因此也保證最終將呼叫裝置的執行時恢復鉤子)。
透過此函式獲得的任何執行時 pm 引用都必須對稱呼叫 intel_runtime_pm_put() 再次釋放引用。
返回
傳遞給 intel_runtime_pm_put() 的 wakeref cookie,如果已獲取 wakeref,則評估為 True,否則為 False。
-
intel_wakeref_t intel_runtime_pm_get_noresume(struct intel_runtime_pm *rpm)¶
獲取執行時 pm 引用
引數
struct intel_runtime_pm *rpmintel_runtime_pm 結構
描述
此函式獲取裝置級別的執行時 pm 引用。
它將 _不_ 恢復裝置,而僅獲取額外的 wakeref。因此,只有在已知裝置處於活動狀態且之前已持有另一個 wakeref 的情況下,呼叫此函式才是有效的。
透過此函式獲得的任何執行時 pm 引用都必須對稱呼叫 intel_runtime_pm_put() 再次釋放引用。
返回
傳遞給 intel_runtime_pm_put() 的 wakeref cookie
-
void intel_runtime_pm_put_raw(struct intel_runtime_pm *rpm, intel_wakeref_t wref)¶
釋放原始執行時 pm 引用
引數
struct intel_runtime_pm *rpmintel_runtime_pm 結構
intel_wakeref_t wref為正在釋放的引用獲取的 wakeref
描述
此函式刪除透過 intel_runtime_pm_get_raw() 獲得的裝置級別執行時 pm 引用,如果這是最後一個引用,則可能會立即關閉相應硬體模組的電源。
-
void intel_runtime_pm_put_unchecked(struct intel_runtime_pm *rpm)¶
釋放未經檢查的執行時 pm 引用
引數
struct intel_runtime_pm *rpmintel_runtime_pm 結構
描述
此函式刪除透過 intel_runtime_pm_get() 獲得的裝置級別執行時 pm 引用,如果這是最後一個引用,則可能會立即關閉相應硬體模組的電源。
此函式僅因歷史原因而存在,應在新程式碼中避免使用,因為無法檢查其使用的正確性。始終使用 intel_runtime_pm_put() 代替。
-
void intel_runtime_pm_put(struct intel_runtime_pm *rpm, intel_wakeref_t wref)¶
釋放執行時 pm 引用
引數
struct intel_runtime_pm *rpmintel_runtime_pm 結構
intel_wakeref_t wref為正在釋放的引用獲取的 wakeref
描述
此函式刪除透過 intel_runtime_pm_get() 獲得的裝置級別執行時 pm 引用,如果這是最後一個引用,則可能會立即關閉相應硬體模組的電源。
-
void intel_runtime_pm_enable(struct intel_runtime_pm *rpm)¶
啟用執行時 pm
引數
struct intel_runtime_pm *rpmintel_runtime_pm 結構
描述
此函式在驅動程式載入序列結束時啟用執行時 pm。
請注意,此函式當前不為從屬顯示電源域啟用執行時 pm。 這由 intel_power_domains_enable() 完成。
-
void intel_uncore_forcewake_get(struct intel_uncore *uncore, enum forcewake_domains fw_domains)¶
獲取 forcewake 域引用
引數
struct intel_uncore *uncoreintel_uncore 結構
enum forcewake_domains fw_domains要在其上獲取引用的 forcewake 域
描述
此函式可用於獲取 GT 的 forcewake 域引用。正常暫存器訪問將自動處理 forcewake 域。但是,如果某些序列要求 GT 不關閉特定 forcewake 域的電源,則應在該序列的開頭呼叫此函式。隨後,應透過對稱呼叫 intel_unforce_forcewake_put() 來刪除引用。通常,呼叫方希望保持所有域處於喚醒狀態,因此 fw_domains 將是 FORCEWAKE_ALL。
-
void intel_uncore_forcewake_user_get(struct intel_uncore *uncore)¶
代表使用者空間宣告 forcewake
引數
struct intel_uncore *uncoreintel_uncore 結構
描述
此函式是 intel_uncore_forcewake_get() 的包裝器,用於獲取 GT 電源井,並在過程中停用使用者空間旁路期間的除錯。
-
void intel_uncore_forcewake_user_put(struct intel_uncore *uncore)¶
代表使用者空間釋放 forcewake
引數
struct intel_uncore *uncoreintel_uncore 結構
描述
此函式補充 intel_uncore_forcewake_user_get(),並釋放代表使用者空間旁路獲取的 GT 電源井。
-
void intel_uncore_forcewake_get__locked(struct intel_uncore *uncore, enum forcewake_domains fw_domains)¶
獲取 forcewake 域引用
引數
struct intel_uncore *uncoreintel_uncore 結構
enum forcewake_domains fw_domains要在其上獲取引用的 forcewake 域
描述
請參閱 intel_uncore_forcewake_get()。此變體將顯式處理 dev_priv->uncore.lock 自旋鎖的責任推給呼叫方。
-
void intel_uncore_forcewake_put(struct intel_uncore *uncore, enum forcewake_domains fw_domains)¶
釋放 forcewake 域引用
引數
struct intel_uncore *uncoreintel_uncore 結構
enum forcewake_domains fw_domains要放置引用的 forcewake 域
描述
此函式刪除透過 intel_uncore_forcewake_get() 獲取的指定域的裝置級別 forcewake。
-
void intel_uncore_forcewake_flush(struct intel_uncore *uncore, enum forcewake_domains fw_domains)¶
重新整理延遲釋放
引數
struct intel_uncore *uncoreintel_uncore 結構
enum forcewake_domains fw_domains要重新整理的 forcewake 域
-
void intel_uncore_forcewake_put__locked(struct intel_uncore *uncore, enum forcewake_domains fw_domains)¶
釋放 forcewake 域引用
引數
struct intel_uncore *uncoreintel_uncore 結構
enum forcewake_domains fw_domains要放置引用的 forcewake 域
描述
請參閱 intel_uncore_forcewake_put()。此變體將顯式處理 dev_priv->uncore.lock 自旋鎖的責任推給呼叫方。
-
int __intel_wait_for_register_fw(struct intel_uncore *uncore, i915_reg_t reg, u32 mask, u32 value, unsigned int fast_timeout_us, unsigned int slow_timeout_ms, u32 *out_value)¶
等待直到暫存器與預期狀態匹配
引數
struct intel_uncore *uncorestruct intel_uncore
i915_reg_t reg要讀取的暫存器
u32 mask要應用於暫存器值的掩碼
u32 value預期值
unsigned int fast_timeout_us原子/緊密等待的快速超時(以微秒為單位)
unsigned int slow_timeout_ms慢速超時(以毫秒為單位)
u32 *out_value可選的佔位符,用於儲存登錄檔值
描述
此例程等待直到目標暫存器 reg 在應用 mask 後包含預期的 value,即它等待直到
(intel_uncore_read_fw(uncore, reg) & mask) == value
否則,等待將在 slow_timeout_ms 毫秒後超時。對於原子上下文,slow_timeout_ms 必須為零,並且 fast_timeout_us 必須不大於 200,000 微秒。
請注意,此例程假定呼叫方已斷言 forcewake,它不適合長時間等待。如果您希望在不持有 forcewake 的情況下等待一段時間(即,您預計等待會很慢),請參閱 intel_wait_for_register()。
返回
如果暫存器與所需的條件匹配,則為 0,否則為 -ETIMEDOUT。
-
int __intel_wait_for_register(struct intel_uncore *uncore, i915_reg_t reg, u32 mask, u32 value, unsigned int fast_timeout_us, unsigned int slow_timeout_ms, u32 *out_value)¶
等待直到暫存器與預期狀態匹配
引數
struct intel_uncore *uncorestruct intel_uncore
i915_reg_t reg要讀取的暫存器
u32 mask要應用於暫存器值的掩碼
u32 value預期值
unsigned int fast_timeout_us原子/緊密等待的快速超時(以微秒為單位)
unsigned int slow_timeout_ms慢速超時(以毫秒為單位)
u32 *out_value可選的佔位符,用於儲存登錄檔值
描述
此例程等待直到目標暫存器 reg 在應用 mask 後包含預期的 value,即它等待直到
(intel_uncore_read(uncore, reg) & mask) == value
否則,等待將在 timeout_ms 毫秒後超時。
返回
如果暫存器與所需的條件匹配,則為 0,否則為 -ETIMEDOUT。
-
enum forcewake_domains intel_uncore_forcewake_for_reg(struct intel_uncore *uncore, i915_reg_t reg, unsigned int op)¶
訪問暫存器需要哪些 forcewake 域
引數
struct intel_uncore *uncore指向 struct intel_uncore 的指標
i915_reg_t reg有問題的暫存器
unsigned int opFW_REG_READ 和/或 FW_REG_WRITE 的操作位掩碼
描述
返回一組 forcewake 域,需要透過例如 intel_uncore_forcewake_get 來獲取,以便指定的暫存器在指定的模式(讀、寫或讀/寫)下透過原始 mmio 訪問器進行訪問。
注意
在 Gen6 和 Gen7 上,寫入 forcewake 域 (FORCEWAKE_RENDER) 需要呼叫者自行進行 FIFO 管理,否則可能丟失寫入。
中斷處理¶
這些函式提供了啟用和停用中斷處理支援的基本支援。i915_irq.c 和相關檔案中還有更多功能,但將在單獨的章節中介紹。
-
void intel_irq_init(struct drm_i915_private *dev_priv)¶
初始化 irq 支援
引數
struct drm_i915_private *dev_privi915 裝置例項
描述
此函式初始化所有 irq 支援,包括工作項、定時器和所有 vtable。但它不會設定中斷本身。
-
void intel_irq_suspend(struct drm_i915_private *i915)¶
掛起中斷
引數
struct drm_i915_private *i915i915 裝置例項
描述
此函式用於在執行時停用中斷。
-
void intel_irq_resume(struct drm_i915_private *i915)¶
恢復中斷
引數
struct drm_i915_private *i915i915 裝置例項
描述
此函式用於在執行時啟用中斷。
Intel GVT-g 客戶機支援 (vGPU)¶
Intel GVT-g 是一種圖形虛擬化技術,它以分時方式在多個虛擬機器之間共享 GPU。每個虛擬機器都呈現一個虛擬 GPU (vGPU),它具有與底層物理 GPU (pGPU) 等效的功能,因此 i915 驅動程式可以在虛擬機器中無縫執行。此檔案提供了在虛擬機器中執行時 vGPU 特定的最佳化,以降低 vGPU 模擬的複雜性並提高整體效能。
此處介紹的主要功能是所謂的“地址空間膨脹”技術。Intel GVT-g 在多個 VM 之間劃分全域性圖形記憶體,因此每個 VM 都可以直接訪問一部分記憶體,而無需管理程式的干預,例如填充紋理或排隊命令。然而,透過分割槽,未修改的 i915 驅動程式會假定一個從地址 ZERO 開始的較小圖形記憶體,然後要求 vGPU 模擬模組在“客戶機檢視”和“主機檢視”之間轉換圖形地址,對於所有包含圖形記憶體地址的暫存器和命令操作碼。為了降低複雜性,Intel GVT-g 引入了“地址空間膨脹”,透過將確切的分割槽知識告訴每個客戶機 i915 驅動程式,然後保留並阻止分配未分配的部分。因此,vGPU 模擬模組只需要掃描和驗證圖形地址,而無需複雜的地址轉換。
-
void intel_vgpu_detect(struct drm_i915_private *dev_priv)¶
檢測虛擬 GPU
引數
struct drm_i915_private *dev_privi915 裝置私有資料
描述
此函式在初始化階段呼叫,以檢測是否在 vGPU 上執行。
-
void intel_vgt_deballoon(struct i915_ggtt *ggtt)¶
釋放保留的圖形地址塊
引數
struct i915_ggtt *ggtt我們之前保留的全域性 GGTT
描述
此函式在解除安裝驅動程式或膨脹失敗時呼叫,以釋放膨脹出來的圖形記憶體。
-
int intel_vgt_balloon(struct i915_ggtt *ggtt)¶
膨脹保留的圖形地址塊
引數
struct i915_ggtt *ggtt要從中保留的全域性 GGTT
描述
此函式在初始化階段呼叫,以膨脹分配給其他 vGPU 的圖形地址空間,方法是將這些空間標記為保留。膨脹相關的知識(可對映/不可對映圖形記憶體的起始地址和大小)在保留的 mmio 範圍內的 vgt_if 結構中描述。
舉例來說,下圖描述了膨脹後的一種典型情況。這裡 vGPU1 有 2 塊圖形地址空間膨脹出來,分別用於可對映和不可對映部分。從 vGPU1 的角度來看,總大小與物理大小相同,其圖形空間的起始地址為零。但有一些部分膨脹出來了(陰影部分,標記為 drm 分配器保留)。從主機的角度來看,圖形地址空間由不同 VM 中的多個 vGPU 分割槽。
vGPU1 view Host view
0 ------> +-----------+ +-----------+
^ |###########| | vGPU3 |
| |###########| +-----------+
| |###########| | vGPU2 |
| +-----------+ +-----------+
mappable GM | available | ==> | vGPU1 |
| +-----------+ +-----------+
| |###########| | |
v |###########| | Host |
+=======+===========+ +===========+
^ |###########| | vGPU3 |
| |###########| +-----------+
| |###########| | vGPU2 |
| +-----------+ +-----------+
unmappable GM | available | ==> | vGPU1 |
| +-----------+ +-----------+
| |###########| | |
| |###########| | Host |
v |###########| | |
total GM size ------> +-----------+ +-----------+
返回
成功時為零,如果配置無效或膨脹失敗則為非零
Intel GVT-g 主機支援 (vGPU 裝置模型)¶
Intel GVT-g 是一種圖形虛擬化技術,它以分時方式在多個虛擬機器之間共享 GPU。每個虛擬機器都呈現一個虛擬 GPU (vGPU),它具有與底層物理 GPU (pGPU) 等效的功能,因此 i915 驅動程式可以在虛擬機器中無縫執行。
為了虛擬化 GPU 資源,GVT-g 驅動程式依賴於管理程式技術,例如 KVM/VFIO/mdev、Xen 等,以提供資源訪問捕獲能力並在 GVT-g 裝置模組中進行虛擬化。更多架構設計文件可在 https://github.com/intel/gvt-linux/wiki 上找到。
-
int intel_gvt_init(struct drm_i915_private *dev_priv)¶
初始化 GVT 元件
引數
struct drm_i915_private *dev_privdrm i915 私有資料
描述
此函式在初始化階段呼叫,以建立 GVT 裝置。
返回
成功時為零,失敗時為負錯誤程式碼。
-
void intel_gvt_driver_remove(struct drm_i915_private *dev_priv)¶
在 i915 驅動程式解除繫結時清理 GVT 元件
引數
struct drm_i915_private *dev_privdrm i915 private *
描述
此函式在 i915 驅動程式解除安裝階段呼叫,以關閉 GVT 元件並釋放相關資源。
-
void intel_gvt_resume(struct drm_i915_private *dev_priv)¶
GVT 恢復例程包裝器
引數
struct drm_i915_private *dev_privdrm i915 private *
描述
此函式在 i915 驅動程式恢復階段呼叫,以恢復 GVT 所需的 HW 狀態,以便 vGPU 在恢復後可以繼續執行。
解決方法¶
硬體解決方法是記錄在驅動程式中執行的暫存器程式設計,這些程式設計不在平臺的正常程式設計序列之外。根據應用的方式/時間,有一些基本類別的解決方法
上下文解決方法:觸及儲存/從 HW 上下文映像恢復的暫存器的解決方法。該列表在初始化裝置時發出一次(透過載入暫存器立即命令),並儲存在預設上下文中。然後,每個上下文建立都使用該預設上下文來獲得“原始黃金上下文”,即已經包含所有暫存器所需更改的上下文映像。
上下文解決方法應在分別針對目標平臺的 *_ctx_workarounds_init() 變體中實現。
引擎解決方法:每當重置特定引擎時,都會應用這些 WA 的列表。一組引擎類也可能共享一個公共電源域,並且它們一起重置。這發生在某些平臺上,涉及渲染和計算引擎。在這種情況下,(至少)其中一個需要保留解決方法程式設計:驅動程式中採用的方法是將這些解決方法與註冊的第一個計算/渲染引擎繫結。使用 GuC 提交執行時,引擎重置不受核心驅動程式控制,因此,在引擎初始化時,將寫入一次涉及的暫存器列表,然後傳遞給 GuC,GuC 會在重置發生之前/之後儲存/恢復它們的值。有關參考,請參見
drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c。針對 RCS 和 CCS 特定的暫存器的解決方法應分別在 rcs_engine_wa_init() 和 ccs_engine_wa_init() 中實現;屬於 BCS、VCS 或 VECS 的暫存器的解決方法應在 xcs_engine_wa_init() 中實現。不屬於特定引擎的 MMIO 範圍但屬於通用 RCS/CCS 重置域的暫存器的解決方法應在 general_render_compute_wa_init() 中實現。有關 CCS 負載平衡的設定應新增到 ccs_engine_wa_mode() 中。
GT 解決方法:每當這些暫存器恢復為預設值時(在 GPU 重置、掛起/恢復 [1] 等時),都會應用這些 WA 的列表。
GT 解決方法應在分別針對目標平臺的 *_gt_workarounds_init() 變體中實現。
暫存器白名單:一些解決方法需要在使用者空間中實現,但需要觸及特權暫存器。核心中的白名單指示硬體允許訪問發生。從核心方面來看,這只是 MMIO 解決方法的一種特殊情況(因為我們將這些要列入白名單的暫存器列表寫入一些特殊的 HW 暫存器)。
暫存器列入白名單應在分別針對目標平臺的 *_whitelist_build() 變體中完成。
解決方法批處理緩衝區:硬體在每次 HW 上下文恢復時自動執行的緩衝區。這些緩衝區在預設上下文中建立和程式設計,因此硬體在切換上下文時始終會透過這些程式設計序列。對解決方法批處理緩衝區的支援已啟用這些硬體機制
INDIRECT_CTX:在預設上下文中提供一個批處理緩衝區和一個偏移量,指示硬體在該偏移量在上下文恢復中達到時跳轉到該位置。驅動程式中的解決方法批處理緩衝區當前對所有平臺都使用此機制。
BB_PER_CTX_PTR:在預設上下文中提供一個批處理緩衝區,指示硬體在上下文恢復序列中恢復引擎暫存器後繼續執行的緩衝區。當前在驅動程式中未使用此功能。
其他:有些 WA 由於其性質,無法從中心位置應用。這些 WA 根據需要在程式碼的其他部分中進行調整。與顯示 IP 相關的解決方法是主要示例。
顯示硬體處理¶
本節涵蓋與顯示硬體相關的所有內容,包括模式設定基礎結構、平面、精靈和游標處理以及顯示、輸出探測和相關主題。
模式設定基礎結構¶
到目前為止,i915 驅動程式是唯一不使用通用 DRM 幫助程式程式碼來實現模式設定序列的 DRM 驅動程式。因此,它具有自己量身定製的基礎結構來執行顯示配置更改。
前緩衝跟蹤¶
許多功能要求我們跟蹤當前活動前緩衝的更改,特別是針對前緩衝的渲染。
為了能夠做到這一點,我們透過 intel_frontbuffer_track() 使用位掩碼來跟蹤所有可能的前緩衝槽中的前緩衝。然後,當使前緩衝的內容無效時、當再次停止前緩衝渲染以清除所有更改時以及當使用翻轉交換前緩衝時,將呼叫此檔案中的函式。對前緩衝更改感興趣的子系統(例如 PSR、FBC、DRRS)應直接將其回撥放入相關位置,並篩選出它們感興趣的前緩衝槽。
在高層上,有兩種型別的節能功能。第一種像特殊的快取(FBC 和 PSR)一樣工作,並且對它們應該何時停止快取以及何時重新啟動快取感興趣。這可以透過將回調放入無效和重新整理函式來實現:在無效時必須停止快取,而在重新整理時可以重新啟動快取。並且可能需要知道前緩衝何時更改(例如,當 hw 不自行啟動無效和重新整理時),這可以透過將回調放入翻轉函式來實現。
另一種型別的顯示節能功能只關心繁忙程度(例如 DRRS)。在這種情況下,所有三個(無效、重新整理和翻轉)都指示繁忙程度。沒有直接的方法來檢測空閒。相反,應該從重新整理和翻轉函式啟動空閒定時器延遲工作,並在檢測到繁忙程度後立即取消。
-
bool intel_frontbuffer_invalidate(struct intel_frontbuffer *front, enum fb_op_origin origin)¶
使前緩衝物件無效
引數
struct intel_frontbuffer *front要使其無效的 GEM 物件
enum fb_op_origin origin哪個操作導致了無效
描述
每次在給定物件上開始渲染時都會呼叫此函式,並且必須使前緩衝快取(fbc、DRRS 的低重新整理率、面板自重新整理)無效。對於 ORIGIN_CS,任何後續無效都將延遲到渲染完成或計劃在此前緩衝平面上進行翻轉。
-
void intel_frontbuffer_flush(struct intel_frontbuffer *front, enum fb_op_origin origin)¶
重新整理前緩衝物件
引數
struct intel_frontbuffer *front要重新整理的 GEM 物件
enum fb_op_origin origin哪個操作導致了重新整理
描述
每次在給定物件上完成渲染時都會呼叫此函式,並且可以再次啟動前緩衝快取。
-
void frontbuffer_flush(struct intel_display *display, unsigned int frontbuffer_bits, enum fb_op_origin origin)¶
重新整理前緩衝
引數
struct intel_display *display顯示裝置
unsigned int frontbuffer_bits前緩衝平面跟蹤位
enum fb_op_origin origin哪個操作導致了重新整理
描述
每次在給定平面上完成渲染時都會呼叫此函式,並且可以再次啟動前緩衝快取。如果重新整理被一些未完成的非同步渲染阻止,重新整理將被延遲。
可以在不持有任何鎖的情況下呼叫。
-
void intel_frontbuffer_flip_prepare(struct intel_display *display, unsigned frontbuffer_bits)¶
準備非同步前緩衝翻轉
引數
struct intel_display *display顯示裝置
unsigned frontbuffer_bits前緩衝平面跟蹤位
描述
此函式在計劃在 obj 上進行翻轉後呼叫。實際的前緩衝重新整理將被延遲,直到使用 intel_frontbuffer_flip_complete 發出完成訊號。如果在此期間發生無效,則將取消此重新整理。
可以在不持有任何鎖的情況下呼叫。
-
void intel_frontbuffer_flip_complete(struct intel_display *display, unsigned frontbuffer_bits)¶
完成非同步前緩衝翻轉
引數
struct intel_display *display顯示裝置
unsigned frontbuffer_bits前緩衝平面跟蹤位
描述
此函式在翻轉已閂鎖並將於下一個 vblank 完成後呼叫。如果尚未取消重新整理,它將執行重新整理。
可以在不持有任何鎖的情況下呼叫。
-
void intel_frontbuffer_flip(struct intel_display *display, unsigned frontbuffer_bits)¶
同步前緩衝翻轉
引數
struct intel_display *display顯示裝置
unsigned frontbuffer_bits前緩衝平面跟蹤位
描述
此函式在計劃在 obj 上進行翻轉後呼叫。這是用於將在下一個 vblank 上發生的同步平面更新,並且不會因掛起的 gpu 渲染而延遲。
可以在不持有任何鎖的情況下呼叫。
-
void intel_frontbuffer_queue_flush(struct intel_frontbuffer *front)¶
重新整理前緩衝區物件的佇列
引數
struct intel_frontbuffer *front要重新整理的 GEM 物件
描述
此函式的目標是我們的髒回撥,用於在 dma 柵欄發出訊號時排隊重新整理
-
void intel_frontbuffer_track(struct intel_frontbuffer *old, struct intel_frontbuffer *new, unsigned int frontbuffer_bits)¶
更新前緩衝區跟蹤
引數
struct intel_frontbuffer *old前緩衝區槽的當前緩衝區
struct intel_frontbuffer *new前緩衝區槽的新緩衝區
unsigned int frontbuffer_bits前緩衝區槽的位掩碼
描述
此函式透過從 old 中清除並設定到 new 中來更新前緩衝區跟蹤位 frontbuffer_bits。 old 和 new 都可以為 NULL。
顯示 FIFO 欠載報告¶
i915 驅動程式使用硬體提供的中斷訊號檢查顯示 fifo 欠載。預設情況下啟用此功能,並且對於除錯顯示問題(尤其是水印設定)非常有用。
如果檢測到欠載,則會將其記錄到 dmesg 中。為了避免日誌氾濫和佔用 cpu,在給定管道上的下一次模式設定之前,欠載中斷會在第一次發生後被停用。
請注意,由於沒有中斷(儘管信令位位於 PIPESTAT 管道中斷暫存器中),因此在 gmch 平臺上進行欠載檢測會更加麻煩。同樣,在某些其他平臺上,欠載中斷是共享的,這意味著如果我們檢測到欠載,則需要停用所有管道上的欠載報告。
該程式碼還支援 PCH 轉碼器上的欠載檢測。
-
bool intel_set_cpu_fifo_underrun_reporting(struct intel_display *display, enum pipe pipe, bool enable)¶
設定 cpu fifo 欠載報告狀態
引數
struct intel_display *display顯示裝置例項
enum pipe pipe要設定狀態的 (CPU) 管道
bool enable是否應報告欠載
描述
此函式設定 pipe 的 fifo 欠載狀態。它在模式設定程式碼中使用,以避免誤報,因為在許多平臺上,停用或啟用管道時會預期出現欠載。
請注意,在某些平臺上,由於共享中斷,停用一個管道的欠載報告會停用所有管道的欠載報告。但是,實際報告仍然是按管道進行的。
返回欠載報告的先前狀態。
-
bool intel_set_pch_fifo_underrun_reporting(struct intel_display *display, enum pipe pch_transcoder, bool enable)¶
設定 PCH fifo 欠載報告狀態
引數
struct intel_display *display顯示裝置例項
enum pipe pch_transcoderPCH 轉碼器(在 IVB 和更早版本上與管道相同)
bool enable是否應報告欠載
描述
此函式使我們能夠為特定的 PCH 轉碼器停用或啟用 PCH fifo 欠載。請注意,在某些 PCH(例如 CPT/PPT)上,由於所有轉碼器只有一箇中斷掩碼/啟用位,因此停用一個轉碼器的 FIFO 欠載報告也可能停用其他轉碼器的所有其他 PCH 錯誤中斷。
返回欠載報告的先前狀態。
-
void intel_cpu_fifo_underrun_irq_handler(struct intel_display *display, enum pipe pipe)¶
處理 CPU fifo 欠載中斷
引數
struct intel_display *display顯示裝置例項
enum pipe pipe要設定狀態的 (CPU) 管道
描述
此函式處理 CPU fifo 欠載中斷,如果在 dmesg 中啟用了欠載報告,則生成欠載警告,然後停用欠載中斷以避免 irq 風暴。
-
void intel_pch_fifo_underrun_irq_handler(struct intel_display *display, enum pipe pch_transcoder)¶
處理 PCH fifo 欠載中斷
引數
struct intel_display *display顯示裝置例項
enum pipe pch_transcoderPCH 轉碼器(在 IVB 和更早版本上與管道相同)
描述
此函式處理 PCH fifo 欠載中斷,如果在 dmesg 中啟用了欠載報告,則生成欠載警告,然後停用欠載中斷以避免 irq 風暴。
-
void intel_check_cpu_fifo_underruns(struct intel_display *display)¶
立即檢查 CPU fifo 欠載
引數
struct intel_display *display顯示裝置例項
描述
立即檢查 CPU fifo 欠載。在 IVB/HSW 上很有用,因為共享錯誤中斷可能已被停用,因此 CPU fifo 欠載不一定會引發中斷,並且在 gmch 平臺上,欠載永遠不會引發中斷。
-
void intel_check_pch_fifo_underruns(struct intel_display *display)¶
立即檢查 PCH fifo 欠載
引數
struct intel_display *display顯示裝置例項
描述
立即檢查 PCH fifo 欠載。在 CPT/PPT 上很有用,因為共享錯誤中斷可能已被停用,因此 PCH fifo 欠載不一定會引發中斷。
平面配置¶
本節介紹平面配置以及與主平面、精靈、游標和覆蓋的合成。這包括對所有此狀態進行原子 vsync 更新的基礎結構,以及緊密耦合的主題,如水印設定和計算、幀緩衝區壓縮和麵板自重新整理。
原子平面幫助程式¶
原子平面幫助程式函式使用此處的函式來實現舊式平面更新(即,drm_plane->update_plane() 和 drm_plane->disable_plane())。這允許平面更新使用原子狀態基礎結構,並將平面更新作為單獨的 prepare/check/commit/cleanup 步驟執行。
引數
struct drm_plane *plane要銷燬的平面
描述
所有型別的平面(主平面、游標、精靈)的公共銷燬函式。
-
struct drm_plane_state *intel_plane_duplicate_state(struct drm_plane *plane)¶
複製平面狀態
引數
struct drm_plane *planedrm 平面
描述
為指定的平面分配並返回平面狀態的副本(包括通用狀態和 Intel 特定狀態)。
返回
新分配的平面狀態,如果失敗,則為 NULL。
-
void intel_plane_destroy_state(struct drm_plane *plane, struct drm_plane_state *state)¶
銷燬平面狀態
引數
struct drm_plane *planedrm 平面
struct drm_plane_state *state要銷燬的狀態物件
描述
銷燬指定平面的平面狀態(包括通用狀態和 Intel 特定狀態)。
-
int intel_prepare_plane_fb(struct drm_plane *_plane, struct drm_plane_state *_new_plane_state)¶
準備要在平面上使用的 fb
引數
struct drm_plane *_plane要準備的 drm 平面
struct drm_plane_state *_new_plane_state要準備的平面狀態
描述
準備要在顯示平面上使用的幀緩衝區。通常,這涉及固定底層物件並更新前緩衝區跟蹤位。一些較舊的平臺需要對游標平面進行特殊的物理地址處理。
成功時返回 0,失敗時返回負錯誤程式碼。
-
void intel_cleanup_plane_fb(struct drm_plane *plane, struct drm_plane_state *_old_plane_state)¶
在使用平面後清理 fb
引數
struct drm_plane *plane要清理的 drm 平面
struct drm_plane_state *_old_plane_state來自先前模式設定的狀態
描述
清理剛剛從平面中刪除的幀緩衝區。
非同步頁面翻轉¶
非同步頁面翻轉是 DRM_MODE_PAGE_FLIP_ASYNC 標誌的實現。目前,非同步翻轉僅透過 drmModePageFlip IOCTL 支援。相應地,當前僅為主平面新增支援。
非同步翻轉只能更改平面表面地址,因此從 intel_async_flip_check_hw() 函式中拒絕任何其他更改。清除此檢查後,使用 intel_crtc_enable_flip_done() 函式啟用翻轉完成中斷。
只要寫入表面地址暫存器,就會生成翻轉完成中斷,並且所請求的事件會透過中斷處理程式本身傳送到使用者空間。在翻轉完成事件期間傳送的時間戳和序列對應於上次 vblank,並且與傳送翻轉完成事件的實際時間無關。
輸出探測¶
本節介紹輸出探測和相關基礎結構,如熱插拔中斷風暴檢測和緩解程式碼。請注意,i915 驅動程式仍然使用大部分常見的 DRM 幫助程式程式碼進行輸出探測,因此這些章節完全適用。
熱插拔¶
簡而言之,當顯示器連線到系統或從系統斷開連線時,就會發生熱插拔。但是,可能涉及介面卡、擴充套件塢和 Display Port 短脈衝和 MST 裝置,從而使情況變得複雜。
i915 中的熱插拔在許多不同的抽象級別上處理。
i915_irq.c 中與平臺相關的中斷處理程式碼啟用、停用和執行中斷的初步處理。中斷處理程式將熱插拔檢測 (HPD) 資訊從相關暫存器收集到已觸發的熱插拔引腳的與平臺無關的掩碼中。
intel_hotplug.c 中與平臺無關的中斷處理程式 intel_hpd_irq_handler() 執行熱插拔 irq 風暴檢測和緩解,並將進一步處理傳遞到適當的下半部分(特定於 Display Port 和常規熱插拔)。
Display Port 工作函式 i915_digport_work_func() 透過掛鉤呼叫 intel_dp_hpd_pulse(),後者處理 DP 短脈衝和 DP MST 長脈衝,出現故障和非 MST 長脈衝會觸發聯結器上的常規熱插拔處理。
常規熱插拔工作函式 i915_hotplug_work_func() 呼叫聯結器檢測掛鉤,並且如果聯結器狀態發生變化,則透過 drm_kms_helper_hotplug_event() 觸發向用戶空間傳送熱插拔 uevent。
最後,使用者空間負責在收到熱插拔 uevent 時觸發模式設定,根據需要停用或啟用 crtc。
熱插拔中斷風暴檢測和緩解程式碼跟蹤每個熱插拔引腳在一段時間內的中斷次數,如果中斷次數超過某個閾值,則會停用中斷一段時間,然後再重新啟用。目的是緩解由損壞的硬體觸發大量中斷並使系統停止的問題。
當前的實現預計在連線 display port sink 時不會看到熱插拔中斷風暴,因此對於其 DP 回撥由 i915_digport_work_func 處理的平臺,不執行 hpd 的重新啟用(從一開始就不希望停用它 ;) )這特定於此例程處理的 DP sink,並且在同一埠上啟用的任何其他顯示器(如 HDMI 或 DVI)都將具有正確的邏輯,因為它將使用 i915_hotplug_work_func,其中已處理此邏輯。
引數
enum port port要獲取關聯引腳的 hpd 埠
描述
它僅對數字埠編碼器有效並由其使用。
返回與 port 關聯的引腳。
-
bool intel_hpd_irq_storm_detect(struct intel_display *display, enum hpd_pin pin, bool long_hpd)¶
收集統計資訊並檢測引腳上的 HPD IRQ 風暴
引數
struct intel_display *display顯示裝置
enum hpd_pin pin要在其上收集統計資訊的引腳
bool long_hpdHPD IRQ 是長脈衝還是短脈衝
描述
從指定的 pin 收集有關 HPD IRQ 的統計資訊,並檢測 IRQ 風暴。僅更改特定於引腳的統計資訊和狀態,呼叫方負責採取進一步操作。
在 HPD_STORM_DETECT_PERIOD 內允許的 IRQ 數量儲存在 display->hotplug.hpd_storm_threshold 中,預設為 HPD_STORM_DEFAULT_THRESHOLD。長 IRQ 計為 +10 到此閾值,短 IRQ 計為 +1。如果超過此閾值,則將其視為 IRQ 風暴,並將 IRQ 狀態設定為 HPD_MARK_DISABLED。
預設情況下,大多數系統只會將長 IRQ 計入 display->hotplug.hpd_storm_threshold。但是,一些較舊的系統也遭受短 IRQ 風暴的影響,並且還必須跟蹤這些風暴。由於短 IRQ 風暴自然是由與 DP MST 裝置的邊帶互動引起的,因此僅對不支援 DP MST 的系統啟用短 IRQ 檢測。足夠新以支援 DP MST 的系統不太可能遭受任何 IRQ 風暴,因此這很好。
HPD 閾值可以透過 debugfs 中的 i915_hpd_storm_ctl 控制,並且僅應針對自動化熱插拔測試進行調整。
如果檢測到 pin 上的 IRQ 風暴,則返回 true。
-
void intel_hpd_trigger_irq(struct intel_digital_port *dig_port)¶
觸發埠的 hpd irq 事件
引數
struct intel_digital_port *dig_port數字埠
描述
為給定埠觸發 HPD 中斷事件,模擬 sink 生成的短脈衝,並安排 dig 埠工作來處理它。
-
void intel_hpd_irq_handler(struct intel_display *display, u32 pin_mask, u32 long_mask)¶
主要的熱插拔IRQ處理程式。
引數
struct intel_display *display顯示裝置
u32 pin_mask觸發IRQ的HPD引腳的掩碼。
u32 long_mask可能是長HPD脈衝的HPD引腳的掩碼。
描述
這是所有平臺上的主要熱插拔IRQ處理程式。平臺特定的IRQ處理程式會呼叫平臺特定的熱插拔IRQ處理程式,這些處理程式會將相應的暫存器讀取並解碼為有關已觸發的HPD引腳的位掩碼 (pin_mask),以及其中哪些引腳可能是長脈衝 (long_mask)。如果與引腳對應的埠不是數字埠,則忽略 long_mask。
在這裡,我們進行熱插拔IRQ風暴檢測和緩解,並將進一步處理傳遞到相應的下半部。
-
void intel_hpd_init(struct intel_display *display)¶
初始化並啟用HPD支援。
引數
struct intel_display *display顯示裝置例項
描述
此函式啟用熱插拔支援。它要求中斷已透過 intel_irq_init_hw() 啟用。從那時起,熱插拔和輪詢請求可以與其他程式碼同時執行,因此必須遵守鎖定規則。
這是與中斷啟用分開的一步,以簡化驅動程式載入和恢復程式碼中的鎖定規則。
-
void intel_hpd_poll_enable(struct intel_display *display)¶
為帶有HPD的聯結器啟用輪詢。
引數
struct intel_display *display顯示裝置例項
描述
此函式為所有支援 HPD 的聯結器啟用輪詢。在某些情況下,HPD 可能無法正常工作。在大多數 Intel GPU 上,當我們進入執行時掛起時,會發生這種情況。在 Valleyview 和 Cherryview 系統上,當我們關閉所有電源域時,也會發生這種情況。
由於此函式可以在我們已經持有 dev->mode_config.mutex 的上下文中呼叫,因此我們在單獨的 worker 中進行實際的熱插拔啟用。
-
void intel_hpd_poll_disable(struct intel_display *display)¶
停用帶有HPD的聯結器的輪詢。
引數
struct intel_display *display顯示裝置例項
描述
此函式為所有支援 HPD 的聯結器停用輪詢。在某些情況下,HPD 可能無法正常工作。在大多數 Intel GPU 上,當我們進入執行時掛起時,會發生這種情況。在 Valleyview 和 Cherryview 系統上,當我們關閉所有電源域時,也會發生這種情況。
由於此函式可以在我們已經持有 dev->mode_config.mutex 的上下文中呼叫,因此我們在單獨的 worker 中進行實際的熱插拔啟用。
也在驅動程式初始化期間使用,以根據所有聯結器適當初始化 connector->polled。
-
void intel_hpd_block(struct intel_encoder *encoder)¶
阻止HPD引腳上的HPD IRQ處理。
引數
struct intel_encoder *encoder要阻止其HPD處理的編碼器。
描述
阻止 encoder 的 HPD 引腳上的 HPD IRQ 處理。
返回時
保證被阻止的編碼器的 HPD 脈衝處理程式(透過 intel_digital_port::hpd_pulse())未執行。
呼叫此函式時掛起的 HPD IRQ 的熱插拔事件處理(透過 intel_encoder::hotplug())可能仍在執行。
仍然允許在編碼器的聯結器上進行檢測(透過 drm_connector_helper_funcs::detect_ctx(), drm_connector_funcs::detect()),例如作為使用者空間聯結器探測或 DRM 核心聯結器輪詢的一部分。
該呼叫後必須呼叫 intel_hpd_unblock() 或 intel_hpd_clear_and_unblock()。
請注意,還將阻止使用與 encoder 相同 HPD 引腳的另一個編碼器的 HPD IRQ 處理。
-
void intel_hpd_unblock(struct intel_encoder *encoder)¶
取消阻止 HPD 引腳上的 HPD IRQ 處理。
引數
struct intel_encoder *encoder要取消阻止其 HPD 處理的編碼器。
描述
取消阻止 encoder 的 HPD 引腳上的 HPD IRQ 處理,該處理以前被 intel_hpd_block() 阻止。在 HPD 引腳被阻止時,在該 HPD 引腳上引發的任何 HPD IRQ 都將為 encoder 和任何其他共享相同 HPD 引腳的編碼器處理。
-
void intel_hpd_clear_and_unblock(struct intel_encoder *encoder)¶
取消阻止 HPD 引腳上的新 HPD IRQ 處理。
引數
struct intel_encoder *encoder要取消阻止其 HPD 處理的編碼器。
描述
取消阻止 encoder 的 HPD 引腳上的 HPD IRQ 處理,該處理以前被 intel_hpd_block() 阻止。在 HPD 引腳被阻止時,在該 HPD 引腳上引發的任何 HPD IRQ 都將被清除,僅處理新的 IRQ。
高畫質晰度音訊¶
圖形和音訊驅動程式共同支援透過 HDMI 和 DisplayPort 的高畫質晰度音訊。音訊程式設計序列分為音訊編解碼器和控制器啟用和停用序列。圖形驅動程式處理音訊編解碼器序列,而音訊驅動程式處理音訊控制器序列。
必須在停用轉碼器或埠之前執行停用序列。啟用序列只能在啟用轉碼器和埠之後以及完成鏈路訓練之後執行。因此,音訊啟用/停用序列是模式設定序列的一部分。
編解碼器和控制器序列可以並行或序列完成,但通常編解碼器序列中的 ELDV/PD 更改會指示音訊驅動程式應啟動控制器序列。實際上,圖形和音訊驅動程式之間的大部分協作都是透過音訊相關暫存器處理的。(一個值得注意的例外是電源管理,這裡不涉及。)
結構 i915_audio_component 用於在圖形和音訊驅動程式之間進行互動。結構 i915_audio_component_ops 中的 ops 在圖形驅動程式中定義,並在音訊驅動程式中呼叫。結構 i915_audio_component_audio_ops audio_ops 從 i915 驅動程式呼叫。
-
void intel_audio_codec_enable(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state, const struct drm_connector_state *conn_state)¶
為HD音訊啟用音訊編解碼器。
引數
struct intel_encoder *encoder在其上啟用音訊的編碼器。
const struct intel_crtc_state *crtc_state指向當前crtc狀態的指標。
const struct drm_connector_state *conn_state指向當前聯結器狀態的指標。
描述
啟用序列只能在啟用轉碼器和埠之後以及完成鏈路訓練之後執行。
-
void intel_audio_codec_disable(struct intel_encoder *encoder, const struct intel_crtc_state *old_crtc_state, const struct drm_connector_state *old_conn_state)¶
為HD音訊停用音訊編解碼器。
引數
struct intel_encoder *encoder在其上停用音訊的編碼器。
const struct intel_crtc_state *old_crtc_state指向舊的crtc狀態的指標。
const struct drm_connector_state *old_conn_state指向舊的聯結器狀態的指標。
描述
必須在停用轉碼器或埠之前執行停用序列。
-
void intel_audio_hooks_init(struct intel_display *display)¶
設定晶片特定的音訊鉤子。
引數
struct intel_display *display顯示裝置
-
void intel_audio_component_init(struct intel_display *display)¶
初始化並註冊音訊元件。
引數
struct intel_display *display顯示裝置
描述
這將在元件框架中註冊一個子元件,當後者註冊時,該子元件將動態繫結到 snd_hda_intel 驅動程式的相應主元件。在繫結期間,子元件初始化它從主元件接收的 struct i915_audio_component 的例項。然後,主元件可以開始使用此結構定義的介面。每一方都可以在任何時候透過登出自己的元件來斷開繫結,之後將呼叫每一方的元件取消繫結回撥。
我們忽略註冊期間的任何錯誤,並繼續使用減少的功能(即沒有HDMI音訊)。
-
void intel_audio_component_cleanup(struct intel_display *display)¶
登出音訊元件。
引數
struct intel_display *display顯示裝置
描述
登出音訊元件,斷開與相應的 snd_hda_intel 驅動程式的主元件的任何現有繫結。
-
void intel_audio_init(struct intel_display *display)¶
使用元件框架或使用lpe音訊橋初始化音訊驅動程式。
引數
struct intel_display *display顯示裝置
-
void intel_audio_deinit(struct intel_display *display)¶
取消初始化音訊驅動程式。
引數
struct intel_display *display顯示裝置
-
struct i915_audio_component¶
用於 i915 和 hda 驅動程式之間的直接通訊。
定義:
struct i915_audio_component {
struct drm_audio_component base;
int aud_sample_rate[MAX_PORTS];
};
成員
basedrm_audio_component 基類
aud_sample_rate每個埠的音訊取樣率陣列
Intel HDMI LPE 音訊支援¶
動機:Atom 平臺(例如 valleyview 和 cherryTrail)集成了一個基於 DMA 的介面,作為傳統 HDaudio 路徑的替代方案。雖然此模式與 LPE 又名 SST 音訊引擎無關,但文件將此模式稱為 LPE,因此為了保持一致性,我們保留此表示法。
該介面由 ALSA 子系統中維護的一個單獨的獨立驅動程式處理,以簡化操作。為了最大限度地減少兩個子系統之間的互動,在 hdmi-lpe-audio 和 i915 之間建立了一個橋樑:1. 建立一個平臺裝置以共享 MMIO/IRQ 資源 2. 使平臺裝置成為 i915 裝置的子裝置,用於執行時 PM。3. 建立 IRQ 晶片以轉發 LPE 音訊 irq。hdmi-lpe-audio 驅動程式探測 lpe 音訊裝置並建立一個新的音效卡。
威脅:由於 Linux 平臺裝置模型中的限制,使用者需要在解除安裝 i915 模組之前手動解除安裝 hdmi-lpe-audio 驅動程式,否則在 i915 移除平臺裝置後,我們可能會遇到使用後釋放問題:即使 hdmi-lpe-audio 驅動程式已釋出,該模組仍處於“已安裝”狀態。
實現:MMIO/REG 平臺資源是根據暫存器規範建立的。當轉發 LPE 音訊 irq 時,流控制處理程式選擇取決於平臺,例如,在 valleyview 上,handle_simple_irq 就足夠了。
-
void intel_lpe_audio_irq_handler(struct intel_display *display)¶
轉發 LPE 音訊 irq。
引數
struct intel_display *display顯示裝置
描述
LPE 音訊 irq 被轉發到 LPE 音訊驅動程式註冊的 irq 處理程式。
-
int intel_lpe_audio_init(struct intel_display *display)¶
檢測並設定 HDMI LPE 音訊驅動程式和 i915 之間的橋樑。
引數
struct intel_display *display顯示裝置
返回
成功時為0。如果檢測或 llocation/初始化失敗,則為非零。
-
void intel_lpe_audio_teardown(struct intel_display *display)¶
銷燬 HDMI LPE 音訊驅動程式和 i915 之間的橋樑。
引數
struct intel_display *display顯示裝置
描述
釋放 LPE 音訊 <-> i915 橋樑的所有資源。
-
void intel_lpe_audio_notify(struct intel_display *display, enum transcoder cpu_transcoder, enum port port, const void *eld, int ls_clock, bool dp_output)¶
通知 lpe 音訊事件音訊驅動程式和 i915。
引數
struct intel_display *display顯示裝置
enum transcoder cpu_transcoderCPU 轉碼器
enum port port埠
const void *eldELD 資料
int ls_clock以 kHz 為單位的鏈路符號時鐘
bool dp_output驅動 DP 輸出?
描述
通知 lpe 音訊驅動程式 eld 更改。
面板自重新整理 PSR (PSR/SRD)¶
由於 Haswell 顯示控制器支援在顯示面板上進行面板自重新整理 (Panel Self-Refresh, PSR),這些面板根據 eDP1.3 中的 PSR 規範實現了遠端幀緩衝區 (Remote Frame Buffer, RFB)。PSR 功能允許系統空閒但顯示器開啟時,顯示器進入較低的待機狀態,因為它完全消除了對 DDR 記憶體的顯示重新整理請求,只要該顯示器的幀緩衝區保持不變。
面板自重新整理必須得到硬體(源)和麵板(宿)的支援。
PSR 透過將幀緩衝區快取在面板 RFB 中來節省功耗,這允許我們關閉鏈路和記憶體控制器的電源。對於 DSI 面板,相同的概念被稱為“手動模式”。
該實現使用基於硬體的 PSR 支援,該支援自動進入/退出自重新整理模式。硬體負責傳送所需的 DP aux 訊息,甚至可以重新訓練鏈路(但該部分尚未啟用)。硬體還會跟蹤任何前緩衝區更改,以便知道何時再次退出自重新整理模式。不幸的是,這部分工作效果不佳,因此 i915 PSR 支援使用軟體前緩衝區跟蹤來確保它不會錯過螢幕更新。對於此整合,intel_psr_invalidate() 和 intel_psr_flush() 由前緩衝區跟蹤程式碼呼叫。請注意,由於鎖定問題,自重新整理重新啟用程式碼是從一個工作佇列完成的,在關閉管道時必須正確同步/取消該佇列。”
DC3CO (DC3 時鐘關閉)
在 PSR2 的基礎上,GEN12 增加了一箇中間省電狀態,該狀態在 PSR2 空閒狀態期間自動關閉時鐘。DC3co 進入/退出開銷與 PSR2 深度睡眠進入/退出開銷相比更小,這使得 HW 即使在定期翻頁時(例如 30fps 影片播放場景)也能進入低功耗狀態。
每次發生翻頁時,PSR2 都會退出深度睡眠狀態(如果它處於深度睡眠狀態),因此啟用 DC3CO,並且計劃在 6 幀後執行 tgl_dc3co_disable_work。如果沒有其他翻頁發生並且執行了上面的函式,則停用 DC3CO,並將 PSR2 配置為進入深度睡眠,在發生另一個翻頁時再次重置。故意不觸發前緩衝區修改的 DC3CO 啟用,因為它會帶來很多複雜性,並且大多數現代系統只會使用頁面翻轉。
-
void intel_psr_disable(struct intel_dp *intel_dp, const struct intel_crtc_state *old_crtc_state)¶
停用 PSR
引數
struct intel_dp *intel_dpIntel DP
const struct intel_crtc_state *old_crtc_state舊的 CRTC 狀態
描述
需要在停用管道之前呼叫此函式。
引數
struct intel_dp *intel_dpIntel DP
描述
需要在啟用 psr 後呼叫此函式。
引數
struct intel_dp *intel_dpIntel DP
描述
需要在暫停 psr 後呼叫此函式。
-
bool intel_psr_needs_vblank_notification(const struct intel_crtc_state *crtc_state)¶
檢查 PSR 是否需要垂直消隱啟用/停用通知。
引數
const struct intel_crtc_state *crtc_stateCRTC 狀態
描述
我們需要阻止面板重放中的 DC6 進入,因為在面板重放中啟用 VBI 並不能阻止它。面板重放在 DC 進入時關閉主鏈路。這意味著不會觸發垂直消隱中斷,如果使用者空間正在輪詢垂直消隱事件,則會出現問題。此外,Wa_16025596647 需要有關何時啟用/停用垂直消隱的資訊。
-
void intel_psr_trigger_frame_change_event(struct intel_dsb *dsb, struct intel_atomic_state *state, struct intel_crtc *crtc)¶
觸發“幀更改”事件
引數
struct intel_dsb *dsbDSB 上下文
struct intel_atomic_state *state原子狀態
struct intel_crtc *crtcCRTC
描述
生成 PSR“幀更改”事件。
-
int intel_psr_min_vblank_delay(const struct intel_crtc_state *crtc_state)¶
PSR 所需的最小垂直消隱延遲
引數
const struct intel_crtc_state *crtc_statecrtc 狀態
描述
返回 PSR 所需的最小垂直消隱延遲。
-
void intel_psr_wait_for_idle_locked(const struct intel_crtc_state *new_crtc_state)¶
等待 PSR 準備好進行管道更新
引數
const struct intel_crtc_state *new_crtc_state新的 CRTC 狀態
描述
期望從 pipe_update_start() 呼叫此函式,在此函式中,它預計不會與 PSR 啟用或停用競爭。
-
void intel_psr_invalidate(struct intel_display *display, unsigned frontbuffer_bits, enum fb_op_origin origin)¶
使 PSR 無效
引數
struct intel_display *display顯示裝置
unsigned frontbuffer_bits前緩衝平面跟蹤位
enum fb_op_origin origin哪個操作導致了無效
描述
由於硬體前緩衝區跟蹤存在差距,我們需要與軟體前緩衝區跟蹤整合。每次前緩衝區渲染開始並且緩衝區變髒時都會呼叫此函式。如果前緩衝區掩碼包含與 PSR 相關的緩衝區,則必須停用 PSR。
與 PSR 相關的髒前緩衝區在 busy_frontbuffer_bits 中跟蹤。”
-
void intel_psr_flush(struct intel_display *display, unsigned frontbuffer_bits, enum fb_op_origin origin)¶
重新整理 PSR
引數
struct intel_display *display顯示裝置
unsigned frontbuffer_bits前緩衝平面跟蹤位
enum fb_op_origin origin哪個操作導致了重新整理
描述
由於硬體前緩衝區跟蹤存在差距,我們需要與軟體前緩衝區跟蹤整合。每次前緩衝區渲染完成並重新整理到記憶體時都會呼叫此函式。如果沒有其他與 PSR 相關的前緩衝區是髒的,則可以再次啟用 PSR。
與 PSR 相關的髒前緩衝區在 busy_frontbuffer_bits 中跟蹤。
引數
struct intel_dp *intel_dpIntel DP
描述
此函式在初始化聯結器後呼叫。(聯結器的初始化處理聯結器功能的處理)並且它為每個 DP 編碼器初始化基本的 PSR 內容。
引數
struct intel_dp *intel_dpstruct intel_dp
描述
我們看到了一些面板的意外鏈路重新訓練。這是由於面板在啟用 PSR 後聲明瞭錯誤的鏈路狀態造成的。檢查鏈路狀態的程式碼可以呼叫此函式以確保它可以忽略面板宣告的錯誤鏈路狀態。即,如果面板聲明瞭錯誤的鏈路,並且 intel_psr_link_ok 宣告鏈路正常,則呼叫者應依賴後者。
link_ok 的返回值
-
void intel_psr_lock(const struct intel_crtc_state *crtc_state)¶
獲取 PSR 鎖
引數
const struct intel_crtc_state *crtc_statecrtc 狀態
描述
這最初意味著在 CRTC 更新前後使用,當更新垂直消隱敏感暫存器時,我們需要先獲取鎖以避免垂直消隱逃避。
-
void intel_psr_unlock(const struct intel_crtc_state *crtc_state)¶
釋放 PSR 鎖
引數
const struct intel_crtc_state *crtc_statecrtc 狀態
描述
釋放管道更新期間持有的 PSR 鎖。
-
void intel_psr_notify_dc5_dc6(struct intel_display *display)¶
通知 PSR 有關啟用/停用 dc5/dc6
引數
struct intel_display *displayintel 原子狀態
描述
這是針對空閒 PSR HW 錯誤(Wa_16025596647)上的欠載執行,以計劃用於應用/刪除該變通方法的 psr_dc5_dc6_wa_work。
-
void intel_psr_dc5_dc6_wa_init(struct intel_display *display)¶
初始化空閒 PSR HW 錯誤 wa 上的欠載執行的工作
引數
struct intel_display *displayintel 原子狀態
描述
這是針對空閒 PSR HW 錯誤(Wa_16025596647)上的欠載執行,以初始化用於應用變通方法的 psr_dc5_dc6_wa_work。
-
void intel_psr_notify_pipe_change(struct intel_atomic_state *state, struct intel_crtc *crtc, bool enable)¶
通知 PSR 有關啟用/停用管道的資訊
引數
struct intel_atomic_state *stateintel 原子狀態
struct intel_crtc *crtcintel crtc
bool enable啟用/停用
描述
這是針對空閒 PSR HW 錯誤(Wa_16025596647)上的欠載執行,以在啟用/停用管道時應用刪除變通方法。
-
void intel_psr_notify_vblank_enable_disable(struct intel_display *display, bool enable)¶
通知 PSR 有關啟用/停用垂直消隱的資訊
引數
struct intel_display *displayintel 顯示結構
bool enable啟用/停用
描述
這是針對空閒 PSR HW 錯誤(Wa_16025596647)上的欠載執行,以在啟用/停用垂直消隱時應用刪除變通方法。
幀緩衝區壓縮 (FBC)¶
FBC 嘗試透過壓縮顯示器使用的記憶體量來節省記憶體頻寬(從而節省功耗)。它對使用者空間完全透明,並且完全在核心中處理。
FBC 的好處在純色背景和無變化的圖案中最為明顯。它來自保持記憶體佔用空間小,並減少為重新整理顯示器而開啟和訪問的記憶體頁面數量。
i915 負責為 FBC 保留被盜記憶體,並在正確的暫存器上配置其偏移量。硬體負責所有壓縮/解壓縮。但是,在許多已知情況下,我們必須強制停用它才能允許正確的螢幕更新。
-
void intel_fbc_disable(struct intel_crtc *crtc)¶
如果 FBC 與 crtc 關聯,則停用 FBC
引數
struct intel_crtc *crtcCRTC
描述
如果 FBC 與提供的 CRTC 關聯,則此函式停用 FBC。
-
void intel_fbc_handle_fifo_underrun_irq(struct intel_display *display)¶
當我們得到 FIFO 欠載執行時,停用 FBC
引數
struct intel_display *display顯示
描述
如果沒有 FBC,大多數欠載執行都是無害的,並且不會真正導致太多問題,除了 dmesg 上一條煩人的訊息。對於 FBC,欠載執行可能會變成黑屏,甚至更糟,尤其是在與不良水印配對時。因此,為了安全起見,如果我們檢測到任何管道上的 FIFO 欠載執行,則完全停用 FBC。任何管道上的欠載執行已經表明水印可能很差,因此請儘量安全。
此函式從 IRQ 處理程式呼叫。
-
void intel_fbc_init(struct intel_display *display)¶
初始化 FBC
引數
struct intel_display *display顯示
描述
此函式可能會在 PM 初始化過程中呼叫。
-
void intel_fbc_sanitize(struct intel_display *display)¶
清理 FBC
引數
struct intel_display *display顯示
描述
確保最初停用 FBC,因為我們不知道例如它可能會塗寫到被盜的哪些部分中。
顯示重新整理率切換 (DRRS)¶
顯示重新整理率切換 (DRRS) 是一種節能功能,它能夠基於使用場景動態地在低重新整理率和高重新整理率之間切換。此功能適用於內部面板。
面板是否支援 DRRS 由面板 EDID 指示,它將列出一種解析度的多個重新整理率。
DRRS 有兩種型別 - 靜態和無縫。靜態 DRRS 涉及透過執行完整模式設定(可能在螢幕上顯示為閃爍)來更改重新整理率 (RR),並且用於底座斷開連線的情況。無縫 DRRS 涉及更改 RR 而不會對使用者產生任何視覺效果,並且可以在正常系統使用期間使用。這是透過程式設計某些暫存器來完成的。
可以基於面板規格中的輸入在 VBT 中指示對靜態/無縫 DRRS 的支援。
DRRS 透過根據使用場景切換到低 RR 來節省功耗。
該實現基於前緩衝區跟蹤實現。當用戶活動或定期系統活動觸發螢幕上的干擾時,停用 DRRS(RR 更改為高 RR)。當螢幕上沒有移動時,在 1 秒超時後,會切換到低 RR。
為了與前緩衝區跟蹤程式碼整合,呼叫了 intel_drrs_invalidate() 和 intel_drrs_flush()。
DRRS 可以進一步擴充套件以支援其他內部面板以及影片播放的場景,其中 RR 基於使用者空間請求的速率設定。
-
void intel_drrs_activate(const struct intel_crtc_state *crtc_state)¶
啟用 DRRS
引數
const struct intel_crtc_state *crtc_statecrtc 狀態
描述
在 crtc 上啟用 DRRS。
-
void intel_drrs_deactivate(const struct intel_crtc_state *old_crtc_state)¶
停用 DRRS
引數
const struct intel_crtc_state *old_crtc_state之前的 CRTC 狀態
描述
停用 CRTC 上的 DRRS。
-
void intel_drrs_invalidate(struct intel_display *display, unsigned int frontbuffer_bits)¶
停用空閒 DRRS
引數
struct intel_display *display顯示裝置
unsigned int frontbuffer_bits前緩衝平面跟蹤位
描述
每次在給定平面上開始渲染時,都會呼叫此函式。 因此,需要將 DRRS 升級,即(LOW_RR -> HIGH_RR)。
與 DRRS 相關的髒前置緩衝區在 busy_frontbuffer_bits 中被追蹤。
-
void intel_drrs_flush(struct intel_display *display, unsigned int frontbuffer_bits)¶
重啟空閒 DRRS
引數
struct intel_display *display顯示裝置
unsigned int frontbuffer_bits前緩衝平面跟蹤位
描述
每次在給定的平面上完成渲染或完成 CRTC 上的翻轉時,都會呼叫此函式。 因此,DRRS 應升級(LOW_RR -> HIGH_RR)。 此外,如果沒有其他平面是髒的,則應再次開始空閒檢測。
與 DRRS 相關的髒前置緩衝區在 busy_frontbuffer_bits 中被追蹤。
-
void intel_drrs_crtc_init(struct intel_crtc *crtc)¶
初始化 CRTC 的 DRRS
引數
struct intel_crtc *crtccrtc
描述
此函式僅在驅動程式載入時呼叫一次,以初始化基本的 DRRS 內容。
DPIO¶
VLV、CHV 和 BXT 具有略微特殊的顯示 PHY,用於驅動 DP/HDMI 埠。 DPIO 是賦予此類顯示 PHY 的名稱。 這些 PHY 不遵循使用直接 MMIO 暫存器的標準程式設計模型,而是必須透過 IOSF 側帶訪問其暫存器。 VLV 有一個這樣的 PHY 用於驅動埠 B 和 C,CHV 增加了另一個 PHY 用於驅動埠 D。 每個 PHY 響應特定的 IOSF-SB 埠。
每個顯示 PHY 由一個或兩個通道組成。 每個通道包含一個公共通道部分,該部分包含 PLL 和其他公共邏輯。 CH0 公共通道還包含用於公共暫存器介面 (CRI) 的 IOSF-SB 邏輯,即 DPIO 暫存器。 訪問任何 DPIO 暫存器時,CRI 時鐘必須執行。
除了擁有自己的暫存器外,PHY 還透過來自顯示控制器的一些專用訊號來控制。 這些包括 PLL 參考時鐘使能、PLL 使能和 CRI 時鐘選擇等。
每個通道還有兩個樣條線(也稱為資料通道),每個樣條線由一個物理訪問編碼子層 (PCS) 塊和兩個 TX 通道組成。 因此,每個通道有兩個 PCS 塊和四個 TX 通道。 TX 通道用作 DP 通道或 TMDS 資料/時鐘對,具體取決於輸出型別。
此外,PHY 還包含一個 AUX 通道,每個通道都有 AUX 塊。 這用於 DP AUX 通訊,但這個事實對於驅動程式來說並不重要,因為 AUX 是從顯示控制器側控制的。 在 AUX 通訊期間不需要訪問任何 DPIO 暫存器。
通常,在 VLV/CHV 上,公共通道對應於管線,樣條線 (PCS/TX) 對應於埠。
對於雙通道 PHY (VLV/CHV)
管線 A == CMN/PLL/REF CH0
管線 B == CMN/PLL/REF CH1
埠 B == PCS/TX CH0
埠 C == PCS/TX CH1
當我們交叉流時,即使用管線 B 驅動埠 B,或使用管線 A 驅動埠 C 時,這一點尤其重要。
對於單通道 PHY (CHV)
管線 C == CMN/PLL/REF CH0
埠 D == PCS/TX CH0
在 BXT 上,整個 PHY 通道對應於埠。 這意味著 PLL 現在也與埠相關聯,而不是與管線相關聯,因此需要將時鐘路由到適當的轉碼器。 埠 A PLL 直接連線到轉碼器 EDP,埠 B/C PLL 可以路由到任何轉碼器 A/B/C。
注意:DDI0 是數字埠 B,DD1 是數字埠 C,DDI2 是數字埠 D (CHV) 或埠 A (BXT)。
Dual channel PHY (VLV/CHV/BXT)
---------------------------------
| CH0 | CH1 |
| CMN/PLL/REF | CMN/PLL/REF |
|---------------|---------------| Display PHY
| PCS01 | PCS23 | PCS01 | PCS23 |
|-------|-------|-------|-------|
|TX0|TX1|TX2|TX3|TX0|TX1|TX2|TX3|
---------------------------------
| DDI0 | DDI1 | DP/HDMI ports
---------------------------------
Single channel PHY (CHV/BXT)
-----------------
| CH0 |
| CMN/PLL/REF |
|---------------| Display PHY
| PCS01 | PCS23 |
|-------|-------|
|TX0|TX1|TX2|TX3|
-----------------
| DDI2 | DP/HDMI port
-----------------
DMC 韌體支援¶
從 gen9 開始,我們在顯示引擎中新添加了 DMC(顯示微控制器),以便在顯示引擎進入低功耗狀態並返回正常狀態時儲存和恢復顯示引擎的狀態。
引數
struct intel_display *display顯示例項
enum pipe pipe用於阻止的管線暫存器
bool block阻止/解除阻止
描述
此介面的目標是 Wa_16025596647 用法。 即,在 PIPEDMC_BLOCK_PKGC_SW 暫存器中設定/清除 PIPEDMC_BLOCK_PKGC_SW_BLOCK_PKGC_ALWAYS 位。
-
void intel_dmc_start_pkgc_exit_at_start_of_undelayed_vblank(struct intel_display *display, enum pipe pipe, bool enable)¶
PKG C 狀態退出開始
引數
struct intel_display *display顯示例項
enum pipe pipe用於阻止的管線暫存器
bool enable啟用/停用
描述
此介面的目標是 Wa_16025596647 用法。 即,在未延遲的 vblank 開始時啟動軟體包 C 退出
-
void intel_dmc_load_program(struct intel_display *display)¶
將韌體從記憶體寫入暫存器。
引數
struct intel_display *display顯示例項
描述
DMC 韌體從 .bin 檔案讀取並一次性儲存在內部儲存器中。 每次顯示從低功耗狀態返回時,都會呼叫此函式將韌體從內部儲存器複製到暫存器。
-
void intel_dmc_disable_program(struct intel_display *display)¶
停用韌體
引數
struct intel_display *display顯示例項
描述
停用韌體中的所有事件處理程式,確保在顯示未初始化後韌體處於非活動狀態。
-
void intel_dmc_init(struct intel_display *display)¶
初始化韌體載入。
引數
struct intel_display *display顯示例項
描述
此函式在載入顯示驅動程式時呼叫,以從 .bin 檔案讀取韌體並複製到內部儲存器中。
-
void intel_dmc_suspend(struct intel_display *display)¶
在系統掛起之前準備 DMC 韌體
引數
struct intel_display *display顯示例項
描述
在進入系統掛起之前準備 DMC 韌體。 這包括重新整理掛起的工項並釋放在初始化期間獲取的任何資源。
-
void intel_dmc_resume(struct intel_display *display)¶
在系統恢復期間初始化 DMC 韌體
-
void intel_dmc_fini(struct intel_display *display)¶
解除安裝 DMC 韌體。
引數
struct intel_display *display顯示例項
描述
韌體解除安裝包括釋放內部儲存器和重置韌體載入狀態。
DMC 喚醒鎖支援¶
喚醒鎖是一種使顯示引擎退出 DC 狀態的機制,以便對這些狀態下斷電的暫存器進行程式設計。 之前的專案在檢測到程式設計時會自動退出 DC 狀態。 現在,軟體透過程式設計喚醒鎖來控制退出。 這提高了系統性能和系統互動,並且更適合於翻轉佇列的程式設計風格。 僅當在 DC_STATE_EN 中啟用了 DC5、DC6 或 DC6v 並且啟用了喚醒鎖操作模式時,才需要喚醒鎖。
DMC 中的喚醒鎖機制允許顯示引擎在對可能斷電的暫存器進行程式設計之前顯式退出 DC 狀態。 在較早的硬體中,當顯示引擎訪問暫存器時,這是自動且隱式地完成的。 透過喚醒鎖實現,驅動程式斷言 DMC 中的喚醒鎖,這會強制它退出 DC 狀態,直到解除喚醒鎖。
可以透過寫入 DMC_WAKELOCK_CFG 暫存器來啟用和停用該機制。 還有 13 個控制暫存器可用於保持和釋放不同的喚醒鎖。 在當前實現中,我們只需要一個喚醒鎖,因此僅使用 DMC_WAKELOCK1_CTL。 此處的其他定義供將來潛在使用。
影片 BIOS 表 (VBT)¶
影片 BIOS 表(簡稱 VBT)向驅動程式提供平臺和板卡特定的配置資訊,這些資訊無法透過其他方式發現或獲取。 該配置主要與顯示硬體相關。 VBT 可透過 ACPI OpRegion 獲得,或者在較舊的系統上,可在 PCI ROM 中獲得。
VBT 由 VBT 標頭(定義為 struct vbt_header)、BDB 標頭 (struct bdb_header) 和許多包含實際配置資訊的 BIOS 資料塊 (BDB) 組成。 VBT 標頭(以及 VBT)以“$VBT”簽名開頭。 VBT 標頭包含 BDB 標頭的偏移量。 資料塊在 BDB 標頭之後連線。 資料塊具有 1 位元組的塊 ID、2 位元組的塊大小和塊大小的位元組資料。(塊 53,MIPI 序列塊是一個例外。)
驅動程式在載入期間解析 VBT。 相關資訊儲存在驅動程式私有資料中以便於使用,之後不再讀取實際的 VBT。
-
bool intel_bios_is_valid_vbt(struct intel_display *display, const void *buf, size_t size)¶
給定的緩衝區是否包含有效的 VBT
引數
struct intel_display *display顯示裝置
const void *buf指向要驗證的緩衝區的指標
size_t size緩衝區的大小
描述
如果 VBT 有效,則返回 true。
-
void intel_bios_init(struct intel_display *display)¶
查詢 VBT 並從 BIOS 初始化設定
引數
struct intel_display *display顯示裝置例項
描述
從影片 BIOS 表 (VBT) 解析和初始化設定。 如果未在 ACPI OpRegion 中找到 VBT,請首先嚐試在 PCI ROM 中找到它。 另外,如果根本不存在 VBT,則初始化一些預設值。
-
void intel_bios_driver_remove(struct intel_display *display)¶
釋放
intel_bios_init()分配的任何資源
引數
struct intel_display *display顯示裝置例項
-
bool intel_bios_is_tv_present(struct intel_display *display)¶
VBT 中是否存在整合電視
引數
struct intel_display *display顯示裝置例項
描述
如果存在電視,則返回 true。 如果沒有從 VBT 解析任何子裝置,則假定存在電視。
-
bool intel_bios_is_lvds_present(struct intel_display *display, u8 *i2c_pin)¶
VBT 中是否存在 LVDS
引數
struct intel_display *display顯示裝置例項
u8 *i2c_pin如果存在 LVDS,則為 LVDS 的 i2c 引腳
描述
如果存在 LVDS,則返回 true。 如果沒有從 VBT 解析任何子裝置,則假定存在 LVDS。
引數
struct intel_display *display顯示裝置例項
enum port port要檢查的埠
描述
如果 port 中的裝置存在,則返回 true。
引數
struct intel_display *display顯示裝置例項
enum port *port如果存在 DSI,則為 DSI 的埠
描述
如果存在 DSI,則返回 true,並在 port 中返回埠。
-
struct vbt_header¶
VBT 標頭結構
定義:
struct vbt_header {
u8 signature[20];
u16 version;
u16 header_size;
u16 vbt_size;
u8 vbt_checksum;
u8 reserved0;
u32 bdb_offset;
u32 aim_offset[4];
};
成員
簽名VBT 簽名,始終以“$VBT”開頭
版本此結構的版本
header_size此結構的大小
vbt_sizeVBT 的大小(VBT 標頭、BDB 標頭和資料塊)
vbt_checksum校驗和
reserved0已保留
bdb_offsetstruct bdb_header從 VBT 開頭的偏移量aim_offset從 VBT 開頭新增的資料塊的偏移量
-
struct bdb_header¶
BDB 標頭結構
定義:
struct bdb_header {
u8 signature[16];
u16 version;
u16 header_size;
u16 bdb_size;
};
成員
簽名BDB 簽名“BIOS_DATA_BLOCK”
版本資料塊定義的版本
header_size此結構的大小
bdb_sizeBDB 的大小(BDB 標頭和資料塊)
顯示時鐘¶
顯示引擎使用幾個不同的時鐘來完成其工作。 涉及兩個主要時鐘,它們與實際畫素時鐘或實際輸出埠的任何符號/位時鐘沒有直接關係。 這些是核心顯示時鐘 (CDCLK) 和 RAWCLK。
CDCLK 為大多數顯示管線邏輯計時,因此其頻率必須足夠高,才能支援畫素流經管線的速率。 還必須考慮降頻,因為這會增加有效畫素速率。
在多個平臺上,可以動態更改 CDCLK 頻率,以最大程度地降低給定顯示配置的功耗。通常,更改 CDCLK 頻率需要關閉所有顯示通道,然後才能更改頻率。
在 SKL+ 上,DMC 將在 DC5/6 進入/退出期間切換 CDCLK 的開啟/關閉。但是,DMC 不會更改活動的 CDCLK 頻率,因此這部分仍將由驅動程式直接執行。
CDCLK 頻率的生成涉及多個元件
我們有 CDCLK PLL,它根據參考時鐘和比率引數生成輸出時鐘。
CD2X 分頻器,它根據從一組預定義選擇中選擇的分頻係數來劃分 PLL 的輸出。
CD2X 壓縮器,它根據表示為位序列的波形進一步劃分輸出,其中每個零“壓縮掉”一個時鐘週期。
最後,有一個固定分頻器將輸出頻率除以 2。
因此,可以使用以下公式計算產生的 CDCLK 頻率
cdclk = vco / cd2x_div / (sq_len / sq_div) / 2
,其中 vco 是 PLL 生成的頻率;cd2x_div 表示 CD2X 分頻器;sq_len 和 sq_div 分別是 CD2X 壓縮器波形的位長度和高位數;2 表示固定分頻器。
請注意,某些較舊的平臺不包含 CD2X 分頻器和/或 CD2X 壓縮器,在這種情況下,我們可以忽略上面公式中各自的因子。
存在多種更改 CDCLK 頻率的方法,支援哪些方法取決於平臺
完全停用 PLL + 使用新的 VCO 頻率重新啟用。管道必須處於非活動狀態。
CD2X 分頻器更新。單個管道可以處於活動狀態,因為分頻器更新可以與管道的垂直消隱開始同步。
將 PLL 平穩地爬升到新的 VCO 頻率。管道可以處於活動狀態。
壓縮波形更新。管道可以處於活動狀態。
爬升和壓縮也可以背靠背完成。管道可以處於活動狀態。
RAWCLK 是一個固定頻率時鐘,通常由各種輔助塊(例如 AUX CH 或背光 PWM)使用。因此,我們真正需要了解的關於 RAWCLK 的是它的頻率,以便可以正確地對各種分頻器進行程式設計。
-
void intel_cdclk_init_hw(struct intel_display *display)¶
初始化 CDCLK 硬體
引數
struct intel_display *display顯示例項
描述
初始化 CDCLK。這主要包括初始化 display->cdclk.hw 和清理硬體的狀態(如果需要)。這通常僅在顯示核心初始化序列期間完成,之後 DMC 將根據需要負責關閉/開啟 CDCLK。
-
void intel_cdclk_uninit_hw(struct intel_display *display)¶
取消初始化 CDCLK 硬體
引數
struct intel_display *display顯示例項
描述
取消初始化 CDCLK。這僅在顯示核心取消初始化序列期間完成。
-
bool intel_cdclk_clock_changed(const struct intel_cdclk_config *a, const struct intel_cdclk_config *b)¶
檢查時鐘是否已更改
引數
const struct intel_cdclk_config *a第一個 CDCLK 配置
const struct intel_cdclk_config *b第二個 CDCLK 配置
返回
如果 CDCLK 的更改方式需要重新程式設計,則為 True,否則為 False。
-
bool intel_cdclk_can_cd2x_update(struct intel_display *display, const struct intel_cdclk_config *a, const struct intel_cdclk_config *b)¶
確定在兩個 CDCLK 配置之間進行更改是否只需要 cd2x 分頻器更新
引數
struct intel_display *display顯示例項
const struct intel_cdclk_config *a第一個 CDCLK 配置
const struct intel_cdclk_config *b第二個 CDCLK 配置
返回
如果在兩個 CDCLK 配置之間進行更改只能透過 cd2x 分頻器更新來完成,則為 True,否則為 false。
-
bool intel_cdclk_changed(const struct intel_cdclk_config *a, const struct intel_cdclk_config *b)¶
確定兩個 CDCLK 配置是否不同
引數
const struct intel_cdclk_config *a第一個 CDCLK 配置
const struct intel_cdclk_config *b第二個 CDCLK 配置
返回
如果 CDCLK 配置不匹配,則為 True,如果匹配,則為 false。
-
void intel_set_cdclk_pre_plane_update(struct intel_atomic_state *state)¶
將 CDCLK 狀態推送到硬體
引數
struct intel_atomic_state *stateintel 原子狀態
描述
如果需要,在更新基於新 CDCLK 狀態的 HW 平面狀態之前,對硬體進行程式設計。
-
void intel_set_cdclk_post_plane_update(struct intel_atomic_state *state)¶
將 CDCLK 狀態推送到硬體
引數
struct intel_atomic_state *stateintel 原子狀態
描述
如果需要,在更新基於新 CDCLK 狀態的 HW 平面狀態之後,對硬體進行程式設計。
-
void intel_update_max_cdclk(struct intel_display *display)¶
確定最大支援 CDCLK 頻率
引數
struct intel_display *display顯示例項
描述
確定平臺支援的最大 CDCLK 頻率,並推匯出最大 CDCLK 頻率允許的最大點時鐘頻率。
-
void intel_update_cdclk(struct intel_display *display)¶
確定當前的 CDCLK 頻率
引數
struct intel_display *display顯示例項
描述
確定當前的 CDCLK 頻率。
-
u32 intel_read_rawclk(struct intel_display *display)¶
確定當前的 RAWCLK 頻率
引數
struct intel_display *display顯示例項
描述
確定當前的 RAWCLK 頻率。RAWCLK 是一個固定頻率時鐘,因此只需要執行一次。
-
void intel_init_cdclk_hooks(struct intel_display *display)¶
初始化 CDCLK 相關的模式設定掛鉤
引數
struct intel_display *display顯示例項
顯示 PLL¶
用於驅動輸出的顯示 PLL 因平臺而異。雖然有些平臺具有每個管道或每個編碼器專用的 PLL,但其他平臺允許使用來自池中的任何 PLL。在後一種情況下,如果它們的配置匹配,則多個管道可以共享一個 PLL。
此檔案提供了顯示 PLL 的抽象。函式 intel_shared_dpll_init() 初始化給定平臺的 PLL。跟蹤 PLL 的使用者,並且該跟蹤與原子 modset 介面整合。在原子操作期間,可以透過呼叫 intel_reserve_shared_dplls() 為給定的 CRTC 和編碼器配置保留所需的 PLL,並且可以使用 intel_release_shared_dplls() 釋放先前保留的 PLL。對使用者的更改首先在原子狀態中進行暫存,然後透過在原子提交階段呼叫 intel_shared_dpll_swap_state() 使其生效。
給定 ID,獲取 DPLL
引數
struct intel_display *displayintel_display 裝置例項
enum intel_dpll_id idpll id
返回
指向具有 id 的 DPLL 的指標
啟用 CRTC 的共享 DPLL
引數
const struct intel_crtc_state *crtc_stateCRTC 及其狀態,具有共享 DPLL
描述
啟用 crtc 使用的共享 DPLL。
停用 CRTC 的共享 DPLL
引數
const struct intel_crtc_state *crtc_stateCRTC 及其狀態,具有共享 DPLL
描述
停用 crtc 使用的共享 DPLL。
獲取 CRTC 的 DPLL 引用
引數
const struct intel_crtc *crtc獲取引用的 CRTC
const struct intel_shared_dpll *pll獲取引用的 DPLL
struct intel_shared_dpll_state *shared_dpll_state在其中跟蹤引用的 DPLL 原子狀態
描述
獲取 pll 的引用,跟蹤 crtc 對它的使用。
刪除 CRTC 的 DPLL 引用
引數
const struct intel_crtc *crtc刪除引用的 CRTC
const struct intel_shared_dpll *pll刪除引用的 DPLL
struct intel_shared_dpll_state *shared_dpll_state在其中跟蹤引用的 DPLL 原子狀態
描述
刪除 pll 的引用,跟蹤 crtc 對它的使用的結束。
使原子 DPLL 配置生效
引數
struct intel_atomic_state *state原子狀態
描述
這是 drm_atomic_helper_swap_state() 的 dpll 版本,因為該助手不處理特定於驅動程式的全域性狀態。
為了與原子助手保持一致,此函式會執行完整的交換,即,它還會將當前狀態放入 state 中,即使目前沒有必要這樣做。
-
void icl_set_active_port_dpll(struct intel_crtc_state *crtc_state, enum icl_port_dpll_id port_dpll_id)¶
為給定的 CRTC 選擇活動的埠 DPLL
引數
struct intel_crtc_state *crtc_state用於選擇 DPLL 的 CRTC 狀態
enum icl_port_dpll_id port_dpll_id要選擇的活動的 port_dpll_id
描述
從為 CRTC 保留的 DPLL 中選擇給定的 port_dpll_id 例項。
初始化共享 DPLL
引數
struct intel_display *displayintel_display 裝置
描述
為 display 初始化共享 DPLL。
計算 CRTC 和編碼器組合的 DPLL 狀態
引數
struct intel_atomic_state *state原子狀態
struct intel_crtc *crtc要計算 DPLL 的 CRTC
struct intel_encoder *encoder編碼器
描述
此函式計算給定 CRTC 和編碼器的 DPLL 狀態。
透過呼叫 intel_shared_dpll_swap_state() 使原子提交 state 中的新配置生效。
返回
成功時為 0,失敗時為負錯誤程式碼。
為 CRTC 和編碼器組合保留 DPLL
引數
struct intel_atomic_state *state原子狀態
struct intel_crtc *crtc要為其保留 DPLL 的 CRTC
struct intel_encoder *encoder編碼器
描述
此函式為當前原子提交狀態和新的 crtc 原子狀態中的給定 CRTC 和編碼器組合保留所有必需的 DPLL。
透過呼叫 intel_shared_dpll_swap_state() 使原子提交 state 中的新配置生效。
應透過呼叫 intel_release_shared_dplls() 釋放保留的 DPLL。
返回
如果所有必需的 DPLL 都已成功保留,則為 0;否則為負錯誤程式碼。
結束 CRTC 在原子狀態下對 DPLL 的使用
引數
struct intel_atomic_state *state原子狀態
struct intel_crtc *crtc要從中釋放 DPLL 的 crtc
描述
此函式從當前原子提交狀態和舊的 crtc 原子狀態釋放由 intel_reserve_shared_dplls() 保留的所有 DPLL。
透過呼叫 intel_shared_dpll_swap_state() 使原子提交 state 中的新配置生效。
-
void intel_update_active_dpll(struct intel_atomic_state *state, struct intel_crtc *crtc, struct intel_encoder *encoder)¶
更新 CRTC/編碼器的活動 DPLL
引數
struct intel_atomic_state *state原子狀態
struct intel_crtc *crtc要為其更新活動 DPLL 的 CRTC
struct intel_encoder *encoder確定埠 DPLL 型別的編碼器
描述
根據編碼器埠的當前模式,從先前由 intel_reserve_shared_dplls() 保留的埠 DPLL,更新 crtc 的原子狀態中給定的 crtc/encoder 的活動 DPLL。
-
int intel_dpll_get_freq(struct intel_display *display, const struct intel_shared_dpll *pll, const struct intel_dpll_hw_state *dpll_hw_state)¶
計算 DPLL 的輸出頻率
引數
struct intel_display *displayintel_display 裝置
const struct intel_shared_dpll *pll要為其計算輸出頻率的 DPLL
const struct intel_dpll_hw_state *dpll_hw_state從中計算輸出頻率的 DPLL 狀態
描述
返回與傳入的 dpll_hw_state 的 pll 對應的輸出頻率。
-
bool intel_dpll_get_hw_state(struct intel_display *display, struct intel_shared_dpll *pll, struct intel_dpll_hw_state *dpll_hw_state)¶
讀出 DPLL 的硬體狀態
引數
struct intel_display *displayintel_display 裝置例項
struct intel_shared_dpll *pll要為其計算輸出頻率的 DPLL
struct intel_dpll_hw_state *dpll_hw_stateDPLL 的硬體狀態
描述
將 pll 的硬體狀態讀出到 dpll_hw_state 中。
-
void intel_dpll_dump_hw_state(struct intel_display *display, struct drm_printer *p, const struct intel_dpll_hw_state *dpll_hw_state)¶
轉儲 hw_state
引數
struct intel_display *displayintel_display 結構
struct drm_printer *p將狀態列印到哪裡
const struct intel_dpll_hw_state *dpll_hw_state要轉儲的硬體狀態
描述
轉儲 dpll_hw_state 中的相關值。
-
bool intel_dpll_compare_hw_state(struct intel_display *display, const struct intel_dpll_hw_state *a, const struct intel_dpll_hw_state *b)¶
比較兩個狀態
引數
struct intel_display *displayintel_display 結構
const struct intel_dpll_hw_state *a第一個 DPLL 硬體狀態
const struct intel_dpll_hw_state *b第二個 DPLL 硬體狀態
描述
比較 DPLL 硬體狀態 a 和 b。
返回
如果狀態相等,則為 true;如果狀態不同,則為 false
-
enum intel_dpll_id¶
可能的 DPLL id
常量
DPLL_ID_PRIVATE正在使用的非共享 dpll
DPLL_ID_PCH_PLL_AILK、SNB 和 IVB 中的 DPLL A
DPLL_ID_PCH_PLL_BILK、SNB 和 IVB 中的 DPLL B
DPLL_ID_WRPLL1HSW 和 BDW WRPLL1
DPLL_ID_WRPLL2HSW 和 BDW WRPLL2
DPLL_ID_SPLLHSW 和 BDW SPLL
DPLL_ID_LCPLL_810HSW 和 BDW 0.81 GHz LCPLL
DPLL_ID_LCPLL_1350HSW 和 BDW 1.35 GHz LCPLL
DPLL_ID_LCPLL_2700HSW 和 BDW 2.7 GHz LCPLL
DPLL_ID_SKL_DPLL0SKL 及更高版本 DPLL0
DPLL_ID_SKL_DPLL1SKL 及更高版本 DPLL1
DPLL_ID_SKL_DPLL2SKL 及更高版本 DPLL2
DPLL_ID_SKL_DPLL3SKL 及更高版本 DPLL3
DPLL_ID_ICL_DPLL0ICL/TGL 組合 PHY DPLL0
DPLL_ID_ICL_DPLL1ICL/TGL 組合 PHY DPLL1
DPLL_ID_EHL_DPLL4EHL 組合 PHY DPLL4
DPLL_ID_ICL_TBTPLLICL/TGL TBT PLL
DPLL_ID_ICL_MGPLL1- ICL MG PLL 1 埠 1 (C),
TGL TC PLL 1 埠 1 (TC1)
DPLL_ID_ICL_MGPLL2- ICL MG PLL 1 埠 2 (D)
TGL TC PLL 1 埠 2 (TC2)
DPLL_ID_ICL_MGPLL3- ICL MG PLL 1 埠 3 (E)
TGL TC PLL 1 埠 3 (TC3)
DPLL_ID_ICL_MGPLL4- ICL MG PLL 1 埠 4 (F)
TGL TC PLL 1 埠 4 (TC4)
DPLL_ID_TGL_MGPLL5TGL TC PLL 埠 5 (TC5)
DPLL_ID_TGL_MGPLL6TGL TC PLL 埠 6 (TC6)
DPLL_ID_DG1_DPLL0DG1 組合 PHY DPLL0
DPLL_ID_DG1_DPLL1DG1 組合 PHY DPLL1
DPLL_ID_DG1_DPLL2DG1 組合 PHY DPLL2
DPLL_ID_DG1_DPLL3DG1 組合 PHY DPLL3
描述
DPLL 可能 ID 的列舉。真正的共享 dpll id 必須 >= 0。
儲存 DPLL 原子狀態
定義:
struct intel_shared_dpll_state {
u8 pipe_mask;
struct intel_dpll_hw_state hw_state;
};
成員
pipe_mask使用此 DPLL 的管道的掩碼,無論是否啟用
hw_stateDPLL 的硬體配置儲存在結構
intel_dpll_hw_state中。
描述
此結構儲存 DPLL 的原子狀態,該狀態可以表示其當前狀態(在結構 intel_shared_dpll 中)或原子模式集將應用的所需的未來狀態(儲存在結構 intel_atomic_state 中)。
另請參見 intel_reserve_shared_dplls() 和 intel_release_shared_dplls()。
-
struct dpll_info¶
顯示 PLL 平臺特定資訊
定義:
struct dpll_info {
const char *name;
const struct intel_shared_dpll_funcs *funcs;
enum intel_dpll_id id;
enum intel_display_power_domain power_domain;
bool always_on;
bool is_alt_port_dpll;
};
成員
nameDPLL 名稱;用於日誌記錄
funcs平臺特定掛鉤
id此 DPLL 的唯一識別符號
power_domainDPLL 需要的額外電源域
always_on通知狀態檢查器,即使任何 CRTC 未使用 DPLL,也始終保持啟用狀態。
is_alt_port_dpll通知狀態檢查器,DPLL 可以用作備用(用於 TC->TBT 備用)。
具有跟蹤狀態和使用者的顯示 PLL
定義:
struct intel_shared_dpll {
struct intel_shared_dpll_state state;
u8 index;
u8 active_mask;
bool on;
const struct dpll_info *info;
intel_wakeref_t wakeref;
};
成員
state儲存 pll 的狀態,包括其硬體狀態和使用它的 CRTC。
index原子狀態的索引
active_mask使用此 DPLL 的活動管道(即 DPMS 開啟)的掩碼
onPLL 實際上是否處於活動狀態?在模式設定期間停用
info平臺特定資訊
wakeref在某些平臺上,可能需要獲取裝置級執行時 pm 引用,以便在此 DPLL 啟用時停用 DC 狀態
顯示狀態緩衝區¶
DSB(顯示狀態緩衝區)是記憶體中 MMIO 指令的佇列,可以解除安裝到顯示控制器中的 DSB 硬體。DSB 硬體是一個 DMA 引擎,可以對其進行程式設計以從記憶體下載 DSB。它允許驅動程式批次提交顯示硬體程式設計。這有助於減少載入時間和 CPU 活動,從而加快上下文切換速度。從基於 Gen12 英特爾顯示卡的平臺開始新增 DSB 支援。
DSB 只能訪問管道、平面和轉碼器資料島資料包暫存器。
DSB 硬體只能支援暫存器寫入(索引和直接 MMIO 寫入)。DSB 硬體引擎無法進行暫存器讀取。
-
void intel_dsb_reg_write_indexed(struct intel_dsb *dsb, i915_reg_t reg, u32 val)¶
將索引暫存器寫入傳送到 DSB 上下文
引數
struct intel_dsb *dsbDSB 上下文
i915_reg_t reg暫存器地址。
u32 val值。
描述
此函式用於在 DSB 的命令緩衝區中寫入暫存器值對。
請注意,對於少量(小於 5 個左右)寫入到同一暫存器的操作,索引寫入比普通 MMIO 寫入速度慢。
-
void intel_dsb_commit(struct intel_dsb *dsb, bool wait_for_vblank)¶
觸發 DSB 的工作負載執行。
引數
struct intel_dsb *dsbDSB 上下文
bool wait_for_vblank在執行之前等待垂直消隱
描述
此函式用於使用 DSB 對硬體進行實際寫入。
-
struct intel_dsb *intel_dsb_prepare(struct intel_atomic_state *state, struct intel_crtc *crtc, enum intel_dsb_id dsb_id, unsigned int max_cmds)¶
分配、固定和對映 DSB 命令緩衝區。
引數
struct intel_atomic_state *state原子狀態
struct intel_crtc *crtcCRTC
enum intel_dsb_id dsb_id要使用的 DSB 引擎
unsigned int max_cmds我們需要放入命令緩衝區的命令數
描述
此函式準備用於儲存帶有資料的 dsb 指令的命令緩衝區。
返回
DSB 上下文,失敗時為 NULL
-
void intel_dsb_cleanup(struct intel_dsb *dsb)¶
清理 DSB 上下文。
引數
struct intel_dsb *dsbDSB 上下文
描述
此函式透過取消固定和釋放與其關聯的 VMA 物件來清理 DSB 上下文。
GT 程式設計¶
多播/複製 (MCR) 暫存器¶
一些 GT 暫存器被設計為“多播”或“複製”暫存器:同一暫存器的多個例項共享一個 MMIO 偏移。 當硬體需要潛在地跟蹤每個硬體單元(例如,每個子切片、每個 L3bank 等)的暫存器的獨立值時,通常會使用 MCR 暫存器。 存在的特定複製型別因平臺而異。
對 MCR 暫存器的 MMIO 訪問是根據平臺上 MCR_SELECTOR 暫存器中程式設計的設定來控制的。 對 MCR 暫存器的 MMIO 寫入可以以多播(即,單個寫入將暫存器的所有例項更新為相同的值)或單播(寫入僅更新一個特定例項)方式完成。 無論 MCR_SELECTOR 中的多播/單播位如何設定,讀取 MCR 暫存器始終以單播方式執行。 為單播操作選擇特定的 MCR 例項稱為“轉向”。
如果 MCR 暫存器操作被導向到熔斷或當前因電源門控而斷電的硬體單元,則 MMIO 操作將被硬體“終止”。 終止的讀取操作將返回零值,而終止的單播寫入操作將被靜默忽略。
-
void intel_gt_mcr_lock(struct intel_gt *gt, unsigned long *flags)¶
獲取 MCR 轉向鎖
引數
struct intel_gt *gtGT 結構
unsigned long *flags用於儲存 IRQ 標誌的儲存
描述
執行鎖定以保護 MCR 操作期間的轉向。 在 MTL 及更高版本上,還將獲取硬體鎖,以便不僅為驅動程式,還為外部硬體和韌體代理序列化訪問。
上下文
獲取 gt->mcr_lock。 呼叫此函式時不應持有 uncore->lock,但可以在此函式呼叫之後獲取它。
-
void intel_gt_mcr_unlock(struct intel_gt *gt, unsigned long flags)¶
釋放 MCR 轉向鎖
引數
struct intel_gt *gtGT 結構
unsigned long flags要恢復的 IRQ 標誌
描述
釋放由 intel_gt_mcr_lock() 獲取的鎖。
上下文
釋放 gt->mcr_lock
-
void intel_gt_mcr_lock_sanitize(struct intel_gt *gt)¶
清理 MCR 轉向鎖
引數
struct intel_gt *gtGT 結構
描述
這將用於清理驅動程式載入和恢復期間硬體鎖的初始狀態,因為此時沒有來自其他代理的併發訪問,但引導韌體可能將鎖置於錯誤狀態。
-
u32 intel_gt_mcr_read(struct intel_gt *gt, i915_mcr_reg_t reg, int group, int instance)¶
讀取 MCR 暫存器的特定例項
引數
struct intel_gt *gtGT 結構
i915_mcr_reg_t reg要讀取的 MCR 暫存器
int groupMCR 組
int instanceMCR 例項
上下文
獲取和釋放 gt->mcr_lock
描述
返回在轉向特定組/例項後從 MCR 暫存器讀取的值。
-
void intel_gt_mcr_unicast_write(struct intel_gt *gt, i915_mcr_reg_t reg, u32 value, int group, int instance)¶
寫入 MCR 暫存器的特定例項
引數
struct intel_gt *gtGT 結構
i915_mcr_reg_t reg要寫入的 MCR 暫存器
u32 value要寫入的值
int groupMCR 組
int instanceMCR 例項
描述
在轉向特定組/例項後,以單播模式寫入 MCR 暫存器。
上下文
呼叫一個獲取和釋放 gt->mcr_lock 的函式
-
void intel_gt_mcr_multicast_write(struct intel_gt *gt, i915_mcr_reg_t reg, u32 value)¶
將值寫入 MCR 暫存器的所有例項
引數
struct intel_gt *gtGT 結構
i915_mcr_reg_t reg要寫入的 MCR 暫存器
u32 value要寫入的值
描述
以多播模式寫入 MCR 暫存器以更新所有例項。
上下文
獲取和釋放 gt->mcr_lock
-
void intel_gt_mcr_multicast_write_fw(struct intel_gt *gt, i915_mcr_reg_t reg, u32 value)¶
將值寫入 MCR 暫存器的所有例項
引數
struct intel_gt *gtGT 結構
i915_mcr_reg_t reg要寫入的 MCR 暫存器
u32 value要寫入的值
描述
以多播模式寫入 MCR 暫存器以更新所有例項。 此函式假定呼叫者已持有任何必要的 forcewake 域; 在應該自動獲取 forcewake 的情況下,請使用 intel_gt_mcr_multicast_write()。
上下文
呼叫者必須持有 gt->mcr_lock。
-
u32 intel_gt_mcr_multicast_rmw(struct intel_gt *gt, i915_mcr_reg_t reg, u32 clear, u32 set)¶
執行多播 RMW 操作
引數
struct intel_gt *gtGT 結構
i915_mcr_reg_t reg要讀取和寫入的 MCR 暫存器
u32 clear在 RMW 期間要清除的位
u32 set在 RMW 期間要設定的位
描述
以多播方式對 MCR 暫存器執行讀取-修改-寫入操作。 此操作僅在期望所有例項都具有相同值的 MCR 暫存器上才有意義。 讀取將針對任何非終止例項,並且寫入將應用於所有例項。
此函式假定呼叫者已持有任何必要的 forcewake 域; 在應該自動獲取 forcewake 的情況下,請使用 intel_gt_mcr_multicast_rmw()。
返回讀取的舊(未修改)值。
上下文
呼叫獲取和釋放 gt->mcr_lock 的函式
-
void intel_gt_mcr_get_nonterminated_steering(struct intel_gt *gt, i915_mcr_reg_t reg, u8 *group, u8 *instance)¶
查詢將暫存器引導至非終止例項的組/例項值
引數
struct intel_gt *gtGT 結構
i915_mcr_reg_t reg需要轉向的暫存器
u8 *group組轉向的返回值
u8 *instance例項轉向的返回值
描述
此函式返回一個組/例項對,保證可用於給定暫存器的讀取轉向。 請注意,即使暫存器未複製,因此實際上不需要轉向,也會返回值。
-
u32 intel_gt_mcr_read_any_fw(struct intel_gt *gt, i915_mcr_reg_t reg)¶
讀取 MCR 暫存器的一個例項
引數
struct intel_gt *gtGT 結構
i915_mcr_reg_t reg要讀取的暫存器
描述
讀取 GT MCR 暫存器。 讀取將被引導至非終止例項(即,未熔斷或被電源門控關閉電源的例項)。 此函式假定呼叫者已持有任何必要的 forcewake 域; 在應該自動獲取 forcewake 的情況下,請使用 intel_gt_mcr_read_any()。
從 reg 的非終止例項返回值。
上下文
呼叫者必須持有 gt->mcr_lock。
-
u32 intel_gt_mcr_read_any(struct intel_gt *gt, i915_mcr_reg_t reg)¶
讀取 MCR 暫存器的一個例項
引數
struct intel_gt *gtGT 結構
i915_mcr_reg_t reg要讀取的暫存器
描述
讀取 GT MCR 暫存器。 讀取將被引導至非終止例項(即,未熔斷或被電源門控關閉電源的例項)。
從 reg 的非終止例項返回值。
上下文
呼叫一個獲取和釋放 gt->mcr_lock 的函式。
-
void intel_gt_mcr_get_ss_steering(struct intel_gt *gt, unsigned int dss, unsigned int *group, unsigned int *instance)¶
返回 SS 的組/例項轉向
引數
struct intel_gt *gtGT 結構
unsigned int dss要獲取轉向的 DSS ID
unsigned int *group用於儲存轉向組 ID 的指標
unsigned int *instance用於儲存轉向例項 ID 的指標
描述
返回與特定子切片/DSS ID 對應的轉向 ID(透過 group 和 instance 引數)。
-
int intel_gt_mcr_wait_for_reg(struct intel_gt *gt, i915_mcr_reg_t reg, u32 mask, u32 value, unsigned int fast_timeout_us, unsigned int slow_timeout_ms)¶
等待直到 MCR 暫存器與預期狀態匹配
引數
struct intel_gt *gtGT 結構
i915_mcr_reg_t reg要讀取的暫存器
u32 mask要應用於暫存器值的掩碼
u32 value要等待的值
unsigned int fast_timeout_us原子/緊密等待的快速超時(以微秒為單位)
unsigned int slow_timeout_ms慢速超時(以毫秒為單位)
描述
此例程等待直到目標暫存器 reg 在應用 mask 後包含預期的 value,即它等待直到
(intel_gt_mcr_read_any_fw(gt, reg) & mask) == value
否則,等待將在 slow_timeout_ms 毫秒後超時。對於原子上下文,slow_timeout_ms 必須為零,並且 fast_timeout_us 必須不大於 200,000 微秒。
此函式基本上是 __intel_wait_for_register_fw() 的 MCR 友好版本。 通常,此函式僅在 GAM 暫存器上使用,這些暫存器有點特殊 --- 儘管它們是 MCR 暫存器,但讀取(例如,等待狀態更新)始終定向到主例項。
請注意,此例程假定呼叫者已斷言 forcewake,它不適合長時間等待。
上下文
呼叫一個獲取和釋放 gt->mcr_lock 的函式
返回
如果暫存器與所需的條件匹配,則為 0,否則為 -ETIMEDOUT。
記憶體管理和命令提交¶
本節涵蓋了 i915 驅動程式中與 GEM 實現相關的所有內容。
Intel GPU 基礎知識¶
Intel GPU 有多個引擎。 有幾種引擎型別
渲染命令流式傳輸器 (RCS)。 用於渲染 3D 和執行計算的引擎。
位塊傳輸命令流式傳輸器 (BCS)。 用於執行位塊傳輸和/或複製操作的引擎。
影片命令流式傳輸器。 用於影片編碼和解碼的引擎。 在硬體文件中也稱為“BSD”。
影片增強命令流式傳輸器 (VECS)。 用於影片增強的引擎。 在硬體文件中也稱為“VEBOX”。
計算命令流式傳輸器 (CCS)。 可以訪問媒體和 GPGPU 管道,但不能訪問 3D 管道的引擎。
圖形安全控制器 (GSCCS)。 專用於與 GSC 控制器進行內部通訊的引擎,用於處理與安全相關的任務,例如高頻寬數字內容保護 (HDCP)、受保護的 Xe 路徑 (PXP) 和 HuC 韌體身份驗證。
Intel GPU 系列是使用統一記憶體訪問的整合 GPU 系列。 為了使 GPU“工作”,使用者空間將透過 ioctl DRM_IOCTL_I915_GEM_EXECBUFFER2 或 DRM_IOCTL_I915_GEM_EXECBUFFER2_WR 將 GPU 批處理緩衝區饋送給 GPU。 大多數此類批處理緩衝區將指示 GPU 執行工作(例如渲染),並且該工作需要從中讀取的記憶體和寫入到的記憶體。 所有記憶體都封裝在 GEM 緩衝區物件中(通常使用 ioctl DRM_IOCTL_I915_GEM_CREATE 建立)。 為 GPU 建立提供批處理緩衝區的 ioctl 還會列出批處理緩衝區讀取和/或寫入的所有 GEM 緩衝區物件。 有關記憶體管理的實現細節,請參見 GEM BO 管理實現細節。
i915 驅動程式允許使用者空間透過 ioctl DRM_IOCTL_I915_GEM_CONTEXT_CREATE 建立上下文,該上下文由 32 位整數標識。 使用者空間應將這樣的上下文視為與作業系統的 CPU 程序的概念 - 大致 - 類似。 i915 驅動程式保證傳送到固定上下文的命令將被執行,以便先前發出的命令的寫入操作被後續命令的讀取操作看到。 在不同上下文之間發出的操作(即使來自同一檔案描述符)不保證這一點,並且跨上下文同步(即使來自同一檔案描述符)的唯一方法是使用柵欄。 至少從 Gen4 開始,上下文還帶有 GPU HW 上下文; HW 上下文字質上是(至少大部分是)GPU 的狀態。 除了排序保證之外,當命令傳送到上下文時,核心還將透過 HW 上下文恢復 GPU 狀態,這節省了使用者空間在每個批處理緩衝區開始時恢復(至少大部分)GPU 狀態的需求。 用於提交批處理緩衝區工作的非棄用 ioctl 可以傳遞該 ID(在 drm_i915_gem_execbuffer2::rsvd1 的低位中)以標識要用於該命令的上下文。
GPU 具有自己的記憶體管理和地址空間。 核心驅動程式維護 GPU 的記憶體轉換表。 對於較舊的 GPU(即 Gen8 之前的 GPU),存在一個全域性的此類轉換表,即全域性圖形轉換表 (GTT)。 對於較新一代的 GPU,每個上下文都有自己的轉換表,稱為按程序圖形轉換表 (PPGTT)。 重要的是要注意,儘管 PPGTT 被命名為按程序,但它實際上是按上下文的。 當用戶空間提交批處理緩衝區時,核心會遍歷批處理緩衝區使用的 GEM 緩衝區物件列表,並保證不僅每個此類 GEM 緩衝區物件的記憶體都駐留在記憶體中,而且還存在於 (PP)GTT 中。 如果 GEM 緩衝區物件尚未放置在 (PP)GTT 中,則會為其分配一個地址。 這有兩個後果:核心需要編輯提交的批處理緩衝區以在為 GEM BO 分配 GPU 地址時寫入正確的 GPU 地址值,並且核心可能會從 (PP)GTT 中逐出不同的 GEM BO 以為另一個 GEM BO 提供地址空間。 因此,提交批處理緩衝區以執行的 ioctl 還包括緩衝區中引用 GPU 地址的所有位置的列表,以便核心可以正確地編輯緩衝區。 此過程稱為重定位。
鎖定指南¶
注意
這是重構完成後鎖定的描述。 不一定反映 WIP 時鎖定的樣子。
需要遵循所有鎖定規則和與跨驅動程式介面(dma-buf、dma_fence)的介面約定。
程式碼中任何地方都沒有 struct_mutex
dma_resv 將是最外層的鎖(如果需要),並且 ww_acquire_ctx 將提升到最高級別,並在 i915_gem_ctx 的呼叫鏈中傳遞下去
在持有 lru/記憶體管理器(buddy、drm_mm,無論什麼)鎖時,不允許系統記憶體分配
透過啟動 lockdep(使用 fs_reclaim)來強制執行此操作。 如果我們在持有這些鎖時分配記憶體,我們會得到收縮器與 struct_mutex 的重新雜湊,這將非常糟糕。
不要在彼此內部巢狀不同的 lru/記憶體管理器鎖。 依次獲取它們以更新記憶體分配,依靠物件的 dma_resv ww_mutex 與其他操作序列化。
對於 lru/記憶體管理器鎖的建議是它們足夠小,可以作為自旋鎖。
所有功能都需要在適當時提供詳盡的核心自測和/或 IGT 測試
所有 LMEM uAPI 路徑都需要完全可重啟(所有鎖/等待/睡眠的 _interruptible())
透過訊號注入進行錯誤處理驗證。 仍然是我們驗證 GEM uAPI 邊界情況的最佳策略。 必須在 IGT 中過度使用,並且我們需要檢查我們是否真正完全覆蓋了所有錯誤情況。
使用 ww_mutex 進行 -EDEADLK 處理
GEM BO 管理實現細節¶
VMA 表示繫結到地址空間的 GEM BO。 因此,無法保證在將物件繫結到地址空間之前或之後 VMA 的存在。
為了使事情儘可能簡單(即沒有引用計數),VMA 的生命週期將始終 <= 物件的生命週期。 因此,物件引用計數應該可以覆蓋我們。
緩衝區物件逐出¶
本節記錄了逐出緩衝區物件以在虛擬 gpu 地址空間中提供空間的介面函式。 請注意,這主要與收縮緩衝區物件快取正交,後者的目標是提供主記憶體(透過統一記憶體體系結構與 gpu 共享)。
-
int i915_gem_evict_something(struct i915_address_space *vm, struct i915_gem_ww_ctx *ww, u64 min_size, u64 alignment, unsigned long color, u64 start, u64 end, unsigned flags)¶
驅逐 VMA 以騰出空間來繫結新的 VMA
引數
struct i915_address_space *vm從中驅逐的地址空間
struct i915_gem_ww_ctx *ww一個可選的 struct i915_gem_ww_ctx。
u64 min_size所需可用空間的大小
u64 alignment所需可用空間的對齊約束
unsigned long color所需空間的顏色
u64 start從中驅逐物件的範圍的起始位置(包含)
u64 end從中驅逐物件的範圍的結束位置(不包含)
unsigned flags用於控制驅逐演算法的附加標誌
描述
此函式將嘗試驅逐 VMA,直到找到滿足要求的可用空間。呼叫者必須先檢查在呼叫此函式之前是否已存在任何此類空洞。
此函式由物件/VMA 繫結程式碼使用。
由於此函式僅用於釋放虛擬地址空間,因此它僅忽略鎖定的 VMA,而不忽略後備儲存本身已鎖定的物件。因此,obj->pages_pin_count 不能防止驅逐。
澄清:這是為了釋放虛擬地址空間,而不是為了在例如收縮器中釋放記憶體。
-
int i915_gem_evict_for_node(struct i915_address_space *vm, struct i915_gem_ww_ctx *ww, struct drm_mm_node *target, unsigned int flags)¶
驅逐 VMA 以騰出空間來繫結新的 VMA
引數
struct i915_address_space *vm從中驅逐的地址空間
struct i915_gem_ww_ctx *ww一個可選的 struct i915_gem_ww_ctx。
struct drm_mm_node *target要驅逐的範圍(和顏色)
unsigned int flags用於控制驅逐演算法的附加標誌
描述
此函式將嘗試驅逐與目標節點重疊的 VMA。
澄清:這是為了釋放虛擬地址空間,而不是為了在例如收縮器中釋放記憶體。
-
int i915_gem_evict_vm(struct i915_address_space *vm, struct i915_gem_ww_ctx *ww, struct drm_i915_gem_object **busy_bo)¶
從 VM 中驅逐所有空閒 VMA
引數
struct i915_address_space *vm要清理的地址空間
struct i915_gem_ww_ctx *ww一個可選的 struct i915_gem_ww_ctx。如果不是 NULL,i915_gem_evict_vm 也將能夠驅逐 ww 鎖定的 VMA。
struct drm_i915_gem_object **busy_bostruct drm_i915_gem_object 的可選指標。如果不是 NULL,則在
i915_gem_evict_vm()無法嘗試鎖定物件進行驅逐時,busy_bo 將指向它。也會返回 -EBUSY。呼叫者必須先釋放 vm->mutex,然後再嘗試再次獲取有爭議的鎖。呼叫者還擁有對該物件的引用。
描述
此函式從 VM 中驅逐所有 VMA。
execbuf 程式碼使用此函式作為碎片整理地址空間的最後一搏。
澄清:這是為了釋放虛擬地址空間,而不是為了在例如收縮器中釋放記憶體。
Buffer Object Memory Shrinking¶
本節記錄了用於減少緩衝物件快取記憶體使用量的介面函式。收縮用於使主記憶體可用。請注意,這主要與驅逐緩衝物件正交,後者旨在在 GPU 虛擬地址空間中騰出空間。
-
unsigned long i915_gem_shrink(struct i915_gem_ww_ctx *ww, struct drm_i915_private *i915, unsigned long target, unsigned long *nr_scanned, unsigned int shrink)¶
收縮緩衝物件快取
引數
struct i915_gem_ww_ctx *wwi915 gem ww 獲取 ctx,或 NULL
struct drm_i915_private *i915i915 裝置
unsigned long target要提供的記憶體量,以頁面為單位
unsigned long *nr_scanned可選的已掃描頁面數輸出(增量)
unsigned int shrink用於選擇快取型別的控制標誌
描述
此函式是收縮器的主要介面。它將嘗試從緩衝物件中釋放最多 target 頁面的主記憶體後備儲存。可以使用 flags 選擇特定的快取。例如,當應優先從快取中刪除可清除物件時,這很有用。
請注意,不能保證釋放的數量實際上可以作為可用系統記憶體 - 由於其他原因(例如 CPU mmap),頁面可能仍在使用中,或者 mm 核心在我們能夠獲取它們之前已重新使用它們。因此,需要顯式收縮緩衝物件快取的程式碼(例如,為了避免記憶體回收中的死鎖)必須回退到 i915_gem_shrink_all()。
另請注意,任何型別的鎖定(每個 VMA 地址空間鎖定和緩衝物件級別的後備儲存鎖定)都會導致收縮器程式碼不得不跳過該物件。
返回
實際釋放的後備儲存頁面數。
-
unsigned long i915_gem_shrink_all(struct drm_i915_private *i915)¶
完全收縮緩衝物件快取
引數
struct drm_i915_private *i915i915 裝置
描述
這是圍繞 i915_gem_shrink() 的一個簡單包裝器,用於積極地完全收縮所有快取。它還首先等待並使所有未完成的請求失效,以便能夠釋放活動物件的後備儲存。
僅應在程式碼中用於有意使 GPU 靜止或作為記憶體似乎已耗盡時的最後一搏。
返回
實際釋放的後備儲存頁面數。
-
void i915_gem_object_make_unshrinkable(struct drm_i915_gem_object *obj)¶
從收縮器中隱藏該物件。預設情況下,所有支援收縮的物件型別(請參閱 IS_SHRINKABLE)也會在分配系統記憶體頁面後使該物件對收縮器可見。
引數
struct drm_i915_gem_object *objGEM 物件。
描述
這通常用於收縮器無法輕鬆處理的特殊核心內部物件,例如它們是永久鎖定的。
-
void __i915_gem_object_make_shrinkable(struct drm_i915_gem_object *obj)¶
將物件移動到可收縮列表的尾部。此列表上的物件可能會被交換出去。與 WILLNEED 物件一起使用。
引數
struct drm_i915_gem_object *objGEM 物件。
描述
請勿使用。這旨在在非常特殊的物件上呼叫,這些物件尚未具有 mm.pages,但保證在其下具有可能可回收的頁面。
-
void __i915_gem_object_make_purgeable(struct drm_i915_gem_object *obj)¶
將物件移動到可清除列表的尾部。此列表上的物件可能會被交換出去。與 DONTNEED 物件一起使用。
引數
struct drm_i915_gem_object *objGEM 物件。
描述
請勿使用。這旨在在非常特殊的物件上呼叫,這些物件尚未具有 mm.pages,但保證在其下具有可能可回收的頁面。
-
void i915_gem_object_make_shrinkable(struct drm_i915_gem_object *obj)¶
將物件移動到可收縮列表的尾部。此列表上的物件可能會被交換出去。與 WILLNEED 物件一起使用。
引數
struct drm_i915_gem_object *objGEM 物件。
描述
必須僅在具有後備頁面的物件上呼叫。
必須與先前對 i915_gem_object_make_unshrinkable() 的呼叫保持平衡。
-
void i915_gem_object_make_purgeable(struct drm_i915_gem_object *obj)¶
將物件移動到可清除列表的尾部。與 DONTNEED 物件一起使用。與可收縮物件不同,收縮器將嘗試放棄後備頁面,而不是嘗試將它們交換出去。
引數
struct drm_i915_gem_object *objGEM 物件。
描述
必須僅在具有後備頁面的物件上呼叫。
必須與先前對 i915_gem_object_make_unshrinkable() 的呼叫保持平衡。
Batchbuffer Parsing¶
動機:某些 OpenGL 功能(例如,變換反饋、效能監控)要求使用者空間程式碼提交包含諸如 MI_LOAD_REGISTER_IMM 之類的命令的批處理來訪問各種暫存器。不幸的是,某些硬體世代將在“不安全”批處理(包括透過 i915 提交的所有使用者空間批處理)中取消這些命令,即使這些命令是安全的並且代表裝置的預期程式設計模型。
軟體命令解析器在操作上與硬體針對不安全批處理完成的命令解析類似。但是,如果解析器確定操作是安全的,並且將批處理作為“安全”提交以防止硬體解析,則軟體解析器允許某些硬體會 noop 的操作。
威脅:在高層次上,硬體(和軟體)檢查嘗試防止授予使用者空間不應有的特權。有三種特權類別。
首先,明確定義為特權的命令或僅應由核心驅動程式使用的命令。解析器拒絕此類命令
其次,訪問暫存器的命令。為了支援正確/增強的使用者空間功能,特別是某些 OpenGL 擴充套件,解析器提供了一個使用者空間可以安全訪問的暫存器白名單
第三,訪問特權記憶體的命令(即 GGTT、HWS 頁面等)。解析器始終拒絕此類命令。
大多數有問題命令屬於 MI_* 範圍,每個引擎上只有幾個特定命令(例如 PIPE_CONTROL 和 MI_FLUSH_DW)。
實現:每個引擎維護命令和暫存器表,解析器在掃描提交到該引擎的批處理緩衝區時使用這些表。
由於解析器必須檢查的命令集明顯小於支援的命令數,因此解析器表僅包含解析器所需的那些命令。這通常有效,因為命令操作碼範圍具有標準命令長度編碼。因此,對於解析器不需要檢查的命令,它可以輕鬆跳過它們。這是透過每個引擎的長度解碼 vfunc 實現的。
不幸的是,有許多命令不遵循其操作碼範圍的標準長度編碼,主要是在 MI_* 命令中。為了處理此問題,解析器提供了一種在每個引擎的命令表中定義顯式“跳過”條目的方法。
其他命令表條目直接對映到上面提到的大多數高階類別:拒絕、暫存器白名單。解析器透過通用的位掩碼機制實現許多檢查,包括特權記憶體檢查。
-
int intel_engine_init_cmd_parser(struct intel_engine_cs *engine)¶
為引擎設定 cmd 解析器相關欄位
引數
struct intel_engine_cs *engine要初始化的引擎
描述
根據平臺是否需要軟體命令解析,有選擇地初始化 struct intel_engine_cs 中與批處理緩衝區命令解析相關的欄位。
-
void intel_engine_cleanup_cmd_parser(struct intel_engine_cs *engine)¶
清理 cmd 解析器相關欄位
引數
struct intel_engine_cs *engine要清理的引擎
描述
釋放可能已為指定引擎初始化的與命令解析相關的任何資源。
-
int intel_engine_cmd_parser(struct intel_engine_cs *engine, struct i915_vma *batch, unsigned long batch_offset, unsigned long batch_length, struct i915_vma *shadow, bool trampoline)¶
解析批處理緩衝區以查詢特權違規
引數
struct intel_engine_cs *engine批處理將在其上執行的引擎
struct i915_vma *batch有問題的批處理緩衝區
unsigned long batch_offset執行開始時批處理中的位元組偏移量
unsigned long batch_lengthbatch_obj 中命令的長度
struct i915_vma *shadow有問題的批處理緩衝區的經過驗證的副本
bool trampoline如果我們需要跳入特權執行,則為 true
描述
解析指定的批處理緩衝區,查詢概述中描述的特權違規。
返回
如果解析器發現違規或以其他方式失敗,則為非零;-EACCES 如果批處理看起來合法但應使用硬體解析
-
int i915_cmd_parser_get_version(struct drm_i915_private *dev_priv)¶
獲取 cmd 解析器版本號
引數
struct drm_i915_private *dev_privi915 裝置私有資料
描述
cmd 解析器維護一個簡單的遞增整數版本號,適用於傳遞給使用者空間客戶端以確定允許的操作。
返回
cmd 解析器的當前版本號
User Batchbuffer Execution¶
-
struct i915_gem_engines¶
一組引擎
定義:
struct i915_gem_engines {
union {
struct list_head link;
struct rcu_head rcu;
};
struct i915_sw_fence fence;
struct i915_gem_context *ctx;
unsigned int num_engines;
struct intel_context *engines[];
};
成員
{unnamed_union}anonymous
linki915_gem_context::stale::engines 中的連結
rcu釋放時使用的 RCU
fence用於延遲銷燬引擎的 Fence
ctxi915_gem_context 後向指標
num_engines此集中引擎的數量
engines引擎陣列
-
struct i915_gem_engines_iter¶
i915_gem_engines 集的迭代器
定義:
struct i915_gem_engines_iter {
unsigned int idx;
const struct i915_gem_engines *engines;
};
成員
idxi915_gem_engines::engines 的索引
engines正在迭代的引擎集
-
enum i915_gem_engine_type¶
描述 i915_gem_proto_engine 的型別
常量
I915_GEM_ENGINE_TYPE_INVALID無效引擎
I915_GEM_ENGINE_TYPE_PHYSICAL單個物理引擎
I915_GEM_ENGINE_TYPE_BALANCED負載均衡引擎集
I915_GEM_ENGINE_TYPE_PARALLEL並行引擎集
-
struct i915_gem_proto_engine¶
原型引擎
定義:
struct i915_gem_proto_engine {
enum i915_gem_engine_type type;
struct intel_engine_cs *engine;
unsigned int num_siblings;
unsigned int width;
struct intel_engine_cs **siblings;
struct intel_sseu sseu;
};
成員
type此引擎的型別
engine引擎,用於物理引擎
num_siblings平衡或並行兄弟節點的數量
width每個兄弟節點的寬度
siblings平衡兄弟節點,或並行兄弟節點的數量 * 寬度
sseu客戶端設定的 SSEU 引數
描述
此結構體描述了一個上下文可能包含的引擎。引擎有四種類型
I915_GEM_ENGINE_TYPE_INVALID:可以建立無效引擎,但它們在 i915_gem_engines::engines[i] 中顯示為 NULL,使用者嘗試使用它們會導致 -EINVAL。它們在原型上下文構建期間也很有用,因為客戶端可以建立無效引擎,然後在以後將它們設定為虛擬引擎。
I915_GEM_ENGINE_TYPE_PHYSICAL:單個物理引擎,由 i915_gem_proto_engine::engine 描述。
I915_GEM_ENGINE_TYPE_BALANCED:負載均衡引擎集,由 i915_gem_proto_engine::num_siblings 和 i915_gem_proto_engine::siblings 描述。
I915_GEM_ENGINE_TYPE_PARALLEL:並行提交引擎集,由 i915_gem_proto_engine::width、i915_gem_proto_engine::num_siblings 和 i915_gem_proto_engine::siblings 描述。
-
struct i915_gem_proto_context¶
原型上下文
定義:
struct i915_gem_proto_context {
struct drm_i915_file_private *fpriv;
struct i915_address_space *vm;
unsigned long user_flags;
struct i915_sched_attr sched;
int num_user_engines;
struct i915_gem_proto_engine *user_engines;
struct intel_sseu legacy_rcs_sseu;
bool single_timeline;
bool uses_protected_content;
intel_wakeref_t pxp_wakeref;
};
成員
fpriv建立上下文的客戶端
vmuser_flagsschednum_user_engines使用者指定的引擎數量,或 -1
user_engines使用者指定的引擎
legacy_rcs_sseu傳統 RCS 的客戶端設定的 SSEU 引數
single_timelineuses_protected_contentpxp_wakeref
描述
struct i915_gem_proto_context 表示 struct i915_gem_context 的建立引數。 它用於收集透過建立標誌或 SET_CONTEXT_PARAM 提供的引數,以便在我們建立最終的 i915_gem_context 時,這些引數可以是不可變的。
上下文 uAPI 允許兩種設定上下文引數的方法:SET_CONTEXT_PARAM 和 CONTEXT_CREATE_EXT_SETPARAM。 前者允許在任何時候呼叫,而後者則作為 GEM_CONTEXT_CREATE 的一部分發生。 當這些最初被新增時,目前,透過一個設定的所有內容都可以透過另一個設定。 雖然一些引數相當簡單,並且在活動的上下文中設定它們是無害的,例如上下文優先順序,但其他引數則更加棘手,例如 VM 或引擎集。 為了避免一些真正令人討厭的競爭條件,我們不允許在活動的上下文中設定 VM 或引擎集。
我們處理這個問題的方式,而不破壞透過 SET_CONTEXT_PARAM 設定 VM 或引擎集的舊使用者空間,是延遲實際上下文的建立,直到客戶端完成使用 SET_CONTEXT_PARAM 配置它之後。 從客戶端的角度來看,它始終具有相同的 u32 上下文 ID。 然而,從 i915 的角度來看,它是一個 i915_gem_proto_context,直到我們嘗試做一些 proto-context 無法處理的事情,這時才會建立真正的上下文。
這是透過一個小的 xarray 舞蹈完成的。 當呼叫 GEM_CONTEXT_CREATE 時,我們建立一個 proto-context,在 context_xa 中保留一個槽但將其保留為 NULL,proto-context 在 proto_context_xa 中的相應槽中。 然後,每當我們去查詢上下文時,我們首先檢查 context_xa。 如果它在那裡,我們返回 i915_gem_context 並且我們完成了。 如果它不存在,我們檢視 proto_context_xa,如果我們在那裡找到它,我們建立實際的上下文並終止 proto-context。
在我們進行此更改時(2021 年 4 月),我們對現有使用者空間進行了相當完整的稽核,以確保這不會破壞任何內容
Mesa/i965 根本不使用引擎或 VM API
Mesa/ANV 使用引擎 API,但透過 CONTEXT_CREATE_EXT_SETPARAM,並且不使用 VM API。
Mesa/iris 根本不使用引擎或 VM API
開源計算執行時尚未使用引擎 API,但透過 SET_CONTEXT_PARAM 使用 VM API。 然而,CONTEXT_SETPARAM 始終是該上下文上的第二個 ioctl,緊隨 GEM_CONTEXT_CREATE 之後。
媒體驅動程式透過 SET_CONTEXT_PARAM 設定引擎和繫結/平衡。 然而,CONTEXT_SETPARAM 設定 VM 始終是該上下文上的第二個 ioctl,緊隨 GEM_CONTEXT_CREATE 之後,設定引擎緊隨其後。
為了使此舞蹈正常工作,透過 drm_i915_file_private::proto_context_xa 暴露給客戶端的任何對 i915_gem_proto_context 的修改都必須由 drm_i915_file_private::proto_context_lock 保護。 唯一的例外是尚未暴露 proto-context,例如在 GEM_CONTEXT_CREATE 期間處理 CONTEXT_CREATE_SET_PARAM 時。
-
struct i915_gem_context¶
客戶端狀態
定義:
struct i915_gem_context {
struct drm_i915_private *i915;
struct drm_i915_file_private *file_priv;
struct i915_gem_engines __rcu *engines;
struct mutex engines_mutex;
struct drm_syncobj *syncobj;
struct i915_address_space *vm;
struct pid *pid;
struct list_head link;
struct i915_drm_client *client;
struct list_head client_link;
struct kref ref;
struct work_struct release_work;
struct rcu_head rcu;
unsigned long user_flags;
#define UCONTEXT_NO_ERROR_CAPTURE 1;
#define UCONTEXT_BANNABLE 2;
#define UCONTEXT_RECOVERABLE 3;
#define UCONTEXT_PERSISTENCE 4;
#define UCONTEXT_LOW_LATENCY 5;
unsigned long flags;
#define CONTEXT_CLOSED 0;
#define CONTEXT_USER_ENGINES 1;
bool uses_protected_content;
intel_wakeref_t pxp_wakeref;
struct mutex mutex;
struct i915_sched_attr sched;
atomic_t guilty_count;
atomic_t active_count;
unsigned long hang_timestamp[2];
#define CONTEXT_FAST_HANG_JIFFIES (120 * HZ) ;
u8 remap_slice;
struct radix_tree_root handles_vma;
struct mutex lut_mutex;
char name[TASK_COMM_LEN + 8];
struct {
spinlock_t lock;
struct list_head engines;
} stale;
};
成員
i915i915 裝置反向指標
file_priv所有者檔案描述符
engines此上下文的使用者定義的引擎
各種 uAPI 提供從該陣列查詢索引以選擇要操作的引擎的能力。
可以在陣列中定義同一引擎的多個邏輯上不同的例項,以及複合虛擬引擎。
Execbuf 使用 I915_EXEC_RING_MASK 作為該陣列的索引,以選擇要在哪個 HW 上下文 + 引擎上執行。 對於預設陣列,user_ring_map[] 用於將傳統 uABI 轉換為適當的索引(例如,I915_EXEC_DEFAULT 和 I915_EXEC_RENDER 都選擇相同的上下文,並且 I915_EXEC_BSD 很奇怪)。 對於使用者定義的陣列,execbuf 使用 I915_EXEC_RING_MASK 作為普通索引。
由 I915_CONTEXT_PARAM_ENGINE 使用者定義(當設定了 CONTEXT_USER_ENGINES 標誌時)。
engines_mutex保護對引擎的寫入
syncobj共享時間線 syncobj
在上下文建立時設定 SHARED_TIMELINE 標誌後,我們使用此 syncobj 模擬所有引擎上的單個時間線。 對於每個 execbuffer2 呼叫,此 syncobj 都用作輸入和輸出 fence。 與真正的 intel_timeline 不同,如果客戶端透過同時呼叫兩次 execbuffer2 與自身競爭,這不會提供完美的原子按順序保證。 然而,如果使用者空間與自身競爭,則不太可能產生明確定義的結果,因此我們選擇不關心。
vm唯一的地址空間 (GTT)
在 full-ppgtt 模式下,每個上下文都有其自己的地址空間,確保一個客戶端與所有其他客戶端完全分離。
在其他模式下,這是一個 NULL 指標,期望呼叫者使用共享的全域性 GTT。
pid建立者的程序 ID
請注意,建立上下文的人可能不是主要使用者,因為上下文可能會透過本地套接字共享。 然而,這應該隻影響預設上下文,預計客戶端顯式建立的所有上下文都是隔離的。
link放置在
drm_i915_private.context_list中clientstruct i915_drm_client
client_link用於連結到
i915_drm_client.ctx_listref引用計數
客戶端建立的上下文和使用請求提交到硬體的每個請求都持有對上下文的引用(以確保硬體有權訪問狀態,直到它完成所有掛起的寫入)。 有關訪問許可權,請參見 i915_gem_context_get() 和 i915_gem_context_put()。
release_work用於延遲清理的工作項,因為 i915_gem_context_put() 往往是從硬中斷上下文中呼叫的。
FIXME:唯一的真正原因是
i915_gem_engines.fence,所有其他呼叫者都來自程序上下文,最多隻需要一些輕微的改組即可將 i915_gem_context_put() 呼叫拉出自旋鎖。rcurcu_head 用於延遲釋放。
user_flags使用者控制的一小組布林值
flags一小組布林值
uses_protected_content上下文使用 PXP 加密的物件。
此標誌只能在 ctx 建立時設定,並且在上下文的生命週期內是不可變的。 有關設定限制和標記上下文的預期行為的更多資訊,請參見 uapi/drm/i915_drm.h 中的 I915_CONTEXT_PARAM_PROTECTED_CONTENT。
pxp_wakerefwakeref 用於在使用 PXP 時保持裝置喚醒
當裝置掛起時,PXP 會話將失效,這反過來會使所有使用它的上下文和物件失效。 為了使流程簡單,我們會在使用 PXP 物件時保持裝置喚醒。 預計使用者空間應用程式僅在顯示器開啟時才使用 PXP,因此在此處使用 wakeref 不應惡化我們的電源指標。
mutex保護所有不是引擎或 handles_vma 的內容
sched排程程式引數
guilty_count此上下文導致 GPU 掛起的次數。
active_count此上下文在 GPU 掛起期間處於活動狀態的次數,但並未導致掛起。
hang_timestamp此上下文上次導致 GPU 掛起的時間
remap_slice需要重新對映的快取行的位掩碼
handles_vmarbtree 用於查詢使用者控制代碼的上下文特定 obj/vma。 (使用者控制代碼是每個 fd,但繫結是每個 vm,每個 vm 可以是每個上下文一個,也可以與全域性 GTT 共享)
lut_mutex鎖定 handles_vma
name任意名稱,用於使用者除錯
從建立者的程序名稱、pid 和使用者控制代碼構造上下文的名稱,以便在訊息中唯一標識上下文。
stale跟蹤要銷燬的過時引擎
描述
struct i915_gem_context 表示特定客戶端的驅動程式和邏輯硬體狀態的組合檢視。
使用者空間提交要在 GPU 上執行的命令,作為 GEM 物件中的指令流,我們稱之為批處理緩衝區。 這些指令可以引用包含輔助狀態的其他 GEM 物件,例如核心、取樣器、渲染目標,甚至二級批處理緩衝區。 使用者空間不知道這些物件位於 GPU 記憶體中的哪個位置,因此在將批處理緩衝區傳遞給 GPU 執行之前,批處理緩衝區和輔助物件中的那些地址會更新。 這被稱為重定位或修補。 為了儘量避免在下次執行時重定位每個物件,使用者空間被告知在此傳遞中這些物件的位置,但這仍然只是一個提示,因為核心將來可能會為任何物件選擇新的位置。
在與硬體對話的層面上,提交批處理緩衝區以供 GPU 執行是將內容新增到 HW 命令流讀取的緩衝區。
將命令新增到載入 HW 上下文。 對於邏輯環上下文(即 Execlists),此命令不放置在與剩餘專案相同的緩衝區上。
將命令新增到使快取失效的緩衝區。
將批處理緩衝區啟動命令新增到緩衝區; 啟動命令本質上是一個令牌,以及要執行的批處理緩衝區的 GPU 地址。
將管道重新整理新增到緩衝區。
將記憶體寫入命令新增到緩衝區,以記錄 GPU 何時完成執行批處理緩衝區。 記憶體寫入寫入請求的全域性序列號,
i915_request::global_seqno; i915 驅動程式使用暫存器中的當前值來確定 GPU 是否已完成批處理緩衝區。將使用者中斷命令新增到緩衝區。 此命令指示 GPU 在命令、管道重新整理和記憶體寫入完成後發出中斷。
通知硬體新增到緩衝區的其他命令(透過更新尾指標)。
處理 execbuf ioctl 在概念上分為幾個階段。
驗證 - 確保所有指標、控制代碼和標誌都有效。
預留 - 為每個物件分配 GPU 地址空間
重定位 - 更新任何地址以指向最終位置
序列化 - 根據其依賴關係對請求進行排序
構造 - 構造請求以執行批處理緩衝區
提交(在將來的某個時間點執行)
為 execbuf 預留資源是最複雜的階段。 我們既不希望必須在地址空間中遷移物件,也不希望必須更新指向此物件的任何重定位。 理想情況下,我們希望將物件留在其所在的位置,並且所有現有重定位都匹配。 如果物件被賦予新地址,或者如果使用者空間認為該物件位於其他位置,我們必須解析所有重定位條目並更新地址。 使用者空間可以設定 I915_EXEC_NORELOC 標誌來提示其所有物件中的所有目標地址都與重定位條目中的值匹配,並且它們都與 execbuffer 物件列表給出的假定偏移量匹配。 利用此知識,我們知道,如果我們沒有移動任何緩衝區,則所有重定位條目都有效,我們可以跳過更新。 (如果使用者空間錯誤,則可能的結果是即興 GPU 掛起。)使用 I915_EXEC_NO_RELOC 的要求是
物件中寫入的地址必須與相應的 reloc.presumed_offset 匹配,而 reloc.presumed_offset 又必須與相應的 execobject.offset 匹配。
批處理中寫入的任何渲染目標都必須使用 EXEC_OBJECT_WRITE 標記。
為避免停頓,execobject.offset 應與活動上下文中該物件的當前地址匹配。
預留分多個階段完成。 首先,我們嘗試保留已繫結在其當前位置的任何物件 - 只要滿足新 execbuffer 施加的約束即可。 第一次傳遞後剩下的任何未繫結的物件都將安裝到任何可用的空閒空間中。 如果物件不適合,則從預留中刪除所有物件,並在按優先順序順序對物件進行排序後重新執行該過程(首先嚐試安裝更難安裝的物件)。 如果失敗,則清除整個 VM,我們在得出結論認為它根本無法安裝之前,最後一次嘗試安裝 execbuf。
所有這些的一個小複雜之處是,我們不僅允許使用者空間為地址空間中的物件指定對齊方式和大小,還允許使用者空間指定確切的偏移量。 這些物件更容易放置(位置是先驗已知的),我們必須做的只是確保空間可用。
一旦所有物件都到位,修補埋藏的指標以指向最終位置就是一個相當簡單的工作,即遍歷重定位條目陣列,查詢正確的地址並將該值重寫到物件中。 簡單! ... 重定位條目儲存在使用者記憶體中,因此為了訪問它們,我們必須將它們複製到本地緩衝區中。 該副本必須避免任何缺頁錯誤,因為它們可能會導致回到需要 struct_mutex 的 GEM 物件(即遞迴死鎖)。 因此,我們再次將重定位拆分為多個傳遞。 首先,我們嘗試在原子上下文中完成所有操作(避免缺頁錯誤),這要求我們永遠不要等待。 如果我們檢測到我們可能會等待,或者如果我們需要缺頁錯誤,那麼我們必須回退到較慢的路徑。 慢速路徑必須放棄 mutex。 (你能聽到警鐘了嗎?)放棄 mutex 意味著我們失去了到目前為止為 execbuf 構建的所有狀態,我們必須重置任何全域性資料。 然而,我們將物件鎖定在它們的最終位置 - 這對於併發 execbuf 來說是一個潛在的問題。 一旦我們離開了 mutex,我們可以隨意分配並將所有重定位條目複製到一個大的陣列中,重新獲取 mutex,回收所有物件和其他狀態,然後繼續使用物件更新任何不正確的地址。
當我們處理重定位條目時,我們會維護物件是否正在寫入的記錄。 使用 NORELOC,我們希望使用者空間改為提供此資訊。 我們還會透過將重定位條目中的預期值與目標的最終地址進行比較來檢查是否可以跳過重定位。 如果它們不同,我們必須對映當前物件並重寫其中的 4 或 8 位元組指標。
根據 GEM ABI 的規則,序列化 execbuf 非常簡單。 每個上下文中的執行都按提交的順序排序。 對任何 GEM 物件的寫入都按提交的順序進行,並且是獨佔的。 從 GEM 物件的讀取相對於其他讀取是無序的,但按寫入排序。 在讀取之後提交的寫入不能在讀取之前發生,類似地,在寫入之後提交的任何讀取不能在寫入之前發生。 寫入在引擎之間排序,以便一次只發生一次寫入(預先完成任何讀取) - 在可用時使用訊號量,否則使用 CPU 序列化。 其他 GEM 訪問服從相同的規則,任何寫入(無論是透過使用 set-domain 的 mmap 還是透過 pwrite)都必須在開始之前重新整理所有 GPU 讀取,並且任何讀取(無論是使用 set-domain 還是 pread)都必須在開始之前重新整理所有 GPU 寫入。 (請注意,我們只在之前使用屏障,我們目前依賴使用者空間不會在讀取或寫入物件時同時啟動新的執行。 這可能是一個優勢,也可能不是,具體取決於你對使用者空間是否會搬起石頭砸自己的腳的信任程度。) 序列化可能只會導致請求插入到 DAG 中等待輪到它,但最簡單的是在 CPU 上等待直到所有依賴項都得到解決。
在所有這些之後,只是關閉請求並將其交給硬體(好吧,將其留在佇列中等待執行)的問題。 然而,我們還提供使用提升的許可權執行批處理緩衝區的能力,以便它們訪問否則隱藏的暫存器。 (用於調整 L3 快取等)在授予任何批處理額外許可權之前,我們首先必須檢查它是否包含任何惡意指令,我們檢查每個指令是否來自我們的白名單,並且所有暫存器也來自允許列表。 我們首先將使用者的批處理緩衝區複製到影子(以便使用者無法透過 CPU 或 GPU 訪問它,因為我們掃描它),然後解析每個指令。 如果一切正常,我們設定一個標誌,告訴硬體以信任模式執行批處理緩衝區,否則拒絕 ioctl。
排程¶
-
struct i915_sched_engine¶
排程程式引擎
定義:
struct i915_sched_engine {
struct kref ref;
spinlock_t lock;
struct list_head requests;
struct list_head hold;
struct tasklet_struct tasklet;
struct i915_priolist default_priolist;
int queue_priority_hint;
struct rb_root_cached queue;
bool no_priolist;
void *private_data;
void (*destroy)(struct kref *kref);
bool (*disabled)(struct i915_sched_engine *sched_engine);
void (*kick_backend)(const struct i915_request *rq, int prio);
void (*bump_inflight_request_prio)(struct i915_request *rq, int prio);
void (*retire_inflight_request_prio)(struct i915_request *rq);
void (*schedule)(struct i915_request *request, const struct i915_sched_attr *attr);
};
成員
ref排程引擎物件的引用計數
lock保護優先順序列表、請求、保留和正在執行的任務中的請求
requests在此排程引擎上正在進行的請求列表
hold就緒請求列表,但處於保留狀態
tasklet用於提交的 softirq 任務
default_priolistI915_PRIORITY_NORMAL 的優先順序列表
queue_priority_hint最高掛起的優先順序。
當我們向佇列中新增請求或調整正在執行的請求的優先順序時,我們會計算那些掛起的請求的最大優先順序。 然後,我們可以使用此值來確定我們是否需要搶佔正在執行的請求以服務於佇列。 然而,由於我們可能已經記錄了我們想要搶佔的正在進行的請求的優先順序,但由於已經完成,因此在出隊時優先順序提示可能不再與最高可用請求優先順序匹配。
queue請求佇列,在優先順序列表中
no_priolist停用優先順序列表
private_data提交後端的私有資料
destroy銷燬排程引擎 / 清理後端
disabled檢查後端是否已停用提交
kick_backend在請求的優先順序更改後啟動後端
bump_inflight_request_prio更新正在進行的請求的優先順序
retire_inflight_request_prio指示請求已從優先順序跟蹤中撤回
schedule調整請求的優先順序
當請求的優先順序發生更改並且它及其依賴項可能需要重新安排時呼叫。 請注意,請求本身可能尚未準備好執行!
描述
排程引擎表示具有不同優先順序帶的提交佇列。 它包含所有公共狀態(相對於後端)以排隊、跟蹤和提交請求。
此物件目前非常特定於 i915,但一旦 i915 與 DRM 排程程式整合,它將轉換為 drm_gpu_scheduler 的容器以及其他一些變數。
邏輯環、邏輯環上下文和 Execlists¶
動機:GEN8 帶來了 HW 上下文的擴充套件:“邏輯環上下文”。 這些擴充套件的上下文啟用了許多新功能,尤其是“Execlists”(也在此檔案中實現)。
與傳統 HW 上下文的主要區別之一是邏輯環上下文將更多內容合併到上下文的狀態中,例如 PDP 或環緩衝區控制暫存器
PDP 包含在上下文中的原因是簡單的:由於 PPGTT(每個程序的 GTT)實際上是每個上下文的,因此將 PDP 包含在那裡意味著你不需要自己進行 ppgtt->switch_mm,而是 GPU 會在上下文切換時為你執行此操作。
但是,環緩衝區控制暫存器(head、tail 等)呢? 我們是否只需要每個引擎命令流的一組這些暫存器? 這就是名稱“邏輯環”開始有意義的地方:透過虛擬化環,引擎 cs 會在每次上下文切換時切換到新的“環緩衝區”。 當你想要將工作負載提交到 GPU 時,你會:A) 選擇你的上下文,B) 找到其合適的虛擬化環,C) 將命令寫入其中,然後,最後,D) 告訴 GPU 切換到該上下文。
你告訴 GPU 切換到上下文的方式不是傳統的 MI_SET_CONTEXT,而是透過上下文執行列表,即“Execlists”。
LRC 實現:關於上下文的建立,我們有
一個全域性預設上下文。
每個開啟的 fd 的一個本地預設上下文。
每個上下文建立 ioctl 呼叫一個本地額外上下文。
現在,環緩衝區屬於每個上下文(而不是像以前那樣屬於每個引擎),並且上下文與給定的引擎唯一繫結(而不是像以前那樣可重用),我們需要
每個上下文中的每個引擎一個環緩衝區。
每個上下文中的每個引擎一個後備物件。
全域性預設上下文在其生命週期開始時,這些新物件已完全分配和填充。 每個開啟的 fd 的本地預設上下文更復雜,因為我們在建立時不知道哪個引擎將使用它們。 為了處理這個問題,我們實現了延遲建立 LR 上下文
本地上下文在其生命週期開始時是一個空洞或空白的佔位符,只有在我們收到 execbuffer 時才會被填充給定的引擎。 如果稍後我們收到另一個用於同一上下文但不同引擎的 execbuffer ioctl,我們將分配/填充一個新的環緩衝區和上下文後備物件,依此類推。
最後,關於使用 ioctl 呼叫建立的本地上下文:由於它們僅允許使用渲染環,因此我們可以立即分配和填充它們(至少現在不需要延遲任何操作)。
Execlists 實現:Execlists 是 gen8+ 硬體上提交工作負載以供執行的新方法(與傳統的基於環緩衝區的方法相反)。 此方法的工作方式如下
當提交請求時,其命令(BB 啟動和任何前導或尾隨命令,例如 seqno 麵包屑)放置在相應上下文的環緩衝區中。 此時硬體上下文中的尾指標不會更新,而是由驅動程式保留在環緩衝區結構中。 表示此請求的結構會新增到相應引擎的請求佇列中:此結構包含在將請求寫入環緩衝區後上下文尾部的副本,以及指向上下文字身的指標。
如果引擎的請求佇列在新增請求之前為空,則佇列會立即被處理。否則,佇列將在上下文切換中斷期間被處理。在任何情況下,佇列中的元素都將以成對的形式傳送到 GPU 的 ExecLists 提交埠(簡稱 ELSP),並帶有一個全域性唯一的 20 位提交 ID。
當請求執行完成時,GPU 會使用上下文完成事件更新上下文狀態緩衝區,並生成上下文切換中斷。在中斷處理期間,驅動程式檢查緩衝區中的事件:對於每個上下文完成事件,如果宣告的 ID 與請求佇列頭部的 ID 匹配,則該請求將被撤回並從佇列中移除。
處理之後,如果任何請求被撤回且佇列不為空,則可以提交新的執行列表。佇列頭部的兩個請求接下來將被提交,但是由於一個上下文在執行列表中可能不會出現兩次,因此如果後續請求與第一個請求具有相同的 ID,則必須合併這兩個請求。這隻需丟棄佇列頭部的請求,直到只剩下一個請求(在這種情況下,我們使用 NULL 作為第二個上下文)或者前兩個請求具有唯一的 ID。
透過始終執行佇列中的前兩個請求,驅動程式可以確保 GPU 儘可能保持繁忙狀態。如果在單個上下文完成但第二個上下文仍在執行的情況下,當我們移除第一個上下文時,第二個上下文的請求將位於佇列的頭部。然後,此請求將與不同上下文的新請求一起重新提交,這將導致硬體繼續執行第二個請求並將新請求排隊(GPU 檢測到上下文被具有相同上下文搶佔的情況,並透過不進行搶佔來最佳化上下文切換流程,而只是取樣新的尾部指標)。
全域性 GTT 檢視¶
背景和先前的狀態
從歷史上看,物件只能作為單個例項存在(被繫結)在全域性 GTT 空間中,並且檢視以線性方式表示物件的所有後備頁面。此檢視將被稱為正常檢視。
為了支援同一物件的多個檢視,其中對映頁面的數量不等於後備儲存,或者頁面的佈局不是線性的,因此添加了 GGTT 檢視的概念。
一個替代檢視的例子是由單個影像驅動的立體顯示器。在這種情況下,我們有一個看起來像這樣的幀緩衝區(2x2 頁面)
12 34
以上表示正常 GGTT 檢視,通常為 GPU 或 CPU 渲染對映。相比之下,提供給顯示引擎的是一個替代檢視,它可能看起來像這樣
1212 3434
在此示例中,替代檢視中頁面的大小和佈局都與正常檢視不同。
實現和使用
GGTT 檢視是使用 VMA 實現的,並透過列舉 i915_gtt_view_type 和結構 i915_gtt_view 來區分。
添加了一種新的核心 GEM 函式風格,該函式與 GGTT 繫結的物件一起使用,並帶有 _ggtt_ 中綴,有時帶有 _view 字尾,以避免大量程式碼中的重新命名。它們採用結構 i915_gtt_view 引數,該引數封裝了實現檢視所需的所有元資料。
作為僅對正常檢視感興趣的呼叫者的幫助,全域性常量 i915_gtt_view_normal 單例例項存在。所有舊的核心 GEM API 函式(未採用檢視引數的函式)都在正常 GGTT 檢視上或使用它進行操作。
想要新增或使用新 GGTT 檢視的程式碼需要
新增一個新的帶有合適名稱的列舉。
如果需要,擴充套件 i915_gtt_view 結構中的元資料。
新增對 i915_get_vma_pages() 的支援。
新檢視需要從 i915_get_vma_pages 函式中構建散佈-收集表。此表儲存在 vma.gtt_view 中,並且在 VMA 的整個生命週期記憶體在。
核心 API 被設計為具有複製語義,這意味著傳入的結構 i915_gtt_view 不需要是持久的(在呼叫核心 API 函式後保留)。
-
int i915_gem_gtt_reserve(struct i915_address_space *vm, struct i915_gem_ww_ctx *ww, struct drm_mm_node *node, u64 size, u64 offset, unsigned long color, unsigned int flags)¶
在 address_space (GTT) 中保留一個節點
引數
struct i915_address_space *vmthe
struct i915_address_spacestruct i915_gem_ww_ctx *ww一個可選的 struct i915_gem_ww_ctx。
struct drm_mm_node *nodethe
struct drm_mm_node(通常是 i915_vma.node)u64 size要在 GTT 內部分配多少空間,必須與 #I915_GTT_PAGE_SIZE 對齊
u64 offset在 GTT 內部插入的位置,必須與 #I915_GTT_MIN_ALIGNMENT 對齊,並且節點 (offset + size) 必須適合地址空間
unsigned long color應用於節點的顏色,如果此節點不是來自 VMA,則顏色必須是 #I915_COLOR_UNEVICTABLE
unsigned int flags控制搜尋和驅逐行為
描述
i915_gem_gtt_reserve() 嘗試將 node 插入到地址空間內部的精確 offset(使用 size 和 color)。如果 node 不適合,它會嘗試從 GTT 中驅逐任何重疊的節點,包括任何相鄰節點(如果顏色不匹配)(以確保不同域之間的保護頁面)。有關驅逐演算法的更多細節,請參閱 i915_gem_evict_for_node()。 #PIN_NONBLOCK 可以用來防止等待驅逐活動重疊物件,並且任何被釘住或標記為不可驅逐的重疊節點也會導致失敗。
返回
成功時為 0,如果未找到合適的孔則為 -ENOSPC,如果被要求等待驅逐且中斷則為 -EINTR。
-
int i915_gem_gtt_insert(struct i915_address_space *vm, struct i915_gem_ww_ctx *ww, struct drm_mm_node *node, u64 size, u64 alignment, unsigned long color, u64 start, u64 end, unsigned int flags)¶
將節點插入到 address_space (GTT) 中
引數
struct i915_address_space *vmthe
struct i915_address_spacestruct i915_gem_ww_ctx *ww一個可選的 struct i915_gem_ww_ctx。
struct drm_mm_node *nodethe
struct drm_mm_node(通常是 i915_vma.node)u64 size要在 GTT 內部分配多少空間,必須與 #I915_GTT_PAGE_SIZE 對齊
u64 alignment起始偏移所需的對齊,可能為 0,但如果指定,則必須是 2 的冪,並且至少為 #I915_GTT_MIN_ALIGNMENT
unsigned long color應用於節點的顏色
u64 startGTT 內部任何範圍限制的開始(所有範圍的開始都為 0),必須與 #I915_GTT_PAGE_SIZE 對齊
u64 endGTT 內部任何範圍限制的結束(所有範圍的結束都為 U64_MAX),如果不是 U64_MAX,則必須與 #I915_GTT_PAGE_SIZE 對齊
unsigned int flags控制搜尋和驅逐行為
描述
i915_gem_gtt_insert() 首先搜尋一個可用的孔,它可以將節點插入到其中。孔地址與 alignment 對齊,並且其 size 必須完全適合 [start, end] 邊界內。孔兩側的節點必須匹配 color,否則將在兩個節點之間插入保護頁面(或驅逐節點)。如果未找到合適的孔,首先會隨機選擇一個犧牲品並測試是否可以驅逐,否則會掃描 GTT 內部物件的 LRU 列表,以找到第一組替換節點來建立孔。那些舊的重疊節點將從 GTT 中驅逐(因此在將來使用之前必須重新繫結)。任何當前被釘住的節點都無法驅逐(參見 i915_vma_pin())。類似地,如果節點的 VMA 當前處於活動狀態並且指定了 #PIN_NONBLOCK,則在搜尋驅逐候選物件時也會跳過該節點。有關驅逐演算法的更多細節,請參閱 i915_gem_evict_something()。
返回
成功時為 0,如果未找到合適的孔則為 -ENOSPC,如果被要求等待驅逐且中斷則為 -EINTR。
GTT 柵欄和交織¶
-
void i915_vma_revoke_fence(struct i915_vma *vma)¶
強制移除 VMA 的柵欄
引數
struct i915_vma *vma要線性對映(而不是透過柵欄暫存器)的 vma
描述
此函式強制從給定的物件中移除任何柵欄,這在核心想要進行非平鋪 GTT 訪問時很有用。
-
int i915_vma_pin_fence(struct i915_vma *vma)¶
為 vma 設定柵欄
引數
struct i915_vma *vma要透過柵欄暫存器對映的 vma
描述
透過 GTT 對映物件時,使用者空間希望能夠寫入它們,而不必擔心物件是否平鋪的交織問題。此函式遍歷柵欄暫存器,查詢 obj 的空閒暫存器,如果找不到任何暫存器,則竊取一個暫存器。
然後,它基於物件的屬性設定暫存器:地址、pitch 和平鋪格式。
對於非平鋪表面,這將移除任何現有的柵欄。
返回
成功時為 0,失敗時為負錯誤程式碼。
-
struct i915_fence_reg *i915_reserve_fence(struct i915_ggtt *ggtt)¶
為 vGPU 保留柵欄
引數
struct i915_ggtt *ggtt全域性 GTT
描述
此函式遍歷柵欄暫存器,查詢空閒暫存器,並將其從 fence_list 中移除。它用於為 vGPU 保留柵欄以供使用。
-
void i915_unreserve_fence(struct i915_fence_reg *fence)¶
回收保留的柵欄
引數
struct i915_fence_reg *fence柵欄暫存器
描述
此函式將來自 vGPU 的保留柵欄暫存器新增到 fence_list 中。
-
void intel_ggtt_restore_fences(struct i915_ggtt *ggtt)¶
恢復柵欄狀態
引數
struct i915_ggtt *ggtt全域性 GTT
描述
再次恢復硬體柵欄狀態以匹配軟體跟蹤,以便在 GPU 重置後和恢復時呼叫。請注意,在執行時掛起時,我們僅取消柵欄,以便稍後由使用者重新獲取。
-
void detect_bit_6_swizzle(struct i915_ggtt *ggtt)¶
檢測位 6 交織模式
引數
struct i915_ggtt *ggtt全域性 GGTT
描述
檢測透過主儲存器在 IGD 訪問和 CPU 訪問之間進行的地址查詢的位 6 交織。
-
void i915_gem_object_do_bit_17_swizzle(struct drm_i915_gem_object *obj, struct sg_table *pages)¶
修復位 17 交織
引數
struct drm_i915_gem_object *obji915 GEM 緩衝區物件
struct sg_table *pages物理頁面的散佈收集列表
描述
如果自使用 i915_gem_object_save_bit_17_swizzle() 儲存該狀態以來,此物件的任何頁面幀編號在位 17 中發生了更改,則此函式會修復交織。
這是在再次釘住後備儲存時呼叫的,因為核心可以自由地移動未釘住的後備儲存(無論是直接移動頁面還是透過將它們換出並換入)。
-
void i915_gem_object_save_bit_17_swizzle(struct drm_i915_gem_object *obj, struct sg_table *pages)¶
儲存位 17 交織
引數
struct drm_i915_gem_object *obji915 GEM 緩衝區物件
struct sg_table *pages物理頁面的散佈收集列表
描述
此函式儲存每個頁面幀編號的位 17,以便稍後可以使用 i915_gem_object_do_bit_17_swizzle() 修復交織。必須在可以取消釘住後備儲存之前呼叫此函式。
全域性 GTT 柵欄處理¶
重要的是要避免混淆:i915 驅動程式中的“柵欄”不是用於跟蹤命令完成情況的執行柵欄,而是硬體反平鋪物件,它包裝了給定的全域性 GTT 範圍。每個平臺只有相當有限的這些物件。
柵欄用於反平鋪 GTT 記憶體對映。它們還連線到硬體前緩衝區渲染跟蹤,因此與前緩衝區壓縮互動。此外,在較舊的平臺上,顯示引擎使用的平鋪物件需要柵欄。渲染引擎也可以使用它們 - blitter 命令需要它們,渲染命令是可選的。但是在 gen4+ 上,除了 fbc 之外,顯示和渲染都有自己的平鋪狀態位,不需要柵欄。
另請注意,柵欄僅支援 X 和 Y 平鋪,因此不能用於更高階的新平鋪格式,如 W、Ys 和 Yf。
最後請注意,由於柵欄是一種非常有限的資源,因此它們是動態地與物件關聯的。此外,柵欄狀態會延遲提交到硬體,以避免 gen2/3 上不必要的停頓。因此,程式碼必須顯式呼叫 i915_gem_object_get_fence() 以同步 CPU 訪問的柵欄狀態。另請注意,某些程式碼需要未加柵欄的檢視,對於這些情況,可以使用 i915_gem_object_put_fence() 強制移除柵欄。
在內部,這些函式將透過根據需要將 CPU ptes 移除到 GTT mmap 中(而不是 GTT ptes 本身)與使用者空間訪問同步。
硬體平鋪和交織細節¶
平鋪背後的想法是透過重新排列畫素資料來增加快取命中率,以便一組畫素訪問位於同一快取行中。在後緩衝區/深度緩衝區上執行此操作的效能提升約為 30%。
但是,英特爾架構透過在記憶體處於交錯模式(成對匹配的 DIMMS)時對資料定址進行調整以提高記憶體頻寬,從而使這變得更加複雜。對於交錯記憶體,CPU 將每個連續的 64 位元組傳送到備用記憶體通道,以便它可以從兩個通道獲取頻寬。
GPU 還重新排列其訪問以提高交錯記憶體的頻寬,並且它與 CPU 對非平鋪記憶體的操作相匹配。但是,當平鋪時,它的做法略有不同,因為不僅在 X 方向上,而且在 Y 方向上也遍歷地址。因此,除了當地址的位 6 翻轉時交替通道之外,當其他位翻轉時也會交替通道 - 位 9(每 512 位元組,即 X 平鋪掃描線)和 10(每兩個 X 平鋪掃描線)是 915 和 965 類硬體共有的。
CPU 有時也會異或更高位,以提高執行步幅式訪問的頻寬,就像我們在圖形中經常做的那樣。這在 MCH 文件中稱為“通道 XOR 隨機化”。結果是 CPU 將位 11 或位 17 異或到位 6 的地址解碼中。
所有這些位 6 XOR 都對我們的記憶體管理產生影響,因為我們需要確保 3d 驅動程式可以正確定址物件內容。
如果我們沒有交錯記憶體,則所有平鋪都是安全的,並且不需要交織。
當位 17 被 XOR 時,我們 просто 拒絕進行任何平鋪。位 17 不僅僅是頁面偏移量,因此當我們分頁進出物件時,其中的各個頁面將具有不同的位 17 地址,導致每個 64 位元組與其鄰居交換!
否則,如果交錯,我們必須告訴 3d 驅動程式它需要執行的地址交織是什麼,因為它正在使用 CPU 寫入頁面(位 6 和可能位 11 被 XOR),並且 GPU 正在從頁面讀取(位 6、9 和 10 被 XOR),導致 CPU 需要累積位交織,異或位 6、9、10 和可能的 11,以便與 GPU 期望的相匹配。
物件平鋪 IOCTL¶
-
u32 i915_gem_fence_size(struct drm_i915_private *i915, u32 size, unsigned int tiling, unsigned int stride)¶
柵欄所需的全域性 GTT 大小
引數
struct drm_i915_private *i915i915 裝置
u32 size物件大小
unsigned int tiling平鋪模式
unsigned int stride平鋪步幅
描述
返回柵欄(平鋪物件的檢視)所需的全域性 GTT 大小,同時考慮到潛在的柵欄暫存器對映。
-
u32 i915_gem_fence_alignment(struct drm_i915_private *i915, u32 size, unsigned int tiling, unsigned int stride)¶
fence所需的全域性GTT對齊
引數
struct drm_i915_private *i915i915 裝置
u32 size物件大小
unsigned int tiling平鋪模式
unsigned int stride平鋪步幅
描述
返回fence所需的全域性GTT對齊(平鋪物件的檢視),同時考慮潛在的fence暫存器對映。
-
int i915_gem_set_tiling_ioctl(struct drm_device *dev, void *data, struct drm_file *file)¶
用於設定平鋪模式的IOCTL處理程式
引數
struct drm_device *devDRM裝置
void *dataioctl的資料指標
struct drm_file *fileioctl呼叫的DRM檔案
描述
設定物件的平鋪模式,返回物件中地址的第6位所需的交換。
由使用者透過ioctl呼叫。
返回
成功時返回零,失敗時返回負的errno。
-
int i915_gem_get_tiling_ioctl(struct drm_device *dev, void *data, struct drm_file *file)¶
用於獲取平鋪模式的IOCTL處理程式
引數
struct drm_device *devDRM裝置
void *dataioctl的資料指標
struct drm_file *fileioctl呼叫的DRM檔案
描述
返回物件的當前平鋪模式和所需的第6位交換。
由使用者透過ioctl呼叫。
返回
成功時返回零,失敗時返回負的errno。
i915_gem_set_tiling_ioctl() 和 i915_gem_get_tiling_ioctl() 是用於宣告fence暫存器要求的使用者空間介面。
原則上,GEM完全不關心物件的內部資料佈局,因此它也不關心平鋪或交換。但有兩個例外:
對於X和Y平鋪,硬體為CPU訪問提供瞭解平鋪器,稱為fence。由於它們的數量有限,核心必須管理這些,因此,如果使用者空間想要使用fence進行解平鋪,則必須告訴核心物件的平鋪方式。
在gen3和gen4平臺上,平鋪物件具有一種交換模式,該模式取決於物理頁面幀編號。當交換此類物件時,頁面幀編號可能會更改,核心必須能夠修復此問題,因此需要知道平鋪方式。請注意,在具有非對稱記憶體通道填充的部分平臺上,交換模式以未知的方式更改,對於這些平臺,核心會完全禁止交換。
由於這兩種情況都不適用於現代平臺(如W、Ys和Yf平鋪)上的新平鋪佈局,因此GEM僅允許將物件平鋪設定為X或Y平鋪。其他任何事情都可以在使用者空間中完全處理,而無需核心的參與。
受保護的物件¶
PXP(受保護的Xe路徑)是Gen12及更高版本平臺上提供的一項功能。它允許執行受保護(即加密)物件的顯示和翻轉。透過CONFIG_DRM_I915_PXP kconfig啟用SW支援。
物件可以透過I915_GEM_CREATE_EXT_PROTECTED_CONTENT create_ext標誌在建立時選擇加入PXP加密。為了正確保護物件,必須將它們與使用I915_CONTEXT_PARAM_PROTECTED_CONTENT標誌建立的上下文結合使用。有關詳細資訊和限制,請參閱這兩個uapi標誌的文件。
受保護的物件與pxp會話相關聯;當前我們僅支援一個會話,該會話由i915管理,其索引可在uapi(I915_PROTECTED_CONTENT_DEFAULT_SESSION)中使用,以用於目標受保護物件的指令。當發生某些事件(例如,掛起/恢復)時,會話將由HW失效。發生這種情況時,所有與會話一起使用的物件都將被標記為無效,並且所有標記為使用受保護內容的上下文都將被禁止。任何進一步嘗試在execbuf呼叫中使用它們的操作都將被拒絕,而翻轉將轉換為黑色幀。
一些PXP設定操作由管理引擎執行,該引擎由mei驅動程式處理;i915和mei之間的通訊透過mei_pxp元件模組執行。
-
struct intel_pxp¶
pxp狀態
定義:
struct intel_pxp {
struct intel_gt *ctrl_gt;
bool platform_cfg_is_bad;
u32 kcr_base;
struct gsccs_session_resources {
u64 host_session_handle;
struct intel_context *ce;
struct i915_vma *pkt_vma;
void *pkt_vaddr;
struct i915_vma *bb_vma;
void *bb_vaddr;
} gsccs_res;
struct i915_pxp_component *pxp_component;
struct device_link *dev_link;
bool pxp_component_added;
struct intel_context *ce;
struct mutex arb_mutex;
bool arb_is_valid;
u32 key_instance;
struct mutex tee_mutex;
struct {
struct drm_i915_gem_object *obj;
void *vaddr;
} stream_cmd;
bool hw_state_invalidated;
bool irq_enabled;
struct completion termination;
struct work_struct session_work;
u32 session_events;
#define PXP_TERMINATION_REQUEST BIT(0);
#define PXP_TERMINATION_COMPLETE BIT(1);
#define PXP_INVAL_REQUIRED BIT(2);
#define PXP_EVENT_TYPE_IRQ BIT(3);
};
成員
ctrl_gt指向擁有VDBOX、KCR引擎(和GSC CS,具體取決於平臺)的PXP子系統資產控制元件的tile的指標
platform_cfg_is_bad用於跟蹤先前任何arb會話建立是否因平臺配置問題而導致失敗,這意味著如果不更改平臺(不是核心),例如BIOS配置、韌體更新等,則無法解決該故障。當呼叫GET_PARAM:I915_PARAM_PXP_STATUS時,此bool將反映出來。
kcr_baseKCR引擎的基本mmio偏移量,在傳統平臺和KCR位於媒體tile內部的較新平臺上有所不同。
gsccs_res用於具有GSC引擎的平臺的請求提交的資源。
pxp_component繫結mei_pxp模組的i915_pxp_component結構。僅在元件繫結/解除繫結函式內部設定和清除,這些函式受
tee_mutex保護。dev_link強制模組關係以進行電源管理排序。
pxp_component_added跟蹤是否已新增pxp元件。分別在tee init和fini函式中設定和清除。
ce用於PXP操作的核心擁有的上下文
arb_mutex保護arb會話啟動
arb_is_valid跟蹤arb會話狀態。拆卸後,即使金鑰已消失,arb會話仍可以在HW上執行,因此我們不能依賴會話的HW狀態來判斷其是否有效,而需要在SW中跟蹤狀態。
key_instance跟蹤我們所在的金鑰例項,因此我們可以使用它來確定物件是使用當前金鑰還是使用先前的金鑰建立的。
tee_mutex保護tee通道繫結和訊息傳遞。
stream_cmd用於將流PXP命令傳送到GSC的LMEM obj
hw_state_invalidated如果HW感知到對加密完整性的攻擊,它將使金鑰失效並期望SW重新初始化會話。我們跟蹤此狀態以確保我們僅在需要時重新啟動arb會話。
irq_enabled跟蹤kcr irq的狀態
termination跟蹤掛起的終止的狀態。僅在gt->irq_lock下重新初始化,並在
session_work中完成。session_work管理會話事件的工作程式。
session_events掛起的會話事件,受gt->irq_lock保護。
微控制器¶
從gen9開始,硬體上有三個微控制器可用:圖形微控制器 (GuC)、HEVC/H.265 微控制器 (HuC) 和顯示微控制器 (DMC)。 驅動程式負責在微控制器上載入韌體;GuC 和 HuC 韌體使用 DMA 引擎傳輸到 WOPCM,而 DMC 韌體透過 MMIO 寫入。
WOPCM¶
WOPCM 佈局¶
在寫入 GuC WOPCM 大小和偏移暫存器後,WOPCM 的佈局將被固定,這些暫存器的值由 HuC/GuC 韌體大小和硬體要求/限制集計算和確定,如下所示
+=========> +====================+ <== WOPCM Top
^ | HW contexts RSVD |
| +===> +====================+ <== GuC WOPCM Top
| ^ | |
| | | |
| | | |
| GuC | |
| WOPCM | |
| Size +--------------------+
WOPCM | | GuC FW RSVD |
| | +--------------------+
| | | GuC Stack RSVD |
| | +------------------- +
| v | GuC WOPCM RSVD |
| +===> +====================+ <== GuC WOPCM base
| | WOPCM RSVD |
| +------------------- + <== HuC Firmware Top
v | HuC FW |
+=========> +====================+ <== WOPCM Base
GuC 可訪問的 WOPCM 從 GuC WOPCM 基礎開始,到 GuC WOPCM 頂部結束。 WOPCM 的頂部保留給硬體上下文(例如,RC6 上下文)。
GuC¶
GuC是GT HW內部的微控制器,在gen9中引入。 GuC旨在解除安裝通常由主機驅動程式執行的某些功能;目前它可以處理的主要操作是
HuC的身份驗證,這是完全啟用HuC使用所必需的。
低延遲圖形上下文排程(也稱為GuC提交)。
GT電源管理。
enable_guc模組引數可用於選擇在GuC中啟用哪些操作。請注意,並非所有操作都受所有gen9+平臺支援。
啟用GuC不是強制性的,因此僅當至少選擇了一個操作時才會載入韌體。但是,不載入GuC可能會導致丟失某些需要GuC的功能(目前只有HuC,但預計將來會有更多)。
-
struct intel_guc¶
GuC的頂級結構。
定義:
struct intel_guc {
struct intel_uc_fw fw;
struct intel_guc_log log;
struct intel_guc_ct ct;
struct intel_guc_slpc slpc;
struct intel_guc_state_capture *capture;
struct dentry *dbgfs_node;
struct i915_sched_engine *sched_engine;
struct i915_request *stalled_request;
enum {
STALL_NONE,
STALL_REGISTER_CONTEXT,
STALL_MOVE_LRC_TAIL,
STALL_ADD_REQUEST,
} submission_stall_reason;
spinlock_t irq_lock;
unsigned int msg_enabled_mask;
atomic_t outstanding_submission_g2h;
struct xarray tlb_lookup;
u32 serial_slot;
u32 next_seqno;
struct {
bool enabled;
void (*reset)(struct intel_guc *guc);
void (*enable)(struct intel_guc *guc);
void (*disable)(struct intel_guc *guc);
} interrupts;
struct {
spinlock_t lock;
struct ida guc_ids;
int num_guc_ids;
unsigned long *guc_ids_bitmap;
struct list_head guc_id_list;
unsigned int guc_ids_in_use;
struct list_head destroyed_contexts;
struct work_struct destroyed_worker;
struct work_struct reset_fail_worker;
intel_engine_mask_t reset_fail_mask;
unsigned int sched_disable_delay_ms;
unsigned int sched_disable_gucid_threshold;
} submission_state;
bool submission_supported;
bool submission_selected;
bool submission_initialized;
struct intel_uc_fw_ver submission_version;
bool rc_supported;
bool rc_selected;
struct i915_vma *ads_vma;
struct iosys_map ads_map;
u32 ads_regset_size;
u32 ads_regset_count[I915_NUM_ENGINES];
struct guc_mmio_reg *ads_regset;
u32 ads_golden_ctxt_size;
u32 ads_waklv_size;
u32 ads_capture_size;
struct i915_vma *lrc_desc_pool_v69;
void *lrc_desc_pool_vaddr_v69;
struct xarray context_lookup;
u32 params[GUC_CTL_MAX_DWORDS];
struct {
u32 base;
unsigned int count;
enum forcewake_domains fw_domains;
} send_regs;
i915_reg_t notify_reg;
u32 mmio_msg;
struct mutex send_mutex;
struct {
spinlock_t lock;
u64 gt_stamp;
unsigned long ping_delay;
struct delayed_work work;
u32 shift;
unsigned long last_stat_jiffies;
} timestamp;
struct work_struct dead_guc_worker;
unsigned long last_dead_guc_jiffies;
#ifdef CONFIG_DRM_I915_SELFTEST;
int number_guc_id_stolen;
u32 fast_response_selftest;
#endif;
};
成員
fwGuC韌體
log包含GuC日誌相關資料和物件的子結構
ct命令傳輸通訊通道
slpc包含SLPC相關資料和物件的子結構
capture錯誤狀態捕獲模組的資料和物件
dbgfs_nodedebugfs節點
sched_engine用於將請求提交到GuC的全域性引擎
stalled_request如果GuC由於任何原因無法處理請求,我們會將其儲存,直到GuC重新開始處理。在處理停滯的請求之前,無法提交其他請求。
submission_stall_reason提交停滯的原因
irq_lock保護GuC irq狀態
msg_enabled_mask接收到INTEL_GUC_ACTION_DEFAULT G2H訊息時處理的事件掩碼。
outstanding_submission_g2h與GuC提交相關的未完成GuC到主機響應的數量,用於確定GT是否空閒
tlb_lookup用於儲存所有掛起的TLB失效請求的xarray
serial_slottlb_lookup中建立的初始等待程式的ID,僅在無法分配新的等待程式時使用。
next_seqno要分配的下一個ID(序列號)。
interrupts指向GuC中斷管理函式的指標。
submission_state用於由單個鎖保護的提交狀態的子結構
submission_state.lock保護submission_state中的所有內容、ce->guc_id.id和ce->guc_id.ref在進出零狀態時的轉換
submission_state.guc_ids用於分配新的guc_ids,single-lrc
submission_state.num_guc_idsguc_ids的數量,自檢功能,以便在測試時能夠減少此數量。
submission_state.guc_ids_bitmap用於分配新的guc_ids,multi-lrc
submission_state.guc_id_list具有有效guc_ids但沒有refs的intel_context列表
submission_state.guc_ids_in_use正在使用的單lrc guc_ids的數量
submission_state.destroyed_contexts等待銷燬的上下文列表(在GuC中取消註冊)
submission_state.destroyed_worker取消註冊上下文的工作程式,我們需要獲取GT PM引用,並且不能從destroy函式中獲取,因為它可能位於原子上下文中(無法睡眠)
submission_state.reset_fail_worker在引擎重置失敗後觸發GT重置的工作程式
submission_state.reset_fail_mask重置失敗的引擎掩碼
submission_state.sched_disable_delay_ms上下文的計劃停用延遲,以毫秒為單位
submission_state.sched_disable_gucid_threshold在我們開始繞過計劃停用延遲之前,剩餘可用guc_ids的最小閾值
submission_supported跟蹤我們是否支援當前平臺上的GuC提交
submission_selected跟蹤使用者是否啟用了GuC提交
submission_initialized跟蹤GuC提交是否已初始化
submission_version當前載入的韌體的提交API版本
rc_supported跟蹤我們是否支援當前平臺上的GuC rc
rc_selected跟蹤使用者是否啟用了GuC rc
ads_vma分配用於儲存GuC ADS的物件
ads_mapGuC ADS的內容
ads_regset_sizeADS中儲存/恢復regset的大小
ads_regset_count每個引擎的ADS中儲存/恢復暫存器的數量
ads_regsetADS中儲存/恢復regset
ads_golden_ctxt_sizeADS中golden上下文的大小
ads_waklv_size解決方法KLV的大小
ads_capture_sizeADS中用於錯誤捕獲的暫存器列表的大小
lrc_desc_pool_v69分配用於儲存GuC LRC描述符池的物件
lrc_desc_pool_vaddr_v69GuC LRC描述符池的內容
context_lookup用於從guc_id解析intel_context,如果上下文中存在此結構,則已在GuC中註冊
params用於韌體初始化的控制引數
send_regsGuC的FW特定暫存器,用於傳送MMIO H2G
notify_reg用於將中斷髮送到GuC FW的暫存器
mmio_msgGuC在其暫存器之一中寫入的通知位掩碼,用於在CT通道被停用時進行處理,以便在通道恢復時進行處理。
send_mutex用於序列化intel_guc_send操作
timestampGT時間戳物件,用於儲存時間戳的副本,並使用worker調整其溢位。
timestamp.lock鎖定保護以下欄位和引擎統計資訊。
timestamp.gt_stampGT時間戳的64位擴充套件值。
timestamp.ping_delay輪詢GT時間戳以查詢溢位的週期。
timestamp.work定期工作,用於調整GT時間戳、引擎和上下文的使用情況以進行溢位。
timestamp.shiftgpm時間戳的右移值
timestamp.last_stat_jiffies上次實際統計資訊收集時的jiffies。我們使用此時間戳來確保我們不會過度取樣統計資訊,因為執行時電源管理事件可以以比所需更高的速率觸發統計資訊收集。
dead_guc_worker用於強制執行GuC重置的非同步worker執行緒。專門用於G2H處理程式想要發出重置時。重置需要重新整理G2H佇列。因此,G2H處理本身不得直接觸發重置。而是透過此worker進行。
last_dead_guc_jiffies先前“dead guc”事件的時間戳,用於防止從根本上損壞的系統持續重新載入GuC。
number_guc_id_stolen已被盜的guc_ids的數量
fast_response_selftest用於快速響應自檢的CT處理程式的後門
描述
它處理韌體載入並管理客戶端池。 intel_guc擁有用於提交的i915_sched_engine。
引數
struct intel_guc *gucintel_guc結構。
struct i915_vma *vmai915圖形虛擬記憶體區域。
描述
GuC不允許任何落在[0, ggtt.pin_bias)範圍內的gfx GGTT地址,該範圍保留給Boot ROM、SRAM和WOPCM。目前,為了將[0, ggtt.pin_bias)地址空間從GGTT中排除,GuC使用的所有gfx物件都使用intel_guc_allocate_vma()分配,並使用PIN_OFFSET_BIAS以及ggtt.pin_bias的值進行鎖定。
返回
vma的GGTT偏移量。
GuC韌體佈局¶
GuC/HuC韌體佈局如下所示
+======================================================================+
| Firmware blob |
+===============+===============+============+============+============+
| CSS header | uCode | RSA key | modulus | exponent |
+===============+===============+============+============+============+
<-header size-> <---header size continued ----------->
<--- size ----------------------------------------------------------->
<-key size->
<-mod size->
<-exp size->
韌體可能具有也可能不具有模數金鑰和指數資料。 標頭、uCode 和 RSA 簽名是驅動程式將使用的必備元件。 每個元件的長度(全部以 dword 為單位)可以在標頭中找到。 如果模數和指數不存在於 fw 中(也稱為截斷影像),則長度值仍然出現在標頭中。
驅動程式將根據以下規則執行一些基本的 fw 大小驗證
標頭、uCode 和 RSA 是必備元件。
所有韌體元件(如果存在)都按照上述佈局表中的順序排列。
每個元件的長度資訊都可以在標頭中找到,以 dword 為單位。
驅動程式不需要模數和指數金鑰。 它們可能不會出現在 fw 中。 因此,在這種情況下,驅動程式將載入截斷的韌體。
從 DG2 開始,HuC 由 GSC 而不是 i915 載入。 GSC 韌體執行所有必需的完整性檢查,我們只需要檢查版本。 請注意,GSC 管理的 blob 的標頭與用於 DMA 載入韌體的 CSS 不同。
GuC 記憶體管理¶
GuC 無法為其自己的使用分配任何記憶體,因此所有分配都必須由主機驅動程式處理。 GuC 透過 GGTT 訪問記憶體,但 4GB 地址空間頂部和底部除外,它們改為由 GuC HW 重新對映到 FW 本身(WOPCM)或其他 HW 部分的記憶體位置。 驅動程式必須注意不要將 GuC 將要訪問的物件放置在這些保留範圍內。 GuC 地址空間的佈局如下所示
+===========> +====================+ <== FFFF_FFFF
^ | Reserved |
| +====================+ <== GUC_GGTT_TOP
| | |
| | DRAM |
GuC | |
Address +===> +====================+ <== GuC ggtt_pin_bias
Space ^ | |
| | | |
| GuC | GuC |
| WOPCM | WOPCM |
| Size | |
| | | |
v v | |
+=======+===> +====================+ <== 0000_0000
GuC 地址空間 [0, ggtt_pin_bias) 的較低部分對映到 GuC WOPCM,而 GuC 地址空間 [ggtt_pin_bias, GUC_GGTT_TOP) 的較高部分對映到 DRAM。 GuC ggtt_pin_bias 的值是 GuC WOPCM 大小。
引數
struct intel_guc *gucguc
u32 size要分配區域的大小(虛擬空間和記憶體)
描述
這是建立用於 GuC 的物件的包裝器。 為了在 GuC 中使用它,需要終身鎖定一個物件,因此我們在 Global GTT 中分配一些後備儲存和一個範圍。 我們必須將其鎖定在 GGTT 中的 [0, GUC ggtt_pin_bias) 之外的某個位置,因為該範圍在 GuC 中是保留的。
返回
如果成功,則為 i915_vma,否則為 ERR_PTR。
GuC 特定韌體載入器¶
引數
struct intel_guc *gucintel_guc 結構體
描述
從驅動程式載入、從睡眠中恢復以及 GPU 重置後,從 intel_uc_init_hw() 呼叫。
韌體映象應該已經被提取到記憶體中,因此只需檢查提取是否成功,然後將映象傳輸到硬體。
返回
錯誤時返回非零程式碼
基於 GuC 的命令提交¶
暫存暫存器:有 16 個基於 MMIO 的暫存器,從 0xC180 開始。核心驅動程式將一個值寫入操作暫存器 (SOFT_SCRATCH_0) 以及任何資料。然後,它透過另一個暫存器寫入 (0xC4C8) 在 GuC 上觸發中斷。韌體在處理完請求後,將成功/失敗程式碼寫回操作暫存器。核心驅動程式輪詢等待此更新,然後繼續。
命令傳輸緩衝區 (CTB):在其他部分詳細介紹,但 CTB(主機到 GuC - H2G,GuC 到主機 - G2H)是 i915 和 GuC 之間的訊息介面。
上下文註冊:在提交上下文之前,必須透過 H2G 向 GuC 註冊。每個上下文都與一個唯一的 guc_id 相關聯。上下文要麼在請求建立時註冊(正常操作),要麼在提交時註冊(異常操作,例如重置後)。
上下文提交:i915 更新記憶體中的 LRC 尾部值。i915 必須啟用 GuC 內的上下文排程,以便 GuC 實際考慮它。因此,第一次提交停用的上下文時,我們使用排程啟用 H2G,而後續提交透過上下文提交 H2G 完成,該 H2G 通知 GuC 先前啟用的上下文有新的工作可用。
上下文取消固定:要取消固定上下文,使用 H2G 來停用排程。當相應的 G2H 返回指示排程停用操作已完成時,可以安全地取消固定上下文。在停用正在進行時,重新提交上下文是不安全的,因此使用柵欄來阻止該上下文的所有未來請求,直到 G2H 返回。因為與 GuC 的這種互動需要非零的時間,所以我們將引腳計數變為零後,透過一個可配置的時間段(參見 SCHED_DISABLE_DELAY_MS)延遲排程停用。想法是這給使用者一個時間視窗,可以在執行此昂貴的操作之前重新提交上下文上的內容。只有在上下文未關閉且 guc_id 使用率小於閾值(參見 NUM_SCHED_DISABLE_GUC_IDS_THRESHOLD)時,才會執行此延遲。
上下文登出:在銷燬上下文之前,或者如果我們竊取其 guc_id,我們必須透過 H2G 向 GuC 登出上下文。如果竊取 guc_id,則在此 guc_id 的登出完成之前,提交任何內容到此 guc_id 都是不安全的,因此使用柵欄來阻止與此 guc_id 相關聯的所有請求,直到相應的 G2H 返回指示 guc_id 已被登出。
submission_state.guc_ids:與上下文註冊/提交/登出期間傳遞的私有 GuC 上下文資料關聯的唯一編號。有 64k 可用。簡單的 ida 用於分配。
竊取 guc_ids:如果沒有 guc_ids 可用,則可以在請求建立時從另一個上下文竊取它們(如果該上下文未固定)。如果找不到 guc_id,我們會將此問題推給使用者,因為我們認為這在正常用例中幾乎不可能發生。
鎖定:在 GuC 提交程式碼中,我們有 3 個基本的自旋鎖來保護所有內容。以下是關於每個鎖的詳細資訊。
sched_engine->lock 這是所有共享 i915 排程引擎 (sched_engine) 的上下文的提交鎖,因此一次只能提交共享 sched_engine 的上下文之一。目前,只有一個 sched_engine 用於 GuC 的所有提交,但將來可能會發生變化。
guc->submission_state.lock GuC 提交狀態的全域性鎖。保護 guc_ids 和已銷燬的上下文列表。
ce->guc_state.lock 保護 ce->guc_state 下的所有內容。確保上下文在發出 H2G 之前處於正確的狀態。例如,我們不會在停用的上下文上發出排程停用(壞主意),我們不會在排程停用正在進行時發出排程啟用,等等...還保護上下文上正在進行的請求列表和優先順序管理狀態。鎖定對於每個上下文都是單獨的。
鎖定順序規則:sched_engine->lock -> ce->guc_state.lock guc->submission_state.lock -> ce->guc_state.lock
重置競爭:當觸發完全 GT 重置時,假定某些 H2G 對 H2G 的 G2H 響應可能會丟失,因為 GuC 也被重置。丟失這些 G2H 可能會證明是致命的,因為我們在收到 G2H 時執行某些操作(例如,銷燬上下文,釋放 guc_ids 等...)。發生這種情況時,我們可以清除上下文狀態並進行適當的清理,但這非常容易出錯。為了避免競爭,重置程式碼必須在清除丟失的 G2H 之前停用提交,而提交程式碼必須檢查是否已停用提交,並在停用時跳過傳送 H2G 和更新上下文狀態。雙方還必須確保持有相關的鎖。
GuC ABI¶
HXG 訊息
與 GuC 交換的所有訊息都使用 32 位雙字定義。第一個雙字被視為訊息頭。其餘雙字是可選的。
位
描述
0
31
- ORIGIN - 訊息的始發者
GUC_HXG_ORIGIN_HOST = 0
GUC_HXG_ORIGIN_GUC = 1
30:28
- TYPE - 訊息型別
GUC_HXG_TYPE_REQUEST = 0
GUC_HXG_TYPE_EVENT = 1
GUC_HXG_TYPE_FAST_REQUEST = 2
GUC_HXG_TYPE_NO_RESPONSE_BUSY = 3
GUC_HXG_TYPE_NO_RESPONSE_RETRY = 5
GUC_HXG_TYPE_RESPONSE_FAILURE = 6
GUC_HXG_TYPE_RESPONSE_SUCCESS = 7
27:0
AUX - 輔助資料(取決於 TYPE)
1
31:0
PAYLOAD - 可選有效負載(取決於 TYPE)
...
n
31:0
HXG 請求
應使用 HXG 請求訊息來啟動同步活動,預期會收到確認或返回資料。
此訊息的接收者應使用 HXG 響應、HXG 失敗或 HXG 重試訊息作為明確的回覆,並且可以使用 HXG 繁忙訊息作為中間回覆。
DATA0 和所有 DATAn 欄位的格式取決於 ACTION 程式碼。
位
描述
0
31
ORIGIN
30:28
TYPE = GUC_HXG_TYPE_REQUEST
27:16
DATA0 - 請求資料(取決於 ACTION)
15:0
ACTION - 請求的操作程式碼
1
31:0
DATAn - 可選資料(取決於 ACTION)
...
n
31:0
HXG 快速請求
應使用 HXG 請求訊息來啟動非同步活動,不預期會收到確認或返回資料。
如果需要確認,則應使用 HXG 請求代替。
如果無法接受此請求(例如,無效資料),則此訊息的接收者只能使用 HXG 失敗訊息。
HXG 快速請求訊息的格式與 HXG 請求相同,除了 TYPE。
位
描述
0
31
ORIGIN - 參見 HXG 訊息
30:28
TYPE = GUC_HXG_TYPE_FAST_REQUEST
27:16
DATA0 - 參見 HXG 請求
15:0
ACTION - 參見 HXG 請求
...
DATAn - 參見 HXG 請求
HXG 事件
應使用 HXG 事件訊息來啟動不涉及即時確認或資料的非同步活動。
DATA0 和所有 DATAn 欄位的格式取決於 ACTION 程式碼。
位
描述
0
31
ORIGIN
30:28
TYPE = GUC_HXG_TYPE_EVENT
27:16
DATA0 - 事件資料(取決於 ACTION)
15:0
ACTION - 事件操作程式碼
1
31:0
DATAn - 可選事件資料(取決於 ACTION)
...
n
31:0
HXG 繁忙
如果接收者預計處理時間將超過預設超時,則可以使用 HXG 繁忙訊息來確認收到 HXG 請求訊息。
COUNTER 欄位可用作進度指示器。
位
描述
0
31
ORIGIN
30:28
27:0
COUNTER - 進度指示器
HXG 重試
接收者應使用 HXG 重試訊息來指示 HXG 請求訊息已被丟棄,應再次傳送。
REASON 欄位可用作提供附加資訊。
位
描述
0
31
ORIGIN
30:28
27:0
- REASON - 重試原因
GUC_HXG_RETRY_REASON_UNSPECIFIED = 0
HXG 失敗
由於錯誤無法處理 HXG 請求訊息時,應使用 HXG 失敗訊息作為回覆。
位
描述
0
31
ORIGIN
30:28
27:16
HINT - 附加錯誤提示
15:0
ERROR - 錯誤/結果程式碼
HXG 響應
成功處理了 HXG 請求訊息且沒有錯誤時,應使用 HXG 響應訊息作為回覆。
基於 GuC MMIO 的通訊
主機和 GuC 之間基於 MMIO 的通訊依賴於特殊的硬體暫存器,這些暫存器的格式可以由軟體定義(所謂的暫存暫存器)。
每個基於 MMIO 的訊息,無論是主機到 GuC (H2G) 還是 GuC 到主機 (G2H) 訊息,其最大長度取決於可用暫存暫存器的數量,都直接寫入這些暫存暫存器。
對於 Gen9+,有 16 個軟體暫存暫存器 0xC180-0xC1B8,但沒有 H2G 命令採用超過 4 個引數,並且 GuC 韌體本身使用一個 4 元素陣列來儲存 H2G 訊息。
對於 Gen11+,還有額外的 4 個暫存器 0x190240-0x19024C,無論計數較低,都優先於舊的暫存器。
基於 MMIO 的通訊主要用於驅動程式初始化階段,以設定之後將使用的 基於 CTB 的通訊。
MMIO HXG 訊息
MMIO 訊息的格式遵循 HXG 訊息的定義。
位
描述
0
31:0
[嵌入式 HXG 訊息]
...
n
31:0
CT 緩衝區
用於傳送 CTB 訊息的迴圈緩衝區
CTB 描述符
位
描述
0
31:0
HEAD - 到從 CT 緩衝區讀取的最後一個雙字的偏移量(以雙字為單位)。它只能由接收者更新。
1
31:0
TAIL - 到寫入 CT 緩衝區的最後一個雙字的偏移量(以雙字為單位)。它只能由傳送者更新。
2
31:0
STATUS - CTB 的狀態
GUC_CTB_STATUS_NO_ERROR = 0(正常操作)
GUC_CTB_STATUS_OVERFLOW = 1(head/tail 太大)
GUC_CTB_STATUS_UNDERFLOW = 2(訊息被截斷)
GUC_CTB_STATUS_MISMATCH = 4(head/tail 被修改)
GUC_CTB_STATUS_UNUSED = 8(CTB 未使用)
...
保留 = MBZ
15
31:0
保留 = MBZ
CTB 訊息
位
描述
0
31:16
FENCE - 訊息識別符號
15:12
- FORMAT - CTB 訊息的格式
GUC_CTB_FORMAT_HXG = 0 - 參見 CTB HXG 訊息
11:8
保留
7:0
NUM_DWORDS - CTB 訊息的長度(不包括頭部)
1
31:0
可選(取決於 FORMAT)
...
n
31:0
CTB HXG 訊息
位
描述
0
31:16
FENCE
15:12
FORMAT = GUC_CTB_FORMAT_HXG
11:8
保留 = MBZ
7:0
NUM_DWORDS = 嵌入式 HXG 訊息的長度(以雙字為單位)
1
31:0
[嵌入式 HXG 訊息]
...
n
31:0
基於 CTB 的通訊
主機和 GuC 之間的 CTB(命令傳輸緩衝區)通訊基於寫入共享緩衝區的 u32 資料流。一個緩衝區只能用於在一個方向上傳輸資料(單向通道)。
每個緩衝區的當前狀態儲存在緩衝區描述符中。緩衝區描述符儲存表示活動資料流的尾部和頭部欄位。尾部欄位由資料生產者(傳送者)更新,頭部欄位由資料消費者(接收者)更新。
+------------+
| DESCRIPTOR | +=================+============+========+
+============+ | | MESSAGE(s) | |
| address |--------->+=================+============+========+
+------------+
| head | ^-----head--------^
+------------+
| tail | ^---------tail-----------------^
+------------+
| size | ^---------------size--------------------^
+------------+
資料流中的每個訊息都以單個 u32 開頭,該 u32 被視為頭部,後跟一組可選的 u32 資料,這些資料構成了特定於訊息的有效負載。
+------------+---------+---------+---------+
| MESSAGE |
+------------+---------+---------+---------+
| msg[0] | [1] | ... | [n-1] |
+------------+---------+---------+---------+
| MESSAGE | MESSAGE PAYLOAD |
+ HEADER +---------+---------+---------+
| | 0 | ... | n |
+======+=====+=========+=========+=========+
| 31:16| code| | | |
+------+-----+ | | |
| 15:5|flags| | | |
+------+-----+ | | |
| 4:0| len| | | |
+------+-----+---------+---------+---------+
^-------------len-------------^
訊息頭包含
len,指示訊息有效負載的長度(以 u32 為單位)
code,指示訊息程式碼
flags,儲存用於控制訊息處理的各種位
HOST2GUC_SELF_CFG
此訊息由主機 KMD 用於設定 GuC 自配置 KLV。
此訊息必須作為 MMIO HXG 訊息傳送。
位
描述
0
31
ORIGIN = GUC_HXG_ORIGIN_HOST
30:28
TYPE = GUC_HXG_TYPE_REQUEST
27:16
DATA0 = MBZ
15:0
ACTION = GUC_ACTION_HOST2GUC_SELF_CFG = 0x0508
1
31:16
KLV_KEY - KLV 鍵,參見 GuC 自配置 KLV
15:0
KLV_LEN - KLV 長度
32 位 KLV = 1
64 位 KLV = 2
2
31:0
VALUE32 - KLV 值的位 31-0
3
31:0
VALUE64 - KLV 值的位 63-32 (KLV_LEN = 2)
位
描述
0
31
ORIGIN = GUC_HXG_ORIGIN_GUC
30:28
27:0
DATA0 = NUM - 如果 KLV 已被解析,則為 1,如果未被識別,則為 0
HOST2GUC_CONTROL_CTB
此 H2G 操作允許 Vf 主機啟用或停用 H2G 和 G2H CT 緩衝區。
此訊息必須作為 MMIO HXG 訊息傳送。
位
描述
0
31
ORIGIN = GUC_HXG_ORIGIN_HOST
30:28
TYPE = GUC_HXG_TYPE_REQUEST
27:16
DATA0 = MBZ
15:0
ACTION = GUC_ACTION_HOST2GUC_CONTROL_CTB = 0x4509
1
31:0
CONTROL - 控制 基於 CTB 的通訊
GUC_CTB_CONTROL_DISABLE = 0
GUC_CTB_CONTROL_ENABLE = 1
位
描述
0
31
ORIGIN = GUC_HXG_ORIGIN_GUC
30:28
27:0
DATA0 = MBZ
GuC KLV
位
描述
0
31:16
- KEY - KLV 鍵識別符號
15:0
LEN - VALUE 的長度(以 32 位雙字為單位)
1
31:0
VALUE - KLV 的實際值(格式取決於 KEY)
...
n
31:0
GuC 自配置 KLV
可用於 HOST2GUC_SELF_CFG 的 GuC KLV 鍵。
- GUC_KLV_SELF_CFG_H2G_CTB_ADDR0x0902
引用 H2G CT 緩衝區的 64 位全域性 Gfx 地址。對於原生模式,應該高於 WOPCM 地址但低於 APIC 基址。
- GUC_KLV_SELF_CFG_H2G_CTB_DESCRIPTOR_ADDR0x0903
引用 H2G CTB 描述符的 64 位全域性 Gfx 地址。對於原生模式,應該高於 WOPCM 地址但低於 APIC 基址。
- GUC_KLV_SELF_CFG_H2G_CTB_SIZE0x0904
引用 H2G CT 緩衝區的大小(以位元組為單位)。應該為 4K 的倍數。
- GUC_KLV_SELF_CFG_G2H_CTB_ADDR0x0905
引用 G2H CT 緩衝區的 64 位全域性 Gfx 地址。對於原生模式,應該高於 WOPCM 地址但低於 APIC 基址。
- GUC_KLV_SELF_CFG_G2H_CTB_DESCRIPTOR_ADDR0x0906
引用 G2H CTB 描述符的 64 位全域性 Gfx 地址。對於原生模式,應該高於 WOPCM 地址但低於 APIC 基址。
- GUC_KLV_SELF_CFG_G2H_CTB_SIZE0x0907
引用 G2H CT 緩衝區的大小(以位元組為單位)。應該為 4K 的倍數。
HuC¶
HuC 是一個專用的微控制器,用於媒體 HEVC(高效影片編碼)操作。使用者空間可以透過將 HuC 特定的命令新增到批處理緩衝區中來直接使用韌體功能。
核心驅動程式僅負責載入 HuC 韌體並觸發其安全認證。這根據平臺以不同的方式完成
較舊的平臺(從 Gen9 到大多數 Gen12):載入是透過 DMA 執行的,認證透過 GuC 執行
DG2:載入和認證都透過 GSC 執行。
MTL 和更新的平臺:載入是透過 DMA 執行的(與非 DG2 的較舊平臺相同),而認證分兩步完成,首先是透過 GuC 進行的用於清晰媒體工作負載的認證,然後是透過 GSC 進行的用於所有工作負載的認證。
在 GuC 進行認證的平臺上,為了正確地執行認證,HuC 二進位制檔案必須在 GuC 之前載入。載入 HuC 是可選的;但是,不使用 HuC 可能會對媒體工作負載的功耗和/或效能產生負面影響,具體取決於使用場景。HuC 必須在導致 WOPCM 丟失其內容(S3/S4、FLR)的事件中重新載入;在較舊的平臺上,HuC 還必須在 GuC/GT 重置時重新載入,而在較新的平臺上,它將能夠存活。
有關 HuC 功能的最新詳細資訊,請參見 https://github.com/intel/media-driver。
-
int intel_huc_auth(struct intel_huc *huc, enum intel_huc_authentication_type type)¶
認證 HuC uCode
引數
struct intel_huc *hucintel_huc 結構體
enum intel_huc_authentication_type type認證型別(透過 GuC 或透過 GSC)
描述
在 intel_uc_init_hw() 期間載入 HuC 和 GuC 韌體後呼叫。
此函式呼叫 GuC 操作來認證 HuC 韌體,並將 RSA 簽名的偏移量傳遞給 intel_guc_auth_huc()。然後,它等待長達 50 毫秒以進行韌體驗證 ACK。
HuC 記憶體管理¶
與 GuC 類似,HuC 也無法自行進行任何記憶體分配,不同之處在於,HuC 使用的分配由使用者空間驅動程式而不是核心驅動程式處理。HuC 透過載入到執行 HuC 特定命令的 VCS 上的上下文所屬的 PPGTT 訪問記憶體。
HuC 韌體佈局¶
HuC FW 佈局與 GuC 佈局相同,參見 GuC 韌體佈局
DMC¶
參見 DMC 韌體支援
跟蹤¶
本節介紹 i915 驅動程式中實現的所有跟蹤點相關內容。
i915_ppgtt_create 和 i915_ppgtt_release¶
啟用完整的 ppgtt 後,每個使用 drm 的程序都將分配至少一個轉換表。透過這些跟蹤,可以跟蹤表的分配和生命週期;這可以在測試/除錯期間用於驗證我們是否沒有洩漏 ppgtt。這些跟蹤透過 vm 指標來識別 ppgtt,該指標也由 i915_vma_bind 和 i915_vma_unbind 跟蹤點列印。
i915_context_create 和 i915_context_free¶
這些跟蹤點用於跟蹤上下文的建立和刪除。如果啟用了完整的ppgtt,它們還會列印分配給上下文的vm的地址。
Perf¶
概述¶
Gen graphics 支援大量的效能計數器,可以幫助驅動程式和應用程式開發人員瞭解和最佳化他們對 GPU 的使用。
這個 i915 perf 介面允許使用者空間配置和開啟一個檔案描述符,該檔案描述符表示 GPU 指標的流,然後可以將其讀作 () 一系列樣本記錄。
該介面特別適合暴露由 GPU 透過 DMA 捕獲的緩衝指標,這些指標與 CPU 不同步且不相關。
表示單個上下文的流可以被具有相應 drm 檔案描述符的應用程式訪問,這樣 OpenGL 可以在沒有特殊許可權的情況下使用該介面。對系統範圍指標的訪問預設需要 root 許可權,除非透過 dev.i915.perf_event_paranoid sysctl 選項進行更改。
與 Core Perf 的比較¶
該介面最初受到核心 Perf 基礎結構的啟發,但一些顯著的差異是
i915 perf 檔案描述符表示“流”而不是“事件”;perf 事件主要對應於單個 64 位值,而流可能會取樣緊密耦合的計數器集,具體取決於配置。例如,Gen OA 單元並非設計為支援各個計數器的正交配置;它配置為一組相關計數器。用於捕獲 OA 指標的 i915 perf 流的樣本將包括以緊湊的 HW 特定格式打包的一組計數器值。OA 單元支援多種不同的打包格式,使用者可以透過開啟流來選擇這些格式。Perf 支援對事件進行分組,但組中的每個事件都使用單獨的系統呼叫進行單獨配置、驗證和身份驗證。
i915 perf 流配置作為 u64(鍵,值)對的陣列提供,而不是帶有多個雜項配置成員(與事件型別特定成員交錯)的固定結構。
i915 perf 不支援透過 mmap'd 迴圈緩衝區公開指標。受支援的指標由 GPU 使用 HW 特定打包格式為計數器集寫入記憶體,與 CPU 不同步。有時,HW 配置的約束要求在將報告公開給非特權應用程式之前對其進行過濾 - 以隱藏其他程序/上下文的指標。對於這些用例,基於 read() 的介面非常合適,並提供了一個在資料從 GPU 對映的緩衝區複製到使用者空間緩衝區時過濾資料的機會。
基於 Core Perf 的第一個原型遇到的問題¶
該驅動程式的第一個原型基於核心 perf 基礎結構,雖然我們確實使其大部分工作正常,並且對 perf 進行了一些更改,但我們發現我們破壞或規避了 perf 當前以 cpu 為中心的設計中內建的太多假設。
最終,我們沒有看到透過更改設計假設來使 perf 的實現和介面更復雜有明顯的好處,同時我們知道我們仍然無法使用任何現有的基於 perf 的使用者空間工具。
此外,考慮到觀測硬體的 Gen 特定性質,以及使用者空間有時需要將 i915 perf OA 指標與透過 MI_REPORT_PERF_COUNT 命令捕獲的邊帶 OA 資料組合在一起;我們希望該介面被特定於平臺的使用者空間(例如 OpenGL 或工具)使用。也就是說;透過不使用 perf,我們本質上並沒有錯過擁有標準的供應商/架構無關介面。
為了供後代參考,如果我們可能會重新嘗試使核心 perf 更適合公開 i915 指標,那麼這些是我們遇到的主要痛點
基於 perf 的 OA PMU 驅動程式破壞了一些重要的設計假設
現有的 perf pmu 用於分析 cpu 上的工作,我們引入了 _IS_DEVICE pmu 的概念,它具有不同的安全含義,需要偽造與 cpu 相關的資料(例如使用者/核心暫存器)以適應 perf 當前的設計,並新增 _DEVICE 記錄作為轉發裝置特定狀態記錄的一種方式。
OA 單元將計數器報告寫入迴圈緩衝區,而無需 CPU 的參與,這使我們的 PMU 驅動程式成為同類首個。
鑑於我們定期將資料從 GPU 對映的 OA 緩衝區轉發到 perf 緩衝區的方式,這些樣本寫入突發對於 perf 來說看起來像是我們取樣太快,因此我們不得不顛覆其限制檢查。
Perf 支援計數器組,並允許透過內部事務讀取這些計數器,但目前事務似乎被設計為從 cpu 顯式啟動(例如,響應使用者空間 read()),雖然我們可以從 OA 緩衝區中提取報告,但我們無法按需從 cpu 觸發報告。
與基於報告相關;OA 計數器在 HW 中配置為一組,而 perf 通常希望計數器配置是正交的。雖然可以將計數器與組領導者相關聯,因為它們是開啟的,但沒有明確的先例可以提供組範圍的配置屬性(例如,我們希望允許使用者空間選擇用於捕獲集合中所有計數器的 OA 單元報告格式,或指定 GPU 上下文以過濾指標)。我們避免使用 perf 的分組功能,並透過 perf 的“原始”樣本欄位將 OA 報告轉發到使用者空間。考慮到在處理規範化時計數器是如何耦合的,這非常適合我們的使用者空間。將計數器拆分為單獨的事件,然後要求使用者空間重新組合它們是不方便的。對於 Mesa 來說,轉發原始的週期性報告以與它使用 MI_REPORT_PERF_COUNT 命令捕獲的邊帶原始報告組合也很方便。
作為關於 perf 分組功能的附註;還有一些擔憂是,使用 PERF_FORMAT_GROUP 作為將計數器值打包在一起的方式會大大增加我們的樣本大小,這可能會降低我們在可用記憶體頻寬有限時可以使用的有效取樣解析度。
使用 OA 單元的報告格式,計數器以 32 位或 40 位值打包在一起,最大的報告大小為 256 位元組。
PERF_FORMAT_GROUP 值為 64 位,但似乎沒有記錄值的順序,這意味著 PERF_FORMAT_ID 也必須用於在每個值之前新增一個 64 位 ID;每個計數器給出 16 位元組。
與計數器正交性相關;我們無法分時共享 OA 單元,而事件排程是 perf 中允許使用者空間開啟 + 啟用比一次可以在 HW 中配置的更多事件的中心設計思想。OA 單元並非設計為允許在使用時重新配置。我們無法重新配置 OA 單元,而不會丟失我們無法顯式訪問以儲存和還原的內部 OA 單元狀態。重新配置 OA 單元也相對較慢,涉及約 100 次暫存器寫入。從使用者空間的角度來看,Mesa 在發出 MI_REPORT_PERF_COUNT 命令時也依賴於穩定的 OA 配置,重要的是,在有未完成的 MI_RPC 命令時,無法停用 OA 單元,否則我們會掛起命令流式傳輸器。
樣本記錄的內容無法被裝置驅動程式擴充套件(即 sample_type 位)。例如;Sourab Gupta 一直在尋找將 GPU 時間戳附加到我們的 OA 樣本。我們透過使用“原始”欄位將 OA 報告塞進樣本記錄中,但是將不止一項內容塞進該欄位非常棘手,因為 events/core.c 當前只允許 pmu 給出一個原始資料指標加上 len,該指標將被複制到環形緩衝區中。要包含 OA 報告以外的內容,我們必須將報告複製到中間的更大緩衝區中。我一直在考慮允許指定資料 + len 值的向量用於複製原始資料,但感覺這是一種為了將原始欄位用於此目的而採用的臨時解決方案。
感覺我們基於 perf 的 PMU 正在進行一些技術上的妥協,僅僅是為了使用 perf
perf_event_open() 要求事件與 pid 或特定的 cpu 核心相關,而我們的裝置 pmu 與兩者都無關。使用 pid 開啟的事件將根據該程序的排程自動啟用/停用 - 因此不適合我們。當事件與 cpu id 相關時,perf 確保 pmu 方法將透過該核心上的程序間中斷來呼叫。為了避免侵入性更改,我們的使用者空間為特定的 cpu 打開了 OA perf 事件。這是可行的,但這意味著 OA 驅動程式的大部分在原子上下文中執行,包括所有 OA 報告轉發,這在我們的例子中實際上是不必要的,並且似乎使我們的鎖定要求有些複雜,因為我們處理了與 i915 驅動程式其餘部分的互動。
i915 驅動程式入口點¶
本節介紹在 i915_perf.c 之外匯出的入口點,用於與 drm/i915 整合並處理 DRM_I915_PERF_OPEN ioctl。
-
int i915_perf_init(struct drm_i915_private *i915)¶
在模組繫結時初始化 i915-perf 狀態
引數
struct drm_i915_private *i915i915 裝置例項
描述
初始化 i915-perf 狀態,而不向使用者空間公開任何內容。
注意
i915-perf 初始化分為“init”和“register”階段,其中 i915_perf_register() 向用戶空間公開狀態。
-
void i915_perf_fini(struct drm_i915_private *i915)¶
與
i915_perf_init()相對的部分
引數
struct drm_i915_private *i915i915 裝置例項
-
void i915_perf_register(struct drm_i915_private *i915)¶
向用戶空間公開 i915-perf
引數
struct drm_i915_private *i915i915 裝置例項
描述
特別是,OA 指標集在 sysfs metrics/ 目錄下發布,允許使用者空間列舉可用於開啟 i915-perf 流的有效 ID。
-
void i915_perf_unregister(struct drm_i915_private *i915)¶
從使用者空間隱藏 i915-perf
引數
struct drm_i915_private *i915i915 裝置例項
描述
i915-perf 狀態清理分為“unregister”和“deinit”階段,其中介面首先透過 i915_perf_unregister() 從使用者空間隱藏,然後再在 i915_perf_fini() 中清理剩餘狀態。
-
int i915_perf_open_ioctl(struct drm_device *dev, void *data, struct drm_file *file)¶
用於使用者空間開啟流 FD 的 DRM ioctl()
引數
struct drm_device *devdrm 裝置
void *data從使用者空間複製的 ioctl 資料(未經驗證)
struct drm_file *filedrm 檔案
描述
驗證使用者空間給出的流開啟引數,包括標誌和 u64 鍵值對屬性的陣列。
關於正在開啟的流的性質,預先做出的假設很少(例如,我們不假設它是用於定期 OA 單元指標)。i915-perf 流有望成為 GPU 寫入的其他形式的緩衝資料的合適介面,除了定期 OA 指標。
請注意,我們在 i915 perf 互斥鎖之外複製使用者空間的屬性,以避免與 mmap_lock 發生笨拙的 lockdep。
大多數實現細節由 i915_perf_open_ioctl_locked() 在獲取 gt->perf.lock 互斥鎖以與任何非檔案操作驅動程式掛鉤進行序列化後處理。
返回
新開啟的 i915 Perf 流檔案描述符或失敗時的負錯誤程式碼。
引數
struct inode *inode與檔案關聯的匿名 inode
struct file *filei915 perf 流檔案
描述
清理與開啟的 i915 perf 流檔案關聯的任何資源。
注意:從使用者空間的角度來看,close() 實際上不會失敗。
返回
成功時返回零,或者返回負錯誤程式碼。
-
int i915_perf_add_config_ioctl(struct drm_device *dev, void *data, struct drm_file *file)¶
用於使用者空間新增新 OA 配置的 DRM ioctl()
引數
struct drm_device *devdrm 裝置
void *data從使用者空間複製的 ioctl 資料(指向
struct drm_i915_perf_oa_config)(未經驗證)struct drm_file *filedrm 檔案
描述
驗證提交的 OA 暫存器以儲存到新的 OA 配置中,然後該配置可用於程式設計 OA 單元及其 NOA 網路。
返回
新的分配的配置編號,用於 perf open ioctl,或者失敗時的負錯誤程式碼。
-
int i915_perf_remove_config_ioctl(struct drm_device *dev, void *data, struct drm_file *file)¶
用於使用者空間刪除 OA 配置的 DRM ioctl()
引數
struct drm_device *devdrm 裝置
void *data從使用者空間複製的 ioctl 資料(指向 u64 整數)
struct drm_file *filedrm 檔案
描述
可以在使用時刪除配置,它們將停止出現在 sysfs 中,並且它們的內容將在關閉使用配置的流時釋放。
返回
成功時返回 0,或者失敗時返回負錯誤程式碼。
i915 Perf 流¶
本節介紹與流語義無關的結構和函式,用於表示 i915 perf 流 FD 和關聯的檔案操作。
-
struct i915_perf_stream¶
單個開啟的流 FD 的狀態
定義:
struct i915_perf_stream {
struct i915_perf *perf;
struct intel_uncore *uncore;
struct intel_engine_cs *engine;
struct mutex lock;
u32 sample_flags;
int sample_size;
struct i915_gem_context *ctx;
bool enabled;
bool hold_preemption;
const struct i915_perf_stream_ops *ops;
struct i915_oa_config *oa_config;
struct llist_head oa_config_bos;
struct intel_context *pinned_ctx;
u32 specific_ctx_id;
u32 specific_ctx_id_mask;
struct hrtimer poll_check_timer;
wait_queue_head_t poll_wq;
bool pollin;
bool periodic;
int period_exponent;
struct {
const struct i915_oa_format *format;
struct i915_vma *vma;
u8 *vaddr;
u32 last_ctx_id;
spinlock_t ptr_lock;
u32 head;
u32 tail;
} oa_buffer;
struct i915_vma *noa_wait;
u64 poll_oa_period;
};
成員
perfi915_perf 反向指標
uncoremmio 訪問路徑
engine與此效能流關聯的引擎。
lock與流操作關聯的鎖
sample_flags表示開啟流時給出的 DRM_I915_PERF_PROP_SAMPLE_* 屬性的標誌,表示使用者空間透過 read() 讀取的單個樣本的內容。
sample_size考慮到樣本的配置內容與所需的標頭大小相結合,這是單個樣本記錄的總大小。
ctx如果在所有上下文中測量系統範圍,則為
NULL,或者為正在監視的特定上下文。enabled考慮到流是否以停用狀態開啟,並基於 I915_PERF_IOCTL_ENABLE 和 I915_PERF_IOCTL_DISABLE 呼叫,流當前是否已啟用。
hold_preemption是否為在 ctx 上完成的命令提交暫停搶佔。對於某些無法輕鬆後處理 OA 緩衝區上下文以減去與 ctx 不關聯的效能計數器的增量的驅動程式,這很有用。
ops提供此特定型別的配置流的實現的回撥。
oa_config流使用的 OA 配置。
oa_config_bos每次 oa_config 更改時延遲分配的 struct i915_oa_config_bo 列表。
pinned_ctxOA 上下文特定資訊。
specific_ctx_id特定上下文的 ID。
specific_ctx_id_mask用於遮蔽 specific_ctx_id 位的掩碼。
poll_check_timer高解析度計時器,將定期檢查迴圈 OA 緩衝區中的資料,以通知使用者空間(例如,在 read() 或 poll() 期間)。
poll_wq當 hrtimer 回撥在迴圈 OA 緩衝區中看到可供讀取的資料時,喚醒的等待佇列。
pollin是否有可供讀取的資料。
periodic當前是否啟用了定期取樣。
period_exponentOA 單元取樣頻率由此派生。
oa_bufferOA 緩衝區的狀態。
oa_buffer.ptr_lock鎖定對所有 head/tail 狀態的讀取和寫入
考慮:head 和 tail 指標狀態需要從 hrtimer 回撥(原子上下文)和 read() fop(使用者上下文)一致地讀取,tail 指標更新發生在原子上下文中,head 更新發生在使用者上下文中,並且(不太可能)read() 錯誤可能需要重置所有 head/tail 狀態。
注意:考慮到 hrtimer 回撥的頻率相對較低(5 毫秒週期),並且讀取通常只在響應 hrtimer 事件時發生,並且可能在下一次回撥之前完成,因此當前對爭用/效能沒有明顯的擔憂。
注意:在讀取和將資料複製到使用者空間時,不持有此鎖,因此 htrimer 回撥中觀察到的 head 值將不表示資料的任何部分消耗。
oa_buffer.head雖然我們總是可以讀回 head 指標暫存器,但我們更喜歡避免信任 HW 狀態,只是為了避免任何硬體條件 * 以某種方式意外地增加 head 指標並導致我們將錯誤的 OA 緩衝區資料轉發到使用者空間的風險。
oa_buffer.tail使用者空間可以讀取的最後一個驗證的尾部。
noa_wait一個批處理緩衝區,在 GPU 上等待 NOA 邏輯被重新程式設計。
poll_oa_period應該檢查 OA 緩衝區中是否有可用資料的時間段(以納秒為單位)。
-
struct i915_perf_stream_ops¶
支援特定流型別的 OP
定義:
struct i915_perf_stream_ops {
void (*enable)(struct i915_perf_stream *stream);
void (*disable)(struct i915_perf_stream *stream);
void (*poll_wait)(struct i915_perf_stream *stream,struct file *file, poll_table *wait);
int (*wait_unlocked)(struct i915_perf_stream *stream);
int (*read)(struct i915_perf_stream *stream,char __user *buf,size_t count, size_t *offset);
void (*destroy)(struct i915_perf_stream *stream);
};
成員
enable啟用 HW 樣本的收集,無論是響應於 I915_PERF_IOCTL_ENABLE 還是在沒有 I915_PERF_FLAG_DISABLED 的情況下開啟流時隱式呼叫。
disable停用 HW 樣本的收集,無論是響應於 I915_PERF_IOCTL_DISABLE 還是在銷燬流之前隱式呼叫。
poll_wait呼叫 poll_wait,傳遞一個等待佇列,一旦有可供流 read() 的內容,該佇列將被喚醒
wait_unlocked對於處理阻塞讀取,請等待直到有可供流 read() 的內容。例如,等待將傳遞給 poll_wait() 的相同等待佇列。
read將緩衝的指標作為記錄複製到使用者空間 buf:使用者空間,目標緩衝區 count:使用者空間請求複製的位元組數 offset:讀取開始時為零,隨著讀取的進行而更新,它表示到目前為止已複製的位元組數和用於複製下一條記錄的緩衝區偏移量。
將此流的儘可能多的緩衝 i915 perf 樣本和記錄複製到使用者空間,以適應給定的緩衝區。
僅寫入完整的記錄;如果沒有足夠的空間用於完整的記錄,則返回 -
ENOSPC。返回導致短讀取的任何錯誤情況,例如 -
ENOSPC或 -EFAULT,即使這些錯誤可能在返回到使用者空間之前被抑制。destroy清除任何特定於流的資源。
流將在呼叫此函式之前始終被停用。
-
int read_properties_unlocked(struct i915_perf *perf, u64 __user *uprops, u32 n_props, struct perf_open_properties *props)¶
驗證並複製使用者空間流開啟屬性
引數
struct i915_perf *perfi915 perf 例項
u64 __user *uprops使用者空間給出的 u64 鍵值對陣列
u32 n_propsuprops 中期望的鍵值對數量
struct perf_open_properties *props驗證屬性時構建的流配置
描述
請注意,此函式僅單獨驗證屬性,而不驗證屬性的組合是否有意義,或者是否已設定特定型別流所需的所有屬性。
請注意,目前對屬性沒有任何排序要求,因此我們不應在此處驗證或假設任何關於排序的資訊。這並不排除將來定義具有排序要求的新屬性。
-
int i915_perf_open_ioctl_locked(struct i915_perf *perf, struct drm_i915_perf_open_param *param, struct perf_open_properties *props, struct drm_file *file)¶
用於使用者空間開啟流 FD 的 DRM ioctl()
引數
struct i915_perf *perfi915 perf 例項
struct drm_i915_perf_open_param *param傳遞給 'DRM_I915_PERF_OPEN' 的開啟引數
struct perf_open_properties *props單獨驗證的 u64 屬性值對
struct drm_file *filedrm 檔案
描述
有關介面詳情,請參閱 i915_perf_ioctl_open()。
代表 i915_perf_open_ioctl() 實現進一步的流配置驗證和流初始化,並使用 gt->perf.lock 互斥鎖進行序列化,以防止與任何非檔案操作的驅動程式鉤子函式衝突。
如果使用者空間對 OA 單元指標感興趣,則進一步的配置驗證和流初始化細節將由 i915_oa_stream_init() 處理。此處的程式碼僅應驗證與所有流型別/後端相關的配置狀態。
注意
此時,props 僅經過單獨驗證,仍需要驗證屬性的組合是否有意義。
返回
成功時返回零,或者返回負錯誤程式碼。
-
void i915_perf_destroy_locked(struct i915_perf_stream *stream)¶
銷燬 i915 perf 流
引數
struct i915_perf_stream *streami915 perf 流
描述
釋放與給定 i915 perf stream 關聯的所有資源,並在此過程中停用任何相關的資料捕獲。
注意
已經獲取了 gt->perf.lock 互斥鎖,以便與任何非檔案操作的驅動程式鉤子函式進行序列化。
-
ssize_t i915_perf_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)¶
處理 i915 perf 流 FD 的 read() FOP
引數
struct file *filei915 perf 流檔案
char __user *buf使用者空間給出的目標緩衝區
size_t count使用者空間希望讀取的位元組數
loff_t *ppos(輸入/輸出)檔案查詢位置(未使用)
描述
處理使用者空間對流檔案描述符執行 read() 操作的入口點。大部分工作都留給 i915_perf_read_locked() 和 i915_perf_stream_ops->read,但為了節省實現流(稍後我們可能需要多個流實現),我們在此處處理阻塞讀取。
我們還可以一致地將嘗試從停用的流中讀取視為 IO 錯誤,因此實現可以假設流在讀取時已啟用。
返回
複製的位元組數,如果失敗,則返回負錯誤程式碼。
-
long i915_perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg)¶
支援 i915 perf 流 FD 的 ioctl() 用法
引數
struct file *filei915 perf 流檔案
unsigned int cmdioctl 請求
unsigned long argioctl 資料
描述
實現推遲到 i915_perf_ioctl_locked()。
返回
成功時返回零,如果失敗,則返回負錯誤程式碼。對於未知 ioctl 請求,返回 -EINVAL。
-
void i915_perf_enable_locked(struct i915_perf_stream *stream)¶
處理 I915_PERF_IOCTL_ENABLE ioctl
引數
struct i915_perf_stream *stream已停用的 i915 perf 流
描述
[重新]啟用此流的關聯資料捕獲。
如果先前已啟用流,則目前沒有意圖向用戶空間提供任何關於保留先前緩衝資料的保證。
-
void i915_perf_disable_locked(struct i915_perf_stream *stream)¶
處理 I915_PERF_IOCTL_DISABLE ioctl
引數
struct i915_perf_stream *stream已啟用的 i915 perf 流
描述
停用此流的關聯資料捕獲。
意圖是停用和重新啟用流在理想情況下比使用相同配置銷燬和重新開啟流更便宜,儘管沒有關於在停用和重新啟用流之間必須保留哪些狀態或緩衝資料的正式保證。
注意
當流被停用時,使用者空間嘗試從該流讀取將被視為錯誤 (-EIO)。
引數
struct file *filei915 perf 流檔案
poll_table *waitpoll() 狀態表
描述
為了處理 i915 perf 流上的使用者空間輪詢,這確保 poll_wait() 被呼叫時使用一個等待佇列,該佇列將在有新的流資料時被喚醒。
注意
實現推遲到 i915_perf_poll_locked()
返回
無需休眠即可準備好的任何輪詢事件
-
__poll_t i915_perf_poll_locked(struct i915_perf_stream *stream, struct file *file, poll_table *wait)¶
使用流的合適等待佇列呼叫 poll_wait()
引數
struct i915_perf_stream *streami915 perf 流
struct file *filei915 perf 流檔案
poll_table *waitpoll() 狀態表
描述
為了處理 i915 perf 流上的使用者空間輪詢,這會透過 i915_perf_stream_ops->poll_wait 呼叫 poll_wait(),並使用一個等待佇列,該佇列將在有新的流資料時被喚醒。
返回
無需休眠即可準備好的任何輪詢事件
i915 Perf 觀測架構流¶
-
struct i915_oa_ops¶
OA 單元流的 Gen 特定實現
定義:
struct i915_oa_ops {
bool (*is_valid_b_counter_reg)(struct i915_perf *perf, u32 addr);
bool (*is_valid_mux_reg)(struct i915_perf *perf, u32 addr);
bool (*is_valid_flex_reg)(struct i915_perf *perf, u32 addr);
int (*enable_metric_set)(struct i915_perf_stream *stream, struct i915_active *active);
void (*disable_metric_set)(struct i915_perf_stream *stream);
void (*oa_enable)(struct i915_perf_stream *stream);
void (*oa_disable)(struct i915_perf_stream *stream);
int (*read)(struct i915_perf_stream *stream,char __user *buf,size_t count, size_t *offset);
u32 (*oa_hw_tail_read)(struct i915_perf_stream *stream);
};
成員
is_valid_b_counter_reg驗證用於為特定平臺程式設計布林計數器的暫存器地址。
is_valid_mux_reg驗證用於為特定平臺程式設計複用器的暫存器地址。
is_valid_flex_reg驗證用於為特定平臺程式設計 flex EU 過濾的暫存器地址。
enable_metric_set選擇並應用任何 MUX 配置,以設定作為取樣計數器報告一部分的布林計數器和自定義 (B/C) 計數器。可能會應用系統約束,例如根據需要停用 EU 時鐘門控。
disable_metric_set刪除與使用 OA 單元關聯的系統約束。
oa_enable啟用定期取樣
oa_disable停用定期取樣
read將資料從迴圈 OA 緩衝區複製到給定的使用者空間緩衝區。
oa_hw_tail_read讀取 OA 尾指標暫存器
特別是,這使我們能夠共享所有用於處理影響多代的 OA 單元尾指標競爭的複雜程式碼。
-
int i915_oa_stream_init(struct i915_perf_stream *stream, struct drm_i915_perf_open_param *param, struct perf_open_properties *props)¶
驗證 OA 流的組合屬性並進行初始化
引數
struct i915_perf_stream *streami915 perf 流
struct drm_i915_perf_open_param *param傳遞給 DRM_I915_PERF_OPEN 的開啟引數
struct perf_open_properties *props配置流的屬性狀態(單獨驗證)
描述
雖然 read_properties_unlocked() 驗證屬性是單獨進行的,但它不能確保組合屬性一定有意義。
此時已經確定使用者空間需要 OA 指標流,但我們仍然需要進一步驗證組合屬性是否正常。
如果配置有意義,我們可以為迴圈 OA 緩衝區分配記憶體並應用請求的指標集配置。
返回
成功時返回零,或者返回負錯誤程式碼。
-
int i915_oa_read(struct i915_perf_stream *stream, char __user *buf, size_t count, size_t *offset)¶
只是簡單地呼叫
i915_oa_ops->read
引數
struct i915_perf_stream *stream為 OA 指標開啟的 i915-perf 流
char __user *buf使用者空間給出的目標緩衝區
size_t count使用者空間希望讀取的位元組數
size_t *offset(輸入/輸出):寫入 buf 的當前位置
描述
根據成功複製到使用者空間緩衝區的位元組數更新 offset。
返回
成功時返回零,如果失敗,則返回負錯誤程式碼
-
void i915_oa_stream_enable(struct i915_perf_stream *stream)¶
處理 OA 流的 I915_PERF_IOCTL_ENABLE
引數
struct i915_perf_stream *stream為 OA 指標開啟的 i915 perf 流
描述
[重新]啟用硬體定期取樣,具體取樣週期根據開啟流時配置的週期。這還會啟動一個 hrtimer,該 hrtimer 會定期檢查迴圈 OA 緩衝區中的資料,以通知使用者空間(例如,在 read() 或 poll() 期間)。
-
void i915_oa_stream_disable(struct i915_perf_stream *stream)¶
處理 OA 流的 I915_PERF_IOCTL_DISABLE
引數
struct i915_perf_stream *stream為 OA 指標開啟的 i915 perf 流
描述
停止 OA 單元定期將計數器報告寫入迴圈 OA 緩衝區。這也停止了定期檢查迴圈 OA 緩衝區中的資料的 hrtimer,用於通知使用者空間。
-
int i915_oa_wait_unlocked(struct i915_perf_stream *stream)¶
處理阻塞 IO,直到 OA 資料可用
引數
struct i915_perf_stream *stream為 OA 指標開啟的 i915-perf 流
描述
當用戶空間嘗試從為 OA 指標開啟的阻塞流 FD 中讀取時呼叫。它會等待,直到 hrtimer 回撥函式找到一個非空的 OA 緩衝區並喚醒我們。
注意
允許此函式返回一些誤報是可以接受的,因為如果使用者空間還沒有真正準備好資料,則任何後續的讀取處理都將返回 -EAGAIN。
返回
成功時返回零,如果失敗,則返回負錯誤程式碼
-
void i915_oa_poll_wait(struct i915_perf_stream *stream, struct file *file, poll_table *wait)¶
為 OA 流 poll() 呼叫 poll_wait()
引數
struct i915_perf_stream *stream為 OA 指標開啟的 i915-perf 流
struct file *filei915 perf 流檔案
poll_table *waitpoll() 狀態表
描述
為了處理 i915 perf 流上為 OA 指標開啟的使用者空間輪詢,這將啟動一個 poll_wait,並使用我們的 hrtimer 回撥在迴圈 OA 緩衝區中看到資料準備好讀取時喚醒的等待佇列。
其他 i915 Perf 內部機制¶
本節僅包括所有當前已記錄的 i915 perf 內部機制,沒有特定的順序,但可能包含一些比更高級別部分中發現的更小的實用程式或平臺特定細節。
-
struct perf_open_properties¶
用於驗證後提供給開啟流的屬性
定義:
struct perf_open_properties {
u32 sample_flags;
u64 single_context:1;
u64 hold_preemption:1;
u64 ctx_handle;
int metrics_set;
int oa_format;
bool oa_periodic;
int oa_period_exponent;
struct intel_engine_cs *engine;
bool has_sseu;
struct intel_sseu sseu;
u64 poll_oa_period;
};
成員
sample_flagsDRM_I915_PERF_PROP_SAMPLE_* 屬性被跟蹤為標誌
single_context應監視單個還是所有 GPU 上下文
hold_preemption是否為篩選的上下文停用了搶佔
ctx_handle一個 gem ctx 控制代碼,用於 single_context
metrics_set透過 sysfs 宣傳的 OA 單元指標集的 ID
oa_formatOA 單元 HW 報告格式
oa_periodic是否啟用定期 OA 單元取樣
oa_period_exponentOA 單元取樣週期由此匯出
engine正由 OA 單元監視的引擎(通常為 rcs0)
has_sseu使用者空間是否指定了 sseu
sseu內部 SSEU 配置,可以從開啟引數中的使用者空間指定配置或預設值計算得出(參見 get_default_sseu_config())
poll_oa_periodCPU 將檢查 OA 資料可用性的時間段(以納秒為單位)
描述
當 read_properties_unlocked() 列舉並驗證提供給開啟指標流的屬性時,配置會在結構中建立,該結構最初初始化為零。
-
bool oa_buffer_check_unlocked(struct i915_perf_stream *stream)¶
檢查資料並更新尾指標狀態
引數
struct i915_perf_stream *streami915 流例項
描述
這可以透過 fops(對於使用者 ctx 中的阻塞讀取)或輪詢檢查 hrtimer(原子 ctx)呼叫,以檢查 OA 緩衝區尾指標並檢查使用者空間是否有資料可讀取。
此函式對於提供解決 OA 單元尾指標與 CPU 可見資料之間的競爭問題的變通方法至關重要。 它負責從硬體讀取尾指標,並在指標可供讀取之前為其提供“老化”時間。(有關更多詳細資訊,請參見上面 OA_TAIL_MARGIN_NSEC 的描述。)
除了在有資料可用於 read() 時返回 true 之外,此函式還會更新 oa_buffer 物件中的尾部。
注意
在這裡讀取 OA 配置狀態是安全的,假設僅在啟用流時才呼叫它,而全域性 OA 配置無法修改。
返回
如果 OA 緩衝區包含資料,則為 true,否則為 false
-
int append_oa_status(struct i915_perf_stream *stream, char __user *buf, size_t count, size_t *offset, enum drm_i915_perf_record_type type)¶
將狀態記錄附加到使用者空間 read() 緩衝區。
引數
struct i915_perf_stream *stream為 OA 指標開啟的 i915-perf 流
char __user *buf使用者空間給出的目標緩衝區
size_t count使用者空間希望讀取的位元組數
size_t *offset(輸入/輸出):寫入 buf 的當前位置
enum drm_i915_perf_record_type type要報告給使用者空間的狀態種類
描述
將狀態記錄(例如 DRM_I915_PERF_RECORD_OA_REPORT_LOST)寫入使用者空間 read() 緩衝區。
只有成功後,buf offset 才會更新。
返回
成功時為 0,失敗時為負錯誤程式碼。
-
int append_oa_sample(struct i915_perf_stream *stream, char __user *buf, size_t count, size_t *offset, const u8 *report)¶
將單個 OA 報告複製到使用者空間 read() 緩衝區。
引數
struct i915_perf_stream *stream為 OA 指標開啟的 i915-perf 流
char __user *buf使用者空間給出的目標緩衝區
size_t count使用者空間希望讀取的位元組數
size_t *offset(輸入/輸出):寫入 buf 的當前位置
const u8 *report要(可選)包含在樣本中的單個 OA 報告
描述
樣本的內容透過開啟流時,作為 stream->sample_flags 跟蹤的 DRM_I915_PERF_PROP_SAMPLE_* 屬性配置。 此函式將單個樣本的請求元件複製到給定的 read() buf。
只有成功後,buf offset 才會更新。
返回
成功時為 0,失敗時為負錯誤程式碼。
-
int gen8_append_oa_reports(struct i915_perf_stream *stream, char __user *buf, size_t count, size_t *offset)¶
將所有緩衝的 OA 報告複製到使用者空間 read() 緩衝區。
引數
struct i915_perf_stream *stream為 OA 指標開啟的 i915-perf 流
char __user *buf使用者空間給出的目標緩衝區
size_t count使用者空間希望讀取的位元組數
size_t *offset(輸入/輸出):寫入 buf 的當前位置
描述
值得注意的是,即使可能已成功複製了一個或多個記錄,也會返回導致短讀取的任何錯誤情況(-ENOSPC 或 -EFAULT)。 在這種情況下,由呼叫者決定是否應在返回到使用者空間之前消除該錯誤。
注意
報告從頭部消耗,並附加到尾部,因此尾部追逐頭部?...如果您認為這很瘋狂並且前後顛倒,那麼您並不孤單,但這遵循 Gen PRM 命名約定。
返回
成功時為 0,失敗時為負錯誤程式碼。
-
int gen8_oa_read(struct i915_perf_stream *stream, char __user *buf, size_t count, size_t *offset)¶
複製狀態記錄,然後複製緩衝的 OA 報告
引數
struct i915_perf_stream *stream為 OA 指標開啟的 i915-perf 流
char __user *buf使用者空間給出的目標緩衝區
size_t count使用者空間希望讀取的位元組數
size_t *offset(輸入/輸出):寫入 buf 的當前位置
描述
檢查 OA 單元狀態暫存器,並在必要時將相應的狀態記錄附加到使用者空間(例如,對於緩衝區滿條件),然後啟動附加任何緩衝的 OA 報告。
根據成功複製到使用者空間緩衝區的位元組數更新 offset。
注意:即使返回了錯誤,也可能已成功將某些資料複製到使用者空間緩衝區,並且這反映在更新後的 offset 中。
返回
成功時返回零,如果失敗,則返回負錯誤程式碼
-
int gen7_append_oa_reports(struct i915_perf_stream *stream, char __user *buf, size_t count, size_t *offset)¶
將所有緩衝的 OA 報告複製到使用者空間 read() 緩衝區。
引數
struct i915_perf_stream *stream為 OA 指標開啟的 i915-perf 流
char __user *buf使用者空間給出的目標緩衝區
size_t count使用者空間希望讀取的位元組數
size_t *offset(輸入/輸出):寫入 buf 的當前位置
描述
值得注意的是,即使可能已成功複製了一個或多個記錄,也會返回導致短讀取的任何錯誤情況(-ENOSPC 或 -EFAULT)。 在這種情況下,由呼叫者決定是否應在返回到使用者空間之前消除該錯誤。
注意
報告從頭部消耗,並附加到尾部,因此尾部追逐頭部?...如果您認為這很瘋狂並且前後顛倒,那麼您並不孤單,但這遵循 Gen PRM 命名約定。
返回
成功時為 0,失敗時為負錯誤程式碼。
-
int gen7_oa_read(struct i915_perf_stream *stream, char __user *buf, size_t count, size_t *offset)¶
複製狀態記錄,然後複製緩衝的 OA 報告
引數
struct i915_perf_stream *stream為 OA 指標開啟的 i915-perf 流
char __user *buf使用者空間給出的目標緩衝區
size_t count使用者空間希望讀取的位元組數
size_t *offset(輸入/輸出):寫入 buf 的當前位置
描述
檢查 Gen 7 特定 OA 單元狀態暫存器,並在必要時將相應的狀態記錄附加到使用者空間(例如,對於緩衝區滿條件),然後啟動附加任何緩衝的 OA 報告。
根據成功複製到使用者空間緩衝區的位元組數更新 offset。
返回
成功時返回零,如果失敗,則返回負錯誤程式碼
-
int oa_get_render_ctx_id(struct i915_perf_stream *stream)¶
確定並保持 ctx hw id
引數
struct i915_perf_stream *stream為 OA 指標開啟的 i915-perf 流
描述
確定渲染上下文硬體 ID,並確保在流的生命週期內保持固定。 這確保了我們不必擔心在執行時更新 OACONTROL 中的上下文 ID。
返回
成功時返回零,如果失敗,則返回負錯誤程式碼
-
void oa_put_render_ctx_id(struct i915_perf_stream *stream)¶
oa_get_render_ctx_id 的對應項釋放保持
引數
struct i915_perf_stream *stream為 OA 指標開啟的 i915-perf 流
描述
如果需要執行任何操作以確保上下文 HW ID 在流的生命週期內保持有效,則可以在此處撤消該操作。
-
long i915_perf_ioctl_locked(struct i915_perf_stream *stream, unsigned int cmd, unsigned long arg)¶
支援 i915 perf 流 FD 的 ioctl() 用法
引數
struct i915_perf_stream *streami915 perf 流
unsigned int cmdioctl 請求
unsigned long argioctl 資料
返回
成功時返回零,如果失敗,則返回負錯誤程式碼。對於未知 ioctl 請求,返回 -EINVAL。
-
int i915_perf_ioctl_version(struct drm_i915_private *i915)¶
i915-perf 子系統的版本
引數
struct drm_i915_private *i915i915 裝置
描述
使用者空間使用此版本號來檢測可用功能。
樣式¶
除了核心編碼樣式之外(在某些情況下,與核心編碼樣式有所不同),drm/i915 驅動程式程式碼庫還有一些樣式規則。
暫存器宏定義樣式¶
i915_reg.h 的樣式指南。
對於新宏,請遵循此處描述的樣式,並在更改現有宏時進行操作。 **不要** 批次更改現有定義,只是為了更新樣式。
檔案佈局¶
將幫助程式宏放在頂部附近。 例如,_PIPE() 及其朋友。
對於通常不應在此檔案外部使用的宏,請使用下劃線“_”作為字首。 例如,_PIPE() 及其朋友,僅為函式式宏使用的單個暫存器例項。
避免在此檔案外部使用下劃線字首的宏。 有例外情況,但請儘量減少。
有兩種基本型別的暫存器定義:單個暫存器和暫存器組。 暫存器組是具有兩個或多個例項的暫存器,例如每個管道、埠、轉碼器等一個例項。 暫存器組應使用函式式宏定義。
對於單個暫存器,請先定義暫存器偏移量,然後再定義暫存器內容。
對於暫存器組,請先定義暫存器例項偏移量,並以下劃線作為字首,然後定義一個函式式宏,該宏根據引數選擇正確的例項,然後再定義暫存器內容。
從最高有效位到最低有效位定義暫存器內容(即,位和位域宏)。 使用 #define 和宏名稱之間兩個額外的空格來縮排暫存器內容宏。
使用 REG_GENMASK(h, l) 定義位欄位。 使用 REG_FIELD_PREP(mask, value) 定義位欄位內容。 這將定義已就位的移位值,因此可以直接將它們 OR 在一起。 為了方便起見,可以使用函式式宏來定義位欄位,但請注意,這些宏可能需要讀取以及寫入暫存器內容。
使用 REG_BIT(N) 定義位。 **不要** 將 _BIT 字尾新增到名稱。
將暫存器及其內容組合在一起,無需空行,並用一個空行與其他暫存器及其內容分隔開。
使用 TAB 從宏名稱縮排宏值。 垂直對齊值。 根據需要使用宏值中的大括號,以避免宏替換後出現意外的優先順序。 根據核心編碼樣式使用宏值中的空格。 在十六進位制值中使用小寫字母。
命名¶
嘗試根據規範命名暫存器。 如果規範中暫存器名稱從一個平臺更改為另一個平臺,請堅持使用原始名稱。
嘗試重用現有暫存器宏定義。 僅為新的暫存器偏移量新增新宏,或者當暫存器內容已更改到足以保證完全重新定義時。
當新平臺更改暫存器宏時,請使用平臺首字母縮寫或生成來為新宏新增字首。 例如,SKL_ 或 GEN8_。 字首表示使用該暫存器的起始平臺/生成。
當新平臺更改或新增位(欄位)宏時,同時保留現有暫存器宏,請將平臺首字母縮寫或生成字尾新增到名稱。 例如,_SKL 或 _GEN8。
示例¶
(請注意,示例中的值使用空格而不是 TAB 縮排,以避免在生成的文件中出現錯位。 在定義中使用 TAB。)
#define _FOO_A 0xf000
#define _FOO_B 0xf001
#define FOO(pipe) _MMIO_PIPE(pipe, _FOO_A, _FOO_B)
#define FOO_ENABLE REG_BIT(31)
#define FOO_MODE_MASK REG_GENMASK(19, 16)
#define FOO_MODE_BAR REG_FIELD_PREP(FOO_MODE_MASK, 0)
#define FOO_MODE_BAZ REG_FIELD_PREP(FOO_MODE_MASK, 1)
#define FOO_MODE_QUX_SNB REG_FIELD_PREP(FOO_MODE_MASK, 2)
#define BAR _MMIO(0xb000)
#define GEN8_BAR _MMIO(0xb888)
i915 DRM 客戶端使用情況統計資訊實現¶
drm/i915 驅動程式實現了 DRM 客戶端使用情況統計資訊規範,如 DRM 客戶端使用情況統計資訊 中所述。
輸出示例顯示了已實現的鍵值對和當前可能的格式選項的全部內容
pos: 0
flags: 0100002
mnt_id: 21
drm-driver: i915
drm-pdev: 0000:00:02.0
drm-client-id: 7
drm-engine-render: 9288864723 ns
drm-engine-copy: 2035071108 ns
drm-engine-video: 0 ns
drm-engine-capacity-video: 2
drm-engine-video-enhance: 0 ns
可能的 drm-engine- 鍵名稱為:render、copy、video 和 video-enhance。