public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/6] soc: qcom: socinfo: Convert to Rust
@ 2026-02-03 15:46 Matthew Maurer
  2026-02-03 15:46 ` [PATCH v2 1/6] rust: Add sparse_array! helper macro Matthew Maurer
                   ` (5 more replies)
  0 siblings, 6 replies; 32+ messages in thread
From: Matthew Maurer @ 2026-02-03 15:46 UTC (permalink / raw)
  To: Bjorn Andersson, Konrad Dybcio, Satya Durga Srinivasu Prabhala,
	Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, Daniel Almeida, Greg Kroah-Hartman,
	Rafael J. Wysocki, David Airlie, Simona Vetter, Michal Wilczynski,
	Dave Ertman, Ira Weiny, Leon Romanovsky
  Cc: Trilok Soni, linux-kernel, linux-arm-msm, rust-for-linux,
	driver-core, dri-devel, linux-pwm, Matthew Maurer

This series converts the Qualcomm Socinfo driver to Rust to improve its
robustness.

The previous driver suffered from CVE-2024-58007, which would have been
prevented by the enforced bounds-checking present in Rust.

It's taken a while to get all the interfaces in place, but at this
point, the only place it needs `unsafe` is to define an abstraction
over the qcom-smem driver.

Feedback on v1 of the patch showed how Rust can help to identify
assumptions being made about APIs by requiring that reasoning be
attached to `unsafe` blocks. Specifically, this identified:

1. The regions being returned by `qcom_smem_get` are not memory regions,
   they are IO mapped memory.
2. These regions will be unmapped if the `smem` device is unloaded.
3. For versions in particular, the behavior of re-reading the version
   info from the IO region when displaying outputs is load-bearing, not
   an implementation detail - these regions are *expected* to change.

The previous driver accessed IO mapped regions through regular C memory
accesses. This was possible without warning because the `qcom_smem_get` 
API exposes pointers stripped of their `__iomem` annotation. This is
unlikely to cause trouble in practice, but goes against the
recommendation of kernel documentation [1].

The previous driver did not have a direct mechanism to ensure it was
being probed as a child of a `qcom-smem` device. While it was only ever
probed correctly (from the `qcom-smem` device), the new implementation
is robust to being probed improperly by other devices.

Since we are now using the IO subsystem, it's now much clearer when we
are intentionally choosing to do an IO read during a DebugFS
implementation.

I have tested this on a SM8650-HDK by diffing the contents of the
exported DebugFS and examining the files under /sys/bus/soc/devices/soc0

While I believe I have everything correctly exported via DebugFS, I have
not checked equivalence across a large swath of devices, only the one.

This driver is currently quirk-compatible in DebugFS-exported values. If
the maintainers do not believe that maintaining the exact formats is a
benefit, we could simplify the code further by dropping some of the
custom formatting functions used to match the output.

I didn't touch MAINTAINERS because the existing socinfo.c is covered by
a blanket directory maintainer, which would automatically cover the new
Rust implementation. If it would be helpful, I would be willing to
assist with this particular driver in the future.

Since it was a surprise in the previous series, I will explicitly call
out that this series is built on driver-core-next plus my patches to
load randomness [2] and derive FromBytes / AsBytes [3]. If you use b4,
this series should have appropriate metadata to recreate the tree for
you.

[1]: https://docs.kernel.org/driver-api/device-io.html#accessing-the-device
[2]: https://lore.kernel.org/all/20260102-add-entropy-v5-1-6b38a7a4a9ee@google.com/
[3]: https://lore.kernel.org/all/20251226-transmute-v3-0-c69a81bf8621@google.com/

Signed-off-by: Matthew Maurer <mmaurer@google.com>
---
Changes in v2:
- Rebase onto updated deps
- Use sparse_array! macro to define PMIC_MODELS
- Migrate to using auxdev
- Add `qcom_smem_get_aux` to help enforce that we are a child device
- Access IO mapped regions through the IO subsystem
- Leverage `Devres` to ensure that the smem device is still present when
  accessing IO regions.
- Switch to new kernel import style
- Switch to c"foo" literals where possible
- Link to v1: https://lore.kernel.org/r/20251213-qcom-socinfo-v1-1-5daa7f5f2a85@google.com

---
Matthew Maurer (6):
      rust: Add sparse_array! helper macro
      rust: io: Support copying arrays and slices
      rust: device: Support testing devices for equality
      rust: auxiliary: Support accessing raw aux pointer
      rust: debugfs: Allow access to device in Devres-wrapped scopes
      soc: qcom: socinfo: Convert to Rust

 drivers/soc/qcom/Kconfig             |   1 +
 drivers/soc/qcom/Makefile            |   2 +-
 drivers/soc/qcom/smem.c              |  42 +-
 drivers/soc/qcom/socinfo.c           | 931 -----------------------------------
 drivers/soc/qcom/socinfo/Makefile    |   2 +
 drivers/soc/qcom/socinfo/bindings.rs | 123 +++++
 drivers/soc/qcom/socinfo/data.rs     | 438 ++++++++++++++++
 drivers/soc/qcom/socinfo/socinfo.rs  | 446 +++++++++++++++++
 include/linux/soc/qcom/smem.h        |   4 +
 rust/bindgen_parameters              |   1 +
 rust/bindings/bindings_helper.h      |   6 +
 rust/kernel/auxiliary.rs             |   6 +-
 rust/kernel/debugfs.rs               |  40 ++
 rust/kernel/device.rs                |   8 +
 rust/kernel/devres.rs                |   2 +-
 rust/kernel/drm/driver.rs            |   2 +-
 rust/kernel/io.rs                    |  72 ++-
 rust/kernel/pwm.rs                   |   2 +-
 rust/kernel/slice.rs                 |  37 ++
 19 files changed, 1220 insertions(+), 945 deletions(-)
---
base-commit: 559ac491542c00e2389f8cfc49661527b3b0d8a0
change-id: 20251029-qcom-socinfo-d8387c7fdb1c
prerequisite-change-id: 20251029-add-entropy-f57e12ebe110:v5
prerequisite-patch-id: f1e8f8f557aa3df7510bd90beb1edf62faa117da
prerequisite-change-id: 20251212-transmute-8ab6076700a8:v3
prerequisite-patch-id: 4f5f7cb002d02d232083ab5c3ce6b3cb90650bd6
prerequisite-patch-id: fcdcb6cfedd70cdc41d2d27244ea2a588ed40eb9
prerequisite-patch-id: f6bc9ae84b31e2400749c0db10e6aa4216b3858b
prerequisite-patch-id: 95a7f946b6533ec4ccafee355626bb24a9be8f70

Best regards,
-- 
Matthew Maurer <mmaurer@google.com>


^ permalink raw reply	[flat|nested] 32+ messages in thread

* [PATCH v2 1/6] rust: Add sparse_array! helper macro
  2026-02-03 15:46 [PATCH v2 0/6] soc: qcom: socinfo: Convert to Rust Matthew Maurer
@ 2026-02-03 15:46 ` Matthew Maurer
  2026-02-03 15:46 ` [PATCH v2 2/6] rust: io: Support copying arrays and slices Matthew Maurer
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 32+ messages in thread
From: Matthew Maurer @ 2026-02-03 15:46 UTC (permalink / raw)
  To: Bjorn Andersson, Konrad Dybcio, Satya Durga Srinivasu Prabhala,
	Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, Daniel Almeida, Greg Kroah-Hartman,
	Rafael J. Wysocki, David Airlie, Simona Vetter, Michal Wilczynski,
	Dave Ertman, Ira Weiny, Leon Romanovsky
  Cc: Trilok Soni, linux-kernel, linux-arm-msm, rust-for-linux,
	driver-core, dri-devel, linux-pwm, Matthew Maurer

An idiom in C code is to have an array of nullable values which is
partially initialized via `{ [0] = x, [7] = y}`. Because Rust expects
everything to be fully initialized, it does not have this idiom by
default.

`sparse_array!` allows declaration of `[Option<T>; _]` constants to
allow Rust code to more easily mimic the safe version of this pattern.

Signed-off-by: Matthew Maurer <mmaurer@google.com>
Co-developed-by: Gary Guo <gary@garyguo.net>
Signed-off-by: Gary Guo <gary@garyguo.net>
---
 rust/kernel/slice.rs | 37 +++++++++++++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)

diff --git a/rust/kernel/slice.rs b/rust/kernel/slice.rs
index ca2cde13506196d46c9169aa6e4ab2ac42af6f5b..826b6f77f0d07775bd22837cc1773b59ec96936c 100644
--- a/rust/kernel/slice.rs
+++ b/rust/kernel/slice.rs
@@ -47,3 +47,40 @@ fn as_flattened_mut(&mut self) -> &mut [T] {
         self.flatten_mut()
     }
 }
+
+/// Create a sparse array of `[Option<T>; _]`.
+///
+/// This is intended for use when C code would write `{ [0] = x, [7] = y}` to perform partial
+/// initialization of an array.
+///
+/// # Example
+/// ```
+/// use kernel::sparse_array;
+/// const FOO: &[Option<usize>] = &sparse_array! {
+///   0: 10,
+///   7: 16,
+/// };
+/// assert_eq!(FOO[0], Some(10));
+/// assert_eq!(FOO[1], None);
+/// assert_eq!(FOO[7], Some(16));
+/// ```
+#[macro_export]
+macro_rules! sparse_array {
+    ($(
+        $index:literal: $value:expr
+    ),* $(,)?) => {{
+        const SIZE: usize = {
+            let mut size = 0;
+            $(if $index >= size {
+                size = $index + 1;
+            })*
+            size
+        };
+
+        const {
+            let mut arr = [None; SIZE];
+            $(arr[$index] = Some($value);)*
+            arr
+        }
+    }}
+}

-- 
2.53.0.rc2.204.g2597b5adb4-goog


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH v2 2/6] rust: io: Support copying arrays and slices
  2026-02-03 15:46 [PATCH v2 0/6] soc: qcom: socinfo: Convert to Rust Matthew Maurer
  2026-02-03 15:46 ` [PATCH v2 1/6] rust: Add sparse_array! helper macro Matthew Maurer
@ 2026-02-03 15:46 ` Matthew Maurer
  2026-02-03 15:53   ` Danilo Krummrich
  2026-02-03 15:46 ` [PATCH v2 3/6] rust: device: Support testing devices for equality Matthew Maurer
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 32+ messages in thread
From: Matthew Maurer @ 2026-02-03 15:46 UTC (permalink / raw)
  To: Bjorn Andersson, Konrad Dybcio, Satya Durga Srinivasu Prabhala,
	Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, Daniel Almeida, Greg Kroah-Hartman,
	Rafael J. Wysocki, David Airlie, Simona Vetter, Michal Wilczynski,
	Dave Ertman, Ira Weiny, Leon Romanovsky
  Cc: Trilok Soni, linux-kernel, linux-arm-msm, rust-for-linux,
	driver-core, dri-devel, linux-pwm, Matthew Maurer

Adds support for doing array copies of data in and out of IO regions.
Fixed size arrays allow for compile-time bound checking, while slice
arguments allow for dynamically checked copies.

Signed-off-by: Matthew Maurer <mmaurer@google.com>
---
 rust/kernel/io.rs | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 71 insertions(+), 1 deletion(-)

diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs
index 056a3ec71647b866a9a4b4c9abe9a0844f126930..6e74245eced2c267ba3b5b744eab3bc2db670e71 100644
--- a/rust/kernel/io.rs
+++ b/rust/kernel/io.rs
@@ -266,8 +266,9 @@ macro_rules! define_write {
 #[inline]
 const fn offset_valid<U>(offset: usize, size: usize) -> bool {
     let type_size = core::mem::size_of::<U>();
+    let type_align = core::mem::align_of::<U>();
     if let Some(end) = offset.checked_add(type_size) {
-        end <= size && offset % type_size == 0
+        end <= size && offset % type_align == 0
     } else {
         false
     }
@@ -323,6 +324,25 @@ fn io_addr<U>(&self, offset: usize) -> Result<usize> {
         self.addr().checked_add(offset).ok_or(EINVAL)
     }
 
+    /// Returns the absolute I/O address for a given `offset`, performing runtime bounds checks
+    /// to ensure the entire range is available.
+    #[inline]
+    fn io_addr_range<U>(&self, offset: usize, count: usize) -> Result<usize> {
+        if count != 0 {
+            // These ranges are contiguous, so we can just check the first and last elements.
+            let bytes = (count - 1)
+                .checked_mul(core::mem::size_of::<U>())
+                .ok_or(EINVAL)?;
+            let end = offset.checked_add(bytes).ok_or(EINVAL)?;
+            if !offset_valid::<U>(offset, self.maxsize()) || !offset_valid::<U>(end, self.maxsize())
+            {
+                return Err(EINVAL);
+            }
+        }
+
+        self.addr().checked_add(offset).ok_or(EINVAL)
+    }
+
     /// Returns the absolute I/O address for a given `offset`,
     /// performing compile-time bound checks.
     // Always inline to optimize out error path of `build_assert`.
@@ -605,4 +625,54 @@ pub unsafe fn from_raw(raw: &MmioRaw<SIZE>) -> &Self {
         pub try_write64_relaxed,
         call_mmio_write(writeq_relaxed) <- u64
     );
+
+    /// Write a known size buffer to an offset known at compile time.
+    ///
+    /// Bound checks are performed at compile time, hence if the offset is not known at compile
+    /// time, the build will fail, and the buffer size must be statically known.
+    #[inline]
+    pub fn copy_from<const N: usize>(&self, src: &[u8; N], offset: usize) {
+        let addr = self.io_addr_assert::<[u8; N]>(offset);
+        // SAFETY: By the type invariant `addr` is a valid address for MMIO operations, and by the
+        // assertion it's valid for `N` bytes.
+        unsafe { bindings::memcpy_toio(addr as *mut c_void, src.as_ptr().cast(), N) }
+    }
+
+    /// Write the contents of a slice to an offset.
+    ///
+    /// Bound checks are performed at runtime and will fail if the offset (plus the slice size) is
+    /// out of bounds.
+    #[inline]
+    pub fn try_copy_from(&self, src: &[u8], offset: usize) -> Result<()> {
+        let addr = self.io_addr_range::<u8>(offset, src.len())?;
+        // SAFETY: By the type invariant `addr` is a valid address for MMIO operations, and by the
+        // range check it's valid for `src.len()` bytes.
+        unsafe { bindings::memcpy_toio(addr as *mut c_void, src.as_ptr().cast(), src.len()) };
+        Ok(())
+    }
+
+    /// Read a known size buffer from an offset known at compile time.
+    ///
+    /// Bound checks are performed at compile time, hence if the offset is not known at compile
+    /// time, the build will fail, and the buffer size must be statically known.
+    #[inline]
+    pub fn copy_to<const N: usize>(&self, dst: &mut [u8; N], offset: usize) {
+        let addr = self.io_addr_assert::<[u8; N]>(offset);
+        // SAFETY: By the type invariant `addr` is a valid address for MMIO operations, and by the
+        // assertion it's valid for `N` bytes.
+        unsafe { bindings::memcpy_fromio(dst.as_mut_ptr().cast(), addr as *mut c_void, N) }
+    }
+
+    /// Read into a slice from an offset.
+    ///
+    /// Bound checks are performed at runtime and will fail if the offset (plus the slice size) is
+    /// out of bounds.
+    #[inline]
+    pub fn try_copy_to(&self, dst: &mut [u8], offset: usize) -> Result<()> {
+        let addr = self.io_addr_range::<u8>(offset, dst.len())?;
+        // SAFETY: By the type invariant `addr` is a valid address for MMIO operations, and by the
+        // range check, it's valid for `dst.len()` bytes.
+        unsafe { bindings::memcpy_fromio(dst.as_mut_ptr().cast(), addr as *mut c_void, dst.len()) }
+        Ok(())
+    }
 }

-- 
2.53.0.rc2.204.g2597b5adb4-goog


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH v2 3/6] rust: device: Support testing devices for equality
  2026-02-03 15:46 [PATCH v2 0/6] soc: qcom: socinfo: Convert to Rust Matthew Maurer
  2026-02-03 15:46 ` [PATCH v2 1/6] rust: Add sparse_array! helper macro Matthew Maurer
  2026-02-03 15:46 ` [PATCH v2 2/6] rust: io: Support copying arrays and slices Matthew Maurer
