From: Daniel Almeida <daniel.almeida@collabora.com>
To: sunke@kylinos.cn
Cc: rust-for-linux@vger.kernel.org, "Miguel Ojeda" <ojeda@kernel.org>,
"Boqun Feng" <boqun@kernel.org>, "Gary Guo" <gary@garyguo.net>,
"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
"Benno Lossin" <lossin@kernel.org>,
"Andreas Hindborg" <a.hindborg@kernel.org>,
"Alice Ryhl" <aliceryhl@google.com>,
"Trevor Gross" <tmgross@umich.edu>,
"Danilo Krummrich" <dakr@kernel.org>,
"Tamir Duberstein" <tamird@kernel.org>,
"Alexandre Courbot" <acourbot@nvidia.com>,
"Onur Özkan" <work@onurozkan.dev>,
"Lorenzo Stoakes" <ljs@kernel.org>,
"Liam R. Howlett" <liam@infradead.org>,
"Lyude Paul" <lyude@redhat.com>,
"David Airlie" <airlied@gmail.com>,
"Simona Vetter" <simona@ffwll.ch>,
linux-kernel@vger.kernel.org, linux-mm@kvack.org,
dri-devel@lists.freedesktop.org,
"Alvin Sun" <alvin.sun@linux.dev>
Subject: Re: [PATCH 8/9] drm/tyr: add VM-related ioctls
Date: Fri, 4 Sep 2026 15:44:18 -0300 [thread overview]
Message-ID: <C59E65EF-33E6-449A-B109-307231B49057@collabora.com> (raw)
In-Reply-To: <20260902-tyr-ioctls-v1-8-e0fdbf8bd108@kylinos.cn>
> On 1 Sep 2026, at 13:09, Ke Sun via B4 Relay <devnull+sunke.kylinos.cn@kernel.org> wrote:
>
> From: Alvin Sun <alvin.sun@linux.dev>
>
> Manage per-file user VMs.
>
> - VM_CREATE creates a user VM and returns its ID.
> - VM_DESTROY destroys the VM identified by the given ID.
> - VM_BIND maps or unmaps BO ranges in the VM's user VA space.
> - VM_GET_STATE reports whether the VM is usable or unusable.
Same comment as the previous patches
>
> Signed-off-by: Alvin Sun <alvin.sun@linux.dev>
> ---
> drivers/gpu/drm/tyr/driver.rs | 12 +-
> drivers/gpu/drm/tyr/file.rs | 324 ++++++++++++++++++++++++++++++++++++++++--
> drivers/gpu/drm/tyr/vm.rs | 24 +++-
> 3 files changed, 346 insertions(+), 14 deletions(-)
>
> diff --git a/drivers/gpu/drm/tyr/driver.rs b/drivers/gpu/drm/tyr/driver.rs
> index 94bc85635725e..b3145526ada06 100644
> --- a/drivers/gpu/drm/tyr/driver.rs
> +++ b/drivers/gpu/drm/tyr/driver.rs
> @@ -33,7 +33,7 @@
> Mutex, //
> },
> time,
> - types::CovariantForLt, //
> + types::ForLt, //
> };
>
> use crate::{
> @@ -72,6 +72,9 @@ pub(crate) struct TyrDrmRegistrationData<'drm> {
> /// Firmware sections.
> pub(crate) fw: Firmware<'drm>,
>
> + /// Memory management unit for address space slots.
> + pub(crate) mmu: Arc<Mmu<'drm>>,
> +
> #[pin]
> clks: Mutex<Clocks>,
>
> @@ -164,6 +167,7 @@ fn probe<'bound>(
> let reg_data = pin_init!(TyrDrmRegistrationData {
> pdev,
> fw: firmware,
> + mmu,
> clks <- new_mutex!(Clocks {
> core: core_clk,
> stacks: stacks_clk,
> @@ -207,7 +211,7 @@ fn drop(self: Pin<&mut Self>) {}
> impl drm::Driver for TyrDrmDriver {
> type Data = ();
> type RegistrationData<'drm> = TyrDrmRegistrationData<'drm>;
> - type File = CovariantForLt!(TyrDrmFileData);
> + type File = ForLt!(TyrDrmFileData<'_>);
> type Object = Bo;
> type ParentDevice<Ctx: DeviceContext> = platform::Device<Ctx>;
>
> @@ -216,6 +220,10 @@ impl drm::Driver for TyrDrmDriver {
>
> kernel::declare_drm_ioctls! {
> (PANTHOR_DEV_QUERY, drm_panthor_dev_query, ioctl::RENDER_ALLOW, TyrDrmFileData::dev_query),
> + (PANTHOR_VM_CREATE, drm_panthor_vm_create, ioctl::RENDER_ALLOW, TyrDrmFileData::vm_create),
> + (PANTHOR_VM_DESTROY, drm_panthor_vm_destroy, ioctl::RENDER_ALLOW, TyrDrmFileData::vm_destroy),
> + (PANTHOR_VM_BIND, drm_panthor_vm_bind, ioctl::RENDER_ALLOW, TyrDrmFileData::vm_bind),
> + (PANTHOR_VM_GET_STATE, drm_panthor_vm_get_state, ioctl::RENDER_ALLOW, TyrDrmFileData::vm_get_state),
> }
> }
>
> diff --git a/drivers/gpu/drm/tyr/file.rs b/drivers/gpu/drm/tyr/file.rs
> index 933a365cb016e..157bc40e1cac4 100644
> --- a/drivers/gpu/drm/tyr/file.rs
> +++ b/drivers/gpu/drm/tyr/file.rs
> @@ -3,37 +3,70 @@
> use kernel::{
> drm::{
> self,
> + gem::BaseObject,
> Registered, //
> },
> prelude::*,
> - uaccess::UserSlice,
> + sizes::SizeConstants,
> + transmute::FromBytes,
> + uaccess::{
> + UserSlice,
> + UserSliceReader, //
> + },
> uapi, //
> };
>
> -use crate::driver::{
> - TyrDrmDevice,
> - TyrDrmDriver,
> - TyrDrmRegistrationData, //
> +use crate::{
> + driver::{
> + TyrDrmDevice,
> + TyrDrmDriver,
> + TyrDrmRegistrationData, //
> + },
> + pool::VmPool,
> + vm::{
> + UserVaRequest,
> + Vm,
> + VmMapFlags,
> + VmSpec, //
> + }, //
> };
>
> -#[pin_data]
> -pub(crate) struct TyrDrmFileData {}
> +#[pin_data(PinnedDrop)]
> +pub(crate) struct TyrDrmFileData<'a> {
> + reg: &'a TyrDrmRegistrationData<'a>,
> +
> + #[pin]
> + vm_pool: VmPool<'a>,
> +}
>
> /// Convenience type alias for our DRM `File` type.
> pub(crate) type TyrDrmFile = drm::file::File<TyrDrmDriver>;
>
> -impl drm::file::DriverFile<'_> for TyrDrmFileData {
> +impl<'a> drm::file::DriverFile<'a> for TyrDrmFileData<'a> {
> type Driver = TyrDrmDriver;
>
> fn open(
> _device: &TyrDrmDevice<Registered>,
> - _reg_data: &TyrDrmRegistrationData<'_>,
> + reg_data: &'a TyrDrmRegistrationData<'a>,
> ) -> impl PinInit<Self, Error> {
> - Ok(Self {})
> + try_pin_init!(Self {
> + reg: reg_data,
> + vm_pool <- VmPool::new()?,
> + })
> }
> }
>
> -impl TyrDrmFileData {
> +#[pinned_drop]
> +impl PinnedDrop for TyrDrmFileData<'_> {
> + fn drop(self: Pin<&mut Self>) {
> + let proj = self.project();
> + while let Some(vm) = proj.vm_pool.pop_first() {
> + vm.kill();
> + }
> + }
> +}
> +
> +impl TyrDrmFileData<'_> {
> pub(crate) fn dev_query(
> _ddev: &TyrDrmDevice<Registered>,
> reg_data: &TyrDrmRegistrationData<'_>,
> @@ -65,4 +98,273 @@ pub(crate) fn dev_query(
> }
> }
> }
> +
> + pub(crate) fn vm_create(
> + ddev: &TyrDrmDevice<Registered>,
> + _reg_data: &TyrDrmRegistrationData<'_>,
> + vmcreate: &mut uapi::drm_panthor_vm_create,
> + file: &TyrDrmFile,
> + ) -> Result<u32> {
> + if vmcreate.flags != 0 {
> + dev_err!(
> + ddev.as_ref(),
> + "Invalid VM create flags: {:#x}\n",
> + vmcreate.flags
> + );
> + return Err(EINVAL);
> + }
> +
> + let ret: Result<u32, Error> = file.inner_with(|fd| {
> + let vm = Vm::new(
> + fd.reg.pdev.as_ref(),
> + ddev,
> + fd.reg.mmu.as_arc_borrow(),
> + &fd.reg.gpu_info,
> + VmSpec::User {
> + user_va: UserVaRequest::from_uapi(vmcreate.user_va_range),
> + },
> + )?;
> + vmcreate.user_va_range = vm.layout.user.end;
> +
> + let id = fd.vm_pool.add(vm.as_arc_borrow()).inspect_err(|_| {
> + vm.kill();
> + })?;
I think we can improve this, because currently we depend on kill() to not leak
resources. I propose the following:
/// The unique right to tear a VM down.
///
/// `Vm::new()` hands one of these back, so a VM is owned from the moment it
/// exists and any early return tears it down. Whoever ends up holding it (the
/// per-file pool) owns the teardown; everyone else takes an `Arc<Vm>` via
/// `VmOwner::get()`, which keeps the object alive but carries no such duty.
pub(crate) struct VmOwner<'drm>(Arc<Vm<'drm>>);
impl<'drm> VmOwner<'drm> {
/// A reference for callers that want to use the VM, not own it.
pub(crate) fn get(&self) -> Arc<Vm<'drm>> {
self.0.clone()
}
}
impl<'drm> core::ops::Deref for VmOwner<'drm> {
type Target = Vm<'drm>;
fn deref(&self) -> &Vm<'drm> { &self.0 }
}
impl Drop for VmOwner<'_> {
fn drop(&mut self) {
self.0.kill();
}
}
Where Vm::new() would be adapted to return VmOwner, instead of Arc<Vm>, so this
API cannot be circumvented. Also, kill() would be changed to private, such that
only VmOwner would be able to call it (since it will live in vm.rs).
> + vmcreate.id = id;
> +
> + Ok(0)
> + });
> + ret
> + }
> +
> + pub(crate) fn vm_destroy(
> + ddev: &TyrDrmDevice<Registered>,
> + _reg_data: &TyrDrmRegistrationData<'_>,
> + vmdestroy: &mut uapi::drm_panthor_vm_destroy,
> + file: &TyrDrmFile,
> + ) -> Result<u32> {
> + if vmdestroy.pad != 0 {
> + dev_err!(
> + ddev.as_ref(),
> + "Invalid VM destroy pad: {:#x}\n",
> + vmdestroy.pad
> + );
> + return Err(EINVAL);
> + }
> +
> + let ret: Result<u32, Error> = file.inner_with(|fd| {
> + let vm = fd.vm_pool.remove(vmdestroy.id)?;
> + vm.kill();
> + Ok(0)
> + });
> + ret
> + }
> +
> + pub(crate) fn vm_bind(
> + ddev: &TyrDrmDevice<Registered>,
> + _reg_data: &TyrDrmRegistrationData<'_>,
> + vmbind: &mut uapi::drm_panthor_vm_bind,
> + file: &TyrDrmFile,
> + ) -> Result<u32> {
> + let async_flag = uapi::drm_panthor_vm_bind_flags_DRM_PANTHOR_VM_BIND_ASYNC;
> +
> + if vmbind.flags & !async_flag != 0 {
> + dev_err!(
> + ddev.as_ref(),
> + "Invalid VM_BIND flags: {:#x}\n",
> + vmbind.flags
> + );
> + return Err(EINVAL);
> + }
> +
> + if vmbind.flags & async_flag != 0 {
> + dev_err!(ddev.as_ref(), "Async VM_BIND not supported\n");
> + return Err(ENOTSUPP);
> + }
> +
> + let count = vmbind.ops.count as usize;
> + if count == 0 {
> + return Ok(0);
> + }
> +
> + let size_of_op = size_of::<VmBindOp>();
> + // Stride versions the UAPI struct: reject only undersized strides.
> + if size_of_op > vmbind.ops.stride as usize {
> + dev_err!(
> + ddev.as_ref(),
> + "Invalid VM_BIND op stride {}\n",
> + vmbind.ops.stride
> + );
> + return Err(EINVAL);
> + }
> + let stride = vmbind.ops.stride as usize;
> +
> + let total_len = stride.checked_mul(count).ok_or_else(|| {
> + dev_err!(ddev.as_ref(), "VM_BIND ops length overflow\n");
> + EINVAL
> + })?;
> + let mut reader =
> + UserSlice::new(UserPtr::from_addr(vmbind.ops.array as usize), total_len).reader();
> + let mut ops = KVec::new();
> + for _ in 0..count {
> + ops.push(reader.read::<VmBindOp>()?, GFP_KERNEL)?;
> + read_padding_zero(&mut reader, stride - size_of_op)?;
> + }
> +
> + let ret: Result<u32, Error> = file.inner_with(|fd| {
> + let vm = fd.vm_pool.get(vmbind.vm_id).ok_or_else(|| {
> + dev_err!(ddev.as_ref(), "Invalid VM_BIND vm_id: {}\n", vmbind.vm_id);
> + EINVAL
> + })?;
> +
> + for (i, op) in ops.iter().enumerate() {
> + if let Err(e) = vm_bind_exec_op(&vm, file, op) {
> + dev_dbg!(ddev.as_ref(), "VM_BIND op {} failed: {:?}\n", i, e);
> + vmbind.ops.count = i as u32;
> + return Err(e);
> + }
> + }
> +
> + Ok(0)
> + });
> + ret
> + }
> +
> + pub(crate) fn vm_get_state(
> + ddev: &TyrDrmDevice<Registered>,
> + _reg_data: &TyrDrmRegistrationData<'_>,
> + vmgetstate: &mut uapi::drm_panthor_vm_get_state,
> + file: &TyrDrmFile,
> + ) -> Result<u32> {
> + file.inner_with(|fd| {
> + let vm = fd.vm_pool.get(vmgetstate.vm_id).ok_or_else(|| {
> + dev_err!(
> + ddev.as_ref(),
> + "Invalid VM_GET_STATE vm_id: {}\n",
> + vmgetstate.vm_id
> + );
> + EINVAL
> + })?;
> + vmgetstate.state = if vm.is_unusable() {
> + uapi::drm_panthor_vm_state_DRM_PANTHOR_VM_STATE_UNUSABLE
> + } else {
> + uapi::drm_panthor_vm_state_DRM_PANTHOR_VM_STATE_USABLE
> + };
> + Ok(0)
> + })
> + }
> +}
> +
> +fn vm_bind_exec_op(vm: &Vm<'_>, file: &TyrDrmFile, op: &VmBindOp) -> Result {
> + if vm.is_unusable() {
> + dev_err!(vm.dev(), "VM_BIND on destroyed VM\n");
> + return Err(EINVAL);
> + }
> +
> + if op.size == 0 {
> + return Ok(());
> + }
> +
> + if op.syncs.count != 0 {
> + dev_err!(vm.dev(), "VM_BIND op syncs not supported\n");
> + return Err(EINVAL);
> + }
> +
> + let end = match op.va.checked_add(op.size) {
> + Some(end) => end,
> + None => {
> + dev_err!(vm.dev(), "VM_BIND op VA range overflow\n");
> + return Err(EINVAL);
> + }
> + };
> + if op.va < vm.layout.user.start || end > vm.layout.user.end {
> + dev_err!(
> + vm.dev(),
> + "VM_BIND op VA range {:#x}..{:#x} outside user range\n",
> + op.va,
> + end
> + );
> + return Err(EINVAL);
> + }
> +
> + if (op.va | op.size | op.bo_offset) & (u64::SZ_4K - 1) != 0 {
> + dev_err!(vm.dev(), "VM_BIND op not GPU-page-aligned\n");
> + return Err(EINVAL);
> + }
> +
> + const TYPE_MASK: u32 =
> + uapi::drm_panthor_vm_bind_op_flags_DRM_PANTHOR_VM_BIND_OP_TYPE_MASK as u32;
> + const TYPE_MAP: u32 = uapi::drm_panthor_vm_bind_op_flags_DRM_PANTHOR_VM_BIND_OP_TYPE_MAP as u32;
> + const TYPE_UNMAP: u32 =
> + uapi::drm_panthor_vm_bind_op_flags_DRM_PANTHOR_VM_BIND_OP_TYPE_UNMAP as u32;
How about:
/// Operation type, packed into the top nibble of
/// `drm_panthor_vm_bind_op::flags`.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum VmBindOpType {
/// Map a BO range into the VM.
Map,
/// Unmap a VA range.
Unmap,
}
impl TryFrom<u32> for VmBindOpType {
type Error = Error;
fn try_from(flags: u32) -> Result<Self, Self::Error> {
const MAP: u32 = uapi::drm_panthor_vm_bind_op_flags_DRM_PANTHOR_VM_BIND_OP_TYPE_MAP as u32;
const UNMAP: u32 =
uapi::drm_panthor_vm_bind_op_flags_DRM_PANTHOR_VM_BIND_OP_TYPE_UNMAP as u32;
match flags & Self::MASK {
MAP => Ok(Self::Map),
UNMAP => Ok(Self::Unmap),
_ => Err(EINVAL),
}
}
}
impl VmBindOpType {
/// Bits occupied by the op type in `drm_panthor_vm_bind_op::flags`.
pub(crate) const MASK: u32 =
uapi::drm_panthor_vm_bind_op_flags_DRM_PANTHOR_VM_BIND_OP_TYPE_MASK as u32;
}
> +
> + match op.flags & TYPE_MASK {
> + TYPE_MAP => {
> + let map_flags = match VmMapFlags::try_from(op.flags & !TYPE_MASK) {
> + Ok(flags) => flags,
> + Err(_) => {
> + dev_err!(vm.dev(), "VM_BIND op invalid map flags {:#x}\n", op.flags);
> + return Err(EINVAL);
> + }
> + };
> + let bo = crate::gem::lookup_handle(file, op.bo_handle).map_err(|_| {
> + dev_err!(vm.dev(), "VM_BIND op invalid BO handle {}\n", op.bo_handle);
> + EINVAL
> + })?;
> + // Validate the BO window before mapping.
> + let bo_size = bo.size() as u64;
> + if op.size > bo_size || op.bo_offset > bo_size - op.size {
> + dev_err!(vm.dev(), "VM_BIND op BO range out of bounds\n");
> + return Err(EINVAL);
> + }
> + vm.map_bo_range(&bo, op.bo_offset, op.size, op.va, map_flags)
> + }
> + TYPE_UNMAP => {
> + // Unmap must not carry map-specific flags or BO references.
> + if op.flags & !TYPE_MASK != 0 || op.bo_handle != 0 || op.bo_offset != 0 {
> + dev_err!(
> + vm.dev(),
> + "VM_BIND UNMAP carries flags/BO refs: flags={:#x} bo_handle={} bo_offset={}\n",
> + op.flags,
> + op.bo_handle,
> + op.bo_offset
> + );
> + return Err(EINVAL);
> + }
> + vm.unmap_range(op.va, op.size)
> + }
> + _ => {
> + dev_err!(vm.dev(), "VM_BIND op type {:#x} not supported\n", op.flags);
> + Err(EINVAL)
> + }
> + }
> }
> +
> +/// Reads `len` bytes of array padding, rejecting any nonzero byte with `E2BIG`.
> +fn read_padding_zero(reader: &mut UserSliceReader, len: usize) -> Result {
> + let mut buf = [0u8; 64];
> + let mut remaining = len;
> + while remaining > 0 {
> + let chunk = remaining.min(buf.len());
> + reader.read_slice(&mut buf[..chunk])?;
> + if buf[..chunk].iter().any(|&b| b != 0) {
> + return Err(E2BIG);
> + }
> + remaining -= chunk;
> + }
> + Ok(())
> +}
> +
> +#[repr(transparent)]
> +struct VmBindOp(uapi::drm_panthor_vm_bind_op);
> +
> +impl core::ops::Deref for VmBindOp {
> + type Target = uapi::drm_panthor_vm_bind_op;
> +
> + fn deref(&self) -> &Self::Target {
> + &self.0
> + }
> +}
> +
> +// SAFETY: `VmBindOp` contains only integers, so any bit pattern is valid;
> +// the `#[repr(transparent)]` wrapper has the same layout as the UAPI struct.
> +unsafe impl FromBytes for VmBindOp {}
> diff --git a/drivers/gpu/drm/tyr/vm.rs b/drivers/gpu/drm/tyr/vm.rs
> index 76c3d60bb2fe2..610bab69c1a55 100644
> --- a/drivers/gpu/drm/tyr/vm.rs
> +++ b/drivers/gpu/drm/tyr/vm.rs
> @@ -10,6 +10,10 @@
> use core::marker::PhantomData;
> use core::num::NonZeroU64;
> use core::ops::Range;
> +use core::sync::atomic::{
> + AtomicBool,
> + Ordering, //
> +};
>
> use kernel::{
> device::{
> @@ -437,6 +441,8 @@ pub(crate) struct Vm<'drm> {
> gpuvm: ARef<GpuVm<GpuVmData<'drm>>>,
> /// VA layout for this VM.
> pub(crate) layout: VmLayout,
> + /// Whether the VM is unusable.
> + unusable: AtomicBool,
Atomic<bool>
> }
>
> impl<'drm> Vm<'drm> {
> @@ -496,6 +502,7 @@ pub(crate) fn new(
> gpuvm,
> gpuvm_unique <- new_mutex!(gpuvm_unique),
> layout,
> + unusable: AtomicBool::new(false),
> }),
> GFP_KERNEL,
> )?;
> @@ -526,7 +533,7 @@ fn deactivate(&self) -> Result {
>
> /// Kills the VM by deactivating it and unmapping all regions.
> pub(crate) fn kill(&self) {
> - // TODO: Turn the VM into a state where it can't be used.
> + self.mark_unusable();
> let _ = self.deactivate();
> let _ = self
> .unmap_range(
> @@ -538,6 +545,15 @@ pub(crate) fn kill(&self) {
> });
> }
>
> + /// Marks the VM unusable.
> + pub(crate) fn mark_unusable(&self) {
> + self.unusable.store(true, Ordering::Release);
> + }
> +
> + pub(crate) fn is_unusable(&self) -> bool {
> + self.unusable.load(Ordering::Acquire)
> + }
> +
> /// Executes a virtual memory operation.
> ///
> /// This handles both map and unmap operations by coordinating between the
> @@ -649,6 +665,12 @@ pub(crate) fn map_bo_range(
> };
> let result = {
> let mut gpuvm_unique = self.gpuvm_unique.lock();
> + // Check under the GPUVM lock so a concurrent `mark_unusable()`
> + // teardown cannot race with this operation.
> + if self.is_unusable() {
> + dev_err!(self.dev, "Cannot map on unusable VM\n");
Can you improve the wording a bit on these messages?
> + return Err(EINVAL);
> + }
> self.exec_op(gpuvm_unique.as_mut().get_mut(), req, &mut resources)
> };
> // We flush the defer cleanup list now. Things will be different in
>
> --
> 2.43.0
>
>
next prev parent reply other threads:[~2026-09-04 18:45 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-01 16:08 [PATCH 0/9] drm/tyr: add VM and BO ioctl support Ke Sun via B4 Relay
2026-09-01 16:09 ` [PATCH 1/9] rust: sizes: add SZ_4G constant Ke Sun via B4 Relay
2026-09-02 12:57 ` Daniel Almeida
2026-09-01 16:09 ` [PATCH 2/9] rust: mm: add `task_size` helper Ke Sun via B4 Relay
2026-09-03 13:09 ` Daniel Almeida
2026-09-01 16:09 ` [PATCH 3/9] rust: sync: arc: relax `ForeignOwnable` for `Arc<T>` Ke Sun via B4 Relay
2026-09-03 13:12 ` Daniel Almeida
2026-09-01 16:09 ` [PATCH 4/9] drm/tyr: add per-file VM pool Ke Sun via B4 Relay
2026-09-03 17:51 ` Daniel Almeida
2026-09-01 16:09 ` [PATCH 5/9] drm/tyr: add user and MCU VM specifications Ke Sun via B4 Relay
2026-09-03 18:10 ` Daniel Almeida
2026-09-01 16:09 ` [PATCH 6/9] drm/tyr: add BO creation and lookup helpers Ke Sun via B4 Relay
2026-09-03 22:06 ` Daniel Almeida
2026-09-01 16:09 ` [PATCH 7/9] drm/tyr: refactor new_dummy_object to use new_object Ke Sun via B4 Relay
2026-09-03 22:16 ` Daniel Almeida
2026-09-01 16:09 ` [PATCH 8/9] drm/tyr: add VM-related ioctls Ke Sun via B4 Relay
2026-09-04 18:44 ` Daniel Almeida [this message]
2026-09-01 16:09 ` [PATCH 9/9] drm/tyr: add BO-related ioctls Ke Sun via B4 Relay
2026-09-04 20:35 ` Daniel Almeida
2026-09-02 0:14 ` [PATCH 0/9] drm/tyr: add VM and BO ioctl support Deborah Brouwer
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=C59E65EF-33E6-449A-B109-307231B49057@collabora.com \
--to=daniel.almeida@collabora.com \
--cc=a.hindborg@kernel.org \
--cc=acourbot@nvidia.com \
--cc=airlied@gmail.com \
--cc=aliceryhl@google.com \
--cc=alvin.sun@linux.dev \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun@kernel.org \
--cc=dakr@kernel.org \
--cc=dri-devel@lists.freedesktop.org \
--cc=gary@garyguo.net \
--cc=liam@infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=ljs@kernel.org \
--cc=lossin@kernel.org \
--cc=lyude@redhat.com \
--cc=ojeda@kernel.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=simona@ffwll.ch \
--cc=sunke@kylinos.cn \
--cc=tamird@kernel.org \
--cc=tmgross@umich.edu \
--cc=work@onurozkan.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox