linux/rust/kernel/drm/gpuvm/vm_bo.rs
Linus Torvalds 4e69c1856b drm for 7.3-rc1
perf:
 - export perf_allow_ APIs for xe
 
 udmabuf:
 - remove default size limit of 64MB
 
 rust:
 - i/o rework (signed tag from driver-core tree)
 - add registration guard and registration data
 - fix unbounded lifetimes in ioctl handler args
 - fix a drm_dev_register race
 - gem_shmem: add DmaResvGuard helper
 - gpuvm: require send/sync for driver data
   - implement send/sync for GpuVaAlloc and GpuVmBo
   - add SmContext lifetime
 - rename dma_handle to dma_address
 - change pci_sriov_get_totalvfs return to unsigned int
 
 core:
 - create drm_of_get_panel_orientation
 - send per-connector hotplug events
 - add thunderbolt UBHR tunneling support
 
 connector:
 - add color format property
 
 dmem:
 - introduce a peak file
 - accept one region per limit
 - add dmemcg support for eviction
 
 gpusvm:
 - reorg code to give drivers more flexibility
 
 atomic:
 - add create_state callback and helper
 - add documentation on atomic commit lifetime
 
 buddy:
 - add per-order free
 - add used block scoreboard
 - fix UAF
 - test buffer clearance on resume
 - add phys_addr->block helper
 
 gem:
 - drop DRIVER_GEM_GPUVA flag
 
 ttm:
 - be more aggressive allocating below protection limit
 
 sched:
 - add test suite for concurrent job submissions
 
 hdmi:
 - hook the color format property in helpers
 
 mipi-dsi:
 - add MIPI_DSI_MODE_DSC_ALL_SLICES_IN_PKT
 
 bridge:
 - add atomic create callbacks
 - drop atomic reset
 - display-connector: don't autoenable HPD IRQ
 - trigger initial HPD for DP
 - ti-sn65dsi83: remove NO_HFP and NO_HBP mode flags
 - analogix_dp: switch to DP link training helpers
 
 dp:
 - add support for DSC max delta BPP
 
 edid:
 - parse panel type from DisplayID 2.x Display Parameters
 
 sysfb:
 - improve panel, stride, framebuffer size validation
 
 panel:
 - implement ref counting for struct drm_panel
 - himax-hx83121a: add backlight regulator support
 - novatek-nt36672a: Inline panel init sequences
 - visionox-vtdr6130: enable DSC
 - novatek-nt37801: Use mipi_dsi_*_multi() functions
 - samsung-s6d16d0: Fix prepare error handling
 - support Novatek NT36536 plus DT bindings
 - sofef00: fix backlight updates
 - osd101t2587: use mipi_dsi_*_multi interface
 - panel-edp: adjust timing for AUO displays
 - panel-lvds: support Opto Logic SCX1001511GGC49
 - panel-simple: support Kyocera tcg070wvlq
 - panel-edp: quirks
   - AUO B116XAT04.3, CMN N116BCP-EA2, CSW MNB601LS1-8
   - BOE NV116WH2-M30, BOE NT116WHM-N21, BOE NV116FH1-M31
   - BOE NV116FH1-M30, NV140FHM-N5B, TM156VDXP25
   - BOE NE160QDM-NY1, MB116AS01
 - new:
   - Samsung ATNA40HQ08-0, Anbernic TD4310
   - Chipone ICNA35XX, Ilitek ILI9488
   - Ilitek ILI7807S, Renesas R63419
   - MNE001BS6-2, MNF601BS4-1, Sharp LQ120P1JX51
 
 virtio:
 - add support for save/restore virtio_gpu_objects
 - abort vq wait on device removal
 
 amdgpu:
 - add color format DRM property
 - initial compute pipe reset support
 - add GFX 6-8 modifier support
 - initial DCN 6.0.0 support
 - dmemcg eviction support
 - improved boundary checking for bios parsing
 - RAS updates and rework
 - VCN secure submission fixes
 - 8K panel fix
 - Display KUNIT tests
 - parse panel type from DisplayID
 - Align IP discovery to pci device lifetime
 - SOC15 register macro cleanups
 - UVD memory placement fixes
 - GFX9 mode2 reset fixes
 - drop unnecessary BUG/BUG_ON
 - GFX8 soft reset rework
 - enable soft reset on GFX8
 - PSP/SMU 15.0.9 update
 - VI ASPM fix
 - userq fixes
 - amdgpu_vm_get_task_info_pasid lifetime fix
 - DC CACP support
 - change system_unbound_wq with system_dfl_wq
 - Loosen VFCT bios parsing to deal with pci=realloc
 - SI/SMU7 AC/DC switch fix
 - VM fence handling fix
 - GEM close optimisation
 - Apple Studio Display fixes
 - DC FRL fixes
 
 amdkfd:
 - initial compute pipe reset support
 - allow applications to opt out of sigbus on fatal errors
 - improve CRIU boundary checks
 - MQD handling rework
 - move TBA/TMA from system to device memory
 - avoid topology-lock in kfd_mmap
 - SVM eviction fixes
 
 radeon:
 - fix unset CONFIG_ACPI build
 
 i915:
 - Novalake (NVL display version 35) timing generator enabling
 - NVL DC3CO enabling
 - enable UBHR link rates on thunderbolt tunnels
 - Reduce Xe3+ PM demand peak bandwidth
 - enable pipe DMC error interrupts for display 30+
 - add kunit tests for DP link config selection
 - refactor and document DP link recovery
 - i915/xe driver display probe/remove/suspend/resume/shutdown cleanup and unification
 - i915/xe display runtime PM unified
 - Break i915 and xe panic dependency on struct intel_framebuffer
 - Streamline Pre/Post-CSC LUT loops
 - drop TGL DC3DO support
 - CDCLK santization
 - fix HDMI scrambling enable
 - fix phys bo pread/pwrite with offset
 - add missing nospec on parallel submit slot
 - fix some NULL derefs
 
 xe:
 - drop force_execlist module param
 - gate observation streams with perf_allow_cpu
 - skip FORCE_WC and vm_bound check for external dma-bufs
 - dmemcg eviction support
 - remove unused NVL-S GuC
 - TLB invalidation improvements
 - NVL-S updated PCI-IDs and w/a
 - madvise: optimise invalidation path
 - fix infinite gt-reset loop in timeout recovery
 - update TTM device benefical_order
 - wait on external BO kernel fences in exec ioctl
 - add/use more KLV helpers
 - sriov: disable display in admin only PF mode
 - add RAS GPU health indicator
 - optimise TTM populate for DONTNEED BO
 - drop force_probe for NVL-s
 - add debugfs for pcode info
 
 amdxdna:
 - disable device buffer export
 
 nova:
 - build nova-core/nova-drm from drivers/gpu
 - export nova-core rust symbols (workaround)
 - GSP boot process consolidation
 - Boot GSP with vGPU enabled
 - TLV firmware image format support
 - Hopper/Blackwell fixes and cleanups
 - I/O projection adoption
 
 tyr:
 - firmware loading and MCU boot
 - add generic slot manager + MMU
 - GPU VM support ARM64 LPAE page tables
 - add kernel buffer object for internal allocations
 - add parser for Mali CSF
 - add MCU booting
 
 nouveau:
 - race fixes
 - check instmem iomapping at first use
 - add dmemcg support
 - expose NVDEC channels
 - add scanline position/head state support for GSP
 
 qxl:
 - convert simple encoder to regular
 
 ethosu:
 - add perf counter support
 
 etnaviv:
 - force flush on power register ops
 
 msm:
 - support DSC configuration with slice_per_pkt > 1
 
 mxsfb:
 - fix disable sequence
 
 panthor:
 - support sparse mappings
 
 rockchip:
 - switch away from simple helpers
 - support YUV background color
 - fix layer config timeout
 - add edp support for rk3576
 - add batch command submission function
 
 rocket:
 - error handling and NULL ptr deref fixes
 
 sun4i:
 - switch away from simple helpers
 
 imagination:
 - mark BXM-4-64 MC1 as support
 
 host1x:
 - support tegra264
 
 tegra:
 - add DSI for tegra 20/30
 
 v3d:
 - reduce PM runtime autosuspend delay
 - scheduler fixes and refactoring
 - deprecate v3d 3.3 and 4.1
 - validate CPU job query boundaries
 
 hibmc:
 - improve plane format handling
 - switch to gem shmem
 
 mediatek:
 - cec: correct compat for mt7623-8167?
 
 exynos:
 - remove simple dependency
 - add error handling to encoder paths
 - take i2c adapter module reference
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEEKbZHaGwW9KfbeusDHTzWXnEhr4FAmqGlb0ACgkQDHTzWXnE
 hr7l9A//TnfntEghigEEFobfJX+p9FzaOTPPia8paooAj52OBK8Z86WpbYwEo4K9
 X+vPXPYpqgKSiGkkC33swAlylWs2v3JoZQ+CESERBk176Ql3ZKhicBINH+k8jIcX
 uaFoDgpgMoV1JCcvF/m48de8YRcejSN43rIucS0aIH5/r/YEyRsE4d4dzCXw/qD8
 92tjbmH20mChfeo8MUNatZx+t8ssSOrVdqouLmmFB8tYTcca6qwN60uA+9VESVtd
 nZLCEiZD0FUI73oT7fmK/zL2rTb2pZRPFNdz0mb6f7UUpu7f8RYnroHrNsGa/FHl
 K5RD1/gSVpfc6CbrhPnePaRKvIGeEC4ief8YRRyeoNVT3cmkf+citpOoKN2JajF1
 bub/ni2z1FGA3y1ckJb4Z6HmGHt5gki/KoAKCmZkJ7bb7WJq/JHMWEFfq4LuNjTA
 FSSxPozM4pb69DL02wwRJIEe8cYcc/gVTgrSkzR/tsVUoE6XI4AwZJ/Exa43+jVe
 hjNkAOMrl/+ma/WGQ4BPUVeTRPZP6RlNM4cSWvG1YA2Pf6+O+XLjukac6t+Ozj0X
 Fz1ePqYxELKSOYkZKxdpxRDyzY6SxvtyDHfHblo4p+BUvaXKP4wfNRexXETD6Qow
 P7rqYN6riDMRPI9CoPd25V7cbfYbvoV0iJzv3EQwU3pvB9Vu1ho=
 =TGZ1
 -----END PGP SIGNATURE-----