@ 2026-02-03 15:46 ` Matthew Maurer
  2026-02-03 15:56   ` Danilo Krummrich
                     ` (3 more replies)
  2026-02-03 15:46 ` [PATCH v2 4/6] rust: auxiliary: Support accessing raw aux pointer Matthew Maurer
                   ` (2 subsequent siblings)
  5 siblings, 4 replies; 32+ messages in thread
From: Matthew Maurer @ 2026-02-03 15:46 UTC (permalink / raw)
  To: Bjorn Andersson, Konrad Dybcio, Satya Durga Srinivasu Prabhala,
	Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, Daniel Almeida, Greg Kroah-Hartman,
	Rafael J. Wysocki, David Airlie, Simona Vetter, Michal Wilczynski,
	Dave Ertman, Ira Weiny, Leon Romanovsky
  Cc: Trilok Soni, linux-kernel, linux-arm-msm, rust-for-linux,
	driver-core, dri-devel, linux-pwm, Matthew Maurer

This allows device drivers to check if, for example, an auxiliary
devices is one of its children by comparing the parent field, or
checking if a device parameter is its own device.

Also convert existing `.as_raw() != .as_raw()` to  use this new
implementation.

Signed-off-by: Matthew Maurer <mmaurer@google.com>
---
 rust/kernel/device.rs     | 8 ++++++++
 rust/kernel/devres.rs     | 2 +-
 rust/kernel/drm/driver.rs | 2 +-
 rust/kernel/pwm.rs        | 2 +-
 4 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/rust/kernel/device.rs b/rust/kernel/device.rs
index 94e0548e76871d8b7de309c1f1c7b77bb49738ed..aa10359d3ebdd1c99cc567a35b89f52ddb2ee050 100644
--- a/rust/kernel/device.rs
+++ b/rust/kernel/device.rs
@@ -516,6 +516,14 @@ unsafe impl Send for Device {}
 // synchronization in `struct device`.
 unsafe impl Sync for Device {}
 
+impl<Ctx: DeviceContext, Ctx2: DeviceContext> PartialEq<Device<Ctx2>> for Device<Ctx> {
+    fn eq(&self, other: &Device<Ctx2>) -> bool {
+        self.as_raw() == other.as_raw()
+    }
+}
+
+impl<Ctx: DeviceContext> Eq for Device<Ctx> {}
+
 /// Marker trait for the context or scope of a bus specific device.
 ///
 /// [`DeviceContext`] is a marker trait for types representing the context of a bus specific
diff --git a/rust/kernel/devres.rs b/rust/kernel/devres.rs
index cdc49677022a6b466e771d9d8cf3818ab9b9112d..20126daad193370868661b9412937937eda6d3c4 100644
--- a/rust/kernel/devres.rs
+++ b/rust/kernel/devres.rs
@@ -281,7 +281,7 @@ pub fn device(&self) -> &Device {
     /// }
     /// ```
     pub fn access<'a>(&'a self, dev: &'a Device<Bound>) -> Result<&'a T> {
-        if self.dev.as_raw() != dev.as_raw() {
+        if self.dev.as_ref() != dev {
             return Err(EINVAL);
         }
 
diff --git a/rust/kernel/drm/driver.rs b/rust/kernel/drm/driver.rs
index f30ee4c6245cda72ac72852bf9362736d8fe992f..497ef46028d560bc9649dbbdf69316ce4fce8199 100644
--- a/rust/kernel/drm/driver.rs
+++ b/rust/kernel/drm/driver.rs
@@ -139,7 +139,7 @@ pub fn new_foreign_owned(
     where
         T: 'static,
     {
-        if drm.as_ref().as_raw() != dev.as_raw() {
+        if drm.as_ref() != dev {
             return Err(EINVAL);
         }
 
diff --git a/rust/kernel/pwm.rs b/rust/kernel/pwm.rs
index cb00f8a8765c8ec58ed78a73275b022b02bf7aa3..033f778909a2633acbc25d5a21a1c8a7b8e41a70 100644
--- a/rust/kernel/pwm.rs
+++ b/rust/kernel/pwm.rs
@@ -680,7 +680,7 @@ impl<T: 'static + PwmOps + Send + Sync> Registration<T> {
     /// calling `pwmchip_remove`. This function should be called from the driver's `probe`.
     pub fn register(dev: &device::Device<Bound>, chip: ARef<Chip<T>>) -> Result {
         let chip_parent = chip.device().parent().ok_or(EINVAL)?;
-        if dev.as_raw() != chip_parent.as_raw() {
+        if dev != chip_parent {
             return Err(EINVAL);
         }
 

-- 
2.53.0.rc2.204.g2597b5adb4-goog


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH v2 4/6] rust: auxiliary: Support accessing raw aux pointer
  2026-02-03 15:46 [PATCH v2 0/6] soc: qcom: socinfo: Convert to Rust Matthew Maurer
                   ` (2 preceding siblings ...)
  2026-02-03 15:46 ` [PATCH v2 3/6] rust: device: Support testing devices for equality Matthew Maurer
@ 2026-02-03 15:46 ` Matthew Maurer
  2026-02-03 15:55   ` Danilo Krummrich
  2026-02-03 15:46 ` [PATCH v2 5/6] rust: debugfs: Allow access to device in Devres-wrapped scopes Matthew Maurer
  2026-02-03 15:46 ` [PATCH v2 6/6] soc: qcom: socinfo: Convert to Rust Matthew Maurer
  5 siblings, 1 reply; 32+ messages in thread
From: Matthew Maurer @ 2026-02-03 15:46 UTC (permalink / raw)
  To: Bjorn Andersson, Konrad Dybcio, Satya Durga Srinivasu Prabhala,
	Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, Daniel Almeida, Greg Kroah-Hartman,
	Rafael J. Wysocki, David Airlie, Simona Vetter, Michal Wilczynski,
	Dave Ertman, Ira Weiny, Leon Romanovsky
  Cc: Trilok Soni, linux-kernel, linux-arm-msm, rust-for-linux,
	driver-core, dri-devel, linux-pwm, Matthew Maurer

While it's preferable to add bindings in the kernel crate rather than
using raw pointers where possible, access to the raw aux pointer is
required to pass it to C interfaces provided by a driver.

Signed-off-by: Matthew Maurer <mmaurer@google.com>
---
 rust/kernel/auxiliary.rs | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/rust/kernel/auxiliary.rs b/rust/kernel/auxiliary.rs
index 93c0db1f66555c97ec7dc58825e97c47c0154e54..1a88277f0fd9ea5ff32cc534dfe5682009de94c2 100644
--- a/rust/kernel/auxiliary.rs
+++ b/rust/kernel/auxiliary.rs
@@ -237,7 +237,11 @@ pub struct Device<Ctx: device::DeviceContext = device::Normal>(
 );
 
 impl<Ctx: device::DeviceContext> Device<Ctx> {
-    fn as_raw(&self) -> *mut bindings::auxiliary_device {
+    /// Returns the underlying auxiliary device
+    ///
+    /// Prefer to add bindings in the kernel crate for any use other than calling driver-specific
+    /// functions.
+    pub fn as_raw(&self) -> *mut bindings::auxiliary_device {
         self.0.get()
     }
 

-- 
2.53.0.rc2.204.g2597b5adb4-goog


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH v2 5/6] rust: debugfs: Allow access to device in Devres-wrapped scopes
  2026-02-03 15:46 [PATCH v2 0/6] soc: qcom: socinfo: Convert to Rust Matthew Maurer
                   ` (3 preceding siblings ...)
  2026-02-03 15:46 ` [PATCH v2 4/6] rust: auxiliary: Support accessing raw aux pointer Matthew Maurer
@ 2026-02-03 15:46 ` Matthew Maurer
  2026-02-03 15:59   ` Danilo Krummrich
  2026-02-03 16:47   ` Gary Guo
  2026-02-03 15:46 ` [PATCH v2 6/6] soc: qcom: socinfo: Convert to Rust Matthew Maurer
  5 siblings, 2 replies; 32+ messages in thread
From: Matthew Maurer @ 2026-02-03 15:46 UTC (permalink / raw)
  To: Bjorn Andersson, Konrad Dybcio, Satya Durga Srinivasu Prabhala,
	Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, Daniel Almeida, Greg Kroah-Hartman,
	Rafael J. Wysocki, David Airlie, Simona Vetter, Michal Wilczynski,
	Dave Ertman, Ira Weiny, Leon Romanovsky
  Cc: Trilok Soni, linux-kernel, linux-arm-msm, rust-for-linux,
	driver-core, dri-devel, linux-pwm, Matthew Maurer

This adds support for creating a DebugFS directory which is aware that
it is bound to a device. As a result, callbacks under that directory
have access to a bound device which gives them efficient access to other
Devres, ability to use dev_err! and friends, etc.

Signed-off-by: Matthew Maurer <mmaurer@google.com>
---
 rust/kernel/debugfs.rs | 40 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/rust/kernel/debugfs.rs b/rust/kernel/debugfs.rs
index d7b8014a6474698235203f2b7d8fec96f2bb43f8..ac614d693fa73929d095b669e9ba61958bec609e 100644
--- a/rust/kernel/debugfs.rs
+++ b/rust/kernel/debugfs.rs
@@ -11,6 +11,11 @@
 #[cfg(CONFIG_DEBUG_FS)]
 use crate::sync::Arc;
 use crate::{
+    device::{
+        Bound,
+        Device, //
+    },
+    devres::Devres,
     fmt,
     prelude::*,
     str::CStr,
@@ -722,3 +727,38 @@ fn new(name: &CStr) -> ScopedDir<'data, 'static> {
         }
     }
 }
+
+impl<'a, T: 'a + Send> Devres<Scope<T>> {
+    /// Creates a new scope, which is a directory at the root of the debugfs filesystem,
+    /// associated with some data `T`, enclosed in a [`Devres`] for the provided device.
+    ///
+    /// The `init` closure is called to populate the directory with files and subdirectories. These
+    /// files can reference the data stored in the scope. Because it is stored inside a `Devres`,
+    /// the init method is granted access to a `&Device<Bound>`.
+    ///
+    /// This can be used for cheaply accessing device-protected data inside DebugFS methods or
+    /// accessing device-specific methods (e.g. [`dev_err!`]).
+    ///
+    /// The entire directory tree created within the scope will be removed when the returned
+    /// `Scope` handle is dropped.
+    pub fn dir<E: 'a, F>(
+        dev: &'a Device<Bound>,
+        data: impl PinInit<T, E> + 'a,
+        name: &'a CStr,
+        init: F,
+    ) -> impl PinInit<Self, Error> + 'a
+    where
+        F: for<'data, 'dir> FnOnce(&'data T, &'data Device<Bound>, &'dir ScopedDir<'data, 'dir>)
+            + 'a,
+        Error: From<E>,
+    {
+        Devres::new(
+            dev,
+            Scope::new(data, |data| {
+                let scoped = ScopedDir::new(name);
+                init(data, dev, &scoped);
+                scoped.into_entry()
+            }),
+        )
+    }
+}

-- 
2.53.0.rc2.204.g2597b5adb4-goog


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH v2 6/6] soc: qcom: socinfo: Convert to Rust
  2026-02-03 15:46 [PATCH v2 0/6] soc: qcom: socinfo: Convert to Rust Matthew Maurer
                   ` (4 preceding siblings ...)
  2026-02-03 15:46 ` [PATCH v2 5/6] rust: debugfs: Allow access to device in Devres-wrapped scopes Matthew Maurer
@ 2026-02-03 15:46 ` Matthew Maurer
  2026-02-03 16:28   ` Greg Kroah-Hartman
  2026-02-03 20:27   ` Bjorn Andersson
  5 siblings, 2 replies; 32+ messages in thread
From: Matthew Maurer @ 2026-02-03 15:46 UTC (permalink / raw)
  To: Bjorn Andersson, Konrad Dybcio, Satya Durga Srinivasu Prabhala,
	Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, Daniel Almeida, Greg Kroah-Hartman,
	Rafael J. Wysocki, David Airlie, Simona Vetter, Michal Wilczynski,
	Dave Ertman, Ira Weiny, Leon Romanovsky
  Cc: Trilok Soni, linux-kernel, linux-arm-msm, rust-for-linux,
	driver-core, dri-devel, linux-pwm, Matthew Maurer

Convert the socinfo driver to Rust for a number of improvements:
* Accessing IO mapped regions through the IO subsystem, rather than
  through regular memory accesses.
* Binds the device as an auxiliary device rather than a platform device,
  ensuring the mapped IO regions cannot be accessed after the smem
  device is removed.
* Adds bounds-checking to all accesses, hardening against a repeat of
  CVE-2024-58007

Signed-off-by: Matthew Maurer <mmaurer@google.com>
---
 drivers/soc/qcom/Kconfig             |   1 +
 drivers/soc/qcom/Makefile            |   2 +-
 drivers/soc/qcom/smem.c              |  42 +-
 drivers/soc/qcom/socinfo.c           | 931 -----------------------------------
 drivers/soc/qcom/socinfo/Makefile    |   2 +
 drivers/soc/qcom/socinfo/bindings.rs | 123 +++++
 drivers/soc/qcom/socinfo/data.rs     | 438 ++++++++++++++++
 drivers/soc/qcom/socinfo/socinfo.rs  | 446 +++++++++++++++++
 include/linux/soc/qcom/smem.h        |   4 +
 rust/bindgen_parameters              |   1 +
 rust/bindings/bindings_helper.h      |   6 +
 11 files changed, 1056 insertions(+), 940 deletions(-)

diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index 2caadbbcf8307ff94f5afbdd1481e5e5e291749f..16d553f66f0cf1101d3a8c7d401d7c4d6a65dac7 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -222,6 +222,7 @@ config QCOM_SMSM
 config QCOM_SOCINFO
 	tristate "Qualcomm socinfo driver"
 	depends on QCOM_SMEM
+	depends on RUST
 	select SOC_BUS
 	help
 	 Say yes here to support the Qualcomm socinfo driver, providing
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index b7f1d2a5736748b8772c090fd24462fa91f321c6..6f6688c76a00a91ce99600f298a8e6e0fefed806 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -28,7 +28,7 @@ obj-$(CONFIG_QCOM_SMEM_STATE) += smem_state.o
 CFLAGS_smp2p.o := -I$(src)
 obj-$(CONFIG_QCOM_SMP2P)	+= smp2p.o
 obj-$(CONFIG_QCOM_SMSM)	+= smsm.o
-obj-$(CONFIG_QCOM_SOCINFO)	+= socinfo.o
+obj-$(CONFIG_QCOM_SOCINFO)	+= socinfo/
 obj-$(CONFIG_QCOM_SPM)		+= spm.o
 obj-$(CONFIG_QCOM_STATS)	+= qcom_stats.o
 obj-$(CONFIG_QCOM_WCNSS_CTRL) += wcnss_ctrl.o
diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c
index fef840b5457407a85051ded0e835430dbebfe8bb..dcea2d7f37067b0b6f801b3d2b457422ad9f342c 100644
--- a/drivers/soc/qcom/smem.c
+++ b/drivers/soc/qcom/smem.c
@@ -4,6 +4,7 @@
  * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  */
 
+#include <linux/auxiliary_bus.h>
 #include <linux/hwspinlock.h>
 #include <linux/io.h>
 #include <linux/module.h>
@@ -279,7 +280,6 @@ struct qcom_smem {
 	struct hwspinlock *hwlock;
 
 	u32 item_count;
-	struct platform_device *socinfo;
 	struct smem_ptable *ptable;
 	struct smem_partition global_partition;
 	struct smem_partition partitions[SMEM_HOST_COUNT];
@@ -675,6 +675,32 @@ static void *qcom_smem_get_private(struct qcom_smem *smem,
 	return ERR_PTR(-EINVAL);
 }
 
+/**
+ * qcom_smem_get_aux() - resolve ptr of size of a smem item
+ * @aux:        an aux device that should be our child
+ * @host:	the remote processor, or -1
+ * @item:	smem item handle
+ * @size:	pointer to be filled out with size of the item
+ *
+ * Looks up smem item and returns pointer to it. Size of smem
+ * item is returned in @size.
+ *
+ * The caller may take the loaded state of the provided aux device as
+ * an acceptable proxy for this memory being valid.
+ *
+ * Return: a pointer to an SMEM item on success, ERR_PTR() on failure.
+ */
+void *qcom_smem_get_aux(struct auxiliary_device *aux, unsigned int host,
+		unsigned int item, size_t *size)
+{
+	if (IS_ERR(__smem))
+		return __smem;
+	if (aux->dev.parent != __smem->dev)
+		return ERR_PTR(-EINVAL);
+	return qcom_smem_get(host, item, size);
+}
+EXPORT_SYMBOL_GPL(qcom_smem_get_aux);
+
 /**
  * qcom_smem_get() - resolve ptr of size of a smem item
  * @host:	the remote processor, or -1
@@ -684,6 +710,9 @@ static void *qcom_smem_get_private(struct qcom_smem *smem,
  * Looks up smem item and returns pointer to it. Size of smem
  * item is returned in @size.
  *
+ * It is up to the caller to ensure that the qcom_smem device remains
+ * loaded by some mechanism when accessing returned memory.
+ *
  * Return: a pointer to an SMEM item on success, ERR_PTR() on failure.
  */
 void *qcom_smem_get(unsigned host, unsigned item, size_t *size)
@@ -1127,6 +1156,7 @@ static int qcom_smem_probe(struct platform_device *pdev)
 	struct smem_header *header;
 	struct reserved_mem *rmem;
 	struct qcom_smem *smem;
+	struct auxiliary_device *socinfo;
 	unsigned long flags;
 	int num_regions;
 	int hwlock_id;
@@ -1234,19 +1264,15 @@ static int qcom_smem_probe(struct platform_device *pdev)
 
 	__smem = smem;
 
-	smem->socinfo = platform_device_register_data(&pdev->dev, "qcom-socinfo",
-						      PLATFORM_DEVID_NONE, NULL,
-						      0);
-	if (IS_ERR(smem->socinfo))
-		dev_dbg(&pdev->dev, "failed to register socinfo device\n");
+	socinfo = devm_auxiliary_device_create(&pdev->dev, "qcom-socinfo", NULL);
+	if (IS_ERR(socinfo))
+		dev_dbg(&pdev->dev, "failed to create socinfo device\n");
 
 	return 0;
 }
 
 static void qcom_smem_remove(struct platform_device *pdev)
 {
-	platform_device_unregister(__smem->socinfo);
-
 	__smem = NULL;
 }
 
diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c
deleted file mode 100644
index 003a2304d535c2655db566c644342dbc387e24a9..0000000000000000000000000000000000000000
--- a/drivers/soc/qcom/socinfo.c
+++ /dev/null
@@ -1,931 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (c) 2009-2017, The Linux Foundation. All rights reserved.
- * Copyright (c) 2017-2019, Linaro Ltd.
- */
-
-#include <linux/debugfs.h>
-#include <linux/err.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/random.h>
-#include <linux/slab.h>
-#include <linux/soc/qcom/smem.h>
-#include <linux/soc/qcom/socinfo.h>
-#include <linux/string.h>
-#include <linux/stringify.h>
-#include <linux/sys_soc.h>
-#include <linux/types.h>
-
-#include <linux/unaligned.h>
-
-#include <dt-bindings/arm/qcom,ids.h>
-
-/* Helper macros to create soc_id table */
-#define qcom_board_id(id) QCOM_ID_ ## id, __stringify(id)
-#define qcom_board_id_named(id, name) QCOM_ID_ ## id, (name)
-
-#ifdef CONFIG_DEBUG_FS
-#define SMEM_IMAGE_VERSION_BLOCKS_COUNT        32
-#define SMEM_IMAGE_VERSION_SIZE                4096
-#define SMEM_IMAGE_VERSION_NAME_SIZE           75
-#define SMEM_IMAGE_VERSION_VARIANT_SIZE        20
-#define SMEM_IMAGE_VERSION_OEM_SIZE            32
-
-/*
- * SMEM Image table indices
- */
-#define SMEM_IMAGE_TABLE_BOOT_INDEX     0
-#define SMEM_IMAGE_TABLE_TZ_INDEX       1
-#define SMEM_IMAGE_TABLE_TZSECAPP_INDEX	2
-#define SMEM_IMAGE_TABLE_RPM_INDEX      3
-#define SMEM_IMAGE_TABLE_SDI_INDEX      4
-#define SMEM_IMAGE_TABLE_HYP_INDEX      5
-#define SMEM_IMAGE_TABLE_ADSP1_INDEX	6
-#define SMEM_IMAGE_TABLE_ADSP2_INDEX	7
-#define SMEM_IMAGE_TABLE_CDSP2_INDEX	8
-#define SMEM_IMAGE_TABLE_APPSBL_INDEX	9
-#define SMEM_IMAGE_TABLE_APPS_INDEX     10
-#define SMEM_IMAGE_TABLE_MPSS_INDEX     11
-#define SMEM_IMAGE_TABLE_ADSP_INDEX     12
-#define SMEM_IMAGE_TABLE_CNSS_INDEX     13
-#define SMEM_IMAGE_TABLE_VIDEO_INDEX    14
-#define SMEM_IMAGE_TABLE_DSPS_INDEX     15
-#define SMEM_IMAGE_TABLE_CDSP_INDEX     16
-#define SMEM_IMAGE_TABLE_NPU_INDEX	17
-#define SMEM_IMAGE_TABLE_WPSS_INDEX     18
-#define SMEM_IMAGE_TABLE_CDSP1_INDEX    19
-#define SMEM_IMAGE_TABLE_GPDSP_INDEX    20
-#define SMEM_IMAGE_TABLE_GPDSP1_INDEX   21
-#define SMEM_IMAGE_TABLE_SENSORPD_INDEX	22
-#define SMEM_IMAGE_TABLE_AUDIOPD_INDEX	23
-#define SMEM_IMAGE_TABLE_OEMPD_INDEX	24
-#define SMEM_IMAGE_TABLE_CHARGERPD_INDEX	25
-#define SMEM_IMAGE_TABLE_OISPD_INDEX	26
-#define SMEM_IMAGE_TABLE_SOCCP_INDEX	27
-#define SMEM_IMAGE_TABLE_TME_INDEX	28
-#define SMEM_IMAGE_TABLE_GEARVM_INDEX	29
-#define SMEM_IMAGE_TABLE_UEFI_INDEX	30
-#define SMEM_IMAGE_TABLE_CDSP3_INDEX	31
-#define SMEM_IMAGE_TABLE_AUDIOPD_ADSP1_INDEX	32
-#define SMEM_IMAGE_TABLE_AUDIOPD_ADSP2_INDEX	33
-#define SMEM_IMAGE_TABLE_DCP_INDEX	34
-#define SMEM_IMAGE_TABLE_OOBS_INDEX	35
-#define SMEM_IMAGE_TABLE_OOBNS_INDEX	36
-#define SMEM_IMAGE_TABLE_DEVCFG_INDEX	37
-#define SMEM_IMAGE_TABLE_BTPD_INDEX	38
-#define SMEM_IMAGE_TABLE_QECP_INDEX	39
-
-#define SMEM_IMAGE_VERSION_TABLE       469
-#define SMEM_IMAGE_VERSION_TABLE_2	667
-
-/*
- * SMEM Image table names
- */
-static const char *const socinfo_image_names[] = {
-	[SMEM_IMAGE_TABLE_ADSP1_INDEX] = "adsp1",
-	[SMEM_IMAGE_TABLE_ADSP2_INDEX] = "adsp2",
-	[SMEM_IMAGE_TABLE_ADSP_INDEX] = "adsp",
-	[SMEM_IMAGE_TABLE_APPSBL_INDEX] = "appsbl",
-	[SMEM_IMAGE_TABLE_APPS_INDEX] = "apps",
-	[SMEM_IMAGE_TABLE_AUDIOPD_INDEX] = "audiopd",
-	[SMEM_IMAGE_TABLE_AUDIOPD_ADSP1_INDEX] = "audiopd_adsp1",
-	[SMEM_IMAGE_TABLE_AUDIOPD_ADSP2_INDEX] = "audiopd_adsp2",
-	[SMEM_IMAGE_TABLE_BOOT_INDEX] = "boot",
-	[SMEM_IMAGE_TABLE_BTPD_INDEX] = "btpd",
-	[SMEM_IMAGE_TABLE_CDSP1_INDEX] = "cdsp1",
-	[SMEM_IMAGE_TABLE_CDSP2_INDEX] = "cdsp2",
-	[SMEM_IMAGE_TABLE_CDSP3_INDEX] = "cdsp3",
-	[SMEM_IMAGE_TABLE_CDSP_INDEX] = "cdsp",
-	[SMEM_IMAGE_TABLE_CHARGERPD_INDEX] = "chargerpd",
-	[SMEM_IMAGE_TABLE_CNSS_INDEX] = "cnss",
-	[SMEM_IMAGE_TABLE_DCP_INDEX] = "dcp",
-	[SMEM_IMAGE_TABLE_DEVCFG_INDEX] = "devcfg",
-	[SMEM_IMAGE_TABLE_DSPS_INDEX] = "dsps",
-	[SMEM_IMAGE_TABLE_GEARVM_INDEX] = "gearvm",
-	[SMEM_IMAGE_TABLE_GPDSP1_INDEX] = "gpdsp1",
-	[SMEM_IMAGE_TABLE_GPDSP_INDEX] = "gpdsp",
-	[SMEM_IMAGE_TABLE_HYP_INDEX] = "hyp",
-	[SMEM_IMAGE_TABLE_MPSS_INDEX] = "mpss",
-	[SMEM_IMAGE_TABLE_NPU_INDEX] = "npu",
-	[SMEM_IMAGE_TABLE_OEMPD_INDEX] = "oempd",
-	[SMEM_IMAGE_TABLE_OISPD_INDEX] = "oispd",
-	[SMEM_IMAGE_TABLE_OOBNS_INDEX] = "oobns",
-	[SMEM_IMAGE_TABLE_OOBS_INDEX] = "oobs",
-	[SMEM_IMAGE_TABLE_QECP_INDEX] = "qecp",
-	[SMEM_IMAGE_TABLE_RPM_INDEX] = "rpm",
-	[SMEM_IMAGE_TABLE_SDI_INDEX] = "sdi",
-	[SMEM_IMAGE_TABLE_SENSORPD_INDEX] = "sensorpd",
-	[SMEM_IMAGE_TABLE_SOCCP_INDEX] = "soccp",
-	[SMEM_IMAGE_TABLE_TME_INDEX] = "tme",
-	[SMEM_IMAGE_TABLE_TZ_INDEX] = "tz",
-	[SMEM_IMAGE_TABLE_TZSECAPP_INDEX] = "tzsecapp",
-	[SMEM_IMAGE_TABLE_UEFI_INDEX] = "uefi",
-	[SMEM_IMAGE_TABLE_VIDEO_INDEX] = "video",
-	[SMEM_IMAGE_TABLE_WPSS_INDEX] = "wpss",
-};
-
-static const char *const pmic_models[] = {
-	[0]  = "Unknown PMIC model",
-	[1]  = "PM8941",
-	[2]  = "PM8841",
-	[3]  = "PM8019",
-	[4]  = "PM8226",
-	[5]  = "PM8110",
-	[6]  = "PMA8084",
-	[7]  = "PMI8962",
-	[8]  = "PMD9635",
-	[9]  = "PM8994",
-	[10] = "PMI8994",
-	[11] = "PM8916",
-	[12] = "PM8004",
-	[13] = "PM8909/PM8058",
-	[14] = "PM8028",
-	[15] = "PM8901",
-	[16] = "PM8950/PM8027",
-	[17] = "PMI8950/ISL9519",
-	[18] = "PMK8001/PM8921",
-	[19] = "PMI8996/PM8018",
-	[20] = "PM8998/PM8015",
-	[21] = "PMI8998/PM8014",
-	[22] = "PM8821",
-	[23] = "PM8038",
-	[24] = "PM8005/PM8922",
-	[25] = "PM8917/PM8937",
-	[26] = "PM660L",
-	[27] = "PM660",
-	[30] = "PM8150",
-	[31] = "PM8150L",
-	[32] = "PM8150B",
-	[33] = "PMK8002",
-	[36] = "PM8009",
-	[37] = "PMI632",
-	[38] = "PM8150C",
-	[40] = "PM6150",
-	[41] = "SMB2351",
-	[44] = "PM8008",
-	[45] = "PM6125",
-	[46] = "PM7250B",
-	[47] = "PMK8350",
-	[48] = "PM8350",
-	[49] = "PM8350C",
-	[50] = "PM8350B",
-	[51] = "PMR735A",
-	[52] = "PMR735B",
-	[54] = "PM6350",
-	[55] = "PM4125",
-	[58] = "PM8450",
-	[65] = "PM8010",
-	[69] = "PM8550VS",
-	[70] = "PM8550VE",
-	[71] = "PM8550B",
-	[72] = "PMR735D",
-	[73] = "PM8550",
-	[74] = "PMK8550",
-	[78] = "PMM8650AU",
-	[79] = "PMM8650AU_PSAIL",
-	[80] = "PM7550",
-	[82] = "PMC8380",
-	[83] = "SMB2360",
-	[91] = "PMIV0108",
-};
-
-struct socinfo_params {
-	u32 raw_device_family;
-	u32 hw_plat_subtype;
-	u32 accessory_chip;
-	u32 raw_device_num;
-	u32 chip_family;
-	u32 foundry_id;
-	u32 plat_ver;
-	u32 raw_ver;
-	u32 hw_plat;
-	u32 fmt;
-	u32 nproduct_id;
-	u32 num_clusters;
-	u32 ncluster_array_offset;
-	u32 num_subset_parts;
-	u32 nsubset_parts_array_offset;
-	u32 nmodem_supported;
-	u32 feature_code;
-	u32 pcode;
-	u32 oem_variant;
-	u32 num_func_clusters;
-	u32 boot_cluster;
-	u32 boot_core;
-	u32 raw_package_type;
-};
-
-struct smem_image_version {
-	char name[SMEM_IMAGE_VERSION_NAME_SIZE];
-	char variant[SMEM_IMAGE_VERSION_VARIANT_SIZE];
-	char pad;
-	char oem[SMEM_IMAGE_VERSION_OEM_SIZE];
-};
-#endif /* CONFIG_DEBUG_FS */
-
-struct qcom_socinfo {
-	struct soc_device *soc_dev;
-	struct soc_device_attribute attr;
-#ifdef CONFIG_DEBUG_FS
-	struct dentry *dbg_root;
-	struct socinfo_params info;
-#endif /* CONFIG_DEBUG_FS */
-};
-
-struct soc_id {
-	unsigned int id;
-	const char *name;
-};
-
-static const struct soc_id soc_id[] = {
-	{ qcom_board_id(MSM8260) },
-	{ qcom_board_id(MSM8660) },
-	{ qcom_board_id(APQ8060) },
-	{ qcom_board_id(MSM8960) },
-	{ qcom_board_id(APQ8064) },
-	{ qcom_board_id(MSM8930) },
-	{ qcom_board_id(MSM8630) },
-	{ qcom_board_id(MSM8230) },
-	{ qcom_board_id(APQ8030) },
-	{ qcom_board_id(MSM8627) },
-	{ qcom_board_id(MSM8227) },
-	{ qcom_board_id(MSM8660A) },
-	{ qcom_board_id(MSM8260A) },
-	{ qcom_board_id(APQ8060A) },
-	{ qcom_board_id(MSM8974) },
-	{ qcom_board_id(MSM8225) },
-	{ qcom_board_id(MSM8625) },
-	{ qcom_board_id(MPQ8064) },
-	{ qcom_board_id(MSM8960AB) },
-	{ qcom_board_id(APQ8060AB) },
-	{ qcom_board_id(MSM8260AB) },
-	{ qcom_board_id(MSM8660AB) },
-	{ qcom_board_id(MSM8930AA) },
-	{ qcom_board_id(MSM8630AA) },
-	{ qcom_board_id(MSM8230AA) },
-	{ qcom_board_id(MSM8626) },
-	{ qcom_board_id(MSM8610) },
-	{ qcom_board_id(APQ8064AB) },
-	{ qcom_board_id(MSM8930AB) },
-	{ qcom_board_id(MSM8630AB) },
-	{ qcom_board_id(MSM8230AB) },
-	{ qcom_board_id(APQ8030AB) },
-	{ qcom_board_id(MSM8226) },
-	{ qcom_board_id(MSM8526) },
-	{ qcom_board_id(APQ8030AA) },
-	{ qcom_board_id(MSM8110) },
-	{ qcom_board_id(MSM8210) },
-	{ qcom_board_id(MSM8810) },
-	{ qcom_board_id(MSM8212) },
-	{ qcom_board_id(MSM8612) },
-	{ qcom_board_id(MSM8112) },
-	{ qcom_board_id(MSM8125) },
-	{ qcom_board_id(MSM8225Q) },
-	{ qcom_board_id(MSM8625Q) },
-	{ qcom_board_id(MSM8125Q) },
-	{ qcom_board_id(APQ8064AA) },
-	{ qcom_board_id(APQ8084) },
-	{ qcom_board_id(MSM8130) },
-	{ qcom_board_id(MSM8130AA) },
-	{ qcom_board_id(MSM8130AB) },
-	{ qcom_board_id(MSM8627AA) },
-	{ qcom_board_id(MSM8227AA) },
-	{ qcom_board_id(APQ8074) },
-	{ qcom_board_id(MSM8274) },
-	{ qcom_board_id(MSM8674) },
-	{ qcom_board_id(MDM9635) },
-	{ qcom_board_id_named(MSM8974PRO_AC, "MSM8974PRO-AC") },
-	{ qcom_board_id(MSM8126) },
-	{ qcom_board_id(APQ8026) },
-	{ qcom_board_id(MSM8926) },
-	{ qcom_board_id(IPQ8062) },
-	{ qcom_board_id(IPQ8064) },
-	{ qcom_board_id(IPQ8066) },
-	{ qcom_board_id(IPQ8068) },
-	{ qcom_board_id(MSM8326) },
-	{ qcom_board_id(MSM8916) },
-	{ qcom_board_id(MSM8994) },
-	{ qcom_board_id_named(APQ8074PRO_AA, "APQ8074PRO-AA") },
-	{ qcom_board_id_named(APQ8074PRO_AB, "APQ8074PRO-AB") },
-	{ qcom_board_id_named(APQ8074PRO_AC, "APQ8074PRO-AC") },
-	{ qcom_board_id_named(MSM8274PRO_AA, "MSM8274PRO-AA") },
-	{ qcom_board_id_named(MSM8274PRO_AB, "MSM8274PRO-AB") },
-	{ qcom_board_id_named(MSM8274PRO_AC, "MSM8274PRO-AC") },
-	{ qcom_board_id_named(MSM8674PRO_AA, "MSM8674PRO-AA") },
-	{ qcom_board_id_named(MSM8674PRO_AB, "MSM8674PRO-AB") },
-	{ qcom_board_id_named(MSM8674PRO_AC, "MSM8674PRO-AC") },
-	{ qcom_board_id_named(MSM8974PRO_AA, "MSM8974PRO-AA") },
-	{ qcom_board_id_named(MSM8974PRO_AB, "MSM8974PRO-AB") },
-	{ qcom_board_id(APQ8028) },
-	{ qcom_board_id(MSM8128) },
-	{ qcom_board_id(MSM8228) },
-	{ qcom_board_id(MSM8528) },
-	{ qcom_board_id(MSM8628) },
-	{ qcom_board_id(MSM8928) },
-	{ qcom_board_id(MSM8510) },
-	{ qcom_board_id(MSM8512) },
-	{ qcom_board_id(MSM8936) },
-	{ qcom_board_id(MDM9640) },
-	{ qcom_board_id(MSM8939) },
-	{ qcom_board_id(APQ8036) },
-	{ qcom_board_id(APQ8039) },
-	{ qcom_board_id(MSM8236) },
-	{ qcom_board_id(MSM8636) },
-	{ qcom_board_id(MSM8909) },
-	{ qcom_board_id(MSM8996) },
-	{ qcom_board_id(APQ8016) },
-	{ qcom_board_id(MSM8216) },
-	{ qcom_board_id(MSM8116) },
-	{ qcom_board_id(MSM8616) },
-	{ qcom_board_id(MSM8992) },
-	{ qcom_board_id(APQ8092) },
-	{ qcom_board_id(APQ8094) },
-	{ qcom_board_id(MSM8209) },
-	{ qcom_board_id(MSM8208) },
-	{ qcom_board_id(MDM9209) },
-	{ qcom_board_id(MDM9309) },
-	{ qcom_board_id(MDM9609) },
-	{ qcom_board_id(MSM8239) },
-	{ qcom_board_id(MSM8952) },
-	{ qcom_board_id(APQ8009) },
-	{ qcom_board_id(MSM8956) },
-	{ qcom_board_id(MSM8929) },
-	{ qcom_board_id(MSM8629) },
-	{ qcom_board_id(MSM8229) },
-	{ qcom_board_id(APQ8029) },
-	{ qcom_board_id(APQ8056) },
-	{ qcom_board_id(MSM8609) },
-	{ qcom_board_id(APQ8076) },
-	{ qcom_board_id(MSM8976) },
-	{ qcom_board_id(IPQ8065) },
-	{ qcom_board_id(IPQ8069) },
-	{ qcom_board_id(MDM9650) },
-	{ qcom_board_id(MDM9655) },
-	{ qcom_board_id(MDM9250) },
-	{ qcom_board_id(MDM9255) },
-	{ qcom_board_id(MDM9350) },
-	{ qcom_board_id(APQ8052) },
-	{ qcom_board_id(MDM9607) },
-	{ qcom_board_id(APQ8096) },
-	{ qcom_board_id(MSM8998) },
-	{ qcom_board_id(MSM8953) },
-	{ qcom_board_id(MSM8937) },
-	{ qcom_board_id(APQ8037) },
-	{ qcom_board_id(MDM8207) },
-	{ qcom_board_id(MDM9207) },
-	{ qcom_board_id(MDM9307) },
-	{ qcom_board_id(MDM9628) },
-	{ qcom_board_id(MSM8909W) },
-	{ qcom_board_id(APQ8009W) },
-	{ qcom_board_id(MSM8996L) },
-	{ qcom_board_id(MSM8917) },
-	{ qcom_board_id(APQ8053) },
-	{ qcom_board_id(MSM8996SG) },
-	{ qcom_board_id(APQ8017) },
-	{ qcom_board_id(MSM8217) },
-	{ qcom_board_id(MSM8617) },
-	{ qcom_board_id(MSM8996AU) },
-	{ qcom_board_id(APQ8096AU) },
-	{ qcom_board_id(APQ8096SG) },
-	{ qcom_board_id(MSM8940) },
-	{ qcom_board_id(SDX201) },
-	{ qcom_board_id(SDM660) },
-	{ qcom_board_id(SDM630) },
-	{ qcom_board_id(APQ8098) },
-	{ qcom_board_id(MSM8920) },
-	{ qcom_board_id(SDM845) },
-	{ qcom_board_id(MDM9206) },
-	{ qcom_board_id(IPQ8074) },
-	{ qcom_board_id(SDA660) },
-	{ qcom_board_id(SDM658) },
-	{ qcom_board_id(SDA658) },
-	{ qcom_board_id(SDA630) },
-	{ qcom_board_id(MSM8905) },
-	{ qcom_board_id(SDX202) },
-	{ qcom_board_id(SDM670) },
-	{ qcom_board_id(SDM450) },
-	{ qcom_board_id(SM8150) },
-	{ qcom_board_id(SDA845) },
-	{ qcom_board_id(IPQ8072) },
-	{ qcom_board_id(IPQ8076) },
-	{ qcom_board_id(IPQ8078) },
-	{ qcom_board_id(SDM636) },
-	{ qcom_board_id(SDA636) },
-	{ qcom_board_id(SDM632) },
-	{ qcom_board_id(SDA632) },
-	{ qcom_board_id(SDA450) },
-	{ qcom_board_id(SDM439) },
-	{ qcom_board_id(SDM429) },
-	{ qcom_board_id(SM8250) },
-	{ qcom_board_id(SA8155) },
-	{ qcom_board_id(SDA439) },
-	{ qcom_board_id(SDA429) },
-	{ qcom_board_id(SM7150) },
-	{ qcom_board_id(SM7150P) },
-	{ qcom_board_id(IPQ8070) },
-	{ qcom_board_id(IPQ8071) },
-	{ qcom_board_id(QM215) },
-	{ qcom_board_id(IPQ8072A) },
-	{ qcom_board_id(IPQ8074A) },
-	{ qcom_board_id(IPQ8076A) },
-	{ qcom_board_id(IPQ8078A) },
-	{ qcom_board_id(SM6125) },
-	{ qcom_board_id(IPQ8070A) },
-	{ qcom_board_id(IPQ8071A) },
-	{ qcom_board_id(IPQ8172) },
-	{ qcom_board_id(IPQ8173) },
-	{ qcom_board_id(IPQ8174) },
-	{ qcom_board_id(IPQ6018) },
-	{ qcom_board_id(IPQ6028) },
-	{ qcom_board_id(SDM429W) },
-	{ qcom_board_id(SM4250) },
-	{ qcom_board_id(IPQ6000) },
-	{ qcom_board_id(IPQ6010) },
-	{ qcom_board_id(SC7180) },
-	{ qcom_board_id(SM6350) },
-	{ qcom_board_id(QCM2150) },
-	{ qcom_board_id(SDA429W) },
-	{ qcom_board_id(SM8350) },
-	{ qcom_board_id(QCM2290) },
-	{ qcom_board_id(SM7125) },
-	{ qcom_board_id(SM6115) },
-	{ qcom_board_id(IPQ5010) },
-	{ qcom_board_id(IPQ5018) },
-	{ qcom_board_id(IPQ5028) },
-	{ qcom_board_id(SC8280XP) },
-	{ qcom_board_id(IPQ6005) },
-	{ qcom_board_id(QRB5165) },
-	{ qcom_board_id(SM8450) },
-	{ qcom_board_id(SM7225) },
-	{ qcom_board_id(SA8295P) },
-	{ qcom_board_id(SA8540P) },
-	{ qcom_board_id(QCM4290) },
-	{ qcom_board_id(QCS4290) },
-	{ qcom_board_id(SM7325) },
-	{ qcom_board_id_named(SM8450_2, "SM8450") },
-	{ qcom_board_id_named(SM8450_3, "SM8450") },
-	{ qcom_board_id(SC7280) },
-	{ qcom_board_id(SC7180P) },
-	{ qcom_board_id(QCM6490) },
-	{ qcom_board_id(QCS6490) },
-	{ qcom_board_id(SM7325P) },
-	{ qcom_board_id(IPQ5000) },
-	{ qcom_board_id(IPQ0509) },
-	{ qcom_board_id(IPQ0518) },
-	{ qcom_board_id(SM6375) },
-	{ qcom_board_id(IPQ9514) },
-	{ qcom_board_id(IPQ9550) },
-	{ qcom_board_id(IPQ9554) },
-	{ qcom_board_id(IPQ9570) },
-	{ qcom_board_id(IPQ9574) },
-	{ qcom_board_id(SM8550) },
-	{ qcom_board_id(IPQ5016) },
-	{ qcom_board_id(IPQ9510) },
-	{ qcom_board_id(QRB4210) },
-	{ qcom_board_id(QRB2210) },
-	{ qcom_board_id(SAR2130P) },
-	{ qcom_board_id(SM8475) },
-	{ qcom_board_id(SM8475P) },
-	{ qcom_board_id(SA8255P) },
-	{ qcom_board_id(SA8775P) },
-	{ qcom_board_id(QRU1000) },
-	{ qcom_board_id(SM8475_2) },
-	{ qcom_board_id(QDU1000) },
-	{ qcom_board_id(X1E80100) },
-	{ qcom_board_id(SM8650) },
-	{ qcom_board_id(SM4450) },
-	{ qcom_board_id(SAR1130P) },
-	{ qcom_board_id(QDU1010) },
-	{ qcom_board_id(QRU1032) },
-	{ qcom_board_id(QRU1052) },
-	{ qcom_board_id(QRU1062) },
-	{ qcom_board_id(IPQ5332) },
-	{ qcom_board_id(IPQ5322) },
-	{ qcom_board_id(IPQ5312) },
-	{ qcom_board_id(IPQ5302) },
-	{ qcom_board_id(QCS8550) },
-	{ qcom_board_id(QCM8550) },
-	{ qcom_board_id(SM8750)  },
-	{ qcom_board_id(IPQ5300) },
-	{ qcom_board_id(SM7635) },
-	{ qcom_board_id(SM6650) },
-	{ qcom_board_id(SM6650P) },
-	{ qcom_board_id(IPQ5321) },
-	{ qcom_board_id(IPQ5424) },
-	{ qcom_board_id(QCM6690) },
-	{ qcom_board_id(QCS6690) },
-	{ qcom_board_id(SM8850) },
-	{ qcom_board_id(IPQ5404) },
-	{ qcom_board_id(QCS9100) },
-	{ qcom_board_id(QCS8300) },
-	{ qcom_board_id(QCS8275) },
-	{ qcom_board_id(QCS9075) },
-	{ qcom_board_id(QCS615) },
-};
-
-static const char *socinfo_machine(struct device *dev, unsigned int id)
-{
-	int idx;
-
-	for (idx = 0; idx < ARRAY_SIZE(soc_id); idx++) {
-		if (soc_id[idx].id == id)
-			return soc_id[idx].name;
-	}
-
-	return NULL;
-}
-
-#ifdef CONFIG_DEBUG_FS
-
-#define QCOM_OPEN(name, _func)						\
-static int qcom_open_##name(struct inode *inode, struct file *file)	\
-{									\
-	return single_open(file, _func, inode->i_private);		\
-}									\
-									\
-static const struct file_operations qcom_ ##name## _ops = {		\
-	.open = qcom_open_##name,					\
-	.read = seq_read,						\
-	.llseek = seq_lseek,						\
-	.release = single_release,					\
-}
-
-#define DEBUGFS_ADD(info, name)						\
-	debugfs_create_file(__stringify(name), 0444,			\
-			    qcom_socinfo->dbg_root,			\
-			    info, &qcom_ ##name## _ops)
-
-
-static int qcom_show_build_id(struct seq_file *seq, void *p)
-{
-	struct socinfo *socinfo = seq->private;
-
-	seq_printf(seq, "%s\n", socinfo->build_id);
-
-	return 0;
-}
-
-static int qcom_show_pmic_model(struct seq_file *seq, void *p)
-{
-	struct socinfo *socinfo = seq->private;
-	int model = SOCINFO_MINOR(le32_to_cpu(socinfo->pmic_model));
-
-	if (model < 0)
-		return -EINVAL;
-
-	if (model < ARRAY_SIZE(pmic_models) && pmic_models[model])
-		seq_printf(seq, "%s\n", pmic_models[model]);
-	else
-		seq_printf(seq, "unknown (%d)\n", model);
-
-	return 0;
-}
-
-static int qcom_show_pmic_model_array(struct seq_file *seq, void *p)
-{
-	struct socinfo *socinfo = seq->private;
-	unsigned int num_pmics = le32_to_cpu(socinfo->num_pmics);
-	unsigned int pmic_array_offset = le32_to_cpu(socinfo->pmic_array_offset);
-	int i;
-	void *ptr = socinfo;
-
-	ptr += pmic_array_offset;
-
-	/* No need for bounds checking, it happened at socinfo_debugfs_init */
-	for (i = 0; i < num_pmics; i++) {
-		unsigned int model = SOCINFO_MINOR(get_unaligned_le32(ptr + 2 * i * sizeof(u32)));
-		unsigned int die_rev = get_unaligned_le32(ptr + (2 * i + 1) * sizeof(u32));
-
-		if (model < ARRAY_SIZE(pmic_models) && pmic_models[model])
-			seq_printf(seq, "%s %u.%u\n", pmic_models[model],
-				   SOCINFO_MAJOR(die_rev),
-				   SOCINFO_MINOR(die_rev));
-		else
-			seq_printf(seq, "unknown (%d)\n", model);
-	}
-
-	return 0;
-}
-
-static int qcom_show_pmic_die_revision(struct seq_file *seq, void *p)
-{
-	struct socinfo *socinfo = seq->private;
-
-	seq_printf(seq, "%u.%u\n",
-		   SOCINFO_MAJOR(le32_to_cpu(socinfo->pmic_die_rev)),
-		   SOCINFO_MINOR(le32_to_cpu(socinfo->pmic_die_rev)));
-
-	return 0;
-}
-
-static int qcom_show_chip_id(struct seq_file *seq, void *p)
-{
-	struct socinfo *socinfo = seq->private;
-
-	seq_printf(seq, "%s\n", socinfo->chip_id);
-
-	return 0;
-}
-
-QCOM_OPEN(build_id, qcom_show_build_id);
-QCOM_OPEN(pmic_model, qcom_show_pmic_model);
-QCOM_OPEN(pmic_model_array, qcom_show_pmic_model_array);
-QCOM_OPEN(pmic_die_rev, qcom_show_pmic_die_revision);
-QCOM_OPEN(chip_id, qcom_show_chip_id);
-
-#define DEFINE_IMAGE_OPS(type)					\
-static int show_image_##type(struct seq_file *seq, void *p)		  \
-{								  \
-	struct smem_image_version *image_version = seq->private;  \
-	if (image_version->type[0] != '\0')			  \
-		seq_printf(seq, "%s\n", image_version->type);	  \
-	return 0;						  \
-}								  \
-static int open_image_##type(struct inode *inode, struct file *file)	  \
-{									  \
-	return single_open(file, show_image_##type, inode->i_private); \
-}									  \
-									  \
-static const struct file_operations qcom_image_##type##_ops = {	  \
-	.open = open_image_##type,					  \
-	.read = seq_read,						  \
-	.llseek = seq_lseek,						  \
-	.release = single_release,					  \
-}
-
-DEFINE_IMAGE_OPS(name);
-DEFINE_IMAGE_OPS(variant);
-DEFINE_IMAGE_OPS(oem);
-
-static void socinfo_debugfs_init(struct qcom_socinfo *qcom_socinfo,
-				 struct socinfo *info, size_t info_size)
-{
-	struct smem_image_version *versions;
-	struct dentry *dentry;
-	size_t size;
-	int i, j;
-	unsigned int num_pmics;
-	unsigned int pmic_array_offset;
-
-	qcom_socinfo->dbg_root = debugfs_create_dir("qcom_socinfo", NULL);
-
-	qcom_socinfo->info.fmt = __le32_to_cpu(info->fmt);
-
-	debugfs_create_x32("info_fmt", 0444, qcom_socinfo->dbg_root,
-			   &qcom_socinfo->info.fmt);
-
-	switch (qcom_socinfo->info.fmt) {
-	case SOCINFO_VERSION(0, 23):
-	case SOCINFO_VERSION(0, 22):
-	case SOCINFO_VERSION(0, 21):
-	case SOCINFO_VERSION(0, 20):
-		qcom_socinfo->info.raw_package_type = __le32_to_cpu(info->raw_package_type);
-		debugfs_create_u32("raw_package_type", 0444, qcom_socinfo->dbg_root,
-				   &qcom_socinfo->info.raw_package_type);
-		fallthrough;
-	case SOCINFO_VERSION(0, 19):
-		qcom_socinfo->info.num_func_clusters = __le32_to_cpu(info->num_func_clusters);
-		qcom_socinfo->info.boot_cluster = __le32_to_cpu(info->boot_cluster);
-		qcom_socinfo->info.boot_core = __le32_to_cpu(info->boot_core);
-
-		debugfs_create_u32("num_func_clusters", 0444, qcom_socinfo->dbg_root,
-				   &qcom_socinfo->info.num_func_clusters);
-		debugfs_create_u32("boot_cluster", 0444, qcom_socinfo->dbg_root,
-				   &qcom_socinfo->info.boot_cluster);
-		debugfs_create_u32("boot_core", 0444, qcom_socinfo->dbg_root,
-				   &qcom_socinfo->info.boot_core);
-		fallthrough;
-	case SOCINFO_VERSION(0, 18):
-	case SOCINFO_VERSION(0, 17):
-		qcom_socinfo->info.oem_variant = __le32_to_cpu(info->oem_variant);
-		debugfs_create_u32("oem_variant", 0444, qcom_socinfo->dbg_root,
-				   &qcom_socinfo->info.oem_variant);
-		fallthrough;
-	case SOCINFO_VERSION(0, 16):
-		qcom_socinfo->info.feature_code = __le32_to_cpu(info->feature_code);
-		qcom_socinfo->info.pcode = __le32_to_cpu(info->pcode);
-
-		debugfs_create_u32("feature_code", 0444, qcom_socinfo->dbg_root,
-				   &qcom_socinfo->info.feature_code);
-		debugfs_create_u32("pcode", 0444, qcom_socinfo->dbg_root,
-				   &qcom_socinfo->info.pcode);
-		fallthrough;
-	case SOCINFO_VERSION(0, 15):
-		qcom_socinfo->info.nmodem_supported = __le32_to_cpu(info->nmodem_supported);
-
-		debugfs_create_u32("nmodem_supported", 0444, qcom_socinfo->dbg_root,
-				   &qcom_socinfo->info.nmodem_supported);
-		fallthrough;
-	case SOCINFO_VERSION(0, 14):
-		qcom_socinfo->info.num_clusters = __le32_to_cpu(info->num_clusters);
-		qcom_socinfo->info.ncluster_array_offset = __le32_to_cpu(info->ncluster_array_offset);
-		qcom_socinfo->info.num_subset_parts = __le32_to_cpu(info->num_subset_parts);
-		qcom_socinfo->info.nsubset_parts_array_offset =
-			__le32_to_cpu(info->nsubset_parts_array_offset);
-
-		debugfs_create_u32("num_clusters", 0444, qcom_socinfo->dbg_root,
-				   &qcom_socinfo->info.num_clusters);
-		debugfs_create_u32("ncluster_array_offset", 0444, qcom_socinfo->dbg_root,
-				   &qcom_socinfo->info.ncluster_array_offset);
-		debugfs_create_u32("num_subset_parts", 0444, qcom_socinfo->dbg_root,
-				   &qcom_socinfo->info.num_subset_parts);
-		debugfs_create_u32("nsubset_parts_array_offset", 0444, qcom_socinfo->dbg_root,
-				   &qcom_socinfo->info.nsubset_parts_array_offset);
-		fallthrough;
-	case SOCINFO_VERSION(0, 13):
-		qcom_socinfo->info.nproduct_id = __le32_to_cpu(info->nproduct_id);
-
-		debugfs_create_u32("nproduct_id", 0444, qcom_socinfo->dbg_root,
-				   &qcom_socinfo->info.nproduct_id);
-		DEBUGFS_ADD(info, chip_id);
-		fallthrough;
-	case SOCINFO_VERSION(0, 12):
-		qcom_socinfo->info.chip_family =
-			__le32_to_cpu(info->chip_family);
-		qcom_socinfo->info.raw_device_family =
-			__le32_to_cpu(info->raw_device_family);
-		qcom_socinfo->info.raw_device_num =
-			__le32_to_cpu(info->raw_device_num);
-
-		debugfs_create_x32("chip_family", 0444, qcom_socinfo->dbg_root,
-				   &qcom_socinfo->info.chip_family);
-		debugfs_create_x32("raw_device_family", 0444,
-				   qcom_socinfo->dbg_root,
-				   &qcom_socinfo->info.raw_device_family);
-		debugfs_create_x32("raw_device_number", 0444,
-				   qcom_socinfo->dbg_root,
-				   &qcom_socinfo->info.raw_device_num);
-		fallthrough;
-	case SOCINFO_VERSION(0, 11):
-		num_pmics = le32_to_cpu(info->num_pmics);
-		pmic_array_offset = le32_to_cpu(info->pmic_array_offset);
-		if (pmic_array_offset + 2 * num_pmics * sizeof(u32) <= info_size)
-			DEBUGFS_ADD(info, pmic_model_array);
-		fallthrough;
-	case SOCINFO_VERSION(0, 10):
-	case SOCINFO_VERSION(0, 9):
-		qcom_socinfo->info.foundry_id = __le32_to_cpu(info->foundry_id);
-
-		debugfs_create_u32("foundry_id", 0444, qcom_socinfo->dbg_root,
-				   &qcom_socinfo->info.foundry_id);
-		fallthrough;
-	case SOCINFO_VERSION(0, 8):
-	case SOCINFO_VERSION(0, 7):
-		DEBUGFS_ADD(info, pmic_model);
-		DEBUGFS_ADD(info, pmic_die_rev);
-		fallthrough;
-	case SOCINFO_VERSION(0, 6):
-		qcom_socinfo->info.hw_plat_subtype =
-			__le32_to_cpu(info->hw_plat_subtype);
-
-		debugfs_create_u32("hardware_platform_subtype", 0444,
-				   qcom_socinfo->dbg_root,
-				   &qcom_socinfo->info.hw_plat_subtype);
-		fallthrough;
-	case SOCINFO_VERSION(0, 5):
-		qcom_socinfo->info.accessory_chip =
-			__le32_to_cpu(info->accessory_chip);
-
-		debugfs_create_u32("accessory_chip", 0444,
-				   qcom_socinfo->dbg_root,
-				   &qcom_socinfo->info.accessory_chip);
-		fallthrough;
-	case SOCINFO_VERSION(0, 4):
-		qcom_socinfo->info.plat_ver = __le32_to_cpu(info->plat_ver);
-
-		debugfs_create_u32("platform_version", 0444,
-				   qcom_socinfo->dbg_root,
-				   &qcom_socinfo->info.plat_ver);
-		fallthrough;
-	case SOCINFO_VERSION(0, 3):
-		qcom_socinfo->info.hw_plat = __le32_to_cpu(info->hw_plat);
-
-		debugfs_create_u32("hardware_platform", 0444,
-				   qcom_socinfo->dbg_root,
-				   &qcom_socinfo->info.hw_plat);
-		fallthrough;
-	case SOCINFO_VERSION(0, 2):
-		qcom_socinfo->info.raw_ver  = __le32_to_cpu(info->raw_ver);
-
-		debugfs_create_u32("raw_version", 0444, qcom_socinfo->dbg_root,
-				   &qcom_socinfo->info.raw_ver);
-		fallthrough;
-	case SOCINFO_VERSION(0, 1):
-		DEBUGFS_ADD(info, build_id);
-		break;
-	}
-
-	for (i = 0, j = 0; i < ARRAY_SIZE(socinfo_image_names); i++, j++) {
-		if (!socinfo_image_names[i])
-			continue;
-
-		if (i == 0) {
-			versions = qcom_smem_get(QCOM_SMEM_HOST_ANY,
-						 SMEM_IMAGE_VERSION_TABLE,
-						 &size);
-		} else if (i == 32) {
-			versions = qcom_smem_get(QCOM_SMEM_HOST_ANY,
-						 SMEM_IMAGE_VERSION_TABLE_2,
-						 &size);
-			if (IS_ERR(versions))
-				break;
-
-			j = 0;
-		}
-
-		dentry = debugfs_create_dir(socinfo_image_names[i],
-					    qcom_socinfo->dbg_root);
-		debugfs_create_file("name", 0444, dentry, &versions[j],
-				    &qcom_image_name_ops);
-		debugfs_create_file("variant", 0444, dentry, &versions[j],
-				    &qcom_image_variant_ops);
-		debugfs_create_file("oem", 0444, dentry, &versions[j],
-				    &qcom_image_oem_ops);
-	}
-}
-
-static void socinfo_debugfs_exit(struct qcom_socinfo *qcom_socinfo)
-{
-	debugfs_remove_recursive(qcom_socinfo->dbg_root);
-}
-#else
-static void socinfo_debugfs_init(struct qcom_socinfo *qcom_socinfo,
-				 struct socinfo *info, size_t info_size)
-{
-}
-static void socinfo_debugfs_exit(struct qcom_socinfo *qcom_socinfo) {  }
-#endif /* CONFIG_DEBUG_FS */
-
-static int qcom_socinfo_probe(struct platform_device *pdev)
-{
-	struct qcom_socinfo *qs;
-	struct socinfo *info;
-	size_t item_size;
-
-	info = qcom_smem_get(QCOM_SMEM_HOST_ANY, SMEM_HW_SW_BUILD_ID,
-			      &item_size);
-	if (IS_ERR(info)) {
-		dev_err(&pdev->dev, "Couldn't find socinfo\n");
-		return PTR_ERR(info);
-	}
-
-	qs = devm_kzalloc(&pdev->dev, sizeof(*qs), GFP_KERNEL);
-	if (!qs)
-		return -ENOMEM;
-
-	qs->attr.family = "Snapdragon";
-	qs->attr.machine = socinfo_machine(&pdev->dev,
-					   le32_to_cpu(info->id));
-	qs->attr.soc_id = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%u",
-					 le32_to_cpu(info->id));
-	qs->attr.revision = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%u.%u",
-					   SOCINFO_MAJOR(le32_to_cpu(info->ver)),
-					   SOCINFO_MINOR(le32_to_cpu(info->ver)));
-	if (!qs->attr.soc_id || !qs->attr.revision)
-		return -ENOMEM;
-
-	if (offsetofend(struct socinfo, serial_num) <= item_size) {
-		qs->attr.serial_number = devm_kasprintf(&pdev->dev, GFP_KERNEL,
-							"%u",
-							le32_to_cpu(info->serial_num));
-		if (!qs->attr.serial_number)
-			return -ENOMEM;
-	}
-
-	qs->soc_dev = soc_device_register(&qs->attr);
-	if (IS_ERR(qs->soc_dev))
-		return PTR_ERR(qs->soc_dev);
-
-	socinfo_debugfs_init(qs, info, item_size);
-
-	/* Feed the soc specific unique data into entropy pool */
-	add_device_randomness(info, item_size);
-
-	platform_set_drvdata(pdev, qs);
-
-	return 0;
-}
-
-static void qcom_socinfo_remove(struct platform_device *pdev)
-{
-	struct qcom_socinfo *qs = platform_get_drvdata(pdev);
-
-	soc_device_unregister(qs->soc_dev);
-
-	socinfo_debugfs_exit(qs);
-}
-
-static struct platform_driver qcom_socinfo_driver = {
-	.probe = qcom_socinfo_probe,
-	.remove = qcom_socinfo_remove,
-	.driver  = {
-		.name = "qcom-socinfo",
-	},
-};
-
-module_platform_driver(qcom_socinfo_driver);
-
-MODULE_DESCRIPTION("Qualcomm SoCinfo driver");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:qcom-socinfo");
diff --git a/drivers/soc/qcom/socinfo/Makefile b/drivers/soc/qcom/socinfo/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..8cdd77f46a22aeb97bcf1eeb90418db8f6352d3b
--- /dev/null
+++ b/drivers/soc/qcom/socinfo/Makefile
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_QCOM_SOCINFO) += socinfo.o
diff --git a/drivers/soc/qcom/socinfo/bindings.rs b/drivers/soc/qcom/socinfo/bindings.rs
new file mode 100644
index 0000000000000000000000000000000000000000..243fd2adf26ccf417166a08465b2b791030a2364
--- /dev/null
+++ b/drivers/soc/qcom/socinfo/bindings.rs
@@ -0,0 +1,123 @@
+// SPDX-License-Identifier: GPL-2.0
+
+// Copyright (C) 2025 Google LLC.
+
+use kernel::{
+    auxiliary,
+    bindings,
+    device::{
+        Bound,
+        Device, //
+    },
+    error::from_err_ptr,
+    ffi::c_char,
+    io::{
+        Io,
+        Mmio,
+        MmioRaw, //
+    },
+    macros::{
+        AsBytes,
+        FromBytes, //
+    },
+    prelude::*,
+    transmute::AsBytes,
+    types::ARef, //
+};
+
+// INVARIANT: raw is a region or subregion returned by get_smem_aux when presented with
+// the auxdev in dev.
+pub(crate) struct Smem {
+    dev: ARef<Device>,
+    raw: MmioRaw,
+}
+
+impl Smem {
+    pub(crate) fn access<'a>(&'a self, dev: &'a Device<Bound>) -> Option<&'a Mmio> {
+        if *dev != *self.dev {
+            return None;
+        }
+
+        // SAFETY: By our invariant, this was a subrange of what was returned by smem_aux_get, for
+        // self.dev, and by our above check, that auxdev is still available.
+        Some(unsafe { Mmio::from_raw(&self.raw) })
+    }
+
+    pub(crate) fn subrange(&self, offset: usize, len: usize) -> Option<Self> {
+        let remaining_len: usize = self.raw.maxsize().checked_sub(offset)?;
+        remaining_len.checked_sub(len)?;
+        // INVARIANT: Maintained because offset is positive, and the length fits.
+        Some(Self {
+            dev: self.dev.clone(),
+            raw: MmioRaw::new(self.raw.addr() + offset, len).ok()?,
+        })
+    }
+
+    pub(crate) fn maxsize(&self) -> usize {
+        self.raw.maxsize()
+    }
+
+    pub(crate) fn get(dev: &auxiliary::Device<Bound>, host: i32, item: u32) -> Result<Self> {
+        let mut size = 0;
+        // SAFETY: qcom_smem_get_aux only requires that the size pointer be a writable size_t,
+        // and that aux be an aux device.
+        let err_ptr =
+            unsafe { bindings::qcom_smem_get_aux(dev.as_raw(), host as u32, item, &mut size) };
+        let ptr = from_err_ptr(err_ptr)?;
+        let base_dev: &Device<Bound> = dev.as_ref();
+        // INVARIANT: If qcom_smem_get_aux does not return an error, the returned pointer points to
+        // a readable IO region that qcom-smem will keep mapped while our provided aux device is
+        // loaded.
+        Ok(Self {
+            dev: base_dev.into(),
+            raw: MmioRaw::new(ptr as usize, size)?,
+        })
+    }
+}
+
+pub(crate) const SMEM_IMAGE_VERSION_TABLE: u32 = 469;
+pub(crate) const SMEM_IMAGE_VERSION_TABLE_2: u32 = 667;
+
+pub(crate) use bindings::socinfo;
+
+/// Produce `socinfo` by initializing from a byte buffer that may be too small.
+/// Code using the resulting value is expected to use the info_fmt field to determine
+/// which fields have meaningful values.
+pub(crate) fn socinfo_from_partial_bytes(soc_info_mem: &Mmio) -> Result<socinfo> {
+    let mut soc_info = socinfo::default();
+    let byte_view: &mut [u8] = soc_info.as_bytes_mut();
+    let len = core::cmp::min(soc_info_mem.maxsize(), byte_view.len());
+    soc_info_mem.try_copy_to(&mut byte_view[..len], 0)?;
+    Ok(soc_info)
+}
+
+#[derive(AsBytes, FromBytes, Default, Copy, Clone)]
+#[repr(C)]
+pub(crate) struct PmicEntry {
+    pub(crate) model: u32,
+    pub(crate) die_rev: u32,
+}
+
+const SMEM_IMAGE_VERSION_NAME_SIZE: usize = 75;
+const SMEM_IMAGE_VERSION_VARIANT_SIZE: usize = 20;
+const SMEM_IMAGE_VERSION_OEM_SIZE: usize = 32;
+
+#[derive(AsBytes, FromBytes)]
+#[repr(C)]
+pub(crate) struct ImageVersion {
+    pub(crate) name: [c_char; SMEM_IMAGE_VERSION_NAME_SIZE],
+    pub(crate) variant: [c_char; SMEM_IMAGE_VERSION_VARIANT_SIZE],
+    pub(crate) pad: c_char,
+    pub(crate) oem: [c_char; SMEM_IMAGE_VERSION_OEM_SIZE],
+}
+
+impl Default for ImageVersion {
+    fn default() -> Self {
+        ImageVersion {
+            name: [0; SMEM_IMAGE_VERSION_NAME_SIZE],
+            variant: [0; SMEM_IMAGE_VERSION_VARIANT_SIZE],
+            pad: 0,
+            oem: [0; SMEM_IMAGE_VERSION_OEM_SIZE],
+        }
+    }
+}
diff --git a/drivers/soc/qcom/socinfo/data.rs b/drivers/soc/qcom/socinfo/data.rs
new file mode 100644
index 0000000000000000000000000000000000000000..e33e040ae34ddfd2acd1e1e64f5e35cc78e85483
--- /dev/null
+++ b/drivers/soc/qcom/socinfo/data.rs
@@ -0,0 +1,438 @@
+// SPDX-License-Identifier: GPL-2.0
+
+// Copyright (C) 2025 Google LLC.
+
+//! Data tables for QCom SocInfo driver
+use kernel::{
+    c_str,
+    prelude::*,
+    sparse_array, //
+};
+
+macro_rules! soc_ids {
+    { $( $entry:tt ),* $(,)? } => {
+        pub(crate) static SOC_IDS: &[SocId] = &[
+            $(
+                soc_id_entry!($entry)
+            ),*
+        ];
+    }
+}
+
+macro_rules! soc_id_entry {
+    ($id:ident) => {
+        kernel::macros::paste! {
+            SocId {
+                id: kernel::bindings::[<QCOM_ID_ $id>],
+                name: c_str!(stringify!($id)),
+            }
+        }
+    };
+    (($id:ident, $name:literal)) => {
+        kernel::macros::paste! {
+            SocId {
+                id: kernel::bindings::[<QCOM_ID_ $id>],
+                name: c_str!($name),
+            }
+        }
+    };
+}
+
+pub(crate) struct SocId {
+    pub(crate) id: u32,
+    pub(crate) name: &'static CStr,
+}
+
+soc_ids! {
+    MSM8260,
+    MSM8660,
+    APQ8060,
+    MSM8960,
+    APQ8064,
+    MSM8930,
+    MSM8630,
+    MSM8230,
+    APQ8030,
+    MSM8627,
+    MSM8227,
+    MSM8660A,
+    MSM8260A,
+    APQ8060A,
+    MSM8974,
+    MSM8225,
+    MSM8625,
+    MPQ8064,
+    MSM8960AB,
+    APQ8060AB,
+    MSM8260AB,
+    MSM8660AB,
+    MSM8930AA,
+    MSM8630AA,
+    MSM8230AA,
+    MSM8626,
+    MSM8610,
+    APQ8064AB,
+    MSM8930AB,
+    MSM8630AB,
+    MSM8230AB,
+    APQ8030AB,
+    MSM8226,
+    MSM8526,
+    APQ8030AA,
+    MSM8110,
+    MSM8210,
+    MSM8810,
+    MSM8212,
+    MSM8612,
+    MSM8112,
+    MSM8125,
+    MSM8225Q,
+    MSM8625Q,
+    MSM8125Q,
+    APQ8064AA,
+    APQ8084,
+    MSM8130,
+    MSM8130AA,
+    MSM8130AB,
+    MSM8627AA,
+    MSM8227AA,
+    APQ8074,
+    MSM8274,
+    MSM8674,
+    MDM9635,
+    (MSM8974PRO_AC, "MSM8974PRO-AC"),
+    MSM8126,
+    APQ8026,
+    MSM8926,
+    IPQ8062,
+    IPQ8064,
+    IPQ8066,
+    IPQ8068,
+    MSM8326,
+    MSM8916,
+    MSM8994,
+    (APQ8074PRO_AA, "APQ8074PRO-AA"),
+    (APQ8074PRO_AB, "APQ8074PRO-AB"),
+    (APQ8074PRO_AC, "APQ8074PRO-AC"),
+    (MSM8274PRO_AA, "MSM8274PRO-AA"),
+    (MSM8274PRO_AB, "MSM8274PRO-AB"),
+    (MSM8274PRO_AC, "MSM8274PRO-AC"),
+    (MSM8674PRO_AA, "MSM8674PRO-AA"),
+    (MSM8674PRO_AB, "MSM8674PRO-AB"),
+    (MSM8674PRO_AC, "MSM8674PRO-AC"),
+    (MSM8974PRO_AA, "MSM8974PRO-AA"),
+    (MSM8974PRO_AB, "MSM8974PRO-AB"),
+    APQ8028,
+    MSM8128,
+    MSM8228,
+    MSM8528,
+    MSM8628,
+    MSM8928,
+    MSM8510,
+    MSM8512,
+    MSM8936,
+    MDM9640,
+    MSM8939,
+    APQ8036,
+    APQ8039,
+    MSM8236,
+    MSM8636,
+    MSM8909,
+    MSM8996,
+    APQ8016,
+    MSM8216,
+    MSM8116,
+    MSM8616,
+    MSM8992,
+    APQ8092,
+    APQ8094,
+    MSM8209,
+    MSM8208,
+    MDM9209,
+    MDM9309,
+    MDM9609,
+    MSM8239,
+    MSM8952,
+    APQ8009,
+    MSM8956,
+    MSM8929,
+    MSM8629,
+    MSM8229,
+    APQ8029,
+    APQ8056,
+    MSM8609,
+    APQ8076,
+    MSM8976,
+    IPQ8065,
+    IPQ8069,
+    MDM9650,
+    MDM9655,
+    MDM9250,
+    MDM9255,
+    MDM9350,
+    APQ8052,
+    MDM9607,
+    APQ8096,
+    MSM8998,
+    MSM8953,
+    MSM8937,
+    APQ8037,
+    MDM8207,
+    MDM9207,
+    MDM9307,
+    MDM9628,
+    MSM8909W,
+    APQ8009W,
+    MSM8996L,
+    MSM8917,
+    APQ8053,
+    MSM8996SG,
+    APQ8017,
+    MSM8217,
+    MSM8617,
+    MSM8996AU,
+    APQ8096AU,
+    APQ8096SG,
+    MSM8940,
+    SDX201,
+    SDM660,
+    SDM630,
+    APQ8098,
+    MSM8920,
+    SDM845,
+    MDM9206,
+    IPQ8074,
+    SDA660,
+    SDM658,
+    SDA658,
+    SDA630,
+    MSM8905,
+    SDX202,
+    SDM670,
+    SDM450,
+    SM8150,
+    SDA845,
+    IPQ8072,
+    IPQ8076,
+    IPQ8078,
+    SDM636,
+    SDA636,
+    SDM632,
+    SDA632,
+    SDA450,
+    SDM439,
+    SDM429,
+    SM8250,
+    SA8155,
+    SDA439,
+    SDA429,
+    SM7150,
+    SM7150P,
+    IPQ8070,
+    IPQ8071,
+    QM215,
+    IPQ8072A,
+    IPQ8074A,
+    IPQ8076A,
+    IPQ8078A,
+    SM6125,
+    IPQ8070A,
+    IPQ8071A,
+    IPQ8172,
+    IPQ8173,
+    IPQ8174,
+    IPQ6018,
+    IPQ6028,
+    SDM429W,
+    SM4250,
+    IPQ6000,
+    IPQ6010,
+    SC7180,
+    SM6350,
+    QCM2150,
+    SDA429W,
+    SM8350,
+    QCM2290,
+    SM7125,
+    SM6115,
+    IPQ5010,
+    IPQ5018,
+    IPQ5028,
+    SC8280XP,
+    IPQ6005,
+    QRB5165,
+    SM8450,
+    SM7225,
+    SA8295P,
+    SA8540P,
+    QCM4290,
+    QCS4290,
+    SM7325,
+    (SM8450_2, "SM8450"),
+    (SM8450_3, "SM8450"),
+    SC7280,
+    SC7180P,
+    QCM6490,
+    QCS6490,
+    SM7325P,
+    IPQ5000,
+    IPQ0509,
+    IPQ0518,
+    SM6375,
+    IPQ9514,
+    IPQ9550,
+    IPQ9554,
+    IPQ9570,
+    IPQ9574,
+    SM8550,
+    IPQ5016,
+    IPQ9510,
+    QRB4210,
+    QRB2210,
+    SAR2130P,
+    SM8475,
+    SM8475P,
+    SA8255P,
+    SA8775P,
+    QRU1000,
+    SM8475_2,
+    QDU1000,
+    X1E80100,
+    SM8650,
+    SM4450,
+    SAR1130P,
+    QDU1010,
+    QRU1032,
+    QRU1052,
+    QRU1062,
+    IPQ5332,
+    IPQ5322,
+    IPQ5312,
+    IPQ5302,
+    QCS8550,
+    QCM8550,
+    SM8750,
+    IPQ5300,
+    SM7635,
+    SM6650,
+    SM6650P,
+    IPQ5321,
+    IPQ5424,
+    QCM6690,
+    QCS6690,
+    SM8850,
+    IPQ5404,
+    QCS9100,
+    QCS8300,
+    QCS8275,
+    QCS9075,
+    QCS615,
+}
+
+pub(crate) const PMIC_MODELS: &[Option<&str>] = &sparse_array! {
+    0: "Unknown PMIC model",
+    1: "PM8941",
+    2: "PM8841",
+    3: "PM8019",
+    4: "PM8226",
+    5: "PM8110",
+    6: "PMA8084",
+    7: "PMI8962",
+    8: "PMD9635",
+    9: "PM8994",
+    10: "PMI8994",
+    11: "PM8916",
+    12: "PM8004",
+    13: "PM8909/PM8058",
+    14: "PM8028",
+    15: "PM8901",
+    16: "PM8950/PM8027",
+    17: "PMI8950/ISL9519",
+    18: "PMK8001/PM8921",
+    19: "PMI8996/PM8018",
+    20: "PM8998/PM8015",
+    21: "PMI8998/PM8014",
+    22: "PM8821",
+    23: "PM8038",
+    24: "PM8005/PM8922",
+    25: "PM8917/PM8937",
+    26: "PM660L",
+    27: "PM660",
+    30: "PM8150",
+    31: "PM8150L",
+    32: "PM8150B",
+    33: "PMK8002",
+    36: "PM8009",
+    37: "PMI632",
+    38: "PM8150C",
+    40: "PM6150",
+    41: "SMB2351",
+    44: "PM8008",
+    45: "PM6125",
+    46: "PM7250B",
+    47: "PMK8350",
+    48: "PM8350",
+    49: "PM8350C",
+    50: "PM8350B",
+    51: "PMR735A",
+    52: "PMR735B",
+    54: "PM6350",
+    55: "PM4125",
+    58: "PM8450",
+    65: "PM8010",
+    69: "PM8550VS",
+    70: "PM8550VE",
+    71: "PM8550B",
+    72: "PMR735D",
+    73: "PM8550",
+    74: "PMK8550",
+    78: "PMM8650AU",
+    79: "PMM8650AU_PSAIL",
+    80: "PM7550",
+    82: "PMC8380",
+    83: "SMB2360",
+    91: "PMIV0108"
+};
+
+pub(crate) const IMAGE_NAMES: &[&CStr] = &[
+    c"boot",
+    c"tz",
+    c"tzsecapp",
+    c"rpm",
+    c"sdi",
+    c"hyp",
+    c"adsp1",
+    c"adsp2",
+    c"cdsp2",
+    c"appsbl",
+    c"apps",
+    c"mpss",
+    c"adsp",
+    c"cnss",
+    c"video",
+    c"dsps",
+    c"cdsp",
+    c"npu",
+    c"wpss",
+    c"cdsp1",
+    c"gpdsp",
+    c"gpdsp1",
+    c"sensorpd",
+    c"audiopd",
+    c"oempd",
+    c"chargerpd",
+    c"oispd",
+    c"soccp",
+    c"tme",
+    c"gearvm",
+    c"uefi",
+    c"cdsp3",
+    c"audiopd",
+    c"audiopd",
+    c"dcp",
+    c"oobs",
+    c"oobns",
+    c"devcfg",
+    c"btpd",
+    c"qecp",
+];
diff --git a/drivers/soc/qcom/socinfo/socinfo.rs b/drivers/soc/qcom/socinfo/socinfo.rs
new file mode 100644
index 0000000000000000000000000000000000000000..c0791b33232eed9aef01c4db9e2031961fca783f
--- /dev/null
+++ b/drivers/soc/qcom/socinfo/socinfo.rs
@@ -0,0 +1,446 @@
+// SPDX-License-Identifier: GPL-2.0
+
+// Copyright (C) 2025 Google LLC.
+
+//! socinfo driver for Qualcomm SoCs.
+
+use core::fmt::{
+    self,
+    Formatter, //
+};
+
+use kernel::{
+    auxiliary,
+    c_str,
+    debugfs::{
+        Scope,
+        ScopedDir, //
+    },
+    device::{
+        Bound,
+        Core,
+        Device, //
+    },
+    devres::Devres,
+    error,
+    io::{
+        Io,
+        Mmio, //
+    },
+    module_auxiliary_driver,
+    pr_warn,
+    prelude::*,
+    soc,
+    str::{
+        CStr,
+        CStrExt,
+        CString, //
+    },
+    transmute::AsBytes,
+    try_pin_init, //
+};
+use pin_init::pin_init_scope;
+
+mod bindings;
+mod data;
+
+use bindings::*;
+use data::{
+    IMAGE_NAMES,
+    PMIC_MODELS,
+    SOC_IDS, //
+};
+
+module_auxiliary_driver! {
+    type: QcomSocInfo,
+    name: "qcom-socinfo",
+    authors: ["Matthew Maurer"],
+    description: "Qualcomm SoCinfo driver",
+    license: "GPL",
+    alias: ["platform:qcom-socinfo"],
+}
+
+#[pin_data]
+struct QcomSocInfo {
+    #[pin]
+    registration: soc::Registration,
+    #[pin]
+    params: Devres<Scope<Params>>,
+}
+
+fn pmic_name(model: u32) -> Option<&'static str> {
+    let idx = SocInfo::version_split(model).1 as usize;
+    PMIC_MODELS.get(idx).copied().flatten()
+}
+
+fn fmt_pmic_model(model: &u32, f: &mut Formatter<'_>) -> fmt::Result {
+    if let Some(model) = pmic_name(*model) {
+        writeln!(f, "{model}")
+    } else {
+        writeln!(f, "unknown ({})", SocInfo::version_split(*model).1)
+    }
+}
+
+fn fmt_pmic_die_rev(rev: &u32, f: &mut Formatter<'_>) -> fmt::Result {
+    let (major, minor) = SocInfo::version_split(*rev);
+    writeln!(f, "{major}.{minor}")
+}
+
+fn fmt_pmic_model_array(array: &KVec<PmicEntry>, f: &mut Formatter<'_>) -> fmt::Result {
+    for pmic_entry in array {
+        let (die_rev_major, die_rev_minor) =
+            SocInfo::version_split(u32::from_le(pmic_entry.die_rev));
+        if let Some(model) = pmic_name(pmic_entry.model) {
+            writeln!(f, "{model} {die_rev_major}.{die_rev_minor}")?
+        } else {
+            writeln!(f, "unknown ({})", pmic_entry.model)?
+        }
+    }
+    Ok(())
+}
+
+#[derive(Default)]
+struct Params {
+    info_fmt: u32,
+    build_id: [u8; 32],
+    raw_version: Option<u32>,
+    hardware_platform: Option<u32>,
+    platform_version: Option<u32>,
+    accessory_chip: Option<u32>,
+    hardware_platform_subtype: Option<u32>,
+    pmic_model: Option<u32>,
+    pmic_die_rev: Option<u32>,
+    foundry_id: Option<u32>,
+    pmic_model_array: Option<KVec<PmicEntry>>,
+    chip_family: Option<u32>,
+    raw_device_family: Option<u32>,
+    raw_device_number: Option<u32>,
+    nproduct_id: Option<u32>,
+    chip_id: Option<[u8; 32]>,
+    num_clusters: Option<u32>,
+    ncluster_array_offset: Option<u32>,
+    num_subset_parts: Option<u32>,
+    nsubset_parts_array_offset: Option<u32>,
+    nmodem_supported: Option<u32>,
+    feature_code: Option<u32>,
+    pcode: Option<u32>,
+    oem_variant: Option<u32>,
+    boot_core: Option<u32>,
+    boot_cluster: Option<u32>,
+    num_func_clusters: Option<u32>,
+    raw_package_type: Option<u32>,
+    versions: KVec<Smem>,
+}
+
+struct SocInfo {
+    soc_info: socinfo,
+    soc_info_mem: Smem,
+    version_mem: Smem,
+    version_mem2: Option<Smem>,
+}
+
+impl SocInfo {
+    fn from_mem(
+        soc_info_mem: Smem,
+        version_mem: Smem,
+        version_mem2: Option<Smem>,
+        dev: &Device<Bound>,
+    ) -> Result<Self> {
+        Ok(Self {
+            soc_info: socinfo_from_partial_bytes(
+                soc_info_mem.access(dev).ok_or(error::code::EINVAL)?,
+            )?,
+            soc_info_mem,
+            version_mem,
+            version_mem2,
+        })
+    }
+    fn id(&self) -> u32 {
+        u32::from_le(self.soc_info.id)
+    }
+    fn version_split(ver: u32) -> (u16, u16) {
+        let major = (ver >> 16) as u16;
+        let minor = (ver & 0xFFFF) as u16;
+        (major, minor)
+    }
+    fn version_fuse(major: u16, minor: u16) -> u32 {
+        (u32::from(major) << 16) | u32::from(minor)
+    }
+    fn version(&self) -> (u16, u16) {
+        Self::version_split(self.soc_info.ver)
+    }
+    fn serial(&self) -> u32 {
+        u32::from_le(self.soc_info.serial_num)
+    }
+    fn machine(&self) -> Result<Option<CString>> {
+        for soc in SOC_IDS {
+            if soc.id == self.id() {
+                return Ok(Some(soc.name.to_cstring()?));
+            }
+        }
+        Ok(None)
+    }
+    fn soc_attributes(&self) -> Result<soc::Attributes> {
+        Ok(soc::Attributes {
+            family: Some(c_str!("Snapdragon").to_cstring()?),
+            machine: self.machine()?,
+            revision: Some(CString::try_from_fmt(fmt!(
+                "{}.{}",
+                self.version().0,
+                self.version().1
+            ))?),
+            serial_number: Some(CString::try_from_fmt(fmt!("{}", self.serial()))?),
+            soc_id: Some(CString::try_from_fmt(fmt!("{}", self.id()))?),
+        })
+    }
+}
+
+macro_rules! u32_le_versioned {
+    { $params:expr, $self:ident,
+        [ $( { $major:expr, $minor:expr, { $( $dst:ident: $src:ident ),* } } ),*  ] } => {$(
+        if $params.info_fmt >= SocInfo::version_fuse($major, $minor) {
+            $( $params.$dst = Some(u32::from_le($self.soc_info.$src).into()) );*
+        }
+    )*}
+}
+
+impl SocInfo {
+    fn build_params(self, dev: &Device<Bound>) -> Result<Params> {
+        let mut params = Params {
+            build_id: self.soc_info.build_id,
+            info_fmt: u32::from_le(self.soc_info.fmt),
+            ..Default::default()
+        };
+        u32_le_versioned! { params, self, [
+            {0, 2, { raw_version: raw_ver }},
+            {0, 3, { hardware_platform: hw_plat }},
+            {0, 4, { platform_version: plat_ver }},
+            {0, 5, { accessory_chip: accessory_chip }},
+            {0, 6, { hardware_platform_subtype: hw_plat_subtype }},
+            {0, 7, { pmic_model: pmic_model, pmic_die_rev: pmic_die_rev }},
+            {0, 9, { foundry_id: foundry_id }},
+            {0, 12, {
+                chip_family: chip_family,
+                raw_device_family: raw_device_family,
+                raw_device_number: raw_device_num
+            }},
+            {0, 13, { nproduct_id: nproduct_id }},
+            {0, 14, {
+                num_clusters: num_clusters,
+                ncluster_array_offset: ncluster_array_offset,
+                num_subset_parts: num_subset_parts,
+                nsubset_parts_array_offset: nsubset_parts_array_offset
+            }},
+            {0, 15, { nmodem_supported: nmodem_supported }},
+            {0, 16, { feature_code: feature_code, pcode: pcode }},
+            {0, 17, { oem_variant: oem_variant }},
+            {0, 19, {
+                boot_core: boot_core,
+                boot_cluster: boot_cluster,
+                num_func_clusters: num_func_clusters
+            }},
+            {0, 20, { raw_package_type: raw_package_type }}
+        ]};
+        if params.info_fmt >= SocInfo::version_fuse(0, 11) {
+            let offset = u32::from_le(self.soc_info.pmic_array_offset) as usize;
+            let num_pmics = u32::from_le(self.soc_info.num_pmics) as usize;
+            let mut pmic_model_array =
+                KVec::from_elem(PmicEntry::default(), num_pmics, GFP_KERNEL)?;
+            self.soc_info_mem
+                .access(dev)
+                .ok_or(error::code::EINVAL)?
+                .try_copy_to(pmic_model_array.as_bytes_mut(), offset)?;
+            params.pmic_model_array = Some(pmic_model_array);
+        }
+        if params.info_fmt >= SocInfo::version_fuse(0, 13) {
+            params.chip_id = Some(self.soc_info.chip_id);
+        }
+        load_versions(&mut params.versions, &self.version_mem)?;
+        if let Some(versions) = self.version_mem2.as_ref() {
+            load_versions(&mut params.versions, versions)?;
+        }
+        Ok(params)
+    }
+}
+
+fn load_versions(versions: &mut KVec<Smem>, mem: &Smem) -> Result<()> {
+    const IMAGE_SIZE: usize = core::mem::size_of::<ImageVersion>();
+    for offset in (0..mem.maxsize()).step_by(IMAGE_SIZE) {
+        if let Some(subrange) = mem.subrange(offset, IMAGE_SIZE) {
+            versions.push(subrange, GFP_KERNEL)?;
+        }
+    }
+    Ok(())
+}
+
+macro_rules! value_attrs {
+    ($builder:ident, $params:ident, @) => {};
+    ($builder:ident, $params:ident, @ $s:ident $($rest:tt)*) => {
+        if let Some(v) = $params.$s.as_ref() {
+            $builder.read_only_file(c_str!(stringify!($s)), v);
+        }
+        value_attrs!($builder, $params, @ $($rest)*)
+    };
+    ($builder:ident, $params:ident, @ {$s:ident, $cb:expr} $($rest:tt)*) => {
+        if let Some(v) = $params.$s.as_ref() {
+            $builder.read_callback_file(c_str!(stringify!($s)), v, $cb);
+        }
+        value_attrs!($builder, $params, @ $($rest)*)
+    };
+    ($builder:ident, $params:ident, {$($items:tt),*}) => {
+        value_attrs!($builder, $params, @ $($items)*)
+    };
+}
+
+fn no_quirk<const SIZE: usize>(buf: &[u8; SIZE], f: &mut Formatter<'_>) -> fmt::Result {
+    if buf[0] == 0 {
+        writeln!(f)
+    } else {
+        nul_array(buf, f)
+    }
+}
+
+fn nul_array<const SIZE: usize>(buf: &[u8; SIZE], f: &mut Formatter<'_>) -> fmt::Result {
+    if let Some(end) = buf.iter().position(|x| *x == 0) {
+        if end == 0 {
+            // Match original driver quirk - empty strings don't have a trailing newline
+            return Ok(());
+        }
+        let Ok(c_str) = CStr::from_bytes_with_nul(&buf[0..=end]) else {
+            pr_warn!("Creating CStr from bytes with known first NUL failed?");
+            return Ok(());
+        };
+        let Ok(str) = c_str.to_str() else {
+            pr_warn!("Non-unicode-compatible character in string");
+            return Ok(());
+        };
+        writeln!(f, "{str}")
+    } else {
+        writeln!(f, "Missing NUL: {buf:?}")
+    }
+}
+
+fn build_image_debugfs<'a>(dir: &ScopedDir<'a, '_>, image_name: &CStr, mem: &'a Mmio) {
+    let subdir = dir.dir(image_name);
+    subdir.read_callback_file(c_str!("name"), mem, &debug_name);
+    subdir.read_callback_file(c_str!("variant"), mem, &debug_variant);
+    subdir.read_callback_file(c_str!("oem"), mem, &debug_oem);
+}
+
+fn debug_name(mem: &Mmio, f: &mut Formatter<'_>) -> fmt::Result {
+    let mut iv = ImageVersion::default();
+    mem.try_copy_to(iv.as_bytes_mut(), 0)
+        .map_err(|_| fmt::Error)?;
+    nul_array(&iv.name, f)
+}
+
+fn debug_variant(mem: &Mmio, f: &mut Formatter<'_>) -> fmt::Result {
+    let mut iv = ImageVersion::default();
+    mem.try_copy_to(iv.as_bytes_mut(), 0)
+        .map_err(|_| fmt::Error)?;
+    nul_array(&iv.variant, f)
+}
+
+fn debug_oem(mem: &Mmio, f: &mut Formatter<'_>) -> fmt::Result {
+    let mut iv = ImageVersion::default();
+    mem.try_copy_to(iv.as_bytes_mut(), 0)
+        .map_err(|_| fmt::Error)?;
+    nul_array(&iv.oem, f)
+}
+
+fn hex(x: &u32, f: &mut Formatter<'_>) -> fmt::Result {
+    writeln!(f, "{x:#010x}")
+}
+
+impl Params {
+    fn build_debugfs<'data>(&'data self, dev: &'data Device<Bound>, dir: &ScopedDir<'data, '_>) {
+        dir.read_callback_file(c_str!("info_fmt"), &self.info_fmt, &hex);
+        dir.read_callback_file(c_str!("build_id"), &self.build_id, &no_quirk);
+        value_attrs!(dir, self, {
+            raw_version,
+            hardware_platform,
+            platform_version,
+            accessory_chip,
+            hardware_platform_subtype,
+            {raw_device_number, &hex},
+            {raw_device_family, &hex},
+            {chip_family, &hex},
+            {chip_id, &nul_array},
+            nproduct_id,
+            nsubset_parts_array_offset,
+            num_subset_parts,
+            ncluster_array_offset,
+            num_clusters,
+            nmodem_supported,
+            pcode,
+            feature_code,
+            oem_variant,
+            boot_core,
+            boot_cluster,
+            num_func_clusters,
+            foundry_id,
+            raw_package_type,
+            {pmic_model, &fmt_pmic_model},
+            {pmic_die_rev, &fmt_pmic_die_rev},
+            {pmic_model_array, &fmt_pmic_model_array}
+        });
+        for (version, name) in self.versions.iter().zip(IMAGE_NAMES.iter()) {
+            if let Some(version_mem) = version.access(dev) {
+                build_image_debugfs(dir, name, version_mem);
+            }
+        }
+    }
+}
+
+kernel::auxiliary_device_table! {
+    AUX_TABLE,
+    MODULE_AUX_TABLE,
+    <QcomSocInfo as auxiliary::Driver>::IdInfo,
+    [(auxiliary::DeviceId::new(c_str!("smem"), c_str!("qcom-socinfo")), ())]
+}
+
+impl auxiliary::Driver for QcomSocInfo {
+    type IdInfo = ();
+    const ID_TABLE: auxiliary::IdTable<Self::IdInfo> = &AUX_TABLE;
+    fn probe(dev: &auxiliary::Device<Core>, _id_info: &Self::IdInfo) -> impl PinInit<Self, Error> {
+        pin_init_scope(move || {
+            let soc_info_mem = Smem::get(
+                dev,
+                kernel::bindings::QCOM_SMEM_HOST_ANY,
+                kernel::bindings::SMEM_HW_SW_BUILD_ID,
+            )?;
+            let version_mem = Smem::get(
+                dev,
+                kernel::bindings::QCOM_SMEM_HOST_ANY,
+                bindings::SMEM_IMAGE_VERSION_TABLE,
+            )?;
+            let version_mem2 = Smem::get(
+                dev,
+                kernel::bindings::QCOM_SMEM_HOST_ANY,
+                bindings::SMEM_IMAGE_VERSION_TABLE_2,
+            )
+            .ok();
+            let base_dev = dev.as_ref();
+            let mem = soc_info_mem.access(base_dev).ok_or(error::code::EINVAL)?;
+
+            rand_from_mmio(mem)?;
+
+            let info = SocInfo::from_mem(soc_info_mem, version_mem, version_mem2, base_dev)?;
+            let attributes = info.soc_attributes()?;
+            let backing = info.build_params(base_dev)?;
+
+            Ok(try_pin_init!(Self {
+                registration <- soc::Registration::new(attributes),
+                params <- Devres::dir(base_dev, backing, c_str!("qcom_socinfo"),
+                                      Params::build_debugfs),
+            }? Error))
+        })
+    }
+}
+
+fn rand_from_mmio(mmio: &Mmio) -> Result<()> {
+    let mut buf: KVec<u8> = KVec::from_elem(0, mmio.maxsize(), GFP_KERNEL)?;
+    mmio.try_copy_to(&mut buf, 0)?;
+    kernel::random::add_device_randomness(&buf);
+    Ok(())
+}
diff --git a/include/linux/soc/qcom/smem.h b/include/linux/soc/qcom/smem.h
index f946e3beca215548ac56dbf779138d05479712f5..1c26f258be1fc1bf34bf3b0112c4a8472e676ed8 100644
--- a/include/linux/soc/qcom/smem.h
+++ b/include/linux/soc/qcom/smem.h
@@ -4,8 +4,12 @@
 
 #define QCOM_SMEM_HOST_ANY -1
 
+struct auxiliary_device;
+
 bool qcom_smem_is_available(void);
 int qcom_smem_alloc(unsigned host, unsigned item, size_t size);
+void *qcom_smem_get_aux(struct auxiliary_device *aux, unsigned int host,
+		unsigned int item, size_t *size);
 void *qcom_smem_get(unsigned host, unsigned item, size_t *size);
 
 int qcom_smem_get_free_space(unsigned host);
diff --git a/rust/bindgen_parameters b/rust/bindgen_parameters
index d56343ca03979e345f8adb7eb8fd7f2b9d4be6ee..3398a8eff517b71c062fd3e52a4a7895526f64a1 100644
--- a/rust/bindgen_parameters
+++ b/rust/bindgen_parameters
@@ -72,3 +72,4 @@
 # We can't auto-derive AsBytes, as we need a const-time check to see if there
 # is padding involved. Add it explicitly when you expect no padding.
 --with-derive-custom-struct cpumask=AsBytesFfi
+--with-derive-custom-struct socinfo=AsBytesFfi
diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h
index 9fdf76ca630e00715503e2a3a809bedc895697fd..b076b847731d97cf345d8ef80df9c315a79c8fab 100644
--- a/rust/bindings/bindings_helper.h
+++ b/rust/bindings/bindings_helper.h
@@ -95,6 +95,12 @@
  */
 #include <../../drivers/base/base.h>
 
+#if IS_ENABLED(CONFIG_QCOM_SOCINFO)
+#include <dt-bindings/arm/qcom,ids.h>
+#include <linux/soc/qcom/smem.h>
+#include <linux/soc/qcom/socinfo.h>
+#endif
+
 #if defined(CONFIG_DRM_PANIC_SCREEN_QR_CODE)
 // Used by `#[export]` in `drivers/gpu/drm/drm_panic_qr.rs`.
 #include <drm/drm_panic.h>

-- 
2.53.0.rc2.204.g2597b5adb4-goog


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* Re: [PATCH v2 2/6] rust: io: Support copying arrays and slices
  2026-02-03 15:46 ` [PATCH v2 2/6] rust: io: Support copying arrays and slices Matthew Maurer
@ 2026-02-03 15:53   ` Danilo Krummrich
  0 siblings, 0 replies; 32+ messages in thread
From: Danilo Krummrich @ 2026-02-03 15:53 UTC (permalink / raw)
  To: Matthew Maurer
  Cc: Bjorn Andersson, Konrad Dybcio, Satya Durga Srinivasu Prabhala,
	Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Daniel Almeida, Greg Kroah-Hartman, Rafael J. Wysocki,
	David Airlie, Simona Vetter, Michal Wilczynski, Dave Ertman,
	Ira Weiny, Leon Romanovsky, Trilok Soni, linux-kernel,
	linux-arm-msm, rust-for-linux, driver-core, dri-devel, linux-pwm

On Tue Feb 3, 2026 at 4:46 PM CET, Matthew Maurer wrote:
> Adds support for doing array copies of data in and out of IO regions.
> Fixed size arrays allow for compile-time bound checking, while slice
> arguments allow for dynamically checked copies.
>
> Signed-off-by: Matthew Maurer <mmaurer@google.com>

This patch needs to go on top of the recent I/O rework and should be generalized
through an IoSlice type [1].

[1] https://rust-for-linux.zulipchat.com/#narrow/channel/288089-General/topic/Generic.20I.2FO.20backends/with/571639597

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v2 4/6] rust: auxiliary: Support accessing raw aux pointer
  2026-02-03 15:46 ` [PATCH v2 4/6] rust: auxiliary: Support accessing raw aux pointer Matthew Maurer
@ 2026-02-03 15:55   ` Danilo Krummrich
  0 siblings, 0 replies; 32+ messages in thread
From: Danilo Krummrich @ 2026-02-03 15:55 UTC (permalink / raw)
  To: Matthew Maurer
  Cc: Bjorn Andersson, Konrad Dybcio, Satya Durga Srinivasu Prabhala,
	Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Daniel Almeida, Greg Kroah-Hartman, Rafael J. Wysocki,
	David Airlie, Simona Vetter, Michal Wilczynski, Dave Ertman,
	Ira Weiny, Leon Romanovsky, Trilok Soni, linux-kernel,
	linux-arm-msm, rust-for-linux, driver-core, dri-devel, linux-pwm

On Tue Feb 3, 2026 at 4:46 PM CET, Matthew Maurer wrote:
> While it's preferable to add bindings in the kernel crate rather than
> using raw pointers where possible, access to the raw aux pointer is
> required to pass it to C interfaces provided by a driver.
>
> Signed-off-by: Matthew Maurer <mmaurer@google.com>
> ---
>  rust/kernel/auxiliary.rs | 6 +++++-
>  1 file changed, 5 insertions(+), 1 deletion(-)
>
> diff --git a/rust/kernel/auxiliary.rs b/rust/kernel/auxiliary.rs
> index 93c0db1f66555c97ec7dc58825e97c47c0154e54..1a88277f0fd9ea5ff32cc534dfe5682009de94c2 100644
> --- a/rust/kernel/auxiliary.rs
> +++ b/rust/kernel/auxiliary.rs
> @@ -237,7 +237,11 @@ pub struct Device<Ctx: device::DeviceContext = device::Normal>(
>  );
>  
>  impl<Ctx: device::DeviceContext> Device<Ctx> {
> -    fn as_raw(&self) -> *mut bindings::auxiliary_device {
> +    /// Returns the underlying auxiliary device

"Returns a pointer to the underlying `struct auxiliary_device`."

> +    ///
> +    /// Prefer to add bindings in the kernel crate for any use other than calling driver-specific
> +    /// functions.

I'm not sure I understand the message of this comment, but I'd probably just
drop it, the above should be enough.

> +    pub fn as_raw(&self) -> *mut bindings::auxiliary_device {
>          self.0.get()
>      }

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v2 3/6] rust: device: Support testing devices for equality
  2026-02-03 15:46 ` [PATCH v2 3/6] rust: device: Support testing devices for equality Matthew Maurer
@ 2026-02-03 15:56   ` Danilo Krummrich
  2026-02-03 16:05   ` Gary Guo
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 32+ messages in thread
From: Danilo Krummrich @ 2026-02-03 15:56 UTC (permalink / raw)
  To: Matthew Maurer
  Cc: Bjorn Andersson, Konrad Dybcio, Satya Durga Srinivasu Prabhala,
	Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Daniel Almeida, Greg Kroah-Hartman, Rafael J. Wysocki,
	David Airlie, Simona Vetter, Michal Wilczynski, Dave Ertman,
	Ira Weiny, Leon Romanovsky, Trilok Soni, linux-kernel,
	linux-arm-msm, rust-for-linux, driver-core, dri-devel, linux-pwm

On Tue Feb 3, 2026 at 4:46 PM CET, Matthew Maurer wrote:
> This allows device drivers to check if, for example, an auxiliary
> devices is one of its children by comparing the parent field, or
> checking if a device parameter is its own device.
>
> Also convert existing `.as_raw() != .as_raw()` to  use this new
> implementation.
>
> Signed-off-by: Matthew Maurer <mmaurer@google.com>

In case this should eventually go through another tree:

Acked-by: Danilo Krummrich <dakr@kernel.org>

But please let me know if you want me to pick it up.

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v2 5/6] rust: debugfs: Allow access to device in Devres-wrapped scopes
  2026-02-03 15:46 ` [PATCH v2 5/6] rust: debugfs: Allow access to device in Devres-wrapped scopes Matthew Maurer
@ 2026-02-03 15:59   ` Danilo Krummrich
  2026-02-03 16:47   ` Gary Guo
  1 sibling, 0 replies; 32+ messages in thread
From: Danilo Krummrich @ 2026-02-03 15:59 UTC (permalink / raw)
  To: Matthew Maurer
  Cc: Bjorn Andersson, Konrad Dybcio, Satya Durga Srinivasu Prabhala,
	Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Daniel Almeida, Greg Kroah-Hartman, Rafael J. Wysocki,
	David Airlie, Simona Vetter, Michal Wilczynski, Dave Ertman,
	Ira Weiny, Leon Romanovsky, Trilok Soni, linux-kernel,
	linux-arm-msm, rust-for-linux, driver-core, dri-devel, linux-pwm

On Tue Feb 3, 2026 at 4:46 PM CET, Matthew Maurer wrote:
> This adds support for creating a DebugFS directory which is aware that
> it is bound to a device. As a result, callbacks under that directory
> have access to a bound device which gives them efficient access to other
> Devres, ability to use dev_err! and friends, etc.
>

Suggested-by: Danilo Krummrich <dakr@kernel.org>

> Signed-off-by: Matthew Maurer <mmaurer@google.com>

Again,

Acked-by: Danilo Krummrich <dakr@kernel.org>

if this should go through another tree, but I can also pick it up.

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v2 3/6] rust: device: Support testing devices for equality
  2026-02-03 15:46 ` [PATCH v2 3/6] rust: device: Support testing devices for equality Matthew Maurer
  2026-02-03 15:56   ` Danilo Krummrich
@ 2026-02-03 16:05   ` Gary Guo
  2026-02-03 16:15   ` Greg Kroah-Hartman
  2026-02-03 16:17   ` Greg Kroah-Hartman
  3 siblings, 0 replies; 32+ messages in thread
From: Gary Guo @ 2026-02-03 16:05 UTC (permalink / raw)
  To: Matthew Maurer, Bjorn Andersson, Konrad Dybcio,
	Satya Durga Srinivasu Prabhala, Miguel Ojeda, Boqun Feng,
	Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg,
	Alice Ryhl, Trevor Gross, Danilo Krummrich, Daniel Almeida,
	Greg Kroah-Hartman, Rafael J. Wysocki, David Airlie,
	Simona Vetter, Michal Wilczynski, Dave Ertman, Ira Weiny,
	Leon Romanovsky
  Cc: Trilok Soni, linux-kernel, linux-arm-msm, rust-for-linux,
	driver-core, dri-devel, linux-pwm

On Tue Feb 3, 2026 at 3:46 PM GMT, Matthew Maurer wrote:
> This allows device drivers to check if, for example, an auxiliary
> devices is one of its children by comparing the parent field, or
> checking if a device parameter is its own device.
> 
> Also convert existing `.as_raw() != .as_raw()` to  use this new
> implementation.
> 
> Signed-off-by: Matthew Maurer <mmaurer@google.com>

Reviewed-by: Gary Guo <gary@garyguo.net>

> ---
>  rust/kernel/device.rs     | 8 ++++++++
>  rust/kernel/devres.rs     | 2 +-
>  rust/kernel/drm/driver.rs | 2 +-
>  rust/kernel/pwm.rs        | 2 +-
>  4 files changed, 11 insertions(+), 3 deletions(-)


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v2 3/6] rust: device: Support testing devices for equality
  2026-02-03 15:46 ` [PATCH v2 3/6] rust: device: Support testing devices for equality Matthew Maurer
  2026-02-03 15:56   ` Danilo Krummrich
  2026-02-03 16:05   ` Gary Guo
@ 2026-02-03 16:15   ` Greg Kroah-Hartman
  2026-02-03 16:17   ` Greg Kroah-Hartman
  3 siblings, 0 replies; 32+ messages in thread
From: Greg Kroah-Hartman @ 2026-02-03 16:15 UTC (permalink / raw)
  To: Matthew Maurer
  Cc: Bjorn Andersson, Konrad Dybcio, Satya Durga Srinivasu Prabhala,
	Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, Daniel Almeida, Rafael J. Wysocki, David Airlie,
	Simona Vetter, Michal Wilczynski, Dave Ertman, Ira Weiny,
	Leon Romanovsky, Trilok Soni, linux-kernel, linux-arm-msm,
	rust-for-linux, driver-core, dri-devel, linux-pwm

On Tue, Feb 03, 2026 at 03:46:32PM +0000, Matthew Maurer wrote:
> This allows device drivers to check if, for example, an auxiliary
> devices is one of its children by comparing the parent field, or
> checking if a device parameter is its own device.

Ok, but why?  This says what it does, but I have no context as to why
this would be needed.

What driver wants to know this?

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v2 3/6] rust: device: Support testing devices for equality
  2026-02-03 15:46 ` [PATCH v2 3/6] rust: device: Support testing devices for equality Matthew Maurer
                     ` (2 preceding siblings ...)
  2026-02-03 16:15   ` Greg Kroah-Hartman
@ 2026-02-03 16:17   ` Greg Kroah-Hartman
  2026-02-03 16:29     ` Danilo Krummrich
  3 siblings, 1 reply; 32+ messages in thread
From: Greg Kroah-Hartman @ 2026-02-03 16:17 UTC (permalink / raw)
  To: Matthew Maurer
  Cc: Bjorn Andersson, Konrad Dybcio, Satya Durga Srinivasu Prabhala,
	Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, Daniel Almeida, Rafael J. Wysocki, David Airlie,
	Simona Vetter, Michal Wilczynski, Dave Ertman, Ira Weiny,
	Leon Romanovsky, Trilok Soni, linux-kernel, linux-arm-msm,
	rust-for-linux, driver-core, dri-devel, linux-pwm

On Tue, Feb 03, 2026 at 03:46:32PM +0000, Matthew Maurer wrote:
> This allows device drivers to check if, for example, an auxiliary
> devices is one of its children by comparing the parent field, or
> checking if a device parameter is its own device.
> 
> Also convert existing `.as_raw() != .as_raw()` to  use this new
> implementation.

Ah, ok, I can see how getting rid of the as_raw() calls here is a "good
thing", but overall it's just the same code paths :)

And I don't see what patch in this series uses this, am I missing it?

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v2 6/6] soc: qcom: socinfo: Convert to Rust
  2026-02-03 15:46 ` [PATCH v2 6/6] soc: qcom: socinfo: Convert to Rust Matthew Maurer
@ 2026-02-03 16:28   ` Greg Kroah-Hartman
  2026-02-03 16:35     ` Danilo Krummrich
  2026-02-03 17:37     ` Matthew Maurer
  2026-02-03 20:27   ` Bjorn Andersson
  1 sibling, 2 replies; 32+ messages in thread
From: Greg Kroah-Hartman @ 2026-02-03 16:28 UTC (permalink / raw)
  To: Matthew Maurer
  Cc: Bjorn Andersson, Konrad Dybcio, Satya Durga Srinivasu Prabhala,
	Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, Daniel Almeida, Rafael J. Wysocki, David Airlie,
	Simona Vetter, Michal Wilczynski, Dave Ertman, Ira Weiny,
	Leon Romanovsky, Trilok Soni, linux-kernel, linux-arm-msm,
	rust-for-linux, driver-core, dri-devel, linux-pwm

On Tue, Feb 03, 2026 at 03:46:35PM +0000, Matthew Maurer wrote:
> Convert the socinfo driver to Rust for a number of improvements:
> * Accessing IO mapped regions through the IO subsystem, rather than
>   through regular memory accesses.

That's good, but the C code could also be "fixed" to do this, right?

> * Binds the device as an auxiliary device rather than a platform device,
>   ensuring the mapped IO regions cannot be accessed after the smem
>   device is removed.

I'm all for this, but is this really an aux device?  What is the
"parent" device of this aux device?  Where are the "siblings"?  What
does sysfs look like before/after this?

> * Adds bounds-checking to all accesses, hardening against a repeat of
>   CVE-2024-58007

How do you now "know" that the bounds checking is correct?  The C
version also had this, it was just "not correct" :)

And which accesses are you referring to?  From userspace?  From the
kernel?  That CVE looks very odd, it's probably not even a real one and
should be revoked, right?


> diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c
> index fef840b5457407a85051ded0e835430dbebfe8bb..dcea2d7f37067b0b6f801b3d2b457422ad9f342c 100644
> --- a/drivers/soc/qcom/smem.c
> +++ b/drivers/soc/qcom/smem.c
> @@ -4,6 +4,7 @@
>   * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
>   */
>  
> +#include <linux/auxiliary_bus.h>
>  #include <linux/hwspinlock.h>
>  #include <linux/io.h>
>  #include <linux/module.h>
> @@ -279,7 +280,6 @@ struct qcom_smem {
>  	struct hwspinlock *hwlock;
>  
>  	u32 item_count;
> -	struct platform_device *socinfo;
>  	struct smem_ptable *ptable;
>  	struct smem_partition global_partition;
>  	struct smem_partition partitions[SMEM_HOST_COUNT];
> @@ -675,6 +675,32 @@ static void *qcom_smem_get_private(struct qcom_smem *smem,
>  	return ERR_PTR(-EINVAL);
>  }
>  
> +/**
> + * qcom_smem_get_aux() - resolve ptr of size of a smem item
> + * @aux:        an aux device that should be our child
> + * @host:	the remote processor, or -1
> + * @item:	smem item handle
> + * @size:	pointer to be filled out with size of the item
> + *
> + * Looks up smem item and returns pointer to it. Size of smem
> + * item is returned in @size.
> + *
> + * The caller may take the loaded state of the provided aux device as
> + * an acceptable proxy for this memory being valid.
> + *
> + * Return: a pointer to an SMEM item on success, ERR_PTR() on failure.
> + */
> +void *qcom_smem_get_aux(struct auxiliary_device *aux, unsigned int host,
> +		unsigned int item, size_t *size)
> +{
> +	if (IS_ERR(__smem))
> +		return __smem;
> +	if (aux->dev.parent != __smem->dev)
> +		return ERR_PTR(-EINVAL);
> +	return qcom_smem_get(host, item, size);

So you are returning a void pointer?  But don't you really know the
"type" of what is being asked here?  It's a memory chunk, so u8?  Or
something else?  void * feels "rough" here.

> +}
> +EXPORT_SYMBOL_GPL(qcom_smem_get_aux);
> +
>  /**
>   * qcom_smem_get() - resolve ptr of size of a smem item
>   * @host:	the remote processor, or -1
> @@ -684,6 +710,9 @@ static void *qcom_smem_get_private(struct qcom_smem *smem,
>   * Looks up smem item and returns pointer to it. Size of smem
>   * item is returned in @size.
>   *
> + * It is up to the caller to ensure that the qcom_smem device remains
> + * loaded by some mechanism when accessing returned memory.

What do you mean by "loaded"?  You are saying that the caller needs to
rely on this driver remaining in memory for that memory to be "valid"?

If this is the case, why not take a reference count?

> +impl Smem {
> +    pub(crate) fn access<'a>(&'a self, dev: &'a Device<Bound>) -> Option<&'a Mmio> {
> +        if *dev != *self.dev {

How can this ever happen?

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v2 3/6] rust: device: Support testing devices for equality
  2026-02-03 16:17   ` Greg Kroah-Hartman
@ 2026-02-03 16:29     ` Danilo Krummrich
  2026-02-03 16:40       ` Greg Kroah-Hartman
  0 siblings, 1 reply; 32+ messages in thread
From: Danilo Krummrich @ 2026-02-03 16:29 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: Matthew Maurer, Bjorn Andersson, Konrad Dybcio,
	Satya Durga Srinivasu Prabhala, Miguel Ojeda, Boqun Feng,
	Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg,
	Alice Ryhl, Trevor Gross, Daniel Almeida, Rafael J. Wysocki,
	David Airlie, Simona Vetter, Michal Wilczynski, Dave Ertman,
	Ira Weiny, Leon Romanovsky, Trilok Soni, linux-kernel,
	linux-arm-msm, rust-for-linux, driver-core, dri-devel, linux-pwm

On Tue Feb 3, 2026 at 5:17 PM CET, Greg Kroah-Hartman wrote:
> And I don't see what patch in this series uses this, am I missing it?

	impl Smem {
	    pub(crate) fn access<'a>(&'a self, dev: &'a Device<Bound>) -> Option<&'a Mmio> {
	        if *dev != *self.dev {
	            return None;
	        }
	
	        // SAFETY: By our invariant, this was a subrange of what was returned by smem_aux_get, for
	        // self.dev, and by our above check, that auxdev is still available.
	        Some(unsafe { Mmio::from_raw(&self.raw) })
	    }
	}

It's used to ensure that the Smem provided by the auxiliary parent can only be
accessed as long as the auxiliary parent device is bound.

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v2 6/6] soc: qcom: socinfo: Convert to Rust
  2026-02-03 16:28   ` Greg Kroah-Hartman
@ 2026-02-03 16:35     ` Danilo Krummrich
  2026-02-03 16:48       ` Greg Kroah-Hartman
  2026-02-03 17:37     ` Matthew Maurer
  1 sibling, 1 reply; 32+ messages in thread
From: Danilo Krummrich @ 2026-02-03 16:35 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: Matthew Maurer, Bjorn Andersson, Konrad Dybcio,
	Satya Durga Srinivasu Prabhala, Miguel Ojeda, Boqun Feng,
	Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg,
	Alice Ryhl, Trevor Gross, Daniel Almeida, Rafael J. Wysocki,
	David Airlie, Simona Vetter, Michal Wilczynski, Dave Ertman,
	Ira Weiny, Leon Romanovsky, Trilok Soni, linux-kernel,
	linux-arm-msm, rust-for-linux, driver-core, dri-devel, linux-pwm

On Tue Feb 3, 2026 at 5:28 PM CET, Greg Kroah-Hartman wrote:
> On Tue, Feb 03, 2026 at 03:46:35PM +0000, Matthew Maurer wrote:
>> +impl Smem {
>> +    pub(crate) fn access<'a>(&'a self, dev: &'a Device<Bound>) -> Option<&'a Mmio> {
>> +        if *dev != *self.dev {
>
> How can this ever happen?

You are right, since this resource is local to the driver, it should not be
possible to have another devce from somewhere else (especially not a
&Device<Bound>).

However, from a Rust perspective I think not having this check would be unsound,
as the method by itself would not be able guarantee correct behavor anymore.

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v2 3/6] rust: device: Support testing devices for equality
  2026-02-03 16:29     ` Danilo Krummrich
@ 2026-02-03 16:40       ` Greg Kroah-Hartman
  2026-02-03 16:46         ` Danilo Krummrich
  0 siblings, 1 reply; 32+ messages in thread
From: Greg Kroah-Hartman @ 2026-02-03 16:40 UTC (permalink / raw)
  To: Danilo Krummrich
  Cc: Matthew Maurer, Bjorn Andersson, Konrad Dybcio,
	Satya Durga Srinivasu Prabhala, Miguel Ojeda, Boqun Feng,
	Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg,
	Alice Ryhl, Trevor Gross, Daniel Almeida, Rafael J. Wysocki,
	David Airlie, Simona Vetter, Michal Wilczynski, Dave Ertman,
	Ira Weiny, Leon Romanovsky, Trilok Soni, linux-kernel,
	linux-arm-msm, rust-for-linux, driver-core, dri-devel, linux-pwm

On Tue, Feb 03, 2026 at 05:29:16PM +0100, Danilo Krummrich wrote:
> On Tue Feb 3, 2026 at 5:17 PM CET, Greg Kroah-Hartman wrote:
> > And I don't see what patch in this series uses this, am I missing it?
> 
> 	impl Smem {
> 	    pub(crate) fn access<'a>(&'a self, dev: &'a Device<Bound>) -> Option<&'a Mmio> {
> 	        if *dev != *self.dev {
> 	            return None;
> 	        }
> 	
> 	        // SAFETY: By our invariant, this was a subrange of what was returned by smem_aux_get, for
> 	        // self.dev, and by our above check, that auxdev is still available.
> 	        Some(unsafe { Mmio::from_raw(&self.raw) })
> 	    }
> 	}
> 
> It's used to ensure that the Smem provided by the auxiliary parent can only be
> accessed as long as the auxiliary parent device is bound.

But how can a parent device ever bevome "unbound"?  A child can always
rely on its parent being present (some odd scsi devices are the one
exception, that mess is hell at times...)

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v2 3/6] rust: device: Support testing devices for equality
  2026-02-03 16:40       ` Greg Kroah-Hartman
@ 2026-02-03 16:46         ` Danilo Krummrich
  2026-02-03 17:17           ` Matthew Maurer
  0 siblings, 1 reply; 32+ messages in thread
From: Danilo Krummrich @ 2026-02-03 16:46 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: Matthew Maurer, Bjorn Andersson, Konrad Dybcio,
	Satya Durga Srinivasu Prabhala, Miguel Ojeda, Boqun Feng,
	Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg,
	Alice Ryhl, Trevor Gross, Daniel Almeida, Rafael J. Wysocki,
	David Airlie, Simona Vetter, Michal Wilczynski, Dave Ertman,
	Ira Weiny, Leon Romanovsky, Trilok Soni, linux-kernel,
	linux-arm-msm, rust-for-linux, driver-core, dri-devel, linux-pwm

On Tue Feb 3, 2026 at 5:40 PM CET, Greg Kroah-Hartman wrote:
> On Tue, Feb 03, 2026 at 05:29:16PM +0100, Danilo Krummrich wrote:
>> On Tue Feb 3, 2026 at 5:17 PM CET, Greg Kroah-Hartman wrote:
>> > And I don't see what patch in this series uses this, am I missing it?
>> 
>> 	impl Smem {
>> 	    pub(crate) fn access<'a>(&'a self, dev: &'a Device<Bound>) -> Option<&'a Mmio> {
>> 	        if *dev != *self.dev {
>> 	            return None;
>> 	        }
>> 	
>> 	        // SAFETY: By our invariant, this was a subrange of what was returned by smem_aux_get, for
>> 	        // self.dev, and by our above check, that auxdev is still available.
>> 	        Some(unsafe { Mmio::from_raw(&self.raw) })
>> 	    }
>> 	}
>> 
>> It's used to ensure that the Smem provided by the auxiliary parent can only be
>> accessed as long as the auxiliary parent device is bound.
>
> But how can a parent device ever bevome "unbound"?

It can't, that's why auxiliary::Device::parent() returns a &Device<Bound>, i.e.
as long as the child is bound the parent is guaranteed to be bound as well.

The point in this implementation is that we need to prove to the resource
container (Smem) that we are allowed to access the resource, since it is only
valid to access for the duration the parent is bound.

In the end this is equivalent to Devres::access(), which bypasses the Revocable
if we can prove that we are in a &Device<Bound> scope.

Having that said, the code should probably just use Devres instead. :)

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v2 5/6] rust: debugfs: Allow access to device in Devres-wrapped scopes
  2026-02-03 15:46 ` [PATCH v2 5/6] rust: debugfs: Allow access to device in Devres-wrapped scopes Matthew Maurer
  2026-02-03 15:59   ` Danilo Krummrich
@ 2026-02-03 16:47   ` Gary Guo
  2026-02-03 16:58     ` Danilo Krummrich
  2026-02-03 18:04     ` Matthew Maurer
  1 sibling, 2 replies; 32+ messages in thread
From: Gary Guo @ 2026-02-03 16:47 UTC (permalink / raw)
  To: Matthew Maurer, Bjorn Andersson, Konrad Dybcio,
	Satya Durga Srinivasu Prabhala, Miguel Ojeda, Boqun Feng,
	Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg,
	Alice Ryhl, Trevor Gross, Danilo Krummrich, Daniel Almeida,
	Greg Kroah-Hartman, Rafael J. Wysocki, David Airlie,
	Simona Vetter, Michal Wilczynski, Dave Ertman, Ira Weiny,
	Leon Romanovsky
  Cc: Trilok Soni, linux-kernel, linux-arm-msm, rust-for-linux,
	driver-core, dri-devel, linux-pwm

On Tue Feb 3, 2026 at 3:46 PM GMT, Matthew Maurer wrote:
> This adds support for creating a DebugFS directory which is aware that
> it is bound to a device. As a result, callbacks under that directory
> have access to a bound device which gives them efficient access to other
> Devres, ability to use dev_err! and friends, etc.
>
> Signed-off-by: Matthew Maurer <mmaurer@google.com>
> ---
>  rust/kernel/debugfs.rs | 40 ++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 40 insertions(+)
>
> diff --git a/rust/kernel/debugfs.rs b/rust/kernel/debugfs.rs
> index d7b8014a6474698235203f2b7d8fec96f2bb43f8..ac614d693fa73929d095b669e9ba61958bec609e 100644
> --- a/rust/kernel/debugfs.rs
> +++ b/rust/kernel/debugfs.rs
> @@ -11,6 +11,11 @@
>  #[cfg(CONFIG_DEBUG_FS)]
>  use crate::sync::Arc;
>  use crate::{
> +    device::{
> +        Bound,
> +        Device, //
> +    },
> +    devres::Devres,
>      fmt,
>      prelude::*,
>      str::CStr,
> @@ -722,3 +727,38 @@ fn new(name: &CStr) -> ScopedDir<'data, 'static> {
>          }
>      }
>  }
> +
> +impl<'a, T: 'a + Send> Devres<Scope<T>> {
> +    /// Creates a new scope, which is a directory at the root of the debugfs filesystem,
> +    /// associated with some data `T`, enclosed in a [`Devres`] for the provided device.
> +    ///
> +    /// The `init` closure is called to populate the directory with files and subdirectories. These
> +    /// files can reference the data stored in the scope. Because it is stored inside a `Devres`,
> +    /// the init method is granted access to a `&Device<Bound>`.
> +    ///
> +    /// This can be used for cheaply accessing device-protected data inside DebugFS methods or
> +    /// accessing device-specific methods (e.g. [`dev_err!`]).
> +    ///
> +    /// The entire directory tree created within the scope will be removed when the returned
> +    /// `Scope` handle is dropped.
> +    pub fn dir<E: 'a, F>(
> +        dev: &'a Device<Bound>,
> +        data: impl PinInit<T, E> + 'a,
> +        name: &'a CStr,
> +        init: F,
> +    ) -> impl PinInit<Self, Error> + 'a
> +    where
> +        F: for<'data, 'dir> FnOnce(&'data T, &'data Device<Bound>, &'dir ScopedDir<'data, 'dir>)
> +            + 'a,
> +        Error: From<E>,
> +    {
> +        Devres::new(
> +            dev,
> +            Scope::new(data, |data| {
> +                let scoped = ScopedDir::new(name);
> +                init(data, dev, &scoped);
> +                scoped.into_entry()
> +            }),
> +        )
> +    }
> +}

I think it is a big strange to have this on `Devres` (in patch v6 it has `Devres::dir` doesn't make
too much sense). I would suggest that we domsomething like

    impl<'a, T: 'a + Send> Scope<T> {
        pub fn devres_dir(
            ...
        ) -> impl PinInit<Devres<Self>, Error> + 'a;
    }

To me `Devres` is just a generic container type, just like `Arc` and `ARef`, so
the assoc functions should be defined on the concrete type.

Also: is there a reason that this needs a special API, and by

    Devres::new(device, Scope::dir(data, c"name", |data| {
        // use data and device
    });

?

Best,
Gary



^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v2 6/6] soc: qcom: socinfo: Convert to Rust
  2026-02-03 16:35     ` Danilo Krummrich
@ 2026-02-03 16:48       ` Greg Kroah-Hartman
  2026-02-03 16:56         ` Danilo Krummrich
  0 siblings, 1 reply; 32+ messages in thread
From: Greg Kroah-Hartman @ 2026-02-03 16:48 UTC (permalink / raw)
  To: Danilo Krummrich
  Cc: Matthew Maurer, Bjorn Andersson, Konrad Dybcio,
	Satya Durga Srinivasu Prabhala, Miguel Ojeda, Boqun Feng,
	Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg,
	Alice Ryhl, Trevor Gross, Daniel Almeida, Rafael J. Wysocki,
	David Airlie, Simona Vetter, Michal Wilczynski, Dave Ertman,
	Ira Weiny, Leon Romanovsky, Trilok Soni, linux-kernel,
	linux-arm-msm, rust-for-linux, driver-core, dri-devel, linux-pwm

On Tue, Feb 03, 2026 at 05:35:24PM +0100, Danilo Krummrich wrote:
> On Tue Feb 3, 2026 at 5:28 PM CET, Greg Kroah-Hartman wrote:
> > On Tue, Feb 03, 2026 at 03:46:35PM +0000, Matthew Maurer wrote:
> >> +impl Smem {
> >> +    pub(crate) fn access<'a>(&'a self, dev: &'a Device<Bound>) -> Option<&'a Mmio> {
> >> +        if *dev != *self.dev {
> >
> > How can this ever happen?
> 
> You are right, since this resource is local to the driver, it should not be
> possible to have another devce from somewhere else (especially not a
> &Device<Bound>).
> 
> However, from a Rust perspective I think not having this check would be unsound,
> as the method by itself would not be able guarantee correct behavor anymore.
> 

I don't really understand this last sentence, sorry.  If this is "not
possible" why would that at the same time be "unsound"?

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v2 6/6] soc: qcom: socinfo: Convert to Rust
  2026-02-03 16:48       ` Greg Kroah-Hartman
@ 2026-02-03 16:56         ` Danilo Krummrich
  2026-02-03 17:17           ` Gary Guo
  0 siblings, 1 reply; 32+ messages in thread
From: Danilo Krummrich @ 2026-02-03 16:56 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: Matthew Maurer, Bjorn Andersson, Konrad Dybcio,
	Satya Durga Srinivasu Prabhala, Miguel Ojeda, Boqun Feng,
	Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg,
	Alice Ryhl, Trevor Gross, Daniel Almeida, Rafael J. Wysocki,
	David Airlie, Simona Vetter, Michal Wilczynski, Dave Ertman,
	Ira Weiny, Leon Romanovsky, Trilok Soni, linux-kernel,
	linux-arm-msm, rust-for-linux, driver-core, dri-devel, linux-pwm

On Tue Feb 3, 2026 at 5:48 PM CET, Greg Kroah-Hartman wrote:
> On Tue, Feb 03, 2026 at 05:35:24PM +0100, Danilo Krummrich wrote:
>> On Tue Feb 3, 2026 at 5:28 PM CET, Greg Kroah-Hartman wrote:
>> > On Tue, Feb 03, 2026 at 03:46:35PM +0000, Matthew Maurer wrote:
>> >> +impl Smem {
>> >> +    pub(crate) fn access<'a>(&'a self, dev: &'a Device<Bound>) -> Option<&'a Mmio> {
>> >> +        if *dev != *self.dev {
>> >
>> > How can this ever happen?
>> 
>> You are right, since this resource is local to the driver, it should not be
>> possible to have another devce from somewhere else (especially not a
>> &Device<Bound>).
>> 
>> However, from a Rust perspective I think not having this check would be unsound,
>> as the method by itself would not be able guarantee correct behavor anymore.
>> 
>
> I don't really understand this last sentence, sorry.  If this is "not
> possible" why would that at the same time be "unsound"?

It would be considered unsound because the function itself can not guarantee
that it does not produce undefined behavior, i.e. it would otherwise becomes
unsafe.

But I'm not an expert on this, I'll let Benno and Gary jump in.

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v2 5/6] rust: debugfs: Allow access to device in Devres-wrapped scopes
  2026-02-03 16:47   ` Gary Guo
@ 2026-02-03 16:58     ` Danilo Krummrich
  2026-02-03 18:04     ` Matthew Maurer
  1 sibling, 0 replies; 32+ messages in thread
From: Danilo Krummrich @ 2026-02-03 16:58 UTC (permalink / raw)
  To: Gary Guo
  Cc: Matthew Maurer, Bjorn Andersson, Konrad Dybcio,
	Satya Durga Srinivasu Prabhala, Miguel Ojeda, Boqun Feng,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Daniel Almeida, Greg Kroah-Hartman,
	Rafael J. Wysocki, David Airlie, Simona Vetter, Michal Wilczynski,
	Dave Ertman, Ira Weiny, Leon Romanovsky, Trilok Soni,
	linux-kernel, linux-arm-msm, rust-for-linux, driver-core,
	dri-devel, linux-pwm

On Tue Feb 3, 2026 at 5:47 PM CET, Gary Guo wrote:
> I think it is a big strange to have this on `Devres` (in patch v6 it has `Devres::dir` doesn't make
> too much sense). I would suggest that we domsomething like
>
>     impl<'a, T: 'a + Send> Scope<T> {
>         pub fn devres_dir(
>             ...
>         ) -> impl PinInit<Devres<Self>, Error> + 'a;
>     }

Good catch, I did not notice that this is implemented on Devres, rather than
debugfs. This should not be implemented on Devres.

> To me `Devres` is just a generic container type, just like `Arc` and `ARef`, so
> the assoc functions should be defined on the concrete type.

Indded.

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v2 3/6] rust: device: Support testing devices for equality
  2026-02-03 16:46         ` Danilo Krummrich
@ 2026-02-03 17:17           ` Matthew Maurer
  0 siblings, 0 replies; 32+ messages in thread
From: Matthew Maurer @ 2026-02-03 17:17 UTC (permalink / raw)
  To: Danilo Krummrich
  Cc: Greg Kroah-Hartman, Bjorn Andersson, Konrad Dybcio,
	Satya Durga Srinivasu Prabhala, Miguel Ojeda, Boqun Feng,
	Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg,
	Alice Ryhl, Trevor Gross, Daniel Almeida, Rafael J. Wysocki,
	David Airlie, Simona Vetter, Michal Wilczynski, Dave Ertman,
	Ira Weiny, Leon Romanovsky, Trilok Soni, linux-kernel,
	linux-arm-msm, rust-for-linux, driver-core, dri-devel, linux-pwm

On Tue, Feb 3, 2026 at 8:46 AM Danilo Krummrich <dakr@kernel.org> wrote:
>
> On Tue Feb 3, 2026 at 5:40 PM CET, Greg Kroah-Hartman wrote:
> > On Tue, Feb 03, 2026 at 05:29:16PM +0100, Danilo Krummrich wrote:
> >> On Tue Feb 3, 2026 at 5:17 PM CET, Greg Kroah-Hartman wrote:
> >> > And I don't see what patch in this series uses this, am I missing it?
> >>
> >>      impl Smem {
> >>          pub(crate) fn access<'a>(&'a self, dev: &'a Device<Bound>) -> Option<&'a Mmio> {
> >>              if *dev != *self.dev {
> >>                  return None;
> >>              }
> >>
> >>              // SAFETY: By our invariant, this was a subrange of what was returned by smem_aux_get, for
> >>              // self.dev, and by our above check, that auxdev is still available.
> >>              Some(unsafe { Mmio::from_raw(&self.raw) })
> >>          }
> >>      }
> >>
> >> It's used to ensure that the Smem provided by the auxiliary parent can only be
> >> accessed as long as the auxiliary parent device is bound.
> >
> > But how can a parent device ever bevome "unbound"?
>
> It can't, that's why auxiliary::Device::parent() returns a &Device<Bound>, i.e.
> as long as the child is bound the parent is guaranteed to be bound as well.
>
> The point in this implementation is that we need to prove to the resource
> container (Smem) that we are allowed to access the resource, since it is only
> valid to access for the duration the parent is bound.
>
> In the end this is equivalent to Devres::access(), which bypasses the Revocable
> if we can prove that we are in a &Device<Bound> scope.
>
> Having that said, the code should probably just use Devres instead. :)

Not using Devres was intentional because:
1. Implementing `subrange` would require more unsafe / invariant logic
with Devres. I would need to either wrap `MmioRaw` in a wrapper that
maintained that it would always be inside a Devres that owned it, or
wrap the Devres<MmioRaw> in a wrapper that encoded that invariant.
Then, I would need to propagate the `dev` from the source `Devres` to
the derived `Devres`.
2. Devres is PinInit, so I can't put it in a vector.
3. I don't need the destructor feature of Devres that necessitates the
extra complexity, because this is morally a checked borrow, not an
owned value.

I considered adding a more lightweight `Devref` to the kernel crate
which only supports types which do not implement `Drop` and access
through `access`, and so does not need to be `PinInit`. However, since
that would still require the manual dev propagation wrapper, it seemed
like it might be overkill.

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v2 6/6] soc: qcom: socinfo: Convert to Rust
  2026-02-03 16:56         ` Danilo Krummrich
@ 2026-02-03 17:17           ` Gary Guo
  2026-02-03 17:26             ` Matthew Maurer
  2026-02-03 17:59             ` Danilo Krummrich
  0 siblings, 2 replies; 32+ messages in thread
From: Gary Guo @ 2026-02-03 17:17 UTC (permalink / raw)
  To: Danilo Krummrich, Greg Kroah-Hartman
  Cc: Matthew Maurer, Bjorn Andersson, Konrad Dybcio,
	Satya Durga Srinivasu Prabhala, Miguel Ojeda, Boqun Feng,
	Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg,
	Alice Ryhl, Trevor Gross, Daniel Almeida, Rafael J. Wysocki,
	David Airlie, Simona Vetter, Michal Wilczynski, Dave Ertman,
	Ira Weiny, Leon Romanovsky, Trilok Soni, linux-kernel,
	linux-arm-msm, rust-for-linux, driver-core, dri-devel, linux-pwm

On Tue Feb 3, 2026 at 4:56 PM GMT, Danilo Krummrich wrote:
> On Tue Feb 3, 2026 at 5:48 PM CET, Greg Kroah-Hartman wrote:
>> On Tue, Feb 03, 2026 at 05:35:24PM +0100, Danilo Krummrich wrote:
>>> On Tue Feb 3, 2026 at 5:28 PM CET, Greg Kroah-Hartman wrote:
>>> > On Tue, Feb 03, 2026 at 03:46:35PM +0000, Matthew Maurer wrote:
>>> >> +impl Smem {
>>> >> +    pub(crate) fn access<'a>(&'a self, dev: &'a Device<Bound>) -> Option<&'a Mmio> {
>>> >> +        if *dev != *self.dev {
>>> >
>>> > How can this ever happen?
>>> 
>>> You are right, since this resource is local to the driver, it should not be
>>> possible to have another devce from somewhere else (especially not a
>>> &Device<Bound>).
>>> 
>>> However, from a Rust perspective I think not having this check would be unsound,
>>> as the method by itself would not be able guarantee correct behavor anymore.
>>> 
>>
>> I don't really understand this last sentence, sorry.  If this is "not
>> possible" why would that at the same time be "unsound"?
>
> It would be considered unsound because the function itself can not guarantee
> that it does not produce undefined behavior, i.e. it would otherwise becomes
> unsafe.
>
> But I'm not an expert on this, I'll let Benno and Gary jump in.

Yes, in this code, `Smem::access` is using the passed-in `&'a Device<Bound>` as
a proof that the device is still bound.

If the check is not present, the user of this API can give in a reference of a
different device, and now you're pontentially providing access to the MMIO
region to a device that is not bound anymore. A important property we want to
enforce is that UB cannot happen no matter how an API is misused (it may still
oops, which is bad, but better than UB).

This particular code, though, probably should use `Devres` as Danilo suggested.

PS. Personally I think this check (and the one in Devres::access) should use
assertion rather than `EINVAL`, because it is a bad driver bug when this is hit,
and adding failing code path for something that is a bug is something I really
dislike... It should at least be a `WARN`.

Best,
Gary

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v2 6/6] soc: qcom: socinfo: Convert to Rust
  2026-02-03 17:17           ` Gary Guo
@ 2026-02-03 17:26             ` Matthew Maurer
  2026-02-03 17:59             ` Danilo Krummrich
  1 sibling, 0 replies; 32+ messages in thread
From: Matthew Maurer @ 2026-02-03 17:26 UTC (permalink / raw)
  To: Gary Guo
  Cc: Danilo Krummrich, Greg Kroah-Hartman, Bjorn Andersson,
	Konrad Dybcio, Satya Durga Srinivasu Prabhala, Miguel Ojeda,
	Boqun Feng, Björn Roy Baron, Benno Lossin, Andreas Hindborg,
	Alice Ryhl, Trevor Gross, Daniel Almeida, Rafael J. Wysocki,
	David Airlie, Simona Vetter, Michal Wilczynski, Dave Ertman,
	Ira Weiny, Leon Romanovsky, Trilok Soni, linux-kernel,
	linux-arm-msm, rust-for-linux, driver-core, dri-devel, linux-pwm

On Tue, Feb 3, 2026 at 9:17 AM Gary Guo <gary@garyguo.net> wrote:
>
> On Tue Feb 3, 2026 at 4:56 PM GMT, Danilo Krummrich wrote:
> > On Tue Feb 3, 2026 at 5:48 PM CET, Greg Kroah-Hartman wrote:
> >> On Tue, Feb 03, 2026 at 05:35:24PM +0100, Danilo Krummrich wrote:
> >>> On Tue Feb 3, 2026 at 5:28 PM CET, Greg Kroah-Hartman wrote:
> >>> > On Tue, Feb 03, 2026 at 03:46:35PM +0000, Matthew Maurer wrote:
> >>> >> +impl Smem {
> >>> >> +    pub(crate) fn access<'a>(&'a self, dev: &'a Device<Bound>) -> Option<&'a Mmio> {
> >>> >> +        if *dev != *self.dev {
> >>> >
> >>> > How can this ever happen?
> >>>
> >>> You are right, since this resource is local to the driver, it should not be
> >>> possible to have another devce from somewhere else (especially not a
> >>> &Device<Bound>).
> >>>
> >>> However, from a Rust perspective I think not having this check would be unsound,
> >>> as the method by itself would not be able guarantee correct behavor anymore.
> >>>
> >>
> >> I don't really understand this last sentence, sorry.  If this is "not
> >> possible" why would that at the same time be "unsound"?

The code as it stands doesn't do anything that would grant `Smem`
objects to something that exceeds the lifetime of the device. The goal
of bindings APIs like these are that it should be impossible for
someone to write Rust code without the word `unsafe` in it that breaks
its invariants. Without that check, someone could do:

let smem = Smem::get(dev)?;
let f = move |offset| smem.try_copy(offset);
some_other_driver_or_subsystem(f);

That other region of the code would now have ownership over that
function, and expect to be able to call it safely. We're not doing
that, but we're trying to design the unsafe API in bindings so that
you can't mess it up even if you wanted to.

> >
> > It would be considered unsound because the function itself can not guarantee
> > that it does not produce undefined behavior, i.e. it would otherwise becomes
> > unsafe.
> >
> > But I'm not an expert on this, I'll let Benno and Gary jump in.
>
> Yes, in this code, `Smem::access` is using the passed-in `&'a Device<Bound>` as
> a proof that the device is still bound.
>
> If the check is not present, the user of this API can give in a reference of a
> different device, and now you're pontentially providing access to the MMIO
> region to a device that is not bound anymore. A important property we want to
> enforce is that UB cannot happen no matter how an API is misused (it may still
> oops, which is bad, but better than UB).
>
> This particular code, though, probably should use `Devres` as Danilo suggested.

Mentioned on the other thread, but I didn't use `Devres` because it
being PinInit is problematic and I would need to encode an additional
invariant anyways.

>
> PS. Personally I think this check (and the one in Devres::access) should use
> assertion rather than `EINVAL`, because it is a bad driver bug when this is hit,
> and adding failing code path for something that is a bug is something I really
> dislike... It should at least be a `WARN`.
>
> Best,
> Gary

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v2 6/6] soc: qcom: socinfo: Convert to Rust
  2026-02-03 16:28   ` Greg Kroah-Hartman
  2026-02-03 16:35     ` Danilo Krummrich
@ 2026-02-03 17:37     ` Matthew Maurer
  2026-02-04  8:38       ` Greg Kroah-Hartman
  1 sibling, 1 reply; 32+ messages in thread
From: Matthew Maurer @ 2026-02-03 17:37 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: Bjorn Andersson, Konrad Dybcio, Satya Durga Srinivasu Prabhala,
	Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, Daniel Almeida, Rafael J. Wysocki, David Airlie,
	Simona Vetter, Michal Wilczynski, Dave Ertman, Ira Weiny,
	Leon Romanovsky, Trilok Soni, linux-kernel, linux-arm-msm,
	rust-for-linux, driver-core, dri-devel, linux-pwm

On Tue, Feb 3, 2026 at 8:28 AM Greg Kroah-Hartman
<gregkh@linuxfoundation.org> wrote:
>
> On Tue, Feb 03, 2026 at 03:46:35PM +0000, Matthew Maurer wrote:
> > Convert the socinfo driver to Rust for a number of improvements:
> > * Accessing IO mapped regions through the IO subsystem, rather than
> >   through regular memory accesses.
>
> That's good, but the C code could also be "fixed" to do this, right?

Yes, nothing stops the C code from being fixed to do all of this - all
of this is representable in C code.

>
> > * Binds the device as an auxiliary device rather than a platform device,
> >   ensuring the mapped IO regions cannot be accessed after the smem
> >   device is removed.
>
> I'm all for this, but is this really an aux device?  What is the
> "parent" device of this aux device?  Where are the "siblings"?  What
> does sysfs look like before/after this?

The parent of this aux device is qcom-smem. In the prior
implementation, qcom-smem loads this device through
`platform_device_register_data` and `platform_device_unregister`,
holding a reference in its global struct to release it when being
released. The probe table for the qcom-socinfo driver was empty, so it
would not probe without an explicit registration.

>
> > * Adds bounds-checking to all accesses, hardening against a repeat of
> >   CVE-2024-58007
>
> How do you now "know" that the bounds checking is correct?  The C
> version also had this, it was just "not correct" :)

While it's technically possible for the Rust code to have an error
here, the error would not be in the driver, but in the kernel crate.
The advantage here is that the bounds checking is all centralized, so
we get it right once, for the entire kernel, instead of needing to get
it right every time.

>
> And which accesses are you referring to?  From userspace?  From the
> kernel?  That CVE looks very odd, it's probably not even a real one and
> should be revoked, right?
>

That CVE looks like this:
1. qcom_smem_get returns an object of size N
2. When initializing the `serial_number` field of
soc_device_attributes, the offset of the serial number field was
checked as <= N, rather than the *end* of the serial number field.
3. This resulted in the driver exposing through sysfs whatever data
was mapped afterwards, interpreted as a number.

I agree that the severity seems oddly high, given that in practice,
this will expose the remainder of the IO mapped page - I don't believe
it crosses a page boundary, so it can't even *really* leak anything.

>
> > diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c
> > index fef840b5457407a85051ded0e835430dbebfe8bb..dcea2d7f37067b0b6f801b3d2b457422ad9f342c 100644
> > --- a/drivers/soc/qcom/smem.c
> > +++ b/drivers/soc/qcom/smem.c
> > @@ -4,6 +4,7 @@
> >   * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
> >   */
> >
> > +#include <linux/auxiliary_bus.h>
> >  #include <linux/hwspinlock.h>
> >  #include <linux/io.h>
> >  #include <linux/module.h>
> > @@ -279,7 +280,6 @@ struct qcom_smem {
> >       struct hwspinlock *hwlock;
> >
> >       u32 item_count;
> > -     struct platform_device *socinfo;
> >       struct smem_ptable *ptable;
> >       struct smem_partition global_partition;
> >       struct smem_partition partitions[SMEM_HOST_COUNT];
> > @@ -675,6 +675,32 @@ static void *qcom_smem_get_private(struct qcom_smem *smem,
> >       return ERR_PTR(-EINVAL);
> >  }
> >
> > +/**
> > + * qcom_smem_get_aux() - resolve ptr of size of a smem item
> > + * @aux:        an aux device that should be our child
> > + * @host:    the remote processor, or -1
> > + * @item:    smem item handle
> > + * @size:    pointer to be filled out with size of the item
> > + *
> > + * Looks up smem item and returns pointer to it. Size of smem
> > + * item is returned in @size.
> > + *
> > + * The caller may take the loaded state of the provided aux device as
> > + * an acceptable proxy for this memory being valid.
> > + *
> > + * Return: a pointer to an SMEM item on success, ERR_PTR() on failure.
> > + */
> > +void *qcom_smem_get_aux(struct auxiliary_device *aux, unsigned int host,
> > +             unsigned int item, size_t *size)
> > +{
> > +     if (IS_ERR(__smem))
> > +             return __smem;
> > +     if (aux->dev.parent != __smem->dev)
> > +             return ERR_PTR(-EINVAL);
> > +     return qcom_smem_get(host, item, size);
>
> So you are returning a void pointer?  But don't you really know the
> "type" of what is being asked here?  It's a memory chunk, so u8?  Or
> something else?  void * feels "rough" here.
>
> > +}
> > +EXPORT_SYMBOL_GPL(qcom_smem_get_aux);
> > +
> >  /**
> >   * qcom_smem_get() - resolve ptr of size of a smem item
> >   * @host:    the remote processor, or -1
> > @@ -684,6 +710,9 @@ static void *qcom_smem_get_private(struct qcom_smem *smem,
> >   * Looks up smem item and returns pointer to it. Size of smem
> >   * item is returned in @size.
> >   *
> > + * It is up to the caller to ensure that the qcom_smem device remains
> > + * loaded by some mechanism when accessing returned memory.
>
> What do you mean by "loaded"?  You are saying that the caller needs to
> rely on this driver remaining in memory for that memory to be "valid"?
>
> If this is the case, why not take a reference count?
>
> > +impl Smem {
> > +    pub(crate) fn access<'a>(&'a self, dev: &'a Device<Bound>) -> Option<&'a Mmio> {
> > +        if *dev != *self.dev {
>
> How can this ever happen?
>
> thanks,
>
> greg k-h

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v2 6/6] soc: qcom: socinfo: Convert to Rust
  2026-02-03 17:17           ` Gary Guo
  2026-02-03 17:26             ` Matthew Maurer
@ 2026-02-03 17:59             ` Danilo Krummrich
  1 sibling, 0 replies; 32+ messages in thread
From: Danilo Krummrich @ 2026-02-03 17:59 UTC (permalink / raw)
  To: Gary Guo
  Cc: Greg Kroah-Hartman, Matthew Maurer, Bjorn Andersson,
	Konrad Dybcio, Satya Durga Srinivasu Prabhala, Miguel Ojeda,
	Boqun Feng, Björn Roy Baron, Benno Lossin, Andreas Hindborg,
	Alice Ryhl, Trevor Gross, Daniel Almeida, Rafael J. Wysocki,
	David Airlie, Simona Vetter, Michal Wilczynski, Dave Ertman,
	Ira Weiny, Leon Romanovsky, Trilok Soni, linux-kernel,
	linux-arm-msm, rust-for-linux, driver-core, dri-devel, linux-pwm

On Tue Feb 3, 2026 at 6:17 PM CET, Gary Guo wrote:
> PS. Personally I think this check (and the one in Devres::access) should use
> assertion rather than `EINVAL`, because it is a bad driver bug when this is hit,
> and adding failing code path for something that is a bug is something I really
> dislike... It should at least be a `WARN`.

I don't think we should panic in this case, as it can happen too easily.

	// Let's assume the resource is owned by the parent.
	fn foo(adev: &auxiliary::Device<Bound>, res: &Devres<Resource>) {
	    let res = res.access(dev.parent()); // OK
	    let res = res.access(dev.as_ref()); // panic()
	}

Printing a warning is probably a good idea though.

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v2 5/6] rust: debugfs: Allow access to device in Devres-wrapped scopes
  2026-02-03 16:47   ` Gary Guo
  2026-02-03 16:58     ` Danilo Krummrich
@ 2026-02-03 18:04     ` Matthew Maurer
  1 sibling, 0 replies; 32+ messages in thread
From: Matthew Maurer @ 2026-02-03 18:04 UTC (permalink / raw)
  To: Gary Guo
  Cc: Bjorn Andersson, Konrad Dybcio, Satya Durga Srinivasu Prabhala,
	Miguel Ojeda, Boqun Feng, Björn Roy Baron, Benno Lossin,
	Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich,
	Daniel Almeida, Greg Kroah-Hartman, Rafael J. Wysocki,
	David Airlie, Simona Vetter, Michal Wilczynski, Dave Ertman,
	Ira Weiny, Leon Romanovsky, Trilok Soni, linux-kernel,
	linux-arm-msm, rust-for-linux, driver-core, dri-devel, linux-pwm

On Tue, Feb 3, 2026 at 8:48 AM Gary Guo <gary@garyguo.net> wrote:
>
> On Tue Feb 3, 2026 at 3:46 PM GMT, Matthew Maurer wrote:
> > This adds support for creating a DebugFS directory which is aware that
> > it is bound to a device. As a result, callbacks under that directory
> > have access to a bound device which gives them efficient access to other
> > Devres, ability to use dev_err! and friends, etc.
> >
> > Signed-off-by: Matthew Maurer <mmaurer@google.com>
> > ---
> >  rust/kernel/debugfs.rs | 40 ++++++++++++++++++++++++++++++++++++++++
> >  1 file changed, 40 insertions(+)
> >
> > diff --git a/rust/kernel/debugfs.rs b/rust/kernel/debugfs.rs
> > index d7b8014a6474698235203f2b7d8fec96f2bb43f8..ac614d693fa73929d095b669e9ba61958bec609e 100644
> > --- a/rust/kernel/debugfs.rs
> > +++ b/rust/kernel/debugfs.rs
> > @@ -11,6 +11,11 @@
> >  #[cfg(CONFIG_DEBUG_FS)]
> >  use crate::sync::Arc;
> >  use crate::{
> > +    device::{
> > +        Bound,
> > +        Device, //
> > +    },
> > +    devres::Devres,
> >      fmt,
> >      prelude::*,
> >      str::CStr,
> > @@ -722,3 +727,38 @@ fn new(name: &CStr) -> ScopedDir<'data, 'static> {
> >          }
> >      }
> >  }
> > +
> > +impl<'a, T: 'a + Send> Devres<Scope<T>> {
> > +    /// Creates a new scope, which is a directory at the root of the debugfs filesystem,
> > +    /// associated with some data `T`, enclosed in a [`Devres`] for the provided device.
> > +    ///
> > +    /// The `init` closure is called to populate the directory with files and subdirectories. These
> > +    /// files can reference the data stored in the scope. Because it is stored inside a `Devres`,
> > +    /// the init method is granted access to a `&Device<Bound>`.
> > +    ///
> > +    /// This can be used for cheaply accessing device-protected data inside DebugFS methods or
> > +    /// accessing device-specific methods (e.g. [`dev_err!`]).
> > +    ///
> > +    /// The entire directory tree created within the scope will be removed when the returned
> > +    /// `Scope` handle is dropped.
> > +    pub fn dir<E: 'a, F>(
> > +        dev: &'a Device<Bound>,
> > +        data: impl PinInit<T, E> + 'a,
> > +        name: &'a CStr,
> > +        init: F,
> > +    ) -> impl PinInit<Self, Error> + 'a
> > +    where
> > +        F: for<'data, 'dir> FnOnce(&'data T, &'data Device<Bound>, &'dir ScopedDir<'data, 'dir>)
> > +            + 'a,
> > +        Error: From<E>,
> > +    {
> > +        Devres::new(
> > +            dev,
> > +            Scope::new(data, |data| {
> > +                let scoped = ScopedDir::new(name);
> > +                init(data, dev, &scoped);
> > +                scoped.into_entry()
> > +            }),
> > +        )
> > +    }
> > +}
>
> I think it is a big strange to have this on `Devres` (in patch v6 it has `Devres::dir` doesn't make
> too much sense). I would suggest that we domsomething like
>
>     impl<'a, T: 'a + Send> Scope<T> {
>         pub fn devres_dir(
>             ...
>         ) -> impl PinInit<Devres<Self>, Error> + 'a;
>     }
>
> To me `Devres` is just a generic container type, just like `Arc` and `ARef`, so
> the assoc functions should be defined on the concrete type.
>
> Also: is there a reason that this needs a special API, and by
>
>     Devres::new(device, Scope::dir(data, c"name", |data| {
>         // use data and device
>     });
>
> ?

Yes - that won't work, because the function being provided to
`Scope::dir` is `for<'data, 'dir> FnOnce(&'data T, &'dir
ScopedDir<'data, 'dir>)` - this means that *intentionally*, if you
capture any non-static-lifetime variable from outside the closure, you
won't be able to use it with the methods on `ScopedDir`, because the
`'data` lifetime bound should stop you. In the general case, we
wouldn't want a reference with the same lifetime as `device` in that
example to be usable inside the debugfs callbacks. The device of a
Devres wrapped scope is a special case because we know that it will
outlive it.

>
> Best,
> Gary
>
>

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v2 6/6] soc: qcom: socinfo: Convert to Rust
  2026-02-03 15:46 ` [PATCH v2 6/6] soc: qcom: socinfo: Convert to Rust Matthew Maurer
  2026-02-03 16:28   ` Greg Kroah-Hartman
@ 2026-02-03 20:27   ` Bjorn Andersson
  2026-02-04  8:40     ` Greg Kroah-Hartman
  1 sibling, 1 reply; 32+ messages in thread
From: Bjorn Andersson @ 2026-02-03 20:27 UTC (permalink / raw)
  To: Matthew Maurer
  Cc: Konrad Dybcio, Satya Durga Srinivasu Prabhala, Miguel Ojeda,
	Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin,
	Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich,
	Daniel Almeida, Greg Kroah-Hartman, Rafael J. Wysocki,
	David Airlie, Simona Vetter, Michal Wilczynski, Dave Ertman,
	Ira Weiny, Leon Romanovsky, Trilok Soni, linux-kernel,
	linux-arm-msm, rust-for-linux, driver-core, dri-devel, linux-pwm

On Tue, Feb 03, 2026 at 03:46:35PM +0000, Matthew Maurer wrote:
> Convert the socinfo driver to Rust for a number of improvements:
> * Accessing IO mapped regions through the IO subsystem, rather than
>   through regular memory accesses.
> * Binds the device as an auxiliary device rather than a platform device,
>   ensuring the mapped IO regions cannot be accessed after the smem
>   device is removed.
> * Adds bounds-checking to all accesses, hardening against a repeat of
>   CVE-2024-58007
> 

These three bullet represents things that would be good to fix (in the
C-implementation), but the commit message does not describe the problem
that a complete Rust-rewrite solves.


I expressed my scepticism in v1 about changing this driver, for the sake
of supporting this experiment in your downstream kernel(s). The people
who suggested this driver to be a good candidate choose not to engage in
either that discussion nor in the review of the solution itself.

[..]
> diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c
> index fef840b5457407a85051ded0e835430dbebfe8bb..dcea2d7f37067b0b6f801b3d2b457422ad9f342c 100644
> --- a/drivers/soc/qcom/smem.c
> +++ b/drivers/soc/qcom/smem.c
> @@ -4,6 +4,7 @@
>   * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
>   */
>  
> +#include <linux/auxiliary_bus.h>
>  #include <linux/hwspinlock.h>
>  #include <linux/io.h>
>  #include <linux/module.h>
> @@ -279,7 +280,6 @@ struct qcom_smem {
>  	struct hwspinlock *hwlock;
>  
>  	u32 item_count;
> -	struct platform_device *socinfo;
>  	struct smem_ptable *ptable;
>  	struct smem_partition global_partition;
>  	struct smem_partition partitions[SMEM_HOST_COUNT];
> @@ -675,6 +675,32 @@ static void *qcom_smem_get_private(struct qcom_smem *smem,
>  	return ERR_PTR(-EINVAL);
>  }
>  
> +/**
> + * qcom_smem_get_aux() - resolve ptr of size of a smem item
> + * @aux:        an aux device that should be our child
> + * @host:	the remote processor, or -1
> + * @item:	smem item handle
> + * @size:	pointer to be filled out with size of the item
> + *
> + * Looks up smem item and returns pointer to it. Size of smem
> + * item is returned in @size.
> + *
> + * The caller may take the loaded state of the provided aux device as
> + * an acceptable proxy for this memory being valid.

Is this sentence trying to say "The purpose of this function is to
implicitly bind the life cycle of the returned pointer to the life of
the child auxiliary_device, which has due to devres will not outlive the
mapping of this pointer"?

IMHO this represents a very specific corner case and any other - real -
use-case of accessing SMEM would have to solve this problem properly.

> + *
> + * Return: a pointer to an SMEM item on success, ERR_PTR() on failure.
> + */
> +void *qcom_smem_get_aux(struct auxiliary_device *aux, unsigned int host,
> +		unsigned int item, size_t *size)
> +{
> +	if (IS_ERR(__smem))
> +		return __smem;
> +	if (aux->dev.parent != __smem->dev)
> +		return ERR_PTR(-EINVAL);
> +	return qcom_smem_get(host, item, size);
> +}
> +EXPORT_SYMBOL_GPL(qcom_smem_get_aux);
> +
>  /**
>   * qcom_smem_get() - resolve ptr of size of a smem item
>   * @host:	the remote processor, or -1
> @@ -684,6 +710,9 @@ static void *qcom_smem_get_private(struct qcom_smem *smem,
>   * Looks up smem item and returns pointer to it. Size of smem
>   * item is returned in @size.
>   *
> + * It is up to the caller to ensure that the qcom_smem device remains
> + * loaded by some mechanism when accessing returned memory.
> + *
>   * Return: a pointer to an SMEM item on success, ERR_PTR() on failure.
>   */
>  void *qcom_smem_get(unsigned host, unsigned item, size_t *size)
> @@ -1127,6 +1156,7 @@ static int qcom_smem_probe(struct platform_device *pdev)
>  	struct smem_header *header;
>  	struct reserved_mem *rmem;
>  	struct qcom_smem *smem;
> +	struct auxiliary_device *socinfo;
>  	unsigned long flags;
>  	int num_regions;
>  	int hwlock_id;
> @@ -1234,19 +1264,15 @@ static int qcom_smem_probe(struct platform_device *pdev)
>  
>  	__smem = smem;
>  
> -	smem->socinfo = platform_device_register_data(&pdev->dev, "qcom-socinfo",
> -						      PLATFORM_DEVID_NONE, NULL,
> -						      0);
> -	if (IS_ERR(smem->socinfo))
> -		dev_dbg(&pdev->dev, "failed to register socinfo device\n");
> +	socinfo = devm_auxiliary_device_create(&pdev->dev, "qcom-socinfo", NULL);
> +	if (IS_ERR(socinfo))
> +		dev_dbg(&pdev->dev, "failed to create socinfo device\n");

I wouldn't mind transitioning this to auxiliary_device independent of
this effort.

Regards,
Bjorn

>  
>  	return 0;
>  }
>  
>  static void qcom_smem_remove(struct platform_device *pdev)
>  {
> -	platform_device_unregister(__smem->socinfo);
> -
>  	__smem = NULL;
>  }
>  

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v2 6/6] soc: qcom: socinfo: Convert to Rust
  2026-02-03 17:37     ` Matthew Maurer
@ 2026-02-04  8:38       ` Greg Kroah-Hartman
  0 siblings, 0 replies; 32+ messages in thread
From: Greg Kroah-Hartman @ 2026-02-04  8:38 UTC (permalink / raw)
  To: Matthew Maurer
  Cc: Bjorn Andersson, Konrad Dybcio, Satya Durga Srinivasu Prabhala,
	Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, Daniel Almeida, Rafael J. Wysocki, David Airlie,
	Simona Vetter, Michal Wilczynski, Dave Ertman, Ira Weiny,
	Leon Romanovsky, Trilok Soni, linux-kernel, linux-arm-msm,
	rust-for-linux, driver-core, dri-devel, linux-pwm

On Tue, Feb 03, 2026 at 09:37:50AM -0800, Matthew Maurer wrote:
> On Tue, Feb 3, 2026 at 8:28 AM Greg Kroah-Hartman
> <gregkh@linuxfoundation.org> wrote:
> >
> > On Tue, Feb 03, 2026 at 03:46:35PM +0000, Matthew Maurer wrote:
> > > Convert the socinfo driver to Rust for a number of improvements:
> > > * Accessing IO mapped regions through the IO subsystem, rather than
> > >   through regular memory accesses.
> >
> > That's good, but the C code could also be "fixed" to do this, right?
> 
> Yes, nothing stops the C code from being fixed to do all of this - all
> of this is representable in C code.

Great!  How about sending fixes for that first so that older kernels can
benifit from those fixes :)

> > > * Binds the device as an auxiliary device rather than a platform device,
> > >   ensuring the mapped IO regions cannot be accessed after the smem
> > >   device is removed.
> >
> > I'm all for this, but is this really an aux device?  What is the
> > "parent" device of this aux device?  Where are the "siblings"?  What
> > does sysfs look like before/after this?
> 
> The parent of this aux device is qcom-smem. In the prior
> implementation, qcom-smem loads this device through
> `platform_device_register_data` and `platform_device_unregister`,
> holding a reference in its global struct to release it when being
> released. The probe table for the qcom-socinfo driver was empty, so it
> would not probe without an explicit registration.

So it's a "fake" platform device being created?  As Bjorn said, moving
this to aux today would probably be good first.

> > > * Adds bounds-checking to all accesses, hardening against a repeat of
> > >   CVE-2024-58007
> >
> > How do you now "know" that the bounds checking is correct?  The C
> > version also had this, it was just "not correct" :)
> 
> While it's technically possible for the Rust code to have an error
> here, the error would not be in the driver, but in the kernel crate.
> The advantage here is that the bounds checking is all centralized, so
> we get it right once, for the entire kernel, instead of needing to get
> it right every time.

I missed where the bounds checking is happening at all here.  I see
fields and sizes of fields, but what is verifying that those sizes are
actually correct?

> > And which accesses are you referring to?  From userspace?  From the
> > kernel?  That CVE looks very odd, it's probably not even a real one and
> > should be revoked, right?
> >
> 
> That CVE looks like this:
> 1. qcom_smem_get returns an object of size N
> 2. When initializing the `serial_number` field of
> soc_device_attributes, the offset of the serial number field was
> checked as <= N, rather than the *end* of the serial number field.
> 3. This resulted in the driver exposing through sysfs whatever data
> was mapped afterwards, interpreted as a number.
> 
> I agree that the severity seems oddly high, given that in practice,
> this will expose the remainder of the IO mapped page - I don't believe
> it crosses a page boundary, so it can't even *really* leak anything.

Where do you see this as "high"?  The kernel CNA does NOT give any
severity info for any CVEs that are issued.

If you are looking at the crap that NVD adds, well, it's just that,
crap, that has no actual relevance to anyone and is flat out wrong most
of the time.  We have asked them to stop doing this, but so far we have
not gotten a response:
	https://github.com/cisagov/vulnrichment/issues/262

In short, for kernel CVEs only look at the data provided by cve.org, or
the raw data provided by the kernel CNA team.

That being said, this seems like a basic "we are just displaying wrong
data in a sysfs file", so it probably should be rejected unless someone
can tell me how it fits the definition of a vulnerability?

As for why it's a CVE at all, it came in as part of the required GSD
import into CVE.org.

> > > +void *qcom_smem_get_aux(struct auxiliary_device *aux, unsigned int host,
> > > +             unsigned int item, size_t *size)
> > > +{
> > > +     if (IS_ERR(__smem))
> > > +             return __smem;
> > > +     if (aux->dev.parent != __smem->dev)
> > > +             return ERR_PTR(-EINVAL);
> > > +     return qcom_smem_get(host, item, size);
> >
> > So you are returning a void pointer?  But don't you really know the
> > "type" of what is being asked here?  It's a memory chunk, so u8?  Or
> > something else?  void * feels "rough" here.
> >
> > > +}
> > > +EXPORT_SYMBOL_GPL(qcom_smem_get_aux);
> > > +
> > >  /**
> > >   * qcom_smem_get() - resolve ptr of size of a smem item
> > >   * @host:    the remote processor, or -1
> > > @@ -684,6 +710,9 @@ static void *qcom_smem_get_private(struct qcom_smem *smem,
> > >   * Looks up smem item and returns pointer to it. Size of smem
> > >   * item is returned in @size.
> > >   *
> > > + * It is up to the caller to ensure that the qcom_smem device remains
> > > + * loaded by some mechanism when accessing returned memory.
> >
> > What do you mean by "loaded"?  You are saying that the caller needs to
> > rely on this driver remaining in memory for that memory to be "valid"?
> >
> > If this is the case, why not take a reference count?
> >
> > > +impl Smem {
> > > +    pub(crate) fn access<'a>(&'a self, dev: &'a Device<Bound>) -> Option<&'a Mmio> {
> > > +        if *dev != *self.dev {
> >
> > How can this ever happen?

I think you missed these review comments?

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v2 6/6] soc: qcom: socinfo: Convert to Rust
  2026-02-03 20:27   ` Bjorn Andersson
@ 2026-02-04  8:40     ` Greg Kroah-Hartman
  0 siblings, 0 replies; 32+ messages in thread
From: Greg Kroah-Hartman @ 2026-02-04  8:40 UTC (permalink / raw)
  To: Bjorn Andersson
  Cc: Matthew Maurer, Konrad Dybcio, Satya Durga Srinivasu Prabhala,
	Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, Daniel Almeida, Rafael J. Wysocki, David Airlie,
	Simona Vetter, Michal Wilczynski, Dave Ertman, Ira Weiny,
	Leon Romanovsky, Trilok Soni, linux-kernel, linux-arm-msm,
	rust-for-linux, driver-core, dri-devel, linux-pwm

On Tue, Feb 03, 2026 at 02:27:21PM -0600, Bjorn Andersson wrote:
> I expressed my scepticism in v1 about changing this driver, for the sake
> of supporting this experiment in your downstream kernel(s). The people
> who suggested this driver to be a good candidate choose not to engage in
> either that discussion nor in the review of the solution itself.

I was told that QCOM wanted this driver to be redone in rust as that is
what they wanted to do for further socinfo drivers going forward.
Hopefully the people that said that actually talked to the kernel
developers/maintainers involved in this driver first before doing so :)

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 32+ messages in thread

end of thread, other threads:[~2026-02-04  8:40 UTC | newest]

Thread overview: 32+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-02-03 15:46 [PATCH v2 0/6] soc: qcom: socinfo: Convert to Rust Matthew Maurer
2026-02-03 15:46 ` [PATCH v2 1/6] rust: Add sparse_array! helper macro Matthew Maurer
2026-02-03 15:46 ` [PATCH v2 2/6] rust: io: Support copying arrays and slices Matthew Maurer
2026-02-03 15:53   ` Danilo Krummrich
2026-02-03 15:46 ` [PATCH v2 3/6] rust: device: Support testing devices for equality Matthew Maurer
2026-02-03 15:56   ` Danilo Krummrich
2026-02-03 16:05   ` Gary Guo
2026-02-03 16:15   ` Greg Kroah-Hartman
2026-02-03 16:17   ` Greg Kroah-Hartman
2026-02-03 16:29     ` Danilo Krummrich
2026-02-03 16:40       ` Greg Kroah-Hartman
2026-02-03 16:46         ` Danilo Krummrich
2026-02-03 17:17           ` Matthew Maurer
2026-02-03 15:46 ` [PATCH v2 4/6] rust: auxiliary: Support accessing raw aux pointer Matthew Maurer
2026-02-03 15:55   ` Danilo Krummrich
2026-02-03 15:46 ` [PATCH v2 5/6] rust: debugfs: Allow access to device in Devres-wrapped scopes Matthew Maurer
2026-02-03 15:59   ` Danilo Krummrich
2026-02-03 16:47   ` Gary Guo
2026-02-03 16:58     ` Danilo Krummrich
2026-02-03 18:04     ` Matthew Maurer
2026-02-03 15:46 ` [PATCH v2 6/6] soc: qcom: socinfo: Convert to Rust Matthew Maurer
2026-02-03 16:28   ` Greg Kroah-Hartman
2026-02-03 16:35     ` Danilo Krummrich
2026-02-03 16:48       ` Greg Kroah-Hartman
2026-02-03 16:56         ` Danilo Krummrich
2026-02-03 17:17           ` Gary Guo
2026-02-03 17:26             ` Matthew Maurer
2026-02-03 17:59             ` Danilo Krummrich
2026-02-03 17:37     ` Matthew Maurer
2026-02-04  8:38       ` Greg Kroah-Hartman
2026-02-03 20:27   ` Bjorn Andersson
2026-02-04  8:40     ` Greg Kroah-Hartman

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox