11 Commits

Author SHA1 Message Date
Danilo Krummrich
a995fe1a3a rust: driver: drop device private data post unbind
Currently, the driver's device private data is allocated and initialized
from driver core code called from bus abstractions after the driver's
probe() callback returned the corresponding initializer.

Similarly, the driver's device private data is dropped within the
remove() callback of bus abstractions after calling the remove()
callback of the corresponding driver.

However, commit 6f61a2637a ("rust: device: introduce
Device::drvdata()") introduced an accessor for the driver's device
private data for a Device<Bound>, i.e. a device that is currently bound
to a driver.

Obviously, this is in conflict with dropping the driver's device private
data in remove(), since a device can not be considered to be fully
unbound after remove() has finished:

We also have to consider registrations guarded by devres - such as IRQ
or class device registrations - which are torn down after remove() in
devres_release_all().

Thus, it can happen that, for instance, a class device or IRQ callback
still calls Device::drvdata(), which then runs concurrently to remove()
(which sets dev->driver_data to NULL and drops the driver's device
private data), before devres_release_all() started to tear down the
corresponding registration. This is because devres guarded registrations
can, as expected, access the corresponding Device<Bound> that defines
their scope.

In C it simply is the driver's responsibility to ensure that its device
private data is freed after e.g. an IRQ registration is unregistered.

Typically, C drivers achieve this by allocating their device private data
with e.g. devm_kzalloc() before doing anything else, i.e. before e.g.
registering an IRQ with devm_request_threaded_irq(), relying on the
reverse order cleanup of devres.

Technically, we could do something similar in Rust. However, the
resulting code would be pretty messy:

In Rust we have to differentiate between allocated but uninitialized
memory and initialized memory in the type system. Thus, we would need to
somehow keep track of whether the driver's device private data object
has been initialized (i.e. probe() was successful and returned a valid
initializer for this memory) and conditionally call the destructor of
the corresponding object when it is freed.

This is because we'd need to allocate and register the memory of the
driver's device private data *before* it is initialized by the
initializer returned by the driver's probe() callback, because the
driver could already register devres guarded registrations within
probe() outside of the driver's device private data initializer.

Luckily there is a much simpler solution: Instead of dropping the
driver's device private data at the end of remove(), we just drop it
after the device has been fully unbound, i.e. after all devres callbacks
have been processed.

For this, we introduce a new post_unbind() callback private to the
driver-core, i.e. the callback is neither exposed to drivers, nor to bus
abstractions.

This way, the driver-core code can simply continue to conditionally
allocate the memory for the driver's device private data when the
driver's initializer is returned from probe() - no change needed - and
drop it when the driver-core code receives the post_unbind() callback.

Closes: https://lore.kernel.org/all/DEZMS6Y4A7XE.XE7EUBT5SJFJ@kernel.org/
Fixes: 6f61a2637a ("rust: device: introduce Device::drvdata()")
Acked-by: Alice Ryhl <aliceryhl@google.com>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Acked-by: Igor Korotin <igor.korotin.linux@gmail.com>
Link: https://patch.msgid.link/20260107103511.570525-7-dakr@kernel.org
[ Remove #ifdef CONFIG_RUST, rename post_unbind() to post_unbind_rust().
 - Danilo]
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
2026-01-16 01:17:29 +01:00
Danilo Krummrich
2ad0f490c2 rust: driver: add DriverData type to the DriverLayout trait
Add an associated type DriverData to the DriverLayout trait indicating
the type of the driver's device private data.

Acked-by: Alice Ryhl <aliceryhl@google.com>
Acked-by: Igor Korotin <igor.korotin.linux@gmail.com>
Link: https://patch.msgid.link/20260107103511.570525-6-dakr@kernel.org
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
2026-01-16 01:17:29 +01:00
Danilo Krummrich
c1d4519e1c rust: driver: add DEVICE_DRIVER_OFFSET to the DriverLayout trait
Add an associated const DEVICE_DRIVER_OFFSET to the DriverLayout trait
indicating the offset of the embedded struct device_driver within
Self::DriverType, i.e. the specific driver structs, such as struct
pci_driver or struct platform_driver.

Acked-by: Alice Ryhl <aliceryhl@google.com>
Acked-by: Igor Korotin <igor.korotin.linux@gmail.com>
Link: https://patch.msgid.link/20260107103511.570525-5-dakr@kernel.org
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
2026-01-16 01:17:29 +01:00
Danilo Krummrich
0af1a9e462 rust: driver: introduce a DriverLayout trait
The DriverLayout trait describes the layout of a specific driver
structure, such as `struct pci_driver` or `struct platform_driver`.

In a first step, this replaces the associated type RegType of the
RegistrationOps with the DriverLayout::DriverType associated type.

Acked-by: Alice Ryhl <aliceryhl@google.com>
Acked-by: Igor Korotin <igor.korotin.linux@gmail.com>
Link: https://patch.msgid.link/20260107103511.570525-4-dakr@kernel.org
[ Rename driver::Driver to driver::DriverLayout, as it represents the
  layout of a driver structure rather than the driver structure itself.
  - Danilo ]
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
2026-01-16 01:16:44 +01:00
Markus Probst
e4addc7cc2 rust: Add trait to convert a device reference to a bus device reference
Implement the `AsBusDevice` trait for converting a `Device` reference to a
bus device reference for all bus devices.

The `AsBusDevice` trait allows abstractions to provide the bus device in
class device callbacks. It must not be used by drivers and is intended for
bus and class device abstractions only.

Signed-off-by: Markus Probst <markus.probst@posteo.de>
Link: https://patch.msgid.link/20251027200547.1038967-2-markus.probst@posteo.de
[ * Remove unused import.
  * Change visibility of AsBusDevice to public.
  * Fix build for USB.
  * Add impl for I2cClient.
  - Danilo ]
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
2025-11-18 11:00:51 +13:00
Danilo Krummrich
fde40a558d rust: usb: fix broken call to T::disconnect()
A refactoring of Device::drvdata_obtain() broke T::disconnect() in the
USB abstractions.

"""
error[E0599]: no method named `data` found for struct `core::pin::Pin<kbox::Box<T, Kmalloc>>` in the current scope
  --> rust/kernel/usb.rs:92:34
   |
92 |         T::disconnect(intf, data.data());
   |                                  ^^^^ method not found in `core::pin::Pin<kbox::Box<T, Kmalloc>>`

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0599`.
make[2]: *** [rust/Makefile:553: rust/kernel.o] Error 1
make[1]: *** [/builddir/build/BUILD/kernel-6.18.0-build/kernel-next-20251103/linux-6.18.0-0.0.next.20251103.436.vanilla.fc44.x86_64/Makefile:1316: prepare] Error 2
make: *** [Makefile:256: __sub-make] Error 2
"""

This slipped through, since the USB abstractions are globally disabled.
However, the USB tree recently enabled them, hence it showed up in
linux-next.

Reported-by: Thorsten Leemhuis <linux@leemhuis.info>
Closes: https://lore.kernel.org/all/1c8afbc0-e888-4702-9e4e-fa8aef0f97ae@leemhuis.info/
Fixes: 6bbaa93912 ("rust: device: narrow the generic of drvdata_obtain()")
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Tested-by: Thorsten Leemhuis <linux@leemhuis.info>
Link: https://patch.msgid.link/20251103110115.1925072-1-dakr@kernel.org
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
2025-11-04 00:31:25 +01:00
Danilo Krummrich
6bbaa93912 rust: device: narrow the generic of drvdata_obtain()
Let T be the actual private driver data type without the surrounding
box, as it leaves less room for potential bugs.

Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
2025-10-29 16:40:28 +01:00
Danilo Krummrich
0242623384 rust: driver: let probe() return impl PinInit<Self, Error>
The driver model defines the lifetime of the private data stored in (and
owned by) a bus device to be valid from when the driver is bound to a
device (i.e. from successful probe()) until the driver is unbound from
the device.

This is already taken care of by the Rust implementation of the driver
model. However, we still ask drivers to return a Result<Pin<KBox<Self>>>
from probe().

Unlike in C, where we do not have the concept of initializers, but
rather deal with uninitialized memory, drivers can just return an
impl PinInit<Self, Error> instead.

This contributes to more clarity to the fact that a driver returns it's
device private data in probe() and the Rust driver model owns the data,
manages the lifetime and - considering the lifetime - provides (safe)
accessors for the driver.

Hence, let probe() functions return an impl PinInit<Self, Error> instead
of Result<Pin<KBox<Self>>>.

Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
Reviewed-by: Alexandre Courbot <acourbot@nvidia.com>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
2025-10-21 18:40:48 +02:00
Danilo Krummrich
22d693e45d rust: usb: keep usb::Device private for now
The USB abstractions target to support USB interface drivers.

While internally the abstraction has to deal with the interface's parent
USB device, there shouldn't be a need for users to deal with the parent
USB device directly.

Functions, such as for preparing and sending USB URBs, can be
implemented for the usb::Interface structure directly. Whether this
internal implementation has to deal with the parent USB device can
remain transparent to USB interface drivers.

Hence, keep the usb::Device structure private for now, in order to avoid
confusion for users and to make it less likely to accidentally expose
APIs with unnecessary indirections.

Should we start supporting USB device drivers, or need it for any other
reason we do not foresee yet, it should be trivial to make it public
again.

Signed-off-by: Danilo Krummrich <dakr@kernel.org>
Link: https://lore.kernel.org/r/20250925190400.144699-2-dakr@kernel.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2025-09-26 08:09:08 +02:00
Danilo Krummrich
f12140f21a rust: usb: don't retain device context for the interface parent
When deriving the parent USB device (struct usb_device) from a USB
interface (struct usb_interface), do not retain the device context.

For the Bound context, as pointed out by Alan in [1], it is not
guaranteed that the parent USB device is always bound when the interface
is bound.

The bigger problem, however, is that we can't infer the Core context,
since eventually it indicates that the device lock is held. However,
there is no guarantee that if the device lock of the interface is held,
also the device lock of the parent USB device is held.

Hence, fix this by not inferring any device context information; while
at it, fix up the (affected) safety comments.

Link: https://lore.kernel.org/all/0ff2a825-1115-426a-a6f9-df544cd0c5fc@rowland.harvard.edu/ [1]
Fixes: e7e2296b0e ("rust: usb: add basic USB abstractions")
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
Link: https://lore.kernel.org/r/20250925190400.144699-1-dakr@kernel.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2025-09-26 08:09:08 +02:00
Daniel Almeida
e7e2296b0e rust: usb: add basic USB abstractions
Add basic USB abstractions, consisting of usb::{Device, Interface,
Driver, Adapter, DeviceId} and the module_usb_driver macro. This is the
first step in being able to write USB device drivers, which paves the
way for USB media drivers - for example - among others.

This initial support will then be used by a subsequent sample driver,
which constitutes the only user of the USB abstractions so far.

Signed-off-by: Daniel Almeida <daniel.almeida@collabora.com>
Link: https://lore.kernel.org/r/20250825-b4-usb-v1-1-7aa024de7ae8@collabora.com
[ force USB = y for now - gregkh ]
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2025-09-24 13:13:04 +02:00