Merge tag 'drm-next-2026-08-20' of https://gitlab.freedesktop.org/drm/kernel

Pull drm updates from Dave Airlie:
 "Highlights:

   - dmemcg eviction support is good for low VRAM things like Steam
     Machine

   - AMD adds gfx6-8 modifier support for older GPUs that enables a
     bunch of wayland stuff

   - i915/xe has some new hw support but also a lot of display
     refactoring

  Everything:

  perf:
   - export perf_allow_ APIs for xe

  udmabuf:
   - remove default size limit of 64MB

  rust:
   - i/o rework (signed tag from driver-core tree)
   - add registration guard and registration data
   - fix unbounded lifetimes in ioctl handler args
   - fix a drm_dev_register race
   - gem_shmem: add DmaResvGuard helper
   - gpuvm: require send/sync for driver data
       - implement send/sync for GpuVaAlloc and GpuVmBo
       - add SmContext lifetime
   - rename dma_handle to dma_address
   - change pci_sriov_get_totalvfs return to unsigned int

  core:
   - create drm_of_get_panel_orientation
   - send per-connector hotplug events
   - add thunderbolt UBHR tunneling support

  connector:
   - add color format property

  dmem:
   - introduce a peak file
   - accept one region per limit
   - add dmemcg support for eviction

  gpusvm:
   - reorg code to give drivers more flexibility

  atomic:
   - add create_state callback and helper
   - add documentation on atomic commit lifetime

  buddy:
   - add per-order free
   - add used block scoreboard
   - fix UAF
   - test buffer clearance on resume
   - add phys_addr->block helper

  gem:
   - drop DRIVER_GEM_GPUVA flag

  ttm:
   - be more aggressive allocating below protection limit

  sched:
   - add test suite for concurrent job submissions

  hdmi:
   - hook the color format property in helpers

  mipi-dsi:
   - add MIPI_DSI_MODE_DSC_ALL_SLICES_IN_PKT

  bridge:
   - add atomic create callbacks
   - drop atomic reset
   - display-connector: don't autoenable HPD IRQ
   - trigger initial HPD for DP
   - ti-sn65dsi83: remove NO_HFP and NO_HBP mode flags
   - analogix_dp: switch to DP link training helpers

  dp:
   - add support for DSC max delta BPP

  edid:
   - parse panel type from DisplayID 2.x Display Parameters

  sysfb:
   - improve panel, stride, framebuffer size validation

  panel:
   - implement ref counting for struct drm_panel
   - himax-hx83121a: add backlight regulator support
   - novatek-nt36672a: Inline panel init sequences
   - visionox-vtdr6130: enable DSC
   - novatek-nt37801: Use mipi_dsi_*_multi() functions
   - samsung-s6d16d0: Fix prepare error handling
   - support Novatek NT36536 plus DT bindings
   - sofef00: fix backlight updates
   - osd101t2587: use mipi_dsi_*_multi interface
   - panel-edp: adjust timing for AUO displays
   - panel-lvds: support Opto Logic SCX1001511GGC49
   - panel-simple: support Kyocera tcg070wvlq
   - panel-edp: quirks
       - AUO B116XAT04.3, CMN N116BCP-EA2, CSW MNB601LS1-8
       - BOE NV116WH2-M30, BOE NT116WHM-N21, BOE NV116FH1-M31
       - BOE NV116FH1-M30, NV140FHM-N5B, TM156VDXP25
       - BOE NE160QDM-NY1, MB116AS01
   - new:
       - Samsung ATNA40HQ08-0, Anbernic TD4310
       - Chipone ICNA35XX, Ilitek ILI9488
       - Ilitek ILI7807S, Renesas R63419
       - MNE001BS6-2, MNF601BS4-1, Sharp LQ120P1JX51

  virtio:
   - add support for save/restore virtio_gpu_objects
   - abort vq wait on device removal

  amdgpu:
   - add color format DRM property
   - initial compute pipe reset support
   - add GFX 6-8 modifier support
   - initial DCN 6.0.0 support
   - dmemcg eviction support
   - improved boundary checking for bios parsing
   - RAS updates and rework
   - VCN secure submission fixes
   - 8K panel fix
   - Display KUNIT tests
   - parse panel type from DisplayID
   - Align IP discovery to pci device lifetime
   - SOC15 register macro cleanups
   - UVD memory placement fixes
   - GFX9 mode2 reset fixes
   - drop unnecessary BUG/BUG_ON
   - GFX8 soft reset rework
   - enable soft reset on GFX8
   - PSP/SMU 15.0.9 update
   - VI ASPM fix
   - userq fixes
   - amdgpu_vm_get_task_info_pasid lifetime fix
   - DC CACP support
   - change system_unbound_wq with system_dfl_wq
   - Loosen VFCT bios parsing to deal with pci=realloc
   - SI/SMU7 AC/DC switch fix
   - VM fence handling fix
   - GEM close optimisation
   - Apple Studio Display fixes
   - DC FRL fixes

  amdkfd:
   - initial compute pipe reset support
   - allow applications to opt out of sigbus on fatal errors
   - improve CRIU boundary checks
   - MQD handling rework
   - move TBA/TMA from system to device memory
   - avoid topology-lock in kfd_mmap
   - SVM eviction fixes

  radeon:
   - fix unset CONFIG_ACPI build

  i915:
   - Novalake (NVL display version 35) timing generator enabling
   - NVL DC3CO enabling
   - enable UBHR link rates on thunderbolt tunnels
   - Reduce Xe3+ PM demand peak bandwidth
   - enable pipe DMC error interrupts for display 30+
   - add kunit tests for DP link config selection
   - refactor and document DP link recovery
   - i915/xe driver display probe/remove/suspend/resume/shutdown cleanup
     and unification
   - i915/xe display runtime PM unified
   - Break i915 and xe panic dependency on struct intel_framebuffer
   - Streamline Pre/Post-CSC LUT loops
   - drop TGL DC3DO support
   - CDCLK santization
   - fix HDMI scrambling enable
   - fix phys bo pread/pwrite with offset
   - add missing nospec on parallel submit slot
   - fix some NULL derefs

  xe:
   - drop force_execlist module param
   - gate observation streams with perf_allow_cpu
   - skip FORCE_WC and vm_bound check for external dma-bufs
   - dmemcg eviction support
   - remove unused NVL-S GuC
   - TLB invalidation improvements
   - NVL-S updated PCI-IDs and w/a
   - madvise: optimise invalidation path
   - fix infinite gt-reset loop in timeout recovery
   - update TTM device benefical_order
   - wait on external BO kernel fences in exec ioctl
   - add/use more KLV helpers
   - sriov: disable display in admin only PF mode
   - add RAS GPU health indicator
   - optimise TTM populate for DONTNEED BO
   - drop force_probe for NVL-s
   - add debugfs for pcode info

  amdxdna:
   - disable device buffer export

  nova:
   - build nova-core/nova-drm from drivers/gpu
   - export nova-core rust symbols (workaround)
   - GSP boot process consolidation
   - Boot GSP with vGPU enabled
   - TLV firmware image format support
   - Hopper/Blackwell fixes and cleanups
   - I/O projection adoption

  tyr:
   - firmware loading and MCU boot
   - add generic slot manager + MMU
   - GPU VM support ARM64 LPAE page tables
   - add kernel buffer object for internal allocations
   - add parser for Mali CSF
   - add MCU booting

  nouveau:
   - race fixes
   - check instmem iomapping at first use
   - add dmemcg support
   - expose NVDEC channels
   - add scanline position/head state support for GSP

  qxl:
   - convert simple encoder to regular

  ethosu:
   - add perf counter support

  etnaviv:
   - force flush on power register ops

  msm:
   - support DSC configuration with slice_per_pkt > 1

  mxsfb:
   - fix disable sequence

  panthor:
   - support sparse mappings

  rockchip:
   - switch away from simple helpers
   - support YUV background color
   - fix layer config timeout
   - add edp support for rk3576
   - add batch command submission function

  rocket:
   - error handling and NULL ptr deref fixes

  sun4i:
   - switch away from simple helpers

  imagination:
   - mark BXM-4-64 MC1 as support

  host1x:
   - support tegra264

  tegra:
   - add DSI for tegra 20/30

  v3d:
   - reduce PM runtime autosuspend delay
   - scheduler fixes and refactoring
   - deprecate v3d 3.3 and 4.1
   - validate CPU job query boundaries

  hibmc:
   - improve plane format handling
   - switch to gem shmem

  mediatek:
   - cec: correct compat for mt7623-8167?

  exynos:
   - remove simple dependency
   - add error handling to encoder paths
   - take i2c adapter module reference"

