From: Deborah Brouwer <deborah.brouwer@collabora.com>
To: Lyude Paul <lyude@redhat.com>
Cc: linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org,
rust-for-linux@vger.kernel.org,
Danilo Krummrich <dakr@kernel.org>,
nouveau@lists.freedesktop.org, Miguel Ojeda <ojeda@kernel.org>,
Simona Vetter <simona@ffwll.ch>,
Alice Ryhl <aliceryhl@google.com>,
Shankari Anand <shankari.ak0208@gmail.com>,
David Airlie <airlied@gmail.com>,
Benno Lossin <lossin@kernel.org>,
Asahi Lina <lina+kernel@asahilina.net>,
Daniel Almeida <daniel.almeida@collabora.com>
Subject: Re: [PATCH v5 1/4] rust/drm: Introduce DeviceContext
Date: Thu, 12 Feb 2026 15:39:20 -0800 [thread overview]
Message-ID: <aY5kqALwqOVl9V7e@um790> (raw)
In-Reply-To: <20260131001602.2095470-2-lyude@redhat.com>
Hi Lyude,
On Fri, Jan 30, 2026 at 07:13:30PM -0500, Lyude Paul wrote:
> One of the tricky things about DRM bindings in Rust is the fact that
> initialization of a DRM device is a multi-step process. It's quite normal
> for a device driver to start making use of its DRM device for tasks like
> creating GEM objects before userspace registration happens. This is an
> issue in rust though, since prior to userspace registration the device is
> only partly initialized. This means there's a plethora of DRM device
> operations we can't yet expose without opening up the door to UB if the DRM
> device in question isn't yet registered.
>
> Additionally, this isn't something we can reliably check at runtime. And
> even if we could, performing an operation which requires the device be
> registered when the device isn't actually registered is a programmer bug,
> meaning there's no real way to gracefully handle such a mistake at runtime.
> And even if that wasn't the case, it would be horrendously annoying and
> noisy to have to check if a device is registered constantly throughout a
> driver.
>
> In order to solve this, we first take inspiration from
> `kernel::device::DeviceContext` and introduce `kernel::drm::DeviceContext`.
> This provides us with a ZST type that we can generalize over to represent
> contexts where a device is known to have been registered with userspace at
> some point in time (`Registered`), along with contexts where we can't make
> such a guarantee (`Uninit`).
>
> It's important to note we intentionally do not provide a `DeviceContext`
> which represents an unregistered device. This is because there's no
> reasonable way to guarantee that a device with long-living references to
> itself will not be registered eventually with userspace. Instead, we
> provide a new-type for this: `UnregisteredDevice` which can
> provide a guarantee that the `Device` has never been registered with
> userspace. To ensure this, we modify `Registration` so that creating a new
> `Registration` requires passing ownership of an `UnregisteredDevice`.
>
> Signed-off-by: Lyude Paul <lyude@redhat.com>
>
> ---
> V2:
> * Make sure that `UnregisteredDevice` is not thread-safe (since DRM device
> initialization is also not thread-safe)
> * Rename from AnyCtx to Uninit, I think this name actually makes a bit more
> sense.
> * Change assume_registered() to assume_ctx()
> Since it looks like in some situations, we'll want to update the
> DeviceContext of a object to the latest DeviceContext we know the Device
> to be in.
> * Rename Init to Uninit
> When we eventually add KMS support, we're going to have 3 different
> DeviceContexts - Uninit, Init, Registered. Additionally, aside from not
> being registered there are a number of portions of the rest of the Device
> which also aren't usable before at least the Init context - so the naming
> of Uninit makes this a little clearer.
> * s/DeviceContext/DeviceContext/
> For consistency with the rest of the kernel
> * Drop as_ref::<Device<T, Uninit>>() for now since I don't actually think
> we need this quite yet
> V3:
> * Get rid of drm_dev_ctx!, as we don't actually need to implement Send or
> Sync ourselves
> * Remove mention of C function in drm::device::Registration rustdoc
> * Add more documentation to the DeviceContext trait, go into detail about
> the various setup phases and such.
> * Add missing period to comment in `UnregisteredDevice::new()`.
> V4:
> * Address some comments from Danilo I missed last round:
> * Remove leftover rebase detritus from new_foreign_owned()
> (the seemingly useless cast)
> * Remove no-op mention in Registered device context
>
> Signed-off-by: Lyude Paul <lyude@redhat.com>
> ---
> drivers/gpu/drm/nova/driver.rs | 8 +-
> drivers/gpu/drm/tyr/driver.rs | 10 +-
> rust/kernel/drm/device.rs | 178 +++++++++++++++++++++++++++------
> rust/kernel/drm/driver.rs | 35 +++++--
> rust/kernel/drm/mod.rs | 4 +
> 5 files changed, 190 insertions(+), 45 deletions(-)
>
...
> --- a/rust/kernel/drm/device.rs
> +++ b/rust/kernel/drm/device.rs
...
> +pub struct UnregisteredDevice<T: drm::Driver>(ARef<Device<T, Uninit>>, NotThreadSafe);
> +
> +impl<T: drm::Driver> Deref for UnregisteredDevice<T> {
> + type Target = Device<T, Uninit>;
> +
> + fn deref(&self) -> &Self::Target {
> + &self.0
> + }
> }
>
> -impl<T: drm::Driver> Device<T> {
> +impl<T: drm::Driver> UnregisteredDevice<T> {
> const VTABLE: bindings::drm_driver = drm_legacy_fields! {
> load: None,
> open: Some(drm::File::<T::File>::open_callback),
> postclose: Some(drm::File::<T::File>::postclose_callback),
> unload: None,
> - release: Some(Self::release),
> + release: Some(Device::<T>::release),
> master_set: None,
> master_drop: None,
> debugfs_init: None,
> @@ -108,8 +185,10 @@ impl<T: drm::Driver> Device<T> {
>
> const GEM_FOPS: bindings::file_operations = drm::gem::create_fops();
>
> - /// Create a new `drm::Device` for a `drm::Driver`.
> - pub fn new(dev: &device::Device, data: impl PinInit<T::Data, Error>) -> Result<ARef<Self>> {
> + /// Create a new `UnregisteredDevice` for a `drm::Driver`.
> + ///
> + /// This can be used to create a [`Registration`](kernel::drm::Registration).
> + pub fn new(dev: &device::Device, data: impl PinInit<T::Data, Error>) -> Result<Self> {
> // `__drm_dev_alloc` uses `kmalloc()` to allocate memory, hence ensure a `kmalloc()`
> // compatible `Layout`.
> let layout = Kmalloc::aligned_layout(Layout::new::<Self>());
> @@ -117,12 +196,12 @@ pub fn new(dev: &device::Device, data: impl PinInit<T::Data, Error>) -> Result<A
> // SAFETY:
> // - `VTABLE`, as a `const` is pinned to the read-only section of the compilation,
> // - `dev` is valid by its type invarants,
> - let raw_drm: *mut Self = unsafe {
> + let raw_drm: *mut Device<T, Uninit> = unsafe {
> bindings::__drm_dev_alloc(
> dev.as_raw(),
> &Self::VTABLE,
> layout.size(),
> - mem::offset_of!(Self, dev),
> + mem::offset_of!(Device<T, Uninit>, dev),
> )
> }
> .cast();
When I was testing this series with Tyr, I got this kernel Oops:
[ 31.351423] tyr fb000000.gpu: mali-unknown id 0xa867 major 0x67 minor 0x0 status 0x5
[ 31.352324] tyr fb000000.gpu: Features: L2:0x7120306 Tiler:0x809 Mem:0x301 MMU:0x2830 AS:0xff
[ 31.353299] tyr fb000000.gpu: shader_present=0x0000000000050005 l2_present=0x0000000000000001 tiler_present=0x0000000000000001
[ 31.357585] Unable to handle kernel paging request at virtual address ffff003064726553
[ 31.358324] Mem abort info:
[ 31.358579] ESR = 0x0000000096000005
[ 31.358956] EC = 0x25: DABT (current EL), IL = 32 bits
[ 31.359592] SET = 0, FnV = 0
[ 31.359898] EA = 0, S1PTW = 0
[ 31.360185] FSC = 0x05: level 1 translation fault
[ 31.360620] Data abort info:
[ 31.360882] ISV = 0, ISS = 0x00000005, ISS2 = 0x00000000
[ 31.361370] CM = 0, WnR = 0, TnD = 0, TagAccess = 0
[ 31.361832] GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0
[ 31.361839] swapper pgtable: 4k pages, 48-bit VAs, pgdp=0000000002926000
[ 31.361847] [ffff003064726553] pgd=0000000000000000, p4d=18000002fffff403, pud=0000000000000000
[ 31.364156] Internal error: Oops: 0000000096000005 [#1] SMP
[ 31.365050] Modules linked in: tyr(+) soundcore sha256 cfg80211 rfkill pci_endpoint_test fuse dm_mod ipv6
[ 31.366212] CPU: 3 UID: 0 PID: 254 Comm: (udev-worker) Not tainted 6.19.0-rc5 #281 PREEMPT
[ 31.366942] Hardware name: Radxa ROCK 5B (DT)
[ 31.367325] pstate: 00400009 (nzcv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--)
[ 31.367935] pc : drmm_kmalloc+0x34/0x128
[ 31.368286] lr : drm_gem_init+0x70/0xb8
[ 31.368627] sp : ffff800081ec3250
[ 31.368918] x29: ffff800081ec3250 x28: ffff800082c01000 x27: ffff800081ec3420
[ 31.369549] x26: ffff000100dc8a00 x25: ffff0001009ab960 x24: ffff000107a14840
[ 31.370179] x23: ffff0001009ab7e0 x22: 0000000000000138 x21: 0000000000000dc0
[ 31.370808] x20: ffff000100a801d0 x19: ffff000100a801d0 x18: 0000000000000003
[ 31.371438] x17: 0000000000000000 x16: ffffc82e1355a228 x15: ffff000107c08978
[ 31.372068] x14: ffffffffffffffff x13: 0000000000000044 x12: 0000000000000000
[ 31.372697] x11: 0000000000000030 x10: ffffc82e12bd2db0 x9 : ffff003064726163
[ 31.373327] x8 : 00000000000001b8 x7 : ffffc82e107c8dc8 x6 : 0000000000000000
[ 31.373956] x5 : 0000000000000000 x4 : 0000000000000003 x3 : 0000000000000000
[ 31.374591] x2 : 0000000000000dc0 x1 : 0000000000000dc0 x0 : 00000000000001b8
[ 31.375221] Call trace:
[ OK ] Listening on systemd-hostnamed.sock[ 31.375438] drmm_kmalloc+0x34/0x128 (P)
et - Hostname Service Socket.
[ 31.376264] drm_gem_init+0x70/0xb8
[ 31.376838] drm_dev_init+0x27c/0x30c
[ 31.377164] __drm_dev_alloc+0x44/0x88
[ 31.377496] _RNvMs3_NtNtCs8pcx3nCgX4X_6kernel3drm6deviceINtB5_18UnregisteredDeviceNtNtCs5CCNNSUyUK_3tyr6driver12TyrDrmDriverE3newB19_+0x50/0xe4 [tyr]
[ 31.378690] _RNvXs0_NtCs5CCNNSUyUK_3tyr6driverNtB5_21TyrPlatformDeviceDataNtNtCs8pcx3nCgX4X_6kernel8platform6Driver5probe+0x30c/0x4ec [tyr]
[ 31.379794] _RNvMs0_NtCs8pcx3nCgX4X_6kernel8platformINtB5_7AdapterNtNtCs5CCNNSUyUK_3tyr6driver21TyrPlatformDeviceDataE14probe_callbackBT_+0x60/0x220 [tyr]
[ 31.381010] platform_probe+0x5c/0x9c
[ 31.381337] really_probe+0x154/0x43c
[ 31.381665] __driver_probe_device+0xa4/0x118
[ 31.382052] driver_probe_device+0x40/0x230
[ 31.382423] __driver_attach+0xf8/0x288
[ 31.382764] bus_for_each_dev+0xec/0x144
[ 31.383112] driver_attach+0x24/0x30
[ 31.383430] bus_add_driver+0x14c/0x2a0
[ 31.383771] driver_register+0x68/0x100
[ 31.384109] __platform_driver_register+0x20/0x2c
[ 31.384524] init_module+0x84/0xfa0 [tyr]
[ 31.384885] do_one_initcall+0x104/0x35c
[ 31.385235] do_init_module+0x58/0x228
[ 31.385569] load_module+0x16f4/0x18f8
[ 31.385901] __arm64_sys_finit_module+0x24c/0x368
[ 31.386317] invoke_syscall+0x40/0xcc
[ 31.386646] el0_svc_common+0x80/0xd8
[ 31.386652] do_el0_svc+0x1c/0x28
[ OK ] Reached target sockets.target -[ 31.387270] el0_svc+0x54/0x1d4
Socket Units.
[ 31.388011] el0t_64_sync_handler+0x84/0x12c
[ 31.388509] el0t_64_sync+0x198/0x19c
[ 31.388838] Code: 54000682 f9400689 aa0803e0 2a1503e1 (b943f122)
[ 31.389372] ---[ end trace 0000000000000000 ]---
[ 31.396698] Unable to handle kernel paging request at virtual address 0030303030306266
I just fixed it by changing the layout size from Self -> Device<T, Uninit>
After this fix, it's working great to load the firmware with the
Unregistered Device.
thanks,
Deborah
next prev parent reply other threads:[~2026-02-12 23:39 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-01-31 0:13 [PATCH v5 0/4] Introduce DeviceContext Lyude Paul
2026-01-31 0:13 ` [PATCH v5 1/4] rust/drm: " Lyude Paul
2026-02-06 13:28 ` Daniel Almeida
2026-02-12 23:39 ` Deborah Brouwer [this message]
2026-01-31 0:13 ` [PATCH v5 2/4] rust/drm: Don't setup private driver data until registration Lyude Paul
2026-02-04 18:28 ` Daniel Almeida
2026-02-04 20:56 ` lyude
2026-02-06 13:46 ` Daniel Almeida
2026-01-31 0:13 ` [PATCH v5 3/4] rust/drm/gem: Add DriverAllocImpl type alias Lyude Paul
2026-02-06 13:48 ` Daniel Almeida
2026-01-31 0:13 ` [PATCH v5 4/4] rust/drm/gem: Use DeviceContext with GEM objects Lyude Paul
2026-02-06 14:08 ` Daniel Almeida
-- strict thread matches above, loose matches on Subject: below --
2026-03-17 21:28 [PATCH v5 0/4] Introduce DeviceContext Lyude Paul
2026-03-17 21:28 ` [PATCH v5 1/4] rust/drm: " Lyude Paul
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=aY5kqALwqOVl9V7e@um790 \
--to=deborah.brouwer@collabora.com \
--cc=airlied@gmail.com \
--cc=aliceryhl@google.com \
--cc=dakr@kernel.org \
--cc=daniel.almeida@collabora.com \
--cc=dri-devel@lists.freedesktop.org \
--cc=lina+kernel@asahilina.net \
--cc=linux-kernel@vger.kernel.org \
--cc=lossin@kernel.org \
--cc=lyude@redhat.com \
--cc=nouveau@lists.freedesktop.org \
--cc=ojeda@kernel.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=shankari.ak0208@gmail.com \
--cc=simona@ffwll.ch \
/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