From 1213cf25cd551a6dc57b5be9df35ccb955f0ab59 Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Fri, 10 May 2024 19:18:33 +0900 Subject: [PATCH] drm/asahi: file: Update to newer VM_BIND API Signed-off-by: Asahi Lina --- drivers/gpu/drm/asahi/file.rs | 141 +++++++++++++------------ drivers/gpu/drm/asahi/gpu.rs | 6 +- drivers/gpu/drm/asahi/mmu.rs | 28 +++-- drivers/gpu/drm/asahi/queue/compute.rs | 4 +- drivers/gpu/drm/asahi/queue/render.rs | 8 +- 5 files changed, 99 insertions(+), 88 deletions(-) diff --git a/drivers/gpu/drm/asahi/file.rs b/drivers/gpu/drm/asahi/file.rs index 5953cfeb72e17b..bb6b870ccb050a 100644 --- a/drivers/gpu/drm/asahi/file.rs +++ b/drivers/gpu/drm/asahi/file.rs @@ -9,8 +9,9 @@ use crate::debug::*; use crate::driver::AsahiDevice; -use crate::{alloc, buffer, driver, gem, mmu, queue}; +use crate::{alloc, buffer, driver, gem, mmu, queue, util::RangeExt}; use core::mem::MaybeUninit; +use core::ops::Range; use kernel::dma_fence::RawDmaFence; use kernel::drm::gem::BaseObject; use kernel::error::code::*; @@ -30,16 +31,29 @@ struct Vm { ualloc: Arc>, ualloc_priv: Arc>, vm: mmu::Vm, + kernel_range: Range, _dummy_mapping: mmu::KernelMapping, } impl Drop for Vm { fn drop(&mut self) { // When the user Vm is dropped, unmap everything in the user range - if self - .vm - .unmap_range(mmu::IOVA_USER_BASE, VM_USER_END) - .is_err() + let left_range = VM_USER_RANGE.start..self.kernel_range.start; + let right_range = self.kernel_range.end..VM_USER_RANGE.end; + + if !left_range.is_empty() + && self + .vm + .unmap_range(left_range.start, left_range.range()) + .is_err() + { + pr_err!("Vm::Drop: vm.unmap_range() failed\n"); + } + if !right_range.is_empty() + && self + .vm + .unmap_range(right_range.start, right_range.range()) + .is_err() { pr_err!("Vm::Drop: vm.unmap_range() failed\n"); } @@ -155,23 +169,11 @@ pub(crate) struct File { /// Convenience type alias for our DRM `File` type. pub(crate) type DrmFile = drm::file::File; -/// Start address of the 32-bit USC address space. -const VM_SHADER_START: u64 = 0x11_00000000; -/// End address of the 32-bit USC address space. -const VM_SHADER_END: u64 = 0x11_ffffffff; -/// Start address of the general user mapping region. -const VM_USER_START: u64 = 0x20_00000000; -/// End address of the general user mapping region. -const VM_USER_END: u64 = 0x6f_ffff0000; - -/// Start address of the kernel-managed GPU-only mapping region. -const VM_DRV_GPU_START: u64 = 0x70_00000000; -/// End address of the kernel-managed GPU-only mapping region. -const VM_DRV_GPU_END: u64 = 0x70_ffffffff; -/// Start address of the kernel-managed GPU/FW shared mapping region. -const VM_DRV_GPUFW_START: u64 = 0x71_00000000; -/// End address of the kernel-managed GPU/FW shared mapping region. -const VM_DRV_GPUFW_END: u64 = 0x71_ffffffff; +/// Available VM range for the user +const VM_USER_RANGE: Range = mmu::IOVA_USER_USABLE_RANGE; + +/// Minimum reserved AS for kernel mappings +const VM_KERNEL_MIN_SIZE: u64 = 0x20000000; impl drm::file::DriverFile for File { type Driver = driver::AsahiDriver; @@ -247,10 +249,11 @@ impl File { vm_page_size: mmu::UAT_PGSZ as u32, pad1: 0, - vm_user_start: VM_USER_START, - vm_user_end: VM_USER_END, - vm_shader_start: VM_SHADER_START, - vm_shader_end: VM_SHADER_END, + vm_user_start: VM_USER_RANGE.start, + vm_user_end: VM_USER_RANGE.end, + vm_usc_start: 0, // Arbitrary + vm_usc_end: 0, + vm_kernel_min_size: VM_KERNEL_MIN_SIZE, max_syncs_per_submission: 0, max_commands_per_submission: MAX_COMMANDS_PER_SUBMISSION, @@ -299,9 +302,25 @@ impl File { return Err(EINVAL); } + let kernel_range = data.kernel_start..data.kernel_end; + + // Validate requested kernel range + if !VM_USER_RANGE.is_superset(kernel_range.clone()) + || kernel_range.range() < VM_KERNEL_MIN_SIZE + || kernel_range.start & (mmu::UAT_PGMSK as u64) != 0 + || kernel_range.end & (mmu::UAT_PGMSK as u64) != 0 + { + cls_pr_debug!(Errors, "vm_create: Invalid kernel range\n"); + return Err(EINVAL); + } + + let kernel_half_size = (kernel_range.range() >> 1) & !(mmu::UAT_PGMSK as u64); + let kernel_gpu_range = kernel_range.start..(kernel_range.start + kernel_half_size); + let kernel_gpufw_range = kernel_gpu_range.end..kernel_range.end; + let gpu = &device.data().gpu; let file_id = file.inner().id; - let vm = gpu.new_vm()?; + let vm = gpu.new_vm(kernel_range.clone())?; let resv = file.inner().vms().reserve()?; let id: u32 = resv.index().try_into()?; @@ -316,7 +335,7 @@ impl File { let ualloc = Arc::pin_init(Mutex::new(alloc::DefaultAllocator::new( device, &vm, - VM_DRV_GPU_START..VM_DRV_GPU_END, + kernel_gpu_range, buffer::PAGE_SIZE, mmu::PROT_GPU_SHARED_RW, 512 * 1024, @@ -327,7 +346,7 @@ impl File { let ualloc_priv = Arc::pin_init(Mutex::new(alloc::DefaultAllocator::new( device, &vm, - VM_DRV_GPUFW_START..VM_DRV_GPUFW_END, + kernel_gpufw_range, buffer::PAGE_SIZE, mmu::PROT_GPU_FW_PRIV_RW, 64 * 1024, @@ -352,6 +371,7 @@ impl File { ualloc, ualloc_priv, vm, + kernel_range, _dummy_mapping: dummy_mapping, })?)?; @@ -512,47 +532,17 @@ impl File { let bo = gem::lookup_handle(file, data.handle)?; let start = data.addr; - let end = data.addr + data.range - 1; - - if (VM_SHADER_START..=VM_SHADER_END).contains(&start) { - if !(VM_SHADER_START..=VM_SHADER_END).contains(&end) { - cls_pr_debug!( - Errors, - "gem_bind: Invalid map range {:#x}..{:#x} (straddles shader range)\n", - start, - end - ); - return Err(EINVAL); // Invalid map range - } - } else if (VM_USER_START..=VM_USER_END).contains(&start) { - if !(VM_USER_START..=VM_USER_END).contains(&end) { - cls_pr_debug!( - Errors, - "gem_bind: Invalid map range {:#x}..{:#x} (straddles user range)\n", - start, - end - ); - return Err(EINVAL); // Invalid map range - } - } else { - cls_pr_debug!( - Errors, - "gem_bind: Invalid map range {:#x}..{:#x}\n", - start, - end - ); - return Err(EINVAL); // Invalid map range - } + let end = data.addr.checked_add(data.range).ok_or(EINVAL)?; + let range = start..end; - // Just in case - if end >= VM_DRV_GPU_START { + if !VM_USER_RANGE.is_superset(range.clone()) { cls_pr_debug!( Errors, - "gem_bind: Invalid map range {:#x}..{:#x} (intrudes in kernel range)\n", + "gem_bind: Invalid map range {:#x}..{:#x} (not contained in user range)\n", start, end ); - return Err(EINVAL); + return Err(EINVAL); // Invalid map range } let prot = if data.flags & uapi::ASAHI_BIND_READ != 0 { @@ -572,15 +562,26 @@ impl File { return Err(EINVAL); // Must specify one of ASAHI_BIND_{READ,WRITE} }; - // Clone it immediately so we aren't holding the XArray lock - let vm = file + let guard = file .inner() .vms() .get(data.vm_id.try_into()?) - .ok_or(ENOENT)? - .borrow() - .vm - .clone(); + .ok_or(ENOENT)?; + + // Clone it immediately so we aren't holding the XArray lock + let vm = guard.borrow().vm.clone(); + let kernel_range = guard.borrow().kernel_range.clone(); + core::mem::drop(guard); + + if kernel_range.overlaps(range) { + cls_pr_debug!( + Errors, + "gem_bind: Invalid map range {:#x}..{:#x} (intrudes in kernel range)\n", + start, + end + ); + return Err(EINVAL); + } vm.bind_object(&bo.gem, data.addr, data.range, data.offset, prot)?; diff --git a/drivers/gpu/drm/asahi/gpu.rs b/drivers/gpu/drm/asahi/gpu.rs index e04476d54173f8..651d3ecb071acc 100644 --- a/drivers/gpu/drm/asahi/gpu.rs +++ b/drivers/gpu/drm/asahi/gpu.rs @@ -229,7 +229,7 @@ pub(crate) trait GpuManager: Send + Sync { /// Get a reference to the KernelAllocators. fn alloc(&self) -> Guard<'_, KernelAllocators, MutexBackend>; /// Create a new `Vm` given a unique `File` ID. - fn new_vm(&self) -> Result; + fn new_vm(&self, kernel_range: Range) -> Result; /// Bind a `Vm` to an available slot and return the `VmBind`. fn bind_vm(&self, vm: &mmu::Vm) -> Result; /// Create a new user command queue. @@ -1164,8 +1164,8 @@ impl GpuManager for GpuManager::ver { guard } - fn new_vm(&self) -> Result { - self.uat.new_vm(self.ids.vm.next()) + fn new_vm(&self, kernel_range: Range) -> Result { + self.uat.new_vm(self.ids.vm.next(), kernel_range) } fn bind_vm(&self, vm: &mmu::Vm) -> Result { diff --git a/drivers/gpu/drm/asahi/mmu.rs b/drivers/gpu/drm/asahi/mmu.rs index 8cdedc967bc06f..2faf21244fd38f 100644 --- a/drivers/gpu/drm/asahi/mmu.rs +++ b/drivers/gpu/drm/asahi/mmu.rs @@ -90,6 +90,8 @@ const PTE_TABLE: u64 = 0x3; // BIT(0) | BIT(1) /// Address of a special dummy page? //const IOVA_UNK_PAGE: u64 = 0x6f_ffff8000; pub(crate) const IOVA_UNK_PAGE: u64 = IOVA_USER_TOP - 2 * UAT_PGSZ as u64; +/// User VA range excluding the unk page +pub(crate) const IOVA_USER_USABLE_RANGE: Range = IOVA_USER_BASE..IOVA_UNK_PAGE; // KernelMapping protection types @@ -998,6 +1000,7 @@ impl Vm { fn new( dev: &driver::AsahiDevice, uat_inner: Arc, + kernel_range: Range, cfg: &'static hw::HwConfig, is_kernel: bool, id: u64, @@ -1015,10 +1018,10 @@ impl Vm { }, (), )?; - let va_range = if is_kernel { - IOVA_KERN_RANGE + let (va_range, gpuvm_range) = if is_kernel { + (IOVA_KERN_RANGE, kernel_range.clone()) } else { - IOVA_USER_RANGE + (IOVA_USER_RANGE, IOVA_USER_USABLE_RANGE) }; let mm = mm::Allocator::new(va_range.start, va_range.range(), ())?; @@ -1040,8 +1043,8 @@ impl Vm { c_str!("Asahi::GpuVm"), dev, &*(dummy_obj.gem), - va_range.clone(), - 0..0, + gpuvm_range, + kernel_range, init!(VmInner { dev: dev.into(), va_range, @@ -1479,8 +1482,15 @@ impl Uat { } /// Creates a new `Vm` linked to this UAT. - pub(crate) fn new_vm(&self, id: u64) -> Result { - Vm::new(&self.dev, self.inner.clone(), self.cfg, false, id) + pub(crate) fn new_vm(&self, id: u64, kernel_range: Range) -> Result { + Vm::new( + &self.dev, + self.inner.clone(), + kernel_range, + self.cfg, + false, + id, + ) } /// Creates the reference-counted inner data for a new `Uat` instance. @@ -1523,8 +1533,8 @@ impl Uat { let pagetables_rgn = Self::map_region(dev, c_str!("pagetables"), PAGETABLES_SIZE, true)?; dev_info!(dev, "MMU: Creating kernel page tables\n"); - let kernel_lower_vm = Vm::new(dev, inner.clone(), cfg, false, 1)?; - let kernel_vm = Vm::new(dev, inner.clone(), cfg, true, 0)?; + let kernel_lower_vm = Vm::new(dev, inner.clone(), IOVA_USER_RANGE, cfg, false, 1)?; + let kernel_vm = Vm::new(dev, inner.clone(), IOVA_KERN_RANGE, cfg, true, 0)?; dev_info!(dev, "MMU: Kernel page tables created\n"); diff --git a/drivers/gpu/drm/asahi/queue/compute.rs b/drivers/gpu/drm/asahi/queue/compute.rs index 1cd52f338d0583..eeaad0e995b07e 100644 --- a/drivers/gpu/drm/asahi/queue/compute.rs +++ b/drivers/gpu/drm/asahi/queue/compute.rs @@ -283,7 +283,7 @@ impl super::Queue::ver { preempt_buf3: inner.preempt_buf.gpu_offset_pointer(preempt3_off), preempt_buf4: inner.preempt_buf.gpu_offset_pointer(preempt4_off), preempt_buf5: inner.preempt_buf.gpu_offset_pointer(preempt5_off), - pipeline_base: U64(0x11_00000000), + pipeline_base: U64(cmdbuf.usc_base), unk_38: U64(0x8c60), helper_program: cmdbuf.helper_program, // Internal program addr | 1 unk_44: 0, @@ -306,7 +306,7 @@ impl super::Queue::ver { r.add(0x1a4d8, inner.preempt_buf.gpu_offset_pointer(preempt3_off).into()); r.add(0x1a4e0, inner.preempt_buf.gpu_offset_pointer(preempt4_off).into()); r.add(0x1a4e8, inner.preempt_buf.gpu_offset_pointer(preempt5_off).into()); - r.add(0x10071, 0x1100000000); // USC_EXEC_BASE_CP + r.add(0x10071, cmdbuf.usc_base); // USC_EXEC_BASE_CP r.add(0x11841, cmdbuf.helper_program.into()); r.add(0x11849, cmdbuf.helper_arg); r.add(0x11f81, cmdbuf.helper_cfg.into()); diff --git a/drivers/gpu/drm/asahi/queue/render.rs b/drivers/gpu/drm/asahi/queue/render.rs index 4dee12c72c747e..e254c7fb8e59fa 100644 --- a/drivers/gpu/drm/asahi/queue/render.rs +++ b/drivers/gpu/drm/asahi/queue/render.rs @@ -839,7 +839,7 @@ impl super::Queue::ver { tile_config: U64(tile_config), aux_fb: inner.aux_fb.gpu_pointer(), unk_108: Default::default(), - pipeline_base: U64(0x11_00000000), + pipeline_base: U64(cmdbuf.fragment_usc_base), unk_140: U64(unks.frg_unk_140), helper_program: cmdbuf.fragment_helper_program, unk_14c: 0, @@ -944,7 +944,7 @@ impl super::Queue::ver { r.add(0x11829, cmdbuf.fragment_helper_arg); r.add(0x11f79, cmdbuf.fragment_helper_cfg.into()); r.add(0x15359, 0); - r.add(0x10069, 0x11_00000000); // USC_EXEC_BASE_ISP + r.add(0x10069, cmdbuf.fragment_usc_base); // USC_EXEC_BASE_ISP r.add(0x16020, 0); r.add(0x16461, inner.aux_fb.gpu_pointer().into()); r.add(0x16090, inner.aux_fb.gpu_pointer().into()); @@ -1341,7 +1341,7 @@ impl super::Queue::ver { #[ver(G < G14)] unk_ac: unks.tiling_control_2 as u32, // fixed unk_b0: Default::default(), // fixed - pipeline_base: U64(0x11_00000000), + pipeline_base: U64(cmdbuf.vertex_usc_base), #[ver(G < G14)] tvb_cluster_meta4: inner .scene @@ -1433,7 +1433,7 @@ impl super::Queue::ver { r.add(0x1c1a9, 0); // 0x10151 bit 1 enables r.add(0x1c1b1, 0); r.add(0x1c1b9, 0); - r.add(0x10061, 0x11_00000000); // USC_EXEC_BASE_TA + r.add(0x10061, cmdbuf.vertex_usc_base); // USC_EXEC_BASE_TA r.add(0x11801, cmdbuf.vertex_helper_program.into()); r.add(0x11809, cmdbuf.vertex_helper_arg); r.add(0x11f71, cmdbuf.vertex_helper_cfg.into());