* tag 'drm-next-2026-08-20' of https://gitlab.freedesktop.org/drm/kernel: (2074 commits)
  drm/xe/mcr: Take vcs1/vecs1 into account for first media slice
  drm/xe: Fix a bug in pc_adjust_freq_bounds()
  drm/xe: Fix xe_device_probe() failure
  drm/xe/drm_ras: Move has_drm_ras check to drm_ras layer
  drm/xe/ras: Fix boot-time ras error processing
  drm/amd/display: make DC_RUN_WITH_PREEMPTION_ENABLED misuse a build error
  drm/amd/pm: silence uninitialized variable warnings
  drm/amdgpu: skip BOs being torn down during GTT recovery
  drm/amdgpu: Reject UVD message with invalid number of h265 refs
  drm/amdgpu: keep PRT mappings off the vm_bo state lists
  drm/amdgpu: fix nbif 6.3.1 l1 low power not functional
  drm/amd/display: fix BT.2020 YCbCr output CSC matrices for DCE
  drm/amd/display: fix BT.2020 YCbCr limited output CSC matrix
  drm/amdgpu: Implement insert_end for VCE 3
  drm/amdgpu: Fix UVD min buffer sizes
  drm/amdgpu: Fix UVD decode image min size calculation
  drm/amdgpu: Fix UVD dpb min size calculation for H264
  drm/amdgpu: Reject UVD message with dimensions above 4096
  drm/amdgpu: check ASPM on the dGPU host link
  drm/radeon: fix autosuspend cleanup during teardown
  ...
