* [PATCH v9 0/4] (no cover subject)
@ 2025-06-03 15:05 Daniel Almeida
2025-06-03 15:05 ` [PATCH v9 1/4] rust: io: add resource abstraction Daniel Almeida
` (5 more replies)
0 siblings, 6 replies; 8+ messages in thread
From: Daniel Almeida @ 2025-06-03 15:05 UTC (permalink / raw)
To: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
Trevor Gross, Danilo Krummrich, Greg Kroah-Hartman,
Rafael J. Wysocki, Andrew Morton, Andy Shevchenko,
Ilpo Järvinen, Bjorn Helgaas, Mika Westerberg, Ying Huang
Cc: linux-kernel, rust-for-linux, Fiona Behrens, Daniel Almeida
Changes in v9:
- Rebased on top of nova-next (for Devres::access())
- Reworked the documentation to add more markdown.
- Converted to &raw mut instead of addr_of_mut!()
- Renamed 'from_ptr' to 'as_ref' for consistency
- Changed the IoMem examples to use the signature for probe()
- Changed resource() to resource_by_index(). It's a better fit given
the existance of resource_by_name().
- Created a separate patch for the resource accessors above.
- Moved the accessors into the generic impl block, so they work with all
Device contexts.
- Take Device<Bound> where applicable
- Renamed "ioremap_*" to "iomap_*", in order to be consistent with the code
in pci.rs
- Switched to Devres::access()
- Link to v8: https://lore.kernel.org/r/20250509-topics-tyr-platform_iomem-v8-0-e9f1725a40da@collabora.com
rust: platform: add Io support
Changes in v8:
- Rebased on driver-core-next
- Opted to wait for 'rust/revocable: add try_with() convenience method' to
land instead of using the suggested closure (let me know if we should
just switch to the closure anyways)
- Cc'd more people
- Link to v7: https://lore.kernel.org/r/20250318-topics-tyr-platform_iomem-v7-0-7438691d9ef7@collabora.com
Changes in v7:
- Rebased on top of rust-next
- Fixed a few Clippy lints
- Fixed typos (Thanks Daniel!)
- "struct Flags" now contains a usize (thanks Daniel)
- Fixed "Doc list without indentation" warning (thanks, Guangbo)
Thanks, Fiona {
- Removed RequestFn, as all functions simply used request_region and RequestFn
had issues. Only request_region() is exposed now.
- Gated iomem_resource on CONFIG_HAS_IOMEM
- Require that the name argument be 'static
}
- Correctly check for IORESOURCE_MEM_NONPOSTED. We now call ioremap_np if that
is set (thanks, Lina!)
- Remove #[dead_code] attribute from ExclusiveIoMem::region.
Changes in v6:
- Added Fiona as co-developer in the first patch, as I merged part of her code
from the LED driver series (thanks, Fiona)
- (Fiona) added the ResourceSize type, thereby fixing the u32 vs u64 issues
pointed out by Christian
- Moved the request_region, release_region and friends to resource.rs
- Added the Region type. This type represents a resource returned by
`request_region` and friends. It is also owned, representing the fact
that the region remains marked as busy until release_region is called on
drop. (Thanks Alice, for pointing out this pattern)
- Rewrote the IoMem abstraction to implement a separate type for exclusive
access to an underlying region. I really disliked the `EXCLUSIVE` const
generic, as it was definitely not ergonomic, i.e.:
`IoMem<0, false>`
...doesn't really say much. In fact, I believe that boolean parameters
hurt readability in general.
This new approach lets users build either regular IoMem's, which basically
call ioremap under the covers, and ExclusiveIoMem's , which also call request_region
via the Region type.
- Added access to the ioresource_port and ioresource_mem globals.
Link to v5: https://lore.kernel.org/rust-for-linux/20250116125632.65017-1-daniel.almeida@collabora.com/
Changes in v5:
- resend v5, as the r4l list was not cc'd
- use srctree where applicable in the docs (Alice)
- Remove 'mut' in Resource::from_ptr() (Alice)
- Add 'invariants' section for Resource (Alice)
- Fix typos in mem.rs (Alice)
- Turn 'exclusive' into a const generic (Alice)
- Fix example in platform.rs (Alice)
- Rework the resource.is_null() check (Alice)
- Refactor IoMem::new() to return DevRes<IoMem> directly (Danilo)
link to v4: https://lore.kernel.org/rust-for-linux/20250109133057.243751-1-daniel.almeida@collabora.com/
Changes in v4:
- Rebased on top of driver-core-next
- Split series in multiple patches (Danilo)
- Move IoMem and Resource into its own files (Danilo)
- Fix a missing "if exclusive {...}" check (Danilo)
- Fixed the example, since it was using the old API (Danilo)
- Use Opaque in `Resource`, instead of NonNull and PhantomData (Boqun)
- Highlight that non-exclusive access to the iomem might be required in some cases
- Fixed the safety comment in IoMem::deref()
Link to v3: https://lore.kernel.org/rust-for-linux/20241211-topic-panthor-rs-platform_io_support-v3-1-08ba707e5e3b@collabora.com/
Changes in v3:
- Rebased on top of v5 for the PCI/Platform abstractions
- platform_get_resource is now called only once when calling ioremap
- Introduced a platform::Resource type, which is bound to the lifetime of the
platform Device
- Allow retrieving resources from the platform device either by index or
name
- Make request_mem_region() optional
- Use resource.name() in request_mem_region
- Reword the example to remove an unaligned, out-of-bounds offset
- Update the safety requirements of platform::IoMem
Changes in v2:
- reworked the commit message
- added missing request_mem_region call (Thanks Alice, Danilo)
- IoMem::new() now takes the platform::Device, the resource number and
the name, instead of an address and a size (thanks, Danilo)
- Added a new example for both sized and unsized versions of IoMem.
- Compiled the examples using kunit.py (thanks for the tip, Alice!)
- Removed instances of `foo as _`. All `as` casts now spell out the actual
type.
- Now compiling with CLIPPY=1 (I realized I had forgotten, sorry)
- Rebased on top of rust-next to check for any warnings given the new
unsafe lints.
Daniel Almeida (3):
rust: io: add resource abstraction
rust: io: mem: add a generic iomem abstraction
rust: platform: allow ioremap of platform resources
rust/bindings/bindings_helper.h | 1 +
rust/helpers/io.c | 36 +++++
rust/kernel/io.rs | 3 +
rust/kernel/io/mem.rs | 125 ++++++++++++++++
rust/kernel/io/resource.rs | 252 ++++++++++++++++++++++++++++++++
rust/kernel/platform.rs | 123 +++++++++++++++-
6 files changed, 539 insertions(+), 1 deletion(-)
create mode 100644 rust/kernel/io/mem.rs
create mode 100644 rust/kernel/io/resource.rs
--
2.48.0
---
Daniel Almeida (4):
rust: io: add resource abstraction
rust: io: mem: add a generic iomem abstraction
rust: platform: add resource accessors
rust: platform: allow ioremap of platform resources
rust/bindings/bindings_helper.h | 1 +
rust/helpers/io.c | 41 ++++++++
rust/kernel/io.rs | 3 +
rust/kernel/io/mem.rs | 142 +++++++++++++++++++++++++
rust/kernel/io/resource.rs | 222 ++++++++++++++++++++++++++++++++++++++++
rust/kernel/platform.rs | 159 +++++++++++++++++++++++++++-
6 files changed, 567 insertions(+), 1 deletion(-)
---
base-commit: 276c53c66e032c8e7cc0da63555f2742eb1afd69
change-id: 20250318-topics-tyr-platform_iomem-1710a177e1df
Best regards,
--
Daniel Almeida <daniel.almeida@collabora.com>
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v9 1/4] rust: io: add resource abstraction
2025-06-03 15:05 [PATCH v9 0/4] (no cover subject) Daniel Almeida
@ 2025-06-03 15:05 ` Daniel Almeida
2025-06-03 15:05 ` [PATCH v9 2/4] rust: io: mem: add a generic iomem abstraction Daniel Almeida
` (4 subsequent siblings)
5 siblings, 0 replies; 8+ messages in thread
From: Daniel Almeida @ 2025-06-03 15:05 UTC (permalink / raw)
To: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
Trevor Gross, Danilo Krummrich, Greg Kroah-Hartman,
Rafael J. Wysocki, Andrew Morton, Andy Shevchenko,
Ilpo Järvinen, Bjorn Helgaas, Mika Westerberg, Ying Huang
Cc: linux-kernel, rust-for-linux, Fiona Behrens, Daniel Almeida
In preparation for ioremap support, add a Rust abstraction for struct
resource.
A future commit will introduce the Rust API to ioremap a resource from a
platform device. The current abstraction, therefore, adds only the
minimum API needed to get that done.
Co-developed-by: Fiona Behrens <me@kloenk.dev>
Signed-off-by: Fiona Behrens <me@kloenk.dev>
Signed-off-by: Daniel Almeida <daniel.almeida@collabora.com>
---
rust/bindings/bindings_helper.h | 1 +
rust/helpers/io.c | 36 +++++++
rust/kernel/io.rs | 2 +
rust/kernel/io/resource.rs | 222 ++++++++++++++++++++++++++++++++++++++++
4 files changed, 261 insertions(+)
diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h
index e0676ba99d372afe197e1866d291570012519a2b..a8d619e8df31d04bd48c1bb2d4fb90105f161c91 100644
--- a/rust/bindings/bindings_helper.h
+++ b/rust/bindings/bindings_helper.h
@@ -25,6 +25,7 @@
#include <linux/file.h>
#include <linux/firmware.h>
#include <linux/fs.h>
+#include <linux/ioport.h>
#include <linux/jiffies.h>
#include <linux/jump_label.h>
#include <linux/mdio.h>
diff --git a/rust/helpers/io.c b/rust/helpers/io.c
index 4c2401ccd72078af4e6901f4cd95f9070522f396..939ab38ca61dac4cf884677a20edc760094d5812 100644
--- a/rust/helpers/io.c
+++ b/rust/helpers/io.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/io.h>
+#include <linux/ioport.h>
void __iomem *rust_helper_ioremap(phys_addr_t offset, size_t size)
{
@@ -99,3 +100,38 @@ void rust_helper_writeq_relaxed(u64 value, volatile void __iomem *addr)
writeq_relaxed(value, addr);
}
#endif
+
+resource_size_t rust_helper_resource_size(struct resource *res)
+{
+ return resource_size(res);
+}
+
+struct resource *rust_helper_request_mem_region(resource_size_t start,
+ resource_size_t n,
+ const char *name)
+{
+ return request_mem_region(start, n, name);
+}
+
+void rust_helper_release_mem_region(resource_size_t start, resource_size_t n)
+{
+ release_mem_region(start, n);
+}
+
+struct resource *rust_helper_request_region(resource_size_t start,
+ resource_size_t n, const char *name)
+{
+ return request_region(start, n, name);
+}
+
+struct resource *rust_helper_request_muxed_region(resource_size_t start,
+ resource_size_t n,
+ const char *name)
+{
+ return request_muxed_region(start, n, name);
+}
+
+void rust_helper_release_region(resource_size_t start, resource_size_t n)
+{
+ release_region(start, n);
+}
diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs
index 72d80a6f131e3e826ecd9d2c3bcf54e89aa60cc3..1da447078633e058000953a581b59d3ed5eb0e69 100644
--- a/rust/kernel/io.rs
+++ b/rust/kernel/io.rs
@@ -7,6 +7,8 @@
use crate::error::{code::EINVAL, Result};
use crate::{bindings, build_assert};
+pub mod resource;
+
/// Raw representation of an MMIO region.
///
/// By itself, the existence of an instance of this structure does not provide any guarantees that
diff --git a/rust/kernel/io/resource.rs b/rust/kernel/io/resource.rs
new file mode 100644
index 0000000000000000000000000000000000000000..611eca8cc693d83bccc2c384db2ff22d11e7ac46
--- /dev/null
+++ b/rust/kernel/io/resource.rs
@@ -0,0 +1,222 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Abstractions for system resources.
+//!
+//! C header: [`include/linux/ioport.h`](srctree/include/linux/ioport.h)
+
+use core::ops::Deref;
+use core::ptr::NonNull;
+
+use crate::str::CStr;
+use crate::types::Opaque;
+
+#[cfg(CONFIG_HAS_IOPORT)]
+/// Returns a reference to the global `ioport_resource` variable.
+pub fn ioport_resource() -> &'static Resource {
+ // SAFETY: `bindings::ioport_resoure` has global lifetime and is of type Resource.
+ unsafe { Resource::as_ref(&raw mut bindings::ioport_resource) }
+}
+
+#[cfg(CONFIG_HAS_IOMEM)]
+/// Returns a reference to the global `iomem_resource` variable.
+pub fn iomem_resource() -> &'static Resource {
+ // SAFETY: `bindings::iomem_resoure` has global lifetime and is of type Resource.
+ unsafe { Resource::as_ref(&raw mut bindings::iomem_resource) }
+}
+
+/// Resource Size type.
+///
+/// This is a type alias to `u64` depending on the config option
+/// `CONFIG_PHYS_ADDR_T_64BIT`.
+#[cfg(CONFIG_PHYS_ADDR_T_64BIT)]
+pub type ResourceSize = u64;
+
+/// Resource Size type.
+///
+/// This is a type alias to `u32` depending on the config option
+/// `CONFIG_PHYS_ADDR_T_64BIT`.
+#[cfg(not(CONFIG_PHYS_ADDR_T_64BIT))]
+pub type ResourceSize = u32;
+
+/// A region allocated from a parent [`Resource`].
+///
+/// # Invariants
+///
+/// - `self.0` points to a valid `bindings::resource` that was obtained through
+/// `bindings::__request_region`.
+pub struct Region(NonNull<bindings::resource>);
+
+impl Deref for Region {
+ type Target = Resource;
+
+ fn deref(&self) -> &Self::Target {
+ // SAFETY: Safe as per the invariant of `Region`
+ unsafe { Resource::as_ref(self.0.as_ptr()) }
+ }
+}
+
+impl Drop for Region {
+ fn drop(&mut self) {
+ // SAFETY: Safe as per the invariant of `Region`
+ let res = unsafe { Resource::as_ref(self.0.as_ptr()) };
+ let flags = res.flags();
+
+ let release_fn = if flags.contains(flags::IORESOURCE_MEM) {
+ bindings::release_mem_region
+ } else {
+ bindings::release_region
+ };
+
+ // SAFETY: Safe as per the invariant of `Region`
+ unsafe { release_fn(res.start(), res.size()) };
+ }
+}
+
+// SAFETY: `Region` only holds a pointer to a C `struct resource`, which is safe to be used from
+// any thread.
+unsafe impl Send for Region {}
+
+// SAFETY: `Region` only holds a pointer to a C `struct resource`, references to which are
+// safe to be used from any thread.
+unsafe impl Sync for Region {}
+
+/// A resource abstraction.
+///
+/// # Invariants
+///
+/// [`Resource`] is a transparent wrapper around a valid `bindings::resource`.
+#[repr(transparent)]
+pub struct Resource(Opaque<bindings::resource>);
+
+impl Resource {
+ /// Creates a reference to a [`Resource`] from a valid pointer.
+ ///
+ /// # Safety
+ ///
+ /// The caller must ensure that for the duration of 'a, the pointer will
+ /// point at a valid `bindings::resource`.
+ ///
+ /// The caller must also ensure that the [`Resource`] is only accessed via the
+ /// returned reference for the duration of 'a.
+ pub(crate) const unsafe fn as_ref<'a>(ptr: *mut bindings::resource) -> &'a Self {
+ // SAFETY: Self is a transparent wrapper around `Opaque<bindings::resource>`.
+ unsafe { &*ptr.cast() }
+ }
+
+ /// Requests a resource region.
+ ///
+ /// Exclusive access will be given and the region will be marked as busy.
+ /// Further calls to [`Self::request_region`] will return [`None`] if
+ /// the region, or a part of it, is already in use.
+ pub fn request_region(
+ &self,
+ start: ResourceSize,
+ size: ResourceSize,
+ name: &'static CStr,
+ flags: Flags,
+ ) -> Option<Region> {
+ // SAFETY: Safe as per the invariant of `Resource`
+ let region = unsafe {
+ bindings::__request_region(
+ self.0.get(),
+ start,
+ size,
+ name.as_char_ptr(),
+ flags.0 as i32,
+ )
+ };
+
+ Some(Region(NonNull::new(region)?))
+ }
+
+ /// Returns the size of the resource.
+ pub fn size(&self) -> ResourceSize {
+ let inner = self.0.get();
+ // SAFETY: safe as per the invariants of `Resource`
+ unsafe { bindings::resource_size(inner) }
+ }
+
+ /// Returns the start address of the resource.
+ pub fn start(&self) -> u64 {
+ let inner = self.0.get();
+ // SAFETY: safe as per the invariants of `Resource`
+ unsafe { *inner }.start
+ }
+
+ /// Returns the name of the resource.
+ pub fn name(&self) -> &'static CStr {
+ let inner = self.0.get();
+ // SAFETY: safe as per the invariants of `Resource`
+ unsafe { CStr::from_char_ptr((*inner).name) }
+ }
+
+ /// Returns the flags associated with the resource.
+ pub fn flags(&self) -> Flags {
+ let inner = self.0.get();
+ // SAFETY: safe as per the invariants of `Resource`
+ let flags = unsafe { *inner }.flags;
+
+ Flags(flags)
+ }
+}
+
+// SAFETY: `Resource` only holds a pointer to a C `struct resource`, which is safe to be used from
+// any thead.
+unsafe impl Send for Resource {}
+
+// SAFETY: `Resource` only holds a pointer to a C `struct resource`, references to which are
+// safe to be used from any thead.
+unsafe impl Sync for Resource {}
+
+/// Resource flags as stored in the C `struct resource::flags` field.
+///
+/// They can be combined with the operators `|`, `&`, and `!`.
+///
+/// Values can be used from the [`flags`] module.
+#[derive(Clone, Copy, PartialEq)]
+pub struct Flags(usize);
+
+impl Flags {
+ /// Check whether `flags` is contained in `self`.
+ pub fn contains(self, flags: Flags) -> bool {
+ (self & flags) == flags
+ }
+}
+
+impl core::ops::BitOr for Flags {
+ type Output = Self;
+ fn bitor(self, rhs: Self) -> Self::Output {
+ Self(self.0 | rhs.0)
+ }
+}
+
+impl core::ops::BitAnd for Flags {
+ type Output = Self;
+ fn bitand(self, rhs: Self) -> Self::Output {
+ Self(self.0 & rhs.0)
+ }
+}
+
+impl core::ops::Not for Flags {
+ type Output = Self;
+ fn not(self) -> Self::Output {
+ Self(!self.0)
+ }
+}
+
+/// Resource flags as stored in the `struct resource::flags` field.
+pub mod flags {
+ use super::Flags;
+
+ /// PCI/ISA I/O ports.
+ pub const IORESOURCE_IO: Flags = Flags(bindings::IORESOURCE_IO as usize);
+
+ /// Resource is software muxed.
+ pub const IORESOURCE_MUXED: Flags = Flags(bindings::IORESOURCE_MUXED as usize);
+
+ /// Resource represents a memory region.
+ pub const IORESOURCE_MEM: Flags = Flags(bindings::IORESOURCE_MEM as usize);
+
+ /// Resource represents a memory region that must be ioremaped using `ioremap_np`.
+ pub const IORESOURCE_MEM_NONPOSTED: Flags = Flags(bindings::IORESOURCE_MEM_NONPOSTED as usize);
+}
--
2.49.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v9 2/4] rust: io: mem: add a generic iomem abstraction
2025-06-03 15:05 [PATCH v9 0/4] (no cover subject) Daniel Almeida
2025-06-03 15:05 ` [PATCH v9 1/4] rust: io: add resource abstraction Daniel Almeida
@ 2025-06-03 15:05 ` Daniel Almeida
2025-06-03 15:05 ` [PATCH v9 3/4] rust: platform: add resource accessors Daniel Almeida
` (3 subsequent siblings)
5 siblings, 0 replies; 8+ messages in thread
From: Daniel Almeida @ 2025-06-03 15:05 UTC (permalink / raw)
To: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
Trevor Gross, Danilo Krummrich, Greg Kroah-Hartman,
Rafael J. Wysocki, Andrew Morton, Andy Shevchenko,
Ilpo Järvinen, Bjorn Helgaas, Mika Westerberg, Ying Huang
Cc: linux-kernel, rust-for-linux, Daniel Almeida
Add a generic iomem abstraction to safely read and write ioremapped
regions.
The reads and writes are done through IoRaw, and are thus checked either
at compile-time, if the size of the region is known at that point, or at
runtime otherwise.
Non-exclusive access to the underlying memory region is made possible to
cater to cases where overlapped regions are unavoidable.
Signed-off-by: Daniel Almeida <daniel.almeida@collabora.com>
---
rust/helpers/io.c | 5 ++
rust/kernel/io.rs | 1 +
rust/kernel/io/mem.rs | 142 ++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 148 insertions(+)
diff --git a/rust/helpers/io.c b/rust/helpers/io.c
index 939ab38ca61dac4cf884677a20edc760094d5812..4fbd70ab60f64155bef835a43b3c64d441aee7bf 100644
--- a/rust/helpers/io.c
+++ b/rust/helpers/io.c
@@ -8,6 +8,11 @@ void __iomem *rust_helper_ioremap(phys_addr_t offset, size_t size)
return ioremap(offset, size);
}
+void __iomem *rust_helper_ioremap_np(phys_addr_t offset, size_t size)
+{
+ return ioremap_np(offset, size);
+}
+
void rust_helper_iounmap(volatile void __iomem *addr)
{
iounmap(addr);
diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs
index 1da447078633e058000953a581b59d3ed5eb0e69..0249aedd8c6ce435b6b00137be0895a206956bca 100644
--- a/rust/kernel/io.rs
+++ b/rust/kernel/io.rs
@@ -7,6 +7,7 @@
use crate::error::{code::EINVAL, Result};
use crate::{bindings, build_assert};
+pub mod mem;
pub mod resource;
/// Raw representation of an MMIO region.
diff --git a/rust/kernel/io/mem.rs b/rust/kernel/io/mem.rs
new file mode 100644
index 0000000000000000000000000000000000000000..2bd9cf4c4f1a59f027999a6e9a203dc99ad6c003
--- /dev/null
+++ b/rust/kernel/io/mem.rs
@@ -0,0 +1,142 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Generic memory-mapped IO.
+
+use core::ops::Deref;
+
+use crate::device::Bound;
+use crate::device::Device;
+use crate::devres::Devres;
+use crate::io;
+use crate::io::resource::Region;
+use crate::io::resource::Resource;
+use crate::io::Io;
+use crate::io::IoRaw;
+use crate::prelude::*;
+
+/// An exclusive memory-mapped IO region.
+///
+/// # Invariants
+///
+/// - [`ExclusiveIoMem`] has exclusive access to the underlying [`IoMem`].
+pub struct ExclusiveIoMem<const SIZE: usize> {
+ /// The region abstraction. This represents exclusive access to the
+ /// range represented by the underlying `iomem`.
+ ///
+ /// It's placed first to ensure that the region is released before it is
+ /// unmapped as a result of the drop order.
+ ///
+ /// This field is needed for ownership of the region.
+ _region: Region,
+ /// The underlying `IoMem` instance.
+ iomem: IoMem<SIZE>,
+}
+
+impl<const SIZE: usize> ExclusiveIoMem<SIZE> {
+ /// Creates a new `ExclusiveIoMem` instance.
+ pub(crate) fn ioremap(resource: &Resource) -> Result<Self> {
+ let iomem = IoMem::ioremap(resource)?;
+
+ let start = resource.start();
+ let size = resource.size();
+ let name = resource.name();
+
+ let region = resource
+ .request_region(start, size, name, io::resource::flags::IORESOURCE_MEM)
+ .ok_or(EBUSY)?;
+
+ let iomem = ExclusiveIoMem {
+ iomem,
+ _region: region,
+ };
+
+ Ok(iomem)
+ }
+
+ pub(crate) fn new(resource: &Resource, device: &Device<Bound>) -> Result<Devres<Self>> {
+ let iomem = Self::ioremap(resource)?;
+ let devres = Devres::new(device, iomem, GFP_KERNEL)?;
+
+ Ok(devres)
+ }
+}
+
+impl<const SIZE: usize> Deref for ExclusiveIoMem<SIZE> {
+ type Target = Io<SIZE>;
+
+ fn deref(&self) -> &Self::Target {
+ &self.iomem
+ }
+}
+
+/// A generic memory-mapped IO region.
+///
+/// Accesses to the underlying region is checked either at compile time, if the
+/// region's size is known at that point, or at runtime otherwise.
+///
+/// # Invariants
+///
+/// [`IoMem`] always holds an [`IoRaw`] instance that holds a valid pointer to the
+/// start of the I/O memory mapped region.
+pub struct IoMem<const SIZE: usize = 0> {
+ io: IoRaw<SIZE>,
+}
+
+impl<const SIZE: usize> IoMem<SIZE> {
+ fn ioremap(resource: &Resource) -> Result<Self> {
+ let size = resource.size();
+ if size == 0 {
+ return Err(EINVAL);
+ }
+
+ let res_start = resource.start();
+
+ let addr = if resource
+ .flags()
+ .contains(io::resource::flags::IORESOURCE_MEM_NONPOSTED)
+ {
+ // SAFETY:
+ // - `res_start` and `size` are read from a presumably valid `struct resource`.
+ // - `size` is known not to be zero at this point.
+ unsafe { bindings::ioremap_np(res_start, size as usize) }
+ } else {
+ // SAFETY:
+ // - `res_start` and `size` are read from a presumably valid `struct resource`.
+ // - `size` is known not to be zero at this point.
+ unsafe { bindings::ioremap(res_start, size as usize) }
+ };
+
+ if addr.is_null() {
+ return Err(ENOMEM);
+ }
+
+ let io = IoRaw::new(addr as usize, size as usize)?;
+ let io = IoMem { io };
+
+ Ok(io)
+ }
+
+ /// Creates a new `IoMem` instance.
+ pub(crate) fn new(resource: &Resource, device: &Device<Bound>) -> Result<Devres<Self>> {
+ let io = Self::ioremap(resource)?;
+ let devres = Devres::new(device, io, GFP_KERNEL)?;
+
+ Ok(devres)
+ }
+}
+
+impl<const SIZE: usize> Drop for IoMem<SIZE> {
+ fn drop(&mut self) {
+ // SAFETY: Safe as by the invariant of `Io`.
+ unsafe { bindings::iounmap(self.io.addr() as *mut core::ffi::c_void) }
+ }
+}
+
+impl<const SIZE: usize> Deref for IoMem<SIZE> {
+ type Target = Io<SIZE>;
+
+ fn deref(&self) -> &Self::Target {
+ // SAFETY: Safe as by the invariant of `IoMem`.
+ unsafe { Io::from_raw(&self.io) }
+ }
+}
--
2.49.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v9 3/4] rust: platform: add resource accessors
2025-06-03 15:05 [PATCH v9 0/4] (no cover subject) Daniel Almeida
2025-06-03 15:05 ` [PATCH v9 1/4] rust: io: add resource abstraction Daniel Almeida
2025-06-03 15:05 ` [PATCH v9 2/4] rust: io: mem: add a generic iomem abstraction Daniel Almeida
@ 2025-06-03 15:05 ` Daniel Almeida
2025-06-03 15:05 ` [PATCH v9 4/4] rust: platform: allow ioremap of platform resources Daniel Almeida
` (2 subsequent siblings)
5 siblings, 0 replies; 8+ messages in thread
From: Daniel Almeida @ 2025-06-03 15:05 UTC (permalink / raw)
To: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
Trevor Gross, Danilo Krummrich, Greg Kroah-Hartman,
Rafael J. Wysocki, Andrew Morton, Andy Shevchenko,
Ilpo Järvinen, Bjorn Helgaas, Mika Westerberg, Ying Huang
Cc: linux-kernel, rust-for-linux, Daniel Almeida
A previous patch has exposed the abstractions struct resource.
Now make it possible to retrieve retrieve resources from platform devices
in Rust using either a name or an index.
Signed-off-by: Daniel Almeida <daniel.almeida@collabora.com>
---
rust/kernel/platform.rs | 38 ++++++++++++++++++++++++++++++++++++++
1 file changed, 38 insertions(+)
diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs
index 08849d92c07418d6390803bb8cc51516368bca84..427bc706f4349083b6bab81a02cb8ed803903590 100644
--- a/rust/kernel/platform.rs
+++ b/rust/kernel/platform.rs
@@ -7,6 +7,7 @@
use crate::{
bindings, container_of, device, driver,
error::{to_result, Result},
+ io::resource::Resource,
of,
prelude::*,
str::CStr,
@@ -187,6 +188,43 @@ impl<Ctx: device::DeviceContext> Device<Ctx> {
fn as_raw(&self) -> *mut bindings::platform_device {
self.0.get()
}
+
+ /// Returns the resource at `index`, if any.
+ pub fn resource_by_index(&self, index: u32) -> Option<&Resource> {
+ // SAFETY: `self.as_raw()` returns a valid pointer to a `struct platform_device`.
+ let resource = unsafe {
+ bindings::platform_get_resource(self.as_raw(), bindings::IORESOURCE_MEM, index)
+ };
+
+ if resource.is_null() {
+ return None;
+ }
+
+ // SAFETY: `resource` is a valid pointer to a `struct resource` as
+ // returned by `platform_get_resource`.
+ Some(unsafe { Resource::as_ref(resource) })
+ }
+
+ /// Returns the resource with a given `name`, if any.
+ pub fn resource_by_name(&self, name: &CStr) -> Option<&Resource> {
+ // SAFETY: `self.as_raw()` returns a valid pointer to a `struct
+ // platform_device` and `name` points to a valid C string.
+ let resource = unsafe {
+ bindings::platform_get_resource_byname(
+ self.as_raw(),
+ bindings::IORESOURCE_MEM,
+ name.as_char_ptr(),
+ )
+ };
+
+ if resource.is_null() {
+ return None;
+ }
+
+ // SAFETY: `resource` is a valid pointer to a `struct resource` as
+ // returned by `platform_get_resource`.
+ Some(unsafe { Resource::as_ref(resource) })
+ }
}
// SAFETY: `Device` is a transparent wrapper of a type that doesn't depend on `Device`'s generic
--
2.49.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v9 4/4] rust: platform: allow ioremap of platform resources
2025-06-03 15:05 [PATCH v9 0/4] (no cover subject) Daniel Almeida
` (2 preceding siblings ...)
2025-06-03 15:05 ` [PATCH v9 3/4] rust: platform: add resource accessors Daniel Almeida
@ 2025-06-03 15:05 ` Daniel Almeida
2025-06-04 22:21 ` Danilo Krummrich
2025-06-03 15:11 ` [PATCH v9 0/4] (no cover subject) Daniel Almeida
2025-06-03 15:17 ` Ilpo Järvinen
5 siblings, 1 reply; 8+ messages in thread
From: Daniel Almeida @ 2025-06-03 15:05 UTC (permalink / raw)
To: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
Trevor Gross, Danilo Krummrich, Greg Kroah-Hartman,
Rafael J. Wysocki, Andrew Morton, Andy Shevchenko,
Ilpo Järvinen, Bjorn Helgaas, Mika Westerberg, Ying Huang
Cc: linux-kernel, rust-for-linux, Daniel Almeida
The preceding patches added support for resources, and for a general
IoMem abstraction, but thus far there is no way to access said IoMem
from drivers, as its creation is unsafe and depends on a resource that
must be acquired from some device first.
Now, allow the ioremap of platform resources themselves, thereby making
the IoMem available to platform drivers.
Signed-off-by: Daniel Almeida <daniel.almeida@collabora.com>
---
rust/kernel/platform.rs | 123 +++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 121 insertions(+), 2 deletions(-)
diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs
index 427bc706f4349083b6bab81a02cb8ed803903590..57414fd0db296e412f45fbefd7707b338b37332a 100644
--- a/rust/kernel/platform.rs
+++ b/rust/kernel/platform.rs
@@ -5,9 +5,14 @@
//! C header: [`include/linux/platform_device.h`](srctree/include/linux/platform_device.h)
use crate::{
- bindings, container_of, device, driver,
+ bindings, container_of, device,
+ devres::Devres,
+ driver,
error::{to_result, Result},
- io::resource::Resource,
+ io::{
+ mem::{ExclusiveIoMem, IoMem},
+ resource::Resource,
+ },
of,
prelude::*,
str::CStr,
@@ -227,6 +232,120 @@ pub fn resource_by_name(&self, name: &CStr) -> Option<&Resource> {
}
}
+impl Device<device::Bound> {
+ /// Maps a platform resource where the size is known at compile time.
+ ///
+ /// This uses the
+ /// [`ioremap()`](https://docs.kernel.org/driver-api/device-io.html#getting-access-to-the-device)
+ /// C API.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use kernel::{bindings, c_str, platform, of, device::Core};
+ /// # struct SampleDriver;
+ ///
+ /// impl platform::Driver for SampleDriver {
+ /// # type IdInfo = ();
+ /// # const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = None;
+ ///
+ /// fn probe(
+ /// pdev: &platform::Device<Core>,
+ /// info: Option<&Self::IdInfo>,
+ /// ) -> Result<Pin<KBox<Self>>> {
+ /// let offset = 0; // Some offset.
+ ///
+ /// // If the size is known at compile time, use [`Self::iomap_resource_sized`].
+ /// //
+ /// // No runtime checks will apply when reading and writing.
+ /// let resource = pdev.resource_by_index(0).ok_or(ENODEV)?;
+ /// let iomem = pdev.iomap_resource_sized::<42>(&resource)?;
+ /// let io = iomem.access(pdev.as_ref())?;
+ ///
+ /// // Read and write a 32-bit value at `offset`. Calling `try_access()` on
+ /// // the `Devres` makes sure that the resource is still valid.
+ /// let data = io.read32_relaxed(offset);
+ ///
+ /// iomem.try_access().ok_or(ENODEV)?.write32_relaxed(data, offset);
+ ///
+ /// # let sample_driver = KBox::new(SampleDriver, GFP_KERNEL).map_err(|_| ENOMEM)?;
+ /// # Ok(sample_driver.into())
+ /// }
+ /// }
+ /// ```
+ pub fn iomap_resource_sized<const SIZE: usize>(
+ &self,
+ resource: &Resource,
+ ) -> Result<Devres<IoMem<SIZE>>> {
+ IoMem::new(resource, self.as_ref())
+ }
+
+ /// Same as [`Self::iomap_resource_sized`] but with exclusive access to the
+ /// underlying region.
+ ///
+ /// This uses the
+ /// [`ioremap()`](https://docs.kernel.org/driver-api/device-io.html#getting-access-to-the-device)
+ /// C API.
+ pub fn iomap_resource_exclusive_sized<const SIZE: usize>(
+ &self,
+ resource: &Resource,
+ ) -> Result<Devres<ExclusiveIoMem<SIZE>>> {
+ ExclusiveIoMem::new(resource, self.as_ref())
+ }
+
+ /// Maps a platform resource through iomap().
+ ///
+ /// This uses the
+ /// [`ioremap()`](https://docs.kernel.org/driver-api/device-io.html#getting-access-to-the-device)
+ /// C API.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use kernel::{bindings, c_str, platform, of, device::Core};
+ /// # struct SampleDriver;
+ ///
+ /// impl platform::Driver for SampleDriver {
+ /// # type IdInfo = ();
+ /// # const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = None;
+ ///
+ /// fn probe(
+ /// pdev: &platform::Device<Core>,
+ /// info: Option<&Self::IdInfo>,
+ /// ) -> Result<Pin<KBox<Self>>> {
+ /// let offset = 0; // Some offset.
+ ///
+ /// // Unlike [`Self::iomap_resource_sized`], here the size of the memory region
+ /// // is not known at compile time, so only the `try_read*` and `try_write*`
+ /// // family of functions should be used, leading to runtime checks on every
+ /// // access.
+ /// let resource = pdev.resource_by_index(0).ok_or(ENODEV)?;
+ /// let iomem = pdev.iomap_resource(&resource)?;
+ /// let io = iomem.access(pdev.as_ref())?;
+ ///
+ /// let data = io.try_read32_relaxed(offset)?;
+ ///
+ /// io.try_write32_relaxed(data, offset)?;
+ ///
+ /// # let sample_driver = KBox::new(SampleDriver, GFP_KERNEL).map_err(|_| ENOMEM)?;
+ /// # Ok(sample_driver.into())
+ /// }
+ /// }
+ /// ```
+ pub fn iomap_resource(&self, resource: &Resource) -> Result<Devres<IoMem<0>>> {
+ self.iomap_resource_sized::<0>(resource)
+ }
+
+ /// Same as [`Self::iomap_resource`] but with exclusive access to the underlying
+ /// region.
+ pub fn iomap_resource_exclusive(
+ &self,
+ resource: &Resource,
+ ) -> Result<Devres<ExclusiveIoMem<0>>> {
+ self.iomap_resource_exclusive_sized::<0>(resource)
+ }
+}
+
// SAFETY: `Device` is a transparent wrapper of a type that doesn't depend on `Device`'s generic
// argument.
kernel::impl_device_context_deref!(unsafe { Device });
--
2.49.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH v9 0/4] (no cover subject)
2025-06-03 15:05 [PATCH v9 0/4] (no cover subject) Daniel Almeida
` (3 preceding siblings ...)
2025-06-03 15:05 ` [PATCH v9 4/4] rust: platform: allow ioremap of platform resources Daniel Almeida
@ 2025-06-03 15:11 ` Daniel Almeida
2025-06-03 15:17 ` Ilpo Järvinen
5 siblings, 0 replies; 8+ messages in thread
From: Daniel Almeida @ 2025-06-03 15:11 UTC (permalink / raw)
To: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
Trevor Gross, Danilo Krummrich, Greg Kroah-Hartman,
Rafael J. Wysocki, Andrew Morton, Andy Shevchenko,
Ilpo Järvinen, Bjorn Helgaas, Mika Westerberg, Ying Huang
Cc: linux-kernel, rust-for-linux, Fiona Behrens
Sorry, messed this one in b4.
The rest of the patches seem OK though.
— Daniel
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v9 0/4] (no cover subject)
2025-06-03 15:05 [PATCH v9 0/4] (no cover subject) Daniel Almeida
` (4 preceding siblings ...)
2025-06-03 15:11 ` [PATCH v9 0/4] (no cover subject) Daniel Almeida
@ 2025-06-03 15:17 ` Ilpo Järvinen
5 siblings, 0 replies; 8+ messages in thread
From: Ilpo Järvinen @ 2025-06-03 15:17 UTC (permalink / raw)
To: Daniel Almeida
Cc: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
Trevor Gross, Danilo Krummrich, Greg Kroah-Hartman,
Rafael J. Wysocki, Andrew Morton, Andy Shevchenko, Bjorn Helgaas,
Mika Westerberg, Ying Huang, LKML, rust-for-linux, Fiona Behrens
On Tue, 3 Jun 2025, Daniel Almeida wrote:
> Changes in v9:
> - Rebased on top of nova-next (for Devres::access())
> - Reworked the documentation to add more markdown.
> - Converted to &raw mut instead of addr_of_mut!()
> - Renamed 'from_ptr' to 'as_ref' for consistency
> - Changed the IoMem examples to use the signature for probe()
> - Changed resource() to resource_by_index(). It's a better fit given
> the existance of resource_by_name().
> - Created a separate patch for the resource accessors above.
> - Moved the accessors into the generic impl block, so they work with all
> Device contexts.
> - Take Device<Bound> where applicable
> - Renamed "ioremap_*" to "iomap_*", in order to be consistent with the code
> in pci.rs
> - Switched to Devres::access()
> - Link to v8: https://lore.kernel.org/r/20250509-topics-tyr-platform_iomem-v8-0-e9f1725a40da@collabora.com
>
> rust: platform: add Io support
>
> Changes in v8:
> - Rebased on driver-core-next
> - Opted to wait for 'rust/revocable: add try_with() convenience method' to
> land instead of using the suggested closure (let me know if we should
> just switch to the closure anyways)
> - Cc'd more people
> - Link to v7: https://lore.kernel.org/r/20250318-topics-tyr-platform_iomem-v7-0-7438691d9ef7@collabora.com
>
> Changes in v7:
>
> - Rebased on top of rust-next
> - Fixed a few Clippy lints
> - Fixed typos (Thanks Daniel!)
> - "struct Flags" now contains a usize (thanks Daniel)
> - Fixed "Doc list without indentation" warning (thanks, Guangbo)
>
> Thanks, Fiona {
> - Removed RequestFn, as all functions simply used request_region and RequestFn
> had issues. Only request_region() is exposed now.
> - Gated iomem_resource on CONFIG_HAS_IOMEM
> - Require that the name argument be 'static
> }
>
> - Correctly check for IORESOURCE_MEM_NONPOSTED. We now call ioremap_np if that
> is set (thanks, Lina!)
> - Remove #[dead_code] attribute from ExclusiveIoMem::region.
>
> Changes in v6:
>
> - Added Fiona as co-developer in the first patch, as I merged part of her code
> from the LED driver series (thanks, Fiona)
>
> - (Fiona) added the ResourceSize type, thereby fixing the u32 vs u64 issues
> pointed out by Christian
>
> - Moved the request_region, release_region and friends to resource.rs
>
> - Added the Region type. This type represents a resource returned by
> `request_region` and friends. It is also owned, representing the fact
> that the region remains marked as busy until release_region is called on
> drop. (Thanks Alice, for pointing out this pattern)
>
> - Rewrote the IoMem abstraction to implement a separate type for exclusive
> access to an underlying region. I really disliked the `EXCLUSIVE` const
> generic, as it was definitely not ergonomic, i.e.:
>
> `IoMem<0, false>`
>
> ...doesn't really say much. In fact, I believe that boolean parameters
> hurt readability in general.
>
> This new approach lets users build either regular IoMem's, which basically
> call ioremap under the covers, and ExclusiveIoMem's , which also call request_region
> via the Region type.
>
> - Added access to the ioresource_port and ioresource_mem globals.
>
> Link to v5: https://lore.kernel.org/rust-for-linux/20250116125632.65017-1-daniel.almeida@collabora.com/
>
> Changes in v5:
>
> - resend v5, as the r4l list was not cc'd
> - use srctree where applicable in the docs (Alice)
> - Remove 'mut' in Resource::from_ptr() (Alice)
> - Add 'invariants' section for Resource (Alice)
> - Fix typos in mem.rs (Alice)
> - Turn 'exclusive' into a const generic (Alice)
> - Fix example in platform.rs (Alice)
> - Rework the resource.is_null() check (Alice)
> - Refactor IoMem::new() to return DevRes<IoMem> directly (Danilo)
>
> link to v4: https://lore.kernel.org/rust-for-linux/20250109133057.243751-1-daniel.almeida@collabora.com/
>
> Changes in v4:
>
> - Rebased on top of driver-core-next
> - Split series in multiple patches (Danilo)
> - Move IoMem and Resource into its own files (Danilo)
> - Fix a missing "if exclusive {...}" check (Danilo)
> - Fixed the example, since it was using the old API (Danilo)
> - Use Opaque in `Resource`, instead of NonNull and PhantomData (Boqun)
> - Highlight that non-exclusive access to the iomem might be required in some cases
> - Fixed the safety comment in IoMem::deref()
>
> Link to v3: https://lore.kernel.org/rust-for-linux/20241211-topic-panthor-rs-platform_io_support-v3-1-08ba707e5e3b@collabora.com/
>
> Changes in v3:
> - Rebased on top of v5 for the PCI/Platform abstractions
> - platform_get_resource is now called only once when calling ioremap
> - Introduced a platform::Resource type, which is bound to the lifetime of the
> platform Device
> - Allow retrieving resources from the platform device either by index or
> name
> - Make request_mem_region() optional
> - Use resource.name() in request_mem_region
> - Reword the example to remove an unaligned, out-of-bounds offset
> - Update the safety requirements of platform::IoMem
>
> Changes in v2:
> - reworked the commit message
> - added missing request_mem_region call (Thanks Alice, Danilo)
> - IoMem::new() now takes the platform::Device, the resource number and
> the name, instead of an address and a size (thanks, Danilo)
> - Added a new example for both sized and unsized versions of IoMem.
> - Compiled the examples using kunit.py (thanks for the tip, Alice!)
> - Removed instances of `foo as _`. All `as` casts now spell out the actual
> type.
> - Now compiling with CLIPPY=1 (I realized I had forgotten, sorry)
> - Rebased on top of rust-next to check for any warnings given the new
> unsafe lints.
>
> Daniel Almeida (3):
> rust: io: add resource abstraction
> rust: io: mem: add a generic iomem abstraction
> rust: platform: allow ioremap of platform resources
>
> rust/bindings/bindings_helper.h | 1 +
> rust/helpers/io.c | 36 +++++
> rust/kernel/io.rs | 3 +
> rust/kernel/io/mem.rs | 125 ++++++++++++++++
> rust/kernel/io/resource.rs | 252 ++++++++++++++++++++++++++++++++
> rust/kernel/platform.rs | 123 +++++++++++++++-
> 6 files changed, 539 insertions(+), 1 deletion(-)
> create mode 100644 rust/kernel/io/mem.rs
> create mode 100644 rust/kernel/io/resource.rs
No MAINTAINERS entries are added for the new files?
> --
> 2.48.0
>
> ---
> Daniel Almeida (4):
> rust: io: add resource abstraction
> rust: io: mem: add a generic iomem abstraction
> rust: platform: add resource accessors
> rust: platform: allow ioremap of platform resources
>
> rust/bindings/bindings_helper.h | 1 +
> rust/helpers/io.c | 41 ++++++++
> rust/kernel/io.rs | 3 +
> rust/kernel/io/mem.rs | 142 +++++++++++++++++++++++++
> rust/kernel/io/resource.rs | 222 ++++++++++++++++++++++++++++++++++++++++
> rust/kernel/platform.rs | 159 +++++++++++++++++++++++++++-
> 6 files changed, 567 insertions(+), 1 deletion(-)
> ---
> base-commit: 276c53c66e032c8e7cc0da63555f2742eb1afd69
> change-id: 20250318-topics-tyr-platform_iomem-1710a177e1df
>
> Best regards,
>
--
i.
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v9 4/4] rust: platform: allow ioremap of platform resources
2025-06-03 15:05 ` [PATCH v9 4/4] rust: platform: allow ioremap of platform resources Daniel Almeida
@ 2025-06-04 22:21 ` Danilo Krummrich
0 siblings, 0 replies; 8+ messages in thread
From: Danilo Krummrich @ 2025-06-04 22:21 UTC (permalink / raw)
To: Daniel Almeida
Cc: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
Trevor Gross, Greg Kroah-Hartman, Rafael J. Wysocki,
Andrew Morton, Andy Shevchenko, Ilpo Järvinen, Bjorn Helgaas,
Mika Westerberg, Ying Huang, linux-kernel, rust-for-linux
On Tue, Jun 03, 2025 at 12:05:30PM -0300, Daniel Almeida wrote:
> The preceding patches added support for resources, and for a general
> IoMem abstraction, but thus far there is no way to access said IoMem
> from drivers, as its creation is unsafe and depends on a resource that
> must be acquired from some device first.
>
> Now, allow the ioremap of platform resources themselves, thereby making
> the IoMem available to platform drivers.
>
> Signed-off-by: Daniel Almeida <daniel.almeida@collabora.com>
> ---
> rust/kernel/platform.rs | 123 +++++++++++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 121 insertions(+), 2 deletions(-)
>
> diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs
> index 427bc706f4349083b6bab81a02cb8ed803903590..57414fd0db296e412f45fbefd7707b338b37332a 100644
> --- a/rust/kernel/platform.rs
> +++ b/rust/kernel/platform.rs
> @@ -5,9 +5,14 @@
> //! C header: [`include/linux/platform_device.h`](srctree/include/linux/platform_device.h)
>
> use crate::{
> - bindings, container_of, device, driver,
> + bindings, container_of, device,
> + devres::Devres,
> + driver,
> error::{to_result, Result},
> - io::resource::Resource,
> + io::{
> + mem::{ExclusiveIoMem, IoMem},
> + resource::Resource,
I think we should add
pub use resource::Resource;
into io.rs, such that we can refer to this as ::kernel::io::Resource.
> + },
> of,
> prelude::*,
> str::CStr,
> @@ -227,6 +232,120 @@ pub fn resource_by_name(&self, name: &CStr) -> Option<&Resource> {
> }
> }
>
> +impl Device<device::Bound> {
> + /// Maps a platform resource where the size is known at compile time.
> + ///
> + /// This uses the
> + /// [`ioremap()`](https://docs.kernel.org/driver-api/device-io.html#getting-access-to-the-device)
> + /// C API.
> + ///
> + /// # Examples
> + ///
> + /// ```no_run
> + /// # use kernel::{bindings, c_str, platform, of, device::Core};
> + /// # struct SampleDriver;
> + ///
> + /// impl platform::Driver for SampleDriver {
> + /// # type IdInfo = ();
> + /// # const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = None;
> + ///
> + /// fn probe(
> + /// pdev: &platform::Device<Core>,
> + /// info: Option<&Self::IdInfo>,
> + /// ) -> Result<Pin<KBox<Self>>> {
> + /// let offset = 0; // Some offset.
> + ///
> + /// // If the size is known at compile time, use [`Self::iomap_resource_sized`].
> + /// //
> + /// // No runtime checks will apply when reading and writing.
> + /// let resource = pdev.resource_by_index(0).ok_or(ENODEV)?;
> + /// let iomem = pdev.iomap_resource_sized::<42>(&resource)?;
> + /// let io = iomem.access(pdev.as_ref())?;
> + ///
> + /// // Read and write a 32-bit value at `offset`. Calling `try_access()` on
> + /// // the `Devres` makes sure that the resource is still valid.
> + /// let data = io.read32_relaxed(offset);
> + ///
> + /// iomem.try_access().ok_or(ENODEV)?.write32_relaxed(data, offset);
io.write32_relaxed(data, offset);
> + ///
> + /// # let sample_driver = KBox::new(SampleDriver, GFP_KERNEL).map_err(|_| ENOMEM)?;
Why the map_err()? We have
impl From<AllocError> for Error {
fn from(_: AllocError) -> Error {
code::ENOMEM
}
}
so you shouldn't need that.
Also, please just write this as
# Ok(KBox::new(SampleDriver, GFP_KERNEL)?.into())
> + /// # Ok(sample_driver.into())
> + /// }
> + /// }
> + /// ```
> + pub fn iomap_resource_sized<const SIZE: usize>(
> + &self,
> + resource: &Resource,
> + ) -> Result<Devres<IoMem<SIZE>>> {
> + IoMem::new(resource, self.as_ref())
> + }
> +
> + /// Same as [`Self::iomap_resource_sized`] but with exclusive access to the
> + /// underlying region.
> + ///
> + /// This uses the
> + /// [`ioremap()`](https://docs.kernel.org/driver-api/device-io.html#getting-access-to-the-device)
> + /// C API.
> + pub fn iomap_resource_exclusive_sized<const SIZE: usize>(
> + &self,
> + resource: &Resource,
> + ) -> Result<Devres<ExclusiveIoMem<SIZE>>> {
> + ExclusiveIoMem::new(resource, self.as_ref())
> + }
> +
> + /// Maps a platform resource through iomap().
> + ///
> + /// This uses the
> + /// [`ioremap()`](https://docs.kernel.org/driver-api/device-io.html#getting-access-to-the-device)
> + /// C API.
> + ///
> + /// # Examples
> + ///
> + /// ```no_run
> + /// # use kernel::{bindings, c_str, platform, of, device::Core};
> + /// # struct SampleDriver;
> + ///
> + /// impl platform::Driver for SampleDriver {
> + /// # type IdInfo = ();
> + /// # const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = None;
> + ///
> + /// fn probe(
> + /// pdev: &platform::Device<Core>,
> + /// info: Option<&Self::IdInfo>,
> + /// ) -> Result<Pin<KBox<Self>>> {
> + /// let offset = 0; // Some offset.
> + ///
> + /// // Unlike [`Self::iomap_resource_sized`], here the size of the memory region
> + /// // is not known at compile time, so only the `try_read*` and `try_write*`
> + /// // family of functions should be used, leading to runtime checks on every
> + /// // access.
> + /// let resource = pdev.resource_by_index(0).ok_or(ENODEV)?;
> + /// let iomem = pdev.iomap_resource(&resource)?;
> + /// let io = iomem.access(pdev.as_ref())?;
> + ///
> + /// let data = io.try_read32_relaxed(offset)?;
> + ///
> + /// io.try_write32_relaxed(data, offset)?;
> + ///
> + /// # let sample_driver = KBox::new(SampleDriver, GFP_KERNEL).map_err(|_| ENOMEM)?;
Same as above.
> + /// # Ok(sample_driver.into())
> + /// }
> + /// }
> + /// ```
> + pub fn iomap_resource(&self, resource: &Resource) -> Result<Devres<IoMem<0>>> {
> + self.iomap_resource_sized::<0>(resource)
> + }
> +
> + /// Same as [`Self::iomap_resource`] but with exclusive access to the underlying
> + /// region.
> + pub fn iomap_resource_exclusive(
> + &self,
> + resource: &Resource,
> + ) -> Result<Devres<ExclusiveIoMem<0>>> {
> + self.iomap_resource_exclusive_sized::<0>(resource)
> + }
> +}
> +
> // SAFETY: `Device` is a transparent wrapper of a type that doesn't depend on `Device`'s generic
> // argument.
> kernel::impl_device_context_deref!(unsafe { Device });
>
> --
> 2.49.0
>
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2025-06-04 22:22 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-06-03 15:05 [PATCH v9 0/4] (no cover subject) Daniel Almeida
2025-06-03 15:05 ` [PATCH v9 1/4] rust: io: add resource abstraction Daniel Almeida
2025-06-03 15:05 ` [PATCH v9 2/4] rust: io: mem: add a generic iomem abstraction Daniel Almeida
2025-06-03 15:05 ` [PATCH v9 3/4] rust: platform: add resource accessors Daniel Almeida
2025-06-03 15:05 ` [PATCH v9 4/4] rust: platform: allow ioremap of platform resources Daniel Almeida
2025-06-04 22:21 ` Danilo Krummrich
2025-06-03 15:11 ` [PATCH v9 0/4] (no cover subject) Daniel Almeida
2025-06-03 15:17 ` Ilpo Järvinen
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).