drm_gpusvm 与 drm_pagemap 执行顺序分析
概述在 SVMShared Virtual Memory实现中drm_gpusvm和drm_pagemap分属两个不同的抽象层协同完成 GPU 对进程虚拟地址空间的共享访问。两者的执行顺序并非固定的先底层后上层而是根据操作场景有不同的编排方式。职责划分组件职责drm_pagemap底层内存操作页面迁移system↔device、设备内存分配、DMA 映射、数据拷贝、CPU PTE 维护drm_gpusvmRange 管理与 GPU 侧状态跟踪range 创建/查找、hmm_range_fault 获取页面、DMA 地址管理、notifier 序列号验证xe_svm驱动级编排决定迁移策略、调用上述两者、更新 GPU 页表、TLB 刷新核心原则drm_pagemap 改变页面的物理归属CPU PTE 层面drm_gpusvm 感知这些变化并管理 GPU 侧的映射状态。凡涉及页面归属变更的操作pagemap 必须先于 gpusvm 的hmm_range_fault()因为后者依赖 CPU 页表来确定页面的当前位置。场景一GPU Page Fault — 迁移到 VRAM当 GPU 访问尚未映射的地址且迁移策略要求迁移到设备内存时执行顺序为GPU Page Fault │ ├─ 1. drm_gpusvm_range_find_or_insert() [range 管理] │ 创建或查找覆盖故障地址的 svm_range │ 纯元数据操作不涉及实际内存 │ ├─ 2. drm_pagemap_populate_mm() [底层迁移] │ ├─ migrate_vma_setup() 获取源 CPU 页 │ ├─ ops-populate_devmem_pfn() 分配设备内存 │ ├─ drm_pagemap_migrate_map_pages() DMA 映射 CPU 页 │ ├─ ops-copy_to_devmem() 数据拷贝 system → device │ └─ migrate_vma_pages() 替换 CPU PTE 为 device_private │ 此时 CPU 页表已变更系统页 → device_private 页 │ ├─ 3. drm_gpusvm_range_get_pages() [获取页面状态] │ ├─ hmm_range_fault() 读取 CPU 页表现在看到 device_private 页 │ ├─ dpagemap-ops-device_map() DMA 映射设备页 │ └─ 更新 dma_addr[]设置 has_devmem_pagestrue │ ├─ 4. svm_range_update_gpu_range() [GPU 页表更新] │ 使用 dma_addr[] 填充 GPU 页表项 │ └─ 5. svm-flush_tlb() [TLB 刷新]关键约束步骤 2 必须在步骤 3 之前。代码注释明确说明Migration modifies the CPU page tables (replacing system PTEs with device_private PTEs), so it must happen before hmm_range_fault() in get_pages().如果顺序颠倒hmm_range_fault()将看到系统页而非设备页导致 GPU 映射指向错误的物理地址。迁移失败的回退步骤 2 失败不是致命错误流程继续执行步骤 3此时hmm_range_fault()看到的仍是系统页GPU 将通过 PCIe 访问系统内存作为回退方案。场景二GPU Page Fault — 不迁移系统内存当迁移策略不要求迁移或设备内存不可用时不涉及 drm_pagemapGPU Page Fault │ ├─ 1. drm_gpusvm_range_find_or_insert() [range 管理] │ ├─ 2. drm_gpusvm_range_get_pages() [获取页面] │ ├─ hmm_range_fault() 获取系统页 PFN │ ├─ dma_map_page() DMA 映射系统页 │ └─ 更新 dma_addr[]has_devmem_pagesfalse │ ├─ 3. svm_range_update_gpu_range() [GPU 页表更新] │ └─ 4. svm-flush_tlb()此场景下 drm_gpusvm 直接通过 HMM 和 DMA API 完成所有工作。场景三驱逐 — 从 VRAM 回到系统内存设备内存压力或 CPU 访问 device_private 页时触发驱逐Eviction Trigger (内存压力 / CPU 访问) │ ├─ 1. drm_pagemap_evict_to_ram() [底层驱逐] │ ├─ drm_pagemap_migrate_populate_ram_pfn() 分配系统页 │ ├─ ops-copy_to_ram() 数据拷贝 device → system │ └─ migrate_vma_pages() 恢复 CPU PTE 为系统页 │ 此时 CPU 页表已恢复device_private → 系统页 │ └─ 2. drm_gpusvm_range_unmap_pages() [清理 GPU 映射] ├─ dpagemap-ops-device_unmap() 解除设备页 DMA 映射 └─ 清除 has_dma_mapping / has_devmem_pages 标志关键约束步骤 1 必须先完成数据拷贝和 CPU PTE 恢复步骤 2 才能安全解除 GPU 侧映射否则可能丢失数据。场景四MMU Notifier 失效CPU 端 unmapCPU 端执行munmap()或部分 unmap 时MMU notifier 回调触发CPU munmap / unmap │ ├─ 1. svm_range_invalidate() [notifier 回调] │ 标记 range 失效记录 pending 操作 │ ├─ 2. drm_gpusvm_range_evict() [驱逐残留设备页] │ └─ 内部调用 drm_pagemap_evict_to_ram() 先迁移数据回系统 │ ├─ 3. drm_gpusvm_range_unmap_pages() [清理 GPU DMA 映射] │ └─ 4. drm_gpusvm_range_remove() [移除 range 元数据]执行顺序总结场景步骤 1步骤 2步骤 3Fault 迁移 VRAMgpusvm: 创建 rangepagemap: 迁移gpusvm: get_pagesFault 系统内存gpusvm: 创建 rangegpusvm: get_pages—驱逐回 RAMpagemap: 数据拷贝 恢复 PTEgpusvm: unmap—MMU invalidategpusvm: 标记失效pagemap: 驱逐gpusvm: unmap remove不变量Range 创建总是最先drm_gpusvm_range_find_or_insert()在所有实际内存操作之前因为它只是元数据管理。pagemap 的迁移操作总是在 gpusvm 的hmm_range_fault()之前因为后者依赖 CPU 页表反映当前页面位置。pagemap 的驱逐操作总是在 gpusvm 的 unmap 之前必须先完成数据拷贝再解除映射。GPU 页表更新在 notifier lock 内完成确保与 MMU notifier 回调的串行化。同步机制锁/机制保护范围svm-svm_lockrange 查找/创建、迁移决策gpusvm-notifier_lockGPU 页表更新、range 状态检查notifier_seq检测 get_pages 到 GPU 页表更新之间 CPU 页表是否变化mmap_read_lockhmm_range_fault 期间保护 VMA
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2480180.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!