Implement ForLt for IoMem<'static, SIZE> and ExclusiveIoMem<'static, SIZE> so that DevresLt can shorten the stored 'static lifetime back to the caller's borrow lifetime via ForLt::cast_ref.
Change into_devres() to return DevresLt instead of Devres; add DevresIoMem<SIZE> and DevresExclusiveIoMem<SIZE> type aliases. Signed-off-by: Danilo Krummrich <[email protected]> --- drivers/pwm/pwm_th1520.rs | 5 ++-- rust/kernel/io/mem.rs | 55 ++++++++++++++++++++++++++++----------- 2 files changed, 42 insertions(+), 18 deletions(-) diff --git a/drivers/pwm/pwm_th1520.rs b/drivers/pwm/pwm_th1520.rs index 3deb39d8e0fc..6b094be35310 100644 --- a/drivers/pwm/pwm_th1520.rs +++ b/drivers/pwm/pwm_th1520.rs @@ -24,9 +24,8 @@ use kernel::{ clk::Clk, device::{Bound, Core, Device}, - devres, io::{ - mem::IoMem, + mem::DevresIoMem, Io, // }, of, platform, @@ -92,7 +91,7 @@ struct Th1520WfHw { #[pin_data(PinnedDrop)] struct Th1520PwmDriverData { #[pin] - iomem: devres::Devres<IoMem<'static, TH1520_PWM_REG_SIZE>>, + iomem: DevresIoMem<TH1520_PWM_REG_SIZE>, clk: Clk, } diff --git a/rust/kernel/io/mem.rs b/rust/kernel/io/mem.rs index a4cb12ee70d3..928aa7742490 100644 --- a/rust/kernel/io/mem.rs +++ b/rust/kernel/io/mem.rs @@ -9,7 +9,7 @@ Bound, Device, // }, - devres::Devres, + devres::DevresLt, io::{ self, resource::{ @@ -20,6 +20,7 @@ MmioRaw, // }, prelude::*, + types::ForLt, // }; /// An IO request for a specific device and resource. @@ -170,6 +171,18 @@ pub struct ExclusiveIoMem<'bound, const SIZE: usize> { _region: Region, } +// SAFETY: `ExclusiveIoMem<'bound, SIZE>` is covariant over `'bound` -- +// it holds an `IoMem<'bound, SIZE>`, which holds +// `&'bound Device<Bound>`, which is covariant. +unsafe impl<const SIZE: usize> ForLt for ExclusiveIoMem<'static, SIZE> { + type Of<'bound> = ExclusiveIoMem<'bound, SIZE>; +} + +/// A device-managed exclusive I/O memory region. +/// +/// See [`ExclusiveIoMem::into_devres`]. +pub type DevresExclusiveIoMem<const SIZE: usize> = DevresLt<ExclusiveIoMem<'static, SIZE>>; + impl<'bound, const SIZE: usize> ExclusiveIoMem<'bound, SIZE> { /// Creates a new `ExclusiveIoMem` instance. fn ioremap(dev: &'bound Device<Bound>, resource: &Resource) -> Result<Self> { @@ -196,15 +209,16 @@ fn ioremap(dev: &'bound Device<Bound>, resource: &Resource) -> Result<Self> { /// Consume the `ExclusiveIoMem` and register it as a device-managed resource. /// - /// The returned `Devres<ExclusiveIoMem<'static, SIZE>>` can outlive the original lifetime - /// `'bound`. Access to the I/O memory is revoked when the device is unbound. - pub fn into_devres(self) -> Result<Devres<ExclusiveIoMem<'static, SIZE>>> { - // SAFETY: Casting to `'static` is sound because `Devres` guarantees the + /// Access methods on the returned [`DevresLt`] shorten the inner lifetime via + /// [`ForLt::cast_ref`], so the transmuted `'static` is never exposed to callers. + pub fn into_devres(self) -> Result<DevresLt<ExclusiveIoMem<'static, SIZE>>> { + // SAFETY: Casting to `'static` is sound because `DevresLt` guarantees the // `ExclusiveIoMem` does not actually outlive the device -- access is revoked and the - // resource is released when the device is unbound. + // resource is released when the device is unbound. The `ForLt` encoding ensures + // `access()` shortens the lifetime back to the caller's borrow. let iomem: ExclusiveIoMem<'static, SIZE> = unsafe { core::mem::transmute(self) }; let dev = iomem.iomem.dev; - Devres::new(dev, iomem) + DevresLt::new(dev, iomem) } } @@ -230,6 +244,17 @@ pub struct IoMem<'bound, const SIZE: usize = 0> { io: MmioRaw<SIZE>, } +// SAFETY: `IoMem<'bound, SIZE>` is covariant over `'bound` -- it holds +// `&'bound Device<Bound>`, which is covariant. +unsafe impl<const SIZE: usize> ForLt for IoMem<'static, SIZE> { + type Of<'bound> = IoMem<'bound, SIZE>; +} + +/// A device-managed I/O memory region. +/// +/// See [`IoMem::into_devres`]. +pub type DevresIoMem<const SIZE: usize> = DevresLt<IoMem<'static, SIZE>>; + impl<'bound, const SIZE: usize> IoMem<'bound, SIZE> { fn ioremap(dev: &'bound Device<Bound>, resource: &Resource) -> Result<Self> { // Note: Some ioremap() implementations use types that depend on the CPU @@ -269,16 +294,16 @@ fn ioremap(dev: &'bound Device<Bound>, resource: &Resource) -> Result<Self> { /// Consume the `IoMem` and register it as a device-managed resource. /// - /// The returned `Devres<IoMem<'static, SIZE>>` can outlive the original - /// lifetime `'bound`. Access to the I/O memory is revoked when the device - /// is unbound. - pub fn into_devres(self) -> Result<Devres<IoMem<'static, SIZE>>> { - // SAFETY: Casting to `'static` is sound because `Devres` guarantees the `IoMem` does not - // actually outlive the device -- access is revoked and the resource is released when the - // device is unbound. + /// Access methods on the returned [`DevresLt`] shorten the inner lifetime via + /// [`ForLt::cast_ref`], so the transmuted `'static` is never exposed to callers. + pub fn into_devres(self) -> Result<DevresLt<IoMem<'static, SIZE>>> { + // SAFETY: Casting to `'static` is sound because `DevresLt` guarantees the `IoMem` does + // not actually outlive the device -- access is revoked and the resource is released when + // the device is unbound. The `ForLt` encoding ensures `access()` shortens the lifetime + // back to the caller's borrow. let iomem: IoMem<'static, SIZE> = unsafe { core::mem::transmute(self) }; let dev = iomem.dev; - Devres::new(dev, iomem) + DevresLt::new(dev, iomem) } } -- 2.54.0