2026-08-21 08:41:00 -07:00

259 lines
10 KiB
Rust

// SPDX-License-Identifier: GPL-2.0 OR MIT
use super::*;
/// Represents that a given GEM object has at least one mapping on this [`GpuVm`] instance.
///
/// Does not assume that GEM lock is held.
///
/// # Invariants
///
/// * Allocated with `kmalloc` and refcounted via `inner`.
/// * Is present in the gem list.
#[repr(C)]
#[pin_data]
pub struct GpuVmBo<T: DriverGpuVm> {
#[pin]
inner: Opaque<bindings::drm_gpuvm_bo>,
#[pin]
data: T::VmBoData,
}
// SAFETY: It is safe to send a `GpuVmBo<T>` to another thread: dropping it there drops
// `T::VmBoData` and the GEM `T::Object`, both `Send` by the `DriverGpuVm` bounds.
unsafe impl<T: DriverGpuVm> Send for GpuVmBo<T> {}
// SAFETY: It is safe to share a `&GpuVmBo<T>` between threads: it effectively shares
// `&T::VmBoData` and the GEM `&T::Object` (both `Sync`), and any thread may upgrade to an
// `ARef` and ultimately drop them (both `Send`), per the `DriverGpuVm` bounds.
unsafe impl<T: DriverGpuVm> Sync for GpuVmBo<T> {}
// SAFETY: By type invariants, the allocation is managed by the refcount in `self.inner`.
unsafe impl<T: DriverGpuVm> AlwaysRefCounted for GpuVmBo<T> {
fn inc_ref(&self) {
// SAFETY: By type invariants, the allocation is managed by the refcount in `self.inner`.
unsafe { bindings::drm_gpuvm_bo_get(self.inner.get()) };
}
unsafe fn dec_ref(obj: NonNull<Self>) {
// CAST: `drm_gpuvm_bo` is first field of repr(C) struct.
// SAFETY: By type invariants, the allocation is managed by the refcount in `self.inner`.
// This GPUVM instance uses immediate mode, so we may put the refcount using the deferred
// mechanism.
unsafe { bindings::drm_gpuvm_bo_put_deferred(obj.as_ptr().cast()) };
}
}
impl<T: DriverGpuVm> PartialEq for GpuVmBo<T> {
#[inline]
fn eq(&self, other: &Self) -> bool {
core::ptr::eq(self.as_raw(), other.as_raw())
}
}
impl<T: DriverGpuVm> Eq for GpuVmBo<T> {}
impl<T: DriverGpuVm> GpuVmBo<T> {
/// The function pointer for allocating a GpuVmBo stored in the gpuvm vtable.
///
/// Allocation is always implemented according to [`Self::vm_bo_alloc`], but it is set to
/// `None` if the default gpuvm behavior is the same as `vm_bo_alloc`.
///
/// This may be `Some` even if `FREE_FN` is `None`, or vice-versa.
pub(super) const ALLOC_FN: Option<unsafe extern "C" fn() -> *mut bindings::drm_gpuvm_bo> = {
use core::alloc::Layout;
let base = Layout::new::<bindings::drm_gpuvm_bo>();
let rust = Layout::new::<Self>();
assert!(base.size() <= rust.size());
if base.size() != rust.size() || base.align() != rust.align() {
Some(Self::vm_bo_alloc)
} else {
// This causes GPUVM to allocate a `GpuVmBo<T>` with `kzalloc(sizeof(drm_gpuvm_bo))`.
None
}
};
/// The function pointer for freeing a GpuVmBo stored in the gpuvm vtable.
///
/// Freeing is always implemented according to [`Self::vm_bo_free`], but it is set to `None` if
/// the default gpuvm behavior is the same as `vm_bo_free`.
///
/// This may be `Some` even if `ALLOC_FN` is `None`, or vice-versa.
pub(super) const FREE_FN: Option<unsafe extern "C" fn(*mut bindings::drm_gpuvm_bo)> = {
if core::mem::needs_drop::<Self>() {
Some(Self::vm_bo_free)
} else {
// This causes GPUVM to free a `GpuVmBo<T>` with `kfree`.
None
}
};
/// Custom function for allocating a `drm_gpuvm_bo`.
///
/// # Safety
///
/// Always safe to call.
unsafe extern "C" fn vm_bo_alloc() -> *mut bindings::drm_gpuvm_bo {
let raw_ptr = KBox::<Self>::new_uninit(GFP_KERNEL | __GFP_ZERO)
.map(KBox::into_raw)
.unwrap_or(ptr::null_mut());
// CAST: `drm_gpuvm_bo` is first field of `Self`.
raw_ptr.cast()
}
/// Custom function for freeing a `drm_gpuvm_bo`.
///
/// # Safety
///
/// The pointer must have been allocated with [`GpuVmBo::ALLOC_FN`], and must not be used after
/// this call.
unsafe extern "C" fn vm_bo_free(ptr: *mut bindings::drm_gpuvm_bo) {
// CAST: `drm_gpuvm_bo` is first field of `Self`.
// SAFETY:
// * The ptr was allocated from kmalloc with the layout of `GpuVmBo<T>`.
// * `ptr->inner` has no destructor.
// * `ptr->data` contains a valid `T::VmBoData` that we can drop.
drop(unsafe { KBox::<Self>::from_raw(ptr.cast()) });
}
/// Access this [`GpuVmBo`] from a raw pointer.
///
/// # Safety
///
/// For the duration of `'a`, the pointer must reference a valid `drm_gpuvm_bo` associated with
/// a [`GpuVm<T>`]. The BO must also be present in the GEM list.
#[inline]
pub(crate) unsafe fn from_raw<'a>(ptr: *mut bindings::drm_gpuvm_bo) -> &'a Self {
// SAFETY: `drm_gpuvm_bo` is first field and `repr(C)`.
unsafe { &*ptr.cast() }
}
/// Returns a raw pointer to underlying C value.
#[inline]
pub fn as_raw(&self) -> *mut bindings::drm_gpuvm_bo {
self.inner.get()
}
/// The [`GpuVm`] that this GEM object is mapped in.
#[inline]
pub fn gpuvm(&self) -> &GpuVm<T> {
// SAFETY: The `obj` pointer is guaranteed to be valid.
unsafe { GpuVm::<T>::from_raw((*self.inner.get()).vm) }
}
/// The [`drm_gem_object`](DriverGpuVm::Object) for these mappings.
#[inline]
pub fn obj(&self) -> &T::Object {
// SAFETY: The `obj` pointer is guaranteed to be valid.
unsafe { <T::Object as IntoGEMObject>::from_raw((*self.inner.get()).obj) }
}
/// The driver data with this buffer object.
#[inline]
pub fn data(&self) -> &T::VmBoData {
&self.data
}
pub(super) fn lock_gpuva(&self) -> crate::sync::MutexGuard<'_, ()> {
// SAFETY: The GEM object is valid.
let ptr = unsafe { &raw mut (*self.obj().as_raw()).gpuva.lock };
// SAFETY: The GEM object is valid, so the mutex is properly initialized.
let mutex = unsafe { crate::sync::Mutex::from_raw(ptr) };
mutex.lock()
}
}
/// A pre-allocated [`GpuVmBo`] object.
///
/// # Invariants
///
/// Points at a `drm_gpuvm_bo` that contains a valid `T::VmBoData`, has a refcount of one, and is
/// absent from any gem, extobj, or evict lists.
pub(super) struct GpuVmBoAlloc<T: DriverGpuVm>(NonNull<GpuVmBo<T>>);
impl<T: DriverGpuVm> GpuVmBoAlloc<T> {
/// Create a new pre-allocated [`GpuVmBo`].
///
/// It's intentional that the initializer is infallible because `drm_gpuvm_bo_put` will call
/// drop on the data, so we don't have a way to free it when the data is missing.
#[inline]
pub(super) fn new(
gpuvm: &GpuVm<T>,
gem: &T::Object,
value: impl PinInit<T::VmBoData>,
) -> Result<GpuVmBoAlloc<T>, AllocError> {
// CAST: `GpuVmBoAlloc::vm_bo_alloc` ensures that this memory was allocated with the layout
// of `GpuVmBo<T>`. The type is repr(C), so `container_of` is not required.
// SAFETY: The provided gpuvm and gem ptrs are valid for the duration of this call.
let raw_ptr = unsafe {
bindings::drm_gpuvm_bo_create(gpuvm.as_raw(), gem.as_raw()).cast::<GpuVmBo<T>>()
};
let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?;
// SAFETY: `ptr->data` is a valid pinned location.
unsafe { pin_init::raw_init(&raw mut (*raw_ptr).data, value) };
// INVARIANTS: We just created the vm_bo so it's absent from lists, and the data is valid
// as we just initialized it.
Ok(GpuVmBoAlloc(ptr))
}
/// Returns a raw pointer to underlying C value.
#[inline]
pub(super) fn as_raw(&self) -> *mut bindings::drm_gpuvm_bo {
// SAFETY: The pointer references a valid `drm_gpuvm_bo`.
unsafe { (*self.0.as_ptr()).inner.get() }
}
/// Look up whether there is an existing [`GpuVmBo`] for this gem object.
///
/// The caller should not hold the GEM mutex or DMA resv lock.
#[inline]
pub(super) fn obtain(self) -> ARef<GpuVmBo<T>> {
let me = ManuallyDrop::new(self);
// SAFETY: Valid `drm_gpuvm_bo` not already in the lists. We do not access `me` after this
// call.
let ptr = unsafe { bindings::drm_gpuvm_bo_obtain_prealloc(me.as_raw()) };
// SAFETY: `drm_gpuvm_bo_obtain_prealloc` always returns a non-null ptr
let nonnull = unsafe { NonNull::new_unchecked(ptr.cast()) };
// INVARIANTS: `drm_gpuvm_bo_obtain_prealloc` ensures that the bo is in the GEM list.
// SAFETY: We received one refcount from `drm_gpuvm_bo_obtain_prealloc`.
let ret = unsafe { ARef::<GpuVmBo<T>>::from_raw(nonnull) };
// Ensure that external objects are in the extobj list.
//
// Note that we must call `extobj_add` even if `ptr != me` to avoid a race condition where
// we could end up using the extobj before the thread with `ptr == me` calls extobj_add.
if ret.gpuvm().is_extobj(ret.obj()) {
let resv_lock = ret.gpuvm().raw_resv();
// TODO: Use a proper lock guard here once a dma_resv lock abstraction exists.
// SAFETY: The GPUVM is still alive, so its resv lock is too.
unsafe { bindings::dma_resv_lock(resv_lock, ptr::null_mut()) };
// SAFETY: We hold the GPUVMs resv lock.
unsafe { bindings::drm_gpuvm_bo_extobj_add(ptr) };
// SAFETY: We took the lock, so we can unlock it.
unsafe { bindings::dma_resv_unlock(resv_lock) };
}
ret
}
}
impl<T: DriverGpuVm> Deref for GpuVmBoAlloc<T> {
type Target = GpuVmBo<T>;
#[inline]
fn deref(&self) -> &GpuVmBo<T> {
// SAFETY: By the type invariants we may deref while `Self` exists.
unsafe { self.0.as_ref() }
}
}
impl<T: DriverGpuVm> Drop for GpuVmBoAlloc<T> {
#[inline]
fn drop(&mut self) {
// TODO: Call drm_gpuvm_bo_destroy_not_in_lists() directly.
// SAFETY: It's safe to perform a deferred put in any context.
unsafe { bindings::drm_gpuvm_bo_put_deferred(self.as_raw()) };
}
}