From nobody Sat Feb 7 17:41:07 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1A021303A0D for ; Fri, 6 Feb 2026 22:35:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770417335; cv=none; b=LlXiMX+mXFAfF6eV47saj++HmNHFXWYqncdsHMPHzXseju2+E5J+ieuT7oCr4yTDezcTIor8uwoKiERxJwu7TXTgfN9jytIvpAzS9eWK91xpNy9JoZfaSHu8V+uU8TuuknU3SOA0fQk5JIVUQphstBGQzLXIgdJgB8h1/0uLcV8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770417335; c=relaxed/simple; bh=/oMWpuRLs8/k5PeqrobArDGGSOaJ8tdgRndRzKhzJNw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=DhF6OtXC6xSt17SJtp+Szx6+Q8bM/k3L58paP7wyHDuqcLWQaH2H+OTqIGUaKlH/CsM9kZjlz2eHINPI6HMIkOJJIk1oKEsk3CBEXtJmOIR3vcTZMyoJ1SuU+nM62DVguRoGAls5+SLEQm2U8jFfnJmGqmoAJsR4wcMYARJyVUA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=C2CWIBIT; arc=none smtp.client-ip=170.10.129.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="C2CWIBIT" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1770417334; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=4YK+4HwwquBYeIuxYMPDw1j2BgvfAbpgHtDrxAyiwYs=; b=C2CWIBITRFeBKOInHTdFvxVT5W8Xsjy2hof7z/T4iQIPaxBRdOZ76yFFcLPxR6Zq4Mgr9f Hos7HGTLJPcQVKT60un+7Tj65juW9APSmP1/z6Y6hDtixwYy848ni2PgC74Aw3GKG/y4Nn WKTKEFyMBl+h2fg6tEqtgFxjPwMdFYM= Received: from mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-269-oAs-S85qMCSvgldeCpQXPg-1; Fri, 06 Feb 2026 17:35:30 -0500 X-MC-Unique: oAs-S85qMCSvgldeCpQXPg-1 X-Mimecast-MFC-AGG-ID: oAs-S85qMCSvgldeCpQXPg_1770417328 Received: from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id AB00A1956095; Fri, 6 Feb 2026 22:35:28 +0000 (UTC) Received: from GoldenWind.redhat.com (unknown [10.22.64.226]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id B9647192C7C3; Fri, 6 Feb 2026 22:35:26 +0000 (UTC) From: Lyude Paul To: linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, rust-for-linux@vger.kernel.org, Danilo Krummrich Cc: nouveau@lists.freedesktop.org, Daniel Almeida , Gary Guo , Benno Lossin , Alexandre Courbot , Janne Grunau Subject: [PATCH v7 1/7] rust: drm: gem: Add raw_dma_resv() function Date: Fri, 6 Feb 2026 17:34:25 -0500 Message-ID: <20260206223431.693765-2-lyude@redhat.com> In-Reply-To: <20260206223431.693765-1-lyude@redhat.com> References: <20260206223431.693765-1-lyude@redhat.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.0 on 10.30.177.17 Content-Type: text/plain; charset="utf-8" For retrieving a pointer to the struct dma_resv for a given GEM object. We also introduce it in a new trait, BaseObjectPrivate, which we automatically implement for all gem objects and don't expose to users outside of the crate. Signed-off-by: Lyude Paul Reviewed-by: Janne Grunau --- rust/kernel/drm/gem/mod.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/rust/kernel/drm/gem/mod.rs b/rust/kernel/drm/gem/mod.rs index e1cc3af8ade9b..82b3151e5ae3b 100644 --- a/rust/kernel/drm/gem/mod.rs +++ b/rust/kernel/drm/gem/mod.rs @@ -197,6 +197,18 @@ fn create_mmap_offset(&self) -> Result { =20 impl BaseObject for T {} =20 +/// Crate-private base operations shared by all GEM object classes. +#[expect(unused)] +pub(crate) trait BaseObjectPrivate: IntoGEMObject { + /// Return a pointer to this object's dma_resv. + fn raw_dma_resv(&self) -> *mut bindings::dma_resv { + // SAFETY: `as_gem_obj()` always returns a valid pointer to the ba= se DRM gem object + unsafe { (*self.as_raw()).resv } + } +} + +impl BaseObjectPrivate for T {} + /// A base GEM object. /// /// # Invariants --=20 2.53.0 From nobody Sat Feb 7 17:41:08 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 698AD311C2E for ; Fri, 6 Feb 2026 22:35:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770417336; cv=none; b=d6kuwAKeuHgls1T0hPgVqtGVUsr1oMF1Y4Q5sirN+w1riI6Q0cxyxqHjgvG/AwK6YUaf63ST/ERUj0z2Uq/raoK3fq0zVgEBrot/dx0hZUxsNAXfp2QjBSj/goE6JNKSlsHmVeD5MinPifnbQij3mxPKlJqzqiu0FcekjBsNX/g= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770417336; c=relaxed/simple; bh=YMYBu9jkhGJ37Ax3uV4TPVaN2J4lFLdXY2yyaHggbXw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=rnb35d1PvoCj5hnCUKPLfgoMxooaiXnqVo4QZahRJpDXC5gihFWvt2tI0d5k7bQF8qOWJqAmU7R955mmKwsrUwWEKB6250t3ey+hKr7Z8o8BpqD0jGCOiwQSYZONSLofsO1FDXk6ogK3/KGHBO0iNy9k4ZoQKys+10lYxJ5NirE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=Mx2xWK/8; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="Mx2xWK/8" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1770417335; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=UE4XXKfvvfpryLgAXCbkxE22KwoSFTyQYL9Yz6BCPbk=; b=Mx2xWK/8oPzv313fK7/CYbkX0G5njvGjNhLkEppHDJ74WfDxwU9gV+zAm7QdNvXBRDPRdL 7Fm4t5gtdIJsWL/+CXBJcNBvnohucJ7nhhacnMegTtay4+T4cxx8Uoh8dkdiHl7PX+//ep jawZzFMBiXI2xMQLL6iWFxLN2aEuXvY= Received: from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-250-pS5TagS7PL26vwJxbZ23IQ-1; Fri, 06 Feb 2026 17:35:32 -0500 X-MC-Unique: pS5TagS7PL26vwJxbZ23IQ-1 X-Mimecast-MFC-AGG-ID: pS5TagS7PL26vwJxbZ23IQ_1770417330 Received: from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 7C8D51955F20; Fri, 6 Feb 2026 22:35:30 +0000 (UTC) Received: from GoldenWind.redhat.com (unknown [10.22.64.226]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id DBA9E19373D8; Fri, 6 Feb 2026 22:35:28 +0000 (UTC) From: Lyude Paul To: linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, rust-for-linux@vger.kernel.org, Danilo Krummrich Cc: nouveau@lists.freedesktop.org, Daniel Almeida , Gary Guo , Benno Lossin , Alexandre Courbot , Janne Grunau Subject: [PATCH v7 2/7] rust: helpers: Add bindings/wrappers for dma_resv_lock Date: Fri, 6 Feb 2026 17:34:26 -0500 Message-ID: <20260206223431.693765-3-lyude@redhat.com> In-Reply-To: <20260206223431.693765-1-lyude@redhat.com> References: <20260206223431.693765-1-lyude@redhat.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.0 on 10.30.177.17 Content-Type: text/plain; charset="utf-8" From: Asahi Lina This is just for basic usage in the DRM shmem abstractions for implied locking, not intended as a full DMA Reservation abstraction yet. Signed-off-by: Asahi Lina Signed-off-by: Daniel Almeida Reviewed-by: Alice Ryhl Reviewed-by: Janne Grunau Signed-off-by: Lyude Paul --- rust/bindings/bindings_helper.h | 1 + rust/helpers/dma-resv.c | 13 +++++++++++++ rust/helpers/helpers.c | 1 + 3 files changed, 15 insertions(+) create mode 100644 rust/helpers/dma-resv.c diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helpe= r.h index 9fdf76ca630e0..ecf31681df806 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -48,6 +48,7 @@ #include #include #include +#include #include #include #include diff --git a/rust/helpers/dma-resv.c b/rust/helpers/dma-resv.c new file mode 100644 index 0000000000000..05501cb814513 --- /dev/null +++ b/rust/helpers/dma-resv.c @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include + +int rust_helper_dma_resv_lock(struct dma_resv *obj, struct ww_acquire_ctx = *ctx) +{ + return dma_resv_lock(obj, ctx); +} + +void rust_helper_dma_resv_unlock(struct dma_resv *obj) +{ + dma_resv_unlock(obj); +} diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c index 79c72762ad9c4..1d3333cc0d2a8 100644 --- a/rust/helpers/helpers.c +++ b/rust/helpers/helpers.c @@ -25,6 +25,7 @@ #include "cred.c" #include "device.c" #include "dma.c" +#include "dma-resv.c" #include "drm.c" #include "err.c" #include "irq.c" --=20 2.53.0 From nobody Sat Feb 7 17:41:08 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 39D1B311959 for ; Fri, 6 Feb 2026 22:35:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770417336; cv=none; b=MTWl3ZPJ4cl5NftYRcBew7qujIQf8mNa3V7DWAkLlMpADp+Po3vOTzrElzvlMfJs41L19kGBHZ+z4pk2BKixPfMYHSAtnWKboK6gWsJ3immbBXdgymnYTajgH7KxLGN0mVt3YhbbyxTNHHskPZejQaygMVCEQzcIT8cZUlt4Muw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770417336; c=relaxed/simple; bh=EWiLw56o2oAZvOESwic91wCfnm+084u+xkfD3e0P20M=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=XYUzp2tQGksoTTdBIvloRLIVBr6cAN1FjJl8wdFaI+6njyHn4HxyL0jsEEb1C59uIsik1ZafUH3wcTp8Ii3FGV90zLxe53wMwTudcxVKLPfUvkf+oeCHem9NMgWW9QYjtzwrTmEeTces/zPtN4JRxxVF5fmaUMjDSxLhWB+/yco= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=Ekw3DqL3; arc=none smtp.client-ip=170.10.129.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="Ekw3DqL3" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1770417335; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=gnS6QBaaX/P+IP6sZlPsB51TH+wxpemSFsKbutcNRhU=; b=Ekw3DqL3d1y701CbFeQgJDOYLO897/PglH3IHA4iQxIvL/BSbn6cK7oUzd/Mm0mYCltxFy VsDGNU8RaCDBsknLr12Ct+ZiEhtlGD18FoFJy6z3CR4e3MOEaEoXYQkPSP9zu2VSSg92Ne IOmVU3WbZGqWRrdsMk1jXpKAmhIayLQ= Received: from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-447-tOO4xw6nO3mXd-uRF53sIg-1; Fri, 06 Feb 2026 17:35:34 -0500 X-MC-Unique: tOO4xw6nO3mXd-uRF53sIg-1 X-Mimecast-MFC-AGG-ID: tOO4xw6nO3mXd-uRF53sIg_1770417332 Received: from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 528131955F23; Fri, 6 Feb 2026 22:35:32 +0000 (UTC) Received: from GoldenWind.redhat.com (unknown [10.22.64.226]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id AEC46192C7C3; Fri, 6 Feb 2026 22:35:30 +0000 (UTC) From: Lyude Paul To: linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, rust-for-linux@vger.kernel.org, Danilo Krummrich Cc: nouveau@lists.freedesktop.org, Daniel Almeida , Gary Guo , Benno Lossin , Alexandre Courbot , Janne Grunau Subject: [PATCH v7 3/7] rust: gem: Introduce DriverObject::Args Date: Fri, 6 Feb 2026 17:34:27 -0500 Message-ID: <20260206223431.693765-4-lyude@redhat.com> In-Reply-To: <20260206223431.693765-1-lyude@redhat.com> References: <20260206223431.693765-1-lyude@redhat.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.0 on 10.30.177.17 Content-Type: text/plain; charset="utf-8" This is an associated type that may be used in order to specify a data-type to pass to gem objects when construction them, allowing for drivers to more easily initialize their private-data for gem objects. Signed-off-by: Lyude Paul Reviewed-by: Alice Ryhl Reviewed-by: Daniel Almeida Reviewed-by: Janne Grunau --- V3: * s/BaseDriverObject/DriverObject/ V4: * Fix leftover reference to BaseObjectDriver in rustdoc for DriverObject::Args V6: * Fix build errors in Tyr drivers/gpu/drm/nova/gem.rs | 5 +++-- drivers/gpu/drm/tyr/gem.rs | 3 ++- rust/kernel/drm/gem/mod.rs | 13 ++++++++++--- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/nova/gem.rs b/drivers/gpu/drm/nova/gem.rs index 2760ba4f3450b..173077eeb2def 100644 --- a/drivers/gpu/drm/nova/gem.rs +++ b/drivers/gpu/drm/nova/gem.rs @@ -18,8 +18,9 @@ pub(crate) struct NovaObject {} =20 impl gem::DriverObject for NovaObject { type Driver =3D NovaDriver; + type Args =3D (); =20 - fn new(_dev: &NovaDevice, _size: usize) -> impl PinInit { + fn new(_dev: &NovaDevice, _size: usize, _args: Self::Args) -> impl Pin= Init { try_pin_init!(NovaObject {}) } } @@ -33,7 +34,7 @@ pub(crate) fn new(dev: &NovaDevice, size: usize) -> Resul= t impl PinInit { + fn new(_dev: &TyrDevice, _size: usize, _args: ()) -> impl PinInit { try_pin_init!(TyrObject {}) } } diff --git a/rust/kernel/drm/gem/mod.rs b/rust/kernel/drm/gem/mod.rs index 82b3151e5ae3b..972d50d4342dd 100644 --- a/rust/kernel/drm/gem/mod.rs +++ b/rust/kernel/drm/gem/mod.rs @@ -62,8 +62,15 @@ pub trait DriverObject: Sync + Send + Sized { /// Parent `Driver` for this object. type Driver: drm::Driver; =20 + /// The data type to use for passing arguments to [`DriverObject::new`= ]. + type Args; + /// Create a new driver data object for a GEM object of a given size. - fn new(dev: &drm::Device, size: usize) -> impl PinInit; + fn new( + dev: &drm::Device, + size: usize, + args: Self::Args, + ) -> impl PinInit; =20 /// Open a new handle to an existing object, associated with a File. fn open(_obj: &::Object, _file: &DriverFi= le) -> Result { @@ -242,11 +249,11 @@ impl Object { }; =20 /// Create a new GEM object. - pub fn new(dev: &drm::Device, size: usize) -> Result> { + pub fn new(dev: &drm::Device, size: usize, args: T::Args) -= > Result> { let obj: Pin> =3D KBox::pin_init( try_pin_init!(Self { obj: Opaque::new(bindings::drm_gem_object::default()), - data <- T::new(dev, size), + data <- T::new(dev, size, args), }), GFP_KERNEL, )?; --=20 2.53.0 From nobody Sat Feb 7 17:41:08 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 52B6D30FC1D for ; Fri, 6 Feb 2026 22:35:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770417340; cv=none; b=RCrZipmPKKiLTgsh++Z6ddsiaZZLs3TlkNlwqRQbgDq9AjWLLBvM+LrsNmvEsgHjtXADF5Bk55yv29hIo/BtN3P2iN8fwrvvLEU7mK7Q2s5Z9zJxVTJx359DwuO/zHccUU14ujVNTA4/FFQA7R9F2Ts1qPFk7CAcQbX4UU0bEOQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770417340; c=relaxed/simple; bh=ctr6Hcp8qg6uBY93hj51stz3R/k8enzH7CXZP0bBMs0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=p/n5HnbHsZFBVjvhML49L/SExLL/I9lDOZikGzKs6wmLSl+98J1Syho/TZwC8LmrF7dMFJrDRynKipE0Ctm5sdoOOSznHe/ZkIqbNJqVXoSGewTEXvHlnXfrohlAhUTeniuzd4bIv0H3EFgBFeZbiuQnoV516kyoRAd0aZF2xRg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=iPo9NsFx; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="iPo9NsFx" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1770417339; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=9euFRlRybiqyIkGhxAechFyyFU8lqI1wOTeJ94GcvRQ=; b=iPo9NsFxOLdAmwVKOTrsLgYjc0P4xyluL6FL3ouGVMtXCgk+FKZNlNIapideDPW/cMtGhJ JCUZ9Jxzpkig8av/WORfSZiqKxmgDLauOp+P0j0Ku3/+l0kH6Rl0rE4zDV/owHPPjTxkSH 8r9UJaFgGJ6gYhnVEqHtDxL+IXxeA08= Received: from mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-76-S0Rr-4lRPTSNnwAxJkwdRw-1; Fri, 06 Feb 2026 17:35:36 -0500 X-MC-Unique: S0Rr-4lRPTSNnwAxJkwdRw-1 X-Mimecast-MFC-AGG-ID: S0Rr-4lRPTSNnwAxJkwdRw_1770417334 Received: from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 4E3D01956089; Fri, 6 Feb 2026 22:35:34 +0000 (UTC) Received: from GoldenWind.redhat.com (unknown [10.22.64.226]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 852B719373D8; Fri, 6 Feb 2026 22:35:32 +0000 (UTC) From: Lyude Paul To: linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, rust-for-linux@vger.kernel.org, Danilo Krummrich Cc: nouveau@lists.freedesktop.org, Daniel Almeida , Gary Guo , Benno Lossin , Alexandre Courbot , Janne Grunau Subject: [PATCH v7 4/7] rust: drm: gem: shmem: Add DRM shmem helper abstraction Date: Fri, 6 Feb 2026 17:34:28 -0500 Message-ID: <20260206223431.693765-5-lyude@redhat.com> In-Reply-To: <20260206223431.693765-1-lyude@redhat.com> References: <20260206223431.693765-1-lyude@redhat.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.0 on 10.30.177.17 From: Asahi Lina The DRM shmem helper includes common code useful for drivers which allocate GEM objects as anonymous shmem. Add a Rust abstraction for this. Drivers can choose the raw GEM implementation or the shmem layer, depending on their needs. Signed-off-by: Asahi Lina Signed-off-by: Daniel Almeida Signed-off-by: Lyude Paul --- V2: * Use the drm_gem_shmem_init() and drm_gem_shmem_release() that I extracted so we can handle memory allocation in rust, which means we no longer have to handle freeing rust members of the struct by hand and have a closer implementation to the main gem object (this also gets rid of gem_create_object) * Get rid of GemObjectRef and UniqueGemObjectRef, we have ARef at home. * Use Device in Object * Cleanup Object::::new() a bit: * Cleanup safety comment * Use cast_mut() * Just import container_of!(), we use it all over anyhow * mut_shmem() -> as_shmem(), make it safe (there's no reason for being unsa= fe) * Remove any *const and *muts in structs, just use NonNull * Get rid of the previously hand-rolled sg_table bindings in shmem, use the bindings from Abdiel's sg_table patch series * Add a TODO at the top about DMA reservation APIs and a desire for WwMutex * Get rid of map_wc() and replace it with a new ObjectConfig struct. While it currently only specifies the map_wc flag, the idea here is that settings like map_wc() and parent_resv_obj() shouldn't be exposed as normal functions since the only place where it's safe to set them is when we're still guaranteed unique access to the GEM object, e.g. before returning it to the caller. Using a struct instead of individual arguments here is mainly because we'll be adding at least one more argument, and there's enough other gem shmem settings that trying to add all of them as individual function arguments in the future would be a bit messy. * Get rid of vm_numa_fields!, Lina didn't like this macro much either and I think that it's fine for us to just specify the #[cfg(=E2=80=A6)] attribu= tes by hand since we only need to do it twice. * Set drm_gem_object_funcs.vm_ops directly to drm_gem_shmem_vm_ops, don't export the various shmem funcs. I'm not sure why this wasn't possible before but it seems to work fine now. V4: * Switch from OpaqueObject to a normal Object now that we've removed it * Remove `dev` from Object, it's redundant as drm_gem_object already has a device pointer we can use. * Use &raw instead of addr_of!() V5: * Fix typo in shmem::Object::as_raw() * Add type invariant around `obj` always being a valid `drm_gem_shmem_object` for the duration of the lifetime of `Object`. * Use Opaque::cast_from() instead of unrestricted casts * Use IS_ENABLED() for gem shmem C helpers. V7: * Fix import style * Don't forget to make Object Send/Sync rust/bindings/bindings_helper.h | 2 + rust/helpers/drm.c | 56 ++++++- rust/kernel/drm/gem/mod.rs | 5 +- rust/kernel/drm/gem/shmem.rs | 249 ++++++++++++++++++++++++++++++++ 4 files changed, 310 insertions(+), 2 deletions(-) create mode 100644 rust/kernel/drm/gem/shmem.rs diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helpe= r.h index ecf31681df806..c93afbd095e87 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -61,6 +62,7 @@ #include #include #include +#include #include #include #include diff --git a/rust/helpers/drm.c b/rust/helpers/drm.c index 450b406c6f273..53ec06879db3d 100644 --- a/rust/helpers/drm.c +++ b/rust/helpers/drm.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 =20 #include +#include #include =20 #ifdef CONFIG_DRM @@ -20,4 +21,57 @@ __u64 rust_helper_drm_vma_node_offset_addr(struct drm_vm= a_offset_node *node) return drm_vma_node_offset_addr(node); } =20 -#endif +#if IS_ENABLED(CONFIG_DRM_GEM_SHMEM_HELPER) +__rust_helper void +rust_helper_drm_gem_shmem_object_free(struct drm_gem_object *obj) +{ + return drm_gem_shmem_object_free(obj); +} + +__rust_helper void +rust_helper_drm_gem_shmem_object_print_info(struct drm_printer *p, unsigne= d int indent, + const struct drm_gem_object *obj) +{ + drm_gem_shmem_object_print_info(p, indent, obj); +} + +__rust_helper int +rust_helper_drm_gem_shmem_object_pin(struct drm_gem_object *obj) +{ + return drm_gem_shmem_object_pin(obj); +} + +__rust_helper void +rust_helper_drm_gem_shmem_object_unpin(struct drm_gem_object *obj) +{ + drm_gem_shmem_object_unpin(obj); +} + +__rust_helper struct sg_table * +rust_helper_drm_gem_shmem_object_get_sg_table(struct drm_gem_object *obj) +{ + return drm_gem_shmem_object_get_sg_table(obj); +} + +__rust_helper int +rust_helper_drm_gem_shmem_object_vmap(struct drm_gem_object *obj, + struct iosys_map *map) +{ + return drm_gem_shmem_object_vmap(obj, map); +} + +__rust_helper void +rust_helper_drm_gem_shmem_object_vunmap(struct drm_gem_object *obj, + struct iosys_map *map) +{ + drm_gem_shmem_object_vunmap(obj, map); +} + +__rust_helper int +rust_helper_drm_gem_shmem_object_mmap(struct drm_gem_object *obj, struct v= m_area_struct *vma) +{ + return drm_gem_shmem_object_mmap(obj, vma); +} + +#endif /* CONFIG_DRM_GEM_SHMEM_HELPER */ +#endif /* CONFIG_DRM */ diff --git a/rust/kernel/drm/gem/mod.rs b/rust/kernel/drm/gem/mod.rs index 972d50d4342dd..379ae3dfb02f5 100644 --- a/rust/kernel/drm/gem/mod.rs +++ b/rust/kernel/drm/gem/mod.rs @@ -3,6 +3,8 @@ //! DRM GEM API //! //! C header: [`include/drm/drm_gem.h`](srctree/include/drm/drm_gem.h) +#[cfg(CONFIG_DRM_GEM_SHMEM_HELPER)] +pub mod shmem; =20 use crate::{ alloc::flags::*, @@ -50,6 +52,8 @@ unsafe fn dec_ref(obj: core::ptr::NonNull) { }; } =20 +pub(crate) use impl_aref_for_gem_obj; + /// A type alias for retrieving a [`Driver`]s [`DriverFile`] implementatio= n from its /// [`DriverObject`] implementation. /// @@ -205,7 +209,6 @@ fn create_mmap_offset(&self) -> Result { impl BaseObject for T {} =20 /// Crate-private base operations shared by all GEM object classes. -#[expect(unused)] pub(crate) trait BaseObjectPrivate: IntoGEMObject { /// Return a pointer to this object's dma_resv. fn raw_dma_resv(&self) -> *mut bindings::dma_resv { diff --git a/rust/kernel/drm/gem/shmem.rs b/rust/kernel/drm/gem/shmem.rs new file mode 100644 index 0000000000000..d9f1a4e95cedc --- /dev/null +++ b/rust/kernel/drm/gem/shmem.rs @@ -0,0 +1,249 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! DRM GEM shmem helper objects +//! +//! C header: [`include/linux/drm/drm_gem_shmem_helper.h`](srctree/include= /linux/drm/drm_gem_shmem_helper.h) + +// TODO: +// - There are a number of spots here that manually acquire/release the DM= A reservation lock using +// dma_resv_(un)lock(). In the future we should add support for ww mutex= , expose a method to +// acquire a reference to the WwMutex, and then use that directly instea= d of the C functions here. + +use crate::{ + container_of, + drm::{ + device, + driver, + gem, + private::Sealed, // + }, + error::{ + from_err_ptr, + to_result, // + }, + prelude::*, + scatterlist, + types::{ + ARef, + Opaque, // + }, // +}; +use core::{ + ops::{ + Deref, + DerefMut, // + }, + ptr::NonNull, +}; +use gem::{ + BaseObjectPrivate, + DriverObject, + IntoGEMObject, // +}; + +/// A struct for controlling the creation of shmem-backed GEM objects. +/// +/// This is used with [`Object::new()`] to control various properties that= can only be set when +/// initially creating a shmem-backed GEM object. +#[derive(Default)] +pub struct ObjectConfig<'a, T: DriverObject> { + /// Whether to set the write-combine map flag. + pub map_wc: bool, + + /// Reuse the DMA reservation from another GEM object. + /// + /// The newly created [`Object`] will hold an owned refcount to `paren= t_resv_obj` if specified. + pub parent_resv_obj: Option<&'a Object>, +} + +/// A shmem-backed GEM object. +/// +/// # Invariants +/// +/// `obj` contains a valid initialized `struct drm_gem_shmem_object` for t= he lifetime of this +/// object. +#[repr(C)] +#[pin_data] +pub struct Object { + #[pin] + obj: Opaque, + // Parent object that owns this object's DMA reservation object + parent_resv_obj: Option>>, + #[pin] + inner: T, +} + +super::impl_aref_for_gem_obj!(impl for Object where T: DriverObject); + +// SAFETY: All GEM objects are thread-safe. +unsafe impl Send for Object {} + +// SAFETY: All GEM objects are thread-safe. +unsafe impl Sync for Object {} + +impl Object { + /// `drm_gem_object_funcs` vtable suitable for GEM shmem objects. + const VTABLE: bindings::drm_gem_object_funcs =3D bindings::drm_gem_obj= ect_funcs { + free: Some(Self::free_callback), + open: Some(super::open_callback::), + close: Some(super::close_callback::), + print_info: Some(bindings::drm_gem_shmem_object_print_info), + export: None, + pin: Some(bindings::drm_gem_shmem_object_pin), + unpin: Some(bindings::drm_gem_shmem_object_unpin), + get_sg_table: Some(bindings::drm_gem_shmem_object_get_sg_table), + vmap: Some(bindings::drm_gem_shmem_object_vmap), + vunmap: Some(bindings::drm_gem_shmem_object_vunmap), + mmap: Some(bindings::drm_gem_shmem_object_mmap), + status: None, + rss: None, + // SAFETY: `drm_gem_shmem_vm_ops` is static const on the C side, s= o immutable references are + // safe here and such references shall be valid forever + vm_ops: unsafe { &bindings::drm_gem_shmem_vm_ops }, + evict: None, + }; + + /// Return a raw pointer to the embedded drm_gem_shmem_object. + fn as_shmem(&self) -> *mut bindings::drm_gem_shmem_object { + self.obj.get() + } + + /// Create a new shmem-backed DRM object of the given size. + /// + /// Additional config options can be specified using `config`. + pub fn new( + dev: &device::Device, + size: usize, + config: ObjectConfig<'_, T>, + args: T::Args, + ) -> Result> { + let new: Pin> =3D KBox::try_pin_init( + try_pin_init!(Self { + obj <- Opaque::init_zeroed(), + parent_resv_obj: config.parent_resv_obj.map(|p| p.into()), + inner <- T::new(dev, size, args), + }), + GFP_KERNEL, + )?; + + // SAFETY: `obj.as_raw()` is guaranteed to be valid by the initial= ization above. + unsafe { (*new.as_raw()).funcs =3D &Self::VTABLE }; + + // SAFETY: The arguments are all valid via the type invariants. + to_result(unsafe { bindings::drm_gem_shmem_init(dev.as_raw(), new.= as_shmem(), size) })?; + + // SAFETY: We never move out of `self`. + let new =3D KBox::into_raw(unsafe { Pin::into_inner_unchecked(new)= }); + + // SAFETY: We're taking over the owned refcount from `drm_gem_shme= m_init`. + let obj =3D unsafe { ARef::from_raw(NonNull::new_unchecked(new)) }; + + // Start filling out values from `config` + if let Some(parent_resv) =3D config.parent_resv_obj { + // SAFETY: We have yet to expose the new gem object outside of= this function, so it is + // safe to modify this field. + unsafe { (*obj.obj.get()).base.resv =3D parent_resv.raw_dma_re= sv() }; + } + + // SAFETY: We have yet to expose this object outside of this funct= ion, so we're guaranteed + // to have exclusive access - thus making this safe to hold a muta= ble reference to. + let shmem =3D unsafe { &mut *obj.as_shmem() }; + shmem.set_map_wc(config.map_wc); + + Ok(obj) + } + + /// Returns the `Device` that owns this GEM object. + pub fn dev(&self) -> &device::Device { + // SAFETY: `dev` will have been initialized in `Self::new()` by `d= rm_gem_shmem_init()`. + unsafe { device::Device::from_raw((*self.as_raw()).dev) } + } + + extern "C" fn free_callback(obj: *mut bindings::drm_gem_object) { + // SAFETY: + // - DRM always passes a valid gem object here + // - We used drm_gem_shmem_create() in our create_gem_object callb= ack, so we know that + // `obj` is contained within a drm_gem_shmem_object + let this =3D unsafe { container_of!(obj, bindings::drm_gem_shmem_o= bject, base) }; + + // SAFETY: + // - We're in free_callback - so this function is safe to call. + // - We won't be using the gem resources on `this` after this call. + unsafe { bindings::drm_gem_shmem_release(this) }; + + // SAFETY: + // - We verified above that `obj` is valid, which makes `this` val= id + // - This function is set in AllocOps, so we know that `this` is c= ontained within a + // `Object` + let this =3D unsafe { container_of!(Opaque::cast_from(this), Self,= obj) }.cast_mut(); + + // SAFETY: We're recovering the Kbox<> we created in gem_create_ob= ject() + let _ =3D unsafe { KBox::from_raw(this) }; + } + + /// Creates (if necessary) and returns an immutable reference to a sca= tter-gather table of DMA + /// pages for this object. + /// + /// This will pin the object in memory. + #[inline] + pub fn sg_table(&self) -> Result<&scatterlist::SGTable> { + // SAFETY: + // - drm_gem_shmem_get_pages_sgt is thread-safe. + // - drm_gem_shmem_get_pages_sgt returns either a valid pointer to= a scatterlist, or an + // error pointer. + let sgt =3D from_err_ptr(unsafe { bindings::drm_gem_shmem_get_page= s_sgt(self.as_shmem()) })?; + + // SAFETY: We checked above that `sgt` is not an error pointer, so= it must be a valid + // pointer to a scatterlist + Ok(unsafe { scatterlist::SGTable::from_raw(sgt) }) + } +} + +impl Deref for Object { + type Target =3D T; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl DerefMut for Object { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.inner + } +} + +impl Sealed for Object {} + +impl gem::IntoGEMObject for Object { + fn as_raw(&self) -> *mut bindings::drm_gem_object { + // SAFETY: + // - Our immutable reference is proof that this is safe to derefer= ence. + // - `obj` is always a valid drm_gem_shmem_object via our type inv= ariants. + unsafe { &raw mut (*self.obj.get()).base } + } + + unsafe fn from_raw<'a>(obj: *mut bindings::drm_gem_object) -> &'a Obje= ct { + // SAFETY: The safety contract of from_gem_obj() guarantees that `= obj` is contained within + // `Self` + unsafe { + let obj =3D Opaque::cast_from(container_of!(obj, bindings::drm= _gem_shmem_object, base)); + + &*container_of!(obj, Object, obj) + } + } +} + +impl driver::AllocImpl for Object { + type Driver =3D T::Driver; + + const ALLOC_OPS: driver::AllocOps =3D driver::AllocOps { + gem_create_object: None, + prime_handle_to_fd: None, + prime_fd_to_handle: None, + gem_prime_import: None, + gem_prime_import_sg_table: Some(bindings::drm_gem_shmem_prime_impo= rt_sg_table), + dumb_create: Some(bindings::drm_gem_shmem_dumb_create), + dumb_map_offset: None, + }; +} --=20 2.53.0 From nobody Sat Feb 7 17:41:08 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id AE59931280C for ; Fri, 6 Feb 2026 22:35:44 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770417344; cv=none; b=aIJ3wBfzTCsyhRruI7n+vSiP47nkRWR67wQ+69g9cPgzosZk8eVVZ7MOhY2eJGeL4Unfuc7nSpYeYjgZUMPhHdlAybxEQPn2an4rlog5Qb0HH1iFSSisj+dqKnZQbJreoMyZKtOpxlvuWjIlJzbfFlSi7BSIoG/l6gKV2V2au74= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770417344; c=relaxed/simple; bh=b48J/ptqFOanvRTrnTd+5tFeDqKjEGau1q1PRJafq5A=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=hPcLc8al6IDx9GhjjYlKn27h/XRAhYIB/OU2g8HDMFmfNCEG7ZWbRG57oMJfyf20OGiJNZ9MOKERzNUxTaEBg2A94VThy8u7ckXw42LcfveE19tJE/Nedcm2hyCdc46eelKSj5acs+X4aRJHvQHQii3UWKVZFpnCZ7Dy7yvVGIs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=Cl26vHPp; arc=none smtp.client-ip=170.10.129.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="Cl26vHPp" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1770417343; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=dA4Lr51Wu0u2/st5Gqdw788WXkyCFbCBFmbyJoArlzs=; b=Cl26vHPpdfdFXfU/Rc5fJMAbrh+k8w90lwhZYDwpc3hw685X6vJuAXLJ+2pUc7ugJq+hoi M3UsS6sP/FYl9rybx93ACbOWpAGZUF1f51N3L5Fj7oVRhMfzKN0isARpH9fYxxRqcoIybv 3J+2oqO9LmLS/fUNct/q5ZDycOva1tE= Received: from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-227-fVvsHauUPQy471kLmQRcWQ-1; Fri, 06 Feb 2026 17:35:37 -0500 X-MC-Unique: fVvsHauUPQy471kLmQRcWQ-1 X-Mimecast-MFC-AGG-ID: fVvsHauUPQy471kLmQRcWQ_1770417336 Received: from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 0419F1955F27; Fri, 6 Feb 2026 22:35:36 +0000 (UTC) Received: from GoldenWind.redhat.com (unknown [10.22.64.226]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 80C0E19373D8; Fri, 6 Feb 2026 22:35:34 +0000 (UTC) From: Lyude Paul To: linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, rust-for-linux@vger.kernel.org, Danilo Krummrich Cc: nouveau@lists.freedesktop.org, Daniel Almeida , Gary Guo , Benno Lossin , Alexandre Courbot , Janne Grunau Subject: [PATCH v7 5/7] rust: drm: gem: Introduce shmem::SGTable Date: Fri, 6 Feb 2026 17:34:29 -0500 Message-ID: <20260206223431.693765-6-lyude@redhat.com> In-Reply-To: <20260206223431.693765-1-lyude@redhat.com> References: <20260206223431.693765-1-lyude@redhat.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.0 on 10.30.177.17 Content-Type: text/plain; charset="utf-8" Currently we expose the ability to retrieve an SGTable for an shmem gem object using gem::shmem::Object::::sg_table(). However, this only gives us a borrowed reference. This being said - retrieving an SGTable is a fallible operation, and as such it's reasonable that a driver may want to hold onto an SGTable for longer then a reference would allow in order to avoid having to deal with fallibility every time they want to access the SGTable. One such driver with this usecase is the Asahi driver. So to support this, let's introduce shmem::SGTable - which both holds a pointer to the SGTable and a reference to its respective GEM object in order to keep the GEM object alive for as long as the shmem::SGTable. The type can be used identically to a normal SGTable. Signed-off-by: Lyude Paul Reviewed-by: Janne Grunau --- V3: * Rename OwnedSGTable to shmem::SGTable. Since the current version of the SGTable abstractions now has a `Owned` and `Borrowed` variant, I think renaming this to shmem::SGTable makes things less confusing. We do however, keep the name of owned_sg_table() as-is. V4: * Clarify safety comments for SGTable to explain why the object is thread-safe. * Rename from SGTableRef to SGTable rust/kernel/drm/gem/shmem.rs | 50 ++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/rust/kernel/drm/gem/shmem.rs b/rust/kernel/drm/gem/shmem.rs index d9f1a4e95cedc..e511a9b6710e0 100644 --- a/rust/kernel/drm/gem/shmem.rs +++ b/rust/kernel/drm/gem/shmem.rs @@ -197,6 +197,25 @@ pub fn sg_table(&self) -> Result<&scatterlist::SGTable= > { // pointer to a scatterlist Ok(unsafe { scatterlist::SGTable::from_raw(sgt) }) } + + /// Creates (if necessary) and returns an owned reference to a scatter= -gather table of DMA pages + /// for this object. + /// + /// This is the same as [`sg_table`](Self::sg_table), except that it i= nstead returns an + /// [`shmem::SGTable`] which holds a reference to the associated gem o= bject, instead of a + /// reference to an [`scatterlist::SGTable`]. + /// + /// This will pin the object in memory. + /// + /// [`shmem::SGTable`]: SGTable + pub fn owned_sg_table(&self) -> Result> { + Ok(SGTable { + sgt: self.sg_table()?.into(), + // INVARIANT: We take an owned refcount to `self` here, ensuri= ng that `sgt` remains + // valid for as long as this `SGTable`. + _owner: self.into(), + }) + } } =20 impl Deref for Object { @@ -247,3 +266,34 @@ impl driver::AllocImpl for Object { dumb_map_offset: None, }; } + +/// An owned reference to a scatter-gather table of DMA address spans for = a GEM shmem object. +/// +/// This object holds an owned reference to the underlying GEM shmem objec= t, ensuring that the +/// [`scatterlist::SGTable`] referenced by this type remains valid for the= lifetime of this object. +/// +/// # Invariants +/// +/// - `sgt` is kept alive by `_owner`, ensuring it remains valid for as lo= ng as `Self`. +/// - `sgt` corresponds to the owned object in `_owner`. +/// - This object is only exposed in situations where we know the underlyi= ng `SGTable` will not be +/// modified for the lifetime of this object. Thus, it is safe to send/a= ccess this type across +/// threads. +pub struct SGTable { + sgt: NonNull, + _owner: ARef>, +} + +// SAFETY: This object is thread-safe via our type invariants. +unsafe impl Send for SGTable {} +// SAFETY: This object is thread-safe via our type invariants. +unsafe impl Sync for SGTable {} + +impl Deref for SGTable { + type Target =3D scatterlist::SGTable; + + fn deref(&self) -> &Self::Target { + // SAFETY: Creating an immutable reference to this is safe via our= type invariants. + unsafe { self.sgt.as_ref() } + } +} --=20 2.53.0 From nobody Sat Feb 7 17:41:08 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 844B731812E for ; Fri, 6 Feb 2026 22:35:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770417355; cv=none; b=tGwax6ctITdzNdzox7P2Av66HukLHyR4NcPqos7YiPlyyDcBYRLML2Uhdj1+GEmuKZjcIAIEhAXRVy7s/7sR0Z92DQ17BwxnGI0kGAvPMoNv6q5bhGjZHcX3nnjl5JNtR+EwkSmcgDRflSGtE9+tUI/Q+IgXbXLP32w39p9kDCg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770417355; c=relaxed/simple; bh=J5XKZccGctsr4b0dM5P7S5WHAQVlUdSGIHqNL/q9+p0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=SW307Bq60tELHeAEagPSZMeBL0rC+HN9nsk5ixioT+VBZjOdK3Ae4LZukQeVc29oluRp2QB1j7eoN15w/qBuhFGxIZMsm1mgTmHsNNi/Sgb2HAPUU+hXXctcqwuRQE2LXk7RduMVc2NmrymN6f6BCZiE9FddIsy0MZ925xJv7JY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=Liw3CAZe; arc=none smtp.client-ip=170.10.129.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="Liw3CAZe" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1770417354; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=ubWrbzuOvF2ccvY5WkapIB6gOHOp4NqWeBmUs5KhfrE=; b=Liw3CAZes+OJifDqYpMyThOnhu+dYyuiuXA6B8Y/h8qBcwqMg+UknPHBzbnyuKf4Bb27WI Z2w9f0nUkn5vRt6ZEDMGjRqJTLr6OB7b2TNBNtn/ryTBlCtRCFVqMfyTrnWiWiL/pt0IFv lZzx0GFn8l6Qi3tYlwMRKS5Etgrid6M= Received: from mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-615-uf5L_7eDOcONEtUO0AFdgA-1; Fri, 06 Feb 2026 17:35:39 -0500 X-MC-Unique: uf5L_7eDOcONEtUO0AFdgA-1 X-Mimecast-MFC-AGG-ID: uf5L_7eDOcONEtUO0AFdgA_1770417337 Received: from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id AFAD01800349; Fri, 6 Feb 2026 22:35:37 +0000 (UTC) Received: from GoldenWind.redhat.com (unknown [10.22.64.226]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 36D7119373D8; Fri, 6 Feb 2026 22:35:36 +0000 (UTC) From: Lyude Paul To: linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, rust-for-linux@vger.kernel.org, Danilo Krummrich Cc: nouveau@lists.freedesktop.org, Daniel Almeida , Gary Guo , Benno Lossin , Alexandre Courbot , Janne Grunau Subject: [PATCH v7 6/7] rust: Introduce iosys_map bindings Date: Fri, 6 Feb 2026 17:34:30 -0500 Message-ID: <20260206223431.693765-7-lyude@redhat.com> In-Reply-To: <20260206223431.693765-1-lyude@redhat.com> References: <20260206223431.693765-1-lyude@redhat.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.0 on 10.30.177.17 Content-Type: text/plain; charset="utf-8" This introduces a set of bindings for working with iosys_map in rust code using the new Io traits. Signed-off-by: Lyude Paul --- V5: - Fix incorrect field size being passed to iosys_map_memcpy_to() - Add an additional unit test, basic_macro(), which can successfully catch the above issue so it doesn't happen again in the future. V6: - Drop as_slice/as_mut_slice (Alice Rhyl) V7: - Start using Alexandre Courbot's wonderful Io, IoCapable and IoKnownSize traits instead of trying to roll our own IO accessors. This also changes the following: - We don't have a custom AsBytes/FromBytes type that we carry around any longer with maps - We now have optional compile-time size checking - We don't need our own unit tests anymore - RawIoSysMap can be used for unsafe IO operations, because why not. - IoSysMapRef::new() can fail now since it needs to ensure SIZE is valid. - We don't implement Deref for IoSysMapRef any longer. The main reason for this is that we want to avoid users having to manually specify if they want the RawIoSysMap or IoSysMapRef variant functions like io_read()/io_write(). This is fine IMHO, but to make sure things remain easy for APIs that wrap around iosys map we make IoSysMapRef.raw_map pub(crate). rust/helpers/helpers.c | 1 + rust/helpers/iosys_map.c | 34 +++++++ rust/kernel/iosys_map.rs | 211 +++++++++++++++++++++++++++++++++++++++ rust/kernel/lib.rs | 1 + 4 files changed, 247 insertions(+) create mode 100644 rust/helpers/iosys_map.c create mode 100644 rust/kernel/iosys_map.rs diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c index 1d3333cc0d2a8..bd8ad237aa02e 100644 --- a/rust/helpers/helpers.c +++ b/rust/helpers/helpers.c @@ -31,6 +31,7 @@ #include "irq.c" #include "fs.c" #include "io.c" +#include "iosys_map.c" #include "jump_label.c" #include "kunit.c" #include "maple_tree.c" diff --git a/rust/helpers/iosys_map.c b/rust/helpers/iosys_map.c new file mode 100644 index 0000000000000..6861d4ec48a4b --- /dev/null +++ b/rust/helpers/iosys_map.c @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include + +#define rust_iosys_map_rd(type__) = \ + __rust_helper type__ = \ + rust_helper_iosys_map_rd_ ## type__(const struct iosys_map *map, size_t o= ffset) \ + { = \ + return iosys_map_rd(map, offset, type__); \ + } +#define rust_iosys_map_wr(type__) = \ + __rust_helper void = \ + rust_helper_iosys_map_wr_ ## type__(const struct iosys_map *map, size_t o= ffset, \ + type__ value) \ + { = \ + iosys_map_wr(map, offset, type__, value); \ + } + +rust_iosys_map_rd(u8); +rust_iosys_map_rd(u16); +rust_iosys_map_rd(u32); + +rust_iosys_map_wr(u8); +rust_iosys_map_wr(u16); +rust_iosys_map_wr(u32); + +#ifdef CONFIG_64BIT +rust_iosys_map_rd(u64); +rust_iosys_map_wr(u64); +#endif + +#undef rust_iosys_map_rd +#undef rust_iosys_map_wr diff --git a/rust/kernel/iosys_map.rs b/rust/kernel/iosys_map.rs new file mode 100644 index 0000000000000..2070f0fb42cb8 --- /dev/null +++ b/rust/kernel/iosys_map.rs @@ -0,0 +1,211 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! IO-agnostic memory mapping interfaces. +//! +//! This crate provides bindings for the `struct iosys_map` type, which pr= ovides a common interface +//! for memory mappings which can reside within coherent memory, or within= IO memory. +//! +//! C header: [`include/linux/iosys-map.h`](srctree/include/linux/pci.h) + +use crate::{ + error::code::*, + io::{ + Io, + IoCapable, + IoKnownSize, // + }, + prelude::*, // +}; +use bindings; +use core::marker::PhantomData; + +/// Raw unsized representation of a `struct iosys_map`. +/// +/// This struct is a transparent wrapper around `struct iosys_map`. The C = API does not provide the +/// size of the mapping by default, and thus this type also does not inclu= de the size of the +/// mapping. As such, it cannot be used for actually accessing the underly= ing data pointed to by the +/// mapping. +/// +/// With the exception of kernel crates which may provide their own wrappe= rs around `RawIoSysMap`, +/// users will typically not interact with this type directly. +#[repr(transparent)] +pub struct RawIoSysMap(bindings::iosys_map); + +impl RawIoSysMap { + /// Convert from a raw `bindings::iosys_map`. + #[expect(unused)] + #[inline] + pub(crate) fn from_raw(val: bindings::iosys_map) -> Self { + Self(val) + } + + /// Returns whether the mapping is within IO memory space or not. + #[inline] + pub fn is_iomem(&self) -> bool { + self.0.is_iomem + } + + /// Convert from a `RawIoSysMap` to a raw `bindings::iosys_map` = ref. + #[expect(unused)] + #[inline] + pub(crate) fn as_raw(&self) -> &bindings::iosys_map { + &self.0 + } + + /// Convert from a `RawIoSysMap` to a raw mutable `bindings::ios= ys_map` ref. + #[allow(unused)] + #[inline] + pub(crate) fn as_raw_mut(&mut self) -> &mut bindings::iosys_map { + &mut self.0 + } + + /// Returns the address pointed to by this iosys map. + /// + /// Note that this address is not guaranteed to be valid, and may or m= ay not reside in I/O + /// memory. + #[inline] + pub fn addr(&self) -> usize { + (if self.is_iomem() { + // SAFETY: We confirmed above that this iosys map is contained= within iomem, so it's + // safe to read vaddr_iomem + unsafe { self.0.__bindgen_anon_1.vaddr_iomem } + } else { + // SAFETY: We confirmed above that this iosys map is not conta= ned within iomem, so it's + // safe to read vaddr. + unsafe { self.0.__bindgen_anon_1.vaddr } + }) as usize + } +} + +// SAFETY: As we make no guarantees about the validity of the mapping, the= re's no issue with sending +// this type between threads. +unsafe impl Send for RawIoSysMap {} + +impl Clone for RawIoSysMap { + fn clone(&self) -> Self { + Self(self.0) + } +} + +macro_rules! impl_raw_iosys_map_io_capable { + ($ty:ty, $read_fn:ident, $write_fn:ident) =3D> { + impl IoCapable<$ty> for RawIoSysMap { + #[inline(always)] + unsafe fn io_read(&self, address: usize) -> $ty { + // SAFETY: By the trait invariant `address` is a valid add= ress for iosys map + // operations. + unsafe { bindings::$read_fn(&self.0, address) } + } + + #[inline(always)] + unsafe fn io_write(&self, value: $ty, address: usize) { + // SAFETY: By the trait invariant `address` is a valid add= ress for iosys map + // operations. + unsafe { bindings::$write_fn(&self.0, address, value) }; + } + } + }; +} + +impl_raw_iosys_map_io_capable!(u8, iosys_map_rd_u8, iosys_map_wr_u8); +impl_raw_iosys_map_io_capable!(u16, iosys_map_rd_u16, iosys_map_wr_u16); +impl_raw_iosys_map_io_capable!(u32, iosys_map_rd_u32, iosys_map_wr_u32); +#[cfg(CONFIG_64BIT)] +impl_raw_iosys_map_io_capable!(u64, iosys_map_rd_u64, iosys_map_wr_u64); + +/// A sized version of a [`RawIoSysMap`]. +/// +/// This type includes the runtime size of the [`RawIoSysMap`] and can be = used for checked I/O +/// operations. +/// +/// # Invariants +/// +/// - The iosys mapping referenced by this type is guaranteed to be of at = least `size` bytes in +/// size +/// - The iosys mapping referenced by this type is valid for the lifetime = `'a`. +#[derive(Clone)] +pub struct IoSysMapRef<'a, const SIZE: usize =3D 0> { + pub(crate) raw_map: RawIoSysMap, + size: usize, + _p: PhantomData<&'a ()>, +} + +impl<'a, const SIZE: usize> IoSysMapRef<'a, SIZE> { + /// Create a new [`IoSysMapRef`] from a [`RawIoSysMap`]. + /// + /// Returns an error if the specified size is invalid. + /// + /// # Safety + /// + /// - The caller guarantees that the mapping is of at least `size` byt= es. + /// - The caller guarantees that the mapping remains valid for the lif= etime of `'a`. + #[expect(unused)] + pub(crate) unsafe fn new(map: RawIoSysMap, size: usize) -> Resul= t { + if size < SIZE { + return Err(EINVAL); + } + + Ok(Self { + raw_map: map, + size, + _p: PhantomData, + }) + } + + /// Returns whether the mapping is within IO memory space or not. + #[inline] + pub fn is_iomem(&self) -> bool { + self.raw_map.is_iomem() + } + + /// Returns the address pointed to by this iosys map. + /// + /// Note that this address is not guaranteed to be valid, and may or m= ay not reside in I/O + /// memory. + #[inline] + pub fn addr(&self) -> usize { + self.raw_map.addr() + } +} + +macro_rules! impl_iosys_map_io_capable { + ($ty:ty) =3D> { + impl<'a, const SIZE: usize> IoCapable<$ty> for IoSysMapRef<'a, SIZ= E> { + #[inline(always)] + unsafe fn io_read(&self, address: usize) -> $ty { + // SAFETY: By the trait invariant `address` is a valid add= ress for iosys map + // operations. + unsafe { self.raw_map.io_read(address) } + } + + #[inline(always)] + unsafe fn io_write(&self, value: $ty, address: usize) { + // SAFETY: By the trait invariant `address` is a valid add= ress for iosys map + // operations. + unsafe { self.raw_map.io_write(value, address) }; + } + } + }; +} + +impl_iosys_map_io_capable!(u8); +impl_iosys_map_io_capable!(u16); +impl_iosys_map_io_capable!(u32); +#[cfg(CONFIG_64BIT)] +impl_iosys_map_io_capable!(u64); + +impl<'a, const SIZE: usize> Io for IoSysMapRef<'a, SIZE> { + #[inline] + fn addr(&self) -> usize { + self.raw_map.addr() + } + + #[inline] + fn maxsize(&self) -> usize { + self.size + } +} + +impl<'a, const SIZE: usize> IoKnownSize for IoSysMapRef<'a, SIZE> { + const MIN_SIZE: usize =3D SIZE; +} diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 6d637e2fed1b6..02385af66fde2 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -103,6 +103,7 @@ pub mod init; pub mod io; pub mod ioctl; +pub mod iosys_map; pub mod iov; pub mod irq; pub mod jump_label; --=20 2.53.0 From nobody Sat Feb 7 17:41:08 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 82D643161AE for ; Fri, 6 Feb 2026 22:35:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770417347; cv=none; b=XjmpB1IA1OMmZRtzVurKTKXf+KdHLIuZMh42NCg3PRwexe7PR/sHGCgQ9z+xQ20mgP4KjRJLqhMBONSbzfHAM9erGZ0Q32CvOSgNnWc9YOUMWLVYAMpupv1FTkBesQ+lAhVSEDpeWH89rpSNUTMz9ht202/M7TzmtaVNY26CniA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770417347; c=relaxed/simple; bh=RN/nEAE1lIEvZ+S6m8XaJKvBL7hfqsvNE/ElFlRmFKM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=RvC+IxHKMluI4Y7Qct/WsJFDhRAda5GwTEtw4JbkthFWksfx/5ubQ1Ob3FKRAISI6olm+pQtyAYt8fpoJ+fCdqG5kbM45ZINF0ScMIUlGrglzIF1OKJwvJpG51Tgs53NEfvUXWHQGXVAu5L+UeKKGyvusOREZ2jjw40PpBCaU0Q= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=CVTF+Czs; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="CVTF+Czs" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1770417346; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=zTebqQ2eipm8YqiSwO1TAoGzLEbFz+blNfHKTyJxzv0=; b=CVTF+CzsaWdssIDtSqNjIP9xkQahXDXWe8OaWNLup3PronQ5r9miwJclYxCUp4zdI1paL8 AdDPiHskiK3TZfUarueceTTbvg7GrWydy1AMV77rqWCV8+ENLnf9sXL/pBLSQX++b7KC2N zbj3POu14tlhhPV1nwVh474JMEHwaK0= Received: from mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-584-3KZVlp8tORq_6hbtHCtJMA-1; Fri, 06 Feb 2026 17:35:41 -0500 X-MC-Unique: 3KZVlp8tORq_6hbtHCtJMA-1 X-Mimecast-MFC-AGG-ID: 3KZVlp8tORq_6hbtHCtJMA_1770417339 Received: from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id B73581956094; Fri, 6 Feb 2026 22:35:39 +0000 (UTC) Received: from GoldenWind.redhat.com (unknown [10.22.64.226]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id E264519373D8; Fri, 6 Feb 2026 22:35:37 +0000 (UTC) From: Lyude Paul To: linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, rust-for-linux@vger.kernel.org, Danilo Krummrich Cc: nouveau@lists.freedesktop.org, Daniel Almeida , Gary Guo , Benno Lossin , Alexandre Courbot , Janne Grunau Subject: [PATCH v7 7/7] rust: drm/gem: Add vmap functions to shmem bindings Date: Fri, 6 Feb 2026 17:34:31 -0500 Message-ID: <20260206223431.693765-8-lyude@redhat.com> In-Reply-To: <20260206223431.693765-1-lyude@redhat.com> References: <20260206223431.693765-1-lyude@redhat.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.0 on 10.30.177.17 Content-Type: text/plain; charset="utf-8" One of the more obvious use cases for gem shmem objects is the ability to create mappings into their contents, specifically iosys mappings. Now that we've added iosys_map rust bindings to the kernel, let's hook these up in gem shmem. Similar to how we handle SGTables, we make sure there's two different types of mappings: owned mappings (kernel::drm::gem::shmem::VMap) and borrowed mappings (kernel::drm::gem::shmem::VMapRef). One last note: we change the #[expect(unused)] for RawIoSysMap::from_raw() to an #[allow(unused)]. Normally we would simply remove the lint assertion, however - since shmem is conditionally built, we need allow to avoid hitting warnings in certain kernel configurations. Signed-off-by: Lyude Paul --- V7: * Switch over to the new iosys map bindings that use the Io trait rust/kernel/drm/gem/shmem.rs | 170 ++++++++++++++++++++++++++++++++++- rust/kernel/iosys_map.rs | 3 +- 2 files changed, 170 insertions(+), 3 deletions(-) diff --git a/rust/kernel/drm/gem/shmem.rs b/rust/kernel/drm/gem/shmem.rs index e511a9b6710e0..604fb10325d1e 100644 --- a/rust/kernel/drm/gem/shmem.rs +++ b/rust/kernel/drm/gem/shmem.rs @@ -21,6 +21,7 @@ from_err_ptr, to_result, // }, + iosys_map::*, prelude::*, scatterlist, types::{ @@ -29,13 +30,18 @@ }, // }; use core::{ + mem::{ + self, + MaybeUninit, // + }, ops::{ Deref, DerefMut, // }, - ptr::NonNull, + ptr::NonNull, // }; use gem::{ + BaseObject, BaseObjectPrivate, DriverObject, IntoGEMObject, // @@ -216,6 +222,72 @@ pub fn owned_sg_table(&self) -> Result> { _owner: self.into(), }) } + + /// Attempt to create a [`RawIoSysMap`] from the gem object. + fn raw_vmap(&self) -> Result> { + let mut map: MaybeUninit =3D MaybeUninit::uni= nit(); + + // SAFETY: drm_gem_shmem_vmap can be called with the DMA reservati= on lock held + to_result(unsafe { + // TODO: see top of file + bindings::dma_resv_lock(self.raw_dma_resv(), core::ptr::null_m= ut()); + let ret =3D bindings::drm_gem_shmem_vmap_locked(self.as_shmem(= ), map.as_mut_ptr()); + bindings::dma_resv_unlock(self.raw_dma_resv()); + ret + })?; + + // SAFETY: if drm_gem_shmem_vmap did not fail, map is initialized = now + Ok(unsafe { RawIoSysMap::::from_raw(map.assume_init()) }) + } + + /// Unmap a [`RawIoSysMap`] from the gem object. + /// + /// # Safety + /// + /// - The caller promises that `map` came from a prior call to [`Self:= :raw_vmap`] on this gem + /// object. + /// - The caller promises that the memory pointed to by `map` will no = longer be accesed through + /// this instance. + unsafe fn raw_vunmap(&self, map: &mut RawIoSysMap) { + let resv =3D self.raw_dma_resv(); + + // SAFETY: + // - This function is safe to call with the DMA reservation lock h= eld + // - Our `ARef` is proof that the underlying gem object here is in= itialized and thus safe to + // dereference. + unsafe { + // TODO: see top of file + bindings::dma_resv_lock(resv, core::ptr::null_mut()); + bindings::drm_gem_shmem_vunmap_locked(self.as_shmem(), map.as_= raw_mut()); + bindings::dma_resv_unlock(resv); + } + } + + /// Creates and returns a virtual kernel memory mapping for this objec= t. + pub fn vmap(&self) -> Result> { + let map =3D self.raw_vmap()?; + + Ok(VMapRef { + // SAFETY: + // - The size of the vmap is the same as the size of the gem + // - The vmap will remain alive until this object is dropped. + map: unsafe { IoSysMapRef::::new(map, self.size()) }?, + owner: self, + }) + } + + /// Creates and returns an owned reference to a virtual kernel memory = mapping for this object. + pub fn owned_vmap(&self) -> Result> { + // INVARIANT: We verify here that the mapping is at least of SIZE = bytes. + if self.size() < SIZE { + return Err(EINVAL); + } + + Ok(VMap { + map: self.raw_vmap()?, + owner: self.into(), + }) + } } =20 impl Deref for Object { @@ -267,6 +339,102 @@ impl driver::AllocImpl for Object= { }; } =20 +/// A borrowed reference to a virtual mapping for a shmem-based GEM object= in kernel address space. +pub struct VMapRef<'a, D: DriverObject, const SIZE: usize =3D 0> { + map: IoSysMapRef<'a, SIZE>, + owner: &'a Object, +} + +impl<'a, D: DriverObject, const SIZE: usize> Clone for VMapRef<'a, D, SIZE= > { + fn clone(&self) -> Self { + // SAFETY: We have a successful vmap already, so this can't fail + unsafe { self.owner.vmap().unwrap_unchecked() } + } +} + +impl<'a, D: DriverObject, const SIZE: usize> Deref for VMapRef<'a, D, SIZE= > { + type Target =3D IoSysMapRef<'a, SIZE>; + + fn deref(&self) -> &Self::Target { + &self.map + } +} + +impl<'a, D: DriverObject, const SIZE: usize> DerefMut for VMapRef<'a, D, S= IZE> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.map + } +} + +impl<'a, D: DriverObject, const SIZE: usize> Drop for VMapRef<'a, D, SIZE>= { + fn drop(&mut self) { + // SAFETY: Our existence is proof that this map was previously cre= ated using self.owner. + unsafe { self.owner.raw_vunmap(&mut self.map.raw_map) }; + } +} + +/// An owned reference to a virtual mapping for a shmem-based GEM object i= n kernel address space. +/// +/// # Invariants +/// +/// - The size of `owner` is >=3D SIZE. +/// - The memory pointed to by `map` is at least as large as `T`. +/// - The memory pointed to by `map` remains valid at least until this obj= ect is dropped. +pub struct VMap { + map: RawIoSysMap, + owner: ARef>, +} + +impl Clone for VMap { + fn clone(&self) -> Self { + // SAFETY: We have a successful vmap already, so this can't fail + unsafe { self.owner.owned_vmap().unwrap_unchecked() } + } +} + +impl<'a, D: DriverObject, const SIZE: usize> From> fo= r VMap { + fn from(value: VMapRef<'a, D, SIZE>) -> Self { + let this =3D Self { + map: value.map.raw_map.clone(), + owner: value.owner.into(), + }; + + mem::forget(value); + this + } +} + +impl VMap { + /// Return a reference to the iosys map for this `VMap`. + #[inline] + pub fn get(&self) -> IoSysMapRef<'_, SIZE> { + // SAFETY: + // - The size of the iosys_map is equivalent to the size of the ge= m object. + // - `size` is >=3D SIZE according to our type invariants, ensurin= g that we can never pass an + // invalid `size` to `IoSysMapRef::new(). + unsafe { + IoSysMapRef::new(self.map.clone(), self.owner.size()).unwrap_u= nchecked() + } + } + + /// Borrows a reference to the object that owns this virtual mapping. + pub fn owner(&self) -> &Object { + &self.owner + } +} + +impl Drop for VMap { + fn drop(&mut self) { + // SAFETY: Our existence is proof that this map was previously cre= ated using self.owner + unsafe { self.owner.raw_vunmap(&mut self.map) }; + } +} + +/// SAFETY: `iosys_map` objects are safe to send across threads. +unsafe impl Send for VMap {} +/// SAFETY: `iosys_map` objects are safe to send across threads. +unsafe impl Sync for VMap {} + /// An owned reference to a scatter-gather table of DMA address spans for = a GEM shmem object. /// /// This object holds an owned reference to the underlying GEM shmem objec= t, ensuring that the diff --git a/rust/kernel/iosys_map.rs b/rust/kernel/iosys_map.rs index 2070f0fb42cb8..b649d2de83093 100644 --- a/rust/kernel/iosys_map.rs +++ b/rust/kernel/iosys_map.rs @@ -33,7 +33,7 @@ =20 impl RawIoSysMap { /// Convert from a raw `bindings::iosys_map`. - #[expect(unused)] + #[allow(unused)] #[inline] pub(crate) fn from_raw(val: bindings::iosys_map) -> Self { Self(val) @@ -139,7 +139,6 @@ impl<'a, const SIZE: usize> IoSysMapRef<'a, SIZE> { /// /// - The caller guarantees that the mapping is of at least `size` byt= es. /// - The caller guarantees that the mapping remains valid for the lif= etime of `'a`. - #[expect(unused)] pub(crate) unsafe fn new(map: RawIoSysMap, size: usize) -> Resul= t { if size < SIZE { return Err(EINVAL); --=20 2.53.0