rust: pci: return DevresLt from Bar::into_devres()

Implement ForLt and CovariantForLt for Bar<'static, SIZE> so that
DevresLt can shorten the stored 'static lifetime back to the caller's
borrow lifetime.

CovariantForLt is sound because Bar<'a, SIZE> only holds &'a
Device<Bound>, which is covariant over 'a.

Since DevresLt::new() handles the lifetime transmutation internally,
into_devres() no longer needs an explicit transmute to Bar<'static>.

Add a DevresBar<SIZE> type alias for convenience.

Reviewed-by: Alexandre Courbot <acourbot@nvidia.com>
Link: https://patch.msgid.link/20260626183630.2585057-7-dakr@kernel.org
[ Add default SIZE parameter to DevresBar. - Danilo ]
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
This commit is contained in:
Danilo Krummrich
2026-06-26 20:36:13 +02:00
parent b85f672a3e
commit e7e6bf5af8
2 changed files with 27 additions and 11 deletions

View File

@@ -45,6 +45,7 @@
ConfigSpace,
ConfigSpaceKind,
ConfigSpaceSize,
DevresBar,
Extended,
Normal, //
};

View File

@@ -6,7 +6,7 @@
use crate::{
bindings,
device,
devres::Devres,
devres::DevresLt,
io::{
Io,
IoCapable,
@@ -14,7 +14,11 @@
Mmio,
MmioRaw, //
},
prelude::*, //
prelude::*,
types::{
CovariantForLt,
ForLt, //
}, //
};
use core::{
marker::PhantomData,
@@ -151,6 +155,19 @@ pub struct Bar<'a, const SIZE: usize = 0> {
num: i32,
}
impl<const SIZE: usize> ForLt for Bar<'static, SIZE> {
type Of<'a> = Bar<'a, SIZE>;
}
// SAFETY: `Bar<'a, SIZE>` is covariant over `'a`; it holds `&'a Device<Bound>`,
// which is covariant.
unsafe impl<const SIZE: usize> CovariantForLt for Bar<'static, SIZE> {}
/// A device-managed PCI BAR mapping.
///
/// See [`Bar::into_devres`].
pub type DevresBar<const SIZE: usize = 0> = DevresLt<Bar<'static, SIZE>>;
impl<'a, const SIZE: usize> Bar<'a, SIZE> {
pub(super) fn new(
pdev: &'a Device<device::Bound>,
@@ -223,15 +240,13 @@ fn release(&self) {
/// Consume the `Bar` and register it as a device-managed resource.
///
/// The returned `Devres<Bar<'static, SIZE>>` can outlive the original lifetime `'a`. Access
/// to the BAR is revoked when the device is unbound.
pub fn into_devres(self) -> Result<Devres<Bar<'static, SIZE>>> {
// SAFETY: Casting to `'static` is sound because `Devres` guarantees the `Bar` does not
// actually outlive the device -- access is revoked and the resource is released when the
// device is unbound.
let bar: Bar<'static, SIZE> = unsafe { core::mem::transmute(self) };
let pdev = bar.pdev;
Devres::new(pdev.as_ref(), bar)
/// The returned [`DevresBar`] can outlive the original borrow and be stored in driver data.
/// Access to the BAR is revoked automatically when the device is unbound.
pub fn into_devres(self) -> Result<DevresBar<SIZE>> {
let pdev = self.pdev;
// SAFETY: `Bar` only holds a reference to the device and an I/O mapping, both of which
// remain valid for the device's full bound scope, not just for `'a`.
unsafe { DevresLt::new(pdev.as_ref(), self) }
}
}