diff --git a/drivers/gpu/drm/asahi/driver.rs b/drivers/gpu/drm/asahi/driver.rs index f99494265234a7..80ea12df7810ed 100644 --- a/drivers/gpu/drm/asahi/driver.rs +++ b/drivers/gpu/drm/asahi/driver.rs @@ -77,6 +77,8 @@ impl drv::Driver for AsahiDriver { ioctl::AUTH | ioctl::RENDER_ALLOW, crate::file::File::queue_destroy), (ASAHI_SUBMIT, drm_asahi_submit, ioctl::AUTH | ioctl::RENDER_ALLOW, crate::file::File::submit), + (ASAHI_GET_TIME, drm_asahi_get_time, + ioctl::AUTH | ioctl::RENDER_ALLOW, crate::file::File::get_time), } } diff --git a/drivers/gpu/drm/asahi/file.rs b/drivers/gpu/drm/asahi/file.rs index 5d1bcb4b04f874..5c50e2aa41c33c 100644 --- a/drivers/gpu/drm/asahi/file.rs +++ b/drivers/gpu/drm/asahi/file.rs @@ -519,7 +519,7 @@ impl File { match data.op { uapi::drm_asahi_bind_op_ASAHI_BIND_OP_BIND => Self::do_gem_bind(device, data, file), - uapi::drm_asahi_bind_op_ASAHI_BIND_OP_UNBIND => Err(ENOTSUPP), + uapi::drm_asahi_bind_op_ASAHI_BIND_OP_UNBIND => Self::do_gem_unbind(device, data, file), uapi::drm_asahi_bind_op_ASAHI_BIND_OP_UNBIND_ALL => { Self::do_gem_unbind_all(device, data, file) } @@ -609,6 +609,66 @@ impl File { Ok(0) } + pub(crate) fn do_gem_unbind( + _device: &AsahiDevice, + data: &mut uapi::drm_asahi_gem_bind, + file: &DrmFile, + ) -> Result { + if data.offset != 0 || data.flags != 0 || data.handle != 0 { + cls_pr_debug!(Errors, "gem_unbind: offset/flags/handle not zero\n"); + return Err(EINVAL); + } + + if (data.addr | data.range) as usize & mmu::UAT_PGMSK != 0 { + cls_pr_debug!( + Errors, + "gem_bind: Addr/range/offset not page aligned: {:#x} {:#x}\n", + data.addr, + data.range + ); + return Err(EINVAL); // Must be page aligned + } + + let start = data.addr; + let end = data.addr.checked_add(data.range).ok_or(EINVAL)?; + let range = start..end; + + if !VM_USER_RANGE.is_superset(range.clone()) { + cls_pr_debug!( + Errors, + "gem_bind: Invalid unmap range {:#x}..{:#x} (not contained in user range)\n", + start, + end + ); + return Err(EINVAL); // Invalid map range + } + + let guard = file + .inner() + .vms() + .get(data.vm_id.try_into()?) + .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.clone()) { + cls_pr_debug!( + Errors, + "gem_bind: Invalid unmap range {:#x}..{:#x} (intrudes in kernel range)\n", + start, + end + ); + return Err(EINVAL); + } + + vm.unmap_range(range.start, range.range())?; + + Ok(0) + } + pub(crate) fn unbind_gem_object(file: &DrmFile, bo: &gem::Object) -> Result { let mut index = 0; loop { @@ -865,6 +925,39 @@ impl File { Ok(_) => Ok(0), } } + + /// IOCTL: get_time: Get the current GPU timer value. + pub(crate) fn get_time( + device: &AsahiDevice, + data: &mut uapi::drm_asahi_get_time, + file: &DrmFile, + ) -> Result { + + if data.extensions != 0 || data.flags != 0 { + cls_pr_debug!(Errors, "get_time: Unexpected extensions or flags\n"); + return Err(EINVAL); + } + + let mut tp: kernel::bindings::timespec64 = Default::default(); + let mut gputime: u64 = 0; + + // TODO: bindings + // SAFETY: These functions are safe to call as long as the argument pointer is valid + unsafe { + core::arch::asm!( + "mrs {x}, CNTPCT_EL0", + x = out(reg) gputime + ); + kernel::bindings::ktime_get_raw_ts64(&mut tp); + kernel::bindings::timens_add_monotonic(&mut tp); + } + + data.gpu_timestamp = gputime; + data.tv_sec = tp.tv_sec; + data.tv_nsec = tp.tv_nsec; + + Ok(0) + } } impl Drop for File { diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c index a2cc0e26eca70a..ad3147a72a05ac 100644 --- a/rust/helpers/helpers.c +++ b/rust/helpers/helpers.c @@ -34,6 +34,7 @@ #include "slab.c" #include "spinlock.c" #include "task.c" +#include "time_namespace.c" #include "timekeeping.c" #include "uaccess.c" #include "wait.c" diff --git a/rust/helpers/time_namespace.c b/rust/helpers/time_namespace.c new file mode 100644 index 00000000000000..9010e8efbcfe0d --- /dev/null +++ b/rust/helpers/time_namespace.c @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include + +void rust_helper_timens_add_monotonic(struct timespec64 *ts) { + timens_add_monotonic(ts); +}