[<prev] [next>] [day] [month] [year] [list]
Message-ID: <tencent_63DD850B43CC086844717B73C574B8358F05@qq.com>
Date: Wed, 7 Jan 2026 16:14:40 +0800
From: 1064094935@...com
To: Miguel Ojeda <ojeda@...nel.org>
Cc: Boqun Feng <boqun.feng@...il.com>,
Gary Guo <gary@...yguo.net>,
Björn Roy Baron <bjorn3_gh@...tonmail.com>,
Benno Lossin <lossin@...nel.org>,
Andreas Hindborg <a.hindborg@...nel.org>,
Alice Ryhl <aliceryhl@...gle.com>,
Trevor Gross <tmgross@...ch.edu>,
Danilo Krummrich <dakr@...nel.org>,
Daniel Almeida <daniel.almeida@...labora.com>,
FUJITA Tomonori <fujita.tomonori@...il.com>,
rust-for-linux@...r.kernel.org,
linux-kernel@...r.kernel.org,
pengfuyuan <pengfuyuan@...inos.cn>
Subject: [PATCH] rust: io: mem: add ioremap_wc support
From: pengfuyuan <pengfuyuan@...inos.cn>
Add write-combining memory mapping support to the Rust iomem abstraction.
This extends the existing IoMem and IoRequest abstractions to support
write-combining cache policy, which is essential for framebuffer memory
and other memory regions that benefit from write-combining semantics.
The implementation follows the same pattern as the existing ioremap and
ioremap_np support:
- Add rust_helper_ioremap_wc() in rust/helpers/io.c to wrap the C API
- Add IoMem::ioremap_wc() to perform the actual mapping with write-combining
- Add IoMem::new_wc() to create IoMem instances with write-combining policy
- Add IoRequest::iomap_wc_sized() and IoRequest::iomap_wc() methods
for compile-time and runtime-sized mappings respectively
This enables Rust drivers, such as framebuffer drivers, to properly map
memory regions with write-combining semantics.
The API design is consistent with the existing iomap() methods, providing
both sized and unsized variants to match the pattern established by the
generic iomem abstraction.
Signed-off-by: pengfuyuan <pengfuyuan@...inos.cn>
---
rust/helpers/io.c | 5 +++
rust/kernel/io/mem.rs | 71 +++++++++++++++++++++++++++++++++++++++++++
2 files changed, 76 insertions(+)
diff --git a/rust/helpers/io.c b/rust/helpers/io.c
index c475913c69e6..6c9edf7f2233 100644
--- a/rust/helpers/io.c
+++ b/rust/helpers/io.c
@@ -13,6 +13,11 @@ void __iomem *rust_helper_ioremap_np(phys_addr_t offset, size_t size)
return ioremap_np(offset, size);
}
+void __iomem *rust_helper_ioremap_wc(phys_addr_t offset, size_t size)
+{
+ return ioremap_wc(offset, size);
+}
+
void rust_helper_iounmap(void __iomem *addr)
{
iounmap(addr);
diff --git a/rust/kernel/io/mem.rs b/rust/kernel/io/mem.rs
index b03b82cd531b..94403d899bbd 100644
--- a/rust/kernel/io/mem.rs
+++ b/rust/kernel/io/mem.rs
@@ -149,6 +149,41 @@ pub fn iomap(self) -> impl PinInit<Devres<IoMem<0>>, Error> + 'a {
pub fn iomap_exclusive(self) -> impl PinInit<Devres<ExclusiveIoMem<0>>, Error> + 'a {
Self::iomap_exclusive_sized::<0>(self)
}
+
+ /// Maps an [`IoRequest`] with write-combining cache policy where the size
+ /// is known at compile time.
+ ///
+ /// This uses the [`ioremap_wc()`] C API, which provides write-combining
+ /// semantics. This is useful for framebuffer memory and other memory
+ /// regions that benefit from write-combining, where multiple writes can
+ /// be combined and reordered for better performance.
+ ///
+ /// Unlike [`Self::iomap`], this method explicitly uses write-combining
+ /// mapping, which is typically needed for video framebuffers.
+ ///
+ /// [`ioremap_wc()`]: https://docs.kernel.org/driver-api/device-io.html#getting-access-to-the-device
+ pub fn iomap_wc_sized<const SIZE: usize>(
+ self,
+ ) -> impl PinInit<Devres<IoMem<SIZE>>, Error> + 'a {
+ IoMem::new_wc(self)
+ }
+
+ /// Maps an [`IoRequest`] with write-combining cache policy where the size
+ /// is not known at compile time.
+ ///
+ /// This uses the [`ioremap_wc()`] C API, which provides write-combining
+ /// semantics. This is useful for framebuffer memory and other memory
+ /// regions that benefit from write-combining.
+ ///
+ /// Unlike [`Self::iomap_wc_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.
+ ///
+ /// [`ioremap_wc()`]: https://docs.kernel.org/driver-api/device-io.html#getting-access-to-the-device
+ pub fn iomap_wc(self) -> impl PinInit<Devres<IoMem<0>>, Error> + 'a {
+ Self::iomap_wc_sized::<0>(self)
+ }
}
/// An exclusive memory-mapped IO region.
@@ -261,6 +296,33 @@ fn ioremap(resource: &Resource) -> Result<Self> {
Ok(io)
}
+ fn ioremap_wc(resource: &Resource) -> Result<Self> {
+ // Note: Some ioremap() implementations use types that depend on the CPU
+ // word width rather than the bus address width.
+ //
+ // TODO: Properly address this in the C code to avoid this `try_into`.
+ let size = resource.size().try_into()?;
+ if size == 0 {
+ return Err(EINVAL);
+ }
+
+ let res_start = resource.start();
+
+ // SAFETY:
+ // - `res_start` and `size` are read from a presumably valid `struct resource`.
+ // - `size` is known not to be zero at this point.
+ let addr = unsafe { bindings::ioremap_wc(res_start, size) };
+
+ if addr.is_null() {
+ return Err(ENOMEM);
+ }
+
+ let io = IoRaw::new(addr as usize, size)?;
+ let io = IoMem { io };
+
+ Ok(io)
+ }
+
/// Creates a new `IoMem` instance from a previously acquired [`IoRequest`].
pub fn new<'a>(io_request: IoRequest<'a>) -> impl PinInit<Devres<Self>, Error> + 'a {
let dev = io_request.device;
@@ -268,6 +330,15 @@ pub fn new<'a>(io_request: IoRequest<'a>) -> impl PinInit<Devres<Self>, Error> +
Devres::new(dev, Self::ioremap(res))
}
+
+ /// Creates a new `IoMem` instance with write-combining cache policy from
+ /// a previously acquired [`IoRequest`].
+ pub fn new_wc<'a>(io_request: IoRequest<'a>) -> impl PinInit<Devres<Self>, Error> + 'a {
+ let dev = io_request.device;
+ let res = io_request.resource;
+
+ Devres::new(dev, Self::ioremap_wc(res))
+ }
}
impl<const SIZE: usize> Drop for IoMem<SIZE> {
--
2.25.1
Powered by blists - more mailing lists