Convert pci::Bar<SIZE> to pci::Bar<'bound, SIZE>, storing &'bound
Device<Bound> to tie the BAR mapping lifetime to the device.

iomap_region_sized() now returns Result<Bar<'bound, SIZE>> directly instead
of impl PinInit<Devres<Bar<SIZE>>, Error>.

Add Bar::into_devres() to consume the bar and register it as a
device-managed resource, returning Devres<Bar<'static, SIZE>>. The
lifetime is erased to 'static because Devres guarantees the bar does not
actually outlive the device -- access is revoked on unbind.

Signed-off-by: Danilo Krummrich <[email protected]>
---
 drivers/gpu/nova-core/driver.rs |  7 ++--
 rust/kernel/devres.rs           |  2 +-
 rust/kernel/pci/io.rs           | 68 +++++++++++++++++----------------
 samples/rust/rust_driver_pci.rs |  5 ++-
 4 files changed, 44 insertions(+), 38 deletions(-)

diff --git a/drivers/gpu/nova-core/driver.rs b/drivers/gpu/nova-core/driver.rs
index ed154cd93fa8..6ee2021ef56e 100644
--- a/drivers/gpu/nova-core/driver.rs
+++ b/drivers/gpu/nova-core/driver.rs
@@ -47,7 +47,7 @@ pub(crate) struct NovaCore {
 // DMA addresses. These systems should be quite rare.
 const GPU_DMA_BITS: u32 = 47;
 
-pub(crate) type Bar0 = pci::Bar<BAR0_SIZE>;
+pub(crate) type Bar0 = pci::Bar<'static, BAR0_SIZE>;
 
 kernel::pci_device_table!(
     PCI_TABLE,
@@ -93,8 +93,9 @@ fn probe(
             // other threads of execution.
             unsafe { 
pdev.dma_set_mask_and_coherent(DmaMask::new::<GPU_DMA_BITS>())? };
 
-            let bar = Arc::pin_init(
-                pdev.iomap_region_sized::<BAR0_SIZE>(0, c"nova-core/bar0"),
+            let bar = Arc::new(
+                pdev.iomap_region_sized::<BAR0_SIZE>(0, c"nova-core/bar0")?
+                    .into_devres()?,
                 GFP_KERNEL,
             )?;
 
diff --git a/rust/kernel/devres.rs b/rust/kernel/devres.rs
index 9e5f93aed20c..ec63317665f4 100644
--- a/rust/kernel/devres.rs
+++ b/rust/kernel/devres.rs
@@ -304,7 +304,7 @@ pub fn device(&self) -> &Device {
     ///     pci, //
     /// };
     ///
-    /// fn from_core(dev: &pci::Device<Core>, devres: Devres<pci::Bar<0x4>>) 
-> Result {
+    /// fn from_core(dev: &pci::Device<Core>, devres: Devres<pci::Bar<'_, 
0x4>>) -> Result {
     ///     let bar = devres.access(dev.as_ref())?;
     ///
     ///     let _ = bar.read32(0x0);
diff --git a/rust/kernel/pci/io.rs b/rust/kernel/pci/io.rs
index ae78676c927f..5668394a155b 100644
--- a/rust/kernel/pci/io.rs
+++ b/rust/kernel/pci/io.rs
@@ -14,8 +14,7 @@
         Mmio,
         MmioRaw, //
     },
-    prelude::*,
-    sync::aref::ARef, //
+    prelude::*, //
 };
 use core::{
     marker::PhantomData,
@@ -78,15 +77,15 @@ impl ConfigSpaceKind for Extended {
 /// The generic parameter `S` indicates the maximum size of the configuration 
space.
 /// Use [`Normal`] for 256-byte legacy configuration space or [`Extended`] for
 /// 4096-byte PCIe extended configuration space (default).
-pub struct ConfigSpace<'a, S: ConfigSpaceKind = Extended> {
-    pub(crate) pdev: &'a Device<device::Bound>,
+pub struct ConfigSpace<'bound, S: ConfigSpaceKind = Extended> {
+    pub(crate) pdev: &'bound Device<device::Bound>,
     _marker: PhantomData<S>,
 }
 
 /// Implements [`IoCapable`] on [`ConfigSpace`] for `$ty` using `$read_fn` and 
`$write_fn`.
 macro_rules! impl_config_space_io_capable {
     ($ty:ty, $read_fn:ident, $write_fn:ident) => {
-        impl<'a, S: ConfigSpaceKind> IoCapable<$ty> for ConfigSpace<'a, S> {
+        impl<'bound, S: ConfigSpaceKind> IoCapable<$ty> for 
ConfigSpace<'bound, S> {
             unsafe fn io_read(&self, address: usize) -> $ty {
                 let mut val: $ty = 0;
 
@@ -119,7 +118,7 @@ unsafe fn io_write(&self, value: $ty, address: usize) {
 impl_config_space_io_capable!(u16, pci_read_config_word, 
pci_write_config_word);
 impl_config_space_io_capable!(u32, pci_read_config_dword, 
pci_write_config_dword);
 
-impl<'a, S: ConfigSpaceKind> Io for ConfigSpace<'a, S> {
+impl<'bound, S: ConfigSpaceKind> Io for ConfigSpace<'bound, S> {
     /// Returns the base address of the I/O region. It is always 0 for 
configuration space.
     #[inline]
     fn addr(&self) -> usize {
@@ -133,7 +132,7 @@ fn maxsize(&self) -> usize {
     }
 }
 
-impl<'a, S: ConfigSpaceKind> IoKnownSize for ConfigSpace<'a, S> {
+impl<'bound, S: ConfigSpaceKind> IoKnownSize for ConfigSpace<'bound, S> {
     const MIN_SIZE: usize = S::SIZE;
 }
 
@@ -146,14 +145,14 @@ impl<'a, S: ConfigSpaceKind> IoKnownSize for 
ConfigSpace<'a, S> {
 ///
 /// `Bar` always holds an `IoRaw` instance that holds a valid pointer to the 
start of the I/O
 /// memory mapped PCI BAR and its size.
-pub struct Bar<const SIZE: usize = 0> {
-    pdev: ARef<Device>,
+pub struct Bar<'bound, const SIZE: usize = 0> {
+    pdev: &'bound Device<device::Bound>,
     io: MmioRaw<SIZE>,
     num: i32,
 }
 
-impl<const SIZE: usize> Bar<SIZE> {
-    pub(super) fn new(pdev: &Device, num: u32, name: &CStr) -> Result<Self> {
+impl<'bound, const SIZE: usize> Bar<'bound, SIZE> {
+    pub(super) fn new(pdev: &'bound Device<device::Bound>, num: u32, name: 
&CStr) -> Result<Self> {
         let len = pdev.resource_len(num)?;
         if len == 0 {
             return Err(ENOMEM);
@@ -196,11 +195,7 @@ pub(super) fn new(pdev: &Device, num: u32, name: &CStr) -> 
Result<Self> {
             }
         };
 
-        Ok(Bar {
-            pdev: pdev.into(),
-            io,
-            num,
-        })
+        Ok(Bar { pdev, io, num })
     }
 
     /// # Safety
@@ -219,11 +214,24 @@ unsafe fn do_release(pdev: &Device, ioptr: usize, num: 
i32) {
 
     fn release(&self) {
         // SAFETY: The safety requirements are guaranteed by the type 
invariant of `self.pdev`.
-        unsafe { Self::do_release(&self.pdev, self.io.addr(), self.num) };
+        unsafe { Self::do_release(self.pdev, self.io.addr(), self.num) };
+    }
+
+    /// Consume the `Bar` and register it as a device-managed resource.
+    ///
+    /// The returned `Devres<Bar<'static, SIZE>>` can outlive the original 
lifetime `'bound`. 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)
     }
 }
 
-impl Bar {
+impl Bar<'_> {
     #[inline]
     pub(super) fn index_is_valid(index: u32) -> bool {
         // A `struct pci_dev` owns an array of resources with at most 
`PCI_NUM_RESOURCES` entries.
@@ -231,13 +239,13 @@ pub(super) fn index_is_valid(index: u32) -> bool {
     }
 }
 
-impl<const SIZE: usize> Drop for Bar<SIZE> {
+impl<const SIZE: usize> Drop for Bar<'_, SIZE> {
     fn drop(&mut self) {
         self.release();
     }
 }
 
-impl<const SIZE: usize> Deref for Bar<SIZE> {
+impl<const SIZE: usize> Deref for Bar<'_, SIZE> {
     type Target = Mmio<SIZE>;
 
     fn deref(&self) -> &Self::Target {
@@ -249,20 +257,16 @@ fn deref(&self) -> &Self::Target {
 impl Device<device::Bound> {
     /// Maps an entire PCI BAR after performing a region-request on it. I/O 
operation bound checks
     /// can be performed on compile time for offsets (plus the requested type 
size) < SIZE.
-    pub fn iomap_region_sized<'a, const SIZE: usize>(
-        &'a self,
+    pub fn iomap_region_sized<'bound, const SIZE: usize>(
+        &'bound self,
         bar: u32,
-        name: &'a CStr,
-    ) -> impl PinInit<Devres<Bar<SIZE>>, Error> + 'a {
-        Devres::new(self.as_ref(), Bar::<SIZE>::new(self, bar, name))
+        name: &CStr,
+    ) -> Result<Bar<'bound, SIZE>> {
+        Bar::new(self, bar, name)
     }
 
     /// Maps an entire PCI BAR after performing a region-request on it.
-    pub fn iomap_region<'a>(
-        &'a self,
-        bar: u32,
-        name: &'a CStr,
-    ) -> impl PinInit<Devres<Bar>, Error> + 'a {
+    pub fn iomap_region<'bound>(&'bound self, bar: u32, name: &CStr) -> 
Result<Bar<'bound>> {
         self.iomap_region_sized::<0>(bar, name)
     }
 
@@ -282,7 +286,7 @@ pub fn cfg_size(&self) -> ConfigSpaceSize {
     }
 
     /// Return an initialized normal (256-byte) config space object.
-    pub fn config_space<'a>(&'a self) -> ConfigSpace<'a, Normal> {
+    pub fn config_space<'bound>(&'bound self) -> ConfigSpace<'bound, Normal> {
         ConfigSpace {
             pdev: self,
             _marker: PhantomData,
@@ -290,7 +294,7 @@ pub fn config_space<'a>(&'a self) -> ConfigSpace<'a, 
Normal> {
     }
 
     /// Return an initialized extended (4096-byte) config space object.
-    pub fn config_space_extended<'a>(&'a self) -> Result<ConfigSpace<'a, 
Extended>> {
+    pub fn config_space_extended<'bound>(&'bound self) -> 
Result<ConfigSpace<'bound, Extended>> {
         if self.cfg_size() != ConfigSpaceSize::Extended {
             return Err(EINVAL);
         }
diff --git a/samples/rust/rust_driver_pci.rs b/samples/rust/rust_driver_pci.rs
index 794311691d1e..bbcb816456e0 100644
--- a/samples/rust/rust_driver_pci.rs
+++ b/samples/rust/rust_driver_pci.rs
@@ -45,7 +45,7 @@ mod regs {
     pub(super) const END: usize = 0x10;
 }
 
-type Bar0 = pci::Bar<{ regs::END }>;
+type Bar0 = pci::Bar<'static, { regs::END }>;
 
 #[derive(Copy, Clone, Debug)]
 struct TestIndex(u8);
@@ -160,7 +160,8 @@ fn probe(
             pdev.set_master();
 
             Ok(try_pin_init!(Self {
-                bar <- pdev.iomap_region_sized::<{ regs::END }>(0, 
c"rust_driver_pci"),
+                bar: pdev.iomap_region_sized::<{ regs::END }>(0, 
c"rust_driver_pci")?
+                    .into_devres()?,
                 index: *info,
                 _: {
                     let bar = bar.access(pdev.as_ref())?;
-- 
2.54.0

Reply via email to