Skip to content

Commit ee524d6

Browse files
committed
drm/asahi: Convert to GPUVM and implement more VM_BIND ops
Signed-off-by: Asahi Lina <[email protected]>
1 parent c264fec commit ee524d6

9 files changed

Lines changed: 564 additions & 270 deletions

File tree

drivers/gpu/drm/asahi/alloc.rs

Lines changed: 22 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -444,7 +444,7 @@ pub(crate) struct SimpleAllocation {
444444
ptr: Option<NonNull<u8>>,
445445
gpu_ptr: u64,
446446
size: usize,
447-
vm: mmu::Vm,
447+
_mapping: mmu::KernelMapping,
448448
obj: crate::gem::ObjectRef,
449449
}
450450

@@ -464,7 +464,6 @@ impl Drop for SimpleAllocation {
464464
vmap.as_mut_slice().fill(0x42);
465465
}
466466
}
467-
self.obj.drop_vm_mappings(self.vm.id());
468467
}
469468
}
470469

@@ -566,7 +565,7 @@ impl Allocator for SimpleAllocator {
566565
if debug_enabled(DebugFlags::FillAllocations) {
567566
obj.vmap()?.as_mut_slice().fill(0xde);
568567
}
569-
let iova = obj.map_into_range(
568+
let mapping = obj.map_into_range(
570569
&self.vm,
571570
self.start,
572571
self.end,
@@ -575,6 +574,8 @@ impl Allocator for SimpleAllocator {
575574
true,
576575
)?;
577576

577+
let iova = mapping.iova();
578+
578579
let ptr = unsafe { p.add(offset) };
579580
let gpu_ptr = (iova + offset) as u64;
580581

@@ -592,7 +593,7 @@ impl Allocator for SimpleAllocator {
592593
ptr: NonNull::new(ptr),
593594
gpu_ptr,
594595
size,
595-
vm: self.vm.clone(),
596+
_mapping: mapping,
596597
obj,
597598
})
598599
}
@@ -696,11 +697,10 @@ impl RawAllocation for HeapAllocation {
696697
struct HeapAllocatorInner {
697698
dev: AsahiDevRef,
698699
allocated: usize,
699-
backing_objects: Vec<(crate::gem::ObjectRef, u64)>,
700+
backing_objects: Vec<(crate::gem::ObjectRef, mmu::KernelMapping, u64)>,
700701
garbage: Option<Vec<mm::Node<HeapAllocatorInner, HeapAllocationInner>>>,
701702
total_garbage: usize,
702703
name: CString,
703-
vm_id: u64,
704704
}
705705

706706
/// A heap allocator which uses the DRM MM range allocator to manage its objects.
@@ -753,7 +753,6 @@ impl HeapAllocator {
753753
backing_objects: Vec::new(),
754754
// TODO: This clearly needs a try_clone() or similar
755755
name: CString::try_from_fmt(fmt!("{}", &*name))?,
756-
vm_id: vm.id(),
757756
garbage: if keep_garbage { Some(Vec::new()) } else { None },
758757
total_garbage: 0,
759758
};
@@ -807,16 +806,18 @@ impl HeapAllocator {
807806
}
808807

809808
let gpu_ptr = self.top;
810-
if let Err(e) = obj.map_at(&self.vm, gpu_ptr, self.prot, self.cpu_maps) {
811-
dev_err!(
812-
&self.dev,
813-
"HeapAllocator[{}]::add_block: Failed to map at {:#x} ({:?})\n",
814-
&*self.name,
815-
gpu_ptr,
816-
e
817-
);
818-
return Err(e);
819-
}
809+
let mapping = obj
810+
.map_at(&self.vm, gpu_ptr, self.prot, self.cpu_maps)
811+
.map_err(|err| {
812+
dev_err!(
813+
&self.dev,
814+
"HeapAllocator[{}]::add_block: Failed to map at {:#x} ({:?})\n",
815+
&*self.name,
816+
gpu_ptr,
817+
err
818+
);
819+
err
820+
})?;
820821

821822
self.mm
822823
.with_inner(|inner| inner.backing_objects.try_reserve(1))?;
@@ -865,7 +866,7 @@ impl HeapAllocator {
865866
);
866867

867868
self.mm
868-
.with_inner(|inner| inner.backing_objects.try_push((obj, gpu_ptr)))?;
869+
.with_inner(|inner| inner.backing_objects.try_push((obj, mapping, gpu_ptr)))?;
869870

870871
self.top = new_top;
871872

@@ -886,8 +887,8 @@ impl HeapAllocator {
886887
inner
887888
.backing_objects
888889
.binary_search_by(|obj| {
889-
let start = obj.1;
890-
let end = obj.1 + obj.0.size() as u64;
890+
let start = obj.2;
891+
let end = obj.2 + obj.0.size() as u64;
891892
if start > addr {
892893
Ordering::Greater
893894
} else if end <= addr {
@@ -1003,7 +1004,7 @@ impl Allocator for HeapAllocator {
10031004
let idx = idx.unwrap_or(inner.backing_objects.len() - 1);
10041005
let obj = &mut inner.backing_objects[idx];
10051006
let p = obj.0.vmap()?.as_mut_ptr() as *mut u8;
1006-
Ok((obj.1, obj.0.size(), p))
1007+
Ok((obj.2, obj.0.size(), p))
10071008
})?;
10081009
assert!(obj_start <= start);
10091010
assert!(obj_start + obj_size as u64 >= end);
@@ -1079,10 +1080,6 @@ impl Drop for HeapAllocatorInner {
10791080
&*self.name,
10801081
self.allocated
10811082
);
1082-
} else {
1083-
for mut obj in self.backing_objects.drain(..) {
1084-
obj.0.drop_vm_mappings(self.vm_id);
1085-
}
10861083
}
10871084
}
10881085
}

drivers/gpu/drm/asahi/driver.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,11 @@ impl drv::Driver for AsahiDriver {
5252
type Object = gem::Object;
5353

5454
const INFO: drv::DriverInfo = INFO;
55-
const FEATURES: u32 =
56-
drv::FEAT_GEM | drv::FEAT_RENDER | drv::FEAT_SYNCOBJ | drv::FEAT_SYNCOBJ_TIMELINE;
55+
const FEATURES: u32 = drv::FEAT_GEM
56+
| drv::FEAT_RENDER
57+
| drv::FEAT_SYNCOBJ
58+
| drv::FEAT_SYNCOBJ_TIMELINE
59+
| drv::FEAT_GEM_GPUVA;
5760

5861
kernel::declare_drm_ioctls! {
5962
(ASAHI_GET_PARAMS, drm_asahi_get_params,

drivers/gpu/drm/asahi/file.rs

Lines changed: 50 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,19 @@ struct Vm {
3030
ualloc: Arc<Mutex<alloc::DefaultAllocator>>,
3131
ualloc_priv: Arc<Mutex<alloc::DefaultAllocator>>,
3232
vm: mmu::Vm,
33-
dummy_obj: gem::ObjectRef,
33+
_dummy_mapping: mmu::KernelMapping,
3434
}
3535

3636
impl Drop for Vm {
3737
fn drop(&mut self) {
38-
// Mappings create a reference loop, make sure to break it.
39-
self.dummy_obj.drop_vm_mappings(self.vm.id());
38+
// When the user Vm is dropped, unmap everything in the user range
39+
if self
40+
.vm
41+
.unmap_range(mmu::IOVA_USER_BASE as u64, VM_USER_END)
42+
.is_err()
43+
{
44+
pr_err!("Vm::Drop: vm.unmap_range() failed\n");
45+
}
4046
}
4147
}
4248

@@ -156,16 +162,16 @@ const VM_SHADER_END: u64 = 0x11_ffffffff;
156162
/// Start address of the general user mapping region.
157163
const VM_USER_START: u64 = 0x20_00000000;
158164
/// End address of the general user mapping region.
159-
const VM_USER_END: u64 = 0x5f_ffffffff;
165+
const VM_USER_END: u64 = 0x6f_ffff0000;
160166

161167
/// Start address of the kernel-managed GPU-only mapping region.
162-
const VM_DRV_GPU_START: u64 = 0x60_00000000;
168+
const VM_DRV_GPU_START: u64 = 0x70_00000000;
163169
/// End address of the kernel-managed GPU-only mapping region.
164-
const VM_DRV_GPU_END: u64 = 0x60_ffffffff;
170+
const VM_DRV_GPU_END: u64 = 0x70_ffffffff;
165171
/// Start address of the kernel-managed GPU/FW shared mapping region.
166-
const VM_DRV_GPUFW_START: u64 = 0x61_00000000;
172+
const VM_DRV_GPUFW_START: u64 = 0x71_00000000;
167173
/// End address of the kernel-managed GPU/FW shared mapping region.
168-
const VM_DRV_GPUFW_END: u64 = 0x61_ffffffff;
174+
const VM_DRV_GPUFW_END: u64 = 0x71_ffffffff;
169175
/// Address of a special dummy page?
170176
const VM_UNK_PAGE: u64 = 0x6f_ffff8000;
171177

@@ -297,7 +303,7 @@ impl File {
297303

298304
let gpu = &device.data().gpu;
299305
let file_id = file.inner().id;
300-
let vm = gpu.new_vm(file_id)?;
306+
let vm = gpu.new_vm()?;
301307

302308
let resv = file.inner().vms().reserve()?;
303309
let id: u32 = resv.index().try_into()?;
@@ -342,14 +348,14 @@ impl File {
342348
);
343349
let mut dummy_obj = gem::new_kernel_object(device, 0x4000)?;
344350
dummy_obj.vmap()?.as_mut_slice().fill(0);
345-
dummy_obj.map_at(&vm, VM_UNK_PAGE, mmu::PROT_GPU_SHARED_RW, true)?;
351+
let dummy_mapping = dummy_obj.map_at(&vm, VM_UNK_PAGE, mmu::PROT_GPU_SHARED_RW, true)?;
346352

347353
mod_dev_dbg!(device, "[File {} VM {}]: VM created\n", file_id, id);
348354
resv.store(Box::try_new(Vm {
349355
ualloc,
350356
ualloc_priv,
351357
vm,
352-
dummy_obj,
358+
_dummy_mapping: dummy_mapping,
353359
})?)?;
354360

355361
data.vm_id = id;
@@ -491,15 +497,10 @@ impl File {
491497
data: &mut uapi::drm_asahi_gem_bind,
492498
file: &DrmFile,
493499
) -> Result<u32> {
494-
if data.offset != 0 {
495-
pr_err!("gem_bind: Offset not supported yet\n");
496-
return Err(EINVAL); // Not supported yet
497-
}
498-
499-
if (data.addr | data.range) as usize & mmu::UAT_PGMSK != 0 {
500+
if (data.addr | data.range | data.offset) as usize & mmu::UAT_PGMSK != 0 {
500501
cls_pr_debug!(
501502
Errors,
502-
"gem_bind: Addr/range not page aligned: {:#x} {:#x}\n",
503+
"gem_bind: Addr/range/offset not page aligned: {:#x} {:#x}\n",
503504
data.addr,
504505
data.range
505506
);
@@ -511,12 +512,7 @@ impl File {
511512
return Err(EINVAL);
512513
}
513514

514-
let mut bo = gem::lookup_handle(file, data.handle)?;
515-
516-
if data.range != bo.size().try_into()? {
517-
pr_err!("gem_bind: Partial maps not supported yet\n");
518-
return Err(EINVAL); // Not supported yet
519-
}
515+
let bo = gem::lookup_handle(file, data.handle)?;
520516

521517
let start = data.addr;
522518
let end = data.addr + data.range - 1;
@@ -589,11 +585,36 @@ impl File {
589585
.vm
590586
.clone();
591587

592-
bo.map_at(&vm, start, prot, true)?;
588+
vm.bind_object(&bo.gem, data.addr, data.range, data.offset, prot)?;
593589

594590
Ok(0)
595591
}
596592

593+
pub(crate) fn unbind_gem_object(file: &DrmFile, bo: &gem::Object) -> Result {
594+
let mut index = 0;
595+
loop {
596+
let item = file
597+
.inner()
598+
.vms()
599+
.find(index, xarray::XArray::<Box<Vm>>::MAX);
600+
match item {
601+
Some((idx, file_vm)) => {
602+
// Clone since we can't hold the xarray spinlock while
603+
// calling drop_mappings()
604+
let vm = file_vm.borrow().vm.clone();
605+
core::mem::drop(file_vm);
606+
vm.drop_mappings(bo)?;
607+
if idx == xarray::XArray::<Box<Vm>>::MAX {
608+
break;
609+
}
610+
index = idx + 1;
611+
}
612+
None => break,
613+
}
614+
}
615+
Ok(())
616+
}
617+
597618
pub(crate) fn do_gem_unbind_all(
598619
_device: &AsahiDevice,
599620
data: &mut uapi::drm_asahi_gem_bind,
@@ -604,20 +625,18 @@ impl File {
604625
return Err(EINVAL);
605626
}
606627

607-
let mut bo = gem::lookup_handle(file, data.handle)?;
628+
let bo = gem::lookup_handle(file, data.handle)?;
608629

609630
if data.vm_id == 0 {
610-
bo.drop_file_mappings(file.inner().id);
631+
Self::unbind_gem_object(file, &bo.gem)?;
611632
} else {
612-
let vm_id = file
613-
.inner()
633+
file.inner()
614634
.vms()
615635
.get(data.vm_id.try_into()?)
616636
.ok_or(ENOENT)?
617637
.borrow()
618638
.vm
619-
.id();
620-
bo.drop_vm_mappings(vm_id);
639+
.drop_mappings(&bo.gem)?;
621640
}
622641

623642
Ok(0)
@@ -827,11 +846,6 @@ impl File {
827846
Ok(_) => Ok(0),
828847
}
829848
}
830-
831-
/// Returns the unique file ID for this `File`.
832-
pub(crate) fn file_id(&self) -> u64 {
833-
self.id
834-
}
835849
}
836850

837851
impl Drop for File {

drivers/gpu/drm/asahi/fw/initdata.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
55
use super::channels;
66
use super::types::*;
7-
use crate::{default_zeroed, gem, no_debug, trivial_gpustruct};
7+
use crate::{default_zeroed, gem, mmu, no_debug, trivial_gpustruct};
88

99
pub(crate) mod raw {
1010
use super::*;
@@ -1326,6 +1326,8 @@ pub(crate) struct RuntimePointers {
13261326
pub(crate) unkptr_1c8: GpuArray<u8>,
13271327

13281328
pub(crate) buffer_mgr_ctl: gem::ObjectRef,
1329+
pub(crate) buffer_mgr_ctl_low_mapping: Option<mmu::KernelMapping>,
1330+
pub(crate) buffer_mgr_ctl_high_mapping: Option<mmu::KernelMapping>,
13291331
}
13301332

13311333
#[versions(AGX)]

0 commit comments

Comments
 (0)